read_write.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright 2014 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package rle implements the run-length encoding used for Ethereum data.
  17. package rle
  18. import (
  19. "bytes"
  20. "errors"
  21. "github.com/ethereum/go-ethereum/crypto"
  22. )
  23. const (
  24. token byte = 0xfe
  25. emptyShaToken = 0xfd
  26. emptyListShaToken = 0xfe
  27. tokenToken = 0xff
  28. )
  29. var empty = crypto.Sha3([]byte(""))
  30. var emptyList = crypto.Sha3([]byte{0x80})
  31. func Decompress(dat []byte) ([]byte, error) {
  32. buf := new(bytes.Buffer)
  33. for i := 0; i < len(dat); i++ {
  34. if dat[i] == token {
  35. if i+1 < len(dat) {
  36. switch dat[i+1] {
  37. case emptyShaToken:
  38. buf.Write(empty)
  39. case emptyListShaToken:
  40. buf.Write(emptyList)
  41. case tokenToken:
  42. buf.WriteByte(token)
  43. default:
  44. buf.Write(make([]byte, int(dat[i+1]-2)))
  45. }
  46. i++
  47. } else {
  48. return nil, errors.New("error reading bytes. token encountered without proceeding bytes")
  49. }
  50. } else {
  51. buf.WriteByte(dat[i])
  52. }
  53. }
  54. return buf.Bytes(), nil
  55. }
  56. func compressChunk(dat []byte) (ret []byte, n int) {
  57. switch {
  58. case dat[0] == token:
  59. return []byte{token, tokenToken}, 1
  60. case len(dat) > 1 && dat[0] == 0x0 && dat[1] == 0x0:
  61. j := 0
  62. for j <= 254 && j < len(dat) {
  63. if dat[j] != 0 {
  64. break
  65. }
  66. j++
  67. }
  68. return []byte{token, byte(j + 2)}, j
  69. case len(dat) >= 32:
  70. if dat[0] == empty[0] && bytes.Compare(dat[:32], empty) == 0 {
  71. return []byte{token, emptyShaToken}, 32
  72. } else if dat[0] == emptyList[0] && bytes.Compare(dat[:32], emptyList) == 0 {
  73. return []byte{token, emptyListShaToken}, 32
  74. }
  75. fallthrough
  76. default:
  77. return dat[:1], 1
  78. }
  79. }
  80. func Compress(dat []byte) []byte {
  81. buf := new(bytes.Buffer)
  82. i := 0
  83. for i < len(dat) {
  84. b, n := compressChunk(dat[i:])
  85. buf.Write(b)
  86. i += n
  87. }
  88. return buf.Bytes()
  89. }