1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage zip 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "bytes" 19*333d2b36SAndroid Build Coastguard Worker "testing" 20*333d2b36SAndroid Build Coastguard Worker) 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Workervar stripZip64Testcases = []struct { 23*333d2b36SAndroid Build Coastguard Worker name string 24*333d2b36SAndroid Build Coastguard Worker in []byte 25*333d2b36SAndroid Build Coastguard Worker out []byte 26*333d2b36SAndroid Build Coastguard Worker}{ 27*333d2b36SAndroid Build Coastguard Worker { 28*333d2b36SAndroid Build Coastguard Worker name: "empty", 29*333d2b36SAndroid Build Coastguard Worker in: []byte{}, 30*333d2b36SAndroid Build Coastguard Worker out: []byte{}, 31*333d2b36SAndroid Build Coastguard Worker }, 32*333d2b36SAndroid Build Coastguard Worker { 33*333d2b36SAndroid Build Coastguard Worker name: "trailing data", 34*333d2b36SAndroid Build Coastguard Worker in: []byte{1, 2, 3}, 35*333d2b36SAndroid Build Coastguard Worker out: []byte{1, 2, 3}, 36*333d2b36SAndroid Build Coastguard Worker }, 37*333d2b36SAndroid Build Coastguard Worker { 38*333d2b36SAndroid Build Coastguard Worker name: "valid non-zip64 extra", 39*333d2b36SAndroid Build Coastguard Worker in: []byte{2, 0, 2, 0, 1, 2}, 40*333d2b36SAndroid Build Coastguard Worker out: []byte{2, 0, 2, 0, 1, 2}, 41*333d2b36SAndroid Build Coastguard Worker }, 42*333d2b36SAndroid Build Coastguard Worker { 43*333d2b36SAndroid Build Coastguard Worker name: "two valid non-zip64 extras", 44*333d2b36SAndroid Build Coastguard Worker in: []byte{2, 0, 2, 0, 1, 2, 2, 0, 0, 0}, 45*333d2b36SAndroid Build Coastguard Worker out: []byte{2, 0, 2, 0, 1, 2, 2, 0, 0, 0}, 46*333d2b36SAndroid Build Coastguard Worker }, 47*333d2b36SAndroid Build Coastguard Worker { 48*333d2b36SAndroid Build Coastguard Worker name: "simple zip64 extra", 49*333d2b36SAndroid Build Coastguard Worker in: []byte{1, 0, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8}, 50*333d2b36SAndroid Build Coastguard Worker out: []byte{}, 51*333d2b36SAndroid Build Coastguard Worker }, 52*333d2b36SAndroid Build Coastguard Worker { 53*333d2b36SAndroid Build Coastguard Worker name: "zip64 extra and valid non-zip64 extra", 54*333d2b36SAndroid Build Coastguard Worker in: []byte{1, 0, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 2, 0, 0, 0}, 55*333d2b36SAndroid Build Coastguard Worker out: []byte{2, 0, 0, 0}, 56*333d2b36SAndroid Build Coastguard Worker }, 57*333d2b36SAndroid Build Coastguard Worker { 58*333d2b36SAndroid Build Coastguard Worker name: "invalid extra", 59*333d2b36SAndroid Build Coastguard Worker in: []byte{0, 0, 8, 0, 0, 0}, 60*333d2b36SAndroid Build Coastguard Worker out: []byte{0, 0, 8, 0, 0, 0}, 61*333d2b36SAndroid Build Coastguard Worker }, 62*333d2b36SAndroid Build Coastguard Worker { 63*333d2b36SAndroid Build Coastguard Worker name: "zip64 extra and extended-timestamp extra and valid non-zip64 extra", 64*333d2b36SAndroid Build Coastguard Worker in: []byte{1, 0, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 85, 84, 5, 0, 1, 1, 2, 3, 4, 2, 0, 0, 0}, 65*333d2b36SAndroid Build Coastguard Worker out: []byte{2, 0, 0, 0}, 66*333d2b36SAndroid Build Coastguard Worker }, 67*333d2b36SAndroid Build Coastguard Worker} 68*333d2b36SAndroid Build Coastguard Worker 69*333d2b36SAndroid Build Coastguard Workerfunc TestStripZip64Extras(t *testing.T) { 70*333d2b36SAndroid Build Coastguard Worker for _, testcase := range stripZip64Testcases { 71*333d2b36SAndroid Build Coastguard Worker got := stripExtras(testcase.in) 72*333d2b36SAndroid Build Coastguard Worker if !bytes.Equal(got, testcase.out) { 73*333d2b36SAndroid Build Coastguard Worker t.Errorf("Failed testcase %s\ninput: %v\n want: %v\n got: %v\n", testcase.name, testcase.in, testcase.out, got) 74*333d2b36SAndroid Build Coastguard Worker } 75*333d2b36SAndroid Build Coastguard Worker } 76*333d2b36SAndroid Build Coastguard Worker} 77*333d2b36SAndroid Build Coastguard Worker 78*333d2b36SAndroid Build Coastguard Workerfunc TestCopyFromZip64(t *testing.T) { 79*333d2b36SAndroid Build Coastguard Worker if testing.Short() { 80*333d2b36SAndroid Build Coastguard Worker t.Skip("slow test; skipping") 81*333d2b36SAndroid Build Coastguard Worker } 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Worker const size = uint32max + 1 84*333d2b36SAndroid Build Coastguard Worker fromZipBytes := &bytes.Buffer{} 85*333d2b36SAndroid Build Coastguard Worker fromZip := NewWriter(fromZipBytes) 86*333d2b36SAndroid Build Coastguard Worker w, err := fromZip.CreateHeaderAndroid(&FileHeader{ 87*333d2b36SAndroid Build Coastguard Worker Name: "large", 88*333d2b36SAndroid Build Coastguard Worker Method: Store, 89*333d2b36SAndroid Build Coastguard Worker UncompressedSize64: size, 90*333d2b36SAndroid Build Coastguard Worker CompressedSize64: size, 91*333d2b36SAndroid Build Coastguard Worker }) 92*333d2b36SAndroid Build Coastguard Worker if err != nil { 93*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Create: %v", err) 94*333d2b36SAndroid Build Coastguard Worker } 95*333d2b36SAndroid Build Coastguard Worker _, err = w.Write(make([]byte, size)) 96*333d2b36SAndroid Build Coastguard Worker if err != nil { 97*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Write: %v", err) 98*333d2b36SAndroid Build Coastguard Worker } 99*333d2b36SAndroid Build Coastguard Worker err = fromZip.Close() 100*333d2b36SAndroid Build Coastguard Worker if err != nil { 101*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Close: %v", err) 102*333d2b36SAndroid Build Coastguard Worker } 103*333d2b36SAndroid Build Coastguard Worker fromZip = nil 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Worker fromZipReader, err := NewReader(bytes.NewReader(fromZipBytes.Bytes()), int64(fromZipBytes.Len())) 106*333d2b36SAndroid Build Coastguard Worker if err != nil { 107*333d2b36SAndroid Build Coastguard Worker t.Fatalf("NewReader: %v", err) 108*333d2b36SAndroid Build Coastguard Worker } 109*333d2b36SAndroid Build Coastguard Worker 110*333d2b36SAndroid Build Coastguard Worker toZipBytes := &bytes.Buffer{} 111*333d2b36SAndroid Build Coastguard Worker toZip := NewWriter(toZipBytes) 112*333d2b36SAndroid Build Coastguard Worker err = toZip.CopyFrom(fromZipReader.File[0], fromZipReader.File[0].Name) 113*333d2b36SAndroid Build Coastguard Worker if err != nil { 114*333d2b36SAndroid Build Coastguard Worker t.Fatalf("CopyFrom: %v", err) 115*333d2b36SAndroid Build Coastguard Worker } 116*333d2b36SAndroid Build Coastguard Worker 117*333d2b36SAndroid Build Coastguard Worker err = toZip.Close() 118*333d2b36SAndroid Build Coastguard Worker if err != nil { 119*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Close: %v", err) 120*333d2b36SAndroid Build Coastguard Worker } 121*333d2b36SAndroid Build Coastguard Worker 122*333d2b36SAndroid Build Coastguard Worker // Save some memory 123*333d2b36SAndroid Build Coastguard Worker fromZipReader = nil 124*333d2b36SAndroid Build Coastguard Worker fromZipBytes.Reset() 125*333d2b36SAndroid Build Coastguard Worker 126*333d2b36SAndroid Build Coastguard Worker toZipReader, err := NewReader(bytes.NewReader(toZipBytes.Bytes()), int64(toZipBytes.Len())) 127*333d2b36SAndroid Build Coastguard Worker if err != nil { 128*333d2b36SAndroid Build Coastguard Worker t.Fatalf("NewReader: %v", err) 129*333d2b36SAndroid Build Coastguard Worker } 130*333d2b36SAndroid Build Coastguard Worker 131*333d2b36SAndroid Build Coastguard Worker if len(toZipReader.File) != 1 { 132*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Expected 1 file in toZip, got %d", len(toZipReader.File)) 133*333d2b36SAndroid Build Coastguard Worker } 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Worker if g, w := toZipReader.File[0].CompressedSize64, uint64(size); g != w { 136*333d2b36SAndroid Build Coastguard Worker t.Errorf("Expected CompressedSize64 %d, got %d", w, g) 137*333d2b36SAndroid Build Coastguard Worker } 138*333d2b36SAndroid Build Coastguard Worker 139*333d2b36SAndroid Build Coastguard Worker if g, w := toZipReader.File[0].UncompressedSize64, uint64(size); g != w { 140*333d2b36SAndroid Build Coastguard Worker t.Errorf("Expected UnompressedSize64 %d, got %d", w, g) 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker} 143*333d2b36SAndroid Build Coastguard Worker 144*333d2b36SAndroid Build Coastguard Worker// Test for b/187485108: zip64 output can't be read by p7zip 16.02. 145*333d2b36SAndroid Build Coastguard Workerfunc TestZip64P7ZipRecords(t *testing.T) { 146*333d2b36SAndroid Build Coastguard Worker if testing.Short() { 147*333d2b36SAndroid Build Coastguard Worker t.Skip("slow test; skipping") 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker 150*333d2b36SAndroid Build Coastguard Worker const size = uint32max + 1 151*333d2b36SAndroid Build Coastguard Worker zipBytes := &bytes.Buffer{} 152*333d2b36SAndroid Build Coastguard Worker zip := NewWriter(zipBytes) 153*333d2b36SAndroid Build Coastguard Worker f, err := zip.CreateHeaderAndroid(&FileHeader{ 154*333d2b36SAndroid Build Coastguard Worker Name: "large", 155*333d2b36SAndroid Build Coastguard Worker Method: Store, 156*333d2b36SAndroid Build Coastguard Worker UncompressedSize64: size, 157*333d2b36SAndroid Build Coastguard Worker CompressedSize64: size, 158*333d2b36SAndroid Build Coastguard Worker }) 159*333d2b36SAndroid Build Coastguard Worker if err != nil { 160*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Create: %v", err) 161*333d2b36SAndroid Build Coastguard Worker } 162*333d2b36SAndroid Build Coastguard Worker _, err = f.Write(make([]byte, size)) 163*333d2b36SAndroid Build Coastguard Worker if err != nil { 164*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Write: %v", err) 165*333d2b36SAndroid Build Coastguard Worker } 166*333d2b36SAndroid Build Coastguard Worker err = zip.Close() 167*333d2b36SAndroid Build Coastguard Worker if err != nil { 168*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Close: %v", err) 169*333d2b36SAndroid Build Coastguard Worker } 170*333d2b36SAndroid Build Coastguard Worker 171*333d2b36SAndroid Build Coastguard Worker buf := zipBytes.Bytes() 172*333d2b36SAndroid Build Coastguard Worker p := findSignatureInBlock(buf) 173*333d2b36SAndroid Build Coastguard Worker if p < 0 { 174*333d2b36SAndroid Build Coastguard Worker t.Fatalf("Missing signature") 175*333d2b36SAndroid Build Coastguard Worker } 176*333d2b36SAndroid Build Coastguard Worker 177*333d2b36SAndroid Build Coastguard Worker b := readBuf(buf[p+4:]) // skip signature 178*333d2b36SAndroid Build Coastguard Worker d := &directoryEnd{ 179*333d2b36SAndroid Build Coastguard Worker diskNbr: uint32(b.uint16()), 180*333d2b36SAndroid Build Coastguard Worker dirDiskNbr: uint32(b.uint16()), 181*333d2b36SAndroid Build Coastguard Worker dirRecordsThisDisk: uint64(b.uint16()), 182*333d2b36SAndroid Build Coastguard Worker directoryRecords: uint64(b.uint16()), 183*333d2b36SAndroid Build Coastguard Worker directorySize: uint64(b.uint32()), 184*333d2b36SAndroid Build Coastguard Worker directoryOffset: uint64(b.uint32()), 185*333d2b36SAndroid Build Coastguard Worker commentLen: b.uint16(), 186*333d2b36SAndroid Build Coastguard Worker } 187*333d2b36SAndroid Build Coastguard Worker 188*333d2b36SAndroid Build Coastguard Worker // p7zip 16.02 wants regular end record directoryRecords to be accurate. 189*333d2b36SAndroid Build Coastguard Worker if g, w := d.directoryRecords, uint64(1); g != w { 190*333d2b36SAndroid Build Coastguard Worker t.Errorf("wanted directoryRecords %d, got %d", w, g) 191*333d2b36SAndroid Build Coastguard Worker } 192*333d2b36SAndroid Build Coastguard Worker 193*333d2b36SAndroid Build Coastguard Worker zip64ExtraBuf := 48 // 4x uint16 + 5x uint64 194*333d2b36SAndroid Build Coastguard Worker expectedDirSize := directoryHeaderLen + zip64ExtraBuf + len("large") // name of header 195*333d2b36SAndroid Build Coastguard Worker if g, w := d.directorySize, uint64(expectedDirSize); g != w { 196*333d2b36SAndroid Build Coastguard Worker t.Errorf("wanted directorySize %d, got %d", w, g) 197*333d2b36SAndroid Build Coastguard Worker } 198*333d2b36SAndroid Build Coastguard Worker 199*333d2b36SAndroid Build Coastguard Worker if g, w := d.directoryOffset, uint64(uint32max); g != w { 200*333d2b36SAndroid Build Coastguard Worker t.Errorf("wanted directoryOffset %d, got %d", w, g) 201*333d2b36SAndroid Build Coastguard Worker } 202*333d2b36SAndroid Build Coastguard Worker 203*333d2b36SAndroid Build Coastguard Worker r := bytes.NewReader(buf) 204*333d2b36SAndroid Build Coastguard Worker 205*333d2b36SAndroid Build Coastguard Worker p64, err := findDirectory64End(r, int64(p)) 206*333d2b36SAndroid Build Coastguard Worker if err != nil { 207*333d2b36SAndroid Build Coastguard Worker t.Fatalf("findDirectory64End: %v", err) 208*333d2b36SAndroid Build Coastguard Worker } 209*333d2b36SAndroid Build Coastguard Worker if p < 0 { 210*333d2b36SAndroid Build Coastguard Worker t.Fatalf("findDirectory64End: not found") 211*333d2b36SAndroid Build Coastguard Worker } 212*333d2b36SAndroid Build Coastguard Worker err = readDirectory64End(r, p64, d) 213*333d2b36SAndroid Build Coastguard Worker if err != nil { 214*333d2b36SAndroid Build Coastguard Worker t.Fatalf("readDirectory64End: %v", err) 215*333d2b36SAndroid Build Coastguard Worker } 216*333d2b36SAndroid Build Coastguard Worker 217*333d2b36SAndroid Build Coastguard Worker if g, w := d.directoryRecords, uint64(1); g != w { 218*333d2b36SAndroid Build Coastguard Worker t.Errorf("wanted directoryRecords %d, got %d", w, g) 219*333d2b36SAndroid Build Coastguard Worker } 220*333d2b36SAndroid Build Coastguard Worker 221*333d2b36SAndroid Build Coastguard Worker if g, w := d.directoryOffset, uint64(uint32max); g <= w { 222*333d2b36SAndroid Build Coastguard Worker t.Errorf("wanted directoryOffset > %d, got %d", w, g) 223*333d2b36SAndroid Build Coastguard Worker } 224*333d2b36SAndroid Build Coastguard Worker} 225