Skip to content

Commit

Permalink
Merge pull request #211 from kenkendk/add_zip64
Browse files Browse the repository at this point in the history
Add zip64
  • Loading branch information
adamhathcock authored Mar 13, 2017
2 parents b3a4fed + 726b9c8 commit f853840
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 43 deletions.
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

0 comments on commit f853840

Please sign in to comment.