public static int inflateResetKeep( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; strm.total_in = strm.total_out = state.total = 0; strm.msg = null; if (state.wrap != 0) /* to support ill-conceived Java test suite */ { strm.adler = (ulong)(state.wrap & 1); } state.mode = inflate_mode.HEAD; state.last = 0; state.havedict = 0; state.dmax = 32768U; state.head = null; state.hold = 0; state.bits = 0; state.next = 0; state.lencode_array = state.codes; state.distcode_array = state.codes; state.lencode_index = 0; state.distcode_index = 0; state.sane = 1; state.back = -1; //Tracev((stderr, "inflate: reset\n")); return(zlib.Z_OK); }
public static int inflatePrime( z_stream strm, int bits, int value) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (bits < 0) { state.hold = 0; state.bits = 0; return(zlib.Z_OK); } if (bits > 16 || state.bits + (uint)bits > 32) { return(zlib.Z_STREAM_ERROR); } value &= (int)((1L << bits) - 1); state.hold += (uint)value << (int)state.bits; state.bits += (uint)bits; return(zlib.Z_OK); }
// The following utility functions are implemented on top of the // basic stream-oriented functions. To simplify the interface, some // default options are assumed (compression level and memory usage, // standard memory allocation functions). The source code of these // utility functions can easily be modified if you need special options. // =========================================================================== // Compresses the source buffer into the destination buffer. The level // parameter has the same meaning as in deflateInit. sourceLen is the byte // length of the source buffer. Upon entry, destLen is the total size of the // destination buffer, which must be at least 0.1% larger than sourceLen plus // 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. // // compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough // memory, Z_BUF_ERROR if there was not enough room in the output buffer, // Z_STREAM_ERROR if the level parameter is invalid. public static int compress2(byte[] dest, ref uint destLen, byte[] source, uint sourceLen, int level) { z_stream stream = new z_stream() { next_in = 0, in_buf = source, avail_in = sourceLen, next_out = 0, out_buf = dest, avail_out = destLen }; if (stream.avail_out != destLen) { return(Z_BUF_ERROR); } int err = deflateInit(stream, level); if (err != Z_OK) { return(err); } err = deflate(stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(stream); return(err == Z_OK ? Z_BUF_ERROR : err); } destLen = stream.total_out; err = deflateEnd(stream); return(err); }
public static int inflateGetDictionary( z_stream strm, byte[] dictionary, ref uint dictLength) { inflate_state state; /* check state */ if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; /* copy dictionary */ if (state.whave != 0 && dictionary != null) { zutil.zmemcpy(dictionary, 0, state.window, state.wnext, state.whave - state.wnext); zutil.zmemcpy(dictionary, state.whave - state.wnext, state.window, 0, state.wnext); } //if (dictLength != null) dictLength = state.whave; return(zlib.Z_OK); }
// The following utility functions are implemented on top of the // basic stream-oriented functions. To simplify the interface, some // default options are assumed (compression level and memory usage, // standard memory allocation functions). The source code of these // utility functions can easily be modified if you need special options. // =========================================================================== // Decompresses the source buffer into the destination buffer. sourceLen is // the byte length of the source buffer. Upon entry, destLen is the total // size of the destination buffer, which must be large enough to hold the // entire uncompressed data. (The size of the uncompressed data must have // been saved previously by the compressor and transmitted to the decompressor // by some mechanism outside the scope of this compression library.) // Upon exit, destLen is the actual size of the compressed buffer. // // uncompress returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if there was not enough room in the output // buffer, or Z_DATA_ERROR if the input data was corrupted. public static int uncompress(byte[] dest, ref uint destLen, byte[] source, uint sourceLen, uint sourceOffset=0, uint destOffset=0) { z_stream stream=new z_stream(); stream.in_buf=source; stream.next_in=sourceOffset; stream.avail_in=sourceLen; // Check for source > 64K on 16-bit machine: if(stream.avail_in!=sourceLen) return Z_BUF_ERROR; stream.out_buf=dest; stream.next_out=(int)destOffset; stream.avail_out=destLen; if(stream.avail_out!=destLen) return Z_BUF_ERROR; int err=inflateInit(stream); if(err!=Z_OK) return err; err=inflate(stream, Z_FINISH); if(err!=Z_STREAM_END) { inflateEnd(stream); if(err==Z_NEED_DICT||(err==Z_BUF_ERROR&&stream.avail_in==0)) return Z_DATA_ERROR; return err; } destLen=stream.total_out; err=inflateEnd(stream); return err; }
public static int inflateInit_( z_stream strm, string version, int stream_size) { const int DEF_WBITS = 15; return(inflateInit2_(strm, DEF_WBITS, version, stream_size)); }
public static int inflateCopy( z_stream dest, z_stream source) { inflate_state state; inflate_state copy; byte[] window; uint wsize; /* check input */ if (inflateStateCheck(source) != 0 || dest == null) { return(zlib.Z_STREAM_ERROR); } state = source.state; /* allocate space */ copy = new inflate_state(); if (copy == null) { return(zlib.Z_MEM_ERROR); } window = null; if (state.window != null) { window = new byte[1U << (int)state.wbits]; if (window == null) { copy = null; return(zlib.Z_MEM_ERROR); } } /* copy state */ zutil.zmemcpy(dest, source); zutil.zmemcpy(copy, state); copy.strm = dest; if (state.lencode_array == state.codes) { copy.lencode_array = copy.codes; copy.lencode_index = state.lencode_index; copy.distcode_array = copy.codes; copy.distcode_index = state.distcode_index; } copy.next = state.next; if (window != null) { wsize = 1U << (int)state.wbits; zutil.zmemcpy(window, 0, state.window, 0, wsize); } copy.window = window; dest.state = copy; return(zlib.Z_OK); }
public static int inflateSync( z_stream strm) { uint len; /* number of bytes to look at or looked at */ ulong @in, @out; /* temporary to save total_in and total_out */ byte[] buf = new byte[4]; /* to restore bit buffer to byte string */ inflate_state state; /* check parameters */ if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (strm.avail_in == 0 && state.bits < 8) { return(zlib.Z_BUF_ERROR); } /* if first time, start search in bit buffer */ if (state.mode != inflate_mode.SYNC) { state.mode = inflate_mode.SYNC; state.hold <<= (int)(state.bits & 7); state.bits -= state.bits & 7; len = 0; while (state.bits >= 8) { buf[len++] = (byte)(state.hold); state.hold >>= 8; state.bits -= 8; } state.have = 0; syncsearch(ref state.have, buf, 0, len); } /* search available input */ len = syncsearch(ref state.have, strm.input_buffer, 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(zlib.Z_DATA_ERROR); } @in = strm.total_in; @out = strm.total_out; inflateReset(strm); strm.total_in = @in; strm.total_out = @out; state.mode = inflate_mode.TYPE; return(zlib.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. */ public static int inflateSyncPoint( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; return((state.mode == inflate_mode.STORED && state.bits == 0) ? 1 : 0); }
public static ulong inflateCodesUsed( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(ulong.MaxValue); } state = strm.state; return((ulong)(state.next)); }
public uint adler; // adler32 value of the uncompressed data public void CopyTo(z_stream s) { s.adler = adler; s.avail_in = avail_in; s.avail_out = avail_out; s.in_buf = in_buf; s.msg = msg; s.next_in = next_in; s.next_out = next_out; s.out_buf = out_buf; s.state = state; s.total_in = total_in; s.total_out = total_out; }
public uint adler; // adler32 value of the uncompressed data public void CopyTo(z_stream s) { s.adler=adler; s.avail_in=avail_in; s.avail_out=avail_out; s.in_buf=in_buf; s.msg=msg; s.next_in=next_in; s.next_out=next_out; s.out_buf=out_buf; s.state=state; s.total_in=total_in; s.total_out=total_out; }
public static long inflateMark( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(-(1L << 16)); } state = strm.state; return((long)(((ulong)((long)state.back)) << 16) + (state.mode == inflate_mode.COPY ? state.length : (state.mode == inflate_mode.MATCH ? state.was - state.length : 0))); }
/* compress.c -- compress a memory buffer * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* =========================================================================== * Compresses the source buffer into the destination buffer. The level * parameter has the same meaning as in deflateInit. sourceLen is the byte * length of the source buffer. Upon entry, destLen is the total size of the * destination buffer, which must be at least 0.1% larger than sourceLen plus * 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. * * compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough * memory, Z_BUF_ERROR if there was not enough room in the output buffer, * Z_STREAM_ERROR if the level parameter is invalid. */ public static int compress2( byte[] dest_array, long dest_index, ref ulong destLen, byte[] source_array, long source_index, ulong sourceLen, int level) { z_stream stream = new z_stream(); int err; const uint max = uint.MaxValue; ulong left; left = destLen; destLen = 0; err = deflate.deflateInit_(stream, level, zlib.ZLIB_VERSION, z_stream._sizeof); if (err != zlib.Z_OK) { return(err); } stream.output_buffer = dest_array; stream.next_out = dest_index; stream.avail_out = 0; stream.input_buffer = source_array; stream.next_in = source_index; stream.avail_in = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (ulong)max ? max : (uint)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = sourceLen > (ulong)max ? max : (uint)sourceLen; sourceLen -= stream.avail_in; } err = deflate.deflate_(stream, sourceLen != 0 ? zlib.Z_NO_FLUSH : zlib.Z_FINISH); } while (err == zlib.Z_OK); destLen = stream.total_out; deflate.deflateEnd(stream); return(err == zlib.Z_STREAM_END ? zlib.Z_OK : err); }
public static int inflateReset( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; state.wsize = 0; state.whave = 0; state.wnext = 0; return(inflateResetKeep(strm)); }
private static int inflateStateCheck( z_stream strm) { inflate_state state; if (strm == null) { return(1); } state = strm.state; if (state == null || state.strm != strm || state.mode < inflate_mode.HEAD || state.mode > inflate_mode.SYNC) { return(1); } return(0); }
// The following utility functions are implemented on top of the // basic stream-oriented functions. To simplify the interface, some // default options are assumed (compression level and memory usage, // standard memory allocation functions). The source code of these // utility functions can easily be modified if you need special options. // =========================================================================== // Decompresses the source buffer into the destination buffer. sourceLen is // the byte length of the source buffer. Upon entry, destLen is the total // size of the destination buffer, which must be large enough to hold the // entire uncompressed data. (The size of the uncompressed data must have // been saved previously by the compressor and transmitted to the decompressor // by some mechanism outside the scope of this compression library.) // Upon exit, destLen is the actual size of the compressed buffer. // // uncompress returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if there was not enough room in the output // buffer, or Z_DATA_ERROR if the input data was corrupted. public static int Uncompress(byte[] dest, ref uint destLen, byte[] source, uint sourceLen, uint sourceOffset = 0, uint destOffset = 0) { z_stream stream = new z_stream { in_buf = source, next_in = sourceOffset, avail_in = sourceLen }; // Check for source > 64K on 16-bit machine: if (stream.avail_in != sourceLen) { return(Z_BUF_ERROR); } stream.out_buf = dest; stream.next_out = (int)destOffset; stream.avail_out = destLen; if (stream.avail_out != destLen) { return(Z_BUF_ERROR); } int err = inflateInit(stream); if (err != Z_OK) { return(err); } err = inflate(stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) { return(Z_DATA_ERROR); } return(err); } destLen = stream.total_out; err = inflateEnd(stream); return(err); }
public static int inflateEnd( z_stream strm) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (state.window != null) { state.window = null; } strm.state = null; //Tracev((stderr, "inflate: end\n")); return(zlib.Z_OK); }
public static int inflateReset2( z_stream strm, int windowBits) { int wrap; inflate_state state; /* get the state */ if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; if (windowBits < 48) { windowBits &= 15; } } /* set number of window bits, free window if different */ if (windowBits != 0 && (windowBits < 8 || windowBits > 15)) { return(zlib.Z_STREAM_ERROR); } if (state.window != null && state.wbits != (uint)windowBits) { state.window = null; } /* update state and reset the rest of it */ state.wrap = wrap; state.wbits = (uint)windowBits; return(inflateReset(strm)); }
public static int inflateUndermine( z_stream strm, int subvert) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR // state.sane = !subvert; // return zlib.Z_OK; //#else state.sane = 1; return(zlib.Z_DATA_ERROR); //#endif }
public static int inflateSetDictionary( z_stream strm, byte[] dictionary, uint dictLength) { inflate_state state; ulong dictid; int ret; /* check state */ if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (state.wrap != 0 && state.mode != inflate_mode.DICT) { return(zlib.Z_STREAM_ERROR); } /* check for correct dictionary identifier */ if (state.mode == inflate_mode.DICT) { dictid = adler32.adler32_(0L, null, 0, 0); dictid = adler32.adler32_(dictid, dictionary, 0, dictLength); if (dictid != state.check) { return(zlib.Z_DATA_ERROR); } } /* copy dictionary to window using updatewindow(), which will amend the * existing dictionary if appropriate */ ret = updatewindow(strm, dictionary, dictLength, dictLength); if (ret != 0) { state.mode = inflate_mode.MEM; return(zlib.Z_MEM_ERROR); } state.havedict = 1; //Tracev((stderr, "inflate: dictionary set\n")); return(zlib.Z_OK); }
public static int inflateValidate( z_stream strm, int check) { inflate_state state; if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (check != 0) { state.wrap |= 4; } else { state.wrap &= ~4; } return(zlib.Z_OK); }
public static int inflateGetHeader( z_stream strm, gz_header head) { inflate_state state; /* check state */ if (inflateStateCheck(strm) != 0) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if ((state.wrap & 2) == 0) { return(zlib.Z_STREAM_ERROR); } /* save header structure */ state.head = head; head.done = 0; return(zlib.Z_OK); }
internal static void zmemcpy(z_stream target, z_stream source) { target.input_buffer = source.input_buffer; target.output_buffer = source.output_buffer; target.next_in = source.next_in; target.avail_in = source.avail_in; target.total_in = source.total_in; target.next_out = source.next_out; target.avail_out = source.avail_out; target.total_out = source.total_out; target.msg = source.msg; target.state = source.state; target.dstate = source.dstate; target.data_type = source.data_type; target.adler = source.adler; target.reserved = source.reserved; }
public static int inflateInit2_( z_stream strm, int windowBits, string version, int stream_size) { int ret; inflate_state state; if (version == null || version.Length == 0 || version[0] != zlib.ZLIB_VERSION[0] || stream_size != (int)z_stream._sizeof) { return(zlib.Z_VERSION_ERROR); } if (strm == null) { return(zlib.Z_STREAM_ERROR); } strm.msg = null; /* in case we return an error */ state = new inflate_state(); if (state == null) { return(zlib.Z_MEM_ERROR); } //Tracev((stderr, "inflate: allocated\n")); strm.state = state; state.strm = strm; state.window = null; state.mode = inflate_mode.HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != zlib.Z_OK) { state = null; strm.state = null; } return(ret); }
// This function inserts bits in the inflate input stream. The intent is // that this function is used to start inflating at a bit position in the // middle of a byte. The provided bits will be used before any bytes are used // from next_in. This function should only be used with raw inflate, and // should be used before the first inflate() call after inflateInit2() or // inflateReset(). bits must be less than or equal to 16, and that many of the // least significant bits of value will be inserted in the input. // inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent. public static int inflatePrime(z_stream strm, int bits, int value) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; inflate_state state=(inflate_state)strm.state; if(bits<0) { state.hold=0; state.bits=0; return Z_OK; } if(bits>16||state.bits+bits>32) return Z_STREAM_ERROR; value&=(1<<(int)bits)-1; state.hold+=(uint)(value<<(int)state.bits); state.bits+=(uint)bits; return Z_OK; }
const int PRESET_DICT=0x20; // preset dictionary flag in zlib header #region deflate // ========================================================================= // deflate compresses as much data as possible, and stops when the input // buffer becomes empty or the output buffer becomes full. It may introduce some // output latency (reading input without producing any output) except when // forced to flush. // The detailed semantics are as follows. deflate performs one or both of the // following actions: // - Compress more input starting at next_in and update next_in and avail_in // accordingly. If not all input can be processed (because there is not // enough room in the output buffer), next_in and avail_in are updated and // processing will resume at this point for the next call of deflate(). // - Provide more output starting at next_out and update next_out and avail_out // accordingly. This action is forced if the parameter flush is non zero. // Forcing flush frequently degrades the compression ratio, so this parameter // should be set only when necessary (in interactive applications). // Some output may be provided even if flush is not set. // Before the call of deflate(), the application should ensure that at least // one of the actions is possible, by providing more input and/or consuming // more output, and updating avail_in or avail_out accordingly; avail_out // should never be zero before the call. The application can consume the // compressed output when it wants, for example when the output buffer is full // (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK // and with zero avail_out, it must be called again after making room in the // output buffer because there might be more output pending. // Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to // decide how much data to accumualte before producing output, in order to // maximize compression. // If the parameter flush is set to Z_SYNC_FLUSH, all pending output is // flushed to the output buffer and the output is aligned on a byte boundary, so // that the decompressor can get all input data available so far. (In particular // avail_in is zero after the call if enough output space has been provided // before the call.) Flushing may degrade compression for some compression // algorithms and so it should be used only when necessary. // If flush is set to Z_FULL_FLUSH, all output is flushed as with // Z_SYNC_FLUSH, and the compression state is reset so that decompression can // restart from this point if previous compressed data has been damaged or if // random access is desired. Using Z_FULL_FLUSH too often can seriously degrade // compression. // If deflate returns with avail_out == 0, this function must be called again // with the same value of the flush parameter and more output space (updated // avail_out), until the flush is complete (deflate returns with non-zero // avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that // avail_out is greater than six to avoid repeated flush markers due to // avail_out == 0 on return. // If the parameter flush is set to Z_FINISH, pending input is processed, // pending output is flushed and deflate returns with Z_STREAM_END if there // was enough output space; if deflate returns with Z_OK, this function must be // called again with Z_FINISH and more output space (updated avail_out) but no // more input data, until it returns with Z_STREAM_END or an error. After // deflate has returned Z_STREAM_END, the only possible operations on the // stream are deflateReset or deflateEnd. // Z_FINISH can be used immediately after deflateInit if all the compression // is to be done in a single step. In this case, avail_out must be at least // the value returned by deflateBound (see below). If deflate does not return // Z_STREAM_END, then it must be called again as described above. // deflate() sets strm.adler to the adler32 checksum of all input read // so far (that is, total_in bytes). // deflate() returns Z_OK if some progress has been made (more input // processed or more output produced), Z_STREAM_END if all input has been // consumed and all output has been produced (only when flush is set to // Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example // if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible // (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not // fatal, and deflate() can be called again with more input and more output // space to continue compressing. public static int deflate(z_stream strm, int flush) { int old_flush; // value of flush param for previous deflate call if(strm==null||strm.state==null||flush>Z_BLOCK||flush<0) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; if(strm.out_buf==null||(strm.in_buf==null&&strm.avail_in!=0)||(s.status==FINISH_STATE&&flush!=Z_FINISH)) { strm.msg=zError(Z_STREAM_ERROR); return Z_STREAM_ERROR; } if(strm.avail_out==0) { strm.msg=zError(Z_BUF_ERROR); return Z_BUF_ERROR; } s.strm=strm; // just in case old_flush=s.last_flush; s.last_flush=flush; // Write the header if(s.status==INIT_STATE) { if(s.wrap==2) { strm.adler=crc32(0, null, 0); s.pending_buf[s.pending++]=31; s.pending_buf[s.pending++]=139; s.pending_buf[s.pending++]=8; if(s.gzhead==null) { s.pending_buf[s.pending++]=0; s.pending_buf[s.pending++]=0; s.pending_buf[s.pending++]=0; s.pending_buf[s.pending++]=0; s.pending_buf[s.pending++]=0; s.pending_buf[s.pending++]=(byte)(s.level==9?2:(s.strategy>=Z_HUFFMAN_ONLY||s.level<2?4:0)); s.pending_buf[s.pending++]=OS_CODE; s.status=BUSY_STATE; } else { s.pending_buf[s.pending++]=(byte)((s.gzhead.text!=0?1:0)+(s.gzhead.hcrc!=0?2:0)+(s.gzhead.extra==null?0:4)+ (s.gzhead.name==null?0:8)+(s.gzhead.comment==null?0:16)); s.pending_buf[s.pending++]=(byte)(s.gzhead.time&0xff); s.pending_buf[s.pending++]=(byte)((s.gzhead.time>>8)&0xff); s.pending_buf[s.pending++]=(byte)((s.gzhead.time>>16)&0xff); s.pending_buf[s.pending++]=(byte)((s.gzhead.time>>24)&0xff); s.pending_buf[s.pending++]=(byte)(s.level==9?2:(s.strategy>=Z_HUFFMAN_ONLY||s.level<2?4:0)); s.pending_buf[s.pending++]=(byte)(s.gzhead.os&0xff); if(s.gzhead.extra!=null) { s.pending_buf[s.pending++]=(byte)(s.gzhead.extra_len&0xff); s.pending_buf[s.pending++]=(byte)((s.gzhead.extra_len>>8)&0xff); } if(s.gzhead.hcrc!=0) strm.adler=crc32(strm.adler, s.pending_buf, s.pending); s.gzindex=0; s.status=EXTRA_STATE; } } else { uint header=(Z_DEFLATED+((s.w_bits-8)<<4))<<8; uint level_flags; if(s.strategy>=Z_HUFFMAN_ONLY||s.level<2) level_flags=0; else if(s.level<6) level_flags=1; else if(s.level==6) level_flags=2; else level_flags=3; header|=(level_flags<<6); if(s.strstart!=0) header|=PRESET_DICT; header+=31-(header%31); s.status=BUSY_STATE; putShortMSB(s, header); // Save the adler32 of the preset dictionary: if(s.strstart!=0) { putShortMSB(s, (uint)(strm.adler>>16)); putShortMSB(s, (uint)(strm.adler&0xffff)); } strm.adler=adler32(0, null, 0); } } if(s.status==EXTRA_STATE) { if(s.gzhead.extra!=null) { uint beg=s.pending; // start of bytes to update crc while(s.gzindex<(s.gzhead.extra_len&0xffff)) { if(s.pending==s.pending_buf_size) { if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); flush_pending(strm); beg=s.pending; if(s.pending==s.pending_buf_size) break; } s.pending_buf[s.pending++]=s.gzhead.extra[s.gzindex]; s.gzindex++; } if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); if(s.gzindex==s.gzhead.extra_len) { s.gzindex=0; s.status=NAME_STATE; } } else s.status=NAME_STATE; } if(s.status==NAME_STATE) { if(s.gzhead.name!=null) { uint beg=s.pending; // start of bytes to update crc byte val; do { if(s.pending==s.pending_buf_size) { if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); flush_pending(strm); beg=s.pending; if(s.pending==s.pending_buf_size) { val=1; break; } } val=s.gzhead.name[s.gzindex++]; s.pending_buf[s.pending++]=val; } while(val!=0); if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); if(val==0) { s.gzindex=0; s.status=COMMENT_STATE; } } else s.status=COMMENT_STATE; } if(s.status==COMMENT_STATE) { if(s.gzhead.comment!=null) { uint beg=s.pending; // start of bytes to update crc byte val; do { if(s.pending==s.pending_buf_size) { if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); flush_pending(strm); beg=s.pending; if(s.pending==s.pending_buf_size) { val=1; break; } } val=s.gzhead.comment[s.gzindex++]; s.pending_buf[s.pending++]=val; } while(val!=0); if(s.gzhead.hcrc!=0&&s.pending>beg) strm.adler=crc32(strm.adler, s.pending_buf, beg, s.pending-beg); if(val==0) s.status=HCRC_STATE; } else s.status=HCRC_STATE; } if(s.status==HCRC_STATE) { if(s.gzhead.hcrc!=0) { if(s.pending+2>s.pending_buf_size) flush_pending(strm); if(s.pending+2<=s.pending_buf_size) { s.pending_buf[s.pending++]=(byte)(strm.adler&0xff); s.pending_buf[s.pending++]=(byte)((strm.adler>>8)&0xff); strm.adler=crc32(0, null, 0); s.status=BUSY_STATE; } } else s.status=BUSY_STATE; } // Flush as much pending output as possible if(s.pending!=0) { flush_pending(strm); if(strm.avail_out==0) { // Since avail_out is 0, deflate will be called again with // more output space, but possibly with both pending and // avail_in equal to zero. There won't be anything to do, // but this is not an error situation so make sure we // return OK instead of BUF_ERROR at next call of deflate: s.last_flush=-1; return Z_OK; } // Make sure there is something to do and avoid duplicate consecutive // flushes. For repeated and useless calls with Z_FINISH, we keep // returning Z_STREAM_END instead of Z_BUF_ERROR. } else if(strm.avail_in==0&&flush<=old_flush&&flush!=Z_FINISH) { strm.msg=zError(Z_BUF_ERROR); return Z_BUF_ERROR; } // User must not provide more input after the first FINISH: if(s.status==FINISH_STATE&&strm.avail_in!=0) { strm.msg=zError(Z_BUF_ERROR); return Z_BUF_ERROR; } // Start a new block or continue the current one. if(strm.avail_in!=0||s.lookahead!=0||(flush!=Z_NO_FLUSH&&s.status!=FINISH_STATE)) { block_state bstate=s.strategy==Z_HUFFMAN_ONLY?deflate_huff(s, flush):(s.strategy==Z_RLE?deflate_rle(s, flush):configuration_table[s.level].func(s, flush)); if(bstate==block_state.finish_started||bstate==block_state.finish_done) s.status=FINISH_STATE; if(bstate==block_state.need_more||bstate==block_state.finish_started) { if(strm.avail_out==0) s.last_flush=-1; // avoid BUF_ERROR next call, see above return Z_OK; // If flush != Z_NO_FLUSH && avail_out == 0, the next call // of deflate should use the same flush parameter to make sure // that the flush is complete. So we don't have to output an // empty block here, this will be done at next call. This also // ensures that for a very small output buffer, we emit at most // one empty block. } if(bstate==block_state.block_done) { if(flush==Z_PARTIAL_FLUSH) _tr_align(s); else if(flush!=Z_BLOCK) { // FULL_FLUSH or SYNC_FLUSH _tr_stored_block(s, null, 0, 0); // For a full flush, this empty block will be recognized // as a special marker by inflate_sync(). if(flush==Z_FULL_FLUSH) { s.head[s.hash_size-1]=NIL; // forget history //was memset((byte*)s.head, 0, (uint)(s.hash_size-1)*sizeof(*s.head)); for(int i=0; i<s.hash_size-1; i++) s.head[i]=0; if(s.lookahead==0) { s.strstart=0; s.block_start=0; } } } flush_pending(strm); if(strm.avail_out==0) { s.last_flush=-1; // avoid BUF_ERROR at next call, see above return Z_OK; } } } //Assert(strm.avail_out>0, "bug2"); if(flush!=Z_FINISH) return Z_OK; if(s.wrap<=0) return Z_STREAM_END; // Write the trailer if(s.wrap==2) { s.pending_buf[s.pending++]=(byte)(strm.adler&0xff); s.pending_buf[s.pending++]=(byte)((strm.adler>>8)&0xff); s.pending_buf[s.pending++]=(byte)((strm.adler>>16)&0xff); s.pending_buf[s.pending++]=(byte)((strm.adler>>24)&0xff); s.pending_buf[s.pending++]=(byte)(strm.total_in&0xff); s.pending_buf[s.pending++]=(byte)((strm.total_in>>8)&0xff); s.pending_buf[s.pending++]=(byte)((strm.total_in>>16)&0xff); s.pending_buf[s.pending++]=(byte)((strm.total_in>>24)&0xff); } else { putShortMSB(s, (uint)(strm.adler>>16)); putShortMSB(s, (uint)(strm.adler&0xffff)); } flush_pending(strm); // If avail_out is zero, the application will call deflate again // to flush the rest. if(s.wrap>0) s.wrap=-s.wrap; // write the trailer only once! return s.pending!=0?Z_OK:Z_STREAM_END; }
// ========================================================================= // All dynamically allocated data structures for this stream are freed. // This function discards any unprocessed input and does not flush any // pending output. // deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the // stream state was inconsistent, Z_DATA_ERROR if the stream was freed // prematurely (some input or output was discarded). In the error case, // msg may be set but then points to a static string (which must not be // deallocated). public static int deflateEnd(z_stream strm) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; int status=s.status; if(status!=INIT_STATE&& status!=EXTRA_STATE&& status!=NAME_STATE&& status!=COMMENT_STATE&& status!=HCRC_STATE&& status!=BUSY_STATE&&status!=FINISH_STATE) return Z_STREAM_ERROR; // Deallocate in reverse order of allocations: //if(s.pending_buf!=null) free(s.pending_buf); //if(s.l_buf!=null) free(s.l_buf); //if(s.d_buf!=null) free(s.d_buf); //if(s.head!=null) free(s.head); //if(s.prev!=null) free(s.prev); //if(s.window!=null) free(s.window); s.pending_buf=s.l_buf=s.window=null; s.d_buf=s.head=s.prev=null; //free(strm.state); strm.state=s=null; return status==BUSY_STATE?Z_DATA_ERROR:Z_OK; }
// Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 // For deflate_fast() (levels <= 3) good is ignored and lazy has a different // meaning. // =========================================================================== // Update a hash value with the given input byte // IN assertion: all calls to to UPDATE_HASH are made with consecutive // input characters, so that a running hash key can be computed from the // previous key instead of complete recalculation each time. //#define UPDATE_HASH(s,h,c) h = ((h<<s.hash_shift) ^ c) & s.hash_mask // =========================================================================== // Insert string str in the dictionary and set match_head to the previous head // of the hash chain (the most recent string with same hash key). Return // the previous length of the hash chain. // If this file is compiled with -DFASTEST, the compression level is forced // to 1, and no hash chains are maintained. // IN assertion: all calls to to INSERT_STRING are made with consecutive // input characters and the first MIN_MATCH bytes of str are valid // (except for the last MIN_MATCH-1 bytes of the input file). //#define INSERT_STRING(s, str, match_head) \ // s.ins_h = ((s.ins_h<<(int)s.hash_shift) ^ s.window[(str) + (MIN_MATCH-1)]) & s.hash_mask; \ // match_head = s.prev[(str) & s.w_mask] = s.head[s.ins_h]; \ // s.head[s.ins_h] = (unsigned short)str // =========================================================================== // Initialize the hash table (avoiding 64K overflow for 16 bit systems). // prev[] will be initialized on the fly. // ========================================================================= // Initializes the internal stream state for compression. The fields // zalloc, zfree and opaque must be initialized before by the caller. // If zalloc and zfree are set to Z_NULL, deflateInit updates them to // use default allocation functions. // The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: // 1 gives best speed, 9 gives best compression, 0 gives no compression at // all (the input data is simply copied a block at a time). // Z_DEFAULT_COMPRESSION requests a default compromise between speed and // compression (currently equivalent to level 6). // deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_STREAM_ERROR if level is not a valid compression level, // Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible // with the version assumed by the caller (ZLIB_VERSION). // msg is set to null if there is no error message. deflateInit does not // perform any compression: this will be done by deflate(). public static int deflateInit(z_stream strm, int level) { return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); // Todo: ignore strm.next_in if we use it as window }
// ========================================================================= // This function is equivalent to deflateEnd followed by deflateInit, // but does not free and reallocate all the internal compression state. // The stream will keep the same compression level and any other attributes // that may have been set by deflateInit2. // deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent (such as zalloc or state being NULL). public static int deflateReset(z_stream strm) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; strm.total_in=strm.total_out=0; strm.msg=null; deflate_state s=(deflate_state)strm.state; s.pending=0; s.pending_out=0; if(s.wrap<0) s.wrap=-s.wrap; // was made negative by deflate(..., Z_FINISH); s.status=s.wrap!=0?INIT_STATE:BUSY_STATE; strm.adler=s.wrap==2?crc32(0, null, 0):adler32(0, null, 0); s.last_flush=Z_NO_FLUSH; _tr_init(s); lm_init(s); return Z_OK; }
// inflate decompresses as much data as possible, and stops when the input // buffer becomes empty or the output buffer becomes full. It may introduce // some output latency (reading input without producing any output) except when // forced to flush. // The detailed semantics are as follows. inflate performs one or both of the // following actions: // - Decompress more input starting at next_in and update next_in and avail_in // accordingly. If not all input can be processed (because there is not // enough room in the output buffer), next_in is updated and processing // will resume at this point for the next call of inflate(). // - Provide more output starting at next_out and update next_out and avail_out // accordingly. inflate() provides as much output as possible, until there // is no more input data or no more space in the output buffer (see below // about the flush parameter). // Before the call of inflate(), the application should ensure that at least // one of the actions is possible, by providing more input and/or consuming // more output, and updating the next_* and avail_* values accordingly. // The application can consume the uncompressed output when it wants, for // example when the output buffer is full (avail_out == 0), or after each // call of inflate(). If inflate returns Z_OK and with zero avail_out, it // must be called again after making room in the output buffer because there // might be more output pending. // The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, // Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much // output as possible to the output buffer. Z_BLOCK requests that inflate() stop // if and when it gets to the next deflate block boundary. When decoding the // zlib or gzip format, this will cause inflate() to return immediately after // the header and before the first block. When doing a raw inflate, inflate() // will go ahead and process the first block, and will return when it gets to // the end of that block, or when it runs out of data. // The Z_BLOCK option assists in appending to or combining deflate streams. // Also to assist in this, on return inflate() will set strm.data_type to the // number of unused bits in the last byte taken from strm.next_in, plus 64 // if inflate() is currently decoding the last block in the deflate stream, // plus 128 if inflate() returned immediately after decoding an end-of-block // code or decoding the complete header up to just before the first byte of the // deflate stream. The end-of-block will not be indicated until all of the // uncompressed data from that block has been written to strm.next_out. The // number of unused bits may in general be greater than seven, except when // bit 7 of data_type is set, in which case the number of unused bits will be // less than eight. // inflate() should normally be called until it returns Z_STREAM_END or an // error. However if all decompression is to be performed in a single step // (a single call of inflate), the parameter flush should be set to // Z_FINISH. In this case all pending input is processed and all pending // output is flushed; avail_out must be large enough to hold all the // uncompressed data. (The size of the uncompressed data may have been saved // by the compressor for this purpose.) The next operation on this stream must // be inflateEnd to deallocate the decompression state. The use of Z_FINISH // is never required, but can be used to inform inflate that a faster approach // may be used for the single inflate() call. // In this implementation, inflate() always flushes as much output as // possible to the output buffer, and always uses the faster approach on the // first call. So the only effect of the flush parameter in this implementation // is on the return value of inflate(), as noted below, or when it returns early // because Z_BLOCK is used. // If a preset dictionary is needed after this call (see inflateSetDictionary // below), inflate sets strm.adler to the adler32 checksum of the dictionary // chosen by the compressor and returns Z_NEED_DICT; otherwise it sets // strm.adler to the adler32 checksum of all output produced so far (that is, // total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described // below. At the end of the stream, inflate() checks that its computed adler32 // checksum is equal to that saved by the compressor and returns Z_STREAM_END // only if the checksum is correct. // inflate() will decompress and check either zlib-wrapped or gzip-wrapped // deflate data. The header type is detected automatically. Any information // contained in the gzip header is not retained, so applications that need that // information should instead use raw inflate, see inflateInit2() below, or // inflateBack() and perform their own processing of the gzip header and // trailer. // inflate() returns Z_OK if some progress has been made (more input processed // or more output produced), Z_STREAM_END if the end of the compressed data has // been reached and all uncompressed output has been produced, Z_NEED_DICT if a // preset dictionary is needed at this point, Z_DATA_ERROR if the input data was // corrupted (input stream not conforming to the zlib format or incorrect check // value), Z_STREAM_ERROR if the stream structure was inconsistent (for example // if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, // Z_BUF_ERROR if no progress is possible or if there was not enough room in the // output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and // inflate() can be called again with more input and more output space to // continue decompressing. If Z_DATA_ERROR is returned, the application may then // call inflateSync() to look for a good compression block if a partial recovery // of the data is desired. public static int inflate(z_stream strm, int flush) { inflate_state state; uint next; // next input int put; // next output uint have, left; // available input and output uint hold; // bit buffer uint bits; // bits in bit buffer uint _in, _out; // save starting available input and output uint copy; // number of stored or match bytes to copy byte[] from; // where to copy match bytes from int from_ind; // where to copy match bytes from code here; // current decoding table entry code last; // parent table entry uint len; // length to copy for repeats, bits to drop int ret; // return code byte[] hbuf=new byte[4];// buffer for gzip header crc calculation if(strm==null||strm.state==null||strm.out_buf==null||(strm.in_buf==null&&strm.avail_in!=0)) return Z_STREAM_ERROR; byte[] in_buf=strm.in_buf; byte[] out_buf=strm.out_buf; state=(inflate_state)strm.state; if(state.mode==inflate_mode.TYPE) state.mode=inflate_mode.TYPEDO; // skip check //was LOAD(); put=strm.next_out; left=strm.avail_out; next=strm.next_in; have=strm.avail_in; hold=state.hold; bits=state.bits; _in=have; _out=left; ret=Z_OK; for(; ; ) { switch(state.mode) { case inflate_mode.HEAD: if(state.wrap==0) { state.mode=inflate_mode.TYPEDO; break; } //was NEEDBITS(16); while(bits<16) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if((state.wrap&2)!=0&&hold==0x8b1f) { // gzip header state.check=crc32(0, null, 0); //was CRC2(state.check, hold); hbuf[0]=(byte)hold; hbuf[1]=(byte)(hold>>8); state.check=crc32(state.check, hbuf, 2); //was INITBITS(); hold=bits=0; state.mode=inflate_mode.FLAGS; break; } state.flags=0; // expect zlib header if(state.head!=null) state.head.done=-1; //was if(!(state.wrap & 1) || // check if zlib header allowed // ((BITS(8)<<8)+(hold>>8))%31) if((state.wrap&1)==0|| // check if zlib header allowed ((((hold&0xFF)<<8)+(hold>>8))%31)!=0) { strm.msg="incorrect header check"; state.mode=inflate_mode.BAD; break; } //was if(BITS(4)!=Z_DEFLATED) if((hold&0x0F)!=Z_DEFLATED) { strm.msg="unknown compression method"; state.mode=inflate_mode.BAD; break; } //was DROPBITS(4); hold>>=4; bits-=4; //was len=BITS(4)+8; len=(hold&0x0F)+8; if(state.wbits==0) state.wbits=len; else if(len>state.wbits) { strm.msg="invalid window size"; state.mode=inflate_mode.BAD; break; } state.dmax=1U<<(int)len; //Tracev((stderr, "inflate: zlib header ok\n")); strm.adler=state.check=adler32(0, null, 0); state.mode=(hold&0x200)!=0?inflate_mode.DICTID:inflate_mode.TYPE; //was INITBITS(); hold=bits=0; break; case inflate_mode.FLAGS: //was NEEDBITS(16); while(bits<16) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } state.flags=(int)hold; if((state.flags&0xff)!=Z_DEFLATED) { strm.msg="unknown compression method"; state.mode=inflate_mode.BAD; break; } if((state.flags&0xe000)!=0) { strm.msg="unknown header flags set"; state.mode=inflate_mode.BAD; break; } if(state.head!=null) state.head.text=(int)((hold>>8)&1); if((state.flags&0x0200)!=0) { //was CRC2(state.check, hold); hbuf[0]=(byte)hold; hbuf[1]=(byte)(hold>>8); state.check=crc32(state.check, hbuf, 2); } //was INITBITS(); hold=bits=0; state.mode=inflate_mode.TIME; break; // no fall through case inflate_mode.TIME: //was NEEDBITS(32); while(bits<32) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(state.head!=null) state.head.time=hold; if((state.flags&0x0200)!=0) { //was CRC4(state.check, hold); hbuf[0]=(byte)hold; hbuf[1]=(byte)(hold>>8); hbuf[2]=(byte)(hold>>16); hbuf[3]=(byte)(hold>>24); state.check=crc32(state.check, hbuf, 4); } //was INITBITS(); hold=bits=0; state.mode=inflate_mode.OS; break; // no fall through case inflate_mode.OS: //was NEEDBITS(16); while(bits<16) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(state.head!=null) { state.head.xflags=(int)(hold&0xff); state.head.os=(int)(hold>>8); } if((state.flags&0x0200)!=0) { //was CRC2(state.check, hold); hbuf[0]=(byte)hold; hbuf[1]=(byte)(hold>>8); state.check=crc32(state.check, hbuf, 2); } //was INITBITS(); hold=bits=0; state.mode=inflate_mode.EXLEN; break; // no fall through case inflate_mode.EXLEN: if((state.flags&0x0400)!=0) { //was NEEDBITS(16); while(bits<16) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } state.length=hold; if(state.head!=null) state.head.extra_len=hold; if((state.flags&0x0200)!=0) { //was CRC2(state.check, hold); hbuf[0]=(byte)hold; hbuf[1]=(byte)(hold>>8); state.check=crc32(state.check, hbuf, 2); } //was INITBITS(); hold=bits=0; } else if(state.head!=null) state.head.extra=null; state.mode=inflate_mode.EXTRA; break; // no fall through case inflate_mode.EXTRA: if((state.flags&0x0400)!=0) { copy=state.length; if(copy>have) copy=have; if(copy!=0) { if(state.head!=null&&state.head.extra!=null) { len=state.head.extra_len-state.length; // should be always zero!!! //was zmemcpy(state.head.extra+len, next, (len+copy>state.head.extra_max)?state.head.extra_max-len:copy); Array.Copy(in_buf, next, state.head.extra, len, (len+copy>state.head.extra_max)?state.head.extra_max-len:copy); } if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy); have-=copy; next+=copy; state.length-=copy; } if(state.length!=0) goto inf_leave; } state.length=0; state.mode=inflate_mode.NAME; break; // no fall through case inflate_mode.NAME: if((state.flags&0x0800)!=0) { if(have==0) goto inf_leave; copy=0; do { //was len=next[copy++]; len=in_buf[next+copy++]; if(state.head!=null&&state.head.name!=null&&state.length<state.head.name_max) state.head.name[state.length++]=(byte)len; } while(len!=0&©<have); if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy); have-=copy; next+=copy; if(len!=0) goto inf_leave; } else if(state.head!=null) state.head.name=null; state.length=0; state.mode=inflate_mode.COMMENT; break; // no fall through case inflate_mode.COMMENT: if((state.flags&0x1000)!=0) { if(have==0) goto inf_leave; copy=0; do { //was len=next[copy++]; len=in_buf[next+copy++]; if(state.head!=null&&state.head.comment!=null&&state.length<state.head.comm_max) state.head.comment[state.length++]=(byte)len; } while(len!=0&©<have); if((state.flags&0x0200)!=0) state.check=crc32(state.check, in_buf, (uint)next, copy); have-=copy; next+=copy; if(len!=0) goto inf_leave; } else if(state.head!=null) state.head.comment=null; state.mode=inflate_mode.HCRC; break; // no fall through case inflate_mode.HCRC: if((state.flags&0x0200)!=0) { //was NEEDBITS(16); while(bits<16) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(hold!=(state.check&0xffff)) { strm.msg="header crc mismatch"; state.mode=inflate_mode.BAD; break; } //was INITBITS(); hold=bits=0; } if(state.head!=null) { state.head.hcrc=(int)((state.flags>>9)&1); state.head.done=1; } strm.adler=state.check=crc32(0, null, 0); state.mode=inflate_mode.TYPE; break; case inflate_mode.DICTID: //was NEEDBITS(32); while(bits<32) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was strm.adler=state.check=REVERSE(hold); strm.adler=state.check=((hold>>24)&0xff)+((hold>>8)&0xff00)+((hold&0xff00)<<8)+((hold&0xff)<<24); //was INITBITS(); hold=bits=0; state.mode=inflate_mode.DICT; break; // no fall through case inflate_mode.DICT: if(state.havedict==0) { //was RESTORE(); strm.next_out=put; strm.avail_out=left; strm.next_in=next; strm.avail_in=have; state.hold=hold; state.bits=bits; return Z_NEED_DICT; } strm.adler=state.check=adler32(0, null, 0); state.mode=inflate_mode.TYPE; break; // no fall through case inflate_mode.TYPE: if(flush==Z_BLOCK||flush==Z_TREES) goto inf_leave; state.mode=inflate_mode.TYPEDO; break; // no fall through case inflate_mode.TYPEDO: if(state.last!=0) { //was BYTEBITS(); hold>>=(int)(bits&7); bits-=bits&7; state.mode=inflate_mode.CHECK; break; } //was NEEDBITS(3); while(bits<3) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was state.last=BITS(1); state.last=(int)(hold&0x01); //was DROPBITS(1); hold>>=1; bits-=1; //was switch(BITS(2)) switch(hold&0x03) { case 0: // stored block //Tracev((stderr, "inflate: stored block%s\n", state.last ? " (last)" : "")); state.mode=inflate_mode.STORED; break; case 1: // fixed block fixedtables(state); //Tracev((stderr, "inflate: fixed codes block%s\n", state.last ? " (last)" : "")); state.mode=inflate_mode.LEN_; // decode codes if(flush==Z_TREES) { //was DROPBITS(2); hold>>=2; bits-=2; goto inf_leave; } break; case 2: // dynamic block //Tracev((stderr, "inflate: dynamic codes block%s\n", state.last ? " (last)" : "")); state.mode=inflate_mode.TABLE; break; case 3: strm.msg="invalid block type"; state.mode=inflate_mode.BAD; break; } //was DROPBITS(2); hold>>=2; bits-=2; break; case inflate_mode.STORED: //was BYTEBITS(); // go to byte boundary hold>>=(int)(bits&7); bits-=bits&7; //was NEEDBITS(32); while(bits<32) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if((hold&0xffff)!=((hold>>16)^0xffff)) { strm.msg="invalid stored block lengths"; state.mode=inflate_mode.BAD; break; } state.length=hold&0xffff; //Tracev((stderr, "inflate: stored length %u\n", state.length)); //was INITBITS(); hold=bits=0; state.mode=inflate_mode.COPY_; if(flush==Z_TREES) goto inf_leave; break; // no fall through case inflate_mode.COPY_: state.mode=inflate_mode.COPY; break; // no fall through case inflate_mode.COPY: copy=state.length; if(copy!=0) { if(copy>have) copy=have; if(copy>left) copy=left; if(copy==0) goto inf_leave; //was memcpy(put, next, copy); Array.Copy(in_buf, next, out_buf, put, copy); have-=copy; next+=copy; left-=copy; put+=(int)copy; state.length-=copy; break; } //Tracev((stderr, "inflate: stored end\n")); state.mode=inflate_mode.TYPE; break; case inflate_mode.TABLE: //was NEEDBITS(14); while(bits<14) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was state.nlen=BITS(5)+257; state.nlen=(hold&0x1f)+257; //was DROPBITS(5); hold>>=5; bits-=5; //was state.ndist=BITS(5)+1; state.ndist=(hold&0x1f)+1; //was DROPBITS(5); hold>>=5; bits-=5; //was state.ncode=BITS(4)+4; state.ncode=(hold&0x0f)+4; //was DROPBITS(4); hold>>=4; bits-=4; if(state.nlen>286||state.ndist>30) { strm.msg="too many length or distance symbols"; state.mode=inflate_mode.BAD; break; } //Tracev((stderr, "inflate: table sizes ok\n")); state.have=0; state.mode=inflate_mode.LENLENS; break; // no fall through case inflate_mode.LENLENS: while(state.have<state.ncode) { //was NEEDBITS(3); while(bits<3) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was state.lens[order[state.have++]]=(ushort)BITS(3); state.lens[order[state.have++]]=(ushort)(hold&0x07); //was DROPBITS(3); hold>>=3; bits-=3; } while(state.have<19) state.lens[order[state.have++]]=0; state.next=0; state.lencode=state.codes; state.lenbits=7; //was ret=inflate_table(codetype.CODES, state.lens, 19, &(state.next), &(state.lenbits), state.work); ret=inflate_table(codetype.CODES, state.lens, 0, 19, state.codes, ref state.next, ref state.lenbits, state.work); if(ret!=0) { strm.msg="invalid code lengths set"; state.mode=inflate_mode.BAD; break; } //Tracev((stderr, "inflate: code lengths ok\n")); state.have=0; state.mode=inflate_mode.CODELENS; break; // no fall through case inflate_mode.CODELENS: while(state.have<(state.nlen+state.ndist)) { for(; ; ) { //was _this=state.lencode[BITS(state.lenbits)]; here=state.lencode[hold&((1<<(int)state.lenbits)-1)]; if(here.bits<=bits) break; //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(here.val<16) { //was NEEDBITS(_this.bits); while(bits<here.bits) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(_this.bits); hold>>=here.bits; bits-=here.bits; state.lens[state.have++]=here.val; } else { if(here.val==16) { //was NEEDBITS(_this.bits+2); while(bits<here.bits+2) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(_this.bits); hold>>=here.bits; bits-=here.bits; if(state.have==0) { strm.msg="invalid bit length repeat"; state.mode=inflate_mode.BAD; break; } len=state.lens[state.have-1]; //was copy=3+BITS(2); copy=3+(hold&0x03); //was DROPBITS(2); hold>>=2; bits-=2; } else if(here.val==17) { //was NEEDBITS(_this.bits+3); while(bits<here.bits+3) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(_this.bits); hold>>=here.bits; bits-=here.bits; len=0; //was copy=3+BITS(3); copy=3+(hold&0x07); //was DROPBITS(3); hold>>=3; bits-=3; } else { //was NEEDBITS(_this.bits+7); while(bits<here.bits+7) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(_this.bits); hold>>=here.bits; bits-=here.bits; len=0; //was copy=11+BITS(7); copy=11+(hold&0x7F); //was DROPBITS(7); hold>>=7; bits-=7; } if(state.have+copy>state.nlen+state.ndist) { strm.msg="invalid bit length repeat"; state.mode=inflate_mode.BAD; break; } while((copy--)!=0) state.lens[state.have++]=(ushort)len; } } // handle error breaks in while if(state.mode==inflate_mode.BAD) break; // check for end-of-block code (better have one) if(state.lens[256]==0) { strm.msg="invalid code -- missing end-of-block"; state.mode=inflate_mode.BAD; break; } // build code tables -- note: do not change the lenbits or distbits // values here (9 and 6) without reading the comments in inftrees.h // concerning the ENOUGH constants, which depend on those values state.next=0; state.lencode=state.codes; state.lenbits=9; //was ret=inflate_table(codetype.LENS, state.lens, state.nlen, &(state.next), &(state.lenbits), state.work); ret=inflate_table(codetype.LENS, state.lens, 0, state.nlen, state.codes, ref state.next, ref state.lenbits, state.work); if(ret!=0) { strm.msg="invalid literal/lengths set"; state.mode=inflate_mode.BAD; break; } //was state.distcode = (code const *)(state.next); state.distcode=state.codes; state.distcode_ind=state.next; state.distbits=6; //was ret=inflate_table(codetype.DISTS, state.lens+state.nlen, state.ndist, &(state.next), &(state.distbits), state.work); ret=inflate_table(codetype.DISTS, state.lens, (int)state.nlen, state.ndist, state.codes, ref state.next, ref state.distbits, state.work); if(ret!=0) { strm.msg="invalid distances set"; state.mode=inflate_mode.BAD; break; } //Tracev((stderr, "inflate: codes ok\n")); state.mode=inflate_mode.LEN_; if(flush==Z_TREES) goto inf_leave; break; // no fall through case inflate_mode.LEN_: state.mode=inflate_mode.LEN; break; // no fall through case inflate_mode.LEN: if(have>=6&&left>=258) { //was RESTORE(); strm.next_out=put; strm.avail_out=left; strm.next_in=next; strm.avail_in=have; state.hold=hold; state.bits=bits; inflate_fast(strm, _out); //was LOAD(); put=strm.next_out; left=strm.avail_out; next=strm.next_in; have=strm.avail_in; hold=state.hold; bits=state.bits; if(state.mode==inflate_mode.TYPE) state.back=-1; break; } state.back=0; for(; ; ) { //was _this=state.lencode[BITS(state.lenbits)]; here=state.lencode[hold&((1<<(int)state.lenbits)-1)]; if(here.bits<=bits) break; //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(here.op!=0&&(here.op&0xf0)==0) { last=here; for(; ; ) { //was _this=state.lencode[last.val+(BITS(last.bits+last.op)>>last.bits)]; here=state.lencode[last.val+((hold&((1<<(int)(last.bits+last.op))-1))>>last.bits)]; if((last.bits+here.bits)<=bits) break; //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(last.bits); hold>>=last.bits; bits-=last.bits; state.back+=last.bits; } //was DROPBITS(here.bits); hold>>=here.bits; bits-=here.bits; state.back+=here.bits; state.length=here.val; if(here.op==0) { //Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", this.val)); state.mode=inflate_mode.LIT; break; } if((here.op&32)!=0) { //Tracevv((stderr, "inflate: end of block\n")); state.back=-1; state.mode=inflate_mode.TYPE; break; } if((here.op&64)!=0) { strm.msg="invalid literal/length code"; state.mode=inflate_mode.BAD; break; } state.extra=(uint)(here.op&15); state.mode=inflate_mode.LENEXT; break; // no fall through case inflate_mode.LENEXT: if(state.extra!=0) { //was NEEDBITS(state.extra); while(bits<state.extra) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was state.length+=BITS(state.extra); state.length+=(uint)(hold&((1<<(int)state.extra)-1)); //was DROPBITS(state.extra); hold>>=(int)state.extra; bits-=state.extra; state.back+=(int)state.extra; } //Tracevv((stderr, "inflate: length %u\n", state.length)); state.was=state.length; state.mode=inflate_mode.DIST; break; // no fall through case inflate_mode.DIST: for(; ; ) { //was _this=state.distcode[BITS(state.distbits)]; here=state.distcode[state.distcode_ind+(hold&((1<<(int)state.distbits)-1))]; if(here.bits<=bits) break; //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if((here.op&0xf0)==0) { last=here; for(; ; ) { //was _this=state.distcode[last.val+(BITS(last.bits+last.op)>>last.bits)]; here=state.distcode[state.distcode_ind+last.val+((hold&((1<<(int)(last.bits+last.op))-1))>>last.bits)]; if((last.bits+here.bits)<=bits) break; //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was DROPBITS(last.bits); hold>>=last.bits; bits-=last.bits; state.back+=last.bits; } //was DROPBITS(_this.bits); hold>>=here.bits; bits-=here.bits; state.back+=here.bits; if((here.op&64)!=0) { strm.msg="invalid distance code"; state.mode=inflate_mode.BAD; break; } state.offset=here.val; state.extra=(uint)(here.op&15); state.mode=inflate_mode.DISTEXT; break; // no fall through case inflate_mode.DISTEXT: if(state.extra!=0) { //was NEEDBITS(state.extra); while(bits<state.extra) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } //was state.offset+=BITS(state.extra); state.offset+=(uint)(hold&((1<<(int)state.extra)-1)); //was DROPBITS(state.extra); hold>>=(int)state.extra; bits-=state.extra; state.back+=(int)state.extra; } if(state.offset>state.dmax) { strm.msg="invalid distance too far back (STRICT)"; state.mode=inflate_mode.BAD; break; } //Tracevv((stderr, "inflate: distance %u\n", state.offset)); state.mode=inflate_mode.MATCH; break; // no fall through case inflate_mode.MATCH: if(left==0) goto inf_leave; copy=_out-left; if(state.offset>copy) { // copy from window copy=state.offset-copy; if(copy>state.whave) { if(state.sane) { strm.msg="invalid distance too far back"; state.mode=inflate_mode.BAD; break; } #if INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR //Trace((stderr, "inflate.c too far\n")); copy-=state.whave; if(copy>state.length) copy=state.length; if(copy>left) copy=left; left-=copy; state.length-=copy; do { out_buf[put++]=0; } while(--copy!=0); if(state.length==0) state.mode=inflate_mode.LEN; break; #endif } if(copy>state.wnext) { copy-=state.wnext; from=state.window; from_ind=(int)(state.wsize-copy); } else { from=state.window; from_ind=(int)(state.wnext-copy); } if(copy>state.length) copy=state.length; } else { // copy from output from=out_buf; from_ind=(int)(put-state.offset); copy=state.length; } if(copy>left) copy=left; left-=copy; state.length-=copy; do { out_buf[put++]=from[from_ind++]; } while(--copy!=0); if(state.length==0) state.mode=inflate_mode.LEN; break; case inflate_mode.LIT: if(left==0) goto inf_leave; out_buf[put++]=(byte)(state.length); left--; state.mode=inflate_mode.LEN; break; case inflate_mode.CHECK: if(state.wrap!=0) { //was NEEDBITS(32); while(bits<32) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } _out-=left; strm.total_out+=_out; state.total+=_out; if(out_buf!=null) strm.adler=state.check=(state.flags!=0?crc32(state.check, out_buf, (uint)(put-_out), _out):adler32(state.check, out_buf, (uint)(put-_out), _out)); _out=left; //was if((state.flags ? hold :REVERSE(hold))!=state.check) if((state.flags!=0?hold:((hold>>24)&0xff)+((hold>>8)&0xff00)+((hold&0xff00)<<8)+((hold&0xff)<<24))!=state.check) { strm.msg="incorrect data check"; state.mode=inflate_mode.BAD; break; } //was INITBITS(); hold=bits=0; //Tracev((stderr, "inflate: check matches trailer\n")); } state.mode=(state.wrap!=0&&state.flags!=0?inflate_mode.LENGTH:inflate_mode.DONE); break; // no fall through case inflate_mode.LENGTH: //was NEEDBITS(32); while(bits<32) { //was PULLBYTE(); if(have==0) goto inf_leave; have--; hold+=(uint)in_buf[next++]<<(int)bits; bits+=8; } if(hold!=(state.total&0xffffffffU)) { strm.msg="incorrect length check"; state.mode=inflate_mode.BAD; break; } //was INITBITS(); hold=bits=0; //Tracev((stderr, "inflate: length matches trailer\n")); state.mode=inflate_mode.DONE; break; // no fall through case inflate_mode.DONE: ret=Z_STREAM_END; goto inf_leave; case inflate_mode.BAD: ret=Z_DATA_ERROR; goto inf_leave; case inflate_mode.MEM: return Z_MEM_ERROR; case inflate_mode.SYNC: return Z_STREAM_ERROR; default: return Z_STREAM_ERROR; } // switch(state.mode) } // for(; ; ) // 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: //was RESTORE(); strm.next_out=put; strm.avail_out=left; strm.next_in=next; strm.avail_in=have; state.hold=hold; state.bits=bits; if(state.wsize!=0||(state.mode<inflate_mode.CHECK&&_out!=strm.avail_out)) { if(updatewindow(strm, _out)!=0) { state.mode=inflate_mode.MEM; 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!=0&&_out!=0) strm.adler=state.check=(state.flags!=0?crc32(state.check, out_buf, (uint)(strm.next_out-_out), _out):adler32(state.check, out_buf, (uint)(strm.next_out-_out), _out)); //??? strm.data_type=state.bits+(state.last!=0?64:0)+(state.mode==inflate_mode.TYPE?128:0); if(((_in==0&&_out==0)||flush==Z_FINISH)&&ret==Z_OK) ret=Z_BUF_ERROR; return ret; }
// ========================================================================= // This is another version of deflateInit with more compression options. The // fields next_in, zalloc, zfree and opaque must be initialized before by // the caller. // The method parameter is the compression method. It must be Z_DEFLATED in // this version of the library. // The windowBits parameter is the base two logarithm of the window size // (the size of the history buffer). It should be in the range 8..15 for this // version of the library. Larger values of this parameter result in better // compression at the expense of memory usage. The default value is 15 if // deflateInit is used instead. // windowBits can also be -8..-15 for raw deflate. In this case, -windowBits // determines the window size. deflate() will then generate raw deflate data // with no zlib header or trailer, and will not compute an adler32 check value. // windowBits can also be greater than 15 for optional gzip encoding. Add // 16 to windowBits to write a simple gzip header and trailer around the // compressed data instead of a zlib wrapper. The gzip header will have no // file name, no extra data, no comment, no modification time (set to zero), // no header crc, and the operating system will be set to 255 (unknown). If a // gzip stream is being written, strm.adler is a crc32 instead of an adler32. // The memLevel parameter specifies how much memory should be allocated // for the internal compression state. memLevel=1 uses minimum memory but // is slow and reduces compression ratio; memLevel=9 uses maximum memory // for optimal speed. The default value is 8. See zconf.h for total memory // usage as a function of windowBits and memLevel. // The strategy parameter is used to tune the compression algorithm. Use the // value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a // filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no // string match), or Z_RLE to limit match distances to one (run-length // encoding). Filtered data consists mostly of small values with a somewhat // random distribution. In this case, the compression algorithm is tuned to // compress them better. The effect of Z_FILTERED is to force more Huffman // coding and less string matching; it is somewhat intermediate between // Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as // Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy // parameter only affects the compression ratio but not the correctness of the // compressed output even if it is not set appropriately. Z_FIXED prevents the // use of dynamic Huffman codes, allowing for a simpler decoder for special // applications. // deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough // memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid // method). msg is set to null if there is no error message. deflateInit2 does // not perform any compression: this will be done by deflate(). public static int deflateInit2(z_stream strm, int level, int method, int windowBits, int memLevel, int strategy) { if(strm==null) return Z_STREAM_ERROR; strm.msg=null; if(level==Z_DEFAULT_COMPRESSION) level=6; int wrap=1; if(windowBits<0) { // suppress zlib wrapper wrap=0; windowBits=-windowBits; } else if(windowBits>15) { wrap=2; // write gzip wrapper instead windowBits-=16; } if(memLevel<1||memLevel>MAX_MEM_LEVEL||method!=Z_DEFLATED||windowBits<8||windowBits>15||level<0||level>9|| strategy<0||strategy>Z_FIXED) return Z_STREAM_ERROR; if(windowBits==8) windowBits=9; // until 256-byte window bug fixed deflate_state s; try { s=new deflate_state(); } catch(Exception) { return Z_MEM_ERROR; } strm.state=s; s.strm=strm; s.wrap=wrap; s.w_bits=(uint)windowBits; s.w_size=1U<<(int)s.w_bits; s.w_mask=s.w_size-1; s.hash_bits=(uint)memLevel+7; s.hash_size=1U<<(int)s.hash_bits; s.hash_mask=s.hash_size-1; s.hash_shift=(s.hash_bits+MIN_MATCH-1)/MIN_MATCH; try { s.window=new byte[s.w_size*2]; s.prev=new ushort[s.w_size]; s.head=new ushort[s.hash_size]; s.high_water=0; // nothing written to s->window yet s.lit_bufsize=1U<<(memLevel+6); // 16K elements by default s.pending_buf=new byte[s.lit_bufsize*4]; s.pending_buf_size=s.lit_bufsize*4; s.d_buf=new ushort[s.lit_bufsize]; s.l_buf=new byte[s.lit_bufsize]; } catch(Exception) { s.status=FINISH_STATE; strm.msg=zError(Z_MEM_ERROR); deflateEnd(strm); return Z_MEM_ERROR; } s.level=level; s.strategy=strategy; s.method=(byte)method; return deflateReset(strm); }
// ========================================================================= // Flush as much pending output as possible. All deflate() output goes // through this function so some applications may wish to modify it // to avoid allocating a large strm.next_out buffer and copying into it. // (See also read_buf()). static void flush_pending(z_stream strm) { deflate_state s=(deflate_state)strm.state; uint len=s.pending; if(len>strm.avail_out) len=strm.avail_out; if(len==0) return; //was memcpy(strm.next_out, s.pending_out, len); Array.Copy(s.pending_buf, s.pending_out, strm.out_buf, strm.next_out, len); strm.next_out+=(int)len; s.pending_out+=(int)len; strm.total_out+=len; strm.avail_out-=len; s.pending-=len; if(s.pending==0) s.pending_out=0; }
// Skips invalid compressed data until a full flush point (see above the // description of deflate with Z_FULL_FLUSH) can be found, or until all // available input is skipped. No output is provided. // inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR // if no more input was provided, Z_DATA_ERROR if no flush point has been found, // or Z_STREAM_ERROR if the stream structure was inconsistent. In the success // case, the application may save the current current value of total_in which // indicates where valid compressed data was found. In the error case, the // application may repeatedly call inflateSync, providing more input each time, // until success or end of the input data. public static int inflateSync(z_stream strm) { uint len; // number of bytes to look at or looked at uint _in, _out; // temporary to save total_in and total_out byte[] buf=new byte[4]; // to restore bit buffer to byte string // check parameters if(strm==null||strm.state==null) return Z_STREAM_ERROR; inflate_state state=(inflate_state)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!=inflate_mode.SYNC) { state.mode=inflate_mode.SYNC; state.hold<<=(int)(state.bits&7); state.bits-=state.bits&7; len=0; while(state.bits>=8) { buf[len++]=(byte)state.hold; state.hold>>=8; state.bits-=8; } state.have=0; syncsearch(ref state.have, buf, 0, len); } // search available input len=syncsearch(ref state.have, strm.in_buf, 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=inflate_mode.TYPE; return Z_OK; }
// ========================================================================= // Dynamically update the compression level and compression strategy. The // interpretation of level and strategy is as in deflateInit2. This can be // used to switch between compression and straight copy of the input data, or // to switch to a different kind of input data requiring a different // strategy. If the compression level is changed, the input available so far // is compressed with the old level (and may be flushed); the new level will // take effect only at the next call of deflate(). // Before the call of deflateParams, the stream state must be set as for // a call of deflate(), since the currently available input may have to // be compressed and flushed. In particular, strm.avail_out must be non-zero. // deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source // stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR // if strm.avail_out was zero. public static int deflateParams(z_stream strm, int level, int strategy) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; if(level==Z_DEFAULT_COMPRESSION) level=6; if(level<0||level>9||strategy<0||strategy>Z_FIXED) return Z_STREAM_ERROR; compress_func func=configuration_table[s.level].func; int err=Z_OK; if((strategy!=s.strategy||func!=configuration_table[level].func)&&strm.total_in!=0) // Flush the last buffer: err=deflate(strm, Z_BLOCK); if(s.level!=level) { s.level=level; s.max_lazy_match=configuration_table[level].max_lazy; s.good_match=configuration_table[level].good_length; s.nice_match=configuration_table[level].nice_length; s.max_chain_length=configuration_table[level].max_chain; } s.strategy=strategy; return err; }
// ========================================================================= // deflatePrime() inserts bits in the deflate output stream. The intent // is that this function is used to start off the deflate output with the // bits leftover from a previous deflate stream when appending to it. As such, // this function can only be used for raw deflate, and must be used before the // first deflate() call after a deflateInit2() or deflateReset(). bits must be // less than or equal to 16, and that many of the least significant bits of // value will be inserted in the output. // deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent. public static int deflatePrime(z_stream strm, int bits, int value) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; s.bi_valid=bits; s.bi_buf=(ushort)(value&((1<<bits)-1)); return Z_OK; }
// ========================================================================= // deflateSetHeader() provides gzip header information for when a gzip // stream is requested by deflateInit2(). deflateSetHeader() may be called // after deflateInit2() or deflateReset() and before the first call of // deflate(). The text, time, os, extra field, name, and comment information // in the provided gz_header structure are written to the gzip header (xflag is // ignored -- the extra flags are set according to the compression level). The // caller must assure that, if not Z_NULL, name and comment are terminated with // a zero byte, and that if extra is not Z_NULL, that extra_len bytes are // available there. If hcrc is true, a gzip header crc is included. Note that // the current versions of the command-line version of gzip (up through version // 1.3.x) do not support header crc's, and will report that it is a "multi-part // gzip file" and give up. // If deflateSetHeader is not used, the default gzip header has text false, // the time set to zero, and os set to 255, with no extra, name, or comment // fields. The gzip header is returned to the default state by deflateReset(). // deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent. public static int deflateSetHeader(z_stream strm, gz_header head) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; if(s.wrap!=2) return Z_STREAM_ERROR; s.gzhead=head; return Z_OK; }
// Initializes the internal stream state for decompression. The fields // next_in, avail_in, zalloc, zfree and opaque must be initialized before by // the caller. If next_in is not Z_NULL and avail_in is large enough (the exact // value depends on the compression method), inflateInit determines the // compression method from the zlib header and allocates all data structures // accordingly; otherwise the allocation will be deferred to the first call of // inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to // use default allocation functions. // inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough // memory, Z_VERSION_ERROR if the zlib library version is incompatible with the // version assumed by the caller. msg is set to null if there is no error // message. inflateInit does not perform any decompression apart from reading // the zlib header if present: this will be done by inflate(). (So next_in and // avail_in may be modified, but next_out and avail_out are unchanged.) public static int inflateInit(z_stream strm) { return inflateInit2(strm, DEF_WBITS); }
public static long inflateMark(z_stream strm) { if(strm==null||strm.state==null) return -1L<<16; inflate_state state=(inflate_state)strm.state; return ((long)(state.back)<<16)+ (state.mode==inflate_mode.COPY?state.length:(state.mode==inflate_mode.MATCH?state.was-state.length:0)); }
/* * 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. */ private static int updatewindow( z_stream strm, byte[] end_array, long end_index, uint copy) { inflate_state state; uint dist; state = strm.state; /* if it hasn't been done already, allocate space for the window */ if (state.window == null) { state.window = new byte[1U << (int)state.wbits]; if (state.window == null) { return(1); } } /* if window not in use yet, initialize */ if (state.wsize == 0) { state.wsize = 1U << (int)state.wbits; state.wnext = 0; state.whave = 0; } /* copy state.wsize or less output bytes into the circular window */ if (copy >= state.wsize) { zutil.zmemcpy(state.window, 0, end_array, end_index - state.wsize, state.wsize); state.wnext = 0; state.whave = state.wsize; } else { dist = state.wsize - state.wnext; if (dist > copy) { dist = copy; } zutil.zmemcpy(state.window, state.wnext, end_array, end_index - copy, dist); copy -= dist; if (copy != 0) { zutil.zmemcpy(state.window, 0, end_array, end_index - copy, copy); state.wnext = copy; state.whave = state.wsize; } else { state.wnext += dist; if (state.wnext == state.wsize) { state.wnext = 0; } if (state.whave < state.wsize) { state.whave += dist; } } } return(0); }
// Sets the destination stream as a complete copy of the source stream. // This function can be useful when randomly accessing a large stream. The // first pass through the stream can periodically record the inflate state, // allowing restarting inflate at those points when randomly accessing the // stream. // inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_STREAM_ERROR if the source stream state was inconsistent // (such as zalloc being NULL). msg is left unchanged in both source and // destination. public static int inflateCopy(z_stream dest, z_stream source) { // check input if(dest==null||source==null||source.state==null) return Z_STREAM_ERROR; inflate_state state=(inflate_state)source.state; // allocate space inflate_state copy=null; try { copy=state.GetCopy(); } catch(Exception) { copy=null; return Z_MEM_ERROR; } source.CopyTo(dest); // copy state dest.state=copy; return Z_OK; }
// This is another version of inflateInit with an extra parameter. The // fields next_in, avail_in, zalloc, zfree and opaque must be initialized // before by the caller. // The windowBits parameter is the base two logarithm of the maximum window // size (the size of the history buffer). It should be in the range 8..15 for // this version of the library. The default value is 15 if inflateInit is used // instead. windowBits must be greater than or equal to the windowBits value // provided to deflateInit2() while compressing, or it must be equal to 15 if // deflateInit2() was not used. If a compressed stream with a larger window // size is given as input, inflate() will return with the error code // Z_DATA_ERROR instead of trying to allocate a larger window. // windowBits can also be -8..-15 for raw inflate. In this case, -windowBits // determines the window size. inflate() will then process raw deflate data, // not looking for a zlib or gzip header, not generating a check value, and not // looking for any check values for comparison at the end of the stream. This // is for use with other formats that use the deflate compressed data format // such as zip. Those formats provide their own check values. If a custom // format is developed using the raw deflate format for compressed data, it is // recommended that a check value such as an adler32 or a crc32 be applied to // the uncompressed data as is done in the zlib, gzip, and zip formats. For // most applications, the zlib format should be used as is. Note that comments // above on the use in deflateInit2() applies to the magnitude of windowBits. // windowBits can also be greater than 15 for optional gzip decoding. Add // 32 to windowBits to enable zlib and gzip decoding with automatic header // detection, or add 16 to decode only the gzip format (the zlib format will // return a Z_DATA_ERROR). If a gzip stream is being decoded, strm.adler is // a crc32 instead of an adler32. // inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough // memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg // is set to null if there is no error message. inflateInit2 does not perform // any decompression apart from reading the zlib header if present: this will // be done by inflate(). (So next_in and avail_in may be modified, but next_out // and avail_out are unchanged.) public static int inflateInit2(z_stream strm, int windowBits) { if(strm==null) return Z_STREAM_ERROR; strm.msg=null; // in case we return an error inflate_state state; try { state=new inflate_state(); } catch(Exception) { return Z_MEM_ERROR; } //Tracev((stderr, "inflate: allocated\n")); strm.state=state; state.window=null; int ret=inflateReset2(strm, windowBits); if(ret!=Z_OK) strm.state=null; return ret; }
// ========================================================================= // Initializes the compression dictionary from the given byte sequence // without producing any compressed output. This function must be called // immediately after deflateInit, deflateInit2 or deflateReset, before any // call of deflate. The compressor and decompressor must use exactly the same // dictionary (see inflateSetDictionary). // The dictionary should consist of strings (byte sequences) that are likely // to be encountered later in the data to be compressed, with the most commonly // used strings preferably put towards the end of the dictionary. Using a // dictionary is most useful when the data to be compressed is short and can be // predicted with good accuracy; the data can then be compressed better than // with the default empty dictionary. // Depending on the size of the compression data structures selected by // deflateInit or deflateInit2, a part of the dictionary may in effect be // discarded, for example if the dictionary is larger than the window size in // deflate or deflate2. Thus the strings most likely to be useful should be // put at the end of the dictionary, not at the front. In addition, the // current implementation of deflate will use at most the window size minus // 262 bytes of the provided dictionary. // Upon return of this function, strm.adler is set to the adler32 value // of the dictionary; the decompressor may later use this value to determine // which dictionary has been used by the compressor. (The adler32 value // applies to the whole dictionary even if only a subset of the dictionary is // actually used by the compressor.) If a raw deflate was requested, then the // adler32 value is not computed and strm.adler is not set. // deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a // parameter is invalid (such as NULL dictionary) or the stream state is // inconsistent (for example if deflate has already been called for this stream // or if the compression method is bsort). deflateSetDictionary does not // perform any compression: this will be done by deflate(). public static int deflateSetDictionary(z_stream strm, byte[] dictionary, uint dictLength) { uint length=dictLength; uint n; uint hash_head=0; if(strm==null||strm.state==null||dictionary==null) return Z_STREAM_ERROR; deflate_state s=strm.state as deflate_state; if(s==null||s.wrap==2||(s.wrap==1&&s.status!=INIT_STATE)) return Z_STREAM_ERROR; if(s.wrap!=0) strm.adler=adler32(strm.adler, dictionary, dictLength); if(length<MIN_MATCH) return Z_OK; int dictionary_ind=0; if(length>s.w_size) { length=s.w_size; dictionary_ind=(int)(dictLength-length); // use the tail of the dictionary } //was memcpy(s.window, dictionary+dictionary_ind, length); Array.Copy(dictionary, dictionary_ind, s.window, 0, length); s.strstart=length; s.block_start=(int)length; // Insert all strings in the hash table (except for the last two bytes). // s.lookahead stays null, so s.ins_h will be recomputed at the next // call of fill_window. s.ins_h=s.window[0]; //was UPDATE_HASH(s, s.ins_h, s.window[1]); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[1])&s.hash_mask; for(n=0; n<=length-MIN_MATCH; n++) { //was INSERT_STRING(s, n, hash_head); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[n+(MIN_MATCH-1)])&s.hash_mask; hash_head=s.prev[n&s.w_mask]=s.head[s.ins_h]; s.head[s.ins_h]=(ushort)n; } if(hash_head!=0) hash_head=0; // to make compiler happy return Z_OK; }
// =========================================================================== // Read a new buffer from the current input stream, update the adler32 // and total number of bytes read. All deflate() input goes through // this function so some applications may wish to modify it to avoid // allocating a large strm.next_in buffer and copying from it. // (See also flush_pending()). static int read_buf(z_stream strm, byte[] buf, uint size) { return read_buf(strm, buf, 0, size); }
// ========================================================================= // Sets the destination stream as a complete copy of the source stream. // This function can be useful when several compression strategies will be // tried, for example when there are several ways of pre-processing the input // data with a filter. The streams that will be discarded should then be freed // by calling deflateEnd. Note that deflateCopy duplicates the internal // compression state which can be quite large, so this strategy is slow and // can consume lots of memory. // deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not // enough memory, Z_STREAM_ERROR if the source stream state was inconsistent // (such as zalloc being NULL). msg is left unchanged in both source and // destination. // Copy the source state to the destination state. public static int deflateCopy(z_stream dest, z_stream source) { if(source==null||dest==null||source.state==null) return Z_STREAM_ERROR; deflate_state ss=(deflate_state)source.state; //was memcpy(dest, source, sizeof(z_stream)); source.CopyTo(dest); deflate_state ds; try { ds=ss.Clone(); } catch(Exception) { return Z_MEM_ERROR; } dest.state=ds; //(done above) memcpy(ds, ss, sizeof(deflate_state)); ds.strm=dest; try { ds.window=new byte[ds.w_size*2]; ds.prev=new ushort[ds.w_size]; ds.head=new ushort[ds.hash_size]; ds.pending_buf=new byte[ds.lit_bufsize*4]; ds.d_buf=new ushort[ds.lit_bufsize]; ds.l_buf=new byte[ds.lit_bufsize]; } catch(Exception) { deflateEnd(dest); return Z_MEM_ERROR; } //was memcpy(ds.window, ss.window, ds.w_size*2*sizeof(byte)); ss.window.CopyTo(ds.window, 0); //was memcpy(ds.prev, ss.prev, ds.w_size*sizeof(ushort)); ss.prev.CopyTo(ds.prev, 0); //was memcpy(ds.head, ss.head, ds.hash_size*sizeof(ushort)); ss.head.CopyTo(ds.head, 0); //was memcpy(ds.pending_buf, ss.pending_buf, (uint)ds.pending_buf_size); ss.pending_buf.CopyTo(ds.pending_buf, 0); ss.d_buf.CopyTo(ds.d_buf, 0); ss.l_buf.CopyTo(ds.l_buf, 0); ds.l_desc.dyn_tree=ds.dyn_ltree; ds.d_desc.dyn_tree=ds.dyn_dtree; ds.bl_desc.dyn_tree=ds.bl_tree; return Z_OK; }
public static int inflateUndermine(z_stream strm, bool subvert) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; inflate_state state=(inflate_state)strm.state; state.sane=!subvert; #if INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state.sane=true; return Z_DATA_ERROR; #endif }
public int run(z_stream _strm, int _flush) { this.strm = _strm; this.flush = _flush; if (inflateStateCheck(strm) != 0 || strm.output_buffer == null || (strm.input_buffer == null && strm.avail_in != 0)) { return(zlib.Z_STREAM_ERROR); } state = strm.state; if (state.mode == inflate_mode.TYPE) { state.mode = inflate_mode.TYPEDO; /* skip check */ } LOAD(); @in = have; @out = left; ret = zlib.Z_OK; for (;;) { switch (state.mode) { case inflate_mode.HEAD: if (state.wrap == 0) { state.mode = inflate_mode.TYPEDO; break; } if (NEEDBITS_(16)) { goto inf_leave; } //#ifdef GUNZIP if ((state.wrap & 2) != 0 && hold == 0x8b1f) /* gzip header */ { if (state.wbits == 0) { state.wbits = 15; } state.check = crc32.crc32_(0L, null, 0, 0); CRC2(state.check, hold); INITBITS(); state.mode = inflate_mode.FLAGS; break; } state.flags = 0; /* expect zlib header */ if (state.head != null) { state.head.done = -1; } if (!((state.wrap & 1) != 0) || /* check if zlib header allowed */ //#else // if ( //#endif (((BITS(8) << 8) + (hold >> 8)) % 31) != 0) { strm.msg = "incorrect header check"; state.mode = inflate_mode.BAD; break; } if (BITS(4) != zlib.Z_DEFLATED) { strm.msg = "unknown compression method"; state.mode = inflate_mode.BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state.wbits == 0) { state.wbits = len; } if (len > 15 || len > state.wbits) { strm.msg = "invalid window size"; state.mode = inflate_mode.BAD; break; } state.dmax = 1U << (int)len; //Tracev((stderr, "inflate: zlib header ok\n")); strm.adler = state.check = adler32.adler32_(0L, null, 0, 0); state.mode = (hold & 0x200) != 0 ? inflate_mode.DICTID : inflate_mode.TYPE; INITBITS(); break; //#ifdef GUNZIP case inflate_mode.FLAGS: if (NEEDBITS_(16)) { goto inf_leave; } state.flags = (int)(hold); if ((state.flags & 0xff) != zlib.Z_DEFLATED) { strm.msg = "unknown compression method"; state.mode = inflate_mode.BAD; break; } if ((state.flags & 0xe000) != 0) { strm.msg = "unknown header flags set"; state.mode = inflate_mode.BAD; break; } if (state.head != null) { state.head.text = (int)((hold >> 8) & 1); } if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { CRC2(state.check, hold); } INITBITS(); state.mode = inflate_mode.TIME; goto case inflate_mode.TIME; case inflate_mode.TIME: if (NEEDBITS_(32)) { goto inf_leave; } if (state.head != null) { state.head.time = hold; } if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { CRC4(state.check, hold); } INITBITS(); state.mode = inflate_mode.OS; goto case inflate_mode.OS; case inflate_mode.OS: if (NEEDBITS_(16)) { goto inf_leave; } if (state.head != null) { state.head.xflags = (int)(hold & 0xff); state.head.os = (int)(hold >> 8); } if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { CRC2(state.check, hold); } INITBITS(); state.mode = inflate_mode.EXLEN; goto case inflate_mode.EXLEN; case inflate_mode.EXLEN: if ((state.flags & 0x0400) != 0) { if (NEEDBITS_(16)) { goto inf_leave; } state.length = (uint)(hold); if (state.head != null) { state.head.extra_len = (uint)hold; } if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { CRC2(state.check, hold); } INITBITS(); } else if (state.head != null) { state.head.extra = null; } state.mode = inflate_mode.EXTRA; goto case inflate_mode.EXTRA; case inflate_mode.EXTRA: if ((state.flags & 0x0400) != 0) { copy = state.length; if (copy > have) { copy = have; } if (copy != 0) { if (state.head != null && state.head.extra != null) { len = state.head.extra_len - state.length; zutil.zmemcpy(state.head.extra, len, next_buffer, next_index, len + copy > state.head.extra_max ? state.head.extra_max - len : copy); } if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { state.check = crc32.crc32_(state.check, next_buffer, next_index, copy); } have -= copy; next_index += copy; state.length -= copy; } if (state.length != 0) { goto inf_leave; } } state.length = 0; state.mode = inflate_mode.NAME; goto case inflate_mode.NAME; case inflate_mode.NAME: if ((state.flags & 0x0800) != 0) { if (have == 0) { goto inf_leave; } copy = 0; do { len = (uint)(next_buffer[next_index + copy++]); if (state.head != null && state.head.name != null && state.length < state.head.name_max) { state.head.name[state.length++] = (byte)len; } } while (len != 0 && copy < have); if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { state.check = crc32.crc32_(state.check, next_buffer, next_index, copy); } have -= copy; next_index += copy; if (len != 0) { goto inf_leave; } } else if (state.head != null) { state.head.name = null; } state.length = 0; state.mode = inflate_mode.COMMENT; goto case inflate_mode.COMMENT; case inflate_mode.COMMENT: if ((state.flags & 0x1000) != 0) { if (have == 0) { goto inf_leave; } copy = 0; do { len = (uint)(next_buffer[next_index + copy++]); if (state.head != null && state.head.comment != null && state.length < state.head.comm_max) { state.head.comment[state.length++] = (byte)len; } } while (len != 0 && copy < have); if ((state.flags & 0x0200) != 0 && (state.wrap & 4) != 0) { state.check = crc32.crc32_(state.check, next_buffer, next_index, copy); } have -= copy; next_index += copy; if (len != 0) { goto inf_leave; } } else if (state.head != null) { state.head.comment = null; } state.mode = inflate_mode.HCRC; goto case inflate_mode.HCRC; case inflate_mode.HCRC: if ((state.flags & 0x0200) != 0) { if (NEEDBITS_(16)) { goto inf_leave; } if ((state.wrap & 4) != 0 && hold != (state.check & 0xffff)) { strm.msg = "header crc mismatch"; state.mode = inflate_mode.BAD; break; } INITBITS(); } if (state.head != null) { state.head.hcrc = (int)((state.flags >> 9) & 1); state.head.done = 1; } strm.adler = state.check = crc32.crc32_(0L, null, 0, 0); state.mode = inflate_mode.TYPE; break; //#endif case inflate_mode.DICTID: if (NEEDBITS_(32)) { goto inf_leave; } strm.adler = state.check = zutil.ZSWAP32((uint)hold); INITBITS(); state.mode = inflate_mode.DICT; goto case inflate_mode.DICT; case inflate_mode.DICT: if (state.havedict == 0) { RESTORE(); return(zlib.Z_NEED_DICT); } strm.adler = state.check = adler32.adler32_(0L, null, 0, 0); state.mode = inflate_mode.TYPE; goto case inflate_mode.TYPE; case inflate_mode.TYPE: if (flush == zlib.Z_BLOCK || flush == zlib.Z_TREES) { goto inf_leave; } goto case inflate_mode.TYPEDO; case inflate_mode.TYPEDO: if (state.last != 0) { BYTEBITS(); state.mode = inflate_mode.CHECK; break; } if (NEEDBITS_(3)) { goto inf_leave; } state.last = (int)BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ //Tracev((stderr, "inflate: stored block%s\n", // state.last ? " (last)" : "")); state.mode = inflate_mode.STORED; break; case 1: /* fixed block */ fixedtables(state); //Tracev((stderr, "inflate: fixed codes block%s\n", // state.last ? " (last)" : "")); state.mode = inflate_mode.LEN_; /* decode codes */ if (flush == zlib.Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ //Tracev((stderr, "inflate: dynamic codes block%s\n", // state.last ? " (last)" : "")); state.mode = inflate_mode.TABLE; break; case 3: strm.msg = "invalid block type"; state.mode = inflate_mode.BAD; break; } DROPBITS(2); break; case inflate_mode.STORED: BYTEBITS(); /* go to byte boundary */ if (NEEDBITS_(32)) { goto inf_leave; } if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm.msg = "invalid stored block lengths"; state.mode = inflate_mode.BAD; break; } state.length = (uint)hold & 0xffff; //Tracev((stderr, "inflate: stored length %u\n", // state.length)); INITBITS(); state.mode = inflate_mode.COPY_; if (flush == zlib.Z_TREES) { goto inf_leave; } goto case inflate_mode.COPY_; case inflate_mode.COPY_: state.mode = inflate_mode.COPY; goto case inflate_mode.COPY; case inflate_mode.COPY: copy = state.length; if (copy != 0) { if (copy > have) { copy = have; } if (copy > left) { copy = left; } if (copy == 0) { goto inf_leave; } zutil.zmemcpy(put_buffer, put_index, next_buffer, next_index, copy); have -= copy; next_index += copy; left -= copy; put_index += copy; state.length -= copy; break; } //Tracev((stderr, "inflate: stored end\n")); state.mode = inflate_mode.TYPE; break; case inflate_mode.TABLE: if (NEEDBITS_(14)) { goto inf_leave; } 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 = "too many length or distance symbols"; state.mode = inflate_mode.BAD; break; } //#endif //Tracev((stderr, "inflate: table sizes ok\n")); state.have = 0; state.mode = inflate_mode.LENLENS; goto case inflate_mode.LENLENS; case inflate_mode.LENLENS: while (state.have < state.ncode) { if (NEEDBITS_(3)) { goto inf_leave; } state.lens[order[state.have++]] = (ushort)BITS(3); DROPBITS(3); } while (state.have < 19) { state.lens[order[state.have++]] = 0; } state.next = 0; state.lencode_array = state.codes; state.lencode_index = state.next; state.lenbits = 7; ret = inftrees.inflate_table(codetype.CODES, state.lens, 0, 19, state.codes, ref state.next, ref state.lenbits, state.work); if (ret != 0) { strm.msg = "invalid code lengths set"; state.mode = inflate_mode.BAD; break; } //Tracev((stderr, "inflate: code lengths ok\n")); state.have = 0; state.mode = inflate_mode.CODELENS; goto case inflate_mode.CODELENS; case inflate_mode.CODELENS: while (state.have < state.nlen + state.ndist) { for (;;) { here = state.lencode_array[state.lencode_index + BITS(state.lenbits)]; if ((uint)(here.bits) <= bits) { break; } if (PULLBYTE_()) { goto inf_leave; } } if (here.val < 16) { DROPBITS(here.bits); state.lens[state.have++] = here.val; } else { if (here.val == 16) { if (NEEDBITS_(here.bits + 2)) { goto inf_leave; } DROPBITS(here.bits); if (state.have == 0) { strm.msg = "invalid bit length repeat"; state.mode = inflate_mode.BAD; break; } len = state.lens[state.have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { if (NEEDBITS_(here.bits + 3)) { goto inf_leave; } DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { if (NEEDBITS_(here.bits + 7)) { goto inf_leave; } DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state.have + copy > state.nlen + state.ndist) { strm.msg = "invalid bit length repeat"; state.mode = inflate_mode.BAD; break; } while (copy-- != 0) { state.lens[state.have++] = (ushort)len; } } } /* handle error breaks in while */ if (state.mode == inflate_mode.BAD) { break; } /* check for end-of-block code (better have one) */ if (state.lens[256] == 0) { strm.msg = "invalid code -- missing end-of-block"; state.mode = inflate_mode.BAD; break; } /* build code tables -- note: do not change the lenbits or distbits * values here (9 and 6) without reading the comments in inftrees.h * concerning the ENOUGH constants, which depend on those values */ state.next = 0; state.lencode_array = state.codes; state.lencode_index = state.next; state.lenbits = 9; ret = inftrees.inflate_table(codetype.LENS, state.lens, 0, state.nlen, state.codes, ref state.next, ref state.lenbits, state.work); if (ret != 0) { strm.msg = "invalid literal/lengths set"; state.mode = inflate_mode.BAD; break; } state.distcode_array = state.codes; state.distcode_index = state.next; state.distbits = 6; ret = inftrees.inflate_table(codetype.DISTS, state.lens, state.nlen, state.ndist, state.codes, ref state.next, ref state.distbits, state.work); if (ret != 0) { strm.msg = "invalid distances set"; state.mode = inflate_mode.BAD; break; } //Tracev((stderr, "inflate: codes ok\n")); state.mode = inflate_mode.LEN_; if (flush == zlib.Z_TREES) { goto inf_leave; } goto case inflate_mode.LEN_; case inflate_mode.LEN_: state.mode = inflate_mode.LEN; goto case inflate_mode.LEN; case inflate_mode.LEN: if (have >= 6 && left >= 258) { RESTORE(); inffast.inflate_fast(strm, @out); LOAD(); if (state.mode == inflate_mode.TYPE) { state.back = -1; } break; } state.back = 0; for (;;) { here = state.lencode_array[state.lencode_index + BITS(state.lenbits)]; if ((uint)(here.bits) <= bits) { break; } if (PULLBYTE_()) { goto inf_leave; } } if (here.op != 0 && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state.lencode_array[state.lencode_index + last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((uint)(last.bits + here.bits) <= bits) { break; } if (PULLBYTE_()) { goto inf_leave; } } DROPBITS(last.bits); state.back += last.bits; } DROPBITS(here.bits); state.back += here.bits; state.length = (uint)here.val; if ((int)(here.op) == 0) { //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? // "inflate: literal '%c'\n" : // "inflate: literal 0x%02x\n", here.val)); state.mode = inflate_mode.LIT; break; } if ((here.op & 32) != 0) { //Tracevv((stderr, "inflate: end of block\n")); state.back = -1; state.mode = inflate_mode.TYPE; break; } if ((here.op & 64) != 0) { strm.msg = "invalid literal/length code"; state.mode = inflate_mode.BAD; break; } state.extra = (uint)(here.op) & 15; state.mode = inflate_mode.LENEXT; goto case inflate_mode.LENEXT; case inflate_mode.LENEXT: if (state.extra != 0) { if (NEEDBITS_(state.extra)) { goto inf_leave; } state.length += BITS(state.extra); DROPBITS(state.extra); state.back += (int)state.extra; } //Tracevv((stderr, "inflate: length %u\n", state.length)); state.was = state.length; state.mode = inflate_mode.DIST; goto case inflate_mode.DIST; case inflate_mode.DIST: for (;;) { here = state.distcode_array[state.distcode_index + BITS(state.distbits)]; if ((uint)(here.bits) <= bits) { break; } if (PULLBYTE_()) { goto inf_leave; } } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state.distcode_array[state.distcode_index + last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((uint)(last.bits + here.bits) <= bits) { break; } if (PULLBYTE_()) { goto inf_leave; } } DROPBITS(last.bits); state.back += last.bits; } DROPBITS(here.bits); state.back += here.bits; if ((here.op & 64) != 0) { strm.msg = "invalid distance code"; state.mode = inflate_mode.BAD; break; } state.offset = (uint)here.val; state.extra = (uint)(here.op) & 15; state.mode = inflate_mode.DISTEXT; goto case inflate_mode.DISTEXT; case inflate_mode.DISTEXT: if (state.extra != 0) { if (NEEDBITS_(state.extra)) { goto inf_leave; } state.offset += BITS(state.extra); DROPBITS(state.extra); state.back += (int)state.extra; } //#ifdef INFLATE_STRICT // if (state.offset > state.dmax) { // strm.msg = "invalid distance too far back"; // state.mode = inflate_mode.BAD; // break; // } //#endif //Tracevv((stderr, "inflate: distance %u\n", state.offset)); state.mode = inflate_mode.MATCH; goto case inflate_mode.MATCH; case inflate_mode.MATCH: if (left == 0) { goto inf_leave; } copy = @out - left; if (state.offset > copy) /* copy from window */ { copy = state.offset - copy; if (copy > state.whave) { if (state.sane != 0) { strm.msg = "invalid distance too far back"; state.mode = inflate_mode.BAD; break; } //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR // Trace((stderr, "inflate.c too far\n")); // copy -= state.whave; // if (copy > state.length) copy = state.length; // if (copy > left) copy = left; // left -= copy; // state.length -= copy; // do { // *put++ = 0; // } while (--copy); // if (state.length == 0) state.mode = inflate_mode.LEN; // break; //#endif } if (copy > state.wnext) { copy -= state.wnext; from_buffer = state.window; from_index = (state.wsize - copy); } else { from_buffer = state.window; from_index = (state.wnext - copy); } if (copy > state.length) { copy = state.length; } } else /* copy from output */ { from_buffer = put_buffer; from_index = put_index - state.offset; copy = state.length; } if (copy > left) { copy = left; } left -= copy; state.length -= copy; do { put_buffer[put_index++] = from_buffer[from_index++]; } while (--copy != 0); if (state.length == 0) { state.mode = inflate_mode.LEN; } break; case inflate_mode.LIT: if (left == 0) { goto inf_leave; } put_buffer[put_index++] = (byte)(state.length); left--; state.mode = inflate_mode.LEN; break; case inflate_mode.CHECK: if (state.wrap != 0) { if (NEEDBITS_(32)) { goto inf_leave; } @out -= left; strm.total_out += @out; state.total += @out; if ((state.wrap & 4) != 0 && @out != 0) { strm.adler = state.check = UPDATE(state.check, put_buffer, put_index - @out, @out); } @out = left; if ((state.wrap & 4) != 0 && ( //#ifdef GUNZIP state.flags != 0 ? hold : //#endif zutil.ZSWAP32((uint)hold)) != state.check) { strm.msg = "incorrect data check"; state.mode = inflate_mode.BAD; break; } INITBITS(); //Tracev((stderr, "inflate: check matches trailer\n")); } //#ifdef GUNZIP state.mode = inflate_mode.LENGTH; goto case inflate_mode.LENGTH; case inflate_mode.LENGTH: if (state.wrap != 0 && state.flags != 0) { if (NEEDBITS_(32)) { goto inf_leave; } if (hold != (state.total & 0xffffffffUL)) { strm.msg = "incorrect length check"; state.mode = inflate_mode.BAD; break; } INITBITS(); //Tracev((stderr, "inflate: length matches trailer\n")); } //#endif state.mode = inflate_mode.DONE; goto case inflate_mode.DONE; case inflate_mode.DONE: ret = zlib.Z_STREAM_END; goto inf_leave; case inflate_mode.BAD: ret = zlib.Z_DATA_ERROR; goto inf_leave; case inflate_mode.MEM: return(zlib.Z_MEM_ERROR); case inflate_mode.SYNC: default: return(zlib.Z_STREAM_ERROR); } } /* * 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 != 0 || (@out != strm.avail_out && state.mode < inflate_mode.BAD && (state.mode < inflate_mode.CHECK || flush != zlib.Z_FINISH))) { if (updatewindow(strm, strm.output_buffer, strm.next_out, @out - strm.avail_out) != 0) { state.mode = inflate_mode.MEM; return(zlib.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 & 4) != 0 && @out != 0) { strm.adler = state.check = UPDATE(state.check, strm.output_buffer, strm.next_out - @out, @out); } strm.data_type = (int)state.bits + (state.last != 0 ? 64 : 0) + (state.mode == inflate_mode.TYPE ? 128 : 0) + (state.mode == inflate_mode.LEN_ || state.mode == inflate_mode.COPY_ ? 256 : 0); if (((@in == 0 && @out == 0) || flush == zlib.Z_FINISH) && ret == zlib.Z_OK) { ret = zlib.Z_BUF_ERROR; } return(ret); }
// 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. public static int inflateSyncPoint(z_stream strm) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; inflate_state state=(inflate_state)strm.state; return (state.mode==inflate_mode.STORED&&state.bits==0)?1:0; }
static int read_buf(z_stream strm, byte[] buf, int buf_ind, uint size) { uint len=strm.avail_in; if(len>size) len=size; if(len==0) return 0; strm.avail_in-=len; deflate_state s=(deflate_state)strm.state; if(s.wrap==1) strm.adler=adler32(strm.adler, strm.in_buf, (uint)strm.next_in, len); else if(s.wrap==2) strm.adler=crc32(strm.adler, strm.in_buf, strm.next_in, len); //was memcpy(buf, strm.in_buf+strm.next_in, len); Array.Copy(strm.in_buf, strm.next_in, buf, buf_ind, len); strm.next_in+=len; strm.total_in+=len; return (int)len; }
private static extern ZLibReturnCode inflate(ref z_stream strm, ZLibFlush flush);
// Decode literal, length, and distance codes and write out the resulting // literal and match bytes until either not enough input or output is // available, an end-of-block is encountered, or a data error is encountered. // When large enough input and output buffers are supplied to inflate(), for // example, a 16K input buffer and a 64K output buffer, more than 95% of the // inflate execution time is spent in this routine. // // Entry assumptions: // // state.mode == LEN // strm.avail_in >= 6 // strm.avail_out >= 258 // start >= strm.avail_out // state.bits < 8 // // On return, state.mode is one of: // // LEN -- ran out of enough output space or enough available input // TYPE -- reached end of block code, inflate() to interpret next block // BAD -- error in block data // // Notes: // // - The maximum input bits used by a length/distance pair is 15 bits for the // length code, 5 bits for the length extra, 15 bits for the distance code, // and 13 bits for the distance extra. This totals 48 bits, or six bytes. // Therefore if strm.avail_in >= 6, then there is enough input to avoid // checking for available input while decoding. // // - The maximum bytes that a single length/distance pair can output is 258 // bytes, which is the maximum length that can be coded. inflate_fast() // requires strm.avail_out >= 258 for each loop to avoid checking for // output space. private static void inflate_fast(z_stream strm, uint start) // inflate()'s starting value for strm.avail_out { inflate_state state = null; byte[] _in; // local strm.next_in uint in_ind; // ind in _in int last; // while in < last, enough input available byte[] @out; // local strm.next_out int out_ind; // ind in @out int beg; // inflate()'s initial strm.next_out int end; // while out < end, enough space available uint dmax; // maximum distance from zlib header uint wsize; // window size or zero if not using window uint whave; // valid bytes in the window uint wnext; // window write index byte[] window; // allocated sliding window, if wsize != 0 uint hold; // local strm.hold uint bits; // local strm.bits code[] lcode; // local strm.lencode code[] dcode; // local strm.distcode int dcode_ind; // index in strm.distcode uint lmask; // mask for first level of length codes uint dmask; // mask for first level of distance codes code here; // retrieved table entry uint op; // code bits, operation, extra bits, or window position, window bytes to copy uint len; // match length, unused bytes uint dist; // match distance byte[] from; // where to copy match from int from_ind; // where to copy match from // copy state to local variables state = (inflate_state)strm.state; _in = strm.in_buf; in_ind = strm.next_in; last = (int)(in_ind + (strm.avail_in - 5)); @out = strm.out_buf; out_ind = strm.next_out; beg = (int)(out_ind - (start - strm.avail_out)); end = (int)(out_ind + (strm.avail_out - 257)); dmax = state.dmax; wsize = state.wsize; whave = state.whave; wnext = state.wnext; window = state.window; hold = state.hold; bits = state.bits; lcode = state.lencode; dcode = state.distcode; dcode_ind = state.distcode_ind; lmask = (1U << (int)state.lenbits) - 1; dmask = (1U << (int)state.distbits) - 1; // decode literals and length/distances until end-of-block or not enough input data or output space do { if (bits < 15) { hold += (uint)_in[in_ind++] << (int)bits; bits += 8; hold += (uint)_in[in_ind++] << (int)bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = here.bits; hold >>= (int)op; bits -= op; op = here.op; if (op == 0) { // literal //Tracevv((stderr, @this.val >= 0x20 && @this.val < 0x7f ? // "inflate: literal '%c'\n" : // "inflate: literal 0x%02x\n", @this.val)); @out[out_ind++] = (byte)here.val; } else if ((op & 16) != 0) { // length base len = here.val; op &= 15; // number of extra bits if (op != 0) { if (bits < op) { hold += (uint)_in[in_ind++] << (int)bits; bits += 8; } len += (uint)hold & ((1U << (int)op) - 1); hold >>= (int)op; bits -= op; } //Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (uint)_in[in_ind++] << (int)bits; bits += 8; hold += (uint)_in[in_ind++] << (int)bits; bits += 8; } here = dcode[dcode_ind + (hold & dmask)]; dodist: op = here.bits; hold >>= (int)op; bits -= op; op = here.op; if ((op & 16) != 0) { // distance base dist = here.val; op &= 15; // number of extra bits if (bits < op) { hold += (uint)_in[in_ind++] << (int)bits; bits += 8; if (bits < op) { hold += (uint)_in[in_ind++] << (int)bits; bits += 8; } } dist += (uint)hold & ((1U << (int)op) - 1); if (dist > dmax) { strm.msg = "invalid distance too far back (STRICT)"; state.mode = inflate_mode.BAD; break; } hold >>= (int)op; bits -= op; //Tracevv((stderr, "inflate: distance %u\n", dist)); op = (uint)(out_ind - beg); // max distance in output if (dist > op) { // see if copy from window op = dist - op; // distance back in window if (op > whave) { if (state.sane) { strm.msg = "invalid distance too far back"; state.mode = inflate_mode.BAD; break; } #if INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { @out[out_ind++] = 0; } while(--len != 0); continue; } len -= op - whave; do { @out[out_ind++] = 0; } while(--op > whave); if (op == 0) { from = @out; from_ind = (int)(out_ind - dist); do { @out[out_ind++] = from[from_ind++]; } while(--len != 0); continue; } #endif } from = window; from_ind = 0; if (wnext == 0) { // very common case from_ind += (int)(wsize - op); if (op < len) { // some from window len -= op; do { @out[out_ind++] = from[from_ind++]; } while ((--op) != 0); from = @out; from_ind = (int)(out_ind - dist); // rest from output } } else if (wnext < op) { // wrap around window from_ind += (int)(wsize + wnext - op); op -= wnext; if (op < len) { // some from end of window len -= op; do { @out[out_ind++] = from[from_ind++]; } while ((--op) != 0); from = window; from_ind = 0; if (wnext < len) { // some from start of window op = wnext; len -= op; do { @out[out_ind++] = from[from_ind++]; } while ((--op) != 0); from = @out; from_ind = (int)(out_ind - dist); // rest from output } } } else { // contiguous in window from_ind += (int)(wnext - op); if (op < len) { // some from window len -= op; do { @out[out_ind++] = from[from_ind++]; } while ((--op) != 0); from = @out; from_ind = (int)(out_ind - dist); // rest from output } } while (len > 2) { @out[out_ind++] = from[from_ind++]; @out[out_ind++] = from[from_ind++]; @out[out_ind++] = from[from_ind++]; len -= 3; } if (len != 0) { @out[out_ind++] = from[from_ind++]; if (len > 1) { @out[out_ind++] = from[from_ind++]; } } } else { from = @out; from_ind = (int)(out_ind - dist); // copy direct from output do { // minimum length is three @out[out_ind++] = from[from_ind++]; @out[out_ind++] = from[from_ind++]; @out[out_ind++] = from[from_ind++]; len -= 3; } while (len > 2); if (len != 0) { @out[out_ind++] = from[from_ind++]; if (len > 1) { @out[out_ind++] = from[from_ind++]; } } } } else if ((op & 64) == 0) { // 2nd level distance code here = dcode[dcode_ind + here.val + (hold & ((1U << (int)op) - 1))]; goto dodist; } else { strm.msg = "invalid distance code"; state.mode = inflate_mode.BAD; break; } } else if ((op & 64) == 0) { // 2nd level length code here = lcode[here.val + (hold & ((1U << (int)op) - 1))]; goto dolen; } else if ((op & 32) != 0) { // end-of-block //Tracevv((stderr, "inflate: end of block\n")); state.mode = inflate_mode.TYPE; break; } else { strm.msg = "invalid literal/length code"; state.mode = inflate_mode.BAD; break; } } while (in_ind < last && out_ind < end); // return unused bytes (on entry, bits < 8, so in won't go too far back) len = bits >> 3; in_ind -= len; bits -= len << 3; hold &= (1U << (int)bits) - 1; // update state and return strm.next_in = in_ind; strm.next_out = out_ind; strm.avail_in = (uint)(in_ind < last ? 5 + (last - in_ind) : 5 - (in_ind - last)); strm.avail_out = (uint)(out_ind < end ? 257 + (end - out_ind) : 257 - (out_ind - end)); state.hold = hold; state.bits = bits; }
private static extern ZLibReturnCode inflateInit2(ref z_stream strm, ZLibOpenType windowBits, string version, int stream_size);
/* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* =========================================================================== * Decompresses the source buffer into the destination buffer. *sourceLen is * the byte length of the source buffer. Upon entry, *destLen is the total size * of the destination buffer, which must be large enough to hold the entire * uncompressed data. (The size of the uncompressed data must have been saved * previously by the compressor and transmitted to the decompressor by some * mechanism outside the scope of this compression library.) Upon exit, * destLen is the size of the decompressed data and *sourceLen is the number * of source bytes consumed. Upon return, source + *sourceLen points to the * first unused input byte. * * uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough * memory, Z_BUF_ERROR if there was not enough room in the output buffer, or * Z_DATA_ERROR if the input data was corrupted, including if the input data is * an incomplete zlib stream. */ public static int uncompress2(byte[] dest_array, long dest_index, ref ulong destLen, byte[] source_array, long source_index, ref ulong sourceLen) { z_stream stream = new z_stream(); int err; const uint max = uint.MaxValue; ulong len, left; byte[] buf = new byte[1]; /* for detection of incomplete stream when *destLen == 0 */ len = sourceLen; if (destLen != 0) { left = destLen; destLen = 0; } else { left = 1; dest_array = buf; dest_index = 0; } stream.input_buffer = source_array; stream.next_in = source_index; stream.avail_in = 0; //stream.zalloc = (alloc_func)0; //stream.zfree = (free_func)0; //stream.opaque = (voidpf)0; err = zlib_sharp.inflate.inflateInit_(stream, zlib.ZLIB_VERSION, z_stream._sizeof); if (err != zlib_sharp.zlib.Z_OK) { return(err); } stream.output_buffer = dest_array; stream.next_out = dest_index; stream.avail_out = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (ulong)max ? max : (uint)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = len > (ulong)max ? max : (uint)len; len -= stream.avail_in; } err = zlib_sharp.inflate.inflate_(stream, zlib_sharp.zlib.Z_NO_FLUSH); } while (err == zlib_sharp.zlib.Z_OK); sourceLen -= len + stream.avail_in; if (dest_array != buf) { destLen = stream.total_out; } else if (stream.total_out != 0 && err == zlib_sharp.zlib.Z_BUF_ERROR) { left = 1; } zlib_sharp.inflate.inflateEnd(stream); return(err == zlib_sharp.zlib.Z_STREAM_END ? zlib_sharp.zlib.Z_OK : err == zlib_sharp.zlib.Z_NEED_DICT ? zlib_sharp.zlib.Z_DATA_ERROR : err == zlib_sharp.zlib.Z_BUF_ERROR && (left + stream.avail_out) != 0 ? zlib_sharp.zlib.Z_DATA_ERROR : err); }
private static extern ZLibReturnCode inflateEnd(ref z_stream strm);
// 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. static int updatewindow(z_stream strm, uint _out) { inflate_state state; uint copy, dist; state=(inflate_state)strm.state; // if it hasn't been done already, allocate space for the window if(state.window==null) { try { state.window=new byte[1<<(int)state.wbits]; } catch(Exception) { return 1; } } // if window not in use yet, initialize if(state.wsize==0) { state.wsize=1U<<(int)state.wbits; state.wnext=0; state.whave=0; } // copy state.wsize or less output bytes into the circular window copy=_out-strm.avail_out; if(copy>=state.wsize) { //memcpy(state.window, strm.next_out-state.wsize, state.wsize); Array.Copy(strm.out_buf, strm.next_out-state.wsize, state.window, 0, state.wsize); state.wnext=0; state.whave=state.wsize; } else { dist=state.wsize-state.wnext; if(dist>copy) dist=copy; //memcpy(state.window+state.write, strm.next_out-copy, dist); Array.Copy(strm.out_buf, strm.next_out-copy, state.window, state.wnext, dist); copy-=dist; if(copy!=0) { //memcpy(state.window, strm.next_out-copy, copy); Array.Copy(strm.out_buf, strm.next_out-copy, state.window, 0, copy); state.wnext=copy; state.whave=state.wsize; } else { state.wnext+=dist; if(state.wnext==state.wsize) state.wnext=0; if(state.whave<state.wsize) state.whave+=dist; } } return 0; }
// ========================================================================= // Fine tune deflate's internal compression parameters. This should only be // used by someone who understands the algorithm used by zlib's deflate for // searching for the best matching string, and even then only by the most // fanatic optimizer trying to squeeze out the last compressed bit for their // specific input data. Read the deflate.cs source code for the meaning of the // max_lazy, good_length, nice_length, and max_chain parameters. // deflateTune() can be called after deflateInit() or deflateInit2(), and // returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. public static int deflateTune(z_stream strm, uint good_length, uint max_lazy, int nice_length, uint max_chain) { if(strm==null||strm.state==null) return Z_STREAM_ERROR; deflate_state s=(deflate_state)strm.state; s.good_match=good_length; s.max_lazy_match=max_lazy; s.nice_match=nice_length; s.max_chain_length=max_chain; return Z_OK; }
public static int inflate_(z_stream strm, int flush) { return(new inflate().run(strm, flush)); }
/* inffast.c -- fast decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Decode literal, length, and distance codes and write out the resulting * literal and match bytes until either not enough input or output is * available, an end-of-block is encountered, or a data error is encountered. * When large enough input and output buffers are supplied to inflate(), for * example, a 16K input buffer and a 64K output buffer, more than 95% of the * inflate execution time is spent in this routine. * * Entry assumptions: * * state->mode == LEN * strm->avail_in >= 6 * strm->avail_out >= 258 * start >= strm->avail_out * state->bits < 8 * * On return, state->mode is one of: * * LEN -- ran out of enough output space or enough available input * TYPE -- reached end of block code, inflate() to interpret next block * BAD -- error in block data * * Notes: * * - The maximum input bits used by a length/distance pair is 15 bits for the * length code, 5 bits for the length extra, 15 bits for the distance code, * and 13 bits for the distance extra. This totals 48 bits, or six bytes. * Therefore if strm->avail_in >= 6, then there is enough input to avoid * checking for available input while decoding. * * - The maximum bytes that a single length/distance pair can output is 258 * bytes, which is the maximum length that can be coded. inflate_fast() * requires strm->avail_out >= 258 for each loop to avoid checking for * output space. */ public static void inflate_fast( z_stream strm, uint start) /* inflate()'s starting value for strm->avail_out */ { inflate_state state; byte[] in_array; long in_index; /* local strm->next_in */ long last; /* have enough input while in < last */ byte [] out_array; /* local strm->next_out */ long out_index; long beg; /* inflate()'s initial strm->next_out */ long end; /* while out < end, enough space available */ //#ifdef INFLATE_STRICT // unsigned dmax; /* maximum distance from zlib header */ //#endif uint wsize; /* window size or zero if not using window */ uint whave; /* valid bytes in the window */ uint wnext; /* window write index */ byte[] window; /* allocated sliding window, if wsize != 0 */ ulong hold; /* local strm->hold */ uint bits; /* local strm->bits */ code[] lcode_array; /* local strm->lencode */ long lcode_index; code[] dcode_array; /* local strm->distcode */ long dcode_index; uint lmask; /* mask for first level of length codes */ uint dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ uint op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ uint len; /* match length, unused bytes */ uint dist; /* match distance */ byte[] from_array; /* where to copy match from */ long from_index; /* copy state to local variables */ state = strm.state; in_array = strm.input_buffer; in_index = strm.next_in; last = in_index + (strm.avail_in - 5); out_array = strm.output_buffer; out_index = strm.next_out; beg = out_index - (start - strm.avail_out); end = out_index + (strm.avail_out - 257); //#ifdef INFLATE_STRICT // dmax = state->dmax; //#endif wsize = state.wsize; whave = state.whave; wnext = state.wnext; window = state.window; hold = state.hold; bits = state.bits; lcode_array = state.lencode_array; lcode_index = state.lencode_index; dcode_array = state.distcode_array; dcode_index = state.distcode_index; lmask = (1U << (int)state.lenbits) - 1; dmask = (1U << (int)state.distbits) - 1; /* decode literals and length/distances until end-of-block or not enough * input data or output space */ do { if (bits < 15) { hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; } here = lcode_array[lcode_index + (long)(hold & lmask)]; dolen: op = (uint)(here.bits); hold >>= (int)op; bits -= op; op = (uint)(here.op); if (op == 0) /* literal */ //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? // "inflate: literal '%c'\n" : // "inflate: literal 0x%02x\n", here.val)); { out_array[out_index++] = (byte)(here.val); } else if ((op & 16) != 0) /* length base */ { len = (uint)(here.val); op &= 15; /* number of extra bits */ if (op != 0) { if (bits < op) { hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; } len += (uint)hold & ((1U << (int)op) - 1); hold >>= (int)op; bits -= op; } //Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; } here = dcode_array[dcode_index + (long)(hold & dmask)]; dodist: op = (uint)(here.bits); hold >>= (int)op; bits -= op; op = (uint)(here.op); if ((op & 16) != 0) /* distance base */ { dist = (uint)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; if (bits < op) { hold += (ulong)(in_array[in_index++]) << (int)bits; bits += 8; } } dist += (uint)hold & ((1U << (int)op) - 1); //#ifdef INFLATE_STRICT // if (dist > dmax) { // strm->msg = (char *)"invalid distance too far back"; // state->mode = BAD; // break; // } //#endif hold >>= (int)op; bits -= op; //Tracevv((stderr, "inflate: distance %u\n", dist)); op = (uint)(out_index - beg); /* max distance in output */ if (dist > op) /* see if copy from window */ { op = dist - op; /* distance back in window */ if (op > whave) { if (state.sane != 0) { strm.msg = "invalid distance too far back"; state.mode = inflate_mode.BAD; break; } //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR // if (len <= op - whave) { // do { // *out++ = 0; // } while (--len); // continue; // } // len -= op - whave; // do { // *out++ = 0; // } while (--op > whave); // if (op == 0) { // from = out - dist; // do { // *out++ = *from++; // } while (--len); // continue; // } //#endif } from_array = window; from_index = 0; if (wnext == 0) /* very common case */ { from_index += wsize - op; if (op < len) /* some from window */ { len -= op; do { out_array[out_index++] = from_array[from_index++]; } while (--op != 0); from_array = out_array; from_index = out_index - dist; /* rest from output */ } } else if (wnext < op) /* wrap around window */ { from_index += wsize + wnext - op; op -= wnext; if (op < len) /* some from end of window */ { len -= op; do { out_array[out_index++] = from_array[from_index++]; } while (--op != 0); from_array = window; from_index = 0; if (wnext < len) /* some from start of window */ { op = wnext; len -= op; do { out_array[out_index++] = from_array[from_index++]; } while (--op != 0); from_array = out_array; from_index = out_index - dist; /* rest from output */ } } } else /* contiguous in window */ { from_index += wnext - op; if (op < len) /* some from window */ { len -= op; do { out_array[out_index++] = from_array[from_index++]; } while (--op != 0); from_array = out_array; from_index = out_index - dist; /* rest from output */ } } while (len > 2) { out_array[out_index++] = from_array[from_index++]; out_array[out_index++] = from_array[from_index++]; out_array[out_index++] = from_array[from_index++]; len -= 3; } if (len != 0) { out_array[out_index++] = from_array[from_index++]; if (len > 1) { out_array[out_index++] = from_array[from_index++]; } } } else { from_array = out_array; from_index = out_index - dist; /* copy direct from output */ do /* minimum length is three */ { out_array[out_index++] = from_array[from_index++]; out_array[out_index++] = from_array[from_index++]; out_array[out_index++] = from_array[from_index++]; len -= 3; } while (len > 2); if (len != 0) { out_array[out_index++] = from_array[from_index++]; if (len > 1) { out_array[out_index++] = from_array[from_index++]; } } } } else if ((op & 64) == 0) /* 2nd level distance code */ { here = dcode_array[dcode_index + here.val + (long)(hold & ((1U << (int)op) - 1))]; goto dodist; } else { strm.msg = "invalid distance code"; state.mode = inflate_mode.BAD; break; } } else if ((op & 64) == 0) /* 2nd level length code */ { here = lcode_array[lcode_index + here.val + (long)(hold & ((1U << (int)op) - 1))]; goto dolen; } else if ((op & 32) != 0) /* end-of-block */ //Tracevv((stderr, "inflate: end of block\n")); { state.mode = inflate_mode.TYPE; break; } else { strm.msg = "invalid literal/length code"; state.mode = inflate_mode.BAD; break; } } while (in_index < last && out_index < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in_index -= len; bits -= len << 3; hold &= (1U << (int)bits) - 1; /* update state and return */ strm.next_in = in_index; strm.next_out = out_index; strm.avail_in = (uint)(in_index < last ? 5 + (last - in_index) : 5 - (in_index - last)); strm.avail_out = (uint)(out_index < end ? 257 + (end - out_index) : 257 - (out_index - end)); state.hold = hold; state.bits = bits; return; }
// ========================================================================= // For the default windowBits of 15 and memLevel of 8, this function returns // a close to exact, as well as small, upper bound on the compressed size. // They are coded as constants here for a reason--if the #define's are // changed, then this function needs to be changed as well. The return // value for 15 and 8 only works for those exact settings. // // For any setting other than those defaults for windowBits and memLevel, // the value returned is a conservative worst case for the maximum expansion // resulting from using fixed blocks instead of stored blocks, which deflate // can emit on compressed data for some combinations of the parameters. // // This function could be more sophisticated to provide closer upper bounds for // every combination of windowBits and memLevel. But even the conservative // upper bound of about 14% expansion does not seem onerous for output buffer // allocation. // deflateBound() returns an upper bound on the compressed size after // deflation of sourceLen bytes. It must be called after deflateInit() // or deflateInit2(). This would be used to allocate an output buffer // for deflation in a single pass, and so would be called before deflate(). public static uint deflateBound(z_stream strm, uint sourceLen) { // conservative upper bound for compressed data uint complen=sourceLen+((sourceLen+7)>>3)+((sourceLen+63)>>6)+5; // if can't get parameters, return conservative bound plus zlib wrapper if(strm==null||strm.state==null) return complen+6; // compute wrapper length deflate_state s=(deflate_state)strm.state; uint wraplen; byte[] str; switch(s.wrap) { case 0: // raw deflate wraplen=0; break; case 1: // zlib wrapper wraplen=(uint)(6+(s.strstart!=0?4:0)); break; case 2: // gzip wrapper wraplen=18; if(s.gzhead!=null) // user-supplied gzip header { if(s.gzhead.extra!=null) wraplen+=2+s.gzhead.extra_len; str=s.gzhead.name; int str_ind=0; if(str!=null) { do { wraplen++; } while(str[str_ind++]!=0); } str=s.gzhead.comment; if(str!=null) { do { wraplen++; } while(str[str_ind++]!=0); } if(s.gzhead.hcrc!=0) wraplen+=2; } break; default: wraplen=6; break; // for compiler happiness } // if not default parameters, return conservative bound if(s.w_bits!=15||s.hash_bits!=8+7) return complen+wraplen; // default settings: return tight bound for that case return sourceLen+(sourceLen>>12)+(sourceLen>>14)+(sourceLen>>25)+13-6+wraplen; }