1 // Copyright 2012 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 // +build ignore 6 7 // This program generates fixedhuff.go 8 // Invoke as 9 // 10 // go run gen.go -output fixedhuff.go 11 12 package main 13 14 import ( 15 "bytes" 16 "flag" 17 "fmt" 18 "go/format" 19 "io/ioutil" 20 "log" 21 ) 22 23 var filename = flag.String("output", "fixedhuff.go", "output file name") 24 25 const maxCodeLen = 16 26 27 // Note: the definition of the huffmanDecoder struct is copied from 28 // inflate.go, as it is private to the implementation. 29 30 // chunk & 15 is number of bits 31 // chunk >> 4 is value, including table link 32 33 const ( 34 huffmanChunkBits = 9 35 huffmanNumChunks = 1 << huffmanChunkBits 36 huffmanCountMask = 15 37 huffmanValueShift = 4 38 ) 39 40 type huffmanDecoder struct { 41 min int // the minimum code length 42 chunks [huffmanNumChunks]uint32 // chunks as described above 43 links [][]uint32 // overflow links 44 linkMask uint32 // mask the width of the link table 45 } 46 47 // Initialize Huffman decoding tables from array of code lengths. 48 // Following this function, h is guaranteed to be initialized into a complete 49 // tree (i.e., neither over-subscribed nor under-subscribed). The exception is a 50 // degenerate case where the tree has only a single symbol with length 1. Empty 51 // trees are permitted. 52 func (h *huffmanDecoder) init(bits []int) bool { 53 // Sanity enables additional runtime tests during Huffman 54 // table construction. It's intended to be used during 55 // development to supplement the currently ad-hoc unit tests. 56 const sanity = false 57 58 if h.min != 0 { 59 *h = huffmanDecoder{} 60 } 61 62 // Count number of codes of each length, 63 // compute min and max length. 64 var count [maxCodeLen]int 65 var min, max int 66 for _, n := range bits { 67 if n == 0 { 68 continue 69 } 70 if min == 0 || n < min { 71 min = n 72 } 73 if n > max { 74 max = n 75 } 76 count[n]++ 77 } 78 79 // Empty tree. The decompressor.huffSym function will fail later if the tree 80 // is used. Technically, an empty tree is only valid for the HDIST tree and 81 // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree 82 // is guaranteed to fail since it will attempt to use the tree to decode the 83 // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is 84 // guaranteed to fail later since the compressed data section must be 85 // composed of at least one symbol (the end-of-block marker). 86 if max == 0 { 87 return true 88 } 89 90 code := 0 91 var nextcode [maxCodeLen]int 92 for i := min; i <= max; i++ { 93 code <<= 1 94 nextcode[i] = code 95 code += count[i] 96 } 97 98 // Check that the coding is complete (i.e., that we've 99 // assigned all 2-to-the-max possible bit sequences). 100 // Exception: To be compatible with zlib, we also need to 101 // accept degenerate single-code codings. See also 102 // TestDegenerateHuffmanCoding. 103 if code != 1<<uint(max) && !(code == 1 && max == 1) { 104 return false 105 } 106 107 h.min = min 108 if max > huffmanChunkBits { 109 numLinks := 1 << (uint(max) - huffmanChunkBits) 110 h.linkMask = uint32(numLinks - 1) 111 112 // create link tables 113 link := nextcode[huffmanChunkBits+1] >> 1 114 h.links = make([][]uint32, huffmanNumChunks-link) 115 for j := uint(link); j < huffmanNumChunks; j++ { 116 reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 117 reverse >>= uint(16 - huffmanChunkBits) 118 off := j - uint(link) 119 if sanity && h.chunks[reverse] != 0 { 120 panic("impossible: overwriting existing chunk") 121 } 122 h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1)) 123 h.links[off] = make([]uint32, numLinks) 124 } 125 } 126 127 for i, n := range bits { 128 if n == 0 { 129 continue 130 } 131 code := nextcode[n] 132 nextcode[n]++ 133 chunk := uint32(i<<huffmanValueShift | n) 134 reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8 135 reverse >>= uint(16 - n) 136 if n <= huffmanChunkBits { 137 for off := reverse; off < len(h.chunks); off += 1 << uint(n) { 138 // We should never need to overwrite 139 // an existing chunk. Also, 0 is 140 // never a valid chunk, because the 141 // lower 4 "count" bits should be 142 // between 1 and 15. 143 if sanity && h.chunks[off] != 0 { 144 panic("impossible: overwriting existing chunk") 145 } 146 h.chunks[off] = chunk 147 } 148 } else { 149 j := reverse & (huffmanNumChunks - 1) 150 if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { 151 // Longer codes should have been 152 // associated with a link table above. 153 panic("impossible: not an indirect chunk") 154 } 155 value := h.chunks[j] >> huffmanValueShift 156 linktab := h.links[value] 157 reverse >>= huffmanChunkBits 158 for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { 159 if sanity && linktab[off] != 0 { 160 panic("impossible: overwriting existing chunk") 161 } 162 linktab[off] = chunk 163 } 164 } 165 } 166 167 if sanity { 168 // Above we've sanity checked that we never overwrote 169 // an existing entry. Here we additionally check that 170 // we filled the tables completely. 171 for i, chunk := range h.chunks { 172 if chunk == 0 { 173 // As an exception, in the degenerate 174 // single-code case, we allow odd 175 // chunks to be missing. 176 if code == 1 && i%2 == 1 { 177 continue 178 } 179 panic("impossible: missing chunk") 180 } 181 } 182 for _, linktab := range h.links { 183 for _, chunk := range linktab { 184 if chunk == 0 { 185 panic("impossible: missing chunk") 186 } 187 } 188 } 189 } 190 191 return true 192 } 193 194 func main() { 195 flag.Parse() 196 197 var h huffmanDecoder 198 var bits [288]int 199 initReverseByte() 200 for i := 0; i < 144; i++ { 201 bits[i] = 8 202 } 203 for i := 144; i < 256; i++ { 204 bits[i] = 9 205 } 206 for i := 256; i < 280; i++ { 207 bits[i] = 7 208 } 209 for i := 280; i < 288; i++ { 210 bits[i] = 8 211 } 212 h.init(bits[:]) 213 if h.links != nil { 214 log.Fatal("Unexpected links table in fixed Huffman decoder") 215 } 216 217 var buf bytes.Buffer 218 219 fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. 220 // Use of this source code is governed by a BSD-style 221 // license that can be found in the LICENSE file.`+"\n\n") 222 223 fmt.Fprintln(&buf, "package flate") 224 fmt.Fprintln(&buf) 225 fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT") 226 fmt.Fprintln(&buf) 227 fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{") 228 fmt.Fprintf(&buf, "\t%d,\n", h.min) 229 fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{") 230 for i := 0; i < huffmanNumChunks; i++ { 231 if i&7 == 0 { 232 fmt.Fprintf(&buf, "\t\t") 233 } else { 234 fmt.Fprintf(&buf, " ") 235 } 236 fmt.Fprintf(&buf, "0x%04x,", h.chunks[i]) 237 if i&7 == 7 { 238 fmt.Fprintln(&buf) 239 } 240 } 241 fmt.Fprintln(&buf, "\t},") 242 fmt.Fprintln(&buf, "\tnil, 0,") 243 fmt.Fprintln(&buf, "}") 244 245 data, err := format.Source(buf.Bytes()) 246 if err != nil { 247 log.Fatal(err) 248 } 249 err = ioutil.WriteFile(*filename, data, 0644) 250 if err != nil { 251 log.Fatal(err) 252 } 253 } 254 255 var reverseByte [256]byte 256 257 func initReverseByte() { 258 for x := 0; x < 256; x++ { 259 var result byte 260 for i := uint(0); i < 8; i++ { 261 result |= byte(((x >> i) & 1) << (7 - i)) 262 } 263 reverseByte[x] = result 264 } 265 } 266