1/*
2 * Copyright (c) 2015-2021 Nicholas Fraser and the MPack authors
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of
5 * this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to
7 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 * the Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22#define MPACK_INTERNAL 1
23
24#include "mpack-node.h"
25
26MPACK_SILENCE_WARNINGS_BEGIN
27
28#if MPACK_NODE
29
30MPACK_STATIC_INLINE const char* mpack_node_data_unchecked(mpack_node_t node) {
31 mpack_assert(mpack_node_error(node) == mpack_ok, "tree is in an error state!");
32
33 mpack_type_t type = node.data->type;
34 MPACK_UNUSED(type);
35 #if MPACK_EXTENSIONS
36 mpack_assert(type == mpack_type_str || type == mpack_type_bin || type == mpack_type_ext,
37 "node of type %i (%s) is not a data type!", type, mpack_type_to_string(type));
38 #else
39 mpack_assert(type == mpack_type_str || type == mpack_type_bin,
40 "node of type %i (%s) is not a data type!", type, mpack_type_to_string(type));
41 #endif
42
43 return node.tree->data + node.data->value.offset;
44}
45
46#if MPACK_EXTENSIONS
47MPACK_STATIC_INLINE int8_t mpack_node_exttype_unchecked(mpack_node_t node) {
48 mpack_assert(mpack_node_error(node) == mpack_ok, "tree is in an error state!");
49
50 mpack_type_t type = node.data->type;
51 MPACK_UNUSED(type);
52 mpack_assert(type == mpack_type_ext, "node of type %i (%s) is not an ext type!",
53 type, mpack_type_to_string(type));
54
55 // the exttype of an ext node is stored in the byte preceding the data
56 return mpack_load_i8(mpack_node_data_unchecked(node) - 1);
57}
58#endif
59
60
61
62/*
63 * Tree Parsing
64 */
65
66#ifdef MPACK_MALLOC
67
68// fix up the alloc size to make sure it exactly fits the
69// maximum number of nodes it can contain (the allocator will
70// waste it back anyway, but we round it down just in case)
71
72#define MPACK_NODES_PER_PAGE \
73 ((MPACK_NODE_PAGE_SIZE - sizeof(mpack_tree_page_t)) / sizeof(mpack_node_data_t) + 1)
74
75#define MPACK_PAGE_ALLOC_SIZE \
76 (sizeof(mpack_tree_page_t) + sizeof(mpack_node_data_t) * (MPACK_NODES_PER_PAGE - 1))
77
78#endif
79
80#ifdef MPACK_MALLOC
81/*
82 * Fills the tree until we have at least enough bytes for the current node.
83 */
84static bool mpack_tree_reserve_fill(mpack_tree_t* tree) {
85 mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
86
87 size_t bytes = tree->parser.current_node_reserved;
88 mpack_assert(bytes > tree->parser.possible_nodes_left,
89 "there are already enough bytes! call mpack_tree_ensure() instead.");
90 mpack_log("filling to reserve %i bytes\n", (int)bytes);
91
92 // if the necessary bytes would put us over the maximum tree
93 // size, fail right away.
94 // TODO: check for overflow?
95 if (tree->data_length + bytes > tree->max_size) {
96 mpack_tree_flag_error(tree, mpack_error_too_big);
97 return false;
98 }
99
100 // we'll need a read function to fetch more data. if there's
101 // no read function, the data should contain an entire message
102 // (or messages), so we flag it as invalid.
103 if (tree->read_fn == NULL) {
104 mpack_log("tree has no read function!\n");
105 mpack_tree_flag_error(tree, mpack_error_invalid);
106 return false;
107 }
108
109 // expand the buffer if needed
110 if (tree->data_length + bytes > tree->buffer_capacity) {
111
112 // TODO: check for overflow?
113 size_t new_capacity = (tree->buffer_capacity == 0) ? MPACK_BUFFER_SIZE : tree->buffer_capacity;
114 while (new_capacity < tree->data_length + bytes)
115 new_capacity *= 2;
116 if (new_capacity > tree->max_size)
117 new_capacity = tree->max_size;
118
119 mpack_log("expanding buffer from %i to %i\n", (int)tree->buffer_capacity, (int)new_capacity);
120
121 char* new_buffer;
122 if (tree->buffer == NULL)
123 new_buffer = (char*)MPACK_MALLOC(new_capacity);
124 else
125 new_buffer = (char*)mpack_realloc(tree->buffer, tree->data_length, new_capacity);
126
127 if (new_buffer == NULL) {
128 mpack_tree_flag_error(tree, mpack_error_memory);
129 return false;
130 }
131
132 tree->data = new_buffer;
133 tree->buffer = new_buffer;
134 tree->buffer_capacity = new_capacity;
135 }
136
137 // request as much data as possible, looping until we have
138 // all the data we need
139 do {
140 size_t read = tree->read_fn(tree, tree->buffer + tree->data_length, tree->buffer_capacity - tree->data_length);
141
142 // If the fill function encounters an error, it should flag an error on
143 // the tree.
144 if (mpack_tree_error(tree) != mpack_ok)
145 return false;
146
147 // We guard against fill functions that return -1 just in case.
148 if (read == (size_t)(-1)) {
149 mpack_tree_flag_error(tree, mpack_error_io);
150 return false;
151 }
152
153 // If the fill function returns 0, the data is not available yet. We
154 // return false to stop parsing the current node.
155 if (read == 0) {
156 mpack_log("not enough data.\n");
157 return false;
158 }
159
160 mpack_log("read %" PRIu32 " more bytes\n", (uint32_t)read);
161 tree->data_length += read;
162 tree->parser.possible_nodes_left += read;
163 } while (tree->parser.possible_nodes_left < bytes);
164
165 return true;
166}
167#endif
168
169/*
170 * Ensures there are enough additional bytes in the tree for the current node
171 * (including reserved bytes for the children of this node, and in addition to
172 * the reserved bytes for children of previous compound nodes), reading more
173 * data if needed.
174 *
175 * extra_bytes is the number of additional bytes to reserve for the current
176 * node beyond the type byte (since one byte is already reserved for each node
177 * by its parent array or map.)
178 *
179 * This may reallocate the tree, which means the tree->data pointer may change!
180 *
181 * Returns false if not enough bytes could be read.
182 */
183MPACK_STATIC_INLINE bool mpack_tree_reserve_bytes(mpack_tree_t* tree, size_t extra_bytes) {
184 mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
185
186 // We guard against overflow here. A compound type could declare more than
187 // MPACK_UINT32_MAX contents which overflows SIZE_MAX on 32-bit platforms. We
188 // flag mpack_error_invalid instead of mpack_error_too_big since it's far
189 // more likely that the message is corrupt than that the data is valid but
190 // not parseable on this architecture (see test_read_node_possible() in
191 // test-node.c .)
192 if ((uint64_t)tree->parser.current_node_reserved + (uint64_t)extra_bytes > SIZE_MAX) {
193 mpack_tree_flag_error(tree, mpack_error_invalid);
194 return false;
195 }
196
197 tree->parser.current_node_reserved += extra_bytes;
198
199 // Note that possible_nodes_left already accounts for reserved bytes for
200 // children of previous compound nodes. So even if there are hundreds of
201 // bytes left in the buffer, we might need to read anyway.
202 if (tree->parser.current_node_reserved <= tree->parser.possible_nodes_left)
203 return true;
204
205 #ifdef MPACK_MALLOC
206 return mpack_tree_reserve_fill(tree);
207 #else
208 return false;
209 #endif
210}
211
212MPACK_STATIC_INLINE size_t mpack_tree_parser_stack_capacity(mpack_tree_t* tree) {
213 #ifdef MPACK_MALLOC
214 return tree->parser.stack_capacity;
215 #else
216 return sizeof(tree->parser.stack) / sizeof(tree->parser.stack[0]);
217 #endif
218}
219
220static bool mpack_tree_push_stack(mpack_tree_t* tree, mpack_node_data_t* first_child, size_t total) {
221 mpack_tree_parser_t* parser = &tree->parser;
222 mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
223
224 // No need to push empty containers
225 if (total == 0)
226 return true;
227
228 // Make sure we have enough room in the stack
229 if (parser->level + 1 == mpack_tree_parser_stack_capacity(tree)) {
230 #ifdef MPACK_MALLOC
231 size_t new_capacity = parser->stack_capacity * 2;
232 mpack_log("growing parse stack to capacity %i\n", (int)new_capacity);
233
234 // Replace the stack-allocated parsing stack
235 if (!parser->stack_owned) {
236 mpack_level_t* new_stack = (mpack_level_t*)MPACK_MALLOC(sizeof(mpack_level_t) * new_capacity);
237 if (!new_stack) {
238 mpack_tree_flag_error(tree, mpack_error_memory);
239 return false;
240 }
241 mpack_memcpy(new_stack, parser->stack, sizeof(mpack_level_t) * parser->stack_capacity);
242 parser->stack = new_stack;
243 parser->stack_owned = true;
244
245 // Realloc the allocated parsing stack
246 } else {
247 mpack_level_t* new_stack = (mpack_level_t*)mpack_realloc(parser->stack,
248 sizeof(mpack_level_t) * parser->stack_capacity, sizeof(mpack_level_t) * new_capacity);
249 if (!new_stack) {
250 mpack_tree_flag_error(tree, mpack_error_memory);
251 return false;
252 }
253 parser->stack = new_stack;
254 }
255 parser->stack_capacity = new_capacity;
256 #else
257 mpack_tree_flag_error(tree, mpack_error_too_big);
258 return false;
259 #endif
260 }
261
262 // Push the contents of this node onto the parsing stack
263 ++parser->level;
264 parser->stack[parser->level].child = first_child;
265 parser->stack[parser->level].left = total;
266 return true;
267}
268
269static bool mpack_tree_parse_children(mpack_tree_t* tree, mpack_node_data_t* node) {
270 mpack_tree_parser_t* parser = &tree->parser;
271 mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
272
273 mpack_type_t type = node->type;
274 size_t total = node->len;
275
276 // Calculate total elements to read
277 if (type == mpack_type_map) {
278 if ((uint64_t)total * 2 > SIZE_MAX) {
279 mpack_tree_flag_error(tree, mpack_error_too_big);
280 return false;
281 }
282 total *= 2;
283 }
284
285 // Make sure we are under our total node limit (TODO can this overflow?)
286 tree->node_count += total;
287 if (tree->node_count > tree->max_nodes) {
288 mpack_tree_flag_error(tree, mpack_error_too_big);
289 return false;
290 }
291
292 // Each node is at least one byte. Count these bytes now to make
293 // sure there is enough data left.
294 if (!mpack_tree_reserve_bytes(tree, total))
295 return false;
296
297 // If there are enough nodes left in the current page, no need to grow
298 if (total <= parser->nodes_left) {
299 node->value.children = parser->nodes;
300 parser->nodes += total;
301 parser->nodes_left -= total;
302
303 } else {
304
305 #ifdef MPACK_MALLOC
306
307 // We can't grow if we're using a fixed pool (i.e. we didn't start with a page)
308 if (!tree->next) {
309 mpack_tree_flag_error(tree, mpack_error_too_big);
310 return false;
311 }
312
313 // Otherwise we need to grow, and the node's children need to be contiguous.
314 // This is a heuristic to decide whether we should waste the remaining space
315 // in the current page and start a new one, or give the children their
316 // own page. With a fraction of 1/8, this causes at most 12% additional
317 // waste. Note that reducing this too much causes less cache coherence and
318 // more malloc() overhead due to smaller allocations, so there's a tradeoff
319 // here. This heuristic could use some improvement, especially with custom
320 // page sizes.
321
322 mpack_tree_page_t* page;
323
324 if (total > MPACK_NODES_PER_PAGE || parser->nodes_left > MPACK_NODES_PER_PAGE / 8) {
325 // TODO: this should check for overflow
326 page = (mpack_tree_page_t*)MPACK_MALLOC(
327 sizeof(mpack_tree_page_t) + sizeof(mpack_node_data_t) * (total - 1));
328 if (page == NULL) {
329 mpack_tree_flag_error(tree, mpack_error_memory);
330 return false;
331 }
332 mpack_log("allocated seperate page %p for %i children, %i left in page of %i total\n",
333 (void*)page, (int)total, (int)parser->nodes_left, (int)MPACK_NODES_PER_PAGE);
334
335 node->value.children = page->nodes;
336
337 } else {
338 page = (mpack_tree_page_t*)MPACK_MALLOC(MPACK_PAGE_ALLOC_SIZE);
339 if (page == NULL) {
340 mpack_tree_flag_error(tree, mpack_error_memory);
341 return false;
342 }
343 mpack_log("allocated new page %p for %i children, wasting %i in page of %i total\n",
344 (void*)page, (int)total, (int)parser->nodes_left, (int)MPACK_NODES_PER_PAGE);
345
346 node->value.children = page->nodes;
347 parser->nodes = page->nodes + total;
348 parser->nodes_left = MPACK_NODES_PER_PAGE - total;
349 }
350
351 page->next = tree->next;
352 tree->next = page;
353
354 #else
355 // We can't grow if we don't have an allocator
356 mpack_tree_flag_error(tree, mpack_error_too_big);
357 return false;
358 #endif
359 }
360
361 return mpack_tree_push_stack(tree, node->value.children, total);
362}
363
364static bool mpack_tree_parse_bytes(mpack_tree_t* tree, mpack_node_data_t* node) {
365 node->value.offset = tree->size + tree->parser.current_node_reserved + 1;
366 return mpack_tree_reserve_bytes(tree, node->len);
367}
368
369#if MPACK_EXTENSIONS
370static bool mpack_tree_parse_ext(mpack_tree_t* tree, mpack_node_data_t* node) {
371 // reserve space for exttype
372 tree->parser.current_node_reserved += sizeof(int8_t);
373 node->type = mpack_type_ext;
374 return mpack_tree_parse_bytes(tree, node);
375}
376#endif
377
378static bool mpack_tree_parse_node_contents(mpack_tree_t* tree, mpack_node_data_t* node) {
379 mpack_assert(tree->parser.state == mpack_tree_parse_state_in_progress);
380 mpack_assert(node != NULL, "null node?");
381
382 // read the type. we've already accounted for this byte in
383 // possible_nodes_left, so we already know it is in bounds, and we don't
384 // need to reserve it for this node.
385 mpack_assert(tree->data_length > tree->size);
386 uint8_t type = mpack_load_u8(tree->data + tree->size);
387 mpack_log("node type %x\n", type);
388 tree->parser.current_node_reserved = 0;
389
390 // as with mpack_read_tag(), the fastest way to parse a node is to switch
391 // on the first byte, and to explicitly list every possible byte. we switch
392 // on the first four bits in size-optimized builds.
393
394 #if MPACK_OPTIMIZE_FOR_SIZE
395 switch (type >> 4) {
396
397 // positive fixnum
398 case 0x0: case 0x1: case 0x2: case 0x3:
399 case 0x4: case 0x5: case 0x6: case 0x7:
400 node->type = mpack_type_uint;
401 node->value.u = type;
402 return true;
403
404 // negative fixnum
405 case 0xe: case 0xf:
406 node->type = mpack_type_int;
407 node->value.i = (int8_t)type;
408 return true;
409
410 // fixmap
411 case 0x8:
412 node->type = mpack_type_map;
413 node->len = (uint32_t)(type & ~0xf0);
414 return mpack_tree_parse_children(tree, node);
415
416 // fixarray
417 case 0x9:
418 node->type = mpack_type_array;
419 node->len = (uint32_t)(type & ~0xf0);
420 return mpack_tree_parse_children(tree, node);
421
422 // fixstr
423 case 0xa: case 0xb:
424 node->type = mpack_type_str;
425 node->len = (uint32_t)(type & ~0xe0);
426 return mpack_tree_parse_bytes(tree, node);
427
428 // not one of the common infix types
429 default:
430 break;
431 }
432 #endif
433
434 switch (type) {
435
436 #if !MPACK_OPTIMIZE_FOR_SIZE
437 // positive fixnum
438 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
439 case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
440 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
441 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
442 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
443 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
444 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
445 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
446 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
447 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
448 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
449 case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
450 case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
451 case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
452 case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
453 case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
454 node->type = mpack_type_uint;
455 node->value.u = type;
456 return true;
457
458 // negative fixnum
459 case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
460 case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
461 case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
462 case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
463 node->type = mpack_type_int;
464 node->value.i = (int8_t)type;
465 return true;
466
467 // fixmap
468 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
469 case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
470 node->type = mpack_type_map;
471 node->len = (uint32_t)(type & ~0xf0);
472 return mpack_tree_parse_children(tree, node);
473
474 // fixarray
475 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
476 case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
477 node->type = mpack_type_array;
478 node->len = (uint32_t)(type & ~0xf0);
479 return mpack_tree_parse_children(tree, node);
480
481 // fixstr
482 case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
483 case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
484 case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
485 case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
486 node->type = mpack_type_str;
487 node->len = (uint32_t)(type & ~0xe0);
488 return mpack_tree_parse_bytes(tree, node);
489 #endif
490
491 // nil
492 case 0xc0:
493 node->type = mpack_type_nil;
494 return true;
495
496 // bool
497 case 0xc2: case 0xc3:
498 node->type = mpack_type_bool;
499 node->value.b = type & 1;
500 return true;
501
502 // bin8
503 case 0xc4:
504 node->type = mpack_type_bin;
505 if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
506 return false;
507 node->len = mpack_load_u8(tree->data + tree->size + 1);
508 return mpack_tree_parse_bytes(tree, node);
509
510 // bin16
511 case 0xc5:
512 node->type = mpack_type_bin;
513 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
514 return false;
515 node->len = mpack_load_u16(tree->data + tree->size + 1);
516 return mpack_tree_parse_bytes(tree, node);
517
518 // bin32
519 case 0xc6:
520 node->type = mpack_type_bin;
521 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
522 return false;
523 node->len = mpack_load_u32(tree->data + tree->size + 1);
524 return mpack_tree_parse_bytes(tree, node);
525
526 #if MPACK_EXTENSIONS
527 // ext8
528 case 0xc7:
529 if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
530 return false;
531 node->len = mpack_load_u8(tree->data + tree->size + 1);
532 return mpack_tree_parse_ext(tree, node);
533
534 // ext16
535 case 0xc8:
536 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
537 return false;
538 node->len = mpack_load_u16(tree->data + tree->size + 1);
539 return mpack_tree_parse_ext(tree, node);
540
541 // ext32
542 case 0xc9:
543 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
544 return false;
545 node->len = mpack_load_u32(tree->data + tree->size + 1);
546 return mpack_tree_parse_ext(tree, node);
547 #endif
548
549 // float
550 case 0xca:
551 #if MPACK_FLOAT
552 if (!mpack_tree_reserve_bytes(tree, sizeof(float)))
553 return false;
554 node->value.f = mpack_load_float(tree->data + tree->size + 1);
555 #else
556 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
557 return false;
558 node->value.f = mpack_load_u32(tree->data + tree->size + 1);
559 #endif
560 node->type = mpack_type_float;
561 return true;
562
563 // double
564 case 0xcb:
565 #if MPACK_DOUBLE
566 if (!mpack_tree_reserve_bytes(tree, sizeof(double)))
567 return false;
568 node->value.d = mpack_load_double(tree->data + tree->size + 1);
569 #else
570 if (!mpack_tree_reserve_bytes(tree, sizeof(uint64_t)))
571 return false;
572 node->value.d = mpack_load_u64(tree->data + tree->size + 1);
573 #endif
574 node->type = mpack_type_double;
575 return true;
576
577 // uint8
578 case 0xcc:
579 node->type = mpack_type_uint;
580 if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
581 return false;
582 node->value.u = mpack_load_u8(tree->data + tree->size + 1);
583 return true;
584
585 // uint16
586 case 0xcd:
587 node->type = mpack_type_uint;
588 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
589 return false;
590 node->value.u = mpack_load_u16(tree->data + tree->size + 1);
591 return true;
592
593 // uint32
594 case 0xce:
595 node->type = mpack_type_uint;
596 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
597 return false;
598 node->value.u = mpack_load_u32(tree->data + tree->size + 1);
599 return true;
600
601 // uint64
602 case 0xcf:
603 node->type = mpack_type_uint;
604 if (!mpack_tree_reserve_bytes(tree, sizeof(uint64_t)))
605 return false;
606 node->value.u = mpack_load_u64(tree->data + tree->size + 1);
607 return true;
608
609 // int8
610 case 0xd0:
611 node->type = mpack_type_int;
612 if (!mpack_tree_reserve_bytes(tree, sizeof(int8_t)))
613 return false;
614 node->value.i = mpack_load_i8(tree->data + tree->size + 1);
615 return true;
616
617 // int16
618 case 0xd1:
619 node->type = mpack_type_int;
620 if (!mpack_tree_reserve_bytes(tree, sizeof(int16_t)))
621 return false;
622 node->value.i = mpack_load_i16(tree->data + tree->size + 1);
623 return true;
624
625 // int32
626 case 0xd2:
627 node->type = mpack_type_int;
628 if (!mpack_tree_reserve_bytes(tree, sizeof(int32_t)))
629 return false;
630 node->value.i = mpack_load_i32(tree->data + tree->size + 1);
631 return true;
632
633 // int64
634 case 0xd3:
635 node->type = mpack_type_int;
636 if (!mpack_tree_reserve_bytes(tree, sizeof(int64_t)))
637 return false;
638 node->value.i = mpack_load_i64(tree->data + tree->size + 1);
639 return true;
640
641 #if MPACK_EXTENSIONS
642 // fixext1
643 case 0xd4:
644 node->len = 1;
645 return mpack_tree_parse_ext(tree, node);
646
647 // fixext2
648 case 0xd5:
649 node->len = 2;
650 return mpack_tree_parse_ext(tree, node);
651
652 // fixext4
653 case 0xd6:
654 node->len = 4;
655 return mpack_tree_parse_ext(tree, node);
656
657 // fixext8
658 case 0xd7:
659 node->len = 8;
660 return mpack_tree_parse_ext(tree, node);
661
662 // fixext16
663 case 0xd8:
664 node->len = 16;
665 return mpack_tree_parse_ext(tree, node);
666 #endif
667
668 // str8
669 case 0xd9:
670 if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t)))
671 return false;
672 node->len = mpack_load_u8(tree->data + tree->size + 1);
673 node->type = mpack_type_str;
674 return mpack_tree_parse_bytes(tree, node);
675
676 // str16
677 case 0xda:
678 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
679 return false;
680 node->len = mpack_load_u16(tree->data + tree->size + 1);
681 node->type = mpack_type_str;
682 return mpack_tree_parse_bytes(tree, node);
683
684 // str32
685 case 0xdb:
686 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
687 return false;
688 node->len = mpack_load_u32(tree->data + tree->size + 1);
689 node->type = mpack_type_str;
690 return mpack_tree_parse_bytes(tree, node);
691
692 // array16
693 case 0xdc:
694 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
695 return false;
696 node->len = mpack_load_u16(tree->data + tree->size + 1);
697 node->type = mpack_type_array;
698 return mpack_tree_parse_children(tree, node);
699
700 // array32
701 case 0xdd:
702 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
703 return false;
704 node->len = mpack_load_u32(tree->data + tree->size + 1);
705 node->type = mpack_type_array;
706 return mpack_tree_parse_children(tree, node);
707
708 // map16
709 case 0xde:
710 if (!mpack_tree_reserve_bytes(tree, sizeof(uint16_t)))
711 return false;
712 node->len = mpack_load_u16(tree->data + tree->size + 1);
713 node->type = mpack_type_map;
714 return mpack_tree_parse_children(tree, node);
715
716 // map32
717 case 0xdf:
718 if (!mpack_tree_reserve_bytes(tree, sizeof(uint32_t)))
719 return false;
720 node->len = mpack_load_u32(tree->data + tree->size + 1);
721 node->type = mpack_type_map;
722 return mpack_tree_parse_children(tree, node);
723
724 // reserved
725 case 0xc1:
726 mpack_tree_flag_error(tree, mpack_error_invalid);
727 return false;
728
729 #if !MPACK_EXTENSIONS
730 // ext
731 case 0xc7: // fallthrough
732 case 0xc8: // fallthrough
733 case 0xc9: // fallthrough
734 // fixext
735 case 0xd4: // fallthrough
736 case 0xd5: // fallthrough
737 case 0xd6: // fallthrough
738 case 0xd7: // fallthrough
739 case 0xd8:
740 mpack_tree_flag_error(tree, mpack_error_unsupported);
741 return false;
742 #endif
743
744 #if MPACK_OPTIMIZE_FOR_SIZE
745 // any other bytes should have been handled by the infix switch
746 default:
747 break;
748 #endif
749 }
750
751 mpack_assert(0, "unreachable");
752 return false;
753}
754
755static bool mpack_tree_parse_node(mpack_tree_t* tree, mpack_node_data_t* node) {
756 mpack_log("parsing a node at position %i in level %i\n",
757 (int)tree->size, (int)tree->parser.level);
758
759 if (!mpack_tree_parse_node_contents(tree, node)) {
760 mpack_log("node parsing returned false\n");
761 return false;
762 }
763
764 tree->parser.possible_nodes_left -= tree->parser.current_node_reserved;
765
766 // The reserve for the current node does not include the initial byte
767 // previously reserved as part of its parent.
768 size_t node_size = tree->parser.current_node_reserved + 1;
769
770 // If the parsed type is a map or array, the reserve includes one byte for
771 // each child. We want to subtract these out of possible_nodes_left, but
772 // not out of the current size of the tree.
773 if (node->type == mpack_type_array)
774 node_size -= node->len;
775 else if (node->type == mpack_type_map)
776 node_size -= node->len * 2;
777 tree->size += node_size;
778
779 mpack_log("parsed a node of type %s of %i bytes and "
780 "%i additional bytes reserved for children.\n",
781 mpack_type_to_string(node->type), (int)node_size,
782 (int)tree->parser.current_node_reserved + 1 - (int)node_size);
783
784 return true;
785}
786
787/*
788 * We read nodes in a loop instead of recursively for maximum performance. The
789 * stack holds the amount of children left to read in each level of the tree.
790 * Parsing can pause and resume when more data becomes available.
791 */
792static bool mpack_tree_continue_parsing(mpack_tree_t* tree) {
793 if (mpack_tree_error(tree) != mpack_ok)
794 return false;
795
796 mpack_tree_parser_t* parser = &tree->parser;
797 mpack_assert(parser->state == mpack_tree_parse_state_in_progress);
798 mpack_log("parsing tree elements, %i bytes in buffer\n", (int)tree->data_length);
799
800 // we loop parsing nodes until the parse stack is empty. we break
801 // by returning out of the function.
802 while (true) {
803 mpack_node_data_t* node = parser->stack[parser->level].child;
804 size_t level = parser->level;
805 if (!mpack_tree_parse_node(tree, node))
806 return false;
807 --parser->stack[level].left;
808 ++parser->stack[level].child;
809
810 mpack_assert(mpack_tree_error(tree) == mpack_ok,
811 "mpack_tree_parse_node() should have returned false due to error!");
812
813 // pop empty stack levels, exiting the outer loop when the stack is empty.
814 // (we could tail-optimize containers by pre-emptively popping empty
815 // stack levels before reading the new element, this way we wouldn't
816 // have to loop. but we eventually want to use the parse stack to give
817 // better error messages that contain the location of the error, so
818 // it needs to be complete.)
819 while (parser->stack[parser->level].left == 0) {
820 if (parser->level == 0)
821 return true;
822 --parser->level;
823 }
824 }
825}
826
827static void mpack_tree_cleanup(mpack_tree_t* tree) {
828 MPACK_UNUSED(tree);
829
830 #ifdef MPACK_MALLOC
831 if (tree->parser.stack_owned) {
832 MPACK_FREE(tree->parser.stack);
833 tree->parser.stack = NULL;
834 tree->parser.stack_owned = false;
835 }
836
837 mpack_tree_page_t* page = tree->next;
838 while (page != NULL) {
839 mpack_tree_page_t* next = page->next;
840 mpack_log("freeing page %p\n", (void*)page);
841 MPACK_FREE(page);
842 page = next;
843 }
844 tree->next = NULL;
845 #endif
846}
847
848static bool mpack_tree_parse_start(mpack_tree_t* tree) {
849 if (mpack_tree_error(tree) != mpack_ok)
850 return false;
851
852 mpack_tree_parser_t* parser = &tree->parser;
853 mpack_assert(parser->state != mpack_tree_parse_state_in_progress,
854 "previous parsing was not finished!");
855
856 if (parser->state == mpack_tree_parse_state_parsed)
857 mpack_tree_cleanup(tree);
858
859 mpack_log("starting parse\n");
860 tree->parser.state = mpack_tree_parse_state_in_progress;
861 tree->parser.current_node_reserved = 0;
862
863 // check if we previously parsed a tree
864 if (tree->size > 0) {
865 #ifdef MPACK_MALLOC
866 // if we're buffered, move the remaining data back to the
867 // start of the buffer
868 // TODO: This is not ideal performance-wise. We should only move data
869 // when we need to call the fill function.
870 // TODO: We could consider shrinking the buffer here, especially if we
871 // determine that the fill function is providing less than a quarter of
872 // the buffer size or if messages take up less than a quarter of the
873 // buffer size. Maybe this should be configurable.
874 if (tree->buffer != NULL) {
875 mpack_memmove(tree->buffer, tree->buffer + tree->size, tree->data_length - tree->size);
876 }
877 else
878 #endif
879 // otherwise advance past the parsed data
880 {
881 tree->data += tree->size;
882 }
883 tree->data_length -= tree->size;
884 tree->size = 0;
885 tree->node_count = 0;
886 }
887
888 // make sure we have at least one byte available before allocating anything
889 parser->possible_nodes_left = tree->data_length;
890 if (!mpack_tree_reserve_bytes(tree, sizeof(uint8_t))) {
891 tree->parser.state = mpack_tree_parse_state_not_started;
892 return false;
893 }
894 mpack_log("parsing tree at %p starting with byte %x\n", tree->data, (uint8_t)tree->data[0]);
895 parser->possible_nodes_left -= 1;
896 tree->node_count = 1;
897
898 #ifdef MPACK_MALLOC
899 parser->stack = parser->stack_local;
900 parser->stack_owned = false;
901 parser->stack_capacity = sizeof(parser->stack_local) / sizeof(*parser->stack_local);
902
903 if (tree->pool == NULL) {
904
905 // allocate first page
906 mpack_tree_page_t* page = (mpack_tree_page_t*)MPACK_MALLOC(MPACK_PAGE_ALLOC_SIZE);
907 mpack_log("allocated initial page %p of size %i count %i\n",
908 (void*)page, (int)MPACK_PAGE_ALLOC_SIZE, (int)MPACK_NODES_PER_PAGE);
909 if (page == NULL) {
910 tree->error = mpack_error_memory;
911 return false;
912 }
913 page->next = NULL;
914 tree->next = page;
915
916 parser->nodes = page->nodes;
917 parser->nodes_left = MPACK_NODES_PER_PAGE;
918 }
919 else
920 #endif
921 {
922 // otherwise use the provided pool
923 mpack_assert(tree->pool != NULL, "no pool provided?");
924 parser->nodes = tree->pool;
925 parser->nodes_left = tree->pool_count;
926 }
927
928 tree->root = parser->nodes;
929 ++parser->nodes;
930 --parser->nodes_left;
931
932 parser->level = 0;
933 parser->stack[0].child = tree->root;
934 parser->stack[0].left = 1;
935
936 return true;
937}
938
939void mpack_tree_parse(mpack_tree_t* tree) {
940 if (mpack_tree_error(tree) != mpack_ok)
941 return;
942
943 if (tree->parser.state != mpack_tree_parse_state_in_progress) {
944 if (!mpack_tree_parse_start(tree)) {
945 mpack_tree_flag_error(tree, (tree->read_fn == NULL) ?
946 mpack_error_invalid : mpack_error_io);
947 return;
948 }
949 }
950
951 if (!mpack_tree_continue_parsing(tree)) {
952 if (mpack_tree_error(tree) != mpack_ok)
953 return;
954
955 // We're parsing synchronously on a blocking fill function. If we
956 // didn't completely finish parsing the tree, it's an error.
957 mpack_log("tree parsing incomplete. flagging error.\n");
958 mpack_tree_flag_error(tree, (tree->read_fn == NULL) ?
959 mpack_error_invalid : mpack_error_io);
960 return;
961 }
962
963 mpack_assert(mpack_tree_error(tree) == mpack_ok);
964 mpack_assert(tree->parser.level == 0);
965 tree->parser.state = mpack_tree_parse_state_parsed;
966 mpack_log("parsed tree of %i bytes, %i bytes left\n", (int)tree->size, (int)tree->parser.possible_nodes_left);
967 mpack_log("%i nodes in final page\n", (int)tree->parser.nodes_left);
968}
969
970bool mpack_tree_try_parse(mpack_tree_t* tree) {
971 if (mpack_tree_error(tree) != mpack_ok)
972 return false;
973
974 if (tree->parser.state != mpack_tree_parse_state_in_progress)
975 if (!mpack_tree_parse_start(tree))
976 return false;
977
978 if (!mpack_tree_continue_parsing(tree))
979 return false;
980
981 mpack_assert(mpack_tree_error(tree) == mpack_ok);
982 mpack_assert(tree->parser.level == 0);
983 tree->parser.state = mpack_tree_parse_state_parsed;
984 return true;
985}
986
987
988
989/*
990 * Tree functions
991 */
992
993mpack_node_t mpack_tree_root(mpack_tree_t* tree) {
994 if (mpack_tree_error(tree) != mpack_ok)
995 return mpack_tree_nil_node(tree);
996
997 // We check that a tree was parsed successfully and assert if not. You must
998 // call mpack_tree_parse() (or mpack_tree_try_parse() with a success
999 // result) in order to access the root node.
1000 if (tree->parser.state != mpack_tree_parse_state_parsed) {
1001 mpack_break("Tree has not been parsed! "
1002 "Did you call mpack_tree_parse() or mpack_tree_try_parse()?");
1003 mpack_tree_flag_error(tree, mpack_error_bug);
1004 return mpack_tree_nil_node(tree);
1005 }
1006
1007 return mpack_node(tree, tree->root);
1008}
1009
1010static void mpack_tree_init_clear(mpack_tree_t* tree) {
1011 mpack_memset(tree, 0, sizeof(*tree));
1012 tree->nil_node.type = mpack_type_nil;
1013 tree->missing_node.type = mpack_type_missing;
1014 tree->max_size = SIZE_MAX;
1015 tree->max_nodes = SIZE_MAX;
1016}
1017
1018#ifdef MPACK_MALLOC
1019void mpack_tree_init_data(mpack_tree_t* tree, const char* data, size_t length) {
1020 mpack_tree_init_clear(tree);
1021
1022 MPACK_STATIC_ASSERT(MPACK_NODE_PAGE_SIZE >= sizeof(mpack_tree_page_t),
1023 "MPACK_NODE_PAGE_SIZE is too small");
1024
1025 MPACK_STATIC_ASSERT(MPACK_PAGE_ALLOC_SIZE <= MPACK_NODE_PAGE_SIZE,
1026 "incorrect page rounding?");
1027
1028 tree->data = data;
1029 tree->data_length = length;
1030 tree->pool = NULL;
1031 tree->pool_count = 0;
1032 tree->next = NULL;
1033
1034 mpack_log("===========================\n");
1035 mpack_log("initializing tree with data of size %i\n", (int)length);
1036}
1037#endif
1038
1039void mpack_tree_init_pool(mpack_tree_t* tree, const char* data, size_t length,
1040 mpack_node_data_t* node_pool, size_t node_pool_count)
1041{
1042 mpack_tree_init_clear(tree);
1043 #ifdef MPACK_MALLOC
1044 tree->next = NULL;
1045 #endif
1046
1047 if (node_pool_count == 0) {
1048 mpack_break("initial page has no nodes!");
1049 mpack_tree_flag_error(tree, mpack_error_bug);
1050 return;
1051 }
1052
1053 tree->data = data;
1054 tree->data_length = length;
1055 tree->pool = node_pool;
1056 tree->pool_count = node_pool_count;
1057
1058 mpack_log("===========================\n");
1059 mpack_log("initializing tree with data of size %i and pool of count %i\n",
1060 (int)length, (int)node_pool_count);
1061}
1062
1063void mpack_tree_init_error(mpack_tree_t* tree, mpack_error_t error) {
1064 mpack_tree_init_clear(tree);
1065 tree->error = error;
1066
1067 mpack_log("===========================\n");
1068 mpack_log("initializing tree error state %i\n", (int)error);
1069}
1070
1071#ifdef MPACK_MALLOC
1072void mpack_tree_init_stream(mpack_tree_t* tree, mpack_tree_read_t read_fn, void* context,
1073 size_t max_message_size, size_t max_message_nodes) {
1074 mpack_tree_init_clear(tree);
1075
1076 tree->read_fn = read_fn;
1077 tree->context = context;
1078
1079 mpack_tree_set_limits(tree, max_message_size, max_message_nodes);
1080 tree->max_size = max_message_size;
1081 tree->max_nodes = max_message_nodes;
1082
1083 mpack_log("===========================\n");
1084 mpack_log("initializing tree with stream, max size %i max nodes %i\n",
1085 (int)max_message_size, (int)max_message_nodes);
1086}
1087#endif
1088
1089void mpack_tree_set_limits(mpack_tree_t* tree, size_t max_message_size, size_t max_message_nodes) {
1090 mpack_assert(max_message_size > 0);
1091 mpack_assert(max_message_nodes > 0);
1092 tree->max_size = max_message_size;
1093 tree->max_nodes = max_message_nodes;
1094}
1095
1096#if MPACK_STDIO
1097typedef struct mpack_file_tree_t {
1098 char* data;
1099 size_t size;
1100 char buffer[MPACK_BUFFER_SIZE];
1101} mpack_file_tree_t;
1102
1103static void mpack_file_tree_teardown(mpack_tree_t* tree) {
1104 mpack_file_tree_t* file_tree = (mpack_file_tree_t*)tree->context;
1105 MPACK_FREE(file_tree->data);
1106 MPACK_FREE(file_tree);
1107}
1108
1109static bool mpack_file_tree_read(mpack_tree_t* tree, mpack_file_tree_t* file_tree, FILE* file, size_t max_bytes) {
1110
1111 // get the file size
1112 errno = 0;
1113 int error = 0;
1114 fseek(file, 0, SEEK_END);
1115 error |= errno;
1116 long size = ftell(file);
1117 error |= errno;
1118 fseek(file, 0, SEEK_SET);
1119 error |= errno;
1120
1121 // check for errors
1122 if (error != 0 || size < 0) {
1123 mpack_tree_init_error(tree, mpack_error_io);
1124 return false;
1125 }
1126 if (size == 0) {
1127 mpack_tree_init_error(tree, mpack_error_invalid);
1128 return false;
1129 }
1130
1131 // make sure the size is less than max_bytes
1132 // (this mess exists to safely convert between long and size_t regardless of their widths)
1133 if (max_bytes != 0 && (((uint64_t)LONG_MAX > (uint64_t)SIZE_MAX && size > (long)SIZE_MAX) || (size_t)size > max_bytes)) {
1134 mpack_tree_init_error(tree, mpack_error_too_big);
1135 return false;
1136 }
1137
1138 // allocate data
1139 file_tree->data = (char*)MPACK_MALLOC((size_t)size);
1140 if (file_tree->data == NULL) {
1141 mpack_tree_init_error(tree, mpack_error_memory);
1142 return false;
1143 }
1144
1145 // read the file
1146 long total = 0;
1147 while (total < size) {
1148 size_t read = fread(file_tree->data + total, 1, (size_t)(size - total), file);
1149 if (read <= 0) {
1150 mpack_tree_init_error(tree, mpack_error_io);
1151 MPACK_FREE(file_tree->data);
1152 return false;
1153 }
1154 total += (long)read;
1155 }
1156
1157 file_tree->size = (size_t)size;
1158 return true;
1159}
1160
1161static bool mpack_tree_file_check_max_bytes(mpack_tree_t* tree, size_t max_bytes) {
1162
1163 // the C STDIO family of file functions use long (e.g. ftell)
1164 if (max_bytes > LONG_MAX) {
1165 mpack_break("max_bytes of %" PRIu64 " is invalid, maximum is LONG_MAX", (uint64_t)max_bytes);
1166 mpack_tree_init_error(tree, mpack_error_bug);
1167 return false;
1168 }
1169
1170 return true;
1171}
1172
1173static void mpack_tree_init_stdfile_noclose(mpack_tree_t* tree, FILE* stdfile, size_t max_bytes) {
1174
1175 // allocate file tree
1176 mpack_file_tree_t* file_tree = (mpack_file_tree_t*) MPACK_MALLOC(sizeof(mpack_file_tree_t));
1177 if (file_tree == NULL) {
1178 mpack_tree_init_error(tree, mpack_error_memory);
1179 return;
1180 }
1181
1182 // read all data
1183 if (!mpack_file_tree_read(tree, file_tree, stdfile, max_bytes)) {
1184 MPACK_FREE(file_tree);
1185 return;
1186 }
1187
1188 mpack_tree_init_data(tree, file_tree->data, file_tree->size);
1189 mpack_tree_set_context(tree, file_tree);
1190 mpack_tree_set_teardown(tree, mpack_file_tree_teardown);
1191}
1192
1193void mpack_tree_init_stdfile(mpack_tree_t* tree, FILE* stdfile, size_t max_bytes, bool close_when_done) {
1194 if (!mpack_tree_file_check_max_bytes(tree, max_bytes))
1195 return;
1196
1197 mpack_tree_init_stdfile_noclose(tree, stdfile, max_bytes);
1198
1199 if (close_when_done)
1200 fclose(stdfile);
1201}
1202
1203void mpack_tree_init_filename(mpack_tree_t* tree, const char* filename, size_t max_bytes) {
1204 if (!mpack_tree_file_check_max_bytes(tree, max_bytes))
1205 return;
1206
1207 // open the file
1208 FILE* file = fopen(filename, "rb");
1209 if (!file) {
1210 mpack_tree_init_error(tree, mpack_error_io);
1211 return;
1212 }
1213
1214 mpack_tree_init_stdfile(tree, file, max_bytes, true);
1215}
1216#endif
1217
1218mpack_error_t mpack_tree_destroy(mpack_tree_t* tree) {
1219 mpack_tree_cleanup(tree);
1220
1221 #ifdef MPACK_MALLOC
1222 if (tree->buffer)
1223 MPACK_FREE(tree->buffer);
1224 #endif
1225
1226 if (tree->teardown)
1227 tree->teardown(tree);
1228 tree->teardown = NULL;
1229
1230 return tree->error;
1231}
1232
1233void mpack_tree_flag_error(mpack_tree_t* tree, mpack_error_t error) {
1234 if (tree->error == mpack_ok) {
1235 mpack_log("tree %p setting error %i: %s\n", (void*)tree, (int)error, mpack_error_to_string(error));
1236 tree->error = error;
1237 if (tree->error_fn)
1238 tree->error_fn(tree, error);
1239 }
1240
1241}
1242
1243
1244
1245/*
1246 * Node misc functions
1247 */
1248
1249void mpack_node_flag_error(mpack_node_t node, mpack_error_t error) {
1250 mpack_tree_flag_error(node.tree, error);
1251}
1252
1253mpack_tag_t mpack_node_tag(mpack_node_t node) {
1254 if (mpack_node_error(node) != mpack_ok)
1255 return mpack_tag_nil();
1256
1257 mpack_tag_t tag = MPACK_TAG_ZERO;
1258
1259 tag.type = node.data->type;
1260 switch (node.data->type) {
1261 case mpack_type_missing:
1262 // If a node is missing, I don't know if it makes sense to ask for
1263 // a tag for it. We'll return a missing tag to match the missing
1264 // node I guess, but attempting to use the tag for anything (like
1265 // writing it for example) will flag mpack_error_bug.
1266 break;
1267 case mpack_type_nil: break;
1268 case mpack_type_bool: tag.v.b = node.data->value.b; break;
1269 case mpack_type_float: tag.v.f = node.data->value.f; break;
1270 case mpack_type_double: tag.v.d = node.data->value.d; break;
1271 case mpack_type_int: tag.v.i = node.data->value.i; break;
1272 case mpack_type_uint: tag.v.u = node.data->value.u; break;
1273
1274 case mpack_type_str: tag.v.l = node.data->len; break;
1275 case mpack_type_bin: tag.v.l = node.data->len; break;
1276
1277 #if MPACK_EXTENSIONS
1278 case mpack_type_ext:
1279 tag.v.l = node.data->len;
1280 tag.exttype = mpack_node_exttype_unchecked(node);
1281 break;
1282 #endif
1283
1284 case mpack_type_array: tag.v.n = node.data->len; break;
1285 case mpack_type_map: tag.v.n = node.data->len; break;
1286
1287 default:
1288 mpack_assert(0, "unrecognized type %i", (int)node.data->type);
1289 break;
1290 }
1291 return tag;
1292}
1293
1294#if MPACK_DEBUG && MPACK_STDIO
1295static void mpack_node_print_element(mpack_node_t node, mpack_print_t* print, size_t depth) {
1296 mpack_node_data_t* data = node.data;
1297 size_t i,j;
1298 switch (data->type) {
1299 case mpack_type_str:
1300 {
1301 mpack_print_append_cstr(print, "\"");
1302 const char* bytes = mpack_node_data_unchecked(node);
1303 for (i = 0; i < data->len; ++i) {
1304 char c = bytes[i];
1305 switch (c) {
1306 case '\n': mpack_print_append_cstr(print, "\\n"); break;
1307 case '\\': mpack_print_append_cstr(print, "\\\\"); break;
1308 case '"': mpack_print_append_cstr(print, "\\\""); break;
1309 default: mpack_print_append(print, &c, 1); break;
1310 }
1311 }
1312 mpack_print_append_cstr(print, "\"");
1313 }
1314 break;
1315
1316 case mpack_type_array:
1317 mpack_print_append_cstr(print, "[\n");
1318 for (i = 0; i < data->len; ++i) {
1319 for (j = 0; j < depth + 1; ++j)
1320 mpack_print_append_cstr(print, " ");
1321 mpack_node_print_element(mpack_node_array_at(node, i), print, depth + 1);
1322 if (i != data->len - 1)
1323 mpack_print_append_cstr(print, ",");
1324 mpack_print_append_cstr(print, "\n");
1325 }
1326 for (i = 0; i < depth; ++i)
1327 mpack_print_append_cstr(print, " ");
1328 mpack_print_append_cstr(print, "]");
1329 break;
1330
1331 case mpack_type_map:
1332 mpack_print_append_cstr(print, "{\n");
1333 for (i = 0; i < data->len; ++i) {
1334 for (j = 0; j < depth + 1; ++j)
1335 mpack_print_append_cstr(print, " ");
1336 mpack_node_print_element(mpack_node_map_key_at(node, i), print, depth + 1);
1337 mpack_print_append_cstr(print, ": ");
1338 mpack_node_print_element(mpack_node_map_value_at(node, i), print, depth + 1);
1339 if (i != data->len - 1)
1340 mpack_print_append_cstr(print, ",");
1341 mpack_print_append_cstr(print, "\n");
1342 }
1343 for (i = 0; i < depth; ++i)
1344 mpack_print_append_cstr(print, " ");
1345 mpack_print_append_cstr(print, "}");
1346 break;
1347
1348 default:
1349 {
1350 const char* prefix = NULL;
1351 size_t prefix_length = 0;
1352 if (mpack_node_type(node) == mpack_type_bin
1353 #if MPACK_EXTENSIONS
1354 || mpack_node_type(node) == mpack_type_ext
1355 #endif
1356 ) {
1357 prefix = mpack_node_data(node);
1358 prefix_length = mpack_node_data_len(node);
1359 }
1360
1361 char buf[256];
1362 mpack_tag_t tag = mpack_node_tag(node);
1363 mpack_tag_debug_pseudo_json(tag, buf, sizeof(buf), prefix, prefix_length);
1364 mpack_print_append_cstr(print, buf);
1365 }
1366 break;
1367 }
1368}
1369
1370void mpack_node_print_to_buffer(mpack_node_t node, char* buffer, size_t buffer_size) {
1371 if (buffer_size == 0) {
1372 mpack_assert(false, "buffer size is zero!");
1373 return;
1374 }
1375
1376 mpack_print_t print;
1377 mpack_memset(&print, 0, sizeof(print));
1378 print.buffer = buffer;
1379 print.size = buffer_size;
1380 mpack_node_print_element(node, &print, 0);
1381 mpack_print_append(&print, "", 1); // null-terminator
1382 mpack_print_flush(&print);
1383
1384 // we always make sure there's a null-terminator at the end of the buffer
1385 // in case we ran out of space.
1386 print.buffer[print.size - 1] = '\0';
1387}
1388
1389void mpack_node_print_to_callback(mpack_node_t node, mpack_print_callback_t callback, void* context) {
1390 char buffer[1024];
1391 mpack_print_t print;
1392 mpack_memset(&print, 0, sizeof(print));
1393 print.buffer = buffer;
1394 print.size = sizeof(buffer);
1395 print.callback = callback;
1396 print.context = context;
1397 mpack_node_print_element(node, &print, 0);
1398 mpack_print_flush(&print);
1399}
1400
1401void mpack_node_print_to_file(mpack_node_t node, FILE* file) {
1402 mpack_assert(file != NULL, "file is NULL");
1403
1404 char buffer[1024];
1405 mpack_print_t print;
1406 mpack_memset(&print, 0, sizeof(print));
1407 print.buffer = buffer;
1408 print.size = sizeof(buffer);
1409 print.callback = &mpack_print_file_callback;
1410 print.context = file;
1411
1412 size_t depth = 2;
1413 size_t i;
1414 for (i = 0; i < depth; ++i)
1415 mpack_print_append_cstr(&print, " ");
1416 mpack_node_print_element(node, &print, depth);
1417 mpack_print_append_cstr(&print, "\n");
1418 mpack_print_flush(&print);
1419}
1420#endif
1421
1422
1423
1424/*
1425 * Node Value Functions
1426 */
1427
1428#if MPACK_EXTENSIONS
1429mpack_timestamp_t mpack_node_timestamp(mpack_node_t node) {
1430 mpack_timestamp_t timestamp = {0, 0};
1431
1432 // we'll let mpack_node_exttype() do most checks
1433 if (mpack_node_exttype(node) != MPACK_EXTTYPE_TIMESTAMP) {
1434 mpack_log("exttype %i\n", mpack_node_exttype(node));
1435 mpack_node_flag_error(node, mpack_error_type);
1436 return timestamp;
1437 }
1438
1439 const char* p = mpack_node_data_unchecked(node);
1440
1441 switch (node.data->len) {
1442 case 4:
1443 timestamp.nanoseconds = 0;
1444 timestamp.seconds = mpack_load_u32(p);
1445 break;
1446
1447 case 8: {
1448 uint64_t value = mpack_load_u64(p);
1449 timestamp.nanoseconds = (uint32_t)(value >> 34);
1450 timestamp.seconds = value & ((MPACK_UINT64_C(1) << 34) - 1);
1451 break;
1452 }
1453
1454 case 12:
1455 timestamp.nanoseconds = mpack_load_u32(p);
1456 timestamp.seconds = mpack_load_i64(p + 4);
1457 break;
1458
1459 default:
1460 mpack_tree_flag_error(node.tree, mpack_error_invalid);
1461 return timestamp;
1462 }
1463
1464 if (timestamp.nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
1465 mpack_tree_flag_error(node.tree, mpack_error_invalid);
1466 mpack_timestamp_t zero = {0, 0};
1467 return zero;
1468 }
1469
1470 return timestamp;
1471}
1472
1473int64_t mpack_node_timestamp_seconds(mpack_node_t node) {
1474 return mpack_node_timestamp(node).seconds;
1475}
1476
1477uint32_t mpack_node_timestamp_nanoseconds(mpack_node_t node) {
1478 return mpack_node_timestamp(node).nanoseconds;
1479}
1480#endif
1481
1482
1483
1484/*
1485 * Node Data Functions
1486 */
1487
1488void mpack_node_check_utf8(mpack_node_t node) {
1489 if (mpack_node_error(node) != mpack_ok)
1490 return;
1491 mpack_node_data_t* data = node.data;
1492 if (data->type != mpack_type_str || !mpack_utf8_check(mpack_node_data_unchecked(node), data->len))
1493 mpack_node_flag_error(node, mpack_error_type);
1494}
1495
1496void mpack_node_check_utf8_cstr(mpack_node_t node) {
1497 if (mpack_node_error(node) != mpack_ok)
1498 return;
1499 mpack_node_data_t* data = node.data;
1500 if (data->type != mpack_type_str || !mpack_utf8_check_no_null(mpack_node_data_unchecked(node), data->len))
1501 mpack_node_flag_error(node, mpack_error_type);
1502}
1503
1504size_t mpack_node_copy_data(mpack_node_t node, char* buffer, size_t bufsize) {
1505 if (mpack_node_error(node) != mpack_ok)
1506 return 0;
1507
1508 mpack_assert(bufsize == 0 || buffer != NULL, "buffer is NULL for maximum of %i bytes", (int)bufsize);
1509
1510 mpack_type_t type = node.data->type;
1511 if (type != mpack_type_str && type != mpack_type_bin
1512 #if MPACK_EXTENSIONS
1513 && type != mpack_type_ext
1514 #endif
1515 ) {
1516 mpack_node_flag_error(node, mpack_error_type);
1517 return 0;
1518 }
1519
1520 if (node.data->len > bufsize) {
1521 mpack_node_flag_error(node, mpack_error_too_big);
1522 return 0;
1523 }
1524
1525 mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
1526 return (size_t)node.data->len;
1527}
1528
1529size_t mpack_node_copy_utf8(mpack_node_t node, char* buffer, size_t bufsize) {
1530 if (mpack_node_error(node) != mpack_ok)
1531 return 0;
1532
1533 mpack_assert(bufsize == 0 || buffer != NULL, "buffer is NULL for maximum of %i bytes", (int)bufsize);
1534
1535 mpack_type_t type = node.data->type;
1536 if (type != mpack_type_str) {
1537 mpack_node_flag_error(node, mpack_error_type);
1538 return 0;
1539 }
1540
1541 if (node.data->len > bufsize) {
1542 mpack_node_flag_error(node, mpack_error_too_big);
1543 return 0;
1544 }
1545
1546 if (!mpack_utf8_check(mpack_node_data_unchecked(node), node.data->len)) {
1547 mpack_node_flag_error(node, mpack_error_type);
1548 return 0;
1549 }
1550
1551 mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
1552 return (size_t)node.data->len;
1553}
1554
1555void mpack_node_copy_cstr(mpack_node_t node, char* buffer, size_t bufsize) {
1556
1557 // we can't break here because the error isn't recoverable; we
1558 // have to add a null-terminator.
1559 mpack_assert(buffer != NULL, "buffer is NULL");
1560 mpack_assert(bufsize >= 1, "buffer size is zero; you must have room for at least a null-terminator");
1561
1562 if (mpack_node_error(node) != mpack_ok) {
1563 buffer[0] = '\0';
1564 return;
1565 }
1566
1567 if (node.data->type != mpack_type_str) {
1568 buffer[0] = '\0';
1569 mpack_node_flag_error(node, mpack_error_type);
1570 return;
1571 }
1572
1573 if (node.data->len > bufsize - 1) {
1574 buffer[0] = '\0';
1575 mpack_node_flag_error(node, mpack_error_too_big);
1576 return;
1577 }
1578
1579 if (!mpack_str_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
1580 buffer[0] = '\0';
1581 mpack_node_flag_error(node, mpack_error_type);
1582 return;
1583 }
1584
1585 mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
1586 buffer[node.data->len] = '\0';
1587}
1588
1589void mpack_node_copy_utf8_cstr(mpack_node_t node, char* buffer, size_t bufsize) {
1590
1591 // we can't break here because the error isn't recoverable; we
1592 // have to add a null-terminator.
1593 mpack_assert(buffer != NULL, "buffer is NULL");
1594 mpack_assert(bufsize >= 1, "buffer size is zero; you must have room for at least a null-terminator");
1595
1596 if (mpack_node_error(node) != mpack_ok) {
1597 buffer[0] = '\0';
1598 return;
1599 }
1600
1601 if (node.data->type != mpack_type_str) {
1602 buffer[0] = '\0';
1603 mpack_node_flag_error(node, mpack_error_type);
1604 return;
1605 }
1606
1607 if (node.data->len > bufsize - 1) {
1608 buffer[0] = '\0';
1609 mpack_node_flag_error(node, mpack_error_too_big);
1610 return;
1611 }
1612
1613 if (!mpack_utf8_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
1614 buffer[0] = '\0';
1615 mpack_node_flag_error(node, mpack_error_type);
1616 return;
1617 }
1618
1619 mpack_memcpy(buffer, mpack_node_data_unchecked(node), node.data->len);
1620 buffer[node.data->len] = '\0';
1621}
1622
1623#ifdef MPACK_MALLOC
1624char* mpack_node_data_alloc(mpack_node_t node, size_t maxlen) {
1625 if (mpack_node_error(node) != mpack_ok)
1626 return NULL;
1627
1628 // make sure this is a valid data type
1629 mpack_type_t type = node.data->type;
1630 if (type != mpack_type_str && type != mpack_type_bin
1631 #if MPACK_EXTENSIONS
1632 && type != mpack_type_ext
1633 #endif
1634 ) {
1635 mpack_node_flag_error(node, mpack_error_type);
1636 return NULL;
1637 }
1638
1639 if (node.data->len > maxlen) {
1640 mpack_node_flag_error(node, mpack_error_too_big);
1641 return NULL;
1642 }
1643
1644 char* ret = (char*) MPACK_MALLOC((size_t)node.data->len);
1645 if (ret == NULL) {
1646 mpack_node_flag_error(node, mpack_error_memory);
1647 return NULL;
1648 }
1649
1650 mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
1651 return ret;
1652}
1653
1654char* mpack_node_cstr_alloc(mpack_node_t node, size_t maxlen) {
1655 if (mpack_node_error(node) != mpack_ok)
1656 return NULL;
1657
1658 // make sure maxlen makes sense
1659 if (maxlen < 1) {
1660 mpack_break("maxlen is zero; you must have room for at least a null-terminator");
1661 mpack_node_flag_error(node, mpack_error_bug);
1662 return NULL;
1663 }
1664
1665 if (node.data->type != mpack_type_str) {
1666 mpack_node_flag_error(node, mpack_error_type);
1667 return NULL;
1668 }
1669
1670 if (node.data->len > maxlen - 1) {
1671 mpack_node_flag_error(node, mpack_error_too_big);
1672 return NULL;
1673 }
1674
1675 if (!mpack_str_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
1676 mpack_node_flag_error(node, mpack_error_type);
1677 return NULL;
1678 }
1679
1680 char* ret = (char*) MPACK_MALLOC((size_t)(node.data->len + 1));
1681 if (ret == NULL) {
1682 mpack_node_flag_error(node, mpack_error_memory);
1683 return NULL;
1684 }
1685
1686 mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
1687 ret[node.data->len] = '\0';
1688 return ret;
1689}
1690
1691char* mpack_node_utf8_cstr_alloc(mpack_node_t node, size_t maxlen) {
1692 if (mpack_node_error(node) != mpack_ok)
1693 return NULL;
1694
1695 // make sure maxlen makes sense
1696 if (maxlen < 1) {
1697 mpack_break("maxlen is zero; you must have room for at least a null-terminator");
1698 mpack_node_flag_error(node, mpack_error_bug);
1699 return NULL;
1700 }
1701
1702 if (node.data->type != mpack_type_str) {
1703 mpack_node_flag_error(node, mpack_error_type);
1704 return NULL;
1705 }
1706
1707 if (node.data->len > maxlen - 1) {
1708 mpack_node_flag_error(node, mpack_error_too_big);
1709 return NULL;
1710 }
1711
1712 if (!mpack_utf8_check_no_null(mpack_node_data_unchecked(node), node.data->len)) {
1713 mpack_node_flag_error(node, mpack_error_type);
1714 return NULL;
1715 }
1716
1717 char* ret = (char*) MPACK_MALLOC((size_t)(node.data->len + 1));
1718 if (ret == NULL) {
1719 mpack_node_flag_error(node, mpack_error_memory);
1720 return NULL;
1721 }
1722
1723 mpack_memcpy(ret, mpack_node_data_unchecked(node), node.data->len);
1724 ret[node.data->len] = '\0';
1725 return ret;
1726}
1727#endif
1728
1729
1730/*
1731 * Compound Node Functions
1732 */
1733
1734static mpack_node_data_t* mpack_node_map_int_impl(mpack_node_t node, int64_t num) {
1735 if (mpack_node_error(node) != mpack_ok)
1736 return NULL;
1737
1738 if (node.data->type != mpack_type_map) {
1739 mpack_node_flag_error(node, mpack_error_type);
1740 return NULL;
1741 }
1742
1743 mpack_node_data_t* found = NULL;
1744
1745 size_t i;
1746 for (i = 0; i < node.data->len; ++i) {
1747 mpack_node_data_t* key = mpack_node_child(node, i * 2);
1748
1749 if ((key->type == mpack_type_int && key->value.i == num) ||
1750 (key->type == mpack_type_uint && num >= 0 && key->value.u == (uint64_t)num))
1751 {
1752 if (found) {
1753 mpack_node_flag_error(node, mpack_error_data);
1754 return NULL;
1755 }
1756 found = mpack_node_child(node, i * 2 + 1);
1757 }
1758 }
1759
1760 if (found)
1761 return found;
1762
1763 return NULL;
1764}
1765
1766static mpack_node_data_t* mpack_node_map_uint_impl(mpack_node_t node, uint64_t num) {
1767 if (mpack_node_error(node) != mpack_ok)
1768 return NULL;
1769
1770 if (node.data->type != mpack_type_map) {
1771 mpack_node_flag_error(node, mpack_error_type);
1772 return NULL;
1773 }
1774
1775 mpack_node_data_t* found = NULL;
1776
1777 size_t i;
1778 for (i = 0; i < node.data->len; ++i) {
1779 mpack_node_data_t* key = mpack_node_child(node, i * 2);
1780
1781 if ((key->type == mpack_type_uint && key->value.u == num) ||
1782 (key->type == mpack_type_int && key->value.i >= 0 && (uint64_t)key->value.i == num))
1783 {
1784 if (found) {
1785 mpack_node_flag_error(node, mpack_error_data);
1786 return NULL;
1787 }
1788 found = mpack_node_child(node, i * 2 + 1);
1789 }
1790 }
1791
1792 if (found)
1793 return found;
1794
1795 return NULL;
1796}
1797
1798static mpack_node_data_t* mpack_node_map_str_impl(mpack_node_t node, const char* str, size_t length) {
1799 if (mpack_node_error(node) != mpack_ok)
1800 return NULL;
1801
1802 mpack_assert(length == 0 || str != NULL, "str of length %i is NULL", (int)length);
1803
1804 if (node.data->type != mpack_type_map) {
1805 mpack_node_flag_error(node, mpack_error_type);
1806 return NULL;
1807 }
1808
1809 mpack_tree_t* tree = node.tree;
1810 mpack_node_data_t* found = NULL;
1811
1812 size_t i;
1813 for (i = 0; i < node.data->len; ++i) {
1814 mpack_node_data_t* key = mpack_node_child(node, i * 2);
1815
1816 if (key->type == mpack_type_str && key->len == length &&
1817 mpack_memcmp(str, mpack_node_data_unchecked(mpack_node(tree, key)), length) == 0) {
1818 if (found) {
1819 mpack_node_flag_error(node, mpack_error_data);
1820 return NULL;
1821 }
1822 found = mpack_node_child(node, i * 2 + 1);
1823 }
1824 }
1825
1826 if (found)
1827 return found;
1828
1829 return NULL;
1830}
1831
1832static mpack_node_t mpack_node_wrap_lookup(mpack_tree_t* tree, mpack_node_data_t* data) {
1833 if (!data) {
1834 if (tree->error == mpack_ok)
1835 mpack_tree_flag_error(tree, mpack_error_data);
1836 return mpack_tree_nil_node(tree);
1837 }
1838 return mpack_node(tree, data);
1839}
1840
1841static mpack_node_t mpack_node_wrap_lookup_optional(mpack_tree_t* tree, mpack_node_data_t* data) {
1842 if (!data) {
1843 if (tree->error == mpack_ok)
1844 return mpack_tree_missing_node(tree);
1845 return mpack_tree_nil_node(tree);
1846 }
1847 return mpack_node(tree, data);
1848}
1849
1850mpack_node_t mpack_node_map_int(mpack_node_t node, int64_t num) {
1851 return mpack_node_wrap_lookup(node.tree, mpack_node_map_int_impl(node, num));
1852}
1853
1854mpack_node_t mpack_node_map_int_optional(mpack_node_t node, int64_t num) {
1855 return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_int_impl(node, num));
1856}
1857
1858mpack_node_t mpack_node_map_uint(mpack_node_t node, uint64_t num) {
1859 return mpack_node_wrap_lookup(node.tree, mpack_node_map_uint_impl(node, num));
1860}
1861
1862mpack_node_t mpack_node_map_uint_optional(mpack_node_t node, uint64_t num) {
1863 return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_uint_impl(node, num));
1864}
1865
1866mpack_node_t mpack_node_map_str(mpack_node_t node, const char* str, size_t length) {
1867 return mpack_node_wrap_lookup(node.tree, mpack_node_map_str_impl(node, str, length));
1868}
1869
1870mpack_node_t mpack_node_map_str_optional(mpack_node_t node, const char* str, size_t length) {
1871 return mpack_node_wrap_lookup_optional(node.tree, mpack_node_map_str_impl(node, str, length));
1872}
1873
1874mpack_node_t mpack_node_map_cstr(mpack_node_t node, const char* cstr) {
1875 mpack_assert(cstr != NULL, "cstr is NULL");
1876 return mpack_node_map_str(node, cstr, mpack_strlen(cstr));
1877}
1878
1879mpack_node_t mpack_node_map_cstr_optional(mpack_node_t node, const char* cstr) {
1880 mpack_assert(cstr != NULL, "cstr is NULL");
1881 return mpack_node_map_str_optional(node, cstr, mpack_strlen(cstr));
1882}
1883
1884bool mpack_node_map_contains_int(mpack_node_t node, int64_t num) {
1885 return mpack_node_map_int_impl(node, num) != NULL;
1886}
1887
1888bool mpack_node_map_contains_uint(mpack_node_t node, uint64_t num) {
1889 return mpack_node_map_uint_impl(node, num) != NULL;
1890}
1891
1892bool mpack_node_map_contains_str(mpack_node_t node, const char* str, size_t length) {
1893 return mpack_node_map_str_impl(node, str, length) != NULL;
1894}
1895
1896bool mpack_node_map_contains_cstr(mpack_node_t node, const char* cstr) {
1897 mpack_assert(cstr != NULL, "cstr is NULL");
1898 return mpack_node_map_contains_str(node, cstr, mpack_strlen(cstr));
1899}
1900
1901size_t mpack_node_enum_optional(mpack_node_t node, const char* strings[], size_t count) {
1902 if (mpack_node_error(node) != mpack_ok)
1903 return count;
1904
1905 // the value is only recognized if it is a string
1906 if (mpack_node_type(node) != mpack_type_str)
1907 return count;
1908
1909 // fetch the string
1910 const char* key = mpack_node_str(node);
1911 size_t keylen = mpack_node_strlen(node);
1912 mpack_assert(mpack_node_error(node) == mpack_ok, "these should not fail");
1913
1914 // find what key it matches
1915 size_t i;
1916 for (i = 0; i < count; ++i) {
1917 const char* other = strings[i];
1918 size_t otherlen = mpack_strlen(other);
1919 if (keylen == otherlen && mpack_memcmp(key, other, keylen) == 0)
1920 return i;
1921 }
1922
1923 // no matches
1924 return count;
1925}
1926
1927size_t mpack_node_enum(mpack_node_t node, const char* strings[], size_t count) {
1928 size_t value = mpack_node_enum_optional(node, strings, count);
1929 if (value == count)
1930 mpack_node_flag_error(node, mpack_error_type);
1931 return value;
1932}
1933
1934mpack_type_t mpack_node_type(mpack_node_t node) {
1935 if (mpack_node_error(node) != mpack_ok)
1936 return mpack_type_nil;
1937 return node.data->type;
1938}
1939
1940bool mpack_node_is_nil(mpack_node_t node) {
1941 if (mpack_node_error(node) != mpack_ok) {
1942 // All nodes are treated as nil nodes when we are in error.
1943 return true;
1944 }
1945 return node.data->type == mpack_type_nil;
1946}
1947
1948bool mpack_node_is_missing(mpack_node_t node) {
1949 if (mpack_node_error(node) != mpack_ok) {
1950 // errors still return nil nodes, not missing nodes.
1951 return false;
1952 }
1953 return node.data->type == mpack_type_missing;
1954}
1955
1956void mpack_node_nil(mpack_node_t node) {
1957 if (mpack_node_error(node) != mpack_ok)
1958 return;
1959 if (node.data->type != mpack_type_nil)
1960 mpack_node_flag_error(node, mpack_error_type);
1961}
1962
1963void mpack_node_missing(mpack_node_t node) {
1964 if (mpack_node_error(node) != mpack_ok)
1965 return;
1966 if (node.data->type != mpack_type_missing)
1967 mpack_node_flag_error(node, mpack_error_type);
1968}
1969
1970bool mpack_node_bool(mpack_node_t node) {
1971 if (mpack_node_error(node) != mpack_ok)
1972 return false;
1973
1974 if (node.data->type == mpack_type_bool)
1975 return node.data->value.b;
1976
1977 mpack_node_flag_error(node, mpack_error_type);
1978 return false;
1979}
1980
1981void mpack_node_true(mpack_node_t node) {
1982 if (mpack_node_bool(node) != true)
1983 mpack_node_flag_error(node, mpack_error_type);
1984}
1985
1986void mpack_node_false(mpack_node_t node) {
1987 if (mpack_node_bool(node) != false)
1988 mpack_node_flag_error(node, mpack_error_type);
1989}
1990
1991uint8_t mpack_node_u8(mpack_node_t node) {
1992 if (mpack_node_error(node) != mpack_ok)
1993 return 0;
1994
1995 if (node.data->type == mpack_type_uint) {
1996 if (node.data->value.u <= MPACK_UINT8_MAX)
1997 return (uint8_t)node.data->value.u;
1998 } else if (node.data->type == mpack_type_int) {
1999 if (node.data->value.i >= 0 && node.data->value.i <= MPACK_UINT8_MAX)
2000 return (uint8_t)node.data->value.i;
2001 }
2002
2003 mpack_node_flag_error(node, mpack_error_type);
2004 return 0;
2005}
2006
2007int8_t mpack_node_i8(mpack_node_t node) {
2008 if (mpack_node_error(node) != mpack_ok)
2009 return 0;
2010
2011 if (node.data->type == mpack_type_uint) {
2012 if (node.data->value.u <= MPACK_INT8_MAX)
2013 return (int8_t)node.data->value.u;
2014 } else if (node.data->type == mpack_type_int) {
2015 if (node.data->value.i >= MPACK_INT8_MIN && node.data->value.i <= MPACK_INT8_MAX)
2016 return (int8_t)node.data->value.i;
2017 }
2018
2019 mpack_node_flag_error(node, mpack_error_type);
2020 return 0;
2021}
2022
2023uint16_t mpack_node_u16(mpack_node_t node) {
2024 if (mpack_node_error(node) != mpack_ok)
2025 return 0;
2026
2027 if (node.data->type == mpack_type_uint) {
2028 if (node.data->value.u <= MPACK_UINT16_MAX)
2029 return (uint16_t)node.data->value.u;
2030 } else if (node.data->type == mpack_type_int) {
2031 if (node.data->value.i >= 0 && node.data->value.i <= MPACK_UINT16_MAX)
2032 return (uint16_t)node.data->value.i;
2033 }
2034
2035 mpack_node_flag_error(node, mpack_error_type);
2036 return 0;
2037}
2038
2039int16_t mpack_node_i16(mpack_node_t node) {
2040 if (mpack_node_error(node) != mpack_ok)
2041 return 0;
2042
2043 if (node.data->type == mpack_type_uint) {
2044 if (node.data->value.u <= MPACK_INT16_MAX)
2045 return (int16_t)node.data->value.u;
2046 } else if (node.data->type == mpack_type_int) {
2047 if (node.data->value.i >= MPACK_INT16_MIN && node.data->value.i <= MPACK_INT16_MAX)
2048 return (int16_t)node.data->value.i;
2049 }
2050
2051 mpack_node_flag_error(node, mpack_error_type);
2052 return 0;
2053}
2054
2055uint32_t mpack_node_u32(mpack_node_t node) {
2056 if (mpack_node_error(node) != mpack_ok)
2057 return 0;
2058
2059 if (node.data->type == mpack_type_uint) {
2060 if (node.data->value.u <= MPACK_UINT32_MAX)
2061 return (uint32_t)node.data->value.u;
2062 } else if (node.data->type == mpack_type_int) {
2063 if (node.data->value.i >= 0 && node.data->value.i <= MPACK_UINT32_MAX)
2064 return (uint32_t)node.data->value.i;
2065 }
2066
2067 mpack_node_flag_error(node, mpack_error_type);
2068 return 0;
2069}
2070
2071int32_t mpack_node_i32(mpack_node_t node) {
2072 if (mpack_node_error(node) != mpack_ok)
2073 return 0;
2074
2075 if (node.data->type == mpack_type_uint) {
2076 if (node.data->value.u <= MPACK_INT32_MAX)
2077 return (int32_t)node.data->value.u;
2078 } else if (node.data->type == mpack_type_int) {
2079 if (node.data->value.i >= MPACK_INT32_MIN && node.data->value.i <= MPACK_INT32_MAX)
2080 return (int32_t)node.data->value.i;
2081 }
2082
2083 mpack_node_flag_error(node, mpack_error_type);
2084 return 0;
2085}
2086
2087uint64_t mpack_node_u64(mpack_node_t node) {
2088 if (mpack_node_error(node) != mpack_ok)
2089 return 0;
2090
2091 if (node.data->type == mpack_type_uint) {
2092 return node.data->value.u;
2093 } else if (node.data->type == mpack_type_int) {
2094 if (node.data->value.i >= 0)
2095 return (uint64_t)node.data->value.i;
2096 }
2097
2098 mpack_node_flag_error(node, mpack_error_type);
2099 return 0;
2100}
2101
2102int64_t mpack_node_i64(mpack_node_t node) {
2103 if (mpack_node_error(node) != mpack_ok)
2104 return 0;
2105
2106 if (node.data->type == mpack_type_uint) {
2107 if (node.data->value.u <= (uint64_t)MPACK_INT64_MAX)
2108 return (int64_t)node.data->value.u;
2109 } else if (node.data->type == mpack_type_int) {
2110 return node.data->value.i;
2111 }
2112
2113 mpack_node_flag_error(node, mpack_error_type);
2114 return 0;
2115}
2116
2117unsigned int mpack_node_uint(mpack_node_t node) {
2118
2119 // This should be true at compile-time, so this just wraps the 32-bit function.
2120 if (sizeof(unsigned int) == 4)
2121 return (unsigned int)mpack_node_u32(node);
2122
2123 // Otherwise we use u64 and check the range.
2124 uint64_t val = mpack_node_u64(node);
2125 if (val <= MPACK_UINT_MAX)
2126 return (unsigned int)val;
2127
2128 mpack_node_flag_error(node, mpack_error_type);
2129 return 0;
2130}
2131
2132int mpack_node_int(mpack_node_t node) {
2133
2134 // This should be true at compile-time, so this just wraps the 32-bit function.
2135 if (sizeof(int) == 4)
2136 return (int)mpack_node_i32(node);
2137
2138 // Otherwise we use i64 and check the range.
2139 int64_t val = mpack_node_i64(node);
2140 if (val >= MPACK_INT_MIN && val <= MPACK_INT_MAX)
2141 return (int)val;
2142
2143 mpack_node_flag_error(node, mpack_error_type);
2144 return 0;
2145}
2146
2147#if MPACK_FLOAT
2148float mpack_node_float(mpack_node_t node) {
2149 if (mpack_node_error(node) != mpack_ok)
2150 return 0.0f;
2151
2152 if (node.data->type == mpack_type_uint)
2153 return (float)node.data->value.u;
2154 if (node.data->type == mpack_type_int)
2155 return (float)node.data->value.i;
2156 if (node.data->type == mpack_type_float)
2157 return node.data->value.f;
2158
2159 if (node.data->type == mpack_type_double) {
2160 #if MPACK_DOUBLE
2161 return (float)node.data->value.d;
2162 #else
2163 return mpack_shorten_raw_double_to_float(node.data->value.d);
2164 #endif
2165 }
2166
2167 mpack_node_flag_error(node, mpack_error_type);
2168 return 0.0f;
2169}
2170#endif
2171
2172#if MPACK_DOUBLE
2173double mpack_node_double(mpack_node_t node) {
2174 if (mpack_node_error(node) != mpack_ok)
2175 return 0.0;
2176
2177 if (node.data->type == mpack_type_uint)
2178 return (double)node.data->value.u;
2179 else if (node.data->type == mpack_type_int)
2180 return (double)node.data->value.i;
2181 else if (node.data->type == mpack_type_float)
2182 return (double)node.data->value.f;
2183 else if (node.data->type == mpack_type_double)
2184 return node.data->value.d;
2185
2186 mpack_node_flag_error(node, mpack_error_type);
2187 return 0.0;
2188}
2189#endif
2190
2191#if MPACK_FLOAT
2192float mpack_node_float_strict(mpack_node_t node) {
2193 if (mpack_node_error(node) != mpack_ok)
2194 return 0.0f;
2195
2196 if (node.data->type == mpack_type_float)
2197 return node.data->value.f;
2198
2199 mpack_node_flag_error(node, mpack_error_type);
2200 return 0.0f;
2201}
2202#endif
2203
2204#if MPACK_DOUBLE
2205double mpack_node_double_strict(mpack_node_t node) {
2206 if (mpack_node_error(node) != mpack_ok)
2207 return 0.0;
2208
2209 if (node.data->type == mpack_type_float)
2210 return (double)node.data->value.f;
2211 else if (node.data->type == mpack_type_double)
2212 return node.data->value.d;
2213
2214 mpack_node_flag_error(node, mpack_error_type);
2215 return 0.0;
2216}
2217#endif
2218
2219#if !MPACK_FLOAT
2220uint32_t mpack_node_raw_float(mpack_node_t node) {
2221 if (mpack_node_error(node) != mpack_ok)
2222 return 0;
2223
2224 if (node.data->type == mpack_type_float)
2225 return node.data->value.f;
2226
2227 mpack_node_flag_error(node, mpack_error_type);
2228 return 0;
2229}
2230#endif
2231
2232#if !MPACK_DOUBLE
2233uint64_t mpack_node_raw_double(mpack_node_t node) {
2234 if (mpack_node_error(node) != mpack_ok)
2235 return 0;
2236
2237 if (node.data->type == mpack_type_double)
2238 return node.data->value.d;
2239
2240 mpack_node_flag_error(node, mpack_error_type);
2241 return 0;
2242}
2243#endif
2244
2245#if MPACK_EXTENSIONS
2246int8_t mpack_node_exttype(mpack_node_t node) {
2247 if (mpack_node_error(node) != mpack_ok)
2248 return 0;
2249
2250 if (node.data->type == mpack_type_ext)
2251 return mpack_node_exttype_unchecked(node);
2252
2253 mpack_node_flag_error(node, mpack_error_type);
2254 return 0;
2255}
2256#endif
2257
2258uint32_t mpack_node_data_len(mpack_node_t node) {
2259 if (mpack_node_error(node) != mpack_ok)
2260 return 0;
2261
2262 mpack_type_t type = node.data->type;
2263 if (type == mpack_type_str || type == mpack_type_bin
2264 #if MPACK_EXTENSIONS
2265 || type == mpack_type_ext
2266 #endif
2267 )
2268 return (uint32_t)node.data->len;
2269
2270 mpack_node_flag_error(node, mpack_error_type);
2271 return 0;
2272}
2273
2274size_t mpack_node_strlen(mpack_node_t node) {
2275 if (mpack_node_error(node) != mpack_ok)
2276 return 0;
2277
2278 if (node.data->type == mpack_type_str)
2279 return (size_t)node.data->len;
2280
2281 mpack_node_flag_error(node, mpack_error_type);
2282 return 0;
2283}
2284
2285const char* mpack_node_str(mpack_node_t node) {
2286 if (mpack_node_error(node) != mpack_ok)
2287 return NULL;
2288
2289 mpack_type_t type = node.data->type;
2290 if (type == mpack_type_str)
2291 return mpack_node_data_unchecked(node);
2292
2293 mpack_node_flag_error(node, mpack_error_type);
2294 return NULL;
2295}
2296
2297const char* mpack_node_data(mpack_node_t node) {
2298 if (mpack_node_error(node) != mpack_ok)
2299 return NULL;
2300
2301 mpack_type_t type = node.data->type;
2302 if (type == mpack_type_str || type == mpack_type_bin
2303 #if MPACK_EXTENSIONS
2304 || type == mpack_type_ext
2305 #endif
2306 )
2307 return mpack_node_data_unchecked(node);
2308
2309 mpack_node_flag_error(node, mpack_error_type);
2310 return NULL;
2311}
2312
2313const char* mpack_node_bin_data(mpack_node_t node) {
2314 if (mpack_node_error(node) != mpack_ok)
2315 return NULL;
2316
2317 if (node.data->type == mpack_type_bin)
2318 return mpack_node_data_unchecked(node);
2319
2320 mpack_node_flag_error(node, mpack_error_type);
2321 return NULL;
2322}
2323
2324size_t mpack_node_bin_size(mpack_node_t node) {
2325 if (mpack_node_error(node) != mpack_ok)
2326 return 0;
2327
2328 if (node.data->type == mpack_type_bin)
2329 return (size_t)node.data->len;
2330
2331 mpack_node_flag_error(node, mpack_error_type);
2332 return 0;
2333}
2334
2335size_t mpack_node_array_length(mpack_node_t node) {
2336 if (mpack_node_error(node) != mpack_ok)
2337 return 0;
2338
2339 if (node.data->type != mpack_type_array) {
2340 mpack_node_flag_error(node, mpack_error_type);
2341 return 0;
2342 }
2343
2344 return (size_t)node.data->len;
2345}
2346
2347mpack_node_t mpack_node_array_at(mpack_node_t node, size_t index) {
2348 if (mpack_node_error(node) != mpack_ok)
2349 return mpack_tree_nil_node(node.tree);
2350
2351 if (node.data->type != mpack_type_array) {
2352 mpack_node_flag_error(node, mpack_error_type);
2353 return mpack_tree_nil_node(node.tree);
2354 }
2355
2356 if (index >= node.data->len) {
2357 mpack_node_flag_error(node, mpack_error_data);
2358 return mpack_tree_nil_node(node.tree);
2359 }
2360
2361 return mpack_node(node.tree, mpack_node_child(node, index));
2362}
2363
2364size_t mpack_node_map_count(mpack_node_t node) {
2365 if (mpack_node_error(node) != mpack_ok)
2366 return 0;
2367
2368 if (node.data->type != mpack_type_map) {
2369 mpack_node_flag_error(node, mpack_error_type);
2370 return 0;
2371 }
2372
2373 return node.data->len;
2374}
2375
2376// internal node map lookup
2377static mpack_node_t mpack_node_map_at(mpack_node_t node, size_t index, size_t offset) {
2378 if (mpack_node_error(node) != mpack_ok)
2379 return mpack_tree_nil_node(node.tree);
2380
2381 if (node.data->type != mpack_type_map) {
2382 mpack_node_flag_error(node, mpack_error_type);
2383 return mpack_tree_nil_node(node.tree);
2384 }
2385
2386 if (index >= node.data->len) {
2387 mpack_node_flag_error(node, mpack_error_data);
2388 return mpack_tree_nil_node(node.tree);
2389 }
2390
2391 return mpack_node(node.tree, mpack_node_child(node, index * 2 + offset));
2392}
2393
2394mpack_node_t mpack_node_map_key_at(mpack_node_t node, size_t index) {
2395 return mpack_node_map_at(node, index, 0);
2396}
2397
2398mpack_node_t mpack_node_map_value_at(mpack_node_t node, size_t index) {
2399 return mpack_node_map_at(node, index, 1);
2400}
2401
2402#endif
2403
2404MPACK_SILENCE_WARNINGS_END
2405