ZipIOExtraField.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 / ZipIOExtraField.cs / 1305600 / ZipIOExtraField.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 is used to implement parsing and 
//  of the extra field optionally present in the fileHeader and Central Dir
// 
// History:
//  05/16/2005: IgorBel: Initial creation.
//  03/23/2006: [....]: Added support for Padding Extra Field
// 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;
using System.Diagnostics; 
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
using System.Windows; 
using MS.Internal.WindowsBase;
 
namespace MS.Internal.IO.Zip 
{
    internal class ZipIOExtraField 
    {
        internal static ZipIOExtraField CreateNew(bool createPadding)
        {
            // we have been asked to create a new record, current zip io implementation will add at most one Zip64 block 
            ZipIOExtraField extraField = new ZipIOExtraField();
 
            extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); 

            if (createPadding) 
            {
                extraField._paddingElement = ZipIOExtraFieldPaddingElement.CreateNew();
            }
 
            return extraField;
        } 
 
        internal static ZipIOExtraField ParseRecord(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage, ushort expectedExtraFieldSize)
        { 
            // most of the files are not ZIP 64, and instead of trying to parse it we should create new empty record
            if (expectedExtraFieldSize == 0)
            {
                if (zip64extraFieldUsage != ZipIOZip64ExtraFieldUsage.None) 
                {
                    // in case there is an expectation by the caller for a non empty record we should throw 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                }
 
                // We are creating Extra Fields for the existing Local File Header,
                //  so no need to create a new padding field
                return CreateNew(false);
            } 

            ZipIOExtraField extraField = new ZipIOExtraField(); 
 
            // Parse all Extra elements from Extra Field
            while (expectedExtraFieldSize > 0) 
            {
                if (expectedExtraFieldSize < ZipIOExtraFieldElement.MinimumSize)
                {
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                }
 
                ZipIOExtraFieldElement newElement = ZipIOExtraFieldElement.Parse(reader, zip64extraFieldUsage); 
                ZipIOExtraFieldZip64Element zip64Element = newElement as ZipIOExtraFieldZip64Element;
                ZipIOExtraFieldPaddingElement paddingElement = newElement as ZipIOExtraFieldPaddingElement; 

                // if we have found the Zip 64 record. let's remember it
                if (zip64Element != null)
                { 
                    if (extraField._zip64Element != null)
                    { 
                        // multiple ZIP 64 extra fields are not allowed 
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    } 

                    extraField._zip64Element = zip64Element;
                }
                else if (paddingElement != null) 
                {
                    if (extraField._paddingElement != null) 
                    { 
                        // multiple padding extra fields are not allowed
                        throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                    }

                    extraField._paddingElement = paddingElement;
                } 
                else
                { 
                    if (extraField._extraFieldElements == null) 
                        extraField._extraFieldElements = new ArrayList(3);    // we expect to see a few records there, as it sould have been produced by other authoring systems.
 
                    // any other instances of extra fields with the same id are allowed
                    extraField._extraFieldElements.Add(newElement);
                }
 
                checked { expectedExtraFieldSize -= newElement.Size; }
            } 
 
            // if we didn't end up at the exact expected position, we are treating this as a corrupted file
            if (expectedExtraFieldSize != 0) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }
 
            // As we treat the ZIP 64 extra field as optional for all version >= 4.5
            // we need to explicitly consider a case when it is missing 
            if (extraField._zip64Element == null) 
            {
                extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); 
            }

            /////////////////////////////////////////////////////////////////////
            //              extraField.Validate(); 
            // an instance Validate function is removed to fix FxCop violation, please add it back
            // if extra validation steps are required 
            // 
            // we are checking for uniqueness of the Zip 64 header ID in the Parse function.
            // Although it might be a good idea to check for record id uniqueness in general, 
            // we are treating the rest of the field as a bag of bits, so it is probably not worth it to
            // search for other duplicate ID especially as appnote considers ID duplication a possibility
            // and even suggest a work around for file producers.
            ///////////////////////////////////////////////////////////////////// 

            return extraField; 
        } 

        internal void Save(BinaryWriter writer) 
        {
            // write Out the Zip 64  extra field first
            if (_zip64Element.SizeField > 0)
            { 
                _zip64Element.Save(writer);
            } 
 
            // write Out the padding field
            if (_paddingElement != null) 
            {
                _paddingElement.Save(writer);
            }
 
            if (_extraFieldElements != null)
            { 
                foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements) 
                {
                    extraFieldElement.Save(writer); 
                }
            }
        }
 
        // Add or remove padding for the given size change
        internal void UpdatePadding(long size) 
        { 
            // If the local file header changed more than 100 bytes, it means
            //  there are some logical errors 
            Debug.Assert(Math.Abs(size) <= 100);

            // The header size change should be no more than what we can hold in UInt16
            if (Math.Abs(size) > UInt16.MaxValue) 
                return;
 
            // Header size increased; need to remove padding if there is an existing padding structure 
            if (size > 0 && _paddingElement != null)
            { 
                // There is enough padding left over to do size adjustment
                // No need to use checked{} since _paddingElement.PaddingSize >= size
                if (_paddingElement.PaddingSize >= size)
                    _paddingElement.PaddingSize -= (UInt16) size; 
                // The size of the whole padding structure exactly matches the size change
                else if (_paddingElement.Size == size) 
                { 
                    // Then the padding structure can be completely removed
                    //  to accommodate the size change 
                    _paddingElement = null;
                }

                return; 
            }
 
            // Header size decreased; need to add padding 
            if (size < 0)
            { 
                // Padding structure is not there but, the size change is big enough for one
                //  to be created
                if (_paddingElement == null)
                { 
                    // No need to use checked{} since size is long type
                    //  and size < 0 
                    //  and (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize + ZipIOExtraFieldElement.MinimumSize) 
                    //      is small number that can not cause the overflow
                    size += (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize 
                                + ZipIOExtraFieldElement.MinimumSize);

                    if (size >= 0)
                    { 
                        _paddingElement = new ZipIOExtraFieldPaddingElement();
                        // No need to use checked{} since size > 0 and less than UInt16.MaxValue 
                        _paddingElement.PaddingSize = (UInt16) size; 
                    }
                } 
                else
                {
                    // Check if we hit the max padding allowed
                    if ((_paddingElement.PaddingSize - size) > UInt16.MaxValue) 
                        return;
 
                    // No need to use checked{} since we already check the overflow 
                    _paddingElement.PaddingSize = (UInt16) (_paddingElement.PaddingSize - size);
                } 
            }
        }

        internal UInt16 Size 
        {
            get 
            { 
                UInt16 size = 0;
 
                if (_extraFieldElements != null)
                {
                    foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements)
                    { 
                        checked{size += extraFieldElement.Size;}
                    } 
                } 

                checked{size += _zip64Element.Size;} 

                if (_paddingElement != null)
                {
                    checked { size += _paddingElement.Size; } 
                 }
 
                return size; 
            }
        } 


        internal ZipIOZip64ExtraFieldUsage Zip64ExtraFieldUsage
        { 
            get
            { 
                return _zip64Element.Zip64ExtraFieldUsage; 
            }
            set 
            {
                _zip64Element.Zip64ExtraFieldUsage = value;
            }
        } 

        internal UInt32 DiskNumberOfFileStart 
        { 
            get
            { 
                return _zip64Element.DiskNumber;
            }
        }
 
        internal long OffsetOfLocalHeader
        { 
            get 
            {
                return _zip64Element.OffsetOfLocalHeader; 
            }
            set
            {
                _zip64Element.OffsetOfLocalHeader = value; 
            }
        } 
 
        internal long CompressedSize
        { 
            get
            {
                return _zip64Element.CompressedSize;
            } 
            set
            { 
                _zip64Element.CompressedSize = value; 
            }
        } 

        internal long UncompressedSize
        {
            get 
            {
                return _zip64Element.UncompressedSize; 
            } 
            set
            { 
                _zip64Element.UncompressedSize = value;
            }
        }
 
        private ZipIOExtraField()
        { 
        } 

        private ArrayList _extraFieldElements; 
        private ZipIOExtraFieldZip64Element _zip64Element;
        private ZipIOExtraFieldPaddingElement _paddingElement;
    }
} 

// 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 is used to implement parsing and 
//  of the extra field optionally present in the fileHeader and Central Dir
// 
// History:
//  05/16/2005: IgorBel: Initial creation.
//  03/23/2006: [....]: Added support for Padding Extra Field
// 
//-----------------------------------------------------------------------------
 
using System; 
using System.IO;
using System.Diagnostics; 
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
using System.Windows; 
using MS.Internal.WindowsBase;
 
namespace MS.Internal.IO.Zip 
{
    internal class ZipIOExtraField 
    {
        internal static ZipIOExtraField CreateNew(bool createPadding)
        {
            // we have been asked to create a new record, current zip io implementation will add at most one Zip64 block 
            ZipIOExtraField extraField = new ZipIOExtraField();
 
            extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); 

            if (createPadding) 
            {
                extraField._paddingElement = ZipIOExtraFieldPaddingElement.CreateNew();
            }
 
            return extraField;
        } 
 
        internal static ZipIOExtraField ParseRecord(BinaryReader reader, ZipIOZip64ExtraFieldUsage zip64extraFieldUsage, ushort expectedExtraFieldSize)
        { 
            // most of the files are not ZIP 64, and instead of trying to parse it we should create new empty record
            if (expectedExtraFieldSize == 0)
            {
                if (zip64extraFieldUsage != ZipIOZip64ExtraFieldUsage.None) 
                {
                    // in case there is an expectation by the caller for a non empty record we should throw 
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                }
 
                // We are creating Extra Fields for the existing Local File Header,
                //  so no need to create a new padding field
                return CreateNew(false);
            } 

            ZipIOExtraField extraField = new ZipIOExtraField(); 
 
            // Parse all Extra elements from Extra Field
            while (expectedExtraFieldSize > 0) 
            {
                if (expectedExtraFieldSize < ZipIOExtraFieldElement.MinimumSize)
                {
                    throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                }
 
                ZipIOExtraFieldElement newElement = ZipIOExtraFieldElement.Parse(reader, zip64extraFieldUsage); 
                ZipIOExtraFieldZip64Element zip64Element = newElement as ZipIOExtraFieldZip64Element;
                ZipIOExtraFieldPaddingElement paddingElement = newElement as ZipIOExtraFieldPaddingElement; 

                // if we have found the Zip 64 record. let's remember it
                if (zip64Element != null)
                { 
                    if (extraField._zip64Element != null)
                    { 
                        // multiple ZIP 64 extra fields are not allowed 
                        throw new FileFormatException(SR.Get(SRID.CorruptedData));
                    } 

                    extraField._zip64Element = zip64Element;
                }
                else if (paddingElement != null) 
                {
                    if (extraField._paddingElement != null) 
                    { 
                        // multiple padding extra fields are not allowed
                        throw new FileFormatException(SR.Get(SRID.CorruptedData)); 
                    }

                    extraField._paddingElement = paddingElement;
                } 
                else
                { 
                    if (extraField._extraFieldElements == null) 
                        extraField._extraFieldElements = new ArrayList(3);    // we expect to see a few records there, as it sould have been produced by other authoring systems.
 
                    // any other instances of extra fields with the same id are allowed
                    extraField._extraFieldElements.Add(newElement);
                }
 
                checked { expectedExtraFieldSize -= newElement.Size; }
            } 
 
            // if we didn't end up at the exact expected position, we are treating this as a corrupted file
            if (expectedExtraFieldSize != 0) 
            {
                throw new FileFormatException(SR.Get(SRID.CorruptedData));
            }
 
            // As we treat the ZIP 64 extra field as optional for all version >= 4.5
            // we need to explicitly consider a case when it is missing 
            if (extraField._zip64Element == null) 
            {
                extraField._zip64Element = ZipIOExtraFieldZip64Element.CreateNew(); 
            }

            /////////////////////////////////////////////////////////////////////
            //              extraField.Validate(); 
            // an instance Validate function is removed to fix FxCop violation, please add it back
            // if extra validation steps are required 
            // 
            // we are checking for uniqueness of the Zip 64 header ID in the Parse function.
            // Although it might be a good idea to check for record id uniqueness in general, 
            // we are treating the rest of the field as a bag of bits, so it is probably not worth it to
            // search for other duplicate ID especially as appnote considers ID duplication a possibility
            // and even suggest a work around for file producers.
            ///////////////////////////////////////////////////////////////////// 

            return extraField; 
        } 

        internal void Save(BinaryWriter writer) 
        {
            // write Out the Zip 64  extra field first
            if (_zip64Element.SizeField > 0)
            { 
                _zip64Element.Save(writer);
            } 
 
            // write Out the padding field
            if (_paddingElement != null) 
            {
                _paddingElement.Save(writer);
            }
 
            if (_extraFieldElements != null)
            { 
                foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements) 
                {
                    extraFieldElement.Save(writer); 
                }
            }
        }
 
        // Add or remove padding for the given size change
        internal void UpdatePadding(long size) 
        { 
            // If the local file header changed more than 100 bytes, it means
            //  there are some logical errors 
            Debug.Assert(Math.Abs(size) <= 100);

            // The header size change should be no more than what we can hold in UInt16
            if (Math.Abs(size) > UInt16.MaxValue) 
                return;
 
            // Header size increased; need to remove padding if there is an existing padding structure 
            if (size > 0 && _paddingElement != null)
            { 
                // There is enough padding left over to do size adjustment
                // No need to use checked{} since _paddingElement.PaddingSize >= size
                if (_paddingElement.PaddingSize >= size)
                    _paddingElement.PaddingSize -= (UInt16) size; 
                // The size of the whole padding structure exactly matches the size change
                else if (_paddingElement.Size == size) 
                { 
                    // Then the padding structure can be completely removed
                    //  to accommodate the size change 
                    _paddingElement = null;
                }

                return; 
            }
 
            // Header size decreased; need to add padding 
            if (size < 0)
            { 
                // Padding structure is not there but, the size change is big enough for one
                //  to be created
                if (_paddingElement == null)
                { 
                    // No need to use checked{} since size is long type
                    //  and size < 0 
                    //  and (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize + ZipIOExtraFieldElement.MinimumSize) 
                    //      is small number that can not cause the overflow
                    size += (ZipIOExtraFieldPaddingElement.MinimumFieldDataSize 
                                + ZipIOExtraFieldElement.MinimumSize);

                    if (size >= 0)
                    { 
                        _paddingElement = new ZipIOExtraFieldPaddingElement();
                        // No need to use checked{} since size > 0 and less than UInt16.MaxValue 
                        _paddingElement.PaddingSize = (UInt16) size; 
                    }
                } 
                else
                {
                    // Check if we hit the max padding allowed
                    if ((_paddingElement.PaddingSize - size) > UInt16.MaxValue) 
                        return;
 
                    // No need to use checked{} since we already check the overflow 
                    _paddingElement.PaddingSize = (UInt16) (_paddingElement.PaddingSize - size);
                } 
            }
        }

        internal UInt16 Size 
        {
            get 
            { 
                UInt16 size = 0;
 
                if (_extraFieldElements != null)
                {
                    foreach (ZipIOExtraFieldElement extraFieldElement in _extraFieldElements)
                    { 
                        checked{size += extraFieldElement.Size;}
                    } 
                } 

                checked{size += _zip64Element.Size;} 

                if (_paddingElement != null)
                {
                    checked { size += _paddingElement.Size; } 
                 }
 
                return size; 
            }
        } 


        internal ZipIOZip64ExtraFieldUsage Zip64ExtraFieldUsage
        { 
            get
            { 
                return _zip64Element.Zip64ExtraFieldUsage; 
            }
            set 
            {
                _zip64Element.Zip64ExtraFieldUsage = value;
            }
        } 

        internal UInt32 DiskNumberOfFileStart 
        { 
            get
            { 
                return _zip64Element.DiskNumber;
            }
        }
 
        internal long OffsetOfLocalHeader
        { 
            get 
            {
                return _zip64Element.OffsetOfLocalHeader; 
            }
            set
            {
                _zip64Element.OffsetOfLocalHeader = value; 
            }
        } 
 
        internal long CompressedSize
        { 
            get
            {
                return _zip64Element.CompressedSize;
            } 
            set
            { 
                _zip64Element.CompressedSize = value; 
            }
        } 

        internal long UncompressedSize
        {
            get 
            {
                return _zip64Element.UncompressedSize; 
            } 
            set
            { 
                _zip64Element.UncompressedSize = value;
            }
        }
 
        private ZipIOExtraField()
        { 
        } 

        private ArrayList _extraFieldElements; 
        private ZipIOExtraFieldZip64Element _zip64Element;
        private ZipIOExtraFieldPaddingElement _paddingElement;
    }
} 

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