|
//-----------------------------------------------------------------------------
//------------- *** 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="ZipIoExtraFieldZip64Element.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved.
// </copyright>
//
// Description:
// This is an internal class that helps managing/parsing the
// ZIP64 Extended Information Extra Field (0x0001): for OPC scenarios
// In order to isolate this from IO and streams, it deals with the data in the Byte[] form
//
// History:
// 05/16/2005: IgorBel: Initial creation.
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
using System.Diagnostics;
using System.Windows;
using MS.Internal.WindowsBase;
namespace MS.Internal.IO.Zip
{
internal enum ZipIOZip64ExtraFieldUsage
{
None = 0,
UncompressedSize = 1,
CompressedSize = 2,
OffsetOfLocalHeader = 4,
DiskNumber = 8,
}
/// <summary>
/// This class is used to represent and parse the the
/// ZIP64 Extended Information Extra Field (0x0001)
/// In order to isolate this from IO and streams it deals with the data in the Byte[] form
/// </summary>
internal class ZipIOExtraFieldZip64Element : ZipIOExtraFieldElement
{
// creates brand new empty ZIP 64 extra field element
internal static ZipIOExtraFieldZip64Element CreateNew()
{
ZipIOExtraFieldZip64Element newElement = new ZipIOExtraFieldZip64Element();
return newElement;
}
// extracts ZIP 64 extra field element from a given byte array
internal override void ParseDataField(BinaryReader reader, UInt16 size)
{
Debug.Assert(reader != null);
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0)
{
_uncompressedSize = reader.ReadUInt64();
if (size < sizeof(UInt64))
{
throw new FileFormatException(SR.Get(SRID.CorruptedData));
}
size -= sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0)
{
_compressedSize = reader.ReadUInt64();
if (size < sizeof(UInt64))
{
throw new FileFormatException(SR.Get(SRID.CorruptedData));
}
size -= sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0)
{
_offsetOfLocalHeader = reader.ReadUInt64();
if (size < sizeof(UInt64))
{
throw new FileFormatException(SR.Get(SRID.CorruptedData));
}
size -= sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0)
{
_diskNumber = reader.ReadUInt32();
if (size < sizeof(UInt32))
{
throw new FileFormatException(SR.Get(SRID.CorruptedData));
}
size -= sizeof(UInt32);
}
// There is an extra field that is not used and must be ignored.
// The reader must also advance past the unused bytes.
if (_zip64ExtraFieldUsage == ZipIOZip64ExtraFieldUsage.None)
{
reader.BaseStream.Seek(size, SeekOrigin.Current);
_ignoredFieldSize = size;
size = 0;
}
if (size != 0)
{
throw new FileFormatException(SR.Get(SRID.CorruptedData));
}
Validate();
}
internal override void Save(BinaryWriter writer)
{
// if it is == 0 we shouldn't be persisting this
Debug.Assert(SizeField > 0);
writer.Write(_constantFieldId);
writer.Write(SizeField);
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0)
{
writer.Write(_uncompressedSize);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0)
{
writer.Write(_compressedSize);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0)
{
writer.Write(_offsetOfLocalHeader);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0)
{
writer.Write(_diskNumber);
}
}
// This property calculates size of the field on disk (how many bytes need to be allocated on the disk)
internal override UInt16 Size
{
get
{
if (SizeField == 0) // we do not need to save this, if it is empty
{
return 0;
}
else
{
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
{
UInt16 size = 0;
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0)
{
size += sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0)
{
size += sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0)
{
size += sizeof(UInt64);
}
if ((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0)
{
size += sizeof(UInt32);
}
// If the file contains a blank extra field, we need to correctly indicate that
// we skipped the data in this field so that the sizes match up in the end.
if (_ignoredFieldSize.HasValue)
{
size += _ignoredFieldSize.Value;
}
return size;
}
}
static internal UInt16 ConstantFieldId
{
get
{
return _constantFieldId;
}
}
internal long UncompressedSize
{
get
{
// we should never be asked to provide such value, if we do not have it
Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.UncompressedSize) != 0);
return (long)_uncompressedSize;
}
set
{
Debug.Assert(value >= 0);
_zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.UncompressedSize;
_uncompressedSize = (UInt64)value;
}
}
internal long CompressedSize
{
get
{
// we should never be asked to provide such value, if we do not have it
Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.CompressedSize) != 0);
return (long)_compressedSize;
}
set
{
Debug.Assert(value >= 0);
_zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.CompressedSize;
_compressedSize = (UInt64)value;
}
}
internal long OffsetOfLocalHeader
{
get
{
// we should never be asked to provide such value, if we do not have it
Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader) != 0);
return (long)_offsetOfLocalHeader;
}
set
{
Debug.Assert(value >= 0);
_zip64ExtraFieldUsage |= ZipIOZip64ExtraFieldUsage.OffsetOfLocalHeader;
_offsetOfLocalHeader = (UInt64)value;
}
}
internal UInt32 DiskNumber
{
get
{
// we should never be asked to provide such value, if we do not have it
Debug.Assert((_zip64ExtraFieldUsage & ZipIOZip64ExtraFieldUsage.DiskNumber) != 0);
return _diskNumber;
}
// set{} for now we do not need to support set on this property
// the only reason to set is an attempt to produce multi disk archives
}
internal ZipIOZip64ExtraFieldUsage Zip64ExtraFieldUsage
{
get
{
return _zip64ExtraFieldUsage;
}
set
{
_zip64ExtraFieldUsage = value;
}
}
//------------------------------------------------------
//
// Private Constructor
//
//------------------------------------------------------
internal ZipIOExtraFieldZip64Element()
: base(_constantFieldId)
{
_zip64ExtraFieldUsage = ZipIOZip64ExtraFieldUsage.None;
}
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
private void Validate()
{
// throw if we got any negative values
if ((_compressedSize >= Int64.MaxValue) ||
(_uncompressedSize >= Int64.MaxValue) ||
(_offsetOfLocalHeader >= Int64.MaxValue))
{
throw new NotSupportedException(SR.Get(SRID.Zip64StructuresTooLarge));
}
// throw if disk number isn't == 0
if (_diskNumber != 0)
{
throw new NotSupportedException(SR.Get(SRID.NotSupportedMultiDisk));
}
}
//------------------------------------------------------
//
// Private fields
//
//------------------------------------------------------
private const UInt16 _constantFieldId = 0x01;
private UInt64 _uncompressedSize;
private UInt64 _compressedSize;
private UInt64 _offsetOfLocalHeader;
private UInt32 _diskNumber;
// Used for indicating there is an ignored extra field
private UInt16? _ignoredFieldSize;
private ZipIOZip64ExtraFieldUsage _zip64ExtraFieldUsage;
}
}
|