1
2
3
4
5 package flate
6
7 import (
8 "errors"
9 "fmt"
10 "io"
11 "math"
12 )
13
14 const (
15 NoCompression = 0
16 BestSpeed = 1
17 BestCompression = 9
18 DefaultCompression = -1
19
20
21
22
23
24
25
26
27
28
29 HuffmanOnly = -2
30 )
31
32 const (
33 logWindowSize = 15
34 windowSize = 1 << logWindowSize
35 windowMask = windowSize - 1
36
37
38
39
40
41
42
43 baseMatchLength = 3
44 minMatchLength = 4
45 maxMatchLength = 258
46 baseMatchOffset = 1
47 maxMatchOffset = 1 << 15
48
49
50
51 maxFlateBlockTokens = 1 << 14
52 maxStoreBlockSize = 65535
53 hashBits = 17
54 hashSize = 1 << hashBits
55 hashMask = (1 << hashBits) - 1
56 maxHashOffset = 1 << 24
57
58 skipNever = math.MaxInt32
59 )
60
61 type compressionLevel struct {
62 level, good, lazy, nice, chain, fastSkipHashing int
63 }
64
65 var levels = []compressionLevel{
66 {0, 0, 0, 0, 0, 0},
67 {1, 0, 0, 0, 0, 0},
68
69 {2, 4, 0, 16, 8, 5},
70 {3, 4, 0, 32, 32, 6},
71
72
73 {4, 4, 4, 16, 16, skipNever},
74 {5, 8, 16, 32, 32, skipNever},
75 {6, 8, 16, 128, 128, skipNever},
76 {7, 8, 32, 128, 256, skipNever},
77 {8, 32, 128, 258, 1024, skipNever},
78 {9, 32, 258, 258, 4096, skipNever},
79 }
80
81 type compressor struct {
82 compressionLevel
83
84 w *huffmanBitWriter
85 bulkHasher func([]byte, []uint32)
86
87
88 fill func(*compressor, []byte) int
89 step func(*compressor)
90 bestSpeed *deflateFast
91
92
93 index int
94 window []byte
95 windowEnd int
96 blockStart int
97 byteAvailable bool
98
99 sync bool
100
101
102 tokens []token
103
104
105 length int
106 offset int
107 maxInsertIndex int
108 err error
109
110
111
112
113
114
115
116
117 chainHead int
118 hashHead [hashSize]uint32
119 hashPrev [windowSize]uint32
120 hashOffset int
121
122
123 hashMatch [maxMatchLength - 1]uint32
124 }
125
126 func (d *compressor) fillDeflate(b []byte) int {
127 if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
128
129 copy(d.window, d.window[windowSize:2*windowSize])
130 d.index -= windowSize
131 d.windowEnd -= windowSize
132 if d.blockStart >= windowSize {
133 d.blockStart -= windowSize
134 } else {
135 d.blockStart = math.MaxInt32
136 }
137 d.hashOffset += windowSize
138 if d.hashOffset > maxHashOffset {
139 delta := d.hashOffset - 1
140 d.hashOffset -= delta
141 d.chainHead -= delta
142
143
144
145 for i, v := range d.hashPrev[:] {
146 if int(v) > delta {
147 d.hashPrev[i] = uint32(int(v) - delta)
148 } else {
149 d.hashPrev[i] = 0
150 }
151 }
152 for i, v := range d.hashHead[:] {
153 if int(v) > delta {
154 d.hashHead[i] = uint32(int(v) - delta)
155 } else {
156 d.hashHead[i] = 0
157 }
158 }
159 }
160 }
161 n := copy(d.window[d.windowEnd:], b)
162 d.windowEnd += n
163 return n
164 }
165
166 func (d *compressor) writeBlock(tokens []token, index int) error {
167 if index > 0 {
168 var window []byte
169 if d.blockStart <= index {
170 window = d.window[d.blockStart:index]
171 }
172 d.blockStart = index
173 d.w.writeBlock(tokens, false, window)
174 return d.w.err
175 }
176 return nil
177 }
178
179
180
181
182
183 func (d *compressor) fillWindow(b []byte) {
184
185 if d.compressionLevel.level < 2 {
186 return
187 }
188 if d.index != 0 || d.windowEnd != 0 {
189 panic("internal error: fillWindow called with stale data")
190 }
191
192
193 if len(b) > windowSize {
194 b = b[len(b)-windowSize:]
195 }
196
197 n := copy(d.window, b)
198
199
200 loops := (n + 256 - minMatchLength) / 256
201 for j := 0; j < loops; j++ {
202 index := j * 256
203 end := index + 256 + minMatchLength - 1
204 if end > n {
205 end = n
206 }
207 toCheck := d.window[index:end]
208 dstSize := len(toCheck) - minMatchLength + 1
209
210 if dstSize <= 0 {
211 continue
212 }
213
214 dst := d.hashMatch[:dstSize]
215 d.bulkHasher(toCheck, dst)
216 for i, val := range dst {
217 di := i + index
218 hh := &d.hashHead[val&hashMask]
219
220
221 d.hashPrev[di&windowMask] = *hh
222
223 *hh = uint32(di + d.hashOffset)
224 }
225 }
226
227 d.windowEnd = n
228 d.index = n
229 }
230
231
232
233 func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
234 minMatchLook := maxMatchLength
235 if lookahead < minMatchLook {
236 minMatchLook = lookahead
237 }
238
239 win := d.window[0 : pos+minMatchLook]
240
241
242 nice := len(win) - pos
243 if d.nice < nice {
244 nice = d.nice
245 }
246
247
248 tries := d.chain
249 length = prevLength
250 if length >= d.good {
251 tries >>= 2
252 }
253
254 wEnd := win[pos+length]
255 wPos := win[pos:]
256 minIndex := pos - windowSize
257
258 for i := prevHead; tries > 0; tries-- {
259 if wEnd == win[i+length] {
260 n := matchLen(win[i:], wPos, minMatchLook)
261
262 if n > length && (n > minMatchLength || pos-i <= 4096) {
263 length = n
264 offset = pos - i
265 ok = true
266 if n >= nice {
267
268 break
269 }
270 wEnd = win[pos+n]
271 }
272 }
273 if i == minIndex {
274
275 break
276 }
277 i = int(d.hashPrev[i&windowMask]) - d.hashOffset
278 if i < minIndex || i < 0 {
279 break
280 }
281 }
282 return
283 }
284
285 func (d *compressor) writeStoredBlock(buf []byte) error {
286 if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
287 return d.w.err
288 }
289 d.w.writeBytes(buf)
290 return d.w.err
291 }
292
293 const hashmul = 0x1e35a7bd
294
295
296
297
298 func hash4(b []byte) uint32 {
299 return ((uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24) * hashmul) >> (32 - hashBits)
300 }
301
302
303
304 func bulkHash4(b []byte, dst []uint32) {
305 if len(b) < minMatchLength {
306 return
307 }
308 hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
309 dst[0] = (hb * hashmul) >> (32 - hashBits)
310 end := len(b) - minMatchLength + 1
311 for i := 1; i < end; i++ {
312 hb = (hb << 8) | uint32(b[i+3])
313 dst[i] = (hb * hashmul) >> (32 - hashBits)
314 }
315 }
316
317
318
319
320 func matchLen(a, b []byte, max int) int {
321 a = a[:max]
322 b = b[:len(a)]
323 for i, av := range a {
324 if b[i] != av {
325 return i
326 }
327 }
328 return max
329 }
330
331
332
333
334 func (d *compressor) encSpeed() {
335
336 if d.windowEnd < maxStoreBlockSize {
337 if !d.sync {
338 return
339 }
340
341
342 if d.windowEnd < 128 {
343 switch {
344 case d.windowEnd == 0:
345 return
346 case d.windowEnd <= 16:
347 d.err = d.writeStoredBlock(d.window[:d.windowEnd])
348 default:
349 d.w.writeBlockHuff(false, d.window[:d.windowEnd])
350 d.err = d.w.err
351 }
352 d.windowEnd = 0
353 d.bestSpeed.reset()
354 return
355 }
356
357 }
358
359 d.tokens = d.bestSpeed.encode(d.tokens[:0], d.window[:d.windowEnd])
360
361
362 if len(d.tokens) > d.windowEnd-(d.windowEnd>>4) {
363 d.w.writeBlockHuff(false, d.window[:d.windowEnd])
364 } else {
365 d.w.writeBlockDynamic(d.tokens, false, d.window[:d.windowEnd])
366 }
367 d.err = d.w.err
368 d.windowEnd = 0
369 }
370
371 func (d *compressor) initDeflate() {
372 d.window = make([]byte, 2*windowSize)
373 d.hashOffset = 1
374 d.tokens = make([]token, 0, maxFlateBlockTokens+1)
375 d.length = minMatchLength - 1
376 d.offset = 0
377 d.byteAvailable = false
378 d.index = 0
379 d.chainHead = -1
380 d.bulkHasher = bulkHash4
381 }
382
383 func (d *compressor) deflate() {
384 if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync {
385 return
386 }
387
388 d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
389
390 Loop:
391 for {
392 if d.index > d.windowEnd {
393 panic("index > windowEnd")
394 }
395 lookahead := d.windowEnd - d.index
396 if lookahead < minMatchLength+maxMatchLength {
397 if !d.sync {
398 break Loop
399 }
400 if d.index > d.windowEnd {
401 panic("index > windowEnd")
402 }
403 if lookahead == 0 {
404
405 if d.byteAvailable {
406
407 d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1])))
408 d.byteAvailable = false
409 }
410 if len(d.tokens) > 0 {
411 if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
412 return
413 }
414 d.tokens = d.tokens[:0]
415 }
416 break Loop
417 }
418 }
419 if d.index < d.maxInsertIndex {
420
421 hash := hash4(d.window[d.index : d.index+minMatchLength])
422 hh := &d.hashHead[hash&hashMask]
423 d.chainHead = int(*hh)
424 d.hashPrev[d.index&windowMask] = uint32(d.chainHead)
425 *hh = uint32(d.index + d.hashOffset)
426 }
427 prevLength := d.length
428 prevOffset := d.offset
429 d.length = minMatchLength - 1
430 d.offset = 0
431 minIndex := d.index - windowSize
432 if minIndex < 0 {
433 minIndex = 0
434 }
435
436 if d.chainHead-d.hashOffset >= minIndex &&
437 (d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 ||
438 d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) {
439 if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok {
440 d.length = newLength
441 d.offset = newOffset
442 }
443 }
444 if d.fastSkipHashing != skipNever && d.length >= minMatchLength ||
445 d.fastSkipHashing == skipNever && prevLength >= minMatchLength && d.length <= prevLength {
446
447
448 if d.fastSkipHashing != skipNever {
449 d.tokens = append(d.tokens, matchToken(uint32(d.length-baseMatchLength), uint32(d.offset-baseMatchOffset)))
450 } else {
451 d.tokens = append(d.tokens, matchToken(uint32(prevLength-baseMatchLength), uint32(prevOffset-baseMatchOffset)))
452 }
453
454
455
456
457 if d.length <= d.fastSkipHashing {
458 var newIndex int
459 if d.fastSkipHashing != skipNever {
460 newIndex = d.index + d.length
461 } else {
462 newIndex = d.index + prevLength - 1
463 }
464 index := d.index
465 for index++; index < newIndex; index++ {
466 if index < d.maxInsertIndex {
467 hash := hash4(d.window[index : index+minMatchLength])
468
469
470 hh := &d.hashHead[hash&hashMask]
471 d.hashPrev[index&windowMask] = *hh
472
473 *hh = uint32(index + d.hashOffset)
474 }
475 }
476 d.index = index
477
478 if d.fastSkipHashing == skipNever {
479 d.byteAvailable = false
480 d.length = minMatchLength - 1
481 }
482 } else {
483
484
485 d.index += d.length
486 }
487 if len(d.tokens) == maxFlateBlockTokens {
488
489 if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
490 return
491 }
492 d.tokens = d.tokens[:0]
493 }
494 } else {
495 if d.fastSkipHashing != skipNever || d.byteAvailable {
496 i := d.index - 1
497 if d.fastSkipHashing != skipNever {
498 i = d.index
499 }
500 d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
501 if len(d.tokens) == maxFlateBlockTokens {
502 if d.err = d.writeBlock(d.tokens, i+1); d.err != nil {
503 return
504 }
505 d.tokens = d.tokens[:0]
506 }
507 }
508 d.index++
509 if d.fastSkipHashing == skipNever {
510 d.byteAvailable = true
511 }
512 }
513 }
514 }
515
516 func (d *compressor) fillStore(b []byte) int {
517 n := copy(d.window[d.windowEnd:], b)
518 d.windowEnd += n
519 return n
520 }
521
522 func (d *compressor) store() {
523 if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
524 d.err = d.writeStoredBlock(d.window[:d.windowEnd])
525 d.windowEnd = 0
526 }
527 }
528
529
530
531
532 func (d *compressor) storeHuff() {
533 if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
534 return
535 }
536 d.w.writeBlockHuff(false, d.window[:d.windowEnd])
537 d.err = d.w.err
538 d.windowEnd = 0
539 }
540
541 func (d *compressor) write(b []byte) (n int, err error) {
542 if d.err != nil {
543 return 0, d.err
544 }
545 n = len(b)
546 for len(b) > 0 {
547 d.step(d)
548 b = b[d.fill(d, b):]
549 if d.err != nil {
550 return 0, d.err
551 }
552 }
553 return n, nil
554 }
555
556 func (d *compressor) syncFlush() error {
557 if d.err != nil {
558 return d.err
559 }
560 d.sync = true
561 d.step(d)
562 if d.err == nil {
563 d.w.writeStoredHeader(0, false)
564 d.w.flush()
565 d.err = d.w.err
566 }
567 d.sync = false
568 return d.err
569 }
570
571 func (d *compressor) init(w io.Writer, level int) (err error) {
572 d.w = newHuffmanBitWriter(w)
573
574 switch {
575 case level == NoCompression:
576 d.window = make([]byte, maxStoreBlockSize)
577 d.fill = (*compressor).fillStore
578 d.step = (*compressor).store
579 case level == HuffmanOnly:
580 d.window = make([]byte, maxStoreBlockSize)
581 d.fill = (*compressor).fillStore
582 d.step = (*compressor).storeHuff
583 case level == BestSpeed:
584 d.compressionLevel = levels[level]
585 d.window = make([]byte, maxStoreBlockSize)
586 d.fill = (*compressor).fillStore
587 d.step = (*compressor).encSpeed
588 d.bestSpeed = newDeflateFast()
589 d.tokens = make([]token, maxStoreBlockSize)
590 case level == DefaultCompression:
591 level = 6
592 fallthrough
593 case 2 <= level && level <= 9:
594 d.compressionLevel = levels[level]
595 d.initDeflate()
596 d.fill = (*compressor).fillDeflate
597 d.step = (*compressor).deflate
598 default:
599 return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
600 }
601 return nil
602 }
603
604 func (d *compressor) reset(w io.Writer) {
605 d.w.reset(w)
606 d.sync = false
607 d.err = nil
608 switch d.compressionLevel.level {
609 case NoCompression:
610 d.windowEnd = 0
611 case BestSpeed:
612 d.windowEnd = 0
613 d.tokens = d.tokens[:0]
614 d.bestSpeed.reset()
615 default:
616 d.chainHead = -1
617 clear(d.hashHead[:])
618 clear(d.hashPrev[:])
619 d.hashOffset = 1
620 d.index, d.windowEnd = 0, 0
621 d.blockStart, d.byteAvailable = 0, false
622 d.tokens = d.tokens[:0]
623 d.length = minMatchLength - 1
624 d.offset = 0
625 d.maxInsertIndex = 0
626 }
627 }
628
629 func (d *compressor) close() error {
630 if d.err == errWriterClosed {
631 return nil
632 }
633 if d.err != nil {
634 return d.err
635 }
636 d.sync = true
637 d.step(d)
638 if d.err != nil {
639 return d.err
640 }
641 if d.w.writeStoredHeader(0, true); d.w.err != nil {
642 return d.w.err
643 }
644 d.w.flush()
645 if d.w.err != nil {
646 return d.w.err
647 }
648 d.err = errWriterClosed
649 return nil
650 }
651
652
653
654
655
656
657
658
659
660
661
662
663
664 func NewWriter(w io.Writer, level int) (*Writer, error) {
665 var dw Writer
666 if err := dw.d.init(w, level); err != nil {
667 return nil, err
668 }
669 return &dw, nil
670 }
671
672
673
674
675
676
677
678 func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
679 dw := &dictWriter{w}
680 zw, err := NewWriter(dw, level)
681 if err != nil {
682 return nil, err
683 }
684 zw.d.fillWindow(dict)
685 zw.dict = append(zw.dict, dict...)
686 return zw, nil
687 }
688
689 type dictWriter struct {
690 w io.Writer
691 }
692
693 func (w *dictWriter) Write(b []byte) (n int, err error) {
694 return w.w.Write(b)
695 }
696
697 var errWriterClosed = errors.New("flate: closed writer")
698
699
700
701 type Writer struct {
702 d compressor
703 dict []byte
704 }
705
706
707
708 func (w *Writer) Write(data []byte) (n int, err error) {
709 return w.d.write(data)
710 }
711
712
713
714
715
716
717
718
719
720
721 func (w *Writer) Flush() error {
722
723
724 return w.d.syncFlush()
725 }
726
727
728 func (w *Writer) Close() error {
729 return w.d.close()
730 }
731
732
733
734
735 func (w *Writer) Reset(dst io.Writer) {
736 if dw, ok := w.d.w.writer.(*dictWriter); ok {
737
738 dw.w = dst
739 w.d.reset(dw)
740 w.d.fillWindow(w.dict)
741 } else {
742
743 w.d.reset(dst)
744 }
745 }
746
View as plain text