github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/hpack/huffman.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package hpack 6 7 import ( 8 "bytes" 9 "errors" 10 "io" 11 "sync" 12 ) 13 14 var bufPool = sync.Pool{ 15 New: func() interface{} { return new(bytes.Buffer) }, 16 } 17 18 // HuffmanDecode decodes the string in v and writes the expanded 19 // result to w, returning the number of bytes written to w and the 20 // Write call's return value. At most one Write call is made. 21 func HuffmanDecode(w io.Writer, v []byte) (int, error) { 22 buf := bufPool.Get().(*bytes.Buffer) 23 buf.Reset() 24 defer bufPool.Put(buf) 25 if err := huffmanDecode(buf, 0, v); err != nil { 26 return 0, err 27 } 28 return w.Write(buf.Bytes()) 29 } 30 31 // HuffmanDecodeToString decodes the string in v. 32 func HuffmanDecodeToString(v []byte) (string, error) { 33 buf := bufPool.Get().(*bytes.Buffer) 34 buf.Reset() 35 defer bufPool.Put(buf) 36 if err := huffmanDecode(buf, 0, v); err != nil { 37 return "", err 38 } 39 return buf.String(), nil 40 } 41 42 // ErrInvalidHuffman is returned for errors found decoding 43 // Huffman-encoded strings. 44 var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") 45 46 // huffmanDecode decodes v to buf. 47 // If maxLen is greater than 0, attempts to write more to buf than 48 // maxLen bytes will return ErrStringLength. 49 func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { 50 n := rootHuffmanNode 51 cur, nbits := uint(0), uint8(0) 52 for _, b := range v { 53 cur = cur<<8 | uint(b) 54 nbits += 8 55 for nbits >= 8 { 56 idx := byte(cur >> (nbits - 8)) 57 n = n.children[idx] 58 if n == nil { 59 return ErrInvalidHuffman 60 } 61 if n.children == nil { 62 if maxLen != 0 && buf.Len() == maxLen { 63 return ErrStringLength 64 } 65 buf.WriteByte(n.sym) 66 nbits -= n.codeLen 67 n = rootHuffmanNode 68 } else { 69 nbits -= 8 70 } 71 } 72 } 73 for nbits > 0 { 74 n = n.children[byte(cur<<(8-nbits))] 75 if n.children != nil || n.codeLen > nbits { 76 break 77 } 78 buf.WriteByte(n.sym) 79 nbits -= n.codeLen 80 n = rootHuffmanNode 81 } 82 return nil 83 } 84 85 type node struct { 86 // children is non-nil for internal nodes 87 children []*node 88 89 // The following are only valid if children is nil: 90 codeLen uint8 // number of bits that led to the output of sym 91 sym byte // output symbol 92 } 93 94 func newInternalNode() *node { 95 return &node{children: make([]*node, 256)} 96 } 97 98 var rootHuffmanNode = newInternalNode() 99 100 func init() { 101 if len(huffmanCodes) != 256 { 102 panic("unexpected size") 103 } 104 for i, code := range huffmanCodes { 105 addDecoderNode(byte(i), code, huffmanCodeLen[i]) 106 } 107 } 108 109 func addDecoderNode(sym byte, code uint32, codeLen uint8) { 110 cur := rootHuffmanNode 111 for codeLen > 8 { 112 codeLen -= 8 113 i := uint8(code >> codeLen) 114 if cur.children[i] == nil { 115 cur.children[i] = newInternalNode() 116 } 117 cur = cur.children[i] 118 } 119 shift := 8 - codeLen 120 start, end := int(uint8(code<<shift)), int(1<<shift) 121 for i := start; i < start+end; i++ { 122 cur.children[i] = &node{sym: sym, codeLen: codeLen} 123 } 124 } 125 126 // AppendHuffmanString appends s, as encoded in Huffman codes, to dst 127 // and returns the extended buffer. 128 func AppendHuffmanString(dst []byte, s string) []byte { 129 rembits := uint8(8) 130 131 for i := 0; i < len(s); i++ { 132 if rembits == 8 { 133 dst = append(dst, 0) 134 } 135 dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i]) 136 } 137 138 if rembits < 8 { 139 // special EOS symbol 140 code := uint32(0x3fffffff) 141 nbits := uint8(30) 142 143 t := uint8(code >> (nbits - rembits)) 144 dst[len(dst)-1] |= t 145 } 146 147 return dst 148 } 149 150 // HuffmanEncodeLength returns the number of bytes required to encode 151 // s in Huffman codes. The result is round up to byte boundary. 152 func HuffmanEncodeLength(s string) uint64 { 153 n := uint64(0) 154 for i := 0; i < len(s); i++ { 155 n += uint64(huffmanCodeLen[s[i]]) 156 } 157 return (n + 7) / 8 158 } 159 160 // appendByteToHuffmanCode appends Huffman code for c to dst and 161 // returns the extended buffer and the remaining bits in the last 162 // element. The appending is not byte aligned and the remaining bits 163 // in the last element of dst is given in rembits. 164 func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) { 165 code := huffmanCodes[c] 166 nbits := huffmanCodeLen[c] 167 168 for { 169 if rembits > nbits { 170 t := uint8(code << (rembits - nbits)) 171 dst[len(dst)-1] |= t 172 rembits -= nbits 173 break 174 } 175 176 t := uint8(code >> (nbits - rembits)) 177 dst[len(dst)-1] |= t 178 179 nbits -= rembits 180 rembits = 8 181 182 if nbits == 0 { 183 break 184 } 185 186 dst = append(dst, 0) 187 } 188 189 return dst, rembits 190 }