Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
632 | diamond | 1 | ; Deflate and Deflate64 decoders for *.zip and *.7z archives. |
2 | ; Written by diamond in 2007. |
||
3 | |||
4 | deflate_decoder: |
||
5 | virtual at 0 |
||
6 | .outStream rb streamInfo.size |
||
7 | .inStream dd ? |
||
8 | .bDeflate64 db ? |
||
9 | .dl db ? |
||
10 | .bLast db ? |
||
11 | rb 1 |
||
12 | .outEnd dd ? |
||
13 | .inLen dd ? |
||
14 | .inPtr dd ? |
||
15 | .continue dd ? |
||
16 | .blockLen dd ? |
||
17 | .lit_len rb 19 |
||
18 | rb 1 |
||
19 | .lengths rb 288+32 |
||
20 | .huff_bl rd 18*2 |
||
21 | .huff_dist rd 31*2 |
||
22 | .huff_lit rd 287*2 |
||
23 | .size = $ |
||
24 | end virtual |
||
25 | |||
26 | .fillBuf: |
||
27 | mov ebp, eax |
||
28 | jecxz .nodata |
||
29 | add ecx, edi |
||
30 | mov [ebp+.outEnd], ecx |
||
31 | mov esi, [ebp+.inPtr] |
||
32 | mov dl, [ebp+.dl] |
||
33 | jmp [ebp+.continue] |
||
34 | .nodata: |
||
35 | popad |
||
36 | ret |
||
37 | .block_loop_done: |
||
38 | mov [ebp+.inPtr], esi |
||
39 | mov [ebp+.dl], dl |
||
40 | mov [ebp+.continue], .block_loop |
||
41 | popad |
||
42 | ret |
||
43 | .start: |
||
44 | xor edx, edx |
||
45 | mov [ebp+.inLen], edx |
||
46 | mov [ebp+.bLast], dl |
||
47 | .block_loop: |
||
48 | cmp edi, [ebp+.outEnd] |
||
49 | jae .block_loop_done |
||
50 | cmp [ebp+.bLast], 0 |
||
51 | jnz return.err |
||
52 | call .get_bit |
||
53 | setc [ebp+.bLast] |
||
54 | call .get_bit |
||
55 | jc .test_block_fh |
||
56 | call .get_bit |
||
57 | jc .block_dh |
||
58 | .block_stored: ; Stored |
||
59 | xor edx, edx |
||
60 | xor eax, eax |
||
61 | call .get_word |
||
62 | mov ecx, eax |
||
63 | call .get_word |
||
64 | not ax |
||
65 | cmp eax, ecx |
||
66 | jnz return.err |
||
67 | mov [ebp+.blockLen], ecx |
||
68 | .continue_stored: |
||
69 | mov ecx, [ebp+.blockLen] |
||
70 | mov eax, [ebp+.outEnd] |
||
71 | sub eax, edi |
||
72 | cmp eax, ecx |
||
73 | jae @f |
||
74 | mov ecx, eax |
||
75 | @@: |
||
76 | sub [ebp+.blockLen], ecx |
||
77 | .bs_loop: |
||
78 | mov eax, [ebp+.inLen] |
||
79 | test eax, eax |
||
80 | jnz @f |
||
81 | call .refill |
||
82 | mov eax, [ebp+.inLen] |
||
83 | inc eax |
||
84 | mov [ebp+.inLen], eax |
||
85 | @@: |
||
86 | push ecx |
||
87 | sub ecx, eax |
||
88 | sbb eax, eax |
||
89 | and ecx, eax |
||
90 | add ecx, [ebp+.inLen] |
||
91 | sub [ebp+.inLen], ecx |
||
92 | sub [esp], ecx |
||
93 | rep movsb |
||
94 | pop ecx |
||
95 | jnz .bs_loop |
||
96 | cmp [ebp+.blockLen], ecx |
||
97 | jz .block_loop |
||
98 | mov [ebp+.inPtr], esi |
||
99 | mov [ebp+.dl], dl |
||
100 | mov [ebp+.continue], .continue_stored |
||
101 | popad |
||
102 | ret |
||
103 | .test_block_fh: |
||
104 | call .get_bit |
||
105 | jc return.err |
||
106 | .block_fh: ; Fixed Huffman |
||
107 | push edi |
||
108 | lea edi, [ebp+.huff_dist] |
||
109 | lea eax, [edi+8] |
||
110 | xor ecx, ecx |
||
111 | mov cl, 30 |
||
112 | @@: |
||
113 | stosd |
||
114 | add eax, 8 |
||
115 | loop @b |
||
116 | xor eax, eax |
||
117 | mov cl, 32 |
||
118 | @@: |
||
119 | stosd |
||
120 | inc eax |
||
121 | loop @b |
||
122 | lea eax, [edi+8] |
||
123 | mov cl, 126 |
||
124 | @@: |
||
125 | stosd |
||
126 | add eax, 8 |
||
127 | loop @b |
||
128 | push eax |
||
129 | mov eax, 256 |
||
130 | mov cl, 24 |
||
131 | @@: |
||
132 | stosd |
||
133 | inc eax |
||
134 | loop @b |
||
135 | pop eax |
||
136 | mov cl, 104 |
||
137 | @@: |
||
138 | stosd |
||
139 | add eax, 8 |
||
140 | loop @b |
||
141 | push eax |
||
142 | xor eax, eax |
||
143 | mov cl, 144 |
||
144 | @@: |
||
145 | stosd |
||
146 | inc eax |
||
147 | loop @b |
||
148 | mov eax, 280 |
||
149 | mov cl, 8 |
||
150 | @@: |
||
151 | stosd |
||
152 | inc eax |
||
153 | loop @b |
||
154 | pop eax |
||
155 | mov cl, 56 |
||
156 | @@: |
||
157 | stosd |
||
158 | add eax, 8 |
||
159 | loop @b |
||
160 | mov eax, 144 |
||
161 | mov cl, 112 |
||
162 | @@: |
||
163 | stosd |
||
164 | inc eax |
||
165 | loop @b |
||
166 | jmp .block_h_start |
||
167 | .block_dh: ; Dynamic Huffman |
||
168 | xor ecx, ecx |
||
169 | mov cl, 5 |
||
170 | push edi |
||
171 | lea edi, [ebp+.lit_len] |
||
172 | push edi |
||
173 | xor eax, eax |
||
174 | rep stosd |
||
175 | pop edi |
||
176 | mov cl, 5 |
||
177 | call .get_bits |
||
178 | push eax |
||
179 | mov cl, 5 |
||
180 | call .get_bits |
||
181 | push eax |
||
182 | mov cl, 4 |
||
183 | call .get_bits |
||
184 | lea ecx, [eax+4] |
||
185 | mov ebx, deflate.CodeLengthOrder |
||
186 | iglobal |
||
187 | deflate.CodeLengthOrder: |
||
188 | db 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 |
||
189 | endg |
||
190 | @@: |
||
191 | push ecx |
||
192 | mov cl, 3 |
||
193 | call .get_bits |
||
194 | mov cl, [ebx] |
||
195 | inc ebx |
||
196 | mov [edi+ecx], al |
||
197 | pop ecx |
||
198 | loop @b |
||
199 | lea ebx, [ebp+.huff_bl] |
||
200 | mov cl, 19 |
||
201 | push 18*8 |
||
202 | call .construct_huffman_tree |
||
203 | mov ecx, [esp] |
||
204 | add ecx, [esp+4] |
||
205 | add ecx, 258 |
||
206 | lea edi, [ebp+.lengths] |
||
207 | .dhl: |
||
208 | lea ebx, [ebp+.huff_bl] |
||
209 | call .get_huffman_code |
||
210 | cmp eax, 16 |
||
211 | jae .dh_special |
||
212 | stosb |
||
213 | loop .dhl |
||
214 | jmp .dhd |
||
215 | .dh_special: |
||
216 | push ecx |
||
217 | sub eax, 16 |
||
218 | jnz .dh_norep |
||
219 | push 2 |
||
220 | pop ecx |
||
221 | call .get_bits |
||
222 | pop ecx |
||
223 | add eax, 3 |
||
224 | sub ecx, eax |
||
225 | jb return.err |
||
226 | @@: |
||
227 | mov bl, [edi-1] |
||
228 | mov [edi], bl |
||
229 | inc edi |
||
230 | dec eax |
||
231 | jnz @b |
||
232 | test ecx, ecx |
||
233 | jnz .dhl |
||
234 | jmp .dhd |
||
235 | .dh_norep: |
||
236 | dec eax |
||
237 | jz .dh_0 |
||
238 | dec eax |
||
239 | jnz return.err |
||
240 | push 7 |
||
241 | pop ecx |
||
242 | call .get_bits |
||
243 | add eax, 11 |
||
244 | jmp @f |
||
245 | .dh_0: |
||
246 | push 3 |
||
247 | pop ecx |
||
248 | call .get_bits |
||
249 | add eax, 3 |
||
250 | @@: |
||
251 | pop ecx |
||
252 | sub ecx, eax |
||
253 | jb return.err |
||
254 | push ecx |
||
255 | mov ecx, eax |
||
256 | xor eax, eax |
||
257 | rep stosb |
||
258 | pop ecx |
||
259 | test ecx, ecx |
||
260 | jnz .dhl |
||
261 | .dhd: |
||
262 | pop ecx |
||
263 | inc ecx |
||
264 | lea ebx, [ebp+.huff_dist] |
||
265 | pop edi |
||
266 | push edi |
||
267 | lea edi, [edi+ebp+.lengths+257] |
||
268 | push 31*8 |
||
269 | call .construct_huffman_tree |
||
270 | pop ecx |
||
271 | add ecx, 257 |
||
272 | lea ebx, [ebp+.huff_lit] |
||
273 | lea edi, [ebp+.lengths] |
||
274 | push 287*8 |
||
275 | call .construct_huffman_tree |
||
276 | .block_h_start: ; Huffman |
||
277 | pop edi |
||
278 | .block_h: |
||
279 | lea ebx, [ebp+.huff_lit] |
||
280 | call .get_huffman_code |
||
281 | sub eax, 256 |
||
282 | jnc .not_char |
||
283 | stosb |
||
284 | .bhc: |
||
285 | cmp edi, [ebp+.outEnd] |
||
286 | jb .block_h |
||
287 | mov [ebp+.inPtr], esi |
||
288 | mov [ebp+.dl], dl |
||
289 | mov [ebp+.continue], .block_h |
||
290 | popad |
||
291 | ret |
||
292 | .not_char: |
||
293 | jz .block_loop |
||
294 | cmp eax, 285-256 |
||
295 | ja return.err |
||
296 | jz .h_max |
||
297 | iglobal |
||
298 | deflate.LengthCodesStart: |
||
299 | db 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59 |
||
300 | db 67,83,99,115,131,163,195,227 |
||
301 | deflate.LengthCodesExtra: |
||
302 | 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 |
||
303 | endg |
||
304 | movzx ebx, byte [deflate.LengthCodesStart+eax-1] |
||
305 | movzx ecx, byte [deflate.LengthCodesExtra+eax-1] |
||
306 | call .get_bits |
||
307 | add ebx, eax |
||
308 | .length_known: |
||
309 | push ebx |
||
310 | lea ebx, [ebp+.huff_dist] |
||
311 | call .get_huffman_code |
||
312 | cmp eax, 32 |
||
313 | jae return.err |
||
314 | iglobal |
||
315 | align 4 |
||
316 | deflate.DistCodesStart: |
||
317 | dd 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537 |
||
318 | dd 2049,3073,4097,6145,8193,12289,16385,24577,32769,49153 |
||
319 | deflate.DistCodesExtra: |
||
320 | 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 |
||
321 | endg |
||
322 | mov ebx, [deflate.DistCodesStart+eax*4] |
||
323 | movzx ecx, byte [deflate.DistCodesExtra+eax] |
||
324 | call .get_bits |
||
325 | add ebx, eax |
||
326 | pop ecx |
||
327 | ; ecx=length, ebx=distance |
||
328 | .repmovsbz: |
||
329 | push esi |
||
330 | .repmovsbr: |
||
331 | mov esi, edi |
||
332 | sub esi, ebx |
||
333 | mov eax, [ebp+streamInfo.bufPtr] |
||
334 | sub eax, esi |
||
335 | ja .repmovsb0 |
||
336 | mov eax, [ebp+.outEnd] |
||
337 | sub eax, edi |
||
338 | push ecx |
||
339 | cmp ecx, eax |
||
340 | jb @f |
||
341 | mov ecx, eax |
||
342 | @@: |
||
343 | sub [esp], ecx |
||
344 | rep movsb |
||
345 | pop ecx |
||
346 | jz .repmovsb1 |
||
347 | .repmovsbc: |
||
348 | pop [ebp+.inPtr] |
||
349 | mov [ebp+.blockLen], ecx |
||
350 | mov dword [ebp+.lit_len], ebx |
||
351 | mov [ebp+.dl], dl |
||
352 | mov [ebp+.continue], .restart_repmovsb |
||
353 | popad |
||
354 | ret |
||
355 | .repmovsb0: |
||
356 | add esi, 0x10000 |
||
357 | push ecx |
||
358 | cmp ecx, eax |
||
359 | jb @f |
||
360 | mov ecx, eax |
||
361 | @@: |
||
362 | mov eax, [ebp+.outEnd] |
||
363 | sub eax, edi |
||
364 | cmp ecx, eax |
||
365 | jb @f |
||
366 | mov ecx, eax |
||
367 | @@: |
||
368 | sub [esp], ecx |
||
369 | rep movsb |
||
370 | pop ecx |
||
371 | jz .repmovsb1 |
||
372 | cmp edi, [ebp+.outEnd] |
||
373 | jb .repmovsbr |
||
374 | jmp .repmovsbc |
||
375 | .repmovsb1: |
||
376 | pop esi |
||
377 | jmp .bhc |
||
378 | .restart_repmovsb: |
||
379 | mov ecx, [ebp+.blockLen] |
||
380 | mov ebx, dword [ebp+.lit_len] |
||
381 | jmp .repmovsbz |
||
382 | .h_max: |
||
383 | mov ebx, 258 |
||
384 | xor ecx, ecx |
||
385 | cmp [ebp+.bDeflate64], cl |
||
386 | jz .length_known |
||
387 | mov cl, 16 |
||
388 | call .get_bits |
||
389 | lea ebx, [eax+3] |
||
390 | jmp .length_known |
||
391 | |||
392 | align 16 |
||
393 | .get_bit: |
||
394 | shr dl, 1 |
||
395 | jnz .ret |
||
396 | sub [ebp+.inLen], 1 |
||
397 | js .gb_refill |
||
398 | @@: |
||
399 | mov dl, [esi] |
||
400 | sub esi, -1 |
||
401 | rcr dl, 1 |
||
402 | .ret: |
||
403 | ret |
||
404 | .gb_refill: |
||
405 | call .refill |
||
406 | jmp @b |
||
407 | |||
408 | .refill: |
||
409 | push eax |
||
410 | mov eax, [ebp+.inStream] |
||
411 | call fillBuf |
||
412 | mov esi, [eax+streamInfo.bufPtr] |
||
413 | mov eax, [eax+streamInfo.bufDataLen] |
||
414 | dec eax |
||
415 | js return.err |
||
416 | mov [ebp+.inLen], eax |
||
417 | pop eax |
||
418 | ret |
||
419 | |||
420 | .get_bits: |
||
421 | push ebx |
||
422 | mov ebx, ecx |
||
423 | xor eax, eax |
||
424 | jecxz .gbr |
||
425 | @@: |
||
426 | call .get_bit |
||
427 | rcr eax, 1 |
||
428 | loop @b |
||
429 | mov cl, 32 |
||
430 | sub cl, bl |
||
431 | shr eax, cl |
||
432 | .gbr: |
||
433 | pop ebx |
||
434 | ret |
||
435 | |||
436 | .get_word: |
||
437 | sub [ebp+.inLen], 1 |
||
438 | jns @f |
||
439 | call .refill |
||
440 | @@: |
||
441 | lodsb |
||
442 | sub [ebp+.inLen], 1 |
||
443 | jns @f |
||
444 | call .refill |
||
445 | @@: |
||
446 | mov ah, [esi] |
||
447 | inc esi |
||
448 | ret |
||
449 | |||
450 | .construct_huffman_tree: |
||
451 | ; edi->bit lengths array, ecx=number of items, ebx->tree root, [esp+4]=size of tree |
||
452 | add [esp+4], ebx |
||
453 | push edx esi |
||
454 | xor eax, eax |
||
455 | xor edx, edx |
||
456 | mov dword [ebx], eax |
||
457 | mov dword [ebx+4], eax |
||
458 | .cht1: |
||
459 | cmp al, [edi+edx] |
||
460 | ja @f |
||
461 | mov al, [edi+edx] |
||
462 | @@: |
||
463 | inc edx |
||
464 | cmp edx, ecx |
||
465 | jb .cht1 |
||
466 | test eax, eax |
||
467 | jz .chtd |
||
468 | push ecx ; remember number of items |
||
469 | push eax ; remember maximum length |
||
470 | lea eax, [ebx+8] |
||
471 | xor edx, edx |
||
472 | inc edx |
||
473 | push 2 |
||
474 | pop ecx |
||
475 | .cht2: |
||
476 | push eax |
||
477 | xor eax, eax |
||
478 | .cht3: |
||
479 | cmp dl, [edi+eax] |
||
480 | jnz @f |
||
481 | dec ecx |
||
482 | js return.err |
||
483 | cmp ebx, [esp+24] |
||
484 | jae return.err |
||
485 | mov [ebx], eax |
||
486 | add ebx, 4 |
||
487 | @@: |
||
488 | inc eax |
||
489 | cmp eax, [esp+8] |
||
490 | jnz .cht3 |
||
491 | pop eax |
||
492 | jecxz .cht4 |
||
493 | push ecx |
||
494 | .cht5: |
||
495 | cmp eax, [esp+24] |
||
496 | jb @f |
||
497 | or eax, -1 |
||
498 | @@: |
||
499 | cmp ebx, [esp+24] |
||
500 | jae return.err |
||
501 | mov [ebx], eax |
||
502 | add ebx, 4 |
||
503 | cmp eax, -1 |
||
504 | jz @f |
||
505 | add eax, 8 |
||
506 | @@: |
||
507 | loop .cht5 |
||
508 | pop ecx |
||
509 | add ecx, ecx |
||
510 | .cht4: |
||
511 | inc edx |
||
512 | cmp edx, [esp] |
||
513 | jbe .cht2 |
||
514 | pop eax |
||
515 | pop eax |
||
516 | jecxz .chtd |
||
517 | or eax, -1 |
||
518 | @@: |
||
519 | cmp ebx, [esp+12] |
||
520 | jae .chtd |
||
521 | mov [ebx], eax |
||
522 | add ebx, 4 |
||
523 | loop @b |
||
524 | .chtd: |
||
525 | pop esi edx |
||
526 | ret 4 |
||
527 | |||
528 | .get_huffman_code: |
||
529 | ; ebx->tree root |
||
530 | xor eax, eax |
||
531 | cmp dword [ebx+4], eax |
||
532 | jz .ghcret |
||
533 | @@: |
||
534 | call .get_bit |
||
535 | setc al |
||
536 | mov ebx, [ebx+4*eax] |
||
537 | cmp ebx, -1 |
||
538 | jz @f |
||
539 | cmp ebx, 0x1000 |
||
540 | jae @b |
||
541 | @@: |
||
542 | mov eax, ebx |
||
543 | .ghcret: |
||
544 | ret |
||
545 | |||
546 | deflate_get_buf_size: |
||
547 | mov eax, deflate_decoder.size |
||
548 | mov edx, 0x10000 |
||
549 | ret |
||
550 | |||
551 | deflate_init_decoder: |
||
552 | mov [ebp+deflate_decoder.bDeflate64], 0 |
||
553 | jmp @f |
||
554 | |||
555 | deflate64_init_decoder: |
||
556 | mov [ebp+deflate_decoder.bDeflate64], 1 |
||
557 | @@: |
||
558 | mov [ebp+streamInfo.fillBuf], deflate_decoder.fillBuf |
||
559 | mov [ebp+deflate_decoder.continue], deflate_decoder.start |
||
560 | ret |