Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(230)

Delta Between Two Patch Sets: src/pkg/compress/gzip/gzip.go

Issue 13435043: code review 13435043: compress/gzip: add Writer.Reset (Closed)
Left Patch Set: Created 10 years, 7 months ago
Right Patch Set: diff -r bf9de8d2e308 https://go.googlecode.com/hg/ Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | src/pkg/compress/gzip/gzip_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2010 The Go Authors. All rights reserved. 1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package gzip 5 package gzip
6 6
7 import ( 7 import (
8 "compress/flate" 8 "compress/flate"
9 "errors" 9 "errors"
10 "fmt" 10 "fmt"
11 "hash" 11 "hash"
12 "hash/crc32" 12 "hash/crc32"
13 "io" 13 "io"
14 ) 14 )
15 15
16 // These constants are copied from the flate package, so that code that imports 16 // These constants are copied from the flate package, so that code that imports
17 // "compress/gzip" does not also have to import "compress/flate". 17 // "compress/gzip" does not also have to import "compress/flate".
18 const ( 18 const (
19 NoCompression = flate.NoCompression 19 NoCompression = flate.NoCompression
20 BestSpeed = flate.BestSpeed 20 BestSpeed = flate.BestSpeed
21 BestCompression = flate.BestCompression 21 BestCompression = flate.BestCompression
22 DefaultCompression = flate.DefaultCompression 22 DefaultCompression = flate.DefaultCompression
23 ) 23 )
24 24
25 // A Writer is an io.WriteCloser that satisfies writes by compressing data writt en 25 // A Writer is an io.WriteCloser that satisfies writes by compressing data writt en
26 // to its wrapped io.Writer. 26 // to its wrapped io.Writer.
27 type Writer struct { 27 type Writer struct {
28 Header 28 Header
29 » w io.Writer 29 » w io.Writer
30 » level int 30 » level int
31 » compressor *flate.Writer 31 » wroteHeader bool
32 » digest hash.Hash32 32 » compressor *flate.Writer
33 » size uint32 33 » digest hash.Hash32
34 » closed bool 34 » size uint32
35 » buf [10]byte 35 » closed bool
36 » err error 36 » buf [10]byte
37 » err error
37 } 38 }
38 39
39 // NewWriter creates a new Writer that satisfies writes by compressing data 40 // NewWriter creates a new Writer that satisfies writes by compressing data
40 // written to w. 41 // written to w.
41 // 42 //
42 // It is the caller's responsibility to call Close on the WriteCloser when done. 43 // It is the caller's responsibility to call Close on the WriteCloser when done.
43 // Writes may be buffered and not flushed until Close. 44 // Writes may be buffered and not flushed until Close.
44 // 45 //
45 // Callers that wish to set the fields in Writer.Header must do so before 46 // Callers that wish to set the fields in Writer.Header must do so before
46 // the first call to Write or Close. The Comment and Name header fields are 47 // the first call to Write or Close. The Comment and Name header fields are
47 // UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO 48 // UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO
48 // 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an 49 // 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an
49 // error on Write. 50 // error on Write.
50 func NewWriter(w io.Writer) *Writer { 51 func NewWriter(w io.Writer) *Writer {
51 z, _ := NewWriterLevel(w, DefaultCompression) 52 z, _ := NewWriterLevel(w, DefaultCompression)
52 return z 53 return z
53 } 54 }
54 55
55 // NewWriterLevel is like NewWriter but specifies the compression level instead 56 // NewWriterLevel is like NewWriter but specifies the compression level instead
56 // of assuming DefaultCompression. 57 // of assuming DefaultCompression.
57 // 58 //
58 // The compression level can be DefaultCompression, NoCompression, or any 59 // The compression level can be DefaultCompression, NoCompression, or any
59 // integer value between BestSpeed and BestCompression inclusive. The error 60 // integer value between BestSpeed and BestCompression inclusive. The error
60 // returned will be nil if the level is valid. 61 // returned will be nil if the level is valid.
61 func NewWriterLevel(w io.Writer, level int) (*Writer, error) { 62 func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
62 if level < DefaultCompression || level > BestCompression { 63 if level < DefaultCompression || level > BestCompression {
63 return nil, fmt.Errorf("gzip: invalid compression level: %d", le vel) 64 return nil, fmt.Errorf("gzip: invalid compression level: %d", le vel)
64 } 65 }
65 » return &Writer{ 66 » z := new(Writer)
67 » z.init(w, level)
68 » return z, nil
69 }
70
71 func (z *Writer) init(w io.Writer, level int) {
72 » digest := z.digest
73 » if digest != nil {
74 » » digest.Reset()
75 » } else {
76 » » digest = crc32.NewIEEE()
77 » }
78 » compressor := z.compressor
79 » if compressor != nil {
80 » » compressor.Reset(w)
81 » }
82 » *z = Writer{
66 Header: Header{ 83 Header: Header{
67 OS: 255, // unknown 84 OS: 255, // unknown
68 }, 85 },
69 » » w: w, 86 » » w: w,
70 » » level: level, 87 » » level: level,
71 » » digest: crc32.NewIEEE(), 88 » » digest: digest,
72 » }, nil 89 » » compressor: compressor,
90 » }
91 }
92
93 // Reset discards the Writer z's state and makes it equivalent to the
94 // result of its original state from NewWriter or NewWriterLevel, but
95 // writing to w instead. This permits reusing a Writer rather than
96 // allocating a new one.
97 func (z *Writer) Reset(w io.Writer) {
98 » z.init(w, z.level)
73 } 99 }
74 100
75 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). 101 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
76 func put2(p []byte, v uint16) { 102 func put2(p []byte, v uint16) {
77 p[0] = uint8(v >> 0) 103 p[0] = uint8(v >> 0)
78 p[1] = uint8(v >> 8) 104 p[1] = uint8(v >> 8)
79 } 105 }
80 106
81 func put4(p []byte, v uint32) { 107 func put4(p []byte, v uint32) {
82 p[0] = uint8(v >> 0) 108 p[0] = uint8(v >> 0)
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 } 157 }
132 158
133 // Write writes a compressed form of p to the underlying io.Writer. The 159 // Write writes a compressed form of p to the underlying io.Writer. The
134 // compressed bytes are not necessarily flushed until the Writer is closed. 160 // compressed bytes are not necessarily flushed until the Writer is closed.
135 func (z *Writer) Write(p []byte) (int, error) { 161 func (z *Writer) Write(p []byte) (int, error) {
136 if z.err != nil { 162 if z.err != nil {
137 return 0, z.err 163 return 0, z.err
138 } 164 }
139 var n int 165 var n int
140 // Write the GZIP header lazily. 166 // Write the GZIP header lazily.
141 » if z.compressor == nil { 167 » if !z.wroteHeader {
168 » » z.wroteHeader = true
142 z.buf[0] = gzipID1 169 z.buf[0] = gzipID1
143 z.buf[1] = gzipID2 170 z.buf[1] = gzipID2
144 z.buf[2] = gzipDeflate 171 z.buf[2] = gzipDeflate
145 z.buf[3] = 0 172 z.buf[3] = 0
146 if z.Extra != nil { 173 if z.Extra != nil {
147 z.buf[3] |= 0x04 174 z.buf[3] |= 0x04
148 } 175 }
149 if z.Name != "" { 176 if z.Name != "" {
150 z.buf[3] |= 0x08 177 z.buf[3] |= 0x08
151 } 178 }
(...skipping 24 matching lines...) Expand all
176 if z.err != nil { 203 if z.err != nil {
177 return n, z.err 204 return n, z.err
178 } 205 }
179 } 206 }
180 if z.Comment != "" { 207 if z.Comment != "" {
181 z.err = z.writeString(z.Comment) 208 z.err = z.writeString(z.Comment)
182 if z.err != nil { 209 if z.err != nil {
183 return n, z.err 210 return n, z.err
184 } 211 }
185 } 212 }
186 » » z.compressor, _ = flate.NewWriter(z.w, z.level) 213 » » if z.compressor == nil {
214 » » » z.compressor, _ = flate.NewWriter(z.w, z.level)
215 » » }
187 } 216 }
188 z.size += uint32(len(p)) 217 z.size += uint32(len(p))
189 z.digest.Write(p) 218 z.digest.Write(p)
190 n, z.err = z.compressor.Write(p) 219 n, z.err = z.compressor.Write(p)
191 return n, z.err 220 return n, z.err
192 } 221 }
193 222
194 // Flush flushes any pending compressed data to the underlying writer. 223 // Flush flushes any pending compressed data to the underlying writer.
195 // 224 //
196 // It is useful mainly in compressed network protocols, to ensure that 225 // It is useful mainly in compressed network protocols, to ensure that
197 // a remote reader has enough data to reconstruct a packet. Flush does 226 // a remote reader has enough data to reconstruct a packet. Flush does
198 // not return until the data has been written. If the underlying 227 // not return until the data has been written. If the underlying
199 // writer returns an error, Flush returns that error. 228 // writer returns an error, Flush returns that error.
200 // 229 //
201 // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. 230 // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
202 func (z *Writer) Flush() error { 231 func (z *Writer) Flush() error {
203 if z.err != nil { 232 if z.err != nil {
204 return z.err 233 return z.err
205 } 234 }
206 if z.closed { 235 if z.closed {
207 return nil 236 return nil
208 } 237 }
209 » if z.compressor == nil { 238 » if !z.wroteHeader {
210 z.Write(nil) 239 z.Write(nil)
240 if z.err != nil {
241 return z.err
242 }
211 } 243 }
212 z.err = z.compressor.Flush() 244 z.err = z.compressor.Flush()
213 return z.err 245 return z.err
214 } 246 }
215 247
216 // Close closes the Writer. It does not close the underlying io.Writer. 248 // Close closes the Writer. It does not close the underlying io.Writer.
217 func (z *Writer) Close() error { 249 func (z *Writer) Close() error {
218 if z.err != nil { 250 if z.err != nil {
219 return z.err 251 return z.err
220 } 252 }
221 if z.closed { 253 if z.closed {
222 return nil 254 return nil
223 } 255 }
224 z.closed = true 256 z.closed = true
225 » if z.compressor == nil { 257 » if !z.wroteHeader {
226 z.Write(nil) 258 z.Write(nil)
227 if z.err != nil { 259 if z.err != nil {
228 return z.err 260 return z.err
229 } 261 }
230 } 262 }
231 z.err = z.compressor.Close() 263 z.err = z.compressor.Close()
232 if z.err != nil { 264 if z.err != nil {
233 return z.err 265 return z.err
234 } 266 }
235 put4(z.buf[0:4], z.digest.Sum32()) 267 put4(z.buf[0:4], z.digest.Sum32())
236 put4(z.buf[4:8], z.size) 268 put4(z.buf[4:8], z.size)
237 _, z.err = z.w.Write(z.buf[0:8]) 269 _, z.err = z.w.Write(z.buf[0:8])
238 return z.err 270 return z.err
239 } 271 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b