internal int DeflateFast(ZlibFlushStrategy flush) { int hash_head; // head of the hash chain bool bflush; // set if current block must be flushed byte * window = this.windowPointer; ushort *head = this.headPointer; ushort *prev = this.prevPointer; while (true) { // 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 MINMATCH bytes to insert the // string following the next match. if (this.lookahead < MINLOOKAHEAD) { this.Fill_window(); if (this.lookahead < MINLOOKAHEAD && flush == ZlibFlushStrategy.ZNOFLUSH) { return(NeedMore); } if (this.lookahead == 0) { break; // flush the current block } } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: hash_head = 0; if (this.lookahead >= MINMATCH) { hash_head = this.InsertString(prev, head, window, this.strStart); } // Find the longest match, discarding those <= prev_length. // At this point we have always match_length < MINMATCH if (hash_head != 0 && (this.strStart - hash_head) <= this.wSize - MINLOOKAHEAD) { // 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). if (this.strategy != ZlibCompressionStrategy.ZHUFFMANONLY) { this.matchLength = this.Longest_match(hash_head); // longest_match() sets match_start } } if (this.matchLength >= MINMATCH) { // check_match(strstart, match_start, match_length); bflush = this.Tr_tally_dist(this.strStart - this.matchStart, this.matchLength - MINMATCH); this.lookahead -= this.matchLength; // Insert new strings in the hash table only if the match length // is not too large. This saves time but degrades compression. if (this.matchLength <= this.maxLazyMatch && this.lookahead >= MINMATCH) { this.matchLength--; // string at strstart already in hash table do { this.strStart++; hash_head = this.InsertString(prev, head, window, this.strStart); // strstart never exceeds WSIZE-MAX_MATCH, so there are // always MINMATCH bytes ahead. }while (--this.matchLength != 0); this.strStart++; } else { this.strStart += this.matchLength; this.matchLength = 0; this.UpdateHash(window[this.strStart + 1]); // If lookahead < MINMATCH, insH is garbage, but it does not // matter since it will be recomputed at next deflate call. } } else { // No match, output a literal byte bflush = this.Tr_tally_lit(window[this.strStart]); this.lookahead--; this.strStart++; } if (bflush) { this.Flush_block_only(false); if (this.strm.AvailOut == 0) { return(NeedMore); } } } this.Flush_block_only(flush == ZlibFlushStrategy.ZFINISH); return(this.strm.AvailOut == 0 ? flush == ZlibFlushStrategy.ZFINISH ? FinishStarted : NeedMore : flush == ZlibFlushStrategy.ZFINISH ? FinishDone : BlockDone); }
private int DeflateSlow(ZlibFlushStrategy flush) { int hash_head = 0; // head of hash chain bool bflush; // set if current block must be flushed byte * window = this.windowPointer; ushort *head = this.headPointer; ushort *prev = this.prevPointer; // Process the input block. while (true) { // 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 MINMATCH bytes to insert the // string following the next match. if (this.lookahead < MINLOOKAHEAD) { this.Fill_window(); if (this.lookahead < MINLOOKAHEAD && flush == ZlibFlushStrategy.ZNOFLUSH) { return(NeedMore); } if (this.lookahead == 0) { break; // flush the current block } } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: if (this.lookahead >= MINMATCH) { hash_head = this.InsertString(prev, head, window, this.strStart); } // Find the longest match, discarding those <= prev_length. this.prevLength = this.matchLength; this.prevMatch = this.matchStart; this.matchLength = MINMATCH - 1; if (hash_head != 0 && this.prevLength < this.maxLazyMatch && this.strStart - hash_head <= this.wSize - MINLOOKAHEAD) { // 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). if (this.strategy != ZlibCompressionStrategy.ZHUFFMANONLY) { this.matchLength = this.Longest_match(hash_head); } // longest_match() sets match_start if (this.matchLength <= 5 && (this.strategy == ZlibCompressionStrategy.ZFILTERED || (this.matchLength == MINMATCH && this.strStart - this.matchStart > 4096))) { // If prev_match is also MINMATCH, match_start is garbage // but we will ignore the current match anyway. this.matchLength = MINMATCH - 1; } } // If there was a match at the previous step and the current // match is not better, output the previous match: if (this.prevLength >= MINMATCH && this.matchLength <= this.prevLength) { int max_insert = this.strStart + this.lookahead - MINMATCH; // Do not insert strings in hash table beyond this. // check_match(strstart-1, prev_match, prev_length); bflush = this.Tr_tally_dist(this.strStart - 1 - this.prevMatch, this.prevLength - MINMATCH); // 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. this.lookahead -= this.prevLength - 1; this.prevLength -= 2; do { if (++this.strStart <= max_insert) { hash_head = this.InsertString(prev, head, window, this.strStart); } }while (--this.prevLength != 0); this.matchAvailable = 0; this.matchLength = MINMATCH - 1; this.strStart++; if (bflush) { this.Flush_block_only(false); if (this.strm.AvailOut == 0) { return(NeedMore); } } } else if (this.matchAvailable != 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. bflush = this.Tr_tally_lit(window[this.strStart - 1]); if (bflush) { this.Flush_block_only(false); } this.strStart++; this.lookahead--; if (this.strm.AvailOut == 0) { return(NeedMore); } } else { // There is no previous match to compare with, wait for // the next step to decide. this.matchAvailable = 1; this.strStart++; this.lookahead--; } } if (this.matchAvailable != 0) { _ = this.Tr_tally_lit(window[this.strStart - 1]); this.matchAvailable = 0; } this.Flush_block_only(flush == ZlibFlushStrategy.ZFINISH); return(this.strm.AvailOut == 0 ? flush == ZlibFlushStrategy.ZFINISH ? FinishStarted : NeedMore : flush == ZlibFlushStrategy.ZFINISH ? FinishDone : BlockDone); }
/// <summary> /// Compress data. /// </summary> /// <param name="flush">The flush mode to use on the data.</param> /// <returns>The zlib status state.</returns> public ZlibCompressionState Deflate(ZlibFlushStrategy flush) => this.Dstate == null ? ZlibCompressionState.ZSTREAMERROR : this.Dstate.Compress(this, flush);
/// <summary> /// Decompresses data. /// </summary> /// <param name="f">The flush mode to use.</param> /// <returns>The zlib status state.</returns> public ZlibCompressionState Inflate(ZlibFlushStrategy f) => this.Istate == null ? ZlibCompressionState.ZSTREAMERROR : Libs.Inflate.Decompress(this, f);
internal static ZlibCompressionState Decompress(ZStream z, ZlibFlushStrategy f) { ZlibCompressionState r; int b; if (z == null || z.Istate == null || z.INextIn == null) { return(ZlibCompressionState.ZSTREAMERROR); } // f = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; r = ZlibCompressionState.ZBUFERROR; while (true) { // System.out.println("mode: "+z.istate.mode); switch (z.Istate.Mode) { case METHOD: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; if (((z.Istate.Method = z.INextIn[z.NextInIndex++]) & 0xf) != ZDEFLATED) { z.Istate.Mode = BAD; z.Msg = "unknown compression method"; z.Istate.Marker = 5; // can't try inflateSync break; } if ((z.Istate.Method >> 4) + 8 > z.Istate.Wbits) { z.Istate.Mode = BAD; z.Msg = "invalid window size"; z.Istate.Marker = 5; // can't try inflateSync break; } z.Istate.Mode = FLAG; goto case FLAG; case FLAG: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; b = z.INextIn[z.NextInIndex++] & 0xff; if ((((z.Istate.Method << 8) + b) % 31) != 0) { z.Istate.Mode = BAD; z.Msg = "incorrect header check"; z.Istate.Marker = 5; // can't try inflateSync break; } if ((b & PRESETDICT) == 0) { z.Istate.Mode = BLOCKS; break; } z.Istate.Mode = DICT4; goto case DICT4; case DICT4: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need = ((z.INextIn[z.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L); z.Istate.Mode = DICT3; goto case DICT3; case DICT3: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += ((z.INextIn[z.NextInIndex++] & 0xff) << 16) & 0xff0000L; z.Istate.Mode = DICT2; goto case DICT2; case DICT2: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += ((z.INextIn[z.NextInIndex++] & 0xff) << 8) & 0xff00L; z.Istate.Mode = DICT1; goto case DICT1; case DICT1: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += z.INextIn[z.NextInIndex++] & 0xffL; z.Adler = (uint)z.Istate.Need; z.Istate.Mode = DICT0; return(ZlibCompressionState.ZNEEDDICT); case DICT0: z.Istate.Mode = BAD; z.Msg = "need dictionary"; z.Istate.Marker = 0; // can try inflateSync return(ZlibCompressionState.ZSTREAMERROR); case BLOCKS: r = z.Istate.Blocks.Proc(z, r); if (r == ZlibCompressionState.ZDATAERROR) { z.Istate.Mode = BAD; z.Istate.Marker = 0; // can try inflateSync break; } if (r == ZlibCompressionState.ZOK) { r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; } if (r != ZlibCompressionState.ZSTREAMEND) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.Istate.Blocks.Reset(z, z.Istate.Was); if (z.Istate.Nowrap != 0) { z.Istate.Mode = DONE; break; } z.Istate.Mode = CHECK4; goto case CHECK4; case CHECK4: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need = ((z.INextIn[z.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L); z.Istate.Mode = CHECK3; goto case CHECK3; case CHECK3: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += ((z.INextIn[z.NextInIndex++] & 0xff) << 16) & 0xff0000L; z.Istate.Mode = CHECK2; goto case CHECK2; case CHECK2: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += ((z.INextIn[z.NextInIndex++] & 0xff) << 8) & 0xff00L; z.Istate.Mode = CHECK1; goto case CHECK1; case CHECK1: if (z.AvailIn == 0) { return(r); } r = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK; z.AvailIn--; z.TotalIn++; z.Istate.Need += z.INextIn[z.NextInIndex++] & 0xffL; if (((int)z.Istate.Was[0]) != ((int)z.Istate.Need)) { z.Istate.Mode = BAD; z.Msg = "incorrect data check"; z.Istate.Marker = 5; // can't try inflateSync break; } z.Istate.Mode = DONE; goto case DONE; case DONE: return(ZlibCompressionState.ZSTREAMEND); case BAD: return(ZlibCompressionState.ZDATAERROR); default: return(ZlibCompressionState.ZSTREAMERROR); } } }
private int DeflateStored(ZlibFlushStrategy flush) { // Smallest worthy block size when not flushing or finishing. By default // this is 32K.This can be as small as 507 bytes for memLevel == 1., pending_buf is limited // to pending_buf_size, and each stored block has a 5 byte header: int max_block_size = Math.Min(this.pendingBufferSize - 5, this.wSize); int max_start; // Copy as much as possible from input to output: while (true) { // Fill the window as much as possible: if (this.lookahead <= 1) { this.Fill_window(); if (this.lookahead == 0 && flush == ZlibFlushStrategy.ZNOFLUSH) { return(NeedMore); } if (this.lookahead == 0) { break; // flush the current block } } this.strStart += this.lookahead; this.lookahead = 0; // Emit a stored block if pending_buf will be full: max_start = this.blockStart + max_block_size; if (this.strStart == 0 || this.strStart >= max_start) { // strstart == 0 is possible when wraparound on 16-bit machine this.lookahead = this.strStart - max_start; this.strStart = max_start; this.Flush_block_only(false); if (this.strm.AvailOut == 0) { return(NeedMore); } } // Flush if we may have to slide, otherwise block_start may become // negative and the data will be gone: if (this.strStart - this.blockStart >= this.wSize - MINLOOKAHEAD) { this.Flush_block_only(false); if (this.strm.AvailOut == 0) { return(NeedMore); } } } this.Flush_block_only(flush == ZlibFlushStrategy.ZFINISH); return(this.strm.AvailOut == 0 ? (flush == ZlibFlushStrategy.ZFINISH) ? FinishStarted : NeedMore : flush == ZlibFlushStrategy.ZFINISH ? FinishDone : BlockDone); }