예제 #1
0
        /// <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);
        }
예제 #3
0
        //------------------------------------------------------
        //
        //  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;
        } 
예제 #5
0
        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);
        }
예제 #6
0
        internal void AddFileBlock(ZipIOLocalFileBlock fileBlock)
        {
            _dirtyFlag = true;

            ZipIOCentralDirectoryFileHeader fileHeader =
                ZipIOCentralDirectoryFileHeader.CreateNew
                    (_blockManager.Encoding, fileBlock);

            CentralDirectoryDictionary.Add(fileHeader.FileName, fileHeader);
        }
예제 #7
0
        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);
        }
예제 #10
0
            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);
                }
            }
예제 #11
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);
        }
예제 #12
0
        /// <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
        } 
예제 #13
0
        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);
 
        }