Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / IO / Zip / ZipIOCentralDirectoryBlock.cs / 1 / ZipIOCentralDirectoryBlock.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. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Collections.Specialized; // OrderedDictionary using System.Globalization; using System.Windows; namespace MS.Internal.IO.Zip { internal class ZipIOCentralDirectoryBlock : IZipIOBlock { //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- // standard IZipIOBlock functionality public long Offset { get { return _offset; } } public long Size { get { long result = 0; if (CentralDirectoryDictionary.Count > 0) { foreach(ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { checked{result += fileHeader.Size;} } // Zeus PS 3: disable creation/parsing of zip archive digital signatures #if ArchiveSignaturesEnabled if (_centralDirectoryDigitalSignature != null) { checked{result += _centralDirectoryDigitalSignature.Size;} } #endif } return result; } } // This property will only return reliable result if Update is called prior public bool GetDirtyFlag(bool closingFlag) { return _dirtyFlag; } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ public void Move(long shiftSize) { if (shiftSize != 0) { checked{_offset +=shiftSize;} _dirtyFlag = true; Debug.Assert(_offset >=0); } } public void Save() { if (_dirtyFlag) { // Central directory is an optional component of the ZIP Archive // we need to save it if it isn't empty if (CentralDirectoryDictionary.Count > 0) { BinaryWriter writer = _blockManager.BinaryWriter; // Emit entries in the same order as the corresponding file items as this // improves interoperability with tools that expect this convention. // Streaming mode must be handled differently if (_blockManager.Streaming) { // In Streaming mode we cannot rely on the order that entries were inserted via AddFiles() // as files can be closed in different order than they are added. // NOTE: Neither ZipIOBlockManager._blockList nor CentralDirectoryDicstionry // are NOT in offset order #if DEBUG long lastOffset = -1; #endif // collect all file headers in central directory into a local list for sorting SortedList blockList = new SortedList(CentralDirectoryDictionary.Count); // We know that in Streaming mode there can be no RawDataFile blocks in // the block list. Therefore, we can emit our headers in the order that they // appear in the block list. foreach (ZipIOCentralDirectoryFileHeader header in CentralDirectoryDictionary.Values) { blockList.Add(header.OffsetOfLocalHeader, header); } // then write out the files headers for central directory in sorted order foreach (ZipIOCentralDirectoryFileHeader header in blockList.Values) { header.Save(writer); #if DEBUG Debug.Assert(lastOffset < header.OffsetOfLocalHeader, "Sort order violated"); lastOffset = header.OffsetOfLocalHeader; #endif } } else { // Non-streaming mode - CentralDirectoryDictionary has correct order. // Assume correct location if streaming - otherwise explicitly seek. if (_blockManager.Stream.Position != _offset) { // we need to seek _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } // Save the headers in the order they were added as this matches the physical offsets foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { fileHeader.Save(writer); } } // Zeus PS 3: disable creation/parsing of zip archive digital signatures #if ArchiveSignaturesEnabled //central directory dig sig is optional if (_centralDirectoryDigitalSignature != null) { _centralDirectoryDigitalSignature.Save(writer); } #endif writer.Flush(); } _dirtyFlag = false; } } public void UpdateReferences(bool closingFlag) { // we just need to ask Block Manager for the new Values for each header // there are 2 distinct cases here // 1. local file data is mapped . loaded and might have been changed in size and position // 2. local file data is not loaded and might have been changed only in position (not in size) foreach(IZipIOBlock block in _blockManager) { ZipIOLocalFileBlock localFileBlock = block as ZipIOLocalFileBlock; ZipIORawDataFileBlock rawDataFileBlock = block as ZipIORawDataFileBlock; if (localFileBlock != null) { // this is case 1 data is mapped and loaded, so we only need to find the matching // Centraldirectory record and update it Debug.Assert(CentralDirectoryDictionary.Contains(localFileBlock.FileName)); ZipIOCentralDirectoryFileHeader centralDirFileHeader = (ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[localFileBlock.FileName]; if (centralDirFileHeader.UpdateIfNeeded(localFileBlock)) { //update was required let's mark ourselves as dirty _dirtyFlag = true; } } //check whether we deal with raw data block and it was moved else if (rawDataFileBlock != null) { long diskImageShift = rawDataFileBlock.DiskImageShift; if (diskImageShift != 0) { //this is case #2 data isn't loaded based on the shift in the RawData Block // we need to move all overlapping central directory references foreach (ZipIOCentralDirectoryFileHeader centralDirFileHeader in CentralDirectoryDictionary.Values) { // check whether central dir header points into the region of a moved RawDataBlock if (rawDataFileBlock.DiskImageContains(centralDirFileHeader.OffsetOfLocalHeader)) { centralDirFileHeader.MoveReference(diskImageShift); _dirtyFlag = true; } } } } } } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { // we can safely ignore this notification as we do not keep any data // after parsing on disk. Everything is in memory, it is ok to override // original Central directory without any additional backups // we can also safely state that there is no need to continue the PreSafeNotification loop // as all the blocks after the central directory (EOCD, Zip64 ....) do not have // data that is buffered on disk return PreSaveNotificationScanControlInstruction.Stop; } //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ // although Zip 64 supports 64 bit counter for the number of // entries in the central directory, we have chossen to not // support those scenarios and stick wit the basic CLR type // int Collections.Count {get;} internal int Count { get { return CentralDirectoryDictionary.Count; } } //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- internal static ZipIOCentralDirectoryBlock SeekableLoad(ZipIOBlockManager blockManager) { // get proper values from zip 64 records request will be redirected to the // regular EOCD if ZIP 64 record wasn't originated from the parsing ZipIOZip64EndOfCentralDirectoryBlock zip64EOCD = blockManager.Zip64EndOfCentralDirectoryBlock; blockManager.Stream.Seek(zip64EOCD.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); block.ParseRecord(blockManager.BinaryReader, zip64EOCD.OffsetOfStartOfCentralDirectory, zip64EOCD.TotalNumberOfEntriesInTheCentralDirectory, zip64EOCD.SizeOfCentralDirectory); return block; } internal static ZipIOCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) { ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); block._offset = 0; // it just an initial value, that will be adjusted later // it doesn't matter whether this offset overlaps anything or not block._dirtyFlag = true; // this dig sig is optional if we ever wanted to make this record, we would need to call // ZipIOCentralDirectoryDigitalSignature.CreateNew(); block._centralDirectoryDigitalSignature = null; return block; } // This properrty returns current snapsot which might be out of date // if there were changes after parsing or last UpdateReferences call internal bool IsZip64BitRequiredForStoring { get { // These values are duplicated the EndOfCentralDirectory record // and if any of them are to big we need to introduce // Zip64 end of central directory record // Zip64 end of central directory locator return (Count >= UInt16.MaxValue) || (Offset >= UInt32.MaxValue) || (Size >= UInt32.MaxValue); } } internal void AddFileBlock(ZipIOLocalFileBlock fileBlock) { _dirtyFlag = true; ZipIOCentralDirectoryFileHeader fileHeader = ZipIOCentralDirectoryFileHeader.CreateNew (_blockManager.Encoding, fileBlock); CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); } ////// /// /// ///precondition: caller must ensure that fileName exists internal void RemoveFileBlock(string fileName) { _dirtyFlag = true; CentralDirectoryDictionary.Remove(fileName); if (CentralDirectoryDictionary.Count == 0) { // in case of the the last one ,we also need to drop the signature record _centralDirectoryDigitalSignature = null; } } internal bool FileExists(string fileName) { return CentralDirectoryDictionary.Contains(fileName); } // this function should be used carefully as it returns reference to an object // that is owned by CentralDirectoryBlock, and should be used by other classes only // for querying information not for updating it. internal ZipIOCentralDirectoryFileHeader GetCentralDirectoryFileHeader (string fileName) { return ((ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[fileName]); } internal ICollection GetFileNamesCollection() { return CentralDirectoryDictionary.Keys; } //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ private ZipIOCentralDirectoryBlock(ZipIOBlockManager blockManager) { _blockManager = blockManager; } ////// Compare FileOffsets for LocalFileHeaders - used by Sort() routine in ParseRecord /// private class HeaderFileOffsetComparer : IComparer { int IComparer.Compare(object o1, object o2) { ZipIOCentralDirectoryFileHeader h1 = o1 as ZipIOCentralDirectoryFileHeader; ZipIOCentralDirectoryFileHeader h2 = o2 as ZipIOCentralDirectoryFileHeader; Debug.Assert(h1 != null && h2 != null, "HeaderFileOffsetComparer: Comparing the wrong data types"); // avoid boxing - don't cast long value to (IComparable) if (h1.OffsetOfLocalHeader > h2.OffsetOfLocalHeader) return 1; else if (h1.OffsetOfLocalHeader < h2.OffsetOfLocalHeader) return -1; else return 0; } } private void ParseRecord (BinaryReader reader, long centralDirectoryOffset, int centralDirectoryCount, long expectedCentralDirectorySize) { if (centralDirectoryCount > 0) { // collect all headers into a local array list for sorting SortedList headerList = new SortedList(centralDirectoryCount); ZipIOCentralDirectoryFileHeader header; for (int i = 0; i < centralDirectoryCount; i++) { header = ZipIOCentralDirectoryFileHeader.ParseRecord(reader, _blockManager.Encoding); headerList.Add(header.OffsetOfLocalHeader, header); } if (reader.BaseStream.Position - centralDirectoryOffset > expectedCentralDirectorySize) { // it looks like a corrupted file, as we have parsed more than central directory supposed to contain throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // then add to the ordered dictionary in sorted order foreach (ZipIOCentralDirectoryFileHeader fileHeader in headerList.Values) { // at this point fileHeader.FileName is normalized using // the ZipIOBlockManager.ValidateNormalizeFileName CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); } //load central directory [digital signature] - this has nothing to // do with OPC digital signing // this record is optional, and the function might return null _centralDirectoryDigitalSignature = ZipIOCentralDirectoryDigitalSignature.ParseRecord(reader); } _offset = centralDirectoryOffset; _dirtyFlag = false; Validate(expectedCentralDirectorySize); } private void Validate(long expectedCentralDirectorySize) { checked { // We only have information about the Compressed data size and the offset of the // local headers. We do not have information about the size of the local header // which varies depending on the file name and the extra field records size. // (Although we do know the expected size of the file name, there is no way to // predict the extra field size, for example it might have a padding record that we use // optimize Disk IO for ZIP 64 scenarios). // We are going to make sure that Blocks do not overlap each other and do not // overlap Central Directory long checkedMark = 0; foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { if ((checkedMark == 0) && (fileHeader.OffsetOfLocalHeader != 0)) { // first block doesn't start at 0 throw new FileFormatException(SR.Get(SRID.CorruptedData)); } else if (fileHeader.OffsetOfLocalHeader < checkedMark) { // the current block overlaps the previously analyzed block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // we move the checked mark up by the sum of the compressed size file name size // and the fixed minimal Local file header size checkedMark += fileHeader.CompressedSize + ZipIOLocalFileHeader.FixedMinimalRecordSize + fileHeader.FileName.Length; } // now we can ensure that that checked mark didn't reach over the start of the Central directory if (_offset < checkedMark) { // the central directory block overlaps the last file block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } //check the total parsed size of the central directory against value declared in EOCd or ZIP64 EOCD records if (Size != expectedCentralDirectorySize) { // the central directory block overlaps the last file block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // we should also check ofr presence of gaps between // Central Directory // ZIP64 EOCD // ZIP 64 EOCD locator // EOCD // Zip64Eocd and Zip64EocdLocator must be either present or absent together Debug.Assert(! (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) ^ (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size==0)); if (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) { // no ZIP 64 record if (_offset + expectedCentralDirectorySize != _blockManager.EndOfCentralDirectoryBlock.Offset) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } else { // ZIP 64 records present if ((_offset + expectedCentralDirectorySize != _blockManager.Zip64EndOfCentralDirectoryBlock.Offset) || (_blockManager.Zip64EndOfCentralDirectoryBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryBlock.Size != _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset) || (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size != _blockManager.EndOfCentralDirectoryBlock.Offset)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } } } //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ private IDictionary CentralDirectoryDictionary { get { if (_centralDirectoryDictionary == null) { // StringComparer.Ordinal guarantees ordinal, case-sensitive comparison for both cases. // if streaming - order is unimportant for us and we can use the cheaper Hashtable if (_blockManager.Streaming) { // We take our order during Save() from the physical order of the elements of the // block table in BlockManager. _centralDirectoryDictionary = new Hashtable(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); } else { // This ordered dictionary serves two purposes. It allows hash-table lookup by file name // and it also maintains the physical order of the blocks on disk. Like any OrderedDictionary, // any of the enumerator, or integer indexer will return the items in the order that they were added. _centralDirectoryDictionary = new OrderedDictionary(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); } } return _centralDirectoryDictionary; } } //------------------------------------------------------ // // Private Members // //----------------------------------------------------- private const int _centralDirectoryDictionaryInitialSize = 50; // used in Parse private static IComparer _headerOffsetComparer = new HeaderFileOffsetComparer(); // This may be a HashTable (Streaming case) or an OrderedDictionary - see private property // for explanation. private IDictionary _centralDirectoryDictionary; private ZipIOCentralDirectoryDigitalSignature _centralDirectoryDigitalSignature; private ZipIOBlockManager _blockManager; private long _offset; private bool _dirtyFlag; } } // 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. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Text; using System.Collections; using System.Collections.Specialized; // OrderedDictionary using System.Globalization; using System.Windows; namespace MS.Internal.IO.Zip { internal class ZipIOCentralDirectoryBlock : IZipIOBlock { //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- // standard IZipIOBlock functionality public long Offset { get { return _offset; } } public long Size { get { long result = 0; if (CentralDirectoryDictionary.Count > 0) { foreach(ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { checked{result += fileHeader.Size;} } // Zeus PS 3: disable creation/parsing of zip archive digital signatures #if ArchiveSignaturesEnabled if (_centralDirectoryDigitalSignature != null) { checked{result += _centralDirectoryDigitalSignature.Size;} } #endif } return result; } } // This property will only return reliable result if Update is called prior public bool GetDirtyFlag(bool closingFlag) { return _dirtyFlag; } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ public void Move(long shiftSize) { if (shiftSize != 0) { checked{_offset +=shiftSize;} _dirtyFlag = true; Debug.Assert(_offset >=0); } } public void Save() { if (_dirtyFlag) { // Central directory is an optional component of the ZIP Archive // we need to save it if it isn't empty if (CentralDirectoryDictionary.Count > 0) { BinaryWriter writer = _blockManager.BinaryWriter; // Emit entries in the same order as the corresponding file items as this // improves interoperability with tools that expect this convention. // Streaming mode must be handled differently if (_blockManager.Streaming) { // In Streaming mode we cannot rely on the order that entries were inserted via AddFiles() // as files can be closed in different order than they are added. // NOTE: Neither ZipIOBlockManager._blockList nor CentralDirectoryDicstionry // are NOT in offset order #if DEBUG long lastOffset = -1; #endif // collect all file headers in central directory into a local list for sorting SortedList blockList = new SortedList(CentralDirectoryDictionary.Count); // We know that in Streaming mode there can be no RawDataFile blocks in // the block list. Therefore, we can emit our headers in the order that they // appear in the block list. foreach (ZipIOCentralDirectoryFileHeader header in CentralDirectoryDictionary.Values) { blockList.Add(header.OffsetOfLocalHeader, header); } // then write out the files headers for central directory in sorted order foreach (ZipIOCentralDirectoryFileHeader header in blockList.Values) { header.Save(writer); #if DEBUG Debug.Assert(lastOffset < header.OffsetOfLocalHeader, "Sort order violated"); lastOffset = header.OffsetOfLocalHeader; #endif } } else { // Non-streaming mode - CentralDirectoryDictionary has correct order. // Assume correct location if streaming - otherwise explicitly seek. if (_blockManager.Stream.Position != _offset) { // we need to seek _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } // Save the headers in the order they were added as this matches the physical offsets foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { fileHeader.Save(writer); } } // Zeus PS 3: disable creation/parsing of zip archive digital signatures #if ArchiveSignaturesEnabled //central directory dig sig is optional if (_centralDirectoryDigitalSignature != null) { _centralDirectoryDigitalSignature.Save(writer); } #endif writer.Flush(); } _dirtyFlag = false; } } public void UpdateReferences(bool closingFlag) { // we just need to ask Block Manager for the new Values for each header // there are 2 distinct cases here // 1. local file data is mapped . loaded and might have been changed in size and position // 2. local file data is not loaded and might have been changed only in position (not in size) foreach(IZipIOBlock block in _blockManager) { ZipIOLocalFileBlock localFileBlock = block as ZipIOLocalFileBlock; ZipIORawDataFileBlock rawDataFileBlock = block as ZipIORawDataFileBlock; if (localFileBlock != null) { // this is case 1 data is mapped and loaded, so we only need to find the matching // Centraldirectory record and update it Debug.Assert(CentralDirectoryDictionary.Contains(localFileBlock.FileName)); ZipIOCentralDirectoryFileHeader centralDirFileHeader = (ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[localFileBlock.FileName]; if (centralDirFileHeader.UpdateIfNeeded(localFileBlock)) { //update was required let's mark ourselves as dirty _dirtyFlag = true; } } //check whether we deal with raw data block and it was moved else if (rawDataFileBlock != null) { long diskImageShift = rawDataFileBlock.DiskImageShift; if (diskImageShift != 0) { //this is case #2 data isn't loaded based on the shift in the RawData Block // we need to move all overlapping central directory references foreach (ZipIOCentralDirectoryFileHeader centralDirFileHeader in CentralDirectoryDictionary.Values) { // check whether central dir header points into the region of a moved RawDataBlock if (rawDataFileBlock.DiskImageContains(centralDirFileHeader.OffsetOfLocalHeader)) { centralDirFileHeader.MoveReference(diskImageShift); _dirtyFlag = true; } } } } } } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { // we can safely ignore this notification as we do not keep any data // after parsing on disk. Everything is in memory, it is ok to override // original Central directory without any additional backups // we can also safely state that there is no need to continue the PreSafeNotification loop // as all the blocks after the central directory (EOCD, Zip64 ....) do not have // data that is buffered on disk return PreSaveNotificationScanControlInstruction.Stop; } //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ // although Zip 64 supports 64 bit counter for the number of // entries in the central directory, we have chossen to not // support those scenarios and stick wit the basic CLR type // int Collections.Count {get;} internal int Count { get { return CentralDirectoryDictionary.Count; } } //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- internal static ZipIOCentralDirectoryBlock SeekableLoad(ZipIOBlockManager blockManager) { // get proper values from zip 64 records request will be redirected to the // regular EOCD if ZIP 64 record wasn't originated from the parsing ZipIOZip64EndOfCentralDirectoryBlock zip64EOCD = blockManager.Zip64EndOfCentralDirectoryBlock; blockManager.Stream.Seek(zip64EOCD.OffsetOfStartOfCentralDirectory, SeekOrigin.Begin); ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); block.ParseRecord(blockManager.BinaryReader, zip64EOCD.OffsetOfStartOfCentralDirectory, zip64EOCD.TotalNumberOfEntriesInTheCentralDirectory, zip64EOCD.SizeOfCentralDirectory); return block; } internal static ZipIOCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) { ZipIOCentralDirectoryBlock block = new ZipIOCentralDirectoryBlock(blockManager); block._offset = 0; // it just an initial value, that will be adjusted later // it doesn't matter whether this offset overlaps anything or not block._dirtyFlag = true; // this dig sig is optional if we ever wanted to make this record, we would need to call // ZipIOCentralDirectoryDigitalSignature.CreateNew(); block._centralDirectoryDigitalSignature = null; return block; } // This properrty returns current snapsot which might be out of date // if there were changes after parsing or last UpdateReferences call internal bool IsZip64BitRequiredForStoring { get { // These values are duplicated the EndOfCentralDirectory record // and if any of them are to big we need to introduce // Zip64 end of central directory record // Zip64 end of central directory locator return (Count >= UInt16.MaxValue) || (Offset >= UInt32.MaxValue) || (Size >= UInt32.MaxValue); } } internal void AddFileBlock(ZipIOLocalFileBlock fileBlock) { _dirtyFlag = true; ZipIOCentralDirectoryFileHeader fileHeader = ZipIOCentralDirectoryFileHeader.CreateNew (_blockManager.Encoding, fileBlock); CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); } ////// /// /// ///precondition: caller must ensure that fileName exists internal void RemoveFileBlock(string fileName) { _dirtyFlag = true; CentralDirectoryDictionary.Remove(fileName); if (CentralDirectoryDictionary.Count == 0) { // in case of the the last one ,we also need to drop the signature record _centralDirectoryDigitalSignature = null; } } internal bool FileExists(string fileName) { return CentralDirectoryDictionary.Contains(fileName); } // this function should be used carefully as it returns reference to an object // that is owned by CentralDirectoryBlock, and should be used by other classes only // for querying information not for updating it. internal ZipIOCentralDirectoryFileHeader GetCentralDirectoryFileHeader (string fileName) { return ((ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[fileName]); } internal ICollection GetFileNamesCollection() { return CentralDirectoryDictionary.Keys; } //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ private ZipIOCentralDirectoryBlock(ZipIOBlockManager blockManager) { _blockManager = blockManager; } ////// Compare FileOffsets for LocalFileHeaders - used by Sort() routine in ParseRecord /// private class HeaderFileOffsetComparer : IComparer { int IComparer.Compare(object o1, object o2) { ZipIOCentralDirectoryFileHeader h1 = o1 as ZipIOCentralDirectoryFileHeader; ZipIOCentralDirectoryFileHeader h2 = o2 as ZipIOCentralDirectoryFileHeader; Debug.Assert(h1 != null && h2 != null, "HeaderFileOffsetComparer: Comparing the wrong data types"); // avoid boxing - don't cast long value to (IComparable) if (h1.OffsetOfLocalHeader > h2.OffsetOfLocalHeader) return 1; else if (h1.OffsetOfLocalHeader < h2.OffsetOfLocalHeader) return -1; else return 0; } } private void ParseRecord (BinaryReader reader, long centralDirectoryOffset, int centralDirectoryCount, long expectedCentralDirectorySize) { if (centralDirectoryCount > 0) { // collect all headers into a local array list for sorting SortedList headerList = new SortedList(centralDirectoryCount); ZipIOCentralDirectoryFileHeader header; for (int i = 0; i < centralDirectoryCount; i++) { header = ZipIOCentralDirectoryFileHeader.ParseRecord(reader, _blockManager.Encoding); headerList.Add(header.OffsetOfLocalHeader, header); } if (reader.BaseStream.Position - centralDirectoryOffset > expectedCentralDirectorySize) { // it looks like a corrupted file, as we have parsed more than central directory supposed to contain throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // then add to the ordered dictionary in sorted order foreach (ZipIOCentralDirectoryFileHeader fileHeader in headerList.Values) { // at this point fileHeader.FileName is normalized using // the ZipIOBlockManager.ValidateNormalizeFileName CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); } //load central directory [digital signature] - this has nothing to // do with OPC digital signing // this record is optional, and the function might return null _centralDirectoryDigitalSignature = ZipIOCentralDirectoryDigitalSignature.ParseRecord(reader); } _offset = centralDirectoryOffset; _dirtyFlag = false; Validate(expectedCentralDirectorySize); } private void Validate(long expectedCentralDirectorySize) { checked { // We only have information about the Compressed data size and the offset of the // local headers. We do not have information about the size of the local header // which varies depending on the file name and the extra field records size. // (Although we do know the expected size of the file name, there is no way to // predict the extra field size, for example it might have a padding record that we use // optimize Disk IO for ZIP 64 scenarios). // We are going to make sure that Blocks do not overlap each other and do not // overlap Central Directory long checkedMark = 0; foreach (ZipIOCentralDirectoryFileHeader fileHeader in CentralDirectoryDictionary.Values) { if ((checkedMark == 0) && (fileHeader.OffsetOfLocalHeader != 0)) { // first block doesn't start at 0 throw new FileFormatException(SR.Get(SRID.CorruptedData)); } else if (fileHeader.OffsetOfLocalHeader < checkedMark) { // the current block overlaps the previously analyzed block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // we move the checked mark up by the sum of the compressed size file name size // and the fixed minimal Local file header size checkedMark += fileHeader.CompressedSize + ZipIOLocalFileHeader.FixedMinimalRecordSize + fileHeader.FileName.Length; } // now we can ensure that that checked mark didn't reach over the start of the Central directory if (_offset < checkedMark) { // the central directory block overlaps the last file block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } //check the total parsed size of the central directory against value declared in EOCd or ZIP64 EOCD records if (Size != expectedCentralDirectorySize) { // the central directory block overlaps the last file block throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // we should also check ofr presence of gaps between // Central Directory // ZIP64 EOCD // ZIP 64 EOCD locator // EOCD // Zip64Eocd and Zip64EocdLocator must be either present or absent together Debug.Assert(! (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) ^ (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size==0)); if (_blockManager.Zip64EndOfCentralDirectoryBlock.Size==0) { // no ZIP 64 record if (_offset + expectedCentralDirectorySize != _blockManager.EndOfCentralDirectoryBlock.Offset) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } else { // ZIP 64 records present if ((_offset + expectedCentralDirectorySize != _blockManager.Zip64EndOfCentralDirectoryBlock.Offset) || (_blockManager.Zip64EndOfCentralDirectoryBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryBlock.Size != _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset) || (_blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Offset + _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.Size != _blockManager.EndOfCentralDirectoryBlock.Offset)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } } } //----------------------------------------------------- // // Private Properties // //------------------------------------------------------ private IDictionary CentralDirectoryDictionary { get { if (_centralDirectoryDictionary == null) { // StringComparer.Ordinal guarantees ordinal, case-sensitive comparison for both cases. // if streaming - order is unimportant for us and we can use the cheaper Hashtable if (_blockManager.Streaming) { // We take our order during Save() from the physical order of the elements of the // block table in BlockManager. _centralDirectoryDictionary = new Hashtable(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); } else { // This ordered dictionary serves two purposes. It allows hash-table lookup by file name // and it also maintains the physical order of the blocks on disk. Like any OrderedDictionary, // any of the enumerator, or integer indexer will return the items in the order that they were added. _centralDirectoryDictionary = new OrderedDictionary(_centralDirectoryDictionaryInitialSize, StringComparer.Ordinal); } } return _centralDirectoryDictionary; } } //------------------------------------------------------ // // Private Members // //----------------------------------------------------- private const int _centralDirectoryDictionaryInitialSize = 50; // used in Parse private static IComparer _headerOffsetComparer = new HeaderFileOffsetComparer(); // This may be a HashTable (Streaming case) or an OrderedDictionary - see private property // for explanation. private IDictionary _centralDirectoryDictionary; private ZipIOCentralDirectoryDigitalSignature _centralDirectoryDigitalSignature; private ZipIOBlockManager _blockManager; private long _offset; private bool _dirtyFlag; } } // 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
- HttpListenerRequest.cs
- EmptyControlCollection.cs
- QueryExpr.cs
- StylusTip.cs
- UriExt.cs
- ContractMapping.cs
- HttpListenerRequest.cs
- ProfilePropertyNameValidator.cs
- IWorkflowDebuggerService.cs
- wgx_render.cs
- ScriptingProfileServiceSection.cs
- CompilationRelaxations.cs
- EndpointAddressAugust2004.cs
- SimpleApplicationHost.cs
- ClientScriptItemCollection.cs
- EditingCoordinator.cs
- DbProviderFactory.cs
- securitycriticaldataClass.cs
- StrongNameIdentityPermission.cs
- HttpListenerRequest.cs
- HtmlPhoneCallAdapter.cs
- RelOps.cs
- BuilderPropertyEntry.cs
- ClonableStack.cs
- LogEntry.cs
- ToolboxItemLoader.cs
- DragEvent.cs
- OperandQuery.cs
- MouseButtonEventArgs.cs
- TextureBrush.cs
- ContextMenuAutomationPeer.cs
- DataRecord.cs
- NamedPipeTransportElement.cs
- SqlDataAdapter.cs
- Command.cs
- QueryOutputWriter.cs
- relpropertyhelper.cs
- StoreContentChangedEventArgs.cs
- UserControl.cs
- Byte.cs
- ErrorRuntimeConfig.cs
- UnsafeNativeMethods.cs
- CommandManager.cs
- ScriptingRoleServiceSection.cs
- HandleDictionary.cs
- UnauthorizedAccessException.cs
- SecurityRuntime.cs
- WindowInteropHelper.cs
- HttpHandlerActionCollection.cs
- HtmlControl.cs
- RoutedEventConverter.cs
- ResourceWriter.cs
- GestureRecognizer.cs
- StorageAssociationTypeMapping.cs
- XpsFilter.cs
- Evaluator.cs
- TransformDescriptor.cs
- PersistNameAttribute.cs
- xamlnodes.cs
- mda.cs
- MouseDevice.cs
- UrlAuthorizationModule.cs
- RepeatInfo.cs
- DesignerForm.cs
- BufferAllocator.cs
- AuthenticationService.cs
- WindowsSecurityTokenAuthenticator.cs
- KeyNotFoundException.cs
- XmlAggregates.cs
- StrokeNodeOperations.cs
- PageCatalogPartDesigner.cs
- CheckBoxStandardAdapter.cs
- SchemaImporterExtensionsSection.cs
- RemotingConfiguration.cs
- Soap12ProtocolImporter.cs
- BitmapEffectDrawingContent.cs
- UIInitializationException.cs
- Converter.cs
- ToolStripDropDown.cs
- DesignerSerializationOptionsAttribute.cs
- QueryCacheEntry.cs
- BindToObject.cs
- WindowsUpDown.cs
- ApplicationSecurityInfo.cs
- TextWriter.cs
- AssociationEndMember.cs
- ChildTable.cs
- EFTableProvider.cs
- RepeaterDesigner.cs
- XmlSchemaInclude.cs
- Size3D.cs
- _StreamFramer.cs
- ImageBrush.cs
- TypeReference.cs
- SqlXmlStorage.cs
- RangeValidator.cs
- Compiler.cs
- XamlClipboardData.cs
- ClientConfigurationHost.cs
- HtmlInputButton.cs