xref: /illumos-gate/usr/src/contrib/zlib/inflate.c (revision 2e401bab)
1b8382935SToomas Soome /* inflate.c -- zlib decompression
2148fd93eSToomas 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  * Change history:
8b8382935SToomas Soome  *
9b8382935SToomas Soome  * 1.2.beta0    24 Nov 2002
10b8382935SToomas Soome  * - First version -- complete rewrite of inflate to simplify code, avoid
11b8382935SToomas Soome  *   creation of window when not needed, minimize use of window when it is
12b8382935SToomas Soome  *   needed, make inffast.c even faster, implement gzip decoding, and to
13b8382935SToomas Soome  *   improve code readability and style over the previous zlib inflate code
14b8382935SToomas Soome  *
15b8382935SToomas Soome  * 1.2.beta1    25 Nov 2002
16b8382935SToomas Soome  * - Use pointers for available input and output checking in inffast.c
17b8382935SToomas Soome  * - Remove input and output counters in inffast.c
18b8382935SToomas Soome  * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
19b8382935SToomas Soome  * - Remove unnecessary second byte pull from length extra in inffast.c
20b8382935SToomas Soome  * - Unroll direct copy to three copies per loop in inffast.c
21b8382935SToomas Soome  *
22b8382935SToomas Soome  * 1.2.beta2    4 Dec 2002
23b8382935SToomas Soome  * - Change external routine names to reduce potential conflicts
24b8382935SToomas Soome  * - Correct filename to inffixed.h for fixed tables in inflate.c
25b8382935SToomas Soome  * - Make hbuf[] unsigned char to match parameter type in inflate.c
26b8382935SToomas Soome  * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
27b8382935SToomas Soome  *   to avoid negation problem on Alphas (64 bit) in inflate.c
28b8382935SToomas Soome  *
29b8382935SToomas Soome  * 1.2.beta3    22 Dec 2002
30b8382935SToomas Soome  * - Add comments on state->bits assertion in inffast.c
31b8382935SToomas Soome  * - Add comments on op field in inftrees.h
32b8382935SToomas Soome  * - Fix bug in reuse of allocated window after inflateReset()
33b8382935SToomas Soome  * - Remove bit fields--back to byte structure for speed
34b8382935SToomas Soome  * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
35b8382935SToomas Soome  * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
36b8382935SToomas Soome  * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
37b8382935SToomas Soome  * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
38b8382935SToomas Soome  * - Use local copies of stream next and avail values, as well as local bit
39b8382935SToomas Soome  *   buffer and bit count in inflate()--for speed when inflate_fast() not used
40b8382935SToomas Soome  *
41b8382935SToomas Soome  * 1.2.beta4    1 Jan 2003
42b8382935SToomas Soome  * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
43b8382935SToomas Soome  * - Move a comment on output buffer sizes from inffast.c to inflate.c
44b8382935SToomas Soome  * - Add comments in inffast.c to introduce the inflate_fast() routine
45b8382935SToomas Soome  * - Rearrange window copies in inflate_fast() for speed and simplification
46b8382935SToomas Soome  * - Unroll last copy for window match in inflate_fast()
47b8382935SToomas Soome  * - Use local copies of window variables in inflate_fast() for speed
48b8382935SToomas Soome  * - Pull out common wnext == 0 case for speed in inflate_fast()
49b8382935SToomas Soome  * - Make op and len in inflate_fast() unsigned for consistency
50b8382935SToomas Soome  * - Add FAR to lcode and dcode declarations in inflate_fast()
51b8382935SToomas Soome  * - Simplified bad distance check in inflate_fast()
52b8382935SToomas Soome  * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
53b8382935SToomas Soome  *   source file infback.c to provide a call-back interface to inflate for
54b8382935SToomas Soome  *   programs like gzip and unzip -- uses window as output buffer to avoid
55b8382935SToomas Soome  *   window copying
56b8382935SToomas Soome  *
57b8382935SToomas Soome  * 1.2.beta5    1 Jan 2003
58b8382935SToomas Soome  * - Improved inflateBack() interface to allow the caller to provide initial
59b8382935SToomas Soome  *   input in strm.
60b8382935SToomas Soome  * - Fixed stored blocks bug in inflateBack()
61b8382935SToomas Soome  *
62b8382935SToomas Soome  * 1.2.beta6    4 Jan 2003
63b8382935SToomas Soome  * - Added comments in inffast.c on effectiveness of POSTINC
64b8382935SToomas Soome  * - Typecasting all around to reduce compiler warnings
65b8382935SToomas Soome  * - Changed loops from while (1) or do {} while (1) to for (;;), again to
66b8382935SToomas Soome  *   make compilers happy
67b8382935SToomas Soome  * - Changed type of window in inflateBackInit() to unsigned char *
68b8382935SToomas Soome  *
69b8382935SToomas Soome  * 1.2.beta7    27 Jan 2003
70b8382935SToomas Soome  * - Changed many types to unsigned or unsigned short to avoid warnings
71b8382935SToomas Soome  * - Added inflateCopy() function
72b8382935SToomas Soome  *
73b8382935SToomas Soome  * 1.2.0        9 Mar 2003
74b8382935SToomas Soome  * - Changed inflateBack() interface to provide separate opaque descriptors
75b8382935SToomas Soome  *   for the in() and out() functions
76b8382935SToomas Soome  * - Changed inflateBack() argument and in_func typedef to swap the length
77b8382935SToomas Soome  *   and buffer address return values for the input function
78b8382935SToomas Soome  * - Check next_in and next_out for Z_NULL on entry to inflate()
79b8382935SToomas Soome  *
80b8382935SToomas Soome  * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
81b8382935SToomas Soome  */
82b8382935SToomas Soome 
83b8382935SToomas Soome #include "zutil.h"
84b8382935SToomas Soome #include "inftrees.h"
85b8382935SToomas Soome #include "inflate.h"
86b8382935SToomas Soome #include "inffast.h"
87b8382935SToomas Soome 
88b8382935SToomas Soome #ifdef MAKEFIXED
89b8382935SToomas Soome #  ifndef BUILDFIXED
90b8382935SToomas Soome #    define BUILDFIXED
91b8382935SToomas Soome #  endif
92b8382935SToomas Soome #endif
93b8382935SToomas Soome 
94b8382935SToomas Soome /* function prototypes */
95b8382935SToomas Soome local int inflateStateCheck OF((z_streamp strm));
96b8382935SToomas Soome local void fixedtables OF((struct inflate_state FAR *state));
97b8382935SToomas Soome local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
98b8382935SToomas Soome                            unsigned copy));
99b8382935SToomas Soome #ifdef BUILDFIXED
100b8382935SToomas Soome    void makefixed OF((void));
101b8382935SToomas Soome #endif
102b8382935SToomas Soome local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
103b8382935SToomas Soome                               unsigned len));
104b8382935SToomas Soome 
inflateStateCheck(z_streamp strm)105b8382935SToomas Soome local int inflateStateCheck(z_streamp strm)
106b8382935SToomas Soome {
107b8382935SToomas Soome     struct inflate_state FAR *state;
108b8382935SToomas Soome     if (strm == Z_NULL ||
109b8382935SToomas Soome         strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
110b8382935SToomas Soome         return 1;
111b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
112b8382935SToomas Soome     if (state == Z_NULL || state->strm != strm ||
113b8382935SToomas Soome         state->mode < HEAD || state->mode > SYNC)
114b8382935SToomas Soome         return 1;
115b8382935SToomas Soome     return 0;
116b8382935SToomas Soome }
117b8382935SToomas Soome 
inflateResetKeep(z_streamp strm)118b8382935SToomas Soome int ZEXPORT inflateResetKeep(z_streamp strm)
119b8382935SToomas Soome {
120b8382935SToomas Soome     struct inflate_state FAR *state;
121b8382935SToomas Soome 
122b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
123b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
124b8382935SToomas Soome     strm->total_in = strm->total_out = state->total = 0;
125b8382935SToomas Soome     strm->msg = Z_NULL;
126b8382935SToomas Soome     if (state->wrap)        /* to support ill-conceived Java test suite */
127b8382935SToomas Soome         strm->adler = state->wrap & 1;
128b8382935SToomas Soome     state->mode = HEAD;
129b8382935SToomas Soome     state->last = 0;
130b8382935SToomas Soome     state->havedict = 0;
131148fd93eSToomas Soome     state->flags = -1;
132b8382935SToomas Soome     state->dmax = 32768U;
133b8382935SToomas Soome     state->head = Z_NULL;
134b8382935SToomas Soome     state->hold = 0;
135b8382935SToomas Soome     state->bits = 0;
136b8382935SToomas Soome     state->lencode = state->distcode = state->next = state->codes;
137b8382935SToomas Soome     state->sane = 1;
138b8382935SToomas Soome     state->back = -1;
139b8382935SToomas Soome     Tracev((stderr, "inflate: reset\n"));
140b8382935SToomas Soome     return Z_OK;
141b8382935SToomas Soome }
142b8382935SToomas Soome 
inflateReset(z_streamp strm)143b8382935SToomas Soome int ZEXPORT inflateReset(z_streamp strm)
144b8382935SToomas Soome {
145b8382935SToomas Soome     struct inflate_state FAR *state;
146b8382935SToomas Soome 
147b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
148b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
149b8382935SToomas Soome     state->wsize = 0;
150b8382935SToomas Soome     state->whave = 0;
151b8382935SToomas Soome     state->wnext = 0;
152b8382935SToomas Soome     return inflateResetKeep(strm);
153b8382935SToomas Soome }
154b8382935SToomas Soome 
inflateReset2(z_streamp strm,int windowBits)155b8382935SToomas Soome int ZEXPORT inflateReset2(z_streamp strm, int windowBits)
156b8382935SToomas Soome {
157b8382935SToomas Soome     int wrap;
158b8382935SToomas Soome     struct inflate_state FAR *state;
159b8382935SToomas Soome 
160b8382935SToomas Soome     /* get the state */
161b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
162b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
163b8382935SToomas Soome 
164b8382935SToomas Soome     /* extract wrap request from windowBits parameter */
165b8382935SToomas Soome     if (windowBits < 0) {
166b8382935SToomas Soome         wrap = 0;
167b8382935SToomas Soome         windowBits = -windowBits;
168b8382935SToomas Soome     }
169b8382935SToomas Soome     else {
170b8382935SToomas Soome         wrap = (windowBits >> 4) + 5;
171b8382935SToomas Soome #ifdef GUNZIP
172b8382935SToomas Soome         if (windowBits < 48)
173b8382935SToomas Soome             windowBits &= 15;
174b8382935SToomas Soome #endif
175b8382935SToomas Soome     }
176b8382935SToomas Soome 
177b8382935SToomas Soome     /* set number of window bits, free window if different */
178b8382935SToomas Soome     if (windowBits && (windowBits < 8 || windowBits > 15))
179b8382935SToomas Soome         return Z_STREAM_ERROR;
180b8382935SToomas Soome     if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
181b8382935SToomas Soome         ZFREE(strm, state->window);
182b8382935SToomas Soome         state->window = Z_NULL;
183b8382935SToomas Soome     }
184b8382935SToomas Soome 
185b8382935SToomas Soome     /* update state and reset the rest of it */
186b8382935SToomas Soome     state->wrap = wrap;
187b8382935SToomas Soome     state->wbits = (unsigned)windowBits;
188b8382935SToomas Soome     return inflateReset(strm);
189b8382935SToomas Soome }
190b8382935SToomas Soome 
inflateInit2_(z_streamp strm,int windowBits,const char * version,int stream_size)191b8382935SToomas Soome int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version,
192b8382935SToomas Soome     int stream_size)
193b8382935SToomas Soome {
194b8382935SToomas Soome     int ret;
195b8382935SToomas Soome     struct inflate_state FAR *state;
196b8382935SToomas Soome 
197b8382935SToomas Soome     if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
198b8382935SToomas Soome         stream_size != (int)(sizeof(z_stream)))
199b8382935SToomas Soome         return Z_VERSION_ERROR;
200b8382935SToomas Soome     if (strm == Z_NULL) return Z_STREAM_ERROR;
201b8382935SToomas Soome     strm->msg = Z_NULL;                 /* in case we return an error */
202b8382935SToomas Soome     if (strm->zalloc == (alloc_func)0) {
203b8382935SToomas Soome #ifdef Z_SOLO
204b8382935SToomas Soome         return Z_STREAM_ERROR;
205b8382935SToomas Soome #else
206b8382935SToomas Soome         strm->zalloc = zcalloc;
207b8382935SToomas Soome         strm->opaque = (voidpf)0;
208b8382935SToomas Soome #endif
209b8382935SToomas Soome     }
210b8382935SToomas Soome     if (strm->zfree == (free_func)0)
211b8382935SToomas Soome #ifdef Z_SOLO
212b8382935SToomas Soome         return Z_STREAM_ERROR;
213b8382935SToomas Soome #else
214b8382935SToomas Soome         strm->zfree = zcfree;
215b8382935SToomas Soome #endif
216b8382935SToomas Soome     state = (struct inflate_state FAR *)
217b8382935SToomas Soome             ZALLOC(strm, 1, sizeof(struct inflate_state));
218b8382935SToomas Soome     if (state == Z_NULL) return Z_MEM_ERROR;
219b8382935SToomas Soome     Tracev((stderr, "inflate: allocated\n"));
220b8382935SToomas Soome     strm->state = (struct internal_state FAR *)state;
221b8382935SToomas Soome     state->strm = strm;
222b8382935SToomas Soome     state->window = Z_NULL;
223b8382935SToomas Soome     state->mode = HEAD;     /* to pass state test in inflateReset2() */
224b8382935SToomas Soome     ret = inflateReset2(strm, windowBits);
225b8382935SToomas Soome     if (ret != Z_OK) {
226b8382935SToomas Soome         ZFREE(strm, state);
227b8382935SToomas Soome         strm->state = Z_NULL;
228b8382935SToomas Soome     }
229b8382935SToomas Soome     return ret;
230b8382935SToomas Soome }
231b8382935SToomas Soome 
inflateInit_(z_streamp strm,const char * version,int stream_size)232b8382935SToomas Soome int ZEXPORT inflateInit_(z_streamp strm, const char *version, int stream_size)
233b8382935SToomas Soome {
234b8382935SToomas Soome     return inflateInit2_(strm, DEF_WBITS, version, stream_size);
235b8382935SToomas Soome }
236b8382935SToomas Soome 
inflatePrime(z_streamp strm,int bits,int value)237b8382935SToomas Soome int ZEXPORT inflatePrime(z_streamp strm, int bits, int value)
238b8382935SToomas Soome {
239b8382935SToomas Soome     struct inflate_state FAR *state;
240b8382935SToomas Soome 
241b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
242b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
243b8382935SToomas Soome     if (bits < 0) {
244b8382935SToomas Soome         state->hold = 0;
245b8382935SToomas Soome         state->bits = 0;
246b8382935SToomas Soome         return Z_OK;
247b8382935SToomas Soome     }
248b8382935SToomas Soome     if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
249b8382935SToomas Soome     value &= (1L << bits) - 1;
250b8382935SToomas Soome     state->hold += (unsigned)value << state->bits;
251b8382935SToomas Soome     state->bits += (uInt)bits;
252b8382935SToomas Soome     return Z_OK;
253b8382935SToomas Soome }
254b8382935SToomas Soome 
255b8382935SToomas Soome /*
256b8382935SToomas Soome    Return state with length and distance decoding tables and index sizes set to
257b8382935SToomas Soome    fixed code decoding.  Normally this returns fixed tables from inffixed.h.
258b8382935SToomas Soome    If BUILDFIXED is defined, then instead this routine builds the tables the
259b8382935SToomas Soome    first time it's called, and returns those tables the first time and
260b8382935SToomas Soome    thereafter.  This reduces the size of the code by about 2K bytes, in
261b8382935SToomas Soome    exchange for a little execution time.  However, BUILDFIXED should not be
262b8382935SToomas Soome    used for threaded applications, since the rewriting of the tables and virgin
263b8382935SToomas Soome    may not be thread-safe.
264b8382935SToomas Soome  */
fixedtables(struct inflate_state FAR * state)265b8382935SToomas Soome local void fixedtables(struct inflate_state FAR *state)
266b8382935SToomas Soome {
267b8382935SToomas Soome #ifdef BUILDFIXED
268b8382935SToomas Soome     static int virgin = 1;
269b8382935SToomas Soome     static code *lenfix, *distfix;
270b8382935SToomas Soome     static code fixed[544];
271b8382935SToomas Soome 
272b8382935SToomas Soome     /* build fixed huffman tables if first call (may not be thread safe) */
273b8382935SToomas Soome     if (virgin) {
274b8382935SToomas Soome         unsigned sym, bits;
275b8382935SToomas Soome         static code *next;
276b8382935SToomas Soome 
277b8382935SToomas Soome         /* literal/length table */
278b8382935SToomas Soome         sym = 0;
279b8382935SToomas Soome         while (sym < 144) state->lens[sym++] = 8;
280b8382935SToomas Soome         while (sym < 256) state->lens[sym++] = 9;
281b8382935SToomas Soome         while (sym < 280) state->lens[sym++] = 7;
282b8382935SToomas Soome         while (sym < 288) state->lens[sym++] = 8;
283b8382935SToomas Soome         next = fixed;
284b8382935SToomas Soome         lenfix = next;
285b8382935SToomas Soome         bits = 9;
286b8382935SToomas Soome         inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
287b8382935SToomas Soome 
288b8382935SToomas Soome         /* distance table */
289b8382935SToomas Soome         sym = 0;
290b8382935SToomas Soome         while (sym < 32) state->lens[sym++] = 5;
291b8382935SToomas Soome         distfix = next;
292b8382935SToomas Soome         bits = 5;
293b8382935SToomas Soome         inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
294b8382935SToomas Soome 
295b8382935SToomas Soome         /* do this just once */
296b8382935SToomas Soome         virgin = 0;
297b8382935SToomas Soome     }
298b8382935SToomas Soome #else /* !BUILDFIXED */
299b8382935SToomas Soome #   include "inffixed.h"
300b8382935SToomas Soome #endif /* BUILDFIXED */
301b8382935SToomas Soome     state->lencode = lenfix;
302b8382935SToomas Soome     state->lenbits = 9;
303b8382935SToomas Soome     state->distcode = distfix;
304b8382935SToomas Soome     state->distbits = 5;
305b8382935SToomas Soome }
306b8382935SToomas Soome 
307b8382935SToomas Soome #ifdef MAKEFIXED
308b8382935SToomas Soome #include <stdio.h>
309b8382935SToomas Soome 
310b8382935SToomas Soome /*
311b8382935SToomas Soome    Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
312b8382935SToomas Soome    defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
313b8382935SToomas Soome    those tables to stdout, which would be piped to inffixed.h.  A small program
314b8382935SToomas Soome    can simply call makefixed to do this:
315b8382935SToomas Soome 
316b8382935SToomas Soome     void makefixed(void);
317b8382935SToomas Soome 
318b8382935SToomas Soome     int main(void)
319b8382935SToomas Soome     {
320b8382935SToomas Soome         makefixed();
321b8382935SToomas Soome         return 0;
322b8382935SToomas Soome     }
323b8382935SToomas Soome 
324b8382935SToomas Soome    Then that can be linked with zlib built with MAKEFIXED defined and run:
325b8382935SToomas Soome 
326b8382935SToomas Soome     a.out > inffixed.h
327b8382935SToomas Soome  */
makefixed(void)328b8382935SToomas Soome void makefixed(void)
329b8382935SToomas Soome {
330b8382935SToomas Soome     unsigned low, size;
331b8382935SToomas Soome     struct inflate_state state;
332b8382935SToomas Soome 
333b8382935SToomas Soome     fixedtables(&state);
334b8382935SToomas Soome     puts("    /* inffixed.h -- table for decoding fixed codes");
335b8382935SToomas Soome     puts("     * Generated automatically by makefixed().");
336b8382935SToomas Soome     puts("     */");
337b8382935SToomas Soome     puts("");
338b8382935SToomas Soome     puts("    /* WARNING: this file should *not* be used by applications.");
339b8382935SToomas Soome     puts("       It is part of the implementation of this library and is");
340b8382935SToomas Soome     puts("       subject to change. Applications should only use zlib.h.");
341b8382935SToomas Soome     puts("     */");
342b8382935SToomas Soome     puts("");
343b8382935SToomas Soome     size = 1U << 9;
344b8382935SToomas Soome     printf("    static const code lenfix[%u] = {", size);
345b8382935SToomas Soome     low = 0;
346b8382935SToomas Soome     for (;;) {
347b8382935SToomas Soome         if ((low % 7) == 0) printf("\n        ");
348b8382935SToomas Soome         printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
349b8382935SToomas Soome                state.lencode[low].bits, state.lencode[low].val);
350b8382935SToomas Soome         if (++low == size) break;
351b8382935SToomas Soome         putchar(',');
352b8382935SToomas Soome     }
353b8382935SToomas Soome     puts("\n    };");
354b8382935SToomas Soome     size = 1U << 5;
355b8382935SToomas Soome     printf("\n    static const code distfix[%u] = {", size);
356b8382935SToomas Soome     low = 0;
357b8382935SToomas Soome     for (;;) {
358b8382935SToomas Soome         if ((low % 6) == 0) printf("\n        ");
359b8382935SToomas Soome         printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
360b8382935SToomas Soome                state.distcode[low].val);
361b8382935SToomas Soome         if (++low == size) break;
362b8382935SToomas Soome         putchar(',');
363b8382935SToomas Soome     }
364b8382935SToomas Soome     puts("\n    };");
365b8382935SToomas Soome }
366b8382935SToomas Soome #endif /* MAKEFIXED */
367b8382935SToomas Soome 
368b8382935SToomas Soome /*
369b8382935SToomas Soome    Update the window with the last wsize (normally 32K) bytes written before
370b8382935SToomas Soome    returning.  If window does not exist yet, create it.  This is only called
371b8382935SToomas Soome    when a window is already in use, or when output has been written during this
372b8382935SToomas Soome    inflate call, but the end of the deflate stream has not been reached yet.
373b8382935SToomas Soome    It is also called to create a window for dictionary data when a dictionary
374b8382935SToomas Soome    is loaded.
375b8382935SToomas Soome 
376b8382935SToomas Soome    Providing output buffers larger than 32K to inflate() should provide a speed
377b8382935SToomas Soome    advantage, since only the last 32K of output is copied to the sliding window
378b8382935SToomas Soome    upon return from inflate(), and since all distances after the first 32K of
379b8382935SToomas Soome    output will fall in the output data, making match copies simpler and faster.
380b8382935SToomas Soome    The advantage may be dependent on the size of the processor's data caches.
381b8382935SToomas Soome  */
updatewindow(z_streamp strm,const Bytef * end,unsigned copy)382b8382935SToomas Soome local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy)
383b8382935SToomas Soome {
384b8382935SToomas Soome     struct inflate_state FAR *state;
385b8382935SToomas Soome     unsigned dist;
386b8382935SToomas Soome 
387b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
388b8382935SToomas Soome 
389b8382935SToomas Soome     /* if it hasn't been done already, allocate space for the window */
390b8382935SToomas Soome     if (state->window == Z_NULL) {
391b8382935SToomas Soome         state->window = (unsigned char FAR *)
392b8382935SToomas Soome                         ZALLOC(strm, 1U << state->wbits,
393b8382935SToomas Soome                                sizeof(unsigned char));
394b8382935SToomas Soome         if (state->window == Z_NULL) return 1;
395b8382935SToomas Soome     }
396b8382935SToomas Soome 
397b8382935SToomas Soome     /* if window not in use yet, initialize */
398b8382935SToomas Soome     if (state->wsize == 0) {
399b8382935SToomas Soome         state->wsize = 1U << state->wbits;
400b8382935SToomas Soome         state->wnext = 0;
401b8382935SToomas Soome         state->whave = 0;
402b8382935SToomas Soome     }
403b8382935SToomas Soome 
404b8382935SToomas Soome     /* copy state->wsize or less output bytes into the circular window */
405b8382935SToomas Soome     if (copy >= state->wsize) {
406b8382935SToomas Soome         zmemcpy(state->window, end - state->wsize, state->wsize);
407b8382935SToomas Soome         state->wnext = 0;
408b8382935SToomas Soome         state->whave = state->wsize;
409b8382935SToomas Soome     }
410b8382935SToomas Soome     else {
411b8382935SToomas Soome         dist = state->wsize - state->wnext;
412b8382935SToomas Soome         if (dist > copy) dist = copy;
413b8382935SToomas Soome         zmemcpy(state->window + state->wnext, end - copy, dist);
414b8382935SToomas Soome         copy -= dist;
415b8382935SToomas Soome         if (copy) {
416b8382935SToomas Soome             zmemcpy(state->window, end - copy, copy);
417b8382935SToomas Soome             state->wnext = copy;
418b8382935SToomas Soome             state->whave = state->wsize;
419b8382935SToomas Soome         }
420b8382935SToomas Soome         else {
421b8382935SToomas Soome             state->wnext += dist;
422b8382935SToomas Soome             if (state->wnext == state->wsize) state->wnext = 0;
423b8382935SToomas Soome             if (state->whave < state->wsize) state->whave += dist;
424b8382935SToomas Soome         }
425b8382935SToomas Soome     }
426b8382935SToomas Soome     return 0;
427b8382935SToomas Soome }
428b8382935SToomas Soome 
429b8382935SToomas Soome /* Macros for inflate(): */
430b8382935SToomas Soome 
431b8382935SToomas Soome /* check function to use adler32() for zlib or crc32() for gzip */
432b8382935SToomas Soome #ifdef GUNZIP
433148fd93eSToomas Soome #  define UPDATE_CHECK(check, buf, len) \
434b8382935SToomas Soome     (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
435b8382935SToomas Soome #else
436148fd93eSToomas Soome #  define UPDATE_CHECK(check, buf, len) adler32(check, buf, len)
437b8382935SToomas Soome #endif
438b8382935SToomas Soome 
439b8382935SToomas Soome /* check macros for header crc */
440b8382935SToomas Soome #ifdef GUNZIP
441b8382935SToomas Soome #  define CRC2(check, word) \
442b8382935SToomas Soome     do { \
443b8382935SToomas Soome         hbuf[0] = (unsigned char)(word); \
444b8382935SToomas Soome         hbuf[1] = (unsigned char)((word) >> 8); \
445b8382935SToomas Soome         check = crc32(check, hbuf, 2); \
446b8382935SToomas Soome     } while (0)
447b8382935SToomas Soome 
448b8382935SToomas Soome #  define CRC4(check, word) \
449b8382935SToomas Soome     do { \
450b8382935SToomas Soome         hbuf[0] = (unsigned char)(word); \
451b8382935SToomas Soome         hbuf[1] = (unsigned char)((word) >> 8); \
452b8382935SToomas Soome         hbuf[2] = (unsigned char)((word) >> 16); \
453b8382935SToomas Soome         hbuf[3] = (unsigned char)((word) >> 24); \
454b8382935SToomas Soome         check = crc32(check, hbuf, 4); \
455b8382935SToomas Soome     } while (0)
456b8382935SToomas Soome #endif
457b8382935SToomas Soome 
458b8382935SToomas Soome /* Load registers with state in inflate() for speed */
459b8382935SToomas Soome #define LOAD() \
460b8382935SToomas Soome     do { \
461b8382935SToomas Soome         put = strm->next_out; \
462b8382935SToomas Soome         left = strm->avail_out; \
463b8382935SToomas Soome         next = strm->next_in; \
464b8382935SToomas Soome         have = strm->avail_in; \
465b8382935SToomas Soome         hold = state->hold; \
466b8382935SToomas Soome         bits = state->bits; \
467b8382935SToomas Soome     } while (0)
468b8382935SToomas Soome 
469b8382935SToomas Soome /* Restore state from registers in inflate() */
470b8382935SToomas Soome #define RESTORE() \
471b8382935SToomas Soome     do { \
472b8382935SToomas Soome         strm->next_out = put; \
473b8382935SToomas Soome         strm->avail_out = left; \
474b8382935SToomas Soome         strm->next_in = next; \
475b8382935SToomas Soome         strm->avail_in = have; \
476b8382935SToomas Soome         state->hold = hold; \
477b8382935SToomas Soome         state->bits = bits; \
478b8382935SToomas Soome     } while (0)
479b8382935SToomas Soome 
480b8382935SToomas Soome /* Clear the input bit accumulator */
481b8382935SToomas Soome #define INITBITS() \
482b8382935SToomas Soome     do { \
483b8382935SToomas Soome         hold = 0; \
484b8382935SToomas Soome         bits = 0; \
485b8382935SToomas Soome     } while (0)
486b8382935SToomas Soome 
487b8382935SToomas Soome /* Get a byte of input into the bit accumulator, or return from inflate()
488b8382935SToomas Soome    if there is no input available. */
489b8382935SToomas Soome #define PULLBYTE() \
490b8382935SToomas Soome     do { \
491b8382935SToomas Soome         if (have == 0) goto inf_leave; \
492b8382935SToomas Soome         have--; \
493b8382935SToomas Soome         hold += (unsigned long)(*next++) << bits; \
494b8382935SToomas Soome         bits += 8; \
495b8382935SToomas Soome     } while (0)
496b8382935SToomas Soome 
497b8382935SToomas Soome /* Assure that there are at least n bits in the bit accumulator.  If there is
498b8382935SToomas Soome    not enough available input to do that, then return from inflate(). */
499b8382935SToomas Soome #define NEEDBITS(n) \
500b8382935SToomas Soome     do { \
501b8382935SToomas Soome         while (bits < (unsigned)(n)) \
502b8382935SToomas Soome             PULLBYTE(); \
503b8382935SToomas Soome     } while (0)
504b8382935SToomas Soome 
505b8382935SToomas Soome /* Return the low n bits of the bit accumulator (n < 16) */
506b8382935SToomas Soome #define BITS(n) \
507b8382935SToomas Soome     ((unsigned)hold & ((1U << (n)) - 1))
508b8382935SToomas Soome 
509b8382935SToomas Soome /* Remove n bits from the bit accumulator */
510b8382935SToomas Soome #define DROPBITS(n) \
511b8382935SToomas Soome     do { \
512b8382935SToomas Soome         hold >>= (n); \
513b8382935SToomas Soome         bits -= (unsigned)(n); \
514b8382935SToomas Soome     } while (0)
515b8382935SToomas Soome 
516b8382935SToomas Soome /* Remove zero to seven bits as needed to go to a byte boundary */
517b8382935SToomas Soome #define BYTEBITS() \
518b8382935SToomas Soome     do { \
519b8382935SToomas Soome         hold >>= bits & 7; \
520b8382935SToomas Soome         bits -= bits & 7; \
521b8382935SToomas Soome     } while (0)
522b8382935SToomas Soome 
523b8382935SToomas Soome /*
524b8382935SToomas Soome    inflate() uses a state machine to process as much input data and generate as
525b8382935SToomas Soome    much output data as possible before returning.  The state machine is
526b8382935SToomas Soome    structured roughly as follows:
527b8382935SToomas Soome 
528b8382935SToomas Soome     for (;;) switch (state) {
529b8382935SToomas Soome     ...
530b8382935SToomas Soome     case STATEn:
531b8382935SToomas Soome         if (not enough input data or output space to make progress)
532b8382935SToomas Soome             return;
533b8382935SToomas Soome         ... make progress ...
534b8382935SToomas Soome         state = STATEm;
535b8382935SToomas Soome         break;
536b8382935SToomas Soome     ...
537b8382935SToomas Soome     }
538b8382935SToomas Soome 
539b8382935SToomas Soome    so when inflate() is called again, the same case is attempted again, and
540b8382935SToomas Soome    if the appropriate resources are provided, the machine proceeds to the
541b8382935SToomas Soome    next state.  The NEEDBITS() macro is usually the way the state evaluates
542b8382935SToomas Soome    whether it can proceed or should return.  NEEDBITS() does the return if
543b8382935SToomas Soome    the requested bits are not available.  The typical use of the BITS macros
544b8382935SToomas Soome    is:
545b8382935SToomas Soome 
546b8382935SToomas Soome         NEEDBITS(n);
547b8382935SToomas Soome         ... do something with BITS(n) ...
548b8382935SToomas Soome         DROPBITS(n);
549b8382935SToomas Soome 
550b8382935SToomas Soome    where NEEDBITS(n) either returns from inflate() if there isn't enough
551b8382935SToomas Soome    input left to load n bits into the accumulator, or it continues.  BITS(n)
552b8382935SToomas Soome    gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
553b8382935SToomas Soome    the low n bits off the accumulator.  INITBITS() clears the accumulator
554b8382935SToomas Soome    and sets the number of available bits to zero.  BYTEBITS() discards just
555b8382935SToomas Soome    enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
556b8382935SToomas Soome    and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
557b8382935SToomas Soome 
558b8382935SToomas Soome    NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
559b8382935SToomas Soome    if there is no input available.  The decoding of variable length codes uses
560b8382935SToomas Soome    PULLBYTE() directly in order to pull just enough bytes to decode the next
561b8382935SToomas Soome    code, and no more.
562b8382935SToomas Soome 
563b8382935SToomas Soome    Some states loop until they get enough input, making sure that enough
564b8382935SToomas Soome    state information is maintained to continue the loop where it left off
565b8382935SToomas Soome    if NEEDBITS() returns in the loop.  For example, want, need, and keep
566b8382935SToomas Soome    would all have to actually be part of the saved state in case NEEDBITS()
567b8382935SToomas Soome    returns:
568b8382935SToomas Soome 
569b8382935SToomas Soome     case STATEw:
570b8382935SToomas Soome         while (want < need) {
571b8382935SToomas Soome             NEEDBITS(n);
572b8382935SToomas Soome             keep[want++] = BITS(n);
573b8382935SToomas Soome             DROPBITS(n);
574b8382935SToomas Soome         }
575b8382935SToomas Soome         state = STATEx;
576b8382935SToomas Soome     case STATEx:
577b8382935SToomas Soome 
578b8382935SToomas Soome    As shown above, if the next state is also the next case, then the break
579b8382935SToomas Soome    is omitted.
580b8382935SToomas Soome 
581b8382935SToomas Soome    A state may also return if there is not enough output space available to
582b8382935SToomas Soome    complete that state.  Those states are copying stored data, writing a
583b8382935SToomas Soome    literal byte, and copying a matching string.
584b8382935SToomas Soome 
585b8382935SToomas Soome    When returning, a "goto inf_leave" is used to update the total counters,
586b8382935SToomas Soome    update the check value, and determine whether any progress has been made
587b8382935SToomas Soome    during that inflate() call in order to return the proper return code.
588b8382935SToomas Soome    Progress is defined as a change in either strm->avail_in or strm->avail_out.
589b8382935SToomas Soome    When there is a window, goto inf_leave will update the window with the last
590b8382935SToomas Soome    output written.  If a goto inf_leave occurs in the middle of decompression
591b8382935SToomas Soome    and there is no window currently, goto inf_leave will create one and copy
592b8382935SToomas Soome    output to the window for the next call of inflate().
593b8382935SToomas Soome 
594b8382935SToomas Soome    In this implementation, the flush parameter of inflate() only affects the
595b8382935SToomas Soome    return code (per zlib.h).  inflate() always writes as much as possible to
596b8382935SToomas Soome    strm->next_out, given the space available and the provided input--the effect
597b8382935SToomas Soome    documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
598b8382935SToomas Soome    the allocation of and copying into a sliding window until necessary, which
599b8382935SToomas Soome    provides the effect documented in zlib.h for Z_FINISH when the entire input
600b8382935SToomas Soome    stream available.  So the only thing the flush parameter actually does is:
601b8382935SToomas Soome    when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
602b8382935SToomas Soome    will return Z_BUF_ERROR if it has not reached the end of the stream.
603b8382935SToomas Soome  */
604b8382935SToomas Soome 
inflate(z_streamp strm,int flush)605b8382935SToomas Soome int ZEXPORT inflate(z_streamp strm, int flush)
606b8382935SToomas Soome {
607b8382935SToomas Soome     struct inflate_state FAR *state;
608b8382935SToomas Soome     z_const unsigned char FAR *next;    /* next input */
609b8382935SToomas Soome     unsigned char FAR *put;     /* next output */
610b8382935SToomas Soome     unsigned have, left;        /* available input and output */
611b8382935SToomas Soome     unsigned long hold;         /* bit buffer */
612b8382935SToomas Soome     unsigned bits;              /* bits in bit buffer */
613b8382935SToomas Soome     unsigned in, out;           /* save starting available input and output */
614b8382935SToomas Soome     unsigned copy;              /* number of stored or match bytes to copy */
615b8382935SToomas Soome     unsigned char FAR *from;    /* where to copy match bytes from */
616b8382935SToomas Soome     code here;                  /* current decoding table entry */
617b8382935SToomas Soome     code last;                  /* parent table entry */
618b8382935SToomas Soome     unsigned len;               /* length to copy for repeats, bits to drop */
619b8382935SToomas Soome     int ret;                    /* return code */
620b8382935SToomas Soome #ifdef GUNZIP
621b8382935SToomas Soome     unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
622b8382935SToomas Soome #endif
623b8382935SToomas Soome     static const unsigned short order[19] = /* permutation of code lengths */
624b8382935SToomas Soome         {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
625b8382935SToomas Soome 
626b8382935SToomas Soome     if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
627b8382935SToomas Soome         (strm->next_in == Z_NULL && strm->avail_in != 0))
628b8382935SToomas Soome         return Z_STREAM_ERROR;
629b8382935SToomas Soome 
630b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
631b8382935SToomas Soome     if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
632b8382935SToomas Soome     LOAD();
633b8382935SToomas Soome     in = have;
634b8382935SToomas Soome     out = left;
635b8382935SToomas Soome     ret = Z_OK;
636b8382935SToomas Soome     for (;;)
637b8382935SToomas Soome         switch (state->mode) {
638b8382935SToomas Soome         case HEAD:
639b8382935SToomas Soome             if (state->wrap == 0) {
640b8382935SToomas Soome                 state->mode = TYPEDO;
641b8382935SToomas Soome                 break;
642b8382935SToomas Soome             }
643b8382935SToomas Soome             NEEDBITS(16);
644b8382935SToomas Soome #ifdef GUNZIP
645b8382935SToomas Soome             if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
646b8382935SToomas Soome                 if (state->wbits == 0)
647b8382935SToomas Soome                     state->wbits = 15;
648b8382935SToomas Soome                 state->check = crc32(0L, Z_NULL, 0);
649b8382935SToomas Soome                 CRC2(state->check, hold);
650b8382935SToomas Soome                 INITBITS();
651b8382935SToomas Soome                 state->mode = FLAGS;
652b8382935SToomas Soome                 break;
653b8382935SToomas Soome             }
654b8382935SToomas Soome             if (state->head != Z_NULL)
655b8382935SToomas Soome                 state->head->done = -1;
656b8382935SToomas Soome             if (!(state->wrap & 1) ||   /* check if zlib header allowed */
657b8382935SToomas Soome #else
658b8382935SToomas Soome             if (
659b8382935SToomas Soome #endif
660b8382935SToomas Soome                 ((BITS(8) << 8) + (hold >> 8)) % 31) {
661b8382935SToomas Soome                 strm->msg = (char *)"incorrect header check";
662b8382935SToomas Soome                 state->mode = BAD;
663b8382935SToomas Soome                 break;
664b8382935SToomas Soome             }
665b8382935SToomas Soome             if (BITS(4) != Z_DEFLATED) {
666b8382935SToomas Soome                 strm->msg = (char *)"unknown compression method";
667b8382935SToomas Soome                 state->mode = BAD;
668b8382935SToomas Soome                 break;
669b8382935SToomas Soome             }
670b8382935SToomas Soome             DROPBITS(4);
671b8382935SToomas Soome             len = BITS(4) + 8;
672b8382935SToomas Soome             if (state->wbits == 0)
673b8382935SToomas Soome                 state->wbits = len;
674b8382935SToomas Soome             if (len > 15 || len > state->wbits) {
675b8382935SToomas Soome                 strm->msg = (char *)"invalid window size";
676b8382935SToomas Soome                 state->mode = BAD;
677b8382935SToomas Soome                 break;
678b8382935SToomas Soome             }
679b8382935SToomas Soome             state->dmax = 1U << len;
680148fd93eSToomas Soome             state->flags = 0;               /* indicate zlib header */
681b8382935SToomas Soome             Tracev((stderr, "inflate:   zlib header ok\n"));
682b8382935SToomas Soome             strm->adler = state->check = adler32(0L, Z_NULL, 0);
683b8382935SToomas Soome             state->mode = hold & 0x200 ? DICTID : TYPE;
684b8382935SToomas Soome             INITBITS();
685b8382935SToomas Soome             break;
686b8382935SToomas Soome #ifdef GUNZIP
687b8382935SToomas Soome         case FLAGS:
688b8382935SToomas Soome             NEEDBITS(16);
689b8382935SToomas Soome             state->flags = (int)(hold);
690b8382935SToomas Soome             if ((state->flags & 0xff) != Z_DEFLATED) {
691b8382935SToomas Soome                 strm->msg = (char *)"unknown compression method";
692b8382935SToomas Soome                 state->mode = BAD;
693b8382935SToomas Soome                 break;
694b8382935SToomas Soome             }
695b8382935SToomas Soome             if (state->flags & 0xe000) {
696b8382935SToomas Soome                 strm->msg = (char *)"unknown header flags set";
697b8382935SToomas Soome                 state->mode = BAD;
698b8382935SToomas Soome                 break;
699b8382935SToomas Soome             }
700b8382935SToomas Soome             if (state->head != Z_NULL)
701b8382935SToomas Soome                 state->head->text = (int)((hold >> 8) & 1);
702b8382935SToomas Soome             if ((state->flags & 0x0200) && (state->wrap & 4))
703b8382935SToomas Soome                 CRC2(state->check, hold);
704b8382935SToomas Soome             INITBITS();
705b8382935SToomas Soome             state->mode = TIME;
706148fd93eSToomas Soome                 /* fallthrough */
707b8382935SToomas Soome         case TIME:
708b8382935SToomas Soome             NEEDBITS(32);
709b8382935SToomas Soome             if (state->head != Z_NULL)
710b8382935SToomas Soome                 state->head->time = hold;
711b8382935SToomas Soome             if ((state->flags & 0x0200) && (state->wrap & 4))
712b8382935SToomas Soome                 CRC4(state->check, hold);
713b8382935SToomas Soome             INITBITS();
714b8382935SToomas Soome             state->mode = OS;
715148fd93eSToomas Soome                 /* fallthrough */
716b8382935SToomas Soome         case OS:
717b8382935SToomas Soome             NEEDBITS(16);
718b8382935SToomas Soome             if (state->head != Z_NULL) {
719b8382935SToomas Soome                 state->head->xflags = (int)(hold & 0xff);
720b8382935SToomas Soome                 state->head->os = (int)(hold >> 8);
721b8382935SToomas Soome             }
722b8382935SToomas Soome             if ((state->flags & 0x0200) && (state->wrap & 4))
723b8382935SToomas Soome                 CRC2(state->check, hold);
724b8382935SToomas Soome             INITBITS();
725b8382935SToomas Soome             state->mode = EXLEN;
726b8382935SToomas Soome 	    /* FALLTHROUGH */
727b8382935SToomas Soome         case EXLEN:
728b8382935SToomas Soome             if (state->flags & 0x0400) {
729b8382935SToomas Soome                 NEEDBITS(16);
730b8382935SToomas Soome                 state->length = (unsigned)(hold);
731b8382935SToomas Soome                 if (state->head != Z_NULL)
732b8382935SToomas Soome                     state->head->extra_len = (unsigned)hold;
733b8382935SToomas Soome                 if ((state->flags & 0x0200) && (state->wrap & 4))
734b8382935SToomas Soome                     CRC2(state->check, hold);
735b8382935SToomas Soome                 INITBITS();
736b8382935SToomas Soome             }
737b8382935SToomas Soome             else if (state->head != Z_NULL)
738b8382935SToomas Soome                 state->head->extra = Z_NULL;
739b8382935SToomas Soome             state->mode = EXTRA;
740b8382935SToomas Soome 	    /* FALLTHROUGH */
741b8382935SToomas Soome         case EXTRA:
742b8382935SToomas Soome             if (state->flags & 0x0400) {
743b8382935SToomas Soome                 copy = state->length;
744b8382935SToomas Soome                 if (copy > have) copy = have;
745b8382935SToomas Soome                 if (copy) {
746b8382935SToomas Soome                     if (state->head != Z_NULL &&
747*2e401babSMark Adler                         state->head->extra != Z_NULL &&
748*2e401babSMark Adler                         (len = state->head->extra_len - state->length) <
749*2e401babSMark Adler                             state->head->extra_max) {
750b8382935SToomas Soome                         zmemcpy(state->head->extra + len, next,
751b8382935SToomas Soome                                 len + copy > state->head->extra_max ?
752b8382935SToomas Soome                                 state->head->extra_max - len : copy);
753b8382935SToomas Soome                     }
754b8382935SToomas Soome                     if ((state->flags & 0x0200) && (state->wrap & 4))
755b8382935SToomas Soome                         state->check = crc32(state->check, next, copy);
756b8382935SToomas Soome                     have -= copy;
757b8382935SToomas Soome                     next += copy;
758b8382935SToomas Soome                     state->length -= copy;
759b8382935SToomas Soome                 }
760b8382935SToomas Soome                 if (state->length) goto inf_leave;
761b8382935SToomas Soome             }
762b8382935SToomas Soome             state->length = 0;
763b8382935SToomas Soome             state->mode = NAME;
764b8382935SToomas Soome 	    /* FALLTHROUGH */
765b8382935SToomas Soome         case NAME:
766b8382935SToomas Soome             if (state->flags & 0x0800) {
767b8382935SToomas Soome                 if (have == 0) goto inf_leave;
768b8382935SToomas Soome                 copy = 0;
769b8382935SToomas Soome                 do {
770b8382935SToomas Soome                     len = (unsigned)(next[copy++]);
771b8382935SToomas Soome                     if (state->head != Z_NULL &&
772b8382935SToomas Soome                             state->head->name != Z_NULL &&
773b8382935SToomas Soome                             state->length < state->head->name_max)
774b8382935SToomas Soome                         state->head->name[state->length++] = (Bytef)len;
775b8382935SToomas Soome                 } while (len && copy < have);
776b8382935SToomas Soome                 if ((state->flags & 0x0200) && (state->wrap & 4))
777b8382935SToomas Soome                     state->check = crc32(state->check, next, copy);
778b8382935SToomas Soome                 have -= copy;
779b8382935SToomas Soome                 next += copy;
780b8382935SToomas Soome                 if (len) goto inf_leave;
781b8382935SToomas Soome             }
782b8382935SToomas Soome             else if (state->head != Z_NULL)
783b8382935SToomas Soome                 state->head->name = Z_NULL;
784b8382935SToomas Soome             state->length = 0;
785b8382935SToomas Soome             state->mode = COMMENT;
786b8382935SToomas Soome 	    /* FALLTHROUGH */
787b8382935SToomas Soome         case COMMENT:
788b8382935SToomas Soome             if (state->flags & 0x1000) {
789b8382935SToomas Soome                 if (have == 0) goto inf_leave;
790b8382935SToomas Soome                 copy = 0;
791b8382935SToomas Soome                 do {
792b8382935SToomas Soome                     len = (unsigned)(next[copy++]);
793b8382935SToomas Soome                     if (state->head != Z_NULL &&
794b8382935SToomas Soome                             state->head->comment != Z_NULL &&
795b8382935SToomas Soome                             state->length < state->head->comm_max)
796b8382935SToomas Soome                         state->head->comment[state->length++] = (Bytef)len;
797b8382935SToomas Soome                 } while (len && copy < have);
798b8382935SToomas Soome                 if ((state->flags & 0x0200) && (state->wrap & 4))
799b8382935SToomas Soome                     state->check = crc32(state->check, next, copy);
800b8382935SToomas Soome                 have -= copy;
801b8382935SToomas Soome                 next += copy;
802b8382935SToomas Soome                 if (len) goto inf_leave;
803b8382935SToomas Soome             }
804b8382935SToomas Soome             else if (state->head != Z_NULL)
805b8382935SToomas Soome                 state->head->comment = Z_NULL;
806b8382935SToomas Soome             state->mode = HCRC;
807b8382935SToomas Soome 	    /* FALLTHROUGH */
808b8382935SToomas Soome         case HCRC:
809b8382935SToomas Soome             if (state->flags & 0x0200) {
810b8382935SToomas Soome                 NEEDBITS(16);
811b8382935SToomas Soome                 if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
812b8382935SToomas Soome                     strm->msg = (char *)"header crc mismatch";
813b8382935SToomas Soome                     state->mode = BAD;
814b8382935SToomas Soome                     break;
815b8382935SToomas Soome                 }
816b8382935SToomas Soome                 INITBITS();
817b8382935SToomas Soome             }
818b8382935SToomas Soome             if (state->head != Z_NULL) {
819b8382935SToomas Soome                 state->head->hcrc = (int)((state->flags >> 9) & 1);
820b8382935SToomas Soome                 state->head->done = 1;
821b8382935SToomas Soome             }
822b8382935SToomas Soome             strm->adler = state->check = crc32(0L, Z_NULL, 0);
823b8382935SToomas Soome             state->mode = TYPE;
824b8382935SToomas Soome             break;
825b8382935SToomas Soome #endif
826b8382935SToomas Soome         case DICTID:
827b8382935SToomas Soome             NEEDBITS(32);
828b8382935SToomas Soome             strm->adler = state->check = ZSWAP32(hold);
829b8382935SToomas Soome             INITBITS();
830b8382935SToomas Soome             state->mode = DICT;
831b8382935SToomas Soome 	    /* FALLTHROUGH */
832b8382935SToomas Soome         case DICT:
833b8382935SToomas Soome             if (state->havedict == 0) {
834b8382935SToomas Soome                 RESTORE();
835b8382935SToomas Soome                 return Z_NEED_DICT;
836b8382935SToomas Soome             }
837b8382935SToomas Soome             strm->adler = state->check = adler32(0L, Z_NULL, 0);
838b8382935SToomas Soome             state->mode = TYPE;
839b8382935SToomas Soome 	    /* FALLTHROUGH */
840b8382935SToomas Soome         case TYPE:
841b8382935SToomas Soome             if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
842b8382935SToomas Soome 	    /* FALLTHROUGH */
843b8382935SToomas Soome         case TYPEDO:
844b8382935SToomas Soome             if (state->last) {
845b8382935SToomas Soome                 BYTEBITS();
846b8382935SToomas Soome                 state->mode = CHECK;
847b8382935SToomas Soome                 break;
848b8382935SToomas Soome             }
849b8382935SToomas Soome             NEEDBITS(3);
850b8382935SToomas Soome             state->last = BITS(1);
851b8382935SToomas Soome             DROPBITS(1);
852b8382935SToomas Soome             switch (BITS(2)) {
853b8382935SToomas Soome             case 0:                             /* stored block */
854b8382935SToomas Soome                 Tracev((stderr, "inflate:     stored block%s\n",
855b8382935SToomas Soome                         state->last ? " (last)" : ""));
856b8382935SToomas Soome                 state->mode = STORED;
857b8382935SToomas Soome                 break;
858b8382935SToomas Soome             case 1:                             /* fixed block */
859b8382935SToomas Soome                 fixedtables(state);
860b8382935SToomas Soome                 Tracev((stderr, "inflate:     fixed codes block%s\n",
861b8382935SToomas Soome                         state->last ? " (last)" : ""));
862b8382935SToomas Soome                 state->mode = LEN_;             /* decode codes */
863b8382935SToomas Soome                 if (flush == Z_TREES) {
864b8382935SToomas Soome                     DROPBITS(2);
865b8382935SToomas Soome                     goto inf_leave;
866b8382935SToomas Soome                 }
867b8382935SToomas Soome                 break;
868b8382935SToomas Soome             case 2:                             /* dynamic block */
869b8382935SToomas Soome                 Tracev((stderr, "inflate:     dynamic codes block%s\n",
870b8382935SToomas Soome                         state->last ? " (last)" : ""));
871b8382935SToomas Soome                 state->mode = TABLE;
872b8382935SToomas Soome                 break;
873b8382935SToomas Soome             case 3:
874b8382935SToomas Soome                 strm->msg = (char *)"invalid block type";
875b8382935SToomas Soome                 state->mode = BAD;
876b8382935SToomas Soome             }
877b8382935SToomas Soome             DROPBITS(2);
878b8382935SToomas Soome             break;
879b8382935SToomas Soome         case STORED:
880b8382935SToomas Soome             BYTEBITS();                         /* go to byte boundary */
881b8382935SToomas Soome             NEEDBITS(32);
882b8382935SToomas Soome             if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
883b8382935SToomas Soome                 strm->msg = (char *)"invalid stored block lengths";
884b8382935SToomas Soome                 state->mode = BAD;
885b8382935SToomas Soome                 break;
886b8382935SToomas Soome             }
887b8382935SToomas Soome             state->length = (unsigned)hold & 0xffff;
888b8382935SToomas Soome             Tracev((stderr, "inflate:       stored length %u\n",
889b8382935SToomas Soome                     state->length));
890b8382935SToomas Soome             INITBITS();
891b8382935SToomas Soome             state->mode = COPY_;
892b8382935SToomas Soome             if (flush == Z_TREES) goto inf_leave;
893b8382935SToomas Soome 	    /* FALLTHROUGH */
894b8382935SToomas Soome         case COPY_:
895b8382935SToomas Soome             state->mode = COPY;
896b8382935SToomas Soome 	    /* FALLTHROUGH */
897b8382935SToomas Soome         case COPY:
898b8382935SToomas Soome             copy = state->length;
899b8382935SToomas Soome             if (copy) {
900b8382935SToomas Soome                 if (copy > have) copy = have;
901b8382935SToomas Soome                 if (copy > left) copy = left;
902b8382935SToomas Soome                 if (copy == 0) goto inf_leave;
903b8382935SToomas Soome                 zmemcpy(put, next, copy);
904b8382935SToomas Soome                 have -= copy;
905b8382935SToomas Soome                 next += copy;
906b8382935SToomas Soome                 left -= copy;
907b8382935SToomas Soome                 put += copy;
908b8382935SToomas Soome                 state->length -= copy;
909b8382935SToomas Soome                 break;
910b8382935SToomas Soome             }
911b8382935SToomas Soome             Tracev((stderr, "inflate:       stored end\n"));
912b8382935SToomas Soome             state->mode = TYPE;
913b8382935SToomas Soome             break;
914b8382935SToomas Soome         case TABLE:
915b8382935SToomas Soome             NEEDBITS(14);
916b8382935SToomas Soome             state->nlen = BITS(5) + 257;
917b8382935SToomas Soome             DROPBITS(5);
918b8382935SToomas Soome             state->ndist = BITS(5) + 1;
919b8382935SToomas Soome             DROPBITS(5);
920b8382935SToomas Soome             state->ncode = BITS(4) + 4;
921b8382935SToomas Soome             DROPBITS(4);
922b8382935SToomas Soome #ifndef PKZIP_BUG_WORKAROUND
923b8382935SToomas Soome             if (state->nlen > 286 || state->ndist > 30) {
924b8382935SToomas Soome                 strm->msg = (char *)"too many length or distance symbols";
925b8382935SToomas Soome                 state->mode = BAD;
926b8382935SToomas Soome                 break;
927b8382935SToomas Soome             }
928b8382935SToomas Soome #endif
929b8382935SToomas Soome             Tracev((stderr, "inflate:       table sizes ok\n"));
930b8382935SToomas Soome             state->have = 0;
931b8382935SToomas Soome             state->mode = LENLENS;
932148fd93eSToomas Soome                 /* fallthrough */
933b8382935SToomas Soome         case LENLENS:
934b8382935SToomas Soome             while (state->have < state->ncode) {
935b8382935SToomas Soome                 NEEDBITS(3);
936b8382935SToomas Soome                 state->lens[order[state->have++]] = (unsigned short)BITS(3);
937b8382935SToomas Soome                 DROPBITS(3);
938b8382935SToomas Soome             }
939b8382935SToomas Soome             while (state->have < 19)
940b8382935SToomas Soome                 state->lens[order[state->have++]] = 0;
941b8382935SToomas Soome             state->next = state->codes;
942b8382935SToomas Soome             state->lencode = (const code FAR *)(state->next);
943b8382935SToomas Soome             state->lenbits = 7;
944b8382935SToomas Soome             ret = inflate_table(CODES, state->lens, 19, &(state->next),
945b8382935SToomas Soome                                 &(state->lenbits), state->work);
946b8382935SToomas Soome             if (ret) {
947b8382935SToomas Soome                 strm->msg = (char *)"invalid code lengths set";
948b8382935SToomas Soome                 state->mode = BAD;
949b8382935SToomas Soome                 break;
950b8382935SToomas Soome             }
951b8382935SToomas Soome             Tracev((stderr, "inflate:       code lengths ok\n"));
952b8382935SToomas Soome             state->have = 0;
953b8382935SToomas Soome             state->mode = CODELENS;
954148fd93eSToomas Soome                 /* fallthrough */
955b8382935SToomas Soome         case CODELENS:
956b8382935SToomas Soome             while (state->have < state->nlen + state->ndist) {
957b8382935SToomas Soome                 for (;;) {
958b8382935SToomas Soome                     here = state->lencode[BITS(state->lenbits)];
959b8382935SToomas Soome                     if ((unsigned)(here.bits) <= bits) break;
960b8382935SToomas Soome                     PULLBYTE();
961b8382935SToomas Soome                 }
962b8382935SToomas Soome                 if (here.val < 16) {
963b8382935SToomas Soome                     DROPBITS(here.bits);
964b8382935SToomas Soome                     state->lens[state->have++] = here.val;
965b8382935SToomas Soome                 }
966b8382935SToomas Soome                 else {
967b8382935SToomas Soome                     if (here.val == 16) {
968b8382935SToomas Soome                         NEEDBITS(here.bits + 2);
969b8382935SToomas Soome                         DROPBITS(here.bits);
970b8382935SToomas Soome                         if (state->have == 0) {
971b8382935SToomas Soome                             strm->msg = (char *)"invalid bit length repeat";
972b8382935SToomas Soome                             state->mode = BAD;
973b8382935SToomas Soome                             break;
974b8382935SToomas Soome                         }
975b8382935SToomas Soome                         len = state->lens[state->have - 1];
976b8382935SToomas Soome                         copy = 3 + BITS(2);
977b8382935SToomas Soome                         DROPBITS(2);
978b8382935SToomas Soome                     }
979b8382935SToomas Soome                     else if (here.val == 17) {
980b8382935SToomas Soome                         NEEDBITS(here.bits + 3);
981b8382935SToomas Soome                         DROPBITS(here.bits);
982b8382935SToomas Soome                         len = 0;
983b8382935SToomas Soome                         copy = 3 + BITS(3);
984b8382935SToomas Soome                         DROPBITS(3);
985b8382935SToomas Soome                     }
986b8382935SToomas Soome                     else {
987b8382935SToomas Soome                         NEEDBITS(here.bits + 7);
988b8382935SToomas Soome                         DROPBITS(here.bits);
989b8382935SToomas Soome                         len = 0;
990b8382935SToomas Soome                         copy = 11 + BITS(7);
991b8382935SToomas Soome                         DROPBITS(7);
992b8382935SToomas Soome                     }
993b8382935SToomas Soome                     if (state->have + copy > state->nlen + state->ndist) {
994b8382935SToomas Soome                         strm->msg = (char *)"invalid bit length repeat";
995b8382935SToomas Soome                         state->mode = BAD;
996b8382935SToomas Soome                         break;
997b8382935SToomas Soome                     }
998b8382935SToomas Soome                     while (copy--)
999b8382935SToomas Soome                         state->lens[state->have++] = (unsigned short)len;
1000b8382935SToomas Soome                 }
1001b8382935SToomas Soome             }
1002b8382935SToomas Soome 
1003b8382935SToomas Soome             /* handle error breaks in while */
1004b8382935SToomas Soome             if (state->mode == BAD) break;
1005b8382935SToomas Soome 
1006b8382935SToomas Soome             /* check for end-of-block code (better have one) */
1007b8382935SToomas Soome             if (state->lens[256] == 0) {
1008b8382935SToomas Soome                 strm->msg = (char *)"invalid code -- missing end-of-block";
1009b8382935SToomas Soome                 state->mode = BAD;
1010b8382935SToomas Soome                 break;
1011b8382935SToomas Soome             }
1012b8382935SToomas Soome 
1013b8382935SToomas Soome             /* build code tables -- note: do not change the lenbits or distbits
1014b8382935SToomas Soome                values here (9 and 6) without reading the comments in inftrees.h
1015b8382935SToomas Soome                concerning the ENOUGH constants, which depend on those values */
1016b8382935SToomas Soome             state->next = state->codes;
1017b8382935SToomas Soome             state->lencode = (const code FAR *)(state->next);
1018b8382935SToomas Soome             state->lenbits = 9;
1019b8382935SToomas Soome             ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
1020b8382935SToomas Soome                                 &(state->lenbits), state->work);
1021b8382935SToomas Soome             if (ret) {
1022b8382935SToomas Soome                 strm->msg = (char *)"invalid literal/lengths set";
1023b8382935SToomas Soome                 state->mode = BAD;
1024b8382935SToomas Soome                 break;
1025b8382935SToomas Soome             }
1026b8382935SToomas Soome             state->distcode = (const code FAR *)(state->next);
1027b8382935SToomas Soome             state->distbits = 6;
1028b8382935SToomas Soome             ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
1029b8382935SToomas Soome                             &(state->next), &(state->distbits), state->work);
1030b8382935SToomas Soome             if (ret) {
1031b8382935SToomas Soome                 strm->msg = (char *)"invalid distances set";
1032b8382935SToomas Soome                 state->mode = BAD;
1033b8382935SToomas Soome                 break;
1034b8382935SToomas Soome             }
1035b8382935SToomas Soome             Tracev((stderr, "inflate:       codes ok\n"));
1036b8382935SToomas Soome             state->mode = LEN_;
1037b8382935SToomas Soome             if (flush == Z_TREES) goto inf_leave;
1038b8382935SToomas Soome 	    /* FALLTHROUGH */
1039b8382935SToomas Soome         case LEN_:
1040b8382935SToomas Soome             state->mode = LEN;
1041b8382935SToomas Soome 	    /* FALLTHROUGH */
1042b8382935SToomas Soome         case LEN:
1043b8382935SToomas Soome             if (have >= 6 && left >= 258) {
1044b8382935SToomas Soome                 RESTORE();
1045b8382935SToomas Soome                 inflate_fast(strm, out);
1046b8382935SToomas Soome                 LOAD();
1047b8382935SToomas Soome                 if (state->mode == TYPE)
1048b8382935SToomas Soome                     state->back = -1;
1049b8382935SToomas Soome                 break;
1050b8382935SToomas Soome             }
1051b8382935SToomas Soome             state->back = 0;
1052b8382935SToomas Soome             for (;;) {
1053b8382935SToomas Soome                 here = state->lencode[BITS(state->lenbits)];
1054b8382935SToomas Soome                 if ((unsigned)(here.bits) <= bits) break;
1055b8382935SToomas Soome                 PULLBYTE();
1056b8382935SToomas Soome             }
1057b8382935SToomas Soome             if (here.op && (here.op & 0xf0) == 0) {
1058b8382935SToomas Soome                 last = here;
1059b8382935SToomas Soome                 for (;;) {
1060b8382935SToomas Soome                     here = state->lencode[last.val +
1061b8382935SToomas Soome                             (BITS(last.bits + last.op) >> last.bits)];
1062b8382935SToomas Soome                     if ((unsigned)(last.bits + here.bits) <= bits) break;
1063b8382935SToomas Soome                     PULLBYTE();
1064b8382935SToomas Soome                 }
1065b8382935SToomas Soome                 DROPBITS(last.bits);
1066b8382935SToomas Soome                 state->back += last.bits;
1067b8382935SToomas Soome             }
1068b8382935SToomas Soome             DROPBITS(here.bits);
1069b8382935SToomas Soome             state->back += here.bits;
1070b8382935SToomas Soome             state->length = (unsigned)here.val;
1071b8382935SToomas Soome             if ((int)(here.op) == 0) {
1072b8382935SToomas Soome                 Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
1073b8382935SToomas Soome                         "inflate:         literal '%c'\n" :
1074b8382935SToomas Soome                         "inflate:         literal 0x%02x\n", here.val));
1075b8382935SToomas Soome                 state->mode = LIT;
1076b8382935SToomas Soome                 break;
1077b8382935SToomas Soome             }
1078b8382935SToomas Soome             if (here.op & 32) {
1079b8382935SToomas Soome                 Tracevv((stderr, "inflate:         end of block\n"));
1080b8382935SToomas Soome                 state->back = -1;
1081b8382935SToomas Soome                 state->mode = TYPE;
1082b8382935SToomas Soome                 break;
1083b8382935SToomas Soome             }
1084b8382935SToomas Soome             if (here.op & 64) {
1085b8382935SToomas Soome                 strm->msg = (char *)"invalid literal/length code";
1086b8382935SToomas Soome                 state->mode = BAD;
1087b8382935SToomas Soome                 break;
1088b8382935SToomas Soome             }
1089b8382935SToomas Soome             state->extra = (unsigned)(here.op) & 15;
1090b8382935SToomas Soome             state->mode = LENEXT;
1091b8382935SToomas Soome 	    /* FALLTHROUGH */
1092b8382935SToomas Soome         case LENEXT:
1093b8382935SToomas Soome             if (state->extra) {
1094b8382935SToomas Soome                 NEEDBITS(state->extra);
1095b8382935SToomas Soome                 state->length += BITS(state->extra);
1096b8382935SToomas Soome                 DROPBITS(state->extra);
1097b8382935SToomas Soome                 state->back += state->extra;
1098b8382935SToomas Soome             }
1099b8382935SToomas Soome             Tracevv((stderr, "inflate:         length %u\n", state->length));
1100b8382935SToomas Soome             state->was = state->length;
1101b8382935SToomas Soome             state->mode = DIST;
1102b8382935SToomas Soome 	    /* FALLTHROUGH */
1103b8382935SToomas Soome         case DIST:
1104b8382935SToomas Soome             for (;;) {
1105b8382935SToomas Soome                 here = state->distcode[BITS(state->distbits)];
1106b8382935SToomas Soome                 if ((unsigned)(here.bits) <= bits) break;
1107b8382935SToomas Soome                 PULLBYTE();
1108b8382935SToomas Soome             }
1109b8382935SToomas Soome             if ((here.op & 0xf0) == 0) {
1110b8382935SToomas Soome                 last = here;
1111b8382935SToomas Soome                 for (;;) {
1112b8382935SToomas Soome                     here = state->distcode[last.val +
1113b8382935SToomas Soome                             (BITS(last.bits + last.op) >> last.bits)];
1114b8382935SToomas Soome                     if ((unsigned)(last.bits + here.bits) <= bits) break;
1115b8382935SToomas Soome                     PULLBYTE();
1116b8382935SToomas Soome                 }
1117b8382935SToomas Soome                 DROPBITS(last.bits);
1118b8382935SToomas Soome                 state->back += last.bits;
1119b8382935SToomas Soome             }
1120b8382935SToomas Soome             DROPBITS(here.bits);
1121b8382935SToomas Soome             state->back += here.bits;
1122b8382935SToomas Soome             if (here.op & 64) {
1123b8382935SToomas Soome                 strm->msg = (char *)"invalid distance code";
1124b8382935SToomas Soome                 state->mode = BAD;
1125b8382935SToomas Soome                 break;
1126b8382935SToomas Soome             }
1127b8382935SToomas Soome             state->offset = (unsigned)here.val;
1128b8382935SToomas Soome             state->extra = (unsigned)(here.op) & 15;
1129b8382935SToomas Soome             state->mode = DISTEXT;
1130b8382935SToomas Soome 	    /* FALLTHROUGH */
1131b8382935SToomas Soome         case DISTEXT:
1132b8382935SToomas Soome             if (state->extra) {
1133b8382935SToomas Soome                 NEEDBITS(state->extra);
1134b8382935SToomas Soome                 state->offset += BITS(state->extra);
1135b8382935SToomas Soome                 DROPBITS(state->extra);
1136b8382935SToomas Soome                 state->back += state->extra;
1137b8382935SToomas Soome             }
1138b8382935SToomas Soome #ifdef INFLATE_STRICT
1139b8382935SToomas Soome             if (state->offset > state->dmax) {
1140b8382935SToomas Soome                 strm->msg = (char *)"invalid distance too far back";
1141b8382935SToomas Soome                 state->mode = BAD;
1142b8382935SToomas Soome                 break;
1143b8382935SToomas Soome             }
1144b8382935SToomas Soome #endif
1145b8382935SToomas Soome             Tracevv((stderr, "inflate:         distance %u\n", state->offset));
1146b8382935SToomas Soome             state->mode = MATCH;
1147b8382935SToomas Soome 	    /* FALLTHROUGH */
1148b8382935SToomas Soome         case MATCH:
1149b8382935SToomas Soome             if (left == 0) goto inf_leave;
1150b8382935SToomas Soome             copy = out - left;
1151b8382935SToomas Soome             if (state->offset > copy) {         /* copy from window */
1152b8382935SToomas Soome                 copy = state->offset - copy;
1153b8382935SToomas Soome                 if (copy > state->whave) {
1154b8382935SToomas Soome                     if (state->sane) {
1155b8382935SToomas Soome                         strm->msg = (char *)"invalid distance too far back";
1156b8382935SToomas Soome                         state->mode = BAD;
1157b8382935SToomas Soome                         break;
1158b8382935SToomas Soome                     }
1159b8382935SToomas Soome #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
1160b8382935SToomas Soome                     Trace((stderr, "inflate.c too far\n"));
1161b8382935SToomas Soome                     copy -= state->whave;
1162b8382935SToomas Soome                     if (copy > state->length) copy = state->length;
1163b8382935SToomas Soome                     if (copy > left) copy = left;
1164b8382935SToomas Soome                     left -= copy;
1165b8382935SToomas Soome                     state->length -= copy;
1166b8382935SToomas Soome                     do {
1167b8382935SToomas Soome                         *put++ = 0;
1168b8382935SToomas Soome                     } while (--copy);
1169b8382935SToomas Soome                     if (state->length == 0) state->mode = LEN;
1170b8382935SToomas Soome                     break;
1171b8382935SToomas Soome #endif
1172b8382935SToomas Soome                 }
1173b8382935SToomas Soome                 if (copy > state->wnext) {
1174b8382935SToomas Soome                     copy -= state->wnext;
1175b8382935SToomas Soome                     from = state->window + (state->wsize - copy);
1176b8382935SToomas Soome                 }
1177b8382935SToomas Soome                 else
1178b8382935SToomas Soome                     from = state->window + (state->wnext - copy);
1179b8382935SToomas Soome                 if (copy > state->length) copy = state->length;
1180b8382935SToomas Soome             }
1181b8382935SToomas Soome             else {                              /* copy from output */
1182b8382935SToomas Soome                 from = put - state->offset;
1183b8382935SToomas Soome                 copy = state->length;
1184b8382935SToomas Soome             }
1185b8382935SToomas Soome             if (copy > left) copy = left;
1186b8382935SToomas Soome             left -= copy;
1187b8382935SToomas Soome             state->length -= copy;
1188b8382935SToomas Soome             do {
1189b8382935SToomas Soome                 *put++ = *from++;
1190b8382935SToomas Soome             } while (--copy);
1191b8382935SToomas Soome             if (state->length == 0) state->mode = LEN;
1192b8382935SToomas Soome             break;
1193b8382935SToomas Soome         case LIT:
1194b8382935SToomas Soome             if (left == 0) goto inf_leave;
1195b8382935SToomas Soome             *put++ = (unsigned char)(state->length);
1196b8382935SToomas Soome             left--;
1197b8382935SToomas Soome             state->mode = LEN;
1198b8382935SToomas Soome             break;
1199b8382935SToomas Soome         case CHECK:
1200b8382935SToomas Soome             if (state->wrap) {
1201b8382935SToomas Soome                 NEEDBITS(32);
1202b8382935SToomas Soome                 out -= left;
1203b8382935SToomas Soome                 strm->total_out += out;
1204b8382935SToomas Soome                 state->total += out;
1205b8382935SToomas Soome                 if ((state->wrap & 4) && out)
1206b8382935SToomas Soome                     strm->adler = state->check =
1207148fd93eSToomas Soome                         UPDATE_CHECK(state->check, put - out, out);
1208b8382935SToomas Soome                 out = left;
1209b8382935SToomas Soome                 if ((state->wrap & 4) && (
1210b8382935SToomas Soome #ifdef GUNZIP
1211b8382935SToomas Soome                      state->flags ? hold :
1212b8382935SToomas Soome #endif
1213b8382935SToomas Soome                      ZSWAP32(hold)) != state->check) {
1214b8382935SToomas Soome                     strm->msg = (char *)"incorrect data check";
1215b8382935SToomas Soome                     state->mode = BAD;
1216b8382935SToomas Soome                     break;
1217b8382935SToomas Soome                 }
1218b8382935SToomas Soome                 INITBITS();
1219b8382935SToomas Soome                 Tracev((stderr, "inflate:   check matches trailer\n"));
1220b8382935SToomas Soome             }
1221b8382935SToomas Soome #ifdef GUNZIP
1222b8382935SToomas Soome             state->mode = LENGTH;
1223b8382935SToomas Soome 	    /* FALLTHROUGH */
1224b8382935SToomas Soome         case LENGTH:
1225b8382935SToomas Soome             if (state->wrap && state->flags) {
1226b8382935SToomas Soome                 NEEDBITS(32);
1227148fd93eSToomas Soome                 if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
1228b8382935SToomas Soome                     strm->msg = (char *)"incorrect length check";
1229b8382935SToomas Soome                     state->mode = BAD;
1230b8382935SToomas Soome                     break;
1231b8382935SToomas Soome                 }
1232b8382935SToomas Soome                 INITBITS();
1233b8382935SToomas Soome                 Tracev((stderr, "inflate:   length matches trailer\n"));
1234b8382935SToomas Soome             }
1235b8382935SToomas Soome #endif
1236b8382935SToomas Soome             state->mode = DONE;
1237b8382935SToomas Soome 	    /* FALLTHROUGH */
1238b8382935SToomas Soome         case DONE:
1239b8382935SToomas Soome             ret = Z_STREAM_END;
1240b8382935SToomas Soome             goto inf_leave;
1241b8382935SToomas Soome         case BAD:
1242b8382935SToomas Soome             ret = Z_DATA_ERROR;
1243b8382935SToomas Soome             goto inf_leave;
1244b8382935SToomas Soome         case MEM:
1245b8382935SToomas Soome             return Z_MEM_ERROR;
1246b8382935SToomas Soome         case SYNC:
1247148fd93eSToomas Soome                 /* fallthrough */
1248b8382935SToomas Soome         default:
1249b8382935SToomas Soome             return Z_STREAM_ERROR;
1250b8382935SToomas Soome         }
1251b8382935SToomas Soome 
1252b8382935SToomas Soome     /*
1253b8382935SToomas Soome        Return from inflate(), updating the total counts and the check value.
1254b8382935SToomas Soome        If there was no progress during the inflate() call, return a buffer
1255b8382935SToomas Soome        error.  Call updatewindow() to create and/or update the window state.
1256b8382935SToomas Soome        Note: a memory error from inflate() is non-recoverable.
1257b8382935SToomas Soome      */
1258b8382935SToomas Soome   inf_leave:
1259b8382935SToomas Soome     RESTORE();
1260b8382935SToomas Soome     if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
1261b8382935SToomas Soome             (state->mode < CHECK || flush != Z_FINISH)))
1262b8382935SToomas Soome         if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
1263b8382935SToomas Soome             state->mode = MEM;
1264b8382935SToomas Soome             return Z_MEM_ERROR;
1265b8382935SToomas Soome         }
1266b8382935SToomas Soome     in -= strm->avail_in;
1267b8382935SToomas Soome     out -= strm->avail_out;
1268b8382935SToomas Soome     strm->total_in += in;
1269b8382935SToomas Soome     strm->total_out += out;
1270b8382935SToomas Soome     state->total += out;
1271b8382935SToomas Soome     if ((state->wrap & 4) && out)
1272b8382935SToomas Soome         strm->adler = state->check =
1273148fd93eSToomas Soome             UPDATE_CHECK(state->check, strm->next_out - out, out);
1274b8382935SToomas Soome     strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
1275b8382935SToomas Soome                       (state->mode == TYPE ? 128 : 0) +
1276b8382935SToomas Soome                       (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
1277b8382935SToomas Soome     if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
1278b8382935SToomas Soome         ret = Z_BUF_ERROR;
1279b8382935SToomas Soome     return ret;
1280b8382935SToomas Soome }
1281b8382935SToomas Soome 
inflateEnd(z_streamp strm)1282b8382935SToomas Soome int ZEXPORT inflateEnd(z_streamp strm)
1283b8382935SToomas Soome {
1284b8382935SToomas Soome     struct inflate_state FAR *state;
1285b8382935SToomas Soome     if (inflateStateCheck(strm))
1286b8382935SToomas Soome         return Z_STREAM_ERROR;
1287b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1288b8382935SToomas Soome     if (state->window != Z_NULL) ZFREE(strm, state->window);
1289b8382935SToomas Soome     ZFREE(strm, strm->state);
1290b8382935SToomas Soome     strm->state = Z_NULL;
1291b8382935SToomas Soome     Tracev((stderr, "inflate: end\n"));
1292b8382935SToomas Soome     return Z_OK;
1293b8382935SToomas Soome }
1294b8382935SToomas Soome 
inflateGetDictionary(z_streamp strm,Bytef * dictionary,uInt * dictLength)1295b8382935SToomas Soome int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary,
1296b8382935SToomas Soome     uInt *dictLength)
1297b8382935SToomas Soome {
1298b8382935SToomas Soome     struct inflate_state FAR *state;
1299b8382935SToomas Soome 
1300b8382935SToomas Soome     /* check state */
1301b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1302b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1303b8382935SToomas Soome 
1304b8382935SToomas Soome     /* copy dictionary */
1305b8382935SToomas Soome     if (state->whave && dictionary != Z_NULL) {
1306b8382935SToomas Soome         zmemcpy(dictionary, state->window + state->wnext,
1307b8382935SToomas Soome                 state->whave - state->wnext);
1308b8382935SToomas Soome         zmemcpy(dictionary + state->whave - state->wnext,
1309b8382935SToomas Soome                 state->window, state->wnext);
1310b8382935SToomas Soome     }
1311b8382935SToomas Soome     if (dictLength != Z_NULL)
1312b8382935SToomas Soome         *dictLength = state->whave;
1313b8382935SToomas Soome     return Z_OK;
1314b8382935SToomas Soome }
1315b8382935SToomas Soome 
inflateSetDictionary(z_streamp strm,const Bytef * dictionary,uInt dictLength)1316b8382935SToomas Soome int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary,
1317b8382935SToomas Soome     uInt dictLength)
1318b8382935SToomas Soome {
1319b8382935SToomas Soome     struct inflate_state FAR *state;
1320b8382935SToomas Soome     unsigned long dictid;
1321b8382935SToomas Soome     int ret;
1322b8382935SToomas Soome 
1323b8382935SToomas Soome     /* check state */
1324b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1325b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1326b8382935SToomas Soome     if (state->wrap != 0 && state->mode != DICT)
1327b8382935SToomas Soome         return Z_STREAM_ERROR;
1328b8382935SToomas Soome 
1329b8382935SToomas Soome     /* check for correct dictionary identifier */
1330b8382935SToomas Soome     if (state->mode == DICT) {
1331b8382935SToomas Soome         dictid = adler32(0L, Z_NULL, 0);
1332b8382935SToomas Soome         dictid = adler32(dictid, dictionary, dictLength);
1333b8382935SToomas Soome         if (dictid != state->check)
1334b8382935SToomas Soome             return Z_DATA_ERROR;
1335b8382935SToomas Soome     }
1336b8382935SToomas Soome 
1337b8382935SToomas Soome     /* copy dictionary to window using updatewindow(), which will amend the
1338b8382935SToomas Soome        existing dictionary if appropriate */
1339b8382935SToomas Soome     ret = updatewindow(strm, dictionary + dictLength, dictLength);
1340b8382935SToomas Soome     if (ret) {
1341b8382935SToomas Soome         state->mode = MEM;
1342b8382935SToomas Soome         return Z_MEM_ERROR;
1343b8382935SToomas Soome     }
1344b8382935SToomas Soome     state->havedict = 1;
1345b8382935SToomas Soome     Tracev((stderr, "inflate:   dictionary set\n"));
1346b8382935SToomas Soome     return Z_OK;
1347b8382935SToomas Soome }
1348b8382935SToomas Soome 
inflateGetHeader(z_streamp strm,gz_headerp head)1349b8382935SToomas Soome int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head)
1350b8382935SToomas Soome {
1351b8382935SToomas Soome     struct inflate_state FAR *state;
1352b8382935SToomas Soome 
1353b8382935SToomas Soome     /* check state */
1354b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1355b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1356b8382935SToomas Soome     if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
1357b8382935SToomas Soome 
1358b8382935SToomas Soome     /* save header structure */
1359b8382935SToomas Soome     state->head = head;
1360b8382935SToomas Soome     head->done = 0;
1361b8382935SToomas Soome     return Z_OK;
1362b8382935SToomas Soome }
1363b8382935SToomas Soome 
1364b8382935SToomas Soome /*
1365b8382935SToomas Soome    Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
1366b8382935SToomas Soome    or when out of input.  When called, *have is the number of pattern bytes
1367b8382935SToomas Soome    found in order so far, in 0..3.  On return *have is updated to the new
1368b8382935SToomas Soome    state.  If on return *have equals four, then the pattern was found and the
1369b8382935SToomas Soome    return value is how many bytes were read including the last byte of the
1370b8382935SToomas Soome    pattern.  If *have is less than four, then the pattern has not been found
1371b8382935SToomas Soome    yet and the return value is len.  In the latter case, syncsearch() can be
1372b8382935SToomas Soome    called again with more data and the *have state.  *have is initialized to
1373b8382935SToomas Soome    zero for the first call.
1374b8382935SToomas Soome  */
syncsearch(unsigned FAR * have,const unsigned char FAR * buf,unsigned len)1375b8382935SToomas Soome local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf,
1376b8382935SToomas Soome     unsigned len)
1377b8382935SToomas Soome {
1378b8382935SToomas Soome     unsigned got;
1379b8382935SToomas Soome     unsigned next;
1380b8382935SToomas Soome 
1381b8382935SToomas Soome     got = *have;
1382b8382935SToomas Soome     next = 0;
1383b8382935SToomas Soome     while (next < len && got < 4) {
1384b8382935SToomas Soome         if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
1385b8382935SToomas Soome             got++;
1386b8382935SToomas Soome         else if (buf[next])
1387b8382935SToomas Soome             got = 0;
1388b8382935SToomas Soome         else
1389b8382935SToomas Soome             got = 4 - got;
1390b8382935SToomas Soome         next++;
1391b8382935SToomas Soome     }
1392b8382935SToomas Soome     *have = got;
1393b8382935SToomas Soome     return next;
1394b8382935SToomas Soome }
1395b8382935SToomas Soome 
inflateSync(z_streamp strm)1396b8382935SToomas Soome int ZEXPORT inflateSync(z_streamp strm)
1397b8382935SToomas Soome {
1398b8382935SToomas Soome     unsigned len;               /* number of bytes to look at or looked at */
1399148fd93eSToomas Soome     int flags;                  /* temporary to save header status */
1400b8382935SToomas Soome     unsigned long in, out;      /* temporary to save total_in and total_out */
1401b8382935SToomas Soome     unsigned char buf[4];       /* to restore bit buffer to byte string */
1402b8382935SToomas Soome     struct inflate_state FAR *state;
1403b8382935SToomas Soome 
1404b8382935SToomas Soome     /* check parameters */
1405b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1406b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1407b8382935SToomas Soome     if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
1408b8382935SToomas Soome 
1409b8382935SToomas Soome     /* if first time, start search in bit buffer */
1410b8382935SToomas Soome     if (state->mode != SYNC) {
1411b8382935SToomas Soome         state->mode = SYNC;
1412b8382935SToomas Soome         state->hold <<= state->bits & 7;
1413b8382935SToomas Soome         state->bits -= state->bits & 7;
1414b8382935SToomas Soome         len = 0;
1415b8382935SToomas Soome         while (state->bits >= 8) {
1416b8382935SToomas Soome             buf[len++] = (unsigned char)(state->hold);
1417b8382935SToomas Soome             state->hold >>= 8;
1418b8382935SToomas Soome             state->bits -= 8;
1419b8382935SToomas Soome         }
1420b8382935SToomas Soome         state->have = 0;
1421b8382935SToomas Soome         syncsearch(&(state->have), buf, len);
1422b8382935SToomas Soome     }
1423b8382935SToomas Soome 
1424b8382935SToomas Soome     /* search available input */
1425b8382935SToomas Soome     len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
1426b8382935SToomas Soome     strm->avail_in -= len;
1427b8382935SToomas Soome     strm->next_in += len;
1428b8382935SToomas Soome     strm->total_in += len;
1429b8382935SToomas Soome 
1430b8382935SToomas Soome     /* return no joy or set up to restart inflate() on a new block */
1431b8382935SToomas Soome     if (state->have != 4) return Z_DATA_ERROR;
1432148fd93eSToomas Soome     if (state->flags == -1)
1433148fd93eSToomas Soome         state->wrap = 0;    /* if no header yet, treat as raw */
1434148fd93eSToomas Soome     else
1435148fd93eSToomas Soome         state->wrap &= ~4;  /* no point in computing a check value now */
1436148fd93eSToomas Soome     flags = state->flags;
1437b8382935SToomas Soome     in = strm->total_in;  out = strm->total_out;
1438b8382935SToomas Soome     inflateReset(strm);
1439b8382935SToomas Soome     strm->total_in = in;  strm->total_out = out;
1440148fd93eSToomas Soome     state->flags = flags;
1441b8382935SToomas Soome     state->mode = TYPE;
1442b8382935SToomas Soome     return Z_OK;
1443b8382935SToomas Soome }
1444b8382935SToomas Soome 
1445b8382935SToomas Soome /*
1446b8382935SToomas Soome    Returns true if inflate is currently at the end of a block generated by
1447b8382935SToomas Soome    Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
1448b8382935SToomas Soome    implementation to provide an additional safety check. PPP uses
1449b8382935SToomas Soome    Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
1450b8382935SToomas Soome    block. When decompressing, PPP checks that at the end of input packet,
1451b8382935SToomas Soome    inflate is waiting for these length bytes.
1452b8382935SToomas Soome  */
inflateSyncPoint(z_streamp strm)1453b8382935SToomas Soome int ZEXPORT inflateSyncPoint(z_streamp strm)
1454b8382935SToomas Soome {
1455b8382935SToomas Soome     struct inflate_state FAR *state;
1456b8382935SToomas Soome 
1457b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1458b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1459b8382935SToomas Soome     return state->mode == STORED && state->bits == 0;
1460b8382935SToomas Soome }
1461b8382935SToomas Soome 
inflateCopy(z_streamp dest,z_streamp source)1462b8382935SToomas Soome int ZEXPORT inflateCopy(z_streamp dest, z_streamp source)
1463b8382935SToomas Soome {
1464b8382935SToomas Soome     struct inflate_state FAR *state;
1465b8382935SToomas Soome     struct inflate_state FAR *copy;
1466b8382935SToomas Soome     unsigned char FAR *window;
1467b8382935SToomas Soome     unsigned wsize;
1468b8382935SToomas Soome 
1469b8382935SToomas Soome     /* check input */
1470b8382935SToomas Soome     if (inflateStateCheck(source) || dest == Z_NULL)
1471b8382935SToomas Soome         return Z_STREAM_ERROR;
1472b8382935SToomas Soome     state = (struct inflate_state FAR *)source->state;
1473b8382935SToomas Soome 
1474b8382935SToomas Soome     /* allocate space */
1475b8382935SToomas Soome     copy = (struct inflate_state FAR *)
1476b8382935SToomas Soome            ZALLOC(source, 1, sizeof(struct inflate_state));
1477b8382935SToomas Soome     if (copy == Z_NULL) return Z_MEM_ERROR;
1478b8382935SToomas Soome     window = Z_NULL;
1479b8382935SToomas Soome     if (state->window != Z_NULL) {
1480b8382935SToomas Soome         window = (unsigned char FAR *)
1481b8382935SToomas Soome                  ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
1482b8382935SToomas Soome         if (window == Z_NULL) {
1483b8382935SToomas Soome             ZFREE(source, copy);
1484b8382935SToomas Soome             return Z_MEM_ERROR;
1485b8382935SToomas Soome         }
1486b8382935SToomas Soome     }
1487b8382935SToomas Soome 
1488b8382935SToomas Soome     /* copy state */
1489b8382935SToomas Soome     zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
1490b8382935SToomas Soome     zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
1491b8382935SToomas Soome     copy->strm = dest;
1492b8382935SToomas Soome     if (state->lencode >= state->codes &&
1493b8382935SToomas Soome         state->lencode <= state->codes + ENOUGH - 1) {
1494b8382935SToomas Soome         copy->lencode = copy->codes + (state->lencode - state->codes);
1495b8382935SToomas Soome         copy->distcode = copy->codes + (state->distcode - state->codes);
1496b8382935SToomas Soome     }
1497b8382935SToomas Soome     copy->next = copy->codes + (state->next - state->codes);
1498b8382935SToomas Soome     if (window != Z_NULL) {
1499b8382935SToomas Soome         wsize = 1U << state->wbits;
1500b8382935SToomas Soome         zmemcpy(window, state->window, wsize);
1501b8382935SToomas Soome     }
1502b8382935SToomas Soome     copy->window = window;
1503b8382935SToomas Soome     dest->state = (struct internal_state FAR *)copy;
1504b8382935SToomas Soome     return Z_OK;
1505b8382935SToomas Soome }
1506b8382935SToomas Soome 
inflateUndermine(z_streamp strm,int subvert)1507b8382935SToomas Soome int ZEXPORT inflateUndermine(z_streamp strm, int subvert)
1508b8382935SToomas Soome {
1509b8382935SToomas Soome     struct inflate_state FAR *state;
1510b8382935SToomas Soome 
1511b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1512b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1513b8382935SToomas Soome #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
1514b8382935SToomas Soome     state->sane = !subvert;
1515b8382935SToomas Soome     return Z_OK;
1516b8382935SToomas Soome #else
1517b8382935SToomas Soome     (void)subvert;
1518b8382935SToomas Soome     state->sane = 1;
1519b8382935SToomas Soome     return Z_DATA_ERROR;
1520b8382935SToomas Soome #endif
1521b8382935SToomas Soome }
1522b8382935SToomas Soome 
inflateValidate(z_streamp strm,int check)1523b8382935SToomas Soome int ZEXPORT inflateValidate(z_streamp strm, int check)
1524b8382935SToomas Soome {
1525b8382935SToomas Soome     struct inflate_state FAR *state;
1526b8382935SToomas Soome 
1527b8382935SToomas Soome     if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
1528b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1529148fd93eSToomas Soome     if (check && state->wrap)
1530b8382935SToomas Soome         state->wrap |= 4;
1531b8382935SToomas Soome     else
1532b8382935SToomas Soome         state->wrap &= ~4;
1533b8382935SToomas Soome     return Z_OK;
1534b8382935SToomas Soome }
1535b8382935SToomas Soome 
inflateMark(z_streamp strm)1536b8382935SToomas Soome long ZEXPORT inflateMark(z_streamp strm)
1537b8382935SToomas Soome {
1538b8382935SToomas Soome     struct inflate_state FAR *state;
1539b8382935SToomas Soome 
1540b8382935SToomas Soome     if (inflateStateCheck(strm))
1541b8382935SToomas Soome         return -(1L << 16);
1542b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1543b8382935SToomas Soome     return (long)(((unsigned long)((long)state->back)) << 16) +
1544b8382935SToomas Soome         (state->mode == COPY ? state->length :
1545b8382935SToomas Soome             (state->mode == MATCH ? state->was - state->length : 0));
1546b8382935SToomas Soome }
1547b8382935SToomas Soome 
inflateCodesUsed(z_streamp strm)1548b8382935SToomas Soome unsigned long ZEXPORT inflateCodesUsed(z_streamp strm)
1549b8382935SToomas Soome {
1550b8382935SToomas Soome     struct inflate_state FAR *state;
1551b8382935SToomas Soome     if (inflateStateCheck(strm)) return (unsigned long)-1;
1552b8382935SToomas Soome     state = (struct inflate_state FAR *)strm->state;
1553b8382935SToomas Soome     return (unsigned long)(state->next - state->codes);
1554b8382935SToomas Soome }
1555