Fix zip64 having invalid header

This commit is contained in:
UnknownShadow200 2018-07-26 05:34:03 +10:00
parent 455e76ad73
commit bd2c38b717

View File

@ -106,7 +106,7 @@ namespace MCGalaxy {
} }
public sealed class ZipWriter { public sealed class ZipWriter {
BinaryWriter w; BinaryWriter writer;
Stream stream; Stream stream;
byte[] buffer = new byte[81920]; byte[] buffer = new byte[81920];
@ -116,11 +116,12 @@ namespace MCGalaxy {
int numEntries; int numEntries;
long centralDirOffset, centralDirSize, zip64EndOffset; long centralDirOffset, centralDirSize, zip64EndOffset;
const ushort ver_norm = 20, ver_zip64 = 45, zip64Extra = 28; const ushort ver_norm = 20, ver_zip64 = 45;
const ushort zip64CentralExtra = 28, zip64LocalExtra = 20;
public ZipWriter(Stream stream) { public ZipWriter(Stream stream) {
this.stream = stream; this.stream = stream;
w = new BinaryWriter(stream); writer = new BinaryWriter(stream);
} }
public void WriteEntry(Stream src, string file, bool compress) { public void WriteEntry(Stream src, string file, bool compress) {
@ -129,7 +130,7 @@ namespace MCGalaxy {
entry.LocalHeaderOffset = stream.Position; entry.LocalHeaderOffset = stream.Position;
// leave some room to fill in header later // leave some room to fill in header later
int headerSize = 30 + entry.Filename.Length + zip64Extra; int headerSize = 30 + entry.Filename.Length + zip64LocalExtra;
stream.Write(buffer, 0, headerSize); stream.Write(buffer, 0, headerSize);
// set bit flag for non-ascii filename // set bit flag for non-ascii filename
@ -156,7 +157,7 @@ namespace MCGalaxy {
for (int i = 0; i < numEntries; i++) { for (int i = 0; i < numEntries; i++) {
// turns out we didn't actually need zip64 extra field // turns out we didn't actually need zip64 extra field
ZipEntry entry = entries[i]; ZipEntry entry = entries[i];
if (!zip64) entry.LocalHeaderOffset += zip64Extra; if (!zip64) entry.LocalHeaderOffset += zip64LocalExtra;
stream.Seek(entry.LocalHeaderOffset, SeekOrigin.Begin); stream.Seek(entry.LocalHeaderOffset, SeekOrigin.Begin);
WriteLocalFileRecord(entry); WriteLocalFileRecord(entry);
@ -190,8 +191,9 @@ namespace MCGalaxy {
void WriteLocalFileRecord(ZipEntry entry) { void WriteLocalFileRecord(ZipEntry entry) {
ushort extraLen = (ushort)(zip64 ? zip64Extra : 0); ushort extraLen = (ushort)(zip64 ? zip64LocalExtra : 0);
ushort version = zip64 ? ver_zip64 : ver_norm; ushort version = zip64 ? ver_zip64 : ver_norm;
BinaryWriter w = writer;
ZipEntry copy = entry; ZipEntry copy = entry;
if (zip64) entry.Reset(); if (zip64) entry.Reset();
@ -207,12 +209,18 @@ namespace MCGalaxy {
w.Write(extraLen); w.Write(extraLen);
w.Write(entry.Filename); w.Write(entry.Filename);
if (zip64) WriteZip64ExtraField(copy, false); if (!zip64) return;
w.Write((ushort)1);
w.Write((ushort)(zip64LocalExtra - 4));
w.Write(copy.UncompressedSize);
w.Write(copy.CompressedSize);
} }
void WriteCentralDirectoryRecord(ZipEntry entry) { void WriteCentralDirectoryRecord(ZipEntry entry) {
ushort extraLen = (ushort)(zip64 ? zip64Extra : 0); ushort extraLen = (ushort)(zip64 ? zip64CentralExtra : 0);
ushort version = zip64 ? ver_zip64 : ver_norm; ushort version = zip64 ? ver_zip64 : ver_norm;
BinaryWriter w = writer;
ZipEntry copy = entry; ZipEntry copy = entry;
if (zip64) entry.Reset(); if (zip64) entry.Reset();
@ -234,30 +242,27 @@ namespace MCGalaxy {
w.Write((int)entry.LocalHeaderOffset); w.Write((int)entry.LocalHeaderOffset);
w.Write(entry.Filename); w.Write(entry.Filename);
if (zip64) WriteZip64ExtraField(copy, true); if (!zip64) return;
} w.Write((ushort)1);
void WriteZip64ExtraField(ZipEntry entry, bool offset) {
int len = zip64Extra - 4; // ignore header size
if (!offset) len -= 8;
w.Write((ushort)1); // mapping id w.Write((ushort)(zip64CentralExtra - 4));
w.Write((ushort)len); w.Write(copy.UncompressedSize);
w.Write(entry.UncompressedSize); w.Write(copy.CompressedSize);
w.Write(entry.CompressedSize); w.Write(copy.LocalHeaderOffset);
if (offset) w.Write(entry.LocalHeaderOffset);
} }
void WriteLastModified() { void WriteLastModified() {
int modTime = (now.Second / 2) | (now.Minute << 5) | (now.Hour << 11); int modTime = (now.Second / 2) | (now.Minute << 5) | (now.Hour << 11);
int modDate = (now.Day) | (now.Month << 5) | ((now.Year - 1980) << 9); int modDate = (now.Day) | (now.Month << 5) | ((now.Year - 1980) << 9);
w.Write((ushort)modTime); writer.Write((ushort)modTime);
w.Write((ushort)modDate); writer.Write((ushort)modDate);
} }
void WriteZip64EndOfCentralDirectoryRecord() { void WriteZip64EndOfCentralDirectoryRecord() {
w.Write((uint)0x06064b50); BinaryWriter w = writer;
const long zip64EndDataSize = (2 * 2) + (2 * 4) + (4 * 8); const long zip64EndDataSize = (2 * 2) + (2 * 4) + (4 * 8);
w.Write((uint)0x06064b50);
w.Write(zip64EndDataSize); w.Write(zip64EndDataSize);
w.Write(ver_zip64); w.Write(ver_zip64);
w.Write(ver_zip64); w.Write(ver_zip64);
@ -270,6 +275,7 @@ namespace MCGalaxy {
} }
void WriteZip64EndOfCentralDirectoryLocator() { void WriteZip64EndOfCentralDirectoryLocator() {
BinaryWriter w = writer;
w.Write((uint)0x07064b50); w.Write((uint)0x07064b50);
w.Write(0); // disk number of zip64 end of central directory w.Write(0); // disk number of zip64 end of central directory
w.Write(zip64EndOffset); w.Write(zip64EndOffset);
@ -277,6 +283,7 @@ namespace MCGalaxy {
} }
void WriteEndOfCentralDirectoryRecord() { void WriteEndOfCentralDirectoryRecord() {
BinaryWriter w = writer;
w.Write(0x06054b50); w.Write(0x06054b50);
w.Write((ushort)0); // disk number w.Write((ushort)0); // disk number
w.Write((ushort)0); // disk number of start w.Write((ushort)0); // disk number of start