diff options
Diffstat (limited to 'llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go')
| -rw-r--r-- | llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go | 125 |
1 files changed, 100 insertions, 25 deletions
diff --git a/llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go b/llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go index 6288ecddd0e..154c89a488e 100644 --- a/llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go +++ b/llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go @@ -45,7 +45,20 @@ type huffmanDecoder struct { } // Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.min != 0 { + *h = huffmanDecoder{} + } + // Count number of codes of each length, // compute min and max length. var count [maxCodeLen]int @@ -62,37 +75,53 @@ func (h *huffmanDecoder) init(bits []int) bool { } count[n]++ } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1<<uint(max) && !(code == 1 && max == 1) { return false } h.min = min - var linkBits uint - var numLinks int if max > huffmanChunkBits { - linkBits = uint(max) - huffmanChunkBits - numLinks = 1 << linkBits + numLinks := 1 << (uint(max) - huffmanChunkBits) h.linkMask = uint32(numLinks - 1) - } - code := 0 - var nextcode [maxCodeLen]int - for i := min; i <= max; i++ { - if i == huffmanChunkBits+1 { - // create link tables - link := code >> 1 - h.links = make([][]uint32, huffmanNumChunks-link) - for j := uint(link); j < huffmanNumChunks; j++ { - reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 - reverse >>= uint(16 - huffmanChunkBits) - off := j - uint(link) - h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i)) - h.links[off] = make([]uint32, 1<<linkBits) + + // create link tables + link := nextcode[huffmanChunkBits+1] >> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") } + h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1)) + h.links[off] = make([]uint32, numLinks) } - n := count[i] - nextcode[i] = code - code += n - code <<= 1 } for i, n := range bits { @@ -105,17 +134,60 @@ func (h *huffmanDecoder) init(bits []int) bool { reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8 reverse >>= uint(16 - n) if n <= huffmanChunkBits { - for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } h.chunks[off] = chunk } } else { - linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift] + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] reverse >>= huffmanChunkBits - for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) { + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } linktab[off] = chunk } } } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + return true } @@ -138,6 +210,9 @@ func main() { bits[i] = 8 } h.init(bits[:]) + if h.links != nil { + log.Fatal("Unexpected links table in fixed Huffman decoder") + } var buf bytes.Buffer |

