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