github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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  // 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  }