diff options
Diffstat (limited to 'libgo/go/compress/gzip')
-rw-r--r-- | libgo/go/compress/gzip/example_test.go | 130 | ||||
-rw-r--r-- | libgo/go/compress/gzip/gunzip.go | 7 | ||||
-rw-r--r-- | libgo/go/compress/gzip/gunzip_test.go | 20 | ||||
-rw-r--r-- | libgo/go/compress/gzip/gzip.go | 23 | ||||
-rw-r--r-- | libgo/go/compress/gzip/gzip_test.go | 4 | ||||
-rw-r--r-- | libgo/go/compress/gzip/issue14937_test.go | 9 |
6 files changed, 178 insertions, 15 deletions
diff --git a/libgo/go/compress/gzip/example_test.go b/libgo/go/compress/gzip/example_test.go new file mode 100644 index 00000000000..4764bcb090a --- /dev/null +++ b/libgo/go/compress/gzip/example_test.go @@ -0,0 +1,130 @@ +// Copyright 2016 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. + +// +build ignore + +package gzip_test + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "log" + "os" + "time" +) + +func Example_writerReader() { + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + + // Setting the Header fields is optional. + zw.Name = "a-new-hope.txt" + zw.Comment = "an epic space opera by George Lucas" + zw.ModTime = time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC) + + _, err := zw.Write([]byte("A long time ago in a galaxy far, far away...")) + if err != nil { + log.Fatal(err) + } + + if err := zw.Close(); err != nil { + log.Fatal(err) + } + + zr, err := gzip.NewReader(&buf) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC()) + + if _, err := io.Copy(os.Stdout, zr); err != nil { + log.Fatal(err) + } + + if err := zr.Close(); err != nil { + log.Fatal(err) + } + + // Output: + // Name: a-new-hope.txt + // Comment: an epic space opera by George Lucas + // ModTime: 1977-05-25 00:00:00 +0000 UTC + // + // A long time ago in a galaxy far, far away... +} + +func ExampleReader_Multistream() { + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + + var files = []struct { + name string + comment string + modTime time.Time + data string + }{ + {"file-1.txt", "file-header-1", time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC), "Hello Gophers - 1"}, + {"file-2.txt", "file-header-2", time.Date(2007, time.March, 2, 4, 5, 6, 1, time.UTC), "Hello Gophers - 2"}, + } + + for _, file := range files { + zw.Name = file.name + zw.Comment = file.comment + zw.ModTime = file.modTime + + if _, err := zw.Write([]byte(file.data)); err != nil { + log.Fatal(err) + } + + if err := zw.Close(); err != nil { + log.Fatal(err) + } + + zw.Reset(&buf) + } + + zr, err := gzip.NewReader(&buf) + if err != nil { + log.Fatal(err) + } + + for { + zr.Multistream(false) + fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC()) + + if _, err := io.Copy(os.Stdout, zr); err != nil { + log.Fatal(err) + } + + fmt.Print("\n\n") + + err = zr.Reset(&buf) + if err == io.EOF { + break + } + if err != nil { + log.Fatal(err) + } + } + + if err := zr.Close(); err != nil { + log.Fatal(err) + } + + // Output: + // Name: file-1.txt + // Comment: file-header-1 + // ModTime: 2006-02-01 03:04:05 +0000 UTC + // + // Hello Gophers - 1 + // + // Name: file-2.txt + // Comment: file-header-2 + // ModTime: 2007-03-02 04:05:06 +0000 UTC + // + // Hello Gophers - 2 +} diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go index 7e640692f3f..8bd750bd8b3 100644 --- a/libgo/go/compress/gzip/gunzip.go +++ b/libgo/go/compress/gzip/gunzip.go @@ -186,7 +186,11 @@ func (z *Reader) readHeader() (hdr Header, err error) { return hdr, ErrHeader } flg := z.buf[3] - hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0) + if t := int64(le.Uint32(z.buf[4:8])); t > 0 { + // Section 2.3.1, the zero value for MTIME means that the + // modified time is not set. + hdr.ModTime = time.Unix(t, 0) + } // z.buf[8] is XFL and is currently ignored. hdr.OS = z.buf[9] z.digest = crc32.ChecksumIEEE(z.buf[:10]) @@ -238,6 +242,7 @@ func (z *Reader) readHeader() (hdr Header, err error) { return hdr, nil } +// Read implements io.Reader, reading uncompressed bytes from its underlying Reader. func (z *Reader) Read(p []byte) (n int, err error) { if z.err != nil { return 0, z.err diff --git a/libgo/go/compress/gzip/gunzip_test.go b/libgo/go/compress/gzip/gunzip_test.go index fdce91989a6..fdea0c5d5ff 100644 --- a/libgo/go/compress/gzip/gunzip_test.go +++ b/libgo/go/compress/gzip/gunzip_test.go @@ -339,6 +339,26 @@ var gunzipTests = []gunzipTest{ }, nil, }, + { + "", + "truncated gzip file amid raw-block", + "hello", + []byte{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x0c, 0x00, 0xf3, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f, + }, + io.ErrUnexpectedEOF, + }, + { + "", + "truncated gzip file amid fixed-block", + "He", + []byte{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xf2, 0x48, 0xcd, + }, + io.ErrUnexpectedEOF, + }, } func TestDecompressor(t *testing.T) { diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go index c702c493c11..aafb442a667 100644 --- a/libgo/go/compress/gzip/gzip.go +++ b/libgo/go/compress/gzip/gzip.go @@ -10,6 +10,7 @@ import ( "fmt" "hash/crc32" "io" + "time" ) // These constants are copied from the flate package, so that code that imports @@ -19,6 +20,7 @@ const ( BestSpeed = flate.BestSpeed BestCompression = flate.BestCompression DefaultCompression = flate.DefaultCompression + HuffmanOnly = flate.HuffmanOnly ) // A Writer is an io.WriteCloser. @@ -52,11 +54,11 @@ func NewWriter(w io.Writer) *Writer { // NewWriterLevel is like NewWriter but specifies the compression level instead // of assuming DefaultCompression. // -// The compression level can be DefaultCompression, NoCompression, or any -// integer value between BestSpeed and BestCompression inclusive. The error -// returned will be nil if the level is valid. +// The compression level can be DefaultCompression, NoCompression, HuffmanOnly +// or any integer value between BestSpeed and BestCompression inclusive. +// The error returned will be nil if the level is valid. func NewWriterLevel(w io.Writer, level int) (*Writer, error) { - if level < DefaultCompression || level > BestCompression { + if level < HuffmanOnly || level > BestCompression { return nil, fmt.Errorf("gzip: invalid compression level: %d", level) } z := new(Writer) @@ -142,10 +144,7 @@ func (z *Writer) Write(p []byte) (int, error) { // Write the GZIP header lazily. if !z.wroteHeader { z.wroteHeader = true - z.buf[0] = gzipID1 - z.buf[1] = gzipID2 - z.buf[2] = gzipDeflate - z.buf[3] = 0 + z.buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate} if z.Extra != nil { z.buf[3] |= 0x04 } @@ -155,13 +154,15 @@ func (z *Writer) Write(p []byte) (int, error) { if z.Comment != "" { z.buf[3] |= 0x10 } - le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix())) + if z.ModTime.After(time.Unix(0, 0)) { + // Section 2.3.1, the zero value for MTIME means that the + // modified time is not set. + le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix())) + } if z.level == BestCompression { z.buf[8] = 2 } else if z.level == BestSpeed { z.buf[8] = 4 - } else { - z.buf[8] = 0 } z.buf[9] = z.OS n, z.err = z.w.Write(z.buf[:10]) diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go index 09271b24e92..865c529f55c 100644 --- a/libgo/go/compress/gzip/gzip_test.go +++ b/libgo/go/compress/gzip/gzip_test.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "io/ioutil" + "reflect" "testing" "time" ) @@ -24,6 +25,9 @@ func TestEmpty(t *testing.T) { if err != nil { t.Fatalf("NewReader: %v", err) } + if want := (Header{OS: 255}); !reflect.DeepEqual(r.Header, want) { + t.Errorf("Header mismatch:\ngot %#v\nwant %#v", r.Header, want) + } b, err := ioutil.ReadAll(r) if err != nil { t.Fatalf("ReadAll: %v", err) diff --git a/libgo/go/compress/gzip/issue14937_test.go b/libgo/go/compress/gzip/issue14937_test.go index 432ad16b1c2..e76d47cc4ee 100644 --- a/libgo/go/compress/gzip/issue14937_test.go +++ b/libgo/go/compress/gzip/issue14937_test.go @@ -7,7 +7,6 @@ import ( "runtime" "strings" "testing" - "time" ) // Per golang.org/issue/14937, check that every .gz file @@ -16,8 +15,12 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) { if testing.Short() && testenv.Builder() == "" { t.Skip("skipping in short mode") } + goroot, err := filepath.EvalSymlinks(runtime.GOROOT()) + if err != nil { + t.Fatal("error evaluating GOROOT: ", err) + } var files []string - err := filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -53,7 +56,7 @@ func checkZeroMTime(t *testing.T, path string) { return } defer gz.Close() - if !gz.ModTime.Equal(time.Unix(0, 0)) { + if !gz.ModTime.IsZero() { t.Errorf("gzip file %s has non-zero mtime (%s)", path, gz.ModTime) } } |