You've already forked linux-packaging-mono
735 lines
24 KiB
C#
735 lines
24 KiB
C#
// ZipEntry.cs
|
|
//
|
|
// Copyright (C) 2001 Mike Krueger
|
|
// Copyright (C) 2004 John Reilly
|
|
//
|
|
// This file was translated from java, it was part of the GNU Classpath
|
|
// Copyright (C) 2001 Free Software Foundation, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
// Linking this library statically or dynamically with other modules is
|
|
// making a combined work based on this library. Thus, the terms and
|
|
// conditions of the GNU General Public License cover the whole
|
|
// combination.
|
|
//
|
|
// As a special exception, the copyright holders of this library give you
|
|
// permission to link this library with independent modules to produce an
|
|
// executable, regardless of the license terms of these independent
|
|
// modules, and to copy and distribute the resulting executable under
|
|
// terms of your choice, provided that you also meet, for each linked
|
|
// independent module, the terms and conditions of the license of that
|
|
// module. An independent module is a module which is not derived from
|
|
// or based on this library. If you modify this library, you may extend
|
|
// this exception to your version of the library, but you are not
|
|
// obligated to do so. If you do not wish to do so, delete this
|
|
// exception statement from your version.
|
|
|
|
using System;
|
|
using System.IO;
|
|
|
|
namespace ICSharpCode.SharpZipLib.Zip
|
|
{
|
|
|
|
/// <summary>
|
|
/// This class represents an entry in a zip archive. This can be a file
|
|
/// or a directory
|
|
/// ZipFile and ZipInputStream will give you instances of this class as
|
|
/// information about the members in an archive. ZipOutputStream
|
|
/// uses an instance of this class when creating an entry in a Zip file.
|
|
/// <br/>
|
|
/// <br/>Author of the original java version : Jochen Hoenicke
|
|
/// </summary>
|
|
[System.ObsoleteAttribute("This assembly has been deprecated. Please use https://www.nuget.org/packages/SharpZipLib/ instead.")]
|
|
public class ZipEntry : ICloneable
|
|
{
|
|
static int KNOWN_SIZE = 1;
|
|
static int KNOWN_CSIZE = 2;
|
|
static int KNOWN_CRC = 4;
|
|
static int KNOWN_TIME = 8;
|
|
static int KNOWN_EXTERN_ATTRIBUTES = 16;
|
|
|
|
ushort known = 0; // Bit flags made up of above bits
|
|
int externalFileAttributes = -1; // contains external attributes (os dependant)
|
|
|
|
ushort versionMadeBy; // Contains host system and version information
|
|
// only relevant for central header entries
|
|
|
|
string name;
|
|
ulong size;
|
|
ulong compressedSize;
|
|
ushort versionToExtract; // Version required to extract (library handles <= 2.0)
|
|
uint crc;
|
|
uint dosTime;
|
|
|
|
CompressionMethod method = CompressionMethod.Deflated;
|
|
byte[] extra = null;
|
|
string comment = null;
|
|
|
|
int flags; // general purpose bit flags
|
|
|
|
int zipFileIndex = -1; // used by ZipFile
|
|
int offset; // used by ZipFile and ZipOutputStream
|
|
|
|
/// <summary>
|
|
/// Get/Set flag indicating if entry is encrypted.
|
|
/// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>
|
|
/// </summary>
|
|
public bool IsCrypted {
|
|
get {
|
|
return (flags & 1) != 0;
|
|
}
|
|
set {
|
|
if (value) {
|
|
flags |= 1;
|
|
} else {
|
|
flags &= ~1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/Set general purpose bit flag for entry
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// General purpose bit flag<br/>
|
|
/// Bit 0: If set, indicates the file is encrypted<br/>
|
|
/// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>
|
|
/// Imploding:<br/>
|
|
/// Bit 1 if set indicates an 8K sliding dictionary was used. If clear a 4k dictionary was used<br/>
|
|
/// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>
|
|
/// <br/>
|
|
/// Deflating:<br/>
|
|
/// Bit 2 Bit 1<br/>
|
|
/// 0 0 Normal compression was used<br/>
|
|
/// 0 1 Maximum compression was used<br/>
|
|
/// 1 0 Fast compression was used<br/>
|
|
/// 1 1 Super fast compression was used<br/>
|
|
/// <br/>
|
|
/// Bit 3: If set, the fields crc-32, compressed size
|
|
/// and uncompressed size are were not able to be written during zip file creation
|
|
/// The correct values are held in a data descriptor immediately following the compressed data. <br/>
|
|
/// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
|
|
/// Bit 5: If set indicates the file contains compressed patch data<br/>
|
|
/// Bit 6: If set indicates strong encryption was used.<br/>
|
|
/// Bit 7-15: Unused or reserved<br/>
|
|
/// </remarks>
|
|
public int Flags {
|
|
get {
|
|
return flags;
|
|
}
|
|
set {
|
|
flags = value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Get/Set index of this entry in Zip file
|
|
/// </summary>
|
|
public int ZipFileIndex {
|
|
get {
|
|
return zipFileIndex;
|
|
}
|
|
set {
|
|
zipFileIndex = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/set offset for use in central header
|
|
/// </summary>
|
|
public int Offset {
|
|
get {
|
|
return offset;
|
|
}
|
|
set {
|
|
if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
|
|
throw new ArgumentOutOfRangeException("Offset");
|
|
}
|
|
offset = value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Get/Set external file attributes as an integer.
|
|
/// The values of this are operating system dependant see
|
|
/// <see cref="HostSystem">HostSystem</see> for details
|
|
/// </summary>
|
|
public int ExternalFileAttributes {
|
|
get {
|
|
if ((known & KNOWN_EXTERN_ATTRIBUTES) == 0) {
|
|
return -1;
|
|
} else {
|
|
return externalFileAttributes;
|
|
}
|
|
}
|
|
|
|
set {
|
|
externalFileAttributes = value;
|
|
known |= (ushort)KNOWN_EXTERN_ATTRIBUTES;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the version made by for this entry or zero if unknown.
|
|
/// The value / 10 indicates the major version number, and
|
|
/// the value mod 10 is the minor version number
|
|
/// </summary>
|
|
public int VersionMadeBy {
|
|
get {
|
|
return versionMadeBy & 0xff;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>
|
|
/// If the external file attributes are compatible with MS-DOS and can be read
|
|
/// by PKZIP for DOS version 2.04g then this value will be zero. Otherwise the value
|
|
/// will be non-zero and identify the host system on which the attributes are compatible.
|
|
/// </summary>
|
|
///
|
|
/// <remarks>
|
|
/// The values for this as defined in the Zip File format and by others are shown below. The values are somewhat
|
|
/// misleading in some cases as they are not all used as shown. You should consult the relevant documentation
|
|
/// to obtain up to date and correct information. The modified appnote by the infozip group is
|
|
/// particularly helpful as it documents a lot of peculiarities. The document is however a little dated.
|
|
/// <list type="table">
|
|
/// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
|
|
/// <item>1 - Amiga</item>
|
|
/// <item>2 - OpenVMS</item>
|
|
/// <item>3 - Unix</item>
|
|
/// <item>4 - VM/CMS</item>
|
|
/// <item>5 - Atari ST</item>
|
|
/// <item>6 - OS/2 HPFS</item>
|
|
/// <item>7 - Macintosh</item>
|
|
/// <item>8 - Z-System</item>
|
|
/// <item>9 - CP/M</item>
|
|
/// <item>10 - Windows NTFS</item>
|
|
/// <item>11 - MVS (OS/390 - Z/OS)</item>
|
|
/// <item>12 - VSE</item>
|
|
/// <item>13 - Acorn Risc</item>
|
|
/// <item>14 - VFAT</item>
|
|
/// <item>15 - Alternate MVS</item>
|
|
/// <item>16 - BeOS</item>
|
|
/// <item>17 - Tandem</item>
|
|
/// <item>18 - OS/400</item>
|
|
/// <item>19 - OS/X (Darwin)</item>
|
|
/// <item>99 - WinZip AES</item>
|
|
/// <item>remainder - unused</item>
|
|
/// </list>
|
|
/// </remarks>
|
|
|
|
public int HostSystem {
|
|
get { return (versionMadeBy >> 8) & 0xff; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a zip entry with the given name.
|
|
/// </summary>
|
|
/// <param name="name">
|
|
/// The name for this entry. Can include directory components.
|
|
/// The convention for names is 'unix' style paths with no device names and
|
|
/// path elements separated by '/' characters. This is not enforced see <see cref="CleanName">CleanName</see>
|
|
/// on how to ensure names are valid if this is desired.
|
|
/// </param>
|
|
/// <exception cref="ArgumentNullException">
|
|
/// The name passed is null
|
|
/// </exception>
|
|
public ZipEntry(string name) : this(name, 0, ZipConstants.VERSION_MADE_BY)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a zip entry with the given name and version required to extract
|
|
/// </summary>
|
|
/// <param name="name">
|
|
/// The name for this entry. Can include directory components.
|
|
/// The convention for names is 'unix' style paths with no device names and
|
|
/// path elements separated by '/' characters. This is not enforced see <see cref="CleanName">CleanName</see>
|
|
/// on how to ensure names are valid if this is desired.
|
|
/// </param>
|
|
/// <param name="versionRequiredToExtract">
|
|
/// The minimum 'feature version' required this entry
|
|
/// </param>
|
|
/// <exception cref="ArgumentNullException">
|
|
/// The name passed is null
|
|
/// </exception>
|
|
internal ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, ZipConstants.VERSION_MADE_BY)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes an entry with the given name and made by information
|
|
/// </summary>
|
|
/// <param name="name">Name for this entry</param>
|
|
/// <param name="madeByInfo">Version and HostSystem Information</param>
|
|
/// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</param>
|
|
/// <exception cref="ArgumentNullException">
|
|
/// The name passed is null
|
|
/// </exception>
|
|
/// <exception cref="ArgumentOutOfRangeException">
|
|
/// versionRequiredToExtract should be 0 (auto-calculate) or > 10
|
|
/// </exception>
|
|
/// <remarks>
|
|
/// This constructor is used by the ZipFile class when reading from the central header
|
|
/// It is not generally useful, use the constructor specifying the name only.
|
|
/// </remarks>
|
|
internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo)
|
|
{
|
|
if (name == null) {
|
|
throw new System.ArgumentNullException("ZipEntry name");
|
|
}
|
|
|
|
if ( name.Length == 0 ) {
|
|
throw new ArgumentException("ZipEntry name is empty");
|
|
}
|
|
|
|
if (versionRequiredToExtract != 0 && versionRequiredToExtract < 10) {
|
|
throw new ArgumentOutOfRangeException("versionRequiredToExtract");
|
|
}
|
|
|
|
this.DateTime = System.DateTime.Now;
|
|
this.name = name;
|
|
this.versionMadeBy = (ushort)madeByInfo;
|
|
this.versionToExtract = (ushort)versionRequiredToExtract;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a copy of the given zip entry.
|
|
/// </summary>
|
|
/// <param name="e">
|
|
/// The entry to copy.
|
|
/// </param>
|
|
public ZipEntry(ZipEntry e)
|
|
{
|
|
known = e.known;
|
|
name = e.name;
|
|
size = e.size;
|
|
compressedSize = e.compressedSize;
|
|
crc = e.crc;
|
|
dosTime = e.dosTime;
|
|
method = e.method;
|
|
ExtraData = e.ExtraData; // Note use of property ensuring data is unique
|
|
comment = e.comment;
|
|
versionToExtract = e.versionToExtract;
|
|
versionMadeBy = e.versionMadeBy;
|
|
externalFileAttributes = e.externalFileAttributes;
|
|
flags = e.flags;
|
|
|
|
zipFileIndex = -1;
|
|
offset = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get minimum Zip feature version required to extract this entry
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Minimum features are defined as:<br/>
|
|
/// 1.0 - Default value<br/>
|
|
/// 1.1 - File is a volume label<br/>
|
|
/// 2.0 - File is a folder/directory<br/>
|
|
/// 2.0 - File is compressed using Deflate compression<br/>
|
|
/// 2.0 - File is encrypted using traditional encryption<br/>
|
|
/// 2.1 - File is compressed using Deflate64<br/>
|
|
/// 2.5 - File is compressed using PKWARE DCL Implode<br/>
|
|
/// 2.7 - File is a patch data set<br/>
|
|
/// 4.5 - File uses Zip64 format extensions<br/>
|
|
/// 4.6 - File is compressed using BZIP2 compression<br/>
|
|
/// 5.0 - File is encrypted using DES<br/>
|
|
/// 5.0 - File is encrypted using 3DES<br/>
|
|
/// 5.0 - File is encrypted using original RC2 encryption<br/>
|
|
/// 5.0 - File is encrypted using RC4 encryption<br/>
|
|
/// 5.1 - File is encrypted using AES encryption<br/>
|
|
/// 5.1 - File is encrypted using corrected RC2 encryption<br/>
|
|
/// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
|
|
/// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
|
|
/// 6.2 - Central directory encryption (not confirmed yet)<br/>
|
|
/// </remarks>
|
|
public int Version {
|
|
get {
|
|
if (versionToExtract != 0) {
|
|
return versionToExtract;
|
|
} else {
|
|
int result = 10;
|
|
if (CompressionMethod.Deflated == method) {
|
|
result = 20;
|
|
} else if (IsDirectory == true) {
|
|
result = 20;
|
|
} else if (IsCrypted == true) {
|
|
result = 20;
|
|
} else if ((known & KNOWN_EXTERN_ATTRIBUTES) != 0 && (externalFileAttributes & 0x08) != 0) {
|
|
result = 11;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating if the entry requires Zip64 extensions to be stored
|
|
/// </summary>
|
|
public bool RequiresZip64 {
|
|
get {
|
|
return (this.size > uint.MaxValue) || (this.compressedSize > uint.MaxValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get/Set DosTime
|
|
/// </summary>
|
|
public long DosTime {
|
|
get {
|
|
if ((known & KNOWN_TIME) == 0) {
|
|
return 0;
|
|
} else {
|
|
return dosTime;
|
|
}
|
|
}
|
|
set {
|
|
this.dosTime = (uint)value;
|
|
known |= (ushort)KNOWN_TIME;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the time of last modification of the entry.
|
|
/// </summary>
|
|
public DateTime DateTime {
|
|
get {
|
|
// Although technically not valid some archives have dates set to zero.
|
|
// This mimics some archivers handling and is a good a cludge as any probably.
|
|
if ( dosTime == 0 ) {
|
|
return DateTime.Now;
|
|
}
|
|
else {
|
|
uint sec = 2 * (dosTime & 0x1f);
|
|
uint min = (dosTime >> 5) & 0x3f;
|
|
uint hrs = (dosTime >> 11) & 0x1f;
|
|
uint day = (dosTime >> 16) & 0x1f;
|
|
uint mon = ((dosTime >> 21) & 0xf);
|
|
uint year = ((dosTime >> 25) & 0x7f) + 1980;
|
|
return new System.DateTime((int)year, (int)mon, (int)day, (int)hrs, (int)min, (int)sec);
|
|
}
|
|
}
|
|
set {
|
|
DosTime = ((uint)value.Year - 1980 & 0x7f) << 25 |
|
|
((uint)value.Month) << 21 |
|
|
((uint)value.Day) << 16 |
|
|
((uint)value.Hour) << 11 |
|
|
((uint)value.Minute) << 5 |
|
|
((uint)value.Second) >> 1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the entry name. The path components in the entry should
|
|
/// always separated by slashes ('/'). Dos device names like C: should also
|
|
/// be removed. See <see cref="CleanName">CleanName</see>.
|
|
/// </summary>
|
|
public string Name {
|
|
get {
|
|
return name;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans a name making it conform to Zip file conventions.
|
|
/// Devices names ('c:\') and UNC share names ('\\server\share') are removed
|
|
/// and forward slashes ('\') are converted to back slashes ('/').
|
|
/// </summary>
|
|
/// <param name="name">Name to clean</param>
|
|
/// <param name="relativePath">Make names relative if true or absolute if false</param>
|
|
static public string CleanName(string name, bool relativePath)
|
|
{
|
|
if (name == null) {
|
|
return "";
|
|
}
|
|
|
|
if (Path.IsPathRooted(name) == true) {
|
|
// NOTE:
|
|
// for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
|
|
name = name.Substring(Path.GetPathRoot(name).Length);
|
|
}
|
|
|
|
name = name.Replace(@"\", "/");
|
|
|
|
if (relativePath == true) {
|
|
if (name.Length > 0 && (name[0] == Path.AltDirectorySeparatorChar || name[0] == Path.DirectorySeparatorChar)) {
|
|
name = name.Remove(0, 1);
|
|
}
|
|
} else {
|
|
if (name.Length > 0 && name[0] != Path.AltDirectorySeparatorChar && name[0] != Path.DirectorySeparatorChar) {
|
|
name = name.Insert(0, "/");
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans a name making it conform to Zip file conventions.
|
|
/// Devices names ('c:\') and UNC share names ('\\server\share') are removed
|
|
/// and forward slashes ('\') are converted to back slashes ('/').
|
|
/// Names are made relative by trimming leading slashes which is compatible
|
|
/// with Windows-XPs built in Zip file handling.
|
|
/// </summary>
|
|
/// <param name="name">Name to clean</param>
|
|
static public string CleanName(string name)
|
|
{
|
|
return CleanName(name, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the size of the uncompressed data.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// If the size is not in the range 0..0xffffffffL
|
|
/// </exception>
|
|
/// <returns>
|
|
/// The size or -1 if unknown.
|
|
/// </returns>
|
|
public long Size {
|
|
get {
|
|
return (known & KNOWN_SIZE) != 0 ? (long)size : -1L;
|
|
}
|
|
set {
|
|
if (((ulong)value & 0xFFFFFFFF00000000L) != 0) {
|
|
throw new ArgumentOutOfRangeException("size");
|
|
}
|
|
this.size = (ulong)value;
|
|
this.known |= (ushort)KNOWN_SIZE;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the size of the compressed data.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// Size is not in the range 0..0xffffffff
|
|
/// </exception>
|
|
/// <returns>
|
|
/// The size or -1 if unknown.
|
|
/// </returns>
|
|
public long CompressedSize {
|
|
get {
|
|
return (known & KNOWN_CSIZE) != 0 ? (long)compressedSize : -1L;
|
|
}
|
|
set {
|
|
if (((ulong)value & 0xffffffff00000000L) != 0) {
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
this.compressedSize = (ulong)value;
|
|
this.known |= (ushort)KNOWN_CSIZE;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the crc of the uncompressed data.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// Crc is not in the range 0..0xffffffffL
|
|
/// </exception>
|
|
/// <returns>
|
|
/// The crc value or -1 if unknown.
|
|
/// </returns>
|
|
public long Crc {
|
|
get {
|
|
return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
|
|
}
|
|
set {
|
|
if (((ulong)crc & 0xffffffff00000000L) != 0) {
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
this.crc = (uint)value;
|
|
this.known |= (ushort)KNOWN_CRC;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the compression method. Only Deflated and Stored are supported.
|
|
/// </summary>
|
|
/// <returns>
|
|
/// The compression method for this entry
|
|
/// </returns>
|
|
/// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Deflated"/>
|
|
/// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Stored"/>
|
|
public CompressionMethod CompressionMethod {
|
|
get {
|
|
return method;
|
|
}
|
|
set {
|
|
this.method = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the extra data.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// Extra data is longer than 0xffff bytes.
|
|
/// </exception>
|
|
/// <returns>
|
|
/// Extra data or null if not set.
|
|
/// </returns>
|
|
public byte[] ExtraData {
|
|
get {
|
|
return extra;
|
|
}
|
|
set {
|
|
if (value == null) {
|
|
this.extra = null;
|
|
return;
|
|
}
|
|
|
|
if (value.Length > 0xffff) {
|
|
throw new System.ArgumentOutOfRangeException();
|
|
}
|
|
|
|
this.extra = new byte[value.Length];
|
|
Array.Copy(value, 0, this.extra, 0, value.Length);
|
|
|
|
try {
|
|
int pos = 0;
|
|
while (pos < extra.Length) {
|
|
int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
|
|
int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
|
|
|
|
if (len < 0 || pos + len > extra.Length) {
|
|
// This is still lenient but the extra data is corrupt
|
|
// TODO: drop the extra data? or somehow indicate to user
|
|
// there is a problem...
|
|
break;
|
|
}
|
|
|
|
if (sig == 0x5455) {
|
|
// extended time stamp, unix format by Rainer Prem <Rainer@Prem.de>
|
|
int flags = extra[pos];
|
|
// Can include other times but these are ignored. Length of data should
|
|
// actually be 1 + 4 * no of bits in flags.
|
|
if ((flags & 1) != 0 && len >= 5) {
|
|
int iTime = ((extra[pos+1] & 0xff) |
|
|
(extra[pos + 2] & 0xff) << 8 |
|
|
(extra[pos + 3] & 0xff) << 16 |
|
|
(extra[pos + 4] & 0xff) << 24);
|
|
|
|
DateTime = (new DateTime ( 1970, 1, 1, 0, 0, 0 ) + new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime ();
|
|
known |= (ushort)KNOWN_TIME;
|
|
}
|
|
} else if (sig == 0x0001) {
|
|
// ZIP64 extended information extra field
|
|
// Of variable size depending on which fields in header are too small
|
|
// fields appear here if the corresponding local or central directory record field
|
|
// is set to 0xFFFF or 0xFFFFFFFF and the entry is in Zip64 format.
|
|
//
|
|
// Original Size 8 bytes
|
|
// Compressed size 8 bytes
|
|
// Relative header offset 8 bytes
|
|
// Disk start number 4 bytes
|
|
}
|
|
pos += len;
|
|
}
|
|
} catch (Exception) {
|
|
/* be lenient */
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets/Sets the entry comment.
|
|
/// </summary>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// If comment is longer than 0xffff.
|
|
/// </exception>
|
|
/// <returns>
|
|
/// The comment or null if not set.
|
|
/// </returns>
|
|
public string Comment {
|
|
get {
|
|
return comment;
|
|
}
|
|
set {
|
|
// TODO: this test is strictly incorrect as the length is in characters
|
|
// While the test is correct in that a comment of this length or greater
|
|
// is definitely invalid, shorter comments may also have an invalid length.
|
|
if (value != null && value.Length > 0xffff) {
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
this.comment = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating of the if the entry is a directory. A directory is determined by
|
|
/// an entry name with a trailing slash '/'. The external file attributes
|
|
/// can also mark a file as a directory. The trailing slash convention should always be followed
|
|
/// however.
|
|
/// </summary>
|
|
public bool IsDirectory {
|
|
get {
|
|
int nlen = name.Length;
|
|
bool result = nlen > 0 && name[nlen - 1] == '/';
|
|
|
|
if (result == false && (known & KNOWN_EXTERN_ATTRIBUTES) != 0) {
|
|
if (HostSystem == 0 && (ExternalFileAttributes & 16) != 0) {
|
|
result = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a value of true if the entry appears to be a file; false otherwise
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This only takes account Windows attributes. Other operating systems are ignored.
|
|
/// For linux and others the result may be incorrect.
|
|
/// </remarks>
|
|
public bool IsFile {
|
|
get {
|
|
bool result = !IsDirectory;
|
|
|
|
// Exclude volume labels
|
|
if ( result && (known & KNOWN_EXTERN_ATTRIBUTES) != 0) {
|
|
if (HostSystem == 0 && (ExternalFileAttributes & 8) != 0) {
|
|
result = false;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a copy of this zip entry.
|
|
/// </summary>
|
|
public object Clone()
|
|
{
|
|
return this.MemberwiseClone();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the string representation of this ZipEntry.
|
|
/// </summary>
|
|
public override string ToString()
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
}
|