Subversion Repositories Kolibri OS

Rev

Rev 89 | 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.         xor     ebx,ebx
  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. .cd_get_parameters_of_file:
  332.     mov   edi,[cd_mem_location]
  333. ; ïîëó÷àåì àòðèáóòû ôàéëà
  334.     xor   eax,eax
  335. ; ôàéë íå àðõèâèðîâàëñÿ
  336.     inc   al
  337.     shl   eax,1
  338. ; ýòî êàòàëîã?
  339.     test  [ebp-8],byte 2
  340.     jz    .file
  341.     inc   al
  342. .file:
  343. ; ìåòêà òîìà íå êàê â FAT, â ýòîì âèäå îòñóòñâóåò
  344. ; ôàéë íå ÿâëÿåòñÿ ñèñòåìíûì
  345.     shl   eax,3
  346. ; ôàéë ÿâëÿåòñÿ ñêðûòûì? (àòðèáóò ñóùåñòâîâàíèå)
  347.     test  [ebp-8],byte 1
  348.     jz    .hidden
  349.     inc   al
  350. .hidden:
  351.     shl   eax,1
  352. ; ôàéë âñåãäà òîëüêî äëÿ ÷òåíèÿ, òàê êàê ýòî CD
  353.     inc   al
  354.     mov   [edi],eax
  355. ; ïîëó÷àåì âðåìÿ äëÿ ôàéëà
  356. ;÷àñ
  357.     movzx eax,byte [ebp-12]
  358.     shl   eax,8
  359. ;ìèíóòà
  360.     mov   al,[ebp-11]
  361.     shl   eax,8
  362. ;ñåêóíäà
  363.     mov   al,[ebp-10]
  364. ;âðåìÿ ñîçäàíèÿ ôàéëà
  365.     mov   [edi+8],eax
  366. ;âðåìÿ ïîñëåäíåãî äîñòóïà
  367.     mov   [edi+16],eax
  368. ;âðåìÿ ïîñëåäíåé çàïèñè
  369.     mov   [edi+24],eax
  370. ; ïîëó÷àåì äàòó äëÿ ôàéëà
  371. ;ãîä
  372.     movzx eax,byte [ebp-15]
  373.     add   eax,1900
  374.     shl   eax,8
  375. ;ìåñÿö
  376.     mov   al,[ebp-14]
  377.     shl   eax,8
  378. ;äåíü
  379.     mov   al,[ebp-13]
  380. ;äàòà ñîçäàíèÿ ôàéëà
  381.     mov   [edi+12],eax
  382. ;âðåìÿ ïîñëåäíåãî äîñòóïà
  383.     mov   [edi+20],eax
  384. ;âðåìÿ ïîñëåäíåé çàïèñè
  385.     mov   [edi+28],eax
  386. ; ïîëó÷àåì òèï äàííûõ èìåíè
  387.     xor   eax,eax
  388.     test   dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE
  389.     jnz    .unicode_1
  390.     mov    [edi+4],eax
  391.     jmp   @f
  392. .unicode_1:
  393.     inc    eax
  394.     mov    [edi+4],eax
  395. @@:
  396. ; ïîëó÷àåì ðàçìåð ôàéëà â áàéòàõ
  397.     xor   eax,eax
  398.     mov   [edi+32+4],eax
  399.     mov   eax,[ebp-23]
  400.     mov   [edi+32],eax
  401.     ret
  402.  
  403. .end_buffer:
  404.     pop   edx edi esi eax
  405.     ret
  406.        
  407. cd_find_lfn:
  408. ; in: esi->name
  409. ; out: CF=1 - file not found
  410. ;      else CF=0 and [cd_current_pointer_of_input] direntry
  411.         push eax esi
  412. ; 16 ñåêòîð íà÷àëî íàáîðà äåñêðèïòîðîâ òîìîâ
  413.         mov  [CDSectorAddress],dword 15
  414. .start:
  415.         inc  dword [CDSectorAddress]
  416.        mov  [CDDataBuf_pointer],CDDataBuf
  417.        call  ReadCDWRetr
  418.        cmp   [DevErrorCode],0
  419.        jne   .access_denied
  420. ; ïðîâåðêà íà âøèâîñòü
  421.         cmp  [CDDataBuf+1],dword 'CD00'
  422.         jne  .access_denied
  423.         cmp  [CDDataBuf+5],byte '1'
  424.         jne  .access_denied
  425. ; ñåêòîð ÿâëÿåòñÿ òåðìèíàòîðîì íàáîð äåñêðèïòîðîâ òîìîâ?
  426.         cmp  [CDDataBuf],byte 0xff
  427.         je  .access_denied        
  428. ; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì è óëó÷øåííûì äåñêðèïòîðîì òîìà?
  429.         cmp  [CDDataBuf],byte 0x2
  430.         jne  .start
  431. ; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì äåñêðèïòîðîì òîìà?
  432.         cmp  [CDDataBuf+6],byte 0x1
  433.         jne  .start
  434. ; ïàðàìåòðû root äèðåêòðîðèè
  435.         mov  eax,[CDDataBuf+0x9c+2] ; íà÷àëî root äèðåêòðîðèè
  436.         mov  [CDSectorAddress],eax
  437.         mov  eax,[CDDataBuf+0x9c+10] ; ðàçìåð root äèðåêòðîðèè
  438.         cmp    byte [esi], 0
  439.         jnz    @f
  440.         mov   [cd_current_pointer_of_input],CDDataBuf+0x9c
  441.         jmp   .done
  442. @@:
  443. ; íà÷èíàåì ïîèñê
  444. .mainloop:
  445.         dec  dword [CDSectorAddress]
  446. .read_to_buffer:
  447.         inc  dword [CDSectorAddress]
  448.         mov  [CDDataBuf_pointer],CDDataBuf
  449.         call ReadCDWRetr         ; ÷èòàåì ñåêòîð äèðåêòîðèè
  450.         cmp   [DevErrorCode],0
  451.         jne   .access_denied
  452.         call cd_find_name_in_buffer
  453.         jnc    .found
  454.         sub  eax,2048
  455. ; äèðåêòîðèÿ çàêîí÷èëàñü?
  456.         cmp  eax,0
  457.         jg   .read_to_buffer
  458. ; íåò èñêîìîãî ýëåìåíòà öåïî÷êè
  459. .access_denied:
  460.         pop  esi eax
  461.         stc
  462.         ret
  463. ; èñêîìûé ýëåìåíò öåïî÷êè íàéäåí
  464.   .found:
  465. ; êîíåö ïóòè ôàéëà
  466.         cmp    byte [esi], 0
  467.         jz    .done
  468.         mov    eax,[cd_current_pointer_of_input]
  469.         add    eax,2
  470.         mov    eax,[eax]
  471.         mov    [CDSectorAddress],eax ; íà÷àëî äèðåêòîðèè
  472.         add    eax,8
  473.         mov    eax,[eax]  ; ðàçìåð äèðåêòîðèè
  474.         jmp    .mainloop
  475. ; óêàçàòåëü ôàéëà íàéäåí
  476.    .done:
  477.         pop  esi eax
  478.         clc
  479.         ret
  480.        
  481. cd_find_name_in_buffer:
  482.         mov     [cd_current_pointer_of_input_2],CDDataBuf
  483. .start:
  484.         call    cd_get_name
  485.         jc    .not_found
  486.         call    cd_compare_name
  487.         jc    .start
  488. .found:
  489.         clc
  490.         ret  
  491. .not_found:
  492.         stc
  493.         ret
  494.  
  495. cd_get_name:
  496.         push eax
  497.         mov   ebp,[cd_current_pointer_of_input_2]
  498.         mov   [cd_current_pointer_of_input],ebp
  499.         mov   eax,[ebp]
  500.         cmp   eax,0   ; âõîäû çàêîí÷èëèñü?
  501.         je    .next_sector
  502.         cmp   ebp,CDDataBuf+2048     ; áóôåð çàêîí÷èëñÿ?
  503.         jae   .next_sector
  504.         movzx eax, byte [ebp]
  505.         add   [cd_current_pointer_of_input_2],eax ; ñëåäóþùèé âõîä êàòàëîãà
  506.         add   ebp,33 ; óêàçàòåëü óñòàíîâëåí íà íà÷àëî èìåíè
  507.         pop   eax
  508.         clc
  509.         ret
  510. .next_sector:
  511.         pop  eax
  512.         stc
  513.         ret
  514.  
  515. cd_compare_name:
  516. ; compares ASCIIZ-names, case-insensitive (cp866 encoding)
  517. ; in: esi->name, ebp->name
  518. ; out: if names match: ZF=1 and esi->next component of name
  519. ;      else: ZF=0, esi is not changed
  520. ; destroys eax
  521.     push    esi eax edi
  522.     mov     edi,ebp
  523. .loop:
  524.     cld
  525.     lodsb
  526.     push ax
  527.     call char_toupper
  528.     call ansi2uni_char
  529.     xchg ah,al
  530.     cld
  531.     scasw
  532.     pop  ax
  533.     je    .coincides
  534.     call char_todown
  535.     call ansi2uni_char
  536.     xchg ah,al
  537.     cld  
  538.     sub  edi,2
  539.     scasw
  540.     jne   .name_not_coincide
  541. .coincides:
  542.     cmp   [esi],byte '/'  ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà
  543.     je   .done
  544.     cmp   [esi],byte 0  ; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà
  545.     je   .done
  546.     jmp   .loop
  547. .name_not_coincide:
  548.     pop    edi eax esi
  549.     stc
  550.     ret
  551. .done:
  552. ; ïðîâåðêà êîíöà ôàéëà
  553.     cmp   [edi],word 3B00h ; ñåïàðàòîð êîíöà ôàéëà ';'
  554.     je   .done_1
  555. ; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì
  556.     movzx   eax,byte [ebp-33]
  557.     add   eax,ebp
  558.     sub   eax,34
  559.     cmp   edi,eax
  560.     je   .done_1
  561. ; ïðîâåðêà êîíöà ïàïêè
  562.     movzx   eax,byte [ebp-1]
  563.     add   eax,ebp
  564.     cmp   edi,eax
  565.     jne   .name_not_coincide
  566. .done_1:
  567.     pop   edi eax
  568.     add   esp,4
  569.     inc   esi
  570.     clc
  571.     ret
  572.    
  573. char_todown:
  574. ; convert character to uppercase, using cp866 encoding
  575. ; in: al=symbol
  576. ; out: al=converted symbol
  577.         cmp     al, 'A'
  578.         jb      .ret
  579.         cmp     al, 'Z'
  580.         jbe     .az
  581.         cmp     al, '€'
  582.         jb      .ret
  583.         cmp     al, ''
  584.         jb      .rus1
  585.         cmp     al, 'Ÿ'
  586.         ja      .ret
  587. ; 0x90-0x9F -> 0xE0-0xEF
  588.         add     al, 'à'-''
  589. .ret:
  590.         ret
  591. .rus1:
  592. ; 0x80-0x8F -> 0xA0-0xAF
  593. .az:
  594.         add     al, 0x20
  595.         ret
  596.        
  597. uni2ansi_char:
  598. ; convert UNICODE character in al to ANSI character in ax, using cp866 encoding
  599. ; in: ax=UNICODE character
  600. ; out: al=converted ANSI character
  601.         cmp     ax, 0x80
  602.         jb      .ascii
  603.         cmp     ax, 0x401
  604.         jz      .yo1
  605.         cmp     ax, 0x451
  606.         jz      .yo2
  607.         cmp     ax, 0x410
  608.         jb      .unk
  609.         cmp     ax, 0x440
  610.         jb      .rus1
  611.         cmp     ax, 0x450
  612.         jb      .rus2
  613. .unk:
  614.         mov     al, '_'
  615.         jmp     .doit
  616. .yo1:
  617.         mov     al, 'ð'
  618.         jmp     .doit
  619. .yo2:
  620.         mov     al, 'ñ'
  621.         jmp     .doit
  622. .rus1:
  623. ; 0x410-0x43F -> 0x80-0xAF
  624.         add     al, 0x70
  625.         jmp     .doit
  626. .rus2:
  627. ; 0x440-0x44F -> 0xE0-0xEF
  628.         add     al, 0xA0
  629. .ascii:
  630. .doit:
  631.         ret
  632.