-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathdecode.go
151 lines (130 loc) · 3.45 KB
/
decode.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package tlv
import (
"encoding"
"iter"
"slices"
)
// Unmarshaler is the interface implemented by an object that can decode an TLV element representation of itself.
type Unmarshaler interface {
UnmarshalTLV(typ uint32, value []byte) error
}
// DecodingBuffer recognizes TLV elements.
type DecodingBuffer []byte
// Rest returns unconsumed input.
func (d DecodingBuffer) Rest() []byte {
return []byte(d)
}
// EOF returns true if decoder is at end of input.
func (d DecodingBuffer) EOF() bool {
return len(d) == 0
}
// ErrUnlessEOF returns an error if there is unconsumed input.
func (d DecodingBuffer) ErrUnlessEOF() error {
if d.EOF() {
return nil
}
return ErrTail
}
// Element recognizes one TLV element from the buffer.
func (d *DecodingBuffer) Element() (de DecodingElement, e error) {
var typ, length VarNum
afterTyp, e := typ.Decode(*d)
if e != nil {
return de, e
}
if typ < minType || typ > maxType {
return de, ErrType
}
afterLen, e := length.Decode(afterTyp)
if e != nil {
return de, e
}
if len(afterLen) < int(length) {
return de, ErrIncomplete
}
de.Type = uint32(typ)
de.Value = afterLen[:length]
de.After = afterLen[length:]
de.Wire = (*d)[:len(*d)-len(de.After)]
*d = de.After
return de, nil
}
// IterElements returns an iterator that recognizes TLV elements from the buffer.
//
// Iteration stops when no more TLV elements can be recognized.
// Remaining bytes are left in the decoder.
func (d *DecodingBuffer) IterElements() iter.Seq[DecodingElement] {
return func(yield func(DecodingElement) bool) {
for {
de, e := d.Element()
if e != nil || !yield(de) {
return
}
}
}
}
// Elements recognizes TLV elements from the buffer.
//
// Remaining bytes that cannot be recognized as TLV elements are left in the decoder.
func (d *DecodingBuffer) Elements() []DecodingElement {
return slices.Collect(d.IterElements())
}
// DecodingElement represents an TLV element during decoding.
type DecodingElement struct {
Element
Wire []byte
After []byte
}
// IsCriticalType returns true if the TLV-TYPE is considered critical for evolvability purpose.
func (de DecodingElement) IsCriticalType() bool {
return de.Type <= 31 || de.Type&0x01 != 0
}
// WireAfter returns Wire+After.
func (de DecodingElement) WireAfter() []byte {
size := len(de.Wire) + len(de.After)
if cap(de.Wire) < size {
panic(de.Wire)
}
return de.Wire[:size]
}
// Unmarshal unmarshals TLV into a value.
func (de DecodingElement) Unmarshal(u Unmarshaler) error {
return u.UnmarshalTLV(de.Type, de.Value)
}
// UnmarshalValue unmarshals TLV-VALUE into a value.
func (de DecodingElement) UnmarshalValue(u encoding.BinaryUnmarshaler) error {
return u.UnmarshalBinary(de.Value)
}
// UnmarshalNNI unmarshals TLV-VALUE as NNI and checks it's within [0:max] range.
//
// This function has an unusual set of parameters to allow for more compact calling code:
//
// if pkt.Field = uint32(de.UnmarshalNNI(math.MaxUint32, &e, tlv.ErrRange)); e != nil {
// return e
// }
func (de DecodingElement) UnmarshalNNI(max uint64, err *error, rangeErr error) (v uint64) {
var n NNI
if e := de.UnmarshalValue(&n); e != nil {
*err = e
return 0
}
v = uint64(n)
if v > max {
*err = rangeErr
return 0
}
*err = nil
return v
}
// Decode unmarshals a buffer that contains a single TLV.
func Decode(wire []byte, u Unmarshaler) error {
d := DecodingBuffer(wire)
de, e := d.Element()
if e != nil {
return e
}
if e = de.Unmarshal(u); e != nil {
return e
}
return d.ErrUnlessEOF()
}