/
name-component.go
140 lines (122 loc) · 3.24 KB
/
name-component.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
package ndn
import (
"bytes"
"strconv"
"strings"
"github.com/usnistgov/ndn-dpdk/ndn/an"
"github.com/usnistgov/ndn-dpdk/ndn/tlv"
)
// NameComponent represents a name component.
// The zero NameComponent is invalid.
type NameComponent struct {
tlv.Element
}
// MakeNameComponent constructs a NameComponent from TLV-TYPE and TLV-VALUE.
func MakeNameComponent(typ uint32, value []byte) (comp NameComponent) {
comp.Element = tlv.MakeElement(typ, value)
return comp
}
// Valid checks whether this component has a valid TLV-TYPE.
func (comp NameComponent) Valid() bool {
return isValidNameComponentType(comp.Type)
}
// Equal determines whether two components are the same.
func (comp NameComponent) Equal(other NameComponent) bool {
return comp.Compare(other) == 0
}
// Compare returns negative when comp<other, zero when comp==other, positive when comp>other.
func (comp NameComponent) Compare(other NameComponent) int {
if d := int(comp.Type) - int(other.Type); d != 0 {
return d
}
if d := comp.Length() - other.Length(); d != 0 {
return d
}
return bytes.Compare(comp.Value, other.Value)
}
// MarshalTlv encodes this component.
func (comp NameComponent) MarshalTlv() (typ uint32, value []byte, e error) {
if !comp.Valid() {
return 0, nil, ErrComponentType
}
return comp.Element.MarshalTlv()
}
// UnmarshalTlv decodes from wire format.
func (comp *NameComponent) UnmarshalTlv(typ uint32, value []byte) error {
if e := comp.Element.UnmarshalTlv(typ, value); e != nil {
return e
}
if !comp.Valid() {
return ErrComponentType
}
return nil
}
// String returns URI representation of this component.
func (comp NameComponent) String() string {
var w strings.Builder
comp.writeStringTo(&w)
return w.String()
}
func (comp NameComponent) writeStringTo(w *strings.Builder) {
w.WriteString(strconv.Itoa(int(comp.Type)))
w.WriteByte('=')
nNonPeriods := 0
for _, b := range comp.Value {
if bytes.IndexByte(unescapedChars, b) >= 0 {
w.WriteByte(b)
} else {
w.WriteByte('%')
w.WriteByte(hexChars[b>>4])
w.WriteByte(hexChars[b&0x0F])
}
if b != '.' {
nNonPeriods++
}
}
if nNonPeriods == 0 {
w.WriteString("...")
}
}
// ParseNameComponent parses URI representation of name component.
// It uses best effort and can accept any input.
func ParseNameComponent(input string) (comp NameComponent) {
comp.Type = uint32(an.TtGenericNameComponent)
pos := strings.IndexByte(input, '=')
if pos >= 0 {
typ, e := strconv.ParseUint(input[:pos], 10, 32)
typ32 := uint32(typ)
if e == nil && isValidNameComponentType(typ32) {
comp.Type = typ32
pos++
} else {
pos = 0
}
} else {
pos = 0
}
if len(strings.TrimRight(input, ".")) == pos && len(input) >= 3 {
comp.Value = []byte(input)[pos+3:]
return comp
}
var value bytes.Buffer
for i := pos; i < len(input); {
ch := input[i]
if ch == '%' && i+2 < len(input) {
b, e := strconv.ParseUint(input[i+1:i+3], 16, 8)
if e == nil {
value.WriteByte(byte(b))
i += 3
continue
}
}
value.WriteByte(ch)
i++
}
comp.Value = value.Bytes()
return comp
}
func isValidNameComponentType(typ uint32) bool {
return typ >= 1 && typ <= 65535
}
var unescapedChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
var hexChars = []byte("0123456789ABCDEF")