Beispiel #1
0
        /// <summary>
        /// Sets input data to be deflated.  Should only be called when <see cref="NeedsInput"/>
        /// returns true
        /// </summary>
        /// <param name="buffer">The buffer containing input data.</param>
        /// <param name="offset">The offset of the first byte of data.</param>
        /// <param name="count">The number of bytes of data to use as input.</param>
        public void SetInput(byte[] buffer, int offset, int count)
        {
            if (buffer is null)
            {
                DeflateThrowHelper.ThrowNull(nameof(buffer));
            }

            if (offset < 0)
            {
                DeflateThrowHelper.ThrowOutOfRange(nameof(offset));
            }

            if (count < 0)
            {
                DeflateThrowHelper.ThrowOutOfRange(nameof(count));
            }

            if (this.inputOff < this.inputEnd)
            {
                DeflateThrowHelper.ThrowNotProcessed();
            }

            int end = offset + count;

            // We want to throw an ArgumentOutOfRangeException early.
            // The check is very tricky: it also handles integer wrap around.
            if ((offset > end) || (end > buffer.Length))
            {
                DeflateThrowHelper.ThrowOutOfRange(nameof(count));
            }

            this.inputBuf = buffer;
            this.inputOff = offset;
            this.inputEnd = end;
        }
Beispiel #2
0
        /// <summary>
        /// Deflate drives actual compression of data
        /// </summary>
        /// <param name="flush">True to flush input buffers</param>
        /// <param name="finish">Finish deflation with the current input.</param>
        /// <returns>Returns true if progress has been made.</returns>
        public bool Deflate(bool flush, bool finish)
        {
            bool progress = false;

            do
            {
                this.FillWindow();
                bool canFlush = flush && (this.inputOff == this.inputEnd);

                switch (this.compressionFunction)
                {
                case DeflaterConstants.DEFLATE_STORED:
                    progress = this.DeflateStored(canFlush, finish);
                    break;

                case DeflaterConstants.DEFLATE_FAST:
                    progress = this.DeflateFast(canFlush, finish);
                    break;

                case DeflaterConstants.DEFLATE_SLOW:
                    progress = this.DeflateSlow(canFlush, finish);
                    break;

                default:
                    DeflateThrowHelper.ThrowUnknownCompression();
                    break;
                }
            }while (this.Pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
            return(progress);
        }
Beispiel #3
0
        public void SetInput(byte[] input, int offset, int count)
        {
            if ((this.state & IsFinishing) != 0)
            {
                DeflateThrowHelper.ThrowAlreadyFinished();
            }

            this.engine.SetInput(input, offset, count);
        }
Beispiel #4
0
        /// <summary>
        /// Deflates the current input block to the given array.
        /// </summary>
        /// <param name="output">Buffer to store the compressed data.</param>
        /// <param name="offset">Offset into the output array.</param>
        /// <param name="length">The maximum number of bytes that may be stored.</param>
        /// <returns>
        /// The number of compressed bytes added to the output, or 0 if either
        /// <see cref="IsNeedingInput"/> or <see cref="IsFinished"/> returns true or length is zero.
        /// </returns>
        public int Deflate(Span <byte> output, int offset, int length)
        {
            int origLength = length;

            if (this.state == ClosedState)
            {
                DeflateThrowHelper.ThrowAlreadyClosed();
            }

            while (true)
            {
                int count = this.engine.Pending.Flush(output, offset, length);
                offset += count;
                length -= count;

                if (length == 0 || this.state == FinishedState)
                {
                    break;
                }

                if (!this.engine.Deflate((this.state & IsFlushing) != 0, (this.state & IsFinishing) != 0))
                {
                    switch (this.state)
                    {
                    case BusyState:
                        // We need more input now
                        return(origLength - length);

                    case FlushingState:
                        if (this.level != NoCompression)
                        {
                            // We have to supply some lookahead.  8 bit lookahead
                            // is needed by the zlib inflater, and we must fill
                            // the next byte, so that all bits are flushed.
                            int neededbits = 8 + ((-this.engine.Pending.BitCount) & 7);
                            while (neededbits > 0)
                            {
                                // Write a static tree block consisting solely of an EOF:
                                this.engine.Pending.WriteBits(2, 10);
                                neededbits -= 10;
                            }
                        }

                        this.state = BusyState;
                        break;

                    case FinishingState:
                        this.engine.Pending.AlignToByte();
                        this.state = FinishedState;
                        break;
                    }
                }
            }

            return(origLength - length);
        }
Beispiel #5
0
        /// <summary>
        /// Set the deflate level (0-9)
        /// </summary>
        /// <param name="level">The value to set the level to.</param>
        public void SetLevel(int level)
        {
            if ((level < 0) || (level > 9))
            {
                DeflateThrowHelper.ThrowOutOfRange(nameof(level));
            }

            this.goodLength = DeflaterConstants.GOOD_LENGTH[level];
            this.maxLazy    = DeflaterConstants.MAX_LAZY[level];
            this.niceLength = DeflaterConstants.NICE_LENGTH[level];
            this.maxChain   = DeflaterConstants.MAX_CHAIN[level];

            if (DeflaterConstants.COMPR_FUNC[level] != this.compressionFunction)
            {
                switch (this.compressionFunction)
                {
                case DeflaterConstants.DEFLATE_STORED:
                    if (this.strstart > this.blockStart)
                    {
                        this.huffman.FlushStoredBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
                        this.blockStart = this.strstart;
                    }

                    this.UpdateHash();
                    break;

                case DeflaterConstants.DEFLATE_FAST:
                    if (this.strstart > this.blockStart)
                    {
                        this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
                        this.blockStart = this.strstart;
                    }

                    break;

                case DeflaterConstants.DEFLATE_SLOW:
                    if (this.prevAvailable)
                    {
                        this.huffman.TallyLit(this.pinnedWindowPointer[this.strstart - 1] & 0xFF);
                    }

                    if (this.strstart > this.blockStart)
                    {
                        this.huffman.FlushBlock(this.window.Span, this.blockStart, this.strstart - this.blockStart, false);
                        this.blockStart = this.strstart;
                    }

                    this.prevAvailable = false;
                    this.matchLen      = DeflaterConstants.MIN_MATCH - 1;
                    break;
                }

                this.compressionFunction = DeflaterConstants.COMPR_FUNC[level];
            }
        }