コード例 #1
0
 private void QuickEndBlock(Trees.CodeData *lTree, bool last)
 {
     if (this.blockOpen)
     {
         Trees.Tr_emit_end_block(this, lTree, last);
         this.blockStart = this.strStart;
         this.blockOpen  = false;
     }
 }
コード例 #2
0
        private bool Tr_tally_dist(int dist, int len)
        {
            byte *pending    = this.DynamicBuffers.PendingPointer;
            int   dbuffindex = this.dBuf + (this.lastLit * 2);

            pending[dbuffindex++] = (byte)(dist >> 8);
            pending[dbuffindex]   = (byte)dist;
            pending[this.lBuf + this.lastLit++] = (byte)len;
            this.matches++;

            // Here, lc is the match length - MINMATCH
            dist--; // dist = match distance - 1
            this.DynLTree[Trees.GetLengthCode(len) + LITERALS + 1].Freq++;
            this.DynDTree[Trees.GetDistanceCode(dist)].Freq++;

            return(this.lastLit == this.litBufsize - 1);
        }
コード例 #3
0
        private void DeflateReset(ZLibStream zStream)
        {
            zStream.TotalIn  = zStream.TotalOut = 0;
            zStream.Message  = null;
            zStream.DataType = ZUNKNOWN;

            this.Pending    = 0;
            this.PendingOut = 0;

            if (this.NoHeader < 0)
            {
                this.NoHeader = 0; // was set to -1 by deflate(..., Z_FINISH);
            }

            this.status   = (this.NoHeader != 0) ? BUSYSTATE : INITSTATE;
            zStream.Adler = Adler32.SeedValue;

            this.lastFlush = FlushMode.NoFlush;

            Trees.Tr_init(this);
            this.Lm_init();
        }
コード例 #4
0
        private CompressionState DeflateReset(ZStream strm)
        {
            strm.TotalIn  = strm.TotalOut = 0;
            strm.Msg      = null;
            strm.DataType = ZUNKNOWN;

            this.Pending    = 0;
            this.PendingOut = 0;

            if (this.Noheader < 0)
            {
                this.Noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
            }

            this.status = (this.Noheader != 0) ? BUSYSTATE : INITSTATE;
            strm.Adler  = Adler32.SeedValue;

            this.lastFlush = FlushStrategy.NoFlush;

            Trees.Tr_init(this);
            this.Lm_init();
            return(CompressionState.ZOK);
        }
コード例 #5
0
 private void Flush_block_only(bool eof)
 {
     Trees.Tr_flush_block(this, this.blockStart >= 0 ? this.blockStart : -1, this.strStart - this.blockStart, eof);
     this.blockStart = this.strStart;
     this.Flush_pending(this.strm);
 }
コード例 #6
0
        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);
        }
コード例 #7
0
        /// <summary>
        /// The deflate_quick deflate strategy, designed to be used when cycles are
        /// at a premium.
        /// </summary>
        /// <param name="flush">The flush strategy.</param>
        /// <returns>The <see cref="int"/>.</returns>
        internal int DeflateQuick(FlushStrategy flush)
        {
            int  hash_head; // head of the hash chain
            int  dist;
            int  matchLen;
            bool last;

            byte *  window = this.DynBuffers.WindowPointer;
            ushort *head   = this.DynBuffers.HeadPointer;
            ushort *prev   = this.DynBuffers.PrevPointer;

            fixed(Trees.CodeData *ltree = &Trees.StaticLTreeDesc.GetCodeDataReference())
            fixed(Trees.CodeData * dtree = &Trees.StaticDTreeDesc.GetCodeDataReference())
            {
                if (!this.blockOpen && this.lookahead > 0)
                {
                    // Start new block when we have lookahead data, so that if no
                    // input data is given an empty block will not be written.
                    last = flush == FlushStrategy.Finish;
                    this.QuickStartBlock(last);
                }

                int pendingBufferSize = this.DynBuffers.PendingSize;

                do
                {
                    if (this.Pending + 12 >= pendingBufferSize)
                    {
                        this.Flush_pending(this.strm);
                        if (this.strm.AvailIn == 0 && flush != FlushStrategy.Finish)
                        {
                            // Break to emit end block and return need_more
                            break;
                        }
                    }

                    if (this.lookahead < MINLOOKAHEAD)
                    {
                        this.Fill_window();
                        if (this.lookahead < MINLOOKAHEAD && flush == FlushStrategy.NoFlush)
                        {
                            // Always emit end block, in case next call is with Z_FINISH
                            // and we need to emit start of last block
                            this.QuickEndBlock(ltree, false);
                            return(NeedMore);
                        }

                        if (this.lookahead == 0)
                        {
                            break;
                        }

                        if (!this.blockOpen)
                        {
                            // Start new block when we have lookahead data, so that if no
                            // input data is given an empty block will not be written.
                            last = flush == FlushStrategy.Finish;
                            this.QuickStartBlock(last);
                        }
                    }

                    if (this.lookahead >= MINMATCH)
                    {
                        hash_head = this.InsertString(prev, head, window, this.strStart);
                        dist      = this.strStart - hash_head;

                        if (dist > 0 && dist < this.wSize - MINLOOKAHEAD)
                        {
                            matchLen = Compare258(window + this.strStart, window + hash_head);

                            if (matchLen >= MINMATCH)
                            {
                                if (matchLen > this.lookahead)
                                {
                                    matchLen = this.lookahead;
                                }

                                Trees.Tr_emit_distance(this, ltree, dtree, matchLen - MINMATCH, dist);
                                this.lookahead -= matchLen;
                                this.strStart  += matchLen;
                                continue;
                            }
                        }
                    }

                    this.Send_code(window[this.strStart], ltree); // send a literal byte
                    this.strStart++;
                    this.lookahead--;
                }while (this.strm.AvailOut != 0);

                last = flush == FlushStrategy.Finish;
                this.QuickEndBlock(ltree, last);
                this.Flush_pending(this.strm);

                if (last)
                {
                    return(this.strm.AvailOut == 0
                        ? this.strm.AvailIn == 0 ? FinishStarted : NeedMore
                        : FinishDone);
                }

                return(BlockDone);
            }
        }
コード例 #8
0
 private void QuickStartBlock(bool last)
 {
     Trees.Tr_emit_tree(this, STATICTREES, last);
     this.blockStart = this.strStart;
     this.blockOpen  = true;
 }