1
2
3
4
5 package gzip
6
7 import (
8 "compress/flate"
9 "errors"
10 "fmt"
11 "hash/crc32"
12 "io"
13 "time"
14 )
15
16
17
18 const (
19 NoCompression = flate.NoCompression
20 BestSpeed = flate.BestSpeed
21 BestCompression = flate.BestCompression
22 DefaultCompression = flate.DefaultCompression
23 HuffmanOnly = flate.HuffmanOnly
24 )
25
26
27
28 type Writer struct {
29 Header
30 w io.Writer
31 level int
32 wroteHeader bool
33 closed bool
34 buf [10]byte
35 compressor *flate.Writer
36 digest uint32
37 size uint32
38 err error
39 }
40
41
42
43
44
45
46
47
48
49
50
51
52
53 func NewWriter(w io.Writer) *Writer {
54 z, _ := NewWriterLevel(w, DefaultCompression)
55 return z
56 }
57
58
59
60
61
62
63
64
65
66
67
68 func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
69 if level < HuffmanOnly || level > BestCompression {
70 return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
71 }
72 z := new(Writer)
73 z.init(w, level)
74 return z, nil
75 }
76
77 func (z *Writer) init(w io.Writer, level int) {
78 compressor := z.compressor
79 if compressor != nil {
80 compressor.Reset(w)
81 }
82 *z = Writer{
83 Header: Header{
84 OS: 255,
85 },
86 w: w,
87 level: level,
88 compressor: compressor,
89 }
90 }
91
92
93
94
95
96 func (z *Writer) Reset(w io.Writer) {
97 z.init(w, z.level)
98 }
99
100
101 func (z *Writer) writeBytes(b []byte) error {
102 if len(b) > 0xffff {
103 return errors.New("gzip.Write: Extra data is too large")
104 }
105 le.PutUint16(z.buf[:2], uint16(len(b)))
106 _, err := z.w.Write(z.buf[:2])
107 if err != nil {
108 return err
109 }
110 _, err = z.w.Write(b)
111 return err
112 }
113
114
115
116 func (z *Writer) writeString(s string) (err error) {
117
118 needconv := false
119 for _, v := range s {
120 if v == 0 || v > 0xff {
121 return errors.New("gzip.Write: non-Latin-1 header string")
122 }
123 if v > 0x7f {
124 needconv = true
125 }
126 }
127 if needconv {
128 b := make([]byte, 0, len(s))
129 for _, v := range s {
130 b = append(b, byte(v))
131 }
132 _, err = z.w.Write(b)
133 } else {
134 _, err = io.WriteString(z.w, s)
135 }
136 if err != nil {
137 return err
138 }
139
140 z.buf[0] = 0
141 _, err = z.w.Write(z.buf[:1])
142 return err
143 }
144
145
146
147 func (z *Writer) Write(p []byte) (int, error) {
148 if z.err != nil {
149 return 0, z.err
150 }
151 var n int
152
153 if !z.wroteHeader {
154 z.wroteHeader = true
155 z.buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate}
156 if z.Extra != nil {
157 z.buf[3] |= 0x04
158 }
159 if z.Name != "" {
160 z.buf[3] |= 0x08
161 }
162 if z.Comment != "" {
163 z.buf[3] |= 0x10
164 }
165 if z.ModTime.After(time.Unix(0, 0)) {
166
167
168 le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
169 }
170 if z.level == BestCompression {
171 z.buf[8] = 2
172 } else if z.level == BestSpeed {
173 z.buf[8] = 4
174 }
175 z.buf[9] = z.OS
176 _, z.err = z.w.Write(z.buf[:10])
177 if z.err != nil {
178 return 0, z.err
179 }
180 if z.Extra != nil {
181 z.err = z.writeBytes(z.Extra)
182 if z.err != nil {
183 return 0, z.err
184 }
185 }
186 if z.Name != "" {
187 z.err = z.writeString(z.Name)
188 if z.err != nil {
189 return 0, z.err
190 }
191 }
192 if z.Comment != "" {
193 z.err = z.writeString(z.Comment)
194 if z.err != nil {
195 return 0, z.err
196 }
197 }
198 if z.compressor == nil {
199 z.compressor, _ = flate.NewWriter(z.w, z.level)
200 }
201 }
202 z.size += uint32(len(p))
203 z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
204 n, z.err = z.compressor.Write(p)
205 return n, z.err
206 }
207
208
209
210
211
212
213
214
215
216 func (z *Writer) Flush() error {
217 if z.err != nil {
218 return z.err
219 }
220 if z.closed {
221 return nil
222 }
223 if !z.wroteHeader {
224 z.Write(nil)
225 if z.err != nil {
226 return z.err
227 }
228 }
229 z.err = z.compressor.Flush()
230 return z.err
231 }
232
233
234
235
236 func (z *Writer) Close() error {
237 if z.err != nil {
238 return z.err
239 }
240 if z.closed {
241 return nil
242 }
243 z.closed = true
244 if !z.wroteHeader {
245 z.Write(nil)
246 if z.err != nil {
247 return z.err
248 }
249 }
250 z.err = z.compressor.Close()
251 if z.err != nil {
252 return z.err
253 }
254 le.PutUint32(z.buf[:4], z.digest)
255 le.PutUint32(z.buf[4:8], z.size)
256 _, z.err = z.w.Write(z.buf[:8])
257 return z.err
258 }
259
View as plain text