int IDeflater.GetDeflateOutput(byte[] outputBuffer) { Debug.Assert(outputBuffer != null, "Can't pass in a null output buffer!"); Debug.Assert(!NeedsInput(), "GetDeflateOutput should only be called after providing input"); output.UpdateBuffer(outputBuffer); switch (processingState) { case DeflaterState.NotStarted: { // first call. Try to compress but if we get bad compression ratio, switch to uncompressed blocks. Debug.Assert(deflateEncoder.BytesInHistory == 0, "have leftover bytes in window"); // save these in case we need to switch to uncompressed format DeflateInput.InputState initialInputState = input.DumpState(); OutputBuffer.BufferState initialOutputState = output.DumpState(); deflateEncoder.GetBlockHeader(output); deflateEncoder.GetCompressedData(input, output); if (!UseCompressed(deflateEncoder.LastCompressionRatio)) { // we're expanding; restore state and switch to uncompressed input.RestoreState(initialInputState); output.RestoreState(initialOutputState); copyEncoder.GetBlock(input, output, false); FlushInputWindows(); processingState = DeflaterState.CheckingForIncompressible; } else { processingState = DeflaterState.CompressThenCheck; } break; } case DeflaterState.CompressThenCheck: { // continue assuming data is compressible. If we reach data that indicates otherwise // finish off remaining data in history and decide whether to compress on a // block-by-block basis deflateEncoder.GetCompressedData(input, output); if (!UseCompressed(deflateEncoder.LastCompressionRatio)) { processingState = DeflaterState.SlowDownForIncompressible1; inputFromHistory = deflateEncoder.UnprocessedInput; } break; } case DeflaterState.SlowDownForIncompressible1: { // finish off previous compressed block deflateEncoder.GetBlockFooter(output); processingState = DeflaterState.SlowDownForIncompressible2; goto case DeflaterState.SlowDownForIncompressible2; // yeah I know, but there's no fallthrough } case DeflaterState.SlowDownForIncompressible2: { // clear out data from history, but add them as uncompressed blocks if (inputFromHistory.Count > 0) { copyEncoder.GetBlock(inputFromHistory, output, false); } if (inputFromHistory.Count == 0) { // now we're clean deflateEncoder.FlushInput(); processingState = DeflaterState.CheckingForIncompressible; } break; } case DeflaterState.CheckingForIncompressible: { // decide whether to compress on a block-by-block basis Debug.Assert(deflateEncoder.BytesInHistory == 0, "have leftover bytes in window"); // save these in case we need to store as uncompressed DeflateInput.InputState initialInputState = input.DumpState(); OutputBuffer.BufferState initialOutputState = output.DumpState(); // enforce max so we can ensure state between calls deflateEncoder.GetBlock(input, output, CleanCopySize); if (!UseCompressed(deflateEncoder.LastCompressionRatio)) { // we're expanding; restore state and switch to uncompressed input.RestoreState(initialInputState); output.RestoreState(initialOutputState); copyEncoder.GetBlock(input, output, false); FlushInputWindows(); } break; } case DeflaterState.StartingSmallData: { // add compressed header and data, but not footer. Subsequent calls will keep // adding compressed data (no header and no footer). We're doing this to // avoid overhead of header and footer size relative to compressed payload. deflateEncoder.GetBlockHeader(output); processingState = DeflaterState.HandlingSmallData; goto case DeflaterState.HandlingSmallData; // yeah I know, but there's no fallthrough } case DeflaterState.HandlingSmallData: { // continue adding compressed data deflateEncoder.GetCompressedData(input, output); break; } } return(output.BytesWritten); }
public int GetDeflateOutput(byte[] outputBuffer) { this.output.UpdateBuffer(outputBuffer); switch (this.processingState) { case DeflaterState.NotStarted: { DeflateInput.InputState state = this.input.DumpState(); OutputBuffer.BufferState state2 = this.output.DumpState(); this.deflateEncoder.GetBlockHeader(this.output); this.deflateEncoder.GetCompressedData(this.input, this.output); if (this.UseCompressed(this.deflateEncoder.LastCompressionRatio)) { this.processingState = DeflaterState.CompressThenCheck; } else { this.input.RestoreState(state); this.output.RestoreState(state2); this.copyEncoder.GetBlock(this.input, this.output, false); this.FlushInputWindows(); this.processingState = DeflaterState.CheckingForIncompressible; } goto Label_023A; } case DeflaterState.SlowDownForIncompressible1: this.deflateEncoder.GetBlockFooter(this.output); this.processingState = DeflaterState.SlowDownForIncompressible2; break; case DeflaterState.SlowDownForIncompressible2: break; case DeflaterState.StartingSmallData: this.deflateEncoder.GetBlockHeader(this.output); this.processingState = DeflaterState.HandlingSmallData; goto Label_0223; case DeflaterState.CompressThenCheck: this.deflateEncoder.GetCompressedData(this.input, this.output); if (!this.UseCompressed(this.deflateEncoder.LastCompressionRatio)) { this.processingState = DeflaterState.SlowDownForIncompressible1; this.inputFromHistory = this.deflateEncoder.UnprocessedInput; } goto Label_023A; case DeflaterState.CheckingForIncompressible: { DeflateInput.InputState state3 = this.input.DumpState(); OutputBuffer.BufferState state4 = this.output.DumpState(); this.deflateEncoder.GetBlock(this.input, this.output, 0xf88); if (!this.UseCompressed(this.deflateEncoder.LastCompressionRatio)) { this.input.RestoreState(state3); this.output.RestoreState(state4); this.copyEncoder.GetBlock(this.input, this.output, false); this.FlushInputWindows(); } goto Label_023A; } case DeflaterState.HandlingSmallData: goto Label_0223; default: goto Label_023A; } if (this.inputFromHistory.Count > 0) { this.copyEncoder.GetBlock(this.inputFromHistory, this.output, false); } if (this.inputFromHistory.Count == 0) { this.deflateEncoder.FlushInput(); this.processingState = DeflaterState.CheckingForIncompressible; } goto Label_023A; Label_0223: this.deflateEncoder.GetCompressedData(this.input, this.output); Label_023A: return(this.output.BytesWritten); }