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  }