github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/compress/zip/zip_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Tests that involve both reading and writing. 6 7 package zip 8 9 import ( 10 "bytes" 11 "fmt" 12 "hash" 13 "io" 14 "io/ioutil" 15 "sort" 16 "strings" 17 "testing" 18 "time" 19 ) 20 21 func TestOver65kFiles(t *testing.T) { 22 buf := new(bytes.Buffer) 23 w := NewWriter(buf) 24 const nFiles = (1 << 16) + 42 25 for i := 0; i < nFiles; i++ { 26 _, err := w.CreateHeader(&FileHeader{ 27 Name: fmt.Sprintf("%d.dat", i), 28 Method: Store, // avoid Issue 6136 and Issue 6138 29 }) 30 if err != nil { 31 t.Fatalf("creating file %d: %v", i, err) 32 } 33 } 34 if err := w.Close(); err != nil { 35 t.Fatalf("Writer.Close: %v", err) 36 } 37 s := buf.String() 38 zr, err := NewReader(strings.NewReader(s), int64(len(s))) 39 if err != nil { 40 t.Fatalf("NewReader: %v", err) 41 } 42 if got := len(zr.File); got != nFiles { 43 t.Fatalf("File contains %d files, want %d", got, nFiles) 44 } 45 for i := 0; i < nFiles; i++ { 46 want := fmt.Sprintf("%d.dat", i) 47 if zr.File[i].Name != want { 48 t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want) 49 } 50 } 51 } 52 53 func TestModTime(t *testing.T) { 54 var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC) 55 fh := new(FileHeader) 56 fh.SetModTime(testTime) 57 outTime := fh.ModTime() 58 if !outTime.Equal(testTime) { 59 t.Errorf("times don't match: got %s, want %s", outTime, testTime) 60 } 61 } 62 63 func testHeaderRoundTrip(fh *FileHeader, wantUncompressedSize uint32, wantUncompressedSize64 uint64, t *testing.T) { 64 fi := fh.FileInfo() 65 fh2, err := FileInfoHeader(fi) 66 if err != nil { 67 t.Fatal(err) 68 } 69 if got, want := fh2.Name, fh.Name; got != want { 70 t.Errorf("Name: got %s, want %s\n", got, want) 71 } 72 if got, want := fh2.UncompressedSize, wantUncompressedSize; got != want { 73 t.Errorf("UncompressedSize: got %d, want %d\n", got, want) 74 } 75 if got, want := fh2.UncompressedSize64, wantUncompressedSize64; got != want { 76 t.Errorf("UncompressedSize64: got %d, want %d\n", got, want) 77 } 78 if got, want := fh2.ModifiedTime, fh.ModifiedTime; got != want { 79 t.Errorf("ModifiedTime: got %d, want %d\n", got, want) 80 } 81 if got, want := fh2.ModifiedDate, fh.ModifiedDate; got != want { 82 t.Errorf("ModifiedDate: got %d, want %d\n", got, want) 83 } 84 85 if sysfh, ok := fi.Sys().(*FileHeader); !ok && sysfh != fh { 86 t.Errorf("Sys didn't return original *FileHeader") 87 } 88 } 89 90 func TestFileHeaderRoundTrip(t *testing.T) { 91 fh := &FileHeader{ 92 Name: "foo.txt", 93 UncompressedSize: 987654321, 94 ModifiedTime: 1234, 95 ModifiedDate: 5678, 96 } 97 testHeaderRoundTrip(fh, fh.UncompressedSize, uint64(fh.UncompressedSize), t) 98 } 99 100 func TestFileHeaderRoundTrip64(t *testing.T) { 101 fh := &FileHeader{ 102 Name: "foo.txt", 103 UncompressedSize64: 9876543210, 104 ModifiedTime: 1234, 105 ModifiedDate: 5678, 106 } 107 testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t) 108 } 109 110 type repeatedByte struct { 111 off int64 112 b byte 113 n int64 114 } 115 116 // rleBuffer is a run-length-encoded byte buffer. 117 // It's an io.Writer (like a bytes.Buffer) and also an io.ReaderAt, 118 // allowing random-access reads. 119 type rleBuffer struct { 120 buf []repeatedByte 121 } 122 123 func (r *rleBuffer) Size() int64 { 124 if len(r.buf) == 0 { 125 return 0 126 } 127 last := &r.buf[len(r.buf)-1] 128 return last.off + last.n 129 } 130 131 func (r *rleBuffer) Write(p []byte) (n int, err error) { 132 var rp *repeatedByte 133 if len(r.buf) > 0 { 134 rp = &r.buf[len(r.buf)-1] 135 // Fast path, if p is entirely the same byte repeated. 136 if lastByte := rp.b; len(p) > 0 && p[0] == lastByte { 137 all := true 138 for _, b := range p { 139 if b != lastByte { 140 all = false 141 break 142 } 143 } 144 if all { 145 rp.n += int64(len(p)) 146 return len(p), nil 147 } 148 } 149 } 150 151 for _, b := range p { 152 if rp == nil || rp.b != b { 153 r.buf = append(r.buf, repeatedByte{r.Size(), b, 1}) 154 rp = &r.buf[len(r.buf)-1] 155 } else { 156 rp.n++ 157 } 158 } 159 return len(p), nil 160 } 161 162 func (r *rleBuffer) ReadAt(p []byte, off int64) (n int, err error) { 163 if len(p) == 0 { 164 return 165 } 166 skipParts := sort.Search(len(r.buf), func(i int) bool { 167 part := &r.buf[i] 168 return part.off+part.n > off 169 }) 170 parts := r.buf[skipParts:] 171 if len(parts) > 0 { 172 skipBytes := off - parts[0].off 173 for len(parts) > 0 { 174 part := parts[0] 175 for i := skipBytes; i < part.n; i++ { 176 if n == len(p) { 177 return 178 } 179 p[n] = part.b 180 n++ 181 } 182 parts = parts[1:] 183 skipBytes = 0 184 } 185 } 186 if n != len(p) { 187 err = io.ErrUnexpectedEOF 188 } 189 return 190 } 191 192 // Just testing the rleBuffer used in the Zip64 test above. Not used by the zip code. 193 func TestRLEBuffer(t *testing.T) { 194 b := new(rleBuffer) 195 var all []byte 196 writes := []string{"abcdeee", "eeeeeee", "eeeefghaaiii"} 197 for _, w := range writes { 198 b.Write([]byte(w)) 199 all = append(all, w...) 200 } 201 if len(b.buf) != 10 { 202 t.Fatalf("len(b.buf) = %d; want 10", len(b.buf)) 203 } 204 205 for i := 0; i < len(all); i++ { 206 for j := 0; j < len(all)-i; j++ { 207 buf := make([]byte, j) 208 n, err := b.ReadAt(buf, int64(i)) 209 if err != nil || n != len(buf) { 210 t.Errorf("ReadAt(%d, %d) = %d, %v; want %d, nil", i, j, n, err, len(buf)) 211 } 212 if !bytes.Equal(buf, all[i:i+j]) { 213 t.Errorf("ReadAt(%d, %d) = %q; want %q", i, j, buf, all[i:i+j]) 214 } 215 } 216 } 217 } 218 219 // fakeHash32 is a dummy Hash32 that always returns 0. 220 type fakeHash32 struct { 221 hash.Hash32 222 } 223 224 func (fakeHash32) Write(p []byte) (int, error) { return len(p), nil } 225 func (fakeHash32) Sum32() uint32 { return 0 } 226 227 func TestZip64(t *testing.T) { 228 if testing.Short() { 229 t.Skip("slow test; skipping") 230 } 231 const size = 1 << 32 // before the "END\n" part 232 buf := testZip64(t, size) 233 testZip64DirectoryRecordLength(buf, t) 234 } 235 236 func TestZip64EdgeCase(t *testing.T) { 237 if testing.Short() { 238 t.Skip("slow test; skipping") 239 } 240 // Test a zip file with uncompressed size 0xFFFFFFFF. 241 // That's the magic marker for a 64-bit file, so even though 242 // it fits in a 32-bit field we must use the 64-bit field. 243 // Go 1.5 and earlier got this wrong, 244 // writing an invalid zip file. 245 const size = 1<<32 - 1 - int64(len("END\n")) // before the "END\n" part 246 buf := testZip64(t, size) 247 testZip64DirectoryRecordLength(buf, t) 248 } 249 250 func testZip64(t testing.TB, size int64) *rleBuffer { 251 const chunkSize = 1024 252 chunks := int(size / chunkSize) 253 // write size bytes plus "END\n" to a zip file 254 buf := new(rleBuffer) 255 w := NewWriter(buf) 256 f, err := w.CreateHeader(&FileHeader{ 257 Name: "huge.txt", 258 Method: Store, 259 }) 260 if err != nil { 261 t.Fatal(err) 262 } 263 f.(*fileWriter).crc32 = fakeHash32{} 264 chunk := make([]byte, chunkSize) 265 for i := range chunk { 266 chunk[i] = '.' 267 } 268 for i := 0; i < chunks; i++ { 269 _, err := f.Write(chunk) 270 if err != nil { 271 t.Fatal("write chunk:", err) 272 } 273 } 274 if frag := int(size % chunkSize); frag > 0 { 275 _, err := f.Write(chunk[:frag]) 276 if err != nil { 277 t.Fatal("write chunk:", err) 278 } 279 } 280 end := []byte("END\n") 281 _, err = f.Write(end) 282 if err != nil { 283 t.Fatal("write end:", err) 284 } 285 if err := w.Close(); err != nil { 286 t.Fatal(err) 287 } 288 289 // read back zip file and check that we get to the end of it 290 r, err := NewReader(buf, int64(buf.Size())) 291 if err != nil { 292 t.Fatal("reader:", err) 293 } 294 f0 := r.File[0] 295 rc, err := f0.Open() 296 if err != nil { 297 t.Fatal("opening:", err) 298 } 299 rc.(*checksumReader).hash = fakeHash32{} 300 for i := 0; i < chunks; i++ { 301 _, err := io.ReadFull(rc, chunk) 302 if err != nil { 303 t.Fatal("read:", err) 304 } 305 } 306 if frag := int(size % chunkSize); frag > 0 { 307 _, err := io.ReadFull(rc, chunk[:frag]) 308 if err != nil { 309 t.Fatal("read:", err) 310 } 311 } 312 gotEnd, err := ioutil.ReadAll(rc) 313 if err != nil { 314 t.Fatal("read end:", err) 315 } 316 if !bytes.Equal(gotEnd, end) { 317 t.Errorf("End of zip64 archive %q, want %q", gotEnd, end) 318 } 319 err = rc.Close() 320 if err != nil { 321 t.Fatal("closing:", err) 322 } 323 if size+int64(len("END\n")) >= 1<<32-1 { 324 if got, want := f0.UncompressedSize, uint32(uint32max); got != want { 325 t.Errorf("UncompressedSize %#x, want %#x", got, want) 326 } 327 } 328 329 if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want { 330 t.Errorf("UncompressedSize64 %#x, want %#x", got, want) 331 } 332 333 return buf 334 } 335 336 // Issue 9857 337 func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) { 338 d := make([]byte, 1024) 339 if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil { 340 t.Fatal("read:", err) 341 } 342 343 sigOff := findSignatureInBlock(d) 344 dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff)) 345 if err != nil { 346 t.Fatal("findDirectory64End:", err) 347 } 348 349 d = make([]byte, directory64EndLen) 350 if _, err := buf.ReadAt(d, dirOff); err != nil { 351 t.Fatal("read:", err) 352 } 353 354 b := readBuf(d) 355 if sig := b.uint32(); sig != directory64EndSignature { 356 t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig) 357 } 358 359 size := b.uint64() 360 if size != directory64EndLen-12 { 361 t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size) 362 } 363 } 364 365 func testInvalidHeader(h *FileHeader, t *testing.T) { 366 var buf bytes.Buffer 367 z := NewWriter(&buf) 368 369 f, err := z.CreateHeader(h) 370 if err != nil { 371 t.Fatalf("error creating header: %v", err) 372 } 373 if _, err := f.Write([]byte("hi")); err != nil { 374 t.Fatalf("error writing content: %v", err) 375 } 376 if err := z.Close(); err != nil { 377 t.Fatalf("error closing zip writer: %v", err) 378 } 379 380 b := buf.Bytes() 381 if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != ErrFormat { 382 t.Fatalf("got %v, expected ErrFormat", err) 383 } 384 } 385 386 func testValidHeader(h *FileHeader, t *testing.T) { 387 var buf bytes.Buffer 388 z := NewWriter(&buf) 389 390 f, err := z.CreateHeader(h) 391 if err != nil { 392 t.Fatalf("error creating header: %v", err) 393 } 394 if _, err := f.Write([]byte("hi")); err != nil { 395 t.Fatalf("error writing content: %v", err) 396 } 397 if err := z.Close(); err != nil { 398 t.Fatalf("error closing zip writer: %v", err) 399 } 400 401 b := buf.Bytes() 402 zf, err := NewReader(bytes.NewReader(b), int64(len(b))) 403 if err != nil { 404 t.Fatalf("got %v, expected nil", err) 405 } 406 zh := zf.File[0].FileHeader 407 if zh.Name != h.Name || zh.Method != h.Method || zh.UncompressedSize64 != uint64(len("hi")) { 408 t.Fatalf("got %q/%d/%d expected %q/%d/%d", zh.Name, zh.Method, zh.UncompressedSize64, h.Name, h.Method, len("hi")) 409 } 410 } 411 412 // Issue 4302. 413 func TestHeaderInvalidTagAndSize(t *testing.T) { 414 const timeFormat = "20060102T150405.000.txt" 415 416 ts := time.Now() 417 filename := ts.Format(timeFormat) 418 419 h := FileHeader{ 420 Name: filename, 421 Method: Deflate, 422 Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len, but Extra is best-effort parsing 423 } 424 h.SetModTime(ts) 425 426 testValidHeader(&h, t) 427 } 428 429 func TestHeaderTooShort(t *testing.T) { 430 h := FileHeader{ 431 Name: "foo.txt", 432 Method: Deflate, 433 Extra: []byte{zip64ExtraId}, // missing size and second half of tag, but Extra is best-effort parsing 434 } 435 testValidHeader(&h, t) 436 } 437 438 func TestHeaderIgnoredSize(t *testing.T) { 439 h := FileHeader{ 440 Name: "foo.txt", 441 Method: Deflate, 442 Extra: []byte{zip64ExtraId & 0xFF, zip64ExtraId >> 8, 24, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, // bad size but shouldn't be consulted 443 } 444 testValidHeader(&h, t) 445 } 446 447 // Issue 4393. It is valid to have an extra data header 448 // which contains no body. 449 func TestZeroLengthHeader(t *testing.T) { 450 h := FileHeader{ 451 Name: "extadata.txt", 452 Method: Deflate, 453 Extra: []byte{ 454 85, 84, 5, 0, 3, 154, 144, 195, 77, // tag 21589 size 5 455 85, 120, 0, 0, // tag 30805 size 0 456 }, 457 } 458 testValidHeader(&h, t) 459 } 460 461 // Just benchmarking how fast the Zip64 test above is. Not related to 462 // our zip performance, since the test above disabled CRC32 and flate. 463 func BenchmarkZip64Test(b *testing.B) { 464 for i := 0; i < b.N; i++ { 465 testZip64(b, 1<<26) 466 } 467 }