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