Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / IO / Zip / ZipIOZip64EndOfCentralDirectoryBlock.cs / 1 / 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; 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; 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
- XComponentModel.cs
- MetadataPropertyvalue.cs
- SapiGrammar.cs
- BulletChrome.cs
- AssemblyUtil.cs
- ModelItemImpl.cs
- TaskFileService.cs
- __ConsoleStream.cs
- BitmapMetadataBlob.cs
- PenContexts.cs
- CryptographicAttribute.cs
- CodeAttributeArgument.cs
- DecimalAnimation.cs
- TypeUnloadedException.cs
- UiaCoreProviderApi.cs
- BaseDataListComponentEditor.cs
- _ContextAwareResult.cs
- FloaterParaClient.cs
- XPathNavigatorKeyComparer.cs
- HttpCookieCollection.cs
- AdapterDictionary.cs
- CompModSwitches.cs
- PathGeometry.cs
- DropDownButton.cs
- PermissionListSet.cs
- UserControlParser.cs
- HwndSubclass.cs
- ColorTransform.cs
- ItemList.cs
- CodeSnippetExpression.cs
- ValueTypeFixupInfo.cs
- HighContrastHelper.cs
- XmlEncoding.cs
- TableLayoutPanel.cs
- ResourcePool.cs
- PopupRootAutomationPeer.cs
- BaseTreeIterator.cs
- PieceDirectory.cs
- AssemblySettingAttributes.cs
- XmlSchemaObjectCollection.cs
- Util.cs
- HtmlFormAdapter.cs
- EventData.cs
- CodeComment.cs
- WebSysDisplayNameAttribute.cs
- ConfigurationStrings.cs
- MetadataCache.cs
- XmlFormatExtensionPointAttribute.cs
- DbConnectionPoolCounters.cs
- Control.cs
- StylusPoint.cs
- XmlSchemaExternal.cs
- TemplateControl.cs
- BitmapEffectInputConnector.cs
- ContentPosition.cs
- SdlChannelSink.cs
- StringSorter.cs
- Int64Storage.cs
- ProfilePropertyNameValidator.cs
- HierarchicalDataSourceDesigner.cs
- HitTestFilterBehavior.cs
- FacetChecker.cs
- HandlerBase.cs
- Literal.cs
- EnumMember.cs
- CollectionConverter.cs
- LightweightCodeGenerator.cs
- RevocationPoint.cs
- BufferBuilder.cs
- MessageDecoder.cs
- BuildProviderCollection.cs
- WhitespaceRuleReader.cs
- HtmlTitle.cs
- HotCommands.cs
- StylusButtonCollection.cs
- MultiView.cs
- ObjectViewFactory.cs
- ConfigPathUtility.cs
- DataReaderContainer.cs
- AutomationEvent.cs
- SymLanguageType.cs
- MetadataSource.cs
- CodeSnippetExpression.cs
- DataServiceExpressionVisitor.cs
- PathSegmentCollection.cs
- EventLogInformation.cs
- DocumentGrid.cs
- VectorCollection.cs
- ToolStripDropTargetManager.cs
- CfgParser.cs
- QueryOptionExpression.cs
- TemplateBindingExtensionConverter.cs
- DataSourceView.cs
- XmlElementList.cs
- InputLanguageCollection.cs
- WebPartMovingEventArgs.cs
- ConfigurationManagerInternal.cs
- GraphicsContainer.cs
- XmlSchemaAttributeGroup.cs
- CmsInterop.cs