UTF-8 based disk system, UTF-16 path input

git-svn-id: svn://kolibrios.org@6471 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
pathoswithin 2016-08-15 16:55:03 +00:00
parent a912a6a094
commit 5435e675b8
6 changed files with 500 additions and 562 deletions

View File

@ -11,7 +11,7 @@ $Revision$
; in: ; in:
; ebx -> parameter structure of sysfunc 70 ; ebx -> parameter structure of sysfunc 70
; ebp -> EXTFS structure ; ebp -> EXTFS structure
; esi -> path string ; esi -> path string in UTF-8
; out: ; out:
; eax, ebx = return values for sysfunc 70 ; eax, ebx = return values for sysfunc 70
iglobal iglobal
@ -193,7 +193,7 @@ ext2_create_partition:
cmp [ebx+SUPERBLOCK.magic], 0xEF53 cmp [ebx+SUPERBLOCK.magic], 0xEF53
jne .fail jne .fail
cmp [ebx+SUPERBLOCK.state], 1 cmp [ebx+SUPERBLOCK.state], 1
jne .fail ja .fail
test [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT test [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
jnz .fail jnz .fail
cmp [ebx+SUPERBLOCK.sectorsPerBlockLog], 6 ; 64KB cmp [ebx+SUPERBLOCK.sectorsPerBlockLog], 6 ; 64KB
@ -1176,7 +1176,7 @@ linkInode:
; in: ; in:
; eax = inode on which to link ; eax = inode on which to link
; ebx = inode to link ; ebx = inode to link
; esi -> name ; esi -> name in UTF-8
; dl = file type ; dl = file type
push esi edi ebx ecx eax edx push esi edi ebx ecx eax edx
call strlen call strlen
@ -1414,9 +1414,9 @@ unlinkInode:
ret ret
findInode_parent: findInode_parent:
; in: esi -> path ; in: esi -> path string in UTF-8
; out: ; out:
; edi -> file name ; edi -> file name in UTF-8
; esi = inode ; esi = inode
push esi push esi
xor edi, edi xor edi, edi
@ -1449,7 +1449,7 @@ findInode_parent:
ret ret
findInode: findInode:
; in: esi -> path string ; in: esi -> path string in UTF-8
; out: ; out:
; [ebp+EXTFS.mainInodeBuffer] = inode ; [ebp+EXTFS.mainInodeBuffer] = inode
; esi = inode number ; esi = inode number
@ -1485,32 +1485,16 @@ findInode:
call extfsReadBlock call extfsReadBlock
jc .error_get_block jc .error_get_block
push esi edx push esi edx
sub esp, 256
mov edx, ebx mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock] add edx, [ebp+EXTFS.bytesPerBlock]
.start_rec: .start_rec:
cmp [ebx+DIRENTRY.inodeNumber], 0 cmp [ebx+DIRENTRY.inodeNumber], 0
jz .next_rec jz .next_rec
mov edi, esp
push esi push esi
movzx ecx, [ebx+DIRENTRY.nameLength] movzx ecx, [ebx+DIRENTRY.nameLength]
lea esi, [ebx+DIRENTRY.name] lea edi, [ebx+DIRENTRY.name]
call utf8_to_cp866 repz cmpsb
mov ecx, edi jz .test_find
lea edi, [esp+4]
sub ecx, edi ; number of bytes in resulting string
mov esi, [esp]
@@: ; edi -> converted string in stack, ecx = size, esi -> original file path
jecxz .test_find
dec ecx
lodsb
call char_toupper
mov ah, [edi]
inc edi
xchg al, ah
call char_toupper
cmp al, ah
je @b
@@: ; doesn't match @@: ; doesn't match
pop esi pop esi
.next_rec: .next_rec:
@ -1528,8 +1512,7 @@ findInode:
jne @b jne @b
inc esi inc esi
@@: @@:
add esp, 256+4 pop edx edx edi ecx
pop edx edi ecx
; ebx -> matched directory entry, esi -> name without parent, or not changed ; ebx -> matched directory entry, esi -> name without parent, or not changed
cmp edi, esi cmp edi, esi
je .next_folder_block je .next_folder_block
@ -1697,10 +1680,12 @@ ext_ReadFolder:
inc dword [edi+8] inc dword [edi+8]
inc dword [edi+4] inc dword [edi+4]
push ebx edi ecx esi edx push ebx edi ecx esi edx
pushd [edi+12]
mov edi, edx mov edi, edx
xor eax, eax xor eax, eax
mov ecx, 40 / 4 mov ecx, 40 / 4
rep stosd rep stosd
popd [edx+4]
mov eax, [ebx+DIRENTRY.inodeNumber] mov eax, [ebx+DIRENTRY.inodeNumber]
lea ebx, [ebp+EXTFS.tempInodeBuffer] lea ebx, [ebp+EXTFS.tempInodeBuffer]
call readInode call readInode
@ -1730,16 +1715,25 @@ ext_ReadFolder:
@@: @@:
mov esi, [esp+12] mov esi, [esp+12]
movzx ecx, [esi+DIRENTRY.nameLength] movzx ecx, [esi+DIRENTRY.nameLength]
lea edi, [edx+40]
lea esi, [esi+DIRENTRY.name] lea esi, [esi+DIRENTRY.name]
call utf8_to_cp866 add ecx, esi
and byte [edi], 0 cmp byte [esi], '.'
pop esi ecx edi ebx jnz @f
cmp byte [edx+40], '.' or byte [edx], KOS_HIDDEN
jne @f
or dword [edx], KOS_HIDDEN
@@: @@:
add edx, 40+264 ; go to the next record lea edi, [edx+40]
cmp byte [edx+4], 1
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
and byte [edi], 0
add edx, 40+264
@@:
pop esi ecx edi ebx
dec ecx dec ecx
.empty_rec: .empty_rec:
movzx eax, [ebx+DIRENTRY.entryLength] movzx eax, [ebx+DIRENTRY.entryLength]
@ -1754,6 +1748,15 @@ ext_ReadFolder:
push .wanted_start push .wanted_start
jmp .end_block jmp .end_block
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
and word [edi], 0
add edx, 40+520
jmp @b
.end_dir: .end_dir:
call ext_unlock call ext_unlock
mov edx, [edi+28] mov edx, [edi+28]

View File

@ -11,7 +11,7 @@ $Revision$
; in: ; in:
; ebx -> parameter structure of sysfunc 70 ; ebx -> parameter structure of sysfunc 70
; ebp -> FAT structure ; ebp -> FAT structure
; esi -> path string ; esi -> path string in UTF-8
; out: ; out:
; eax, ebx = return values for sysfunc 70 ; eax, ebx = return values for sysfunc 70
iglobal iglobal
@ -445,35 +445,20 @@ label fat_legal_chars byte
endg endg
fat_name_is_legal: fat_name_is_legal:
; in: esi->(long) name ; in: esi -> UTF-8 name
; out: CF set <=> legal ; out: CF=1 -> legal
; destroys eax
push esi push esi
xor eax, eax xor eax, eax
@@: @@:
lodsb lodsb
test al, al test al, al
jz .done js @b
cmp al, 80h
jae .big
test [fat_legal_chars+eax], 1 test [fat_legal_chars+eax], 1
jnz @b jnz @b
.err: test al, al
pop esi jnz @f
clc stc
ret @@:
.big:
; 0x80-0xAF, 0xE0-0xEF
cmp al, 0xB0
jb @b
cmp al, 0xE0
jb .err
cmp al, 0xF0
jb @b
jmp .err
.done:
sub esi, [esp]
cmp esi, 257
pop esi pop esi
ret ret
@ -567,9 +552,9 @@ fat_next_short_name:
ret ret
fat_gen_short_name: fat_gen_short_name:
; in: esi->long name ; in:
; edi->buffer (8+3=11 chars) ; esi -> UTF-8 name
; out: buffer filled ; edi -> buffer (8+3=11 chars)
pushad pushad
mov eax, ' ' mov eax, ' '
push edi push edi
@ -583,38 +568,24 @@ fat_gen_short_name:
.loop: .loop:
lodsb lodsb
test al, al test al, al
js .space
jz .done jz .done
call char_toupper
cmp al, ' '
jz .space
cmp al, 80h
ja .big
test [fat_legal_chars+eax], 2 test [fat_legal_chars+eax], 2
jnz .symbol jz .space
.inv_symbol:
mov al, '_'
or bh, 1
.symbol:
cmp al, '.' cmp al, '.'
jz .dot jz .dot
.normal_symbol:
dec bl dec bl
jns .store jns .store
mov bl, 0 inc bl
.space: .space:
or bh, 1 or bh, 1
jmp .loop jmp .loop
.store: .store:
call cp866toUpper
stosb stosb
jmp .loop jmp .loop
.big:
cmp al, 0xB0
jb .normal_symbol
cmp al, 0xE0
jb .inv_symbol
cmp al, 0xF0
jb .normal_symbol
jmp .inv_symbol
.dot: .dot:
test bh, 2 test bh, 2
jz .firstdot jz .firstdot
@ -1187,107 +1158,58 @@ fat_unlock:
lea ecx, [ebp+FAT.Lock] lea ecx, [ebp+FAT.Lock]
jmp mutex_unlock jmp mutex_unlock
fat_get_name: fat_get_name:
; in: edi->FAT entry ; in: edi -> FAT entry
; out: CF=1 - no valid entry ; out: ebp -> UTF-16 name, CF=1 -> no valid entry
; else CF=0 and ebp->ASCIIZ-name
; (maximum length of filename is 255 (wide) symbols without trailing 0,
; but implementation requires buffer 261 words)
; destroys eax
cmp byte [edi], 0 cmp byte [edi], 0
jz .no jz .no
cmp byte [edi], 0xE5 cmp byte [edi], 0xE5
jnz @f jz .no
.no:
stc
ret
@@:
cmp byte [edi+11], 0xF cmp byte [edi+11], 0xF
jz .longname jz .longname
test byte [edi+11], 8 test byte [edi+11], 8
jnz .no jnz .no
push ecx push ecx esi edi
push edi ebp mov esi, edi
test byte [ebp-4], 1 mov edi, ebp
jnz .unicode_short
mov eax, [edi]
mov ecx, [edi+4]
mov [ebp], eax
mov [ebp+4], ecx
mov ecx, 8 mov ecx, 8
@@: @@:
cmp byte [ebp+ecx-1], ' ' lodsb
loope @b
mov eax, [edi+8]
cmp al, ' '
je .done
shl eax, 8
mov al, '.'
lea ebp, [ebp+ecx+1]
mov [ebp], eax
mov ecx, 3
@@:
rol eax, 8
cmp al, ' '
jne .done
loop @b
dec ebp
.done:
and byte [ebp+ecx+1], 0 ; CF=0
pop ebp edi ecx
ret
.unicode_short:
mov ecx, 8
push ecx
@@:
mov al, [edi]
inc edi
call ansi2uni_char call ansi2uni_char
mov [ebp], ax stosw
inc ebp
inc ebp
loop @b loop @b
pop ecx mov cl, 8
@@: @@:
cmp word [ebp-2], ' ' cmp word [edi-2], ' '
jnz @f jnz @f
dec ebp sub edi, 2
dec ebp
loop @b loop @b
@@: @@:
mov word [ebp], '.' mov word [edi], '.'
inc ebp add edi, 2
inc ebp mov cl, 3
mov ecx, 3
push ecx
@@: @@:
mov al, [edi] lodsb
inc edi
call ansi2uni_char call ansi2uni_char
mov [ebp], ax stosw
inc ebp
inc ebp
loop @b loop @b
pop ecx mov cl, 3
@@: @@:
cmp word [ebp-2], ' ' cmp word [edi-2], ' '
jnz @f jnz @f
dec ebp sub edi, 2
dec ebp
loop @b loop @b
dec ebp sub edi, 2
dec ebp
@@: @@:
and word [ebp], 0 ; CF=0 and word [edi], 0 ; CF=0
pop ebp edi ecx pop edi esi ecx
ret ret
.no:
stc
ret
.longname: .longname:
; LFN
mov al, byte [edi] mov al, byte [edi]
and eax, 0x3F and eax, 0x3F
dec eax dec eax
@ -1295,86 +1217,62 @@ fat_get_name:
jae .no ; ignore invalid entries jae .no ; ignore invalid entries
mov word [ebp+260*2], 0 ; force null-terminating for orphans mov word [ebp+260*2], 0 ; force null-terminating for orphans
imul eax, 13*2 imul eax, 13*2
add ebp, eax
test byte [edi], 0x40 test byte [edi], 0x40
jz @f jz @f
mov word [ebp+13*2], 0 mov word [ebp+eax+13*2], 0
@@: @@: ; copy name (13 chars in UTF-16)
push eax
; now copy name from edi to ebp ...
mov eax, [edi+1]
mov [ebp], eax ; symbols 1,2
mov eax, [edi+5]
mov [ebp+4], eax ; 3,4
mov eax, [edi+9]
mov [ebp+8], ax ; 5
mov eax, [edi+14]
mov [ebp+10], eax ; 6,7
mov eax, [edi+18]
mov [ebp+14], eax ; 8,9
mov eax, [edi+22]
mov [ebp+18], eax ; 10,11
mov eax, [edi+28]
mov [ebp+22], eax ; 12,13
; ... done
pop eax
sub ebp, eax
test eax, eax
jz @f
; if this is not first entry, more processing required
stc
ret
@@:
; if this is first entry:
test byte [ebp-4], 1
jnz .ret
; buffer at ebp contains UNICODE name, convert it to ANSI
push esi edi push esi edi
mov esi, ebp lea esi, [edi+1]
mov edi, ebp lea edi, [ebp+eax]
call uni2ansi_str movsd
movsd
movsd
inc esi
sub edi, 2
movsd
movsd
movsd
add esi, 2
movsd
pop edi esi pop edi esi
.ret: test eax, eax
clc jnz .no ; if this is not first entry, more processing required
ret ret
fat_compare_name: fat_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding) ; in: esi -> name in UTF-8, ebp -> name in UTF-16
; in: esi->name, ebp->name ; out:
; out: if names match: ZF=1 and esi->next component of name ; ZF=1 -> names match, esi -> next component of name
; else: ZF=0, esi is not changed ; ZF=0 -> esi is not changed
; destroys eax
push ebp esi push ebp esi
.loop:
mov al, [ebp]
inc ebp
call char_toupper
push eax
lodsb
call char_toupper
cmp al, [esp]
jnz .done
pop eax
test al, al
jnz .loop
dec esi
pop eax
pop ebp
xor eax, eax ; set ZF flag
ret
.done:
cmp al, '/'
jnz @f
cmp byte [esp], 0
jnz @f
mov [esp+4], esi
@@: @@:
pop eax call utf8to16
call utf16toUpper
mov edx, eax
mov ax, [ebp]
call utf16toUpper
cmp ax, dx
jnz .done
add ebp, 2
test ax, ax
jnz @b
dec esi
pop eax ebp
xor eax, eax ; set ZF
ret
.done:
cmp dx, '/'
jnz @f
test ax, ax
jnz @f
mov [esp], esi
@@:
pop esi ebp pop esi ebp
ret ret
fat_find_lfn: fat_find_lfn:
; in: esi->name ; in: esi -> name in UTF-8
; [esp+4] = next ; [esp+4] = next
; [esp+8] = first ; [esp+8] = first
; [esp+C]... - possibly parameters for first and next ; [esp+C]... - possibly parameters for first and next
@ -1385,26 +1283,26 @@ fat_find_lfn:
call dword [eax-4] call dword [eax-4]
jc .reterr jc .reterr
sub esp, 262*2 ; reserve place for LFN sub esp, 262*2 ; reserve place for LFN
push 0 ; for fat_get_name: read ASCII name
.l1: .l1:
lea ebp, [esp+4] lea ebp, [esp]
call fat_get_name call fat_get_name
jc .l2 jc .l2
call fat_compare_name call fat_compare_name
jz .found jz .found
.l2: .l2:
mov ebp, [esp+8+262*2+4] mov ebp, [esp+8+262*2]
lea eax, [esp+0Ch+20h+262*2+4] lea eax, [esp+0Ch+20h+262*2]
call dword [eax-8] call dword [eax-8]
jnc .l1 jnc .l1
add esp, 262*2+4 add esp, 262*2
.reterr: .reterr:
mov [esp+28], eax mov [esp+28], eax
stc stc
popa popa
ret ret
.found: .found:
add esp, 262*2+4 add esp, 262*2
mov ebp, [esp+8] mov ebp, [esp+8]
; if this is LFN entry, advance to true entry ; if this is LFN entry, advance to true entry
cmp byte [edi+11], 0xF cmp byte [edi+11], 0xF
@ -1413,7 +1311,7 @@ fat_find_lfn:
call dword [eax-8] call dword [eax-8]
jc .reterr jc .reterr
@@: @@:
add esp, 8 ; CF=0 add esp, 8 ; CF=0
push esi push esi
push edi push edi
popa popa
@ -1481,9 +1379,8 @@ bdfe_to_fat_date:
fat_entry_to_bdfe: fat_entry_to_bdfe:
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi ; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
; destroys eax
mov eax, [ebp-4] mov eax, [ebp-4]
mov [esi+4], eax ; ASCII/UNICODE name mov [esi+4], eax ; cp866/UNICODE name
fat_entry_to_bdfe2: fat_entry_to_bdfe2:
movzx eax, byte [edi+11] movzx eax, byte [edi+11]
mov [esi], eax ; attributes mov [esi], eax ; attributes
@ -1512,6 +1409,7 @@ fat_entry_to_bdfe2:
push ecx edi push ecx edi
lea edi, [esi+40] lea edi, [esi+40]
mov esi, ebp mov esi, ebp
mov ecx, 263
test byte [esi-4], 1 test byte [esi-4], 1
jz .ansi jz .ansi
mov ecx, 260/2 mov ecx, 260/2
@ -1522,10 +1420,14 @@ fat_entry_to_bdfe2:
pop edi ecx pop edi ecx
.ret: .ret:
ret ret
.ansi: .ansi:
mov ecx, 264/4 lodsw
rep movsd call uni2ansi_char
mov [edi-1], al stosb
loop .ansi
xor eax, eax
stosb
jmp @b jmp @b
bdfe_to_fat_entry: bdfe_to_fat_entry:
@ -1557,7 +1459,7 @@ bdfe_to_fat_entry:
ret ret
hd_find_lfn: hd_find_lfn:
; in: esi -> path string ; in: esi -> path string in UTF-8
; out: CF=1 - file not found, eax=error code ; out: CF=1 - file not found, eax=error code
; else CF=0 and edi->direntry, eax=sector ; else CF=0 and edi->direntry, eax=sector
push esi edi push esi edi
@ -1825,7 +1727,7 @@ fat_ReadFolder:
.doit: .doit:
push esi push esi
sub esp, 262*2 ; reserve space for LFN sub esp, 262*2 ; reserve space for LFN
push dword [ebx+8] ; for fat_get_name: read ANSI/UNICODE name push dword [ebx+8] ; cp866/UNICODE name
mov edx, [ebx+16] ; pointer to buffer mov edx, [ebx+16] ; pointer to buffer
; init header ; init header
push eax push eax
@ -2386,22 +2288,19 @@ fat_CreateFile:
movi eax, 1 ; 1 entry movi eax, 1 ; 1 entry
jnz .notilde jnz .notilde
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total ; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
xor eax, eax xor ecx, ecx
push esi
@@: @@:
cmp byte [esi], 0 call utf8to16
jz @f inc ecx
inc esi test ax, ax
inc eax jnz @b
jmp @b pop esi
mov eax, ecx
@@: add eax, 12+13-1
sub esi, eax
add eax, 12+13
mov ecx, 13 mov ecx, 13
push edx
cdq cdq
div ecx div ecx
pop edx
.notilde: .notilde:
push -1 push -1
push -1 push -1
@ -2480,7 +2379,7 @@ fat_CreateFile:
jmp .disk_full jmp .disk_full
@@: @@:
mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere
.no.preallocate.folder.data: ; calculate name checksum .no.preallocate.folder.data: ; calculate name checksum
mov esi, [esp+8+12] mov esi, [esp+8+12]
mov ecx, 11 mov ecx, 11
@ -2490,26 +2389,28 @@ fat_CreateFile:
add al, [esi] add al, [esi]
inc esi inc esi
loop @b loop @b
pop ecx esi pop ecx esi edi
pop edi
pop dword [esp+8+12+12] pop dword [esp+8+12+12]
pop dword [esp+8+12+12] pop dword [esp+8+12+12]
; edi points to first entry in free chunk ; edi points to first entry in free chunk
dec ecx dec ecx
jz .nolfn jz .nolfn
push esi push esi eax
push eax
lea eax, [esp+8+8+12+8] lea eax, [esp+8+8+12+8]
call dword [eax+8] ; begin write call dword [eax+8] ; begin write
mov al, 40h mov al, 40h
.writelfn: .writelfn:
or al, cl or al, cl
stosb
mov esi, [esp+4] mov esi, [esp+4]
push ecx push ecx
dec ecx dec ecx
jz @f
imul ecx, 13 imul ecx, 13
add esi, ecx .scroll:
stosb call utf8to16
loop .scroll
@@:
mov cl, 5 mov cl, 5
call fat_read_symbols call fat_read_symbols
mov ax, 0xF mov ax, 0xF
@ -2524,11 +2425,10 @@ fat_CreateFile:
call fat_read_symbols call fat_read_symbols
pop ecx pop ecx
lea eax, [esp+8+8+12+8] lea eax, [esp+8+8+12+8]
call dword [eax+12] ; next write call dword [eax+12] ; next write
xor eax, eax xor eax, eax
loop .writelfn loop .writelfn
pop eax pop eax esi
pop esi
.nolfn: .nolfn:
xchg esi, [esp] xchg esi, [esp]
mov ecx, 11 mov ecx, 11
@ -2730,21 +2630,20 @@ fat_CreateFile:
mov [edi-32+20], cx mov [edi-32+20], cx
jmp .writedircont jmp .writedircont
fat_read_symbol: @@:
or ax, -1 or eax, -1
test esi, esi rep stosw
jz .retFFFF
lodsb
test al, al
jnz ansi2uni_char
xor eax, eax
xor esi, esi
.retFFFF:
ret ret
fat_read_symbols: fat_read_symbols:
call fat_read_symbol test esi, esi
jz @b
call utf8to16
stosw stosw
test ax, ax
jnz @f
xor esi, esi
@@:
loop fat_read_symbols loop fat_read_symbols
ret ret

View File

@ -67,6 +67,11 @@ file_system_lfn:
@@: @@:
cmp word [ebp], '/' cmp word [ebp], '/'
jz .rootdir jz .rootdir
cmp byte [ebp], 2
jnz @f
cmp dword[ebp+1], '/'
jz .rootdir
@@:
stdcall kernel_alloc, maxPathLength stdcall kernel_alloc, maxPathLength
push ebx push ebx
mov ebx, ebp mov ebx, ebp
@ -75,6 +80,8 @@ file_system_lfn:
push eax push eax
call get_full_file_name call get_full_file_name
pop ebx pop ebx
test eax, eax
jz .notfound
mov esi, ebp mov esi, ebp
mov ax, [ebp] mov ax, [ebp]
or ax, 2020h or ax, 2020h
@ -349,16 +356,14 @@ file_system_lfn:
process_replace_file_name: process_replace_file_name:
; in: [esi] = virtual path ; in: [esi] = virtual path
; out: [esi]+[ebp] = physical path ; out: [esi]+[ebp] = physical path
pushfd
cli
mov ebp, [full_file_name_table]
xor edi, edi xor edi, edi
xor ebp, ebp
.loop: .loop:
cmp edi, [full_file_name_table.size] cmp edi, [full_file_name_table.size]
jae .notfound jae .notfound
push esi edi push esi edi
shl edi, 7 shl edi, 7
add edi, ebp add edi, [full_file_name_table]
@@: @@:
cmp byte [edi], 0 cmp byte [edi], 0
jz .dest_done jz .dest_done
@ -378,24 +383,18 @@ process_replace_file_name:
jz .found jz .found
cmp byte [esi], '/' cmp byte [esi], '/'
jnz .cont jnz .cont
inc esi
.found: .found:
pop edi eax pop edi eax
shl edi, 7 shl edi, 7
add edi, ebp add edi, [full_file_name_table]
mov ebp, esi mov ebp, esi
cmp byte [esi], 0
lea esi, [edi+64] lea esi, [edi+64]
jnz .ret
.notfound: .notfound:
xor ebp, ebp
.ret:
popfd
ret ret
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
uglobal uglobal
lock_flag_for_f30_3 rb 1 addDirSeal db ?
endg endg
sys_current_directory: ; sysfunction 30 sys_current_directory: ; sysfunction 30
@ -407,62 +406,86 @@ sys_current_directory: ; sysfunction 30
jz .get jz .get
dec ebx dec ebx
jz .mount_additional_directory jz .mount_additional_directory
dec ebx
jz .get16
@@:
ret ret
.mount_additional_directory: .mount_additional_directory:
; in: ecx -> dir name+dir path (128) ; in: ecx -> dir name+dir path (128)
cmp [lock_flag_for_f30_3], 1 ; check lock mov al, 1
je @f xchg [addDirSeal], al
test al, al
jnz @b
mov esi, ecx mov esi, ecx
mov edi, sysdir_name1 mov edi, sysdir_name1
mov ecx, 63 mov ecx, 63
pushfd
cli
cld
rep movsb ; copying fake directory name rep movsb ; copying fake directory name
inc esi inc esi
xor eax, eax xor eax, eax
stosb ; terminator of name, in case if we get the inlet trash stosb ; terminator of name, in case if we get the inlet trash
mov ecx, 63 mov cl, 63
rep movsb ; copying real directory path for mounting cmp word [esi], 2
xor eax, eax jz .utf16
stosb call cp866toUTF8_string
; increase the pointer of inputs for procedure "process_replace_file_name"
mov [full_file_name_table.size], 2
mov [lock_flag_for_f30_3], 1 ; lock
popfd
@@: @@:
mov byte [edi], 0
mov [full_file_name_table.size], 2
ret ret
.utf16:
add esi, 2
call UTF16to8_string
jmp @b
.get: ; in: ecx -> buffer, edx = length .get: ; in: ecx -> buffer, edx = length
mov ebx, edi ; buffer mov esi, edi
push ecx mov edi, ecx
push edi cmp edx, maxPathLength
xor eax, eax jc @f
mov ecx, maxPathLength mov edx, maxPathLength
repne scasb
jnz .error
sub edi, ebx
inc edi
mov [esp+32+8], edi ; return in eax
cmp edx, edi
jbe @f
mov edx, edi
@@: @@:
pop esi
pop edi
cmp edx, 1
jbe .ret
mov al, '/' mov al, '/'
stosb stosb
mov ecx, edx mov ecx, edx
rep movsb dec ecx
.ret: @@:
dec ecx
js @f
call utf8to16
call uni2ansi_char
stosb
test al, al
jnz @b
sub edx, ecx
mov ecx, edx
@@:
mov [esp+32], ecx
ret ret
.error: .get16:
add esp, 8 mov esi, edi
or dword[esp+32], -1 mov edi, ecx
cmp edx, maxPathLength
jc @f
mov edx, maxPathLength
@@:
shr edx, 1
mov ax, '/'
stosw
mov ecx, edx
dec ecx
@@:
dec ecx
js @f
call utf8to16
stosw
test ax, ax
jnz @b
sub edx, ecx
mov ecx, edx
@@:
mov [esp+32], ecx
ret ret
.set: .set:
@ -473,118 +496,144 @@ sys_current_directory: ; sysfunction 30
mov ebx, ecx mov ebx, ecx
get_full_file_name: get_full_file_name:
; in: ebx -> file name, [esp+4] -> destination, [esp+8] = max length ; in: ebx -> file name, [esp+4] -> destination, [esp+8] = max length
; destroys all registers ; out: eax=0 -> out of length
push ebp push ebp ebx
cmp byte [ebx], '/' mov esi, ebx
cmp byte [ebx], 2
jnz @f
inc esi
@@:
cmp byte [esi], '/'
jnz .set_relative jnz .set_relative
lea esi, [ebx+1] inc esi
cmp byte [ebx], 2
jnz @f
inc esi
@@:
call process_replace_file_name call process_replace_file_name
mov edi, [esp+8] mov edi, [esp+12]
mov edx, [esp+12] mov ecx, [esp+16]
add edx, edi test ebp, ebp
.set_copy: jz .absolute
@@:
lodsb lodsb
stosb stosb
dec ecx
test al, al test al, al
jz .set_part2 jnz @b
.set_copy_cont: mov esi, ebp
cmp edi, edx
jb .set_copy
.overflow:
dec edi dec edi
.absolute:
cmp byte [ebx], 2
jz @f
call cp866toUTF8_string
jns .ret
jmp .fail
@@:
call UTF16to8_string
jns .ret
.fail: .fail:
mov byte [edi], 0 mov byte [edi], 0
xor eax, eax xor eax, eax
pop ebp pop ebx ebp
ret 8 ret 8
.set_part2:
mov esi, ebp
xor ebp, ebp
test esi, esi
jz .ret.ok
mov byte [edi-1], '/'
jmp .set_copy_cont
.set_relative: .set_relative:
mov edi, [current_slot] mov edi, [current_slot]
mov edi, [edi+APPDATA.cur_dir] mov edi, [edi+APPDATA.cur_dir]
mov edx, edi mov edx, edi
mov ecx, [esp+12] mov ecx, [esp+16]
xor eax, eax xor eax, eax
repnz scasb repnz scasb
mov esi, edi mov esi, edi
dec esi dec esi
mov edi, [esp+8] mov edi, [esp+12]
jecxz .fail jecxz .fail
cmp byte [ebx], 2
jz .relative16
.relative: .relative:
cmp byte [ebx], 0 cmp byte [ebx], 0
jz .set_ok jz .set_ok
cmp word [ebx], '.' cmp word [ebx], '.'
jz .set_ok jz .set_ok
cmp word [ebx], './' cmp word [ebx], './'
jnz @f jz .next
add ebx, 2
jmp .relative
@@:
cmp word [ebx], '..' cmp word [ebx], '..'
jnz .doset_relative jnz .doset_relative
cmp byte [ebx+2], 0 cmp byte [ebx+2], 0
jz @f jz @f
cmp byte [ebx+2], '/' cmp byte [ebx+2], '/'
jnz .doset_relative jnz .doset_relative
inc ebx
@@: @@:
dec esi dec esi
cmp byte [esi], '/' cmp byte [esi], '/'
jnz @b jnz @b
add ebx, 3 .next:
add ebx, 2
jmp .relative jmp .relative
.set_ok: .set_ok:
cmp edx, edi ; is destination equal to APPDATA.cur_dir? cmp edx, edi ; is destination equal to cur_dir?
jz @f jz @f
mov ecx, esi mov ecx, esi
sub ecx, edx sub ecx, edx
mov esi, edx mov esi, edx
rep movsb rep movsb
mov byte [edi], 0 mov byte [edi], 0
.ret.ok: .ret:
mov al, 1 mov al, 1
pop ebp pop ebx ebp
ret 8 ret 8
@@: @@:
mov byte [esi], 0 mov byte [esi], 0
jmp .ret.ok jmp .ret
.doset_relative: .doset_relative:
cmp edx, edi cmp edx, edi ; is destination equal to cur_dir?
jz .doset_relative.cur_dir mov edi, esi
jz @f
mov edi, [esp+12]
mov ecx, esi mov ecx, esi
sub ecx, edx sub ecx, edx
mov esi, edx mov esi, edx
mov edx, edi mov edx, edi
rep movsb rep movsb
jmp .doset_relative.copy @@:
.doset_relative.cur_dir:
mov edi, esi
.doset_relative.copy:
add edx, [esp+12]
mov byte [edi], '/' mov byte [edi], '/'
inc edi inc edi
cmp edi, edx mov esi, ebx
jae .overflow mov ecx, edx
add ecx, [esp+16]
sub ecx, edi
mov ebx, [esp]
jmp .absolute
.relative16:
cmp word [ebx], 0
jz .set_ok
cmp word [ebx], '.'
jnz .doset_relative
cmp word [ebx+2], 0
jz .set_ok
cmp word [ebx+2], '/'
jz .next16
cmp word [ebx+2], '.'
jnz .doset_relative
cmp word [ebx+4], 0
jz @f
cmp word [ebx+4], '/'
jnz .doset_relative
add ebx, 2
@@: @@:
mov al, [ebx] dec esi
inc ebx cmp byte [esi], '/'
stosb jnz @b
test al, al .next16:
jz .ret.ok add ebx, 4
cmp edi, edx jmp .relative16
jb @b
jmp .overflow
include "parse_fn.inc" include "parse_fn.inc"
include "fs_common.inc" include "fs_common.inc"

View File

@ -9,7 +9,7 @@ $Revision$
; CD external functions ; CD external functions
; in: ; in:
; esi -> path string ; esi -> path string in UTF-8
; ebx -> offset in file (qword) ; ebx -> offset in file (qword)
; ecx = bytes to read ; ecx = bytes to read
; edx -> buffer ; edx -> buffer
@ -604,9 +604,8 @@ fs_CdGetFileInfo:
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
cd_find_lfn: cd_find_lfn:
mov [cd_appl_data], 0 mov [cd_appl_data], 0
; in: esi -> path string ; in: esi -> path string in UTF-8
; out: CF=1 - file not found ; out: [cd_current_pointer_of_input] -> direntry, CF=1 -> file not found
; else CF=0 and [cd_current_pointer_of_input] direntry
push eax esi push eax esi
; Sector 16 - start set of volume descriptors ; Sector 16 - start set of volume descriptors
call WaitUnitReady call WaitUnitReady
@ -754,45 +753,25 @@ cd_get_name:
ret ret
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
cd_compare_name: cd_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding) ; in: esi -> UTF-8 name, ebp -> UTF-16BE name
; in: esi->name, ebp->name ; out: CF=0 -> names match, esi -> next component of name
; out: if names match: ZF=1 and esi->next component of name ; CF=1 -> esi is not changed
; else: ZF=0, esi is not changed push edx edi eax esi
; destroys eax
push esi eax edi
mov edi, ebp mov edi, ebp
;--------------------------------------
.loop: .loop:
cld call utf8to16
lodsb call utf16toUpper
push eax mov edx, eax
call char_todown mov ax, [edi]
call ansi2uni_char xchg al, ah
xchg ah, al call utf16toUpper
scasw cmp ax, dx
pop eax
je .coincides
call char_toupper
call ansi2uni_char
xchg ah, al
sub edi, 2
scasw
jne .name_not_coincide jne .name_not_coincide
;-------------------------------------- add edi, 2
.coincides:
cmp [esi], byte '/' ; path separator is end of current element cmp [esi], byte '/' ; path separator is end of current element
je .done je .done
cmp [esi], byte 0 ; path separator end of name cmp [esi], byte 0 ; path separator end of name
je .done jne .loop
jmp .loop
;--------------------------------------
.name_not_coincide:
pop edi eax esi
stc
ret
;--------------------------------------
.done: .done:
; check end of file ; check end of file
cmp [edi], word 3B00h; separator end of file ';' cmp [edi], word 3B00h; separator end of file ';'
@ -808,10 +787,12 @@ cd_compare_name:
add eax, ebp add eax, ebp
cmp edi, eax cmp edi, eax
jne .name_not_coincide jne .name_not_coincide
;--------------------------------------
.done_1: .done_1:
pop edi eax pop eax eax edi edx
add esp, 4
inc esi inc esi
clc ret
.name_not_coincide:
pop esi eax edi edx
stc
ret ret

View File

@ -11,7 +11,7 @@ $Revision$
; in: ; in:
; ebx -> parameter structure of sysfunc 70 ; ebx -> parameter structure of sysfunc 70
; ebp -> NTFS structure ; ebp -> NTFS structure
; esi -> path string ; esi -> path string in UTF-8
; out: ; out:
; eax, ebx = return values for sysfunc 70 ; eax, ebx = return values for sysfunc 70
iglobal iglobal
@ -1161,20 +1161,8 @@ ntfs_decode_mcb_entry:
pop edi ecx eax pop edi ecx eax
ret ret
unichar_toupper:
push eax
call uni2ansi_char
cmp al, '_'
jz .unk
add esp, 4
call char_toupper
jmp ansi2uni_char
.unk:
pop eax
ret
ntfs_find_lfn: ntfs_find_lfn:
; in: esi -> path string ; in: esi -> path string in UTF-8
; out: ; out:
; [ebp+NTFS.cur_iRecord] = target fileRecord ; [ebp+NTFS.cur_iRecord] = target fileRecord
; eax -> target index in the node ; eax -> target index in the node
@ -1214,39 +1202,40 @@ ntfs_find_lfn:
add eax, rootNode add eax, rootNode
cmp [ebp+NTFS.cur_read], eax cmp [ebp+NTFS.cur_read], eax
jc .err jc .err
mov edi, [esp+4]
mov eax, [ebp+NTFS.mftLastRead] mov eax, [ebp+NTFS.mftLastRead]
mov [ebp+NTFS.rootLastRead], eax mov [ebp+NTFS.rootLastRead], eax
mov eax, [ebp+NTFS.attr_offs] mov eax, [ebp+NTFS.attr_offs]
mov [ebp+NTFS.indexRoot], eax mov [ebp+NTFS.indexRoot], eax
; edi -> name, esi -> current index node .scanloop: ; esi -> current index node
.scanloop:
add esi, [esi+indexOffset] add esi, [esi+indexOffset]
.scanloopint: .scanloopint:
push esi
test byte [esi+indexFlags], 2 test byte [esi+indexFlags], 2
jnz .subnode jnz .subnode
push esi
movzx ecx, byte [esi+fileNameLength] movzx ecx, byte [esi+fileNameLength]
add esi, fileName lea edi, [esi+fileName]
push edi mov esi, [esp+8]
@@: @@:
lodsw call utf8to16
call unichar_toupper cmp ax, '/'
jz .subnode
call utf16toUpper
push eax push eax
mov al, [edi] mov ax, [edi]
inc edi call utf16toUpper
cmp al, '/' cmp [esp], ax
jz .slash
call char_toupper
call ansi2uni_char
cmp ax, [esp]
pop eax pop eax
loopz @b jc .subnode
jnz .scanloopcont
add edi, 2
loop @b
call utf8to16
cmp ax, '/'
jz .found
test ax, ax
jz .found jz .found
pop edi
pop esi
jb .subnode
.scanloopcont: .scanloopcont:
pop esi
movzx eax, word [esi+indexAllocatedSize] movzx eax, word [esi+indexAllocatedSize]
add esi, eax add esi, eax
jmp .scanloopint jmp .scanloopint
@ -1273,7 +1262,7 @@ ntfs_find_lfn:
jmp .doit2 jmp .doit2
.notfound: .notfound:
mov [esp+1Ch], esi mov [esp+28], esi
.err: .err:
popad popad
stc stc
@ -1282,11 +1271,8 @@ ntfs_find_lfn:
.ret: .ret:
ret ret
.slash:
pop eax
pop edi
pop esi
.subnode: .subnode:
pop esi
test byte [esi+indexFlags], 1 test byte [esi+indexFlags], 1
jz .notfound jz .notfound
mov eax, [ebp+NTFS.LastRead] mov eax, [ebp+NTFS.LastRead]
@ -1321,25 +1307,14 @@ ntfs_find_lfn:
jmp .scanloop jmp .scanloop
.found: .found:
cmp byte [edi], 0 mov [esp+8], esi
jz @f pop eax
cmp byte [edi], '/' mov [esp+28], eax
jz @f mov eax, [eax+fileRecordReference]
pop edi
pop esi
jmp .scanloopcont
@@:
pop esi
pop esi
mov eax, [esi]
mov [ebp+NTFS.cur_iRecord], eax mov [ebp+NTFS.cur_iRecord], eax
mov [esp+1Ch], esi
mov [esp+4], edi
popad popad
cmp byte [esi], 0 cmp byte [esi-1], 0
jz .ret2 jz .ret2
inc esi
pop eax pop eax
jmp .doit2 jmp .doit2
@ -1859,8 +1834,7 @@ ntfs_GetFileInfo:
lodsw lodsw
call uni2ansi_char call uni2ansi_char
stosb stosb
dec ecx loop @b
jnz @b
mov byte [edi], 0 mov byte [edi], 0
jmp .end jmp .end
@ -1964,25 +1938,29 @@ ntfs_CreateFile:
cmp [ebp+NTFS.fragmentCount], 1 cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented jnz ntfsUnsupported ; record fragmented
; 2. Prepare directory record ; 2. Prepare directory record
mov ecx, esi mov edi, esi
mov edx, eax
xor ecx, ecx
@@: ; count characters @@: ; count characters
inc ecx call utf8to16
cmp byte [ecx], '/' cmp ax, '/'
jz ntfsNotFound ; path folder not found jz ntfsNotFound ; path folder not found
cmp byte [ecx], 0 inc ecx
test ax, ax
jnz @b jnz @b
sub ecx, esi dec ecx
push ecx ; name length push ecx ; name length in chars
push edi
shl ecx, 1 shl ecx, 1
add ecx, fileName+7 add ecx, fileName+7
and ecx, not 7 and ecx, not 7
mov edi, [ebp+NTFS.cur_index_buf] mov edi, [ebp+NTFS.cur_index_buf]
mov edx, [ebx+12] mov eax, [ebx+12]
mov [ebp+NTFS.fileRealSize], edx mov [ebp+NTFS.fileRealSize], eax
mov edx, [ebx+16] mov eax, [ebx+16]
mov [ebp+NTFS.fileDataBuffer], edx mov [ebp+NTFS.fileDataBuffer], eax
push esi
push ecx ; index length push ecx ; index length
mov eax, edx
mov edx, ecx mov edx, ecx
cmp dword [edi], 'INDX' cmp dword [edi], 'INDX'
jz .indexRecord jz .indexRecord
@ -2483,11 +2461,9 @@ ntfs_CreateFile:
mov [edi+fileNameLength], cl mov [edi+fileNameLength], cl
add edi, fileName add edi, fileName
@@: ; record filename @@: ; record filename
lodsb call utf8to16
call ansi2uni_char
stosw stosw
dec ecx loop @b
jnz @b
mov eax, [ebp+NTFS.LastRead] mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax mov [ebp+NTFS.nodeLastRead], eax
cmp [ebp+NTFS.bFolder], 0 cmp [ebp+NTFS.bFolder], 0
@ -2805,8 +2781,7 @@ writeRecord:
add esi, 510 add esi, 510
movsw movsw
mov [esi-2], ax mov [esi-2], ax
dec ecx loop @b
jnz @b
mov eax, edx mov eax, edx
xor edx, edx xor edx, edx
pop ecx pop ecx

View File

@ -237,76 +237,53 @@ proc get_every_key.replace
ret ret
endp endp
cp866toUpper:
char_todown: ; convert cp866 character in al to uppercase
; convert character in al to downcase, using cp866 encoding
cmp al, 'A'
jb .ret
cmp al, 'Z'
jbe .az
cmp al, 0x80 ; 'А'
jb .ret
cmp al, 0x90 ; 'Р'
jb .rus
cmp al, 0xF0 ; 'Ё'
jz .yo
cmp al, 0x9F ; 'Я'
ja .ret
; 0x90-0x9F -> 0xE0-0xEF
add al, 0xE0-0x90
.ret:
ret
.az:
.rus: ; 0x80-0x8F -> 0xA0-0xAF
add al, 0x20
ret
.yo:
inc al
ret
char_toupper:
; convert character in al to uppercase, using cp866 encoding
cmp al, 'a' cmp al, 'a'
jb .ret jb .ret
cmp al, 'z' cmp al, 'z'
jbe .az jbe @f
cmp al, 0xA0 ; 'а' cmp al, 0xA0
jb .ret jb .ret
cmp al, 0xE0 ; 'р' cmp al, 0xB0
jb @f
cmp al, 0xE0
jb .ret
cmp al, 0xF0
jb .rus jb .rus
cmp al, 0xF1 ; 'ё' cmp al, 0xF7
jz .yo
cmp al, 0xEF ; 'я'
ja .ret ja .ret
; 0xE0-0xEF -> 0x90-0x9F and eax, -2
sub al, 0xE0-0x90
.ret: .ret:
ret ret
.az: @@:
.rus: ; 0xA0-0xAF -> 0x80-0x8F sub eax, 32
and al, not 0x20
ret ret
.yo: .rus:
dec al sub eax, 0xE0-0x90
ret ret
utf16toUpper:
uni2ansi_str: ; convert UTF-16 character in ax to uppercase
; convert UNICODE zero-terminated string to ASCII-string (codepage 866) cmp ax, 'a'
; in: esi->source, edi->buffer (may be esi=edi) jb .ret
; destroys: eax,esi,edi cmp ax, 'z'
lodsw jbe @f
call uni2ansi_char cmp ax, 430h
stosb jb .ret
test al, al cmp ax, 450h
jnz uni2ansi_str jb @f
cmp ax, 460h
jnc .ret
sub eax, 80
.ret:
ret ret
@@:
sub eax, 32
ret
uni2ansi_char: uni2ansi_char:
; convert UNICODE character in ax to ANSI character in al using cp866 encoding ; convert UNICODE character in ax to ANSI character in al using cp866 encoding
@ -355,7 +332,6 @@ uni2ansi_char:
.table db 1, 51h, 4, 54h, 7, 57h, 0Eh, 5Eh .table db 1, 51h, 4, 54h, 7, 57h, 0Eh, 5Eh
ansi2uni_char: ansi2uni_char:
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding ; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
movzx eax, al movzx eax, al
@ -392,25 +368,85 @@ ansi2uni_char:
mov al, '_' mov al, '_'
ret ret
utf8_to_cp866: cp866toUTF8_string:
; in: esi, edi, ecx
; destroys esi, edi, ecx, eax
call utf8to16
js utf8to16.ret
call uni2ansi_char
stosb
jmp utf8_to_cp866
utf8to16:
; in: ; in:
; esi -> string ; esi -> cp866 string (could be zero terminated)
; ecx = byte counter ; edi -> buffer for UTF-8 string
; out: ; ecx = buffer size (signed)
; SF=1 -> end lodsb
; ax = UTF-16 char call ansi2uni_char
; changes esi, ecx push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz cp866toUTF8_string
@@:
ret
; SF=1 -> counter
; ZF=1 -> zero char
UTF16to8_string:
; in:
; esi -> UTF-16 string (could be zero terminated)
; edi -> buffer for UTF-8 string
; ecx = buffer size (signed)
xor eax, eax
@@:
lodsw
push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz @b
@@:
ret
UTF16to8:
; in:
; eax = UTF-16 char
; edi -> buffer for UTF-8 char (increasing)
; ecx = byte counter (decreasing)
dec ecx dec ecx
js .ret js .ret
cmp eax, 80h
jnc @f
stosb
test eax, eax ; SF=0
.ret:
ret
@@:
dec ecx
js .ret
cmp eax, 800h
jnc @f
shl eax, 2
shr al, 2
or eax, 1100000010000000b
xchg al, ah
stosw
ret
@@:
dec ecx
js .ret
shl eax, 4
shr ax, 2
shr al, 2
or eax, 111000001000000010000000b
bswap eax
shr eax, 8
stosb
shr eax, 8
stosw
ret
utf8to16:
; in: esi -> UTF-8 char (increasing)
; out: ax = UTF-16 char
lodsb lodsb
test al, al test al, al
jns .got jns .got
@ -418,8 +454,6 @@ utf8to16:
jnc utf8to16 jnc utf8to16
@@: @@:
shl ax, 8 shl ax, 8
dec ecx
js .ret
lodsb lodsb
test al, al test al, al
jns .got jns .got
@ -429,8 +463,6 @@ utf8to16:
shl ax, 3 shl ax, 3
jnc @f jnc @f
shl eax, 3 shl eax, 3
dec ecx
js .ret
lodsb lodsb
test al, al test al, al
jns .got jns .got
@ -445,7 +477,6 @@ utf8to16:
.got: .got:
xor ah, ah xor ah, ah
.ret:
ret ret
strlen: strlen: