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  }