github.com/protolambda/zssz@v0.1.5/dec/decoder.go (about) 1 package dec 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "unsafe" 9 ) 10 11 type DecoderFn func(dr *DecodingReader, pointer unsafe.Pointer) error 12 type DryCheckFn func(dr *DecodingReader) error 13 14 type DecodingReader struct { 15 input io.Reader 16 i uint64 17 max uint64 18 fuzzMode bool 19 scratch [32]byte 20 } 21 22 func NewDecodingReader(input io.Reader) *DecodingReader { 23 return &DecodingReader{input: input, i: 0, max: ^uint64(0)} 24 } 25 26 // returns a scope of the SSZ reader. Re-uses same scratchpad. 27 func (dr *DecodingReader) Scope(count uint64) (*DecodingReader, error) { 28 if span := dr.GetBytesSpan(); span < count { 29 return nil, fmt.Errorf("cannot create scoped decoding reader, scope of %d bytes is bigger than parent scope has available space %d", count, span) 30 } 31 return &DecodingReader{input: io.LimitReader(dr.input, int64(count)), i: 0, max: count}, nil 32 } 33 34 func (dr *DecodingReader) EnableFuzzMode() { 35 dr.fuzzMode = true 36 } 37 38 func (dr *DecodingReader) UpdateIndexFromScoped(other *DecodingReader) { 39 dr.i += other.i 40 } 41 42 // how far we have read so far (scoped per container) 43 func (dr *DecodingReader) Index() uint64 { 44 return dr.i 45 } 46 47 // How far we can read (max - i = remaining bytes to read without error). 48 // Note: when a child element is not fixed length, 49 // the parent should set the scope, so that the child can infer its size from it. 50 func (dr *DecodingReader) Max() uint64 { 51 return dr.max 52 } 53 54 func (dr *DecodingReader) checkedIndexUpdate(x uint64) (n int, err error) { 55 v := dr.i + x 56 if v > dr.max { 57 return int(dr.i), fmt.Errorf("cannot read %d bytes, %d beyond scope", x, v-dr.max) 58 } 59 dr.i = v 60 return int(x), nil 61 } 62 63 func (dr *DecodingReader) Skip(count uint64) (int, error) { 64 if n, err := dr.checkedIndexUpdate(count); err != nil { 65 return n, err 66 } 67 switch r := dr.input.(type) { 68 case io.Seeker: 69 n, err := r.Seek(int64(count), io.SeekCurrent) 70 return int(n), err 71 default: 72 n, err := io.CopyN(ioutil.Discard, dr.input, int64(count)) 73 return int(n), err 74 } 75 } 76 77 func (dr *DecodingReader) Read(p []byte) (int, error) { 78 if len(p) == 0 { 79 return 0, nil 80 } 81 if n, err := dr.checkedIndexUpdate(uint64(len(p))); err != nil { 82 return n, err 83 } 84 n := 0 85 for n < len(p) { 86 v, err := dr.input.Read(p[n:]) 87 n += v 88 if err != nil { 89 return n, err 90 } 91 } 92 return n, nil 93 } 94 95 func (dr *DecodingReader) ReadByte() (byte, error) { 96 _, err := dr.Read(dr.scratch[0:1]) 97 return dr.scratch[0], err 98 } 99 100 func (dr *DecodingReader) ReadUint16() (uint16, error) { 101 _, err := dr.Read(dr.scratch[0:2]) 102 return binary.LittleEndian.Uint16(dr.scratch[0:2]), err 103 } 104 105 func (dr *DecodingReader) ReadUint32() (uint32, error) { 106 _, err := dr.Read(dr.scratch[0:4]) 107 return binary.LittleEndian.Uint32(dr.scratch[0:4]), err 108 } 109 110 func (dr *DecodingReader) ReadUint64() (uint64, error) { 111 _, err := dr.Read(dr.scratch[0:8]) 112 return binary.LittleEndian.Uint64(dr.scratch[0:8]), err 113 } 114 115 // returns the remaining span that can be read 116 func (dr *DecodingReader) GetBytesSpan() uint64 { 117 return dr.Max() - dr.Index() 118 } 119 120 // Reads an offset, and wraps it in maximum size, a uint64, for safety. 121 func (dr *DecodingReader) ReadOffset() (uint64, error) { 122 v, err := dr.ReadUint32() 123 return uint64(v), err 124 } 125 126 // if normal, offsets are used and enforced. 127 // if fuzzMode, no offsets are used, and lengths are read from the input, and adjusted to match remaining space. 128 func (dr *DecodingReader) IsFuzzMode() bool { 129 return dr.fuzzMode 130 }