// ZipStorer, by Jaime Olivares
// Website: http://github.com/jaime-olivares/zipstorer
namespace System.IO.Compression
{
///
/// Represents an entry in Zip file directory
///
public class ZipFileEntry
{
/// Compression method
public ZipStorer.Compression Method { get; set; }
/// Full path and filename as stored in Zip
public string FilenameInZip { get; set; }
/// Original file size
public long FileSize { get; set; }
/// Compressed file size
public long CompressedSize { get; set; }
/// Offset of header information inside Zip storage
public long HeaderOffset { get; set; }
/// Offset of file inside Zip storage
public long FileOffset { get; set; }
/// Size of header information
public uint HeaderSize { get; set; }
/// 32-bit checksum of entire file
public uint Crc32 { get; set; }
/// Last modification time of file
public DateTime ModifyTime { get; set; }
/// Creation time of file
public DateTime CreationTime { get; set; }
/// Last access time of file
public DateTime AccessTime { get; set; }
/// User comment for file
public string Comment { get; set; }
/// True if UTF8 encoding for filename and comments, false if default (CP 437)
public bool EncodeUTF8 { get; set; }
/// Overriden method
/// Filename in Zip
public override string ToString()
{
return this.FilenameInZip;
}
public override bool Equals(object obj)
{
ZipFileEntry o = obj as ZipFileEntry;
if (o is null)
return false;
return this.HeaderOffset == o.HeaderOffset;
}
public override int GetHashCode()
{
return this.FilenameInZip.GetHashCode() + this.FileSize.GetHashCode();
}
public bool IsZip64ExtNeeded(byte mask)
{
bool zip64 = false;
if ((mask & 1) != 0)
zip64 = this.FileSize >= 0xFFFFFFFF || this.CompressedSize >= 0xFFFFFFFF;
if (!zip64 && (mask & 2) != 0)
zip64 = this.HeaderOffset >= 0xFFFFFFFF;
return zip64;
}
public byte[] CreateExtraInfo(bool localHeader)
{
var zip64FileSize = this.FileSize >= 0xFFFFFFFF || localHeader && this.FileSize == 0;
var zip64CompSize = this.CompressedSize >= 0xFFFFFFFF || localHeader && (this.FileSize == 0 || this.FileSize >= 0xFFFFFFFF);
var zip64Offset = !localHeader && this.HeaderOffset >= 0xFFFFFFFF;
int offset = (zip64FileSize ? 8 : 0) + (zip64CompSize ? 8 : 0) + (zip64Offset ? 8 : 0);
if (offset != 0)
offset += 4;
byte[] buffer = new byte[offset + 36];
if (offset > 0)
{
BitConverter.GetBytes((ushort)0x0001).CopyTo(buffer, 0); // ZIP64 Information
BitConverter.GetBytes((ushort)(offset - 4)).CopyTo(buffer, 2); // Length
BitConverter.GetBytes(zip64FileSize ? this.FileSize : zip64CompSize ? this.CompressedSize : this.HeaderOffset).CopyTo(buffer, 4);
if (zip64CompSize || zip64Offset)
BitConverter.GetBytes(zip64CompSize ? this.CompressedSize : this.HeaderOffset).CopyTo(buffer, 12);
if (zip64Offset)
BitConverter.GetBytes(this.HeaderOffset).CopyTo(buffer, 20);
}
BitConverter.GetBytes((ushort)0x000A).CopyTo(buffer, offset); // NTFS FileTime
BitConverter.GetBytes((ushort)32).CopyTo(buffer, offset + 2); // Length
BitConverter.GetBytes((uint)0).CopyTo(buffer, offset + 4); // Reserved
BitConverter.GetBytes((ushort)0x0001).CopyTo(buffer, offset + 8); // Tag 1
BitConverter.GetBytes((ushort)24).CopyTo(buffer, offset + 10); // Size 1
BitConverter.GetBytes(this.ModifyTime.ToFileTime()).CopyTo(buffer, offset + 12); // MTime
BitConverter.GetBytes(this.AccessTime.ToFileTime()).CopyTo(buffer, offset + 20); // ATime
BitConverter.GetBytes(this.CreationTime.ToFileTime()).CopyTo(buffer, offset + 28); // CTime
return buffer;
}
public void ReadExtraInfo(byte[] buffer, int offset, int extraSize)
{
if (buffer.Length < 4)
return;
int start = offset;
int pos = offset;
uint tag, size;
while (pos < buffer.Length - 4 && pos - start < extraSize)
{
uint extraId = BitConverter.ToUInt16(buffer, pos);
uint length = BitConverter.ToUInt16(buffer, pos + 2);
if (extraId == 0x0001) // ZIP64 Information
{
int fieldOffset = 0;
while (fieldOffset < Math.Min(length, 24))
{
var data = BitConverter.ToInt64(buffer, pos + 4 + fieldOffset);
if (this.FileSize == 0xFFFFFFFF)
this.FileSize = data;
else if (this.CompressedSize == 0xFFFFFFFF)
this.CompressedSize = data;
else if (this.HeaderOffset == 0xFFFFFFFF)
this.HeaderOffset = data;
fieldOffset += 8;
}
}
if (extraId == 0x000A) // NTFS FileTime
{
tag = BitConverter.ToUInt16(buffer, pos + 8);
size = BitConverter.ToUInt16(buffer, pos + 10);
if (tag == 1 && size == 24)
{
this.ModifyTime = DateTime.FromFileTime(BitConverter.ToInt64(buffer, pos + 12));
this.AccessTime = DateTime.FromFileTime(BitConverter.ToInt64(buffer, pos + 20));
this.CreationTime = DateTime.FromFileTime(BitConverter.ToInt64(buffer, pos + 28));
}
}
pos += (int)length + 4;
}
}
}
}