...

Source file src/github.com/klauspost/compress/flate/_gen/gen_inflate.go

Documentation: github.com/klauspost/compress/flate/_gen

     1  //go:build generate
     2  // +build generate
     3  
     4  //go:generate go run $GOFILE
     5  //go:generate go fmt ../inflate_gen.go
     6  
     7  package main
     8  
     9  import (
    10  	"os"
    11  	"strings"
    12  )
    13  
    14  func main() {
    15  	f, err := os.Create("../inflate_gen.go")
    16  	if err != nil {
    17  		panic(err)
    18  	}
    19  	defer f.Close()
    20  	types := []string{"*bytes.Buffer", "*bytes.Reader", "*bufio.Reader", "*strings.Reader", "Reader"}
    21  	names := []string{"BytesBuffer", "BytesReader", "BufioReader", "StringsReader", "GenericReader"}
    22  	imports := []string{"bytes", "bufio", "fmt", "strings", "math/bits"}
    23  	f.WriteString(`// Code generated by go generate gen_inflate.go. DO NOT EDIT.
    24  
    25  package flate
    26  
    27  import (
    28  `)
    29  
    30  	for _, imp := range imports {
    31  		f.WriteString("\t\"" + imp + "\"\n")
    32  	}
    33  	f.WriteString(")\n\n")
    34  
    35  	template := `
    36  
    37  // Decode a single Huffman block from f.
    38  // hl and hd are the Huffman states for the lit/length values
    39  // and the distance values, respectively. If hd == nil, using the
    40  // fixed distance encoding associated with fixed Huffman blocks.
    41  func (f *decompressor) $FUNCNAME$() {
    42  	const (
    43  		stateInit = iota // Zero value must be stateInit
    44  		stateDict
    45  	)
    46  	fr := f.r.($TYPE$)
    47  
    48  	// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
    49  	// but is smart enough to keep local variables in registers, so use nb and b,
    50  	// inline call to moreBits and reassign b,nb back to f on return.
    51  	fnb, fb, dict := f.nb, f.b, &f.dict
    52  
    53  	switch f.stepState {
    54  	case stateInit:
    55  		goto readLiteral
    56  	case stateDict:
    57  		goto copyHistory
    58  	}
    59  
    60  readLiteral:
    61  	// Read literal and/or (length, distance) according to RFC section 3.2.3.
    62  	{
    63  		var v int
    64  		{
    65  			// Inlined v, err := f.huffSym(f.hl)
    66  			// Since a huffmanDecoder can be empty or be composed of a degenerate tree
    67  			// with single element, huffSym must error on these two edge cases. In both
    68  			// cases, the chunks slice will be 0 for the invalid sequence, leading it
    69  			// satisfy the n == 0 check below.
    70  			n := uint(f.hl.maxRead)
    71  			for {
    72  				for fnb < n {
    73  					c, err := fr.ReadByte()
    74  					if err != nil {
    75  						f.b, f.nb = fb, fnb
    76  						f.err = noEOF(err)
    77  						return
    78  					}
    79  					f.roffset++
    80  					fb |= uint32(c) << (fnb & regSizeMaskUint32)
    81  					fnb += 8
    82  				}
    83  				chunk := f.hl.chunks[fb&(huffmanNumChunks-1)]
    84  				n = uint(chunk & huffmanCountMask)
    85  				if n > huffmanChunkBits {
    86  					chunk = f.hl.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hl.linkMask]
    87  					n = uint(chunk & huffmanCountMask)
    88  				}
    89  				if n <= fnb {
    90  					if n == 0 {
    91  						f.b, f.nb = fb, fnb
    92  						if debugDecode {
    93  							fmt.Println("huffsym: n==0")
    94  						}
    95  						f.err = CorruptInputError(f.roffset)
    96  						return
    97  					}
    98  					fb = fb >> (n & regSizeMaskUint32)
    99  					fnb = fnb - n
   100  					v = int(chunk >> huffmanValueShift)
   101  					break
   102  				}
   103  			}
   104  		}
   105  
   106  		var length int
   107  		switch {
   108  		case v < 256:
   109  			dict.writeByte(byte(v))
   110  			if dict.availWrite() == 0 {
   111  				f.toRead = dict.readFlush()
   112  				f.step = $FUNCNAME$
   113  				f.stepState = stateInit
   114  				f.b, f.nb = fb, fnb
   115  				return
   116  			}
   117  			goto readLiteral
   118  		case v == 256:
   119  			f.b, f.nb = fb, fnb
   120  			f.finishBlock()
   121  			return
   122  		// otherwise, reference to older data
   123  		case v < 265:
   124  			length = v - (257 - 3)
   125  		case v < maxNumLit:
   126  			val := decCodeToLen[(v - 257)]
   127  			length = int(val.length) + 3
   128  			n := uint(val.extra)
   129  			for fnb < n {
   130  				c, err := fr.ReadByte()
   131  				if err != nil {
   132  					f.b, f.nb = fb, fnb
   133  					if debugDecode {
   134  						fmt.Println("morebits n>0:", err)
   135  					}
   136  					f.err = err
   137  					return
   138  				}
   139  				f.roffset++
   140  				fb |= uint32(c) << (fnb&regSizeMaskUint32)
   141  				fnb += 8	
   142  			}
   143  			length += int(fb & bitMask32[n])
   144  			fb >>= n & regSizeMaskUint32
   145  			fnb -= n
   146  		default:
   147  			if debugDecode {
   148  				fmt.Println(v, ">= maxNumLit")
   149  			}
   150  			f.err = CorruptInputError(f.roffset)
   151  			f.b, f.nb = fb, fnb
   152  			return
   153  		}
   154  
   155  		var dist uint32
   156  		if f.hd == nil {
   157  			for fnb < 5 {
   158  				c, err := fr.ReadByte()
   159  				if err != nil {
   160  					f.b, f.nb = fb, fnb
   161  					if debugDecode {
   162  						fmt.Println("morebits f.nb<5:", err)
   163  					}
   164  					f.err = err
   165  					return
   166  				}
   167  				f.roffset++
   168  				fb |= uint32(c) << (fnb&regSizeMaskUint32)
   169  				fnb += 8
   170  			}
   171  			dist = uint32(bits.Reverse8(uint8(fb & 0x1F << 3)))
   172  			fb >>= 5
   173  			fnb -= 5
   174  		} else {
   175  			// Since a huffmanDecoder can be empty or be composed of a degenerate tree
   176  			// with single element, huffSym must error on these two edge cases. In both
   177  			// cases, the chunks slice will be 0 for the invalid sequence, leading it
   178  			// satisfy the n == 0 check below.
   179  			n := uint(f.hd.maxRead)
   180  			// Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
   181  			// but is smart enough to keep local variables in registers, so use nb and b,
   182  			// inline call to moreBits and reassign b,nb back to f on return.
   183  			for {
   184  				for fnb < n {
   185  					c, err := fr.ReadByte()
   186  					if err != nil {
   187  						f.b, f.nb = fb, fnb
   188  						f.err = noEOF(err)
   189  						return
   190  					}
   191  					f.roffset++
   192  					fb |= uint32(c) << (fnb & regSizeMaskUint32)
   193  					fnb += 8
   194  				}
   195  				chunk := f.hd.chunks[fb&(huffmanNumChunks-1)]
   196  				n = uint(chunk & huffmanCountMask)
   197  				if n > huffmanChunkBits {
   198  					chunk = f.hd.links[chunk>>huffmanValueShift][(fb>>huffmanChunkBits)&f.hd.linkMask]
   199  					n = uint(chunk & huffmanCountMask)
   200  				}
   201  				if n <= fnb {
   202  					if n == 0 {
   203  						f.b, f.nb = fb, fnb
   204  						if debugDecode {
   205  							fmt.Println("huffsym: n==0")
   206  						}
   207  						f.err = CorruptInputError(f.roffset)
   208  						return
   209  					}
   210  					fb = fb >> (n & regSizeMaskUint32)
   211  					fnb = fnb - n
   212  					dist = uint32(chunk >> huffmanValueShift)
   213  					break
   214  				}
   215  			}
   216  		}
   217  
   218  		switch {
   219  		case dist < 4:
   220  			dist++
   221  		case dist < maxNumDist:
   222  			nb := uint(dist-2) >> 1
   223  			// have 1 bit in bottom of dist, need nb more.
   224  			extra := (dist & 1) << (nb & regSizeMaskUint32)
   225  			for fnb < nb {
   226  				c, err := fr.ReadByte()
   227  				if err != nil {
   228  					f.b, f.nb = fb, fnb
   229  					if debugDecode {
   230  						fmt.Println("morebits f.nb<nb:", err)
   231  					}
   232  					f.err = err
   233  					return
   234  				}
   235  				f.roffset++
   236  				fb |= uint32(c) << (fnb&regSizeMaskUint32)
   237  				fnb += 8
   238  			}
   239  			extra |= fb & bitMask32[nb]
   240  			fb >>= nb & regSizeMaskUint32
   241  			fnb -= nb
   242  			dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
   243  			// slower: dist = bitMask32[nb+1] + 2 + extra
   244  		default:
   245  			f.b, f.nb = fb, fnb
   246  			if debugDecode {
   247  				fmt.Println("dist too big:", dist, maxNumDist)
   248  			}
   249  			f.err = CorruptInputError(f.roffset)
   250  			return
   251  		}
   252  
   253  		// No check on length; encoding can be prescient.
   254  		if dist > uint32(dict.histSize()) {
   255  			f.b, f.nb = fb, fnb
   256  			if debugDecode {
   257  				fmt.Println("dist > dict.histSize():", dist, dict.histSize())
   258  			}
   259  			f.err = CorruptInputError(f.roffset)
   260  			return
   261  		}
   262  
   263  		f.copyLen, f.copyDist = length, int(dist)
   264  		goto copyHistory
   265  	}
   266  
   267  copyHistory:
   268  	// Perform a backwards copy according to RFC section 3.2.3.
   269  	{
   270  		cnt := dict.tryWriteCopy(f.copyDist, f.copyLen)
   271  		if cnt == 0 {
   272  			cnt = dict.writeCopy(f.copyDist, f.copyLen)
   273  		}
   274  		f.copyLen -= cnt
   275  
   276  		if dict.availWrite() == 0 || f.copyLen > 0 {
   277  			f.toRead = dict.readFlush()
   278  			f.step = $FUNCNAME$ // We need to continue this work
   279  			f.stepState = stateDict
   280  			f.b, f.nb = fb, fnb
   281  			return
   282  		}
   283  		goto readLiteral
   284  	}
   285  	// Not reached
   286  }
   287  
   288  `
   289  	for i, t := range types {
   290  		s := strings.Replace(template, "$FUNCNAME$", "huffman"+names[i], -1)
   291  		s = strings.Replace(s, "$TYPE$", t, -1)
   292  		f.WriteString(s)
   293  	}
   294  	f.WriteString("func (f *decompressor) huffmanBlockDecoder() {\n")
   295  	f.WriteString("\tswitch f.r.(type) {\n")
   296  	for i, t := range types {
   297  		f.WriteString("\t\tcase " + t + ":\n")
   298  		f.WriteString("\t\t\tf.huffman" + names[i] + "()\n")
   299  	}
   300  	f.WriteString("\t\tdefault:\n")
   301  	f.WriteString("\t\t\tf.huffmanGenericReader()\n")
   302  	f.WriteString("\t}\n}\n")
   303  }
   304  

View as plain text