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