Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Zip / ZipIOZip64EndOfCentralDirectoryBlock.cs / 1305600 / ZipIOZip64EndOfCentralDirectoryBlock.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 (Zip 64 bit support) // // History: // 01/26/2005: IgorBel: Initial creation. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Runtime.Serialization; using System.Windows; using MS.Internal.WindowsBase; namespace MS.Internal.IO.Zip { internal class ZipIOZip64EndOfCentralDirectoryBlock : IZipIOBlock { // standard IZipIOBlock functionality public long Offset { get { return _offset; } } public long Size { get { return _size; } } // This property will only return reliable result if UpdateReferences is called prior public bool GetDirtyFlag(bool closingFlag) { return _dirtyFlag; } public void Move(long shiftSize) { if (shiftSize != 0) { checked{_offset +=shiftSize;} if (_size > 0) { _dirtyFlag = true; } Debug.Assert(_offset >=0); } } public void Save() { // this record is optional and shouldn't be saved if size is 0 if (GetDirtyFlag(true) && (Size > 0)) { BinaryWriter writer = _blockManager.BinaryWriter; if (_blockManager.Stream.Position != _offset) { // we need to seek , as current position isn't accurate _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } writer.Write(_signatureConstant); writer.Write(_sizeOfZip64EndOfCentralDirectory); writer.Write(_versionMadeBy); writer.Write(_versionNeededToExtract); writer.Write(_numberOfThisDisk); writer.Write(_numberOfTheDiskWithTheStartOfTheCentralDirectory); writer.Write(_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk); writer.Write(_totalNumberOfEntriesInTheCentralDirectory); writer.Write(_sizeOfTheCentralDirectory); writer.Write(_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber); if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) { Debug.Assert(_zip64ExtensibleDataSector != null); Debug.Assert(_zip64ExtensibleDataSector.Length == checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); writer.Write(_zip64ExtensibleDataSector, 0, checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); } writer.Flush(); } _dirtyFlag = false; } public void UpdateReferences(bool closingFlag) { checked { // check whether Central directory is loaded and update references accordingly // if one or more of the following conditions are true // 1. Central Directory is dirty // 2. streaming mode // if Central Directory isn't loaded or none of the relevant structure is dirty, // there is nothing to update for Zip64 End Of Central directory record if (_blockManager.IsCentralDirectoryBlockLoaded && (_blockManager.Streaming || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag))) { if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) { UInt64 centralDirCount = (UInt64)_blockManager.CentralDirectoryBlock.Count; UInt64 centralDirBlockSize = (UInt64)_blockManager.CentralDirectoryBlock.Size; UInt64 centralDirOffset = (UInt64)_blockManager.CentralDirectoryBlock.Offset; // Here is a diagram of the record //---------------------------------------------------------------------------------------------------------------------- //|SignatureConst (4 bytes)|sizeOfZip64Eocd (8 bytes)|misc fixed fields (44 bytes)|Variable Size Extensible Data sector| //A------------------------B-------------------------C----------------------------D------------------------------------E // // in order to calculate the actual record size we subtract _fixedMinimalValueOfSizeOfZip64EOCD (This is a chunk marked // (C,D) in thre diagram above) from _fixedMinimalRecordSize (This is a chunk marked (A,D) in the diagram above). // Then we add the resulting value (which would be chunked marked (A,C) to the value of sizeOfZip64Eocd field which // contains the size of the record starting at point (C) and going to the end (E). So we get the total size as // (A,C) + (C,E) = (A,E) // long size = checked((long)( // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD _sizeOfZip64EndOfCentralDirectory + // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 _fixedMinimalRecordSize - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 _fixedMinimalValueOfSizeOfZip64EOCD)); // update value and mark record dirty if either it is already dirty or there is a mismatch if ((_dirtyFlag) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != centralDirCount) || (_totalNumberOfEntriesInTheCentralDirectory != centralDirCount ) || (_sizeOfTheCentralDirectory != centralDirBlockSize) || (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber != centralDirOffset) || (_size != size)) { _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; _numberOfThisDisk = 0; _numberOfTheDiskWithTheStartOfTheCentralDirectory = 0; _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = centralDirCount; _totalNumberOfEntriesInTheCentralDirectory = centralDirCount; _sizeOfTheCentralDirectory = centralDirBlockSize; _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = centralDirOffset; _size = size; _dirtyFlag = true; } } else { // we do not need zip 64 structures if (_size != 0) { _dirtyFlag = true; _size = 0; } } } } } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { // we can safely ignore this notification as we do not keep any data on disk // after parsing on disk. Everything is in memory, it is ok to override // original Zip64 EndOf Central Directory Block without any additional backups // we can also safely state that there is no need to continue the PreSafeNotification loop // as the blocks after the Zip64 Eocd (EOCD, Zip64 locator ) do not have // data that is buffered on disk return PreSaveNotificationScanControlInstruction.Stop; } internal static ZipIOZip64EndOfCentralDirectoryBlock SeekableLoad (ZipIOBlockManager blockManager) { ZipIOZip64EndOfCentralDirectoryLocatorBlock zip64endOfCentralDirectoryLocator = blockManager.Zip64EndOfCentralDirectoryLocatorBlock; long zip64EndOfCentralDirectoryOffset = zip64endOfCentralDirectoryLocator.OffsetOfZip64EndOfCentralDirectoryRecord; ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); blockManager.Stream.Seek(zip64EndOfCentralDirectoryOffset, SeekOrigin.Begin); block.ParseRecord(blockManager.BinaryReader, zip64EndOfCentralDirectoryOffset); return block; } internal static ZipIOZip64EndOfCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) { ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); block._size = 0; // brand new created records are optional by definition untill UpdateReferences is called, so size must be 0 block._offset = 0; block._dirtyFlag = false; // initialize fields with ythe data from the EOCD block.InitializeFromEndOfCentralDirectory(blockManager.EndOfCentralDirectoryBlock); return block; } internal long OffsetOfStartOfCentralDirectory { get { return (long)_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; } } internal int TotalNumberOfEntriesInTheCentralDirectory { get { return (int)_totalNumberOfEntriesInTheCentralDirectory; // checked isn't required as we do validation during parsing } } internal long SizeOfCentralDirectory { get { return (long)_sizeOfTheCentralDirectory; } } private ZipIOZip64EndOfCentralDirectoryBlock(ZipIOBlockManager blockManager) { Debug.Assert(blockManager != null); _blockManager= blockManager; } private void ParseRecord (BinaryReader reader, long position) { _signature = reader.ReadUInt32(); _sizeOfZip64EndOfCentralDirectory = reader.ReadUInt64(); _versionMadeBy = reader.ReadUInt16(); _versionNeededToExtract = reader.ReadUInt16(); _numberOfThisDisk = reader.ReadUInt32(); _numberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt32(); _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = reader.ReadUInt64(); _totalNumberOfEntriesInTheCentralDirectory = reader.ReadUInt64(); _sizeOfTheCentralDirectory = reader.ReadUInt64(); _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt64(); // pre validate before reading data based on parsed values if ((_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) || // we are refusing to buffer large extended areas (_sizeOfZip64EndOfCentralDirectory > UInt16.MaxValue)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) { _zip64ExtensibleDataSector = reader.ReadBytes((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD)); } // override some numbers bvased on the EOCD data according to the apnote // even in presence of Zip64Eocd we still need to use the regular EOCD data OverrideValuesBasedOnEndOfCentralDirectory(_blockManager.EndOfCentralDirectoryBlock); _size = checked((long)( // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD _sizeOfZip64EndOfCentralDirectory + // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 _fixedMinimalRecordSize - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 _fixedMinimalValueOfSizeOfZip64EOCD)); Debug.Assert(_size >= _fixedMinimalRecordSize); _offset = position; _dirtyFlag = false; Validate(); } ////// This function is called from the Create New routine. The purpose of this exercise , is to copy data from 32 bit EOCD into this record, /// for scenarios when ZIP64 EOCD wasn't parsed from a file, but was just made up. /// This is done so that Central Dir parsing code can ask the ZIP64 EOCD for this data, and regardless of whether it is real zip 64 file or /// not a zip 64 file it will get the right CD offset , size and so on /// private void InitializeFromEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) { _numberOfThisDisk = zipIoEocd.NumberOfThisDisk; _numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory; _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk; _totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory; _sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory; _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory; } ////// This function is called from the Parse routine. The purpose of this exercise , is to figure out the escape /// values in the regular 32 bit EOCD. We shouldn't be using values from the 64 bit structure if it wasn't /// escaped in the 32 bit structure. /// private void OverrideValuesBasedOnEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) { // 16 bit numbers if (zipIoEocd.NumberOfThisDisk < UInt16.MaxValue) {_numberOfThisDisk = zipIoEocd.NumberOfThisDisk;} if (zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory < UInt16.MaxValue) {_numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory;} if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk < UInt16.MaxValue) {_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk;} if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory < UInt16.MaxValue) {_totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory;} // 32 bit numbers if (zipIoEocd.SizeOfTheCentralDirectory < UInt32.MaxValue) {_sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory;} if (zipIoEocd.OffsetOfStartOfCentralDirectory < UInt32.MaxValue) {_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory;} } private void Validate() { if (_signature != _signatureConstant) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if ((_numberOfThisDisk != 0) || (_numberOfTheDiskWithTheStartOfTheCentralDirectory != 0) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != _totalNumberOfEntriesInTheCentralDirectory)) { throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); } // this will throw an unsupported version exception if we see a version that we do not support ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); // if it is one of the supported version but it isn't a ZIP64, it is an indication of a corrupted file if (_versionNeededToExtract != (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) { // if version isn't equal to the 4.5 it is a corrupted file (as we) // as appnote explicitly states that // When using ZIP64 extensions, the corresponding value in the // Zip64 end of central directory record should also be set. // This field currently supports only the value 45 to indicate // ZIP64 extensions are present. throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if ((_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk > Int32.MaxValue) || (_totalNumberOfEntriesInTheCentralDirectory > Int32.MaxValue) || (_sizeOfTheCentralDirectory > Int64.MaxValue) || (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber > Int64.MaxValue)) { // although we are trying to support 64 bit structures // we are limited by the CLR model for collections (down to 32 bit collection size for // _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk ) // and streams (down to 63 bit size) for all the outher Uint64 fields throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge)); } ulong sizeOfZip64ExtensibleDataSector = 0; if (_zip64ExtensibleDataSector != null) { sizeOfZip64ExtensibleDataSector = (ulong)_zip64ExtensibleDataSector.Length; } // the subtraction below doesn't need to be checked as we have validation in the parse logic // if (_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) { throw .. } if (_sizeOfZip64EndOfCentralDirectory - _fixedMinimalValueOfSizeOfZip64EOCD != sizeOfZip64ExtensibleDataSector) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } //calculated record size must be larger than the min value // it could be 0 for newly created from scratch records, but we do not pass those records through validation // we only validate parsed data if (_size < _fixedMinimalRecordSize) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } private ZipIOBlockManager _blockManager; private long _offset; private long _size; private bool _dirtyFlag; private const UInt32 _signatureConstant = 0x06064b50; private const uint _fixedMinimalRecordSize = 56; private const uint _fixedMinimalValueOfSizeOfZip64EOCD = 44; // doesn't include the signature and the size itself // data persisted on disk private UInt32 _signature = _signatureConstant; private UInt64 _sizeOfZip64EndOfCentralDirectory = _fixedMinimalValueOfSizeOfZip64EOCD; private UInt16 _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; private UInt16 _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; private UInt32 _numberOfThisDisk; private UInt32 _numberOfTheDiskWithTheStartOfTheCentralDirectory; private UInt64 _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk; // all int64s declared as signed values private UInt64 _totalNumberOfEntriesInTheCentralDirectory; // as we can not suport true unsigned 64 bit sizes private UInt64 _sizeOfTheCentralDirectory; // as a result of limitations in Stream interface private UInt64 _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; private byte[] _zip64ExtensibleDataSector; } } // 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 (Zip 64 bit support) // // History: // 01/26/2005: IgorBel: Initial creation. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Runtime.Serialization; using System.Windows; using MS.Internal.WindowsBase; namespace MS.Internal.IO.Zip { internal class ZipIOZip64EndOfCentralDirectoryBlock : IZipIOBlock { // standard IZipIOBlock functionality public long Offset { get { return _offset; } } public long Size { get { return _size; } } // This property will only return reliable result if UpdateReferences is called prior public bool GetDirtyFlag(bool closingFlag) { return _dirtyFlag; } public void Move(long shiftSize) { if (shiftSize != 0) { checked{_offset +=shiftSize;} if (_size > 0) { _dirtyFlag = true; } Debug.Assert(_offset >=0); } } public void Save() { // this record is optional and shouldn't be saved if size is 0 if (GetDirtyFlag(true) && (Size > 0)) { BinaryWriter writer = _blockManager.BinaryWriter; if (_blockManager.Stream.Position != _offset) { // we need to seek , as current position isn't accurate _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } writer.Write(_signatureConstant); writer.Write(_sizeOfZip64EndOfCentralDirectory); writer.Write(_versionMadeBy); writer.Write(_versionNeededToExtract); writer.Write(_numberOfThisDisk); writer.Write(_numberOfTheDiskWithTheStartOfTheCentralDirectory); writer.Write(_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk); writer.Write(_totalNumberOfEntriesInTheCentralDirectory); writer.Write(_sizeOfTheCentralDirectory); writer.Write(_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber); if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) { Debug.Assert(_zip64ExtensibleDataSector != null); Debug.Assert(_zip64ExtensibleDataSector.Length == checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); writer.Write(_zip64ExtensibleDataSector, 0, checked((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD))); } writer.Flush(); } _dirtyFlag = false; } public void UpdateReferences(bool closingFlag) { checked { // check whether Central directory is loaded and update references accordingly // if one or more of the following conditions are true // 1. Central Directory is dirty // 2. streaming mode // if Central Directory isn't loaded or none of the relevant structure is dirty, // there is nothing to update for Zip64 End Of Central directory record if (_blockManager.IsCentralDirectoryBlockLoaded && (_blockManager.Streaming || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag))) { if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) { UInt64 centralDirCount = (UInt64)_blockManager.CentralDirectoryBlock.Count; UInt64 centralDirBlockSize = (UInt64)_blockManager.CentralDirectoryBlock.Size; UInt64 centralDirOffset = (UInt64)_blockManager.CentralDirectoryBlock.Offset; // Here is a diagram of the record //---------------------------------------------------------------------------------------------------------------------- //|SignatureConst (4 bytes)|sizeOfZip64Eocd (8 bytes)|misc fixed fields (44 bytes)|Variable Size Extensible Data sector| //A------------------------B-------------------------C----------------------------D------------------------------------E // // in order to calculate the actual record size we subtract _fixedMinimalValueOfSizeOfZip64EOCD (This is a chunk marked // (C,D) in thre diagram above) from _fixedMinimalRecordSize (This is a chunk marked (A,D) in the diagram above). // Then we add the resulting value (which would be chunked marked (A,C) to the value of sizeOfZip64Eocd field which // contains the size of the record starting at point (C) and going to the end (E). So we get the total size as // (A,C) + (C,E) = (A,E) // long size = checked((long)( // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD _sizeOfZip64EndOfCentralDirectory + // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 _fixedMinimalRecordSize - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 _fixedMinimalValueOfSizeOfZip64EOCD)); // update value and mark record dirty if either it is already dirty or there is a mismatch if ((_dirtyFlag) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != centralDirCount) || (_totalNumberOfEntriesInTheCentralDirectory != centralDirCount ) || (_sizeOfTheCentralDirectory != centralDirBlockSize) || (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber != centralDirOffset) || (_size != size)) { _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; _numberOfThisDisk = 0; _numberOfTheDiskWithTheStartOfTheCentralDirectory = 0; _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = centralDirCount; _totalNumberOfEntriesInTheCentralDirectory = centralDirCount; _sizeOfTheCentralDirectory = centralDirBlockSize; _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = centralDirOffset; _size = size; _dirtyFlag = true; } } else { // we do not need zip 64 structures if (_size != 0) { _dirtyFlag = true; _size = 0; } } } } } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { // we can safely ignore this notification as we do not keep any data on disk // after parsing on disk. Everything is in memory, it is ok to override // original Zip64 EndOf Central Directory Block without any additional backups // we can also safely state that there is no need to continue the PreSafeNotification loop // as the blocks after the Zip64 Eocd (EOCD, Zip64 locator ) do not have // data that is buffered on disk return PreSaveNotificationScanControlInstruction.Stop; } internal static ZipIOZip64EndOfCentralDirectoryBlock SeekableLoad (ZipIOBlockManager blockManager) { ZipIOZip64EndOfCentralDirectoryLocatorBlock zip64endOfCentralDirectoryLocator = blockManager.Zip64EndOfCentralDirectoryLocatorBlock; long zip64EndOfCentralDirectoryOffset = zip64endOfCentralDirectoryLocator.OffsetOfZip64EndOfCentralDirectoryRecord; ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); blockManager.Stream.Seek(zip64EndOfCentralDirectoryOffset, SeekOrigin.Begin); block.ParseRecord(blockManager.BinaryReader, zip64EndOfCentralDirectoryOffset); return block; } internal static ZipIOZip64EndOfCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager) { ZipIOZip64EndOfCentralDirectoryBlock block = new ZipIOZip64EndOfCentralDirectoryBlock(blockManager); block._size = 0; // brand new created records are optional by definition untill UpdateReferences is called, so size must be 0 block._offset = 0; block._dirtyFlag = false; // initialize fields with ythe data from the EOCD block.InitializeFromEndOfCentralDirectory(blockManager.EndOfCentralDirectoryBlock); return block; } internal long OffsetOfStartOfCentralDirectory { get { return (long)_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; } } internal int TotalNumberOfEntriesInTheCentralDirectory { get { return (int)_totalNumberOfEntriesInTheCentralDirectory; // checked isn't required as we do validation during parsing } } internal long SizeOfCentralDirectory { get { return (long)_sizeOfTheCentralDirectory; } } private ZipIOZip64EndOfCentralDirectoryBlock(ZipIOBlockManager blockManager) { Debug.Assert(blockManager != null); _blockManager= blockManager; } private void ParseRecord (BinaryReader reader, long position) { _signature = reader.ReadUInt32(); _sizeOfZip64EndOfCentralDirectory = reader.ReadUInt64(); _versionMadeBy = reader.ReadUInt16(); _versionNeededToExtract = reader.ReadUInt16(); _numberOfThisDisk = reader.ReadUInt32(); _numberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt32(); _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = reader.ReadUInt64(); _totalNumberOfEntriesInTheCentralDirectory = reader.ReadUInt64(); _sizeOfTheCentralDirectory = reader.ReadUInt64(); _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt64(); // pre validate before reading data based on parsed values if ((_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) || // we are refusing to buffer large extended areas (_sizeOfZip64EndOfCentralDirectory > UInt16.MaxValue)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if (_sizeOfZip64EndOfCentralDirectory > _fixedMinimalValueOfSizeOfZip64EOCD) { _zip64ExtensibleDataSector = reader.ReadBytes((int)(_sizeOfZip64EndOfCentralDirectory -_fixedMinimalValueOfSizeOfZip64EOCD)); } // override some numbers bvased on the EOCD data according to the apnote // even in presence of Zip64Eocd we still need to use the regular EOCD data OverrideValuesBasedOnEndOfCentralDirectory(_blockManager.EndOfCentralDirectoryBlock); _size = checked((long)( // value that was either parsed from a file or initialized to the _fixedMinimalValueOfSizeOfZip64EOCD _sizeOfZip64EndOfCentralDirectory + // const (value indicating minimal whole record size, how many bytes on disk it needs) 56 _fixedMinimalRecordSize - // const (value indicating minimal value for the SizeOfZip64EOCD field as it is contains // the whole size without record signature(4), and the itself (8) it is 56 - 12 = 44 _fixedMinimalValueOfSizeOfZip64EOCD)); Debug.Assert(_size >= _fixedMinimalRecordSize); _offset = position; _dirtyFlag = false; Validate(); } ////// This function is called from the Create New routine. The purpose of this exercise , is to copy data from 32 bit EOCD into this record, /// for scenarios when ZIP64 EOCD wasn't parsed from a file, but was just made up. /// This is done so that Central Dir parsing code can ask the ZIP64 EOCD for this data, and regardless of whether it is real zip 64 file or /// not a zip 64 file it will get the right CD offset , size and so on /// private void InitializeFromEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) { _numberOfThisDisk = zipIoEocd.NumberOfThisDisk; _numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory; _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk; _totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory; _sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory; _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory; } ////// This function is called from the Parse routine. The purpose of this exercise , is to figure out the escape /// values in the regular 32 bit EOCD. We shouldn't be using values from the 64 bit structure if it wasn't /// escaped in the 32 bit structure. /// private void OverrideValuesBasedOnEndOfCentralDirectory(ZipIOEndOfCentralDirectoryBlock zipIoEocd) { // 16 bit numbers if (zipIoEocd.NumberOfThisDisk < UInt16.MaxValue) {_numberOfThisDisk = zipIoEocd.NumberOfThisDisk;} if (zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory < UInt16.MaxValue) {_numberOfTheDiskWithTheStartOfTheCentralDirectory = zipIoEocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory;} if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk < UInt16.MaxValue) {_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk;} if (zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory < UInt16.MaxValue) {_totalNumberOfEntriesInTheCentralDirectory = zipIoEocd.TotalNumberOfEntriesInTheCentralDirectory;} // 32 bit numbers if (zipIoEocd.SizeOfTheCentralDirectory < UInt32.MaxValue) {_sizeOfTheCentralDirectory = zipIoEocd.SizeOfTheCentralDirectory;} if (zipIoEocd.OffsetOfStartOfCentralDirectory < UInt32.MaxValue) {_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = zipIoEocd.OffsetOfStartOfCentralDirectory;} } private void Validate() { if (_signature != _signatureConstant) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if ((_numberOfThisDisk != 0) || (_numberOfTheDiskWithTheStartOfTheCentralDirectory != 0) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != _totalNumberOfEntriesInTheCentralDirectory)) { throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); } // this will throw an unsupported version exception if we see a version that we do not support ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); // if it is one of the supported version but it isn't a ZIP64, it is an indication of a corrupted file if (_versionNeededToExtract != (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) { // if version isn't equal to the 4.5 it is a corrupted file (as we) // as appnote explicitly states that // When using ZIP64 extensions, the corresponding value in the // Zip64 end of central directory record should also be set. // This field currently supports only the value 45 to indicate // ZIP64 extensions are present. throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if ((_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk > Int32.MaxValue) || (_totalNumberOfEntriesInTheCentralDirectory > Int32.MaxValue) || (_sizeOfTheCentralDirectory > Int64.MaxValue) || (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber > Int64.MaxValue)) { // although we are trying to support 64 bit structures // we are limited by the CLR model for collections (down to 32 bit collection size for // _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk ) // and streams (down to 63 bit size) for all the outher Uint64 fields throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge)); } ulong sizeOfZip64ExtensibleDataSector = 0; if (_zip64ExtensibleDataSector != null) { sizeOfZip64ExtensibleDataSector = (ulong)_zip64ExtensibleDataSector.Length; } // the subtraction below doesn't need to be checked as we have validation in the parse logic // if (_sizeOfZip64EndOfCentralDirectory < _fixedMinimalValueOfSizeOfZip64EOCD) { throw .. } if (_sizeOfZip64EndOfCentralDirectory - _fixedMinimalValueOfSizeOfZip64EOCD != sizeOfZip64ExtensibleDataSector) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } //calculated record size must be larger than the min value // it could be 0 for newly created from scratch records, but we do not pass those records through validation // we only validate parsed data if (_size < _fixedMinimalRecordSize) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } private ZipIOBlockManager _blockManager; private long _offset; private long _size; private bool _dirtyFlag; private const UInt32 _signatureConstant = 0x06064b50; private const uint _fixedMinimalRecordSize = 56; private const uint _fixedMinimalValueOfSizeOfZip64EOCD = 44; // doesn't include the signature and the size itself // data persisted on disk private UInt32 _signature = _signatureConstant; private UInt64 _sizeOfZip64EndOfCentralDirectory = _fixedMinimalValueOfSizeOfZip64EOCD; private UInt16 _versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; private UInt16 _versionNeededToExtract = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; private UInt32 _numberOfThisDisk; private UInt32 _numberOfTheDiskWithTheStartOfTheCentralDirectory; private UInt64 _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk; // all int64s declared as signed values private UInt64 _totalNumberOfEntriesInTheCentralDirectory; // as we can not suport true unsigned 64 bit sizes private UInt64 _sizeOfTheCentralDirectory; // as a result of limitations in Stream interface private UInt64 _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; private byte[] _zip64ExtensibleDataSector; } } // 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
- TdsEnums.cs
- ComEventsMethod.cs
- MetadataSource.cs
- TextTreeRootNode.cs
- TextParagraphProperties.cs
- FileRecordSequence.cs
- ConstraintEnumerator.cs
- UIElementParaClient.cs
- Comparer.cs
- TrustSection.cs
- MemoryPressure.cs
- IdnElement.cs
- QueueProcessor.cs
- ObjectStateEntryDbDataRecord.cs
- ObjectDataSourceEventArgs.cs
- OrderingInfo.cs
- HtmlInputText.cs
- ByteViewer.cs
- HMACSHA384.cs
- ServicePointManager.cs
- TiffBitmapEncoder.cs
- Math.cs
- ConfigurationLockCollection.cs
- DefaultHttpHandler.cs
- FormViewCommandEventArgs.cs
- MediaSystem.cs
- HttpCacheParams.cs
- XMLSchema.cs
- DefaultBindingPropertyAttribute.cs
- SecurityKeyEntropyMode.cs
- SequenceFullException.cs
- QueryConverter.cs
- StylusPointDescription.cs
- RangeValuePattern.cs
- XmlSchemaComplexContentExtension.cs
- RadioButtonStandardAdapter.cs
- Maps.cs
- _SSPIWrapper.cs
- ValueType.cs
- PassportPrincipal.cs
- ContainerActivationHelper.cs
- DataTrigger.cs
- _StreamFramer.cs
- HttpCacheVaryByContentEncodings.cs
- ParameterReplacerVisitor.cs
- ContentType.cs
- TextSelectionHelper.cs
- ListViewInsertedEventArgs.cs
- Point3D.cs
- StateRuntime.cs
- IncrementalHitTester.cs
- RuntimeHandles.cs
- Int32CollectionValueSerializer.cs
- WebHttpSecurityModeHelper.cs
- SerializableAttribute.cs
- MessageFilterException.cs
- ScrollItemProviderWrapper.cs
- MouseWheelEventArgs.cs
- SafeNativeMethodsCLR.cs
- SingleBodyParameterMessageFormatter.cs
- AssemblyInfo.cs
- CachedBitmap.cs
- RegisteredArrayDeclaration.cs
- UpDownEvent.cs
- PlatformNotSupportedException.cs
- WindowsRebar.cs
- Stylesheet.cs
- Debug.cs
- ColorConverter.cs
- MediaPlayerState.cs
- BitmapCacheBrush.cs
- ScrollEvent.cs
- ShapeTypeface.cs
- Item.cs
- CompositionAdorner.cs
- TextTabProperties.cs
- ObjectStateEntryDbUpdatableDataRecord.cs
- CqlErrorHelper.cs
- Types.cs
- ObjectStateFormatter.cs
- PostBackOptions.cs
- InvalidWMPVersionException.cs
- DocComment.cs
- TileBrush.cs
- ExpressionBuilderContext.cs
- TableCellCollection.cs
- DrawingDrawingContext.cs
- ErrorFormatter.cs
- ConfigurationSectionHelper.cs
- DataListAutoFormat.cs
- MemberJoinTreeNode.cs
- SecurityMessageProperty.cs
- HttpRequestTraceRecord.cs
- DecoderReplacementFallback.cs
- formatter.cs
- TextEffectResolver.cs
- DataViewManagerListItemTypeDescriptor.cs
- GraphicsPath.cs
- FileSystemInfo.cs
- Atom10FormatterFactory.cs