0,0 → 1,560 |
; 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 |