snappy.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package snappy
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. master "github.com/golang/snappy"
  7. )
  8. const (
  9. sizeOffset = 16
  10. sizeBytes = 4
  11. )
  12. var (
  13. xerialHeader = []byte{130, 83, 78, 65, 80, 80, 89, 0}
  14. // ErrMalformed is returned by the decoder when the xerial framing
  15. // is malformed
  16. ErrMalformed = errors.New("malformed xerial framing")
  17. )
  18. // Encode encodes data as snappy with no framing header.
  19. func Encode(src []byte) []byte {
  20. return master.Encode(nil, src)
  21. }
  22. // Decode decodes snappy data whether it is traditional unframed
  23. // or includes the xerial framing format.
  24. func Decode(src []byte) ([]byte, error) {
  25. return DecodeInto(nil, src)
  26. }
  27. // DecodeInto decodes snappy data whether it is traditional unframed
  28. // or includes the xerial framing format into the specified `dst`.
  29. // It is assumed that the entirety of `dst` including all capacity is available
  30. // for use by this function. If `dst` is nil *or* insufficiently large to hold
  31. // the decoded `src`, new space will be allocated.
  32. func DecodeInto(dst, src []byte) ([]byte, error) {
  33. var max = len(src)
  34. if max < len(xerialHeader) {
  35. return nil, ErrMalformed
  36. }
  37. if !bytes.Equal(src[:8], xerialHeader) {
  38. return master.Decode(dst[:cap(dst)], src)
  39. }
  40. if max < sizeOffset+sizeBytes {
  41. return nil, ErrMalformed
  42. }
  43. if dst == nil {
  44. dst = make([]byte, 0, len(src))
  45. }
  46. dst = dst[:0]
  47. var (
  48. pos = sizeOffset
  49. chunk []byte
  50. err error
  51. )
  52. for pos+sizeBytes <= max {
  53. size := int(binary.BigEndian.Uint32(src[pos : pos+sizeBytes]))
  54. pos += sizeBytes
  55. nextPos := pos + size
  56. // On architectures where int is 32-bytes wide size + pos could
  57. // overflow so we need to check the low bound as well as the
  58. // high
  59. if nextPos < pos || nextPos > max {
  60. return nil, ErrMalformed
  61. }
  62. chunk, err = master.Decode(chunk[:cap(chunk)], src[pos:nextPos])
  63. if err != nil {
  64. return nil, err
  65. }
  66. pos = nextPos
  67. dst = append(dst, chunk...)
  68. }
  69. return dst, nil
  70. }