snappy.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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. var max = len(src)
  26. if max < len(xerialHeader) {
  27. return nil, ErrMalformed
  28. }
  29. if !bytes.Equal(src[:8], xerialHeader) {
  30. return master.Decode(nil, src)
  31. }
  32. if max < sizeOffset+sizeBytes {
  33. return nil, ErrMalformed
  34. }
  35. var (
  36. pos = sizeOffset
  37. dst = make([]byte, 0, len(src))
  38. chunk []byte
  39. err error
  40. )
  41. for pos+sizeBytes <= max {
  42. size := int(binary.BigEndian.Uint32(src[pos : pos+sizeBytes]))
  43. pos += sizeBytes
  44. nextPos := pos + size
  45. // On architectures where int is 32-bytes wide size + pos could
  46. // overflow so we need to check the low bound as well as the
  47. // high
  48. if nextPos < pos || nextPos > max {
  49. return nil, ErrMalformed
  50. }
  51. chunk, err = master.Decode(chunk, src[pos:nextPos])
  52. if err != nil {
  53. return nil, err
  54. }
  55. pos = nextPos
  56. dst = append(dst, chunk...)
  57. }
  58. return dst, nil
  59. }