ZipIOCentralDirectoryFileHeader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Zip / ZipIOCentralDirectoryFileHeader.cs / 1305600 / ZipIOCentralDirectoryFileHeader.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.Text; 
using System.Collections;
using System.Runtime.Serialization;
using System.Windows;
using MS.Internal.WindowsBase; 

namespace MS.Internal.IO.Zip 
{ 
    internal class ZipIOCentralDirectoryFileHeader
    { 
        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 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 void Save(BinaryWriter writer)
        { 
            writer.Write(_signatureConstant);
            writer.Write(_versionMadeBy);
            writer.Write(_versionNeededToExtract);
            writer.Write(_generalPurposeBitFlag); 
            writer.Write(_compressionMethod);
            writer.Write(_lastModFileDateTime); 
            writer.Write(_crc32); 
            writer.Write(_compressedSize);
            writer.Write(_uncompressedSize); 
            writer.Write(_fileNameLength);
            writer.Write(_extraField.Size);
            writer.Write(_fileCommentLength);
            writer.Write(_diskNumberStart); 
            writer.Write(_internalFileAttributes);
            writer.Write(_externalFileAttributes); 
            writer.Write(_relativeOffsetOfLocalHeader); 

 
            Debug.Assert(_fileNameLength > 0); // we validate this for both parsing and API entry points
            writer.Write(_fileName, 0, _fileNameLength);

            _extraField.Save(writer); 

            if (_fileCommentLength > 0) 
            { 
                writer.Write(_fileComment , 0, _fileCommentLength);
            } 
        }

        internal bool UpdateIfNeeded(ZipIOLocalFileBlock fileBlock)
        { 
            if (CheckIfUpdateNeeded(fileBlock))
            { 
                UpdateFromLocalFileBlock(fileBlock); 
                return true;
            } 
            else
            {
                return false;
            } 
        }
 
        internal string FileName 
        {
            get 
            {
                return _stringFileName;
            }
            // set method if needed will have to update both the _stringFileName and 
            // _fileName
        } 
 
        internal UInt16 VersionNeededToExtract
        { 
            get
            {
                return _versionNeededToExtract;
            } 
        }
 
        internal UInt16 GeneralPurposeBitFlag 
        {
            get 
            {
                return _generalPurposeBitFlag;
            }
        } 

        internal CompressionMethodEnum CompressionMethod 
        { 
            get
            { 
                // cast is safe because the value is validated in Validate()
                return (CompressionMethodEnum)_compressionMethod;
            }
        } 

        internal long Size 
        { 
            get
            { 
                return checked(_fixedMinimalRecordSize + _fileNameLength + _extraField.Size + _fileCommentLength);
            }
        }
 
        internal long OffsetOfLocalHeader
        { 
            get 
            {
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) 
                {
                    // zip 64 extra field is there
                    return _extraField.OffsetOfLocalHeader;
                } 
                else
                { 
                    // 32 bit case 
                    return _relativeOffsetOfLocalHeader;
                } 
            }
        }

        internal long CompressedSize 
        {
            get 
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0)
                { 
                    // zip 64 extra field is there
                    return _extraField.CompressedSize;
                }
                else 
                {
                    // 32 bit case 
                    return _compressedSize; 
                }
            } 
        }

        internal long UncompressedSize
        { 
            get
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) 
                {
                    // zip 64 extra field is there 
                    return _extraField.UncompressedSize;
                }
                else
                { 
                    // 32 bit case
                    return _uncompressedSize; 
                } 
            }
        } 

        internal UInt32 Crc32
        {
            get 
            {
                return _crc32; 
            } 
        }
 
        internal UInt32 DiskNumberStart
        {
            get
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0)
                { 
                    // zip 64 extra field is there (32 bit value returned) 
                    return _extraField.DiskNumberOfFileStart;
                } 
                else
                {
                    // 16 bit case
                    return _diskNumberStart;; 
                }
            } 
        } 

        internal bool FolderFlag 
        {
            get
            {
                // The upper byte of version made by indicates the compatibility of the file attribute information. 
                // If the external file attributes are compatible with MS-DOS then this value
                // will be zero. 
 
                // lower byte of the external file attribute is the the MS-DOS directory attribute byte
                // 
                //                          0x20 5   file has been changed since last backup
                //                          0x10 4   entry represents a subdirectory XXXXXXXXX
                //                          0x08 3   entry represents a volume label
                //                          0x04 2   system file 
                //                          0x02 1   hidden file
                //                          0x01 0   read-only 
 
                return  ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos)
                        && 
                            ((_externalFileAttributes & 0x10) != 0);
            }
        }
 
        internal bool VolumeLabelFlag
        { 
            get 
            {
                // The upper byte of version made by indicates the compatibility of the file attribute information. 
                // If the external file attributes are compatible with MS-DOS then this value
                // will be zero.

                // lower byte of the external file attribute is the the MS-DOS directory attribute byte 
                //
                //                          0x20 5   file has been changed since last backup 
                //                          0x10 4   entry represents a subdirectory 
                //                          0x08 3   entry represents a volume label  XXXXXXXXX
                //                          0x04 2   system file 
                //                          0x02 1   hidden file
                //                          0x01 0   read-only

                return  ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos) 
                        &&
                            ((_externalFileAttributes & 0x08) != 0); 
            } 
        }
 
        // this function is called by the Central Dir in order to notify us that
        // the appropriate file item was shifted (as detected by the shift in the Raw Data Block)
        // holding given file item.
        // for us it means that although all the size characteristics are preserved (local file header 
        // wasn't even parsed if it still in the Raw). But the offset could have changed which
        // might result in Zip64 struicture. 
        internal void MoveReference(long shiftSize) 
        {
 
            UpdateZip64Structures(CompressedSize,
                                                            UncompressedSize,
                                                            checked(OffsetOfLocalHeader +shiftSize));
        } 

        // this function is sets the sizes into the either 64 or 32 bit structures based on values of the fields 
        // It used in 2 places by the MoveReference and by the UpdateFromLocalFileBlock 
        private void UpdateZip64Structures
                (long compressedSize, long uncompressedSize, long offset) 
        {
            Debug.Assert((compressedSize >= 0) && (uncompressedSize>=0) && (offset >=0));

            // according to the appnote central directory extra field might be a mix of any values based on escaping 
            // we will fully (without disk number) use it every time we are building a ZIP 64 arhichive
            // we also trying to stay on the safe side and treeat the boundary case of 32 escape values 
            // as a zip 64 scenrio 
            if ((compressedSize >= UInt32.MaxValue) ||
                    (uncompressedSize >= UInt32.MaxValue) || 
                    (offset >= UInt32.MaxValue))
            {
                // Zip 64 case
                _extraField.CompressedSize = compressedSize; 
                _extraField.UncompressedSize = uncompressedSize;
                _extraField.OffsetOfLocalHeader = offset; 
 
                //set proper escape values
               _compressedSize = UInt32.MaxValue; 
               _uncompressedSize = UInt32.MaxValue;
               _relativeOffsetOfLocalHeader = UInt32.MaxValue;

                // update version needed to extract to 4.5 
                _versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat;
            } 
            else 
            {
                // 32 bit case 
               _compressedSize = checked((UInt32)compressedSize);
               _uncompressedSize = checked((UInt32)uncompressedSize);
               _relativeOffsetOfLocalHeader = checked((UInt32)offset);
 
                // reset the extra ZIP 64 field to empty
               _extraField.Zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None; 
 
                // version needed to extract needs to be recalculated from scratch based on compression
                _versionNeededToExtract = (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression 
                                                                                            ((CompressionMethodEnum)_compressionMethod);
            }
        }
 
        private void  UpdateFromLocalFileBlock(ZipIOLocalFileBlock fileBlock)
        { 
            Debug.Assert(DiskNumberStart == 0); 

            _signature = _signatureConstant; 
            _generalPurposeBitFlag = fileBlock.GeneralPurposeBitFlag;
            _compressionMethod = (UInt16)fileBlock.CompressionMethod;
            _lastModFileDateTime = fileBlock.LastModFileDateTime;
            _crc32 = fileBlock.Crc32; 

            // file name is easy to copy 
            _fileNameLength = (UInt16)fileBlock.FileName.Length; // this is safe cast as file name is always validate for size 
            _fileName = _encoding.GetBytes(fileBlock.FileName);
            _stringFileName = fileBlock.FileName; 

            // this will properly update the 32 or zip 64 fields
            UpdateZip64Structures(fileBlock.CompressedSize,
                                    fileBlock.UncompressedSize, 
                                    fileBlock.Offset);
 
            // Previous instruction may determine that we don't really need 4.5, but we 
            // want to ensure that the version is identical with what is stored in the local file header.
            Debug.Assert(_versionNeededToExtract <= fileBlock.VersionNeededToExtract, "Should never be making this smaller"); 

            _versionNeededToExtract = fileBlock.VersionNeededToExtract;

            // These fields are intentionally ignored, as they are not present in the local header 
                        //_fileCommentLength;
                        //_fileComment; 
                        //_diskNumberStart; 
                        //_internalFileAttributes;
                        //_externalFileAttributes; 
        }

        private bool CheckIfUpdateNeeded(ZipIOLocalFileBlock fileBlock)
        { 
            // there is a special case for the _generalPurposeBitFlag.Bit #3
            // it could be set in the local file header indicating streaming 
            // creation, while it doesn't need to be set in the Central directory 
            // so having
            //  (fileBlock.GeneralPurposeBitFlag == 8 && and _generalPurposeBitFlag  == 0) 
            // is a valid case when update is not required

            // let's compare the 3rd bit of the general purpose bit flag
            bool localFileHeaderStreamingFlag = (0 != (fileBlock.GeneralPurposeBitFlag & _streamingBitMask)); 
            bool centralDirStreamingFlag = (0 != (_generalPurposeBitFlag & _streamingBitMask));
 
            if (!localFileHeaderStreamingFlag  && centralDirStreamingFlag) 
            {
                // the mismatch if local file header in non streaming but the central directory is in streaming mode 
                // all the other combinations do not require an update and valid as is
                // this includes scenario when local file header is in streaming and central dir is not
                return true;
            } 

            Debug.Assert(String.CompareOrdinal(_stringFileName, fileBlock.FileName) == 0); 
 
            return
                (_signature != _signatureConstant) || 
                (_versionNeededToExtract != fileBlock.VersionNeededToExtract) ||
                (_generalPurposeBitFlag != fileBlock.GeneralPurposeBitFlag) ||
                (_compressionMethod != (UInt16)fileBlock.CompressionMethod) ||
                (_crc32 != fileBlock.Crc32) || 
                (CompressedSize != fileBlock.CompressedSize) ||
                (UncompressedSize != fileBlock.UncompressedSize) || 
                (OffsetOfLocalHeader != fileBlock.Offset); 

                // These fields are intentionally ignored, as they are not present in the local header 
                            //_fileCommentLength;
                            //_fileComment;
                            //_diskNumberStart;
                            //_internalFileAttributes; 
                            //_externalFileAttributes;
        } 
 

        private ZipIOCentralDirectoryFileHeader(Encoding encoding) 
        {
            _encoding = encoding;
        }
 
        private void Validate ()
        { 
            if (_signature != _signatureConstant) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }

            if (DiskNumberStart != 0)
            { 
                throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk));
            } 
 
            if (_fileNameLength != _fileName.Length)
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }

            if (_extraFieldLength != _extraField.Size) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            } 

            ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); 

            // if verson is below 4.5 make sure that ZIP 64 extra filed isn't present
            // if it is it might be a security concern
            if ((_versionNeededToExtract < (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) && 
                (_extraField.Zip64ExtraFieldUsage != ZipIOZip64ExtraFieldUsage.None))
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
 
            if (_fileCommentLength != _fileComment.Length)
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            } 

            if ((_compressionMethod != (UInt16)CompressionMethodEnum.Stored) && 
                (_compressionMethod != (UInt16)CompressionMethodEnum.Deflated)) 
            {
                throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); 
            }
        }

        private Encoding _encoding; 
        private const int _fixedMinimalRecordSize = 46;
 
        private const byte _constantUpperVersionMadeByMsDos = 0x0; 

        private const UInt16 _streamingBitMask = 0x08; // bit #3 

        private const UInt32 _signatureConstant = 0x02014b50;
        private UInt32 _signature = _signatureConstant;
 
        // we expect all variables to be initialized to 0
        private UInt16 _versionMadeBy; 
        private UInt16 _versionNeededToExtract; 
        private UInt16 _generalPurposeBitFlag;
        private UInt16 _compressionMethod; 
        private UInt32 _lastModFileDateTime;
        private UInt32 _crc32;
        private UInt32 _compressedSize;
        private UInt32 _uncompressedSize; 
        private UInt16 _fileNameLength;
        private UInt16 _extraFieldLength; 
        private UInt16 _fileCommentLength; 
        private UInt16 _diskNumberStart;
        private UInt16 _internalFileAttributes; 
        private UInt32 _externalFileAttributes;
        private UInt32 _relativeOffsetOfLocalHeader;
        private byte[] _fileName;
        private ZipIOExtraField _extraField; 
        private byte[] _fileComment;
 
        //duplicate dat for fast access 
        private string _stringFileName;
    } 
}

// 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
// 
// History:
//  11/19/2004: IgorBel: Initial creation.
//
//----------------------------------------------------------------------------- 

using System; 
using System.IO; 
using System.Diagnostics;
using System.Text; 
using System.Collections;
using System.Runtime.Serialization;
using System.Windows;
using MS.Internal.WindowsBase; 

namespace MS.Internal.IO.Zip 
{ 
    internal class ZipIOCentralDirectoryFileHeader
    { 
        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 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 void Save(BinaryWriter writer)
        { 
            writer.Write(_signatureConstant);
            writer.Write(_versionMadeBy);
            writer.Write(_versionNeededToExtract);
            writer.Write(_generalPurposeBitFlag); 
            writer.Write(_compressionMethod);
            writer.Write(_lastModFileDateTime); 
            writer.Write(_crc32); 
            writer.Write(_compressedSize);
            writer.Write(_uncompressedSize); 
            writer.Write(_fileNameLength);
            writer.Write(_extraField.Size);
            writer.Write(_fileCommentLength);
            writer.Write(_diskNumberStart); 
            writer.Write(_internalFileAttributes);
            writer.Write(_externalFileAttributes); 
            writer.Write(_relativeOffsetOfLocalHeader); 

 
            Debug.Assert(_fileNameLength > 0); // we validate this for both parsing and API entry points
            writer.Write(_fileName, 0, _fileNameLength);

            _extraField.Save(writer); 

            if (_fileCommentLength > 0) 
            { 
                writer.Write(_fileComment , 0, _fileCommentLength);
            } 
        }

        internal bool UpdateIfNeeded(ZipIOLocalFileBlock fileBlock)
        { 
            if (CheckIfUpdateNeeded(fileBlock))
            { 
                UpdateFromLocalFileBlock(fileBlock); 
                return true;
            } 
            else
            {
                return false;
            } 
        }
 
        internal string FileName 
        {
            get 
            {
                return _stringFileName;
            }
            // set method if needed will have to update both the _stringFileName and 
            // _fileName
        } 
 
        internal UInt16 VersionNeededToExtract
        { 
            get
            {
                return _versionNeededToExtract;
            } 
        }
 
        internal UInt16 GeneralPurposeBitFlag 
        {
            get 
            {
                return _generalPurposeBitFlag;
            }
        } 

        internal CompressionMethodEnum CompressionMethod 
        { 
            get
            { 
                // cast is safe because the value is validated in Validate()
                return (CompressionMethodEnum)_compressionMethod;
            }
        } 

        internal long Size 
        { 
            get
            { 
                return checked(_fixedMinimalRecordSize + _fileNameLength + _extraField.Size + _fileCommentLength);
            }
        }
 
        internal long OffsetOfLocalHeader
        { 
            get 
            {
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0) 
                {
                    // zip 64 extra field is there
                    return _extraField.OffsetOfLocalHeader;
                } 
                else
                { 
                    // 32 bit case 
                    return _relativeOffsetOfLocalHeader;
                } 
            }
        }

        internal long CompressedSize 
        {
            get 
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0)
                { 
                    // zip 64 extra field is there
                    return _extraField.CompressedSize;
                }
                else 
                {
                    // 32 bit case 
                    return _compressedSize; 
                }
            } 
        }

        internal long UncompressedSize
        { 
            get
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0) 
                {
                    // zip 64 extra field is there 
                    return _extraField.UncompressedSize;
                }
                else
                { 
                    // 32 bit case
                    return _uncompressedSize; 
                } 
            }
        } 

        internal UInt32 Crc32
        {
            get 
            {
                return _crc32; 
            } 
        }
 
        internal UInt32 DiskNumberStart
        {
            get
            { 
                if ((_extraField.Zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0)
                { 
                    // zip 64 extra field is there (32 bit value returned) 
                    return _extraField.DiskNumberOfFileStart;
                } 
                else
                {
                    // 16 bit case
                    return _diskNumberStart;; 
                }
            } 
        } 

        internal bool FolderFlag 
        {
            get
            {
                // The upper byte of version made by indicates the compatibility of the file attribute information. 
                // If the external file attributes are compatible with MS-DOS then this value
                // will be zero. 
 
                // lower byte of the external file attribute is the the MS-DOS directory attribute byte
                // 
                //                          0x20 5   file has been changed since last backup
                //                          0x10 4   entry represents a subdirectory XXXXXXXXX
                //                          0x08 3   entry represents a volume label
                //                          0x04 2   system file 
                //                          0x02 1   hidden file
                //                          0x01 0   read-only 
 
                return  ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos)
                        && 
                            ((_externalFileAttributes & 0x10) != 0);
            }
        }
 
        internal bool VolumeLabelFlag
        { 
            get 
            {
                // The upper byte of version made by indicates the compatibility of the file attribute information. 
                // If the external file attributes are compatible with MS-DOS then this value
                // will be zero.

                // lower byte of the external file attribute is the the MS-DOS directory attribute byte 
                //
                //                          0x20 5   file has been changed since last backup 
                //                          0x10 4   entry represents a subdirectory 
                //                          0x08 3   entry represents a volume label  XXXXXXXXX
                //                          0x04 2   system file 
                //                          0x02 1   hidden file
                //                          0x01 0   read-only

                return  ((_versionMadeBy & 0xFF00) == _constantUpperVersionMadeByMsDos) 
                        &&
                            ((_externalFileAttributes & 0x08) != 0); 
            } 
        }
 
        // this function is called by the Central Dir in order to notify us that
        // the appropriate file item was shifted (as detected by the shift in the Raw Data Block)
        // holding given file item.
        // for us it means that although all the size characteristics are preserved (local file header 
        // wasn't even parsed if it still in the Raw). But the offset could have changed which
        // might result in Zip64 struicture. 
        internal void MoveReference(long shiftSize) 
        {
 
            UpdateZip64Structures(CompressedSize,
                                                            UncompressedSize,
                                                            checked(OffsetOfLocalHeader +shiftSize));
        } 

        // this function is sets the sizes into the either 64 or 32 bit structures based on values of the fields 
        // It used in 2 places by the MoveReference and by the UpdateFromLocalFileBlock 
        private void UpdateZip64Structures
                (long compressedSize, long uncompressedSize, long offset) 
        {
            Debug.Assert((compressedSize >= 0) && (uncompressedSize>=0) && (offset >=0));

            // according to the appnote central directory extra field might be a mix of any values based on escaping 
            // we will fully (without disk number) use it every time we are building a ZIP 64 arhichive
            // we also trying to stay on the safe side and treeat the boundary case of 32 escape values 
            // as a zip 64 scenrio 
            if ((compressedSize >= UInt32.MaxValue) ||
                    (uncompressedSize >= UInt32.MaxValue) || 
                    (offset >= UInt32.MaxValue))
            {
                // Zip 64 case
                _extraField.CompressedSize = compressedSize; 
                _extraField.UncompressedSize = uncompressedSize;
                _extraField.OffsetOfLocalHeader = offset; 
 
                //set proper escape values
               _compressedSize = UInt32.MaxValue; 
               _uncompressedSize = UInt32.MaxValue;
               _relativeOffsetOfLocalHeader = UInt32.MaxValue;

                // update version needed to extract to 4.5 
                _versionNeededToExtract = (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat;
            } 
            else 
            {
                // 32 bit case 
               _compressedSize = checked((UInt32)compressedSize);
               _uncompressedSize = checked((UInt32)uncompressedSize);
               _relativeOffsetOfLocalHeader = checked((UInt32)offset);
 
                // reset the extra ZIP 64 field to empty
               _extraField.Zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None; 
 
                // version needed to extract needs to be recalculated from scratch based on compression
                _versionNeededToExtract = (UInt16)ZipIOBlockManager.CalcVersionNeededToExtractFromCompression 
                                                                                            ((CompressionMethodEnum)_compressionMethod);
            }
        }
 
        private void  UpdateFromLocalFileBlock(ZipIOLocalFileBlock fileBlock)
        { 
            Debug.Assert(DiskNumberStart == 0); 

            _signature = _signatureConstant; 
            _generalPurposeBitFlag = fileBlock.GeneralPurposeBitFlag;
            _compressionMethod = (UInt16)fileBlock.CompressionMethod;
            _lastModFileDateTime = fileBlock.LastModFileDateTime;
            _crc32 = fileBlock.Crc32; 

            // file name is easy to copy 
            _fileNameLength = (UInt16)fileBlock.FileName.Length; // this is safe cast as file name is always validate for size 
            _fileName = _encoding.GetBytes(fileBlock.FileName);
            _stringFileName = fileBlock.FileName; 

            // this will properly update the 32 or zip 64 fields
            UpdateZip64Structures(fileBlock.CompressedSize,
                                    fileBlock.UncompressedSize, 
                                    fileBlock.Offset);
 
            // Previous instruction may determine that we don't really need 4.5, but we 
            // want to ensure that the version is identical with what is stored in the local file header.
            Debug.Assert(_versionNeededToExtract <= fileBlock.VersionNeededToExtract, "Should never be making this smaller"); 

            _versionNeededToExtract = fileBlock.VersionNeededToExtract;

            // These fields are intentionally ignored, as they are not present in the local header 
                        //_fileCommentLength;
                        //_fileComment; 
                        //_diskNumberStart; 
                        //_internalFileAttributes;
                        //_externalFileAttributes; 
        }

        private bool CheckIfUpdateNeeded(ZipIOLocalFileBlock fileBlock)
        { 
            // there is a special case for the _generalPurposeBitFlag.Bit #3
            // it could be set in the local file header indicating streaming 
            // creation, while it doesn't need to be set in the Central directory 
            // so having
            //  (fileBlock.GeneralPurposeBitFlag == 8 && and _generalPurposeBitFlag  == 0) 
            // is a valid case when update is not required

            // let's compare the 3rd bit of the general purpose bit flag
            bool localFileHeaderStreamingFlag = (0 != (fileBlock.GeneralPurposeBitFlag & _streamingBitMask)); 
            bool centralDirStreamingFlag = (0 != (_generalPurposeBitFlag & _streamingBitMask));
 
            if (!localFileHeaderStreamingFlag  && centralDirStreamingFlag) 
            {
                // the mismatch if local file header in non streaming but the central directory is in streaming mode 
                // all the other combinations do not require an update and valid as is
                // this includes scenario when local file header is in streaming and central dir is not
                return true;
            } 

            Debug.Assert(String.CompareOrdinal(_stringFileName, fileBlock.FileName) == 0); 
 
            return
                (_signature != _signatureConstant) || 
                (_versionNeededToExtract != fileBlock.VersionNeededToExtract) ||
                (_generalPurposeBitFlag != fileBlock.GeneralPurposeBitFlag) ||
                (_compressionMethod != (UInt16)fileBlock.CompressionMethod) ||
                (_crc32 != fileBlock.Crc32) || 
                (CompressedSize != fileBlock.CompressedSize) ||
                (UncompressedSize != fileBlock.UncompressedSize) || 
                (OffsetOfLocalHeader != fileBlock.Offset); 

                // These fields are intentionally ignored, as they are not present in the local header 
                            //_fileCommentLength;
                            //_fileComment;
                            //_diskNumberStart;
                            //_internalFileAttributes; 
                            //_externalFileAttributes;
        } 
 

        private ZipIOCentralDirectoryFileHeader(Encoding encoding) 
        {
            _encoding = encoding;
        }
 
        private void Validate ()
        { 
            if (_signature != _signatureConstant) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }

            if (DiskNumberStart != 0)
            { 
                throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk));
            } 
 
            if (_fileNameLength != _fileName.Length)
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }

            if (_extraFieldLength != _extraField.Size) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            } 

            ZipArchive.VerifyVersionNeededToExtract(_versionNeededToExtract); 

            // if verson is below 4.5 make sure that ZIP 64 extra filed isn't present
            // if it is it might be a security concern
            if ((_versionNeededToExtract < (UInt16)ZipIOVersionNeededToExtract.Zip64FileFormat) && 
                (_extraField.Zip64ExtraFieldUsage != ZipIOZip64ExtraFieldUsage.None))
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
 
            if (_fileCommentLength != _fileComment.Length)
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            } 

            if ((_compressionMethod != (UInt16)CompressionMethodEnum.Stored) && 
                (_compressionMethod != (UInt16)CompressionMethodEnum.Deflated)) 
            {
                throw new NotSupportedException(SR.Get(SRID.ZipNotSupportedCompressionMethod)); 
            }
        }

        private Encoding _encoding; 
        private const int _fixedMinimalRecordSize = 46;
 
        private const byte _constantUpperVersionMadeByMsDos = 0x0; 

        private const UInt16 _streamingBitMask = 0x08; // bit #3 

        private const UInt32 _signatureConstant = 0x02014b50;
        private UInt32 _signature = _signatureConstant;
 
        // we expect all variables to be initialized to 0
        private UInt16 _versionMadeBy; 
        private UInt16 _versionNeededToExtract; 
        private UInt16 _generalPurposeBitFlag;
        private UInt16 _compressionMethod; 
        private UInt32 _lastModFileDateTime;
        private UInt32 _crc32;
        private UInt32 _compressedSize;
        private UInt32 _uncompressedSize; 
        private UInt16 _fileNameLength;
        private UInt16 _extraFieldLength; 
        private UInt16 _fileCommentLength; 
        private UInt16 _diskNumberStart;
        private UInt16 _internalFileAttributes; 
        private UInt32 _externalFileAttributes;
        private UInt32 _relativeOffsetOfLocalHeader;
        private byte[] _fileName;
        private ZipIOExtraField _extraField; 
        private byte[] _fileComment;
 
        //duplicate dat for fast access 
        private string _stringFileName;
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK