diff options
author | Colin Cross <ccross@android.com> | 2020-12-17 15:08:01 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2020-12-17 15:08:50 -0800 |
commit | 373147baa9bf38a54140b75db4f4f39b17b02800 (patch) | |
tree | 371febfeb1c4256763e63b1dbe7dbd3dc36aac8c | |
parent | f1c48afc31fcb07d19c9c3a088a1ccb3d67127ef (diff) | |
download | soong-373147baa9bf38a54140b75db4f4f39b17b02800.tar.gz |
Support writing a ZIP64 file header
If the length of a stored file is more than 2^32 and a data descriptor
is not being used then a ZIP64 extra is required in the file header to
store the uncompressed and compressed lengths.
Bug: 175055267
Test: TestCopyFromZip64
Change-Id: Id414b4c04f48aefabfd835bd8339333d36576375
-rw-r--r-- | third_party/zip/android_test.go | 66 | ||||
-rw-r--r-- | third_party/zip/writer.go | 18 |
2 files changed, 81 insertions, 3 deletions
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go index 5154a17b3..9932c1b13 100644 --- a/third_party/zip/android_test.go +++ b/third_party/zip/android_test.go @@ -74,3 +74,69 @@ func TestStripZip64Extras(t *testing.T) { } } } + +func TestCopyFromZip64(t *testing.T) { + if testing.Short() { + t.Skip("slow test; skipping") + } + + const size = uint32max + 1 + fromZipBytes := &bytes.Buffer{} + fromZip := NewWriter(fromZipBytes) + w, err := fromZip.CreateHeaderAndroid(&FileHeader{ + Name: "large", + Method: Store, + UncompressedSize64: size, + CompressedSize64: size, + }) + if err != nil { + t.Fatalf("Create: %v", err) + } + _, err = w.Write(make([]byte, size)) + if err != nil { + t.Fatalf("Write: %v", err) + } + err = fromZip.Close() + if err != nil { + t.Fatalf("Close: %v", err) + } + fromZip = nil + + fromZipReader, err := NewReader(bytes.NewReader(fromZipBytes.Bytes()), int64(fromZipBytes.Len())) + if err != nil { + t.Fatalf("NewReader: %v", err) + } + + toZipBytes := &bytes.Buffer{} + toZip := NewWriter(toZipBytes) + err = toZip.CopyFrom(fromZipReader.File[0], fromZipReader.File[0].Name) + if err != nil { + t.Fatalf("CopyFrom: %v", err) + } + + err = toZip.Close() + if err != nil { + t.Fatalf("Close: %v", err) + } + + // Save some memory + fromZipReader = nil + fromZipBytes.Reset() + + toZipReader, err := NewReader(bytes.NewReader(toZipBytes.Bytes()), int64(toZipBytes.Len())) + if err != nil { + t.Fatalf("NewReader: %v", err) + } + + if len(toZipReader.File) != 1 { + t.Fatalf("Expected 1 file in toZip, got %d", len(toZipReader.File)) + } + + if g, w := toZipReader.File[0].CompressedSize64, uint64(size); g != w { + t.Errorf("Expected CompressedSize64 %d, got %d", w, g) + } + + if g, w := toZipReader.File[0].UncompressedSize64, uint64(size); g != w { + t.Errorf("Expected UnompressedSize64 %d, got %d", w, g) + } +} diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go index 4c5eb78b3..8dd986eb1 100644 --- a/third_party/zip/writer.go +++ b/third_party/zip/writer.go @@ -276,9 +276,6 @@ func writeHeader(w io.Writer, h *FileHeader) error { } else { b.uint32(h.CRC32) - if h.CompressedSize64 > uint32max || h.UncompressedSize64 > uint32max { - panic("skipping writing the data descriptor for a 64-bit value is not yet supported") - } compressedSize := uint32(h.CompressedSize64) if compressedSize == 0 { compressedSize = h.CompressedSize @@ -289,6 +286,21 @@ func writeHeader(w io.Writer, h *FileHeader) error { uncompressedSize = h.UncompressedSize } + if h.CompressedSize64 > uint32max || h.UncompressedSize64 > uint32max { + // Sizes don't fit in a 32-bit field, put them in a zip64 extra instead. + compressedSize = uint32max + uncompressedSize = uint32max + + // append a zip64 extra block to Extra + var buf [20]byte // 2x uint16 + 2x uint64 + eb := writeBuf(buf[:]) + eb.uint16(zip64ExtraId) + eb.uint16(16) // size = 2x uint64 + eb.uint64(h.UncompressedSize64) + eb.uint64(h.CompressedSize64) + h.Extra = append(h.Extra, buf[:]...) + } + b.uint32(compressedSize) b.uint32(uncompressedSize) } |