Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Zip / ZipIOEndOfCentralDirectoryBlock.cs / 1305600 / ZipIOEndOfCentralDirectoryBlock.cs
//------------------------------------------------------------------------------ //------------- *** WARNING *** //------------- This file is part of a legally monitored development project. //------------- Do not check in changes to this project. Do not raid bugs on this //------------- code in the main PS database. Do not contact the owner of this //------------- code directly. Contact the legal team at �ZSLegal� for assistance. //------------- *** WARNING *** //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This is an internal class that enables interactions with Zip archives // for OPC scenarios // // History: // 11/19/2004: IgorBel: Initial creation. // //----------------------------------------------------------------------------- using System; using System.IO; using System.Diagnostics; using System.Runtime.Serialization; using System.Windows; using MS.Internal.IO.Packaging; // for PackagingUtilities using MS.Internal.WindowsBase; namespace MS.Internal.IO.Zip { internal class ZipIOEndOfCentralDirectoryBlock : IZipIOBlock { //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- // standard IZipIOBlock functionality public long Offset { get { return _offset; } } public long Size { get { return _fixedMinimalRecordSize + _zipFileCommentLength; } } public bool GetDirtyFlag(bool closingFlag) { return _dirtyFlag; } //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ public void Move(long shiftSize) { if (shiftSize != 0) { checked{_offset +=shiftSize;} _dirtyFlag = true; Debug.Assert(_offset >=0); } } public void Save() { if (GetDirtyFlag(true)) { BinaryWriter writer = _blockManager.BinaryWriter; // never seek in streaming mode if (!_blockManager.Streaming && _blockManager.Stream.Position != _offset) { // we need to seek _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); } writer.Write(_signatureConstant); writer.Write(_numberOfThisDisk); writer.Write(_numberOfTheDiskWithTheStartOfTheCentralDirectory); writer.Write(_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk); writer.Write(_totalNumberOfEntriesInTheCentralDirectory); writer.Write(_sizeOfTheCentralDirectory); writer.Write(_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber); writer.Write(_zipFileCommentLength); if (_zipFileCommentLength > 0) { writer.Write(_zipFileComment, 0, _zipFileCommentLength); } writer.Flush(); _dirtyFlag = false; } } public void UpdateReferences(bool closingFlag) { // 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. Zip64 End of Central Directory is dirty // 3. Zip64 End of Central Directory Locator is dirty // 4. streaming mode // if Central Directory isn't loded or none of the relevant structure is dirty, // there is nothing to update for End Of Central directory record if (_blockManager.IsCentralDirectoryBlockLoaded && (_blockManager.Streaming || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag) || _blockManager.Zip64EndOfCentralDirectoryBlock.GetDirtyFlag(closingFlag) || _blockManager.Zip64EndOfCentralDirectoryLocatorBlock.GetDirtyFlag(closingFlag))) { // intialize them to zIP64 case, and update them if needed UInt16 centralDirCount = UInt16.MaxValue; UInt32 centralDirBlockSize = UInt32.MaxValue; UInt32 centralDirOffset = UInt32.MaxValue; UInt16 numberOfTheDiskWithTheStartOfTheCentralDirectory = 0; UInt16 numberOfThisDisk = 0; // If we don't need Zip 64 struture if (!_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) { // if it isn't zip 64 let's get the data out centralDirCount = (UInt16)_blockManager.CentralDirectoryBlock.Count; centralDirBlockSize = (UInt32)_blockManager.CentralDirectoryBlock.Size; centralDirOffset = (UInt32)_blockManager.CentralDirectoryBlock.Offset; } // 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) || (_numberOfTheDiskWithTheStartOfTheCentralDirectory != numberOfTheDiskWithTheStartOfTheCentralDirectory) || (_numberOfThisDisk != numberOfThisDisk)) { _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = centralDirCount; _totalNumberOfEntriesInTheCentralDirectory = centralDirCount; _sizeOfTheCentralDirectory = centralDirBlockSize; _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = centralDirOffset; _numberOfTheDiskWithTheStartOfTheCentralDirectory = numberOfTheDiskWithTheStartOfTheCentralDirectory; _numberOfThisDisk = numberOfThisDisk; _dirtyFlag = true; } } } public PreSaveNotificationScanControlInstruction PreSaveNotification(long offset, long size) { // we can safely ignore this notification as we do not keep any data // after parsing on disk. Everything is in memory, it is ok to override // original End of Central directory without any additional backups // we can also safely state that there is no need to continue the PreSafeNotification loop // as there shouldn't be any blocks after the EOCD return PreSaveNotificationScanControlInstruction.Stop; } //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ internal static ZipIOEndOfCentralDirectoryBlock SeekableLoad (ZipIOBlockManager blockManager) { // perform custom serach for record long blockPosition = FindPosition(blockManager.Stream); blockManager.Stream.Seek(blockPosition, SeekOrigin.Begin); ZipIOEndOfCentralDirectoryBlock block = new ZipIOEndOfCentralDirectoryBlock(blockManager); block.ParseRecord(blockManager.BinaryReader, blockPosition); return block; } internal static ZipIOEndOfCentralDirectoryBlock CreateNew(ZipIOBlockManager blockManager, long offset) { ZipIOEndOfCentralDirectoryBlock block = new ZipIOEndOfCentralDirectoryBlock(blockManager); block._offset = offset; block._dirtyFlag = true; return block; } internal void ValidateZip64TriggerValues() { if ((_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber > _offset) || ((_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == _offset) && (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk > 0))) { // central directory must start prior to the offset of the end of central directory. // the only exception is when size of the central directory is 0 throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if ((_numberOfThisDisk != 0) || (_numberOfTheDiskWithTheStartOfTheCentralDirectory != 0) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk != _totalNumberOfEntriesInTheCentralDirectory)) { throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); } } internal uint NumberOfThisDisk { get { return _numberOfThisDisk; } } internal uint NumberOfTheDiskWithTheStartOfTheCentralDirectory { get { return _numberOfTheDiskWithTheStartOfTheCentralDirectory; } } internal uint TotalNumberOfEntriesInTheCentralDirectoryOnThisDisk { get { return _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk ; } } internal uint TotalNumberOfEntriesInTheCentralDirectory { get { return _totalNumberOfEntriesInTheCentralDirectory; } } internal uint SizeOfTheCentralDirectory { get { return _sizeOfTheCentralDirectory; } } internal uint OffsetOfStartOfCentralDirectory { get { return _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; } } #if false internal string Comment { get { return _stringZipFileComment; } } #endif internal bool ContainValuesHintingToPossibilityOfZip64 { get { return ((_numberOfThisDisk == UInt16.MaxValue) || (_numberOfTheDiskWithTheStartOfTheCentralDirectory == UInt16.MaxValue) || (_totalNumberOfEntriesInTheCentralDirectoryOnThisDisk == UInt16.MaxValue) || (_totalNumberOfEntriesInTheCentralDirectory == UInt16.MaxValue) || (_sizeOfTheCentralDirectory == UInt32.MaxValue) || (_offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == UInt32.MaxValue)); } } //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- private ZipIOEndOfCentralDirectoryBlock(ZipIOBlockManager blockManager) { Debug.Assert(blockManager != null); _blockManager= blockManager; } private static long FindPosition(Stream archiveStream) { Debug.Assert(archiveStream.CanSeek); byte [] buffer = new byte[_scanBlockSize + _fixedMinimalRecordSize]; long streamLength = archiveStream.Length; for(long endPos = streamLength; endPos > 0; endPos -= _scanBlockSize) { // calculate offset position of the block to be read based on the end // Position loop variable long beginPos = Math.Max(0, endPos -_scanBlockSize); //read the block archiveStream.Seek(beginPos, SeekOrigin.Begin); // the reads that we do actually overlap each other by the size == _fixedMinimalRecordSize // this is done in order to simplify our searching logic, this way we do not need to specially // process matches that cross buffer boundaries, as we are guaranteed that if match is present // it falls completely inside one of the buffers, as a result of overlapping in the read requests int bytesRead = PackagingUtilities.ReliableRead(archiveStream, buffer, 0, buffer.Length); // We need to pass this parameter into the function, so it knows // the relative positon of the buffer in regard to the end of the stream; // it needs this info in order to checke whether the candidate record // has length of Comment field consistent with the postion of the record long distanceFromStartOfBufferToTheEndOfStream = streamLength -beginPos; for(int i = bytesRead - _fixedMinimalRecordSize; i>=0; i--) { if (IsPositionMatched(i, buffer, distanceFromStartOfBufferToTheEndOfStream)) { return beginPos + i; } } } // At this point we have finished scanning the file and haven't find anything throw new FileFormatException(SR.Get(SRID.CorruptedData)); } private static bool IsPositionMatched (int pos, byte[] buffer, long bufferOffsetFromEndOfStream) { Debug.Assert(buffer != null); Debug.Assert(buffer.Length >= _fixedMinimalRecordSize); // the end of central directory record must fit in there Debug.Assert(pos <= buffer.Length - _fixedMinimalRecordSize); // enough space to fit the record after pos Debug.Assert(bufferOffsetFromEndOfStream >= _fixedMinimalRecordSize); // there is no reason to start searching for the record // after less than 22 byrtes left till the end of stream for(int i = 0; i<_signatureBuffer.Length; i++) { if (_signatureBuffer[i] != buffer[pos+i]) { //signature mismatch return false; } } //we got signature matching, let's see if we can get comment length to match // to handle little endian order of the bytes in the 16 bit length long commentLengthFromRecord = buffer[pos + _fixedMinimalRecordSize-2] + (buffer[pos + _fixedMinimalRecordSize-1] << 8); long commentLengthFromPos = bufferOffsetFromEndOfStream - pos - _fixedMinimalRecordSize; if (commentLengthFromPos != commentLengthFromRecord) { return false; } return true; } private void ParseRecord (BinaryReader reader, long position) { _signature = reader.ReadUInt32(); _numberOfThisDisk = reader.ReadUInt16(); _numberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt16(); _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk = reader.ReadUInt16(); _totalNumberOfEntriesInTheCentralDirectory = reader.ReadUInt16(); _sizeOfTheCentralDirectory = reader.ReadUInt32(); _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt32(); _zipFileCommentLength = reader.ReadUInt16(); _zipFileComment = reader.ReadBytes(_zipFileCommentLength); _stringZipFileComment = _blockManager.Encoding.GetString(_zipFileComment); _offset = position; _dirtyFlag = false; Validate(); } // Do minimum validatation here // The rest of validation on the fields that can indicate the possiblity of Zip64 will be validated later // If there is the zip64 End of Central Directory, thoses values will be valided // by ZipIO64EndOfCentralDirectoryBlock // Otherwise it will be validated in ZipIoBlockManager when it tries load ZipIO64EndOfCentralDirectoryBlock // In all of the supported scenarios we always try to load ZipIO64EndOfCentralDirectoryBlock immediately // after it loads ZipIOEndOfCentralDirectoryBlock; so there is not much difference in the timing of // the validation private void Validate() { if (_signature != _signatureConstant) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } if (_zipFileCommentLength != _zipFileComment.Length) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } } //----------------------------------------------------- // // Private Members // //------------------------------------------------------ // constant that is used for locating EndOf record signature private static byte [] _signatureBuffer = new byte[] {0x50, 0x4b, 0x05, 0x06}; // this blocks size is used to read data thro the tail of stream block by block private static int _scanBlockSize = 0x01000; private ZipIOBlockManager _blockManager; private long _offset; private bool _dirtyFlag; private const UInt32 _signatureConstant = 0x06054b50; private const int _fixedMinimalRecordSize = 22; // data persisted on disk private UInt32 _signature = _signatureConstant; private UInt16 _numberOfThisDisk; private UInt16 _numberOfTheDiskWithTheStartOfTheCentralDirectory; private UInt16 _totalNumberOfEntriesInTheCentralDirectoryOnThisDisk; private UInt16 _totalNumberOfEntriesInTheCentralDirectory; private UInt32 _sizeOfTheCentralDirectory; private UInt32 _offsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; private UInt16 _zipFileCommentLength; private byte[] _zipFileComment; private string _stringZipFileComment; } } // 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
- DeploymentSectionCache.cs
- MetadataException.cs
- RootBuilder.cs
- ItemContainerGenerator.cs
- X509Utils.cs
- XmlBinaryReader.cs
- DBSqlParserColumn.cs
- MdImport.cs
- Brushes.cs
- FactoryGenerator.cs
- FieldNameLookup.cs
- Matrix.cs
- XmlUtf8RawTextWriter.cs
- WindowsUpDown.cs
- AppDomainCompilerProxy.cs
- safex509handles.cs
- ApplicationSecurityInfo.cs
- BrowserCapabilitiesCodeGenerator.cs
- _IPv4Address.cs
- AutoResetEvent.cs
- ObjectStateManager.cs
- Matrix3D.cs
- TraceContextEventArgs.cs
- MulticastNotSupportedException.cs
- StreamUpdate.cs
- WMIGenerator.cs
- RenderContext.cs
- Image.cs
- PageParserFilter.cs
- Size.cs
- XmlParserContext.cs
- HttpRequestCacheValidator.cs
- LinqDataSource.cs
- WebPartChrome.cs
- X509CertificateValidator.cs
- BitmapEffectCollection.cs
- EventTrigger.cs
- Column.cs
- ConsumerConnectionPointCollection.cs
- DataGridViewButtonCell.cs
- EventHandlerList.cs
- WindowsStartMenu.cs
- DbDataSourceEnumerator.cs
- SmiEventSink_Default.cs
- RunClient.cs
- CollectionViewGroupInternal.cs
- WebDisplayNameAttribute.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- TitleStyle.cs
- DeviceFilterEditorDialog.cs
- TabControlCancelEvent.cs
- FormDesigner.cs
- ServerReliableChannelBinder.cs
- ICollection.cs
- XmlNotation.cs
- XmlMemberMapping.cs
- SoapMessage.cs
- ClientSideQueueItem.cs
- Matrix3D.cs
- CodeDirectoryCompiler.cs
- Axis.cs
- PeerDuplexChannelListener.cs
- sitestring.cs
- PointAnimationUsingPath.cs
- XsdDuration.cs
- ProfileGroupSettings.cs
- TypeUtils.cs
- AnnotationResourceCollection.cs
- LinqDataSourceHelper.cs
- ArrayWithOffset.cs
- ChangePassword.cs
- ExpressionDumper.cs
- UserInitiatedRoutedEventPermissionAttribute.cs
- BooleanSwitch.cs
- DataGridViewCellErrorTextNeededEventArgs.cs
- RequestNavigateEventArgs.cs
- IIS7WorkerRequest.cs
- SystemEvents.cs
- RunInstallerAttribute.cs
- ItemContainerProviderWrapper.cs
- ItemCheckEvent.cs
- SchemaObjectWriter.cs
- AxHost.cs
- NativeCompoundFileAPIs.cs
- MetaType.cs
- ContextTokenTypeConverter.cs
- PrintDocument.cs
- PassportIdentity.cs
- ValidationHelper.cs
- Soap.cs
- BuildResultCache.cs
- DbDataSourceEnumerator.cs
- Listbox.cs
- ValidationSummary.cs
- RowUpdatedEventArgs.cs
- Internal.cs
- DesignerObjectListAdapter.cs
- NamedPipeProcessProtocolHandler.cs
- JavaScriptObjectDeserializer.cs
- ResourceDisplayNameAttribute.cs