Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Sys / System / IO / compression / Deflater.cs / 1305376 / Deflater.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // zlib.h -- interface of the 'zlib' general purpose compression library // version 1.2.1, November 17th, 2003 // // Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // // ==--== // Compression engine namespace System.IO.Compression { using System; using System.Diagnostics; internal class Deflater { private const int MinBlockSize = 256; private const int MaxHeaderFooterGoo = 120; private const int CleanCopySize = DeflateStream.DefaultBufferSize - MaxHeaderFooterGoo; private const double BadCompressionThreshold = 1.0; private FastEncoder deflateEncoder; private CopyEncoder copyEncoder; private DeflateInput input; private OutputBuffer output; private DeflaterState processingState; private DeflateInput inputFromHistory; public Deflater() { deflateEncoder = new FastEncoder(); copyEncoder = new CopyEncoder(); input = new DeflateInput(); output = new OutputBuffer(); processingState = DeflaterState.NotStarted; } public bool NeedsInput() { return input.Count == 0 && deflateEncoder.BytesInHistory == 0; } // Sets the input to compress. The only buffer copy occurs when the input is copied // to the FastEncoderWindow public void SetInput(byte[] inputBuffer, int startIndex, int count) { Debug.Assert(input.Count == 0, "We have something left in previous input!"); input.Buffer = inputBuffer; input.Count = count; input.StartIndex = startIndex; if (count > 0 && count < MinBlockSize) { // user is writing small buffers. If buffer size is below MinBlockSize, we // need to switch to a small data mode, to avoid block headers and footers // dominating the output. switch (processingState) { case DeflaterState.NotStarted : case DeflaterState.CheckingForIncompressible: // clean states, needs a block header first processingState = DeflaterState.StartingSmallData; break; case DeflaterState.CompressThenCheck: // already has correct block header processingState = DeflaterState.HandlingSmallData; break; } } } public int 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 Finish(byte[] outputBuffer) { Debug.Assert(outputBuffer != null, "Can't pass in a null output buffer!"); Debug.Assert(processingState == DeflaterState.NotStarted || processingState == DeflaterState.CheckingForIncompressible || processingState == DeflaterState.HandlingSmallData || processingState == DeflaterState.CompressThenCheck || processingState == DeflaterState.SlowDownForIncompressible1, "got unexpected processing state = " + processingState); Debug.Assert(NeedsInput()); // no need to add end of block info if we didn't write anything if (processingState == DeflaterState.NotStarted) { return 0; } output.UpdateBuffer(outputBuffer); if (processingState == DeflaterState.CompressThenCheck || processingState == DeflaterState.HandlingSmallData || processingState == DeflaterState.SlowDownForIncompressible1) { // need to finish off block deflateEncoder.GetBlockFooter(output); } // write final block WriteFinal(); return output.BytesWritten; } // Is compression ratio under threshold? private bool UseCompressed(double ratio) { return (ratio <= BadCompressionThreshold); } private void FlushInputWindows() { deflateEncoder.FlushInput(); } private void WriteFinal() { copyEncoder.GetBlock(null, output, true); } // These states allow us to assume that data is compressible and keep compression ratios at least // as good as historical values, but switch to different handling if that approach may increase the // data. If we detect we're getting a bad compression ratio, we switch to CheckingForIncompressible // state and decide to compress on a block by block basis. // // If we're getting small data buffers, we want to avoid overhead of excessive header and footer // info, so we add one header and keep adding blocks as compressed. This means that if the user uses // small buffers, they won't get the "don't increase size" improvements. // // An earlier iteration of this fix handled that data separately by buffering this data until it // reached a reasonable size, but given that Flush is not implemented on DeflateStream, this meant // data could be flushed only on Dispose. In the future, it would be reasonable to revisit this, in // case this isn't breaking. // // NotStarted -> CheckingForIncompressible, CompressThenCheck, StartingSmallData // CompressThenCheck -> SlowDownForIncompressible1 // SlowDownForIncompressible1 -> SlowDownForIncompressible2 // SlowDownForIncompressible2 -> CheckingForIncompressible // StartingSmallData -> HandlingSmallData internal enum DeflaterState { // no bytes to write yet NotStarted, // transient states SlowDownForIncompressible1, SlowDownForIncompressible2, StartingSmallData, // stable state: may transition to CheckingForIncompressible (via transient states) if it // appears we're expanding data CompressThenCheck, // sink states CheckingForIncompressible, HandlingSmallData } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // zlib.h -- interface of the 'zlib' general purpose compression library // version 1.2.1, November 17th, 2003 // // Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // // ==--== // Compression engine namespace System.IO.Compression { using System; using System.Diagnostics; internal class Deflater { private const int MinBlockSize = 256; private const int MaxHeaderFooterGoo = 120; private const int CleanCopySize = DeflateStream.DefaultBufferSize - MaxHeaderFooterGoo; private const double BadCompressionThreshold = 1.0; private FastEncoder deflateEncoder; private CopyEncoder copyEncoder; private DeflateInput input; private OutputBuffer output; private DeflaterState processingState; private DeflateInput inputFromHistory; public Deflater() { deflateEncoder = new FastEncoder(); copyEncoder = new CopyEncoder(); input = new DeflateInput(); output = new OutputBuffer(); processingState = DeflaterState.NotStarted; } public bool NeedsInput() { return input.Count == 0 && deflateEncoder.BytesInHistory == 0; } // Sets the input to compress. The only buffer copy occurs when the input is copied // to the FastEncoderWindow public void SetInput(byte[] inputBuffer, int startIndex, int count) { Debug.Assert(input.Count == 0, "We have something left in previous input!"); input.Buffer = inputBuffer; input.Count = count; input.StartIndex = startIndex; if (count > 0 && count < MinBlockSize) { // user is writing small buffers. If buffer size is below MinBlockSize, we // need to switch to a small data mode, to avoid block headers and footers // dominating the output. switch (processingState) { case DeflaterState.NotStarted : case DeflaterState.CheckingForIncompressible: // clean states, needs a block header first processingState = DeflaterState.StartingSmallData; break; case DeflaterState.CompressThenCheck: // already has correct block header processingState = DeflaterState.HandlingSmallData; break; } } } public int 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 Finish(byte[] outputBuffer) { Debug.Assert(outputBuffer != null, "Can't pass in a null output buffer!"); Debug.Assert(processingState == DeflaterState.NotStarted || processingState == DeflaterState.CheckingForIncompressible || processingState == DeflaterState.HandlingSmallData || processingState == DeflaterState.CompressThenCheck || processingState == DeflaterState.SlowDownForIncompressible1, "got unexpected processing state = " + processingState); Debug.Assert(NeedsInput()); // no need to add end of block info if we didn't write anything if (processingState == DeflaterState.NotStarted) { return 0; } output.UpdateBuffer(outputBuffer); if (processingState == DeflaterState.CompressThenCheck || processingState == DeflaterState.HandlingSmallData || processingState == DeflaterState.SlowDownForIncompressible1) { // need to finish off block deflateEncoder.GetBlockFooter(output); } // write final block WriteFinal(); return output.BytesWritten; } // Is compression ratio under threshold? private bool UseCompressed(double ratio) { return (ratio <= BadCompressionThreshold); } private void FlushInputWindows() { deflateEncoder.FlushInput(); } private void WriteFinal() { copyEncoder.GetBlock(null, output, true); } // These states allow us to assume that data is compressible and keep compression ratios at least // as good as historical values, but switch to different handling if that approach may increase the // data. If we detect we're getting a bad compression ratio, we switch to CheckingForIncompressible // state and decide to compress on a block by block basis. // // If we're getting small data buffers, we want to avoid overhead of excessive header and footer // info, so we add one header and keep adding blocks as compressed. This means that if the user uses // small buffers, they won't get the "don't increase size" improvements. // // An earlier iteration of this fix handled that data separately by buffering this data until it // reached a reasonable size, but given that Flush is not implemented on DeflateStream, this meant // data could be flushed only on Dispose. In the future, it would be reasonable to revisit this, in // case this isn't breaking. // // NotStarted -> CheckingForIncompressible, CompressThenCheck, StartingSmallData // CompressThenCheck -> SlowDownForIncompressible1 // SlowDownForIncompressible1 -> SlowDownForIncompressible2 // SlowDownForIncompressible2 -> CheckingForIncompressible // StartingSmallData -> HandlingSmallData internal enum DeflaterState { // no bytes to write yet NotStarted, // transient states SlowDownForIncompressible1, SlowDownForIncompressible2, StartingSmallData, // stable state: may transition to CheckingForIncompressible (via transient states) if it // appears we're expanding data CompressThenCheck, // sink states CheckingForIncompressible, HandlingSmallData } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlEncoding.cs
- TemplatedWizardStep.cs
- RadioButtonPopupAdapter.cs
- ApplyTemplatesAction.cs
- Point3DConverter.cs
- ClientUIRequest.cs
- IgnoreFileBuildProvider.cs
- QilLiteral.cs
- PassportAuthenticationModule.cs
- COM2PropertyDescriptor.cs
- TextPointer.cs
- DetailsViewDeletedEventArgs.cs
- CategoryNameCollection.cs
- ConstraintCollection.cs
- DocumentViewerBaseAutomationPeer.cs
- IPEndPoint.cs
- WizardStepBase.cs
- EntityDataSourceChangingEventArgs.cs
- UnauthorizedWebPart.cs
- CustomLineCap.cs
- StorageMappingItemLoader.cs
- UIElementPropertyUndoUnit.cs
- BaseCAMarshaler.cs
- updateconfighost.cs
- BitmapFrame.cs
- MethodBuilder.cs
- SecurityVerifiedMessage.cs
- XmlBinaryReader.cs
- ScaleTransform3D.cs
- ReceiveActivityDesigner.cs
- CorrelationHandle.cs
- FlowDocumentScrollViewerAutomationPeer.cs
- GlobalizationSection.cs
- WebPartTransformerAttribute.cs
- FlowPosition.cs
- XmlNotation.cs
- ErrorTableItemStyle.cs
- LoginCancelEventArgs.cs
- FileDialogPermission.cs
- TransportChannelFactory.cs
- PartitionResolver.cs
- BinaryFormatterWriter.cs
- TraceHelpers.cs
- ZipIOCentralDirectoryDigitalSignature.cs
- WebConfigurationFileMap.cs
- Regex.cs
- XPathMultyIterator.cs
- TargetPerspective.cs
- MediaSystem.cs
- Margins.cs
- VoiceSynthesis.cs
- FixedFlowMap.cs
- PreservationFileReader.cs
- SizeIndependentAnimationStorage.cs
- BindToObject.cs
- ResourceCodeDomSerializer.cs
- PathFigure.cs
- ExpressionHelper.cs
- UnsafeNativeMethods.cs
- DataConnectionHelper.cs
- XmlNodeChangedEventArgs.cs
- UpdatePanel.cs
- WpfXamlType.cs
- OSFeature.cs
- DesignerAttributeInfo.cs
- SafeBitVector32.cs
- Utility.cs
- TargetException.cs
- Tuple.cs
- WebPartTracker.cs
- ToolStripDesignerAvailabilityAttribute.cs
- DetailsViewUpdatedEventArgs.cs
- DataGridToolTip.cs
- SoapSchemaImporter.cs
- IndexedString.cs
- ImplicitInputBrush.cs
- SystemIPAddressInformation.cs
- TemplateEditingVerb.cs
- ImageCodecInfo.cs
- Perspective.cs
- Rotation3DKeyFrameCollection.cs
- TargetControlTypeAttribute.cs
- PageParserFilter.cs
- DesignerSerializationVisibilityAttribute.cs
- BulletedList.cs
- ButtonFlatAdapter.cs
- _TLSstream.cs
- ResourceDescriptionAttribute.cs
- Matrix3D.cs
- DataSourceSerializationException.cs
- DetailsViewUpdatedEventArgs.cs
- XdrBuilder.cs
- NullableLongAverageAggregationOperator.cs
- PipelineModuleStepContainer.cs
- ReadOnlyDictionary.cs
- VirtualDirectoryMappingCollection.cs
- DynamicDocumentPaginator.cs
- SQLStringStorage.cs
- ClientSettingsSection.cs
- ImageBrush.cs