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