1
2
3
4
5 package gzip
6
7 import (
8 "compress/flate"
9 "hash"
10 "hash/crc32"
11 "io"
12 "os"
13 )
14
15
16
17 const (
18 NoCompression = flate.NoCompression
19 BestSpeed = flate.BestSpeed
20 BestCompression = flate.BestCompression
21 DefaultCompression = flate.DefaultCompression
22 )
23
24
25
26 type Compressor struct {
27 Header
28 w io.Writer
29 level int
30 compressor io.WriteCloser
31 digest hash.Hash32
32 size uint32
33 closed bool
34 buf [10]byte
35 err os.Error
36 }
37
38
39 func NewWriter(w io.Writer) (*Compressor, os.Error) {
40 return NewWriterLevel(w, DefaultCompression)
41 }
42
43
44
45
46
47
48
49
50 func NewWriterLevel(w io.Writer, level int) (*Compressor, os.Error) {
51 z := new(Compressor)
52 z.OS = 255
53 z.w = w
54 z.level = level
55 z.digest = crc32.NewIEEE()
56 return z, nil
57 }
58
59
60 func put2(p []byte, v uint16) {
61 p[0] = uint8(v >> 0)
62 p[1] = uint8(v >> 8)
63 }
64
65 func put4(p []byte, v uint32) {
66 p[0] = uint8(v >> 0)
67 p[1] = uint8(v >> 8)
68 p[2] = uint8(v >> 16)
69 p[3] = uint8(v >> 24)
70 }
71
72
73 func (z *Compressor) writeBytes(b []byte) os.Error {
74 if len(b) > 0xffff {
75 return os.NewError("gzip.Write: Extra data is too large")
76 }
77 put2(z.buf[0:2], uint16(len(b)))
78 _, err := z.w.Write(z.buf[0:2])
79 if err != nil {
80 return err
81 }
82 _, err = z.w.Write(b)
83 return err
84 }
85
86
87 func (z *Compressor) writeString(s string) os.Error {
88
89
90 for _, v := range s {
91 if v == 0 || v > 0x7f {
92 return os.NewError("gzip.Write: non-ASCII header string")
93 }
94 }
95 _, err := io.WriteString(z.w, s)
96 if err != nil {
97 return err
98 }
99
100 z.buf[0] = 0
101 _, err = z.w.Write(z.buf[0:1])
102 return err
103 }
104
105 func (z *Compressor) Write(p []byte) (int, os.Error) {
106 if z.err != nil {
107 return 0, z.err
108 }
109 var n int
110
111 if z.compressor == nil {
112 z.buf[0] = gzipID1
113 z.buf[1] = gzipID2
114 z.buf[2] = gzipDeflate
115 z.buf[3] = 0
116 if z.Extra != nil {
117 z.buf[3] |= 0x04
118 }
119 if z.Name != "" {
120 z.buf[3] |= 0x08
121 }
122 if z.Comment != "" {
123 z.buf[3] |= 0x10
124 }
125 put4(z.buf[4:8], z.Mtime)
126 if z.level == BestCompression {
127 z.buf[8] = 2
128 } else if z.level == BestSpeed {
129 z.buf[8] = 4
130 } else {
131 z.buf[8] = 0
132 }
133 z.buf[9] = z.OS
134 n, z.err = z.w.Write(z.buf[0:10])
135 if z.err != nil {
136 return n, z.err
137 }
138 if z.Extra != nil {
139 z.err = z.writeBytes(z.Extra)
140 if z.err != nil {
141 return n, z.err
142 }
143 }
144 if z.Name != "" {
145 z.err = z.writeString(z.Name)
146 if z.err != nil {
147 return n, z.err
148 }
149 }
150 if z.Comment != "" {
151 z.err = z.writeString(z.Comment)
152 if z.err != nil {
153 return n, z.err
154 }
155 }
156 z.compressor = flate.NewWriter(z.w, z.level)
157 }
158 z.size += uint32(len(p))
159 z.digest.Write(p)
160 n, z.err = z.compressor.Write(p)
161 return n, z.err
162 }
163
164
165 func (z *Compressor) Close() os.Error {
166 if z.err != nil {
167 return z.err
168 }
169 if z.closed {
170 return nil
171 }
172 z.closed = true
173 if z.compressor == nil {
174 z.Write(nil)
175 if z.err != nil {
176 return z.err
177 }
178 }
179 z.err = z.compressor.Close()
180 if z.err != nil {
181 return z.err
182 }
183 put4(z.buf[0:4], z.digest.Sum32())
184 put4(z.buf[4:8], z.size)
185 _, z.err = z.w.Write(z.buf[0:8])
186 return z.err
187 }