package flate
import (
"encoding/binary"
"fmt"
"io"
"math"
)
const (
offsetCodeCount = 30
endBlockMarker = 256
lengthCodesStart = 257
codegenCodeCount = 19
badCode = 255
maxPredefinedTokens = 250
bufferFlushSize = 246
)
const lengthExtraBitsMinCode = 8
var lengthExtraBits = [32 ]uint8 {
0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 2 ,
2 , 2 , 2 , 3 , 3 , 3 , 3 , 4 , 4 , 4 ,
4 , 5 , 5 , 5 , 5 , 0 ,
}
var lengthBase = [32 ]uint8 {
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 10 ,
12 , 14 , 16 , 20 , 24 , 28 , 32 , 40 , 48 , 56 ,
64 , 80 , 96 , 112 , 128 , 160 , 192 , 224 , 255 ,
}
const offsetExtraBitsMinCode = 4
var offsetExtraBits = [32 ]int8 {
0 , 0 , 0 , 0 , 1 , 1 , 2 , 2 , 3 , 3 ,
4 , 4 , 5 , 5 , 6 , 6 , 7 , 7 , 8 , 8 ,
9 , 9 , 10 , 10 , 11 , 11 , 12 , 12 , 13 , 13 ,
14 , 14 ,
}
var offsetCombined = [32 ]uint32 {}
func init () {
var offsetBase = [32 ]uint32 {
0x000000 , 0x000001 , 0x000002 , 0x000003 , 0x000004 ,
0x000006 , 0x000008 , 0x00000c , 0x000010 , 0x000018 ,
0x000020 , 0x000030 , 0x000040 , 0x000060 , 0x000080 ,
0x0000c0 , 0x000100 , 0x000180 , 0x000200 , 0x000300 ,
0x000400 , 0x000600 , 0x000800 , 0x000c00 , 0x001000 ,
0x001800 , 0x002000 , 0x003000 , 0x004000 , 0x006000 ,
0x008000 , 0x00c000 ,
}
for i := range offsetCombined [:] {
if offsetExtraBits [i ] == 0 || offsetBase [i ] > 0x006000 {
continue
}
offsetCombined [i ] = uint32 (offsetExtraBits [i ]) | (offsetBase [i ] << 8 )
}
}
var codegenOrder = []uint32 {16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 }
type huffmanBitWriter struct {
writer io .Writer
bits uint64
nbits uint8
nbytes uint8
lastHuffMan bool
literalEncoding *huffmanEncoder
tmpLitEncoding *huffmanEncoder
offsetEncoding *huffmanEncoder
codegenEncoding *huffmanEncoder
err error
lastHeader int
logNewTablePenalty uint
bytes [256 + 8 ]byte
literalFreq [lengthCodesStart + 32 ]uint16
offsetFreq [32 ]uint16
codegenFreq [codegenCodeCount ]uint16
codegen [literalCount + offsetCodeCount + 1 ]uint8
}
func newHuffmanBitWriter (w io .Writer ) *huffmanBitWriter {
return &huffmanBitWriter {
writer : w ,
literalEncoding : newHuffmanEncoder (literalCount ),
tmpLitEncoding : newHuffmanEncoder (literalCount ),
codegenEncoding : newHuffmanEncoder (codegenCodeCount ),
offsetEncoding : newHuffmanEncoder (offsetCodeCount ),
}
}
func (w *huffmanBitWriter ) reset (writer io .Writer ) {
w .writer = writer
w .bits , w .nbits , w .nbytes , w .err = 0 , 0 , 0 , nil
w .lastHeader = 0
w .lastHuffMan = false
}
func (w *huffmanBitWriter ) canReuse (t *tokens ) (ok bool ) {
a := t .offHist [:offsetCodeCount ]
b := w .offsetEncoding .codes
b = b [:len (a )]
for i , v := range a {
if v != 0 && b [i ].zero () {
return false
}
}
a = t .extraHist [:literalCount -256 ]
b = w .literalEncoding .codes [256 :literalCount ]
b = b [:len (a )]
for i , v := range a {
if v != 0 && b [i ].zero () {
return false
}
}
a = t .litHist [:256 ]
b = w .literalEncoding .codes [:len (a )]
for i , v := range a {
if v != 0 && b [i ].zero () {
return false
}
}
return true
}
func (w *huffmanBitWriter ) flush () {
if w .err != nil {
w .nbits = 0
return
}
if w .lastHeader > 0 {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
}
n := w .nbytes
for w .nbits != 0 {
w .bytes [n ] = byte (w .bits )
w .bits >>= 8
if w .nbits > 8 {
w .nbits -= 8
} else {
w .nbits = 0
}
n ++
}
w .bits = 0
w .write (w .bytes [:n ])
w .nbytes = 0
}
func (w *huffmanBitWriter ) write (b []byte ) {
if w .err != nil {
return
}
_, w .err = w .writer .Write (b )
}
func (w *huffmanBitWriter ) writeBits (b int32 , nb uint8 ) {
w .bits |= uint64 (b ) << (w .nbits & 63 )
w .nbits += nb
if w .nbits >= 48 {
w .writeOutBits ()
}
}
func (w *huffmanBitWriter ) writeBytes (bytes []byte ) {
if w .err != nil {
return
}
n := w .nbytes
if w .nbits &7 != 0 {
w .err = InternalError ("writeBytes with unfinished bits" )
return
}
for w .nbits != 0 {
w .bytes [n ] = byte (w .bits )
w .bits >>= 8
w .nbits -= 8
n ++
}
if n != 0 {
w .write (w .bytes [:n ])
}
w .nbytes = 0
w .write (bytes )
}
func (w *huffmanBitWriter ) generateCodegen (numLiterals int , numOffsets int , litEnc , offEnc *huffmanEncoder ) {
for i := range w .codegenFreq {
w .codegenFreq [i ] = 0
}
codegen := w .codegen [:]
cgnl := codegen [:numLiterals ]
for i := range cgnl {
cgnl [i ] = litEnc .codes [i ].len ()
}
cgnl = codegen [numLiterals : numLiterals +numOffsets ]
for i := range cgnl {
cgnl [i ] = offEnc .codes [i ].len ()
}
codegen [numLiterals +numOffsets ] = badCode
size := codegen [0 ]
count := 1
outIndex := 0
for inIndex := 1 ; size != badCode ; inIndex ++ {
nextSize := codegen [inIndex ]
if nextSize == size {
count ++
continue
}
if size != 0 {
codegen [outIndex ] = size
outIndex ++
w .codegenFreq [size ]++
count --
for count >= 3 {
n := 6
if n > count {
n = count
}
codegen [outIndex ] = 16
outIndex ++
codegen [outIndex ] = uint8 (n - 3 )
outIndex ++
w .codegenFreq [16 ]++
count -= n
}
} else {
for count >= 11 {
n := 138
if n > count {
n = count
}
codegen [outIndex ] = 18
outIndex ++
codegen [outIndex ] = uint8 (n - 11 )
outIndex ++
w .codegenFreq [18 ]++
count -= n
}
if count >= 3 {
codegen [outIndex ] = 17
outIndex ++
codegen [outIndex ] = uint8 (count - 3 )
outIndex ++
w .codegenFreq [17 ]++
count = 0
}
}
count --
for ; count >= 0 ; count -- {
codegen [outIndex ] = size
outIndex ++
w .codegenFreq [size ]++
}
size = nextSize
count = 1
}
codegen [outIndex ] = badCode
}
func (w *huffmanBitWriter ) codegens () int {
numCodegens := len (w .codegenFreq )
for numCodegens > 4 && w .codegenFreq [codegenOrder [numCodegens -1 ]] == 0 {
numCodegens --
}
return numCodegens
}
func (w *huffmanBitWriter ) headerSize () (size , numCodegens int ) {
numCodegens = len (w .codegenFreq )
for numCodegens > 4 && w .codegenFreq [codegenOrder [numCodegens -1 ]] == 0 {
numCodegens --
}
return 3 + 5 + 5 + 4 + (3 * numCodegens ) +
w .codegenEncoding .bitLength (w .codegenFreq [:]) +
int (w .codegenFreq [16 ])*2 +
int (w .codegenFreq [17 ])*3 +
int (w .codegenFreq [18 ])*7 , numCodegens
}
func (w *huffmanBitWriter ) dynamicReuseSize (litEnc , offEnc *huffmanEncoder ) (size int ) {
size = litEnc .bitLength (w .literalFreq [:]) +
offEnc .bitLength (w .offsetFreq [:])
return size
}
func (w *huffmanBitWriter ) dynamicSize (litEnc , offEnc *huffmanEncoder , extraBits int ) (size , numCodegens int ) {
header , numCodegens := w .headerSize ()
size = header +
litEnc .bitLength (w .literalFreq [:]) +
offEnc .bitLength (w .offsetFreq [:]) +
extraBits
return size , numCodegens
}
func (w *huffmanBitWriter ) extraBitSize () int {
total := 0
for i , n := range w .literalFreq [257 :literalCount ] {
total += int (n ) * int (lengthExtraBits [i &31 ])
}
for i , n := range w .offsetFreq [:offsetCodeCount ] {
total += int (n ) * int (offsetExtraBits [i &31 ])
}
return total
}
func (w *huffmanBitWriter ) fixedSize (extraBits int ) int {
return 3 +
fixedLiteralEncoding .bitLength (w .literalFreq [:]) +
fixedOffsetEncoding .bitLength (w .offsetFreq [:]) +
extraBits
}
func (w *huffmanBitWriter ) storedSize (in []byte ) (int , bool ) {
if in == nil {
return 0 , false
}
if len (in ) <= maxStoreBlockSize {
return (len (in ) + 5 ) * 8 , true
}
return 0 , false
}
func (w *huffmanBitWriter ) writeCode (c hcode ) {
w .bits |= c .code64 () << (w .nbits & 63 )
w .nbits += c .len ()
if w .nbits >= 48 {
w .writeOutBits ()
}
}
func (w *huffmanBitWriter ) writeOutBits () {
bits := w .bits
w .bits >>= 48
w .nbits -= 48
n := w .nbytes
binary .LittleEndian .PutUint64 (w .bytes [n :], bits )
n += 6
if n >= bufferFlushSize {
if w .err != nil {
n = 0
return
}
w .write (w .bytes [:n ])
n = 0
}
w .nbytes = n
}
func (w *huffmanBitWriter ) writeDynamicHeader (numLiterals int , numOffsets int , numCodegens int , isEof bool ) {
if w .err != nil {
return
}
var firstBits int32 = 4
if isEof {
firstBits = 5
}
w .writeBits (firstBits , 3 )
w .writeBits (int32 (numLiterals -257 ), 5 )
w .writeBits (int32 (numOffsets -1 ), 5 )
w .writeBits (int32 (numCodegens -4 ), 4 )
for i := 0 ; i < numCodegens ; i ++ {
value := uint (w .codegenEncoding .codes [codegenOrder [i ]].len ())
w .writeBits (int32 (value ), 3 )
}
i := 0
for {
var codeWord = uint32 (w .codegen [i ])
i ++
if codeWord == badCode {
break
}
w .writeCode (w .codegenEncoding .codes [codeWord ])
switch codeWord {
case 16 :
w .writeBits (int32 (w .codegen [i ]), 2 )
i ++
case 17 :
w .writeBits (int32 (w .codegen [i ]), 3 )
i ++
case 18 :
w .writeBits (int32 (w .codegen [i ]), 7 )
i ++
}
}
}
func (w *huffmanBitWriter ) writeStoredHeader (length int , isEof bool ) {
if w .err != nil {
return
}
if w .lastHeader > 0 {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
}
if length == 0 && isEof {
w .writeFixedHeader (isEof )
w .writeBits (0 , 7 )
w .flush ()
return
}
var flag int32
if isEof {
flag = 1
}
w .writeBits (flag , 3 )
w .flush ()
w .writeBits (int32 (length ), 16 )
w .writeBits (int32 (^uint16 (length )), 16 )
}
func (w *huffmanBitWriter ) writeFixedHeader (isEof bool ) {
if w .err != nil {
return
}
if w .lastHeader > 0 {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
}
var value int32 = 2
if isEof {
value = 3
}
w .writeBits (value , 3 )
}
func (w *huffmanBitWriter ) writeBlock (tokens *tokens , eof bool , input []byte ) {
if w .err != nil {
return
}
tokens .AddEOB ()
if w .lastHeader > 0 {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
}
numLiterals , numOffsets := w .indexTokens (tokens , false )
w .generate ()
var extraBits int
storedSize , storable := w .storedSize (input )
if storable {
extraBits = w .extraBitSize ()
}
var literalEncoding = fixedLiteralEncoding
var offsetEncoding = fixedOffsetEncoding
var size = math .MaxInt32
if tokens .n < maxPredefinedTokens {
size = w .fixedSize (extraBits )
}
var numCodegens int
w .generateCodegen (numLiterals , numOffsets , w .literalEncoding , w .offsetEncoding )
w .codegenEncoding .generate (w .codegenFreq [:], 7 )
dynamicSize , numCodegens := w .dynamicSize (w .literalEncoding , w .offsetEncoding , extraBits )
if dynamicSize < size {
size = dynamicSize
literalEncoding = w .literalEncoding
offsetEncoding = w .offsetEncoding
}
if storable && storedSize <= size {
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
if literalEncoding == fixedLiteralEncoding {
w .writeFixedHeader (eof )
} else {
w .writeDynamicHeader (numLiterals , numOffsets , numCodegens , eof )
}
w .writeTokens (tokens .Slice (), literalEncoding .codes , offsetEncoding .codes )
}
func (w *huffmanBitWriter ) writeBlockDynamic (tokens *tokens , eof bool , input []byte , sync bool ) {
if w .err != nil {
return
}
sync = sync || eof
if sync {
tokens .AddEOB ()
}
if (w .lastHuffMan || eof ) && w .lastHeader > 0 {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
w .lastHuffMan = false
}
const fillReuse = false
if !fillReuse && w .lastHeader > 0 && !w .canReuse (tokens ) {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
}
numLiterals , numOffsets := w .indexTokens (tokens , !sync )
extraBits := 0
ssize , storable := w .storedSize (input )
const usePrefs = true
if storable || w .lastHeader > 0 {
extraBits = w .extraBitSize ()
}
var size int
if w .lastHeader > 0 {
newSize := w .lastHeader + tokens .EstimatedBits ()
newSize += int (w .literalEncoding .codes [endBlockMarker ].len ()) + newSize >>w .logNewTablePenalty
reuseSize := w .dynamicReuseSize (w .literalEncoding , w .offsetEncoding ) + extraBits
if newSize < reuseSize {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
size = newSize
w .lastHeader = 0
} else {
size = reuseSize
}
if tokens .n < maxPredefinedTokens {
if preSize := w .fixedSize (extraBits ) + 7 ; usePrefs && preSize < size {
if storable && ssize <= size {
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
w .writeFixedHeader (eof )
if !sync {
tokens .AddEOB ()
}
w .writeTokens (tokens .Slice (), fixedLiteralEncoding .codes , fixedOffsetEncoding .codes )
return
}
}
if storable && ssize <= size {
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
}
if w .lastHeader == 0 {
if fillReuse && !sync {
w .fillTokens ()
numLiterals , numOffsets = maxNumLit , maxNumDist
} else {
w .literalFreq [endBlockMarker ] = 1
}
w .generate ()
w .generateCodegen (numLiterals , numOffsets , w .literalEncoding , w .offsetEncoding )
w .codegenEncoding .generate (w .codegenFreq [:], 7 )
var numCodegens int
if fillReuse && !sync {
w .indexTokens (tokens , true )
}
size , numCodegens = w .dynamicSize (w .literalEncoding , w .offsetEncoding , extraBits )
if tokens .n < maxPredefinedTokens {
if preSize := w .fixedSize (extraBits ); usePrefs && preSize <= size {
if storable && ssize <= preSize {
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
w .writeFixedHeader (eof )
if !sync {
tokens .AddEOB ()
}
w .writeTokens (tokens .Slice (), fixedLiteralEncoding .codes , fixedOffsetEncoding .codes )
return
}
}
if storable && ssize <= size {
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
w .writeDynamicHeader (numLiterals , numOffsets , numCodegens , eof )
if !sync {
w .lastHeader , _ = w .headerSize ()
}
w .lastHuffMan = false
}
if sync {
w .lastHeader = 0
}
w .writeTokens (tokens .Slice (), w .literalEncoding .codes , w .offsetEncoding .codes )
}
func (w *huffmanBitWriter ) fillTokens () {
for i , v := range w .literalFreq [:literalCount ] {
if v == 0 {
w .literalFreq [i ] = 1
}
}
for i , v := range w .offsetFreq [:offsetCodeCount ] {
if v == 0 {
w .offsetFreq [i ] = 1
}
}
}
func (w *huffmanBitWriter ) indexTokens (t *tokens , filled bool ) (numLiterals , numOffsets int ) {
*(*[256 ]uint16 )(w .literalFreq [:]) = t .litHist
*(*[32 ]uint16 )(w .literalFreq [256 :]) = t .extraHist
w .offsetFreq = t .offHist
if t .n == 0 {
return
}
if filled {
return maxNumLit , maxNumDist
}
numLiterals = len (w .literalFreq )
for w .literalFreq [numLiterals -1 ] == 0 {
numLiterals --
}
numOffsets = len (w .offsetFreq )
for numOffsets > 0 && w .offsetFreq [numOffsets -1 ] == 0 {
numOffsets --
}
if numOffsets == 0 {
w .offsetFreq [0 ] = 1
numOffsets = 1
}
return
}
func (w *huffmanBitWriter ) generate () {
w .literalEncoding .generate (w .literalFreq [:literalCount ], 15 )
w .offsetEncoding .generate (w .offsetFreq [:offsetCodeCount ], 15 )
}
func (w *huffmanBitWriter ) writeTokens (tokens []token , leCodes , oeCodes []hcode ) {
if w .err != nil {
return
}
if len (tokens ) == 0 {
return
}
var deferEOB bool
if tokens [len (tokens )-1 ] == endBlockMarker {
tokens = tokens [:len (tokens )-1 ]
deferEOB = true
}
lits := leCodes [:256 ]
offs := oeCodes [:32 ]
lengths := leCodes [lengthCodesStart :]
lengths = lengths [:32 ]
bits , nbits , nbytes := w .bits , w .nbits , w .nbytes
for _ , t := range tokens {
if t < 256 {
c := lits [t ]
bits |= c .code64 () << (nbits & 63 )
nbits += c .len ()
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
continue
}
length := t .length ()
lengthCode := lengthCode (length ) & 31
if false {
w .writeCode (lengths [lengthCode ])
} else {
c := lengths [lengthCode ]
bits |= c .code64 () << (nbits & 63 )
nbits += c .len ()
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
}
if lengthCode >= lengthExtraBitsMinCode {
extraLengthBits := lengthExtraBits [lengthCode ]
extraLength := int32 (length - lengthBase [lengthCode ])
bits |= uint64 (extraLength ) << (nbits & 63 )
nbits += extraLengthBits
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
}
offset := t .offset ()
offsetCode := (offset >> 16 ) & 31
if false {
w .writeCode (offs [offsetCode ])
} else {
c := offs [offsetCode ]
bits |= c .code64 () << (nbits & 63 )
nbits += c .len ()
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
}
if offsetCode >= offsetExtraBitsMinCode {
offsetComb := offsetCombined [offsetCode ]
bits |= uint64 ((offset -(offsetComb >>8 ))&matchOffsetOnlyMask ) << (nbits & 63 )
nbits += uint8 (offsetComb )
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
}
}
w .bits , w .nbits , w .nbytes = bits , nbits , nbytes
if deferEOB {
w .writeCode (leCodes [endBlockMarker ])
}
}
var huffOffset *huffmanEncoder
func init () {
w := newHuffmanBitWriter (nil )
w .offsetFreq [0 ] = 1
huffOffset = newHuffmanEncoder (offsetCodeCount )
huffOffset .generate (w .offsetFreq [:offsetCodeCount ], 15 )
}
func (w *huffmanBitWriter ) writeBlockHuff (eof bool , input []byte , sync bool ) {
if w .err != nil {
return
}
for i := range w .literalFreq [:] {
w .literalFreq [i ] = 0
}
if !w .lastHuffMan {
for i := range w .offsetFreq [:] {
w .offsetFreq [i ] = 0
}
}
const numLiterals = endBlockMarker + 1
const numOffsets = 1
const guessHeaderSizeBits = 70 * 8
histogram (input , w .literalFreq [:numLiterals ])
ssize , storable := w .storedSize (input )
if storable && len (input ) > 1024 {
abs := float64 (0 )
avg := float64 (len (input )) / 256
max := float64 (len (input ) * 2 )
for _ , v := range w .literalFreq [:256 ] {
diff := float64 (v ) - avg
abs += diff * diff
if abs > max {
break
}
}
if abs < max {
if debugDeflate {
fmt .Println ("stored" , abs , "<" , max )
}
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
}
w .literalFreq [endBlockMarker ] = 1
w .tmpLitEncoding .generate (w .literalFreq [:numLiterals ], 15 )
estBits := w .tmpLitEncoding .canReuseBits (w .literalFreq [:numLiterals ])
if estBits < math .MaxInt32 {
estBits += w .lastHeader
if w .lastHeader == 0 {
estBits += guessHeaderSizeBits
}
estBits += estBits >> w .logNewTablePenalty
}
if storable && ssize <= estBits {
if debugDeflate {
fmt .Println ("stored," , ssize , "<=" , estBits )
}
w .writeStoredHeader (len (input ), eof )
w .writeBytes (input )
return
}
if w .lastHeader > 0 {
reuseSize := w .literalEncoding .canReuseBits (w .literalFreq [:256 ])
if estBits < reuseSize {
if debugDeflate {
fmt .Println ("NOT reusing, reuse:" , reuseSize /8 , "> new:" , estBits /8 , "header est:" , w .lastHeader /8 , "bytes" )
}
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
} else if debugDeflate {
fmt .Println ("reusing, reuse:" , reuseSize /8 , "> new:" , estBits /8 , "- header est:" , w .lastHeader /8 )
}
}
count := 0
if w .lastHeader == 0 {
w .literalEncoding , w .tmpLitEncoding = w .tmpLitEncoding , w .literalEncoding
w .generateCodegen (numLiterals , numOffsets , w .literalEncoding , huffOffset )
w .codegenEncoding .generate (w .codegenFreq [:], 7 )
numCodegens := w .codegens ()
w .writeDynamicHeader (numLiterals , numOffsets , numCodegens , eof )
w .lastHuffMan = true
w .lastHeader , _ = w .headerSize ()
if debugDeflate {
count += w .lastHeader
fmt .Println ("header:" , count /8 )
}
}
encoding := w .literalEncoding .codes [:256 ]
bits , nbits , nbytes := w .bits , w .nbits , w .nbytes
if debugDeflate {
count -= int (nbytes )*8 + int (nbits )
}
for len (input ) > 3 {
if nbits >= 8 {
n := nbits >> 3
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= (n * 8 ) & 63
nbits -= n * 8
nbytes += n
}
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
if debugDeflate {
count += int (nbytes ) * 8
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
a , b := encoding [input [0 ]], encoding [input [1 ]]
bits |= a .code64 () << (nbits & 63 )
bits |= b .code64 () << ((nbits + a .len ()) & 63 )
c := encoding [input [2 ]]
nbits += b .len () + a .len ()
bits |= c .code64 () << (nbits & 63 )
nbits += c .len ()
input = input [3 :]
}
for _ , t := range input {
if nbits >= 48 {
binary .LittleEndian .PutUint64 (w .bytes [nbytes :], bits )
bits >>= 48
nbits -= 48
nbytes += 6
if nbytes >= bufferFlushSize {
if w .err != nil {
nbytes = 0
return
}
if debugDeflate {
count += int (nbytes ) * 8
}
_, w .err = w .writer .Write (w .bytes [:nbytes ])
nbytes = 0
}
}
c := encoding [t ]
bits |= c .code64 () << (nbits & 63 )
nbits += c .len ()
if debugDeflate {
count += int (c .len ())
}
}
w .bits , w .nbits , w .nbytes = bits , nbits , nbytes
if debugDeflate {
nb := count + int (nbytes )*8 + int (nbits )
fmt .Println ("wrote" , nb , "bits," , nb /8 , "bytes." )
}
if w .nbits >= 48 {
w .writeOutBits ()
}
if eof || sync {
w .writeCode (w .literalEncoding .codes [endBlockMarker ])
w .lastHeader = 0
w .lastHuffMan = false
}
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .