ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / IO / Zip / ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs / 1 / 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;

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;

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