github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/ethutil/rlp.go (about) 1 package ethutil 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/big" 7 "reflect" 8 ) 9 10 type RlpEncode interface { 11 RlpEncode() []byte 12 } 13 14 type RlpEncodeDecode interface { 15 RlpEncode 16 RlpValue() []interface{} 17 } 18 19 type RlpEncodable interface { 20 RlpData() interface{} 21 } 22 23 func Rlp(encoder RlpEncode) []byte { 24 return encoder.RlpEncode() 25 } 26 27 type RlpEncoder struct { 28 rlpData []byte 29 } 30 31 func NewRlpEncoder() *RlpEncoder { 32 encoder := &RlpEncoder{} 33 34 return encoder 35 } 36 func (coder *RlpEncoder) EncodeData(rlpData interface{}) []byte { 37 return Encode(rlpData) 38 } 39 40 const ( 41 RlpEmptyList = 0x80 42 RlpEmptyStr = 0x40 43 ) 44 45 const rlpEof = -1 46 47 func Char(c []byte) int { 48 if len(c) > 0 { 49 return int(c[0]) 50 } 51 52 return rlpEof 53 } 54 55 func DecodeWithReader(reader *bytes.Buffer) interface{} { 56 var slice []interface{} 57 58 // Read the next byte 59 char := Char(reader.Next(1)) 60 switch { 61 case char <= 0x7f: 62 return char 63 64 case char <= 0xb7: 65 return reader.Next(int(char - 0x80)) 66 67 case char <= 0xbf: 68 length := ReadVarInt(reader.Next(int(char - 0xb7))) 69 70 return reader.Next(int(length)) 71 72 case char <= 0xf7: 73 length := int(char - 0xc0) 74 for i := 0; i < length; i++ { 75 obj := DecodeWithReader(reader) 76 slice = append(slice, obj) 77 } 78 79 return slice 80 case char <= 0xff: 81 length := ReadVarInt(reader.Next(int(char - 0xf7))) 82 for i := uint64(0); i < length; i++ { 83 obj := DecodeWithReader(reader) 84 slice = append(slice, obj) 85 } 86 87 return slice 88 default: 89 panic(fmt.Sprintf("byte not supported: %q", char)) 90 } 91 92 return slice 93 } 94 95 var ( 96 directRlp = big.NewInt(0x7f) 97 numberRlp = big.NewInt(0xb7) 98 zeroRlp = big.NewInt(0x0) 99 ) 100 101 func intlen(i int64) (length int) { 102 for i > 0 { 103 i = i >> 8 104 length++ 105 } 106 return 107 } 108 109 func Encode(object interface{}) []byte { 110 var buff bytes.Buffer 111 112 if object != nil { 113 switch t := object.(type) { 114 case *Value: 115 buff.Write(Encode(t.Raw())) 116 case RlpEncodable: 117 buff.Write(Encode(t.RlpData())) 118 // Code dup :-/ 119 case int: 120 buff.Write(Encode(big.NewInt(int64(t)))) 121 case uint: 122 buff.Write(Encode(big.NewInt(int64(t)))) 123 case int8: 124 buff.Write(Encode(big.NewInt(int64(t)))) 125 case int16: 126 buff.Write(Encode(big.NewInt(int64(t)))) 127 case int32: 128 buff.Write(Encode(big.NewInt(int64(t)))) 129 case int64: 130 buff.Write(Encode(big.NewInt(t))) 131 case uint16: 132 buff.Write(Encode(big.NewInt(int64(t)))) 133 case uint32: 134 buff.Write(Encode(big.NewInt(int64(t)))) 135 case uint64: 136 buff.Write(Encode(big.NewInt(int64(t)))) 137 case byte: 138 buff.Write(Encode(big.NewInt(int64(t)))) 139 case *big.Int: 140 // Not sure how this is possible while we check for nil 141 if t == nil { 142 buff.WriteByte(0xc0) 143 } else { 144 buff.Write(Encode(t.Bytes())) 145 } 146 case Bytes: 147 buff.Write(Encode([]byte(t))) 148 case []byte: 149 if len(t) == 1 && t[0] <= 0x7f { 150 buff.Write(t) 151 } else if len(t) < 56 { 152 buff.WriteByte(byte(len(t) + 0x80)) 153 buff.Write(t) 154 } else { 155 b := big.NewInt(int64(len(t))) 156 buff.WriteByte(byte(len(b.Bytes()) + 0xb7)) 157 buff.Write(b.Bytes()) 158 buff.Write(t) 159 } 160 case string: 161 buff.Write(Encode([]byte(t))) 162 case []interface{}: 163 // Inline function for writing the slice header 164 WriteSliceHeader := func(length int) { 165 if length < 56 { 166 buff.WriteByte(byte(length + 0xc0)) 167 } else { 168 b := big.NewInt(int64(length)) 169 buff.WriteByte(byte(len(b.Bytes()) + 0xf7)) 170 buff.Write(b.Bytes()) 171 } 172 } 173 174 var b bytes.Buffer 175 for _, val := range t { 176 b.Write(Encode(val)) 177 } 178 WriteSliceHeader(len(b.Bytes())) 179 buff.Write(b.Bytes()) 180 default: 181 // This is how it should have been from the start 182 // needs refactoring (@fjl) 183 v := reflect.ValueOf(t) 184 switch v.Kind() { 185 case reflect.Slice: 186 var b bytes.Buffer 187 for i := 0; i < v.Len(); i++ { 188 b.Write(Encode(v.Index(i).Interface())) 189 } 190 191 blen := b.Len() 192 if blen < 56 { 193 buff.WriteByte(byte(blen) + 0xc0) 194 } else { 195 ilen := byte(intlen(int64(blen))) 196 buff.WriteByte(ilen + 0xf7) 197 t := make([]byte, ilen) 198 for i := byte(0); i < ilen; i++ { 199 t[ilen-i-1] = byte(blen >> (i * 8)) 200 } 201 buff.Write(t) 202 } 203 buff.ReadFrom(&b) 204 } 205 } 206 } else { 207 // Empty list for nil 208 buff.WriteByte(0xc0) 209 } 210 211 return buff.Bytes() 212 } 213 214 // TODO Use a bytes.Buffer instead of a raw byte slice. 215 // Cleaner code, and use draining instead of seeking the next bytes to read 216 func Decode(data []byte, pos uint64) (interface{}, uint64) { 217 var slice []interface{} 218 char := int(data[pos]) 219 switch { 220 case char <= 0x7f: 221 return data[pos], pos + 1 222 223 case char <= 0xb7: 224 b := uint64(data[pos]) - 0x80 225 226 return data[pos+1 : pos+1+b], pos + 1 + b 227 228 case char <= 0xbf: 229 b := uint64(data[pos]) - 0xb7 230 231 b2 := ReadVarInt(data[pos+1 : pos+1+b]) 232 233 return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 234 235 case char <= 0xf7: 236 b := uint64(data[pos]) - 0xc0 237 prevPos := pos 238 pos++ 239 for i := uint64(0); i < b; { 240 var obj interface{} 241 242 // Get the next item in the data list and append it 243 obj, prevPos = Decode(data, pos) 244 slice = append(slice, obj) 245 246 // Increment i by the amount bytes read in the previous 247 // read 248 i += (prevPos - pos) 249 pos = prevPos 250 } 251 return slice, pos 252 253 case char <= 0xff: 254 l := uint64(data[pos]) - 0xf7 255 b := ReadVarInt(data[pos+1 : pos+1+l]) 256 257 pos = pos + l + 1 258 259 prevPos := b 260 for i := uint64(0); i < uint64(b); { 261 var obj interface{} 262 263 obj, prevPos = Decode(data, pos) 264 slice = append(slice, obj) 265 266 i += (prevPos - pos) 267 pos = prevPos 268 } 269 return slice, pos 270 271 default: 272 panic(fmt.Sprintf("byte not supported: %q", char)) 273 } 274 275 return slice, 0 276 }