mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-11-15 17:02:03 +00:00
Merge pull request #803 from DannyBoyk/802_Add_UnixTimeExtraField_Support_Zips
Add support for the UnixTimeExtraField in Zip files
This commit is contained in:
@@ -85,6 +85,36 @@ internal class DirectoryEntryHeader : ZipFileEntry
|
||||
RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader;
|
||||
}
|
||||
}
|
||||
|
||||
var unixTimeExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnixTimeExtraField);
|
||||
|
||||
if (unixTimeExtra is not null)
|
||||
{
|
||||
// Tuple order is last modified time, last access time, and creation time.
|
||||
var unixTimeTuple = ((UnixTimeExtraField)unixTimeExtra).UnicodeTimes;
|
||||
|
||||
if (unixTimeTuple.Item1.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item1.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
else if (unixTimeTuple.Item2.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item2.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
else if (unixTimeTuple.Item3.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item3.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal ushort Version { get; private set; }
|
||||
|
||||
@@ -64,6 +64,36 @@ internal class LocalEntryHeader : ZipFileEntry
|
||||
UncompressedSize = zip64ExtraData.UncompressedSize;
|
||||
}
|
||||
}
|
||||
|
||||
var unixTimeExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnixTimeExtraField);
|
||||
|
||||
if (unixTimeExtra is not null)
|
||||
{
|
||||
// Tuple order is last modified time, last access time, and creation time.
|
||||
var unixTimeTuple = ((UnixTimeExtraField)unixTimeExtra).UnicodeTimes;
|
||||
|
||||
if (unixTimeTuple.Item1.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item1.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
else if (unixTimeTuple.Item2.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item2.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
else if (unixTimeTuple.Item3.HasValue)
|
||||
{
|
||||
var dosTime = Utility.DateTimeToDosTime(unixTimeTuple.Item3.Value);
|
||||
|
||||
LastModifiedDate = (ushort)(dosTime >> 16);
|
||||
LastModifiedTime = (ushort)(dosTime & 0x0FFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal ushort Version { get; private set; }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Text;
|
||||
|
||||
@@ -13,7 +13,8 @@ internal enum ExtraDataType : ushort
|
||||
// Third Party Mappings
|
||||
// -Info-ZIP Unicode Path Extra Field
|
||||
UnicodePathExtraField = 0x7075,
|
||||
Zip64ExtendedInformationExtraField = 0x0001
|
||||
Zip64ExtendedInformationExtraField = 0x0001,
|
||||
UnixTimeExtraField = 0x5455
|
||||
}
|
||||
|
||||
internal class ExtraData
|
||||
@@ -145,6 +146,84 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData
|
||||
public uint VolumeNumber { get; private set; }
|
||||
}
|
||||
|
||||
internal sealed class UnixTimeExtraField : ExtraData
|
||||
{
|
||||
public UnixTimeExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
|
||||
: base(type, length, dataBytes) { }
|
||||
|
||||
/// <summary>
|
||||
/// The unix modified time, last access time, and creation time, if set.
|
||||
/// </summary>
|
||||
/// <remarks>Must return Tuple explicitly due to net462 support.</remarks>
|
||||
internal Tuple<DateTime?, DateTime?, DateTime?> UnicodeTimes
|
||||
{
|
||||
get
|
||||
{
|
||||
// There has to be at least 5 byte for there to be a timestamp.
|
||||
// 1 byte for flags and 4 bytes for a timestamp.
|
||||
if (DataBytes is null || DataBytes.Length < 5)
|
||||
{
|
||||
return Tuple.Create<DateTime?, DateTime?, DateTime?>(null, null, null);
|
||||
}
|
||||
|
||||
var flags = DataBytes[0];
|
||||
var isModifiedTimeSpecified = (flags & 0x01) == 1;
|
||||
var isLastAccessTimeSpecified = (flags & 0x02) == 1;
|
||||
var isCreationTimeSpecified = (flags & 0x04) == 1;
|
||||
var currentIndex = 1;
|
||||
DateTime? modifiedTime = null;
|
||||
DateTime? lastAccessTime = null;
|
||||
DateTime? creationTime = null;
|
||||
|
||||
if (isModifiedTimeSpecified)
|
||||
{
|
||||
var modifiedEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
|
||||
DataBytes.AsSpan(currentIndex, 4)
|
||||
);
|
||||
|
||||
currentIndex += 4;
|
||||
modifiedTime = DateTimeOffset.FromUnixTimeSeconds(modifiedEpochTime).UtcDateTime;
|
||||
}
|
||||
|
||||
if (isLastAccessTimeSpecified)
|
||||
{
|
||||
if (currentIndex + 4 > DataBytes.Length)
|
||||
{
|
||||
throw new ArchiveException("Invalid UnicodeExtraTime field");
|
||||
}
|
||||
|
||||
var lastAccessEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
|
||||
DataBytes.AsSpan(currentIndex, 4)
|
||||
);
|
||||
|
||||
currentIndex += 4;
|
||||
lastAccessTime = DateTimeOffset
|
||||
.FromUnixTimeSeconds(lastAccessEpochTime)
|
||||
.UtcDateTime;
|
||||
}
|
||||
|
||||
if (isCreationTimeSpecified)
|
||||
{
|
||||
if (currentIndex + 4 > DataBytes.Length)
|
||||
{
|
||||
throw new ArchiveException("Invalid UnicodeExtraTime field");
|
||||
}
|
||||
|
||||
var creationTimeEpochTime = BinaryPrimitives.ReadInt32LittleEndian(
|
||||
DataBytes.AsSpan(currentIndex, 4)
|
||||
);
|
||||
|
||||
currentIndex += 4;
|
||||
creationTime = DateTimeOffset
|
||||
.FromUnixTimeSeconds(creationTimeEpochTime)
|
||||
.UtcDateTime;
|
||||
}
|
||||
|
||||
return Tuple.Create(modifiedTime, lastAccessTime, creationTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LocalEntryHeaderExtraFactory
|
||||
{
|
||||
internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData) =>
|
||||
@@ -154,6 +233,7 @@ internal static class LocalEntryHeaderExtraFactory
|
||||
=> new ExtraUnicodePathExtraField(type, length, extraData),
|
||||
ExtraDataType.Zip64ExtendedInformationExtraField
|
||||
=> new Zip64ExtendedInformationExtraField(type, length, extraData),
|
||||
ExtraDataType.UnixTimeExtraField => new UnixTimeExtraField(type, length, extraData),
|
||||
_ => new ExtraData(type, length, extraData)
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user