; Copyright (c) 2009, <Lrz>
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;       * Redistributions of source code must retain the above copyright
;       notice, this list of conditions and the following disclaimer.
;       * Redistributions in binary form must reproduce the above copyright
;       notice, this list of conditions and the following disclaimer in the
;       documentation and/or other materials provided with the distribution.
;       * Neither the name of the <organization> nor the
;       names of its contributors may be used to endorse or promote products
;       derived from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov nickname <Lrz> ''AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;*****************************************************************************

; в этой секции идет разбор параметров указатель на секцию храниться в point_default
;типы ошибок при обработке макроса
;Макрос RamdiskFS
;/определение флагов в записи корневой директории
ATTR_READ_ONLY  equ     0x01
ATTR_HIDDEN     equ     0x02
ATTR_SYSTEM     equ     0x04
ATTR_VOLUME_ID  equ     0x08
ATTR_DIRECTORY  equ     0x10
ATTR_ARCHIVE    equ     0x20



show_error_1    equ     0x1     ;кончились данные - не запланированный конец секции
show_error_2    equ     0x2     ;нет завершающего символа в размере рам диска.
show_error_3    equ     0x4     ; рам диск будет иметь размер =64 кб. 
show_error_4    equ     0x8     ;

macro use_parse_def_sect
{
        mov     di,point_default
        push    ini_data_
        pop     es
        mov     si,point_to_point_def
        sub     si,2
        mov     cx,[si]         ;загрузим указатель наследующию секцию

        xor     ax,ax   ;обнулим аx для очистки флагов  

        sub     cx,di           ;вот теперь имеем истиный размер
        mov     save_cx_d,cx    ;сохраним значение cx своей переменной
;обнулим переменную флагов, это необходимо, для того, что бы избежать обработку повторяющихся значений

        mov     status_flag,ax
;;;;
;ВХод в обработку парсинга значений секций. es:di - указатель на начало секции cx размер секции доступной для парсинга
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;соглашение не разрушаем bp, es, cs, sp         
;use_Loader_Image       ;загрузить образ выше 1 мб
use_RamdiskFS
;проверяется самый последний.
use_LoaderModule    ;особенность - передает управление на загруженный модуль.
}

macro use_LoaderModule
;как вариант сейчас используется модель, при загрузке модуля на него передается управление, решение временое
;управление будет передаваться только после обработки всей секции 
{
local .found_end_str

        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_p_LM:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      ._afterLoaderModule     ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'L'
        jnz     .start_p_LM
;проверка на значение LoaderModule
;        parse_LoaderModule
        mov     bx,cx
        mov     ax,di

        mov     si,parse_LoaderModule
        mov     cx,parse_LoaderModule_e - parse_LoaderModule
        repe    cmpsb
        jnz     .rest_value_loop_LM        ;is not compare

        sub     bx,parse_LoaderModule_e - parse_LoaderModule ;correct cx
        add     bx,cx
        mov     cx,bx

        test    status_flag,flag_found_LM               ;оценка флагов
        jz      .correct_is_not_set_LM          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

.correct_is_not_set_LM:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        jcxz    .rest_value_loop_LM          ;not found param timeout
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .rest_value_loop_LM
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка LoaderModule = kord/kernel.loader
;мы ее модифицируем до такого состояния       dw,dw,db'kord/kernel.loader',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word
        push    dword [es:di-6]
        lea     si,[di-6]

        push    word  [es:di-2]
        xor     ax,ax
        mov     word [es:di-6],ax       ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
        mov     ax,info_real_mode_size  ;0x3000   ;следующий сегмент за данными


        mov     word [es:di-4],ax
        mov     word [es:di-2],16       ;кол-во блоков по 4 кб =64 кб т.е. больше не считаем 
;;;;;; поиск конца строчки
@@:     mov     al,byte [es:di]
        cmp     al,' '
        jz      .found_end_str
        cmp     al,0xa
        jz      .found_end_str
        cmp     al,0xd
        jz      .found_end_str
        inc     di
        dec     cx
        jnz     @b
;;;not found допустим,что это конец файла и он не имеет привычного заверешния строки
.found_end_str:

        push    word [es:di]
        xor     ax,ax
        mov     word [es:di],ax
;        xor     ax,ax   ; function 1 - read file
        mov     di,si   ;file_data
        inc     ax
        push    si
        push    es

        push    es
        pop     ds
        push    cs
        pop     es

        call    far  dword [es:loader_callback]

        push    cs
        pop     ds

        pop     es
        pop     si

        test    bx,bx
        jnz     .error_LM


        jmp     far     dword [es:si]


.error_LM:
        call    error.LoaderModule
.rest_value_loop_LM:
        mov     di,ax
        mov     cx,bx
        jmp     .start_p_LM

._afterLoaderModule:
}

macro use_RamdiskFS
; формирование рам диска, + обработка всего связанного.
{
if DEBUG
local ._not_memory_in_sys
;//////// clear window
        mov     ax,3
        int     0x10
;\\\\\\\\\ clear window is end
        mov     si,ramdiskFS_st
        call    printplain
end if
; обнулим регистр состояния ошибок
        xor     ax,ax
        mov     show_errors_sect,ax
use_free_memory ; узнаем какого объема у нас доступна память. значение возаращается в ax
;узнаем сколько у нас есть памяти и сможем ли мы сформировать нужного размера рам диск.
use_RamdiskSize ;значение возвращается в bx
        cmp     free_ad_memory,bx       ; размерность в кб.
        jbe     ._not_memory_in_sys
        movzx   eax,bx
        shl     eax,10  ;*1024 = get size in byte
        mov     save_ramdisksize,eax    ; сорханим размер в byte

get_type_FS     ;получим тип файловой системы + создадим ее 

        
._not_memory_in_sys:
        
if DEBUG
;pause
        xor     ax,ax
        int     0x16
end if
}
macro use_RamdiskSize
{
local .start_p_RS
local .correct_is_not_set_RS
local .CS
local .correct_val_RS
local .correct_size_RS
local .rest_value_loop_RS
local .end_get_RS_ERROR_1
local .end_get_RS_ERROR_2
local ._end_parse_RS
;обрабатывается размер формируемого рам диска
;загрузим начало секции, т.к. будем просматривать с начала и всю секцию
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
.start_p_RS:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      ._end_parse_RS  ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'R'
        jnz     .start_p_RS     
;проверка на значения RamdiskSize
;        parse_RamdiskSize
        mov     bx,cx
        mov     ax,di

        mov     si,parse_RamdiskSize
        mov     cx,parse_RamdiskSize_e - parse_RamdiskSize
        repe    cmpsb
        jnz     .rest_value_loop_RS    ;is not compare

        sub     bx,parse_RamdiskSize_e - parse_RamdiskSize ;correct cx
        add     bx,cx
        mov     cx,bx

        test    status_flag,flag_found_RS               ;оценка флагов
        jz      .correct_is_not_set_RS          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

.correct_is_not_set_RS:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        jcxz    .end_get_RS_ERROR_1          ;not found param 
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .start_p_RS                     ; перейдем на начало и попробуем найти еще секцию 
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Тут нужно преобразовывать строчку в цифровое значение.
;;;;;;;;;;;;;;;;;;;;;;;;;;
        xor     bx,bx
        mov     cx,5
@@:     mov     al,byte [es:di]
        cmp     al,'0'
        jb      .CS
        cmp     al,'9'
        jbe     .correct_val_RS
.CS:
        cmp     al,'K'
        jz      .correct_size_RS
        jmp     .end_get_RS_ERROR_2
.correct_val_RS:        
        imul    bx,10
        xor     al,0x30
        add     bl,al
        inc     di
        loop    @b

.correct_size_RS:
;возможен 1 вариант, когда размер задан в K киллобайтах
;внутренный формат данных это кол-во запрощеной памяти в кб.
        test    bx,bx
        jnz     @f      ;если значение отлично от 0
;;;;;сообщение об ошибке, размер "найденого" блока =0 минимально мы должны
;установить 64 кб размер рам диска.
        or      show_errors_sect,show_error_3
        mov     bx,64
@@:
        jmp     ._end_parse_RS


.rest_value_loop_RS:
        mov     di,ax
        mov     cx,bx
        jmp     .start_p_RS
        
        
        
.end_get_RS_ERROR_1:
;сообщение об ошибке - данный участок кода не был корректно обработан :(
        or      show_errors_sect,show_error_1
        jmp     ._end_parse_RS
.end_get_RS_ERROR_2:    
        or      show_errors_sect,show_error_2

._end_parse_RS:
if DEBUG
        pusha
        movzx   eax,bx
        mov     cx,0x0a
        mov     di,RamdiskSize_msg
        mov     dword[ds:di],'    '
        mov     word [ds:di+4],'  '
        call    decode
;Show size
        mov     si,RamdiskSize_msg
        call    printplain

        popa
end if  

}

macro use_free_memory
{       
local _support_function_use_free_memory
;макрос для получения общего числа доступной памяти в кб, для формирования рам диска за пределами 1 мб.
;используется 0х88 функция 0х15 прерывания
; если поддерживается функция, то в ax значение в кб, если нет, то в ax=0
        mov     ah,0x88  ;ah,0x88
        int     0x15
        jnc     ._support_function_use_free_memory
        xor     ax,ax
;возвращает в ax число в кб 
._support_function_use_free_memory:
        mov     free_ad_memory,ax  ; если не поддерживается биосом, то в ax=0
if DEBUG
        pushad
        movzx   eax,ax
        mov     cx,0x0a
        mov     di,free_memory_msg
        mov     dword[ds:di],'    '
        mov     word [ds:di+4],'  '
        call    decode
;Show size
        mov     si,free_memory_msg
        call    printplain

        popad
end if  




}
macro show_ERRORS
{

}

macro get_type_FS ;получить и создать образ для заданной RFS.
{
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
.start_g_tpe_RFS:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      ._end_parse_FRS ;._end_get_type_RFS     ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'R'
        jnz     .start_g_tpe_RFS
;проверка на значения RamdiskSize
;        parse_RamdiskSize
        mov     bx,cx
        mov     ax,di

        mov     si,parse_RamdiskFS
        mov     cx,parse_RamdiskFS_e - parse_RamdiskFS
        repe    cmpsb
        jnz     .start_g_tpe_RFS_rest_v    ;is not compare

        sub     bx,parse_RamdiskFS_e - parse_RamdiskFS ;correct cx
        add     bx,cx
        mov     cx,bx

        test    status_flag,flag_found_GTRFMS           ;оценка флагов
        jz      .correct_is_not_set_FRS          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

.correct_is_not_set_FRS:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        test    cx,cx
        jz      .end_get_FRS_ERROR_1          ;not found param 
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .start_g_tpe_RFS                        ; перейдем на начало и попробуем найти еще секцию 
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Тут нужно преобразовывать строчку в цифровое значение.
;;;;;;;;;;;;;;;;;;;;;;;;;;
        mov     bx,cx
        mov     ax,di

        mov     si,parse_RFS_FAT
        mov     cx,parse_RFS_FAT_e - parse_RFS_FAT
        repe    cmpsb
        jnz     .krfs_cmp          ;is not compare

make_FAT_RamFS  ;сделать 

if DEBUG
        pusha
        mov     si,make_fat12_RFS_msg
        call    printplain
        popa
end if  
        jmp     ._end_parse_FRS

.krfs_cmp:              
        mov     cx,bx
        mov     di,ax

        mov     si,parse_RFS_KRFS
        mov     cx,parse_RFS_KRFS_e - parse_RFS_KRFS
        repe    cmpsb
;       jnz     @f         ;is not compare

        jmp ._end_parse_FRS


.start_g_tpe_RFS_rest_v:
        mov     cx,bx
        mov     di,ax
        jmp     .start_g_tpe_RFS
        
        
        
.end_get_FRS_ERROR_1:
;сообщение об ошибке - данный участок кода не был корректно обработан :(
        or      show_errors_sect,show_error_1
        jmp     ._end_parse_FRS
.end_get_FRS_ERROR_2:   
        or      show_errors_sect,show_error_2

._end_parse_FRS:
if DEBUG
        pusha
        mov     si,get_type_FS_msg
        call    printplain
        popa
end if  



}
macro make_FAT_RamFS
{
local .RS1
local .fat12
local .fat16
; мы должны сформировать в начальный образ Ram FS, а потом записать его за область выше 1 мб..
;для случая с FAT12
;       mov     di,fat12_buffer ;ds должен быть = cs
;es:di - указывают на начало блока для формирования рам фс.
use_RamdiskSector       ;возращаемое значение в ax размер сектора в байтах
        cmp     ax,4096 ;по спецификации значение должно быть в пределах от 1 до 4096
        ja      .RS1
        test    ax,ax
        jnz     @f      ;ошибка если сюда прыгнули все таки ... 

.RS1:   mov     word [fat12_buffer.BPB_BytsPerSec],512
;;;;;;;;;;скажем что по дефолту будем юзать значение... 
@@:     mov     word [fat12_buffer.BPB_BytsPerSec],ax ;тут все ок

;BPB_SecPerClus кол-во секторов в кластере
use_RamdiskCluster      ;возращаемое значение в al
        cmp     al,128
        ja      @f
;       test    al,0x1  ;проверка на кратность ) 
;       jnz     @f

        mov     byte [fat12_buffer.BPB_SecPerClus],al

        ;incorrect value will be set dafault

;ниже некорректное значение в т.к. размер кратен 2 и в диапазоне от 1 до 128 включительно
; мы должны ругнуться на это 
;@@:    ;mov    byte [fat12_buffer.BPB_SecPerClus],1    

;;;;; определеим какая у нас будет использоваться FAT 
;по условию, fat12<4085<=fat16<65525<=fat32
; fat12_buffer.BPB_BytsPerSec*fat12_buffer.BPB_SecPerClus = кол-во секторов
        movzx   eax,word [fat12_buffer.BPB_BytsPerSec]
        movzx   ebx,byte [fat12_buffer.BPB_SecPerClus]

        imul    ebx,eax ;тут размерность сектора 
        mov     eax,save_ramdisksize  ;размер запрошенного рам диска в байтах
        cdq
        idiv    ebx
;;;;;;;; сейчас частное в eax, а остаток в edx
;получим кол-во секторов, и можем уже определить тип FAT которую нужно делать.
        cmp     eax,4085
        jb      .fat12
        cmp     eax,65525
        jb      .fat16
;;;;;;;;;;;;;;;;;;;;;;;; тут fat32
        mov     set_ramfs,32    ;установим тип файловой системы
        mov     word [fat12_buffer.BPB_RsvdSecCnt],32
        xor     eax,eax
        mov     word [fat12_buffer.BPB_RootEntCnt],ax
        mov     word [fat12_buffer.BPB_TotSec16],ax
        mov     dword [fat12_buffer.BPB_TotSec32],eax


.fat16: ;fat16
;Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение <умещается> (меньше 0x10000).
        jmp     $
        mov     set_ramfs,16    ;установим тип файловой системы
        movzx   ebx,byte [fat12_buffer.BPB_SecPerClus]
        imul    eax,ebx    

        cmp     eax,0x10000
        jae     @f
        mov     word [fat12_buffer.BPB_TotSec16],ax
        mov     dword [fat12_buffer.BPB_TotSec32],0
@@:
;количество секторов занимаемое одной копией фат
;       mov     word [fat12_buffer.BPB_FATSz16],0x9     ;Для FAT12/FAT16 это количество секторов одной FAT. ??
;;;; заполним BPB_RootEntCnt Для FAT12 и FAT16 дисков, это поле содержит число
;32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно
;быть 0. Пока константа, нужно будет позже доделать. 
        mov     eax,root_dir_entry_count
        mov     word [fat12_buffer.BPB_RootEntCnt],ax   ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
;по документации рекомендуют отрезать 16 кб для рут дир но это оч много, даже для коос. имхо для начала хватит и 7 кб
;;;;;;;
;Для FAT16 это количество секторов одной FAT. Для FAT32 это значение
;равно 0, а количество секторов одной FAT содержится в BPB_FATSz32.
;RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec;

;TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
;TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
;If(FATType == FAT32)
;    TmpVal2 = TmpVal2 / 2;
;FATSz = (TMPVal1 + (TmpVal2 - 1)) / TmpVal2;
;If(FATType == FAT32) {
;    BPB_FATSz16 = 0;
;    BPB_FATSz32 = FATSz;
;} else {
;    BPB_FATSz16 = LOWORD(FATSz);
;    /* there is no BPB_FATSz32 in a FAT16 BPB */
;}
;=====================================
;RootDirSectors
        movzx   ebx, word [fat12_buffer.BPB_BytsPerSec]
        imul    eax,32
        add     eax,ebx
        dec     eax

        cdq
        idiv    ebx
;;;;;;;; сейчас частное в eax, а остаток в edx для дискеты 1.44 у нас должно быть значение =14
;BPB_ResvdSecCnt + RootDirSectors
        movzx   ebx, word [fat12_buffer.BPB_RsvdSecCnt]
        add     ebx,eax 
         
;DskSize у нас это значение уже получено и доступно 
        movzx   eax,word [fat12_buffer.BPB_TotSec16]    ;должен быть в секторах
        sub     eax,ebx


;TmpVal1=eax
        shl     edi,8   ;=edi*256
        movzx   ecx,byte [fat12_buffer.BPB_NumFATs]
        add     edi,ecx
;TmpVal2=edi
        add     eax,edi
        dec     eax
        cdq
        idiv    edi
;FATSz = сейчас частное в eax, а остаток в edx
        mov     word [fat12_buffer.BPB_FATSz16],ax








.fat12: ;fat12
if DEBUG
; выведем в отладке, что собираемся делать образ диска c FS=fat12
	pushad
	mov	si,start_making_FAT12_msg
	call	printplain
	popad
end if



;Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение <умещается> (меньше 0x10000).
        mov     set_ramfs,12    ;установим тип файловой системы
        movzx   ebx,byte [fat12_buffer.BPB_SecPerClus]
        imul    eax,ebx    

        cmp     eax,0x10000
        jae     @f
        mov     word [fat12_buffer.BPB_TotSec16],ax
        mov     dword [fat12_buffer.BPB_TotSec32],0
@@:
;количество секторов занимаемое одной копией фат
;       mov     word [fat12_buffer.BPB_FATSz16],0x9     ;Для FAT12/FAT16 это количество секторов одной FAT. ??
;;;; заполним BPB_RootEntCnt Для FAT12 и FAT16 дисков, это поле содержит число
;32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно
;быть 0. Пока константа, нужно будет позже доделать. 
        mov     eax,root_dir_entry_count
        mov     word [fat12_buffer.BPB_RootEntCnt],ax   ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
;по документации рекомендуют отрезать 16 кб для рут дир но это оч много, даже для коос. имхо для начала хватит и 7 кб
;;;;;;;
;DskSize(в секторах)*12 (размерность файловой системы, т.е предположим сколько битов потребуется для адресации этого объема) /8 (что получить размер в байтах)
;полученное число округляем в большую сторону кратное сектору т.е. 512 байт Такой подход не универсален, но пока пойдет
;вообще у мелкософт это все считается ручками, но мы будем юзать только под коос рам диск с фат12
        movzx   eax, word [fat12_buffer.BPB_TotSec16]
        imul    eax,12
        shr     eax,3   ;делим на 8 но т.е. нам нужно делить еще и на 512 или более в зависимости от размеров кластера
        movzx   ebx,word  [fat12_buffer.BPB_BytsPerSec] ;размер сектора
        cdq
        idiv    ebx     ;разделим на размер кластера
;сейчас у нас в eax значение его нужно округлить в большую сторону кратному 512 байтам
;применим следующее очистим and и добавим 512 байт. таким образом выравним на 512 байт
;но т.к. все равно делить нижний код нам не нужен
;       and     eax,0xfff200
;       add     eax,0x200       ;добавим 512 байт        для 1.44 дискеты идеально подходит ))  

        inc     ax
;по идее должно на каждую фат таблицу
;резервироваться 9 секторов т.е. получается 2*9=18+1 =19 секторов т.е. рут дир находиться на с 20 сетора т.е. с адреса 0х2600
;сейчас нужно вычислить сколько будет секторов занимать фат ) нужно разделить на 512
;FATSz = сейчас частное в eax
        mov     word [fat12_buffer.BPB_FATSz16],ax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_firstDataSector ;получить смещение до данных 
;создадим певую запись в фат по определенному адресу.
first_create_fat_table
;закиним BPB файловой системы за 1 мб.
use_BPB_RAM
;
;копирование файла.
use_RamdiskFile

;;;; вычисляем указатель на корневую дир FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16);
;       movzx   ebx, [fat12_buffer.BPB_NumFATs]
;       movzx   eax,ax
;       imul    eax,ebx
;eax=(BPB_NumFATs * BPB_FATSz16)
;       inc     eax
; BPB_ResvdSecCnt значение только 1 для fat12/16
;в eax указатель на root dir. для дискеты fat12 должно получиться при кол-во копий fat 1  = 1+ (1*1) =2 или 3

if DEBUG        
        pusha
;       mov     ax,point_default
;        mov     ax,cx
        mov     cx,0x0a
        mov     di,show_db1
;        mov     dword[ds:di],'    '
;       mov     word [ds:di+4],'  '
        call    decode                                                                    
;Show size
        mov     si,show_db1
        call    printplain
;
;       xor     ax,ax
;       int     0x16
        popa
end if  







}

macro use_RamdiskSector
{
;для некоторых FS будет игнорироваться 
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d

.start_RamdiskSector:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      .end_RamdiskSector      ;нету? ну ладно - следующее значение тогда ) 

        cmp     al,'R'
        jnz     .start_RamdiskSector
;проверка на значения RamdiskSize
;        parse_RamdiskSize

        mov     bx,cx
        mov     ax,di

        mov     si,parse_RamdiskSector
        mov     cx,parse_RamdiskSector_e - parse_RamdiskSector
        repe    cmpsb
        jnz     .RamdiskSector_rest_val    ;is not compare

        sub     bx,parse_RamdiskSector_e - parse_RamdiskSector ;correct cx
        add     bx,cx
        mov     cx,bx

        test    status_flag,flag_found_RamdiskSector            ;оценка флагов
        jz      .correct_is_not_set_RamdiskSector          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

.correct_is_not_set_RamdiskSector:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        jcxz    .end_get_RamS_ERROR_1          ;not found param 
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .start_RamdiskSector                    ; перейдем на начало и попробуем найти еще секцию 
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        xor     bx,bx
        mov     cx,4
@@:     movzx   ax,byte [es:di]
        cmp     al,'0'
        jb      .end_RamdiskSector
        cmp     al,'9'
        ja      .end_RamdiskSector
;;;;;;;;;;;;;;;;;;;

        imul    bx,10
        xor     al,0x30
        add     bx,ax

        inc     di

        loop    @b
        jmp     .end_RamdiskSector


.RamdiskSector_rest_val:
        mov     cx,bx
        mov     di,ax
        jmp     .start_RamdiskSector
.end_get_RamS_ERROR_1:

.end_RamdiskSector:
        mov     ax,bx

if DEBUG
        pusha
        movzx   eax,bx;save_cx_d;point_default
        mov     cx,0x0a
        mov     di,RamdiskSector_msg
        mov     dword[ds:di],'    '
        mov     dword [ds:di+4],'    '
        call    decode
;Show size
        mov     si,RamdiskSector_msg
        call    printplain

        popa
end if  

;       pop     di
;       pop     es
}

macro use_RamdiskCluster
{
;для некоторых FS будет игнорироваться 
;       push    es
;       push    di
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
;       push    ini_data_
;       pop     es
.start_RamdiskCluster:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      .end_RamdiskCluster     ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'R'
        jnz     .start_RamdiskCluster
;проверка на значения RamdiskSize
;        parse_RamdiskSize

        mov     bx,cx
        mov     ax,di

        mov     si,parse_RamdiskCluster
        mov     cx,parse_RamdiskCluster_e - parse_RamdiskCluster
        repe    cmpsb
        jnz     .RamdiskCluster_rest_val           ;is not compare

        sub     bx,parse_RamdiskCluster_e - parse_RamdiskCluster ;correct cx
        add     bx,cx
        mov     cx,bx

        test    status_flag,flag_found_RamdiskCluster           ;оценка флагов
        jz      .correct_is_not_set_RamdiskCluster          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

.correct_is_not_set_RamdiskCluster:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        jcxz    .end_get_RamSC_ERROR_1          ;not found param 
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .start_RamdiskCluster                   ; перейдем на начало и попробуем найти еще секцию 
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@:     movzx   ax,byte [es:di]
        cmp     al,'0'
        jb      .end_RamdiskCluster
        cmp     al,'9'
        ja      .end_RamdiskCluster
;;;;;;;;;;;;;;;;;;;
        xor     al,0x30

        jmp     .end_RamdiskCluster


.RamdiskCluster_rest_val:
        mov     cx,bx
        mov     di,ax
        jmp     .start_RamdiskCluster
.end_get_RamSC_ERROR_1:

.end_RamdiskCluster:
if DEBUG
        pusha
        mov     cx,0x0a
        mov     di,RamdiskCluster_msg
;        mov     word[ds:di],'  '
        call    decode
;Show size
        mov     si,RamdiskCluster_msg
        call    printplain

        popa
end if  

}

macro use_Loader_Image
;предназначен для загрузки образов выше 1 Мб.
;первоначальная версия загружает образ дискеты 1.44 мб
{
local .start_p_LI
local .exit
local .error_LI
local .rest_value_loop
local .found_end_str
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_p_LI:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      .exit   ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'L'
        jnz     .start_p_LI
;проверка на значение LoaderModule
;        parse_LoaderModule
        mov     bx,cx
        mov     ax,di

        mov     si,parse_LoaderImage
        mov     cx,parse_LoaderImage_e - parse_LoaderImage
        repe    cmpsb
        jnz     .rest_value_loop           ;is not compare

        sub     bx,parse_LoaderImage_e - parse_LoaderImage ;correct cx
        add     bx,cx
        mov     cx,bx

;       test    status_flag,flag_found_LM               ;оценка флагов
;       jz      .correct_is_not_set_LI          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

;.correct_is_not_set_LI:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        jcxz    .rest_value_loop_LI          ;not found param timeout
        
        cmp     ah,byte [es:di-1]    ;find '='
        jnz     .rest_value_loop_LI
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка LoaderModule = kord/kernel.loader
;мы ее модифицируем до такого состояния       dw,dw,db'kord/kernel.loader',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word
        push    dword [es:di-6]
        lea     si,[di-6]

        push    word  [es:di-2]
        xor     ax,ax
        mov     word [es:di-6],ax       ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
        mov     ax,info_real_mode_size  ;0x3000   ;следующий сегмент за данными


        mov     word [es:di-4],ax
        mov     word [es:di-2],16       ;кол-во блоков по 4 кб =64 кб т.е. больше не считаем 
;;;;;; поиск конца строчки
@@:     mov     al,byte [es:di]
        cmp     al,' '
        jz      .found_end_str
        cmp     al,0xa
        jz      .found_end_str
        cmp     al,0xd
        jz      .found_end_str
        inc     di
        dec     cx
        jnz     @b
;;;not found допустим,что это конец файла и он не имеет привычного заверешния строки
.found_end_str:
; чтение блока по 64 кб в сегмент и забрасывание его выше 1 мб.
        push    word [es:di]
        xor     ax,ax
        mov     word [es:di],ax
;        xor     ax,ax   ; function 1 - read file
        mov     di,si   ;file_data
        inc     ax
        push    si
        push    es
        call    far  dword [loader_callback]
        push    cs
        pop     ds

        pop     es
        pop     si

        test    bx,bx
        jnz     .error_LM


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; забрасывание блока в 64 кб выше 1 мб.
        mov     si,table_15_87
        push    es
        push    ds
        pop     es
        mov     cx, 256*18
        mov     ah, 0x87
        int     0x15
        pop     es
        pop     dx cx
        test    ah, ah



        jmp     far     dword [es:si]




.rest_value_loop:
        mov     di,ax
        mov     cx,bx
        jmp     .start_p_LI

.exit:



}



macro name_in_root_fat
;макрос, который записывает информацию о загруженном файле в корневую фат таблицу
{

}



macro use_RamdiskFile
{
;загрузка файлов с использование callback сервиса первичного загрузчика
;используется только для загрузки необходимых и небольших файлов, т.к. достаточно медленно работает
;для загрузки использует 0х87 функцию int 0x15 прерывания - загрузка блоков данных до 64 кб выше 1 мб
local   .start_loop
local   ._end
local   .rest_value_loop
local   .error
        mov     di,point_default   ;restore value
        mov     cx,save_cx_d
        mov     data_offset,0   ;clean offset
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_loop:
        call    get_firs_sym    ;get first symbol on new line
        test    cx,cx
        jz      ._end   ;нету? ну ладно - следующее значение тогда ) 
        cmp     al,'R'
        jnz     .start_loop
;проверка на значение RamdiskFile
        mov     bx,cx
        mov     ax,di

        mov     si,parse_RamdiskFile
        mov     cx,parse_RamdiskFile_e - parse_RamdiskFile
        repe    cmpsb
        jnz     .rest_value_loop           ;is not compare

        sub     bx,parse_RamdiskFile_e - parse_RamdiskFile ;correct cx
        add     bx,cx
        mov     cx,bx
;       test    status_flag,flag_found_LM               ;оценка флагов
;       jz      .correct_is_not_set_LM          

;       mov     si,found_equal_timeout                          ;мы нашли что флаг уже установлен, информируем
;       call    printplain
;       jmp     .get_next_str

;.correct_is_not_set_LM:
        mov     ax,0x3d20          ;cut al=' ' ah='='
        repe    scasb 
        test    ecx,ecx
        jz      .rest_value_loop   ;not found param timeout
        
        cmp     ah,byte [es:di-1]  ;find '='
        jnz     .rest_value_loop
        
        repe    scasb              ;cut ' '
        inc     cx
        dec     di

        mov     save_di_RAMDISK,di
        mov     save_cx_RAMDISK,cx
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка RamdiskFile = @menu,@menu
;мы ее модифицируем до такого состояния       dw,dw,db'@menu',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word

;
@@:     mov     al,byte [es:di]
        cmp     al,','          ; т.е. ищем разделитель 
        jz      .found_end_str
        inc     di
        dec     cx
        jnz     @b
;;;not found допустим,что это конец файла и он не имеет привычного завершения строки
.found_end_str:
;        mov    al,byte [es:di]
;       cmp     al,' '          ; убираем пробелы, если они есть
;       jnz     @f
;       inc     di
;       dec     cx
;       jnz     .found_end_str

;@@:
        mov     point_to_dest_file_name,di
        inc     di
;проверка индивидуальности имени файла
check_name_file
;/restore di - point and cx -size section
        mov     di,save_di_RAMDISK
        mov     cx,save_cx_RAMDISK

        test    al,al
        jnz     .start_loop     ;если в al значение не =0, то такое имя уже существует в системе.



        push    dword [es:di-6]
        lea     si,[di-6]

        push    word  [es:di-2]
        push    di
        xor     ax,ax
        mov     word [es:di-6],ax       ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
        mov     ax,info_real_mode_size  ;0x3000   ;следующий сегмент за данными


        mov     word [es:di-4],ax
        mov     word [es:di-2],16       ;кол-во блоков по 4 кб =64 кб т.е. больше не читаем 

        mov     di,point_to_dest_file_name

if DEBUG
        pushad
;	mov	ax,di
        mov     cx,0x0a
        mov     di,name_of_seg_get_64
        mov     dword[ds:di],'    '
        mov     word[ds:di+4],'  '
        call    decode
;Show size
        mov     si,name_of_seg_get_64
        call    printplain

        popad
end if  

        push    word [es:di]
        push    cx
        xor     ax,ax
        mov     word [es:di],ax
;        xor     ax,ax   ; function 1 - read file
        push    di
        mov     di,si   ;file_data
        inc     ax
        push    si
        push    es
        push    bp

        push    es
        pop     ds
        push    cs
        pop     es

        call    far  dword [es:loader_callback]


        push    cs
        pop     ds

        pop     bp
        pop     es
        pop     si

        cmp    bx,2
        ja     .error
; сейчас у нас в dx:ax размер файла, который мы загрузили.
; возможна ситуация, когда в bx=1 т.е. есть еще данные на диске 
        mov     status_flag_loader_f,bx

        shl     edx,16
        mov     dx,ax
;       shr     edx,10  ;размер файла в кб.
;;в edx размер в байтах.        
        mov     save_file_size,edx
        mov     eax,edx
;восстановим полностью файл сценария
        pop     di
        pop     cx      ;длинна остатка с 2-ой частью имени т.е. с именем назначением.
        pop     word [es:di]
        pop     di
        pop     word  [es:di-2]
        pop     dword [es:di-6]
        

if DEBUG
        pushad
        mov     cx,0x0a
        mov     di,RamdiskFile_msg
        mov     dword[ds:di],'    '
        call    decode
;Show size
        mov     si,RamdiskFile_msg
        call    printplain

        popad
end if  










; загрузим чему у нас равен кластер
;       mov     ax,word [fat12_buffer.BPB_BytsPerSec] ;кол-во байтов в секторе может быть любое 512 1024 2048 4096 2 байта
;       movzx   bx,byte [fat12_buffer.BPB_SecPerClus] ;кол-во секторов в кластере
;       imul    ax,bx
;сейчас в eax размер кластера (512) байт
;в edx длина файла в байтах до 64 кб    
;закиним файл за 1 мб
;1 нам нужно составить фат таблицу т.е. произвести разметку рамдиска, затем перенесем по адресу файл

;записать инфорамацию о файле в корневую директорию
register_file_in_fat
;перенести за 1 мб содержимое файла
move_file_up

;проверим, загружен ли до конца файл? т.е. если размер файла больше чем 64 кб, то будет подгружать оставшиеся блоки
        cmp     status_flag_loader_f,0x1
        jnz     @f
;нужно дозагузить данные файла и перенести их за 1-ый мб согласно фат структуре 









@@:
;тут организован цикл по загрузке файлов в корневую директорию
        mov     di,save_di_RAMDISK
        mov     cx,save_cx_RAMDISK
if DEBUG        
        pusha
        xor     ax,ax
        int     0x16
        popa
end if  


        jmp     .start_loop


.error:
        ;call   error.LoaderModule
;fixme!
.rest_value_loop:
        mov     di,ax
        mov     cx,bx
        jmp     .start_loop

._end:
;перенесем за 1-ый мб фат и рут дир
move_up_fat_and_root_d






;загрузка блока 
;       mov     ah,0x87
;       mov     cx,     ;size in byte
        

;es:si point to descripts


}

macro use_BPB_RAM ;закинуть самые первые 512 байт за 1-й мб
;данный макрос закидывает BPB структуру т.е. первые 512 байт, пока только фат12 за 1 мб
{
        mov     ax,fat12_buffer
        mov     si,table_15_87
        add     word [si+8*2+2],ax
        push    es
        push    ds
        pop     es
        mov     cx,256   ;бут сектор  укладывается в 512 байт 512/2=256
        mov     ah, 0x87
        int     0x15
        pop     es
;add 512 byte for destination adress
;       add     dword [si+8*3+2], 512
;        test    ah, ah
;        jz     
if DEBUG        
        pusha
        mov     ax,word [si+8*2+2]
        mov     cx,0x0a
        mov     di,BPB_msg
        call    decode                                                                    
;Show size
        mov     si,BPB_msg
        call    printplain
        popa
end if  
}
macro first_create_fat_table
;данный макрос создает оформляет 3 первых байта fat таблицы, и устанавливает указатель на следующий блок, и вносит 0 значение
;для смещения в корневой таблице.
{
        mov     al,byte [fat12_buffer.BPB_Media]


        push    ds


        mov     di,info_real_mode_size
        add     di,0x1000

if DEBUG
        pushad

        mov     ax,info_real_mode_size
        add     ax,0x1000
;	mov	ax,ds
	mov	cx,0xa
	       
        mov     di,first_entry_in_fat
        mov     dword [di],'    '
        mov     word  [di+4],'  '
        call    decode                                                                    
;Show size
        mov     si,first_entry_in_fat
        call    printplain

        xor     ax,ax
        int     0x16
      
        popad
end if


        push    di   ;  push    word info_real_mode_size+0x1000   ;cледующий сегмент за загруженным участком
        
        xor     di,di
        mov     point_to_free_root,di   ;значение смещения =0 в корневой фат таблице описания 

        pop     ds   ; загружен следующий сегмент т.е. пустой сегмент

        mov     byte [di],al
        or      ax,-1
        inc     di
        mov     word [di],ax

        pop     ds
        mov     point_next_fat_str,3

if DEBUG        
        pushad
        mov     ax,point_next_fat_str
        mov     cx,0x0a
        mov     di,fat_create_msg
        call    decode                                                                    
;Show size
        mov     si,fat_create_msg
        call    printplain
        popad
end if  

}
macro register_file_in_fat
;макрос регистрации файла в файловой структуре Fat
;пока поддерживается только фат12, пока )) 
;вычисление смежных кластеров и занесение инфы в fat/
{
local   .step2
local   .step3
local   .end
local   .eof_file

;di point on root dir на фри секцию.
        push    es

        mov     ax,info_real_mode_size
        add     ax,0x1000
        mov     es,ax  ;        push    word info_real_mode_size+0x1000   ;сегмент следующий за загруженным блоком в 64 кб

; определяем тип фат пока не определяем, пока только фат 12 
; 12 бит, для вычесления соседних каластеров. 
        mov     di,firstDataSect     ;в секторах
        sub     di,size_root_dir
;теперь в ax размер в секторах начала рут дир
        shl     di,9 ;imul 512
        add     di,point_to_free_root   ;смещение в уже записанных 32-х структурах.
;необходимо внести значение в рут дир т.е. 32 байта
if DEBUG        
        pushad
;       mov     ax,point_default
;        mov     ax,
        mov     cx,0x0a
        mov     di,show_db2
        mov     dword[ds:di],'    '
       mov     word [ds:di+4],'  '
        call    decode                                                                    
;Show size
        mov     si,show_db2
        call    printplain
;
;       xor     ax,ax
;       int     0x16
        popad
end if  



;gs:di - указатель для внесения инфорации в рут область фат таблицы инормации о файле.
        mov     si,shot_name_fat
        mov     cx,11
;запишем в структуру имя
@@:     lodsb
        stosb
        loop    @b

;запишем атрибуты файла и DIR_NTRes - зарезеврированный байт =0
        xor     ax,ax
        mov     ah,ATTR_VOLUME_ID
        mov     word [es:di],ax
        add     di,2
;DIR_CrtTimeTenth
        mov     byte [es:di],100
        inc     di
;DIR_CrtTime
        mov     word [es:di],0x032b    ;дата
        add     di,2
;DIR_CrtDate
        mov     word [es:di],0x0       ;время ><
        add     di,2
;DIR_LstAccDate
        mov     word [es:di],0x032b    ;дата моего
        add     di,2
;DIR_FstClusHI
        mov     word [es:di],0x0       ;время для фат12 /16 всегда 0
        add     di,2
;DIR_WrtTime
        mov     word [es:di],0x0       ;время ><
        add     di,2
;DIR_WrtDate
        mov     word [es:di],0x032b    
        add     di,2
        
        mov     ax,point_next_fat_str
        mov     word [es:di],ax 
        add     di,2

        push    di
;DIR_FstClusLO                  Младшее слово номера первого кластера.
 ;       mov     ax,point_next_fat_str   ;загрузим указатель на элемент фат таблицы т.е. это номер фат записи
;FATOffset = N + (N / 2) т.е. это уже у нас смещение мы знаем что -начинается все с 3-го элемента записи фат
        mov     bx,ax
        shr     bx,1
        add     ax,bx
;в ах сейчас FATOffset
;ThisFATEntOffset = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);
        mov     bx, word [fat12_buffer.BPB_BytsPerSec]
        cwd
        idiv    bx
;ax=ThisFATEntOffset= rem (FATOffset / BPB_BytsPerSec) четный или нечетный указатель.
        mov     si,ax
;нам нужно в цикле записать все кластеры которые будут использованы для размещения файла.
;узнаем размер кластера. 
        movzx   eax,word [fat12_buffer.BPB_BytsPerSec] 
        movzx   ebx,byte [fat12_buffer.BPB_SecPerClus]
        imul    eax,ebx
;ax - размер кластера.
;сейчас будем записывать во временный буфер фат таблицу для выбранного файла. Поскольку мы его загрузили возможно не полностью
;мы обработаем запись для фат полностью, в не зависимости от предела буфера где возможна часть файла.   
        mov     ebx,save_file_size      ;размер файла в байтах
        
@@:     sub     ebx,eax
        cmp     ebx,eax
        jbe     .eof_file

        inc     point_next_fat_str
        mov     cx,point_next_fat_str   ;загрузим указатель на элемент фат таблицы т.е. это номер фат записи
;FATOffset = N + (N / 2) т.е. это уже у нас смещение мы знаем что -начинается все с 3-го элемента записи фат
        mov     dx,ax
        shr     dx,1
        add     cx,dx



        test    si,0x1
        jz      .step2
        shl     cx,4
        mov     word[es:si],cx
        inc     si
        add     cx,ax
        jmp     @b

.step2: and     cx,0x0FFF
        mov     word[es:si],cx
        inc     si
        add     cx,ax
        jmp     @b

.eof_file:
        mov     cx,0x0fff
        test    si,0x1
        jz      .step3
        shl     cx,4
        mov     word[es:si],cx
        jmp     .end

.step3: and     cx,0x0FFF
        mov     word[es:si],cx

.end:   inc     point_next_fat_str

        pop     di
;DIR_FileSize 32-битный DWORD содержит размер файла в байтах.
        mov     eax,save_file_size
        mov     dword [es:di],eax

if DEBUG        
        pushad

        mov     di,firstDataSect     ;в секторах
        sub     di,size_root_dir
;теперь в ax размер в секторах начала рут дир
        shl     di,9 ;imul 512
        add     di,point_to_free_root   ;смещение в уже записанных 32-х структурах.

	push	di

        mov     si,dest_name_fat
        mov     cx,11

;запишем в структуру имя
@@:     mov     al,byte [es:di]
        inc     di
        mov     byte [ds:si],al
        inc     si
        loop    @b
        
        mov	di,si
	inc 	di
	pop	ax
	mov	cx,0xa
	call	decode

        mov     si,dest_name_fat
        call    printplain
        popad

END IF





        add     point_to_free_root,32   ;увелицим смещение до следующего значения.
        pop     es

}





macro get_firstDataSector
;макрос для вычисления певого сектора данных т.е. данных файлов в фате
;вычислим FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors;
{
        mov     ax,word [fat12_buffer.BPB_FATSz16]
        movzx   bx,byte [fat12_buffer.BPB_NumFATs]
        imul    ax,bx   ;9x1=9
;ax=BPB_NumFATs * FATSz
        mov     bx,word [fat12_buffer.BPB_RootEntCnt]   ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
        shr     bx,4    ;imul bx,32 and then div 512 -> in bx size in sectors
        add     ax,bx   ;9+14=23
        mov     size_root_dir,bx
        movzx   bx,byte [fat12_buffer.BPB_RsvdSecCnt]   ;add 1 for fat 16/12
        add     ax,bx
;ax=firstDataSector - где начинается первый секторо от 0 сектора в секторах. - фактически = 24 сектор
        mov     firstDataSect,ax        ;сохраним для вычисления
;       получимзначение кластеров, это объем в который мы можем записать данные
        mov     bx,word [fat12_buffer.BPB_TotSec16]
        sub     bx,ax
        mov     ax,bx
        movzx   bx,byte [fat12_buffer.BPB_SecPerClus]
        cwd
        idiv    bx
        mov     DataClasters,ax

if DEBUG        
        pushad
        mov     ax,firstDataSect        ;первый сектор данных
        mov     cx,0x0a
        mov     di,firstDataSect_msg
        call    decode                                                                    
;Show size
        mov     si,firstDataSect_msg
        call    printplain
;;;;;;;;;;;;;;;;;;;;;;;;;;
        mov     ax,size_root_dir        ;размер рут дир в сетокторах
        mov     cx,0x0a
        mov     di,size_root_dir_msg
        call    decode                                                                    
;Show size
        mov     si,size_root_dir_msg
        call    printplain
;;;;;;;;;;;;;;;;;;;;;;;;;;
        mov     ax,DataClasters ;кластеры
        mov     cx,0x0a
        mov     di,DataClasters_msg
        call    decode                                                                    
;Show size
        mov     si,DataClasters_msg
        call    printplain
        popad

end if  

}

macro use_RamdiskPATHS
;парсинг пути источника файлов.
{

}

macro use_RamdiskPATHD
;парсинг пути назначения файлов.
{

}
macro check_name_file
;макрос проверки имени на повтор, имя должно быть уникальным.
;входные данные: es- сегмент где лежит файл для парсинга т.е. startos.ini
;di - указатель на имя файла т.е. es:di указывает на имя файла назначения
;выходные данные eax =-1 имя совпало, eax=0 имя не совпало.
{
local   .no_equal
local   .exit
local 	.loop_size_root_dir
;вычислим длинну строчки имени назначения, которую будем сравнивать с уже записанными данными.
;преобразуем в аналог фат записи сточку с именем назначения
        convertion_file_name	; преобразовали имя по нужным правилам
        test    ax,ax
        jnz     .exit

        lea     si,[shot_name_fat]	; desination name of file

;вычислим указатель на корневую директорию
        mov     di,firstDataSect
        sub     di,size_root_dir
;теперь в ax размер в секторах начала рут дир
        shl     di,9 ;imul 512
;di= Это смещение от начала буфера до рут директории. в пределах 64 кб.
;загрузим значение - т.е. кол-во элементов, которые мы можем просматривать.
        mov     dx,root_dir_entry_count
        
        mov     ax,info_real_mode_size
        add     ax,0x1000


        mov     gs,ax
.loop_size_root_dir:
DEBUG1 equ 0
if DEBUG1        
        pushad
	push	di
        mov	eax,dword[gs:di]
        lea	si,[check_root_fat_+14]
        mov     dword [ds:si],'----'
	mov     dword [ds:si+4],'----'
	mov     dword [ds:si+8],'----'
        mov	dword[ds:si],eax
        mov	eax,dword[gs:di+4]
        mov	dword[ds:si+4],eax
        mov	eax,dword[gs:di+8]
        mov	dword[ds:si+8],eax

;
	xor	eax,eax
        mov     ax,gs;point_next_fat_str
        mov     cx,0x0a
        mov     di,check_root_fat_
        mov     dword [di],'    '
        mov     word  [di+4],'  '
        call    decode
	xor	eax,eax
	pop	ax
	mov	di,(check_root_fat_+7)
        mov     dword [di],'    '
        mov     word  [di+4],'  '
        call    decode

;Show size
        lea     si,[check_root_fat_]
        call    printplain

        lea     si,[shot_name_fat]
        call    printplain

	xor	ax,ax
	int	0x16
        popad
end if  

	xor	bx,bx
        mov     cx,11   ;size of name in struct FAT

@@:     
        mov     al,byte [ds:si+bx]	;ds:si - point to name of convertion variable.
        mov     ah,byte [gs:di+bx]      ;gs:di - point to name in fat struct
        inc     bx

if DEBUG
;        pushad
;        lea	si,[check_root_fat_+14]
;        mov     dword [ds:si],'----'
;        mov	word [ds:si],ax
;	call    printplain

;	xor	ax,ax
;	int	0x16

;        popad
end if



        cmp    ah,al
        jnz    .no_equal

;       dec     cx
;       jnz     @b
        loop    @b

;.succesfuly:
;печально, такое имя уже имеется :(
        or      ax,-1
        jmp     .exit


.no_equal:
        add     di,32           ;fat struct =32 byte
        dec     dx
        jnz     .loop_size_root_dir

;.exit_check_name:
        and     ax,0

.exit:

if DEBUG        
        pushad
;Show size
        lea     si,[check_name_fat_msg_n]
	test	ax,ax
	jz	@f
        lea     si,[check_name_fat_msg_y]
	call    printplain
	lea     si,[alarm_msg]
@@:     call    printplain
        popad
end if  

}


macro convertion_file_name
;макрос конвертации имени, это нужно поскольку формат представленный не соответсвует фат и напрямую редко можно когда использовать
;преобразование имени типа hello.asm в 'HELLO   ASM', в соответствии с правилами fat.
;входные параметры es:di указатель на имя файла которое нужно преобразовать, конечный буфер shot_name_fat
{
local   .next_step
local   .error
local   .st1
local   .st2
local   .st2_l
local   .st3
local   .st4_s
local   .st4
local   .st5

;вычислим длинну строчки имени назначения, которую будем сравнивать с уже записанными данными.
;       mov     di,point_to_dest_file_name   входной параметр
        mov     si,shot_name_fat
        or      first_input,-1  ;при первом входе устанавливаем флаг
        mov     cx,11   ;длинна имени в стуктуре фат таблицы

@@:     
        mov     al,byte [es:di]
        cmp     al,0xa
        jz      .st4_s
        cmp     al,0xd
        jz      .st4_s
        cmp     al,0x20
        jz      .st4_s

        cmp     al,0x20
        jb      .error
        cmp     al,0x22
        jz      .error
        cmp     al,0x2a
        jz      .error
        cmp     al,0x2b
        jz      .error
        cmp     al,0x2c
        jz      .error
        cmp     al,0x2F
        jz      .error

        cmp     al,0x3a
        jz      .error
        cmp     al,0x3b
        jz      .error
        cmp     al,0x3c
        jz      .error
        cmp     al,0x3d
        jz      .error
        cmp     al,0x3E
        jz      .error
        cmp     al,0x3F
        jz      .error

        cmp     al,0x5b
        jz      .error
        cmp     al,0x5c
        jz      .error
        cmp     al,0x5d
        jz      .error

        cmp     al,0x7c
        jz      .error

        
        cmp     first_input,-1
        jnz     .next_step
        and     first_input,0   ;сборосим флаг.
        cmp     al,'.'
        jz      .error  ;обработка точки, файл не может начинаться с точки

.next_step:
        cmp     al,0x2e
        jnz     .st2            ;обработка точки, в середине файла
;тут у нас установлен разделитель
;все остальнео место займут пробелы
        mov     al,' '

;!fixme обработаны не все исключения :(
        cmp     cl,3    ;формат файла такой GIDGIDIIASM т.е. gidgidii.asm
        jbe     .st2


.st3:   
        mov     byte [si],al
        inc     si
        dec     cx
        cmp     cx,3
        ja      .st3
;       inc     cx
        inc     di
        jmp     @b

.st2:
        cmp     al,0x60
        jbe     .st2_l
        
        xor     al,0x20 ;сделаем заглавные буквы
.st2_l: mov     byte [si],al
        inc     di
        inc     si
;        dec    cx
;       jnz     @b
        loop    @b
.st5:   xor     ax,ax
        jmp     @f

;;;;;;;;файл закончился, и нужно внести в конец пробелы
.st4_s: mov     al,' '
.st4:   mov     byte [si],al
        inc     si
        loop    .st4
        jmp     .st5

.error: or      ax,-1
@@:

if DEBUG        
        pushad
	
        mov     si,convertion_file_name_msg_y
	test	ax,ax
	jz	@f
        mov     si,convertion_file_name_msg_n
@@:     call    printplain

        mov     si,shot_name_fat
        mov     byte [si+12],0
        call    printplain
        popad

end if  
}

macro move_file_up
;макрос который перемещает за 1 мб с правилами фат данные файла.
{
local   .st1
local   .correct_on_byte
;сейчас имеет быть ситуация, когда BPB уже перемещен за 1 мб, фат, и рут дир будут позже перемещены,
;а нам нужно вычислить место, и перенести туда содержимое файла
;полученое значение указывает в байтах на начало данных

        mov     ax,info_real_mode_size  ; сегмент где расположены данные
        mov     si,table_15_87
        mov     word [si+8*2+2],ax
;смещение до данных уже за 1-м мб
        movzx   eax,firstDataSect
        movzx   edx,data_offset
        add     eax,edx

        movzx   ebx,word [fat12_buffer.BPB_BytsPerSec] 
        movzx   edx,byte [fat12_buffer.BPB_SecPerClus]
        imul    bx,dx   ;получим размер кластера



        push    ebx     ;save bx

        imul    eax,ebx
;       shl     eax,9   ;умножим на 512
        
if DEBUG
        pushad
	xor	eax,eax
        mov     ax,info_real_mode_size
        mov     cx,0x0a
        mov     di,seg_where_get_data
        mov     dword [di],'    '
        mov     word  [di+4],'  '
        call    decode                                                                    
;Show size
        mov     si,seg_where_get_data
        call    printplain
        popad

end if

;       mov     bx,word [fat12_buffer.BPB_BytsPerSec] 
;       movzx   dx,byte [fat12_buffer.BPB_SecPerClus]
;       imul    bx,dx
;       cwd
;       idiv    bx

        mov     dl,0x10

@@:     cmp     eax,0x00010000
        jb      @f

        sub     eax,0x00010000
        inc     dl
        jmp     @b


@@:     mov     byte [si+8*3+3],dl      ;куда писать
        mov     word [si+8*3+2],ax

        mov     ecx,save_file_size      ;размер файла в байтах.
        cmp     ecx,0x0000ffff          ;размер блока т.е. 64 кб
        jbe     .correct_on_byte        ;корректировка на байт значения



        mov     ecx,0x00010000          ;65536 
        sub     save_file_size,ecx      ;отнимим
;       jmp     .st1                    ;получим 0х8000




;корректировка значения должна быть выполенена на размер кластера
.correct_on_byte:
;/узнаем размер кластера
        pop     eax     ;restore size of claster
        push    ecx
@@:     inc     data_offset

        cmp     eax,ecx
        jae     @f
        sub     ecx,eax
        jmp     @b
@@:     pop     ecx




        test    ecx,0x1
        jz      .st1
        inc     ecx
.st1:   shr     ecx,1     ; преобразовать значение для 0x87 function

;перенесем блок за 1 мб        
        push    es
        push    ds
        pop     es

        mov     ah, 0x87
        int     0x15
        pop     es

if DEBUG
        pusha
;       mov     ax,point_next_fat_str
        mov     cx,0x0a
        mov     di,return_code_af_move
        call    decode                                                                    
;Show size
        mov     si,return_code_af_move
        call    printplain
        popa

end if

}


macro move_up_fat_and_root_d
;макрос, который позволяет перенести выше 1 мб в структуру образа фат таблицу и рут директорию
{
local  .st1

        mov     ax,info_real_mode_size
        add     ax,0x1000

        mov     si,table_15_87
        mov     word [si+8*2+2],ax
;смещение до данных
        mov     ax,512
        mov     word [si+8*3+2],ax
;fixme! тут необходимо сделать подержку т.е. формировать смещение файла в уже записанных данных.

        movzx   ecx,word [fat12_buffer.BPB_FATSz16]
        movzx   bx,byte [fat12_buffer.BPB_NumFATs]
        imul    cx,bx   ;9x1=9

        add     cx,size_root_dir        ;размер корневой дирректории
        shl     ecx,9   ;imul 512


;корректировка значения
        test    ecx,0x1
        jz      .st1
        inc     ecx
.st1:   shr     ecx,1

        push    es
        push    ds
        pop     es

        mov     ah, 0x87
        int     0x15
        pop     es

if DEBUG
        pusha
;       mov     ax,point_next_fat_str
        mov     cx,0x0a
        mov     di,return_code_af_fat_m
        call    decode                                                                    
;Show size
        mov     si,return_code_af_fat_m
        call    printplain
        popa

end if

}