github.com/bir3/gocompiler@v0.9.2202/extra/compress/huff0/decompress_generic.go (about)

     1  //go:build !amd64 || appengine || !gc || noasm
     2  // +build !amd64 appengine !gc noasm
     3  
     4  // This file contains a generic implementation of Decoder.Decompress4X.
     5  package huff0
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  )
    11  
    12  // Decompress4X will decompress a 4X encoded stream.
    13  // The length of the supplied input must match the end of a block exactly.
    14  // The *capacity* of the dst slice must match the destination size of
    15  // the uncompressed data exactly.
    16  func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
    17  	if len(d.dt.single) == 0 {
    18  		return nil, errors.New("no table loaded")
    19  	}
    20  	if len(src) < 6+(4*1) {
    21  		return nil, errors.New("input too small")
    22  	}
    23  	if use8BitTables && d.actualTableLog <= 8 {
    24  		return d.decompress4X8bit(dst, src)
    25  	}
    26  
    27  	var br [4]bitReaderShifted
    28  	// Decode "jump table"
    29  	start := 6
    30  	for i := 0; i < 3; i++ {
    31  		length := int(src[i*2]) | (int(src[i*2+1]) << 8)
    32  		if start+length >= len(src) {
    33  			return nil, errors.New("truncated input (or invalid offset)")
    34  		}
    35  		err := br[i].init(src[start : start+length])
    36  		if err != nil {
    37  			return nil, err
    38  		}
    39  		start += length
    40  	}
    41  	err := br[3].init(src[start:])
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	// destination, offset to match first output
    47  	dstSize := cap(dst)
    48  	dst = dst[:dstSize]
    49  	out := dst
    50  	dstEvery := (dstSize + 3) / 4
    51  
    52  	const tlSize = 1 << tableLogMax
    53  	const tlMask = tlSize - 1
    54  	single := d.dt.single[:tlSize]
    55  
    56  	// Use temp table to avoid bound checks/append penalty.
    57  	buf := d.buffer()
    58  	var off uint8
    59  	var decoded int
    60  
    61  	// Decode 2 values from each decoder/loop.
    62  	const bufoff = 256
    63  	for {
    64  		if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
    65  			break
    66  		}
    67  
    68  		{
    69  			const stream = 0
    70  			const stream2 = 1
    71  			br[stream].fillFast()
    72  			br[stream2].fillFast()
    73  
    74  			val := br[stream].peekBitsFast(d.actualTableLog)
    75  			val2 := br[stream2].peekBitsFast(d.actualTableLog)
    76  			v := single[val&tlMask]
    77  			v2 := single[val2&tlMask]
    78  			br[stream].advance(uint8(v.entry))
    79  			br[stream2].advance(uint8(v2.entry))
    80  			buf[stream][off] = uint8(v.entry >> 8)
    81  			buf[stream2][off] = uint8(v2.entry >> 8)
    82  
    83  			val = br[stream].peekBitsFast(d.actualTableLog)
    84  			val2 = br[stream2].peekBitsFast(d.actualTableLog)
    85  			v = single[val&tlMask]
    86  			v2 = single[val2&tlMask]
    87  			br[stream].advance(uint8(v.entry))
    88  			br[stream2].advance(uint8(v2.entry))
    89  			buf[stream][off+1] = uint8(v.entry >> 8)
    90  			buf[stream2][off+1] = uint8(v2.entry >> 8)
    91  		}
    92  
    93  		{
    94  			const stream = 2
    95  			const stream2 = 3
    96  			br[stream].fillFast()
    97  			br[stream2].fillFast()
    98  
    99  			val := br[stream].peekBitsFast(d.actualTableLog)
   100  			val2 := br[stream2].peekBitsFast(d.actualTableLog)
   101  			v := single[val&tlMask]
   102  			v2 := single[val2&tlMask]
   103  			br[stream].advance(uint8(v.entry))
   104  			br[stream2].advance(uint8(v2.entry))
   105  			buf[stream][off] = uint8(v.entry >> 8)
   106  			buf[stream2][off] = uint8(v2.entry >> 8)
   107  
   108  			val = br[stream].peekBitsFast(d.actualTableLog)
   109  			val2 = br[stream2].peekBitsFast(d.actualTableLog)
   110  			v = single[val&tlMask]
   111  			v2 = single[val2&tlMask]
   112  			br[stream].advance(uint8(v.entry))
   113  			br[stream2].advance(uint8(v2.entry))
   114  			buf[stream][off+1] = uint8(v.entry >> 8)
   115  			buf[stream2][off+1] = uint8(v2.entry >> 8)
   116  		}
   117  
   118  		off += 2
   119  
   120  		if off == 0 {
   121  			if bufoff > dstEvery {
   122  				d.bufs.Put(buf)
   123  				return nil, errors.New("corruption detected: stream overrun 1")
   124  			}
   125  			// There must at least be 3 buffers left.
   126  			if len(out)-bufoff < dstEvery*3 {
   127  				d.bufs.Put(buf)
   128  				return nil, errors.New("corruption detected: stream overrun 2")
   129  			}
   130  			//copy(out, buf[0][:])
   131  			//copy(out[dstEvery:], buf[1][:])
   132  			//copy(out[dstEvery*2:], buf[2][:])
   133  			//copy(out[dstEvery*3:], buf[3][:])
   134  			*(*[bufoff]byte)(out) = buf[0]
   135  			*(*[bufoff]byte)(out[dstEvery:]) = buf[1]
   136  			*(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
   137  			*(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
   138  			out = out[bufoff:]
   139  			decoded += bufoff * 4
   140  		}
   141  	}
   142  	if off > 0 {
   143  		ioff := int(off)
   144  		if len(out) < dstEvery*3+ioff {
   145  			d.bufs.Put(buf)
   146  			return nil, errors.New("corruption detected: stream overrun 3")
   147  		}
   148  		copy(out, buf[0][:off])
   149  		copy(out[dstEvery:], buf[1][:off])
   150  		copy(out[dstEvery*2:], buf[2][:off])
   151  		copy(out[dstEvery*3:], buf[3][:off])
   152  		decoded += int(off) * 4
   153  		out = out[off:]
   154  	}
   155  
   156  	// Decode remaining.
   157  	remainBytes := dstEvery - (decoded / 4)
   158  	for i := range br {
   159  		offset := dstEvery * i
   160  		endsAt := offset + remainBytes
   161  		if endsAt > len(out) {
   162  			endsAt = len(out)
   163  		}
   164  		br := &br[i]
   165  		bitsLeft := br.remaining()
   166  		for bitsLeft > 0 {
   167  			br.fill()
   168  			if offset >= endsAt {
   169  				d.bufs.Put(buf)
   170  				return nil, errors.New("corruption detected: stream overrun 4")
   171  			}
   172  
   173  			// Read value and increment offset.
   174  			val := br.peekBitsFast(d.actualTableLog)
   175  			v := single[val&tlMask].entry
   176  			nBits := uint8(v)
   177  			br.advance(nBits)
   178  			bitsLeft -= uint(nBits)
   179  			out[offset] = uint8(v >> 8)
   180  			offset++
   181  		}
   182  		if offset != endsAt {
   183  			d.bufs.Put(buf)
   184  			return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
   185  		}
   186  		decoded += offset - dstEvery*i
   187  		err = br.close()
   188  		if err != nil {
   189  			return nil, err
   190  		}
   191  	}
   192  	d.bufs.Put(buf)
   193  	if dstSize != decoded {
   194  		return nil, errors.New("corruption detected: short output block")
   195  	}
   196  	return dst, nil
   197  }
   198  
   199  // Decompress1X will decompress a 1X encoded stream.
   200  // The cap of the output buffer will be the maximum decompressed size.
   201  // The length of the supplied input must match the end of a block exactly.
   202  func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
   203  	if len(d.dt.single) == 0 {
   204  		return nil, errors.New("no table loaded")
   205  	}
   206  	if use8BitTables && d.actualTableLog <= 8 {
   207  		return d.decompress1X8Bit(dst, src)
   208  	}
   209  	var br bitReaderShifted
   210  	err := br.init(src)
   211  	if err != nil {
   212  		return dst, err
   213  	}
   214  	maxDecodedSize := cap(dst)
   215  	dst = dst[:0]
   216  
   217  	// Avoid bounds check by always having full sized table.
   218  	const tlSize = 1 << tableLogMax
   219  	const tlMask = tlSize - 1
   220  	dt := d.dt.single[:tlSize]
   221  
   222  	// Use temp table to avoid bound checks/append penalty.
   223  	bufs := d.buffer()
   224  	buf := &bufs[0]
   225  	var off uint8
   226  
   227  	for br.off >= 8 {
   228  		br.fillFast()
   229  		v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
   230  		br.advance(uint8(v.entry))
   231  		buf[off+0] = uint8(v.entry >> 8)
   232  
   233  		v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
   234  		br.advance(uint8(v.entry))
   235  		buf[off+1] = uint8(v.entry >> 8)
   236  
   237  		// Refill
   238  		br.fillFast()
   239  
   240  		v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
   241  		br.advance(uint8(v.entry))
   242  		buf[off+2] = uint8(v.entry >> 8)
   243  
   244  		v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
   245  		br.advance(uint8(v.entry))
   246  		buf[off+3] = uint8(v.entry >> 8)
   247  
   248  		off += 4
   249  		if off == 0 {
   250  			if len(dst)+256 > maxDecodedSize {
   251  				br.close()
   252  				d.bufs.Put(bufs)
   253  				return nil, ErrMaxDecodedSizeExceeded
   254  			}
   255  			dst = append(dst, buf[:]...)
   256  		}
   257  	}
   258  
   259  	if len(dst)+int(off) > maxDecodedSize {
   260  		d.bufs.Put(bufs)
   261  		br.close()
   262  		return nil, ErrMaxDecodedSizeExceeded
   263  	}
   264  	dst = append(dst, buf[:off]...)
   265  
   266  	// br < 8, so uint8 is fine
   267  	bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
   268  	for bitsLeft > 0 {
   269  		br.fill()
   270  		if false && br.bitsRead >= 32 {
   271  			if br.off >= 4 {
   272  				v := br.in[br.off-4:]
   273  				v = v[:4]
   274  				low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
   275  				br.value = (br.value << 32) | uint64(low)
   276  				br.bitsRead -= 32
   277  				br.off -= 4
   278  			} else {
   279  				for br.off > 0 {
   280  					br.value = (br.value << 8) | uint64(br.in[br.off-1])
   281  					br.bitsRead -= 8
   282  					br.off--
   283  				}
   284  			}
   285  		}
   286  		if len(dst) >= maxDecodedSize {
   287  			d.bufs.Put(bufs)
   288  			br.close()
   289  			return nil, ErrMaxDecodedSizeExceeded
   290  		}
   291  		v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
   292  		nBits := uint8(v.entry)
   293  		br.advance(nBits)
   294  		bitsLeft -= nBits
   295  		dst = append(dst, uint8(v.entry>>8))
   296  	}
   297  	d.bufs.Put(bufs)
   298  	return dst, br.close()
   299  }