Лисья Нора

Оглавление


§ Описание

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

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

LZW_decompress:
 
mov [.size], ecx ; Окончание потока
add [.size], ebx
call .init
.rept: cmp ebx, [.size]
jnb .end ; Декомпрессия закончилась?
mov cl, [.bitn]
mov eax, [ebx]
shr eax, cl ; Сдвинуть на CL бит
and eax, [.mask] ; Срезать bitn бит
add cl, [.bitk] ; Передвинуть поток
mov [.bitn], cl
and [.bitn], byte 7 ; Запись в .bitn младших 3 бит
movzx ecx, cl
shr ecx, 3
add ebx, ecx ; Передвинуть EBX на (CL>>3)
cmp eax, 100h
jb .single ; ax < 100h -- простой байт
je .cmd ; ax = 100h -- команда очистки словаря
sub eax, 101h ; Указатель на построенный словарь
cmp edx, eax
jbe .error ; eax - указатель на словарь если edx <= eax, словарь превышен
 
; СЛОВАРЬ (8 байт на 1 эл-т)
; 4 | +0 | Количество символов
; 4 | +4 | Указатель на строку для повторения
mov ecx, [ebp + 8*eax + 0] ; Длина последовательности
mov esi, [ebp + 8*eax + 4] ; Начало
 
; Скопировать кол-во символов из предыдущего элемента и +1 к длине
; Записать в следующий элемент текущий указатель EDI (построение словаря)
lea eax, [ecx + 1]
mov [ebp + 8*edx + 0], eax
mov [ebp + 8*edx + 4], edi
rep movsb
jmp .next
 
; Строительство нового словаря
.single:
 
mov [ebp + 8*edx + 0], dword 2 ; Добавить словарь: длина = 2
mov [ebp + 8*edx + 4], edi ; Текущий указатель на выходной поток
stosb ; Скопировать один байт из входящего потока
 
.next: ; Добавляем +1 элемент к словарю и переходим далее
inc edx
cmp edx, [.topnext]
jb .rept
 
; .topnext = [100, 300, 700, F00, 1F00, 3F00, 7F00]
mov eax, [.topnext]
add eax, 100h
add eax, eax
sub eax, 100h
mov [.topnext], eax
inc byte [.bitk]
 
; Установка новой маски (2^CH)-1
mov cl, [.bitk]
mov eax, 1
shl eax, cl
dec eax
mov [.mask], eax
jmp .rept
 
; Выровнять указатель
.cmd: call .init
and ebx, 0xFFFFFF0
add ebx, 10h
jmp .rept
 
; Сброс счетчиков и словаря
.init: mov [.bitn], byte 0
mov [.bitk], byte 9
mov [.mask], dword 1FFh
mov [.topnext], dword 100h
xor edx, edx
ret
 
.error: stc ; СF=1 Ошибка декомпрессии
ret
.end: clc ; СF=0 Распаковалось успешно
ret
 
; ----------------------------------------------------------------------
.bitn: db 0 ; Текущий бит 0..7
.bitk: db 9 ; Количество бит
.size: dd 0 ; Размер входящего файла
.topnext: dd 100h ; Следующий верхний предел словаря
.mask: dd 1FFh ; Значение (1^.bitk)-1
; ----------------------------------------------------------------------