1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26 #include <string.h>
27 #include <stdio.h>
28
29 static const char * const parser_errs[] = {
30 "",
31 "",
32 "No opening '{'",
33 "Expected closing '}'",
34 "Expected '\"'",
35 "String underrun",
36 "Illegal unescaped control char",
37 "Illegal escape format",
38 "Illegal hex number",
39 "Expected ':'",
40 "Illegal value start",
41 "Digit required after decimal point",
42 "Bad number format",
43 "Bad exponent format",
44 "Unknown token",
45 "Too many ']'",
46 "Mismatched ']'",
47 "Expected ']'",
48 "JSON nesting limit exceeded",
49 "Nesting tracking used up",
50 "Number too long",
51 "Comma or block end expected",
52 "Unknown",
53 "Parser callback errored (see earlier error)",
54 };
55
56 /**
57 * lejp_construct - prepare a struct lejp_ctx for use
58 *
59 * \param ctx: pointer to your struct lejp_ctx
60 * \param callback: your user callback which will received parsed tokens
61 * \param user: optional user data pointer untouched by lejp
62 * \param paths: your array of name elements you are interested in
63 * \param count_paths: LWS_ARRAY_SIZE() of @paths
64 *
65 * Prepares your context struct for use with lejp
66 */
67
68 void
lejp_construct(struct lejp_ctx * ctx,signed char (* callback)(struct lejp_ctx * ctx,char reason),void * user,const char * const * paths,unsigned char count_paths)69 lejp_construct(struct lejp_ctx *ctx,
70 signed char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
71 const char * const *paths, unsigned char count_paths)
72 {
73 ctx->st[0].s = 0;
74 ctx->st[0].p = 0;
75 ctx->st[0].i = 0;
76 ctx->st[0].b = 0;
77 ctx->sp = 0;
78 ctx->ipos = 0;
79 ctx->outer_array = 0;
80 ctx->path_match = 0;
81 ctx->path_stride = 0;
82 ctx->path[0] = '\0';
83 ctx->user = user;
84 ctx->line = 1;
85
86 ctx->pst_sp = 0;
87 ctx->pst[0].callback = callback;
88 ctx->pst[0].paths = paths;
89 ctx->pst[0].count_paths = count_paths;
90 ctx->pst[0].user = NULL;
91 ctx->pst[0].ppos = 0;
92
93 ctx->pst[0].callback(ctx, LEJPCB_CONSTRUCTED);
94 }
95
96 /**
97 * lejp_destruct - retire a previously constructed struct lejp_ctx
98 *
99 * \param ctx: pointer to your struct lejp_ctx
100 *
101 * lejp does not perform any allocations, but since your user code might, this
102 * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where
103 * you can clean up in your callback.
104 */
105
106 void
lejp_destruct(struct lejp_ctx * ctx)107 lejp_destruct(struct lejp_ctx *ctx)
108 {
109 /* no allocations... just let callback know what it happening */
110 if (ctx && ctx->pst[0].callback)
111 ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
112 }
113
114 /**
115 * lejp_change_callback - switch to a different callback from now on
116 *
117 * \param ctx: pointer to your struct lejp_ctx
118 * \param callback: your user callback which will received parsed tokens
119 *
120 * This tells the old callback it was destroyed, in case you want to take any
121 * action because that callback "lost focus", then changes to the new
122 * callback and tells it first that it was constructed, and then started.
123 *
124 * Changing callback is a cheap and powerful trick to split out handlers
125 * according to information earlier in the parse. For example you may have
126 * a JSON pair "schema" whose value defines what can be expected for the rest
127 * of the JSON. Rather than having one huge callback for all cases, you can
128 * have an initial one looking for "schema" which then calls
129 * lejp_change_callback() to a handler specific for the schema.
130 *
131 * Notice that afterwards, you need to construct the context again anyway to
132 * parse another JSON object, and the callback is reset then to the main,
133 * schema-interpreting one. The construction action is very lightweight.
134 */
135
136 void
lejp_change_callback(struct lejp_ctx * ctx,signed char (* callback)(struct lejp_ctx * ctx,char reason))137 lejp_change_callback(struct lejp_ctx *ctx,
138 signed char (*callback)(struct lejp_ctx *ctx, char reason))
139 {
140 ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
141 ctx->pst[0].callback = callback;
142 ctx->pst[0].callback(ctx, LEJPCB_CONSTRUCTED);
143 ctx->pst[0].callback(ctx, LEJPCB_START);
144 }
145
146 void
lejp_check_path_match(struct lejp_ctx * ctx)147 lejp_check_path_match(struct lejp_ctx *ctx)
148 {
149 const char *p, *q;
150 int n;
151 size_t s = sizeof(char *);
152
153 if (ctx->path_stride)
154 s = ctx->path_stride;
155
156 /* we only need to check if a match is not active */
157 for (n = 0; !ctx->path_match &&
158 n < ctx->pst[ctx->pst_sp].count_paths; n++) {
159 ctx->wildcount = 0;
160 p = ctx->path;
161
162 q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) + ((unsigned int)n * s)));
163
164 while (*p && *q) {
165 if (*q != '*') {
166 if (*p != *q)
167 break;
168 p++;
169 q++;
170 continue;
171 }
172 ctx->wild[ctx->wildcount++] = (uint16_t)lws_ptr_diff_size_t(p, ctx->path);
173 q++;
174 /*
175 * if * has something after it, match to .
176 * if ends with *, eat everything.
177 * This implies match sequences must be ordered like
178 * x.*.*
179 * x.*
180 * if both options are possible
181 */
182 while (*p && (*p != '.' || !*q))
183 p++;
184 }
185 if (*p || *q)
186 continue;
187
188 ctx->path_match = (uint8_t)(n + 1);
189 ctx->path_match_len = ctx->pst[ctx->pst_sp].ppos;
190 return;
191 }
192
193 if (!ctx->path_match)
194 ctx->wildcount = 0;
195 }
196
197 int
lejp_get_wildcard(struct lejp_ctx * ctx,int wildcard,char * dest,int len)198 lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
199 {
200 int n;
201
202 if (wildcard >= ctx->wildcount || !len)
203 return 0;
204
205 n = ctx->wild[wildcard];
206
207 while (--len && n < ctx->pst[ctx->pst_sp].ppos &&
208 (n == ctx->wild[wildcard] || ctx->path[n] != '.'))
209 *dest++ = ctx->path[n++];
210
211 *dest = '\0';
212 n++;
213
214 return n - ctx->wild[wildcard];
215 }
216
217 /**
218 * lejp_parse - interpret some more incoming data incrementally
219 *
220 * \param ctx: previously constructed parsing context
221 * \param json: char buffer with the new data to interpret
222 * \param len: amount of data in the buffer
223 *
224 * Because lejp is a stream parser, it incrementally parses as new data
225 * becomes available, maintaining all state in the context struct. So an
226 * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE
227 * return, signalling there's no error but to call again with more data when
228 * it comes to complete the parsing. Successful parsing completes with a
229 * 0 or positive integer indicating how much of the last input buffer was
230 * unused.
231 */
232
233 static const char esc_char[] = "\"\\/bfnrt";
234 static const char esc_tran[] = "\"\\/\b\f\n\r\t";
235 static const char tokens[] = "rue alse ull ";
236
237 int
lejp_parse(struct lejp_ctx * ctx,const unsigned char * json,int len)238 lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
239 {
240 unsigned char c, n, s;
241 int ret = LEJP_REJECT_UNKNOWN;
242
243 if (!ctx->sp && !ctx->pst[ctx->pst_sp].ppos)
244 ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_START);
245
246 while (len--) {
247 c = *json++;
248 s = (unsigned char)ctx->st[ctx->sp].s;
249
250 /* skip whitespace unless we should care */
251 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
252 if (c == '\n') {
253 ctx->line++;
254 ctx->st[ctx->sp].s &= (char)~LEJP_FLAG_WS_COMMENTLINE;
255 }
256 if (!(s & LEJP_FLAG_WS_KEEP)) {
257 if (c == '#')
258 ctx->st[ctx->sp].s |=
259 LEJP_FLAG_WS_COMMENTLINE;
260 continue;
261 }
262 }
263
264 if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE)
265 continue;
266
267 switch (s) {
268 case LEJP_IDLE:
269 if (!ctx->sp && c == '[') {
270 /* push */
271 ctx->outer_array = 1;
272 ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
273 c = LEJP_MP_VALUE;
274 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '[';
275 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = ']';
276 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
277 if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START))
278 goto reject_callback;
279 ctx->i[ctx->ipos++] = 0;
280 if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
281 ret = LEJP_REJECT_MP_DELIM_ISTACK;
282 goto reject;
283 }
284 goto add_stack_level;
285 }
286 if (c != '{') {
287 ret = LEJP_REJECT_IDLE_NO_BRACE;
288 goto reject;
289 }
290 if (ctx->pst[ctx->pst_sp].callback(ctx,
291 LEJPCB_OBJECT_START))
292 goto reject_callback;
293 ctx->st[ctx->sp].s = LEJP_MEMBERS;
294 break;
295 case LEJP_MEMBERS:
296 if (c == '}') {
297 if (ctx->sp >= 1)
298 goto pop_level;
299
300 ctx->st[ctx->sp].s = LEJP_IDLE;
301 ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
302 goto reject;
303 }
304 ctx->st[ctx->sp].s = LEJP_M_P;
305 goto redo_character;
306 case LEJP_M_P:
307 if (c != '\"') {
308 ret = LEJP_REJECT_MP_NO_OPEN_QUOTE;
309 goto reject;
310 }
311 /* push */
312 ctx->st[ctx->sp].s = LEJP_MP_DELIM;
313 c = LEJP_MP_STRING;
314 goto add_stack_level;
315
316 case LEJP_MP_STRING:
317 if (c == '\"') {
318 if (!ctx->sp) { /* JSON can't end on quote */
319 ret = LEJP_REJECT_MP_STRING_UNDERRUN;
320 goto reject;
321 }
322 if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
323 ctx->buf[ctx->npos] = '\0';
324 if (ctx->pst[ctx->pst_sp].callback(ctx,
325 LEJPCB_VAL_STR_END) < 0)
326 goto reject_callback;
327 }
328 /* pop */
329 ctx->sp--;
330 break;
331 }
332 if (c == '\\') {
333 ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC;
334 break;
335 }
336 if (c < ' ') {/* "control characters" not allowed */
337 ret = LEJP_REJECT_MP_ILLEGAL_CTRL;
338 goto reject;
339 }
340 goto emit_string_char;
341
342 case LEJP_MP_STRING_ESC:
343 if (c == 'u') {
344 ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1;
345 ctx->uni = 0;
346 break;
347 }
348 for (n = 0; n < sizeof(esc_char); n++) {
349 if (c != esc_char[n])
350 continue;
351 /* found it */
352 c = (unsigned char)esc_tran[n];
353 ctx->st[ctx->sp].s = LEJP_MP_STRING;
354 goto emit_string_char;
355 }
356 ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;
357 /* illegal escape char */
358 goto reject;
359
360 case LEJP_MP_STRING_ESC_U1:
361 case LEJP_MP_STRING_ESC_U2:
362 case LEJP_MP_STRING_ESC_U3:
363 case LEJP_MP_STRING_ESC_U4:
364 ctx->uni = (uint16_t)(ctx->uni << 4);
365 if (c >= '0' && c <= '9')
366 ctx->uni |= (uint16_t)(c - '0');
367 else
368 if (c >= 'a' && c <= 'f')
369 ctx->uni |= (uint16_t)(c - 'a' + 10);
370 else
371 if (c >= 'A' && c <= 'F')
372 ctx->uni |= (uint16_t)(c - 'A' + 10);
373 else {
374 ret = LEJP_REJECT_ILLEGAL_HEX;
375 goto reject;
376 }
377 ctx->st[ctx->sp].s++;
378 switch (s) {
379 case LEJP_MP_STRING_ESC_U2:
380 if (ctx->uni < 0x08)
381 break;
382 /*
383 * 0x08-0xff (0x0800 - 0xffff)
384 * emit 3-byte UTF-8
385 */
386 c = (unsigned char)(0xe0 | ((ctx->uni >> 4) & 0xf));
387 goto emit_string_char;
388
389 case LEJP_MP_STRING_ESC_U3:
390 if (ctx->uni >= 0x080) {
391 /*
392 * 0x080 - 0xfff (0x0800 - 0xffff)
393 * middle 3-byte seq
394 * send ....XXXXXX..
395 */
396 c = (unsigned char)(0x80 | ((ctx->uni >> 2) & 0x3f));
397 goto emit_string_char;
398 }
399 if (ctx->uni < 0x008)
400 break;
401 /*
402 * 0x008 - 0x7f (0x0080 - 0x07ff)
403 * start 2-byte seq
404 */
405 c = (unsigned char)(0xc0 | (ctx->uni >> 2));
406 goto emit_string_char;
407
408 case LEJP_MP_STRING_ESC_U4:
409 if (ctx->uni >= 0x0080)
410 /* end of 2 or 3-byte seq */
411 c = (unsigned char)(0x80 | (ctx->uni & 0x3f));
412 else
413 /* literal */
414 c = (unsigned char)ctx->uni;
415
416 ctx->st[ctx->sp].s = LEJP_MP_STRING;
417 goto emit_string_char;
418 default:
419 break;
420 }
421 break;
422
423 case LEJP_MP_DELIM:
424 if (c != ':') {
425 ret = LEJP_REJECT_MP_DELIM_MISSING_COLON;
426 goto reject;
427 }
428 ctx->st[ctx->sp].s = LEJP_MP_VALUE;
429 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
430
431 lejp_check_path_match(ctx);
432 if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_PAIR_NAME))
433 goto reject_callback;
434 break;
435
436 case LEJP_MP_VALUE:
437 if (c == '-' || (c >= '0' && c <= '9')) {
438 ctx->npos = 0;
439 ctx->dcount = 0;
440 ctx->f = 0;
441 ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
442 goto redo_character;
443 }
444 switch (c) {
445 case'\"':
446 /* push */
447 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
448 c = LEJP_MP_STRING;
449 ctx->npos = 0;
450 ctx->buf[0] = '\0';
451 if (ctx->pst[ctx->pst_sp].callback(ctx,
452 LEJPCB_VAL_STR_START))
453 goto reject_callback;
454 goto add_stack_level;
455
456 case '{':
457 /* push */
458 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
459 c = LEJP_MEMBERS;
460 lejp_check_path_match(ctx);
461 if (ctx->pst[ctx->pst_sp].callback(ctx,
462 LEJPCB_OBJECT_START))
463 goto reject_callback;
464 ctx->path_match = 0;
465 goto add_stack_level;
466
467 case '[':
468 /* push */
469 ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
470 c = LEJP_MP_VALUE;
471 if (ctx->pst[ctx->pst_sp].ppos + 3u >=
472 sizeof(ctx->path))
473 goto reject;
474 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '[';
475 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = ']';
476 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
477 if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START))
478 goto reject_callback;
479 ctx->i[ctx->ipos++] = 0;
480 if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
481 ret = LEJP_REJECT_MP_DELIM_ISTACK;
482 goto reject;
483 }
484 goto add_stack_level;
485
486 case ']':
487 /* pop */
488 if (!ctx->sp) { /* JSON can't end on ] */
489 ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
490 goto reject;
491 }
492 ctx->sp--;
493 if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
494 ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
495 goto reject;
496 }
497 /* drop the path [n] bit */
498 if (ctx->sp) {
499 ctx->pst[ctx->pst_sp].ppos = (unsigned char)
500 ctx->st[ctx->sp - 1].p;
501 ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
502 }
503 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
504 if (ctx->path_match &&
505 ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
506 /*
507 * we shrank the path to be
508 * smaller than the matching point
509 */
510 ctx->path_match = 0;
511 if (ctx->outer_array && !ctx->sp) { /* ended on ] */
512 n = LEJPCB_ARRAY_END;
513 goto completed;
514 }
515 goto array_end;
516
517 case 't': /* true */
518 ctx->uni = 0;
519 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
520 break;
521
522 case 'f':
523 ctx->uni = 4;
524 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
525 break;
526
527 case 'n':
528 ctx->uni = 4 + 5;
529 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
530 break;
531 default:
532 ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START;
533 goto reject;
534 }
535 break;
536
537 case LEJP_MP_VALUE_NUM_INT:
538 if (!ctx->npos && c == '-') {
539 ctx->f |= LEJP_SEEN_MINUS;
540 goto append_npos;
541 }
542
543 if (ctx->dcount < 20 && c >= '0' && c <= '9') {
544 if (ctx->f & LEJP_SEEN_POINT)
545 ctx->f |= LEJP_SEEN_POST_POINT;
546 ctx->dcount++;
547 goto append_npos;
548 }
549 if (c == '.') {
550 if (!ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) {
551 ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
552 goto reject;
553 }
554 ctx->f |= LEJP_SEEN_POINT;
555 goto append_npos;
556 }
557 /*
558 * before exponent, if we had . we must have had at
559 * least one more digit
560 */
561 if ((ctx->f &
562 (LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) ==
563 LEJP_SEEN_POINT) {
564 ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;
565 goto reject;
566 }
567 if (c == 'e' || c == 'E') {
568 if (ctx->f & LEJP_SEEN_EXP) {
569 ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
570 goto reject;
571 }
572 ctx->f |= LEJP_SEEN_EXP;
573 ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP;
574 goto append_npos;
575 }
576 /* if none of the above, did we even have a number? */
577 if (!ctx->dcount) {
578 ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
579 goto reject;
580 }
581
582 ctx->buf[ctx->npos] = '\0';
583 if (ctx->f & LEJP_SEEN_POINT) {
584 if (ctx->pst[ctx->pst_sp].callback(ctx,
585 LEJPCB_VAL_NUM_FLOAT))
586 goto reject_callback;
587 } else {
588 if (ctx->pst[ctx->pst_sp].callback(ctx,
589 LEJPCB_VAL_NUM_INT))
590 goto reject_callback;
591 }
592
593 /* then this is the post-number character, loop */
594 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
595 goto redo_character;
596
597 case LEJP_MP_VALUE_NUM_EXP:
598 ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
599 if (c >= '0' && c <= '9')
600 goto redo_character;
601 if (c == '+' || c == '-')
602 goto append_npos;
603 ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;
604 goto reject;
605
606 case LEJP_MP_VALUE_TOK: /* true, false, null */
607 if (c != tokens[ctx->uni]) {
608 ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN;
609 goto reject;
610 }
611 ctx->uni++;
612 if (tokens[ctx->uni] != ' ')
613 break;
614 switch (ctx->uni) {
615 case 3:
616 ctx->buf[0] = '1';
617 ctx->buf[1] = '\0';
618 if (ctx->pst[ctx->pst_sp].callback(ctx,
619 LEJPCB_VAL_TRUE))
620 goto reject_callback;
621 break;
622 case 8:
623 ctx->buf[0] = '0';
624 ctx->buf[1] = '\0';
625 if (ctx->pst[ctx->pst_sp].callback(ctx,
626 LEJPCB_VAL_FALSE))
627 goto reject_callback;
628 break;
629 case 12:
630 ctx->buf[0] = '\0';
631 if (ctx->pst[ctx->pst_sp].callback(ctx,
632 LEJPCB_VAL_NULL))
633 goto reject_callback;
634 break;
635 }
636 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
637 break;
638
639 case LEJP_MP_COMMA_OR_END:
640 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
641 if (c == ',') {
642 /* increment this stack level's index */
643 ctx->st[ctx->sp].s = LEJP_M_P;
644 if (!ctx->sp) {
645 ctx->pst[ctx->pst_sp].ppos = 0;
646 /*
647 * since we came back to root level,
648 * no path can still match
649 */
650 ctx->path_match = 0;
651 break;
652 }
653 ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp - 1].p;
654 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
655 if (ctx->path_match &&
656 ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
657 /*
658 * we shrank the path to be
659 * smaller than the matching point
660 */
661 ctx->path_match = 0;
662
663 if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
664 break;
665 /* top level is definitely an array... */
666 if (ctx->ipos)
667 ctx->i[ctx->ipos - 1]++;
668 ctx->st[ctx->sp].s = LEJP_MP_VALUE;
669 break;
670 }
671 if (c == ']') {
672 if (!ctx->sp) {
673 ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
674 goto reject;
675 }
676 /* pop */
677 ctx->sp--;
678 if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
679 ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
680 goto reject;
681 }
682
683 /* drop the path [n] bit */
684 if (ctx->sp) {
685 ctx->pst[ctx->pst_sp].ppos = (unsigned char)
686 ctx->st[ctx->sp - 1].p;
687 ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
688 }
689 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
690 if (ctx->path_match &&
691 ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
692 /*
693 * we shrank the path to be
694 * smaller than the matching point
695 */
696 ctx->path_match = 0;
697
698 if (ctx->outer_array && !ctx->sp) { /* ended on ] */
699 n = LEJPCB_ARRAY_END;
700 goto completed;
701 }
702
703 /* do LEJP_MP_ARRAY_END processing */
704 goto redo_character;
705 }
706 if (c != '}') {
707 ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
708 goto reject;
709 }
710 if (!ctx->sp) {
711 n = LEJPCB_OBJECT_END;
712 completed:
713 lejp_check_path_match(ctx);
714 if (ctx->pst[ctx->pst_sp].callback(ctx, (char)n) ||
715 ctx->pst[ctx->pst_sp].callback(ctx,
716 LEJPCB_COMPLETE))
717 goto reject_callback;
718
719 /* done, return unused amount */
720 return len;
721 }
722
723 /* pop */
724 pop_level:
725 ctx->sp--;
726 if (ctx->sp) {
727 ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp].p;
728 ctx->ipos = (unsigned char)ctx->st[ctx->sp].i;
729 }
730 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
731 if (ctx->path_match &&
732 ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
733 /*
734 * we shrank the path to be
735 * smaller than the matching point
736 */
737 ctx->path_match = 0;
738
739 lejp_check_path_match(ctx);
740 if (ctx->pst[ctx->pst_sp].callback(ctx,
741 LEJPCB_OBJECT_END))
742 goto reject_callback;
743 break;
744
745 case LEJP_MP_ARRAY_END:
746 array_end:
747 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
748 if (c == ',') {
749 /* increment this stack level's index */
750 if (ctx->ipos)
751 ctx->i[ctx->ipos - 1]++;
752 ctx->st[ctx->sp].s = LEJP_MP_VALUE;
753 if (ctx->sp)
754 ctx->pst[ctx->pst_sp].ppos = (unsigned char)
755 ctx->st[ctx->sp - 1].p;
756 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
757 break;
758 }
759 if (c != ']') {
760 ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
761 goto reject;
762 }
763
764 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
765 ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_END);
766 break;
767 }
768
769 continue;
770
771 emit_string_char:
772 if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
773 /* assemble the string value into chunks */
774 ctx->buf[ctx->npos++] = (char)c;
775 if (ctx->npos == sizeof(ctx->buf) - 1) {
776 if (ctx->pst[ctx->pst_sp].callback(ctx,
777 LEJPCB_VAL_STR_CHUNK))
778 goto reject_callback;
779 ctx->npos = 0;
780 }
781 continue;
782 }
783 /* name part of name:value pair */
784 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = (char)c;
785 continue;
786
787 add_stack_level:
788 /* push on to the object stack */
789 if (ctx->pst[ctx->pst_sp].ppos &&
790 ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
791 ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
792 ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '.';
793
794 ctx->st[ctx->sp].p = (char)ctx->pst[ctx->pst_sp].ppos;
795 ctx->st[ctx->sp].i = (char)ctx->ipos;
796 if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
797 ret = LEJP_REJECT_STACK_OVERFLOW;
798 goto reject;
799 }
800 ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
801 ctx->st[ctx->sp].s = (char)c;
802 ctx->st[ctx->sp].b = 0;
803 continue;
804
805 append_npos:
806 if (ctx->npos >= sizeof(ctx->buf)) {
807 ret = LEJP_REJECT_NUM_TOO_LONG;
808 goto reject;
809 }
810 ctx->buf[ctx->npos++] = (char)c;
811 continue;
812
813 redo_character:
814 json--;
815 len++;
816 }
817
818 return LEJP_CONTINUE;
819
820
821 reject_callback:
822 ret = LEJP_REJECT_CALLBACK;
823
824 reject:
825 ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_FAILED);
826 return ret;
827 }
828
829 int
830 lejp_parser_push(struct lejp_ctx *ctx, void *user, const char * const *paths,
831 unsigned char paths_count, lejp_callback lejp_cb)
832 {
833 struct _lejp_parsing_stack *p;
834
835 if (ctx->pst_sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
836 return -1;
837
838 lejp_check_path_match(ctx);
839
840 ctx->pst[ctx->pst_sp].path_match = ctx->path_match;
841 ctx->pst_sp++;
842
843 p = &ctx->pst[ctx->pst_sp];
844 p->user = user;
845 p->callback = lejp_cb;
846 p->paths = paths;
847 p->count_paths = paths_count;
848 p->ppos = 0;
849
850 ctx->path_match = 0;
851 lejp_check_path_match(ctx);
852
853 lwsl_debug("%s: pushed parser stack to %d (path %s)\n", __func__,
854 ctx->pst_sp, ctx->path);
855
856 return 0;
857 }
858
859 int
860 lejp_parser_pop(struct lejp_ctx *ctx)
861 {
862 if (!ctx->pst_sp)
863 return -1;
864
865 ctx->pst_sp--;
866 lwsl_debug("%s: popped parser stack to %d\n", __func__, ctx->pst_sp);
867
868 ctx->path_match = 0; /* force it to check */
869 lejp_check_path_match(ctx);
870
871 return 0;
872 }
873
874 const char *
875 lejp_error_to_string(int e)
876 {
877 if (e > 0)
878 e = 0;
879 else
880 e = -e;
881
882 if (e >= (int)LWS_ARRAY_SIZE(parser_errs))
883 return "Unknown error";
884
885 return parser_errs[e];
886 }
887
888