mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
6.9 KiB
265 lines
6.9 KiB
// Copyright 2012 The Go Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
// +build ignore |
|
|
|
// This program generates fixedhuff.go |
|
// Invoke as |
|
// |
|
// go run gen.go -output fixedhuff.go |
|
|
|
package main |
|
|
|
import ( |
|
"bytes" |
|
"flag" |
|
"fmt" |
|
"go/format" |
|
"io/ioutil" |
|
"log" |
|
) |
|
|
|
var filename = flag.String("output", "fixedhuff.go", "output file name") |
|
|
|
const maxCodeLen = 16 |
|
|
|
// Note: the definition of the huffmanDecoder struct is copied from |
|
// inflate.go, as it is private to the implementation. |
|
|
|
// chunk & 15 is number of bits |
|
// chunk >> 4 is value, including table link |
|
|
|
const ( |
|
huffmanChunkBits = 9 |
|
huffmanNumChunks = 1 << huffmanChunkBits |
|
huffmanCountMask = 15 |
|
huffmanValueShift = 4 |
|
) |
|
|
|
type huffmanDecoder struct { |
|
min int // the minimum code length |
|
chunks [huffmanNumChunks]uint32 // chunks as described above |
|
links [][]uint32 // overflow links |
|
linkMask uint32 // mask the width of the link table |
|
} |
|
|
|
// 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 |
|
var min, max int |
|
for _, n := range bits { |
|
if n == 0 { |
|
continue |
|
} |
|
if min == 0 || n < min { |
|
min = n |
|
} |
|
if n > max { |
|
max = n |
|
} |
|
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 |
|
if max > huffmanChunkBits { |
|
numLinks := 1 << (uint(max) - huffmanChunkBits) |
|
h.linkMask = uint32(numLinks - 1) |
|
|
|
// 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) |
|
} |
|
} |
|
|
|
for i, n := range bits { |
|
if n == 0 { |
|
continue |
|
} |
|
code := nextcode[n] |
|
nextcode[n]++ |
|
chunk := uint32(i<<huffmanValueShift | n) |
|
reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8 |
|
reverse >>= uint(16 - n) |
|
if n <= huffmanChunkBits { |
|
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 { |
|
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 < 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 |
|
} |
|
|
|
func main() { |
|
flag.Parse() |
|
|
|
var h huffmanDecoder |
|
var bits [288]int |
|
initReverseByte() |
|
for i := 0; i < 144; i++ { |
|
bits[i] = 8 |
|
} |
|
for i := 144; i < 256; i++ { |
|
bits[i] = 9 |
|
} |
|
for i := 256; i < 280; i++ { |
|
bits[i] = 7 |
|
} |
|
for i := 280; i < 288; i++ { |
|
bits[i] = 8 |
|
} |
|
h.init(bits[:]) |
|
if h.links != nil { |
|
log.Fatal("Unexpected links table in fixed Huffman decoder") |
|
} |
|
|
|
var buf bytes.Buffer |
|
|
|
fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file.`+"\n\n") |
|
|
|
fmt.Fprintln(&buf, "package flate") |
|
fmt.Fprintln(&buf) |
|
fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT") |
|
fmt.Fprintln(&buf) |
|
fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{") |
|
fmt.Fprintf(&buf, "\t%d,\n", h.min) |
|
fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{") |
|
for i := 0; i < huffmanNumChunks; i++ { |
|
if i&7 == 0 { |
|
fmt.Fprintf(&buf, "\t\t") |
|
} else { |
|
fmt.Fprintf(&buf, " ") |
|
} |
|
fmt.Fprintf(&buf, "0x%04x,", h.chunks[i]) |
|
if i&7 == 7 { |
|
fmt.Fprintln(&buf) |
|
} |
|
} |
|
fmt.Fprintln(&buf, "\t},") |
|
fmt.Fprintln(&buf, "\tnil, 0,") |
|
fmt.Fprintln(&buf, "}") |
|
|
|
data, err := format.Source(buf.Bytes()) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
err = ioutil.WriteFile(*filename, data, 0644) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
} |
|
|
|
var reverseByte [256]byte |
|
|
|
func initReverseByte() { |
|
for x := 0; x < 256; x++ { |
|
var result byte |
|
for i := uint(0); i < 8; i++ { |
|
result |= byte(((x >> i) & 1) << (7 - i)) |
|
} |
|
reverseByte[x] = result |
|
} |
|
}
|
|
|