mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-24 23:32:06 +00:00
191 lines
4.3 KiB
Go
191 lines
4.3 KiB
Go
// 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.
|
|
func (h *huffmanDecoder) init(bits []int) bool {
|
|
// 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]++
|
|
}
|
|
if max == 0 {
|
|
return false
|
|
}
|
|
|
|
h.min = min
|
|
var linkBits uint
|
|
var numLinks int
|
|
if max > huffmanChunkBits {
|
|
linkBits = uint(max) - huffmanChunkBits
|
|
numLinks = 1 << linkBits
|
|
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)
|
|
}
|
|
}
|
|
n := count[i]
|
|
nextcode[i] = code
|
|
code += n
|
|
code <<= 1
|
|
}
|
|
|
|
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 < huffmanNumChunks; off += 1 << uint(n) {
|
|
h.chunks[off] = chunk
|
|
}
|
|
} else {
|
|
linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift]
|
|
reverse >>= huffmanChunkBits
|
|
for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
|
|
linktab[off] = 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[:])
|
|
|
|
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
|
|
}
|
|
}
|