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 }