Add a new generic container registry client via a new `container` package. Use this to create a command line utility as well as a new upload target for container registries. The code uses the github.com/containers/* project and packages to interact with container registires that is also used by skopeo, podman et al. One if the dependencies is `proglottis/gpgme` that is using cgo to bind libgpgme, so we have to add the corresponding devel package to the BuildRequires as well as installing it on CI. Checks will follow later via an integration test.
1283 lines
32 KiB
Go
1283 lines
32 KiB
Go
// Code generated by go generate gen_inflate.go. DO NOT EDIT.
|
|
|
|
package flate
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"math/bits"
|
|
"strings"
|
|
)
|
|
|
|
// Decode a single Huffman block from f.
|
|
// hl and hd are the Huffman states for the lit/length values
|
|
// and the distance values, respectively. If hd == nil, using the
|
|
// fixed distance encoding associated with fixed Huffman blocks.
|
|
func (f *decompressor) huffmanBytesBuffer() {
|
|
const (
|
|
stateInit = iota // Zero value must be stateInit
|
|
stateDict
|
|
)
|
|
fr := f.r.(*bytes.Buffer)
|
|
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
fnb, fb := f.nb, f.b
|
|
|
|
switch f.stepState {
|
|
case stateInit:
|
|
goto readLiteral
|
|
case stateDict:
|
|
goto copyHistory
|
|
}
|
|
|
|
readLiteral:
|
|
// Read literal and/or (length, distance) according to RFC section 3.2.3.
|
|
{
|
|
var v int
|
|
{
|
|
// Inlined v, err := f.huffSym(f.hl)
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hl.maxRead)
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
v = int(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var length int
|
|
switch {
|
|
case v < 256:
|
|
f.dict.writeByte(byte(v))
|
|
if f.dict.availWrite() == 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBytesBuffer
|
|
f.stepState = stateInit
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
case v == 256:
|
|
f.b, f.nb = fb, fnb
|
|
f.finishBlock()
|
|
return
|
|
// otherwise, reference to older data
|
|
case v < 265:
|
|
length = v - (257 - 3)
|
|
case v < maxNumLit:
|
|
val := decCodeToLen[(v - 257)]
|
|
length = int(val.length) + 3
|
|
n := uint(val.extra)
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits n>0:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
length += int(fb & bitMask32[n])
|
|
fb >>= n & regSizeMaskUint32
|
|
fnb -= n
|
|
default:
|
|
if debugDecode {
|
|
fmt.Println(v, ">= maxNumLit")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
|
|
var dist uint32
|
|
if f.hd == nil {
|
|
for fnb < 5 {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<5:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
|
|
fb >>= 5
|
|
fnb -= 5
|
|
} else {
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hd.maxRead)
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
dist = uint32(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case dist < 4:
|
|
dist++
|
|
case dist < maxNumDist:
|
|
nb := uint(dist-2) >> 1
|
|
// have 1 bit in bottom of dist, need nb more.
|
|
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
|
for fnb < nb {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<nb:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
extra |= fb & bitMask32[nb]
|
|
fb >>= nb & regSizeMaskUint32
|
|
fnb -= nb
|
|
dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
|
|
// slower: dist = bitMask32[nb+1] + 2 + extra
|
|
default:
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist too big:", dist, maxNumDist)
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
// No check on length; encoding can be prescient.
|
|
if dist > uint32(f.dict.histSize()) {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
f.copyLen, f.copyDist = length, int(dist)
|
|
goto copyHistory
|
|
}
|
|
|
|
copyHistory:
|
|
// Perform a backwards copy according to RFC section 3.2.3.
|
|
{
|
|
cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
|
|
if cnt == 0 {
|
|
cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
|
|
}
|
|
f.copyLen -= cnt
|
|
|
|
if f.dict.availWrite() == 0 || f.copyLen > 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBytesBuffer // We need to continue this work
|
|
f.stepState = stateDict
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
}
|
|
// Not reached
|
|
}
|
|
|
|
// Decode a single Huffman block from f.
|
|
// hl and hd are the Huffman states for the lit/length values
|
|
// and the distance values, respectively. If hd == nil, using the
|
|
// fixed distance encoding associated with fixed Huffman blocks.
|
|
func (f *decompressor) huffmanBytesReader() {
|
|
const (
|
|
stateInit = iota // Zero value must be stateInit
|
|
stateDict
|
|
)
|
|
fr := f.r.(*bytes.Reader)
|
|
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
fnb, fb := f.nb, f.b
|
|
|
|
switch f.stepState {
|
|
case stateInit:
|
|
goto readLiteral
|
|
case stateDict:
|
|
goto copyHistory
|
|
}
|
|
|
|
readLiteral:
|
|
// Read literal and/or (length, distance) according to RFC section 3.2.3.
|
|
{
|
|
var v int
|
|
{
|
|
// Inlined v, err := f.huffSym(f.hl)
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hl.maxRead)
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
v = int(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var length int
|
|
switch {
|
|
case v < 256:
|
|
f.dict.writeByte(byte(v))
|
|
if f.dict.availWrite() == 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBytesReader
|
|
f.stepState = stateInit
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
case v == 256:
|
|
f.b, f.nb = fb, fnb
|
|
f.finishBlock()
|
|
return
|
|
// otherwise, reference to older data
|
|
case v < 265:
|
|
length = v - (257 - 3)
|
|
case v < maxNumLit:
|
|
val := decCodeToLen[(v - 257)]
|
|
length = int(val.length) + 3
|
|
n := uint(val.extra)
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits n>0:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
length += int(fb & bitMask32[n])
|
|
fb >>= n & regSizeMaskUint32
|
|
fnb -= n
|
|
default:
|
|
if debugDecode {
|
|
fmt.Println(v, ">= maxNumLit")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
|
|
var dist uint32
|
|
if f.hd == nil {
|
|
for fnb < 5 {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<5:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
|
|
fb >>= 5
|
|
fnb -= 5
|
|
} else {
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hd.maxRead)
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
dist = uint32(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case dist < 4:
|
|
dist++
|
|
case dist < maxNumDist:
|
|
nb := uint(dist-2) >> 1
|
|
// have 1 bit in bottom of dist, need nb more.
|
|
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
|
for fnb < nb {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<nb:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
extra |= fb & bitMask32[nb]
|
|
fb >>= nb & regSizeMaskUint32
|
|
fnb -= nb
|
|
dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
|
|
// slower: dist = bitMask32[nb+1] + 2 + extra
|
|
default:
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist too big:", dist, maxNumDist)
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
// No check on length; encoding can be prescient.
|
|
if dist > uint32(f.dict.histSize()) {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
f.copyLen, f.copyDist = length, int(dist)
|
|
goto copyHistory
|
|
}
|
|
|
|
copyHistory:
|
|
// Perform a backwards copy according to RFC section 3.2.3.
|
|
{
|
|
cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
|
|
if cnt == 0 {
|
|
cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
|
|
}
|
|
f.copyLen -= cnt
|
|
|
|
if f.dict.availWrite() == 0 || f.copyLen > 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBytesReader // We need to continue this work
|
|
f.stepState = stateDict
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
}
|
|
// Not reached
|
|
}
|
|
|
|
// Decode a single Huffman block from f.
|
|
// hl and hd are the Huffman states for the lit/length values
|
|
// and the distance values, respectively. If hd == nil, using the
|
|
// fixed distance encoding associated with fixed Huffman blocks.
|
|
func (f *decompressor) huffmanBufioReader() {
|
|
const (
|
|
stateInit = iota // Zero value must be stateInit
|
|
stateDict
|
|
)
|
|
fr := f.r.(*bufio.Reader)
|
|
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
fnb, fb := f.nb, f.b
|
|
|
|
switch f.stepState {
|
|
case stateInit:
|
|
goto readLiteral
|
|
case stateDict:
|
|
goto copyHistory
|
|
}
|
|
|
|
readLiteral:
|
|
// Read literal and/or (length, distance) according to RFC section 3.2.3.
|
|
{
|
|
var v int
|
|
{
|
|
// Inlined v, err := f.huffSym(f.hl)
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hl.maxRead)
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
v = int(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var length int
|
|
switch {
|
|
case v < 256:
|
|
f.dict.writeByte(byte(v))
|
|
if f.dict.availWrite() == 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBufioReader
|
|
f.stepState = stateInit
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
case v == 256:
|
|
f.b, f.nb = fb, fnb
|
|
f.finishBlock()
|
|
return
|
|
// otherwise, reference to older data
|
|
case v < 265:
|
|
length = v - (257 - 3)
|
|
case v < maxNumLit:
|
|
val := decCodeToLen[(v - 257)]
|
|
length = int(val.length) + 3
|
|
n := uint(val.extra)
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits n>0:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
length += int(fb & bitMask32[n])
|
|
fb >>= n & regSizeMaskUint32
|
|
fnb -= n
|
|
default:
|
|
if debugDecode {
|
|
fmt.Println(v, ">= maxNumLit")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
|
|
var dist uint32
|
|
if f.hd == nil {
|
|
for fnb < 5 {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<5:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
|
|
fb >>= 5
|
|
fnb -= 5
|
|
} else {
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hd.maxRead)
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
dist = uint32(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case dist < 4:
|
|
dist++
|
|
case dist < maxNumDist:
|
|
nb := uint(dist-2) >> 1
|
|
// have 1 bit in bottom of dist, need nb more.
|
|
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
|
for fnb < nb {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<nb:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
extra |= fb & bitMask32[nb]
|
|
fb >>= nb & regSizeMaskUint32
|
|
fnb -= nb
|
|
dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
|
|
// slower: dist = bitMask32[nb+1] + 2 + extra
|
|
default:
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist too big:", dist, maxNumDist)
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
// No check on length; encoding can be prescient.
|
|
if dist > uint32(f.dict.histSize()) {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
f.copyLen, f.copyDist = length, int(dist)
|
|
goto copyHistory
|
|
}
|
|
|
|
copyHistory:
|
|
// Perform a backwards copy according to RFC section 3.2.3.
|
|
{
|
|
cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
|
|
if cnt == 0 {
|
|
cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
|
|
}
|
|
f.copyLen -= cnt
|
|
|
|
if f.dict.availWrite() == 0 || f.copyLen > 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanBufioReader // We need to continue this work
|
|
f.stepState = stateDict
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
}
|
|
// Not reached
|
|
}
|
|
|
|
// Decode a single Huffman block from f.
|
|
// hl and hd are the Huffman states for the lit/length values
|
|
// and the distance values, respectively. If hd == nil, using the
|
|
// fixed distance encoding associated with fixed Huffman blocks.
|
|
func (f *decompressor) huffmanStringsReader() {
|
|
const (
|
|
stateInit = iota // Zero value must be stateInit
|
|
stateDict
|
|
)
|
|
fr := f.r.(*strings.Reader)
|
|
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
fnb, fb := f.nb, f.b
|
|
|
|
switch f.stepState {
|
|
case stateInit:
|
|
goto readLiteral
|
|
case stateDict:
|
|
goto copyHistory
|
|
}
|
|
|
|
readLiteral:
|
|
// Read literal and/or (length, distance) according to RFC section 3.2.3.
|
|
{
|
|
var v int
|
|
{
|
|
// Inlined v, err := f.huffSym(f.hl)
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hl.maxRead)
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
v = int(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var length int
|
|
switch {
|
|
case v < 256:
|
|
f.dict.writeByte(byte(v))
|
|
if f.dict.availWrite() == 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanStringsReader
|
|
f.stepState = stateInit
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
case v == 256:
|
|
f.b, f.nb = fb, fnb
|
|
f.finishBlock()
|
|
return
|
|
// otherwise, reference to older data
|
|
case v < 265:
|
|
length = v - (257 - 3)
|
|
case v < maxNumLit:
|
|
val := decCodeToLen[(v - 257)]
|
|
length = int(val.length) + 3
|
|
n := uint(val.extra)
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits n>0:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
length += int(fb & bitMask32[n])
|
|
fb >>= n & regSizeMaskUint32
|
|
fnb -= n
|
|
default:
|
|
if debugDecode {
|
|
fmt.Println(v, ">= maxNumLit")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
|
|
var dist uint32
|
|
if f.hd == nil {
|
|
for fnb < 5 {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<5:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
|
|
fb >>= 5
|
|
fnb -= 5
|
|
} else {
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hd.maxRead)
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
dist = uint32(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case dist < 4:
|
|
dist++
|
|
case dist < maxNumDist:
|
|
nb := uint(dist-2) >> 1
|
|
// have 1 bit in bottom of dist, need nb more.
|
|
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
|
for fnb < nb {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<nb:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
extra |= fb & bitMask32[nb]
|
|
fb >>= nb & regSizeMaskUint32
|
|
fnb -= nb
|
|
dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
|
|
// slower: dist = bitMask32[nb+1] + 2 + extra
|
|
default:
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist too big:", dist, maxNumDist)
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
// No check on length; encoding can be prescient.
|
|
if dist > uint32(f.dict.histSize()) {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
f.copyLen, f.copyDist = length, int(dist)
|
|
goto copyHistory
|
|
}
|
|
|
|
copyHistory:
|
|
// Perform a backwards copy according to RFC section 3.2.3.
|
|
{
|
|
cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
|
|
if cnt == 0 {
|
|
cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
|
|
}
|
|
f.copyLen -= cnt
|
|
|
|
if f.dict.availWrite() == 0 || f.copyLen > 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanStringsReader // We need to continue this work
|
|
f.stepState = stateDict
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
}
|
|
// Not reached
|
|
}
|
|
|
|
// Decode a single Huffman block from f.
|
|
// hl and hd are the Huffman states for the lit/length values
|
|
// and the distance values, respectively. If hd == nil, using the
|
|
// fixed distance encoding associated with fixed Huffman blocks.
|
|
func (f *decompressor) huffmanGenericReader() {
|
|
const (
|
|
stateInit = iota // Zero value must be stateInit
|
|
stateDict
|
|
)
|
|
fr := f.r.(Reader)
|
|
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
fnb, fb := f.nb, f.b
|
|
|
|
switch f.stepState {
|
|
case stateInit:
|
|
goto readLiteral
|
|
case stateDict:
|
|
goto copyHistory
|
|
}
|
|
|
|
readLiteral:
|
|
// Read literal and/or (length, distance) according to RFC section 3.2.3.
|
|
{
|
|
var v int
|
|
{
|
|
// Inlined v, err := f.huffSym(f.hl)
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hl.maxRead)
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
v = int(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var length int
|
|
switch {
|
|
case v < 256:
|
|
f.dict.writeByte(byte(v))
|
|
if f.dict.availWrite() == 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanGenericReader
|
|
f.stepState = stateInit
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
case v == 256:
|
|
f.b, f.nb = fb, fnb
|
|
f.finishBlock()
|
|
return
|
|
// otherwise, reference to older data
|
|
case v < 265:
|
|
length = v - (257 - 3)
|
|
case v < maxNumLit:
|
|
val := decCodeToLen[(v - 257)]
|
|
length = int(val.length) + 3
|
|
n := uint(val.extra)
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits n>0:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
length += int(fb & bitMask32[n])
|
|
fb >>= n & regSizeMaskUint32
|
|
fnb -= n
|
|
default:
|
|
if debugDecode {
|
|
fmt.Println(v, ">= maxNumLit")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
|
|
var dist uint32
|
|
if f.hd == nil {
|
|
for fnb < 5 {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<5:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
|
|
fb >>= 5
|
|
fnb -= 5
|
|
} else {
|
|
// Since a huffmanDecoder can be empty or be composed of a degenerate tree
|
|
// with single element, huffSym must error on these two edge cases. In both
|
|
// cases, the chunks slice will be 0 for the invalid sequence, leading it
|
|
// satisfy the n == 0 check below.
|
|
n := uint(f.hd.maxRead)
|
|
// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
|
|
// but is smart enough to keep local variables in registers, so use nb and b,
|
|
// inline call to moreBits and reassign b,nb back to f on return.
|
|
for {
|
|
for fnb < n {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
f.err = noEOF(err)
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
|
|
n = uint(chunk & huffmanCountMask)
|
|
if n > huffmanChunkBits {
|
|
chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
|
|
n = uint(chunk & huffmanCountMask)
|
|
}
|
|
if n <= fnb {
|
|
if n == 0 {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("huffsym: n==0")
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
fb = fb >> (n & regSizeMaskUint32)
|
|
fnb = fnb - n
|
|
dist = uint32(chunk >> huffmanValueShift)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case dist < 4:
|
|
dist++
|
|
case dist < maxNumDist:
|
|
nb := uint(dist-2) >> 1
|
|
// have 1 bit in bottom of dist, need nb more.
|
|
extra := (dist & 1) << (nb & regSizeMaskUint32)
|
|
for fnb < nb {
|
|
c, err := fr.ReadByte()
|
|
if err != nil {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("morebits f.nb<nb:", err)
|
|
}
|
|
f.err = err
|
|
return
|
|
}
|
|
f.roffset++
|
|
fb |= uint32(c) << (fnb & regSizeMaskUint32)
|
|
fnb += 8
|
|
}
|
|
extra |= fb & bitMask32[nb]
|
|
fb >>= nb & regSizeMaskUint32
|
|
fnb -= nb
|
|
dist = 1<<((nb+1)®SizeMaskUint32) + 1 + extra
|
|
// slower: dist = bitMask32[nb+1] + 2 + extra
|
|
default:
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist too big:", dist, maxNumDist)
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
// No check on length; encoding can be prescient.
|
|
if dist > uint32(f.dict.histSize()) {
|
|
f.b, f.nb = fb, fnb
|
|
if debugDecode {
|
|
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
|
|
}
|
|
f.err = CorruptInputError(f.roffset)
|
|
return
|
|
}
|
|
|
|
f.copyLen, f.copyDist = length, int(dist)
|
|
goto copyHistory
|
|
}
|
|
|
|
copyHistory:
|
|
// Perform a backwards copy according to RFC section 3.2.3.
|
|
{
|
|
cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
|
|
if cnt == 0 {
|
|
cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
|
|
}
|
|
f.copyLen -= cnt
|
|
|
|
if f.dict.availWrite() == 0 || f.copyLen > 0 {
|
|
f.toRead = f.dict.readFlush()
|
|
f.step = (*decompressor).huffmanGenericReader // We need to continue this work
|
|
f.stepState = stateDict
|
|
f.b, f.nb = fb, fnb
|
|
return
|
|
}
|
|
goto readLiteral
|
|
}
|
|
// Not reached
|
|
}
|
|
|
|
func (f *decompressor) huffmanBlockDecoder() func() {
|
|
switch f.r.(type) {
|
|
case *bytes.Buffer:
|
|
return f.huffmanBytesBuffer
|
|
case *bytes.Reader:
|
|
return f.huffmanBytesReader
|
|
case *bufio.Reader:
|
|
return f.huffmanBufioReader
|
|
case *strings.Reader:
|
|
return f.huffmanStringsReader
|
|
case Reader:
|
|
return f.huffmanGenericReader
|
|
default:
|
|
return f.huffmanGenericReader
|
|
}
|
|
}
|