forked from maxmind/mmdbwriter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deserializer.go
161 lines (133 loc) · 3.26 KB
/
deserializer.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
156
157
158
159
160
161
package mmdbwriter
import (
"math/big"
"github.com/maxmind/mmdbwriter/mmdbtype"
"github.com/pkg/errors"
)
// Potentially, it would make sense to add this to mmdbtypes and make
// it public, but we should wait until the API stabilized here and in
// maxminddb first.
type stackValue struct {
value mmdbtype.DataType
curSize int
}
type deserializer struct {
key *mmdbtype.String
cache map[uintptr]mmdbtype.DataType
rv mmdbtype.DataType
stack []*stackValue
lastOffset uintptr
}
func newDeserializer() *deserializer {
return &deserializer{
cache: map[uintptr]mmdbtype.DataType{},
lastOffset: noOffset,
}
}
const noOffset uintptr = ^uintptr(0)
func (d *deserializer) ShouldSkip(offset uintptr) (bool, error) {
v, ok := d.cache[offset]
if ok {
d.lastOffset = noOffset
return true, d.simpleAdd(v)
}
d.lastOffset = offset
return false, nil
}
func (d *deserializer) StartSlice(size uint) error {
// We make the slice its finalize size to avoid
// appending, which could interfere with the caching.
return d.add(make(mmdbtype.Slice, size))
}
func (d *deserializer) StartMap(size uint) error {
return d.add(make(mmdbtype.Map, size))
}
func (d *deserializer) End() error {
if len(d.stack) == 0 {
return errors.New("received an End but the stack in empty")
}
d.stack = d.stack[:len(d.stack)-1]
return nil
}
func (d *deserializer) String(v string) error {
return d.add(mmdbtype.String(v))
}
func (d *deserializer) Float64(v float64) error {
return d.add(mmdbtype.Float64(v))
}
func (d *deserializer) Bytes(v []byte) error {
return d.add(mmdbtype.Bytes(v))
}
func (d *deserializer) Uint16(v uint16) error {
return d.add(mmdbtype.Uint16(v))
}
func (d *deserializer) Uint32(v uint32) error {
return d.add(mmdbtype.Uint32(v))
}
func (d *deserializer) Int32(v int32) error {
return d.add(mmdbtype.Int32(v))
}
func (d *deserializer) Uint64(v uint64) error {
return d.add(mmdbtype.Uint64(v))
}
func (d *deserializer) Uint128(v *big.Int) error {
t := mmdbtype.Uint128(*v)
return d.add(&t)
}
func (d *deserializer) Bool(v bool) error {
return d.add(mmdbtype.Bool(v))
}
func (d *deserializer) Float32(v float32) error {
return d.add(mmdbtype.Float32(v))
}
func (d *deserializer) simpleAdd(v mmdbtype.DataType) error {
if len(d.stack) == 0 {
d.rv = v
} else {
top := d.stack[len(d.stack)-1]
switch parent := top.value.(type) {
case mmdbtype.Map:
if d.key == nil {
key, ok := v.(mmdbtype.String)
if !ok {
return errors.Errorf("expected a String Map key but received %T", v)
}
d.key = &key
} else {
parent[*d.key] = v
d.key = nil
top.curSize++
}
case mmdbtype.Slice:
parent[top.curSize] = v
top.curSize++
default:
}
}
return nil
}
func (d *deserializer) add(v mmdbtype.DataType) error {
err := d.simpleAdd(v)
if err != nil {
return err
}
switch v := v.(type) {
case mmdbtype.Map, mmdbtype.Slice:
d.stack = append(d.stack, &stackValue{value: v})
default:
}
if d.lastOffset != noOffset {
d.cache[d.lastOffset] = v
d.lastOffset = noOffset
}
return nil
}
func (d *deserializer) clear() {
d.rv = nil
// Although these shouldn't be necessary normally, they could be needed
// if we are recovering from an error.
d.key = nil
if len(d.stack) > 0 {
d.stack = d.stack[:0]
}
}