/// <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; }
/// <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); }
public void SetInput(byte[] input, int offset, int count) { if ((this.state & IsFinishing) != 0) { DeflateThrowHelper.ThrowAlreadyFinished(); } this.engine.SetInput(input, offset, count); }
/// <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(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); }
/// <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, 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, 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, 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]; } }
private void Deflate(bool flushing) { while (flushing || !this.deflater.IsNeedingInput) { int deflateCount = this.deflater.Deflate(this.buffer, 0, BufferLength); if (deflateCount <= 0) { break; } this.rawStream.Write(this.buffer, 0, deflateCount); } if (!this.deflater.IsNeedingInput) { DeflateThrowHelper.ThrowNoDeflate(); } }
private void Finish() { this.deflater.Finish(); while (!this.deflater.IsFinished) { int len = this.deflater.Deflate(this.buffer, 0, BufferLength); if (len <= 0) { break; } this.rawStream.Write(this.buffer, 0, len); } if (!this.deflater.IsFinished) { DeflateThrowHelper.ThrowNoDeflate(); } this.rawStream.Flush(); }