github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/snappy-go/snappy/decode.go (about) 1 // Copyright 2011 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 snappy 6 7 import ( 8 "encoding/binary" 9 "errors" 10 ) 11 12 // ErrCorrupt reports that the input is invalid. 13 var ErrCorrupt = errors.New("snappy: corrupt input") 14 15 // DecodedLen returns the length of the decoded block. 16 func DecodedLen(src []byte) (int, error) { 17 v, _, err := decodedLen(src) 18 return v, err 19 } 20 21 // decodedLen returns the length of the decoded block and the number of bytes 22 // that the length header occupied. 23 func decodedLen(src []byte) (blockLen, headerLen int, err error) { 24 v, n := binary.Uvarint(src) 25 if n == 0 { 26 return 0, 0, ErrCorrupt 27 } 28 if uint64(int(v)) != v { 29 return 0, 0, errors.New("snappy: decoded block is too large") 30 } 31 return int(v), n, nil 32 } 33 34 // Decode returns the decoded form of src. The returned slice may be a sub- 35 // slice of dst if dst was large enough to hold the entire decoded block. 36 // Otherwise, a newly allocated slice will be returned. 37 // It is valid to pass a nil dst. 38 func Decode(dst, src []byte) ([]byte, error) { 39 dLen, s, err := decodedLen(src) 40 if err != nil { 41 return nil, err 42 } 43 if len(dst) < dLen { 44 dst = make([]byte, dLen) 45 } 46 47 var d, offset, length int 48 for s < len(src) { 49 switch src[s] & 0x03 { 50 case tagLiteral: 51 x := uint(src[s] >> 2) 52 switch { 53 case x < 60: 54 s += 1 55 case x == 60: 56 s += 2 57 if s > len(src) { 58 return nil, ErrCorrupt 59 } 60 x = uint(src[s-1]) 61 case x == 61: 62 s += 3 63 if s > len(src) { 64 return nil, ErrCorrupt 65 } 66 x = uint(src[s-2]) | uint(src[s-1])<<8 67 case x == 62: 68 s += 4 69 if s > len(src) { 70 return nil, ErrCorrupt 71 } 72 x = uint(src[s-3]) | uint(src[s-2])<<8 | uint(src[s-1])<<16 73 case x == 63: 74 s += 5 75 if s > len(src) { 76 return nil, ErrCorrupt 77 } 78 x = uint(src[s-4]) | uint(src[s-3])<<8 | uint(src[s-2])<<16 | uint(src[s-1])<<24 79 } 80 length = int(x + 1) 81 if length <= 0 { 82 return nil, errors.New("snappy: unsupported literal length") 83 } 84 if length > len(dst)-d || length > len(src)-s { 85 return nil, ErrCorrupt 86 } 87 copy(dst[d:], src[s:s+length]) 88 d += length 89 s += length 90 continue 91 92 case tagCopy1: 93 s += 2 94 if s > len(src) { 95 return nil, ErrCorrupt 96 } 97 length = 4 + int(src[s-2])>>2&0x7 98 offset = int(src[s-2])&0xe0<<3 | int(src[s-1]) 99 100 case tagCopy2: 101 s += 3 102 if s > len(src) { 103 return nil, ErrCorrupt 104 } 105 length = 1 + int(src[s-3])>>2 106 offset = int(src[s-2]) | int(src[s-1])<<8 107 108 case tagCopy4: 109 return nil, errors.New("snappy: unsupported COPY_4 tag") 110 } 111 112 end := d + length 113 if offset > d || end > len(dst) { 114 return nil, ErrCorrupt 115 } 116 for ; d < end; d++ { 117 dst[d] = dst[d-offset] 118 } 119 } 120 return dst, nil 121 }