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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <string.h>
#include "object.h"
static int mpack_parser_full(mpack_parser_t *w);
static mpack_node_t *mpack_parser_push(mpack_parser_t *w);
static mpack_node_t *mpack_parser_pop(mpack_parser_t *w);
MPACK_API void mpack_parser_init(mpack_parser_t *parser,
mpack_uint32_t capacity)
{
mpack_tokbuf_init(&parser->tokbuf);
parser->data.p = NULL;
parser->capacity = capacity ? capacity : MPACK_MAX_OBJECT_DEPTH;
parser->size = 0;
parser->exiting = 0;
memset(parser->items, 0, sizeof(mpack_node_t) * (parser->capacity + 1));
parser->items[0].pos = (size_t)-1;
parser->status = 0;
}
#define MPACK_EXCEPTION_CHECK(parser) \
do { \
if (parser->status == MPACK_EXCEPTION) { \
return MPACK_EXCEPTION; \
} \
} while (0)
#define MPACK_WALK(action) \
do { \
mpack_node_t *n; \
\
if (parser->exiting) goto exit; \
if (mpack_parser_full(parser)) return MPACK_NOMEM; \
n = mpack_parser_push(parser); \
action; \
MPACK_EXCEPTION_CHECK(parser); \
parser->exiting = 1; \
return MPACK_EOF; \
\
exit: \
parser->exiting = 0; \
while ((n = mpack_parser_pop(parser))) { \
exit_cb(parser, n); \
MPACK_EXCEPTION_CHECK(parser); \
if (!parser->size) return MPACK_OK; \
} \
\
return MPACK_EOF; \
} while (0)
MPACK_API int mpack_parse_tok(mpack_parser_t *parser, mpack_token_t tok,
mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
{
MPACK_EXCEPTION_CHECK(parser);
MPACK_WALK({n->tok = tok; enter_cb(parser, n);});
}
MPACK_API int mpack_unparse_tok(mpack_parser_t *parser, mpack_token_t *tok,
mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
{
MPACK_EXCEPTION_CHECK(parser);
MPACK_WALK({enter_cb(parser, n); *tok = n->tok;});
}
MPACK_API int mpack_parse(mpack_parser_t *parser, const char **buf,
size_t *buflen, mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
{
int status = MPACK_EOF;
MPACK_EXCEPTION_CHECK(parser);
while (*buflen && status) {
mpack_token_t tok;
mpack_tokbuf_t *tb = &parser->tokbuf;
const char *buf_save = *buf;
size_t buflen_save = *buflen;
if ((status = mpack_read(tb, buf, buflen, &tok)) == MPACK_EOF) continue;
else if (status == MPACK_ERROR) goto rollback;
do {
status = mpack_parse_tok(parser, tok, enter_cb, exit_cb);
MPACK_EXCEPTION_CHECK(parser);
} while (parser->exiting);
if (status != MPACK_NOMEM) continue;
rollback:
/* restore buf/buflen so the next call will try to read the same token */
*buf = buf_save;
*buflen = buflen_save;
break;
}
return status;
}
MPACK_API int mpack_unparse(mpack_parser_t *parser, char **buf, size_t *buflen,
mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
{
int status = MPACK_EOF;
MPACK_EXCEPTION_CHECK(parser);
while (*buflen && status) {
int write_status;
mpack_token_t tok;
mpack_tokbuf_t *tb = &parser->tokbuf;
if (!tb->plen)
parser->status = mpack_unparse_tok(parser, &tok, enter_cb, exit_cb);
MPACK_EXCEPTION_CHECK(parser);
status = parser->status;
if (status == MPACK_NOMEM)
break;
if (parser->exiting) {
write_status = mpack_write(tb, buf, buflen, &tok);
status = write_status ? write_status : status;
}
}
return status;
}
MPACK_API void mpack_parser_copy(mpack_parser_t *dst, mpack_parser_t *src)
{
mpack_uint32_t i;
mpack_uint32_t dst_capacity = dst->capacity;
assert(src->capacity <= dst_capacity);
/* copy all fields except the stack */
memcpy(dst, src, sizeof(mpack_one_parser_t) - sizeof(mpack_node_t));
/* reset capacity */
dst->capacity = dst_capacity;
/* copy the stack */
for (i = 0; i <= src->capacity; i++) {
dst->items[i] = src->items[i];
}
}
static int mpack_parser_full(mpack_parser_t *parser)
{
return parser->size == parser->capacity;
}
static mpack_node_t *mpack_parser_push(mpack_parser_t *parser)
{
mpack_node_t *top;
assert(parser->size < parser->capacity);
top = parser->items + parser->size + 1;
top->data[0].p = NULL;
top->data[1].p = NULL;
top->pos = 0;
top->key_visited = 0;
/* increase size and invoke callback, passing parent node if any */
parser->size++;
return top;
}
static mpack_node_t *mpack_parser_pop(mpack_parser_t *parser)
{
mpack_node_t *top, *parent;
assert(parser->size);
top = parser->items + parser->size;
if (top->tok.type > MPACK_TOKEN_CHUNK && top->pos < top->tok.length) {
/* continue processing children */
return NULL;
}
parent = MPACK_PARENT_NODE(top);
if (parent) {
/* we use parent->tok.length to keep track of how many children remain.
* update it to reflect the processed node. */
if (top->tok.type == MPACK_TOKEN_CHUNK) {
parent->pos += top->tok.length;
} else if (parent->tok.type == MPACK_TOKEN_MAP) {
/* maps allow up to 2^32 - 1 pairs, so to allow this many items in a
* 32-bit length variable we use an additional flag to determine if the
* key of a certain position was visited */
if (parent->key_visited) {
parent->pos++;
}
parent->key_visited = !parent->key_visited;
} else {
parent->pos++;
}
}
parser->size--;
return top;
}
|