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