ZipIOZip64EndOfCentralDirectoryLocatorBlock.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 / ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs / 1305600 / ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs

                            //------------------------------------------------------------------------------ 
//-------------   *** WARNING ***
//-------------    This file is part of a legally monitored development project.
//-------------    Do not check in changes to this project.  Do not raid bugs on this
//-------------    code in the main PS database.  Do not contact the owner of this 
//-------------    code directly.  Contact the legal team at ‘ZSLegal’ for assistance.
//-------------   *** WARNING *** 
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This is an internal class that enables interactions with Zip archives 
//  for OPC scenarios (Zip 64 bit support)
// 
// History:
//  01/26/2005: IgorBel: Initial creation.
//
//----------------------------------------------------------------------------- 

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

namespace MS.Internal.IO.Zip 
{
    internal class ZipIOZip64EndOfCentralDirectoryLocatorBlock : IZipIOBlock 
    { 
        // standard IZipIOBlock functionality
        public long Offset 
        {
            get
            {
                return _offset; 
            }
        } 
 
        public long Size
        { 
            get
            {
                return _size;
            } 
        }
 
        // This property will only return reliable result if Update is called prior 
        public bool GetDirtyFlag(bool closingFlag)
        { 
            return _dirtyFlag;
        }

        public void Move(long shiftSize) 
        {
            if (shiftSize != 0) 
            { 
                checked{_offset +=shiftSize;}
 
                if (_size > 0)
                {
                    _dirtyFlag = true;
                } 

                Debug.Assert(_offset >=0); 
            } 
        }
 
        public void Save()
        {
            if (GetDirtyFlag(true) && (Size > 0))
            { 
                BinaryWriter writer = _blockManager.BinaryWriter;
                if (_blockManager.Stream.Position != _offset) 
                { 
                    // we need to seek
                    _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); 

                    // in non seekable streams we are expected to be at the right position, no seeking required
                    // if this assumption is ever violated. Seek will throw on non-seekable stream, which would provide us
                    // with a detection mechanism for such problems 
                }
 
                writer.Write(_signatureConstant); 
                writer.Write(_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory);
                writer.Write(_offsetOfStartOfZip64EndOfCentralDirectoryRecord); 
                writer.Write(_totalNumberOfDisks);

                writer.Flush();
            } 

            _dirtyFlag = false; 
        } 

        public void UpdateReferences(bool closingFlag) 
        {
            checked
            {
                // check whether Central directory is loaded and update references accordingly 
                //  if one or more of the following conditions are true
                //  1. Central Directory is dirty 
                //  2. Zip64 End of Central Directory is dirty 
                //  3. streaming mode
                // if Central Directory isn't loded or none of the relevant structure is dirty, 
                //  there is nothing to update for Zip64 End Of Central directory record
                if ((_blockManager.IsCentralDirectoryBlockLoaded
                            && (_blockManager.Streaming
                                || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag)) 
                                || _blockManager.Zip64EndOfCentralDirectoryBlock.GetDirtyFlag(closingFlag)))
                { 
                    if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) 
                    {
                        UInt64 offsetOfStartOfZip64EndOfCentralDirectoryRecord = 
                                                (UInt64)_blockManager.Zip64EndOfCentralDirectoryBlock.Offset;

                        // update value and mark record dirty if either it is already dirty or there is a mismatch
                        if ((_dirtyFlag) || 
                            (offsetOfStartOfZip64EndOfCentralDirectoryRecord != _offsetOfStartOfZip64EndOfCentralDirectoryRecord) ||
                            (_fixedMinimalRecordSize != _size)) 
                        { 
                            _offsetOfStartOfZip64EndOfCentralDirectoryRecord = offsetOfStartOfZip64EndOfCentralDirectoryRecord;
                            _size = _fixedMinimalRecordSize; 

                            _dirtyFlag = true;
                        }
                    } 
                    else
                    { 
                        // we do not need zip 64 structures 
                        if (_size != 0)
                        { 
                            _size = 0;
                            _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 the only blocks after the Zip64 EOCD (EOCD) doesn't have 
            // data that is buffered on disk
            return PreSaveNotificationScanControlInstruction.Stop; 
        }

        internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock SeekableLoad (ZipIOBlockManager blockManager)
        { 
            // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition
            // in both retail and debug builds 
            Debug.Assert(SniffTheBlockSignature(blockManager)); 

            long blockPosition = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); 

            blockManager.Stream.Seek(blockPosition, SeekOrigin.Begin);

            ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); 

            block.ParseRecord(blockManager.BinaryReader, blockPosition); 
            return block; 
        }
 
        internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock CreateNew(ZipIOBlockManager blockManager)
        {
            // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition
            // in both retail and debug builds 
            Debug.Assert(!SniffTheBlockSignature(blockManager));
 
            ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); 

            block._offset = 0; 
            block._size = 0;
            block._dirtyFlag = false;

            return block; 
        }
 
        internal static bool SniffTheBlockSignature(ZipIOBlockManager blockManager) 
        {
            long suspectPos = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); 

            // let's check that EndOfCentralDirectoryBlock.Offset is not too close to the start of the stream
            // for the record to fit there
 
            // the second check isn't required, strictily speaking, as we are stepping back from the  EOCD.offset
            // however in some theoretical cases EOCD might not be trustable so to ensure that  ReadUInt32 
            // isn't going to throw we do additional check 
            if ((suspectPos < 0) ||
                (checked(suspectPos + sizeof(UInt32)) > blockManager.Stream.Length)) 
            {
                return false;
            }
 
            blockManager.Stream.Seek(suspectPos, SeekOrigin.Begin);
 
            UInt32 signature = blockManager.BinaryReader.ReadUInt32(); 
            return (signature == _signatureConstant);
        } 

        internal long OffsetOfZip64EndOfCentralDirectoryRecord
        {
            get 
            {
                return (long)_offsetOfStartOfZip64EndOfCentralDirectoryRecord; 
            } 
        }
 
        private ZipIOZip64EndOfCentralDirectoryLocatorBlock(ZipIOBlockManager blockManager)
        {
            Debug.Assert(blockManager != null);
            _blockManager= blockManager; 
        }
 
        private void ParseRecord (BinaryReader reader, long position) 
        {
            _signature = reader.ReadUInt32(); 
            _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory = reader.ReadUInt32();
            _offsetOfStartOfZip64EndOfCentralDirectoryRecord = reader.ReadUInt64();
            _totalNumberOfDisks = reader.ReadUInt32();
 
            _offset = position;
            _size = _fixedMinimalRecordSize; 
            _dirtyFlag = false; 

            Validate(); 
        }

        private void Validate()
        { 
            if (_offsetOfStartOfZip64EndOfCentralDirectoryRecord > Int64.MaxValue)  // C# does proper upcasting to ULONG of both operands
            { 
                // although we are trying to support 64 bit structures 
                // we are limited by the CLR model for streams down to 63
                // bit size for all the Uint64 fields 

                throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge));
            }
 
            if (_signature != _signatureConstant)
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
 
            if ((_totalNumberOfDisks != 1) ||
                (_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory != 0))
            {
                throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); 
            }
 
            // The offset of the ZIP 64 EOCD must preceed the location of the ZIP64 EOCD locator 
            if ((UInt64)_offset <= _offsetOfStartOfZip64EndOfCentralDirectoryRecord) // we assume that _offset >=0
            { 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }

            // this record is optional size must be either 0 or _fixedMinimalRecordSize 
            if ((_size != _fixedMinimalRecordSize) && (_size != 0))
            { 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
        } 

        private ZipIOBlockManager _blockManager;

        private long _offset; 
        private long _size;
        private bool _dirtyFlag; 
 
        private  const UInt32 _signatureConstant  = 0x07064b50;
        private const int _fixedMinimalRecordSize = 20; 

        // data persisted on disk
        private UInt32 _signature = _signatureConstant;
        private UInt32 _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory; 
        private UInt64 _offsetOfStartOfZip64EndOfCentralDirectoryRecord;
        private UInt32 _totalNumberOfDisks = 1; 
    } 
}

// 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 (Zip 64 bit support)
// 
// History:
//  01/26/2005: IgorBel: Initial creation.
//
//----------------------------------------------------------------------------- 

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

namespace MS.Internal.IO.Zip 
{
    internal class ZipIOZip64EndOfCentralDirectoryLocatorBlock : IZipIOBlock 
    { 
        // standard IZipIOBlock functionality
        public long Offset 
        {
            get
            {
                return _offset; 
            }
        } 
 
        public long Size
        { 
            get
            {
                return _size;
            } 
        }
 
        // This property will only return reliable result if Update is called prior 
        public bool GetDirtyFlag(bool closingFlag)
        { 
            return _dirtyFlag;
        }

        public void Move(long shiftSize) 
        {
            if (shiftSize != 0) 
            { 
                checked{_offset +=shiftSize;}
 
                if (_size > 0)
                {
                    _dirtyFlag = true;
                } 

                Debug.Assert(_offset >=0); 
            } 
        }
 
        public void Save()
        {
            if (GetDirtyFlag(true) && (Size > 0))
            { 
                BinaryWriter writer = _blockManager.BinaryWriter;
                if (_blockManager.Stream.Position != _offset) 
                { 
                    // we need to seek
                    _blockManager.Stream.Seek(_offset, SeekOrigin.Begin); 

                    // in non seekable streams we are expected to be at the right position, no seeking required
                    // if this assumption is ever violated. Seek will throw on non-seekable stream, which would provide us
                    // with a detection mechanism for such problems 
                }
 
                writer.Write(_signatureConstant); 
                writer.Write(_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory);
                writer.Write(_offsetOfStartOfZip64EndOfCentralDirectoryRecord); 
                writer.Write(_totalNumberOfDisks);

                writer.Flush();
            } 

            _dirtyFlag = false; 
        } 

        public void UpdateReferences(bool closingFlag) 
        {
            checked
            {
                // check whether Central directory is loaded and update references accordingly 
                //  if one or more of the following conditions are true
                //  1. Central Directory is dirty 
                //  2. Zip64 End of Central Directory is dirty 
                //  3. streaming mode
                // if Central Directory isn't loded or none of the relevant structure is dirty, 
                //  there is nothing to update for Zip64 End Of Central directory record
                if ((_blockManager.IsCentralDirectoryBlockLoaded
                            && (_blockManager.Streaming
                                || _blockManager.CentralDirectoryBlock.GetDirtyFlag(closingFlag)) 
                                || _blockManager.Zip64EndOfCentralDirectoryBlock.GetDirtyFlag(closingFlag)))
                { 
                    if (_blockManager.CentralDirectoryBlock.IsZip64BitRequiredForStoring) 
                    {
                        UInt64 offsetOfStartOfZip64EndOfCentralDirectoryRecord = 
                                                (UInt64)_blockManager.Zip64EndOfCentralDirectoryBlock.Offset;

                        // update value and mark record dirty if either it is already dirty or there is a mismatch
                        if ((_dirtyFlag) || 
                            (offsetOfStartOfZip64EndOfCentralDirectoryRecord != _offsetOfStartOfZip64EndOfCentralDirectoryRecord) ||
                            (_fixedMinimalRecordSize != _size)) 
                        { 
                            _offsetOfStartOfZip64EndOfCentralDirectoryRecord = offsetOfStartOfZip64EndOfCentralDirectoryRecord;
                            _size = _fixedMinimalRecordSize; 

                            _dirtyFlag = true;
                        }
                    } 
                    else
                    { 
                        // we do not need zip 64 structures 
                        if (_size != 0)
                        { 
                            _size = 0;
                            _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 the only blocks after the Zip64 EOCD (EOCD) doesn't have 
            // data that is buffered on disk
            return PreSaveNotificationScanControlInstruction.Stop; 
        }

        internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock SeekableLoad (ZipIOBlockManager blockManager)
        { 
            // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition
            // in both retail and debug builds 
            Debug.Assert(SniffTheBlockSignature(blockManager)); 

            long blockPosition = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); 

            blockManager.Stream.Seek(blockPosition, SeekOrigin.Begin);

            ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); 

            block.ParseRecord(blockManager.BinaryReader, blockPosition); 
            return block; 
        }
 
        internal static ZipIOZip64EndOfCentralDirectoryLocatorBlock CreateNew(ZipIOBlockManager blockManager)
        {
            // This Debug assert is a secondary check in debug builds, callers are responcible for verifying condition
            // in both retail and debug builds 
            Debug.Assert(!SniffTheBlockSignature(blockManager));
 
            ZipIOZip64EndOfCentralDirectoryLocatorBlock block = new ZipIOZip64EndOfCentralDirectoryLocatorBlock(blockManager); 

            block._offset = 0; 
            block._size = 0;
            block._dirtyFlag = false;

            return block; 
        }
 
        internal static bool SniffTheBlockSignature(ZipIOBlockManager blockManager) 
        {
            long suspectPos = checked(blockManager.EndOfCentralDirectoryBlock.Offset - _fixedMinimalRecordSize); 

            // let's check that EndOfCentralDirectoryBlock.Offset is not too close to the start of the stream
            // for the record to fit there
 
            // the second check isn't required, strictily speaking, as we are stepping back from the  EOCD.offset
            // however in some theoretical cases EOCD might not be trustable so to ensure that  ReadUInt32 
            // isn't going to throw we do additional check 
            if ((suspectPos < 0) ||
                (checked(suspectPos + sizeof(UInt32)) > blockManager.Stream.Length)) 
            {
                return false;
            }
 
            blockManager.Stream.Seek(suspectPos, SeekOrigin.Begin);
 
            UInt32 signature = blockManager.BinaryReader.ReadUInt32(); 
            return (signature == _signatureConstant);
        } 

        internal long OffsetOfZip64EndOfCentralDirectoryRecord
        {
            get 
            {
                return (long)_offsetOfStartOfZip64EndOfCentralDirectoryRecord; 
            } 
        }
 
        private ZipIOZip64EndOfCentralDirectoryLocatorBlock(ZipIOBlockManager blockManager)
        {
            Debug.Assert(blockManager != null);
            _blockManager= blockManager; 
        }
 
        private void ParseRecord (BinaryReader reader, long position) 
        {
            _signature = reader.ReadUInt32(); 
            _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory = reader.ReadUInt32();
            _offsetOfStartOfZip64EndOfCentralDirectoryRecord = reader.ReadUInt64();
            _totalNumberOfDisks = reader.ReadUInt32();
 
            _offset = position;
            _size = _fixedMinimalRecordSize; 
            _dirtyFlag = false; 

            Validate(); 
        }

        private void Validate()
        { 
            if (_offsetOfStartOfZip64EndOfCentralDirectoryRecord > Int64.MaxValue)  // C# does proper upcasting to ULONG of both operands
            { 
                // although we are trying to support 64 bit structures 
                // we are limited by the CLR model for streams down to 63
                // bit size for all the Uint64 fields 

                throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge));
            }
 
            if (_signature != _signatureConstant)
            { 
                throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
 
            if ((_totalNumberOfDisks != 1) ||
                (_numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory != 0))
            {
                throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk)); 
            }
 
            // The offset of the ZIP 64 EOCD must preceed the location of the ZIP64 EOCD locator 
            if ((UInt64)_offset <= _offsetOfStartOfZip64EndOfCentralDirectoryRecord) // we assume that _offset >=0
            { 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }

            // this record is optional size must be either 0 or _fixedMinimalRecordSize 
            if ((_size != _fixedMinimalRecordSize) && (_size != 0))
            { 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
            }
        } 

        private ZipIOBlockManager _blockManager;

        private long _offset; 
        private long _size;
        private bool _dirtyFlag; 
 
        private  const UInt32 _signatureConstant  = 0x07064b50;
        private const int _fixedMinimalRecordSize = 20; 

        // data persisted on disk
        private UInt32 _signature = _signatureConstant;
        private UInt32 _numberOfTheDiskWithTheStartOfZip64EndOfCentralDirectory; 
        private UInt64 _offsetOfStartOfZip64EndOfCentralDirectoryRecord;
        private UInt32 _totalNumberOfDisks = 1; 
    } 
}

// 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