2011-07-10 11:30:16 +10:00
|
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
|
|
package zip
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"bytes"
|
archive/zip: add FileHeader.Modified field
The ModifiedTime and ModifiedDate fields are not expressive enough
for many of the time extensions that have since been added to ZIP,
nor are they easy to access since they in a legacy MS-DOS format,
and must be set and retrieved via the SetModTime and ModTime methods.
Instead, we add new field Modified of time.Time type that contains
all of the previous information and more.
Support for extended timestamps have been attempted before, but the
change was reverted because it provided no ability for the user to
specify the timezone of the legacy MS-DOS fields.
Technically the old API did not either, but users were manually offsetting
the timestamp to achieve the same effect.
The Writer now writes the legacy timestamps according to the timezone
of the FileHeader.Modified field. When the Modified field is set via
the SetModTime method, it is in UTC, which preserves the old behavior.
The Reader attempts to determine the timezone if both the legacy
and extended timestamps are present since it can compute the delta
between the two values.
Since Modified is a superset of the information in ModifiedTime and ModifiedDate,
we mark ModifiedTime, ModifiedDate, ModTime, and SetModTime as deprecated.
Fixes #18359
Change-Id: I29c6bc0a62908095d02740df3e6902f50d3152f1
Reviewed-on: https://go-review.googlesource.com/74970
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-28 12:07:58 -07:00
|
|
|
|
"fmt"
|
2014-08-31 21:32:13 -07:00
|
|
|
|
"io"
|
2011-07-10 11:30:16 +10:00
|
|
|
|
"io/ioutil"
|
2011-11-08 15:40:58 -08:00
|
|
|
|
"math/rand"
|
2011-12-12 15:22:55 -05:00
|
|
|
|
"os"
|
2017-08-26 18:44:27 +09:00
|
|
|
|
"strings"
|
2011-07-10 11:30:16 +10:00
|
|
|
|
"testing"
|
archive/zip: add FileHeader.Modified field
The ModifiedTime and ModifiedDate fields are not expressive enough
for many of the time extensions that have since been added to ZIP,
nor are they easy to access since they in a legacy MS-DOS format,
and must be set and retrieved via the SetModTime and ModTime methods.
Instead, we add new field Modified of time.Time type that contains
all of the previous information and more.
Support for extended timestamps have been attempted before, but the
change was reverted because it provided no ability for the user to
specify the timezone of the legacy MS-DOS fields.
Technically the old API did not either, but users were manually offsetting
the timestamp to achieve the same effect.
The Writer now writes the legacy timestamps according to the timezone
of the FileHeader.Modified field. When the Modified field is set via
the SetModTime method, it is in UTC, which preserves the old behavior.
The Reader attempts to determine the timezone if both the legacy
and extended timestamps are present since it can compute the delta
between the two values.
Since Modified is a superset of the information in ModifiedTime and ModifiedDate,
we mark ModifiedTime, ModifiedDate, ModTime, and SetModTime as deprecated.
Fixes #18359
Change-Id: I29c6bc0a62908095d02740df3e6902f50d3152f1
Reviewed-on: https://go-review.googlesource.com/74970
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-28 12:07:58 -07:00
|
|
|
|
"time"
|
2011-07-10 11:30:16 +10:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(adg): a more sophisticated test suite
|
|
|
|
|
|
|
2011-09-25 20:48:03 -03:00
|
|
|
|
type WriteTest struct {
|
|
|
|
|
|
Name string
|
|
|
|
|
|
Data []byte
|
|
|
|
|
|
Method uint16
|
2011-12-12 15:22:55 -05:00
|
|
|
|
Mode os.FileMode
|
2011-09-25 20:48:03 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var writeTests = []WriteTest{
|
2011-12-01 14:33:24 -08:00
|
|
|
|
{
|
2011-09-25 20:48:03 -03:00
|
|
|
|
Name: "foo",
|
|
|
|
|
|
Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
|
|
|
|
|
|
Method: Store,
|
2011-12-12 15:22:55 -05:00
|
|
|
|
Mode: 0666,
|
2011-09-25 20:48:03 -03:00
|
|
|
|
},
|
2011-12-01 14:33:24 -08:00
|
|
|
|
{
|
2011-09-25 20:48:03 -03:00
|
|
|
|
Name: "bar",
|
|
|
|
|
|
Data: nil, // large data set in the test
|
|
|
|
|
|
Method: Deflate,
|
2011-12-12 15:22:55 -05:00
|
|
|
|
Mode: 0644,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
Name: "setuid",
|
|
|
|
|
|
Data: []byte("setuid file"),
|
|
|
|
|
|
Method: Deflate,
|
|
|
|
|
|
Mode: 0755 | os.ModeSetuid,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
Name: "setgid",
|
|
|
|
|
|
Data: []byte("setgid file"),
|
|
|
|
|
|
Method: Deflate,
|
|
|
|
|
|
Mode: 0755 | os.ModeSetgid,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2012-02-06 11:58:32 -02:00
|
|
|
|
Name: "symlink",
|
|
|
|
|
|
Data: []byte("../link/target"),
|
2011-12-12 15:22:55 -05:00
|
|
|
|
Method: Deflate,
|
2012-02-06 11:58:32 -02:00
|
|
|
|
Mode: 0755 | os.ModeSymlink,
|
2011-09-25 20:48:03 -03:00
|
|
|
|
},
|
|
|
|
|
|
}
|
2011-07-10 11:30:16 +10:00
|
|
|
|
|
|
|
|
|
|
func TestWriter(t *testing.T) {
|
|
|
|
|
|
largeData := make([]byte, 1<<17)
|
2017-07-03 15:38:55 -07:00
|
|
|
|
if _, err := rand.Read(largeData); err != nil {
|
|
|
|
|
|
t.Fatal("rand.Read failed:", err)
|
2011-07-10 11:30:16 +10:00
|
|
|
|
}
|
2011-09-25 20:48:03 -03:00
|
|
|
|
writeTests[1].Data = largeData
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
writeTests[1].Data = nil
|
|
|
|
|
|
}()
|
2011-07-10 11:30:16 +10:00
|
|
|
|
|
|
|
|
|
|
// write a zip file
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
w := NewWriter(buf)
|
2011-09-25 20:48:03 -03:00
|
|
|
|
|
|
|
|
|
|
for _, wt := range writeTests {
|
|
|
|
|
|
testCreate(t, w, &wt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-07-10 11:30:16 +10:00
|
|
|
|
if err := w.Close(); err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read it back
|
2012-02-15 12:58:00 +11:00
|
|
|
|
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
2011-07-10 11:30:16 +10:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
2011-09-25 20:48:03 -03:00
|
|
|
|
for i, wt := range writeTests {
|
|
|
|
|
|
testReadFile(t, r.File[i], &wt)
|
|
|
|
|
|
}
|
2011-07-10 11:30:16 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-26 18:44:27 +09:00
|
|
|
|
// TestWriterComment is test for EOCD comment read/write.
|
|
|
|
|
|
func TestWriterComment(t *testing.T) {
|
|
|
|
|
|
var tests = []struct {
|
|
|
|
|
|
comment string
|
|
|
|
|
|
ok bool
|
|
|
|
|
|
}{
|
|
|
|
|
|
{"hi, hello", true},
|
|
|
|
|
|
{"hi, こんにちわ", true},
|
|
|
|
|
|
{strings.Repeat("a", uint16max), true},
|
|
|
|
|
|
{strings.Repeat("a", uint16max+1), false},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
|
// write a zip file
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
w := NewWriter(buf)
|
2017-11-22 11:10:47 -05:00
|
|
|
|
if err := w.SetComment(test.comment); err != nil {
|
|
|
|
|
|
if test.ok {
|
|
|
|
|
|
t.Fatalf("SetComment: unexpected error %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
continue
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if !test.ok {
|
|
|
|
|
|
t.Fatalf("SetComment: unexpected success, want error")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-08-26 18:44:27 +09:00
|
|
|
|
|
|
|
|
|
|
if err := w.Close(); test.ok == (err != nil) {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if w.closed != test.ok {
|
|
|
|
|
|
t.Fatalf("Writer.closed: got %v, want %v", w.closed, test.ok)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// skip read test in failure cases
|
|
|
|
|
|
if !test.ok {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read it back
|
|
|
|
|
|
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if r.Comment != test.comment {
|
|
|
|
|
|
t.Fatalf("Reader.Comment: got %v, want %v", r.Comment, test.comment)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-05 17:32:09 +09:00
|
|
|
|
func TestWriterUTF8(t *testing.T) {
|
|
|
|
|
|
var utf8Tests = []struct {
|
|
|
|
|
|
name string
|
|
|
|
|
|
comment string
|
archive/zip: add FileHeader.NonUTF8 field
The NonUTF8 field provides users with a way to explictly tell the
ZIP writer to avoid setting the UTF-8 flag.
This is necessary because many readers:
1) (Still) do not support UTF-8
2) And use the local system encoding instead
Thus, even though character encodings other than CP-437 and UTF-8
are not officially supported by the ZIP specification, pragmatically
the world has permitted use of them.
When a non-standard encoding is used, it is the user's responsibility
to ensure that the target system is expecting the encoding used
(e.g., producing a ZIP file you know is used on a Chinese version of Windows).
We adjust the detectUTF8 function to account for Shift-JIS and EUC-KR
not being identical to ASCII for two characters.
We don't need an API for users to explicitly specify that they are encoding
with UTF-8 since all single byte characters are compatible with all other
common encodings (Windows-1256, Windows-1252, Windows-1251, Windows-1250,
IEC-8859, EUC-KR, KOI8-R, Latin-1, Shift-JIS, GB-2312, GBK) except for
the non-printable characters and the backslash character (all of which
are invalid characters in a path name anyways).
Fixes #10741
Change-Id: I9004542d1d522c9137973f1b6e2b623fa54dfd66
Reviewed-on: https://go-review.googlesource.com/75592
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-02 13:53:16 -07:00
|
|
|
|
nonUTF8 bool
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags uint16
|
2017-04-05 17:32:09 +09:00
|
|
|
|
}{
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "hi, hello",
|
|
|
|
|
|
comment: "in the world",
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x8,
|
2017-04-05 17:32:09 +09:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "hi, こんにちわ",
|
|
|
|
|
|
comment: "in the world",
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x808,
|
2017-04-05 17:32:09 +09:00
|
|
|
|
},
|
archive/zip: add FileHeader.NonUTF8 field
The NonUTF8 field provides users with a way to explictly tell the
ZIP writer to avoid setting the UTF-8 flag.
This is necessary because many readers:
1) (Still) do not support UTF-8
2) And use the local system encoding instead
Thus, even though character encodings other than CP-437 and UTF-8
are not officially supported by the ZIP specification, pragmatically
the world has permitted use of them.
When a non-standard encoding is used, it is the user's responsibility
to ensure that the target system is expecting the encoding used
(e.g., producing a ZIP file you know is used on a Chinese version of Windows).
We adjust the detectUTF8 function to account for Shift-JIS and EUC-KR
not being identical to ASCII for two characters.
We don't need an API for users to explicitly specify that they are encoding
with UTF-8 since all single byte characters are compatible with all other
common encodings (Windows-1256, Windows-1252, Windows-1251, Windows-1250,
IEC-8859, EUC-KR, KOI8-R, Latin-1, Shift-JIS, GB-2312, GBK) except for
the non-printable characters and the backslash character (all of which
are invalid characters in a path name anyways).
Fixes #10741
Change-Id: I9004542d1d522c9137973f1b6e2b623fa54dfd66
Reviewed-on: https://go-review.googlesource.com/75592
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-02 13:53:16 -07:00
|
|
|
|
{
|
|
|
|
|
|
name: "hi, こんにちわ",
|
|
|
|
|
|
comment: "in the world",
|
|
|
|
|
|
nonUTF8: true,
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x8,
|
archive/zip: add FileHeader.NonUTF8 field
The NonUTF8 field provides users with a way to explictly tell the
ZIP writer to avoid setting the UTF-8 flag.
This is necessary because many readers:
1) (Still) do not support UTF-8
2) And use the local system encoding instead
Thus, even though character encodings other than CP-437 and UTF-8
are not officially supported by the ZIP specification, pragmatically
the world has permitted use of them.
When a non-standard encoding is used, it is the user's responsibility
to ensure that the target system is expecting the encoding used
(e.g., producing a ZIP file you know is used on a Chinese version of Windows).
We adjust the detectUTF8 function to account for Shift-JIS and EUC-KR
not being identical to ASCII for two characters.
We don't need an API for users to explicitly specify that they are encoding
with UTF-8 since all single byte characters are compatible with all other
common encodings (Windows-1256, Windows-1252, Windows-1251, Windows-1250,
IEC-8859, EUC-KR, KOI8-R, Latin-1, Shift-JIS, GB-2312, GBK) except for
the non-printable characters and the backslash character (all of which
are invalid characters in a path name anyways).
Fixes #10741
Change-Id: I9004542d1d522c9137973f1b6e2b623fa54dfd66
Reviewed-on: https://go-review.googlesource.com/75592
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-02 13:53:16 -07:00
|
|
|
|
},
|
2017-04-05 17:32:09 +09:00
|
|
|
|
{
|
|
|
|
|
|
name: "hi, hello",
|
|
|
|
|
|
comment: "in the 世界",
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x808,
|
2017-04-05 17:32:09 +09:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "hi, こんにちわ",
|
|
|
|
|
|
comment: "in the 世界",
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x808,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "the replacement rune is <20>",
|
|
|
|
|
|
comment: "the replacement rune is <20>",
|
|
|
|
|
|
flags: 0x808,
|
2017-04-05 17:32:09 +09:00
|
|
|
|
},
|
2017-10-23 13:47:15 -07:00
|
|
|
|
{
|
|
|
|
|
|
// Name is Japanese encoded in Shift JIS.
|
|
|
|
|
|
name: "\x93\xfa\x96{\x8c\xea.txt",
|
|
|
|
|
|
comment: "in the 世界",
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags: 0x008, // UTF-8 must not be set
|
2017-10-23 13:47:15 -07:00
|
|
|
|
},
|
2017-04-05 17:32:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// write a zip file
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
w := NewWriter(buf)
|
|
|
|
|
|
|
|
|
|
|
|
for _, test := range utf8Tests {
|
|
|
|
|
|
h := &FileHeader{
|
|
|
|
|
|
Name: test.name,
|
|
|
|
|
|
Comment: test.comment,
|
archive/zip: add FileHeader.NonUTF8 field
The NonUTF8 field provides users with a way to explictly tell the
ZIP writer to avoid setting the UTF-8 flag.
This is necessary because many readers:
1) (Still) do not support UTF-8
2) And use the local system encoding instead
Thus, even though character encodings other than CP-437 and UTF-8
are not officially supported by the ZIP specification, pragmatically
the world has permitted use of them.
When a non-standard encoding is used, it is the user's responsibility
to ensure that the target system is expecting the encoding used
(e.g., producing a ZIP file you know is used on a Chinese version of Windows).
We adjust the detectUTF8 function to account for Shift-JIS and EUC-KR
not being identical to ASCII for two characters.
We don't need an API for users to explicitly specify that they are encoding
with UTF-8 since all single byte characters are compatible with all other
common encodings (Windows-1256, Windows-1252, Windows-1251, Windows-1250,
IEC-8859, EUC-KR, KOI8-R, Latin-1, Shift-JIS, GB-2312, GBK) except for
the non-printable characters and the backslash character (all of which
are invalid characters in a path name anyways).
Fixes #10741
Change-Id: I9004542d1d522c9137973f1b6e2b623fa54dfd66
Reviewed-on: https://go-review.googlesource.com/75592
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-02 13:53:16 -07:00
|
|
|
|
NonUTF8: test.nonUTF8,
|
2017-04-05 17:32:09 +09:00
|
|
|
|
Method: Deflate,
|
|
|
|
|
|
}
|
|
|
|
|
|
w, err := w.CreateHeader(h)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
w.Write([]byte{})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := w.Close(); err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read it back
|
|
|
|
|
|
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
for i, test := range utf8Tests {
|
2017-11-15 11:47:31 -05:00
|
|
|
|
flags := r.File[i].Flags
|
|
|
|
|
|
if flags != test.flags {
|
|
|
|
|
|
t.Errorf("CreateHeader(name=%q comment=%q nonUTF8=%v): flags=%#x, want %#x", test.name, test.comment, test.nonUTF8, flags, test.flags)
|
2017-04-05 17:32:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
archive/zip: add FileHeader.Modified field
The ModifiedTime and ModifiedDate fields are not expressive enough
for many of the time extensions that have since been added to ZIP,
nor are they easy to access since they in a legacy MS-DOS format,
and must be set and retrieved via the SetModTime and ModTime methods.
Instead, we add new field Modified of time.Time type that contains
all of the previous information and more.
Support for extended timestamps have been attempted before, but the
change was reverted because it provided no ability for the user to
specify the timezone of the legacy MS-DOS fields.
Technically the old API did not either, but users were manually offsetting
the timestamp to achieve the same effect.
The Writer now writes the legacy timestamps according to the timezone
of the FileHeader.Modified field. When the Modified field is set via
the SetModTime method, it is in UTC, which preserves the old behavior.
The Reader attempts to determine the timezone if both the legacy
and extended timestamps are present since it can compute the delta
between the two values.
Since Modified is a superset of the information in ModifiedTime and ModifiedDate,
we mark ModifiedTime, ModifiedDate, ModTime, and SetModTime as deprecated.
Fixes #18359
Change-Id: I29c6bc0a62908095d02740df3e6902f50d3152f1
Reviewed-on: https://go-review.googlesource.com/74970
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-28 12:07:58 -07:00
|
|
|
|
func TestWriterTime(t *testing.T) {
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
h := &FileHeader{
|
|
|
|
|
|
Name: "test.txt",
|
|
|
|
|
|
Modified: time.Date(2017, 10, 31, 21, 11, 57, 0, timeZone(-7*time.Hour)),
|
|
|
|
|
|
}
|
|
|
|
|
|
w := NewWriter(&buf)
|
|
|
|
|
|
if _, err := w.CreateHeader(h); err != nil {
|
|
|
|
|
|
t.Fatalf("unexpected CreateHeader error: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := w.Close(); err != nil {
|
|
|
|
|
|
t.Fatalf("unexpected Close error: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
want, err := ioutil.ReadFile("testdata/time-go.zip")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("unexpected ReadFile error: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if got := buf.Bytes(); !bytes.Equal(got, want) {
|
|
|
|
|
|
fmt.Printf("%x\n%x\n", got, want)
|
|
|
|
|
|
t.Error("contents of time-go.zip differ")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-03-12 11:54:11 +11:00
|
|
|
|
func TestWriterOffset(t *testing.T) {
|
2015-01-19 14:39:33 +01:00
|
|
|
|
largeData := make([]byte, 1<<17)
|
2017-07-03 15:38:55 -07:00
|
|
|
|
if _, err := rand.Read(largeData); err != nil {
|
|
|
|
|
|
t.Fatal("rand.Read failed:", err)
|
2015-01-19 14:39:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
writeTests[1].Data = largeData
|
|
|
|
|
|
defer func() {
|
|
|
|
|
|
writeTests[1].Data = nil
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
// write a zip file
|
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
|
|
|
|
|
|
n, _ := buf.Write(existingData)
|
2015-03-12 11:54:11 +11:00
|
|
|
|
w := NewWriter(buf)
|
|
|
|
|
|
w.SetOffset(int64(n))
|
2015-01-19 14:39:33 +01:00
|
|
|
|
|
|
|
|
|
|
for _, wt := range writeTests {
|
|
|
|
|
|
testCreate(t, w, &wt)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := w.Close(); err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read it back
|
|
|
|
|
|
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
for i, wt := range writeTests {
|
|
|
|
|
|
testReadFile(t, r.File[i], &wt)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-08-31 21:32:13 -07:00
|
|
|
|
func TestWriterFlush(t *testing.T) {
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
w := NewWriter(struct{ io.Writer }{&buf})
|
|
|
|
|
|
_, err := w.Create("foo")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if buf.Len() > 0 {
|
|
|
|
|
|
t.Fatalf("Unexpected %d bytes already in buffer", buf.Len())
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := w.Flush(); err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if buf.Len() == 0 {
|
|
|
|
|
|
t.Fatal("No bytes written after Flush")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-25 20:48:03 -03:00
|
|
|
|
func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
|
2011-07-10 11:30:16 +10:00
|
|
|
|
header := &FileHeader{
|
2011-09-25 20:48:03 -03:00
|
|
|
|
Name: wt.Name,
|
|
|
|
|
|
Method: wt.Method,
|
|
|
|
|
|
}
|
|
|
|
|
|
if wt.Mode != 0 {
|
|
|
|
|
|
header.SetMode(wt.Mode)
|
2011-07-10 11:30:16 +10:00
|
|
|
|
}
|
|
|
|
|
|
f, err := w.CreateHeader(header)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
2011-09-25 20:48:03 -03:00
|
|
|
|
_, err = f.Write(wt.Data)
|
2011-07-10 11:30:16 +10:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-09-25 20:48:03 -03:00
|
|
|
|
func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
|
|
|
|
|
if f.Name != wt.Name {
|
2011-09-27 09:33:26 -07:00
|
|
|
|
t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
|
2011-09-25 20:48:03 -03:00
|
|
|
|
}
|
2017-11-29 11:40:52 -05:00
|
|
|
|
testFileMode(t, f, wt.Mode)
|
2011-07-10 11:30:16 +10:00
|
|
|
|
rc, err := f.Open()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal("opening:", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
b, err := ioutil.ReadAll(rc)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal("reading:", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
err = rc.Close()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatal("closing:", err)
|
|
|
|
|
|
}
|
2011-09-25 20:48:03 -03:00
|
|
|
|
if !bytes.Equal(b, wt.Data) {
|
|
|
|
|
|
t.Errorf("File contents %q, want %q", b, wt.Data)
|
2011-07-10 11:30:16 +10:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-02-09 13:56:47 -08:00
|
|
|
|
|
|
|
|
|
|
func BenchmarkCompressedZipGarbage(b *testing.B) {
|
|
|
|
|
|
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
|
2017-02-10 12:46:14 -05:00
|
|
|
|
|
|
|
|
|
|
runOnce := func(buf *bytes.Buffer) {
|
2014-02-09 13:56:47 -08:00
|
|
|
|
buf.Reset()
|
2017-02-10 12:46:14 -05:00
|
|
|
|
zw := NewWriter(buf)
|
2014-02-09 13:56:47 -08:00
|
|
|
|
for j := 0; j < 3; j++ {
|
|
|
|
|
|
w, _ := zw.CreateHeader(&FileHeader{
|
|
|
|
|
|
Name: "foo",
|
|
|
|
|
|
Method: Deflate,
|
|
|
|
|
|
})
|
|
|
|
|
|
w.Write(bigBuf)
|
|
|
|
|
|
}
|
|
|
|
|
|
zw.Close()
|
|
|
|
|
|
}
|
2017-02-10 12:46:14 -05:00
|
|
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
|
|
// Run once and then reset the timer.
|
|
|
|
|
|
// This effectively discards the very large initial flate setup cost,
|
|
|
|
|
|
// as well as the initialization of bigBuf.
|
|
|
|
|
|
runOnce(&bytes.Buffer{})
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
|
|
|
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
for pb.Next() {
|
|
|
|
|
|
runOnce(&buf)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2014-02-09 13:56:47 -08:00
|
|
|
|
}
|