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