Subversion Repositories Kolibri OS

Rev

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

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