-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnode_decoder.go
96 lines (82 loc) · 2.04 KB
/
node_decoder.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 y3
import (
"bytes"
"errors"
"github.com/yomorun/y3/encoding"
"github.com/yomorun/y3/utils"
)
func parsePayload(b []byte) (consumedBytes int, ifNodePacket bool, np *NodePacket, pp *PrimitivePacket, err error) {
if len(b) == 0 {
return 0, false, nil, nil, errors.New("parsePacket params can not be nil")
}
pos := 0
// NodePacket
if ok := utils.IsNodePacket(b[pos]); ok {
np = &NodePacket{}
endPos, err := DecodeToNodePacket(b, np)
return endPos, true, np, nil, err
}
pp = &PrimitivePacket{}
state, err := DecodeToPrimitivePacket(b, pp)
return state.ConsumedBytes, false, nil, pp, err
}
// DecodeToNodePacket parse out whole buffer to a NodePacket
func DecodeToNodePacket(buf []byte, pct *NodePacket) (consumedBytes int, err error) {
if len(buf) == 0 {
return 0, errors.New("empty buf")
}
pct.basePacket = &basePacket{
valbuf: buf,
buf: &bytes.Buffer{},
}
pct.NodePackets = map[byte]NodePacket{}
pct.PrimitivePackets = map[byte]PrimitivePacket{}
pos := 0
// `Tag`
tag := NewTag(buf[pos])
pct.basePacket.tag = tag
pct.buf.WriteByte(buf[pos])
pos++
// `Length`: the type is `varint`
tmpBuf := buf[pos:]
var vallen int32
codec := encoding.VarCodec{}
err = codec.DecodePVarInt32(tmpBuf, &vallen)
if err != nil {
return 0, err
}
pct.basePacket.length = int(vallen)
pct.buf.Write(buf[pos : pos+codec.Size])
pos += codec.Size
// if `Length` is 0, means empty node packet
if vallen == 0 {
return pos, nil
}
// `Value`
// `raw` is pct.Length() length
vl := int(vallen)
if vl < 0 {
return pos, errors.New("found L of V smaller than 0")
}
endPos := pos + vl
pct.basePacket.valbuf = buf[pos:endPos]
pct.buf.Write(buf[pos:endPos])
// Parse value to Packet
for {
if pos >= endPos || pos >= len(buf) {
break
}
_p, isNode, np, pp, err := parsePayload(buf[pos:endPos])
pos += _p
if err != nil {
return 0, err
}
if isNode {
pct.NodePackets[np.basePacket.tag.SeqID()] = *np
} else {
pct.PrimitivePackets[byte(pp.SeqID())] = *pp
}
}
consumedBytes = endPos
return consumedBytes, nil
}