github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/compress/flate/gen.go (about) 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 func (h *huffmanDecoder) init(bits []int) bool { 49 // Sanity enables additional runtime tests during Huffman 50 // table construction. It's intended to be used during 51 // development to supplement the currently ad-hoc unit tests. 52 const sanity = false 53 54 if h.min != 0 { 55 *h = huffmanDecoder{} 56 } 57 58 // Count number of codes of each length, 59 // compute min and max length. 60 var count [maxCodeLen]int 61 var min, max int 62 for _, n := range bits { 63 if n == 0 { 64 continue 65 } 66 if min == 0 || n < min { 67 min = n 68 } 69 if n > max { 70 max = n 71 } 72 count[n]++ 73 } 74 if max == 0 { 75 return false 76 } 77 78 code := 0 79 var nextcode [maxCodeLen]int 80 for i := min; i <= max; i++ { 81 code <<= 1 82 nextcode[i] = code 83 code += count[i] 84 } 85 86 // Check that the coding is complete (i.e., that we've 87 // assigned all 2-to-the-max possible bit sequences). 88 // Exception: To be compatible with zlib, we also need to 89 // accept degenerate single-code codings. See also 90 // TestDegenerateHuffmanCoding. 91 if code != 1<<uint(max) && !(code == 1 && max == 1) { 92 return false 93 } 94 95 h.min = min 96 if max > huffmanChunkBits { 97 numLinks := 1 << (uint(max) - huffmanChunkBits) 98 h.linkMask = uint32(numLinks - 1) 99 100 // create link tables 101 link := nextcode[huffmanChunkBits+1] >> 1 102 h.links = make([][]uint32, huffmanNumChunks-link) 103 for j := uint(link); j < huffmanNumChunks; j++ { 104 reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 105 reverse >>= uint(16 - huffmanChunkBits) 106 off := j - uint(link) 107 if sanity && h.chunks[reverse] != 0 { 108 panic("impossible: overwriting existing chunk") 109 } 110 h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1)) 111 h.links[off] = make([]uint32, numLinks) 112 } 113 } 114 115 for i, n := range bits { 116 if n == 0 { 117 continue 118 } 119 code := nextcode[n] 120 nextcode[n]++ 121 chunk := uint32(i<<huffmanValueShift | n) 122 reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8 123 reverse >>= uint(16 - n) 124 if n <= huffmanChunkBits { 125 for off := reverse; off < len(h.chunks); off += 1 << uint(n) { 126 // We should never need to overwrite 127 // an existing chunk. Also, 0 is 128 // never a valid chunk, because the 129 // lower 4 "count" bits should be 130 // between 1 and 15. 131 if sanity && h.chunks[off] != 0 { 132 panic("impossible: overwriting existing chunk") 133 } 134 h.chunks[off] = chunk 135 } 136 } else { 137 j := reverse & (huffmanNumChunks - 1) 138 if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { 139 // Longer codes should have been 140 // associated with a link table above. 141 panic("impossible: not an indirect chunk") 142 } 143 value := h.chunks[j] >> huffmanValueShift 144 linktab := h.links[value] 145 reverse >>= huffmanChunkBits 146 for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { 147 if sanity && linktab[off] != 0 { 148 panic("impossible: overwriting existing chunk") 149 } 150 linktab[off] = chunk 151 } 152 } 153 } 154 155 if sanity { 156 // Above we've sanity checked that we never overwrote 157 // an existing entry. Here we additionally check that 158 // we filled the tables completely. 159 for i, chunk := range h.chunks { 160 if chunk == 0 { 161 // As an exception, in the degenerate 162 // single-code case, we allow odd 163 // chunks to be missing. 164 if code == 1 && i%2 == 1 { 165 continue 166 } 167 panic("impossible: missing chunk") 168 } 169 } 170 for _, linktab := range h.links { 171 for _, chunk := range linktab { 172 if chunk == 0 { 173 panic("impossible: missing chunk") 174 } 175 } 176 } 177 } 178 179 return true 180 } 181 182 func main() { 183 flag.Parse() 184 185 var h huffmanDecoder 186 var bits [288]int 187 initReverseByte() 188 for i := 0; i < 144; i++ { 189 bits[i] = 8 190 } 191 for i := 144; i < 256; i++ { 192 bits[i] = 9 193 } 194 for i := 256; i < 280; i++ { 195 bits[i] = 7 196 } 197 for i := 280; i < 288; i++ { 198 bits[i] = 8 199 } 200 h.init(bits[:]) 201 if h.links != nil { 202 log.Fatal("Unexpected links table in fixed Huffman decoder") 203 } 204 205 var buf bytes.Buffer 206 207 fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. 208 // Use of this source code is governed by a BSD-style 209 // license that can be found in the LICENSE file.`+"\n\n") 210 211 fmt.Fprintln(&buf, "package flate") 212 fmt.Fprintln(&buf) 213 fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT") 214 fmt.Fprintln(&buf) 215 fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{") 216 fmt.Fprintf(&buf, "\t%d,\n", h.min) 217 fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{") 218 for i := 0; i < huffmanNumChunks; i++ { 219 if i&7 == 0 { 220 fmt.Fprintf(&buf, "\t\t") 221 } else { 222 fmt.Fprintf(&buf, " ") 223 } 224 fmt.Fprintf(&buf, "0x%04x,", h.chunks[i]) 225 if i&7 == 7 { 226 fmt.Fprintln(&buf) 227 } 228 } 229 fmt.Fprintln(&buf, "\t},") 230 fmt.Fprintln(&buf, "\tnil, 0,") 231 fmt.Fprintln(&buf, "}") 232 233 data, err := format.Source(buf.Bytes()) 234 if err != nil { 235 log.Fatal(err) 236 } 237 err = ioutil.WriteFile(*filename, data, 0644) 238 if err != nil { 239 log.Fatal(err) 240 } 241 } 242 243 var reverseByte [256]byte 244 245 func initReverseByte() { 246 for x := 0; x < 256; x++ { 247 var result byte 248 for i := uint(0); i < 8; i++ { 249 result |= byte(((x >> i) & 1) << (7 - i)) 250 } 251 reverseByte[x] = result 252 } 253 }