object.c (6875B)
1 #include <string.h> 2 3 #include "object.h" 4 5 static int mpack_parser_full(mpack_parser_t *w); 6 static mpack_node_t *mpack_parser_push(mpack_parser_t *w); 7 static mpack_node_t *mpack_parser_pop(mpack_parser_t *w); 8 9 MPACK_API void mpack_parser_init(mpack_parser_t *parser, 10 mpack_uint32_t capacity) 11 { 12 mpack_tokbuf_init(&parser->tokbuf); 13 parser->data.p = NULL; 14 parser->capacity = capacity ? capacity : MPACK_MAX_OBJECT_DEPTH; 15 parser->size = 0; 16 parser->exiting = 0; 17 memset(parser->items, 0, sizeof(mpack_node_t) * (parser->capacity + 1)); 18 parser->items[0].pos = (size_t)-1; 19 parser->status = 0; 20 } 21 22 #define MPACK_EXCEPTION_CHECK(parser) \ 23 do { \ 24 if (parser->status == MPACK_EXCEPTION) { \ 25 return MPACK_EXCEPTION; \ 26 } \ 27 } while (0) 28 29 #define MPACK_WALK(action) \ 30 do { \ 31 mpack_node_t *n; \ 32 \ 33 if (parser->exiting) goto exit; \ 34 if (mpack_parser_full(parser)) return MPACK_NOMEM; \ 35 n = mpack_parser_push(parser); \ 36 action; \ 37 MPACK_EXCEPTION_CHECK(parser); \ 38 parser->exiting = 1; \ 39 return MPACK_EOF; \ 40 \ 41 exit: \ 42 parser->exiting = 0; \ 43 while ((n = mpack_parser_pop(parser))) { \ 44 exit_cb(parser, n); \ 45 MPACK_EXCEPTION_CHECK(parser); \ 46 if (!parser->size) return MPACK_OK; \ 47 } \ 48 \ 49 return MPACK_EOF; \ 50 } while (0) 51 52 MPACK_API int mpack_parse_tok(mpack_parser_t *parser, mpack_token_t tok, 53 mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) 54 { 55 MPACK_EXCEPTION_CHECK(parser); 56 MPACK_WALK({n->tok = tok; enter_cb(parser, n);}); 57 } 58 59 MPACK_API int mpack_unparse_tok(mpack_parser_t *parser, mpack_token_t *tok, 60 mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) 61 { 62 MPACK_EXCEPTION_CHECK(parser); 63 MPACK_WALK({enter_cb(parser, n); *tok = n->tok;}); 64 } 65 66 MPACK_API int mpack_parse(mpack_parser_t *parser, const char **buf, 67 size_t *buflen, mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) 68 { 69 int status = MPACK_EOF; 70 MPACK_EXCEPTION_CHECK(parser); 71 72 while (*buflen && status) { 73 mpack_token_t tok; 74 mpack_tokbuf_t *tb = &parser->tokbuf; 75 const char *buf_save = *buf; 76 size_t buflen_save = *buflen; 77 78 if ((status = mpack_read(tb, buf, buflen, &tok)) == MPACK_EOF) continue; 79 else if (status == MPACK_ERROR) goto rollback; 80 81 do { 82 status = mpack_parse_tok(parser, tok, enter_cb, exit_cb); 83 MPACK_EXCEPTION_CHECK(parser); 84 } while (parser->exiting); 85 86 if (status != MPACK_NOMEM) continue; 87 88 rollback: 89 /* restore buf/buflen so the next call will try to read the same token */ 90 *buf = buf_save; 91 *buflen = buflen_save; 92 break; 93 } 94 95 return status; 96 } 97 98 MPACK_API int mpack_unparse(mpack_parser_t *parser, char **buf, size_t *buflen, 99 mpack_walk_cb enter_cb, mpack_walk_cb exit_cb) 100 { 101 int status = MPACK_EOF; 102 MPACK_EXCEPTION_CHECK(parser); 103 104 while (*buflen && status) { 105 int write_status; 106 mpack_token_t tok; 107 mpack_tokbuf_t *tb = &parser->tokbuf; 108 109 if (!tb->plen) 110 parser->status = mpack_unparse_tok(parser, &tok, enter_cb, exit_cb); 111 112 MPACK_EXCEPTION_CHECK(parser); 113 114 status = parser->status; 115 116 if (status == MPACK_NOMEM) 117 break; 118 119 if (parser->exiting) { 120 write_status = mpack_write(tb, buf, buflen, &tok); 121 status = write_status ? write_status : status; 122 } 123 } 124 125 return status; 126 } 127 128 MPACK_API void mpack_parser_copy(mpack_parser_t *d, mpack_parser_t *s) 129 { 130 // workaround UBSAN being NOT happy with a flexible array member with arr[N>1] initial size 131 mpack_one_parser_t *dst = (mpack_one_parser_t *)d; 132 mpack_one_parser_t *src = (mpack_one_parser_t *)s; 133 mpack_uint32_t i; 134 mpack_uint32_t dst_capacity = dst->capacity; 135 assert(src->capacity <= dst_capacity); 136 /* copy all fields except the stack */ 137 memcpy(dst, src, sizeof(mpack_one_parser_t) - sizeof(mpack_node_t)); 138 /* reset capacity */ 139 dst->capacity = dst_capacity; 140 /* copy the stack */ 141 for (i = 0; i <= src->capacity; i++) { 142 dst->items[i] = src->items[i]; 143 } 144 } 145 146 static int mpack_parser_full(mpack_parser_t *parser) 147 { 148 return parser->size == parser->capacity; 149 } 150 151 static mpack_node_t *mpack_parser_push(mpack_parser_t *p) 152 { 153 mpack_one_parser_t *parser = (mpack_one_parser_t *)p; 154 mpack_node_t *top; 155 assert(parser->size < parser->capacity); 156 top = parser->items + parser->size + 1; 157 top->data[0].p = NULL; 158 top->data[1].p = NULL; 159 top->pos = 0; 160 top->key_visited = 0; 161 /* increase size and invoke callback, passing parent node if any */ 162 parser->size++; 163 return top; 164 } 165 166 static mpack_node_t *mpack_parser_pop(mpack_parser_t *p) 167 { 168 mpack_one_parser_t *parser = (mpack_one_parser_t *)p; 169 mpack_node_t *top, *parent; 170 assert(parser->size); 171 top = parser->items + parser->size; 172 173 if (top->tok.type > MPACK_TOKEN_CHUNK && top->pos < top->tok.length) { 174 /* continue processing children */ 175 return NULL; 176 } 177 178 parent = MPACK_PARENT_NODE(top); 179 if (parent) { 180 /* we use parent->tok.length to keep track of how many children remain. 181 * update it to reflect the processed node. */ 182 if (top->tok.type == MPACK_TOKEN_CHUNK) { 183 parent->pos += top->tok.length; 184 } else if (parent->tok.type == MPACK_TOKEN_MAP) { 185 /* maps allow up to 2^32 - 1 pairs, so to allow this many items in a 186 * 32-bit length variable we use an additional flag to determine if the 187 * key of a certain position was visited */ 188 if (parent->key_visited) { 189 parent->pos++; 190 } 191 parent->key_visited = !parent->key_visited; 192 } else { 193 parent->pos++; 194 } 195 } 196 197 parser->size--; 198 return top; 199 }