public CompressionState Compress(ZLibStream zStream, FlushMode flush) { FlushMode old_flush; if (flush > FlushMode.Finish || flush < 0) { return(CompressionState.ZSTREAMERROR); } if (zStream.NextOut == null || (zStream.NextIn == null && zStream.AvailableIn != 0) || (this.status == FINISHSTATE && flush != FlushMode.Finish)) { zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZSTREAMERROR]; return(CompressionState.ZSTREAMERROR); } if (zStream.AvailableOut == 0) { zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR]; return(CompressionState.ZBUFERROR); } this.strm = zStream; // just in case old_flush = this.lastFlush; this.lastFlush = flush; // Write the zlib header if (this.status == INITSTATE) { int header = (ZDEFLATED + ((this.wBits - 8) << 4)) << 8; int level_flags = (((int)this.level - 1) & 0xff) >> 1; if (level_flags > 3) { level_flags = 3; } header |= level_flags << 6; if (this.strStart != 0) { header |= PRESETDICT; } header += 31 - (header % 31); this.status = BUSYSTATE; this.PutShortMSB(header); // Save the adler32 of the preset dictionary: if (this.strStart != 0) { this.PutShortMSB((int)zStream.Adler >> 16); this.PutShortMSB((int)zStream.Adler); } zStream.Adler = Adler32.SeedValue; } // Flush as much pending output as possible if (this.Pending != 0) { this.Flush_pending(zStream); if (zStream.AvailableOut == 0) { // System.out.println(" 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: this.lastFlush = (FlushMode)(-1); return(CompressionState.ZOK); } // 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_BUFF_ERROR. } else if (zStream.AvailableIn == 0 && flush <= old_flush && flush != FlushMode.Finish) { zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR]; return(CompressionState.ZBUFERROR); } // User must not provide more input after the first FINISH: if (this.status == FINISHSTATE && zStream.AvailableIn != 0) { zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR]; return(CompressionState.ZBUFERROR); } // Start a new block or continue the current one. if (zStream.AvailableIn != 0 || this.lookahead != 0 || (flush != FlushMode.NoFlush && this.status != FINISHSTATE)) { int bstate = -1; if (this.Strategy == CompressionStrategy.Rle) { bstate = this.DeflateRle(flush); } else { switch (ConfigTable[(int)this.level].Func) { case STORED: bstate = this.DeflateStored(flush); break; case FAST: bstate = this.DeflateFast(flush); break; case SLOW: bstate = this.DeflateSlow(flush); break; case QUICK: bstate = this.DeflateQuick(flush); break; } } if (bstate == FinishStarted || bstate == FinishDone) { this.status = FINISHSTATE; } if (bstate == NeedMore || bstate == FinishStarted) { if (zStream.AvailableOut == 0) { this.lastFlush = (FlushMode)(-1); // avoid BUF_ERROR next call, see above } return(CompressionState.ZOK); // 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 == BlockDone) { if (flush == FlushMode.PartialFlush) { Trees.Tr_align(this); } else { // FULL_FLUSH or SYNC_FLUSH Trees.Tr_stored_block(this, 0, 0, false); // For a full flush, this empty block will be recognized // as a special marker by inflate_sync(). if (flush == FlushMode.FullFlush) { // state.head[s.hash_size-1]=0; ushort *head = this.DynamicBuffers.HeadPointer; for (int i = 0; i < this.hashSize; i++) { // forget history head[i] = 0; } } } this.Flush_pending(zStream); if (zStream.AvailableOut == 0) { this.lastFlush = (FlushMode)(-1); // avoid BUF_ERROR at next call, see above return(CompressionState.ZOK); } } } if (flush != FlushMode.Finish) { return(CompressionState.ZOK); } if (this.NoHeader != 0) { return(CompressionState.ZSTREAMEND); } // Write the zlib trailer (adler32) this.PutShortMSB((int)zStream.Adler >> 16); this.PutShortMSB((int)zStream.Adler); this.Flush_pending(zStream); // If avail_out is zero, the application will call deflate again // to flush the rest. this.NoHeader = -1; // write the trailer only once! return(this.Pending != 0 ? CompressionState.ZOK : CompressionState.ZSTREAMEND); }
/// <summary> /// Initializes a new instance of the <see cref="Deflate"/> class. /// </summary> /// <param name="zStream">The zlib stream.</param> /// <param name="options">The zlib options.</param> /// <param name="windowBits">The window size in bits.</param> public Deflate(ZLibStream zStream, ZlibOptions options, int windowBits) : this(zStream, options, ZDEFLATED, windowBits, DEFMEMLEVEL) { }
public Deflate( ZLibStream zStream, ZlibOptions options, int method, int windowBits, int memLevel) { int noheader = 0; zStream.Message = null; CompressionLevel level = options.CompressionLevel.GetValueOrDefault(); CompressionStrategy strategy = options.CompressionStrategy; if (level == CompressionLevel.DefaultCompression) { level = CompressionLevel.Level6; } if (level == CompressionLevel.NoCompression) { memLevel = DEFNOCOMPRESSIONMEMLEVEL; } if (windowBits < 0) { // undocumented feature: suppress zlib header noheader = 1; windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAXMEMLEVEL) { ThrowHelper.ThrowArgumentRangeException(nameof(memLevel)); } if (method != ZDEFLATED) { ThrowHelper.ThrowArgumentRangeException(nameof(method)); } if (windowBits < 9 || windowBits > 15) { ThrowHelper.ThrowArgumentRangeException(nameof(windowBits)); } if (level < CompressionLevel.NoCompression || level > CompressionLevel.BestCompression) { ThrowHelper.ThrowArgumentRangeException(nameof(level)); } if (strategy < CompressionStrategy.DefaultStrategy || strategy > CompressionStrategy.Fixed) { ThrowHelper.ThrowArgumentRangeException(nameof(strategy)); } #if USE_QUICK if (level == ZlibCompressionLevel.ZBESTSPEED) { windowBits = 13; } #endif this.NoHeader = noheader; this.wBits = windowBits; this.wSize = 1 << this.wBits; this.wMask = this.wSize - 1; this.hashBits = memLevel + 7; this.hashSize = 1 << this.hashBits; this.hashMask = (uint)this.hashSize - 1; this.litBufsize = 1 << (memLevel + 6); // 16K elements by default this.dBuf = this.litBufsize; this.lBuf = (1 + 2) * this.litBufsize; this.level = level; this.Strategy = strategy; this.method = (byte)method; this.FixedBuffers = new FixedLengthBuffers(); this.DynamicBuffers = new DynamicLengthBuffers(this.wSize, this.hashSize, this.litBufsize * 4); this.DeflateReset(zStream); }
internal static CompressionState Inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZLibStream z) { CompressionState r; var hn = new int[1]; // hufts used in space var v = new int[288]; // work area for huft_build // build literal/length tree r = Huft_build(c, 0, nl, 257, Cplens, Cplext, tl, bl, hp, hn, v); if (r != CompressionState.ZOK || bl[0] == 0) { if (r == CompressionState.ZDATAERROR) { z.Message = "oversubscribed literal/length tree"; } else if (r != CompressionState.ZMEMERROR) { z.Message = "incomplete literal/length tree"; r = CompressionState.ZDATAERROR; } return(r); } // build distance tree r = Huft_build(c, nl, nd, 0, Cpdist, Cpdext, td, bd, hp, hn, v); if (r != CompressionState.ZOK || (bd[0] == 0 && nl > 257)) { if (r == CompressionState.ZDATAERROR) { z.Message = "oversubscribed distance tree"; } else if (r == CompressionState.ZBUFERROR) { z.Message = "incomplete distance tree"; r = CompressionState.ZDATAERROR; } else if (r != CompressionState.ZMEMERROR) { z.Message = "empty distance tree with lengths"; r = CompressionState.ZDATAERROR; } return(r); } return(CompressionState.ZOK); }
internal static CompressionState Inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZLibStream z) { CompressionState r; var hn = new int[1]; // hufts used in space var v = new int[19]; // work area for huft_build r = Huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); if (r == CompressionState.ZDATAERROR) { z.Message = "oversubscribed dynamic bit lengths tree"; } else if (r == CompressionState.ZBUFERROR || bb[0] == 0) { z.Message = "incomplete dynamic bit lengths tree"; r = CompressionState.ZDATAERROR; } return(r); }
// 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. internal static CompressionState InflateSyncPoint(ZLibStream z) => (z == null || z.InflateState == null || z.InflateState.Blocks == null) ? CompressionState.ZSTREAMERROR : z.InflateState.Blocks.Sync_point();
internal static CompressionState InflateSync(ZLibStream zStream) { int n; // number of bytes to look at int p; // pointer to bytes int m; // number of marker bytes found in a row long r, w; // temporaries to save total_in and total_out // set up if (zStream == null || zStream.InflateState == null) { return(CompressionState.ZSTREAMERROR); } if (zStream.InflateState.Mode != BAD) { zStream.InflateState.Mode = BAD; zStream.InflateState.Marker = 0; } if ((n = zStream.AvailableIn) == 0) { return(CompressionState.ZBUFERROR); } p = zStream.NextInIndex; m = zStream.InflateState.Marker; // search while (n != 0 && m < 4) { if (zStream.NextIn[p] == Mark[m]) { m++; } else { m = zStream.NextIn[p] != 0 ? 0 : 4 - m; } p++; n--; } // restore zStream.TotalIn += p - zStream.NextInIndex; zStream.NextInIndex = p; zStream.AvailableIn = n; zStream.InflateState.Marker = m; // return no joy or set up to restart on a new block if (m != 4) { return(CompressionState.ZDATAERROR); } r = zStream.TotalIn; w = zStream.TotalOut; InflateReset(zStream, zStream.InflateState); zStream.TotalIn = r; zStream.TotalOut = w; zStream.InflateState.Mode = BLOCKS; return(CompressionState.ZOK); }
internal static CompressionState Decompress(ZLibStream zStream, FlushMode strategy) { CompressionState state; int b; if (zStream == null || zStream.InflateState == null || zStream.NextIn == null) { return(CompressionState.ZSTREAMERROR); } // f = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; state = CompressionState.ZBUFERROR; while (true) { // System.out.println("mode: "+z.istate.mode); switch (zStream.InflateState.Mode) { case METHOD: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; if (((zStream.InflateState.Method = zStream.NextIn[zStream.NextInIndex++]) & 0xf) != ZDEFLATED) { zStream.InflateState.Mode = BAD; zStream.Message = "unknown compression method"; zStream.InflateState.Marker = 5; // can't try inflateSync break; } if ((zStream.InflateState.Method >> 4) + 8 > zStream.InflateState.WindowBits) { zStream.InflateState.Mode = BAD; zStream.Message = "invalid window size"; zStream.InflateState.Marker = 5; // can't try inflateSync break; } zStream.InflateState.Mode = FLAG; goto case FLAG; case FLAG: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; b = zStream.NextIn[zStream.NextInIndex++] & 0xff; if ((((zStream.InflateState.Method << 8) + b) % 31) != 0) { zStream.InflateState.Mode = BAD; zStream.Message = "incorrect header check"; zStream.InflateState.Marker = 5; // can't try inflateSync break; } if ((b & PRESETDICT) == 0) { zStream.InflateState.Mode = BLOCKS; break; } zStream.InflateState.Mode = DICT4; goto case DICT4; case DICT4: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need = ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L); zStream.InflateState.Mode = DICT3; goto case DICT3; case DICT3: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 16) & 0xff0000L; zStream.InflateState.Mode = DICT2; goto case DICT2; case DICT2: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 8) & 0xff00L; zStream.InflateState.Mode = DICT1; goto case DICT1; case DICT1: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += zStream.NextIn[zStream.NextInIndex++] & 0xffL; zStream.Adler = (uint)zStream.InflateState.Need; zStream.InflateState.Mode = DICT0; return(CompressionState.ZNEEDDICT); case DICT0: zStream.InflateState.Mode = BAD; zStream.Message = "need dictionary"; zStream.InflateState.Marker = 0; // can try inflateSync return(CompressionState.ZSTREAMERROR); case BLOCKS: state = zStream.InflateState.Blocks.Process(zStream, state); if (state == CompressionState.ZDATAERROR) { zStream.InflateState.Mode = BAD; zStream.InflateState.Marker = 0; // can try inflateSync break; } if (state == CompressionState.ZOK) { state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; } if (state != CompressionState.ZSTREAMEND) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.InflateState.Blocks.Reset(zStream, zStream.InflateState.Was); if (zStream.InflateState.NoWrap) { zStream.InflateState.Mode = DONE; break; } zStream.InflateState.Mode = CHECK4; goto case CHECK4; case CHECK4: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need = ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L); zStream.InflateState.Mode = CHECK3; goto case CHECK3; case CHECK3: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 16) & 0xff0000L; zStream.InflateState.Mode = CHECK2; goto case CHECK2; case CHECK2: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 8) & 0xff00L; zStream.InflateState.Mode = CHECK1; goto case CHECK1; case CHECK1: if (zStream.AvailableIn == 0) { return(state); } state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK; zStream.AvailableIn--; zStream.TotalIn++; zStream.InflateState.Need += zStream.NextIn[zStream.NextInIndex++] & 0xffL; if (((int)zStream.InflateState.Was[0]) != ((int)zStream.InflateState.Need)) { zStream.InflateState.Mode = BAD; zStream.Message = "incorrect data check"; zStream.InflateState.Marker = 5; // can't try inflateSync break; } zStream.InflateState.Mode = DONE; goto case DONE; case DONE: return(CompressionState.ZSTREAMEND); case BAD: return(CompressionState.ZDATAERROR); default: return(CompressionState.ZSTREAMERROR); } } }