// Copyright 2011 The Snappy-Go Authors. All rights reserved.// Copyright (c) 2019 Klaus Post. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package s2import ()var (// ErrCorrupt reports that the input is invalid.ErrCorrupt = errors.New("s2: corrupt input")// ErrCRC reports that the input failed CRC validation (streams only)ErrCRC = errors.New("s2: corrupt input, crc mismatch")// ErrTooLarge reports that the uncompressed length is too large.ErrTooLarge = errors.New("s2: decoded block is too large")// ErrUnsupported reports that the input isn't supported.ErrUnsupported = errors.New("s2: unsupported input"))// DecodedLen returns the length of the decoded block.func ( []byte) (int, error) { , , := decodedLen()return , }// decodedLen returns the length of the decoded block and the number of bytes// that the length header occupied.func decodedLen( []byte) (, int, error) { , := binary.Uvarint()if <= 0 || > 0xffffffff {return0, 0, ErrCorrupt }const = 32 << (^uint(0) >> 32 & 1)if == 32 && > 0x7fffffff {return0, 0, ErrTooLarge }returnint(), , nil}const ( decodeErrCodeCorrupt = 1)// Decode returns the decoded form of src. The returned slice may be a sub-// slice of dst if dst was large enough to hold the entire decoded block.// Otherwise, a newly allocated slice will be returned.//// The dst and src must not overlap. It is valid to pass a nil dst.func (, []byte) ([]byte, error) { , , := decodedLen()if != nil {returnnil, }if <= cap() { = [:] } else { = make([]byte, ) }race.WriteSlice()race.ReadSlice([:])ifs2Decode(, [:]) != 0 {returnnil, ErrCorrupt }return , nil}// s2DecodeDict writes the decoding of src to dst. It assumes that the varint-encoded// length of the decompressed bytes has already been read, and that len(dst)// equals that length.//// It returns 0 on success or a decodeErrCodeXxx error code on failure.func s2DecodeDict(, []byte, *Dict) int {if == nil {returns2Decode(, ) }const = falseconst = if {fmt.Println("Starting decode, dst len:", len()) }var , , int := len(.dict) - .repeat// As long as we can read at least 5 bytes...for < len()-5 {// Removing bounds checks is SLOWER, when if doing // in := src[s:s+5] // Checked on Go 1.18switch [] & 0x03 {casetagLiteral: := uint32([] >> 2)switch {case < 60: ++case == 60: += 2 = uint32([-1])case == 61: := [ : +3] = uint32([1]) | uint32([2])<<8 += 3case == 62: := [ : +4]// Load as 32 bit and shift down. = uint32([0]) | uint32([1])<<8 | uint32([2])<<16 | uint32([3])<<24 >>= 8 += 4case == 63: := [ : +5] = uint32([1]) | uint32([2])<<8 | uint32([3])<<16 | uint32([4])<<24 += 5 } = int() + 1if {fmt.Println("literals, length:", , "d-after:", +) }if > len()- || > len()- || (strconv.IntSize == 32 && <= 0) {if {fmt.Println("corrupt literal: length:", , "d-left:", len()-, "src-left:", len()-) }returndecodeErrCodeCorrupt }copy([:], [:+]) += += continuecasetagCopy1: += 2 := int(uint32([-2])&0xe0<<3 | uint32([-1])) = int([-2]) >> 2 & 0x7if == 0 {if {fmt.Print("(repeat) ") }// keep last offsetswitch {case5: = int([]) + 4 += 1case6: := [ : +2] = int(uint32([0])|(uint32([1])<<8)) + (1 << 8) += 2case7: := [ : +3] = int((uint32([2])<<16)|(uint32([1])<<8)|uint32([0])) + (1 << 16) += 3default: // 0-> 4 } } else { = } += 4casetagCopy2: := [ : +3] = int(uint32([1]) | uint32([2])<<8) = 1 + int([0])>>2 += 3casetagCopy4: := [ : +5] = int(uint32([1]) | uint32([2])<<8 | uint32([3])<<16 | uint32([4])<<24) = 1 + int([0])>>2 += 5 }if <= 0 || > len()- {if {fmt.Println("match error; offset:", , "length:", , "dst-left:", len()-) }returndecodeErrCodeCorrupt }// copy from dictif < {if > MaxDictSrcOffset {if {fmt.Println("dict after", MaxDictSrcOffset, "d:", , "offset:", , "length:", ) }returndecodeErrCodeCorrupt } := len(.dict) - + if < 0 || + > len(.dict) {if {fmt.Printf("offset (%d) + length (%d) bigger than dict (%d)\n", , , len(.dict)) }returndecodeErrCodeCorrupt }if {fmt.Println("dict copy, length:", , "offset:", , "d-after:", +, "dict start offset:", ) }copy([:+], .dict[:]) += continue }if {fmt.Println("copy, length:", , "offset:", , "d-after:", +) }// Copy from an earlier sub-slice of dst to a later sub-slice. // If no overlap, use the built-in copy:if > {copy([:+], [-:]) += continue }// Unlike the built-in copy function, this byte-by-byte copy always runs // forwards, even if the slices overlap. Conceptually, this is: // // d += forwardCopy(dst[d:d+length], dst[d-offset:]) // // We align the slices into a and b and show the compiler they are the same size. // This allows the loop to run without bounds checks. := [ : +] := [-:] = [:len()]for := range { [] = [] } += }// Remaining with extra checks...for < len() {switch [] & 0x03 {casetagLiteral: := uint32([] >> 2)switch {case < 60: ++case == 60: += 2ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = uint32([-1])case == 61: += 3ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = uint32([-2]) | uint32([-1])<<8case == 62: += 4ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = uint32([-3]) | uint32([-2])<<8 | uint32([-1])<<16case == 63: += 5ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = uint32([-4]) | uint32([-3])<<8 | uint32([-2])<<16 | uint32([-1])<<24 } = int() + 1if > len()- || > len()- || (strconv.IntSize == 32 && <= 0) {if {fmt.Println("corrupt literal: length:", , "d-left:", len()-, "src-left:", len()-) }returndecodeErrCodeCorrupt }if {fmt.Println("literals, length:", , "d-after:", +) }copy([:], [:+]) += += continuecasetagCopy1: += 2ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = int([-2]) >> 2 & 0x7 := int(uint32([-2])&0xe0<<3 | uint32([-1]))if == 0 {if {fmt.Print("(repeat) ") }// keep last offsetswitch {case5: += 1ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = int(uint32([-1])) + 4case6: += 2ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = int(uint32([-2])|(uint32([-1])<<8)) + (1 << 8)case7: += 3ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = int(uint32([-3])|(uint32([-2])<<8)|(uint32([-1])<<16)) + (1 << 16)default: // 0-> 4 } } else { = } += 4casetagCopy2: += 3ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = 1 + int([-3])>>2 = int(uint32([-2]) | uint32([-1])<<8)casetagCopy4: += 5ifuint() > uint(len()) { // The uint conversions catch overflow from the previous line.if {fmt.Println("src went oob") }returndecodeErrCodeCorrupt } = 1 + int([-5])>>2 = int(uint32([-4]) | uint32([-3])<<8 | uint32([-2])<<16 | uint32([-1])<<24) }if <= 0 || > len()- {if {fmt.Println("match error; offset:", , "length:", , "dst-left:", len()-) }returndecodeErrCodeCorrupt }// copy from dictif < {if > MaxDictSrcOffset {if {fmt.Println("dict after", MaxDictSrcOffset, "d:", , "offset:", , "length:", ) }returndecodeErrCodeCorrupt } := len(.dict) - ( - )if {fmt.Println("starting dict entry from dict offset", len(.dict)-) }if + > len(.dict) {if {fmt.Println("err: END offset", +, "bigger than dict", len(.dict), "dict offset:", , "length:", ) }returndecodeErrCodeCorrupt }if < 0 {if {fmt.Println("err: START offset", , "less than 0", len(.dict), "dict offset:", , "length:", ) }returndecodeErrCodeCorrupt }copy([:+], .dict[:]) += continue }if {fmt.Println("copy, length:", , "offset:", , "d-after:", +) }// Copy from an earlier sub-slice of dst to a later sub-slice. // If no overlap, use the built-in copy:if > {copy([:+], [-:]) += continue }// Unlike the built-in copy function, this byte-by-byte copy always runs // forwards, even if the slices overlap. Conceptually, this is: // // d += forwardCopy(dst[d:d+length], dst[d-offset:]) // // We align the slices into a and b and show the compiler they are the same size. // This allows the loop to run without bounds checks. := [ : +] := [-:] = [:len()]for := range { [] = [] } += }if != len() {if {fmt.Println("wanted length", len(), "got", ) }returndecodeErrCodeCorrupt }return0}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.