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  }