summaryrefslogtreecommitdiffstats
path: root/llgo/third_party/gofrontend/libgo/go/compress/flate/gen.go
diff options
context:
space:
mode:
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.go125
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
OpenPOWER on IntegriCloud