forked from mirror/go-ethereum
parent
12c0e82703
commit
fedbd9a962
@ -1,279 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"github.com/ethereum/ethutil-go" |
||||
"math" |
||||
"math/big" |
||||
) |
||||
|
||||
type RlpEncoder struct { |
||||
rlpData []byte |
||||
} |
||||
|
||||
func NewRlpEncoder() *RlpEncoder { |
||||
encoder := &RlpEncoder{} |
||||
|
||||
return encoder |
||||
} |
||||
func (coder *RlpEncoder) EncodeData(rlpData []interface{}) []byte { |
||||
return nil |
||||
} |
||||
|
||||
// Data attributes are returned by the rlp decoder. The data attributes represents
|
||||
// one item within the rlp data structure. It's responsible for all the casting
|
||||
// It always returns something valid
|
||||
type RlpDataAttribute struct { |
||||
dataAttrib interface{} |
||||
} |
||||
|
||||
func NewRlpDataAttribute(attrib interface{}) *RlpDataAttribute { |
||||
return &RlpDataAttribute{dataAttrib: attrib} |
||||
} |
||||
|
||||
func (attr *RlpDataAttribute) Length() int { |
||||
if data, ok := attr.dataAttrib.([]interface{}); ok { |
||||
return len(data) |
||||
} |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
|
||||
func (attr *RlpDataAttribute) AsUint() uint64 { |
||||
if value, ok := attr.dataAttrib.(uint8); ok { |
||||
return uint64(value) |
||||
} else if value, ok := attr.dataAttrib.(uint16); ok { |
||||
return uint64(value) |
||||
} else if value, ok := attr.dataAttrib.(uint32); ok { |
||||
return uint64(value) |
||||
} else if value, ok := attr.dataAttrib.(uint64); ok { |
||||
return value |
||||
} |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
func (attr *RlpDataAttribute) AsBigInt() *big.Int { |
||||
if a, ok := attr.dataAttrib.([]byte); ok { |
||||
return ethutil.Big(string(a)) |
||||
} |
||||
|
||||
return big.NewInt(0) |
||||
} |
||||
|
||||
func (attr *RlpDataAttribute) AsString() string { |
||||
if a, ok := attr.dataAttrib.([]byte); ok { |
||||
return string(a) |
||||
} |
||||
|
||||
return "" |
||||
} |
||||
|
||||
func (attr *RlpDataAttribute) AsBytes() []byte { |
||||
if a, ok := attr.dataAttrib.([]byte); ok { |
||||
return a |
||||
} |
||||
|
||||
return make([]byte, 0) |
||||
} |
||||
|
||||
// Threat the attribute as a slice
|
||||
func (attr *RlpDataAttribute) Get(idx int) *RlpDataAttribute { |
||||
if d, ok := attr.dataAttrib.([]interface{}); ok { |
||||
// Guard for oob
|
||||
if len(d) < idx { |
||||
return NewRlpDataAttribute(nil) |
||||
} |
||||
|
||||
return NewRlpDataAttribute(d[idx]) |
||||
} |
||||
|
||||
// If this wasn't a slice you probably shouldn't be using this function
|
||||
return NewRlpDataAttribute(nil) |
||||
} |
||||
|
||||
type RlpDecoder struct { |
||||
rlpData interface{} |
||||
} |
||||
|
||||
func NewRlpDecoder(rlpData []byte) *RlpDecoder { |
||||
decoder := &RlpDecoder{} |
||||
// Decode the data
|
||||
data, _ := Decode(rlpData, 0) |
||||
decoder.rlpData = data |
||||
|
||||
return decoder |
||||
} |
||||
|
||||
func (dec *RlpDecoder) Get(idx int) *RlpDataAttribute { |
||||
return NewRlpDataAttribute(dec.rlpData).Get(idx) |
||||
} |
||||
|
||||
/// Raw methods
|
||||
func BinaryLength(n uint64) uint64 { |
||||
if n == 0 { |
||||
return 0 |
||||
} |
||||
|
||||
return 1 + BinaryLength(n/256) |
||||
} |
||||
|
||||
func ToBinarySlice(n uint64, length uint64) []uint64 { |
||||
if length == 0 { |
||||
length = BinaryLength(n) |
||||
} |
||||
|
||||
if n == 0 { |
||||
return make([]uint64, 1) |
||||
} |
||||
|
||||
slice := ToBinarySlice(n/256, 0) |
||||
slice = append(slice, n%256) |
||||
|
||||
return slice |
||||
} |
||||
|
||||
func ToBin(n uint64, length uint64) string { |
||||
var buf bytes.Buffer |
||||
for _, val := range ToBinarySlice(n, length) { |
||||
buf.WriteString(string(val)) |
||||
} |
||||
|
||||
return buf.String() |
||||
} |
||||
|
||||
func FromBin(data []byte) uint64 { |
||||
if len(data) == 0 { |
||||
return 0 |
||||
} |
||||
|
||||
return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) |
||||
} |
||||
|
||||
func Decode(data []byte, pos int) (interface{}, int) { |
||||
if pos > len(data)-1 { |
||||
panic(fmt.Sprintf("index out of range %d for data %q, l = %d", pos, data, len(data))) |
||||
} |
||||
|
||||
char := int(data[pos]) |
||||
slice := make([]interface{}, 0) |
||||
switch { |
||||
case char < 24: |
||||
return data[pos], pos + 1 |
||||
|
||||
case char < 56: |
||||
b := int(data[pos]) - 23 |
||||
return FromBin(data[pos+1 : pos+1+b]), pos + 1 + b |
||||
|
||||
case char < 64: |
||||
b := int(data[pos]) - 55 |
||||
b2 := int(FromBin(data[pos+1 : pos+1+b])) |
||||
return FromBin(data[pos+1+b : pos+1+b+b2]), pos + 1 + b + b2 |
||||
|
||||
case char < 120: |
||||
b := int(data[pos]) - 64 |
||||
return data[pos+1 : pos+1+b], pos + 1 + b |
||||
|
||||
case char < 128: |
||||
b := int(data[pos]) - 119 |
||||
b2 := int(FromBin(data[pos+1 : pos+1+b])) |
||||
return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 |
||||
|
||||
case char < 184: |
||||
b := int(data[pos]) - 128 |
||||
pos++ |
||||
for i := 0; i < b; i++ { |
||||
var obj interface{} |
||||
|
||||
obj, pos = Decode(data, pos) |
||||
slice = append(slice, obj) |
||||
} |
||||
return slice, pos |
||||
|
||||
case char < 192: |
||||
b := int(data[pos]) - 183 |
||||
//b2 := int(FromBin(data[pos+1 : pos+1+b])) (ref implementation has an unused variable)
|
||||
pos = pos + 1 + b |
||||
for i := 0; i < b; i++ { |
||||
var obj interface{} |
||||
|
||||
obj, pos = Decode(data, pos) |
||||
slice = append(slice, obj) |
||||
} |
||||
return slice, pos |
||||
|
||||
default: |
||||
panic(fmt.Sprintf("byte not supported: %q", char)) |
||||
} |
||||
|
||||
return slice, 0 |
||||
} |
||||
|
||||
func Encode(object interface{}) []byte { |
||||
var buff bytes.Buffer |
||||
|
||||
switch t := object.(type) { |
||||
case uint32, uint64: |
||||
var num uint64 |
||||
if _num, ok := t.(uint64); ok { |
||||
num = _num |
||||
} else if _num, ok := t.(uint32); ok { |
||||
num = uint64(_num) |
||||
} |
||||
|
||||
if num >= 0 && num < 24 { |
||||
buff.WriteString(string(num)) |
||||
} else if num <= uint64(math.Pow(2, 256)) { |
||||
b := ToBin(num, 0) |
||||
buff.WriteString(string(len(b)+23) + b) |
||||
} else { |
||||
b := ToBin(num, 0) |
||||
b2 := ToBin(uint64(len(b)), 0) |
||||
buff.WriteString(string(len(b2)+55) + b2 + b) |
||||
} |
||||
|
||||
case *big.Int: |
||||
buff.Write(Encode(t.String())) |
||||
|
||||
case string: |
||||
if len(t) < 56 { |
||||
buff.WriteString(string(len(t)+64) + t) |
||||
} else { |
||||
b2 := ToBin(uint64(len(t)), 0) |
||||
buff.WriteString(string(len(b2)+119) + b2 + t) |
||||
} |
||||
|
||||
case []byte: |
||||
// Cast the byte slice to a string
|
||||
buff.Write(Encode(string(t))) |
||||
|
||||
case []interface{}, []string: |
||||
// Inline function for writing the slice header
|
||||
WriteSliceHeader := func(length int) { |
||||
if length < 56 { |
||||
buff.WriteByte(byte(length + 128)) |
||||
} else { |
||||
b2 := ToBin(uint64(length), 0) |
||||
buff.WriteByte(byte(len(b2) + 183)) |
||||
buff.WriteString(b2) |
||||
} |
||||
} |
||||
|
||||
// FIXME How can I do this "better"?
|
||||
if interSlice, ok := t.([]interface{}); ok { |
||||
WriteSliceHeader(len(interSlice)) |
||||
for _, val := range interSlice { |
||||
buff.Write(Encode(val)) |
||||
} |
||||
} else if stringSlice, ok := t.([]string); ok { |
||||
WriteSliceHeader(len(stringSlice)) |
||||
for _, val := range stringSlice { |
||||
buff.Write(Encode(val)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
return buff.Bytes() |
||||
} |
@ -1,54 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"testing" |
||||
) |
||||
|
||||
func TestEncode(t *testing.T) { |
||||
strRes := "Cdog" |
||||
|
||||
bytes := Encode("dog") |
||||
|
||||
str := string(bytes) |
||||
if str != strRes { |
||||
t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) |
||||
} |
||||
//dec,_ := Decode(bytes, 0)
|
||||
|
||||
sliceRes := "\x83CdogCgodCcat" |
||||
strs := []string{"dog", "god", "cat"} |
||||
bytes = Encode(strs) |
||||
slice := string(bytes) |
||||
if slice != sliceRes { |
||||
t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) |
||||
} |
||||
|
||||
//dec,_ = Decode(bytes, 0)
|
||||
} |
||||
|
||||
func TestMultiEncode(t *testing.T) { |
||||
inter := []interface{}{ |
||||
[]interface{}{ |
||||
"1", "2", "3", |
||||
}, |
||||
[]string{ |
||||
"string", |
||||
"string2", |
||||
"\x86A0J1234567890A\x00B20A0\x82F395843F657986", |
||||
"\x86A0J1234567890A\x00B20A0\x8cF395843F657986I335612448F524099H16716881A0H13114947G2039362G1507139H16719697G1048387E65360", |
||||
}, |
||||
"test", |
||||
} |
||||
|
||||
bytes := Encode(inter) |
||||
|
||||
Decode(bytes, 0) |
||||
} |
||||
|
||||
func BenchmarkEncodeDecode(b *testing.B) { |
||||
for i := 0; i < b.N; i++ { |
||||
bytes := Encode([]string{"dog", "god", "cat"}) |
||||
Decode(bytes, 0) |
||||
} |
||||
} |
Loading…
Reference in new issue