rlp: add Stream.Raw

This commit is contained in:
Felix Lange 2015-03-21 00:49:31 +01:00
parent 81800ca39e
commit a829a56587
3 changed files with 60 additions and 13 deletions

View File

@ -540,6 +540,31 @@ func (s *Stream) Bytes() ([]byte, error) {
} }
} }
// Raw reads a raw encoded value including RLP type information.
func (s *Stream) Raw() ([]byte, error) {
kind, size, err := s.Kind()
if err != nil {
return nil, err
}
if kind == Byte {
s.kind = -1 // rearm Kind
return []byte{s.byteval}, nil
}
// the original header has already been read and is no longer
// available. read content and put a new header in front of it.
start := headsize(size)
buf := make([]byte, uint64(start)+size)
if err := s.readFull(buf[start:]); err != nil {
return nil, err
}
if kind == String {
puthead(buf, 0x80, 0xB8, size)
} else {
puthead(buf, 0xC0, 0xF7, size)
}
return buf, nil
}
var errUintOverflow = errors.New("rlp: uint overflow") var errUintOverflow = errors.New("rlp: uint overflow")
// Uint reads an RLP string of up to 8 bytes and returns its contents // Uint reads an RLP string of up to 8 bytes and returns its contents

View File

@ -165,6 +165,20 @@ func TestStreamList(t *testing.T) {
} }
} }
func TestStreamRaw(t *testing.T) {
s := NewStream(bytes.NewReader(unhex("C58401010101")))
s.List()
want := unhex("8401010101")
raw, err := s.Raw()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(want, raw) {
t.Errorf("raw mismatch: got %x, want %x", raw, want)
}
}
func TestDecodeErrors(t *testing.T) { func TestDecodeErrors(t *testing.T) {
r := bytes.NewReader(nil) r := bytes.NewReader(nil)
@ -331,7 +345,7 @@ var decodeTests = []decodeTest{
{input: "C109", ptr: new(*[]uint), value: &[]uint{9}}, {input: "C109", ptr: new(*[]uint), value: &[]uint{9}},
{input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}}, {input: "C58403030303", ptr: new(*[][]byte), value: &[][]byte{{3, 3, 3, 3}}},
// check that input position is advanced also empty values. // check that input position is advanced also for empty values.
{input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}}, {input: "C3808005", ptr: new([]*uint), value: []*uint{nil, nil, uintp(5)}},
// pointer should be reset to nil // pointer should be reset to nil

View File

@ -70,7 +70,7 @@ func (e flatenc) EncodeRLP(out io.Writer) error {
newhead := eb.lheads[prevnheads] newhead := eb.lheads[prevnheads]
copy(eb.lheads[prevnheads:], eb.lheads[prevnheads+1:]) copy(eb.lheads[prevnheads:], eb.lheads[prevnheads+1:])
eb.lheads = eb.lheads[:len(eb.lheads)-1] eb.lheads = eb.lheads[:len(eb.lheads)-1]
eb.lhsize -= newhead.tagsize() eb.lhsize -= headsize(uint64(newhead.size))
return nil return nil
} }
@ -155,21 +155,29 @@ type listhead struct {
// encode writes head to the given buffer, which must be at least // encode writes head to the given buffer, which must be at least
// 9 bytes long. It returns the encoded bytes. // 9 bytes long. It returns the encoded bytes.
func (head *listhead) encode(buf []byte) []byte { func (head *listhead) encode(buf []byte) []byte {
if head.size < 56 { return buf[:puthead(buf, 0xC0, 0xF7, uint64(head.size))]
buf[0] = 0xC0 + byte(head.size)
return buf[:1]
} else {
sizesize := putint(buf[1:], uint64(head.size))
buf[0] = 0xF7 + byte(sizesize)
return buf[:sizesize+1]
}
} }
func (head *listhead) tagsize() int { // headsize returns the size of a list or string header
if head.size < 56 { // for a value of the given size.
func headsize(size uint64) int {
if size < 56 {
return 1 return 1
} }
return 1 + intsize(uint64(head.size)) return 1 + intsize(size)
}
// puthead writes a list or string header to buf.
// buf must be at least 9 bytes long.
func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
if size < 56 {
buf[0] = smalltag + byte(size)
return 1
} else {
sizesize := putint(buf[1:], size)
buf[0] = largetag + byte(sizesize)
return sizesize + 1
}
} }
func newencbuf() *encbuf { func newencbuf() *encbuf {