...
Source file src/compress/lzw/writer.go
1
2
3
4
5 package lzw
6
7 import (
8 "bufio"
9 "errors"
10 "fmt"
11 "io"
12 )
13
14
15 type writer interface {
16 io.ByteWriter
17 Flush() error
18 }
19
20
21 type errWriteCloser struct {
22 err error
23 }
24
25 func (e *errWriteCloser) Write([]byte) (int, error) {
26 return 0, e.err
27 }
28
29 func (e *errWriteCloser) Close() error {
30 return e.err
31 }
32
33 const (
34
35
36 maxCode = 1<<12 - 1
37 invalidCode = 1<<32 - 1
38
39
40 tableSize = 4 * 1 << 12
41 tableMask = tableSize - 1
42
43
44 invalidEntry = 0
45 )
46
47
48 type encoder struct {
49
50 w writer
51
52
53 order Order
54 write func(*encoder, uint32) error
55 bits uint32
56 nBits uint
57 width uint
58
59 litWidth uint
60
61
62 hi, overflow uint32
63
64
65 savedCode uint32
66
67
68 err error
69
70
71
72
73 table [tableSize]uint32
74 }
75
76
77 func (e *encoder) writeLSB(c uint32) error {
78 e.bits |= c << e.nBits
79 e.nBits += e.width
80 for e.nBits >= 8 {
81 if err := e.w.WriteByte(uint8(e.bits)); err != nil {
82 return err
83 }
84 e.bits >>= 8
85 e.nBits -= 8
86 }
87 return nil
88 }
89
90
91 func (e *encoder) writeMSB(c uint32) error {
92 e.bits |= c << (32 - e.width - e.nBits)
93 e.nBits += e.width
94 for e.nBits >= 8 {
95 if err := e.w.WriteByte(uint8(e.bits >> 24)); err != nil {
96 return err
97 }
98 e.bits <<= 8
99 e.nBits -= 8
100 }
101 return nil
102 }
103
104
105
106 var errOutOfCodes = errors.New("lzw: out of codes")
107
108
109
110
111 func (e *encoder) incHi() error {
112 e.hi++
113 if e.hi == e.overflow {
114 e.width++
115 e.overflow <<= 1
116 }
117 if e.hi == maxCode {
118 clear := uint32(1) << e.litWidth
119 if err := e.write(e, clear); err != nil {
120 return err
121 }
122 e.width = e.litWidth + 1
123 e.hi = clear + 1
124 e.overflow = clear << 1
125 for i := range e.table {
126 e.table[i] = invalidEntry
127 }
128 return errOutOfCodes
129 }
130 return nil
131 }
132
133
134 func (e *encoder) Write(p []byte) (n int, err error) {
135 if e.err != nil {
136 return 0, e.err
137 }
138 if len(p) == 0 {
139 return 0, nil
140 }
141 if maxLit := uint8(1<<e.litWidth - 1); maxLit != 0xff {
142 for _, x := range p {
143 if x > maxLit {
144 e.err = errors.New("lzw: input byte too large for the litWidth")
145 return 0, e.err
146 }
147 }
148 }
149 n = len(p)
150 code := e.savedCode
151 if code == invalidCode {
152
153 code, p = uint32(p[0]), p[1:]
154 }
155 loop:
156 for _, x := range p {
157 literal := uint32(x)
158 key := code<<8 | literal
159
160
161 hash := (key>>12 ^ key) & tableMask
162 for h, t := hash, e.table[hash]; t != invalidEntry; {
163 if key == t>>12 {
164 code = t & maxCode
165 continue loop
166 }
167 h = (h + 1) & tableMask
168 t = e.table[h]
169 }
170
171
172 if e.err = e.write(e, code); e.err != nil {
173 return 0, e.err
174 }
175 code = literal
176
177
178 if err1 := e.incHi(); err1 != nil {
179 if err1 == errOutOfCodes {
180 continue
181 }
182 e.err = err1
183 return 0, e.err
184 }
185
186 for {
187 if e.table[hash] == invalidEntry {
188 e.table[hash] = (key << 12) | e.hi
189 break
190 }
191 hash = (hash + 1) & tableMask
192 }
193 }
194 e.savedCode = code
195 return n, nil
196 }
197
198
199
200 func (e *encoder) Close() error {
201 if e.err != nil {
202 if e.err == errClosed {
203 return nil
204 }
205 return e.err
206 }
207
208 e.err = errClosed
209
210 if e.savedCode != invalidCode {
211 if err := e.write(e, e.savedCode); err != nil {
212 return err
213 }
214 if err := e.incHi(); err != nil && err != errOutOfCodes {
215 return err
216 }
217 }
218
219 eof := uint32(1)<<e.litWidth + 1
220 if err := e.write(e, eof); err != nil {
221 return err
222 }
223
224 if e.nBits > 0 {
225 if e.order == MSB {
226 e.bits >>= 24
227 }
228 if err := e.w.WriteByte(uint8(e.bits)); err != nil {
229 return err
230 }
231 }
232 return e.w.Flush()
233 }
234
235
236
237
238
239
240
241 func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
242 var write func(*encoder, uint32) error
243 switch order {
244 case LSB:
245 write = (*encoder).writeLSB
246 case MSB:
247 write = (*encoder).writeMSB
248 default:
249 return &errWriteCloser{errors.New("lzw: unknown order")}
250 }
251 if litWidth < 2 || 8 < litWidth {
252 return &errWriteCloser{fmt.Errorf("lzw: litWidth %d out of range", litWidth)}
253 }
254 bw, ok := w.(writer)
255 if !ok {
256 bw = bufio.NewWriter(w)
257 }
258 lw := uint(litWidth)
259 return &encoder{
260 w: bw,
261 order: order,
262 write: write,
263 width: 1 + lw,
264 litWidth: lw,
265 hi: 1<<lw + 1,
266 overflow: 1 << (lw + 1),
267 savedCode: invalidCode,
268 }
269 }
270
View as plain text