;===============================================================================
;       includes

;===============================================================================
;       checks if given cd is correct iso image
proc    iso_is_valid            hiso
  locals
    buffer      rb 2048
  endl
        osscall setptr, [hiso], 2048*16, OSS_BEGIN
        lea     edx, [buffer]
        osscall read, [hiso], edx, 2048
        lea     eax, [buffer]
        cmp     [eax+VOLUME_DESCRIPTOR.VolumeDescriptorType],\
                ISO9660_PRIMARY_VOLUME_DESCRIPTOR
        jnz     iso_invalid
        cmp     dword [eax+VOLUME_DESCRIPTOR.StandardIdentifier], 'CD00'
        jnz     iso_invalid
        cmp     byte [eax+VOLUME_DESCRIPTOR.StandardIdentifier+04], '1'
        jnz     iso_invalid
        cmp     [eax+VOLUME_DESCRIPTOR.VolumeDescriptorVersion], 1
        jnz     iso_invalid
        clc
        ret
  iso_invalid:
        stc
        ret
endp

;===============================================================================
;       writes all directories
idata
  d_iso_recursive_flag          db FALSE
endg
udata
  d_iso_is_joliet               db ?
endg
proc    iso_enum_directories    hiso, callback
  locals
    buffer_ptr                  dd ?
    buffer                      rb 2048
  endl
        lea     eax, [buffer]
        mov     [buffer_ptr], eax
        push    ebx
        mov     ebx, 16
    @@:
        inc     ebx
        shl     ebx, 11
        osscall setptr, [hiso], ebx, OSS_BEGIN
        osscall read, [hiso], [buffer_ptr], 2048
        cmp     [buffer+VOLUME_DESCRIPTOR.VolumeDescriptorType], ISO9660_TERMINATOR
        jz      iso_no_joliet
        cmp     [buffer+VOLUME_DESCRIPTOR.VolumeDescriptorType], ISO9660_SVD
        jnz     @B
        mov     [d_iso_is_joliet], TRUE
        lea     ebx, [buffer+SVD.RootDirectory]
        stdcall iso_write_extent, [hiso], ebx, 0, [callback]
        ret
  iso_no_joliet:
        mov     [d_iso_is_joliet], FALSE
        pop     ebx
        ret
endp

;*******************************************************************************
;       used internally
;       writes content of one extent only
iglobal
  d_iso_root_directory_name     du '.', 0
  d_iso_parent_directory_name   du '..', 0
endg
proc    iso_write_extent        hiso, root_dir, last_extent, callback
  locals
    current_extent              dd ?
    hbuffer                     dd ?
    whole_size                  dd ?
  endl
        push    esi edi ebx
        mov     ebx, [root_dir]
        mov     eax, [ebx+DIRECTORY_RECORD.LocationOfExtent]
        shl     eax, 11
        osscall setptr, [hiso], eax, OSS_BEGIN
        mov     eax, [ebx+DIRECTORY_RECORD.DataLength]
        mov     [whole_size], eax
        osscall alloc, eax
        mov     [hbuffer], eax
        mov     eax, [ebx+DIRECTORY_RECORD.LocationOfExtent]
        shl     eax, 11
        osscall setptr, [hiso], eax, OSS_BEGIN
        osscall read, [hiso], [hbuffer], [ebx+DIRECTORY_RECORD.DataLength]

        mov     ebx, [hbuffer]
        add     ebx, sizeof.DIRECTORY_RECORD*2
;        int     3
  iso_extent_loop:
        cmp     [ebx+DIRECTORY_RECORD.LengthOfDirectoryRecord], 0
        jnz     iso_extent_continue
        mov     eax, ebx
        sub     eax, [hbuffer]
        mov     ecx, 2048
        xor     edx, edx
        idiv    ecx
        test    edx, edx
        jz      @F
        inc     eax
    @@:
        shl     eax, 11
        cmp     eax, [whole_size]
        jz      iso_no_more_processing
        mov     ebx, [hbuffer]
        add     ebx, eax
    iso_extent_continue:
        lea     edx, [ebx+DIRECTORY_RECORD.FileIdentifier]
        movzx   ecx, [ebx+DIRECTORY_RECORD.LengthOfFileIdentifier]
        shr     ecx, 1
    @@:
        mov     ax, [edx+ecx*2-2]
        rol     ax, 8
        mov     [edx+ecx*2-2], ax
        loop    @B
        movzx   ecx, [ebx+DIRECTORY_RECORD.FileFlags]
        lea     eax, [ebx+DIRECTORY_RECORD.RecordingDateAndTime]
        push    ecx
        push    [ebx+DIRECTORY_RECORD.LocationOfExtent]
        push    eax
        push    [ebx+DIRECTORY_RECORD.DataLength]
        movzx   eax, [ebx+DIRECTORY_RECORD.LengthOfFileIdentifier]
        shr     eax, 1
        push    eax
        push    edx
        push    [hiso]
        call    [callback]
        test    eax, eax
        jz      iso_no_more_processing
        test    [ebx+DIRECTORY_RECORD.FileFlags], FILE_FLAG_DIRECTORY
        jz      iso_file_processed
        cmp     [d_iso_recursive_flag], TRUE
        jnz     @F
        stdcall iso_write_extent, [hiso], ebx, [current_extent], [callback]
    @@:
        stdcall [callback], 0, 0, 0, 0, 0, 0, 0
    iso_file_processed:
        movzx   eax, [ebx+DIRECTORY_RECORD.LengthOfDirectoryRecord]
        movzx   edx, [ebx+DIRECTORY_RECORD.ExtendedAttributeRecordLength]
        lea     eax, [eax+edx]
        add     ebx, eax
        jmp     iso_extent_loop
  iso_no_more_processing:
        mov     eax, [last_extent]
        shl     eax, 11
        osscall setptr, [hiso], eax, OSS_BEGIN
        osscall dealloc, [hbuffer]
        pop     ebx edi esi
        ret
endp

;===============================================================================
;       returns number of files in current directory
uglobal
  d_iso_file_number             dd ?
  d_iso_file_size               dd ?
endg
proc    iso_get_file_number     hiso, extent, size
  locals
    halloc_extent               dd ?
  endl
        push    ebx
        osscall alloc, [size]
        mov     [halloc_extent], eax
        mov     ebx, eax
        mov     eax, [extent]
        shl     eax, 11
        osscall setptr, [hiso], eax, OSS_BEGIN
        osscall read, [hiso], ebx, [size]
        add     ebx, sizeof.DIRECTORY_RECORD*2
    iso_file_number_loop:
        mov     eax, [halloc_extent]
        add     eax, [size]
        cmp     eax, ebx
        jle     iso_file_number_loop_finished
        movzx   ecx, [ebx+DIRECTORY_RECORD.LengthOfDirectoryRecord]
        test    ecx, ecx
        jnz     iso_file_number_continue
        mov     eax, ebx
        sub     eax, [halloc_extent]
        mov     ecx, 2048
        xor     edx, edx
        idiv    ecx
        test    edx, edx
        jz      @F
        inc     eax
    @@:
        shl     eax, 11
        cmp     eax, [size]
        jz      iso_file_number_loop_finished
        mov     ebx, [halloc_extent]
        add     ebx, eax
        xor     ecx, ecx
    iso_file_number_continue:
        mov     edx, ebx
        inc     [d_iso_file_number]
        add     ebx, ecx
        test    [edx+DIRECTORY_RECORD.FileFlags], FILE_FLAG_DIRECTORY
        jnz     @F
        mov     eax, [edx+DIRECTORY_RECORD.DataLength]
        add     [d_iso_file_size], eax
    @@:
        cmp     [d_iso_recursive_flag], TRUE
        jnz     iso_file_number_loop
        test    [edx+DIRECTORY_RECORD.FileFlags], FILE_FLAG_DIRECTORY
        jz      iso_file_number_loop
        stdcall iso_get_file_number, [hiso],\
                [edx+DIRECTORY_RECORD.LocationOfExtent],\
                [edx+DIRECTORY_RECORD.DataLength]
        jmp     iso_file_number_loop
    iso_file_number_loop_finished:
        osscall dealloc, [halloc_extent]
        pop     ebx
        mov     eax, [d_iso_file_number]
        mov     edx, [d_iso_file_size]
        ret
endp

;===============================================================================
;       copies a single file
uglobal
  d_iso_wrong_sectors_count     dd ?
endg
proc    iso_copy_file           hiso, hfile, extent, size, callback
  locals
    counter                     db ?
    buffer                      rb 2048
  endl
        push    esi edi ebx
        lea     edi, [buffer]
        mov     ebx, [extent]
        shl     ebx, 11
        mov     esi, 2048
        and     [d_iso_wrong_sectors_count], 0
        jmp     iso_check_condition
    iso_copy_loop:
;        inc     [counter]
;        cmp     [counter], 0
;        jnz     @F
;        invoke  Sleep, 1000
;    @@:
;        osscall setptr, [hiso], ebx, OSS_BEGIN
        invoke  SetFilePointer, [hiso], ebx, 0, FILE_BEGIN
        invoke  ReadFile, [hiso], edi, esi, esp, 0
        or      eax, eax
        jnz     @F
        inc     [d_iso_wrong_sectors_count]
        mov     ecx, esi
        shr     ecx, 2
        rep     stosd
        sub     edi, esi
    @@:
        push    esi
        push    edi
        push    [hfile]
        call    [callback]
        add     ebx, esi
        sub     [size], esi
        jz      @F
        js      @F
    iso_check_condition:
        cmp     [size], esi
        ja      iso_copy_loop
        mov     esi, [size]
        jmp     iso_copy_loop
    @@:
        pop     ebx edi esi
        ret
endp