xref: /plan9/sys/src/cmd/gs/zlib/infback.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1*593dc095SDavid du Colombier /* infback.c -- inflate using a call-back interface
2*593dc095SDavid du Colombier  * Copyright (C) 1995-2003 Mark Adler
3*593dc095SDavid du Colombier  * For conditions of distribution and use, see copyright notice in zlib.h
4*593dc095SDavid du Colombier  */
5*593dc095SDavid du Colombier 
6*593dc095SDavid du Colombier /*
7*593dc095SDavid du Colombier    This code is largely copied from inflate.c.  Normally either infback.o or
8*593dc095SDavid du Colombier    inflate.o would be linked into an application--not both.  The interface
9*593dc095SDavid du Colombier    with inffast.c is retained so that optimized assembler-coded versions of
10*593dc095SDavid du Colombier    inflate_fast() can be used with either inflate.c or infback.c.
11*593dc095SDavid du Colombier  */
12*593dc095SDavid du Colombier 
13*593dc095SDavid du Colombier #include "zutil.h"
14*593dc095SDavid du Colombier #include "inftrees.h"
15*593dc095SDavid du Colombier #include "inflate.h"
16*593dc095SDavid du Colombier #include "inffast.h"
17*593dc095SDavid du Colombier 
18*593dc095SDavid du Colombier /* function prototypes */
19*593dc095SDavid du Colombier local void fixedtables OF((struct inflate_state FAR *state));
20*593dc095SDavid du Colombier 
21*593dc095SDavid du Colombier /*
22*593dc095SDavid du Colombier    strm provides memory allocation functions in zalloc and zfree, or
23*593dc095SDavid du Colombier    Z_NULL to use the library memory allocation functions.
24*593dc095SDavid du Colombier 
25*593dc095SDavid du Colombier    windowBits is in the range 8..15, and window is a user-supplied
26*593dc095SDavid du Colombier    window and output buffer that is 2**windowBits bytes.
27*593dc095SDavid du Colombier  */
inflateBackInit_(strm,windowBits,window,version,stream_size)28*593dc095SDavid du Colombier int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
29*593dc095SDavid du Colombier z_stream FAR *strm;
30*593dc095SDavid du Colombier int windowBits;
31*593dc095SDavid du Colombier unsigned char FAR *window;
32*593dc095SDavid du Colombier const char *version;
33*593dc095SDavid du Colombier int stream_size;
34*593dc095SDavid du Colombier {
35*593dc095SDavid du Colombier     struct inflate_state FAR *state;
36*593dc095SDavid du Colombier 
37*593dc095SDavid du Colombier     if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
38*593dc095SDavid du Colombier         stream_size != (int)(sizeof(z_stream)))
39*593dc095SDavid du Colombier         return Z_VERSION_ERROR;
40*593dc095SDavid du Colombier     if (strm == Z_NULL || window == Z_NULL ||
41*593dc095SDavid du Colombier         windowBits < 8 || windowBits > 15)
42*593dc095SDavid du Colombier         return Z_STREAM_ERROR;
43*593dc095SDavid du Colombier     strm->msg = Z_NULL;                 /* in case we return an error */
44*593dc095SDavid du Colombier     if (strm->zalloc == (alloc_func)0) {
45*593dc095SDavid du Colombier         strm->zalloc = zcalloc;
46*593dc095SDavid du Colombier         strm->opaque = (voidpf)0;
47*593dc095SDavid du Colombier     }
48*593dc095SDavid du Colombier     if (strm->zfree == (free_func)0) strm->zfree = zcfree;
49*593dc095SDavid du Colombier     state = (struct inflate_state FAR *)ZALLOC(strm, 1,
50*593dc095SDavid du Colombier                                                sizeof(struct inflate_state));
51*593dc095SDavid du Colombier     if (state == Z_NULL) return Z_MEM_ERROR;
52*593dc095SDavid du Colombier     Tracev((stderr, "inflate: allocated\n"));
53*593dc095SDavid du Colombier     strm->state = (voidpf)state;
54*593dc095SDavid du Colombier     state->wbits = windowBits;
55*593dc095SDavid du Colombier     state->wsize = 1U << windowBits;
56*593dc095SDavid du Colombier     state->window = window;
57*593dc095SDavid du Colombier     state->write = 0;
58*593dc095SDavid du Colombier     state->whave = 0;
59*593dc095SDavid du Colombier     return Z_OK;
60*593dc095SDavid du Colombier }
61*593dc095SDavid du Colombier 
62*593dc095SDavid du Colombier /*
63*593dc095SDavid du Colombier    Return state with length and distance decoding tables and index sizes set to
64*593dc095SDavid du Colombier    fixed code decoding.  Normally this returns fixed tables from inffixed.h.
65*593dc095SDavid du Colombier    If BUILDFIXED is defined, then instead this routine builds the tables the
66*593dc095SDavid du Colombier    first time it's called, and returns those tables the first time and
67*593dc095SDavid du Colombier    thereafter.  This reduces the size of the code by about 2K bytes, in
68*593dc095SDavid du Colombier    exchange for a little execution time.  However, BUILDFIXED should not be
69*593dc095SDavid du Colombier    used for threaded applications, since the rewriting of the tables and virgin
70*593dc095SDavid du Colombier    may not be thread-safe.
71*593dc095SDavid du Colombier  */
fixedtables(state)72*593dc095SDavid du Colombier local void fixedtables(state)
73*593dc095SDavid du Colombier struct inflate_state FAR *state;
74*593dc095SDavid du Colombier {
75*593dc095SDavid du Colombier #ifdef BUILDFIXED
76*593dc095SDavid du Colombier     static int virgin = 1;
77*593dc095SDavid du Colombier     static code *lenfix, *distfix;
78*593dc095SDavid du Colombier     static code fixed[544];
79*593dc095SDavid du Colombier 
80*593dc095SDavid du Colombier     /* build fixed huffman tables if first call (may not be thread safe) */
81*593dc095SDavid du Colombier     if (virgin) {
82*593dc095SDavid du Colombier         unsigned sym, bits;
83*593dc095SDavid du Colombier         static code *next;
84*593dc095SDavid du Colombier 
85*593dc095SDavid du Colombier         /* literal/length table */
86*593dc095SDavid du Colombier         sym = 0;
87*593dc095SDavid du Colombier         while (sym < 144) state->lens[sym++] = 8;
88*593dc095SDavid du Colombier         while (sym < 256) state->lens[sym++] = 9;
89*593dc095SDavid du Colombier         while (sym < 280) state->lens[sym++] = 7;
90*593dc095SDavid du Colombier         while (sym < 288) state->lens[sym++] = 8;
91*593dc095SDavid du Colombier         next = fixed;
92*593dc095SDavid du Colombier         lenfix = next;
93*593dc095SDavid du Colombier         bits = 9;
94*593dc095SDavid du Colombier         inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
95*593dc095SDavid du Colombier 
96*593dc095SDavid du Colombier         /* distance table */
97*593dc095SDavid du Colombier         sym = 0;
98*593dc095SDavid du Colombier         while (sym < 32) state->lens[sym++] = 5;
99*593dc095SDavid du Colombier         distfix = next;
100*593dc095SDavid du Colombier         bits = 5;
101*593dc095SDavid du Colombier         inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
102*593dc095SDavid du Colombier 
103*593dc095SDavid du Colombier         /* do this just once */
104*593dc095SDavid du Colombier         virgin = 0;
105*593dc095SDavid du Colombier     }
106*593dc095SDavid du Colombier #else /* !BUILDFIXED */
107*593dc095SDavid du Colombier #   include "inffixed.h"
108*593dc095SDavid du Colombier #endif /* BUILDFIXED */
109*593dc095SDavid du Colombier     state->lencode = lenfix;
110*593dc095SDavid du Colombier     state->lenbits = 9;
111*593dc095SDavid du Colombier     state->distcode = distfix;
112*593dc095SDavid du Colombier     state->distbits = 5;
113*593dc095SDavid du Colombier }
114*593dc095SDavid du Colombier 
115*593dc095SDavid du Colombier /* Macros for inflateBack(): */
116*593dc095SDavid du Colombier 
117*593dc095SDavid du Colombier /* Load returned state from inflate_fast() */
118*593dc095SDavid du Colombier #define LOAD() \
119*593dc095SDavid du Colombier     do { \
120*593dc095SDavid du Colombier         put = strm->next_out; \
121*593dc095SDavid du Colombier         left = strm->avail_out; \
122*593dc095SDavid du Colombier         next = strm->next_in; \
123*593dc095SDavid du Colombier         have = strm->avail_in; \
124*593dc095SDavid du Colombier         hold = state->hold; \
125*593dc095SDavid du Colombier         bits = state->bits; \
126*593dc095SDavid du Colombier     } while (0)
127*593dc095SDavid du Colombier 
128*593dc095SDavid du Colombier /* Set state from registers for inflate_fast() */
129*593dc095SDavid du Colombier #define RESTORE() \
130*593dc095SDavid du Colombier     do { \
131*593dc095SDavid du Colombier         strm->next_out = put; \
132*593dc095SDavid du Colombier         strm->avail_out = left; \
133*593dc095SDavid du Colombier         strm->next_in = next; \
134*593dc095SDavid du Colombier         strm->avail_in = have; \
135*593dc095SDavid du Colombier         state->hold = hold; \
136*593dc095SDavid du Colombier         state->bits = bits; \
137*593dc095SDavid du Colombier     } while (0)
138*593dc095SDavid du Colombier 
139*593dc095SDavid du Colombier /* Clear the input bit accumulator */
140*593dc095SDavid du Colombier #define INITBITS() \
141*593dc095SDavid du Colombier     do { \
142*593dc095SDavid du Colombier         hold = 0; \
143*593dc095SDavid du Colombier         bits = 0; \
144*593dc095SDavid du Colombier     } while (0)
145*593dc095SDavid du Colombier 
146*593dc095SDavid du Colombier /* Assure that some input is available.  If input is requested, but denied,
147*593dc095SDavid du Colombier    then return a Z_BUF_ERROR from inflateBack(). */
148*593dc095SDavid du Colombier #define PULL() \
149*593dc095SDavid du Colombier     do { \
150*593dc095SDavid du Colombier         if (have == 0) { \
151*593dc095SDavid du Colombier             have = in(in_desc, &next); \
152*593dc095SDavid du Colombier             if (have == 0) { \
153*593dc095SDavid du Colombier                 next = Z_NULL; \
154*593dc095SDavid du Colombier                 ret = Z_BUF_ERROR; \
155*593dc095SDavid du Colombier                 goto inf_leave; \
156*593dc095SDavid du Colombier             } \
157*593dc095SDavid du Colombier         } \
158*593dc095SDavid du Colombier     } while (0)
159*593dc095SDavid du Colombier 
160*593dc095SDavid du Colombier /* Get a byte of input into the bit accumulator, or return from inflateBack()
161*593dc095SDavid du Colombier    with an error if there is no input available. */
162*593dc095SDavid du Colombier #define PULLBYTE() \
163*593dc095SDavid du Colombier     do { \
164*593dc095SDavid du Colombier         PULL(); \
165*593dc095SDavid du Colombier         have--; \
166*593dc095SDavid du Colombier         hold += (unsigned long)(*next++) << bits; \
167*593dc095SDavid du Colombier         bits += 8; \
168*593dc095SDavid du Colombier     } while (0)
169*593dc095SDavid du Colombier 
170*593dc095SDavid du Colombier /* Assure that there are at least n bits in the bit accumulator.  If there is
171*593dc095SDavid du Colombier    not enough available input to do that, then return from inflateBack() with
172*593dc095SDavid du Colombier    an error. */
173*593dc095SDavid du Colombier #define NEEDBITS(n) \
174*593dc095SDavid du Colombier     do { \
175*593dc095SDavid du Colombier         while (bits < (unsigned)(n)) \
176*593dc095SDavid du Colombier             PULLBYTE(); \
177*593dc095SDavid du Colombier     } while (0)
178*593dc095SDavid du Colombier 
179*593dc095SDavid du Colombier /* Return the low n bits of the bit accumulator (n < 16) */
180*593dc095SDavid du Colombier #define BITS(n) \
181*593dc095SDavid du Colombier     ((unsigned)hold & ((1U << (n)) - 1))
182*593dc095SDavid du Colombier 
183*593dc095SDavid du Colombier /* Remove n bits from the bit accumulator */
184*593dc095SDavid du Colombier #define DROPBITS(n) \
185*593dc095SDavid du Colombier     do { \
186*593dc095SDavid du Colombier         hold >>= (n); \
187*593dc095SDavid du Colombier         bits -= (unsigned)(n); \
188*593dc095SDavid du Colombier     } while (0)
189*593dc095SDavid du Colombier 
190*593dc095SDavid du Colombier /* Remove zero to seven bits as needed to go to a byte boundary */
191*593dc095SDavid du Colombier #define BYTEBITS() \
192*593dc095SDavid du Colombier     do { \
193*593dc095SDavid du Colombier         hold >>= bits & 7; \
194*593dc095SDavid du Colombier         bits -= bits & 7; \
195*593dc095SDavid du Colombier     } while (0)
196*593dc095SDavid du Colombier 
197*593dc095SDavid du Colombier /* Assure that some output space is available, by writing out the window
198*593dc095SDavid du Colombier    if it's full.  If the write fails, return from inflateBack() with a
199*593dc095SDavid du Colombier    Z_BUF_ERROR. */
200*593dc095SDavid du Colombier #define ROOM() \
201*593dc095SDavid du Colombier     do { \
202*593dc095SDavid du Colombier         if (left == 0) { \
203*593dc095SDavid du Colombier             put = state->window; \
204*593dc095SDavid du Colombier             left = state->wsize; \
205*593dc095SDavid du Colombier             state->whave = left; \
206*593dc095SDavid du Colombier             if (out(out_desc, put, left)) { \
207*593dc095SDavid du Colombier                 ret = Z_BUF_ERROR; \
208*593dc095SDavid du Colombier                 goto inf_leave; \
209*593dc095SDavid du Colombier             } \
210*593dc095SDavid du Colombier         } \
211*593dc095SDavid du Colombier     } while (0)
212*593dc095SDavid du Colombier 
213*593dc095SDavid du Colombier /*
214*593dc095SDavid du Colombier    strm provides the memory allocation functions and window buffer on input,
215*593dc095SDavid du Colombier    and provides information on the unused input on return.  For Z_DATA_ERROR
216*593dc095SDavid du Colombier    returns, strm will also provide an error message.
217*593dc095SDavid du Colombier 
218*593dc095SDavid du Colombier    in() and out() are the call-back input and output functions.  When
219*593dc095SDavid du Colombier    inflateBack() needs more input, it calls in().  When inflateBack() has
220*593dc095SDavid du Colombier    filled the window with output, or when it completes with data in the
221*593dc095SDavid du Colombier    window, it calls out() to write out the data.  The application must not
222*593dc095SDavid du Colombier    change the provided input until in() is called again or inflateBack()
223*593dc095SDavid du Colombier    returns.  The application must not change the window/output buffer until
224*593dc095SDavid du Colombier    inflateBack() returns.
225*593dc095SDavid du Colombier 
226*593dc095SDavid du Colombier    in() and out() are called with a descriptor parameter provided in the
227*593dc095SDavid du Colombier    inflateBack() call.  This parameter can be a structure that provides the
228*593dc095SDavid du Colombier    information required to do the read or write, as well as accumulated
229*593dc095SDavid du Colombier    information on the input and output such as totals and check values.
230*593dc095SDavid du Colombier 
231*593dc095SDavid du Colombier    in() should return zero on failure.  out() should return non-zero on
232*593dc095SDavid du Colombier    failure.  If either in() or out() fails, than inflateBack() returns a
233*593dc095SDavid du Colombier    Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
234*593dc095SDavid du Colombier    was in() or out() that caused in the error.  Otherwise,  inflateBack()
235*593dc095SDavid du Colombier    returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
236*593dc095SDavid du Colombier    error, or Z_MEM_ERROR if it could not allocate memory for the state.
237*593dc095SDavid du Colombier    inflateBack() can also return Z_STREAM_ERROR if the input parameters
238*593dc095SDavid du Colombier    are not correct, i.e. strm is Z_NULL or the state was not initialized.
239*593dc095SDavid du Colombier  */
inflateBack(strm,in,in_desc,out,out_desc)240*593dc095SDavid du Colombier int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
241*593dc095SDavid du Colombier z_stream FAR *strm;
242*593dc095SDavid du Colombier in_func in;
243*593dc095SDavid du Colombier void FAR *in_desc;
244*593dc095SDavid du Colombier out_func out;
245*593dc095SDavid du Colombier void FAR *out_desc;
246*593dc095SDavid du Colombier {
247*593dc095SDavid du Colombier     struct inflate_state FAR *state;
248*593dc095SDavid du Colombier     unsigned char FAR *next;    /* next input */
249*593dc095SDavid du Colombier     unsigned char FAR *put;     /* next output */
250*593dc095SDavid du Colombier     unsigned have, left;        /* available input and output */
251*593dc095SDavid du Colombier     unsigned long hold;         /* bit buffer */
252*593dc095SDavid du Colombier     unsigned bits;              /* bits in bit buffer */
253*593dc095SDavid du Colombier     unsigned copy;              /* number of stored or match bytes to copy */
254*593dc095SDavid du Colombier     unsigned char FAR *from;    /* where to copy match bytes from */
255*593dc095SDavid du Colombier     code this;                  /* current decoding table entry */
256*593dc095SDavid du Colombier     code last;                  /* parent table entry */
257*593dc095SDavid du Colombier     unsigned len;               /* length to copy for repeats, bits to drop */
258*593dc095SDavid du Colombier     int ret;                    /* return code */
259*593dc095SDavid du Colombier     static const unsigned short order[19] = /* permutation of code lengths */
260*593dc095SDavid du Colombier         {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
261*593dc095SDavid du Colombier 
262*593dc095SDavid du Colombier     /* Check that the strm exists and that the state was initialized */
263*593dc095SDavid du Colombier     if (strm == Z_NULL || strm->state == Z_NULL)
264*593dc095SDavid du Colombier         return Z_STREAM_ERROR;
265*593dc095SDavid du Colombier     state = (struct inflate_state FAR *)strm->state;
266*593dc095SDavid du Colombier 
267*593dc095SDavid du Colombier     /* Reset the state */
268*593dc095SDavid du Colombier     strm->msg = Z_NULL;
269*593dc095SDavid du Colombier     state->mode = TYPE;
270*593dc095SDavid du Colombier     state->last = 0;
271*593dc095SDavid du Colombier     state->whave = 0;
272*593dc095SDavid du Colombier     next = strm->next_in;
273*593dc095SDavid du Colombier     have = next != Z_NULL ? strm->avail_in : 0;
274*593dc095SDavid du Colombier     hold = 0;
275*593dc095SDavid du Colombier     bits = 0;
276*593dc095SDavid du Colombier     put = state->window;
277*593dc095SDavid du Colombier     left = state->wsize;
278*593dc095SDavid du Colombier 
279*593dc095SDavid du Colombier     /* Inflate until end of block marked as last */
280*593dc095SDavid du Colombier     for (;;)
281*593dc095SDavid du Colombier         switch (state->mode) {
282*593dc095SDavid du Colombier         case TYPE:
283*593dc095SDavid du Colombier             /* determine and dispatch block type */
284*593dc095SDavid du Colombier             if (state->last) {
285*593dc095SDavid du Colombier                 BYTEBITS();
286*593dc095SDavid du Colombier                 state->mode = DONE;
287*593dc095SDavid du Colombier                 break;
288*593dc095SDavid du Colombier             }
289*593dc095SDavid du Colombier             NEEDBITS(3);
290*593dc095SDavid du Colombier             state->last = BITS(1);
291*593dc095SDavid du Colombier             DROPBITS(1);
292*593dc095SDavid du Colombier             switch (BITS(2)) {
293*593dc095SDavid du Colombier             case 0:                             /* stored block */
294*593dc095SDavid du Colombier                 Tracev((stderr, "inflate:     stored block%s\n",
295*593dc095SDavid du Colombier                         state->last ? " (last)" : ""));
296*593dc095SDavid du Colombier                 state->mode = STORED;
297*593dc095SDavid du Colombier                 break;
298*593dc095SDavid du Colombier             case 1:                             /* fixed block */
299*593dc095SDavid du Colombier                 fixedtables(state);
300*593dc095SDavid du Colombier                 Tracev((stderr, "inflate:     fixed codes block%s\n",
301*593dc095SDavid du Colombier                         state->last ? " (last)" : ""));
302*593dc095SDavid du Colombier                 state->mode = LEN;              /* decode codes */
303*593dc095SDavid du Colombier                 break;
304*593dc095SDavid du Colombier             case 2:                             /* dynamic block */
305*593dc095SDavid du Colombier                 Tracev((stderr, "inflate:     dynamic codes block%s\n",
306*593dc095SDavid du Colombier                         state->last ? " (last)" : ""));
307*593dc095SDavid du Colombier                 state->mode = TABLE;
308*593dc095SDavid du Colombier                 break;
309*593dc095SDavid du Colombier             case 3:
310*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid block type";
311*593dc095SDavid du Colombier                 state->mode = BAD;
312*593dc095SDavid du Colombier             }
313*593dc095SDavid du Colombier             DROPBITS(2);
314*593dc095SDavid du Colombier             break;
315*593dc095SDavid du Colombier 
316*593dc095SDavid du Colombier         case STORED:
317*593dc095SDavid du Colombier             /* get and verify stored block length */
318*593dc095SDavid du Colombier             BYTEBITS();                         /* go to byte boundary */
319*593dc095SDavid du Colombier             NEEDBITS(32);
320*593dc095SDavid du Colombier             if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
321*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid stored block lengths";
322*593dc095SDavid du Colombier                 state->mode = BAD;
323*593dc095SDavid du Colombier                 break;
324*593dc095SDavid du Colombier             }
325*593dc095SDavid du Colombier             state->length = (unsigned)hold & 0xffff;
326*593dc095SDavid du Colombier             Tracev((stderr, "inflate:       stored length %u\n",
327*593dc095SDavid du Colombier                     state->length));
328*593dc095SDavid du Colombier             INITBITS();
329*593dc095SDavid du Colombier 
330*593dc095SDavid du Colombier             /* copy stored block from input to output */
331*593dc095SDavid du Colombier             while (state->length != 0) {
332*593dc095SDavid du Colombier                 copy = state->length;
333*593dc095SDavid du Colombier                 PULL();
334*593dc095SDavid du Colombier                 ROOM();
335*593dc095SDavid du Colombier                 if (copy > have) copy = have;
336*593dc095SDavid du Colombier                 if (copy > left) copy = left;
337*593dc095SDavid du Colombier                 zmemcpy(put, next, copy);
338*593dc095SDavid du Colombier                 have -= copy;
339*593dc095SDavid du Colombier                 next += copy;
340*593dc095SDavid du Colombier                 left -= copy;
341*593dc095SDavid du Colombier                 put += copy;
342*593dc095SDavid du Colombier                 state->length -= copy;
343*593dc095SDavid du Colombier             }
344*593dc095SDavid du Colombier             Tracev((stderr, "inflate:       stored end\n"));
345*593dc095SDavid du Colombier             state->mode = TYPE;
346*593dc095SDavid du Colombier             break;
347*593dc095SDavid du Colombier 
348*593dc095SDavid du Colombier         case TABLE:
349*593dc095SDavid du Colombier             /* get dynamic table entries descriptor */
350*593dc095SDavid du Colombier             NEEDBITS(14);
351*593dc095SDavid du Colombier             state->nlen = BITS(5) + 257;
352*593dc095SDavid du Colombier             DROPBITS(5);
353*593dc095SDavid du Colombier             state->ndist = BITS(5) + 1;
354*593dc095SDavid du Colombier             DROPBITS(5);
355*593dc095SDavid du Colombier             state->ncode = BITS(4) + 4;
356*593dc095SDavid du Colombier             DROPBITS(4);
357*593dc095SDavid du Colombier #ifndef PKZIP_BUG_WORKAROUND
358*593dc095SDavid du Colombier             if (state->nlen > 286 || state->ndist > 30) {
359*593dc095SDavid du Colombier                 strm->msg = (char *)"too many length or distance symbols";
360*593dc095SDavid du Colombier                 state->mode = BAD;
361*593dc095SDavid du Colombier                 break;
362*593dc095SDavid du Colombier             }
363*593dc095SDavid du Colombier #endif
364*593dc095SDavid du Colombier             Tracev((stderr, "inflate:       table sizes ok\n"));
365*593dc095SDavid du Colombier 
366*593dc095SDavid du Colombier             /* get code length code lengths (not a typo) */
367*593dc095SDavid du Colombier             state->have = 0;
368*593dc095SDavid du Colombier             while (state->have < state->ncode) {
369*593dc095SDavid du Colombier                 NEEDBITS(3);
370*593dc095SDavid du Colombier                 state->lens[order[state->have++]] = (unsigned short)BITS(3);
371*593dc095SDavid du Colombier                 DROPBITS(3);
372*593dc095SDavid du Colombier             }
373*593dc095SDavid du Colombier             while (state->have < 19)
374*593dc095SDavid du Colombier                 state->lens[order[state->have++]] = 0;
375*593dc095SDavid du Colombier             state->next = state->codes;
376*593dc095SDavid du Colombier             state->lencode = (code const FAR *)(state->next);
377*593dc095SDavid du Colombier             state->lenbits = 7;
378*593dc095SDavid du Colombier             ret = inflate_table(CODES, state->lens, 19, &(state->next),
379*593dc095SDavid du Colombier                                 &(state->lenbits), state->work);
380*593dc095SDavid du Colombier             if (ret) {
381*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid code lengths set";
382*593dc095SDavid du Colombier                 state->mode = BAD;
383*593dc095SDavid du Colombier                 break;
384*593dc095SDavid du Colombier             }
385*593dc095SDavid du Colombier             Tracev((stderr, "inflate:       code lengths ok\n"));
386*593dc095SDavid du Colombier 
387*593dc095SDavid du Colombier             /* get length and distance code code lengths */
388*593dc095SDavid du Colombier             state->have = 0;
389*593dc095SDavid du Colombier             while (state->have < state->nlen + state->ndist) {
390*593dc095SDavid du Colombier                 for (;;) {
391*593dc095SDavid du Colombier                     this = state->lencode[BITS(state->lenbits)];
392*593dc095SDavid du Colombier                     if ((unsigned)(this.bits) <= bits) break;
393*593dc095SDavid du Colombier                     PULLBYTE();
394*593dc095SDavid du Colombier                 }
395*593dc095SDavid du Colombier                 if (this.val < 16) {
396*593dc095SDavid du Colombier                     NEEDBITS(this.bits);
397*593dc095SDavid du Colombier                     DROPBITS(this.bits);
398*593dc095SDavid du Colombier                     state->lens[state->have++] = this.val;
399*593dc095SDavid du Colombier                 }
400*593dc095SDavid du Colombier                 else {
401*593dc095SDavid du Colombier                     if (this.val == 16) {
402*593dc095SDavid du Colombier                         NEEDBITS(this.bits + 2);
403*593dc095SDavid du Colombier                         DROPBITS(this.bits);
404*593dc095SDavid du Colombier                         if (state->have == 0) {
405*593dc095SDavid du Colombier                             strm->msg = (char *)"invalid bit length repeat";
406*593dc095SDavid du Colombier                             state->mode = BAD;
407*593dc095SDavid du Colombier                             break;
408*593dc095SDavid du Colombier                         }
409*593dc095SDavid du Colombier                         len = (unsigned)(state->lens[state->have - 1]);
410*593dc095SDavid du Colombier                         copy = 3 + BITS(2);
411*593dc095SDavid du Colombier                         DROPBITS(2);
412*593dc095SDavid du Colombier                     }
413*593dc095SDavid du Colombier                     else if (this.val == 17) {
414*593dc095SDavid du Colombier                         NEEDBITS(this.bits + 3);
415*593dc095SDavid du Colombier                         DROPBITS(this.bits);
416*593dc095SDavid du Colombier                         len = 0;
417*593dc095SDavid du Colombier                         copy = 3 + BITS(3);
418*593dc095SDavid du Colombier                         DROPBITS(3);
419*593dc095SDavid du Colombier                     }
420*593dc095SDavid du Colombier                     else {
421*593dc095SDavid du Colombier                         NEEDBITS(this.bits + 7);
422*593dc095SDavid du Colombier                         DROPBITS(this.bits);
423*593dc095SDavid du Colombier                         len = 0;
424*593dc095SDavid du Colombier                         copy = 11 + BITS(7);
425*593dc095SDavid du Colombier                         DROPBITS(7);
426*593dc095SDavid du Colombier                     }
427*593dc095SDavid du Colombier                     if (state->have + copy > state->nlen + state->ndist) {
428*593dc095SDavid du Colombier                         strm->msg = (char *)"invalid bit length repeat";
429*593dc095SDavid du Colombier                         state->mode = BAD;
430*593dc095SDavid du Colombier                         break;
431*593dc095SDavid du Colombier                     }
432*593dc095SDavid du Colombier                     while (copy--)
433*593dc095SDavid du Colombier                         state->lens[state->have++] = (unsigned short)len;
434*593dc095SDavid du Colombier                 }
435*593dc095SDavid du Colombier             }
436*593dc095SDavid du Colombier 
437*593dc095SDavid du Colombier             /* handle error breaks in while */
438*593dc095SDavid du Colombier             if (state->mode == BAD) break;
439*593dc095SDavid du Colombier 
440*593dc095SDavid du Colombier             /* build code tables */
441*593dc095SDavid du Colombier             state->next = state->codes;
442*593dc095SDavid du Colombier             state->lencode = (code const FAR *)(state->next);
443*593dc095SDavid du Colombier             state->lenbits = 9;
444*593dc095SDavid du Colombier             ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
445*593dc095SDavid du Colombier                                 &(state->lenbits), state->work);
446*593dc095SDavid du Colombier             if (ret) {
447*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid literal/lengths set";
448*593dc095SDavid du Colombier                 state->mode = BAD;
449*593dc095SDavid du Colombier                 break;
450*593dc095SDavid du Colombier             }
451*593dc095SDavid du Colombier             state->distcode = (code const FAR *)(state->next);
452*593dc095SDavid du Colombier             state->distbits = 6;
453*593dc095SDavid du Colombier             ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
454*593dc095SDavid du Colombier                             &(state->next), &(state->distbits), state->work);
455*593dc095SDavid du Colombier             if (ret) {
456*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid distances set";
457*593dc095SDavid du Colombier                 state->mode = BAD;
458*593dc095SDavid du Colombier                 break;
459*593dc095SDavid du Colombier             }
460*593dc095SDavid du Colombier             Tracev((stderr, "inflate:       codes ok\n"));
461*593dc095SDavid du Colombier             state->mode = LEN;
462*593dc095SDavid du Colombier 
463*593dc095SDavid du Colombier         case LEN:
464*593dc095SDavid du Colombier             /* use inflate_fast() if we have enough input and output */
465*593dc095SDavid du Colombier             if (have >= 6 && left >= 258) {
466*593dc095SDavid du Colombier                 RESTORE();
467*593dc095SDavid du Colombier                 if (state->whave < state->wsize)
468*593dc095SDavid du Colombier                     state->whave = state->wsize - left;
469*593dc095SDavid du Colombier                 inflate_fast(strm, state->wsize);
470*593dc095SDavid du Colombier                 LOAD();
471*593dc095SDavid du Colombier                 break;
472*593dc095SDavid du Colombier             }
473*593dc095SDavid du Colombier 
474*593dc095SDavid du Colombier             /* get a literal, length, or end-of-block code */
475*593dc095SDavid du Colombier             for (;;) {
476*593dc095SDavid du Colombier                 this = state->lencode[BITS(state->lenbits)];
477*593dc095SDavid du Colombier                 if ((unsigned)(this.bits) <= bits) break;
478*593dc095SDavid du Colombier                 PULLBYTE();
479*593dc095SDavid du Colombier             }
480*593dc095SDavid du Colombier             if (this.op && (this.op & 0xf0) == 0) {
481*593dc095SDavid du Colombier                 last = this;
482*593dc095SDavid du Colombier                 for (;;) {
483*593dc095SDavid du Colombier                     this = state->lencode[last.val +
484*593dc095SDavid du Colombier                             (BITS(last.bits + last.op) >> last.bits)];
485*593dc095SDavid du Colombier                     if ((unsigned)(last.bits + this.bits) <= bits) break;
486*593dc095SDavid du Colombier                     PULLBYTE();
487*593dc095SDavid du Colombier                 }
488*593dc095SDavid du Colombier                 DROPBITS(last.bits);
489*593dc095SDavid du Colombier             }
490*593dc095SDavid du Colombier             DROPBITS(this.bits);
491*593dc095SDavid du Colombier             state->length = (unsigned)this.val;
492*593dc095SDavid du Colombier 
493*593dc095SDavid du Colombier             /* process literal */
494*593dc095SDavid du Colombier             if (this.op == 0) {
495*593dc095SDavid du Colombier                 Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
496*593dc095SDavid du Colombier                         "inflate:         literal '%c'\n" :
497*593dc095SDavid du Colombier                         "inflate:         literal 0x%02x\n", this.val));
498*593dc095SDavid du Colombier                 ROOM();
499*593dc095SDavid du Colombier                 *put++ = (unsigned char)(state->length);
500*593dc095SDavid du Colombier                 left--;
501*593dc095SDavid du Colombier                 state->mode = LEN;
502*593dc095SDavid du Colombier                 break;
503*593dc095SDavid du Colombier             }
504*593dc095SDavid du Colombier 
505*593dc095SDavid du Colombier             /* process end of block */
506*593dc095SDavid du Colombier             if (this.op & 32) {
507*593dc095SDavid du Colombier                 Tracevv((stderr, "inflate:         end of block\n"));
508*593dc095SDavid du Colombier                 state->mode = TYPE;
509*593dc095SDavid du Colombier                 break;
510*593dc095SDavid du Colombier             }
511*593dc095SDavid du Colombier 
512*593dc095SDavid du Colombier             /* invalid code */
513*593dc095SDavid du Colombier             if (this.op & 64) {
514*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid literal/length code";
515*593dc095SDavid du Colombier                 state->mode = BAD;
516*593dc095SDavid du Colombier                 break;
517*593dc095SDavid du Colombier             }
518*593dc095SDavid du Colombier 
519*593dc095SDavid du Colombier             /* length code -- get extra bits, if any */
520*593dc095SDavid du Colombier             state->extra = (unsigned)(this.op) & 15;
521*593dc095SDavid du Colombier             if (state->extra != 0) {
522*593dc095SDavid du Colombier                 NEEDBITS(state->extra);
523*593dc095SDavid du Colombier                 state->length += BITS(state->extra);
524*593dc095SDavid du Colombier                 DROPBITS(state->extra);
525*593dc095SDavid du Colombier             }
526*593dc095SDavid du Colombier             Tracevv((stderr, "inflate:         length %u\n", state->length));
527*593dc095SDavid du Colombier 
528*593dc095SDavid du Colombier             /* get distance code */
529*593dc095SDavid du Colombier             for (;;) {
530*593dc095SDavid du Colombier                 this = state->distcode[BITS(state->distbits)];
531*593dc095SDavid du Colombier                 if ((unsigned)(this.bits) <= bits) break;
532*593dc095SDavid du Colombier                 PULLBYTE();
533*593dc095SDavid du Colombier             }
534*593dc095SDavid du Colombier             if ((this.op & 0xf0) == 0) {
535*593dc095SDavid du Colombier                 last = this;
536*593dc095SDavid du Colombier                 for (;;) {
537*593dc095SDavid du Colombier                     this = state->distcode[last.val +
538*593dc095SDavid du Colombier                             (BITS(last.bits + last.op) >> last.bits)];
539*593dc095SDavid du Colombier                     if ((unsigned)(last.bits + this.bits) <= bits) break;
540*593dc095SDavid du Colombier                     PULLBYTE();
541*593dc095SDavid du Colombier                 }
542*593dc095SDavid du Colombier                 DROPBITS(last.bits);
543*593dc095SDavid du Colombier             }
544*593dc095SDavid du Colombier             DROPBITS(this.bits);
545*593dc095SDavid du Colombier             if (this.op & 64) {
546*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid distance code";
547*593dc095SDavid du Colombier                 state->mode = BAD;
548*593dc095SDavid du Colombier                 break;
549*593dc095SDavid du Colombier             }
550*593dc095SDavid du Colombier             state->offset = (unsigned)this.val;
551*593dc095SDavid du Colombier 
552*593dc095SDavid du Colombier             /* get distance extra bits, if any */
553*593dc095SDavid du Colombier             state->extra = (unsigned)(this.op) & 15;
554*593dc095SDavid du Colombier             if (state->extra != 0) {
555*593dc095SDavid du Colombier                 NEEDBITS(state->extra);
556*593dc095SDavid du Colombier                 state->offset += BITS(state->extra);
557*593dc095SDavid du Colombier                 DROPBITS(state->extra);
558*593dc095SDavid du Colombier             }
559*593dc095SDavid du Colombier             if (state->offset > state->wsize - (state->whave < state->wsize ?
560*593dc095SDavid du Colombier                                                 left : 0)) {
561*593dc095SDavid du Colombier                 strm->msg = (char *)"invalid distance too far back";
562*593dc095SDavid du Colombier                 state->mode = BAD;
563*593dc095SDavid du Colombier                 break;
564*593dc095SDavid du Colombier             }
565*593dc095SDavid du Colombier             Tracevv((stderr, "inflate:         distance %u\n", state->offset));
566*593dc095SDavid du Colombier 
567*593dc095SDavid du Colombier             /* copy match from window to output */
568*593dc095SDavid du Colombier             do {
569*593dc095SDavid du Colombier                 ROOM();
570*593dc095SDavid du Colombier                 copy = state->wsize - state->offset;
571*593dc095SDavid du Colombier                 if (copy < left) {
572*593dc095SDavid du Colombier                     from = put + copy;
573*593dc095SDavid du Colombier                     copy = left - copy;
574*593dc095SDavid du Colombier                 }
575*593dc095SDavid du Colombier                 else {
576*593dc095SDavid du Colombier                     from = put - state->offset;
577*593dc095SDavid du Colombier                     copy = left;
578*593dc095SDavid du Colombier                 }
579*593dc095SDavid du Colombier                 if (copy > state->length) copy = state->length;
580*593dc095SDavid du Colombier                 state->length -= copy;
581*593dc095SDavid du Colombier                 left -= copy;
582*593dc095SDavid du Colombier                 do {
583*593dc095SDavid du Colombier                     *put++ = *from++;
584*593dc095SDavid du Colombier                 } while (--copy);
585*593dc095SDavid du Colombier             } while (state->length != 0);
586*593dc095SDavid du Colombier             break;
587*593dc095SDavid du Colombier 
588*593dc095SDavid du Colombier         case DONE:
589*593dc095SDavid du Colombier             /* inflate stream terminated properly -- write leftover output */
590*593dc095SDavid du Colombier             ret = Z_STREAM_END;
591*593dc095SDavid du Colombier             if (left < state->wsize) {
592*593dc095SDavid du Colombier                 if (out(out_desc, state->window, state->wsize - left))
593*593dc095SDavid du Colombier                     ret = Z_BUF_ERROR;
594*593dc095SDavid du Colombier             }
595*593dc095SDavid du Colombier             goto inf_leave;
596*593dc095SDavid du Colombier 
597*593dc095SDavid du Colombier         case BAD:
598*593dc095SDavid du Colombier             ret = Z_DATA_ERROR;
599*593dc095SDavid du Colombier             goto inf_leave;
600*593dc095SDavid du Colombier 
601*593dc095SDavid du Colombier         default:                /* can't happen, but makes compilers happy */
602*593dc095SDavid du Colombier             ret = Z_STREAM_ERROR;
603*593dc095SDavid du Colombier             goto inf_leave;
604*593dc095SDavid du Colombier         }
605*593dc095SDavid du Colombier 
606*593dc095SDavid du Colombier     /* Return unused input */
607*593dc095SDavid du Colombier   inf_leave:
608*593dc095SDavid du Colombier     strm->next_in = next;
609*593dc095SDavid du Colombier     strm->avail_in = have;
610*593dc095SDavid du Colombier     return ret;
611*593dc095SDavid du Colombier }
612*593dc095SDavid du Colombier 
inflateBackEnd(strm)613*593dc095SDavid du Colombier int ZEXPORT inflateBackEnd(strm)
614*593dc095SDavid du Colombier z_stream FAR *strm;
615*593dc095SDavid du Colombier {
616*593dc095SDavid du Colombier     if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
617*593dc095SDavid du Colombier         return Z_STREAM_ERROR;
618*593dc095SDavid du Colombier     ZFREE(strm, strm->state);
619*593dc095SDavid du Colombier     strm->state = Z_NULL;
620*593dc095SDavid du Colombier     Tracev((stderr, "inflate: end\n"));
621*593dc095SDavid du Colombier     return Z_OK;
622*593dc095SDavid du Colombier }
623