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