Subversion Repositories Kolibri OS

Rev

Rev 90 | Rev 95 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
94 mario79 1
 
87 mario79 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
 
9
10
 
11
12
 
13
    cmp   [cd_status],0
14
    je    reserve_ok2
15
16
 
17
    call  change_task
18
    jmp   reserve_hd1
19
20
 
21
22
 
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
 
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
 
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
 
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
 
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]
89 diamond 229
        mov     eax,ERROR_SUCCESS
87 mario79 230
        ret
231
232
 
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
90 mario79 280
    add   [cd_mem_location],304
87 mario79 281
    jmp   .get_names_from_buffer_1
282
283
 
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
 
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
90 mario79 317
    add   [cd_mem_location],560
87 mario79 318
    jmp   .get_names_from_buffer_1
319
320
 
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
 
90 mario79 332
    pop   edx edi esi eax
333
    ret
334
335
 
336
    mov   edi,[cd_mem_location]
87 mario79 337
cd_get_parameters_of_file_1:
90 mario79 338
; получаем атрибуты файла
87 mario79 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
 
90 mario79 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
 
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
 
94 mario79 446
;
447
;  fs_CdExecute - LFN variant for executing from CD
448
;
449
;  esi  points to hd filename (e.g. 'dir1/name')
450
;  ebp  points to full filename (e.g. '/hd0/1/dir1/name')
451
;  dword [ebx] = flags
452
;  dword [ebx+4] = cmdline
453
;
454
;  ret ebx,edx destroyed
455
;      eax > 0 - PID, < 0 - error
456
;
457
;--------------------------------------------------------------
458
fs_CdExecute:
459
        mov     edx, [ebx]
460
        mov     ebx, [ebx+4]
461
        test    ebx, ebx
462
        jz      @f
463
        add     ebx, std_application_base_address
464
@@:
465
466
 
467
;
468
; fs_CdExecute.flags - second entry
469
;
470
;  esi  points to floppy filename (kernel address)
471
;  ebp  points to full filename
472
;  edx  flags
473
;  ebx  cmdline (kernel address)
474
;
475
;  ret  eax > 0 - PID, < 0 - error
476
;
477
;--------------------------------------------------------------
478
479
 
480
        cmp     byte [esi], 0
481
        jnz     @f
482
; cannot execute root!
483
        mov     eax, -ERROR_ACCESS_DENIED
484
        ret
485
@@:
486
        push    edi
487
        call    cd_find_lfn
488
        jnc     .found
489
        pop     edi
490
        mov     eax, -ERROR_FILE_NOT_FOUND
491
        cmp     [DevErrorCode], 0
492
        jz      @f
493
        mov     al, -11
494
@@:
495
        ret
496
.found:
497
        mov     edi,[cd_current_pointer_of_input]
498
        mov    eax,[edi+2]
499
        push    0
500
        push    eax
501
        push    dword [edi+10]          ; size
502
        push    .DoRead
503
        call    fs_execute
504
        add     esp, 16
505
        pop     edi
506
        ret
507
508
 
509
; read next block
510
; in: eax->parameters, edi->buffer
511
; out: eax = error code
512
        pushad
513
        cmp     dword [eax], 0  ; file size
514
        jz      .eof
515
        cmp     [eax+8],dword 0
516
        jne     @f
517
        mov     ecx,[eax+4]
518
        inc     dword [eax+4]
519
        mov     [CDSectorAddress],ecx
520
        mov     [CDDataBuf_pointer],CDDataBuf  ;edi
521
        call    ReadCDWRetr
522
        cmp     [DevErrorCode], 0
523
        jnz     .err
524
@@:
525
        push    esi edi ecx
526
        mov     esi,512
527
        imul    esi,[eax+8]
528
        add     esi,CDDataBuf
529
        mov     ecx,512/4
530
        cld
531
        rep     movsd
532
        pop     ecx edi esi
533
534
 
535
        mov     ecx, [eax]
536
        sub     ecx, 512
537
        jae     @f
538
        lea     edi, [edi+ecx+512]
539
        neg     ecx
540
        push    eax
541
        xor     eax, eax
542
        rep     stosb
543
        pop     eax
544
@@:
545
        mov     [eax], ecx
546
        mov     edx, [eax+8]
547
        inc     edx
548
        cmp     edx, 4  ; 2048/512=4
549
        jb      @f
550
        xor     edx, edx
551
@@:
552
        mov     [eax+8], edx
553
        popad
554
        xor     eax, eax
555
        ret
556
.eof:
557
        popad
558
        mov     eax, 6
559
        ret
560
.err:
561
        popad
562
        mov     eax, 11
563
        ret
564
565
 
87 mario79 566
; in: esi->name
567
; out: CF=1 - file not found
568
;      else CF=0 and [cd_current_pointer_of_input] direntry
569
        push eax esi
570
; 16 сектор начало набора дескрипторов томов
571
        mov  [CDSectorAddress],dword 15
572
.start:
573
        inc  dword [CDSectorAddress]
574
       mov  [CDDataBuf_pointer],CDDataBuf
575
       call  ReadCDWRetr
576
       cmp   [DevErrorCode],0
577
       jne   .access_denied
578
; проверка на вшивость
579
        cmp  [CDDataBuf+1],dword 'CD00'
580
        jne  .access_denied
581
        cmp  [CDDataBuf+5],byte '1'
582
        jne  .access_denied
583
; сектор является терминатором набор дескрипторов томов?
584
        cmp  [CDDataBuf],byte 0xff
585
        je  .access_denied
586
; сектор является дополнительным и улучшенным дескриптором тома?
587
        cmp  [CDDataBuf],byte 0x2
588
        jne  .start
589
; сектор является дополнительным дескриптором тома?
590
        cmp  [CDDataBuf+6],byte 0x1
591
        jne  .start
592
; параметры root директрории
593
        mov  eax,[CDDataBuf+0x9c+2] ; начало root директрории
594
        mov  [CDSectorAddress],eax
595
        mov  eax,[CDDataBuf+0x9c+10] ; размер root директрории
596
        cmp    byte [esi], 0
597
        jnz    @f
598
        mov   [cd_current_pointer_of_input],CDDataBuf+0x9c
599
        jmp   .done
600
@@:
601
; начинаем поиск
602
.mainloop:
603
        dec  dword [CDSectorAddress]
604
.read_to_buffer:
605
        inc  dword [CDSectorAddress]
606
        mov  [CDDataBuf_pointer],CDDataBuf
607
        call ReadCDWRetr         ; читаем сектор директории
608
        cmp   [DevErrorCode],0
609
        jne   .access_denied
610
        call cd_find_name_in_buffer
611
        jnc    .found
612
        sub  eax,2048
613
; директория закончилась?
614
        cmp  eax,0
615
        jg   .read_to_buffer
616
; нет искомого элемента цепочки
617
.access_denied:
618
        pop  esi eax
619
        stc
620
        ret
621
; искомый элемент цепочки найден
622
  .found:
623
; конец пути файла
624
        cmp    byte [esi-1], 0
94 mario79 625
        jz    .done
87 mario79 626
        mov    eax,[cd_current_pointer_of_input]
627
        add    eax,2
628
        mov    eax,[eax]
629
        mov    [CDSectorAddress],eax ; начало директории
630
        add    eax,8
631
        mov    eax,[eax]  ; размер директории
632
        jmp    .mainloop
633
; указатель файла найден
634
   .done:
635
        pop  esi eax
636
        clc
637
        ret
638
639
 
640
        mov     [cd_current_pointer_of_input_2],CDDataBuf
641
.start:
642
        call    cd_get_name
643
        jc    .not_found
644
        call    cd_compare_name
645
        jc    .start
646
.found:
647
        clc
648
        ret
649
.not_found:
650
        stc
651
        ret
652
653
 
654
        push eax
655
        mov   ebp,[cd_current_pointer_of_input_2]
656
        mov   [cd_current_pointer_of_input],ebp
657
        mov   eax,[ebp]
658
        cmp   eax,0   ; входы закончились?
659
        je    .next_sector
660
        cmp   ebp,CDDataBuf+2048     ; буфер закончился?
661
        jae   .next_sector
662
        movzx eax, byte [ebp]
663
        add   [cd_current_pointer_of_input_2],eax ; следующий вход каталога
664
        add   ebp,33 ; указатель установлен на начало имени
665
        pop   eax
666
        clc
667
        ret
668
.next_sector:
669
        pop  eax
670
        stc
671
        ret
672
673
 
674
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
675
; in: esi->name, ebp->name
676
; out: if names match: ZF=1 and esi->next component of name
677
;      else: ZF=0, esi is not changed
678
; destroys eax
679
    push    esi eax edi
680
    mov     edi,ebp
681
.loop:
682
    cld
683
    lodsb
684
    push ax
685
    call char_toupper
686
    call ansi2uni_char
687
    xchg ah,al
688
    cld
689
    scasw
690
    pop  ax
691
    je    .coincides
692
    call char_todown
693
    call ansi2uni_char
694
    xchg ah,al
695
    cld
696
    sub  edi,2
697
    scasw
698
    jne   .name_not_coincide
699
.coincides:
700
    cmp   [esi],byte '/'  ; разделитель пути, конец имени текущего элемента
701
    je   .done
702
    cmp   [esi],byte 0  ; разделитель пути, конец имени текущего элемента
703
    je   .done
704
    jmp   .loop
705
.name_not_coincide:
706
    pop    edi eax esi
707
    stc
708
    ret
709
.done:
710
; проверка конца файла
711
    cmp   [edi],word 3B00h ; сепаратор конца файла ';'
712
    je   .done_1
713
; проверка для файлов не заканчивающихся сепаратором
714
    movzx   eax,byte [ebp-33]
715
    add   eax,ebp
716
    sub   eax,34
717
    cmp   edi,eax
718
    je   .done_1
719
; проверка конца папки
720
    movzx   eax,byte [ebp-1]
721
    add   eax,ebp
722
    cmp   edi,eax
723
    jne   .name_not_coincide
724
.done_1:
725
    pop   edi eax
726
    add   esp,4
727
    inc   esi
728
    clc
729
    ret
730
731
 
732
; convert character to uppercase, using cp866 encoding
733
; in: al=symbol
734
; out: al=converted symbol
735
        cmp     al, 'A'
736
        jb      .ret
737
        cmp     al, 'Z'
738
        jbe     .az
739
        cmp     al, 'Ђ'
740
        jb      .ret
741
        cmp     al, 'ђ'
742
        jb      .rus1
743
        cmp     al, 'џ'
744
        ja      .ret
745
; 0x90-0x9F -> 0xE0-0xEF
746
        add     al, 'а'-'ђ'
747
.ret:
748
        ret
749
.rus1:
750
; 0x80-0x8F -> 0xA0-0xAF
751
.az:
752
        add     al, 0x20
753
        ret
754
755
 
756
; convert UNICODE character in al to ANSI character in ax, using cp866 encoding
757
; in: ax=UNICODE character
758
; out: al=converted ANSI character
759
        cmp     ax, 0x80
760
        jb      .ascii
761
        cmp     ax, 0x401
762
        jz      .yo1
763
        cmp     ax, 0x451
764
        jz      .yo2
765
        cmp     ax, 0x410
766
        jb      .unk
767
        cmp     ax, 0x440
768
        jb      .rus1
769
        cmp     ax, 0x450
770
        jb      .rus2
771
.unk:
772
        mov     al, '_'
773
        jmp     .doit
774
.yo1:
775
        mov     al, 'р'
776
        jmp     .doit
777
.yo2:
778
        mov     al, 'с'
779
        jmp     .doit
780
.rus1:
781
; 0x410-0x43F -> 0x80-0xAF
782
        add     al, 0x70
783
        jmp     .doit
784
.rus2:
785
; 0x440-0x44F -> 0xE0-0xEF
786
        add     al, 0xA0
787
.ascii:
788
.doit:
789
        ret
790