summaryrefslogtreecommitdiff
path: root/libgo/go/archive/zip
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-09-14 17:11:35 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2017-09-14 17:11:35 +0000
commite104cab8d4ab9422a0ca55bb24c00c9fea9a5d4d (patch)
tree8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/archive/zip
parent4a85c0b16ef3722655012f596b7e3e7e272eeb56 (diff)
downloadgcc-e104cab8d4ab9422a0ca55bb24c00c9fea9a5d4d.tar.gz
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@252767 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/archive/zip')
-rw-r--r--libgo/go/archive/zip/register.go47
-rw-r--r--libgo/go/archive/zip/struct.go2
-rw-r--r--libgo/go/archive/zip/writer.go21
-rw-r--r--libgo/go/archive/zip/writer_test.go90
-rw-r--r--libgo/go/archive/zip/zip_test.go14
5 files changed, 134 insertions, 40 deletions
diff --git a/libgo/go/archive/zip/register.go b/libgo/go/archive/zip/register.go
index 2e76386b1fd..51e9c3e4d4b 100644
--- a/libgo/go/archive/zip/register.go
+++ b/libgo/go/archive/zip/register.go
@@ -103,51 +103,46 @@ func (r *pooledFlateReader) Close() error {
}
var (
- mu sync.RWMutex // guards compressor and decompressor maps
+ compressors sync.Map // map[uint16]Compressor
+ decompressors sync.Map // map[uint16]Decompressor
+)
- compressors = map[uint16]Compressor{
- Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
- Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
- }
+func init() {
+ compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
+ compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
- decompressors = map[uint16]Decompressor{
- Store: ioutil.NopCloser,
- Deflate: newFlateReader,
- }
-)
+ decompressors.Store(Store, Decompressor(ioutil.NopCloser))
+ decompressors.Store(Deflate, Decompressor(newFlateReader))
+}
// RegisterDecompressor allows custom decompressors for a specified method ID.
// The common methods Store and Deflate are built in.
func RegisterDecompressor(method uint16, dcomp Decompressor) {
- mu.Lock()
- defer mu.Unlock()
-
- if _, ok := decompressors[method]; ok {
+ if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
panic("decompressor already registered")
}
- decompressors[method] = dcomp
}
// RegisterCompressor registers custom compressors for a specified method ID.
// The common methods Store and Deflate are built in.
func RegisterCompressor(method uint16, comp Compressor) {
- mu.Lock()
- defer mu.Unlock()
-
- if _, ok := compressors[method]; ok {
+ if _, dup := compressors.LoadOrStore(method, comp); dup {
panic("compressor already registered")
}
- compressors[method] = comp
}
func compressor(method uint16) Compressor {
- mu.RLock()
- defer mu.RUnlock()
- return compressors[method]
+ ci, ok := compressors.Load(method)
+ if !ok {
+ return nil
+ }
+ return ci.(Compressor)
}
func decompressor(method uint16) Decompressor {
- mu.RLock()
- defer mu.RUnlock()
- return decompressors[method]
+ di, ok := decompressors.Load(method)
+ if !ok {
+ return nil
+ }
+ return di.(Decompressor)
}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index e92d02f8a2e..0be210e8e73 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -5,7 +5,7 @@
/*
Package zip provides support for reading and writing ZIP archives.
-See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
+See: https://www.pkware.com/appnote
This package does not support disk spanning.
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index 8940e25560e..9f4fceee844 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -11,10 +11,9 @@ import (
"hash"
"hash/crc32"
"io"
+ "unicode/utf8"
)
-// TODO(adg): support zip file comments
-
// Writer implements a zip file writer.
type Writer struct {
cw *countWriter
@@ -201,6 +200,20 @@ func (w *Writer) Create(name string) (io.Writer, error) {
return w.CreateHeader(header)
}
+func hasValidUTF8(s string) bool {
+ n := 0
+ for _, r := range s {
+ // By default, ZIP uses CP437, which is only identical to ASCII for the printable characters.
+ if r < 0x20 || r >= 0x7f {
+ if !utf8.ValidRune(r) {
+ return false
+ }
+ n++
+ }
+ }
+ return n > 0
+}
+
// CreateHeader adds a file to the zip file using the provided FileHeader
// for the file metadata.
// It returns a Writer to which the file contents should be written.
@@ -221,6 +234,10 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
fh.Flags |= 0x8 // we will write a data descriptor
+ if hasValidUTF8(fh.Name) || hasValidUTF8(fh.Comment) {
+ fh.Flags |= 0x800 // filename or comment have valid utf-8 string
+ }
+
fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
fh.ReaderVersion = zipVersion20
diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go
index 86841c755f1..92fb6ecf0ed 100644
--- a/libgo/go/archive/zip/writer_test.go
+++ b/libgo/go/archive/zip/writer_test.go
@@ -87,6 +87,69 @@ func TestWriter(t *testing.T) {
}
}
+func TestWriterUTF8(t *testing.T) {
+ var utf8Tests = []struct {
+ name string
+ comment string
+ expect uint16
+ }{
+ {
+ name: "hi, hello",
+ comment: "in the world",
+ expect: 0x8,
+ },
+ {
+ name: "hi, こんにちわ",
+ comment: "in the world",
+ expect: 0x808,
+ },
+ {
+ name: "hi, hello",
+ comment: "in the 世界",
+ expect: 0x808,
+ },
+ {
+ name: "hi, こんにちわ",
+ comment: "in the 世界",
+ expect: 0x808,
+ },
+ }
+
+ // write a zip file
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+
+ for _, test := range utf8Tests {
+ h := &FileHeader{
+ Name: test.name,
+ Comment: test.comment,
+ 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 {
+ got := r.File[i].Flags
+ t.Logf("name %v, comment %v", test.name, test.comment)
+ if got != test.expect {
+ t.Fatalf("Flags: got %v, want %v", got, test.expect)
+ }
+ }
+}
+
func TestWriterOffset(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
@@ -181,12 +244,11 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
}
func BenchmarkCompressedZipGarbage(b *testing.B) {
- b.ReportAllocs()
- var buf bytes.Buffer
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
- for i := 0; i <= b.N; i++ {
+
+ runOnce := func(buf *bytes.Buffer) {
buf.Reset()
- zw := NewWriter(&buf)
+ zw := NewWriter(buf)
for j := 0; j < 3; j++ {
w, _ := zw.CreateHeader(&FileHeader{
Name: "foo",
@@ -195,11 +257,19 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
w.Write(bigBuf)
}
zw.Close()
- if i == 0 {
- // Reset the timer after the first time through.
- // This effectively discards the very large initial flate setup cost,
- // as well as the initialization of bigBuf.
- b.ResetTimer()
- }
}
+
+ 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)
+ }
+ })
}
diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go
index 57edb2cabf4..18c2171ba6c 100644
--- a/libgo/go/archive/zip/zip_test.go
+++ b/libgo/go/archive/zip/zip_test.go
@@ -255,7 +255,7 @@ func TestZip64EdgeCase(t *testing.T) {
testZip64DirectoryRecordLength(buf, t)
}
-// Tests that we generate a zip64 file if the the directory at offset
+// Tests that we generate a zip64 file if the directory at offset
// 0xFFFFFFFF, but not before.
func TestZip64DirectoryOffset(t *testing.T) {
if testing.Short() && race.Enabled {
@@ -681,6 +681,18 @@ func BenchmarkZip64Test(b *testing.B) {
}
}
+func BenchmarkZip64TestSizes(b *testing.B) {
+ for _, size := range []int64{1 << 12, 1 << 20, 1 << 26} {
+ b.Run(fmt.Sprint(size), func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ testZip64(b, size)
+ }
+ })
+ })
+ }
+}
+
func TestSuffixSaver(t *testing.T) {
const keep = 10
ss := &suffixSaver{keep: keep}