Subversion Repositories Kolibri OS

Rev

Rev 89 | Rev 94 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. uglobal
  2. cd_current_pointer_of_input    dd  0
  3. cd_current_pointer_of_input_2  dd  0
  4. cd_mem_location                dd  0
  5. cd_counter_block               dd  0
  6. endg
  7.  
  8. CDDataBuf equ 0x7000
  9.  
  10. reserve_cd:
  11.  
  12.     cli
  13.     cmp   [cd_status],0
  14.     je    reserve_ok2
  15.  
  16.     sti
  17.     call  change_task
  18.     jmp   reserve_hd1
  19.  
  20.   reserve_ok2:
  21.  
  22.     push  eax
  23.     mov   eax,[0x3000]
  24.     shl   eax,5
  25.     mov   eax,[eax+0x3000+4]
  26.     mov   [cd_status],eax
  27.     pop   eax
  28.     sti
  29.     ret
  30.    
  31. cd_status dd 0
  32.  
  33. ;----------------------------------------------------------------
  34. ;
  35. ;  fs_CdRead - LFN variant for reading CD disk
  36. ;
  37. ;  esi  points to filename /dir1/dir2/.../dirn/file,0
  38. ;  ebx  pointer to 64-bit number = first wanted byte, 0+
  39. ;       may be ebx=0 - start from first byte
  40. ;  ecx  number of bytes to read, 0+
  41. ;  edx  mem location to return data
  42. ;
  43. ;  ret ebx = bytes read or 0xffffffff file not found
  44. ;      eax = 0 ok read or other = errormsg
  45. ;
  46. ;--------------------------------------------------------------
  47. fs_CdRead:
  48.     push    edi
  49.     cmp    byte [esi], 0
  50.     jnz    @f
  51. .noaccess:
  52.     pop    edi
  53. .noaccess_2:
  54.     or    ebx, -1
  55.     mov    eax, ERROR_ACCESS_DENIED
  56.     ret
  57.  
  58. .noaccess_3:
  59.     pop     eax edx ecx edi
  60.     jmp  .noaccess_2
  61.  
  62. @@:
  63.     call    cd_find_lfn
  64.     jnc    .found
  65.     pop    edi
  66.     cmp   [DevErrorCode],0
  67.     jne   .noaccess_2
  68.     or    ebx, -1
  69.     mov    eax, ERROR_FILE_NOT_FOUND
  70.     ret
  71.  
  72. .found:
  73.     mov    edi,[cd_current_pointer_of_input]
  74.     test   byte [edi+25],10b    ; do not allow read directories
  75.     jnz    .noaccess
  76.     test    ebx, ebx
  77.     jz    .l1
  78.     cmp    dword [ebx+4], 0
  79.     jz    @f
  80.         xor     ebx, ebx
  81. .reteof:
  82.     mov    eax, 6 ; end of file
  83.     pop    edi
  84.     ret
  85. @@:
  86.     mov    ebx, [ebx]
  87. .l1:
  88.         push    ecx edx
  89.         push    0
  90.         mov     eax, [edi+10] ; ðåàëüíûé ðàçìåð ôàéëîâîé ñåêöèè
  91.         sub     eax, ebx
  92.         jb      .eof
  93.         cmp     eax, ecx
  94.         jae     @f
  95.         mov     ecx, eax
  96.         mov     byte [esp], 6
  97. @@:
  98.      mov    eax,[edi+2]
  99.      mov    [CDSectorAddress],eax
  100. ; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
  101. .new_sector:
  102.     test    ecx, ecx
  103.     jz    .done
  104.     sub    ebx, 2048
  105.     jae    .new_sector
  106.     add    ebx, 2048
  107.     jnz    .incomplete_sector
  108.     cmp    ecx, 2048
  109.     jb    .incomplete_sector
  110. ; we may read and memmove complete sector
  111.     mov  [CDDataBuf_pointer],edx
  112.     call ReadCDWRetr      ; ÷èòàåì ñåêòîð ôàéëà
  113.     cmp   [DevErrorCode],0
  114.     jne   .noaccess_3
  115.     inc  dword [CDSectorAddress]
  116.     add    edx, 2048
  117.     sub    ecx, 2048
  118.     jmp    .new_sector
  119. .incomplete_sector:
  120. ; we must read and memmove incomplete sector
  121.     mov  [CDDataBuf_pointer],CDDataBuf
  122.     call ReadCDWRetr      ; ÷èòàåì ñåêòîð ôàéëà
  123.     cmp   [DevErrorCode],0
  124.     jne   .noaccess_3
  125.     inc  dword [CDSectorAddress]
  126.     mov    eax,CDDataBuf
  127.     add    eax, ebx
  128.     push    ecx
  129.     add    ecx, ebx
  130.     cmp    ecx, 2048
  131.     jbe    @f
  132.     mov    ecx, 2048
  133. @@:
  134.     sub    ecx, ebx
  135.      push edi esi ecx
  136.      mov edi,edx
  137.      mov esi,eax ;0x7000   ; CD data buffer
  138.      cld
  139.      rep movsb
  140.      pop ecx esi edi
  141.     add    edx, ecx
  142.     sub    [esp], ecx
  143.     pop    ecx
  144.     xor    ebx, ebx
  145.     jmp    .new_sector
  146.      
  147. .done:
  148.         mov     ebx, edx
  149.         pop     eax edx ecx edi
  150.         sub     ebx, edx
  151.         ret
  152. .eof:
  153.         mov     ebx, edx
  154.         pop     eax edx ecx
  155.         sub     ebx, edx
  156.         jmp     .reteof
  157.  
  158. ;----------------------------------------------------------------
  159. ;
  160. ;  fs_CdReadFolder - LFN variant for reading CD disk folder
  161. ;
  162. ;  esi  points to filename  /dir1/dir2/.../dirn/file,0
  163. ;  ebx  pointer to structure 32-bit number = first wanted block, 0+
  164. ;                          & flags (bitfields)
  165. ; flags: bit 0: 0=ANSI names, 1=UNICODE names
  166. ;  ecx  number of blocks to read, 0+
  167. ;  edx  mem location to return data
  168. ;
  169. ;  ret ebx = blocks read or 0xffffffff folder not found
  170. ;      eax = 0 ok read or other = errormsg
  171. ;
  172. ;--------------------------------------------------------------
  173. fs_CdReadFolder:
  174.         push    edi
  175.         call    cd_find_lfn
  176.         jnc     .found
  177.         pop     edi
  178.         cmp   [DevErrorCode],0
  179.         jne     .noaccess_1
  180.         or      ebx, -1
  181.         mov     eax, ERROR_FILE_NOT_FOUND
  182.         ret
  183. .found:
  184.         mov    edi,[cd_current_pointer_of_input]
  185.         test   byte [edi+25],10b    ; do not allow read directories
  186.         jnz     .found_dir
  187.         pop     edi
  188. .noaccess_1:
  189.         or      ebx, -1
  190.         mov     eax, ERROR_ACCESS_DENIED
  191.         ret
  192. .found_dir:
  193.         mov    eax,[edi+2]    ; eax=cluster
  194.         mov    [CDSectorAddress],eax
  195.         mov    eax,[edi+10] ; ðàçìåð äèðåêòðîðèè
  196. .doit:
  197. ; init header
  198.         push    eax ecx
  199.         mov     edi, edx
  200.         mov     ecx, 32/4
  201.         xor     eax, eax
  202.         rep     stosd
  203.         pop     ecx eax
  204.         mov     byte [edx], 1   ; version
  205.         mov     [cd_mem_location],edx
  206.         add     [cd_mem_location],32
  207. ; íà÷èíàåì ïåðåáðîñêó ÁÄÂÊ â ÓÑÂÊ
  208. ;.mainloop:
  209.         mov  [cd_counter_block],dword 0
  210.         dec  dword [CDSectorAddress]
  211.         push ecx
  212. .read_to_buffer:
  213.         inc  dword [CDSectorAddress]
  214.         mov  [CDDataBuf_pointer],CDDataBuf
  215.         call ReadCDWRetr         ; ÷èòàåì ñåêòîð äèðåêòîðèè
  216.         cmp   [DevErrorCode],0
  217.         jne   .noaccess_1
  218.         call .get_names_from_buffer
  219.         sub  eax,2048
  220. ; äèðåêòîðèÿ çàêîí÷èëàñü?
  221.         cmp  eax,0
  222.         jg   .read_to_buffer
  223.         mov   edi,[cd_counter_block]
  224.         mov   [edx+8],edi
  225.         mov   edi,[ebx]
  226.         sub   [edx+4],edi
  227.         pop     ecx edi
  228.         mov     ebx, [edx+4]
  229.         mov     eax,ERROR_SUCCESS
  230.         ret    
  231.    
  232. .get_names_from_buffer:
  233.     mov     [cd_current_pointer_of_input_2],CDDataBuf
  234.     push    eax esi edi edx
  235. .get_names_from_buffer_1:
  236.     call    cd_get_name
  237.     jc    .end_buffer
  238.     inc    dword [cd_counter_block]
  239.     mov    eax,[cd_counter_block]
  240.     cmp    [ebx],eax
  241.     jae     .get_names_from_buffer_1
  242.     test    ecx, ecx
  243.     jz    .get_names_from_buffer_1
  244.     mov   edi,[cd_counter_block]
  245.     mov   [edx+4],edi  
  246.     dec     ecx
  247.     mov   esi,ebp
  248.     mov   edi,[cd_mem_location]
  249.     add   edi,40
  250.     test   dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE
  251.     jnz    .unicode
  252. ;    jmp  .unicode
  253. .ansi:
  254.     cmp   [cd_counter_block],2
  255.     jbe   .ansi_parent_directory
  256.     cld
  257.     lodsw
  258.     xchg ah,al
  259.     call uni2ansi_char
  260.     cld
  261.     stosb
  262. ; ïðîâåðêà êîíöà ôàéëà
  263.     mov   al,[esi+1]
  264.     cmp   al,byte 3Bh ; ñåïàðàòîð êîíöà ôàéëà ';'
  265.     je   .cd_get_parameters_of_file_1
  266. ; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì
  267.     movzx   eax,byte [ebp-33]
  268.     add   eax,ebp
  269.     sub   eax,34
  270.     cmp   esi,eax
  271.     je   .cd_get_parameters_of_file_1
  272. ; ïðîâåðêà êîíöà ïàïêè
  273.     movzx   eax,byte [ebp-1]
  274.     add   eax,ebp
  275.     cmp   esi,eax
  276.     jb   .ansi
  277. .cd_get_parameters_of_file_1:
  278.     mov   [edi],byte 0
  279.     call  cd_get_parameters_of_file
  280.     add   [cd_mem_location],304
  281.     jmp   .get_names_from_buffer_1
  282.  
  283. .ansi_parent_directory:
  284.     cmp   [cd_counter_block],2
  285.     je    @f
  286.     mov   [edi],byte '.'
  287.     inc   edi
  288.     jmp  .cd_get_parameters_of_file_1
  289. @@:
  290.     mov   [edi],word '..'
  291.     add   edi,2
  292.     jmp  .cd_get_parameters_of_file_1
  293.  
  294. .unicode:
  295.     cmp   [cd_counter_block],2
  296.     jbe   .unicode_parent_directory
  297.     cld
  298.     movsw
  299. ; ïðîâåðêà êîíöà ôàéëà
  300.     mov   ax,[esi]
  301.     cmp   ax,word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';'
  302.     je   .cd_get_parameters_of_file_2
  303. ; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì
  304.     movzx   eax,byte [ebp-33]
  305.     add   eax,ebp
  306.     sub   eax,34
  307.     cmp   esi,eax
  308.     je   .cd_get_parameters_of_file_2
  309. ; ïðîâåðêà êîíöà ïàïêè
  310.     movzx   eax,byte [ebp-1]
  311.     add   eax,ebp
  312.     cmp   esi,eax
  313.     jb   .unicode
  314. .cd_get_parameters_of_file_2:
  315.     mov   [edi],word 0
  316.     call  cd_get_parameters_of_file
  317.     add   [cd_mem_location],560
  318.     jmp   .get_names_from_buffer_1
  319.  
  320. .unicode_parent_directory:
  321.     cmp   [cd_counter_block],2
  322.     je    @f
  323.     mov   [edi],word 2E00h ; '.'
  324.     add   edi,2
  325.     jmp   .cd_get_parameters_of_file_2
  326. @@:
  327.     mov   [edi],dword 2E002E00h ; '..'
  328.     add   edi,4
  329.     jmp   .cd_get_parameters_of_file_2
  330.  
  331. .end_buffer:
  332.     pop   edx edi esi eax
  333.     ret
  334.  
  335. cd_get_parameters_of_file:
  336.     mov   edi,[cd_mem_location]
  337. cd_get_parameters_of_file_1:
  338. ; ïîëó÷àåì àòðèáóòû ôàéëà
  339.     xor   eax,eax
  340. ; ôàéë íå àðõèâèðîâàëñÿ
  341.     inc   al
  342.     shl   eax,1
  343. ; ýòî êàòàëîã?
  344.     test  [ebp-8],byte 2
  345.     jz    .file
  346.     inc   al
  347. .file:
  348. ; ìåòêà òîìà íå êàê â FAT, â ýòîì âèäå îòñóòñâóåò
  349. ; ôàéë íå ÿâëÿåòñÿ ñèñòåìíûì
  350.     shl   eax,3
  351. ; ôàéë ÿâëÿåòñÿ ñêðûòûì? (àòðèáóò ñóùåñòâîâàíèå)
  352.     test  [ebp-8],byte 1
  353.     jz    .hidden
  354.     inc   al
  355. .hidden:
  356.     shl   eax,1
  357. ; ôàéë âñåãäà òîëüêî äëÿ ÷òåíèÿ, òàê êàê ýòî CD
  358.     inc   al
  359.     mov   [edi],eax
  360. ; ïîëó÷àåì âðåìÿ äëÿ ôàéëà
  361. ;÷àñ
  362.     movzx eax,byte [ebp-12]
  363.     shl   eax,8
  364. ;ìèíóòà
  365.     mov   al,[ebp-11]
  366.     shl   eax,8
  367. ;ñåêóíäà
  368.     mov   al,[ebp-10]
  369. ;âðåìÿ ñîçäàíèÿ ôàéëà
  370.     mov   [edi+8],eax
  371. ;âðåìÿ ïîñëåäíåãî äîñòóïà
  372.     mov   [edi+16],eax
  373. ;âðåìÿ ïîñëåäíåé çàïèñè
  374.     mov   [edi+24],eax
  375. ; ïîëó÷àåì äàòó äëÿ ôàéëà
  376. ;ãîä
  377.     movzx eax,byte [ebp-15]
  378.     add   eax,1900
  379.     shl   eax,8
  380. ;ìåñÿö
  381.     mov   al,[ebp-14]
  382.     shl   eax,8
  383. ;äåíü
  384.     mov   al,[ebp-13]
  385. ;äàòà ñîçäàíèÿ ôàéëà
  386.     mov   [edi+12],eax
  387. ;âðåìÿ ïîñëåäíåãî äîñòóïà
  388.     mov   [edi+20],eax
  389. ;âðåìÿ ïîñëåäíåé çàïèñè
  390.     mov   [edi+28],eax
  391. ; ïîëó÷àåì òèï äàííûõ èìåíè
  392.     xor   eax,eax
  393.     test   dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE
  394.     jnz    .unicode_1
  395.     mov    [edi+4],eax
  396.     jmp   @f
  397. .unicode_1:
  398.     inc    eax
  399.     mov    [edi+4],eax
  400. @@:
  401. ; ïîëó÷àåì ðàçìåð ôàéëà â áàéòàõ
  402.     xor   eax,eax
  403.     mov   [edi+32+4],eax
  404.     mov   eax,[ebp-23]
  405.     mov   [edi+32],eax
  406.     ret
  407.  
  408. ;----------------------------------------------------------------
  409. ;
  410. ;  fs_CdGetFileInfo - LFN variant for CD
  411. ;                     get file/directory attributes structure
  412. ;        
  413. ;----------------------------------------------------------------
  414. fs_CdGetFileInfo:
  415.         cmp     byte [esi], 0
  416.         jnz     @f
  417.         mov     eax, 2
  418.         ret
  419. @@:
  420.         push    edi ebp
  421.         call    cd_find_lfn
  422.         pushfd
  423.         cmp     [DevErrorCode], 0
  424.         jz      @f
  425.         popfd
  426.         pop     ebp edi
  427.         mov     eax, 11
  428.         ret
  429. @@:
  430.         popfd
  431.         jnc     @f
  432.         pop     ebp edi
  433.         mov     eax, ERROR_FILE_NOT_FOUND
  434.         ret
  435. @@:
  436.  
  437.         mov     edi, edx
  438.         call    cd_get_parameters_of_file_1
  439.         and     dword [edi+4], 0
  440.         pop     ebp
  441.         pop     ebp edi
  442.         xor     eax, eax
  443.         ret
  444.  
  445. cd_find_lfn:
  446. ; in: esi->name
  447. ; out: CF=1 - file not found
  448. ;      else CF=0 and [cd_current_pointer_of_input] direntry
  449.         push eax esi
  450. ; 16 ñåêòîð íà÷àëî íàáîðà äåñêðèïòîðîâ òîìîâ
  451.         mov  [CDSectorAddress],dword 15
  452. .start:
  453.         inc  dword [CDSectorAddress]
  454.        mov  [CDDataBuf_pointer],CDDataBuf
  455.        call  ReadCDWRetr
  456.        cmp   [DevErrorCode],0
  457.        jne   .access_denied
  458. ; ïðîâåðêà íà âøèâîñòü
  459.         cmp  [CDDataBuf+1],dword 'CD00'
  460.         jne  .access_denied
  461.         cmp  [CDDataBuf+5],byte '1'
  462.         jne  .access_denied
  463. ; ñåêòîð ÿâëÿåòñÿ òåðìèíàòîðîì íàáîð äåñêðèïòîðîâ òîìîâ?
  464.         cmp  [CDDataBuf],byte 0xff
  465.         je  .access_denied        
  466. ; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì è óëó÷øåííûì äåñêðèïòîðîì òîìà?
  467.         cmp  [CDDataBuf],byte 0x2
  468.         jne  .start
  469. ; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì äåñêðèïòîðîì òîìà?
  470.         cmp  [CDDataBuf+6],byte 0x1
  471.         jne  .start
  472. ; ïàðàìåòðû root äèðåêòðîðèè
  473.         mov  eax,[CDDataBuf+0x9c+2] ; íà÷àëî root äèðåêòðîðèè
  474.         mov  [CDSectorAddress],eax
  475.         mov  eax,[CDDataBuf+0x9c+10] ; ðàçìåð root äèðåêòðîðèè
  476.         cmp    byte [esi], 0
  477.         jnz    @f
  478.         mov   [cd_current_pointer_of_input],CDDataBuf+0x9c
  479.         jmp   .done
  480. @@:
  481. ; íà÷èíàåì ïîèñê
  482. .mainloop:
  483.         dec  dword [CDSectorAddress]
  484. .read_to_buffer:
  485.         inc  dword [CDSectorAddress]
  486.         mov  [CDDataBuf_pointer],CDDataBuf
  487.         call ReadCDWRetr         ; ÷èòàåì ñåêòîð äèðåêòîðèè
  488.         cmp   [DevErrorCode],0
  489.         jne   .access_denied
  490.         call cd_find_name_in_buffer
  491.         jnc    .found
  492.         sub  eax,2048
  493. ; äèðåêòîðèÿ çàêîí÷èëàñü?
  494.         cmp  eax,0
  495.         jg   .read_to_buffer
  496. ; íåò èñêîìîãî ýëåìåíòà öåïî÷êè
  497. .access_denied:
  498.         pop  esi eax
  499.         stc
  500.         ret
  501. ; èñêîìûé ýëåìåíò öåïî÷êè íàéäåí
  502.   .found:
  503. ; êîíåö ïóòè ôàéëà
  504.         cmp    byte [esi], 0
  505.         jz    .done
  506.         mov    eax,[cd_current_pointer_of_input]
  507.         add    eax,2
  508.         mov    eax,[eax]
  509.         mov    [CDSectorAddress],eax ; íà÷àëî äèðåêòîðèè
  510.         add    eax,8
  511.         mov    eax,[eax]  ; ðàçìåð äèðåêòîðèè
  512.         jmp    .mainloop
  513. ; óêàçàòåëü ôàéëà íàéäåí
  514.    .done:
  515.         pop  esi eax
  516.         clc
  517.         ret
  518.        
  519. cd_find_name_in_buffer:
  520.         mov     [cd_current_pointer_of_input_2],CDDataBuf
  521. .start:
  522.         call    cd_get_name
  523.         jc    .not_found
  524.         call    cd_compare_name
  525.         jc    .start
  526. .found:
  527.         clc
  528.         ret  
  529. .not_found:
  530.         stc
  531.         ret
  532.  
  533. cd_get_name:
  534.         push eax
  535.         mov   ebp,[cd_current_pointer_of_input_2]
  536.         mov   [cd_current_pointer_of_input],ebp
  537.         mov   eax,[ebp]
  538.         cmp   eax,0   ; âõîäû çàêîí÷èëèñü?
  539.         je    .next_sector
  540.         cmp   ebp,CDDataBuf+2048     ; áóôåð çàêîí÷èëñÿ?
  541.         jae   .next_sector
  542.         movzx eax, byte [ebp]
  543.         add   [cd_current_pointer_of_input_2],eax ; ñëåäóþùèé âõîä êàòàëîãà
  544.         add   ebp,33 ; óêàçàòåëü óñòàíîâëåí íà íà÷àëî èìåíè
  545.         pop   eax
  546.         clc
  547.         ret
  548. .next_sector:
  549.         pop  eax
  550.         stc
  551.         ret
  552.  
  553. cd_compare_name:
  554. ; compares ASCIIZ-names, case-insensitive (cp866 encoding)
  555. ; in: esi->name, ebp->name
  556. ; out: if names match: ZF=1 and esi->next component of name
  557. ;      else: ZF=0, esi is not changed
  558. ; destroys eax
  559.     push    esi eax edi
  560.     mov     edi,ebp
  561. .loop:
  562.     cld
  563.     lodsb
  564.     push ax
  565.     call char_toupper
  566.     call ansi2uni_char
  567.     xchg ah,al
  568.     cld
  569.     scasw
  570.     pop  ax
  571.     je    .coincides
  572.     call char_todown
  573.     call ansi2uni_char
  574.     xchg ah,al
  575.     cld  
  576.     sub  edi,2
  577.     scasw
  578.     jne   .name_not_coincide
  579. .coincides:
  580.     cmp   [esi],byte '/'  ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà
  581.     je   .done
  582.     cmp   [esi],byte 0  ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà
  583.     je   .done
  584.     jmp   .loop
  585. .name_not_coincide:
  586.     pop    edi eax esi
  587.     stc
  588.     ret
  589. .done:
  590. ; ïðîâåðêà êîíöà ôàéëà
  591.     cmp   [edi],word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';'
  592.     je   .done_1
  593. ; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì
  594.     movzx   eax,byte [ebp-33]
  595.     add   eax,ebp
  596.     sub   eax,34
  597.     cmp   edi,eax
  598.     je   .done_1
  599. ; ïðîâåðêà êîíöà ïàïêè
  600.     movzx   eax,byte [ebp-1]
  601.     add   eax,ebp
  602.     cmp   edi,eax
  603.     jne   .name_not_coincide
  604. .done_1:
  605.     pop   edi eax
  606.     add   esp,4
  607.     inc   esi
  608.     clc
  609.     ret
  610.    
  611. char_todown:
  612. ; convert character to uppercase, using cp866 encoding
  613. ; in: al=symbol
  614. ; out: al=converted symbol
  615.         cmp     al, 'A'
  616.         jb      .ret
  617.         cmp     al, 'Z'
  618.         jbe     .az
  619.         cmp     al, '€'
  620.         jb      .ret
  621.         cmp     al, ''
  622.         jb      .rus1
  623.         cmp     al, 'Ÿ'
  624.         ja      .ret
  625. ; 0x90-0x9F -> 0xE0-0xEF
  626.         add     al, 'à'-''
  627. .ret:
  628.         ret
  629. .rus1:
  630. ; 0x80-0x8F -> 0xA0-0xAF
  631. .az:
  632.         add     al, 0x20
  633.         ret
  634.        
  635. uni2ansi_char:
  636. ; convert UNICODE character in al to ANSI character in ax, using cp866 encoding
  637. ; in: ax=UNICODE character
  638. ; out: al=converted ANSI character
  639.         cmp     ax, 0x80
  640.         jb      .ascii
  641.         cmp     ax, 0x401
  642.         jz      .yo1
  643.         cmp     ax, 0x451
  644.         jz      .yo2
  645.         cmp     ax, 0x410
  646.         jb      .unk
  647.         cmp     ax, 0x440
  648.         jb      .rus1
  649.         cmp     ax, 0x450
  650.         jb      .rus2
  651. .unk:
  652.         mov     al, '_'
  653.         jmp     .doit
  654. .yo1:
  655.         mov     al, 'ð'
  656.         jmp     .doit
  657. .yo2:
  658.         mov     al, 'ñ'
  659.         jmp     .doit
  660. .rus1:
  661. ; 0x410-0x43F -> 0x80-0xAF
  662.         add     al, 0x70
  663.         jmp     .doit
  664. .rus2:
  665. ; 0x440-0x44F -> 0xE0-0xEF
  666.         add     al, 0xA0
  667. .ascii:
  668. .doit:
  669.         ret
  670.