| ||||||||||||||||
|
Lempel-Ziv-Welch compression
by herm1t
See also the project folder
; By using this file, you agree to the terms and conditions set
; forth in the COPYING file which can be found at the top level
; of this distribution.
;
; Lempel-Ziv-Welch compression (c) herm1t@vx.netlux.org, 2006-04-19
;
; int lzw_compress(unsigned char *src, unsigned char *dst, int len, unsigned char *temp)
; int lzw_expand(unsigned char *src, unsigned char *dst, unsigned char *temp)
;
; Size of temp buffer
; Bits Compress Expand
; -----------------------------
; 14 90225 58143
; 13 45165 40136
; 12 25125 19083
;
BITS 32
CPU 386
global lzw_compress, lzw_expand
%define MAX_BITS 14
%if MAX_BITS == 14
%define TABLE_SIZE 18041
%endif
%if MAX_BITS == 13
%define TABLE_SIZE 9029
%endif
%if MAX_BITS <= 12
%define TABLE_SIZE 5021
%endif
%define HASHING_SHIFT (MAX_BITS - 8)
%define MAX_VALUE ((1 << MAX_BITS) - 1)
%define MAX_CODE (MAX_VALUE - 1)
%define pos [ebp + 0] ;4
%define buf [ebp + 4] ;4
%define next_code [ebp + 8] ;4
%define length [ebp + 12] ;4
%define save_esp [ebp + 16] ;4
%define append_character [ebp + 20] ;1*TABLE_SIZE
%define prefix_code [ebp + 20 + TABLE_SIZE] ;2*TABLE_SIZE
%define code_value [ebp + 20 + TABLE_SIZE * 3] ;2*TABLE_SIZE
%define decode_stack [ebp + 20 + TABLE_SIZE * 3] ;4000
lzw_compress: pusha
cld
mov ebp, [esp + 48]
mov save_esp, esp
mov eax, [esp + 40]
mov buf, eax
xor eax, eax
mov pos, eax
mov ecx, TABLE_SIZE
lea edi, code_value
dec eax
rep stosw
mov esi, [esp + 36]
mov dword next_code, 256
xor eax, eax
lodsb
mov edi, eax
mov ecx, [esp + 44]
mov length, ecx
dec ecx
.while: xor eax, eax
lodsb
push ecx
mov ecx, next_code
push eax
push eax
push edi
call find_match
mov ebx, eax
pop eax
lea edx, code_value
cmp [edx + ebx * 2], word -1
je .else
mov di, [edx + ebx * 2]
jmp .end_if
.else: cmp cx, MAX_CODE
ja .L2
lea edx, append_character
mov [edx + ebx], al
lea edx, prefix_code
mov [edx + ebx * 2], di
lea edx, code_value
mov [edx + ebx * 2], cx
inc ecx
.L2: push edi
call output_code
mov edi, eax
.end_if: mov next_code, ecx
pop ecx
loop .while
push edi
call output_code
push MAX_VALUE
call output_code
push ecx
call output_code
mov eax, pos
shr eax, 3
.error: mov [esp + 28], eax
popa
ret
output_code: pusha
mov eax, [esp + 36]
mov esi, buf
mov edx, pos
push MAX_BITS
pop ecx
.bit: rcr eax, 1
jnc .zero
bts [esi], edx
jmp .done
.zero: btr [esi], edx
.done: inc edx
loop .bit
mov pos, edx
shr edx, 3
cmp edx, length
jb .ok
mov esp, save_esp
xor eax, eax
jmp lzw_compress.error
.ok: popa
retn 4
find_match: pusha
mov eax, [esp + 36]
mov ebx, [esp + 40]
xor edx, edx
inc edx
mov ecx, ebx
shl ecx, HASHING_SHIFT
xor ecx, eax
or ecx, ecx
jz .fm_while
mov edx, TABLE_SIZE
sub edx, ecx
.fm_while: lea esi, code_value
cmp word [esi + ecx * 2], -1
je .fm_done
lea esi, prefix_code
cmp [esi + ecx * 2], ax
jne .fm_L1
lea esi, append_character
cmp [esi + ecx], bl
je .fm_done
.fm_L1: sub ecx, edx
jns .fm_while
add ecx, TABLE_SIZE
jmp .fm_while
.fm_done: mov [esp + 28], ecx
popa
retn 8
lzw_expand: pusha
cld
mov esi, [esp + 36]
mov edi, [esp + 40]
mov ebp, [esp + 44]
mov buf, esi
xor eax, eax
mov pos, eax
mov dword next_code, 256
call input_code
mov ecx, eax
mov ebx, eax
stosb
.while: call input_code
mov esi, eax
cmp ax, MAX_VALUE
je .end_while
lea eax, decode_stack
mov edx, eax
cmp esi, next_code
jb .else
mov byte [eax], bl
inc eax
push ecx
jmp .end_if
.else: push esi
.end_if: push eax
call decode_string
mov bl, [eax]
.while2: cmp eax, edx
jb .end_while2
push eax
mov al, [eax]
stosb
pop eax
dec eax
jmp .while2
.end_while2: cmp dword next_code, MAX_CODE
ja .end_if2
lea edx, prefix_code
mov eax, next_code
mov [edx + eax * 2], cx
lea edx, append_character
mov [edx + eax], bl
inc dword next_code
.end_if2: mov ecx, esi
jmp .while
.end_while:
sub edi, [esp + 40]
mov [esp + 28], edi
popa
ret
input_code: pusha
mov edx, pos
mov esi, buf
push MAX_BITS
pop ecx
xor eax, eax
.bits: bt [esi], edx
rcr eax, 1
inc edx
loop .bits
shr eax, (32 - MAX_BITS)
mov pos, edx
mov [esp + 28], eax
popa
ret
decode_string: pusha
mov ecx, [esp + 36]
mov edx, [esp + 40]
lea esi, append_character
lea edi, prefix_code
.ds_while: cmp dx, 255
jbe .ds_done
mov al, [esi + edx]
mov [ecx], al
inc ecx
mov dx, [edi + edx * 2]
jmp .ds_while
.ds_done: mov [ecx], dl
mov [esp + 28], ecx
popa
retn 8
| ||||||||||||||||