LEFT | RIGHT |
(no file at all) | |
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 /* | 5 /* |
6 Package zlib implements reading and writing of zlib format compressed data, | 6 Package zlib implements reading and writing of zlib format compressed data, |
7 as specified in RFC 1950. | 7 as specified in RFC 1950. |
8 | 8 |
9 The implementation provides filters that uncompress during reading | 9 The implementation provides filters that uncompress during reading |
10 and compress during writing. For example, to write compressed data | 10 and compress during writing. For example, to write compressed data |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 ) | 44 ) |
45 | 45 |
46 type reader struct { | 46 type reader struct { |
47 r flate.Reader | 47 r flate.Reader |
48 decompressor io.ReadCloser | 48 decompressor io.ReadCloser |
49 digest hash.Hash32 | 49 digest hash.Hash32 |
50 err error | 50 err error |
51 scratch [4]byte | 51 scratch [4]byte |
52 } | 52 } |
53 | 53 |
54 // NewReader creates a new io.ReadCloser. | 54 // Resetter resets a ReadCloser returned by NewReader or NewReaderDict to |
55 // Reads from the returned io.ReadCloser read and decompress data from r. | 55 // to switch to a new underlying Reader. This permits reusing a ReadCloser |
| 56 // instead of allocating a new one. |
| 57 type Resetter interface { |
| 58 » // Reset discards any buffered data and resets the Resetter as if it was |
| 59 » // newly initialized with the given reader. |
| 60 » Reset(r io.Reader, dict []byte) error |
| 61 } |
| 62 |
| 63 // NewReader creates a new ReadCloser. |
| 64 // Reads from the returned ReadCloser read and decompress data from r. |
56 // The implementation buffers input and may read more data than necessary from r
. | 65 // The implementation buffers input and may read more data than necessary from r
. |
57 // It is the caller's responsibility to call Close on the ReadCloser when done. | 66 // It is the caller's responsibility to call Close on the ReadCloser when done. |
| 67 // |
| 68 // The ReadCloser returned by NewReader also implements Resetter. |
58 func NewReader(r io.Reader) (io.ReadCloser, error) { | 69 func NewReader(r io.Reader) (io.ReadCloser, error) { |
59 return NewReaderDict(r, nil) | 70 return NewReaderDict(r, nil) |
60 } | 71 } |
61 | 72 |
62 // NewReaderDict is like NewReader but uses a preset dictionary. | 73 // NewReaderDict is like NewReader but uses a preset dictionary. |
63 // NewReaderDict ignores the dictionary if the compressed data does not refer to
it. | 74 // NewReaderDict ignores the dictionary if the compressed data does not refer to
it. |
64 // If the compressed data refers to a different dictionary, NewReaderDict return
s ErrDictionary. | 75 // If the compressed data refers to a different dictionary, NewReaderDict return
s ErrDictionary. |
| 76 // |
| 77 // The ReadCloser returned by NewReaderDict also implements Resetter. |
65 func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) { | 78 func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) { |
66 z := new(reader) | 79 z := new(reader) |
67 » if fr, ok := r.(flate.Reader); ok { | 80 » err := z.Reset(r, dict) |
68 » » z.r = fr | |
69 » } else { | |
70 » » z.r = bufio.NewReader(r) | |
71 » } | |
72 » _, err := io.ReadFull(z.r, z.scratch[0:2]) | |
73 if err != nil { | 81 if err != nil { |
74 return nil, err | 82 return nil, err |
75 } | 83 } |
76 h := uint(z.scratch[0])<<8 | uint(z.scratch[1]) | |
77 if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) { | |
78 return nil, ErrHeader | |
79 } | |
80 if z.scratch[1]&0x20 != 0 { | |
81 _, err = io.ReadFull(z.r, z.scratch[0:4]) | |
82 if err != nil { | |
83 return nil, err | |
84 } | |
85 checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16
| uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) | |
86 if checksum != adler32.Checksum(dict) { | |
87 return nil, ErrDictionary | |
88 } | |
89 z.decompressor = flate.NewReaderDict(z.r, dict) | |
90 } else { | |
91 z.decompressor = flate.NewReader(z.r) | |
92 } | |
93 z.digest = adler32.New() | |
94 return z, nil | 84 return z, nil |
95 } | 85 } |
96 | 86 |
97 func (z *reader) Read(p []byte) (n int, err error) { | 87 func (z *reader) Read(p []byte) (n int, err error) { |
98 if z.err != nil { | 88 if z.err != nil { |
99 return 0, z.err | 89 return 0, z.err |
100 } | 90 } |
101 if len(p) == 0 { | 91 if len(p) == 0 { |
102 return 0, nil | 92 return 0, nil |
103 } | 93 } |
(...skipping 20 matching lines...) Expand all Loading... |
124 } | 114 } |
125 | 115 |
126 // Calling Close does not close the wrapped io.Reader originally passed to NewRe
ader. | 116 // Calling Close does not close the wrapped io.Reader originally passed to NewRe
ader. |
127 func (z *reader) Close() error { | 117 func (z *reader) Close() error { |
128 if z.err != nil { | 118 if z.err != nil { |
129 return z.err | 119 return z.err |
130 } | 120 } |
131 z.err = z.decompressor.Close() | 121 z.err = z.decompressor.Close() |
132 return z.err | 122 return z.err |
133 } | 123 } |
| 124 |
| 125 func (z *reader) Reset(r io.Reader, dict []byte) error { |
| 126 if fr, ok := r.(flate.Reader); ok { |
| 127 z.r = fr |
| 128 } else { |
| 129 z.r = bufio.NewReader(r) |
| 130 } |
| 131 _, err := io.ReadFull(z.r, z.scratch[0:2]) |
| 132 if err != nil { |
| 133 return err |
| 134 } |
| 135 h := uint(z.scratch[0])<<8 | uint(z.scratch[1]) |
| 136 if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) { |
| 137 return ErrHeader |
| 138 } |
| 139 haveDict := z.scratch[1]&0x20 != 0 |
| 140 if haveDict { |
| 141 _, err = io.ReadFull(z.r, z.scratch[0:4]) |
| 142 if err != nil { |
| 143 return err |
| 144 } |
| 145 checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16
| uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) |
| 146 if checksum != adler32.Checksum(dict) { |
| 147 return ErrDictionary |
| 148 } |
| 149 } |
| 150 if z.decompressor == nil { |
| 151 if haveDict { |
| 152 z.decompressor = flate.NewReaderDict(z.r, dict) |
| 153 } else { |
| 154 z.decompressor = flate.NewReader(z.r) |
| 155 } |
| 156 } else { |
| 157 z.decompressor.(flate.Resetter).Reset(z.r, dict) |
| 158 } |
| 159 z.digest = adler32.New() |
| 160 return nil |
| 161 } |
LEFT | RIGHT |