// deflate.cs -- internal compression state & compress data using the deflation algorithm // Copyright (C) 1995-2010 Jean-loup Gailly. // Copyright (C) 2007-2011 by the Authors // For conditions of distribution and use, see copyright notice in License.txt #region ALGORITHM , ACKNOWLEDGEMENTS & REFERENCES // ALGORITHM // // The "deflation" process depends on being able to identify portions // of the input text which are identical to earlier input (within a // sliding window trailing behind the input currently being processed). // // The most straightforward technique turns out to be the fastest for // most input files: try all possible matches and select the longest. // The key feature of this algorithm is that insertions into the string // dictionary are very simple and thus fast, and deletions are avoided // completely. Insertions are performed at each input character, whereas // string matches are performed only when the previous match ends. So it // is preferable to spend more time in matches to allow very fast string // insertions and avoid deletions. The matching algorithm for small // strings is inspired from that of Rabin & Karp. A brute force approach // is used to find longer strings when a small match has been found. // A similar algorithm is used in comic (by Jan-Mark Wams) and freeze // (by Leonid Broukhis). // A previous version of this file used a more sophisticated algorithm // (by Fiala and Greene) which is guaranteed to run in linear amortized // time, but has a larger average cost, uses more memory and is patented. // However the F&G algorithm may be faster for some highly redundant // files if the parameter max_chain_length (described below) is too large. // // ACKNOWLEDGEMENTS // // The idea of lazy evaluation of matches is due to Jan-Mark Wams, and // I found it in 'freeze' written by Leonid Broukhis. // Thanks to many people for bug reports and testing. // // REFERENCES // // Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". // Available in http://www.ietf.org/rfc/rfc1951.txt // // A description of the Rabin and Karp algorithm is given in the book // "Algorithms" by R. Sedgewick, Addison-Wesley, p252. // // Fiala,E.R., and Greene,D.H. // Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 #endregion using System; namespace Framework.IO { public static partial class ZLib { #region deflate.h // =========================================================================== // Internal compression state. // number of length codes, not counting the special END_BLOCK code private const int LENGTH_CODES=29; // number of literal bytes 0..255 private const int LITERALS=256; // number of Literal or Length codes, including the END_BLOCK code private const int L_CODES=LITERALS+1+LENGTH_CODES; // number of distance codes private const int D_CODES=30; // number of codes used to transfer the bit lengths private const int BL_CODES=19; // maximum heap size private const int HEAP_SIZE=2*L_CODES+1; // All codes must not exceed MAX_BITS bits private const int MAX_BITS=15; // Stream status private const int INIT_STATE=42; private const int EXTRA_STATE=69; private const int NAME_STATE=73; private const int COMMENT_STATE=91; private const int HCRC_STATE=103; private const int BUSY_STATE=113; private const int FINISH_STATE=666; // Data structure describing a single value and its code string. struct ct_data { ushort freq; public ushort Freq { get { return freq; } set { freq=value; } } // frequency count public ushort Code { get { return freq; } set { freq=value; } } // bit string ushort dad; public ushort Dad { get { return dad; } set { dad=value; } } // father node in Huffman tree public ushort Len { get { return dad; } set { dad=value; } } // length of bit string public ct_data(ushort freq, ushort dad) { this.freq=freq; this.dad=dad; } public ct_data(ct_data data) { freq=data.freq; dad=data.dad; } } struct tree_desc { public ct_data[] dyn_tree; // the dynamic tree public int max_code; // largest code with non zero frequency public static_tree_desc stat_desc; // the corresponding static tree public tree_desc(tree_desc desc) { dyn_tree=desc.dyn_tree; max_code=desc.max_code; stat_desc=desc.stat_desc; } } class deflate_state //internal_state { public z_stream strm; // pointer back to this zlib stream public int status; // as the name implies public byte[] pending_buf; // output still pending public uint pending_buf_size; // size of pending_buf public int pending_out; // next pending byte to output to the stream public uint pending; // nb of bytes in the pending buffer public int wrap; // bit 0 true for zlib, bit 1 true for gzip public gz_header gzhead; // gzip header information to write public uint gzindex; // where in extra, name, or comment public byte method; // STORED (for zip only) or DEFLATED public int last_flush; // value of flush param for previous deflate call // used by deflate.c: public uint w_size; // LZ77 window size (32K by default) public uint w_bits; // log2(w_size) (8..16) public uint w_mask; // w_size - 1 // Sliding window. Input bytes are read into the second half of the window, // and move to the first half later to keep a dictionary of at least wSize // bytes. With this organization, matches are limited to a distance of // wSize-MAX_MATCH bytes, but this ensures that IO is always // performed with a length multiple of the block size. Also, it limits // the window size to 64K, which is quite useful on MSDOS. // To do: use the user input buffer as sliding window. public byte[] window; // Actual size of window: 2*wSize, except when the user input buffer // is directly used as sliding window. public uint window_size; // Link to older string with same hash index. To limit the size of this // array to 64K, this link is maintained only for the last 32K strings. // An index in this array is thus a window index modulo 32K. public ushort[] prev; public ushort[] head; // Heads of the hash chains or NIL. public uint ins_h; // hash index of string to be inserted public uint hash_size; // number of elements in hash table public uint hash_bits; // log2(hash_size) public uint hash_mask; // hash_size-1 // Number of bits by which ins_h must be shifted at each input // step. It must be such that after MIN_MATCH steps, the oldest // byte no longer takes part in the hash key, that is: // hash_shift * MIN_MATCH >= hash_bits public uint hash_shift; // Window position at the beginning of the current output block. Gets // negative when the window is moved backwards. public int block_start; public uint match_length; // length of best match public uint prev_match; // previous match public int match_available; // set if previous match exists public uint strstart; // start of string to insert public uint match_start; // start of matching string public uint lookahead; // number of valid bytes ahead in window // Length of the best match at previous step. Matches not greater than this // are discarded. This is used in the lazy match evaluation. public uint prev_length; // To speed up deflation, hash chains are never searched beyond this // length. A higher limit improves compression ratio but degrades the speed. public uint max_chain_length; // Attempt to find a better match only when the current match is strictly // smaller than this value. This mechanism is used only for compression // levels >= 4. public uint max_lazy_match; // Insert new strings in the hash table only if the match length is not // greater than this length. This saves time but degrades compression. // max_insert_length is used only for compression levels <= 3. //#define max_insert_length max_lazy_match public int level; // compression level (1..9) public int strategy; // favor or force Huffman coding public uint good_match; // Use a faster search when the previous match is longer than this public int nice_match; // Stop searching when current match exceeds this // used by trees.c: public ct_data[] dyn_ltree=new ct_data[HEAP_SIZE]; // literal and length tree public ct_data[] dyn_dtree=new ct_data[2*D_CODES+1]; // distance tree public ct_data[] bl_tree=new ct_data[2*BL_CODES+1]; // Huffman tree for bit lengths public tree_desc l_desc=new(); // desc. for literal tree public tree_desc d_desc=new(); // desc. for distance tree public tree_desc bl_desc=new(); // desc. for bit length tree // number of codes at each bit length for an optimal tree public ushort[] bl_count=new ushort[MAX_BITS+1]; // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. // The same heap array is used to build all trees. public int[] heap=new int[2*L_CODES+1]; // heap used to build the Huffman trees public int heap_len; // number of elements in the heap public int heap_max; // element of largest frequency // Depth of each subtree used as tie breaker for trees of equal frequency public byte[] depth=new byte[2*L_CODES+1]; public byte[] l_buf; // buffer for literals or lengths // Size of match buffer for literals/lengths. There are 4 reasons for // limiting lit_bufsize to 64K: // - frequencies can be kept in 16 bit counters // - if compression is not successful for the first block, all input // data is still in the window so we can still emit a stored block even // when input comes from standard input. (This can also be done for // all blocks if lit_bufsize is not greater than 32K.) // - if compression is not successful for a file smaller than 64K, we can // even emit a stored file instead of a stored block (saving 5 bytes). // This is applicable only for zip (not zlib). // - creating new Huffman trees less frequently may not provide fast // adaptation to changes in the input data statistics. (Take for // example a binary file with poorly compressible code followed by // a highly compressible string table.) Smaller buffer sizes give // fast adaptation but have of course the overhead of transmitting // trees more frequently. // - I can't count above 4 public uint lit_bufsize; public uint last_lit; // running index in l_buf // Buffer for distances. To simplify the code, d_buf and l_buf have // the same number of elements. To use different lengths, an extra flag // array would be necessary. public ushort[] d_buf; public uint opt_len; // bit length of current block with optimal trees public uint static_len; // bit length of current block with static trees public uint matches; // number of string matches in current block public int last_eob_len; // bit length of EOB code for last block // Output buffer. bits are inserted starting at the bottom (least // significant bits). public ushort bi_buf; // Number of valid bits in bi_buf. All bits above the last valid bit // are always zero. public int bi_valid; // High water mark offset in window for initialized bytes -- bytes above // this are set to zero in order to avoid memory check warnings when // longest match routines access bytes past the input. This is then // updated to the new high water mark. public uint high_water; public deflate_state Clone() { deflate_state ret=(deflate_state)MemberwiseClone(); ret.dyn_ltree=new ct_data[HEAP_SIZE]; for(int i=0; i>7)]) #endregion // If you use the zlib library in a product, an acknowledgment is welcome // in the documentation of your product. If for some reason you cannot // include such an acknowledgment, I would appreciate that you keep this // copyright string in the executable of your product. private const string deflate_copyright=" deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly "; // =========================================================================== // Function prototypes. enum block_state { need_more, // block not completed, need more input or more output block_done, // block flush performed finish_started, // finish started, need only more output at next deflate finish_done // finish done, accept no more input or output } // Compression function. Returns the block state after the call. delegate block_state compress_func(deflate_state s, int flush); // =========================================================================== // Local data // Tail of hash chains private const int NIL=0; // Matches of length 3 are discarded if their distance exceeds TOO_FAR private const int TOO_FAR=4096; // Values for max_lazy_match, good_match and max_chain_length, depending on // the desired pack level (0..9). The values given below have been tuned to // exclude worst case performance for pathological files. Better values may be // found for specific files. struct config { public ushort good_length; // reduce lazy search above this match length public ushort max_lazy; // do not perform lazy search above this match length public ushort nice_length; // quit search above this match length public ushort max_chain; public compress_func func; public config(ushort good_length, ushort max_lazy, ushort nice_length, ushort max_chain, compress_func func) { this.good_length=good_length; this.max_lazy=max_lazy; this.nice_length=nice_length; this.max_chain=max_chain; this.func=func; } } static readonly config[] configuration_table=new config[] { // good lazy nice chain new config( 0, 0, 0, 0, deflate_stored), // store only new config( 4, 4, 8, 4, deflate_fast), // max speed, no lazy matches new config( 4, 5, 16, 8, deflate_fast), new config( 4, 6, 32, 32, deflate_fast), new config( 4, 4, 16, 16, deflate_slow), // lazy matches new config( 8, 16, 32, 32, deflate_slow), new config( 8, 16, 128, 128, deflate_slow), new config( 8, 32, 128, 256, deflate_slow), new config(32, 128, 258, 1024, deflate_slow), new config(32, 258, 258, 4096, deflate_slow) // max compression }; // 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<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); } // ========================================================================= // 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; if (strm.state is not deflate_state s || 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(lengths.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; } // ========================================================================= // 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; } // ========================================================================= // 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; } // ========================================================================= // 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<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; } // ========================================================================= // 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; } // ========================================================================= // 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; } // ========================================================================= // Put a short in the pending buffer. The 16-bit value is put in MSB order. // IN assertion: the stream state is correct and there is enough room in // pending_buf. static void putShortMSB(deflate_state s, uint b) { //was put_byte(s, (byte)(b >> 8)); s.pending_buf[s.pending++]=(byte)(b >> 8); //was put_byte(s, (byte)(b & 0xff)); s.pending_buf[s.pending++]=(byte)(b & 0xff); } // ========================================================================= // 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; } 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) { 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 int old_flush = s.last_flush;// value of flush param for previous deflate call 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; i0, "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; } #endregion // ========================================================================= // 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; } // ========================================================================= // 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; } // =========================================================================== // 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); } 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; } // =========================================================================== // Initialize the "longest match" routines for a new zlib stream static void lm_init(deflate_state s) { s.window_size=(uint)2*s.w_size; s.head[s.hash_size-1]=NIL; //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; // Set the default configuration parameters: s.max_lazy_match=configuration_table[s.level].max_lazy; s.good_match=configuration_table[s.level].good_length; s.nice_match=configuration_table[s.level].nice_length; s.max_chain_length=configuration_table[s.level].max_chain; s.strstart=0; s.block_start=0; s.lookahead=0; s.match_length=s.prev_length=MIN_MATCH-1; s.match_available=0; s.ins_h=0; } // =========================================================================== // Set match_start to the longest match starting at the given string and // return its length. Matches shorter or equal to prev_length are discarded, // in which case the result is equal to prev_length and match_start is // garbage. // IN assertions: cur_match is the head of the hash chain for the current // string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 // OUT assertion: the match length is not greater than s.lookahead. static uint longest_match(deflate_state s, uint cur_match) { uint chain_length=s.max_chain_length; // max hash chain length byte[] scan=s.window; // current string int scan_ind=(int)s.strstart; int len; // length of current match int best_len=(int)s.prev_length; // best match length so far int nice_match=s.nice_match; // stop if match long enough uint limit=s.strstart>(uint)(s.w_size-MIN_LOOKAHEAD)?s.strstart-(uint)(s.w_size-MIN_LOOKAHEAD):NIL; // Stop when cur_match becomes <= limit. To simplify the code, // we prevent matches with the string of window index 0. ushort[] prev=s.prev; uint wmask=s.w_mask; int strend_ind=(int)s.strstart+MAX_MATCH; byte scan_end1=scan[scan_ind+best_len-1]; byte scan_end=scan[scan_ind+best_len]; // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. // It is easy to get rid of this optimization if necessary. //Assert(s.hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); // Do not waste too much time if we already have a good match: if(s.prev_length>=s.good_match) chain_length>>=2; // Do not look for matches beyond the end of the input. This is necessary // to make deflate deterministic. if((uint)nice_match>s.lookahead) nice_match=(int)s.lookahead; //Assert((uint)s.strstart <= s.window_size-MIN_LOOKAHEAD, "need lookahead"); byte[] match=s.window; do { //Assert(cur_match= 8. scan_ind+=2; match_ind++; //Assert(scan[scan_ind]==match[match_ind], "match[2]?"); // We check for insufficient lookahead only every 8th comparison; // the 256th check will be made at strstart+258. do { } while(scan[++scan_ind]==match[++match_ind]&&scan[++scan_ind]==match[++match_ind]&& scan[++scan_ind]==match[++match_ind]&&scan[++scan_ind]==match[++match_ind]&& scan[++scan_ind]==match[++match_ind]&&scan[++scan_ind]==match[++match_ind]&& scan[++scan_ind]==match[++match_ind]&&scan[++scan_ind]==match[++match_ind]&& scan_indbest_len) { s.match_start=cur_match; best_len=len; if(len>=nice_match) break; scan_end1=scan[scan_ind+best_len-1]; scan_end=scan[scan_ind+best_len]; } } while((cur_match=prev[cur_match&wmask])>limit&&--chain_length!=0); if((uint)best_len<=s.lookahead) return (uint)best_len; return s.lookahead; } // --------------------------------------------------------------------------- // Optimized version for FASTEST only static uint longest_match_fast(deflate_state s, uint cur_match) { byte[] scan = s.window; int scan_ind = (int) s.strstart; // current string int strend_ind = (int) s.strstart + MAX_MATCH; // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. // It is easy to get rid of this optimization if necessary. //Assert(s.hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); //Assert((uint)s.strstart <= s.window_size-MIN_LOOKAHEAD, "need lookahead"); //Assert(cur_match < s.strstart, "no future"); byte[] match = s.window; int match_ind = (int) cur_match; // Return failure if the match length is less than 2: if (match[match_ind] != scan[scan_ind] || match[match_ind + 1] != scan[scan_ind + 1]) return MIN_MATCH - 1; // The check at best_len-1 can be removed because it will be made // again later. (This heuristic is not always a win.) // It is not necessary to compare scan[2] and match[2] since they // are always equal when the other bytes match, given that // the hash keys are equal and that HASH_BITS >= 8. scan_ind += 2; match_ind += 2; //Assert(scan[scan_ind] == match[match_ind], "match[2]?"); // We check for insufficient lookahead only every 8th comparison; // the 256th check will be made at strstart+258. do { } while (scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan[++scan_ind] == match[++match_ind] && scan_ind < strend_ind); //Assert(scan_ind <= (uint)(s.window_size-1), "wild scan"); int len = MAX_MATCH - (int) (strend_ind - scan_ind);// length of current match if (len < MIN_MATCH) return MIN_MATCH - 1; s.match_start = cur_match; return (uint) len <= s.lookahead ? (uint) len : s.lookahead; } // =========================================================================== // Fill the window when the lookahead becomes insufficient. // Updates strstart and lookahead. // // IN assertion: lookahead < MIN_LOOKAHEAD // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD // At least one byte has been read, or avail_in == 0; reads are // performed for at least two bytes (required for the zip translate_eol // option -- not supported here). static void fill_window(deflate_state s) { uint n, m; uint more; // Amount of free space at the end of the window. uint wsize=s.w_size; do { more=(uint)(s.window_size-(uint)s.lookahead-(uint)s.strstart); // If the window is almost full and there is insufficient lookahead, // move the upper half to the lower one to make room in the upper half. if(s.strstart>=wsize+s.w_size-MIN_LOOKAHEAD) { //was memcpy(s.window, s.window+wsize, (uint)wsize); Array.Copy(s.window, wsize, s.window, 0, wsize); s.match_start-=wsize; s.strstart-=wsize; // we now have strstart >= MAX_DIST s.block_start-=(int)wsize; // Slide the hash table (could be avoided with 32 bit values // at the expense of memory usage). We slide even when level == 0 // to keep the hash table consistent if we switch back to level > 0 // later. (Using level 0 permanently is not an optimal usage of // zlib, so we don't care about this pathological case.) n=s.hash_size; uint p=n; do { m=s.head[--p]; s.head[p]=(ushort)(m>=wsize?m-wsize:NIL); } while((--n)!=0); n=wsize; p=n; do { m=s.prev[--p]; s.prev[p]=(ushort)(m>=wsize?m-wsize:NIL); // If n is not on any hash chain, prev[n] is garbage but // its value will never be used. } while((--n)!=0); more+=wsize; } if(s.strm.avail_in==0) return; // If there was no sliding: // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && // more == window_size - lookahead - strstart // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) // => more >= window_size - 2*WSIZE + 2 // In the BIG_MEM or MMAP case (not yet supported), // window_size == input_size + MIN_LOOKAHEAD && // strstart + s.lookahead <= input_size => more >= MIN_LOOKAHEAD. // Otherwise, window_size == 2*WSIZE so more >= 2. // If there was sliding, more >= WSIZE. So in all cases, more >= 2. //Assert(more>=2, "more < 2"); n=(uint)read_buf(s.strm, s.window, (int)(s.strstart+s.lookahead), more); s.lookahead+=n; // Initialize the hash value now that we have some input: if(s.lookahead>=MIN_MATCH) { s.ins_h=s.window[s.strstart]; //was UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+1])&s.hash_mask; } // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, // but this is not important since only literal bytes will be emitted. } while(s.lookaheadWIN_INIT) init=WIN_INIT; for(int i=0; is.window_size-s.high_water) init=s.window_size-s.high_water; for(int i=0; i= 0 ? s.window : null, s.block_start >= 0?s.block_start:0, \ // (uint)((int)s.strstart - s.block_start), (last)); \ // s.block_start = s.strstart; \ // flush_pending(s.strm); \ // Tracev((stderr,"[FLUSH]")); \ //} // Same but force premature exit if necessary. //#define FLUSH_BLOCK(s, last) \ //{ \ // _tr_flush_block(s, s.block_start >= 0 ? s.window : null, s.block_start >= 0?s.block_start:0, \ // (uint)((int)s.strstart - s.block_start), (last)); \ // s.block_start = s.strstart; \ // flush_pending(s.strm); \ // Tracev((stderr,"[FLUSH]")); \ // if (s.strm.avail_out == 0) return (last) ? finish_started : need_more; \ //} // =========================================================================== // Copy without compression as much as possible from the input stream, return // the current block state. // This function does not insert new strings in the dictionary since // uncompressible data is probably not useful. This function is used // only for the level=0 compression option. // NOTE: this function should be optimized to avoid extra copying from // window to pending_buf. static block_state deflate_stored(deflate_state s, int flush) { // Stored blocks are limited to 0xffff bytes, pending_buf is limited // to pending_buf_size, and each stored block has a 5 byte header: uint max_block_size=0xffff; uint max_start; if(max_block_size>s.pending_buf_size-5) max_block_size=s.pending_buf_size-5; // Copy as much as possible from input to output: for(; ; ) { // Fill the window as much as possible: if(s.lookahead<=1) { //Assert(s.strstart=(int)s.w_size, "slide too late"); fill_window(s); if(s.lookahead==0&&flush==Z_NO_FLUSH) return block_state.need_more; if(s.lookahead==0) break; // flush the current block } //Assert(s.block_start>=0, "block gone"); s.strstart+=s.lookahead; s.lookahead=0; // Emit a stored block if pending_buf will be full: max_start=(uint)s.block_start+max_block_size; if(s.strstart==0||(uint)s.strstart>=max_start) { // strstart == 0 is possible when wraparound on 16-bit machine s.lookahead=(uint)(s.strstart-max_start); s.strstart=(uint)max_start; //was FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return block_state.need_more; } // Flush if we may have to slide, otherwise block_start may become // negative and the data will be gone: if(s.strstart-(uint)s.block_start>=(s.w_size-MIN_LOOKAHEAD)) { //was FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start >= 0 ? s.window : null, s.block_start >= 0?s.block_start:0, (uint)((int)s.strstart - s.block_start), 0); s.block_start = (int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if (s.strm.avail_out == 0) return block_state.need_more; } } //was FLUSH_BLOCK(s, flush==Z_FINISH); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), flush==Z_FINISH?1:0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return flush==Z_FINISH?block_state.finish_started:block_state.need_more; return flush==Z_FINISH?block_state.finish_done:block_state.block_done; } // =========================================================================== // Compress as much as possible from the input stream, return the current // block state. // This function does not perform lazy evaluation of matches and inserts // new strings in the dictionary only for unmatched strings or for short // matches. It is used only for the fast compression options. static block_state deflate_fast(deflate_state s, int flush) { uint hash_head=NIL; // head of the hash chain int bflush; // set if current block must be flushed for(; ; ) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if(s.lookahead=MIN_MATCH) { //was INSERT_STRING(s, s.strstart, hash_head); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+(MIN_MATCH-1)])&s.hash_mask; hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h]; s.head[s.ins_h]=(ushort)s.strstart; } // Find the longest match, discarding those <= prev_length. // At this point we have always match_length < MIN_MATCH if(hash_head!=NIL&&s.strstart-hash_head<=(s.w_size-MIN_LOOKAHEAD)) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match // of the string with itself at the start of the input file). s.match_length=longest_match_fast(s, hash_head); // longest_match_fast() sets match_start } if(s.match_length>=MIN_MATCH) { //was _tr_tally_dist(s, s.strstart - s.match_start, s.match_length - MIN_MATCH, bflush); { byte len=(byte)(s.match_length-MIN_MATCH); ushort dist=(ushort)(s.strstart-s.match_start); s.d_buf[s.last_lit]=dist; s.l_buf[s.last_lit++]=len; dist--; s.dyn_ltree[_length_code[len]+LITERALS+1].Freq++; s.dyn_dtree[(dist<256?_dist_code[dist]:_dist_code[256+(dist>>7)])].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?1:0; } s.lookahead-=s.match_length; // Insert new strings in the hash table only if the match length // is not too large. This saves time but degrades compression. if(s.match_length<=s.max_lazy_match&&s.lookahead>=MIN_MATCH) // max_lazy_match was max_insert_length as #define { s.match_length--; // string at strstart already in table do { s.strstart++; //was INSERT_STRING(s, s.strstart, hash_head); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+(MIN_MATCH-1)])&s.hash_mask; hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h]; s.head[s.ins_h]=(ushort)s.strstart; // strstart never exceeds WSIZE-MAX_MATCH, so there are // always MIN_MATCH bytes ahead. } while(--s.match_length!=0); s.strstart++; } else { s.strstart+=s.match_length; s.match_length=0; s.ins_h=s.window[s.strstart]; //was UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+1])&s.hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does not // matter since it will be recomputed at next deflate call. } } else { // No match, output a literal byte //Tracevv((stderr,"%c", s.window[s.strstart])); //was _tr_tally_lit (s, s.window[s.strstart], bflush); { byte cc=s.window[s.strstart]; s.d_buf[s.last_lit]=0; s.l_buf[s.last_lit++]=cc; s.dyn_ltree[cc].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?1:0; } s.lookahead--; s.strstart++; } if(bflush!=0) { //was FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return block_state.need_more; } } //was FLUSH_BLOCK(s, flush==Z_FINISH); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), flush==Z_FINISH?1:0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return flush==Z_FINISH?block_state.finish_started:block_state.need_more; return flush==Z_FINISH?block_state.finish_done:block_state.block_done; } // =========================================================================== // Same as above, but achieves better compression. We use a lazy // evaluation for matches: a match is finally adopted only if there is // no better match at the next window position. static block_state deflate_slow(deflate_state s, int flush) { uint hash_head=NIL; // head of hash chain int bflush; // set if current block must be flushed // Process the input block. for(; ; ) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if(s.lookahead=MIN_MATCH) { //was INSERT_STRING(s, s.strstart, hash_head); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+(MIN_MATCH-1)])&s.hash_mask; hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h]; s.head[s.ins_h]=(ushort)s.strstart; } // Find the longest match, discarding those <= prev_length. s.prev_length=s.match_length; s.prev_match=s.match_start; s.match_length=MIN_MATCH-1; if(hash_head!=NIL&&s.prev_lengthTOO_FAR))) { // If prev_match is also MIN_MATCH, match_start is garbage // but we will ignore the current match anyway. s.match_length=MIN_MATCH-1; } } // If there was a match at the previous step and the current // match is not better, output the previous match: if(s.prev_length>=MIN_MATCH&&s.match_length<=s.prev_length) { uint max_insert=s.strstart+s.lookahead-MIN_MATCH; // Do not insert strings in hash table beyond this. //was _tr_tally_dist(s, s.strstart -1 - s.prev_match, s.prev_length - MIN_MATCH, bflush); { byte len=(byte)(s.prev_length-MIN_MATCH); ushort dist=(ushort)(s.strstart-1-s.prev_match); s.d_buf[s.last_lit]=dist; s.l_buf[s.last_lit++]=len; dist--; s.dyn_ltree[_length_code[len]+LITERALS+1].Freq++; s.dyn_dtree[(dist<256?_dist_code[dist]:_dist_code[256+(dist>>7)])].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?1:0; } // Insert in hash table all strings up to the end of the match. // strstart-1 and strstart are already inserted. If there is not // enough lookahead, the last two strings are not inserted in // the hash table. s.lookahead-=s.prev_length-1; s.prev_length-=2; do { if(++s.strstart<=max_insert) { //was INSERT_STRING(s, s.strstart, hash_head); s.ins_h=((s.ins_h<<(int)s.hash_shift)^s.window[s.strstart+(MIN_MATCH-1)])&s.hash_mask; hash_head=s.prev[s.strstart&s.w_mask]=s.head[s.ins_h]; s.head[s.ins_h]=(ushort)s.strstart; } } while(--s.prev_length!=0); s.match_available=0; s.match_length=MIN_MATCH-1; s.strstart++; if(bflush!=0) { //was FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return block_state.need_more; } } else if(s.match_available!=0) { // If there was no match at the previous position, output a // single literal. If there was a match but the current match // is longer, truncate the previous match to a single literal. //Tracevv((stderr,"%c", s.window[s.strstart-1])); //was _tr_tally_lit(s, s.window[s.strstart-1], bflush); { byte cc=s.window[s.strstart-1]; s.d_buf[s.last_lit]=0; s.l_buf[s.last_lit++]=cc; s.dyn_ltree[cc].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?1:0; } if(bflush!=0) { //was FLUSH_BLOCK_ONLY(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); } s.strstart++; s.lookahead--; if(s.strm.avail_out==0) return block_state.need_more; } else { // There is no previous match to compare with, wait for // the next step to decide. s.match_available=1; s.strstart++; s.lookahead--; } } //Assert(flush!=Z_NO_FLUSH, "no flush?"); if(s.match_available!=0) { //Tracevv((stderr,"%c", s.window[s.strstart-1])); //was _tr_tally_lit(s, s.window[s.strstart-1], bflush); { byte cc=s.window[s.strstart-1]; s.d_buf[s.last_lit]=0; s.l_buf[s.last_lit++]=cc; s.dyn_ltree[cc].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?1:0; } s.match_available=0; } //was FLUSH_BLOCK(s, flush==Z_FINISH); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), flush==Z_FINISH?1:0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return flush==Z_FINISH?block_state.finish_started:block_state.need_more; return flush==Z_FINISH?block_state.finish_done:block_state.block_done; } // =========================================================================== // For Z_RLE, simply look for runs of bytes, generate matches only of distance // one. Do not maintain a hash table. (It will be regenerated if this run of // deflate switches away from Z_RLE.) static block_state deflate_rle(deflate_state s, int flush) { bool bflush; // set if current block must be flushed uint prev; // byte at distance one to match int scan, strend; // scan goes up to strend for length of run for(; ; ) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the longest encodable run. if(s.lookahead=MIN_MATCH&&s.strstart>0) { scan=(int)(s.strstart-1); prev=s.window[scan]; if(prev==s.window[++scan]&&prev==s.window[++scan]&&prev==s.window[++scan]) { strend=(int)(s.strstart+MAX_MATCH); do { } while(prev==s.window[++scan]&&prev==s.window[++scan]&& prev==s.window[++scan]&&prev==s.window[++scan]&& prev==s.window[++scan]&&prev==s.window[++scan]&& prev==s.window[++scan]&&prev==s.window[++scan]&& scans.lookahead) s.match_length=s.lookahead; } } // Emit match if have run of MIN_MATCH or longer, else emit literal if(s.match_length>=MIN_MATCH) { //was _tr_tally_dist(s, 1, s.match_length-MIN_MATCH, bflush); { byte len=(byte)(s.match_length-MIN_MATCH); ushort dist=1; s.d_buf[s.last_lit]=dist; s.l_buf[s.last_lit++]=len; dist--; s.dyn_ltree[_length_code[len]+LITERALS+1].Freq++; s.dyn_dtree[(dist<256?_dist_code[dist]:_dist_code[256+(dist>>7)])].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?true:false; } s.lookahead-=s.match_length; s.strstart+=s.match_length; s.match_length=0; } else { // No match, output a literal byte //Tracevv((stderr,"%c", s.window[s.strstart])); //was _tr_tally_lit(s, s.window[s.strstart], bflush); { byte cc=s.window[s.strstart]; s.d_buf[s.last_lit]=0; s.l_buf[s.last_lit++]=cc; s.dyn_ltree[cc].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?true:false; } s.lookahead--; s.strstart++; } if(bflush) { // FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return block_state.need_more; } } //was FLUSH_BLOCK(s, flush==Z_FINISH); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), flush==Z_FINISH?1:0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return flush==Z_FINISH?block_state.finish_started:block_state.need_more; return flush==Z_FINISH?block_state.finish_done:block_state.block_done; } // =========================================================================== // For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. // (It will be regenerated if this run of deflate switches away from Huffman.) static block_state deflate_huff(deflate_state s, int flush) { bool bflush; // set if current block must be flushed for(; ; ) { // Make sure that we have a literal to write. if(s.lookahead==0) { fill_window(s); if(s.lookahead==0) { if(flush==Z_NO_FLUSH) return block_state.need_more; break; // flush the current block } } // Output a literal byte s.match_length=0; //Tracevv((stderr,"%c", s.window[s.strstart])); //was _tr_tally_lit(s, s.window[s.strstart], bflush); { byte cc=s.window[s.strstart]; s.d_buf[s.last_lit]=0; s.l_buf[s.last_lit++]=cc; s.dyn_ltree[cc].Freq++; bflush=(s.last_lit==s.lit_bufsize-1)?true:false; } s.lookahead--; s.strstart++; if(bflush) { // FLUSH_BLOCK(s, 0); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), 0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return block_state.need_more; } } //was FLUSH_BLOCK(s, flush==Z_FINISH); _tr_flush_block(s, s.block_start>=0?s.window:null, s.block_start>=0?s.block_start:0, (uint)((int)s.strstart-s.block_start), flush==Z_FINISH?1:0); s.block_start=(int)s.strstart; flush_pending(s.strm); //Tracev((stderr,"[FLUSH]")); if(s.strm.avail_out==0) return flush==Z_FINISH?block_state.finish_started:block_state.need_more; return flush==Z_FINISH?block_state.finish_done:block_state.block_done; } } }