Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / IO / Zip / ZipIOLocalFileBlock.cs / 1 / ZipIOLocalFileBlock.cs
//------------------------------------------------------------------------------ //------------- *** WARNING *** //------------- This file is part of a legally monitored development project. //------------- Do not check in changes to this project. Do not raid bugs on this //------------- code in the main PS database. Do not contact the owner of this //------------- code directly. Contact the legal team at ‘ZSLegal’ for assistance. //------------- *** WARNING *** //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This is an internal class that enables interactions with Zip archives // for OPC scenarios // // History: // 11/19/2004: IgorBel: Initial creation. // 10/21/2005: brucemac: Apply security mitigations // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Runtime.Serialization; using System.Globalization; using System.Windows; using MS.Internal.IO.Packaging; // For CompressStream namespace MS.Internal.IO.Zip { internal class ZipIOLocalFileBlock : IZipIOBlock, IDisposable { //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- // standard IZipIOBlock functionality public long Offset { get { CheckDisposed(); return _offset; } } public long Size { get { CheckDisposed(); checked { long size = _localFileHeader.Size + _fileItemStream.Length; if (_localFileDataDescriptor != null) { // we only account for the data descriptor // if it is there and data wasn't changed yet , // because we will discard it as a part of saving size += _localFileDataDescriptor.Size; } return size; } } } public bool GetDirtyFlag(bool closingFlag) { CheckDisposed(); bool deflateStreamDirty = false; if (_deflateStream != null) deflateStreamDirty = ((CompressStream) _deflateStream).IsDirty(closingFlag); // !!! ATTENTION !!!! // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty". // In the past we had Dirty flag on the ZipIoModeEnforcing stream that was always false. Enumerating // those flags had significant perf cost (allocating all the Enumerator classes). We are removing Dirty flag // from the ZipIoModeEnforcingStream and all the processing code associated with that. //If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to // reintroduce Dirty state/flag and properly account for this value in the ZipIoLocalFileBlock.DirtyFlag. return _dirtyFlag || _fileItemStream.DirtyFlag || deflateStreamDirty; } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ public void Move(long shiftSize) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); if (shiftSize != 0) { checked{_offset +=shiftSize;} _fileItemStream.Move(shiftSize); _dirtyFlag = true; Debug.Assert(_offset >=0); } } ////// Streaming-specific variant of Save() /// /// internal void SaveStreaming(bool closingFlag) { CheckDisposed(); Debug.Assert(_blockManager.Streaming, "Only legal in Streaming mode"); if (GetDirtyFlag(closingFlag)) { BinaryWriter writer = _blockManager.BinaryWriter; // write the local file header if not already done so if (!_localFileHeaderSaved) { // our first access to the ArchiveStream - note our offset _offset = _blockManager.Stream.Position; _localFileHeader.Save(writer); _localFileHeaderSaved = true; } FlushExposedStreams(); //this will cause the actual write to disk, and it safe to do so, // because all we're in streaming mode and there is // no data in the way _fileItemStream.SaveStreaming(); // Data Descriptor required for streaming mode if (closingFlag) { // now prior to possibly closing streams we need to preserve uncompressed Size // otherwise Length function will fail to give it to us later after closing _localFileDataDescriptor.UncompressedSize = _crcCalculatingStream.Length; // calculate CRC prior to closing _localFileDataDescriptor.Crc32 = _crcCalculatingStream.CalculateCrc(); // If we are closing we can do extra things , calculate CRC , close deflate stream // it is particularly important to close the deflate stream as it might hold some extra bytes // even after Flush() // close outstanding streams to signal that we need new pieces if more data comes CloseExposedStreams(); // in order to get proper compressed size we have to close the deflate stream if (_deflateStream != null) { _deflateStream.Close(); _fileItemStream.SaveStreaming(); // get the extra bytes emitted by the DeflateStream } _localFileDataDescriptor.CompressedSize = _fileItemStream.Length; _localFileDataDescriptor.Save(writer); _dirtyFlag = false; } } } ////// Save() /// public void Save() { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); // Note: This triggers a call to UpdateReferences() which will // discard any _localFileDataDescriptor. if (GetDirtyFlag(true)) // if we do not have closingFlag value (we should be using closingFlag=true as a more conservative approach) { // We need to notify the _fileItemStream that we about to save our FileHeader; // otherwise we might be overriding some of the FileItemStream data with the // FileHeader. Specifically we are concerned about scenario when a previous // block become large by just a couple of bytes, so that the PreSaveNotification // issued prior to saving the previous block didn’t trigger caching of our FileItemStream, // but we still need to make sure that the current FileHeader will not override any data // in our FileItemStream. _fileItemStream.PreSaveNotification(_offset, _localFileHeader.Size); //position the stream BinaryWriter writer = _blockManager.BinaryWriter; if (_blockManager.Stream.Position != _offset) { // we need to seek _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } _localFileHeader.Save(writer); //this will cause the actual write to disk, and it safe to do so, // because all overlapping data was moved out of the way // by the calling BlockManager _fileItemStream.Save(); _dirtyFlag = false; } } // !!! ATTENTION !!!! This function is only supposed to be called by // Block Manager.Save which has proper protection to ensure no stack overflow will happen // as a result of Stream.Flush calls which in turn result in BlockManager.Save calls public void UpdateReferences(bool closingFlag) { Invariant.Assert(!_blockManager.Streaming); long uncompressedSize; long compressedSize; CheckDisposed(); if (closingFlag) { CloseExposedStreams(); } else { FlushExposedStreams(); } // At this point we can update Local Headers with the proper CRC Value // We can also update other Local File Header Values (compressed/uncompressed size) // we rely on our DirtyFlag property to properly account for all possbile modifications within streams if (GetDirtyFlag(closingFlag)) { // Remember the size of the header before update long headerSizeBeforeUpdate = _localFileHeader.Size; // now prior to possibly closing streams we need to preserve uncompressed Size // otherwise Length function will fail to give it to us later after closing uncompressedSize = _crcCalculatingStream.Length; // calculate CRC prior to closing _localFileHeader.Crc32 = _crcCalculatingStream.CalculateCrc(); // If we are closing we can do extra things , calculate CRC , close deflate stream // it is particularly important to close the deflate stream as it might hold some extra bytes // even after Flush() if (closingFlag) { // we have got the CRC so we can close the stream _crcCalculatingStream.Close(); // in order to get proper compressed size we have to close the deflate stream if (_deflateStream != null) { _deflateStream.Close(); } } if (_fileItemStream.DataChanged) { _localFileHeader.LastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); } // get compressed size after possible closing Deflated stream // as a result of some ineffeciencies in CRC calculation it might result in Seek in compressed stream // and there fore switching mode and flushing extra compressed bytes compressedSize = _fileItemStream.Length; // this will properly (taking into account ZIP64 scenario) update local file header // Offset is passed in to determine whether ZIP 64 is required for small files that // happened to be located required 32 bit offset in the archive _localFileHeader.UpdateZip64Structures(compressedSize, uncompressedSize, Offset); // Add/remove padding to compensate the header size change // NOTE: Padding needs to be updated only after updating all the header fields // that can affect the header size _localFileHeader.UpdatePadding(_localFileHeader.Size - headerSizeBeforeUpdate); // We always save File Items in Non-streaming mode unless it wasn't touched //in which case we leave them alone _localFileHeader.StreamingCreationFlag = false; _localFileDataDescriptor = null; // in some cases UpdateZip64Structures call might result in creation/removal // of extra field if such thing happened we need to move FileItemStream appropriatel _fileItemStream.Move(checked(Offset + _localFileHeader.Size - _fileItemStream.Offset)); _dirtyFlag = true; } #if FALSE // we would like to take this oppportunity and validate basic asumption // that our GetDirtyFlag method is a reliable way to finding changes // there is no scenario in which change will happened, affecting sizes // and will not be registered by the GetDirtyFlag // ??????????????????????? else { // we even willing to recalculate CRC just in case for verification purposes UInt32 calculatedCRC32 = CalculateCrc32(); if (!_localFileHeader.StreamingCreationFlag) { Debug.Assert(_localFileHeader.Crc32 == calculatedCRC32); Debug.Assert(_localFileHeader.CompressedSize == CompressedSize); Debug.Assert(_localFileHeader.UncompressedSize == UncompressedSize); } else { Debug.Assert(_localFileDataDescriptor.Crc32 == calculatedCRC32); Debug.Assert(_localFileDataDescriptor.CompressedSize == CompressedSize); Debug.Assert(_localFileDataDescriptor.UncompressedSize == UncompressedSize); } /////////////////////////////////////////////////////////////////////// // we do not have an initialized value for the compressed size in this case compressedSize = _fileItemStream.Length; Debug.Assert(CompressedSize == compressedSize); Debug.Assert(UncompressedSize == uncompressedSize); } #endif } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { CheckDisposed(); // local file header and data descryptor are completely cached // we only need to worry about the actual data return _fileItemStream.PreSaveNotification(offset, size); } ////// Dispose pattern - required implementation for classes that introduce IDisposable /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // not strictly necessary, but if we ever have a subclass with a finalizer, this will be more efficient } //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ internal static ZipIOLocalFileBlock SeekableLoad (ZipIOBlockManager blockManager, string fileName) { Debug.Assert(!blockManager.Streaming); Debug.Assert(blockManager.CentralDirectoryBlock.FileExists(fileName)); // Get info from the central directory ZipIOCentralDirectoryBlock centralDir = blockManager.CentralDirectoryBlock; ZipIOCentralDirectoryFileHeader centralDirFileHeader = centralDir.GetCentralDirectoryFileHeader(fileName); long localHeaderOffset = centralDirFileHeader.OffsetOfLocalHeader; bool folderFlag = centralDirFileHeader.FolderFlag; bool volumeLabelFlag = centralDirFileHeader.VolumeLabelFlag; blockManager.Stream.Seek(localHeaderOffset, SeekOrigin.Begin); ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, folderFlag, volumeLabelFlag); block.ParseRecord( blockManager.BinaryReader, fileName, localHeaderOffset, centralDir, centralDirFileHeader); return block; } internal static ZipIOLocalFileBlock CreateNew(ZipIOBlockManager blockManager, string fileName, CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption) { //this should be ensured by the higher levels Debug.Assert(Enum.IsDefined(typeof(CompressionMethodEnum), compressionMethod)); Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), deflateOption)); ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, false, false); block._localFileHeader = ZipIOLocalFileHeader.CreateNew (fileName, blockManager.Encoding, compressionMethod, deflateOption, blockManager.Streaming); // if in streaming mode - force to Zip64 mode in case the streams get large if (blockManager.Streaming) { block._localFileDataDescriptor = ZipIOLocalFileDataDescriptor.CreateNew(); } block._offset = 0; // intial value, that is not too important for the brand new File item block._dirtyFlag = true; block._fileItemStream = new ZipIOFileItemStream(blockManager, block, block._offset + block._localFileHeader.Size, 0); // create deflate wrapper if necessary if (compressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(block._fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); // Pass bool to indicate that this stream is "new" and must be dirty so that // the valid empty deflate stream is emitted (2-byte sequence - see CompressStream for details). block._deflateStream = new CompressStream(block._fileItemStream, 0, true); block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._deflateStream); } else { block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._fileItemStream); } return block; } internal Stream GetStream(FileMode mode, FileAccess access) { CheckDisposed(); // the main stream held by block Manager must be compatible with the request CheckFileAccessParameter(_blockManager.Stream, access); // validate mode and Access switch(mode) { case FileMode.Create: // Check to make sure that stream isn't read only if (!_blockManager.Stream.CanWrite) { throw new InvalidOperationException(SR.Get(SRID.CanNotWriteInReadOnlyMode)); } if (_crcCalculatingStream != null && !_blockManager.Streaming) { _crcCalculatingStream.SetLength(0); } break; case FileMode.Open: break; case FileMode.OpenOrCreate: break; case FileMode.CreateNew: // because we deal with the GetStream call CreateNew is a really strange // request, as the FileInfo is already there throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "CreateNew")); case FileMode.Append: throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Append")); case FileMode.Truncate: throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Truncate")); default: throw new ArgumentOutOfRangeException("mode"); } // Streaming mode: always return the same stream (if it exists already) Stream exposedStream; if (_blockManager.Streaming && _exposedPublicStreams != null && _exposedPublicStreams.Count > 0) { Debug.Assert(_exposedPublicStreams.Count == 1, "Should only be one stream returned in streaming mode"); exposedStream = (Stream)_exposedPublicStreams[0]; } else { Debug.Assert((!_blockManager.Streaming) || (_exposedPublicStreams == null), "Should be first and only stream returned in streaming mode"); exposedStream = new ZipIOModeEnforcingStream(_crcCalculatingStream, access, _blockManager, this); RegisterExposedStream(exposedStream); } return exposedStream; } // NOTE: This method should NOT be called anywhere else except from ZipIOModeEnforcingStream.Dispose(bool) // This is not designed to be the part of the cyclic process of flushing internal void DeregisterExposedStream(Stream exposedStream) { Debug.Assert(_exposedPublicStreams != null); _exposedPublicStreams.Remove(exposedStream); } ////// Throwes exception if object already Disposed/Closed. This is the only internal /// (and not private CheckDisposed method). It ismade internal for ZipFileInfo to call /// internal void CheckDisposed() { if (_disposedFlag) { throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); } } //----------------------------------------------------- // // Internal Properties // //----------------------------------------------------- internal UInt16 VersionNeededToExtract { get { CheckDisposed(); return _localFileHeader.VersionNeededToExtract; } } internal UInt16 GeneralPurposeBitFlag { get { CheckDisposed(); return _localFileHeader.GeneralPurposeBitFlag; } } internal CompressionMethodEnum CompressionMethod { get { CheckDisposed(); return _localFileHeader.CompressionMethod; } } internal UInt32 LastModFileDateTime { get { CheckDisposed(); return _localFileHeader.LastModFileDateTime; } } ////// Return stale CRC value stored in the header. /// This property doesn't flush streams nor does it recalculates CRC BY DESIGN /// all updates and revcalculations should be made as a part of the UpdateReferences function /// which is called by the BlockManager.Save /// internal UInt32 Crc32 { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.Crc32; } else { return _localFileHeader.Crc32; } } } ////// Return stale Compressed Size based on the local file header /// This property doesn't flush streams, so it is possible that /// this value will be out of date if Updatereferences isn't /// called before getting this property /// internal long CompressedSize { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.CompressedSize; } else { return _localFileHeader.CompressedSize; } } } ////// Return possibly stale Uncompressed Size based on the local file header /// This property doesn't flush streams, so it is possible that /// this value will be out of date if Updatereferences isn't /// called before getting this property /// internal long UncompressedSize { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.UncompressedSize; } else { return _localFileHeader.UncompressedSize; } } } internal DeflateOptionEnum DeflateOption { get { CheckDisposed(); return _localFileHeader.DeflateOption; } } internal string FileName { get { CheckDisposed(); return _localFileHeader.FileName; } } internal bool FolderFlag { get { CheckDisposed(); return _folderFlag; } } internal bool VolumeLabelFlag { get { CheckDisposed(); return _volumeLabelFlag; } } //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ ////// Dispose(bool) /// /// protected virtual void Dispose(bool disposing) { if (disposing) { // multiple calls are fine - just ignore them if (!_disposedFlag) { try { // close all the public streams that have been exposed CloseExposedStreams(); _crcCalculatingStream.Close(); if (_deflateStream != null) _deflateStream.Close(); _fileItemStream.Close(); } finally { _disposedFlag = true; _crcCalculatingStream = null; _deflateStream = null; _fileItemStream = null; } } } } //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ private ZipIOLocalFileBlock(ZipIOBlockManager blockManager, bool folderFlag, bool volumeLabelFlag) { _blockManager = blockManager; _folderFlag = folderFlag; _volumeLabelFlag = volumeLabelFlag; } private void ParseRecord (BinaryReader reader, string fileName, long position, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); _localFileHeader = ZipIOLocalFileHeader.ParseRecord(reader, _blockManager.Encoding); // Let's find out whether local file descriptor is there or not if (_localFileHeader.StreamingCreationFlag) { // seek forward by the uncompressed size _blockManager.Stream.Seek(centralDirFileHeader.CompressedSize, SeekOrigin.Current); _localFileDataDescriptor = ZipIOLocalFileDataDescriptor.ParseRecord(reader, centralDirFileHeader.CompressedSize, centralDirFileHeader.UncompressedSize, centralDirFileHeader.Crc32, _localFileHeader.VersionNeededToExtract); } else { _localFileDataDescriptor = null; } _offset = position; _dirtyFlag = false; checked { _fileItemStream = new ZipIOFileItemStream(_blockManager, this, position + _localFileHeader.Size, centralDirFileHeader.CompressedSize); } // init deflate stream if necessary if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(_fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); _deflateStream = new CompressStream(_fileItemStream, centralDirFileHeader.UncompressedSize); _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _deflateStream, Crc32); } else if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Stored) { _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _fileItemStream, Crc32); } else { throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); } Validate(fileName, centralDir, centralDirFileHeader); } ////// Validate /// /// pre-trimmed and normalized filename (see ValidateNormalizeFileName) /// central directory block /// file header from central directory private void Validate(string fileName, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { // check that name matches parameter in a case sensitive culture neutral way if (0 != String.CompareOrdinal(_localFileHeader.FileName, fileName)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // compare compressed and uncompressed sizes, crc from central directory if ((VersionNeededToExtract != centralDirFileHeader.VersionNeededToExtract) || (GeneralPurposeBitFlag != centralDirFileHeader.GeneralPurposeBitFlag) || (CompressedSize != centralDirFileHeader.CompressedSize) || (UncompressedSize != centralDirFileHeader.UncompressedSize) || (CompressionMethod != centralDirFileHeader.CompressionMethod) || (Crc32 != centralDirFileHeader.Crc32)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // check for read into central directory (which would indicate file corruption) if (Offset + Size > centralDir.Offset) throw new FileFormatException(SR.Get(SRID.CorruptedData)); // No CRC check here // delay validating the actual CRC until it is possible to do so without additional read operations // This is only for non-streaming mode (at this point we only support creation not consumption) // This is to avoid the forced reading of entire stream just for CRC check // CRC check is delegated to ProgressiveCrcCalculatingStream and CRC is only validated // once calculated CRC is available. This implies that CRC check operation is not // guaranteed to be performed } static private void CheckFileAccessParameter(Stream stream, FileAccess access) { switch(access) { case FileAccess.Read: if (!stream.CanRead) { throw new ArgumentException (SR.Get(SRID.CanNotReadInWriteOnlyMode)); } break; case FileAccess.Write: if (!stream.CanWrite) { throw new ArgumentException (SR.Get(SRID.CanNotWriteInReadOnlyMode)); } break; case FileAccess.ReadWrite: if (!stream.CanRead || !stream.CanWrite) { throw new ArgumentException (SR.Get(SRID.CanNotReadWriteInReadOnlyWriteOnlyMode)); } break; default: throw new ArgumentOutOfRangeException ("access"); } } private void RegisterExposedStream(Stream exposedStream) { if (_exposedPublicStreams == null) { _exposedPublicStreams = new ArrayList(_initialExposedPublicStreamsCollectionSize); } _exposedPublicStreams.Add(exposedStream); } private void CloseExposedStreams() { if (_exposedPublicStreams != null) { for (int i = _exposedPublicStreams.Count - 1; i >= 0; i--) { ZipIOModeEnforcingStream exposedStream = (ZipIOModeEnforcingStream)_exposedPublicStreams[i]; exposedStream.Close(); } } } private void FlushExposedStreams() { // !!! ATTENTION !!!! // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty"; // therefore, there is no need to flush them. Enumerating and flashing those streams has some non-trivial // perf costs. Instead, it is much cheaper to flush the CrcCalculatingStream. // If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to flush // all of the _exposedPublicStreams in this method. _crcCalculatingStream.Flush(); // We are going to walk through the exposed streams and if we can not find any stream that isn't Disposed yet // we will switch deflate stream into Start Mode, by doing this we will achieve 2 goals: // 1. Relieve Memory Pressure in the Sparse Memory Stream // 2. Close Deflate stream in the write through mode and get the tail bytes (we can only get them if // we close Deflate stream). This way we can make the disk layout of the File Items that are closed final. if ((_deflateStream != null) && (!_localFileHeader.StreamingCreationFlag)) { if ((_exposedPublicStreams == null) ||(_exposedPublicStreams.Count == 0)) { ((CompressStream)_deflateStream).Reset(); } } } private const int _initialExposedPublicStreamsCollectionSize= 5; private ZipIOFileItemStream _fileItemStream; private Stream _deflateStream; // may be null - only used if stream is Deflated // _crcCalculatingStream is used to do optimal CRC calcuation when it is possible. // This stream can wrap either _fileItemStream or _deflateStream // For CRC to be calculated correctly, all regualar stream operations have to // go through this stream. This means file item streams we hand out to a client // need to be wrapped as ProgressiveCrcCalculatingStream. // Any other operations specific to ZipIOFileItemStream or DeflateStream should // be directed to those streams. private ProgressiveCrcCalculatingStream _crcCalculatingStream; private ArrayList _exposedPublicStreams; private ZipIOLocalFileHeader _localFileHeader = null; private bool _localFileHeaderSaved; // only used in Streaming mode private ZipIOLocalFileDataDescriptor _localFileDataDescriptor = null; private ZipIOBlockManager _blockManager; private long _offset; // This is a shallow dirtyFlag which doesn't account for the substructures // (ModeEnforcing Streams, compression stream FileItem Stream ) // GetDirtyFlag method is supposed to be used everywhere where a // complete (deep ; non-shallow) check for "dirty" is required; private bool _dirtyFlag; private bool _disposedFlag = false; private bool _folderFlag = false; private bool _volumeLabelFlag = false; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ //------------- *** WARNING *** //------------- This file is part of a legally monitored development project. //------------- Do not check in changes to this project. Do not raid bugs on this //------------- code in the main PS database. Do not contact the owner of this //------------- code directly. Contact the legal team at ‘ZSLegal’ for assistance. //------------- *** WARNING *** //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This is an internal class that enables interactions with Zip archives // for OPC scenarios // // History: // 11/19/2004: IgorBel: Initial creation. // 10/21/2005: brucemac: Apply security mitigations // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Runtime.Serialization; using System.Globalization; using System.Windows; using MS.Internal.IO.Packaging; // For CompressStream namespace MS.Internal.IO.Zip { internal class ZipIOLocalFileBlock : IZipIOBlock, IDisposable { //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- // standard IZipIOBlock functionality public long Offset { get { CheckDisposed(); return _offset; } } public long Size { get { CheckDisposed(); checked { long size = _localFileHeader.Size + _fileItemStream.Length; if (_localFileDataDescriptor != null) { // we only account for the data descriptor // if it is there and data wasn't changed yet , // because we will discard it as a part of saving size += _localFileDataDescriptor.Size; } return size; } } } public bool GetDirtyFlag(bool closingFlag) { CheckDisposed(); bool deflateStreamDirty = false; if (_deflateStream != null) deflateStreamDirty = ((CompressStream) _deflateStream).IsDirty(closingFlag); // !!! ATTENTION !!!! // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty". // In the past we had Dirty flag on the ZipIoModeEnforcing stream that was always false. Enumerating // those flags had significant perf cost (allocating all the Enumerator classes). We are removing Dirty flag // from the ZipIoModeEnforcingStream and all the processing code associated with that. //If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to // reintroduce Dirty state/flag and properly account for this value in the ZipIoLocalFileBlock.DirtyFlag. return _dirtyFlag || _fileItemStream.DirtyFlag || deflateStreamDirty; } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ public void Move(long shiftSize) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); if (shiftSize != 0) { checked{_offset +=shiftSize;} _fileItemStream.Move(shiftSize); _dirtyFlag = true; Debug.Assert(_offset >=0); } } ////// Streaming-specific variant of Save() /// /// internal void SaveStreaming(bool closingFlag) { CheckDisposed(); Debug.Assert(_blockManager.Streaming, "Only legal in Streaming mode"); if (GetDirtyFlag(closingFlag)) { BinaryWriter writer = _blockManager.BinaryWriter; // write the local file header if not already done so if (!_localFileHeaderSaved) { // our first access to the ArchiveStream - note our offset _offset = _blockManager.Stream.Position; _localFileHeader.Save(writer); _localFileHeaderSaved = true; } FlushExposedStreams(); //this will cause the actual write to disk, and it safe to do so, // because all we're in streaming mode and there is // no data in the way _fileItemStream.SaveStreaming(); // Data Descriptor required for streaming mode if (closingFlag) { // now prior to possibly closing streams we need to preserve uncompressed Size // otherwise Length function will fail to give it to us later after closing _localFileDataDescriptor.UncompressedSize = _crcCalculatingStream.Length; // calculate CRC prior to closing _localFileDataDescriptor.Crc32 = _crcCalculatingStream.CalculateCrc(); // If we are closing we can do extra things , calculate CRC , close deflate stream // it is particularly important to close the deflate stream as it might hold some extra bytes // even after Flush() // close outstanding streams to signal that we need new pieces if more data comes CloseExposedStreams(); // in order to get proper compressed size we have to close the deflate stream if (_deflateStream != null) { _deflateStream.Close(); _fileItemStream.SaveStreaming(); // get the extra bytes emitted by the DeflateStream } _localFileDataDescriptor.CompressedSize = _fileItemStream.Length; _localFileDataDescriptor.Save(writer); _dirtyFlag = false; } } } ////// Save() /// public void Save() { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); // Note: This triggers a call to UpdateReferences() which will // discard any _localFileDataDescriptor. if (GetDirtyFlag(true)) // if we do not have closingFlag value (we should be using closingFlag=true as a more conservative approach) { // We need to notify the _fileItemStream that we about to save our FileHeader; // otherwise we might be overriding some of the FileItemStream data with the // FileHeader. Specifically we are concerned about scenario when a previous // block become large by just a couple of bytes, so that the PreSaveNotification // issued prior to saving the previous block didn’t trigger caching of our FileItemStream, // but we still need to make sure that the current FileHeader will not override any data // in our FileItemStream. _fileItemStream.PreSaveNotification(_offset, _localFileHeader.Size); //position the stream BinaryWriter writer = _blockManager.BinaryWriter; if (_blockManager.Stream.Position != _offset) { // we need to seek _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } _localFileHeader.Save(writer); //this will cause the actual write to disk, and it safe to do so, // because all overlapping data was moved out of the way // by the calling BlockManager _fileItemStream.Save(); _dirtyFlag = false; } } // !!! ATTENTION !!!! This function is only supposed to be called by // Block Manager.Save which has proper protection to ensure no stack overflow will happen // as a result of Stream.Flush calls which in turn result in BlockManager.Save calls public void UpdateReferences(bool closingFlag) { Invariant.Assert(!_blockManager.Streaming); long uncompressedSize; long compressedSize; CheckDisposed(); if (closingFlag) { CloseExposedStreams(); } else { FlushExposedStreams(); } // At this point we can update Local Headers with the proper CRC Value // We can also update other Local File Header Values (compressed/uncompressed size) // we rely on our DirtyFlag property to properly account for all possbile modifications within streams if (GetDirtyFlag(closingFlag)) { // Remember the size of the header before update long headerSizeBeforeUpdate = _localFileHeader.Size; // now prior to possibly closing streams we need to preserve uncompressed Size // otherwise Length function will fail to give it to us later after closing uncompressedSize = _crcCalculatingStream.Length; // calculate CRC prior to closing _localFileHeader.Crc32 = _crcCalculatingStream.CalculateCrc(); // If we are closing we can do extra things , calculate CRC , close deflate stream // it is particularly important to close the deflate stream as it might hold some extra bytes // even after Flush() if (closingFlag) { // we have got the CRC so we can close the stream _crcCalculatingStream.Close(); // in order to get proper compressed size we have to close the deflate stream if (_deflateStream != null) { _deflateStream.Close(); } } if (_fileItemStream.DataChanged) { _localFileHeader.LastModFileDateTime = ZipIOBlockManager.ToMsDosDateTime(DateTime.Now); } // get compressed size after possible closing Deflated stream // as a result of some ineffeciencies in CRC calculation it might result in Seek in compressed stream // and there fore switching mode and flushing extra compressed bytes compressedSize = _fileItemStream.Length; // this will properly (taking into account ZIP64 scenario) update local file header // Offset is passed in to determine whether ZIP 64 is required for small files that // happened to be located required 32 bit offset in the archive _localFileHeader.UpdateZip64Structures(compressedSize, uncompressedSize, Offset); // Add/remove padding to compensate the header size change // NOTE: Padding needs to be updated only after updating all the header fields // that can affect the header size _localFileHeader.UpdatePadding(_localFileHeader.Size - headerSizeBeforeUpdate); // We always save File Items in Non-streaming mode unless it wasn't touched //in which case we leave them alone _localFileHeader.StreamingCreationFlag = false; _localFileDataDescriptor = null; // in some cases UpdateZip64Structures call might result in creation/removal // of extra field if such thing happened we need to move FileItemStream appropriatel _fileItemStream.Move(checked(Offset + _localFileHeader.Size - _fileItemStream.Offset)); _dirtyFlag = true; } #if FALSE // we would like to take this oppportunity and validate basic asumption // that our GetDirtyFlag method is a reliable way to finding changes // there is no scenario in which change will happened, affecting sizes // and will not be registered by the GetDirtyFlag // ??????????????????????? else { // we even willing to recalculate CRC just in case for verification purposes UInt32 calculatedCRC32 = CalculateCrc32(); if (!_localFileHeader.StreamingCreationFlag) { Debug.Assert(_localFileHeader.Crc32 == calculatedCRC32); Debug.Assert(_localFileHeader.CompressedSize == CompressedSize); Debug.Assert(_localFileHeader.UncompressedSize == UncompressedSize); } else { Debug.Assert(_localFileDataDescriptor.Crc32 == calculatedCRC32); Debug.Assert(_localFileDataDescriptor.CompressedSize == CompressedSize); Debug.Assert(_localFileDataDescriptor.UncompressedSize == UncompressedSize); } /////////////////////////////////////////////////////////////////////// // we do not have an initialized value for the compressed size in this case compressedSize = _fileItemStream.Length; Debug.Assert(CompressedSize == compressedSize); Debug.Assert(UncompressedSize == uncompressedSize); } #endif } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { CheckDisposed(); // local file header and data descryptor are completely cached // we only need to worry about the actual data return _fileItemStream.PreSaveNotification(offset, size); } ////// Dispose pattern - required implementation for classes that introduce IDisposable /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // not strictly necessary, but if we ever have a subclass with a finalizer, this will be more efficient } //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ internal static ZipIOLocalFileBlock SeekableLoad (ZipIOBlockManager blockManager, string fileName) { Debug.Assert(!blockManager.Streaming); Debug.Assert(blockManager.CentralDirectoryBlock.FileExists(fileName)); // Get info from the central directory ZipIOCentralDirectoryBlock centralDir = blockManager.CentralDirectoryBlock; ZipIOCentralDirectoryFileHeader centralDirFileHeader = centralDir.GetCentralDirectoryFileHeader(fileName); long localHeaderOffset = centralDirFileHeader.OffsetOfLocalHeader; bool folderFlag = centralDirFileHeader.FolderFlag; bool volumeLabelFlag = centralDirFileHeader.VolumeLabelFlag; blockManager.Stream.Seek(localHeaderOffset, SeekOrigin.Begin); ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, folderFlag, volumeLabelFlag); block.ParseRecord( blockManager.BinaryReader, fileName, localHeaderOffset, centralDir, centralDirFileHeader); return block; } internal static ZipIOLocalFileBlock CreateNew(ZipIOBlockManager blockManager, string fileName, CompressionMethodEnum compressionMethod, DeflateOptionEnum deflateOption) { //this should be ensured by the higher levels Debug.Assert(Enum.IsDefined(typeof(CompressionMethodEnum), compressionMethod)); Debug.Assert(Enum.IsDefined(typeof(DeflateOptionEnum), deflateOption)); ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, false, false); block._localFileHeader = ZipIOLocalFileHeader.CreateNew (fileName, blockManager.Encoding, compressionMethod, deflateOption, blockManager.Streaming); // if in streaming mode - force to Zip64 mode in case the streams get large if (blockManager.Streaming) { block._localFileDataDescriptor = ZipIOLocalFileDataDescriptor.CreateNew(); } block._offset = 0; // intial value, that is not too important for the brand new File item block._dirtyFlag = true; block._fileItemStream = new ZipIOFileItemStream(blockManager, block, block._offset + block._localFileHeader.Size, 0); // create deflate wrapper if necessary if (compressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(block._fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); // Pass bool to indicate that this stream is "new" and must be dirty so that // the valid empty deflate stream is emitted (2-byte sequence - see CompressStream for details). block._deflateStream = new CompressStream(block._fileItemStream, 0, true); block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._deflateStream); } else { block._crcCalculatingStream = new ProgressiveCrcCalculatingStream(blockManager, block._fileItemStream); } return block; } internal Stream GetStream(FileMode mode, FileAccess access) { CheckDisposed(); // the main stream held by block Manager must be compatible with the request CheckFileAccessParameter(_blockManager.Stream, access); // validate mode and Access switch(mode) { case FileMode.Create: // Check to make sure that stream isn't read only if (!_blockManager.Stream.CanWrite) { throw new InvalidOperationException(SR.Get(SRID.CanNotWriteInReadOnlyMode)); } if (_crcCalculatingStream != null && !_blockManager.Streaming) { _crcCalculatingStream.SetLength(0); } break; case FileMode.Open: break; case FileMode.OpenOrCreate: break; case FileMode.CreateNew: // because we deal with the GetStream call CreateNew is a really strange // request, as the FileInfo is already there throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "CreateNew")); case FileMode.Append: throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Append")); case FileMode.Truncate: throw new ArgumentException(SR.Get(SRID.FileModeUnsupported, "Truncate")); default: throw new ArgumentOutOfRangeException("mode"); } // Streaming mode: always return the same stream (if it exists already) Stream exposedStream; if (_blockManager.Streaming && _exposedPublicStreams != null && _exposedPublicStreams.Count > 0) { Debug.Assert(_exposedPublicStreams.Count == 1, "Should only be one stream returned in streaming mode"); exposedStream = (Stream)_exposedPublicStreams[0]; } else { Debug.Assert((!_blockManager.Streaming) || (_exposedPublicStreams == null), "Should be first and only stream returned in streaming mode"); exposedStream = new ZipIOModeEnforcingStream(_crcCalculatingStream, access, _blockManager, this); RegisterExposedStream(exposedStream); } return exposedStream; } // NOTE: This method should NOT be called anywhere else except from ZipIOModeEnforcingStream.Dispose(bool) // This is not designed to be the part of the cyclic process of flushing internal void DeregisterExposedStream(Stream exposedStream) { Debug.Assert(_exposedPublicStreams != null); _exposedPublicStreams.Remove(exposedStream); } ////// Throwes exception if object already Disposed/Closed. This is the only internal /// (and not private CheckDisposed method). It ismade internal for ZipFileInfo to call /// internal void CheckDisposed() { if (_disposedFlag) { throw new ObjectDisposedException(null, SR.Get(SRID.ZipFileItemDisposed)); } } //----------------------------------------------------- // // Internal Properties // //----------------------------------------------------- internal UInt16 VersionNeededToExtract { get { CheckDisposed(); return _localFileHeader.VersionNeededToExtract; } } internal UInt16 GeneralPurposeBitFlag { get { CheckDisposed(); return _localFileHeader.GeneralPurposeBitFlag; } } internal CompressionMethodEnum CompressionMethod { get { CheckDisposed(); return _localFileHeader.CompressionMethod; } } internal UInt32 LastModFileDateTime { get { CheckDisposed(); return _localFileHeader.LastModFileDateTime; } } ////// Return stale CRC value stored in the header. /// This property doesn't flush streams nor does it recalculates CRC BY DESIGN /// all updates and revcalculations should be made as a part of the UpdateReferences function /// which is called by the BlockManager.Save /// internal UInt32 Crc32 { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.Crc32; } else { return _localFileHeader.Crc32; } } } ////// Return stale Compressed Size based on the local file header /// This property doesn't flush streams, so it is possible that /// this value will be out of date if Updatereferences isn't /// called before getting this property /// internal long CompressedSize { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.CompressedSize; } else { return _localFileHeader.CompressedSize; } } } ////// Return possibly stale Uncompressed Size based on the local file header /// This property doesn't flush streams, so it is possible that /// this value will be out of date if Updatereferences isn't /// called before getting this property /// internal long UncompressedSize { get { CheckDisposed(); if (_localFileHeader.StreamingCreationFlag) { Invariant.Assert(_localFileDataDescriptor != null); return _localFileDataDescriptor.UncompressedSize; } else { return _localFileHeader.UncompressedSize; } } } internal DeflateOptionEnum DeflateOption { get { CheckDisposed(); return _localFileHeader.DeflateOption; } } internal string FileName { get { CheckDisposed(); return _localFileHeader.FileName; } } internal bool FolderFlag { get { CheckDisposed(); return _folderFlag; } } internal bool VolumeLabelFlag { get { CheckDisposed(); return _volumeLabelFlag; } } //----------------------------------------------------- // // Protected Methods // //------------------------------------------------------ ////// Dispose(bool) /// /// protected virtual void Dispose(bool disposing) { if (disposing) { // multiple calls are fine - just ignore them if (!_disposedFlag) { try { // close all the public streams that have been exposed CloseExposedStreams(); _crcCalculatingStream.Close(); if (_deflateStream != null) _deflateStream.Close(); _fileItemStream.Close(); } finally { _disposedFlag = true; _crcCalculatingStream = null; _deflateStream = null; _fileItemStream = null; } } } } //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ private ZipIOLocalFileBlock(ZipIOBlockManager blockManager, bool folderFlag, bool volumeLabelFlag) { _blockManager = blockManager; _folderFlag = folderFlag; _volumeLabelFlag = volumeLabelFlag; } private void ParseRecord (BinaryReader reader, string fileName, long position, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); _localFileHeader = ZipIOLocalFileHeader.ParseRecord(reader, _blockManager.Encoding); // Let's find out whether local file descriptor is there or not if (_localFileHeader.StreamingCreationFlag) { // seek forward by the uncompressed size _blockManager.Stream.Seek(centralDirFileHeader.CompressedSize, SeekOrigin.Current); _localFileDataDescriptor = ZipIOLocalFileDataDescriptor.ParseRecord(reader, centralDirFileHeader.CompressedSize, centralDirFileHeader.UncompressedSize, centralDirFileHeader.Crc32, _localFileHeader.VersionNeededToExtract); } else { _localFileDataDescriptor = null; } _offset = position; _dirtyFlag = false; checked { _fileItemStream = new ZipIOFileItemStream(_blockManager, this, position + _localFileHeader.Size, centralDirFileHeader.CompressedSize); } // init deflate stream if necessary if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(_fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); _deflateStream = new CompressStream(_fileItemStream, centralDirFileHeader.UncompressedSize); _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _deflateStream, Crc32); } else if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Stored) { _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _fileItemStream, Crc32); } else { throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); } Validate(fileName, centralDir, centralDirFileHeader); } ////// Validate /// /// pre-trimmed and normalized filename (see ValidateNormalizeFileName) /// central directory block /// file header from central directory private void Validate(string fileName, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { // check that name matches parameter in a case sensitive culture neutral way if (0 != String.CompareOrdinal(_localFileHeader.FileName, fileName)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // compare compressed and uncompressed sizes, crc from central directory if ((VersionNeededToExtract != centralDirFileHeader.VersionNeededToExtract) || (GeneralPurposeBitFlag != centralDirFileHeader.GeneralPurposeBitFlag) || (CompressedSize != centralDirFileHeader.CompressedSize) || (UncompressedSize != centralDirFileHeader.UncompressedSize) || (CompressionMethod != centralDirFileHeader.CompressionMethod) || (Crc32 != centralDirFileHeader.Crc32)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // check for read into central directory (which would indicate file corruption) if (Offset + Size > centralDir.Offset) throw new FileFormatException(SR.Get(SRID.CorruptedData)); // No CRC check here // delay validating the actual CRC until it is possible to do so without additional read operations // This is only for non-streaming mode (at this point we only support creation not consumption) // This is to avoid the forced reading of entire stream just for CRC check // CRC check is delegated to ProgressiveCrcCalculatingStream and CRC is only validated // once calculated CRC is available. This implies that CRC check operation is not // guaranteed to be performed } static private void CheckFileAccessParameter(Stream stream, FileAccess access) { switch(access) { case FileAccess.Read: if (!stream.CanRead) { throw new ArgumentException (SR.Get(SRID.CanNotReadInWriteOnlyMode)); } break; case FileAccess.Write: if (!stream.CanWrite) { throw new ArgumentException (SR.Get(SRID.CanNotWriteInReadOnlyMode)); } break; case FileAccess.ReadWrite: if (!stream.CanRead || !stream.CanWrite) { throw new ArgumentException (SR.Get(SRID.CanNotReadWriteInReadOnlyWriteOnlyMode)); } break; default: throw new ArgumentOutOfRangeException ("access"); } } private void RegisterExposedStream(Stream exposedStream) { if (_exposedPublicStreams == null) { _exposedPublicStreams = new ArrayList(_initialExposedPublicStreamsCollectionSize); } _exposedPublicStreams.Add(exposedStream); } private void CloseExposedStreams() { if (_exposedPublicStreams != null) { for (int i = _exposedPublicStreams.Count - 1; i >= 0; i--) { ZipIOModeEnforcingStream exposedStream = (ZipIOModeEnforcingStream)_exposedPublicStreams[i]; exposedStream.Close(); } } } private void FlushExposedStreams() { // !!! ATTENTION !!!! // We know for a fact that ZipIoModeEnforcingStream doesn't perform any buffering and is never "dirty"; // therefore, there is no need to flush them. Enumerating and flashing those streams has some non-trivial // perf costs. Instead, it is much cheaper to flush the CrcCalculatingStream. // If at any point we choose to add some buffering to the ZipIoModeEnforcingStream we will have to flush // all of the _exposedPublicStreams in this method. _crcCalculatingStream.Flush(); // We are going to walk through the exposed streams and if we can not find any stream that isn't Disposed yet // we will switch deflate stream into Start Mode, by doing this we will achieve 2 goals: // 1. Relieve Memory Pressure in the Sparse Memory Stream // 2. Close Deflate stream in the write through mode and get the tail bytes (we can only get them if // we close Deflate stream). This way we can make the disk layout of the File Items that are closed final. if ((_deflateStream != null) && (!_localFileHeader.StreamingCreationFlag)) { if ((_exposedPublicStreams == null) ||(_exposedPublicStreams.Count == 0)) { ((CompressStream)_deflateStream).Reset(); } } } private const int _initialExposedPublicStreamsCollectionSize= 5; private ZipIOFileItemStream _fileItemStream; private Stream _deflateStream; // may be null - only used if stream is Deflated // _crcCalculatingStream is used to do optimal CRC calcuation when it is possible. // This stream can wrap either _fileItemStream or _deflateStream // For CRC to be calculated correctly, all regualar stream operations have to // go through this stream. This means file item streams we hand out to a client // need to be wrapped as ProgressiveCrcCalculatingStream. // Any other operations specific to ZipIOFileItemStream or DeflateStream should // be directed to those streams. private ProgressiveCrcCalculatingStream _crcCalculatingStream; private ArrayList _exposedPublicStreams; private ZipIOLocalFileHeader _localFileHeader = null; private bool _localFileHeaderSaved; // only used in Streaming mode private ZipIOLocalFileDataDescriptor _localFileDataDescriptor = null; private ZipIOBlockManager _blockManager; private long _offset; // This is a shallow dirtyFlag which doesn't account for the substructures // (ModeEnforcing Streams, compression stream FileItem Stream ) // GetDirtyFlag method is supposed to be used everywhere where a // complete (deep ; non-shallow) check for "dirty" is required; private bool _dirtyFlag; private bool _disposedFlag = false; private bool _folderFlag = false; private bool _volumeLabelFlag = false; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Inflater.cs
- MetadataArtifactLoaderComposite.cs
- safelink.cs
- RecordManager.cs
- ThousandthOfEmRealDoubles.cs
- WpfSharedBamlSchemaContext.cs
- OleDbSchemaGuid.cs
- RowToParametersTransformer.cs
- XPathNavigator.cs
- ApplicationFileCodeDomTreeGenerator.cs
- BooleanConverter.cs
- DataRecord.cs
- odbcmetadatafactory.cs
- CmsUtils.cs
- Tag.cs
- IntMinMaxAggregationOperator.cs
- StringPropertyBuilder.cs
- AdCreatedEventArgs.cs
- ObjectComplexPropertyMapping.cs
- VariableBinder.cs
- TogglePattern.cs
- sortedlist.cs
- DataGridViewRowDividerDoubleClickEventArgs.cs
- CroppedBitmap.cs
- MobileControlPersister.cs
- ScaleTransform.cs
- NavigationProgressEventArgs.cs
- HostedHttpContext.cs
- SafePointer.cs
- ServiceRoute.cs
- EmbeddedMailObjectsCollection.cs
- SqlNotificationRequest.cs
- DataGridViewToolTip.cs
- KeySplineConverter.cs
- RemoveStoryboard.cs
- ImmutablePropertyDescriptorGridEntry.cs
- DataSourceControl.cs
- TimelineCollection.cs
- Graph.cs
- HtmlInputImage.cs
- SizeChangedInfo.cs
- TaskFileService.cs
- NativeMethods.cs
- UnsafeNativeMethods.cs
- MailAddressParser.cs
- RouteItem.cs
- PlatformCulture.cs
- GlyphRun.cs
- FontFamilyValueSerializer.cs
- TargetPerspective.cs
- OdbcStatementHandle.cs
- UserPreferenceChangingEventArgs.cs
- ClientUrlResolverWrapper.cs
- ThemeInfoAttribute.cs
- Helper.cs
- DataRelationPropertyDescriptor.cs
- ListDictionary.cs
- TabControlAutomationPeer.cs
- contentDescriptor.cs
- HtmlEmptyTagControlBuilder.cs
- CodeSnippetTypeMember.cs
- CodeArrayIndexerExpression.cs
- ConfigurationManagerInternalFactory.cs
- SafeWaitHandle.cs
- PngBitmapDecoder.cs
- HtmlSelect.cs
- StaticResourceExtension.cs
- DateTimeParse.cs
- TextParagraph.cs
- FixedLineResult.cs
- ProfilePropertySettingsCollection.cs
- NetSectionGroup.cs
- _AuthenticationState.cs
- RegistryPermission.cs
- HashSetEqualityComparer.cs
- TextPointerBase.cs
- VirtualizingStackPanel.cs
- List.cs
- ThreadStateException.cs
- PersonalizationStateInfo.cs
- MouseButton.cs
- QilGeneratorEnv.cs
- DataControlLinkButton.cs
- XhtmlBasicListAdapter.cs
- VSWCFServiceContractGenerator.cs
- CommonRemoteMemoryBlock.cs
- XmlSchemaParticle.cs
- WebPartZoneCollection.cs
- LabelDesigner.cs
- TileBrush.cs
- DynamicResourceExtension.cs
- Bidi.cs
- Queue.cs
- SyndicationSerializer.cs
- ObjectToIdCache.cs
- ObservableDictionary.cs
- ScrollItemPatternIdentifiers.cs
- MsmqIntegrationReceiveParameters.cs
- PieceNameHelper.cs
- TemplateComponentConnector.cs