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
- WsdlBuildProvider.cs
- MonthChangedEventArgs.cs
- ListViewVirtualItemsSelectionRangeChangedEvent.cs
- TextContainerChangeEventArgs.cs
- CqlBlock.cs
- ManagementObject.cs
- TextElementAutomationPeer.cs
- LayoutTableCell.cs
- FragmentNavigationEventArgs.cs
- unsafenativemethodstextservices.cs
- DataGridCellEditEndingEventArgs.cs
- Vector3DValueSerializer.cs
- CryptoApi.cs
- RequestBringIntoViewEventArgs.cs
- WriteFileContext.cs
- TableHeaderCell.cs
- CompositeActivityMarkupSerializer.cs
- PrimitiveDataContract.cs
- ToolStripRenderer.cs
- ClassDataContract.cs
- IIS7UserPrincipal.cs
- TokenBasedSet.cs
- GridViewDeleteEventArgs.cs
- CancellationHandler.cs
- RuleInfoComparer.cs
- ByteBufferPool.cs
- DesignerDataRelationship.cs
- EventSchemaTraceListener.cs
- Int64Storage.cs
- ComplexBindingPropertiesAttribute.cs
- InternalConfigHost.cs
- Section.cs
- ReflectionPermission.cs
- PageSetupDialog.cs
- TrustVersion.cs
- HandleCollector.cs
- ConfigPathUtility.cs
- ContextMenu.cs
- RichTextBoxConstants.cs
- Point3DCollectionConverter.cs
- XmlComment.cs
- SyncMethodInvoker.cs
- ParameterToken.cs
- ThreadExceptionEvent.cs
- BindingSource.cs
- AssemblyUtil.cs
- ProcessThread.cs
- DetailsViewInsertedEventArgs.cs
- FixUpCollection.cs
- CodeExpressionCollection.cs
- AggregateNode.cs
- PlatformNotSupportedException.cs
- X509Utils.cs
- DeflateEmulationStream.cs
- ItemsPanelTemplate.cs
- JsonGlobals.cs
- ProjectedSlot.cs
- IncrementalCompileAnalyzer.cs
- ConstructorBuilder.cs
- JavaScriptString.cs
- TimelineClockCollection.cs
- DataRowView.cs
- ProfileBuildProvider.cs
- InitializerFacet.cs
- DataGridViewCellContextMenuStripNeededEventArgs.cs
- SqlCacheDependencySection.cs
- ArithmeticException.cs
- DataConnectionHelper.cs
- LZCodec.cs
- DataSourceCache.cs
- IWorkflowDebuggerService.cs
- Comparer.cs
- QilStrConcatenator.cs
- MergeLocalizationDirectives.cs
- GridViewDeleteEventArgs.cs
- DataGridViewRowPostPaintEventArgs.cs
- RelationshipNavigation.cs
- ListItemsCollectionEditor.cs
- ArrangedElementCollection.cs
- MetadataArtifactLoader.cs
- FocusChangedEventArgs.cs
- PreviewControlDesigner.cs
- FrameworkTemplate.cs
- WindowsAuthenticationModule.cs
- ErrorFormatter.cs
- RadioButton.cs
- TextTreeUndoUnit.cs
- RawTextInputReport.cs
- DrawTreeNodeEventArgs.cs
- ClientTargetCollection.cs
- HeaderedContentControl.cs
- OutOfMemoryException.cs
- XmlQualifiedNameTest.cs
- DragSelectionMessageFilter.cs
- CodeFieldReferenceExpression.cs
- TemplateComponentConnector.cs
- DeviceContext2.cs
- AllMembershipCondition.cs
- DataServiceQueryContinuation.cs
- TemplatedMailWebEventProvider.cs