// Copyright 2014 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package hpackimport ()varbufPool = sync.Pool{New: func() interface{} { returnnew(bytes.Buffer) },}// HuffmanDecode decodes the string in v and writes the expanded// result to w, returning the number of bytes written to w and the// Write call's return value. At most one Write call is made.func ( io.Writer, []byte) (int, error) { := bufPool.Get().(*bytes.Buffer) .Reset()deferbufPool.Put()if := huffmanDecode(, 0, ); != nil {return0, }return .Write(.Bytes())}// HuffmanDecodeToString decodes the string in v.func ( []byte) (string, error) { := bufPool.Get().(*bytes.Buffer) .Reset()deferbufPool.Put()if := huffmanDecode(, 0, ); != nil {return"", }return .String(), nil}// ErrInvalidHuffman is returned for errors found decoding// Huffman-encoded strings.varErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")// huffmanDecode decodes v to buf.// If maxLen is greater than 0, attempts to write more to buf than// maxLen bytes will return ErrStringLength.func ( *bytes.Buffer, int, []byte) error { := getRootHuffmanNode() := // cur is the bit buffer that has not been fed into n. // cbits is the number of low order bits in cur that are valid. // sbits is the number of bits of the symbol prefix being decoded. , , := uint(0), uint8(0), uint8(0)for , := range { = <<8 | uint() += 8 += 8for >= 8 { := byte( >> ( - 8)) = .children[]if == nil {returnErrInvalidHuffman }if .children == nil {if != 0 && .Len() == {returnErrStringLength } .WriteByte(.sym) -= .codeLen = = } else { -= 8 } } }for > 0 { = .children[byte(<<(8-))]if == nil {returnErrInvalidHuffman }if .children != nil || .codeLen > {break }if != 0 && .Len() == {returnErrStringLength } .WriteByte(.sym) -= .codeLen = = }if > 7 {// Either there was an incomplete symbol, or overlong padding. // Both are decoding errors per RFC 7541 section 5.2.returnErrInvalidHuffman }if := uint(1<< - 1); & != {// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.returnErrInvalidHuffman }returnnil}// incomparable is a zero-width, non-comparable type. Adding it to a struct// makes that struct also non-comparable, and generally doesn't add// any size (as long as it's first).typeincomparable [0]func()typenodestruct { _ incomparable// children is non-nil for internal nodeschildren *[256]*node// The following are only valid if children is nil:codeLenuint8// number of bits that led to the output of symsymbyte// output symbol}func () *node {return &node{children: new([256]*node)}}var (buildRootOncesync.OncelazyRootHuffmanNode *node)func () *node {buildRootOnce.Do(buildRootHuffmanNode)returnlazyRootHuffmanNode}func () {iflen(huffmanCodes) != 256 {panic("unexpected size") }lazyRootHuffmanNode = newInternalNode()// allocate a leaf node for each of the 256 symbols := new([256]node)for , := rangehuffmanCodes { := huffmanCodeLen[] := lazyRootHuffmanNodefor > 8 { -= 8 := uint8( >> )if .children[] == nil { .children[] = newInternalNode() } = .children[] } := 8 - , := int(uint8(<<)), int(1<<) [].sym = byte() [].codeLen = for := ; < +; ++ { .children[] = &[] } }}// AppendHuffmanString appends s, as encoded in Huffman codes, to dst// and returns the extended buffer.func ( []byte, string) []byte { := uint8(8)for := 0; < len(); ++ {if == 8 { = append(, 0) } , = appendByteToHuffmanCode(, , []) }if < 8 {// special EOS symbol := uint32(0x3fffffff) := uint8(30) := uint8( >> ( - )) [len()-1] |= }return}// HuffmanEncodeLength returns the number of bytes required to encode// s in Huffman codes. The result is round up to byte boundary.func ( string) uint64 { := uint64(0)for := 0; < len(); ++ { += uint64(huffmanCodeLen[[]]) }return ( + 7) / 8}// appendByteToHuffmanCode appends Huffman code for c to dst and// returns the extended buffer and the remaining bits in the last// element. The appending is not byte aligned and the remaining bits// in the last element of dst is given in rembits.func ( []byte, uint8, byte) ([]byte, uint8) { := huffmanCodes[] := huffmanCodeLen[]for {if > { := uint8( << ( - )) [len()-1] |= -= break } := uint8( >> ( - )) [len()-1] |= -= = 8if == 0 {break } = append(, 0) }return , }
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)