LEFT | RIGHT |
(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 Loading... |
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 Loading... |
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 } |
LEFT | RIGHT |