package hpack
import (
)
var bufPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
func ( io.Writer, []byte) (int, error) {
:= bufPool.Get().(*bytes.Buffer)
.Reset()
defer bufPool.Put()
if := huffmanDecode(, 0, ); != nil {
return 0,
}
return .Write(.Bytes())
}
func ( []byte) (string, error) {
:= bufPool.Get().(*bytes.Buffer)
.Reset()
defer bufPool.Put()
if := huffmanDecode(, 0, ); != nil {
return "",
}
return .String(), nil
}
var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
func ( *bytes.Buffer, int, []byte) error {
:= getRootHuffmanNode()
:=
, , := uint(0), uint8(0), uint8(0)
for , := range {
= <<8 | uint()
+= 8
+= 8
for >= 8 {
:= byte( >> ( - 8))
= .children[]
if == nil {
return ErrInvalidHuffman
}
if .children == nil {
if != 0 && .Len() == {
return ErrStringLength
}
.WriteByte(.sym)
-= .codeLen
=
=
} else {
-= 8
}
}
}
for > 0 {
= .children[byte(<<(8-))]
if == nil {
return ErrInvalidHuffman
}
if .children != nil || .codeLen > {
break
}
if != 0 && .Len() == {
return ErrStringLength
}
.WriteByte(.sym)
-= .codeLen
=
=
}
if > 7 {
return ErrInvalidHuffman
}
if := uint(1<< - 1); & != {
return ErrInvalidHuffman
}
return nil
}
type incomparable [0]func()
type node struct {
_ incomparable
children *[256]*node
codeLen uint8
sym byte
}
func () *node {
return &node{children: new([256]*node)}
}
var (
buildRootOnce sync.Once
lazyRootHuffmanNode *node
)
func () *node {
buildRootOnce.Do(buildRootHuffmanNode)
return lazyRootHuffmanNode
}
func () {
if len(huffmanCodes) != 256 {
panic("unexpected size")
}
lazyRootHuffmanNode = newInternalNode()
for , := range huffmanCodes {
addDecoderNode(byte(), , huffmanCodeLen[])
}
}
func ( byte, uint32, uint8) {
:= lazyRootHuffmanNode
for > 8 {
-= 8
:= uint8( >> )
if .children[] == nil {
.children[] = newInternalNode()
}
= .children[]
}
:= 8 -
, := int(uint8(<<)), int(1<<)
for := ; < +; ++ {
.children[] = &node{sym: , codeLen: }
}
}
func ( []byte, string) []byte {
:= uint8(8)
for := 0; < len(); ++ {
if == 8 {
= append(, 0)
}
, = appendByteToHuffmanCode(, , [])
}
if < 8 {
:= uint32(0x3fffffff)
:= uint8(30)
:= uint8( >> ( - ))
[len()-1] |=
}
return
}
func ( string) uint64 {
:= uint64(0)
for := 0; < len(); ++ {
+= uint64(huffmanCodeLen[[]])
}
return ( + 7) / 8
}
func ( []byte, uint8, byte) ([]byte, uint8) {
:= huffmanCodes[]
:= huffmanCodeLen[]
for {
if > {
:= uint8( << ( - ))
[len()-1] |=
-=
break
}
:= uint8( >> ( - ))
[len()-1] |=
-=
= 8
if == 0 {
break
}
= append(, 0)
}
return ,
}