kolibrios/programs/fs/kfar/trunk/kfar_arc/deflate.inc
Evgeny Grechnikov (Diamond) c2d16441b9 sorry, I forgot to 'svn add' some files for 631
git-svn-id: svn://kolibrios.org@632 a494cfbc-eb01-0410-851d-a64ba20cac60
2007-09-20 16:22:12 +00:00

561 lines
13 KiB
PHP

; Deflate and Deflate64 decoders for *.zip and *.7z archives.
; Written by diamond in 2007.
deflate_decoder:
virtual at 0
.outStream rb streamInfo.size
.inStream dd ?
.bDeflate64 db ?
.dl db ?
.bLast db ?
rb 1
.outEnd dd ?
.inLen dd ?
.inPtr dd ?
.continue dd ?
.blockLen dd ?
.lit_len rb 19
rb 1
.lengths rb 288+32
.huff_bl rd 18*2
.huff_dist rd 31*2
.huff_lit rd 287*2
.size = $
end virtual
.fillBuf:
mov ebp, eax
jecxz .nodata
add ecx, edi
mov [ebp+.outEnd], ecx
mov esi, [ebp+.inPtr]
mov dl, [ebp+.dl]
jmp [ebp+.continue]
.nodata:
popad
ret
.block_loop_done:
mov [ebp+.inPtr], esi
mov [ebp+.dl], dl
mov [ebp+.continue], .block_loop
popad
ret
.start:
xor edx, edx
mov [ebp+.inLen], edx
mov [ebp+.bLast], dl
.block_loop:
cmp edi, [ebp+.outEnd]
jae .block_loop_done
cmp [ebp+.bLast], 0
jnz return.err
call .get_bit
setc [ebp+.bLast]
call .get_bit
jc .test_block_fh
call .get_bit
jc .block_dh
.block_stored: ; Stored
xor edx, edx
xor eax, eax
call .get_word
mov ecx, eax
call .get_word
not ax
cmp eax, ecx
jnz return.err
mov [ebp+.blockLen], ecx
.continue_stored:
mov ecx, [ebp+.blockLen]
mov eax, [ebp+.outEnd]
sub eax, edi
cmp eax, ecx
jae @f
mov ecx, eax
@@:
sub [ebp+.blockLen], ecx
.bs_loop:
mov eax, [ebp+.inLen]
test eax, eax
jnz @f
call .refill
mov eax, [ebp+.inLen]
inc eax
mov [ebp+.inLen], eax
@@:
push ecx
sub ecx, eax
sbb eax, eax
and ecx, eax
add ecx, [ebp+.inLen]
sub [ebp+.inLen], ecx
sub [esp], ecx
rep movsb
pop ecx
jnz .bs_loop
cmp [ebp+.blockLen], ecx
jz .block_loop
mov [ebp+.inPtr], esi
mov [ebp+.dl], dl
mov [ebp+.continue], .continue_stored
popad
ret
.test_block_fh:
call .get_bit
jc return.err
.block_fh: ; Fixed Huffman
push edi
lea edi, [ebp+.huff_dist]
lea eax, [edi+8]
xor ecx, ecx
mov cl, 30
@@:
stosd
add eax, 8
loop @b
xor eax, eax
mov cl, 32
@@:
stosd
inc eax
loop @b
lea eax, [edi+8]
mov cl, 126
@@:
stosd
add eax, 8
loop @b
push eax
mov eax, 256
mov cl, 24
@@:
stosd
inc eax
loop @b
pop eax
mov cl, 104
@@:
stosd
add eax, 8
loop @b
push eax
xor eax, eax
mov cl, 144
@@:
stosd
inc eax
loop @b
mov eax, 280
mov cl, 8
@@:
stosd
inc eax
loop @b
pop eax
mov cl, 56
@@:
stosd
add eax, 8
loop @b
mov eax, 144
mov cl, 112
@@:
stosd
inc eax
loop @b
jmp .block_h_start
.block_dh: ; Dynamic Huffman
xor ecx, ecx
mov cl, 5
push edi
lea edi, [ebp+.lit_len]
push edi
xor eax, eax
rep stosd
pop edi
mov cl, 5
call .get_bits
push eax
mov cl, 5
call .get_bits
push eax
mov cl, 4
call .get_bits
lea ecx, [eax+4]
mov ebx, deflate.CodeLengthOrder
iglobal
deflate.CodeLengthOrder:
db 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15
endg
@@:
push ecx
mov cl, 3
call .get_bits
mov cl, [ebx]
inc ebx
mov [edi+ecx], al
pop ecx
loop @b
lea ebx, [ebp+.huff_bl]
mov cl, 19
push 18*8
call .construct_huffman_tree
mov ecx, [esp]
add ecx, [esp+4]
add ecx, 258
lea edi, [ebp+.lengths]
.dhl:
lea ebx, [ebp+.huff_bl]
call .get_huffman_code
cmp eax, 16
jae .dh_special
stosb
loop .dhl
jmp .dhd
.dh_special:
push ecx
sub eax, 16
jnz .dh_norep
push 2
pop ecx
call .get_bits
pop ecx
add eax, 3
sub ecx, eax
jb return.err
@@:
mov bl, [edi-1]
mov [edi], bl
inc edi
dec eax
jnz @b
test ecx, ecx
jnz .dhl
jmp .dhd
.dh_norep:
dec eax
jz .dh_0
dec eax
jnz return.err
push 7
pop ecx
call .get_bits
add eax, 11
jmp @f
.dh_0:
push 3
pop ecx
call .get_bits
add eax, 3
@@:
pop ecx
sub ecx, eax
jb return.err
push ecx
mov ecx, eax
xor eax, eax
rep stosb
pop ecx
test ecx, ecx
jnz .dhl
.dhd:
pop ecx
inc ecx
lea ebx, [ebp+.huff_dist]
pop edi
push edi
lea edi, [edi+ebp+.lengths+257]
push 31*8
call .construct_huffman_tree
pop ecx
add ecx, 257
lea ebx, [ebp+.huff_lit]
lea edi, [ebp+.lengths]
push 287*8
call .construct_huffman_tree
.block_h_start: ; Huffman
pop edi
.block_h:
lea ebx, [ebp+.huff_lit]
call .get_huffman_code
sub eax, 256
jnc .not_char
stosb
.bhc:
cmp edi, [ebp+.outEnd]
jb .block_h
mov [ebp+.inPtr], esi
mov [ebp+.dl], dl
mov [ebp+.continue], .block_h
popad
ret
.not_char:
jz .block_loop
cmp eax, 285-256
ja return.err
jz .h_max
iglobal
deflate.LengthCodesStart:
db 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59
db 67,83,99,115,131,163,195,227
deflate.LengthCodesExtra:
db 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5
endg
movzx ebx, byte [deflate.LengthCodesStart+eax-1]
movzx ecx, byte [deflate.LengthCodesExtra+eax-1]
call .get_bits
add ebx, eax
.length_known:
push ebx
lea ebx, [ebp+.huff_dist]
call .get_huffman_code
cmp eax, 32
jae return.err
iglobal
align 4
deflate.DistCodesStart:
dd 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537
dd 2049,3073,4097,6145,8193,12289,16385,24577,32769,49153
deflate.DistCodesExtra:
db 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14
endg
mov ebx, [deflate.DistCodesStart+eax*4]
movzx ecx, byte [deflate.DistCodesExtra+eax]
call .get_bits
add ebx, eax
pop ecx
; ecx=length, ebx=distance
.repmovsbz:
push esi
.repmovsbr:
mov esi, edi
sub esi, ebx
mov eax, [ebp+streamInfo.bufPtr]
sub eax, esi
ja .repmovsb0
mov eax, [ebp+.outEnd]
sub eax, edi
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
pop ecx
jz .repmovsb1
.repmovsbc:
pop [ebp+.inPtr]
mov [ebp+.blockLen], ecx
mov dword [ebp+.lit_len], ebx
mov [ebp+.dl], dl
mov [ebp+.continue], .restart_repmovsb
popad
ret
.repmovsb0:
add esi, 0x10000
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
mov eax, [ebp+.outEnd]
sub eax, edi
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
pop ecx
jz .repmovsb1
cmp edi, [ebp+.outEnd]
jb .repmovsbr
jmp .repmovsbc
.repmovsb1:
pop esi
jmp .bhc
.restart_repmovsb:
mov ecx, [ebp+.blockLen]
mov ebx, dword [ebp+.lit_len]
jmp .repmovsbz
.h_max:
mov ebx, 258
xor ecx, ecx
cmp [ebp+.bDeflate64], cl
jz .length_known
mov cl, 16
call .get_bits
lea ebx, [eax+3]
jmp .length_known
align 16
.get_bit:
shr dl, 1
jnz .ret
sub [ebp+.inLen], 1
js .gb_refill
@@:
mov dl, [esi]
sub esi, -1
rcr dl, 1
.ret:
ret
.gb_refill:
call .refill
jmp @b
.refill:
push eax
mov eax, [ebp+.inStream]
call fillBuf
mov esi, [eax+streamInfo.bufPtr]
mov eax, [eax+streamInfo.bufDataLen]
dec eax
js return.err
mov [ebp+.inLen], eax
pop eax
ret
.get_bits:
push ebx
mov ebx, ecx
xor eax, eax
jecxz .gbr
@@:
call .get_bit
rcr eax, 1
loop @b
mov cl, 32
sub cl, bl
shr eax, cl
.gbr:
pop ebx
ret
.get_word:
sub [ebp+.inLen], 1
jns @f
call .refill
@@:
lodsb
sub [ebp+.inLen], 1
jns @f
call .refill
@@:
mov ah, [esi]
inc esi
ret
.construct_huffman_tree:
; edi->bit lengths array, ecx=number of items, ebx->tree root, [esp+4]=size of tree
add [esp+4], ebx
push edx esi
xor eax, eax
xor edx, edx
mov dword [ebx], eax
mov dword [ebx+4], eax
.cht1:
cmp al, [edi+edx]
ja @f
mov al, [edi+edx]
@@:
inc edx
cmp edx, ecx
jb .cht1
test eax, eax
jz .chtd
push ecx ; remember number of items
push eax ; remember maximum length
lea eax, [ebx+8]
xor edx, edx
inc edx
push 2
pop ecx
.cht2:
push eax
xor eax, eax
.cht3:
cmp dl, [edi+eax]
jnz @f
dec ecx
js return.err
cmp ebx, [esp+24]
jae return.err
mov [ebx], eax
add ebx, 4
@@:
inc eax
cmp eax, [esp+8]
jnz .cht3
pop eax
jecxz .cht4
push ecx
.cht5:
cmp eax, [esp+24]
jb @f
or eax, -1
@@:
cmp ebx, [esp+24]
jae return.err
mov [ebx], eax
add ebx, 4
cmp eax, -1
jz @f
add eax, 8
@@:
loop .cht5
pop ecx
add ecx, ecx
.cht4:
inc edx
cmp edx, [esp]
jbe .cht2
pop eax
pop eax
jecxz .chtd
or eax, -1
@@:
cmp ebx, [esp+12]
jae .chtd
mov [ebx], eax
add ebx, 4
loop @b
.chtd:
pop esi edx
ret 4
.get_huffman_code:
; ebx->tree root
xor eax, eax
cmp dword [ebx+4], eax
jz .ghcret
@@:
call .get_bit
setc al
mov ebx, [ebx+4*eax]
cmp ebx, -1
jz @f
cmp ebx, 0x1000
jae @b
@@:
mov eax, ebx
.ghcret:
ret
deflate_get_buf_size:
mov eax, deflate_decoder.size
mov edx, 0x10000
ret
deflate_init_decoder:
mov [ebp+deflate_decoder.bDeflate64], 0
jmp @f
deflate64_init_decoder:
mov [ebp+deflate_decoder.bDeflate64], 1
@@:
mov [ebp+streamInfo.fillBuf], deflate_decoder.fillBuf
mov [ebp+deflate_decoder.continue], deflate_decoder.start
ret