]> git.lizzy.rs Git - zlib.git/blob - contrib/inflate86/inffas86.c
zlib 1.2.1.1
[zlib.git] / contrib / inflate86 / inffas86.c
1 /* inffas86.c is a hand tuned assembler version of
2  *
3  * inffast.c -- fast decoding
4  * Copyright (C) 1995-2003 Mark Adler
5  * For conditions of distribution and use, see copyright notice in zlib.h
6  *
7  * Copyright (C) 2003 Chris Anderson <christop@charm.net>
8  * Please use the copyright conditions above.
9  *
10  * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
11  * the gcc -S output of zlib-1.2.0/inffast.c.  Zlib-1.2.0 is in beta release at
12  * the moment.  I have successfully compiled and tested this code with gcc2.96,
13  * gcc3.2, icc5.0, msvc6.0.  It is very close to the speed of inffast.S
14  * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
15  * enabled.  I will attempt to merge the MMX code into this version.  Newer
16  * versions of this and inffast.S can be found at
17  * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
18  */
19
20 #include "zutil.h"
21 #include "inftrees.h"
22 #include "inflate.h"
23 #include "inffast.h"
24
25 /* Mark Adler's comments from inffast.c: */
26
27 /*
28    Decode literal, length, and distance codes and write out the resulting
29    literal and match bytes until either not enough input or output is
30    available, an end-of-block is encountered, or a data error is encountered.
31    When large enough input and output buffers are supplied to inflate(), for
32    example, a 16K input buffer and a 64K output buffer, more than 95% of the
33    inflate execution time is spent in this routine.
34
35    Entry assumptions:
36
37         state->mode == LEN
38         strm->avail_in >= 6
39         strm->avail_out >= 258
40         start >= strm->avail_out
41         state->bits < 8
42
43    On return, state->mode is one of:
44
45         LEN -- ran out of enough output space or enough available input
46         TYPE -- reached end of block code, inflate() to interpret next block
47         BAD -- error in block data
48
49    Notes:
50
51     - The maximum input bits used by a length/distance pair is 15 bits for the
52       length code, 5 bits for the length extra, 15 bits for the distance code,
53       and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
54       Therefore if strm->avail_in >= 6, then there is enough input to avoid
55       checking for available input while decoding.
56
57     - The maximum bytes that a single length/distance pair can output is 258
58       bytes, which is the maximum length that can be coded.  inflate_fast()
59       requires strm->avail_out >= 258 for each loop to avoid checking for
60       output space.
61  */
62 void inflate_fast(strm, start)
63 z_streamp strm;
64 unsigned start;         /* inflate()'s starting value for strm->avail_out */
65 {
66     struct inflate_state FAR *state;
67     struct inffast_ar {
68       void *esp;                  /* esp save */
69       unsigned char FAR *in;      /* local strm->next_in */
70       unsigned char FAR *last;    /* while in < last, enough input available */
71       unsigned char FAR *out;     /* local strm->next_out */
72       unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
73       unsigned char FAR *end;     /* while out < end, enough space available */
74       unsigned wsize;             /* window size or zero if not using window */
75       unsigned write;             /* window write index */
76       unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
77       unsigned long hold;         /* local strm->hold */
78       unsigned bits;              /* local strm->bits */
79       code const FAR *lcode;      /* local strm->lencode */
80       code const FAR *dcode;      /* local strm->distcode */
81       unsigned lmask;             /* mask for first level of length codes */
82       unsigned dmask;             /* mask for first level of distance codes */
83       unsigned len;               /* match length, unused bytes */
84       unsigned dist;              /* match distance */
85       unsigned status;            /* this is set when state changes */
86     } ar;
87
88     /* copy state to local variables */
89     state = (struct inflate_state FAR *)strm->state;
90     ar.in = strm->next_in;
91     ar.last = ar.in + (strm->avail_in - 5);
92     ar.out = strm->next_out;
93     ar.beg = ar.out - (start - strm->avail_out);
94     ar.end = ar.out + (strm->avail_out - 257);
95     ar.wsize = state->wsize;
96     ar.write = state->write;
97     ar.window = state->window;
98     ar.hold = state->hold;
99     ar.bits = state->bits;
100     ar.lcode = state->lencode;
101     ar.dcode = state->distcode;
102     ar.lmask = (1U << state->lenbits) - 1;
103     ar.dmask = (1U << state->distbits) - 1;
104
105     /* decode literals and length/distances until end-of-block or not enough
106        input data or output space */
107
108     /* align in on 2 byte boundary */
109     if (((unsigned long)(void *)ar.in & 0x1) != 0) {
110         ar.hold += (unsigned long)*ar.in++ << ar.bits;
111         ar.bits += 8;
112     }
113
114 #if defined( __GNUC__ ) || defined( __ICC )
115     __asm__ __volatile__ (
116 "        leal    %0, %%eax\n"
117 "        pushf\n"
118 "        pushl   %%ebp\n"
119 "        movl    %%esp, (%%eax)\n"
120 "        movl    %%eax, %%esp\n"
121 "        movl    4(%%esp), %%esi\n"       /* esi = in */
122 "        movl    12(%%esp), %%edi\n"      /* edi = out */
123 "        movl    36(%%esp), %%edx\n"      /* edx = hold */
124 "        movl    40(%%esp), %%ebx\n"      /* ebx = bits */
125 "        movl    44(%%esp), %%ebp\n"      /* ebp = lcode */
126
127 "        cld\n"
128 "        jmp     .L_do_loop\n"
129
130 ".L_while_test:\n"
131 "        cmpl    %%edi, 20(%%esp)\n"
132 "        jbe     .L_break_loop\n"
133 "        cmpl    %%esi, 8(%%esp)\n"
134 "        jbe     .L_break_loop\n"
135
136 ".L_do_loop:\n"
137 "        cmpb    $15, %%bl\n"
138 "        ja      .L_get_length_code\n"    /* if (15 < bits) */
139
140 "        xorl    %%eax, %%eax\n"
141 "        lodsw\n"                         /* al = *(ushort *)in++ */
142 "        movb    %%bl, %%cl\n"            /* cl = bits, needs it for shifting */
143 "        addb    $16, %%bl\n"             /* bits += 16 */
144 "        shll    %%cl, %%eax\n"
145 "        orl     %%eax, %%edx\n"        /* hold |= *((ushort *)in)++ << bits */
146
147 ".L_get_length_code:\n"
148 "        movl    52(%%esp), %%eax\n"      /* eax = lmask */
149 "        andl    %%edx, %%eax\n"          /* eax &= hold */
150 "        movl    (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */
151
152 ".L_dolen:\n"
153 "        movb    %%ah, %%cl\n"            /* cl = this.bits */
154 "        subb    %%ah, %%bl\n"            /* bits -= this.bits */
155 "        shrl    %%cl, %%edx\n"           /* hold >>= this.bits */
156
157 "        testb   %%al, %%al\n"
158 "        jnz     .L_test_for_length_base\n" /* if (op != 0) 45.7% */
159
160 "        shrl    $16, %%eax\n"            /* output this.val char */
161 "        stosb\n"
162 "        jmp     .L_while_test\n"
163
164 ".L_test_for_length_base:\n"
165 "        movl    %%eax, %%ecx\n"          /* len = this */
166 "        shrl    $16, %%ecx\n"            /* len = this.val */
167 "        movl    %%ecx, 60(%%esp)\n"      /* len = this */
168 "        movb    %%al, %%cl\n"
169
170 "        testb   $16, %%al\n"
171 "        jz      .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */
172 "        andb    $15, %%cl\n"             /* op &= 15 */
173 "        jz      .L_decode_distance\n"    /* if (!op) */
174 "        cmpb    %%cl, %%bl\n"
175 "        jae     .L_add_bits_to_len\n"    /* if (op <= bits) */
176
177 "        movb    %%cl, %%ch\n"            /* stash op in ch, freeing cl */
178 "        xorl    %%eax, %%eax\n"
179 "        lodsw\n"                         /* al = *(ushort *)in++ */
180 "        movb    %%bl, %%cl\n"            /* cl = bits, needs it for shifting */
181 "        addb    $16, %%bl\n"             /* bits += 16 */
182 "        shll    %%cl, %%eax\n"
183 "        orl     %%eax, %%edx\n"         /* hold |= *((ushort *)in)++ << bits */
184 "        movb    %%ch, %%cl\n"            /* move op back to ecx */
185
186 ".L_add_bits_to_len:\n"
187 "        movl    $1, %%eax\n"
188 "        shll    %%cl, %%eax\n"
189 "        decl    %%eax\n"
190 "        subb    %%cl, %%bl\n"
191 "        andl    %%edx, %%eax\n"          /* eax &= hold */
192 "        shrl    %%cl, %%edx\n"
193 "        addl    %%eax, 60(%%esp)\n"      /* len += hold & mask[op] */
194
195 ".L_decode_distance:\n"
196 "        cmpb    $15, %%bl\n"
197 "        ja      .L_get_distance_code\n"  /* if (15 < bits) */
198
199 "        xorl    %%eax, %%eax\n"
200 "        lodsw\n"                         /* al = *(ushort *)in++ */
201 "        movb    %%bl, %%cl\n"            /* cl = bits, needs it for shifting */
202 "        addb    $16, %%bl\n"             /* bits += 16 */
203 "        shll    %%cl, %%eax\n"
204 "        orl     %%eax, %%edx\n"         /* hold |= *((ushort *)in)++ << bits */
205
206 ".L_get_distance_code:\n"
207 "        movl    56(%%esp), %%eax\n"      /* eax = dmask */
208 "        movl    48(%%esp), %%ecx\n"      /* ecx = dcode */
209 "        andl    %%edx, %%eax\n"          /* eax &= hold */
210 "        movl    (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */
211
212 ".L_dodist:\n"
213 "        movl    %%eax, %%ebp\n"          /* dist = this */
214 "        shrl    $16, %%ebp\n"            /* dist = this.val */
215 "        movb    %%ah, %%cl\n"
216 "        subb    %%ah, %%bl\n"            /* bits -= this.bits */
217 "        shrl    %%cl, %%edx\n"           /* hold >>= this.bits */
218 "        movb    %%al, %%cl\n"            /* cl = this.op */
219
220 "        testb   $16, %%al\n"             /* if ((op & 16) == 0) */
221 "        jz      .L_test_for_second_level_dist\n"
222 "        andb    $15, %%cl\n"             /* op &= 15 */
223 "        jz      .L_check_dist_one\n"
224 "        cmpb    %%cl, %%bl\n"
225 "        jae     .L_add_bits_to_dist\n"   /* if (op <= bits) 97.6% */
226
227 "        movb    %%cl, %%ch\n"            /* stash op in ch, freeing cl */
228 "        xorl    %%eax, %%eax\n"
229 "        lodsw\n"                         /* al = *(ushort *)in++ */
230 "        movb    %%bl, %%cl\n"            /* cl = bits, needs it for shifting */
231 "        addb    $16, %%bl\n"             /* bits += 16 */
232 "        shll    %%cl, %%eax\n"
233 "        orl     %%eax, %%edx\n"        /* hold |= *((ushort *)in)++ << bits */
234 "        movb    %%ch, %%cl\n"            /* move op back to ecx */
235
236 ".L_add_bits_to_dist:\n"
237 "        movl    $1, %%eax\n"
238 "        shll    %%cl, %%eax\n"
239 "        decl    %%eax\n"                 /* (1 << op) - 1 */
240 "        subb    %%cl, %%bl\n"
241 "        andl    %%edx, %%eax\n"          /* eax &= hold */
242 "        shrl    %%cl, %%edx\n"
243 "        addl    %%eax, %%ebp\n"          /* dist += hold & ((1 << op) - 1) */
244
245 ".L_check_window:\n"
246 "        movl    %%esi, 4(%%esp)\n"       /* save in so from can use it's reg */
247 "        movl    %%edi, %%eax\n"
248 "        subl    16(%%esp), %%eax\n"      /* nbytes = out - beg */
249
250 "        cmpl    %%ebp, %%eax\n"
251 "        jb      .L_clip_window\n"        /* if (dist > nbytes) 4.2% */
252
253 "        movl    60(%%esp), %%ecx\n"
254 "        movl    %%edi, %%esi\n"
255 "        subl    %%ebp, %%esi\n"          /* from = out - dist */
256
257 "        subl    $3, %%ecx\n"             /* copy from to out */
258 "        movb    (%%esi), %%al\n"
259 "        movb    %%al, (%%edi)\n"
260 "        movb    1(%%esi), %%al\n"
261 "        movb    2(%%esi), %%ah\n"
262 "        addl    $3, %%esi\n"
263 "        movb    %%al, 1(%%edi)\n"
264 "        movb    %%ah, 2(%%edi)\n"
265 "        addl    $3, %%edi\n"
266 "        rep     movsb\n"
267
268 "        movl    4(%%esp), %%esi\n"      /* move in back to %esi, toss from */
269 "        movl    44(%%esp), %%ebp\n"     /* ebp = lcode */
270 "        jmp     .L_while_test\n"
271
272 ".L_check_dist_one:\n"
273 "        cmpl    $1, %%ebp\n"            /* if dist 1, is a memset */
274 "        jne     .L_check_window\n"
275 "        cmpl    %%edi, 16(%%esp)\n"
276 "        je      .L_check_window\n"
277
278 "        decl    %%edi\n"
279 "        movl    60(%%esp), %%ecx\n"
280 "        movb    (%%edi), %%al\n"
281 "        subl    $3, %%ecx\n"
282
283 "        movb    %%al, 1(%%edi)\n"       /* memset out with from[-1] */
284 "        movb    %%al, 2(%%edi)\n"
285 "        movb    %%al, 3(%%edi)\n"
286 "        addl    $4, %%edi\n"
287 "        rep     stosb\n"
288 "        movl    44(%%esp), %%ebp\n"      /* ebp = lcode */
289 "        jmp     .L_while_test\n"
290
291 ".L_test_for_second_level_length:\n"
292 "        testb   $64, %%al\n"
293 "        jnz     .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */
294
295 "        movl    $1, %%eax\n"
296 "        shll    %%cl, %%eax\n"
297 "        decl    %%eax\n"
298 "        andl    %%edx, %%eax\n"         /* eax &= hold */
299 "        addl    60(%%esp), %%eax\n"     /* eax += this.val */
300 "        movl    (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/
301 "        jmp     .L_dolen\n"
302
303 ".L_test_for_second_level_dist:\n"
304 "        testb   $64, %%al\n"
305 "        jnz     .L_invalid_distance_code\n" /* if ((op & 64) != 0) */
306
307 "        movl    $1, %%eax\n"
308 "        shll    %%cl, %%eax\n"
309 "        decl    %%eax\n"
310 "        andl    %%edx, %%eax\n"         /* eax &= hold */
311 "        addl    %%ebp, %%eax\n"         /* eax += this.val */
312 "        movl    48(%%esp), %%ecx\n"     /* ecx = dcode */
313 "        movl    (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/
314 "        jmp     .L_dodist\n"
315
316 ".L_clip_window:\n"
317 "        movl    %%eax, %%ecx\n"
318 "        movl    24(%%esp), %%eax\n"     /* prepare for dist compare */
319 "        negl    %%ecx\n"                /* nbytes = -nbytes */
320 "        movl    32(%%esp), %%esi\n"     /* from = window */
321
322 "        cmpl    %%ebp, %%eax\n"
323 "        jb      .L_invalid_distance_too_far\n" /* if (dist > wsize) */
324
325 "        addl    %%ebp, %%ecx\n"         /* nbytes = dist - nbytes */
326 "        cmpl    $0, 28(%%esp)\n"
327 "        jne     .L_wrap_around_window\n" /* if (write != 0) */
328
329 "        subl    %%ecx, %%eax\n"
330 "        addl    %%eax, %%esi\n"         /* from += wsize - nbytes */
331
332 "        movl    60(%%esp), %%eax\n"
333 "        cmpl    %%ecx, %%eax\n"
334 "        jbe     .L_do_copy1\n"          /* if (nbytes >= len) */
335
336 "        subl    %%ecx, %%eax\n"         /* len -= nbytes */
337 "        rep     movsb\n"
338 "        movl    %%edi, %%esi\n"
339 "        subl    %%ebp, %%esi\n"         /* from = out - dist */
340 "        jmp     .L_do_copy1\n"
341
342 "        cmpl    %%ecx, %%eax\n"
343 "        jbe     .L_do_copy1\n"          /* if (nbytes >= len) */
344
345 "        subl    %%ecx, %%eax\n"         /* len -= nbytes */
346 "        rep     movsb\n"
347 "        movl    %%edi, %%esi\n"
348 "        subl    %%ebp, %%esi\n"         /* from = out - dist */
349 "        jmp     .L_do_copy1\n"
350
351 ".L_wrap_around_window:\n"
352 "        movl    28(%%esp), %%eax\n"
353 "        cmpl    %%eax, %%ecx\n"
354 "        jbe     .L_contiguous_in_window\n" /* if (write >= nbytes) */
355
356 "        addl    24(%%esp), %%esi\n"
357 "        addl    %%eax, %%esi\n"
358 "        subl    %%ecx, %%esi\n"         /* from += wsize + write - nbytes */
359 "        subl    %%eax, %%ecx\n"         /* nbytes -= write */
360
361 "        movl    60(%%esp), %%eax\n"
362 "        cmpl    %%ecx, %%eax\n"
363 "        jbe     .L_do_copy1\n"          /* if (nbytes >= len) */
364
365 "        subl    %%ecx, %%eax\n"         /* len -= nbytes */
366 "        rep     movsb\n"
367 "        movl    32(%%esp), %%esi\n"     /* from = window */
368 "        movl    28(%%esp), %%ecx\n"     /* nbytes = write */
369 "        cmpl    %%ecx, %%eax\n"
370 "        jbe     .L_do_copy1\n"          /* if (nbytes >= len) */
371
372 "        subl    %%ecx, %%eax\n"         /* len -= nbytes */
373 "        rep     movsb\n"
374 "        movl    %%edi, %%esi\n"
375 "        subl    %%ebp, %%esi\n"         /* from = out - dist */
376 "        jmp     .L_do_copy1\n"
377
378 ".L_contiguous_in_window:\n"
379 "        addl    %%eax, %%esi\n"
380 "        subl    %%ecx, %%esi\n"         /* from += write - nbytes */
381
382 "        movl    60(%%esp), %%eax\n"
383 "        cmpl    %%ecx, %%eax\n"
384 "        jbe     .L_do_copy1\n"          /* if (nbytes >= len) */
385
386 "        subl    %%ecx, %%eax\n"         /* len -= nbytes */
387 "        rep     movsb\n"
388 "        movl    %%edi, %%esi\n"
389 "        subl    %%ebp, %%esi\n"         /* from = out - dist */
390
391 ".L_do_copy1:\n"
392 "        movl    %%eax, %%ecx\n"
393 "        rep     movsb\n"
394
395 "        movl    4(%%esp), %%esi\n"      /* move in back to %esi, toss from */
396 "        movl    44(%%esp), %%ebp\n"     /* ebp = lcode */
397 "        jmp     .L_while_test\n"
398
399 ".L_test_for_end_of_block:\n"
400 "        testb   $32, %%al\n"
401 "        jz      .L_invalid_literal_length_code\n"
402 "        movl    $1, 68(%%esp)\n"
403 "        jmp     .L_break_loop_with_status\n"
404
405 ".L_invalid_literal_length_code:\n"
406 "        movl    $2, 68(%%esp)\n"
407 "        jmp     .L_break_loop_with_status\n"
408
409 ".L_invalid_distance_code:\n"
410 "        movl    $3, 68(%%esp)\n"
411 "        jmp     .L_break_loop_with_status\n"
412
413 ".L_invalid_distance_too_far:\n"
414 "        movl    4(%%esp), %%esi\n"
415 "        movl    $4, 68(%%esp)\n"
416 "        jmp     .L_break_loop_with_status\n"
417
418 ".L_break_loop:\n"
419 "        movl    $0, 68(%%esp)\n"
420
421 ".L_break_loop_with_status:\n"
422 /* put in, out, bits, and hold back into ar and pop esp */
423 "        movl    %%esi, 4(%%esp)\n"
424 "        movl    %%edi, 12(%%esp)\n"
425 "        movl    %%ebx, 40(%%esp)\n"
426 "        movl    %%edx, 36(%%esp)\n"
427 "        movl    (%%esp), %%esp\n"
428 "        popl    %%ebp\n"
429 "        popf\n"
430           :
431           : "m" (ar)
432           : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi"
433     );
434 #elif defined( _MSC_VER )
435     __asm {
436         lea     eax, ar
437         pushfd
438         push    ebp
439         mov     [eax], esp
440         mov     esp, eax
441         mov     esi, [esp+4]       /* esi = in */
442         mov     edi, [esp+12]      /* edi = out */
443         mov     edx, [esp+36]      /* edx = hold */
444         mov     ebx, [esp+40]      /* ebx = bits */
445         mov     ebp, [esp+44]      /* ebp = lcode */
446
447         cld
448         jmp     L_do_loop
449
450 L_while_test:
451         cmp     [esp+20], edi
452         jbe     L_break_loop
453         cmp     [esp+8], esi
454         jbe     L_break_loop
455
456 L_do_loop:
457         cmp     bl, 15
458         ja      L_get_length_code    /* if (15 < bits) */
459
460         xor     eax, eax
461         lodsw                         /* al = *(ushort *)in++ */
462         mov     cl, bl            /* cl = bits, needs it for shifting */
463         add     bl, 16             /* bits += 16 */
464         shl     eax, cl
465         or      edx, eax        /* hold |= *((ushort *)in)++ << bits */
466
467 L_get_length_code:
468         mov     eax, [esp+52]      /* eax = lmask */
469         and     eax, edx          /* eax &= hold */
470         mov     eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */
471
472 L_dolen:
473         mov     cl, ah            /* cl = this.bits */
474         sub     bl, ah            /* bits -= this.bits */
475         shr     edx, cl           /* hold >>= this.bits */
476
477         test    al, al
478         jnz     L_test_for_length_base /* if (op != 0) 45.7% */
479
480         shr     eax, 16            /* output this.val char */
481         stosb
482         jmp     L_while_test
483
484 L_test_for_length_base:
485         mov     ecx, eax          /* len = this */
486         shr     ecx, 16            /* len = this.val */
487         mov     [esp+60], ecx      /* len = this */
488         mov     cl, al
489
490         test    al, 16
491         jz      L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
492         and     cl, 15             /* op &= 15 */
493         jz      L_decode_distance    /* if (!op) */
494         cmp     bl, cl
495         jae     L_add_bits_to_len    /* if (op <= bits) */
496
497         mov     ch, cl            /* stash op in ch, freeing cl */
498         xor     eax, eax
499         lodsw                         /* al = *(ushort *)in++ */
500         mov     cl, bl            /* cl = bits, needs it for shifting */
501         add     bl, 16             /* bits += 16 */
502         shl     eax, cl
503         or      edx, eax         /* hold |= *((ushort *)in)++ << bits */
504         mov     cl, ch            /* move op back to ecx */
505
506 L_add_bits_to_len:
507         mov     eax, 1
508         shl     eax, cl
509         dec     eax
510         sub     bl, cl
511         and     eax, edx          /* eax &= hold */
512         shr     edx, cl
513         add     [esp+60], eax      /* len += hold & mask[op] */
514
515 L_decode_distance:
516         cmp     bl, 15
517         ja      L_get_distance_code  /* if (15 < bits) */
518
519         xor     eax, eax
520         lodsw                         /* al = *(ushort *)in++ */
521         mov     cl, bl            /* cl = bits, needs it for shifting */
522         add     bl, 16             /* bits += 16 */
523         shl     eax, cl
524         or      edx, eax         /* hold |= *((ushort *)in)++ << bits */
525
526 L_get_distance_code:
527         mov     eax, [esp+56]      /* eax = dmask */
528         mov     ecx, [esp+48]      /* ecx = dcode */
529         and     eax, edx          /* eax &= hold */
530         mov     eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */
531
532 L_dodist:
533         mov     ebp, eax          /* dist = this */
534         shr     ebp, 16            /* dist = this.val */
535         mov     cl, ah
536         sub     bl, ah            /* bits -= this.bits */
537         shr     edx, cl           /* hold >>= this.bits */
538         mov     cl, al            /* cl = this.op */
539
540         test    al, 16             /* if ((op & 16) == 0) */
541         jz      L_test_for_second_level_dist
542         and     cl, 15             /* op &= 15 */
543         jz      L_check_dist_one
544         cmp     bl, cl
545         jae     L_add_bits_to_dist   /* if (op <= bits) 97.6% */
546
547         mov     ch, cl            /* stash op in ch, freeing cl */
548         xor     eax, eax
549         lodsw                         /* al = *(ushort *)in++ */
550         mov     cl, bl            /* cl = bits, needs it for shifting */
551         add     bl, 16             /* bits += 16 */
552         shl     eax, cl
553         or      edx, eax        /* hold |= *((ushort *)in)++ << bits */
554         mov     cl, ch            /* move op back to ecx */
555
556 L_add_bits_to_dist:
557         mov     eax, 1
558         shl     eax, cl
559         dec     eax                 /* (1 << op) - 1 */
560         sub     bl, cl
561         and     eax, edx          /* eax &= hold */
562         shr     edx, cl
563         add     ebp, eax          /* dist += hold & ((1 << op) - 1) */
564
565 L_check_window:
566         mov     [esp+4], esi       /* save in so from can use it's reg */
567         mov     eax, edi
568         sub     eax, [esp+16]      /* nbytes = out - beg */
569
570         cmp     eax, ebp
571         jb      L_clip_window        /* if (dist > nbytes) 4.2% */
572
573         mov     ecx, [esp+60]
574         mov     esi, edi
575         sub     esi, ebp          /* from = out - dist */
576
577         sub     ecx, 3             /* copy from to out */
578         mov     al, [esi]
579         mov     [edi], al
580         mov     al, [esi+1]
581         mov     ah, [esi+2]
582         add     esi, 3
583         mov     [edi+1], al
584         mov     [edi+2], ah
585         add     edi, 3
586         rep     movsb
587
588         mov     esi, [esp+4]      /* move in back to %esi, toss from */
589         mov     ebp, [esp+44]     /* ebp = lcode */
590         jmp     L_while_test
591
592 L_check_dist_one:
593         cmp     ebp, 1            /* if dist 1, is a memset */
594         jne     L_check_window
595         cmp     [esp+16], edi
596         je      L_check_window
597
598         dec     edi
599         mov     ecx, [esp+60]
600         mov     al, [edi]
601         sub     ecx, 3
602
603         mov     [edi+1], al       /* memset out with from[-1] */
604         mov     [edi+2], al
605         mov     [edi+3], al
606         add     edi, 4
607         rep     stosb
608         mov     ebp, [esp+44]      /* ebp = lcode */
609         jmp     L_while_test
610
611 L_test_for_second_level_length:
612         test    al, 64
613         jnz     L_test_for_end_of_block /* if ((op & 64) != 0) */
614
615         mov     eax, 1
616         shl     eax, cl
617         dec     eax
618         and     eax, edx         /* eax &= hold */
619         add     eax, [esp+60]     /* eax += this.val */
620         mov     eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/
621         jmp     L_dolen
622
623 L_test_for_second_level_dist:
624         test    al, 64
625         jnz     L_invalid_distance_code /* if ((op & 64) != 0) */
626
627         mov     eax, 1
628         shl     eax, cl
629         dec     eax
630         and     eax, edx         /* eax &= hold */
631         add     eax, ebp         /* eax += this.val */
632         mov     ecx, [esp+48]     /* ecx = dcode */
633         mov     eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/
634         jmp     L_dodist
635
636 L_clip_window:
637         mov     ecx, eax
638         mov     eax, [esp+24]     /* prepare for dist compare */
639         neg     ecx                /* nbytes = -nbytes */
640         mov     esi, [esp+32]     /* from = window */
641
642         cmp     eax, ebp
643         jb      L_invalid_distance_too_far /* if (dist > wsize) */
644
645         add     ecx, ebp         /* nbytes = dist - nbytes */
646         cmp     dword ptr [esp+28], 0
647         jne     L_wrap_around_window /* if (write != 0) */
648
649         sub     eax, ecx
650         add     esi, eax         /* from += wsize - nbytes */
651
652         mov     eax, [esp+60]
653         cmp     eax, ecx
654         jbe     L_do_copy1          /* if (nbytes >= len) */
655
656         sub     eax, ecx         /* len -= nbytes */
657         rep     movsb
658         mov     esi, edi
659         sub     esi, ebp         /* from = out - dist */
660         jmp     L_do_copy1
661
662         cmp     eax, ecx
663         jbe     L_do_copy1          /* if (nbytes >= len) */
664
665         sub     eax, ecx         /* len -= nbytes */
666         rep     movsb
667         mov     esi, edi
668         sub     esi, ebp         /* from = out - dist */
669         jmp     L_do_copy1
670
671 L_wrap_around_window:
672         mov     eax, [esp+28]
673         cmp     ecx, eax
674         jbe     L_contiguous_in_window /* if (write >= nbytes) */
675
676         add     esi, [esp+24]
677         add     esi, eax
678         sub     esi, ecx         /* from += wsize + write - nbytes */
679         sub     ecx, eax         /* nbytes -= write */
680
681         mov     eax, [esp+60]
682         cmp     eax, ecx
683         jbe     L_do_copy1          /* if (nbytes >= len) */
684
685         sub     eax, ecx         /* len -= nbytes */
686         rep     movsb
687         mov     esi, [esp+32]     /* from = window */
688         mov     ecx, [esp+28]     /* nbytes = write */
689         cmp     eax, ecx
690         jbe     L_do_copy1          /* if (nbytes >= len) */
691
692         sub     eax, ecx         /* len -= nbytes */
693         rep     movsb
694         mov     esi, edi
695         sub     esi, ebp         /* from = out - dist */
696         jmp     L_do_copy1
697
698 L_contiguous_in_window:
699         add     esi, eax
700         sub     esi, ecx         /* from += write - nbytes */
701
702         mov     eax, [esp+60]
703         cmp     eax, ecx
704         jbe     L_do_copy1          /* if (nbytes >= len) */
705
706         sub     eax, ecx         /* len -= nbytes */
707         rep     movsb
708         mov     esi, edi
709         sub     esi, ebp         /* from = out - dist */
710
711 L_do_copy1:
712         mov     ecx, eax
713         rep     movsb
714
715         mov     esi, [esp+4]      /* move in back to %esi, toss from */
716         mov     ebp, [esp+44]     /* ebp = lcode */
717         jmp     L_while_test
718
719 L_test_for_end_of_block:
720         test    al, 32
721         jz      L_invalid_literal_length_code
722         mov     dword ptr [esp+68], 1
723         jmp     L_break_loop_with_status
724
725 L_invalid_literal_length_code:
726         mov     dword ptr [esp+68], 2
727         jmp     L_break_loop_with_status
728
729 L_invalid_distance_code:
730         mov     dword ptr [esp+68], 3
731         jmp     L_break_loop_with_status
732
733 L_invalid_distance_too_far:
734         mov     esi, [esp+4]
735         mov     dword ptr [esp+68], 4
736         jmp     L_break_loop_with_status
737
738 L_break_loop:
739         mov     dword ptr [esp+68], 0
740
741 L_break_loop_with_status:
742 /* put in, out, bits, and hold back into ar and pop esp */
743         mov     [esp+4], esi
744         mov     [esp+12], edi
745         mov     [esp+40], ebx
746         mov     [esp+36], edx
747         mov     esp, [esp]
748         pop     ebp
749         popfd
750     }
751 #endif
752
753     if (ar.status > 1) {
754         if (ar.status == 2)
755             strm->msg = "invalid literal/length code";
756         else if (ar.status == 3)
757             strm->msg = "invalid distance code";
758         else
759             strm->msg = "invalid distance too far back";
760         state->mode = BAD;
761     }
762     else if ( ar.status == 1 ) {
763         state->mode = TYPE;
764     }
765
766     /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
767     ar.len = ar.bits >> 3;
768     ar.in -= ar.len;
769     ar.bits -= ar.len << 3;
770     ar.hold &= (1U << ar.bits) - 1;
771
772     /* update state and return */
773     strm->next_in = ar.in;
774     strm->next_out = ar.out;
775     strm->avail_in = (unsigned)(ar.in < ar.last ? 5 + (ar.last - ar.in) :
776                                                   5 - (ar.in - ar.last));
777     strm->avail_out = (unsigned)(ar.out < ar.end ? 257 + (ar.end - ar.out) :
778                                                    257 - (ar.out - ar.end));
779     state->hold = ar.hold;
780     state->bits = ar.bits;
781     return;
782 }
783