Source file src/pkg/compress/flate/deflate.go
1
2
3
4
5 package flate
6
7 import (
8 "fmt"
9 "io"
10 "math"
11 )
12
13 const (
14 NoCompression = 0
15 BestSpeed = 1
16 BestCompression = 9
17 DefaultCompression = -1
18
19
20
21
22
23
24
25
26
27
28 HuffmanOnly = -2
29 )
30
31 const (
32 logWindowSize = 15
33 windowSize = 1 << logWindowSize
34 windowMask = windowSize - 1
35
36
37
38
39
40
41
42 baseMatchLength = 3
43 minMatchLength = 4
44 maxMatchLength = 258
45 baseMatchOffset = 1
46 maxMatchOffset = 1 << 15
47
48
49
50 maxFlateBlockTokens = 1 << 14
51 maxStoreBlockSize = 65535
52 hashBits = 17
53 hashSize = 1 << hashBits
54 hashMask = (1 << hashBits) - 1
55 maxHashOffset = 1 << 24
56
57 skipNever = math.MaxInt32
58 )
59
60 type compressionLevel struct {
61 level, good, lazy, nice, chain, fastSkipHashing int
62 }
63
64 var levels = []compressionLevel{
65 {0, 0, 0, 0, 0, 0},
66 {1, 0, 0, 0, 0, 0},
67
68 {2, 4, 0, 16, 8, 5},
69 {3, 4, 0, 32, 32, 6},
70
71
72 {4, 4, 4, 16, 16, skipNever},
73 {5, 8, 16, 32, 32, skipNever},
74 {6, 8, 16, 128, 128, skipNever},
75 {7, 8, 32, 128, 256, skipNever},
76 {8, 32, 128, 258, 1024, skipNever},
77 {9, 32, 258, 258, 4096, skipNever},
78 }
79
80 type compressor struct {
81 compressionLevel
82
83 w *huffmanBitWriter
84 bulkHasher func([]byte, []uint32)
85
86
87 fill func(*compressor, []byte) int
88 step func(*compressor)
89 sync bool
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
110 tokens []token
111
112
113 length int
114 offset int
115 hash uint32
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 var newH uint32
214 for i, val := range dst {
215 di := i + index
216 newH = val
217 hh := &d.hashHead[newH&hashMask]
218
219
220 d.hashPrev[di&windowMask] = *hh
221
222 *hh = uint32(di + d.hashOffset)
223 }
224 d.hash = newH
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.hash = 0
380 d.chainHead = -1
381 d.bulkHasher = bulkHash4
382 }
383
384 func (d *compressor) deflate() {
385 if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync {
386 return
387 }
388
389 d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
390 if d.index < d.maxInsertIndex {
391 d.hash = hash4(d.window[d.index : d.index+minMatchLength])
392 }
393
394 Loop:
395 for {
396 if d.index > d.windowEnd {
397 panic("index > windowEnd")
398 }
399 lookahead := d.windowEnd - d.index
400 if lookahead < minMatchLength+maxMatchLength {
401 if !d.sync {
402 break Loop
403 }
404 if d.index > d.windowEnd {
405 panic("index > windowEnd")
406 }
407 if lookahead == 0 {
408
409 if d.byteAvailable {
410
411 d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1])))
412 d.byteAvailable = false
413 }
414 if len(d.tokens) > 0 {
415 if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
416 return
417 }
418 d.tokens = d.tokens[:0]
419 }
420 break Loop
421 }
422 }
423 if d.index < d.maxInsertIndex {
424
425 d.hash = hash4(d.window[d.index : d.index+minMatchLength])
426 hh := &d.hashHead[d.hash&hashMask]
427 d.chainHead = int(*hh)
428 d.hashPrev[d.index&windowMask] = uint32(d.chainHead)
429 *hh = uint32(d.index + d.hashOffset)
430 }
431 prevLength := d.length
432 prevOffset := d.offset
433 d.length = minMatchLength - 1
434 d.offset = 0
435 minIndex := d.index - windowSize
436 if minIndex < 0 {
437 minIndex = 0
438 }
439
440 if d.chainHead-d.hashOffset >= minIndex &&
441 (d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 ||
442 d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) {
443 if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok {
444 d.length = newLength
445 d.offset = newOffset
446 }
447 }
448 if d.fastSkipHashing != skipNever && d.length >= minMatchLength ||
449 d.fastSkipHashing == skipNever && prevLength >= minMatchLength && d.length <= prevLength {
450
451
452 if d.fastSkipHashing != skipNever {
453 d.tokens = append(d.tokens, matchToken(uint32(d.length-baseMatchLength), uint32(d.offset-baseMatchOffset)))
454 } else {
455 d.tokens = append(d.tokens, matchToken(uint32(prevLength-baseMatchLength), uint32(prevOffset-baseMatchOffset)))
456 }
457
458
459
460
461 if d.length <= d.fastSkipHashing {
462 var newIndex int
463 if d.fastSkipHashing != skipNever {
464 newIndex = d.index + d.length
465 } else {
466 newIndex = d.index + prevLength - 1
467 }
468 for d.index++; d.index < newIndex; d.index++ {
469 if d.index < d.maxInsertIndex {
470 d.hash = hash4(d.window[d.index : d.index+minMatchLength])
471
472
473 hh := &d.hashHead[d.hash&hashMask]
474 d.hashPrev[d.index&windowMask] = *hh
475
476 *hh = uint32(d.index + d.hashOffset)
477 }
478 }
479 if d.fastSkipHashing == skipNever {
480 d.byteAvailable = false
481 d.length = minMatchLength - 1
482 }
483 } else {
484
485
486 d.index += d.length
487 if d.index < d.maxInsertIndex {
488 d.hash = hash4(d.window[d.index : d.index+minMatchLength])
489 }
490 }
491 if len(d.tokens) == maxFlateBlockTokens {
492
493 if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
494 return
495 }
496 d.tokens = d.tokens[:0]
497 }
498 } else {
499 if d.fastSkipHashing != skipNever || d.byteAvailable {
500 i := d.index - 1
501 if d.fastSkipHashing != skipNever {
502 i = d.index
503 }
504 d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
505 if len(d.tokens) == maxFlateBlockTokens {
506 if d.err = d.writeBlock(d.tokens, i+1); d.err != nil {
507 return
508 }
509 d.tokens = d.tokens[:0]
510 }
511 }
512 d.index++
513 if d.fastSkipHashing == skipNever {
514 d.byteAvailable = true
515 }
516 }
517 }
518 }
519
520 func (d *compressor) fillStore(b []byte) int {
521 n := copy(d.window[d.windowEnd:], b)
522 d.windowEnd += n
523 return n
524 }
525
526 func (d *compressor) store() {
527 if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
528 d.err = d.writeStoredBlock(d.window[:d.windowEnd])
529 d.windowEnd = 0
530 }
531 }
532
533
534
535
536 func (d *compressor) storeHuff() {
537 if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
538 return
539 }
540 d.w.writeBlockHuff(false, d.window[:d.windowEnd])
541 d.err = d.w.err
542 d.windowEnd = 0
543 }
544
545 func (d *compressor) write(b []byte) (n int, err error) {
546 if d.err != nil {
547 return 0, d.err
548 }
549 n = len(b)
550 for len(b) > 0 {
551 d.step(d)
552 b = b[d.fill(d, b):]
553 if d.err != nil {
554 return 0, d.err
555 }
556 }
557 return n, nil
558 }
559
560 func (d *compressor) syncFlush() error {
561 if d.err != nil {
562 return d.err
563 }
564 d.sync = true
565 d.step(d)
566 if d.err == nil {
567 d.w.writeStoredHeader(0, false)
568 d.w.flush()
569 d.err = d.w.err
570 }
571 d.sync = false
572 return d.err
573 }
574
575 func (d *compressor) init(w io.Writer, level int) (err error) {
576 d.w = newHuffmanBitWriter(w)
577
578 switch {
579 case level == NoCompression:
580 d.window = make([]byte, maxStoreBlockSize)
581 d.fill = (*compressor).fillStore
582 d.step = (*compressor).store
583 case level == HuffmanOnly:
584 d.window = make([]byte, maxStoreBlockSize)
585 d.fill = (*compressor).fillStore
586 d.step = (*compressor).storeHuff
587 case level == BestSpeed:
588 d.compressionLevel = levels[level]
589 d.window = make([]byte, maxStoreBlockSize)
590 d.fill = (*compressor).fillStore
591 d.step = (*compressor).encSpeed
592 d.bestSpeed = newDeflateFast()
593 d.tokens = make([]token, maxStoreBlockSize)
594 case level == DefaultCompression:
595 level = 6
596 fallthrough
597 case 2 <= level && level <= 9:
598 d.compressionLevel = levels[level]
599 d.initDeflate()
600 d.fill = (*compressor).fillDeflate
601 d.step = (*compressor).deflate
602 default:
603 return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
604 }
605 return nil
606 }
607
608 func (d *compressor) reset(w io.Writer) {
609 d.w.reset(w)
610 d.sync = false
611 d.err = nil
612 switch d.compressionLevel.level {
613 case NoCompression:
614 d.windowEnd = 0
615 case BestSpeed:
616 d.windowEnd = 0
617 d.tokens = d.tokens[:0]
618 d.bestSpeed.reset()
619 default:
620 d.chainHead = -1
621 for i := range d.hashHead {
622 d.hashHead[i] = 0
623 }
624 for i := range d.hashPrev {
625 d.hashPrev[i] = 0
626 }
627 d.hashOffset = 1
628 d.index, d.windowEnd = 0, 0
629 d.blockStart, d.byteAvailable = 0, false
630 d.tokens = d.tokens[:0]
631 d.length = minMatchLength - 1
632 d.offset = 0
633 d.hash = 0
634 d.maxInsertIndex = 0
635 }
636 }
637
638 func (d *compressor) close() error {
639 if d.err != nil {
640 return d.err
641 }
642 d.sync = true
643 d.step(d)
644 if d.err != nil {
645 return d.err
646 }
647 if d.w.writeStoredHeader(0, true); d.w.err != nil {
648 return d.w.err
649 }
650 d.w.flush()
651 return d.w.err
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666 func NewWriter(w io.Writer, level int) (*Writer, error) {
667 var dw Writer
668 if err := dw.d.init(w, level); err != nil {
669 return nil, err
670 }
671 return &dw, nil
672 }
673
674
675
676
677
678
679
680 func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
681 dw := &dictWriter{w}
682 zw, err := NewWriter(dw, level)
683 if err != nil {
684 return nil, err
685 }
686 zw.d.fillWindow(dict)
687 zw.dict = append(zw.dict, dict...)
688 return zw, err
689 }
690
691 type dictWriter struct {
692 w io.Writer
693 }
694
695 func (w *dictWriter) Write(b []byte) (n int, err error) {
696 return w.w.Write(b)
697 }
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