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