test-server-status: increase tx size to avoid WRITEABLE loops
[platform/upstream/libwebsockets.git] / lib / lejp.c
1 /*
2  * Lightweight Embedded JSON Parser
3  *
4  * Copyright (C) 2013 Andy Green <andy@warmcat.com>
5  * This code is licensed under LGPL 2.1
6  * http://www.gnu.org/licenses/lgpl-2.1.html
7  */
8
9 #include <string.h>
10 #include "lejp.h"
11
12 #include <stdio.h>
13
14 /**
15  * lejp_construct - prepare a struct lejp_ctx for use
16  *
17  * \param ctx:  pointer to your struct lejp_ctx
18  * \param callback:     your user callback which will received parsed tokens
19  * \param user: optional user data pointer untouched by lejp
20  * \param paths:        your array of name elements you are interested in
21  * \param count_paths:  ARRAY_SIZE() of @paths
22  *
23  * Prepares your context struct for use with lejp
24  */
25
26 void
27 lejp_construct(struct lejp_ctx *ctx,
28         char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
29                         const char * const *paths, unsigned char count_paths)
30 {
31         ctx->st[0].s = 0;
32         ctx->st[0].p = 0;
33         ctx->st[0].i = 0;
34         ctx->st[0].b = 0;
35         ctx->sp = 0;
36         ctx->ipos = 0;
37         ctx->ppos = 0;
38         ctx->path_match = 0;
39         ctx->path[0] = '\0';
40         ctx->callback = callback;
41         ctx->user = user;
42         ctx->paths = paths;
43         ctx->count_paths = count_paths;
44         ctx->line = 1;
45         ctx->callback(ctx, LEJPCB_CONSTRUCTED);
46 }
47
48 /**
49  * lejp_destruct - retire a previously constructed struct lejp_ctx
50  *
51  * \param ctx:  pointer to your struct lejp_ctx
52  *
53  * lejp does not perform any allocations, but since your user code might, this
54  * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where
55  * you can clean up in your callback.
56  */
57
58 void
59 lejp_destruct(struct lejp_ctx *ctx)
60 {
61         /* no allocations... just let callback know what it happening */
62         ctx->callback(ctx, LEJPCB_DESTRUCTED);
63 }
64
65 /**
66  * lejp_change_callback - switch to a different callback from now on
67  *
68  * \param ctx:  pointer to your struct lejp_ctx
69  * \param callback:     your user callback which will received parsed tokens
70  *
71  * This tells the old callback it was destroyed, in case you want to take any
72  * action because that callback "lost focus", then changes to the new
73  * callback and tells it first that it was constructed, and then started.
74  *
75  * Changing callback is a cheap and powerful trick to split out handlers
76  * according to information earlier in the parse.  For example you may have
77  * a JSON pair "schema" whose value defines what can be expected for the rest
78  * of the JSON.  Rather than having one huge callback for all cases, you can
79  * have an initial one looking for "schema" which then calls
80  * lejp_change_callback() to a handler specific for the schema.
81  *
82  * Notice that afterwards, you need to construct the context again anyway to
83  * parse another JSON object, and the callback is reset then to the main,
84  * schema-interpreting one.  The construction action is very lightweight.
85  */
86
87 void
88 lejp_change_callback(struct lejp_ctx *ctx,
89                        char (*callback)(struct lejp_ctx *ctx, char reason))
90 {
91         ctx->callback(ctx, LEJPCB_DESTRUCTED);
92         ctx->callback = callback;
93         ctx->callback(ctx, LEJPCB_CONSTRUCTED);
94         ctx->callback(ctx, LEJPCB_START);
95 }
96
97 static void
98 lejp_check_path_match(struct lejp_ctx *ctx)
99 {
100         const char *p, *q;
101         int n;
102
103         /* we only need to check if a match is not active */
104         for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) {
105                 ctx->wildcount = 0;
106                 p = ctx->path;
107                 q = ctx->paths[n];
108                 while (*p && *q) {
109                         if (*q != '*') {
110                                 if (*p != *q)
111                                         break;
112                                 p++;
113                                 q++;
114                                 continue;
115                         }
116                         ctx->wild[ctx->wildcount++] = p - ctx->path;
117                         q++;
118                         /*
119                          * if * has something after it, match to .
120                          * if ends with *, eat everything.
121                          * This implies match sequences must be ordered like
122                          *  x.*.*
123                          *  x.*
124                          * if both options are possible
125                          */
126                         while (*p && (*p != '.' || !*q))
127                                 p++;
128                 }
129                 if (*p || *q)
130                         continue;
131
132                 ctx->path_match = n + 1;
133                 ctx->path_match_len = ctx->ppos;
134                 return;
135         }
136
137         if (!ctx->path_match)
138                 ctx->wildcount = 0;
139 }
140
141 int
142 lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
143 {
144         int n;
145
146         if (wildcard >= ctx->wildcount || !len)
147                 return 0;
148
149         n = ctx->wild[wildcard];
150
151         while (--len && n < ctx->ppos && (n == ctx->wild[wildcard] || ctx->path[n] != '.'))
152                 *dest++ = ctx->path[n++];
153
154         *dest = '\0';
155         n++;
156
157         return n - ctx->wild[wildcard];
158 }
159
160 /**
161  * lejp_parse - interpret some more incoming data incrementally
162  *
163  * \param ctx:  previously constructed parsing context
164  * \param json: char buffer with the new data to interpret
165  * \param len:  amount of data in the buffer
166  *
167  * Because lejp is a stream parser, it incrementally parses as new data
168  * becomes available, maintaining all state in the context struct.  So an
169  * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE
170  * return, signalling there's no error but to call again with more data when
171  * it comes to complete the parsing.  Successful parsing completes with a
172  * 0 or positive integer indicating how much of the last input buffer was
173  * unused.
174  */
175
176 int
177 lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
178 {
179         unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN;
180         static const char esc_char[] = "\"\\/bfnrt";
181         static const char esc_tran[] = "\"\\/\b\f\n\r\t";
182         static const char tokens[] = "rue alse ull ";
183
184         if (!ctx->sp && !ctx->ppos)
185                 ctx->callback(ctx, LEJPCB_START);
186
187         while (len--) {
188                 c = *json++;
189
190                 s = ctx->st[ctx->sp].s;
191
192                 /* skip whitespace unless we should care */
193                 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
194                         if (c == '\n') {
195                                 ctx->line++;
196                                 ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE;
197                         }
198                         if (!(s & LEJP_FLAG_WS_KEEP)) {
199                                 if (c == '#')
200                                         ctx->st[ctx->sp].s |=
201                                                 LEJP_FLAG_WS_COMMENTLINE;
202                                 continue;
203                         }
204                 }
205
206                 if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE)
207                         continue;
208
209                 switch (s) {
210                 case LEJP_IDLE:
211                         if (c != '{') {
212                                 ret = LEJP_REJECT_IDLE_NO_BRACE;
213                                 goto reject;
214                         }
215                         if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
216                                 ret = LEJP_REJECT_CALLBACK;
217                                 goto reject;
218                         }
219                         ctx->st[ctx->sp].s = LEJP_MEMBERS;
220                         break;
221                 case LEJP_MEMBERS:
222                         if (c == '}') {
223                                 ctx->st[ctx->sp].s = LEJP_IDLE;
224                                 ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
225                                 goto reject;
226                         }
227                         ctx->st[ctx->sp].s = LEJP_M_P;
228                         goto redo_character;
229                 case LEJP_M_P:
230                         if (c != '\"') {
231                                 ret = LEJP_REJECT_MP_NO_OPEN_QUOTE;
232                                 goto reject;
233                         }
234                         /* push */
235                         ctx->st[ctx->sp].s = LEJP_MP_DELIM;
236                         c = LEJP_MP_STRING;
237                         goto add_stack_level;
238
239                 case LEJP_MP_STRING:
240                         if (c == '\"') {
241                                 if (!ctx->sp) {
242                                         ret = LEJP_REJECT_MP_STRING_UNDERRUN;
243                                         goto reject;
244                                 }
245                                 if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
246                                         ctx->buf[ctx->npos] = '\0';
247                                         if (ctx->callback(ctx,
248                                                       LEJPCB_VAL_STR_END) < 0) {
249                                                 ret = LEJP_REJECT_CALLBACK;
250                                                 goto reject;
251                                         }
252                                 }
253                                 /* pop */
254                                 ctx->sp--;
255                                 break;
256                         }
257                         if (c == '\\') {
258                                 ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC;
259                                 break;
260                         }
261                         if (c < ' ') {/* "control characters" not allowed */
262                                 ret = LEJP_REJECT_MP_ILLEGAL_CTRL;
263                                 goto reject;
264                         }
265                         goto emit_string_char;
266
267                 case LEJP_MP_STRING_ESC:
268                         if (c == 'u') {
269                                 ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1;
270                                 ctx->uni = 0;
271                                 break;
272                         }
273                         for (n = 0; n < sizeof(esc_char); n++) {
274                                 if (c != esc_char[n])
275                                         continue;
276                                 /* found it */
277                                 c = esc_tran[n];
278                                 ctx->st[ctx->sp].s = LEJP_MP_STRING;
279                                 goto emit_string_char;
280                         }
281                         ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;
282                         /* illegal escape char */
283                         goto reject;
284
285                 case LEJP_MP_STRING_ESC_U1:
286                 case LEJP_MP_STRING_ESC_U2:
287                 case LEJP_MP_STRING_ESC_U3:
288                 case LEJP_MP_STRING_ESC_U4:
289                         ctx->uni <<= 4;
290                         if (c >= '0' && c <= '9')
291                                 ctx->uni |= c - '0';
292                         else
293                                 if (c >= 'a' && c <= 'f')
294                                         ctx->uni = c - 'a' + 10;
295                                 else
296                                         if (c >= 'A' && c <= 'F')
297                                                 ctx->uni = c - 'A' + 10;
298                                         else {
299                                                 ret = LEJP_REJECT_ILLEGAL_HEX;
300                                                 goto reject;
301                                         }
302                         ctx->st[ctx->sp].s++;
303                         switch (s) {
304                         case LEJP_MP_STRING_ESC_U2:
305                                 if (ctx->uni < 0x08)
306                                         break;
307                                 /*
308                                  * 0x08-0xff (0x0800 - 0xffff)
309                                  * emit 3-byte UTF-8
310                                  */
311                                 c = 0xe0 | ((ctx->uni >> 4) & 0xf);
312                                 goto emit_string_char;
313
314                         case LEJP_MP_STRING_ESC_U3:
315                                 if (ctx->uni >= 0x080) {
316                                         /*
317                                          * 0x080 - 0xfff (0x0800 - 0xffff)
318                                          * middle 3-byte seq
319                                          * send ....XXXXXX..
320                                          */
321                                         c = 0x80 | ((ctx->uni >> 2) & 0x3f);
322                                         goto emit_string_char;
323                                 }
324                                 if (ctx->uni < 0x008)
325                                         break;
326                                 /*
327                                  * 0x008 - 0x7f (0x0080 - 0x07ff)
328                                  * start 2-byte seq
329                                  */
330                                 c = 0xc0 | (ctx->uni >> 2);
331                                 goto emit_string_char;
332
333                         case LEJP_MP_STRING_ESC_U4:
334                                 if (ctx->uni >= 0x0080)
335                                         /* end of 2 or 3-byte seq */
336                                         c = 0x80 | (ctx->uni & 0x3f);
337                                 else
338                                         /* literal */
339                                         c = (unsigned char)ctx->uni;
340
341                                 ctx->st[ctx->sp].s = LEJP_MP_STRING;
342                                 goto emit_string_char;
343                         default:
344                                 break;
345                         }
346                         break;
347
348                 case LEJP_MP_DELIM:
349                         if (c != ':') {
350                                 ret = LEJP_REJECT_MP_DELIM_MISSING_COLON;
351                                 goto reject;
352                         }
353                         ctx->st[ctx->sp].s = LEJP_MP_VALUE;
354                         ctx->path[ctx->ppos] = '\0';
355
356                         lejp_check_path_match(ctx);
357                         if (ctx->callback(ctx, LEJPCB_PAIR_NAME)) {
358                                 ret = LEJP_REJECT_CALLBACK;
359                                 goto reject;
360                         }
361                         break;
362
363                 case LEJP_MP_VALUE:
364                         if (c >= '0' && c <= '9') {
365                                 ctx->npos = 0;
366                                 ctx->dcount = 0;
367                                 ctx->f = 0;
368                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
369                                 goto redo_character;
370                         }
371                         switch (c) {
372                         case'\"':
373                                 /* push */
374                                 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
375                                 c = LEJP_MP_STRING;
376                                 ctx->npos = 0;
377                                 ctx->buf[0] = '\0';
378                                 if (ctx->callback(ctx, LEJPCB_VAL_STR_START)) {
379                                         ret = LEJP_REJECT_CALLBACK;
380                                         goto reject;
381                                 }
382                                 goto add_stack_level;
383
384                         case '{':
385                                 /* push */
386                                 ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
387                                 c = LEJP_MEMBERS;
388                                 lejp_check_path_match(ctx);
389                                 if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
390                                         ret = LEJP_REJECT_CALLBACK;
391                                         goto reject;
392                                 }
393                                 ctx->path_match = 0;
394                                 goto add_stack_level;
395
396                         case '[':
397                                 /* push */
398                                 ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
399                                 c = LEJP_MP_VALUE;
400                                 ctx->path[ctx->ppos++] = '[';
401                                 ctx->path[ctx->ppos++] = ']';
402                                 ctx->path[ctx->ppos] = '\0';
403                                 if (ctx->callback(ctx, LEJPCB_ARRAY_START)) {
404                                         ret = LEJP_REJECT_CALLBACK;
405                                         goto reject;
406                                 }
407                                 ctx->i[ctx->ipos++] = 0;
408                                 if (ctx->ipos > ARRAY_SIZE(ctx->i)) {
409                                         ret = LEJP_REJECT_MP_DELIM_ISTACK;
410                                         goto reject;
411                                 }
412                                 goto add_stack_level;
413
414                         case 't': /* true */
415                                 ctx->uni = 0;
416                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
417                                 break;
418
419                         case 'f':
420                                 ctx->uni = 4;
421                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
422                                 break;
423
424                         case 'n':
425                                 ctx->uni = 4 + 5;
426                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
427                                 break;
428                         default:
429                                 ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START;
430                                 goto reject;
431                         }
432                         break;
433
434                 case LEJP_MP_VALUE_NUM_INT:
435                         if (!ctx->npos && c == '-') {
436                                 ctx->f |= LEJP_SEEN_MINUS;
437                                 goto append_npos;
438                         }
439
440                         if (ctx->dcount < 10 && c >= '0' && c <= '9') {
441                                 if (ctx->f & LEJP_SEEN_POINT)
442                                         ctx->f |= LEJP_SEEN_POST_POINT;
443                                 ctx->dcount++;
444                                 goto append_npos;
445                         }
446                         if (c == '.') {
447                                 if (ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) {
448                                         ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
449                                         goto reject;
450                                 }
451                                 ctx->f |= LEJP_SEEN_POINT;
452                                 goto append_npos;
453                         }
454                         /*
455                          * before exponent, if we had . we must have had at
456                          * least one more digit
457                          */
458                         if ((ctx->f &
459                                 (LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) ==
460                                                               LEJP_SEEN_POINT) {
461                                 ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;
462                                 goto reject;
463                         }
464                         if (c == 'e' || c == 'E') {
465                                 if (ctx->f & LEJP_SEEN_EXP) {
466                                         ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
467                                         goto reject;
468                                 }
469                                 ctx->f |= LEJP_SEEN_EXP;
470                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP;
471                                 goto append_npos;
472                         }
473                         /* if none of the above, did we even have a number? */
474                         if (!ctx->dcount) {
475                                 ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
476                                 goto reject;
477                         }
478
479                         ctx->buf[ctx->npos] = '\0';
480                         if (ctx->f & LEJP_SEEN_POINT) {
481                                 if (ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
482                                         ret = LEJP_REJECT_CALLBACK;
483                                         goto reject;
484                                 }
485                         } else {
486                                 if (ctx->callback(ctx, LEJPCB_VAL_NUM_INT)) {
487                                         ret = LEJP_REJECT_CALLBACK;
488                                         goto reject;
489                                 }
490                         }
491
492                         /* then this is the post-number character, loop */
493                         ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
494                         goto redo_character;
495
496                 case LEJP_MP_VALUE_NUM_EXP:
497                         ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
498                         if (c >= '0' && c <= '9')
499                                 goto redo_character;
500                         if (c == '+' || c == '-')
501                                 goto append_npos;
502                         ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;
503                         goto reject;
504
505                 case LEJP_MP_VALUE_TOK: /* true, false, null */
506                         if (c != tokens[ctx->uni]) {
507                                 ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN;
508                                 goto reject;
509                         }
510                         ctx->uni++;
511                         if (tokens[ctx->uni] != ' ')
512                                 break;
513                         switch (ctx->uni) {
514                         case 3:
515                                 ctx->buf[0] = '1';
516                                 ctx->buf[1] = '\0';
517                                 if (ctx->callback(ctx, LEJPCB_VAL_TRUE)) {
518                                         ret = LEJP_REJECT_CALLBACK;
519                                         goto reject;
520                                 }
521                                 break;
522                         case 8:
523                                 ctx->buf[0] = '0';
524                                 ctx->buf[1] = '\0';
525                                 if (ctx->callback(ctx, LEJPCB_VAL_FALSE)) {
526                                         ret = LEJP_REJECT_CALLBACK;
527                                         goto reject;
528                                 }
529                                 break;
530                         case 12:
531                                 ctx->buf[0] = '\0';
532                                 if (ctx->callback(ctx, LEJPCB_VAL_NULL)) {
533                                         ret = LEJP_REJECT_CALLBACK;
534                                         goto reject;
535                                 }
536                                 break;
537                         }
538                         ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
539                         break;
540
541                 case LEJP_MP_COMMA_OR_END:
542                         ctx->path[ctx->ppos] = '\0';
543                         if (c == ',') {
544                                 /* increment this stack level's index */
545                                 ctx->st[ctx->sp].s = LEJP_M_P;
546                                 if (!ctx->sp) {
547                                         ctx->ppos = 0;
548                                         /*
549                                          * since we came back to root level,
550                                          * no path can still match
551                                          */
552                                         ctx->path_match = 0;
553                                         break;
554                                 }
555                                 ctx->ppos = ctx->st[ctx->sp - 1].p;
556                                 ctx->path[ctx->ppos] = '\0';
557                                 if (ctx->path_match &&
558                                                ctx->ppos <= ctx->path_match_len)
559                                         /*
560                                          * we shrank the path to be
561                                          * smaller than the matching point
562                                          */
563                                         ctx->path_match = 0;
564
565                                 if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
566                                         break;
567                                 /* top level is definitely an array... */
568                                 if (ctx->ipos)
569                                         ctx->i[ctx->ipos - 1]++;
570                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE;
571                                 break;
572                         }
573                         if (c == ']') {
574                                 if (!ctx->sp) {
575                                         ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
576                                         goto reject;
577                                 }
578                                 /* pop */
579                                 ctx->sp--;
580                                 if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
581                                         ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
582                                         goto reject;
583                                 }
584                                 /* drop the path [n] bit */
585                                 ctx->ppos = ctx->st[ctx->sp - 1].p;
586                                 ctx->ipos = ctx->st[ctx->sp - 1].i;
587                                 ctx->path[ctx->ppos] = '\0';
588                                 if (ctx->path_match &&
589                                                ctx->ppos <= ctx->path_match_len)
590                                         /*
591                                          * we shrank the path to be
592                                          * smaller than the matching point
593                                          */
594                                         ctx->path_match = 0;
595
596                                 /* do LEJP_MP_ARRAY_END processing */
597                                 goto redo_character;
598                         }
599                         if (c == '}') {
600                                 if (ctx->sp == 0) {
601                                         lejp_check_path_match(ctx);
602                                         if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
603                                                 ret = LEJP_REJECT_CALLBACK;
604                                                 goto reject;
605                                         }
606                                         ctx->callback(ctx, LEJPCB_COMPLETE);
607                                         /* done, return unused amount */
608                                         return len;
609                                 }
610                                 /* pop */
611                                 ctx->sp--;
612                                 ctx->ppos = ctx->st[ctx->sp - 1].p;
613                                 ctx->ipos = ctx->st[ctx->sp - 1].i;
614                                 ctx->path[ctx->ppos] = '\0';
615                                 if (ctx->path_match &&
616                                                ctx->ppos <= ctx->path_match_len)
617                                         /*
618                                          * we shrank the path to be
619                                          * smaller than the matching point
620                                          */
621                                         ctx->path_match = 0;
622                                 lejp_check_path_match(ctx);
623                                 if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
624                                         ret = LEJP_REJECT_CALLBACK;
625                                         goto reject;
626                                 }
627                                 break;
628                         }
629
630                         ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
631                         goto reject;
632
633                 case LEJP_MP_ARRAY_END:
634                         ctx->path[ctx->ppos] = '\0';
635                         if (c == ',') {
636                                 /* increment this stack level's index */
637                                 if (ctx->ipos)
638                                         ctx->i[ctx->ipos - 1]++;
639                                 ctx->st[ctx->sp].s = LEJP_MP_VALUE;
640                                 if (ctx->sp)
641                                         ctx->ppos = ctx->st[ctx->sp - 1].p;
642                                 ctx->path[ctx->ppos] = '\0';
643                                 break;
644                         }
645                         if (c != ']') {
646                                 ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
647                                 goto reject;
648                         }
649
650                         ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
651                         ctx->callback(ctx, LEJPCB_ARRAY_END);
652                         break;
653                 }
654
655                 continue;
656
657 emit_string_char:
658                 if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
659                         /* assemble the string value into chunks */
660                         ctx->buf[ctx->npos++] = c;
661                         if (ctx->npos == sizeof(ctx->buf) - 1) {
662                                 if (ctx->callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
663                                         ret = LEJP_REJECT_CALLBACK;
664                                         goto reject;
665                                 }
666                                 ctx->npos = 0;
667                         }
668                         continue;
669                 }
670                 /* name part of name:value pair */
671                 ctx->path[ctx->ppos++] = c;
672                 continue;
673
674 add_stack_level:
675                 /* push on to the object stack */
676                 if (ctx->ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
677                                 ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
678                         ctx->path[ctx->ppos++] = '.';
679
680                 ctx->st[ctx->sp].p = ctx->ppos;
681                 ctx->st[ctx->sp].i = ctx->ipos;
682                 if (++ctx->sp == ARRAY_SIZE(ctx->st)) {
683                         ret = LEJP_REJECT_STACK_OVERFLOW;
684                         goto reject;
685                 }
686                 ctx->path[ctx->ppos] = '\0';
687                 ctx->st[ctx->sp].s = c;
688                 ctx->st[ctx->sp].b = 0;
689                 continue;
690
691 append_npos:
692                 if (ctx->npos >= sizeof(ctx->buf)) {
693                         ret = LEJP_REJECT_NUM_TOO_LONG;
694                         goto reject;
695                 }
696                 ctx->buf[ctx->npos++] = c;
697                 continue;
698
699 redo_character:
700                 json--;
701                 len++;
702         }
703
704         return LEJP_CONTINUE;
705
706 reject:
707         ctx->callback(ctx, LEJPCB_FAILED);
708         return ret;
709 }