-
Notifications
You must be signed in to change notification settings - Fork 1
/
bin.go
139 lines (119 loc) · 2.58 KB
/
bin.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
package binstruct
import (
"encoding/binary"
"io"
"reflect"
"strconv"
"strings"
)
type tag string
func (t tag) nonEmpty() bool {
return len(t) > 0
}
type tags reflect.StructTag
func (t tags) hex() tag {
return tag(reflect.StructTag(t).Get("hex"))
}
func (t tags) cond() tag {
return tag(reflect.StructTag(t).Get("cond"))
}
func (t tags) endianness() tag {
return tag(reflect.StructTag(t).Get("endianness"))
}
func (t tags) size() tag {
return tag(reflect.StructTag(t).Get("size"))
}
func (t tags) bitmask() tag {
return tag(reflect.StructTag(t).Get("bitmask"))
}
func (t tags) bits() tag {
return tag(reflect.StructTag(t).Get("bits"))
}
func (t tags) bound() tag {
return tag(reflect.StructTag(t).Get("bound"))
}
func (t tags) transient() tag {
return tag(reflect.StructTag(t).Get("transient"))
}
func valueConvertTo(value reflect.Value, typ reflect.Type) reflect.Value {
return value.Convert(typ)
}
func bitmaskBits(value tag) (bitmaskBits uint64) {
prefix := string(value[:2])
bitmask := string(value[2:])
if prefix == "0x" {
bitmaskBits, _ = strconv.ParseUint(bitmask, 16, len(bitmask)*4)
return
} else if prefix == "0b" {
bitmaskBits, _ = strconv.ParseUint(bitmask, 2, len(bitmask))
return
}
panic("Unsupported prefix: " + prefix)
}
func order(endianness tag) binary.ByteOrder {
if endianness == "be" {
return binary.BigEndian
}
return binary.LittleEndian
}
func checkConditions(cond tag, parent reflect.Value) bool {
if cond.nonEmpty() {
conditions := strings.Split(string(cond), ";")
for _, c := range conditions {
if !checkCondition(c, parent) {
return false
}
}
}
return true
}
func checkCondition(cond string, parent reflect.Value) bool {
v := strings.Split(cond, ":")
t := v[0]
c := v[1]
var op string
switch {
case strings.Contains(c, "=="):
op = "=="
case strings.Contains(c, "!="):
op = "!="
}
v = strings.Split(c, op)
l := v[0]
r := v[1]
getField := func() reflect.Value {
v := parent
pathElements := strings.Split(l, ".")
for _, e := range pathElements {
v = unpoint(v.FieldByName(e))
}
return v
}
switch t {
case "uint":
lv := uint64(getField().Uint())
n, _ := strconv.Atoi(r)
rv := uint64(n)
switch op {
case "==":
return lv == rv
case "!=":
return lv != rv
}
default:
panic("Unknown condition type: " + t)
}
return true
}
func unpoint(p reflect.Value) reflect.Value {
if p.Kind() == reflect.Ptr {
return unpoint(p.Elem())
} else {
return p
}
}
type Serializable interface {
Serialize(w io.Writer)
Deserialize(r io.Reader)
}
var serializable = reflect.TypeOf((*Serializable)(nil)).Elem()