/// <summary> /// Validate /// </summary> /// <param name="fileName">pre-trimmed and normalized filename (see ValidateNormalizeFileName)</param> /// <param name="centralDir">central directory block</param> /// <param name="centralDirFileHeader">file header from central directory</param> private void Validate(string fileName, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { // check that name matches parameter in a case sensitive culture neutral way if (0 != String.CompareOrdinal(_localFileHeader.FileName, fileName)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // compare compressed and uncompressed sizes, crc from central directory if ((VersionNeededToExtract != centralDirFileHeader.VersionNeededToExtract) || (GeneralPurposeBitFlag != centralDirFileHeader.GeneralPurposeBitFlag) || (CompressedSize != centralDirFileHeader.CompressedSize) || (UncompressedSize != centralDirFileHeader.UncompressedSize) || (CompressionMethod != centralDirFileHeader.CompressionMethod) || (Crc32 != centralDirFileHeader.Crc32)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // check for read into central directory (which would indicate file corruption) if (Offset + Size > centralDir.Offset) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // No CRC check here // delay validating the actual CRC until it is possible to do so without additional read operations // This is only for non-streaming mode (at this point we only support creation not consumption) // This is to avoid the forced reading of entire stream just for CRC check // CRC check is delegated to ProgressiveCrcCalculatingStream and CRC is only validated // once calculated CRC is available. This implies that CRC check operation is not // guaranteed to be performed }
internal static ZipIOCentralDirectoryFileHeader ParseRecord(BinaryReader reader, Encoding encoding) { ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); header._signature = reader.ReadUInt32(); header._versionMadeBy = reader.ReadUInt16(); header._versionNeededToExtract = reader.ReadUInt16(); header._generalPurposeBitFlag = reader.ReadUInt16(); header._compressionMethod = reader.ReadUInt16(); header._lastModFileDateTime = reader.ReadUInt32(); header._crc32 = reader.ReadUInt32(); header._compressedSize = reader.ReadUInt32(); header._uncompressedSize = reader.ReadUInt32(); header._fileNameLength = reader.ReadUInt16(); header._extraFieldLength = reader.ReadUInt16(); header._fileCommentLength = reader.ReadUInt16(); header._diskNumberStart = reader.ReadUInt16(); header._internalFileAttributes = reader.ReadUInt16(); header._externalFileAttributes = reader.ReadUInt32(); header._relativeOffsetOfLocalHeader = reader.ReadUInt32(); header._fileName = reader.ReadBytes(header._fileNameLength); // check for the ZIP 64 version and escaped values ZipIOZip64ExtraFieldUsage zip64extraFieldUsage = ZipIOZip64ExtraFieldUsage.None; if (header._versionNeededToExtract >= (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat) { if (header._compressedSize == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize; } if (header._uncompressedSize == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize; } if (header._relativeOffsetOfLocalHeader == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader; } if (header._diskNumberStart == UInt16.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.DiskNumber; } } // if the ZIP 64 record is missing the zip64extraFieldUsage value will be ignored header._extraField = ZipIOExtraField.ParseRecord(reader, zip64extraFieldUsage, header._extraFieldLength); header._fileComment = reader.ReadBytes(header._fileCommentLength); //populate frequently used field with user friendly data representations header._stringFileName = ZipIOBlockManager.ValidateNormalizeFileName(encoding.GetString(header._fileName)); header.Validate(); return(header); }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ internal static ZipIOLocalFileBlock SeekableLoad(ZipIOBlockManager blockManager, string fileName) { Debug.Assert(!blockManager.Streaming); Debug.Assert(blockManager.CentralDirectoryBlock.FileExists(fileName)); // Get info from the central directory ZipIOCentralDirectoryBlock centralDir = blockManager.CentralDirectoryBlock; ZipIOCentralDirectoryFileHeader centralDirFileHeader = centralDir.GetCentralDirectoryFileHeader(fileName); long localHeaderOffset = centralDirFileHeader.OffsetOfLocalHeader; bool folderFlag = centralDirFileHeader.FolderFlag; bool volumeLabelFlag = centralDirFileHeader.VolumeLabelFlag; blockManager.Stream.Seek(localHeaderOffset, SeekOrigin.Begin); ZipIOLocalFileBlock block = new ZipIOLocalFileBlock(blockManager, folderFlag, volumeLabelFlag); block.ParseRecord( blockManager.BinaryReader, fileName, localHeaderOffset, centralDir, centralDirFileHeader); return(block); }
internal static ZipIOCentralDirectoryFileHeader ParseRecord(BinaryReader reader, Encoding encoding) { ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); header._signature = reader.ReadUInt32(); header._versionMadeBy = reader.ReadUInt16(); header._versionNeededToExtract = reader.ReadUInt16(); header._generalPurposeBitFlag = reader.ReadUInt16(); header._compressionMethod = reader.ReadUInt16(); header._lastModFileDateTime = reader.ReadUInt32(); header._crc32 = reader.ReadUInt32(); header._compressedSize = reader.ReadUInt32(); header._uncompressedSize = reader.ReadUInt32(); header._fileNameLength = reader.ReadUInt16(); header._extraFieldLength = reader.ReadUInt16(); header._fileCommentLength = reader.ReadUInt16(); header._diskNumberStart = reader.ReadUInt16(); header._internalFileAttributes = reader.ReadUInt16(); header._externalFileAttributes = reader.ReadUInt32(); header._relativeOffsetOfLocalHeader = reader.ReadUInt32(); header._fileName = reader.ReadBytes(header._fileNameLength); // check for the ZIP 64 version and escaped values ZipIOZip64ExtraFieldUsage zip64extraFieldUsage = ZipIOZip64ExtraFieldUsage.None; if (header._versionNeededToExtract >= (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat) { if (header._compressedSize == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize; } if (header._uncompressedSize == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize; } if (header._relativeOffsetOfLocalHeader == UInt32.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader; } if (header._diskNumberStart == UInt16.MaxValue) { zip64extraFieldUsage |= ZipIOZip64ExtraFieldUsage.DiskNumber; } } // if the ZIP 64 record is missing the zip64extraFieldUsage value will be ignored header._extraField = ZipIOExtraField.ParseRecord(reader, zip64extraFieldUsage, header._extraFieldLength); header._fileComment = reader.ReadBytes(header._fileCommentLength); //populate frequently used field with user friendly data representations header._stringFileName = ZipIOBlockManager.ValidateNormalizeFileName(encoding.GetString(header._fileName)); header.Validate(); return header; }
private void ParseRecord(BinaryReader reader, string fileName, long position, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); _localFileHeader = ZipIOLocalFileHeader.ParseRecord(reader, _blockManager.Encoding); // Let's find out whether local file descriptor is there or not if (_localFileHeader.StreamingCreationFlag) { // seek forward by the uncompressed size _blockManager.Stream.Seek(centralDirFileHeader.CompressedSize, SeekOrigin.Current); _localFileDataDescriptor = ZipIOLocalFileDataDescriptor.ParseRecord(reader, centralDirFileHeader.CompressedSize, centralDirFileHeader.UncompressedSize, centralDirFileHeader.Crc32, _localFileHeader.VersionNeededToExtract); } else { _localFileDataDescriptor = null; } _offset = position; _dirtyFlag = false; checked { _fileItemStream = new ZipIOFileItemStream(_blockManager, this, position + _localFileHeader.Size, centralDirFileHeader.CompressedSize); } // init deflate stream if necessary if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(_fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); _deflateStream = new CompressStream(_fileItemStream, centralDirFileHeader.UncompressedSize); _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _deflateStream, Crc32); } else if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Stored) { _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _fileItemStream, Crc32); } else { throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); } Validate(fileName, centralDir, centralDirFileHeader); }
internal void AddFileBlock(ZipIOLocalFileBlock fileBlock) { _dirtyFlag = true; ZipIOCentralDirectoryFileHeader fileHeader = ZipIOCentralDirectoryFileHeader.CreateNew (_blockManager.Encoding, fileBlock); CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); }
public void UpdateReferences(bool closingFlag) { // we just need to ask Block Manager for the new Values for each header // there are 2 distinct cases here // 1. local file data is mapped . loaded and might have been changed in size and position // 2. local file data is not loaded and might have been changed only in position (not in size) foreach (IZipIOBlock block in _blockManager) { ZipIOLocalFileBlock localFileBlock = block as ZipIOLocalFileBlock; ZipIORawDataFileBlock rawDataFileBlock = block as ZipIORawDataFileBlock; if (localFileBlock != null) { // this is case 1 data is mapped and loaded, so we only need to find the matching // Centraldirectory record and update it Debug.Assert(CentralDirectoryDictionary.Contains(localFileBlock.FileName)); ZipIOCentralDirectoryFileHeader centralDirFileHeader = (ZipIOCentralDirectoryFileHeader)CentralDirectoryDictionary[localFileBlock.FileName]; if (centralDirFileHeader.UpdateIfNeeded(localFileBlock)) { //update was required let's mark ourselves as dirty _dirtyFlag = true; } } //check whether we deal with raw data block and it was moved else if (rawDataFileBlock != null) { long diskImageShift = rawDataFileBlock.DiskImageShift; if (diskImageShift != 0) { //this is case #2 data isn't loaded based on the shift in the RawData Block // we need to move all overlapping central directory references foreach (ZipIOCentralDirectoryFileHeader centralDirFileHeader in CentralDirectoryDictionary.Values) { // check whether central dir header points into the region of a moved RawDataBlock if (rawDataFileBlock.DiskImageContains(centralDirFileHeader.OffsetOfLocalHeader)) { centralDirFileHeader.MoveReference(diskImageShift); _dirtyFlag = true; } } } } } }
internal static ZipIOCentralDirectoryFileHeader CreateNew(Encoding encoding, ZipIOLocalFileBlock fileBlock) { ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); // initialize fields that are not duplicated in the local file block(header) header._fileCommentLength =0; header._fileComment = null; header._diskNumberStart = 0; header._internalFileAttributes = 0; header._externalFileAttributes = 0; header._versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; header._extraField = ZipIOExtraField.CreateNew(false /* no padding */); // update the rest of the fields based on the local file header header.UpdateFromLocalFileBlock(fileBlock); return header; }
internal static ZipIOCentralDirectoryFileHeader CreateNew(Encoding encoding, ZipIOLocalFileBlock fileBlock) { ZipIOCentralDirectoryFileHeader header = new ZipIOCentralDirectoryFileHeader(encoding); // initialize fields that are not duplicated in the local file block(header) header._fileCommentLength = 0; header._fileComment = null; header._diskNumberStart = 0; header._internalFileAttributes = 0; header._externalFileAttributes = 0; header._versionMadeBy = (ushort)ZipIOVersionNeededToExtract.Zip64FileFormat; header._extraField = ZipIOExtraField.CreateNew(false /* no padding */); // update the rest of the fields based on the local file header header.UpdateFromLocalFileBlock(fileBlock); return(header); }
int IComparer.Compare(object o1, object o2) { ZipIOCentralDirectoryFileHeader h1 = o1 as ZipIOCentralDirectoryFileHeader; ZipIOCentralDirectoryFileHeader h2 = o2 as ZipIOCentralDirectoryFileHeader; Debug.Assert(h1 != null && h2 != null, "HeaderFileOffsetComparer: Comparing the wrong data types"); // avoid boxing - don't cast long value to (IComparable) if (h1.OffsetOfLocalHeader > h2.OffsetOfLocalHeader) { return(1); } else if (h1.OffsetOfLocalHeader < h2.OffsetOfLocalHeader) { return(-1); } else { return(0); } }
private void ParseRecord(BinaryReader reader, long centralDirectoryOffset, int centralDirectoryCount, long expectedCentralDirectorySize) { if (centralDirectoryCount > 0) { // collect all headers into a local array list for sorting SortedList headerList = new SortedList(centralDirectoryCount); ZipIOCentralDirectoryFileHeader header; for (int i = 0; i < centralDirectoryCount; i++) { header = ZipIOCentralDirectoryFileHeader.ParseRecord(reader, _blockManager.Encoding); headerList.Add(header.OffsetOfLocalHeader, header); } if (reader.BaseStream.Position - centralDirectoryOffset > expectedCentralDirectorySize) { // it looks like a corrupted file, as we have parsed more than central directory supposed to contain throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // then add to the ordered dictionary in sorted order foreach (ZipIOCentralDirectoryFileHeader fileHeader in headerList.Values) { // at this point fileHeader.FileName is normalized using // the ZipIOBlockManager.ValidateNormalizeFileName CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader); } //load central directory [digital signature] - this has nothing to // do with OPC digital signing // this record is optional, and the function might return null _centralDirectoryDigitalSignature = ZipIOCentralDirectoryDigitalSignature.ParseRecord(reader); } _offset = centralDirectoryOffset; _dirtyFlag = false; Validate(expectedCentralDirectorySize); }
/// <summary> /// Validate /// </summary> /// <param name="fileName">pre-trimmed and normalized filename (see ValidateNormalizeFileName)</param> /// <param name="centralDir">central directory block</param> /// <param name="centralDirFileHeader">file header from central directory</param> private void Validate(string fileName, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { // check that name matches parameter in a case sensitive culture neutral way if (0 != String.CompareOrdinal(_localFileHeader.FileName, fileName)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // compare compressed and uncompressed sizes, crc from central directory if ((VersionNeededToExtract != centralDirFileHeader.VersionNeededToExtract) || (GeneralPurposeBitFlag != centralDirFileHeader.GeneralPurposeBitFlag) || (CompressedSize != centralDirFileHeader.CompressedSize) || (UncompressedSize != centralDirFileHeader.UncompressedSize) || (CompressionMethod != centralDirFileHeader.CompressionMethod) || (Crc32 != centralDirFileHeader.Crc32)) { throw new FileFormatException(SR.Get(SRID.CorruptedData)); } // check for read into central directory (which would indicate file corruption) if (Offset + Size > centralDir.Offset) throw new FileFormatException(SR.Get(SRID.CorruptedData)); // No CRC check here // delay validating the actual CRC until it is possible to do so without additional read operations // This is only for non-streaming mode (at this point we only support creation not consumption) // This is to avoid the forced reading of entire stream just for CRC check // CRC check is delegated to ProgressiveCrcCalculatingStream and CRC is only validated // once calculated CRC is available. This implies that CRC check operation is not // guaranteed to be performed }
private void ParseRecord (BinaryReader reader, string fileName, long position, ZipIOCentralDirectoryBlock centralDir, ZipIOCentralDirectoryFileHeader centralDirFileHeader) { CheckDisposed(); Debug.Assert(!_blockManager.Streaming, "Not legal in Streaming mode"); _localFileHeader = ZipIOLocalFileHeader.ParseRecord(reader, _blockManager.Encoding); // Let's find out whether local file descriptor is there or not if (_localFileHeader.StreamingCreationFlag) { // seek forward by the uncompressed size _blockManager.Stream.Seek(centralDirFileHeader.CompressedSize, SeekOrigin.Current); _localFileDataDescriptor = ZipIOLocalFileDataDescriptor.ParseRecord(reader, centralDirFileHeader.CompressedSize, centralDirFileHeader.UncompressedSize, centralDirFileHeader.Crc32, _localFileHeader.VersionNeededToExtract); } else { _localFileDataDescriptor = null; } _offset = position; _dirtyFlag = false; checked { _fileItemStream = new ZipIOFileItemStream(_blockManager, this, position + _localFileHeader.Size, centralDirFileHeader.CompressedSize); } // init deflate stream if necessary if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Deflated) { Debug.Assert(_fileItemStream.Position == 0, "CompressStream assumes base stream is at position zero"); _deflateStream = new CompressStream(_fileItemStream, centralDirFileHeader.UncompressedSize); _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _deflateStream, Crc32); } else if ((CompressionMethodEnum)_localFileHeader.CompressionMethod == CompressionMethodEnum.Stored) { _crcCalculatingStream = new ProgressiveCrcCalculatingStream(_blockManager, _fileItemStream, Crc32); } else { throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); } Validate(fileName, centralDir, centralDirFileHeader); }