Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EntitySetBase.cs
- ByeOperationCD1AsyncResult.cs
- ObjectKeyFrameCollection.cs
- SQLInt64.cs
- ToolStripSplitButton.cs
- SqlDataSourceWizardForm.cs
- DebugView.cs
- MarshalByValueComponent.cs
- Compiler.cs
- MatrixAnimationUsingPath.cs
- CancellationToken.cs
- CodeDomExtensionMethods.cs
- StateDesignerConnector.cs
- CryptoKeySecurity.cs
- CFStream.cs
- Pair.cs
- HtmlWindow.cs
- EventSinkHelperWriter.cs
- MatrixKeyFrameCollection.cs
- SelectedGridItemChangedEvent.cs
- RegionInfo.cs
- codemethodreferenceexpression.cs
- DataSourceControl.cs
- EtwTrackingBehaviorElement.cs
- DynamicRenderer.cs
- HopperCache.cs
- HwndAppCommandInputProvider.cs
- ISAPIRuntime.cs
- SqlDataSourceFilteringEventArgs.cs
- NotCondition.cs
- DbProviderFactoriesConfigurationHandler.cs
- XmlSchemaImporter.cs
- ManipulationVelocities.cs
- CachedPathData.cs
- ProjectionRewriter.cs
- CharacterBuffer.cs
- SqlCrossApplyToCrossJoin.cs
- ResXResourceReader.cs
- XComponentModel.cs
- sqlinternaltransaction.cs
- RelatedPropertyManager.cs
- WebBaseEventKeyComparer.cs
- TableRow.cs
- WindowsTreeView.cs
- ListenerSessionConnection.cs
- MessageQueueTransaction.cs
- SmtpTransport.cs
- DependencyPropertyAttribute.cs
- ViewKeyConstraint.cs
- BitmapSourceSafeMILHandle.cs
- login.cs
- CommandLibraryHelper.cs
- ExchangeUtilities.cs
- UpdatePanel.cs
- RepeaterItemEventArgs.cs
- DesignerValidatorAdapter.cs
- DataFormat.cs
- _SingleItemRequestCache.cs
- SimpleHandlerFactory.cs
- RowsCopiedEventArgs.cs
- HttpException.cs
- EntityContainerEmitter.cs
- PenCursorManager.cs
- AudioFileOut.cs
- OdbcDataAdapter.cs
- AppSettingsReader.cs
- CreateUserErrorEventArgs.cs
- TracePayload.cs
- PathFigure.cs
- _UriTypeConverter.cs
- WrapPanel.cs
- WrapPanel.cs
- FileDialogPermission.cs
- CharAnimationBase.cs
- PhonemeConverter.cs
- PropertyItem.cs
- UInt32Converter.cs
- Ray3DHitTestResult.cs
- Point4D.cs
- KeyTime.cs
- TraceSource.cs
- CuspData.cs
- DesignerAdRotatorAdapter.cs
- RootProfilePropertySettingsCollection.cs
- Image.cs
- ExpandSegment.cs
- ToolStripDropDownButton.cs
- SimpleBitVector32.cs
- DataRelation.cs
- PropertyConverter.cs
- ConnectionStringsSection.cs
- HttpApplicationStateWrapper.cs
- XPathChildIterator.cs
- WindowsListViewGroupSubsetLink.cs
- InputMethod.cs
- ButtonFieldBase.cs
- CountAggregationOperator.cs
- ParserHooks.cs
- AxWrapperGen.cs
- DataView.cs