Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlColumnizer.cs
- TextBoxRenderer.cs
- UnmanagedMemoryStream.cs
- FormsIdentity.cs
- SchemaRegistration.cs
- DownloadProgressEventArgs.cs
- HttpMethodAttribute.cs
- RectAnimation.cs
- NotImplementedException.cs
- PointUtil.cs
- SingleObjectCollection.cs
- DataBoundLiteralControl.cs
- ZeroOpNode.cs
- QilTernary.cs
- XmlValidatingReader.cs
- ComponentSerializationService.cs
- AuthenticationServiceManager.cs
- PreviewKeyDownEventArgs.cs
- PathStreamGeometryContext.cs
- UnorderedHashRepartitionStream.cs
- Matrix.cs
- HttpPostLocalhostServerProtocol.cs
- TypedDataSetSchemaImporterExtensionFx35.cs
- CapabilitiesUse.cs
- MSAANativeProvider.cs
- TypeExtensionSerializer.cs
- TraceContextRecord.cs
- ButtonBase.cs
- PermissionSetEnumerator.cs
- XamlSerializer.cs
- AesManaged.cs
- ImageCodecInfo.cs
- Stroke.cs
- RuntimeEnvironment.cs
- LinqDataSourceInsertEventArgs.cs
- DesignerDataColumn.cs
- HttpApplicationStateWrapper.cs
- QueryCursorEventArgs.cs
- NotSupportedException.cs
- PresentationAppDomainManager.cs
- SettingsBase.cs
- ObjectHandle.cs
- SqlXml.cs
- OleDbWrapper.cs
- CheckBoxPopupAdapter.cs
- DataSetViewSchema.cs
- ConnectionManagementSection.cs
- DataGridCommandEventArgs.cs
- SpeechDetectedEventArgs.cs
- StdValidatorsAndConverters.cs
- ItemsChangedEventArgs.cs
- IisHelper.cs
- Component.cs
- RectangleHotSpot.cs
- ProfilePropertyMetadata.cs
- IndentTextWriter.cs
- ContentElement.cs
- SqlDependencyUtils.cs
- CornerRadius.cs
- PhysicalFontFamily.cs
- NonClientArea.cs
- PolyQuadraticBezierSegment.cs
- TypeDescriptorFilterService.cs
- XmlEventCache.cs
- Missing.cs
- LockCookie.cs
- SqlMethodCallConverter.cs
- DeadCharTextComposition.cs
- KnowledgeBase.cs
- ResourceExpressionBuilder.cs
- EventListenerClientSide.cs
- LogEntryDeserializer.cs
- Common.cs
- CodeAccessPermission.cs
- IPCCacheManager.cs
- TraceSection.cs
- Formatter.cs
- CompilerResults.cs
- ApplicationServiceManager.cs
- QfeChecker.cs
- ScriptManagerProxy.cs
- WebPartMinimizeVerb.cs
- XamlInt32CollectionSerializer.cs
- UnsafeNativeMethods.cs
- FixedStringLookup.cs
- ConnectorSelectionGlyph.cs
- UpdateEventArgs.cs
- GeneralTransform3D.cs
- CompiledRegexRunner.cs
- RadioButtonBaseAdapter.cs
- EntityDesignerBuildProvider.cs
- KnownBoxes.cs
- XsdDateTime.cs
- CodeCompiler.cs
- SelectionProviderWrapper.cs
- SqlDataSourceCache.cs
- TransformationRules.cs
- DbConnectionInternal.cs
- PartitionResolver.cs
- InstanceContextMode.cs