§ Описание

Ниже представлен код для ассемблера fasm, который распаковывает данные, сжатые через утилиту compress. Она в деталях немного отличается от того, что сжимает GIF. Размер словаря может быть до 256 Кб. Необходимо указать следующие параметры:
  • EBX — стартовый адрес байтовой последовательности (без заголовка LZW)
  • ECX — размер входного файла
  • EBP — адрес начала словаря, временная память
  • EDI — область памяти, куда распаковать
При указании ebx нужно обязательно пропустить 3 первых байта заголовка, где написано LZW.

§ Код на ассемблере

1LZW_decompress:
2
3        mov     [.size], ecx        ; Окончание потока
4        add     [.size], ebx
5        call    .init
6.rept:  cmp     ebx, [.size]
7        jnb     .end                ; Декомпрессия закончилась?
8        mov     cl, [.bitn]
9        mov     eax, [ebx]
10        shr     eax, cl             ; Сдвинуть на CL бит
11        and     eax, [.mask]        ; Срезать bitn бит
12        add     cl, [.bitk]         ; Передвинуть поток
13        mov     [.bitn], cl
14        and     [.bitn], byte 7     ; Запись в .bitn младших 3 бит
15        movzx   ecx, cl
16        shr     ecx, 3
17        add     ebx, ecx            ; Передвинуть EBX на (CL>>3)
18        cmp     eax, 100h
19        jb      .single             ; ax < 100h -- простой байт
20        je      .cmd                ; ax = 100h -- команда очистки словаря
21        sub     eax, 101h           ; Указатель на построенный словарь
22        cmp     edx, eax
23        jbe     .error              ; eax - указатель на словарь если edx <= eax, словарь превышен
24
25        ; СЛОВАРЬ (8 байт на 1 эл-т)
26        ; 4 | +0 | Количество символов
27        ; 4 | +4 | Указатель на строку для повторения
28        mov     ecx, [ebp + 8*eax + 0]  ; Длина последовательности
29        mov     esi, [ebp + 8*eax + 4]  ; Начало
30
31        ; Скопировать кол-во символов из предыдущего элемента и +1 к длине
32        ; Записать в следующий элемент текущий указатель EDI (построение словаря)
33        lea     eax, [ecx + 1]
34        mov     [ebp + 8*edx + 0], eax
35        mov     [ebp + 8*edx + 4], edi
36        rep     movsb
37        jmp     .next
38
39; Строительство нового словаря
40.single:
41
42        mov     [ebp + 8*edx + 0], dword 2  ; Добавить словарь: длина = 2
43        mov     [ebp + 8*edx + 4], edi      ; Текущий указатель на выходной поток
44        stosb   ; Скопировать один байт из входящего потока
45
46.next:  ; Добавляем +1 элемент к словарю и переходим далее
47        inc     edx
48        cmp     edx, [.topnext]
49        jb      .rept
50
51        ; .topnext = [100, 300, 700, F00, 1F00, 3F00, 7F00]
52        mov     eax, [.topnext]
53        add     eax, 100h
54        add     eax, eax
55        sub     eax, 100h
56        mov     [.topnext], eax
57        inc     byte [.bitk]
58
59        ; Установка новой маски (2^CH)-1
60        mov     cl, [.bitk]
61        mov     eax, 1
62        shl     eax, cl
63        dec     eax
64        mov     [.mask], eax
65        jmp     .rept
66
67        ; Выровнять указатель
68.cmd:   call    .init
69        and     ebx, 0xFFFFFF0
70        add     ebx, 10h
71        jmp     .rept
72
73        ; Сброс счетчиков и словаря
74.init:  mov     [.bitn], byte 0
75        mov     [.bitk], byte 9
76        mov     [.mask], dword 1FFh
77        mov     [.topnext], dword 100h
78        xor     edx, edx
79        ret
80
81.error: stc ; СF=1 Ошибка декомпрессии
82        ret
83.end:   clc ; СF=0 Распаковалось успешно
84        ret
85
86; ----------------------------------------------------------------------
87.bitn:       db 0            ; Текущий бит 0..7
88.bitk:       db 9            ; Количество бит
89.size:       dd 0            ; Размер входящего файла
90.topnext:    dd 100h         ; Следующий верхний предел словаря
91.mask:       dd 1FFh         ; Значение (1^.bitk)-1
92; ----------------------------------------------------------------------
93