1
0
mirror of https://github.com/golang/go synced 2024-11-24 21:10:04 -07:00

compress/gzip: add Writer.Reset

compress/flate is https://golang.org/cl/12953048
compress/zlib is https://golang.org/cl/13171046

Update #6138

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/13435043
This commit is contained in:
Brad Fitzpatrick 2013-08-30 11:41:12 -07:00
parent 41c5d8d85f
commit db12f9d4e4
2 changed files with 64 additions and 17 deletions

View File

@ -26,14 +26,15 @@ const (
// to its wrapped io.Writer. // to its wrapped io.Writer.
type Writer struct { type Writer struct {
Header Header
w io.Writer w io.Writer
level int level int
compressor *flate.Writer wroteHeader bool
digest hash.Hash32 compressor *flate.Writer
size uint32 digest hash.Hash32
closed bool size uint32
buf [10]byte closed bool
err error buf [10]byte
err error
} }
// NewWriter creates a new Writer that satisfies writes by compressing data // NewWriter creates a new Writer that satisfies writes by compressing data
@ -62,14 +63,39 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
if level < DefaultCompression || level > BestCompression { if level < DefaultCompression || level > BestCompression {
return nil, fmt.Errorf("gzip: invalid compression level: %d", level) return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
} }
return &Writer{ z := new(Writer)
z.init(w, level)
return z, nil
}
func (z *Writer) init(w io.Writer, level int) {
digest := z.digest
if digest != nil {
digest.Reset()
} else {
digest = crc32.NewIEEE()
}
compressor := z.compressor
if compressor != nil {
compressor.Reset(w)
}
*z = Writer{
Header: Header{ Header: Header{
OS: 255, // unknown OS: 255, // unknown
}, },
w: w, w: w,
level: level, level: level,
digest: crc32.NewIEEE(), digest: digest,
}, nil compressor: compressor,
}
}
// Reset discards the Writer z's state and makes it equivalent to the
// result of its original state from NewWriter or NewWriterLevel, but
// writing to w instead. This permits reusing a Writer rather than
// allocating a new one.
func (z *Writer) Reset(w io.Writer) {
z.init(w, z.level)
} }
// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
@ -138,7 +164,8 @@ func (z *Writer) Write(p []byte) (int, error) {
} }
var n int var n int
// Write the GZIP header lazily. // Write the GZIP header lazily.
if z.compressor == nil { if !z.wroteHeader {
z.wroteHeader = true
z.buf[0] = gzipID1 z.buf[0] = gzipID1
z.buf[1] = gzipID2 z.buf[1] = gzipID2
z.buf[2] = gzipDeflate z.buf[2] = gzipDeflate
@ -183,7 +210,9 @@ func (z *Writer) Write(p []byte) (int, error) {
return n, z.err return n, z.err
} }
} }
z.compressor, _ = flate.NewWriter(z.w, z.level) if z.compressor == nil {
z.compressor, _ = flate.NewWriter(z.w, z.level)
}
} }
z.size += uint32(len(p)) z.size += uint32(len(p))
z.digest.Write(p) z.digest.Write(p)
@ -206,8 +235,11 @@ func (z *Writer) Flush() error {
if z.closed { if z.closed {
return nil return nil
} }
if z.compressor == nil { if !z.wroteHeader {
z.Write(nil) z.Write(nil)
if z.err != nil {
return z.err
}
} }
z.err = z.compressor.Flush() z.err = z.compressor.Flush()
return z.err return z.err
@ -222,7 +254,7 @@ func (z *Writer) Close() error {
return nil return nil
} }
z.closed = true z.closed = true
if z.compressor == nil { if !z.wroteHeader {
z.Write(nil) z.Write(nil)
if z.err != nil { if z.err != nil {
return z.err return z.err

View File

@ -214,3 +214,18 @@ func TestConcat(t *testing.T) {
t.Fatalf("ReadAll = %q, %v, want %q, nil", data, err, "hello world") t.Fatalf("ReadAll = %q, %v, want %q, nil", data, err, "hello world")
} }
} }
func TestWriterReset(t *testing.T) {
buf := new(bytes.Buffer)
buf2 := new(bytes.Buffer)
z := NewWriter(buf)
msg := []byte("hello world")
z.Write(msg)
z.Close()
z.Reset(buf2)
z.Write(msg)
z.Close()
if buf.String() != buf2.String() {
t.Errorf("buf2 %q != original buf of %q", buf2.String(), buf.String())
}
}