Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / 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
- TimeZoneInfo.cs
- GroupByExpressionRewriter.cs
- ValidationHelpers.cs
- GraphicsContainer.cs
- UIElement3D.cs
- PolygonHotSpot.cs
- CatalogPart.cs
- XmlTypeMapping.cs
- AutomationPropertyInfo.cs
- SamlAuthorizationDecisionStatement.cs
- SchemaImporterExtension.cs
- ConfigUtil.cs
- X509ChainPolicy.cs
- NeedSkipTokenVisitor.cs
- PagedDataSource.cs
- HtmlUtf8RawTextWriter.cs
- ServiceDiscoveryBehavior.cs
- AssociatedControlConverter.cs
- BufferedOutputStream.cs
- UrlRoutingHandler.cs
- HelloOperationCD1AsyncResult.cs
- StyleCollection.cs
- TraceInternal.cs
- UmAlQuraCalendar.cs
- WSSecurityPolicy11.cs
- ButtonBaseAdapter.cs
- ReachDocumentSequenceSerializer.cs
- PageThemeParser.cs
- PopupRoot.cs
- StateMachineWorkflowDesigner.cs
- SqlUtil.cs
- ListViewContainer.cs
- ArcSegment.cs
- TableLayoutSettings.cs
- ResizeGrip.cs
- XmlSchemaAttribute.cs
- MatrixTransform3D.cs
- RadioButton.cs
- DataFormats.cs
- CircleHotSpot.cs
- KeyEventArgs.cs
- AlternateViewCollection.cs
- Rotation3D.cs
- PersonalizationAdministration.cs
- LogExtent.cs
- CompensationParticipant.cs
- NumericExpr.cs
- SourceInterpreter.cs
- CompoundFileIOPermission.cs
- InlinedAggregationOperator.cs
- CollectionChangeEventArgs.cs
- EntityDataSourceWizardForm.cs
- GridViewColumnHeader.cs
- DetailsViewDesigner.cs
- SafeNativeMethods.cs
- ResetableIterator.cs
- IncrementalReadDecoders.cs
- MultiView.cs
- CompilerTypeWithParams.cs
- SafeRegistryHandle.cs
- DataGridViewTextBoxColumn.cs
- CodeVariableReferenceExpression.cs
- LinkLabel.cs
- TransactionScopeDesigner.cs
- WebRequestModuleElement.cs
- StringValueSerializer.cs
- HttpConfigurationSystem.cs
- CatalogPart.cs
- SpecularMaterial.cs
- QueryException.cs
- AspCompat.cs
- _IPv4Address.cs
- SecurityRequiresReviewAttribute.cs
- AbstractSvcMapFileLoader.cs
- DocComment.cs
- CodeLabeledStatement.cs
- securestring.cs
- AddInEnvironment.cs
- PeerChannelFactory.cs
- FormViewDeleteEventArgs.cs
- ObjectQueryState.cs
- HtmlTableRowCollection.cs
- RedistVersionInfo.cs
- LiteralTextContainerControlBuilder.cs
- Normalizer.cs
- NavigationWindow.cs
- SmuggledIUnknown.cs
- DirectoryInfo.cs
- XComponentModel.cs
- WebPartRestoreVerb.cs
- FormsAuthenticationUserCollection.cs
- ErrorHandler.cs
- QueryResponse.cs
- ItemAutomationPeer.cs
- SqlBulkCopy.cs
- NavigationProperty.cs
- EmptyStringExpandableObjectConverter.cs
- EditorBrowsableAttribute.cs
- InternalTypeHelper.cs
- ProtectedConfiguration.cs