github.com/bir3/gocompiler@v0.9.2202/extra/compress/internal/snapref/decode_other.go (about)

     1  // Copyright 2016 The Snappy-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  package snapref
     6  
     7  // decode writes the decoding of src to dst. It assumes that the varint-encoded
     8  // length of the decompressed bytes has already been read, and that len(dst)
     9  // equals that length.
    10  //
    11  // It returns 0 on success or a decodeErrCodeXxx error code on failure.
    12  func decode(dst, src []byte) int {
    13  	var d, s, offset, length int
    14  	for s < len(src) {
    15  		switch src[s] & 0x03 {
    16  		case tagLiteral:
    17  			x := uint32(src[s] >> 2)
    18  			switch {
    19  			case x < 60:
    20  				s++
    21  			case x == 60:
    22  				s += 2
    23  				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    24  					return decodeErrCodeCorrupt
    25  				}
    26  				x = uint32(src[s-1])
    27  			case x == 61:
    28  				s += 3
    29  				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    30  					return decodeErrCodeCorrupt
    31  				}
    32  				x = uint32(src[s-2]) | uint32(src[s-1])<<8
    33  			case x == 62:
    34  				s += 4
    35  				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    36  					return decodeErrCodeCorrupt
    37  				}
    38  				x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
    39  			case x == 63:
    40  				s += 5
    41  				if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    42  					return decodeErrCodeCorrupt
    43  				}
    44  				x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
    45  			}
    46  			length = int(x) + 1
    47  			if length <= 0 {
    48  				return decodeErrCodeUnsupportedLiteralLength
    49  			}
    50  			if length > len(dst)-d || length > len(src)-s {
    51  				return decodeErrCodeCorrupt
    52  			}
    53  			copy(dst[d:], src[s:s+length])
    54  			d += length
    55  			s += length
    56  			continue
    57  
    58  		case tagCopy1:
    59  			s += 2
    60  			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    61  				return decodeErrCodeCorrupt
    62  			}
    63  			length = 4 + int(src[s-2])>>2&0x7
    64  			offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
    65  
    66  		case tagCopy2:
    67  			s += 3
    68  			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    69  				return decodeErrCodeCorrupt
    70  			}
    71  			length = 1 + int(src[s-3])>>2
    72  			offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
    73  
    74  		case tagCopy4:
    75  			s += 5
    76  			if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
    77  				return decodeErrCodeCorrupt
    78  			}
    79  			length = 1 + int(src[s-5])>>2
    80  			offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
    81  		}
    82  
    83  		if offset <= 0 || d < offset || length > len(dst)-d {
    84  			return decodeErrCodeCorrupt
    85  		}
    86  		// Copy from an earlier sub-slice of dst to a later sub-slice.
    87  		// If no overlap, use the built-in copy:
    88  		if offset >= length {
    89  			copy(dst[d:d+length], dst[d-offset:])
    90  			d += length
    91  			continue
    92  		}
    93  
    94  		// Unlike the built-in copy function, this byte-by-byte copy always runs
    95  		// forwards, even if the slices overlap. Conceptually, this is:
    96  		//
    97  		// d += forwardCopy(dst[d:d+length], dst[d-offset:])
    98  		//
    99  		// We align the slices into a and b and show the compiler they are the same size.
   100  		// This allows the loop to run without bounds checks.
   101  		a := dst[d : d+length]
   102  		b := dst[d-offset:]
   103  		b = b[:len(a)]
   104  		for i := range a {
   105  			a[i] = b[i]
   106  		}
   107  		d += length
   108  	}
   109  	if d != len(dst) {
   110  		return decodeErrCodeCorrupt
   111  	}
   112  	return 0
   113  }