-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbinary_scan.go
117 lines (109 loc) · 2.34 KB
/
binary_scan.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
package llsd
import (
"encoding/binary"
"fmt"
"io"
)
const BinaryHeader = "<?llsd/binary?>\n"
type BinaryScanner struct {
r io.Reader
off int64
}
func NewBinaryScanner(r io.Reader) *BinaryScanner {
return &BinaryScanner{r: r}
}
func (s *BinaryScanner) Offset() int64 {
return s.off
}
func (s *BinaryScanner) Token() (Token, error) {
for {
op, err := s.read(1)
if err != nil {
return nil, err
}
switch op[0] {
case 'i':
buf, err := s.read(4)
if err != nil {
return nil, err
}
return Scalar{Type: Integer, Data: buf}, nil
case 'r':
buf, err := s.read(8)
return Scalar{Type: Real, Data: buf}, err
case 'u':
buf, err := s.read(16)
return Scalar{Type: UUIDType, Data: buf}, err
case 'b':
buf, err := s.read(4)
if err != nil {
return nil, err
}
size := binary.BigEndian.Uint32(buf)
buf, err = s.read(size)
return Scalar{Type: Binary, Data: buf}, err
case 's':
buf, err := s.read(4)
if err != nil {
return nil, err
}
size := binary.BigEndian.Uint32(buf)
buf, err = s.read(size)
return Scalar{Type: String, Data: buf}, err
case 'd':
buf, err := s.read(4)
return Scalar{Type: Date, Data: buf}, err
case 'k':
buf, err := s.read(4)
if err != nil {
return nil, err
}
size := binary.BigEndian.Uint32(buf)
buf, err = s.read(size)
return Key(buf), err
case '{':
// Eat map size, could use it to provide a skip() method
_, err := s.read(4)
return MapStart{}, err
case '}':
return MapEnd{}, nil
case '[':
// Eat array size
_, err := s.read(4)
return ArrayStart{}, err
case ']':
return ArrayEnd{}, nil
case '1':
return Scalar{Type: Boolean, Data: []byte{1}}, nil
case '0':
return Scalar{Type: Boolean, Data: []byte{}}, nil
case '!':
return Scalar{Type: Undefined}, nil
case '<':
// Read header
if s.off == 1 {
buf, err := s.read(15)
if err != nil {
return nil, err
}
header := "<" + string(buf)
if header != BinaryHeader {
return nil, fmt.Errorf("Invalid LLSD: unrecognized header %s", header)
}
continue
}
fallthrough
default:
return nil, fmt.Errorf("Invalid LLSD %s", op)
}
}
}
func (s *BinaryScanner) read(num uint32) ([]byte, error) {
buf := make([]byte, num)
_, err := s.r.Read(buf)
s.off += int64(num)
if err != nil {
return buf, err
}
return buf, nil
}