;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$

;-----------------------------------------------------------------------------
uglobal
cd_current_pointer_of_input    dd  0
cd_current_pointer_of_input_2  dd  0
cd_mem_location                dd  0
cd_counter_block               dd  0
endg
;-----------------------------------------------------------------------------
reserve_cd:
        cli
        cmp     [cd_status], 0
        je      reserve_ok2

        sti
        call    change_task
        jmp     reserve_cd
;-----------------------------------------------------------------------------
reserve_ok2:
        push    eax
        mov     eax, [CURRENT_TASK]
        shl     eax, 5
        mov     eax, [eax+CURRENT_TASK+TASKDATA.pid]
        mov     [cd_status], eax
        pop     eax
        sti
        ret
;-----------------------------------------------------------------------------
reserve_cd_channel:
        pushad
        mov     eax, [cdpos]
        dec     eax
        shr     eax, 2

        test    eax, eax
        jnz     .1

        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel1_mutex
        jmp     .mutex_lock
;--------------------------------------
@@:
        mov     ecx, ide_channel2_mutex
        jmp     .mutex_lock
;--------------------------------------
.1:
        dec     eax
        jnz     .2

        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel3_mutex
        jmp     .mutex_lock
;--------------------------------------
@@:
        mov     ecx, ide_channel4_mutex
        jmp     .mutex_lock
;--------------------------------------
.2:
        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel5_mutex
        jmp     .mutex_lock
;--------------------------------------
@@:
        mov     ecx, ide_channel6_mutex
.mutex_lock:
        call    mutex_lock
        popad
        ret
;-----------------------------------------------------------------------------
free_cd_channel:
        pushad
        mov     eax, [cdpos]
        dec     eax
        shr     eax, 2

        test    eax, eax
        jnz     .1

        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel1_mutex
        jmp     .mutex_unlock
;--------------------------------------
@@:
        mov     ecx, ide_channel2_mutex
        jmp     .mutex_unlock
;--------------------------------------
.1:
        dec     eax
        jnz     .2

        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel3_mutex
        jmp     .mutex_unlock
;--------------------------------------
@@:
        mov     ecx, ide_channel4_mutex
        jmp     .mutex_unlock
;--------------------------------------
.2:
        cmp     [ChannelNumber], 1
        jne     @f

        mov     ecx, ide_channel5_mutex
        jmp     .mutex_unlock
;--------------------------------------
@@:
        mov     ecx, ide_channel6_mutex
.mutex_unlock:
        call    mutex_unlock
        popad
        ret
;-----------------------------------------------------------------------------
uglobal
cd_status dd 0
endg
;-----------------------------------------------------------------------------
;
;  fs_CdRead - LFN variant for reading CD disk
;
;  esi  points to filename /dir1/dir2/.../dirn/file,0
;  ebx  pointer to 64-bit number = first wanted byte, 0+
;       may be ebx=0 - start from first byte
;  ecx  number of bytes to read, 0+
;  edx  mem location to return data
;
;  ret ebx = bytes read or 0xffffffff file not found
;      eax = 0 ok read or other = errormsg
;
;-----------------------------------------------------------------------------
fs_CdRead:
        push    edi
        cmp     byte [esi], 0
        jnz     @f
;--------------------------------------
.noaccess:
        pop     edi
;--------------------------------------
.noaccess_2:
        or      ebx, -1
        mov     eax, ERROR_ACCESS_DENIED
        ret
;--------------------------------------
.noaccess_3:
        pop     eax edx ecx edi
        jmp     .noaccess_2
;--------------------------------------
@@:
        call    cd_find_lfn
        jnc     .found

        pop     edi
        cmp     [DevErrorCode], 0
        jne     .noaccess_2

        or      ebx, -1
        mov     eax, ERROR_FILE_NOT_FOUND
        ret
;--------------------------------------
.found:
        mov     edi, [cd_current_pointer_of_input]
        test    byte [edi+25], 10b; do not allow read directories
        jnz     .noaccess

        test    ebx, ebx
        jz      .l1

        cmp     dword [ebx+4], 0
        jz      @f

        xor     ebx, ebx
;--------------------------------------
.reteof:
        mov     eax, 6; end of file
        pop     edi
        ret
;--------------------------------------
@@:
        mov     ebx, [ebx]
;--------------------------------------
.l1:
        push    ecx edx
        push    0
        mov     eax, [edi+10] ; real size of the file section
        sub     eax, ebx
        jb      .eof

        cmp     eax, ecx
        jae     @f

        mov     ecx, eax
        mov     byte [esp], 6
;--------------------------------------
@@:
        mov     eax, [edi+2]
        mov     [CDSectorAddress], eax
;--------------------------------------
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
.new_sector:
        test    ecx, ecx
        jz      .done

        sub     ebx, 2048
        jae     .next

        add     ebx, 2048
        jnz     .incomplete_sector

        cmp     ecx, 2048
        jb      .incomplete_sector
; we may read and memmove complete sector
        mov     [CDDataBuf_pointer], edx
        call    ReadCDWRetr ; read sector of file
        cmp     [DevErrorCode], 0
        jne     .noaccess_3

        add     edx, 2048
        sub     ecx, 2048
;--------------------------------------
.next:
        inc     dword [CDSectorAddress]
        jmp     .new_sector
;--------------------------------------
.incomplete_sector:
; we must read and memmove incomplete sector
        mov     [CDDataBuf_pointer], CDDataBuf
        call    ReadCDWRetr ; read sector of file
        cmp     [DevErrorCode], 0
        jne     .noaccess_3

        push    ecx
        add     ecx, ebx
        cmp     ecx, 2048
        jbe     @f

        mov     ecx, 2048
;--------------------------------------
@@:
        sub     ecx, ebx
        push    edi esi ecx
        mov     edi, edx
        lea     esi, [CDDataBuf + ebx]
        cld
        rep movsb
        pop     ecx esi edi
        add     edx, ecx
        sub     [esp], ecx
        pop     ecx
        xor     ebx, ebx
        jmp     .next
;--------------------------------------
.done:
        mov     ebx, edx
        pop     eax edx ecx edi
        sub     ebx, edx
        ret
;--------------------------------------
.eof:
        mov     ebx, edx
        pop     eax edx ecx
        sub     ebx, edx
        jmp     .reteof
;-----------------------------------------------------------------------------
;
;  fs_CdReadFolder - LFN variant for reading CD disk folder
;
;  esi  points to filename  /dir1/dir2/.../dirn/file,0
;  ebx  pointer to structure 32-bit number = first wanted block, 0+
;                          & flags (bitfields)
; flags: bit 0: 0=ANSI names, 1=UNICODE names
;  ecx  number of blocks to read, 0+
;  edx  mem location to return data
;
;  ret ebx = blocks read or 0xffffffff folder not found
;      eax = 0 ok read or other = errormsg
;
;-----------------------------------------------------------------------------
fs_CdReadFolder:
        push    edi
        call    cd_find_lfn
        jnc     .found

        pop     edi
        cmp     [DevErrorCode], 0
        jne     .noaccess_1

        or      ebx, -1
        mov     eax, ERROR_FILE_NOT_FOUND
        ret
;--------------------------------------
.found:
        mov     edi, [cd_current_pointer_of_input]
        test    byte [edi+25], 10b    ; do not allow read directories
        jnz     .found_dir

        pop     edi
;--------------------------------------
.noaccess_1:
        or      ebx, -1
        mov     eax, ERROR_ACCESS_DENIED
        ret
;--------------------------------------
.found_dir:
        mov     eax, [edi+2]    ; eax=cluster
        mov     [CDSectorAddress], eax
        mov     eax, [edi+10]   ; directory size
;--------------------------------------
.doit:
; init header
        push    eax ecx
        mov     edi, edx
        mov     ecx, 32/4
        xor     eax, eax
        rep stosd
        pop     ecx eax
        mov     byte [edx], 1   ; version
        mov     [cd_mem_location], edx
        add     [cd_mem_location], 32
;.mainloop:
        mov     [cd_counter_block], dword 0
        dec     dword [CDSectorAddress]
        push    ecx
;--------------------------------------
.read_to_buffer:
        inc     dword [CDSectorAddress]
        mov     [CDDataBuf_pointer], CDDataBuf
        call    ReadCDWRetr         ; read sector of directory
        cmp     [DevErrorCode], 0
        jne     .noaccess_1

        call    .get_names_from_buffer
        sub     eax, 2048
; directory is over?
        ja      .read_to_buffer

        mov     edi, [cd_counter_block]
        mov     [edx+8], edi
        mov     edi, [ebx]
        sub     [edx+4], edi
        xor     eax, eax
        dec     ecx
        js      @f

        mov     al, ERROR_END_OF_FILE
;--------------------------------------
@@:
        pop     ecx edi
        mov     ebx, [edx+4]
        ret
;--------------------------------------
.get_names_from_buffer:
        mov     [cd_current_pointer_of_input_2], CDDataBuf
        push    eax esi edi edx
;--------------------------------------
.get_names_from_buffer_1:
        call    cd_get_name
        jc      .end_buffer

        inc     dword [cd_counter_block]
        mov     eax, [cd_counter_block]
        cmp     [ebx], eax
        jae     .get_names_from_buffer_1

        test    ecx, ecx
        jz      .get_names_from_buffer_1

        mov     edi, [cd_counter_block]
        mov     [edx+4], edi
        dec     ecx
        mov     esi, ebp
        mov     edi, [cd_mem_location]
        add     edi, 40
        test    dword [ebx+4], 1; 0=ANSI, 1=UNICODE
        jnz     .unicode
;--------------------------------------
.ansi:
        cmp     [cd_counter_block], 2
        jbe     .ansi_parent_directory

        cld
        lodsw
        xchg    ah, al
        call    uni2ansi_char
        cld
        stosb
; check end of file
        mov     ax, [esi]
        cmp     ax, word 3B00h ; separator end of file ';'
        je      .cd_get_parameters_of_file_1
; check for files not ending with separator
        movzx   eax, byte [ebp-33]
        add     eax, ebp
        sub     eax, 34
        cmp     esi, eax
        je      .cd_get_parameters_of_file_1
; check the end of the directory
        movzx   eax, byte [ebp-1]
        add     eax, ebp
        cmp     esi, eax
        jb      .ansi
;--------------------------------------
.cd_get_parameters_of_file_1:
        mov     [edi], byte 0
        call    cd_get_parameters_of_file
        add     [cd_mem_location], 304
        jmp     .get_names_from_buffer_1
;--------------------------------------
.ansi_parent_directory:
        cmp     [cd_counter_block], 2
        je      @f

        mov     [edi], byte '.'
        inc     edi
        jmp     .cd_get_parameters_of_file_1
;--------------------------------------
@@:
        mov     [edi], word '..'
        add     edi, 2
        jmp     .cd_get_parameters_of_file_1
;--------------------------------------
.unicode:
        cmp     [cd_counter_block], 2
        jbe     .unicode_parent_directory

        cld
        movsw
; check end of file
        mov     ax, [esi]
        cmp     ax, word 3B00h; separator end of file ';'
        je      .cd_get_parameters_of_file_2
; check for files not ending with separator
        movzx   eax, byte [ebp-33]
        add     eax, ebp
        sub     eax, 34
        cmp     esi, eax
        je      .cd_get_parameters_of_file_2
; check the end of the directory
        movzx   eax, byte [ebp-1]
        add     eax, ebp
        cmp     esi, eax
        jb      .unicode
;--------------------------------------
.cd_get_parameters_of_file_2:
        mov     [edi], word 0
        call    cd_get_parameters_of_file
        add     [cd_mem_location], 560
        jmp     .get_names_from_buffer_1
;--------------------------------------
.unicode_parent_directory:
        cmp     [cd_counter_block], 2
        je      @f

        mov     [edi], word 2E00h; '.'
        add     edi, 2
        jmp     .cd_get_parameters_of_file_2
;--------------------------------------
@@:
        mov     [edi], dword 2E002E00h; '..'
        add     edi, 4
        jmp     .cd_get_parameters_of_file_2
;--------------------------------------
.end_buffer:
        pop     edx edi esi eax
        ret
;-----------------------------------------------------------------------------
cd_get_parameters_of_file:
        mov     edi, [cd_mem_location]
cd_get_parameters_of_file_1:
; get file attributes
        xor     eax, eax
; file is not archived
        inc     eax
        shl     eax, 1
; is a directory?
        test    [ebp-8], byte 2
        jz      .file

        inc     eax
;--------------------------------------
.file:
; not as a volume label in the FAT, in this form not available
; file is not a system
        shl     eax, 3
; file is hidden? (attribute of existence)
        test    [ebp-8], byte 1
        jz      .hidden

        inc     eax
;--------------------------------------
.hidden:
        shl     eax, 1
; file is always read-only, as this CD
        inc     eax
        mov     [edi], eax
; get the time to file
; hour
        movzx   eax, byte [ebp-12]
        shl     eax, 8
; minute
        mov     al, [ebp-11]
        shl     eax, 8
; second
        mov     al, [ebp-10]
; file creation time
        mov     [edi+8], eax
; last access time
        mov     [edi+16], eax
; last write time
        mov     [edi+24], eax
; get date for file
; year
        movzx   eax, byte [ebp-15]
        add     eax, 1900
        shl     eax, 8
; month
        mov     al, [ebp-14]
        shl     eax, 8
; day
        mov     al, [ebp-13]
; file creation date
        mov     [edi+12], eax
; last access date
        mov     [edi+20], eax
; last write date 
        mov     [edi+28], eax
; get the data type of name
        xor     eax, eax
        test    dword [ebx+4], 1; 0=ANSI, 1=UNICODE
        jnz     .unicode_1

        mov     [edi+4], eax
        jmp     @f
;--------------------------------------
.unicode_1:
        inc     eax
        mov     [edi+4], eax
;--------------------------------------
@@:
; get the file size in bytes
        xor     eax, eax
        mov     [edi+32+4], eax
        mov     eax, [ebp-23]
        mov     [edi+32], eax
        ret
;-----------------------------------------------------------------------------
;
;  fs_CdGetFileInfo - LFN variant for CD
;                     get file/directory attributes structure
;
;-----------------------------------------------------------------------------
fs_CdGetFileInfo:
        cmp     byte [esi], 0
        jnz     @f

        mov     eax, 2
        ret
;--------------------------------------
@@:
        push    edi
        call    cd_find_lfn
        pushfd
        cmp     [DevErrorCode], 0
        jz      @f

        popfd
        pop     edi
        mov     eax, 11
        ret
;--------------------------------------
@@:
        popfd
        jnc     @f

        pop     edi
        mov     eax, ERROR_FILE_NOT_FOUND
        ret
;--------------------------------------
@@:

        mov     edi, edx
        push    ebp
        mov     ebp, [cd_current_pointer_of_input]
        add     ebp, 33
        call    cd_get_parameters_of_file_1
        pop     ebp
        and     dword [edi+4], 0
        pop     edi
        xor     eax, eax
        ret
;-----------------------------------------------------------------------------
cd_find_lfn:
        mov     [cd_appl_data], 0
; in: esi+ebp -> name
; out: CF=1 - file not found
; else CF=0 and [cd_current_pointer_of_input] direntry
        push    eax esi
; Sector 16 - start set of volume descriptors
        call    WaitUnitReady
        cmp     [DevErrorCode], 0
        jne     .access_denied

        call    prevent_medium_removal
; testing of reading
        mov     [CDSectorAddress], dword 16
        mov     [CDDataBuf_pointer], CDDataBuf
        call    ReadCDWRetr;_1
        cmp     [DevErrorCode], 0
        jne     .access_denied

; calculation of the last session
        call    WaitUnitReady
        cmp     [DevErrorCode], 0
        jne     .access_denied

        call    Read_TOC
        mov     ah, [CDDataBuf+4+4]
        mov     al, [CDDataBuf+4+5]
        shl     eax, 16
        mov     ah, [CDDataBuf+4+6]
        mov     al, [CDDataBuf+4+7]
        add     eax, 15
        mov     [CDSectorAddress], eax
;  mov  [CDSectorAddress],dword 15
        mov     [CDDataBuf_pointer], CDDataBuf
;--------------------------------------
.start:
        inc     dword [CDSectorAddress]
        call    ReadCDWRetr;_1
        cmp     [DevErrorCode], 0
        jne     .access_denied

.start_check:
; checking for "lice"
        cmp     [CDDataBuf+1], dword 'CD00'
        jne     .access_denied

        cmp     [CDDataBuf+5], byte '1'
        jne     .access_denied
; sector is the terminator of set of descriptors volumes?
        cmp     [CDDataBuf], byte 0xff
        je      .access_denied
; sector is an additional and improved descriptor of volume?
        cmp     [CDDataBuf], byte 0x2
        jne     .start
; sector is an additional descriptor of volume?
        cmp     [CDDataBuf+6], byte 0x1
        jne     .start

; parameters of root directory
        mov     eax, [CDDataBuf+0x9c+2]; start of root directory
        mov     [CDSectorAddress], eax
        mov     eax, [CDDataBuf+0x9c+10]; size of root directory
        cmp     byte [esi], 0
        jnz     @f

        mov     [cd_current_pointer_of_input], CDDataBuf+0x9c
        jmp     .done
;--------------------------------------
@@:
; start the search
.mainloop:
        dec     dword [CDSectorAddress]
;--------------------------------------
.read_to_buffer:
        inc     dword [CDSectorAddress]
        mov     [CDDataBuf_pointer], CDDataBuf
        call    ReadCDWRetr      ; read sector of directory
        cmp     [DevErrorCode], 0
        jne     .access_denied

        push    ebp
        call    cd_find_name_in_buffer
        pop     ebp
        jnc     .found

        sub     eax, 2048
; directory is over?
        cmp     eax, 0
        ja      .read_to_buffer
; desired element of chain is not found
.access_denied:
        pop     esi eax
        mov     [cd_appl_data], 1
        stc
        ret
;--------------------------------------
; desired element of chain found
.found:
; the end of the file path
        cmp     byte [esi-1], 0
        jz      .done
  .nested:
        mov     eax, [cd_current_pointer_of_input]
        push    dword [eax+2]
        pop     dword [CDSectorAddress] ; beginning of the directory
        mov     eax, [eax+2+8] ; size of directory
        jmp     .mainloop
;--------------------------------------
; file pointer found
.done:
        test    ebp, ebp
        jz      @f

        mov     esi, ebp
        xor     ebp, ebp
        jmp     .nested
;--------------------------------------
@@:
        pop     esi eax
        mov     [cd_appl_data], 1
        clc
        ret
;-----------------------------------------------------------------------------
cd_find_name_in_buffer:
        mov     [cd_current_pointer_of_input_2], CDDataBuf
;--------------------------------------
.start:
        call    cd_get_name
        jc      .not_found

        call    cd_compare_name
        jc      .start
;--------------------------------------
.found:
        clc
        ret
;--------------------------------------
.not_found:
        stc
        ret
;-----------------------------------------------------------------------------
cd_get_name:
        push    eax
        mov     ebp, [cd_current_pointer_of_input_2]
        mov     [cd_current_pointer_of_input], ebp
        mov     eax, [ebp]
        test    eax, eax ; entry's is over?
        jz      .next_sector

        cmp     ebp, CDDataBuf+2048  ; buffer is over?
        jae     .next_sector

        movzx   eax, byte [ebp]
        add     [cd_current_pointer_of_input_2], eax ; next entry of directory
        add     ebp, 33; pointer is set to the beginning of the name
        pop     eax
        clc
        ret
;--------------------------------------
.next_sector:
        pop     eax
        stc
        ret
;-----------------------------------------------------------------------------
cd_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
; in: esi->name, ebp->name
; out: if names match: ZF=1 and esi->next component of name
;      else: ZF=0, esi is not changed
; destroys eax
        push    esi eax edi
        mov     edi, ebp
;--------------------------------------
.loop:
        cld
        lodsb
        push    eax
        call    char_todown
        call    ansi2uni_char
        xchg    ah, al
        scasw
        pop     eax
        je      .coincides
        call    char_toupper
        call    ansi2uni_char
        xchg    ah, al
        sub     edi, 2
        scasw
        jne     .name_not_coincide
;--------------------------------------
.coincides:
        cmp     [esi], byte '/' ; path separator is end of current element
        je      .done

        cmp     [esi], byte 0 ; path separator end of name
        je      .done

        jmp     .loop
;--------------------------------------
.name_not_coincide:
        pop     edi eax esi
        stc
        ret
;--------------------------------------
.done:
; check end of file
        cmp     [edi], word 3B00h; separator end of file ';'
        je      .done_1
; check for files not ending with separator
        movzx   eax, byte [ebp-33]
        add     eax, ebp
        sub     eax, 34
        cmp     edi, eax
        je      .done_1
; check the end of directory
        movzx   eax, byte [ebp-1]
        add     eax, ebp
        cmp     edi, eax
        jne     .name_not_coincide
;--------------------------------------
.done_1:
        pop     edi eax
        add     esp, 4
        inc     esi
        clc
        ret