read_write.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package rle
  2. import (
  3. "bytes"
  4. "errors"
  5. "github.com/ethereum/go-ethereum/crypto"
  6. )
  7. const (
  8. token byte = 0xfe
  9. emptyShaToken = 0xfd
  10. emptyListShaToken = 0xfe
  11. tokenToken = 0xff
  12. )
  13. var empty = crypto.Sha3([]byte(""))
  14. var emptyList = crypto.Sha3([]byte{0x80})
  15. func Decompress(dat []byte) ([]byte, error) {
  16. buf := new(bytes.Buffer)
  17. for i := 0; i < len(dat); i++ {
  18. if dat[i] == token {
  19. if i+1 < len(dat) {
  20. switch dat[i+1] {
  21. case emptyShaToken:
  22. buf.Write(empty)
  23. case emptyListShaToken:
  24. buf.Write(emptyList)
  25. case tokenToken:
  26. buf.WriteByte(token)
  27. default:
  28. buf.Write(make([]byte, int(dat[i+1]-2)))
  29. }
  30. i++
  31. } else {
  32. return nil, errors.New("error reading bytes. token encountered without proceeding bytes")
  33. }
  34. } else {
  35. buf.WriteByte(dat[i])
  36. }
  37. }
  38. return buf.Bytes(), nil
  39. }
  40. func compressChunk(dat []byte) (ret []byte, n int) {
  41. switch {
  42. case dat[0] == token:
  43. return []byte{token, tokenToken}, 1
  44. case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0:
  45. j := 0
  46. for j <= 254 && j < len(dat) {
  47. if dat[j] != 0 {
  48. break
  49. }
  50. j++
  51. }
  52. return []byte{token, byte(j + 2)}, j
  53. case len(dat) >= 32:
  54. if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 {
  55. return []byte{token, emptyShaToken}, 32
  56. } else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 {
  57. return []byte{token, emptyListShaToken}, 32
  58. }
  59. fallthrough
  60. default:
  61. return dat[:1], 1
  62. }
  63. }
  64. func Compress(dat []byte) []byte {
  65. buf := new(bytes.Buffer)
  66. i := 0
  67. for i < len(dat) {
  68. b, n := compressChunk(dat[i:])
  69. buf.Write(b)
  70. i += n
  71. }
  72. return buf.Bytes()
  73. }