File: Base\MS\Internal\IO\Zip\ZipIOExtraFieldPaddingElement.cs
Project: wpf\src\WindowsBase.csproj (WindowsBase)
//-----------------------------------------------------------------------------
//-------------   *** 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 file="ZipIoExtraFieldPaddingElement.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//  This is an internal class that is used to implement parsing and editing of a padding extra field
//  structure. This extra field is used to optimize the performance dealing with Zip64 extra field.
//  When we need to create Zip64 extra field the extra padding bytes are used to create such
//  structure so that the subsequent bytes don't have to be moved.
//
// History:
//  03/23/2006: Microsoft: Added support for Padding Extra Field
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
 
namespace MS.Internal.IO.Zip
{
    /// <summary>
    /// This class is used to represent and parse the Padding Extra Field
    ///
    /// The Padding Extra Field is defined as:
    /// Header ID               UInt16 (2 bytes)    0xA220
    /// Length of the field     UInt16 (2 bytes)
    /// Signature               UInt16 (2 bytes)    0xA028 (for verification)
    /// Padding Initial Value   UInt16 (2 bytes)    Padding size originally requested by the caller
    /// Padding                 ? bytes             Padding respresented by null characters
    /// </summary>                
    internal class ZipIOExtraFieldPaddingElement  : ZipIOExtraFieldElement
    {
        // creates a brand new empty Padding extra field element 
        internal static ZipIOExtraFieldPaddingElement CreateNew()
        {
            ZipIOExtraFieldPaddingElement newElement = new ZipIOExtraFieldPaddingElement();
 
            return newElement;
        }
 
        // parse Padding extra field element
        internal override void ParseDataField(BinaryReader reader, UInt16 size)
        {
            // The signature is already read and validated
            Debug.Assert(size >= MinimumSize);
 
            // It is guaranteed that there is enough bytes to read in UInt16
            //  since it is already checked from ZipIOExtraFieldElement.Parse()
            _initialRequestedPaddingSize = reader.ReadUInt16();
 
            // need to subtract the size of the signature and size fields
            // We don't need to use checked{} since size is guaranteed to be bigger than
            //  MinimumFieldDataSize by the called (ZipIOExtraFieldElement.Parse)
            size -= _minimumFieldDataSize;
 
            _paddingSize = size;
 
            // Skip the padding
            if (_paddingSize != 0)
            {
                reader.BaseStream.Seek(size, SeekOrigin.Current);
            }
        }
 
        internal static bool MatchesPaddingSignature(byte[] sniffiedBytes)
        {
            if (sniffiedBytes.Length < _signatureSize)
            {
                return false;
            }
 
            Debug.Assert(sniffiedBytes.Length == _signatureSize);
 
            if (BitConverter.ToUInt16(sniffiedBytes, 0) != _signature)
            {
                return false;
            }
 
            return true;
        }
 
        internal override void Save(BinaryWriter writer)
        {
            writer.Write(_constantFieldId);
            writer.Write(SizeField);
            writer.Write(_signature);
            writer.Write(_initialRequestedPaddingSize);
 
            for (int i = 0; i < _paddingSize; ++i)
            {
                writer.Write((byte) 0);
            }
        }
 
        // This property calculates size of the field on disk (how many bytes need to be allocated on the disk)
        //  id + size field + data field (SizeField)
        internal override UInt16 Size
        {
            get
            {
                return checked((UInt16) (SizeField + MinimumSize));
            }
        }
 
        // This property calculates the value of the size record whch holds the size without the Id and without the size itself.
        // we are always guranteed that Size == SizeField + 2 * sizeof(UInt16))
        internal override UInt16 SizeField
        {
            get
            {
                return checked((UInt16) (_minimumFieldDataSize + _paddingSize));
            }
        }
 
        static internal UInt16 ConstantFieldId
        {
            get
            {
                return _constantFieldId; 
            }
        }
 
        static internal UInt16 MinimumFieldDataSize
        {
            get
            {
                return _minimumFieldDataSize; 
            }
        }
 
        static internal UInt16 SignatureSize
        {
            get
            {
                return _signatureSize; 
            }
        }
 
        internal UInt16 PaddingSize
        {
            get
            {
                return _paddingSize; 
            }
            set
            {
                _paddingSize = value;
            }
        }
 
        //------------------------------------------------------
        //
        //  Private Constructor 
        //
        //------------------------------------------------------
        internal ZipIOExtraFieldPaddingElement() : base(_constantFieldId)
        {
            _initialRequestedPaddingSize = _newInitialPaddingSize;
            _paddingSize = _initialRequestedPaddingSize;
        }
 
        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------
 
        //------------------------------------------------------
        //
        //  Private fields 
        //
        //------------------------------------------------------
        private const UInt16 _constantFieldId = 0xA220;
        private const UInt16 _signature = 0xA028;
        // 20 is the maximum size of Zip64 Extra Field element we can use for Local File Header
        //  (Id, Size, Compressed and UnCompressed Sizes; 2 + 2 + 8 + 8 = 20)
        //  DiskNumber and Relative Offset of Local File Header is not counted since we don't use
        //  it in Local File Header
        private const UInt16 _newInitialPaddingSize = 20;
 
        // UInt16 signature
        // UInt16 initial requested padding size
        private static readonly UInt16 _minimumFieldDataSize = 2 * sizeof(UInt16);
        private static readonly UInt16 _signatureSize = sizeof(UInt16);
 
        private UInt16 _paddingSize;
        private UInt16 _initialRequestedPaddingSize;
    }
}