github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/utils/cser/binary.go (about)

     1  package cser
     2  
     3  import (
     4  	"github.com/unicornultrafoundation/go-u2u/utils/bits"
     5  	"github.com/unicornultrafoundation/go-u2u/utils/fast"
     6  )
     7  
     8  func MarshalBinaryAdapter(marshalCser func(*Writer) error) ([]byte, error) {
     9  	w := NewWriter()
    10  	err := marshalCser(w)
    11  	if err != nil {
    12  		return nil, err
    13  	}
    14  
    15  	return binaryFromCSER(w.BitsW.Array, w.BytesW.Bytes())
    16  }
    17  
    18  // binaryFromCSER packs body bytes and bits into raw
    19  func binaryFromCSER(bbits *bits.Array, bbytes []byte) (raw []byte, err error) {
    20  	bodyBytes := fast.NewWriter(bbytes)
    21  	bodyBytes.Write(bbits.Bytes)
    22  	// write bits size
    23  	sizeWriter := fast.NewWriter(make([]byte, 0, 4))
    24  	writeUint64Compact(sizeWriter, uint64(len(bbits.Bytes)))
    25  	bodyBytes.Write(reversed(sizeWriter.Bytes()))
    26  	return bodyBytes.Bytes(), nil
    27  }
    28  
    29  // binaryToCSER unpacks raw on body bytes and bits
    30  func binaryToCSER(raw []byte) (bbits *bits.Array, bbytes []byte, err error) {
    31  	// read bitsArray size
    32  	bitsSizeBuf := reversed(tail(raw, 9))
    33  	bitsSizeReader := fast.NewReader(bitsSizeBuf)
    34  	bitsSize := readUint64Compact(bitsSizeReader)
    35  	raw = raw[:len(raw)-bitsSizeReader.Position()]
    36  
    37  	if uint64(len(raw)) < bitsSize {
    38  		err = ErrMalformedEncoding
    39  		return
    40  	}
    41  
    42  	bbits = &bits.Array{Bytes: raw[uint64(len(raw))-bitsSize:]}
    43  	bbytes = raw[:uint64(len(raw))-bitsSize]
    44  	return
    45  }
    46  
    47  func UnmarshalBinaryAdapter(raw []byte, unmarshalCser func(reader *Reader) error) (err error) {
    48  	defer func() {
    49  		if r := recover(); r != nil {
    50  			err = ErrMalformedEncoding
    51  		}
    52  	}()
    53  
    54  	bbits, bbytes, err := binaryToCSER(raw)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	bodyReader := &Reader{
    60  		BitsR:  bits.NewReader(bbits),
    61  		BytesR: fast.NewReader(bbytes),
    62  	}
    63  	err = unmarshalCser(bodyReader)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	// check that everything is read
    69  	if bodyReader.BitsR.NonReadBytes() > 1 {
    70  		return ErrNonCanonicalEncoding
    71  	}
    72  	tail := bodyReader.BitsR.Read(bodyReader.BitsR.NonReadBits())
    73  	if tail != 0 {
    74  		return ErrNonCanonicalEncoding
    75  	}
    76  	if !bodyReader.BytesR.Empty() {
    77  		return ErrNonCanonicalEncoding
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func tail(b []byte, cap int) []byte {
    84  	if len(b) > cap {
    85  		return b[len(b)-cap:]
    86  	}
    87  	return b
    88  }
    89  
    90  func reversed(b []byte) []byte {
    91  	reversed := make([]byte, len(b))
    92  	for i, v := range b {
    93  		reversed[len(b)-1-i] = v
    94  	}
    95  	return reversed
    96  }