OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 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 implements reading and writing of gzip format compressed files, | 5 // Package gzip implements reading and writing of gzip format compressed files, |
6 // as specified in RFC 1952. | 6 // as specified in RFC 1952. |
7 package gzip | 7 package gzip |
8 | 8 |
9 import ( | 9 import ( |
10 "bufio" | 10 "bufio" |
11 "compress/flate" | 11 "compress/flate" |
12 "errors" | 12 "errors" |
13 "hash" | 13 "hash" |
14 "hash/crc32" | 14 "hash/crc32" |
15 "io" | 15 "io" |
16 "time" | 16 "time" |
17 ) | 17 ) |
18 | 18 |
19 // BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes ou
tside of | |
20 // the 0x00-0x7f range to ISO 8859-1 (Latin-1). | |
21 | |
22 const ( | 19 const ( |
23 gzipID1 = 0x1f | 20 gzipID1 = 0x1f |
24 gzipID2 = 0x8b | 21 gzipID2 = 0x8b |
25 gzipDeflate = 8 | 22 gzipDeflate = 8 |
26 flagText = 1 << 0 | 23 flagText = 1 << 0 |
27 flagHdrCrc = 1 << 1 | 24 flagHdrCrc = 1 << 1 |
28 flagExtra = 1 << 2 | 25 flagExtra = 1 << 2 |
29 flagName = 1 << 3 | 26 flagName = 1 << 3 |
30 flagComment = 1 << 4 | 27 flagComment = 1 << 4 |
31 ) | 28 ) |
32 | 29 |
33 func makeReader(r io.Reader) flate.Reader { | 30 func makeReader(r io.Reader) flate.Reader { |
34 if rr, ok := r.(flate.Reader); ok { | 31 if rr, ok := r.(flate.Reader); ok { |
35 return rr | 32 return rr |
36 } | 33 } |
37 return bufio.NewReader(r) | 34 return bufio.NewReader(r) |
38 } | 35 } |
39 | 36 |
40 var ErrHeader = errors.New("invalid gzip header") | 37 var ErrHeader = errors.New("invalid gzip header") |
41 var ErrChecksum = errors.New("gzip checksum error") | 38 var ErrChecksum = errors.New("gzip checksum error") |
42 | 39 |
43 // The gzip file stores a header giving metadata about the compressed file. | 40 // The gzip file stores a header giving metadata about the compressed file. |
44 // That header is exposed as the fields of the Compressor and Decompressor struc
ts. | 41 // That header is exposed as the fields of the Writer and Reader structs. |
45 type Header struct { | 42 type Header struct { |
46 Comment string // comment | 43 Comment string // comment |
47 Extra []byte // "extra data" | 44 Extra []byte // "extra data" |
48 ModTime time.Time // modification time | 45 ModTime time.Time // modification time |
49 Name string // file name | 46 Name string // file name |
50 OS byte // operating system type | 47 OS byte // operating system type |
51 } | 48 } |
52 | 49 |
53 // An Decompressor is an io.Reader that can be read to retrieve | 50 // A Reader is an io.Reader that can be read to retrieve |
54 // uncompressed data from a gzip-format compressed file. | 51 // uncompressed data from a gzip-format compressed file. |
55 // | 52 // |
56 // In general, a gzip file can be a concatenation of gzip files, | 53 // In general, a gzip file can be a concatenation of gzip files, |
57 // each with its own header. Reads from the Decompressor | 54 // each with its own header. Reads from the Reader |
58 // return the concatenation of the uncompressed data of each. | 55 // return the concatenation of the uncompressed data of each. |
59 // Only the first header is recorded in the Decompressor fields. | 56 // Only the first header is recorded in the Reader fields. |
60 // | 57 // |
61 // Gzip files store a length and checksum of the uncompressed data. | 58 // Gzip files store a length and checksum of the uncompressed data. |
62 // The Decompressor will return a ErrChecksum when Read | 59 // The Reader will return a ErrChecksum when Read |
63 // reaches the end of the uncompressed data if it does not | 60 // reaches the end of the uncompressed data if it does not |
64 // have the expected length or checksum. Clients should treat data | 61 // have the expected length or checksum. Clients should treat data |
65 // returned by Read as tentative until they receive the successful | 62 // returned by Read as tentative until they receive the io.EOF |
66 // (zero length, nil error) Read marking the end of the data. | 63 // marking the end of the data. |
67 type Decompressor struct { | 64 type Reader struct { |
68 Header | 65 Header |
69 r flate.Reader | 66 r flate.Reader |
70 decompressor io.ReadCloser | 67 decompressor io.ReadCloser |
71 digest hash.Hash32 | 68 digest hash.Hash32 |
72 size uint32 | 69 size uint32 |
73 flg byte | 70 flg byte |
74 buf [512]byte | 71 buf [512]byte |
75 err error | 72 err error |
76 } | 73 } |
77 | 74 |
78 // NewReader creates a new Decompressor reading the given reader. | 75 // NewReader creates a new Reader reading the given reader. |
79 // The implementation buffers input and may read more data than necessary from r
. | 76 // The implementation buffers input and may read more data than necessary from r
. |
80 // It is the caller's responsibility to call Close on the Decompressor when done
. | 77 // It is the caller's responsibility to call Close on the Reader when done. |
81 func NewReader(r io.Reader) (*Decompressor, error) { | 78 func NewReader(r io.Reader) (*Reader, error) { |
82 » z := new(Decompressor) | 79 » z := new(Reader) |
83 z.r = makeReader(r) | 80 z.r = makeReader(r) |
84 z.digest = crc32.NewIEEE() | 81 z.digest = crc32.NewIEEE() |
85 if err := z.readHeader(true); err != nil { | 82 if err := z.readHeader(true); err != nil { |
86 return nil, err | 83 return nil, err |
87 } | 84 } |
88 return z, nil | 85 return z, nil |
89 } | 86 } |
90 | 87 |
91 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). | 88 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). |
92 func get4(p []byte) uint32 { | 89 func get4(p []byte) uint32 { |
93 return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<
<24 | 90 return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<
<24 |
94 } | 91 } |
95 | 92 |
96 func (z *Decompressor) readString() (string, error) { | 93 func (z *Reader) readString() (string, error) { |
97 var err error | 94 var err error |
98 needconv := false | 95 needconv := false |
99 for i := 0; ; i++ { | 96 for i := 0; ; i++ { |
100 if i >= len(z.buf) { | 97 if i >= len(z.buf) { |
101 return "", ErrHeader | 98 return "", ErrHeader |
102 } | 99 } |
103 z.buf[i], err = z.r.ReadByte() | 100 z.buf[i], err = z.r.ReadByte() |
104 if err != nil { | 101 if err != nil { |
105 return "", err | 102 return "", err |
106 } | 103 } |
107 if z.buf[i] > 0x7f { | 104 if z.buf[i] > 0x7f { |
108 needconv = true | 105 needconv = true |
109 } | 106 } |
110 if z.buf[i] == 0 { | 107 if z.buf[i] == 0 { |
111 // GZIP (RFC 1952) specifies that strings are NUL-termin
ated ISO 8859-1 (Latin-1). | 108 // GZIP (RFC 1952) specifies that strings are NUL-termin
ated ISO 8859-1 (Latin-1). |
112 if needconv { | 109 if needconv { |
113 s := make([]rune, 0, i) | 110 s := make([]rune, 0, i) |
114 for _, v := range z.buf[0:i] { | 111 for _, v := range z.buf[0:i] { |
115 s = append(s, rune(v)) | 112 s = append(s, rune(v)) |
116 } | 113 } |
117 return string(s), nil | 114 return string(s), nil |
118 } | 115 } |
119 return string(z.buf[0:i]), nil | 116 return string(z.buf[0:i]), nil |
120 } | 117 } |
121 } | 118 } |
122 panic("not reached") | 119 panic("not reached") |
123 } | 120 } |
124 | 121 |
125 func (z *Decompressor) read2() (uint32, error) { | 122 func (z *Reader) read2() (uint32, error) { |
126 _, err := io.ReadFull(z.r, z.buf[0:2]) | 123 _, err := io.ReadFull(z.r, z.buf[0:2]) |
127 if err != nil { | 124 if err != nil { |
128 return 0, err | 125 return 0, err |
129 } | 126 } |
130 return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil | 127 return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil |
131 } | 128 } |
132 | 129 |
133 func (z *Decompressor) readHeader(save bool) error { | 130 func (z *Reader) readHeader(save bool) error { |
134 _, err := io.ReadFull(z.r, z.buf[0:10]) | 131 _, err := io.ReadFull(z.r, z.buf[0:10]) |
135 if err != nil { | 132 if err != nil { |
136 return err | 133 return err |
137 } | 134 } |
138 if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate
{ | 135 if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate
{ |
139 return ErrHeader | 136 return ErrHeader |
140 } | 137 } |
141 z.flg = z.buf[3] | 138 z.flg = z.buf[3] |
142 if save { | 139 if save { |
143 z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0) | 140 z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0) |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 if n != sum { | 186 if n != sum { |
190 return ErrHeader | 187 return ErrHeader |
191 } | 188 } |
192 } | 189 } |
193 | 190 |
194 z.digest.Reset() | 191 z.digest.Reset() |
195 z.decompressor = flate.NewReader(z.r) | 192 z.decompressor = flate.NewReader(z.r) |
196 return nil | 193 return nil |
197 } | 194 } |
198 | 195 |
199 func (z *Decompressor) Read(p []byte) (n int, err error) { | 196 func (z *Reader) Read(p []byte) (n int, err error) { |
200 if z.err != nil { | 197 if z.err != nil { |
201 return 0, z.err | 198 return 0, z.err |
202 } | 199 } |
203 if len(p) == 0 { | 200 if len(p) == 0 { |
204 return 0, nil | 201 return 0, nil |
205 } | 202 } |
206 | 203 |
207 n, err = z.decompressor.Read(p) | 204 n, err = z.decompressor.Read(p) |
208 z.digest.Write(p[0:n]) | 205 z.digest.Write(p[0:n]) |
209 z.size += uint32(n) | 206 z.size += uint32(n) |
(...skipping 19 matching lines...) Expand all Loading... |
229 z.err = err | 226 z.err = err |
230 return | 227 return |
231 } | 228 } |
232 | 229 |
233 // Yes. Reset and read from it. | 230 // Yes. Reset and read from it. |
234 z.digest.Reset() | 231 z.digest.Reset() |
235 z.size = 0 | 232 z.size = 0 |
236 return z.Read(p) | 233 return z.Read(p) |
237 } | 234 } |
238 | 235 |
239 // Calling Close does not close the wrapped io.Reader originally passed to NewRe
ader. | 236 // Close closes the Reader. It does not close the underlying io.Reader. |
240 func (z *Decompressor) Close() error { return z.decompressor.Close() } | 237 func (z *Reader) Close() error { return z.decompressor.Close() } |
OLD | NEW |