diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2009-07-25 21:36:11 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2009-07-25 21:36:11 +0000 |
commit | a175e3a42a18e3462095242700daa7229d6aa4c7 (patch) | |
tree | 4e87587d7e17850f8186a734f6211450835ad29f /apps/plugins/png/inflate.c | |
parent | fee24eefa9c843bac5586fb762da2d8871df3a65 (diff) |
Add a png viewer plugin
Author: Christophe Gouiran
Flyspray: FS#9493
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22037 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/png/inflate.c')
-rw-r--r-- | apps/plugins/png/inflate.c | 1334 |
1 files changed, 1334 insertions, 0 deletions
diff --git a/apps/plugins/png/inflate.c b/apps/plugins/png/inflate.c new file mode 100644 index 0000000000..2cf6f972a4 --- /dev/null +++ b/apps/plugins/png/inflate.c @@ -0,0 +1,1334 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state.offset] to *(strm->next_out - state.offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state.bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" +#include "plugin.h" +#include "png.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +struct inflate_state state; + +/* function prototypes */ +local void fixedtables OF((void)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + //struct inflate_state FAR *state; + + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = strm->state; + strm->total_in = strm->total_out = state.total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768U; + state.head = Z_NULL; + state.wsize = 0; + state.whave = 0; + state.write = 0; + state.hold = 0; + state.bits = 0; + state.lencode = state.distcode = state.next = state.codes; + //DEBUGF("inflate: reset\n"); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + //struct inflate_state FAR *state; + + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state.bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state.hold += value << state.bits; + state.bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + //struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + //if (strm->zalloc == (alloc_func)0) { + // strm->zalloc = zcalloc; + // strm->opaque = (voidpf)0; + //} + //if (strm->zfree == (free_func)0) strm->zfree = zcfree; + //state = (struct inflate_state FAR *) + // ZALLOC(strm, 1, sizeof(struct inflate_state)); + //if (state == Z_NULL) return Z_MEM_ERROR; + //DEBUGF("inflate: allocated\n"); + //strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state.wrap = 0; + windowBits = -windowBits; + } + else { + state.wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + //ZFREE(strm, state); + //strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state.wbits = (unsigned)windowBits; + state.window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(void) +//struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state.lens[sym++] = 8; + while (sym < 256) state.lens[sym++] = 9; + while (sym < 280) state.lens[sym++] = 7; + while (sym < 288) state.lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state.lens, 288, &(next), &(bits), state.work); + + /* distance table */ + sym = 0; + while (sym < 32) state.lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state.lens, 32, &(next), &(bits), state.work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +} + +#ifdef MAKEFIXED +#include <stdio.h> + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + //struct inflate_state FAR *state; + unsigned copy, dist; + + //state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window == Z_NULL) { + state.window = (unsigned char FAR *) + ZALLOC(strm, 1U << state.wbits, + sizeof(unsigned char)); + if (state.window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state.wsize == 0) { + state.wsize = 1U << state.wbits; + state.write = 0; + state.whave = 0; + } + + /* copy state.wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state.wsize) { + zmemcpy(state.window, strm->next_out - state.wsize, state.wsize); + state.write = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.write; + if (dist > copy) dist = copy; + zmemcpy(state.window + state.write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state.window, strm->next_out - copy, copy); + state.write = copy; + state.whave = state.wsize; + } + else { + state.write += dist; + if (state.write == state.wsize) state.write = 0; + if (state.whave < state.wsize) state.whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state.flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state.hold; \ + bits = state.bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state.hold = hold; \ + state.bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +extern void cb_progress(int current, int total); + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + //struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + uInt insize = strm->avail_in; + + //state = (struct inflate_state FAR *)strm->state; + if (state.mode == TYPE) state.mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap == 0) { + state.mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state.wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state.check = crc32(0L, Z_NULL, 0); + CRC2(state.check, hold); + INITBITS(); + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head != Z_NULL) + state.head->done = -1; + if (!(state.wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state.mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state.mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state.wbits) { + strm->msg = (char *)"invalid window size"; + state.mode = BAD; + break; + } + state.dmax = 1U << len; + //DEBUGF("inflate: zlib header ok\n"); + strm->adler = state.check = adler32(0L, Z_NULL, 0); + state.mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state.flags = (int)(hold); + if ((state.flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state.mode = BAD; + break; + } + if (state.head != Z_NULL) + state.head->text = (int)((hold >> 8) & 1); + if (state.flags & 0x0200) CRC2(state.check, hold); + INITBITS(); + state.mode = TIME; + case TIME: + NEEDBITS(32); + if (state.head != Z_NULL) + state.head->time = hold; + if (state.flags & 0x0200) CRC4(state.check, hold); + INITBITS(); + state.mode = OS; + case OS: + NEEDBITS(16); + if (state.head != Z_NULL) { + state.head->xflags = (int)(hold & 0xff); + state.head->os = (int)(hold >> 8); + } + if (state.flags & 0x0200) CRC2(state.check, hold); + INITBITS(); + state.mode = EXLEN; + case EXLEN: + if (state.flags & 0x0400) { + NEEDBITS(16); + state.length = (unsigned)(hold); + if (state.head != Z_NULL) + state.head->extra_len = (unsigned)hold; + if (state.flags & 0x0200) CRC2(state.check, hold); + INITBITS(); + } + else if (state.head != Z_NULL) + state.head->extra = Z_NULL; + state.mode = EXTRA; + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) copy = have; + if (copy) { + if (state.head != Z_NULL && + state.head->extra != Z_NULL) { + len = state.head->extra_len - state.length; + zmemcpy(state.head->extra + len, next, + len + copy > state.head->extra_max ? + state.head->extra_max - len : copy); + } + if (state.flags & 0x0200) + state.check = crc32(state.check, next, copy); + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) goto inf_leave; + } + state.length = 0; + state.mode = NAME; + case NAME: + if (state.flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state.head != Z_NULL && + state.head->name != Z_NULL && + state.length < state.head->name_max) + state.head->name[state.length++] = len; + } while (len && copy < have); + if (state.flags & 0x0200) + state.check = crc32(state.check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state.head != Z_NULL) + state.head->name = Z_NULL; + state.length = 0; + state.mode = COMMENT; + case COMMENT: + if (state.flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state.head != Z_NULL && + state.head->comment != Z_NULL && + state.length < state.head->comm_max) + state.head->comment[state.length++] = len; + } while (len && copy < have); + if (state.flags & 0x0200) + state.check = crc32(state.check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state.head != Z_NULL) + state.head->comment = Z_NULL; + state.mode = HCRC; + case HCRC: + if (state.flags & 0x0200) { + NEEDBITS(16); + if (hold != (state.check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state.mode = BAD; + break; + } + INITBITS(); + } + if (state.head != Z_NULL) { + state.head->hcrc = (int)((state.flags >> 9) & 1); + state.head->done = 1; + } + strm->adler = state.check = crc32(0L, Z_NULL, 0); + state.mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state.check = REVERSE(hold); + INITBITS(); + state.mode = DICT; + case DICT: + if (state.havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state.check = adler32(0L, Z_NULL, 0); + state.mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state.last) { + BYTEBITS(); + state.mode = CHECK; + break; + } + NEEDBITS(3); + state.last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + //DEBUGF("inflate: stored block%s\n", + //state.last ? " (last)" : ""); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(); + //DEBUGF("inflate: fixed codes block%s\n", + //state.last ? " (last)" : ""); + state.mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + //DEBUGF("inflate: dynamic codes block%s\n", + //state.last ? " (last)" : ""); + state.mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state.mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state.mode = BAD; + break; + } + state.length = (unsigned)hold & 0xffff; + //DEBUGF("inflate: stored length %u\n", + //state.length); + INITBITS(); + state.mode = COPY; + case COPY: + copy = state.length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //DEBUGF("inflate: stored end\n"); + state.mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state.nlen = BITS(5) + 257; + DROPBITS(5); + state.ndist = BITS(5) + 1; + DROPBITS(5); + state.ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state.mode = BAD; + break; + } +#endif + //DEBUGF("inflate: table sizes ok\n"); + state.have = 0; + state.mode = LENLENS; + case LENLENS: + while (state.have < state.ncode) { + NEEDBITS(3); + state.lens[order[state.have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state.have < 19) + state.lens[order[state.have++]] = 0; + state.next = state.codes; + state.lencode = (code const FAR *)(state.next); + state.lenbits = 7; + ret = inflate_table(CODES, state.lens, 19, &(state.next), + &(state.lenbits), state.work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state.mode = BAD; + break; + } + //DEBUGF("inflate: code lengths ok\n"); + state.have = 0; + state.mode = CODELENS; + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + this = state.lencode[BITS(state.lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state.lens[state.have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state.have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state.have + copy > state.nlen + state.ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state.mode = BAD; + break; + } + while (copy--) + state.lens[state.have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state.mode == BAD) break; + + /* build code tables */ + state.next = state.codes; + state.lencode = (code const FAR *)(state.next); + state.lenbits = 9; + ret = inflate_table(LENS, state.lens, state.nlen, &(state.next), + &(state.lenbits), state.work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state.mode = BAD; + break; + } + state.distcode = (code const FAR *)(state.next); + state.distbits = 6; + ret = inflate_table(DISTS, state.lens + state.nlen, state.ndist, + &(state.next), &(state.distbits), state.work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state.mode = BAD; + break; + } + //DEBUGF("inflate: codes ok\n"); + state.mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state.lencode[BITS(state.lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state.lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state.length = (unsigned)this.val; + if ((int)(this.op) == 0) { + //DEBUGF(this.val >= 0x20 && this.val < 0x7f ? + //"inflate: literal '%c'\n" : + //"inflate: literal 0x%02x\n", this.val); + state.mode = LIT; + break; + } + if (this.op & 32) { + //DEBUGF("inflate: end of block\n"); + state.mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state.mode = BAD; + break; + } + state.extra = (unsigned)(this.op) & 15; + state.mode = LENEXT; + case LENEXT: + if (state.extra) { + NEEDBITS(state.extra); + state.length += BITS(state.extra); + DROPBITS(state.extra); + } + //DEBUGF("inflate: length %u\n", state.length); + state.mode = DIST; + case DIST: + for (;;) { + this = state.distcode[BITS(state.distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state.distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state.mode = BAD; + break; + } + state.offset = (unsigned)this.val; + state.extra = (unsigned)(this.op) & 15; + state.mode = DISTEXT; + case DISTEXT: + if (state.extra) { + NEEDBITS(state.extra); + state.offset += BITS(state.extra); + DROPBITS(state.extra); + } +#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm->msg = (char *)"invalid distance too far back"; + state.mode = BAD; + break; + } +#endif + if (state.offset > state.whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state.mode = BAD; + break; + } + //DEBUGF("inflate: distance %u\n", state.offset); + state.mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.write) { + copy -= state.write; + from = state.window + (state.wsize - copy); + } + else + from = state.window + (state.write - copy); + if (copy > state.length) copy = state.length; + } + else { /* copy from output */ + from = put - state.offset; + copy = state.length; + } + if (copy > left) copy = left; + left -= copy; + state.length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state.length == 0) state.mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state.length); + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state.total += out; + if (out) + strm->adler = state.check = + UPDATE(state.check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state.flags ? hold : +#endif + REVERSE(hold)) != state.check) { + strm->msg = (char *)"incorrect data check"; + state.mode = BAD; + break; + } + INITBITS(); + //DEBUGF("inflate: check matches trailer\n"); + } +#ifdef GUNZIP + state.mode = LENGTH; + case LENGTH: + if (state.wrap && state.flags) { + NEEDBITS(32); + if (hold != (state.total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state.mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state.mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case ZMEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + //DEBUGF("%d / %d\n", strm->total_in, strm->avail_in); + if (rb->button_get(false) == PNG_MENU) + return PLUGIN_ABORT; + else cb_progress(insize - strm->avail_in, insize); + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state.wsize || (state.mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state.mode = ZMEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state.total += out; + if (state.wrap && out) + strm->adler = state.check = + UPDATE(state.check, strm->next_out - out, out); + strm->data_type = state.bits + (state.last ? 64 : 0) + + (state.mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + //struct inflate_state FAR *state; + if (strm == Z_NULL /*|| strm->zfree == (free_func)0*/) + return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + //if (state.window != Z_NULL) ZFREE(strm, state.window); + //ZFREE(strm, strm->state); + //strm->state = Z_NULL; + //DEBUGF("inflate: end\n"); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + //struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + if (state.wrap != 0 && state.mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state.mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state.check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state.mode = ZMEM; + return Z_MEM_ERROR; + } + if (dictLength > state.wsize) { + zmemcpy(state.window, dictionary + dictLength - state.wsize, + state.wsize); + state.whave = state.wsize; + } + else { + zmemcpy(state.window + state.wsize - dictLength, dictionary, + dictLength); + state.whave = dictLength; + } + state.havedict = 1; + //DEBUGF("inflate: dictionary set\n"); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + //struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + if ((state.wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state.head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + //struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state.bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state.mode != SYNC) { + state.mode = SYNC; + state.hold <<= state.bits & 7; + state.bits -= state.bits & 7; + len = 0; + while (state.bits >= 8) { + buf[len++] = (unsigned char)(state.hold); + state.hold >>= 8; + state.bits -= 8; + } + state.have = 0; + syncsearch(&(state.have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state.have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state.have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state.mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + //struct inflate_state FAR *state; + + if (strm == Z_NULL) return Z_STREAM_ERROR; + //state = (struct inflate_state FAR *)strm->state; + return state.mode == STORED && state.bits == 0; +} |