-
Notifications
You must be signed in to change notification settings - Fork 2
/
major.go
155 lines (129 loc) · 3.07 KB
/
major.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
152
153
154
155
package cboring
import (
"fmt"
"io"
)
// MajorType defines a Major Type, as specified in RFC7049, section 2.1
type MajorType = byte
const (
UInt MajorType = 0x00
ByteString MajorType = 0x40
TextString MajorType = 0x60
Array MajorType = 0x80
Map MajorType = 0xA0
SimpleData MajorType = 0xE0
)
const (
IndefiniteArray byte = 0x9F
BreakCode byte = 0xFF
)
type Flag byte
func (f Flag) Error() string {
return string(f)
}
const (
FlagIndefiniteArray = Flag(iota)
FlagBreakCode = Flag(iota)
)
func readMajorType(b byte) (major MajorType, adds byte) {
major = b & 0xE0
adds = b & 0x1F
return
}
// ReadMajors parses a (major) type definition from the Reader.
func ReadMajors(r io.Reader) (m MajorType, n uint64, err error) {
var buff [8]byte
tmpBuff := buff[:1]
if _, rerr := io.ReadFull(r, tmpBuff); rerr != nil {
err = rerr
return
}
switch b := tmpBuff[0]; b {
case IndefiniteArray:
err = FlagIndefiniteArray
case BreakCode:
err = FlagBreakCode
default:
var adds byte
m, adds = readMajorType(b)
if adds <= 23 {
n = uint64(adds)
} else if 24 <= adds && adds <= 27 {
l := 1 << (adds - 24)
tmpBuff = buff[:l]
if rn, rerr := io.ReadFull(r, tmpBuff); rerr != nil {
err = rerr
return
} else if rn != l {
err = fmt.Errorf("ReadMajors: Read %d bytes instead of %d", rn, l)
return
}
for i := 0; i < l; i++ {
n = n<<8 | uint64(tmpBuff[i])
}
} else {
err = fmt.Errorf("ReadMajors: Other additional information 0x%x", adds)
}
}
return
}
// ReadExpectMajors parses the next (major) type, which must equal the requested
// one. This function wraps ReadMajors.
func ReadExpectMajors(m MajorType, r io.Reader) (n uint64, err error) {
mTmp, n, err := ReadMajors(r)
if err == nil && m != mTmp {
err = fmt.Errorf("ReadExpectMajors: Wrong Major Type: 0x%x instead of 0x%x",
m, mTmp)
}
return
}
// ReadExpect reads one byte from the Reader and errors if it does not contain
// the expected value. This might be useful to check if an indefinite-length
// array begins or ends with an break stop code.
func ReadExpect(b byte, r io.Reader) error {
var buff [1]byte
if _, err := r.Read(buff[:1]); err != nil {
return err
}
if data := buff[0]; data != b {
return fmt.Errorf("ReadExpect: Expected 0x%x, got 0x%x", b, data)
}
return nil
}
func writeMajorType(major MajorType, adds byte) byte {
return major | adds
}
// WriteMajors composes a (major) type definition into the Writer.
func WriteMajors(m MajorType, n uint64, w io.Writer) (err error) {
var buff [9]byte
var bc = 0
if n < 24 {
buff[0] = writeMajorType(m, byte(n))
} else {
var mt byte
if n < 1<<8 {
bc = 1
mt = 24
} else if n < 1<<16 {
bc = 2
mt = 25
} else if n < 1<<32 {
bc = 4
mt = 26
} else {
bc = 8
mt = 27
}
buff[0] = writeMajorType(m, mt)
for i := bc; i > 0; i-- {
buff[i] = byte(n & 0xFF)
n = n >> 8
}
}
if wn, werr := w.Write(buff[:bc+1]); werr != nil {
err = werr
} else if wn != bc+1 {
err = fmt.Errorf("WriteMajors: Wrote %d instead of %d bytes", wn, bc+1)
}
return
}