Skip to content

Add zip64 #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,31 +63,51 @@ internal override void Read(BinaryReader reader)

internal override void Write(BinaryWriter writer)
{
var zip64 = CompressedSize >= uint.MaxValue || UncompressedSize >= uint.MaxValue || RelativeOffsetOfEntryHeader >= uint.MaxValue;
if (zip64)
Version = (ushort)(Version > 45 ? Version : 45);

writer.Write(Version);
writer.Write(VersionNeededToExtract);
writer.Write((ushort)Flags);
writer.Write((ushort)CompressionMethod);
writer.Write(LastModifiedTime);
writer.Write(LastModifiedDate);
writer.Write(Crc);
writer.Write((uint)CompressedSize);
writer.Write((uint)UncompressedSize);
writer.Write(zip64 ? uint.MaxValue : CompressedSize);
writer.Write(zip64 ? uint.MaxValue : UncompressedSize);

byte[] nameBytes = EncodeString(Name);
writer.Write((ushort)nameBytes.Length);

//writer.Write((ushort)Extra.Length);
writer.Write((ushort)0);
if (zip64)
{
writer.Write((ushort)(2 + 2 + 8 + 8 + 8 + 4));
}
else
{
//writer.Write((ushort)Extra.Length);
writer.Write((ushort)0);
}
writer.Write((ushort)Comment.Length);

writer.Write(DiskNumberStart);
writer.Write(InternalFileAttributes);
writer.Write(ExternalFileAttributes);
writer.Write(RelativeOffsetOfEntryHeader);
writer.Write(zip64 ? uint.MaxValue : RelativeOffsetOfEntryHeader);

writer.Write(nameBytes);

// writer.Write(Extra);
if (zip64)
{
writer.Write((ushort)0x0001);
writer.Write((ushort)((8 + 8 + 8 + 4)));

writer.Write((ulong)UncompressedSize);
writer.Write((ulong)CompressedSize);
writer.Write((ulong)RelativeOffsetOfEntryHeader);
writer.Write((uint)0); // VolumeNumber = 0
}
writer.Write(Comment);
}

Expand Down
33 changes: 30 additions & 3 deletions src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,52 @@ internal override void Read(BinaryReader reader)

internal override void Write(BinaryWriter writer)
{
if (IsZip64)
Version = (ushort)(Version > 45 ? Version : 45);

writer.Write(Version);

writer.Write((ushort)Flags);
writer.Write((ushort)CompressionMethod);
writer.Write(LastModifiedTime);
writer.Write(LastModifiedDate);
writer.Write(Crc);
writer.Write((uint)CompressedSize);
writer.Write((uint)UncompressedSize);

if (IsZip64)
{
writer.Write(uint.MaxValue);
writer.Write(uint.MaxValue);
}
else
{
writer.Write(CompressedSize);
writer.Write(UncompressedSize);
}

byte[] nameBytes = EncodeString(Name);

writer.Write((ushort)nameBytes.Length);
writer.Write((ushort)0);
if (IsZip64)
{
writer.Write((ushort)(2 + 2 + (2 * 8)));
}
else
{
writer.Write((ushort)0);
}

//if (Extra != null)
//{
// writer.Write(Extra);
//}
writer.Write(nameBytes);
if (IsZip64)
{
writer.Write((ushort)0x0001);
writer.Write((ushort)(2 * 8));
writer.Write((ulong)CompressedSize);
writer.Write((ulong)UncompressedSize);
}
}

internal ushort Version { get; private set; }
Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/IO/CountingWritableSubStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal CountingWritableSubStream(Stream stream)
writableStream = stream;
}

public uint Count { get; private set; }
public ulong Count { get; private set; }

public override bool CanRead { get { return false; } }

Expand Down
53 changes: 42 additions & 11 deletions src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,56 @@ internal class ZipCentralDirectoryEntry
internal DateTime? ModificationTime { get; set; }
internal string Comment { get; set; }
internal uint Crc { get; set; }
internal uint HeaderOffset { get; set; }
internal uint Compressed { get; set; }
internal uint Decompressed { get; set; }
internal ulong HeaderOffset { get; set; }
internal ulong Compressed { get; set; }
internal ulong Decompressed { get; set; }
internal ushort Zip64HeaderOffset { get; set; }

internal uint Write(Stream outputStream, ZipCompressionMethod compression)
{
byte[] encodedFilename = Encoding.UTF8.GetBytes(FileName);
byte[] encodedComment = Encoding.UTF8.GetBytes(Comment);

//constant sig, then version made by, compabitility, then version to extract
outputStream.Write(new byte[] {80, 75, 1, 2, 0x14, 0, 0x0A, 0}, 0, 8);
var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue;
var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue || Zip64HeaderOffset != 0;

var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed;
var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed;
var headeroffsetvalue = zip64 ? uint.MaxValue : (uint)HeaderOffset;
var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0;
var version = (byte)(zip64 ? 45 : 10);

HeaderFlags flags = HeaderFlags.UTF8;
if (!outputStream.CanSeek)
{
flags |= HeaderFlags.UsePostDataDescriptor;
// Cannot use data descriptors with zip64:
// https://blogs.oracle.com/xuemingshen/entry/is_zipinput_outputstream_handling_of

// We check that streams are not written too large in the ZipWritingStream,
// so this extra guard is not required, but kept to simplify changing the code
// once the zip64 post-data issue is resolved
if (!zip64_stream)
flags |= HeaderFlags.UsePostDataDescriptor;

if (compression == ZipCompressionMethod.LZMA)
{
flags |= HeaderFlags.Bit1; // eos marker
}
}

//constant sig, then version made by, compabitility, then version to extract
outputStream.Write(new byte[] { 80, 75, 1, 2, 0x14, 0, version, 0 }, 0, 8);

outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)flags), 0, 2);
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)compression), 0, 2); // zipping method
outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4);

// zipping date and time
outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC
outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 4); // compressed file size
outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 4); // uncompressed file size
outputStream.Write(DataConverter.LittleEndian.GetBytes(compressedvalue), 0, 4); // compressed file size
outputStream.Write(DataConverter.LittleEndian.GetBytes(decompressedvalue), 0, 4); // uncompressed file size
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // extra length
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)extralength), 0, 2); // extra length
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedComment.Length), 0, 2);

outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // disk=0
Expand All @@ -51,13 +71,24 @@ internal uint Write(Stream outputStream, ZipCompressionMethod compression)
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x8100), 0, 2);

// External file attributes (normal/readable)
outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 4); // Offset of header
outputStream.Write(DataConverter.LittleEndian.GetBytes(headeroffsetvalue), 0, 4); // Offset of header

outputStream.Write(encodedFilename, 0, encodedFilename.Length);
if (zip64)
{
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x0001), 0, 2);
outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)(extralength - 4)), 0, 2);

outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 8);
outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 8);
outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 8);
outputStream.Write(DataConverter.LittleEndian.GetBytes(0), 0, 4); // VolumeNumber = 0
}

outputStream.Write(encodedComment, 0, encodedComment.Length);

return (uint)(8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2
+ 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + encodedComment.Length);
+ 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + extralength + encodedComment.Length);
}
}
}
Loading