mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-27 16:59:41 +03:00
66417e61bd
1) Fix - sectors read with errors now are not brought in the cache. 2) Timeout at absence of the disk in ATAPI drive is reduced about 10 seconds without lowering reliability of reading at presence of the disk. Earlier time the waiting could make 1-1.5 minutes. git-svn-id: svn://kolibrios.org@628 a494cfbc-eb01-0410-851d-a64ba20cac60
735 lines
16 KiB
PHP
735 lines
16 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; ;;
|
||
;; Copyright (C) KolibriOS team 2004-2007. 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
|
||
IDE_Channel_1 db 0
|
||
IDE_Channel_2 db 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:
|
||
cmp [ChannelNumber],1
|
||
jne .IDE_Channel_2
|
||
.IDE_Channel_1:
|
||
cli
|
||
cmp [IDE_Channel_1],0
|
||
je .reserve_ok_1
|
||
sti
|
||
call change_task
|
||
jmp .IDE_Channel_1
|
||
.IDE_Channel_2:
|
||
cli
|
||
cmp [IDE_Channel_2],0
|
||
je .reserve_ok_2
|
||
sti
|
||
call change_task
|
||
jmp .IDE_Channel_1
|
||
.reserve_ok_1:
|
||
mov [IDE_Channel_1],1
|
||
ret
|
||
.reserve_ok_2:
|
||
mov [IDE_Channel_2],1
|
||
ret
|
||
|
||
free_cd_channel:
|
||
cmp [ChannelNumber],1
|
||
jne .IDE_Channel_2
|
||
.IDE_Channel_1:
|
||
mov [IDE_Channel_1],0
|
||
ret
|
||
.IDE_Channel_2:
|
||
mov [IDE_Channel_2],0
|
||
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] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.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
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
;.mainloop:
|
||
mov [cd_counter_block], dword 0
|
||
dec dword [CDSectorAddress]
|
||
push ecx
|
||
.read_to_buffer:
|
||
inc dword [CDSectorAddress]
|
||
mov [CDDataBuf_pointer], CDDataBuf
|
||
call ReadCDWRetr ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp [DevErrorCode], 0
|
||
jne .noaccess_1
|
||
call .get_names_from_buffer
|
||
sub eax,2048
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
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
|
||
; jmp .unicode
|
||
.ansi:
|
||
cmp [cd_counter_block],2
|
||
jbe .ansi_parent_directory
|
||
cld
|
||
lodsw
|
||
xchg ah,al
|
||
call uni2ansi_char
|
||
cld
|
||
stosb
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov ax,[esi]
|
||
cmp ax,word 3B00h ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ';'
|
||
je .cd_get_parameters_of_file_1
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
movzx eax,byte [ebp-33]
|
||
add eax,ebp
|
||
sub eax,34
|
||
cmp esi,eax
|
||
je .cd_get_parameters_of_file_1
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov ax,[esi]
|
||
cmp ax,word 3B00h ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ';'
|
||
je .cd_get_parameters_of_file_2
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
movzx eax,byte [ebp-33]
|
||
add eax,ebp
|
||
sub eax,34
|
||
cmp esi,eax
|
||
je .cd_get_parameters_of_file_2
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
xor eax,eax
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
inc eax
|
||
shl eax,1
|
||
; <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
test [ebp-8],byte 2
|
||
jz .file
|
||
inc eax
|
||
.file:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD> FAT, <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
shl eax,3
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||
test [ebp-8],byte 1
|
||
jz .hidden
|
||
inc eax
|
||
.hidden:
|
||
shl eax,1
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> CD
|
||
inc eax
|
||
mov [edi],eax
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
;<EFBFBD><EFBFBD><EFBFBD>
|
||
movzx eax,byte [ebp-12]
|
||
shl eax,8
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov al,[ebp-11]
|
||
shl eax,8
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov al,[ebp-10]
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+8],eax
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+16],eax
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+24],eax
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
;<EFBFBD><EFBFBD><EFBFBD>
|
||
movzx eax,byte [ebp-15]
|
||
add eax,1900
|
||
shl eax,8
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov al,[ebp-14]
|
||
shl eax,8
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov al,[ebp-13]
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+12],eax
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+20],eax
|
||
;<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [edi+28],eax
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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
|
||
@@:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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
|
||
; 16 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [CDSectorAddress],dword 15
|
||
mov [CDDataBuf_pointer],CDDataBuf
|
||
|
||
call WaitUnitReady
|
||
cmp [DevErrorCode],0
|
||
jne .access_denied
|
||
|
||
call prevent_medium_removal
|
||
.start:
|
||
inc dword [CDSectorAddress]
|
||
call ReadCDWRetr ;_1
|
||
cmp [DevErrorCode],0
|
||
jne .access_denied
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp [CDDataBuf+1],dword 'CD00'
|
||
jne .access_denied
|
||
cmp [CDDataBuf+5],byte '1'
|
||
jne .access_denied
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
cmp [CDDataBuf],byte 0xff
|
||
je .access_denied
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
cmp [CDDataBuf],byte 0x2
|
||
jne .start
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
cmp [CDDataBuf+6],byte 0x1
|
||
jne .start
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> root <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax,[CDDataBuf+0x9c+2] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> root <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov [CDSectorAddress],eax
|
||
mov eax,[CDDataBuf+0x9c+10] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> root <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp byte [esi], 0
|
||
jnz @f
|
||
mov [cd_current_pointer_of_input],CDDataBuf+0x9c
|
||
jmp .done
|
||
@@:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.mainloop:
|
||
dec dword [CDSectorAddress]
|
||
.read_to_buffer:
|
||
inc dword [CDSectorAddress]
|
||
mov [CDDataBuf_pointer],CDDataBuf
|
||
call ReadCDWRetr ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp [DevErrorCode],0
|
||
jne .access_denied
|
||
push ebp
|
||
call cd_find_name_in_buffer
|
||
pop ebp
|
||
jnc .found
|
||
sub eax,2048
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
cmp eax,0
|
||
ja .read_to_buffer
|
||
; <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.access_denied:
|
||
pop esi eax
|
||
mov [cd_appl_data],1
|
||
stc
|
||
ret
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.found:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp byte [esi-1], 0
|
||
jz .done
|
||
.nested:
|
||
mov eax,[cd_current_pointer_of_input]
|
||
push dword [eax+2]
|
||
pop dword [CDSectorAddress] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax,[eax+2+8] ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
jmp .mainloop
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.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]
|
||
cmp eax,0 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
je .next_sector
|
||
cmp ebp,CDDataBuf+2048 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?
|
||
jae .next_sector
|
||
movzx eax, byte [ebp]
|
||
add [cd_current_pointer_of_input_2],eax ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
add ebp,33 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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 '/' ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
je .done
|
||
cmp [esi],byte 0 ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
je .done
|
||
jmp .loop
|
||
.name_not_coincide:
|
||
pop edi eax esi
|
||
stc
|
||
ret
|
||
.done:
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
cmp [edi],word 3B00h ; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ';'
|
||
je .done_1
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
movzx eax,byte [ebp-33]
|
||
add eax,ebp
|
||
sub eax,34
|
||
cmp edi,eax
|
||
je .done_1
|
||
; <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
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
|
||
|
||
char_todown:
|
||
; convert character to uppercase, using cp866 encoding
|
||
; in: al=symbol
|
||
; out: al=converted symbol
|
||
cmp al, 'A'
|
||
jb .ret
|
||
cmp al, 'Z'
|
||
jbe .az
|
||
cmp al, '<27>'
|
||
jb .ret
|
||
cmp al, '<27>'
|
||
jb .rus1
|
||
cmp al, '<27>'
|
||
ja .ret
|
||
; 0x90-0x9F -> 0xE0-0xEF
|
||
add al, '<27>'-'<27>'
|
||
.ret:
|
||
ret
|
||
.rus1:
|
||
; 0x80-0x8F -> 0xA0-0xAF
|
||
.az:
|
||
add al, 0x20
|
||
ret
|
||
|
||
uni2ansi_char:
|
||
; convert UNICODE character in al to ANSI character in ax, using cp866 encoding
|
||
; in: ax=UNICODE character
|
||
; out: al=converted ANSI character
|
||
cmp ax, 0x80
|
||
jb .ascii
|
||
cmp ax, 0x401
|
||
jz .yo1
|
||
cmp ax, 0x451
|
||
jz .yo2
|
||
cmp ax, 0x410
|
||
jb .unk
|
||
cmp ax, 0x440
|
||
jb .rus1
|
||
cmp ax, 0x450
|
||
jb .rus2
|
||
.unk:
|
||
mov al, '_'
|
||
jmp .doit
|
||
.yo1:
|
||
mov al, '<27>'
|
||
jmp .doit
|
||
.yo2:
|
||
mov al, '<27>'
|
||
jmp .doit
|
||
.rus1:
|
||
; 0x410-0x43F -> 0x80-0xAF
|
||
add al, 0x70
|
||
jmp .doit
|
||
.rus2:
|
||
; 0x440-0x44F -> 0xE0-0xEF
|
||
add al, 0xA0
|
||
.ascii:
|
||
.doit:
|
||
ret
|