xref: /aosp_15_r20/external/libwebsockets/lib/misc/lecp.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 - 2021 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  * Stream parser for RFC8949 CBOR
25*1c60b9acSAndroid Build Coastguard Worker  */
26*1c60b9acSAndroid Build Coastguard Worker 
27*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
28*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
29*1c60b9acSAndroid Build Coastguard Worker #include <stdio.h>
30*1c60b9acSAndroid Build Coastguard Worker 
31*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CBOR_FLOAT)
32*1c60b9acSAndroid Build Coastguard Worker #include <math.h>
33*1c60b9acSAndroid Build Coastguard Worker #endif
34*1c60b9acSAndroid Build Coastguard Worker 
35*1c60b9acSAndroid Build Coastguard Worker #define lwsl_lecp lwsl_debug
36*1c60b9acSAndroid Build Coastguard Worker 
37*1c60b9acSAndroid Build Coastguard Worker static const char * const parser_errs[] = {
38*1c60b9acSAndroid Build Coastguard Worker 	"",
39*1c60b9acSAndroid Build Coastguard Worker 	"",
40*1c60b9acSAndroid Build Coastguard Worker 	"Bad CBOR coding",
41*1c60b9acSAndroid Build Coastguard Worker 	"Unknown",
42*1c60b9acSAndroid Build Coastguard Worker 	"Parser callback errored (see earlier error)",
43*1c60b9acSAndroid Build Coastguard Worker 	"Overflow"
44*1c60b9acSAndroid Build Coastguard Worker };
45*1c60b9acSAndroid Build Coastguard Worker 
46*1c60b9acSAndroid Build Coastguard Worker enum lecp_states {
47*1c60b9acSAndroid Build Coastguard Worker 	LECP_OPC,
48*1c60b9acSAndroid Build Coastguard Worker 	LECP_COLLECT,
49*1c60b9acSAndroid Build Coastguard Worker 	LECP_SIMPLEX8,
50*1c60b9acSAndroid Build Coastguard Worker 	LECP_COLLATE,
51*1c60b9acSAndroid Build Coastguard Worker 	LECP_ONLY_SAME
52*1c60b9acSAndroid Build Coastguard Worker };
53*1c60b9acSAndroid Build Coastguard Worker 
54*1c60b9acSAndroid Build Coastguard Worker void
lecp_construct(struct lecp_ctx * ctx,lecp_callback cb,void * user,const char * const * paths,unsigned char count_paths)55*1c60b9acSAndroid Build Coastguard Worker lecp_construct(struct lecp_ctx *ctx, lecp_callback cb, void *user,
56*1c60b9acSAndroid Build Coastguard Worker 	       const char * const *paths, unsigned char count_paths)
57*1c60b9acSAndroid Build Coastguard Worker {
58*1c60b9acSAndroid Build Coastguard Worker 	uint16_t x = 0x1234;
59*1c60b9acSAndroid Build Coastguard Worker 
60*1c60b9acSAndroid Build Coastguard Worker 	memset(ctx, 0, sizeof(*ctx) - sizeof(ctx->buf));
61*1c60b9acSAndroid Build Coastguard Worker 
62*1c60b9acSAndroid Build Coastguard Worker 	ctx->user		= user;
63*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].cb		= cb;
64*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].paths	= paths;
65*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].count_paths = count_paths;
66*1c60b9acSAndroid Build Coastguard Worker 	ctx->be			= *((uint8_t *)&x) == 0x12;
67*1c60b9acSAndroid Build Coastguard Worker 
68*1c60b9acSAndroid Build Coastguard Worker 	ctx->st[0].s		= LECP_OPC;
69*1c60b9acSAndroid Build Coastguard Worker 
70*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].cb(ctx, LECPCB_CONSTRUCTED);
71*1c60b9acSAndroid Build Coastguard Worker }
72*1c60b9acSAndroid Build Coastguard Worker 
73*1c60b9acSAndroid Build Coastguard Worker void
lecp_destruct(struct lecp_ctx * ctx)74*1c60b9acSAndroid Build Coastguard Worker lecp_destruct(struct lecp_ctx *ctx)
75*1c60b9acSAndroid Build Coastguard Worker {
76*1c60b9acSAndroid Build Coastguard Worker 	/* no allocations... just let callback know what it happening */
77*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->pst[0].cb)
78*1c60b9acSAndroid Build Coastguard Worker 		ctx->pst[0].cb(ctx, LECPCB_DESTRUCTED);
79*1c60b9acSAndroid Build Coastguard Worker }
80*1c60b9acSAndroid Build Coastguard Worker 
81*1c60b9acSAndroid Build Coastguard Worker void
lecp_change_callback(struct lecp_ctx * ctx,lecp_callback cb)82*1c60b9acSAndroid Build Coastguard Worker lecp_change_callback(struct lecp_ctx *ctx, lecp_callback cb)
83*1c60b9acSAndroid Build Coastguard Worker {
84*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].cb(ctx, LECPCB_DESTRUCTED);
85*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].cb = cb;
86*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[0].cb(ctx, LECPCB_CONSTRUCTED);
87*1c60b9acSAndroid Build Coastguard Worker }
88*1c60b9acSAndroid Build Coastguard Worker 
89*1c60b9acSAndroid Build Coastguard Worker 
90*1c60b9acSAndroid Build Coastguard Worker const char *
lecp_error_to_string(int e)91*1c60b9acSAndroid Build Coastguard Worker lecp_error_to_string(int e)
92*1c60b9acSAndroid Build Coastguard Worker {
93*1c60b9acSAndroid Build Coastguard Worker 	if (e > 0)
94*1c60b9acSAndroid Build Coastguard Worker 		e = 0;
95*1c60b9acSAndroid Build Coastguard Worker 	else
96*1c60b9acSAndroid Build Coastguard Worker 		e = -e;
97*1c60b9acSAndroid Build Coastguard Worker 
98*1c60b9acSAndroid Build Coastguard Worker 	if (e >= (int)LWS_ARRAY_SIZE(parser_errs))
99*1c60b9acSAndroid Build Coastguard Worker 		return "Unknown error";
100*1c60b9acSAndroid Build Coastguard Worker 
101*1c60b9acSAndroid Build Coastguard Worker 	return parser_errs[e];
102*1c60b9acSAndroid Build Coastguard Worker }
103*1c60b9acSAndroid Build Coastguard Worker 
104*1c60b9acSAndroid Build Coastguard Worker static void
ex(struct lecp_ctx * ctx,void * _start,size_t len)105*1c60b9acSAndroid Build Coastguard Worker ex(struct lecp_ctx *ctx, void *_start, size_t len)
106*1c60b9acSAndroid Build Coastguard Worker {
107*1c60b9acSAndroid Build Coastguard Worker 	struct _lecp_stack *st = &ctx->st[ctx->sp];
108*1c60b9acSAndroid Build Coastguard Worker 	uint8_t *start = (uint8_t *)_start;
109*1c60b9acSAndroid Build Coastguard Worker 
110*1c60b9acSAndroid Build Coastguard Worker 	st->s = LECP_COLLECT;
111*1c60b9acSAndroid Build Coastguard Worker 	st->collect_rem = (uint8_t)len;
112*1c60b9acSAndroid Build Coastguard Worker 
113*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->be)
114*1c60b9acSAndroid Build Coastguard Worker 		ctx->collect_tgt = start;
115*1c60b9acSAndroid Build Coastguard Worker 	else
116*1c60b9acSAndroid Build Coastguard Worker 		ctx->collect_tgt = start + len - 1;
117*1c60b9acSAndroid Build Coastguard Worker }
118*1c60b9acSAndroid Build Coastguard Worker 
119*1c60b9acSAndroid Build Coastguard Worker static void
lecp_check_path_match(struct lecp_ctx * ctx)120*1c60b9acSAndroid Build Coastguard Worker lecp_check_path_match(struct lecp_ctx *ctx)
121*1c60b9acSAndroid Build Coastguard Worker {
122*1c60b9acSAndroid Build Coastguard Worker 	const char *p, *q;
123*1c60b9acSAndroid Build Coastguard Worker 	size_t s = sizeof(char *);
124*1c60b9acSAndroid Build Coastguard Worker 	int n;
125*1c60b9acSAndroid Build Coastguard Worker 
126*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->path_stride)
127*1c60b9acSAndroid Build Coastguard Worker 		s = ctx->path_stride;
128*1c60b9acSAndroid Build Coastguard Worker 
129*1c60b9acSAndroid Build Coastguard Worker 	/* we only need to check if a match is not active */
130*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; !ctx->path_match &&
131*1c60b9acSAndroid Build Coastguard Worker 	     n < ctx->pst[ctx->pst_sp].count_paths; n++) {
132*1c60b9acSAndroid Build Coastguard Worker 		ctx->wildcount = 0;
133*1c60b9acSAndroid Build Coastguard Worker 		p = ctx->path;
134*1c60b9acSAndroid Build Coastguard Worker 
135*1c60b9acSAndroid Build Coastguard Worker 		q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) +
136*1c60b9acSAndroid Build Coastguard Worker 							((unsigned int)n * s)));
137*1c60b9acSAndroid Build Coastguard Worker 
138*1c60b9acSAndroid Build Coastguard Worker 		while (*p && *q) {
139*1c60b9acSAndroid Build Coastguard Worker 			if (*q != '*') {
140*1c60b9acSAndroid Build Coastguard Worker 				if (*p != *q)
141*1c60b9acSAndroid Build Coastguard Worker 					break;
142*1c60b9acSAndroid Build Coastguard Worker 				p++;
143*1c60b9acSAndroid Build Coastguard Worker 				q++;
144*1c60b9acSAndroid Build Coastguard Worker 				continue;
145*1c60b9acSAndroid Build Coastguard Worker 			}
146*1c60b9acSAndroid Build Coastguard Worker 			ctx->wild[ctx->wildcount++] =
147*1c60b9acSAndroid Build Coastguard Worker 				    (uint16_t)lws_ptr_diff_size_t(p, ctx->path);
148*1c60b9acSAndroid Build Coastguard Worker 			q++;
149*1c60b9acSAndroid Build Coastguard Worker 			/*
150*1c60b9acSAndroid Build Coastguard Worker 			 * if * has something after it, match to .
151*1c60b9acSAndroid Build Coastguard Worker 			 * if ends with *, eat everything.
152*1c60b9acSAndroid Build Coastguard Worker 			 * This implies match sequences must be ordered like
153*1c60b9acSAndroid Build Coastguard Worker 			 *  x.*.*
154*1c60b9acSAndroid Build Coastguard Worker 			 *  x.*
155*1c60b9acSAndroid Build Coastguard Worker 			 * if both options are possible
156*1c60b9acSAndroid Build Coastguard Worker 			 */
157*1c60b9acSAndroid Build Coastguard Worker 			while (*p && (*p != '.' || !*q))
158*1c60b9acSAndroid Build Coastguard Worker 				p++;
159*1c60b9acSAndroid Build Coastguard Worker 		}
160*1c60b9acSAndroid Build Coastguard Worker 		if (*p || *q)
161*1c60b9acSAndroid Build Coastguard Worker 			continue;
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 		ctx->path_match = (uint8_t)(n + 1);
164*1c60b9acSAndroid Build Coastguard Worker 		ctx->path_match_len = ctx->pst[ctx->pst_sp].ppos;
165*1c60b9acSAndroid Build Coastguard Worker 		return;
166*1c60b9acSAndroid Build Coastguard Worker 	}
167*1c60b9acSAndroid Build Coastguard Worker 
168*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->path_match)
169*1c60b9acSAndroid Build Coastguard Worker 		ctx->wildcount = 0;
170*1c60b9acSAndroid Build Coastguard Worker }
171*1c60b9acSAndroid Build Coastguard Worker 
172*1c60b9acSAndroid Build Coastguard Worker int
lecp_push(struct lecp_ctx * ctx,char s_start,char s_end,char state)173*1c60b9acSAndroid Build Coastguard Worker lecp_push(struct lecp_ctx *ctx, char s_start, char s_end, char state)
174*1c60b9acSAndroid Build Coastguard Worker {
175*1c60b9acSAndroid Build Coastguard Worker 	struct _lecp_stack *st = &ctx->st[ctx->sp];
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->sp + 1 == LWS_ARRAY_SIZE(ctx->st))
178*1c60b9acSAndroid Build Coastguard Worker 		return LECP_STACK_OVERFLOW;
179*1c60b9acSAndroid Build Coastguard Worker 
180*1c60b9acSAndroid Build Coastguard Worker 	if (s_start && ctx->pst[ctx->pst_sp].cb(ctx, s_start))
181*1c60b9acSAndroid Build Coastguard Worker 		return LECP_REJECT_CALLBACK;
182*1c60b9acSAndroid Build Coastguard Worker 
183*1c60b9acSAndroid Build Coastguard Worker 	lwsl_lecp("%s: pushing from sp %d, parent "
184*1c60b9acSAndroid Build Coastguard Worker 		  "(opc %d, indet %d, collect_rem %d)\n",
185*1c60b9acSAndroid Build Coastguard Worker 		  __func__, ctx->sp, st->opcode >> 5, st->indet,
186*1c60b9acSAndroid Build Coastguard Worker 		  (int)st->collect_rem);
187*1c60b9acSAndroid Build Coastguard Worker 
188*1c60b9acSAndroid Build Coastguard Worker 
189*1c60b9acSAndroid Build Coastguard Worker 	st->pop_iss = s_end; /* issue this when we pop back here */
190*1c60b9acSAndroid Build Coastguard Worker 	ctx->st[ctx->sp + 1] = *st;
191*1c60b9acSAndroid Build Coastguard Worker 	ctx->sp++;
192*1c60b9acSAndroid Build Coastguard Worker 	st++;
193*1c60b9acSAndroid Build Coastguard Worker 
194*1c60b9acSAndroid Build Coastguard Worker 	st->s			= state;
195*1c60b9acSAndroid Build Coastguard Worker 	st->collect_rem		= 0;
196*1c60b9acSAndroid Build Coastguard Worker 	st->intermediate	= 0;
197*1c60b9acSAndroid Build Coastguard Worker 	st->indet		= 0;
198*1c60b9acSAndroid Build Coastguard Worker 	st->ordinal		= 0;
199*1c60b9acSAndroid Build Coastguard Worker 	st->send_new_array_item = 0;
200*1c60b9acSAndroid Build Coastguard Worker 	st->barrier		= 0;
201*1c60b9acSAndroid Build Coastguard Worker 
202*1c60b9acSAndroid Build Coastguard Worker 	return 0;
203*1c60b9acSAndroid Build Coastguard Worker }
204*1c60b9acSAndroid Build Coastguard Worker 
205*1c60b9acSAndroid Build Coastguard Worker int
lecp_pop(struct lecp_ctx * ctx)206*1c60b9acSAndroid Build Coastguard Worker lecp_pop(struct lecp_ctx *ctx)
207*1c60b9acSAndroid Build Coastguard Worker {
208*1c60b9acSAndroid Build Coastguard Worker 	struct _lecp_stack *st;
209*1c60b9acSAndroid Build Coastguard Worker 
210*1c60b9acSAndroid Build Coastguard Worker 	assert(ctx->sp);
211*1c60b9acSAndroid Build Coastguard Worker 	ctx->sp--;
212*1c60b9acSAndroid Build Coastguard Worker 
213*1c60b9acSAndroid Build Coastguard Worker 	st = &ctx->st[ctx->sp];
214*1c60b9acSAndroid Build Coastguard Worker 
215*1c60b9acSAndroid Build Coastguard Worker 	if (st->pop_iss == LECPCB_ARRAY_END) {
216*1c60b9acSAndroid Build Coastguard Worker 		assert(ctx->ipos);
217*1c60b9acSAndroid Build Coastguard Worker 		ctx->ipos--;
218*1c60b9acSAndroid Build Coastguard Worker 	}
219*1c60b9acSAndroid Build Coastguard Worker 
220*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[ctx->pst_sp].ppos = st->p;
221*1c60b9acSAndroid Build Coastguard Worker 	ctx->path[st->p] = '\0';
222*1c60b9acSAndroid Build Coastguard Worker 	lecp_check_path_match(ctx);
223*1c60b9acSAndroid Build Coastguard Worker 
224*1c60b9acSAndroid Build Coastguard Worker 	lwsl_lecp("%s: popping to sp %d, parent "
225*1c60b9acSAndroid Build Coastguard Worker 		  "(opc %d, indet %d, collect_rem %d)\n",
226*1c60b9acSAndroid Build Coastguard Worker 		   __func__, ctx->sp, st->opcode >> 5, st->indet,
227*1c60b9acSAndroid Build Coastguard Worker 		   (int)st->collect_rem);
228*1c60b9acSAndroid Build Coastguard Worker 
229*1c60b9acSAndroid Build Coastguard Worker 	if (st->pop_iss && ctx->pst[ctx->pst_sp].cb(ctx, st->pop_iss))
230*1c60b9acSAndroid Build Coastguard Worker 		return LECP_REJECT_CALLBACK;
231*1c60b9acSAndroid Build Coastguard Worker 
232*1c60b9acSAndroid Build Coastguard Worker 	return 0;
233*1c60b9acSAndroid Build Coastguard Worker }
234*1c60b9acSAndroid Build Coastguard Worker 
235*1c60b9acSAndroid Build Coastguard Worker static struct _lecp_stack *
lwcp_st_parent(struct lecp_ctx * ctx)236*1c60b9acSAndroid Build Coastguard Worker lwcp_st_parent(struct lecp_ctx *ctx)
237*1c60b9acSAndroid Build Coastguard Worker {
238*1c60b9acSAndroid Build Coastguard Worker 	assert(ctx->sp);
239*1c60b9acSAndroid Build Coastguard Worker 
240*1c60b9acSAndroid Build Coastguard Worker 	return &ctx->st[ctx->sp - 1];
241*1c60b9acSAndroid Build Coastguard Worker }
242*1c60b9acSAndroid Build Coastguard Worker 
243*1c60b9acSAndroid Build Coastguard Worker int
lwcp_completed(struct lecp_ctx * ctx,char indet)244*1c60b9acSAndroid Build Coastguard Worker lwcp_completed(struct lecp_ctx *ctx, char indet)
245*1c60b9acSAndroid Build Coastguard Worker {
246*1c60b9acSAndroid Build Coastguard Worker 	int r, il = ctx->ipos;
247*1c60b9acSAndroid Build Coastguard Worker 
248*1c60b9acSAndroid Build Coastguard Worker 	ctx->st[ctx->sp].s = LECP_OPC;
249*1c60b9acSAndroid Build Coastguard Worker 
250*1c60b9acSAndroid Build Coastguard Worker 	while (ctx->sp && !ctx->st[ctx->sp].barrier) {
251*1c60b9acSAndroid Build Coastguard Worker 		struct _lecp_stack *parent = lwcp_st_parent(ctx);
252*1c60b9acSAndroid Build Coastguard Worker 
253*1c60b9acSAndroid Build Coastguard Worker 		lwsl_lecp("%s: sp %d, parent "
254*1c60b9acSAndroid Build Coastguard Worker 			  "(opc %d, indet %d, collect_rem %d)\n",
255*1c60b9acSAndroid Build Coastguard Worker 			  __func__, ctx->sp, parent->opcode >> 5, parent->indet,
256*1c60b9acSAndroid Build Coastguard Worker 			  (int)parent->collect_rem);
257*1c60b9acSAndroid Build Coastguard Worker 
258*1c60b9acSAndroid Build Coastguard Worker 		parent->ordinal++;
259*1c60b9acSAndroid Build Coastguard Worker 		if (parent->opcode == LWS_CBOR_MAJTYP_ARRAY) {
260*1c60b9acSAndroid Build Coastguard Worker 			assert(il);
261*1c60b9acSAndroid Build Coastguard Worker 			il--;
262*1c60b9acSAndroid Build Coastguard Worker 			ctx->i[il]++;
263*1c60b9acSAndroid Build Coastguard Worker 			if (!parent->send_new_array_item) {
264*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->pst[ctx->pst_sp].cb(ctx,
265*1c60b9acSAndroid Build Coastguard Worker 						LECPCB_ARRAY_ITEM_END))
266*1c60b9acSAndroid Build Coastguard Worker 					return LECP_REJECT_CALLBACK;
267*1c60b9acSAndroid Build Coastguard Worker 				parent->send_new_array_item = 1;
268*1c60b9acSAndroid Build Coastguard Worker 			}
269*1c60b9acSAndroid Build Coastguard Worker 		}
270*1c60b9acSAndroid Build Coastguard Worker 
271*1c60b9acSAndroid Build Coastguard Worker 		if (!indet && parent->indet) {
272*1c60b9acSAndroid Build Coastguard Worker 			lwsl_lecp("%s: abandoning walk as parent needs indet\n", __func__);
273*1c60b9acSAndroid Build Coastguard Worker 			break;
274*1c60b9acSAndroid Build Coastguard Worker 		}
275*1c60b9acSAndroid Build Coastguard Worker 
276*1c60b9acSAndroid Build Coastguard Worker 		if (!parent->indet && parent->collect_rem) {
277*1c60b9acSAndroid Build Coastguard Worker 			parent->collect_rem--;
278*1c60b9acSAndroid Build Coastguard Worker 			lwsl_lecp("%s: sp %d, parent (opc %d, indet %d, collect_rem -> %d)\n",
279*1c60b9acSAndroid Build Coastguard Worker 					__func__, ctx->sp, parent->opcode >> 5, parent->indet, (int)parent->collect_rem);
280*1c60b9acSAndroid Build Coastguard Worker 
281*1c60b9acSAndroid Build Coastguard Worker 			if (parent->collect_rem) {
282*1c60b9acSAndroid Build Coastguard Worker 				/* more items to come */
283*1c60b9acSAndroid Build Coastguard Worker 				if (parent->opcode == LWS_CBOR_MAJTYP_ARRAY)
284*1c60b9acSAndroid Build Coastguard Worker 					parent->send_new_array_item = 1;
285*1c60b9acSAndroid Build Coastguard Worker 				break;
286*1c60b9acSAndroid Build Coastguard Worker 			}
287*1c60b9acSAndroid Build Coastguard Worker 		}
288*1c60b9acSAndroid Build Coastguard Worker 
289*1c60b9acSAndroid Build Coastguard Worker 		lwsl_lecp("%s: parent (opc %d) collect_rem became zero\n", __func__, parent->opcode >> 5);
290*1c60b9acSAndroid Build Coastguard Worker 
291*1c60b9acSAndroid Build Coastguard Worker 		ctx->st[ctx->sp - 1].s = LECP_OPC;
292*1c60b9acSAndroid Build Coastguard Worker 		r = lecp_pop(ctx);
293*1c60b9acSAndroid Build Coastguard Worker 		if (r)
294*1c60b9acSAndroid Build Coastguard Worker 			return r;
295*1c60b9acSAndroid Build Coastguard Worker 		indet = 0;
296*1c60b9acSAndroid Build Coastguard Worker 	}
297*1c60b9acSAndroid Build Coastguard Worker 
298*1c60b9acSAndroid Build Coastguard Worker 	return 0;
299*1c60b9acSAndroid Build Coastguard Worker }
300*1c60b9acSAndroid Build Coastguard Worker 
301*1c60b9acSAndroid Build Coastguard Worker static int
lwcp_is_indet_string(struct lecp_ctx * ctx)302*1c60b9acSAndroid Build Coastguard Worker lwcp_is_indet_string(struct lecp_ctx *ctx)
303*1c60b9acSAndroid Build Coastguard Worker {
304*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->st[ctx->sp].indet)
305*1c60b9acSAndroid Build Coastguard Worker 		return 1;
306*1c60b9acSAndroid Build Coastguard Worker 
307*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->sp)
308*1c60b9acSAndroid Build Coastguard Worker 		return 0;
309*1c60b9acSAndroid Build Coastguard Worker 
310*1c60b9acSAndroid Build Coastguard Worker 	if (lwcp_st_parent(ctx)->opcode != LWS_CBOR_MAJTYP_BSTR &&
311*1c60b9acSAndroid Build Coastguard Worker 	    lwcp_st_parent(ctx)->opcode != LWS_CBOR_MAJTYP_TSTR)
312*1c60b9acSAndroid Build Coastguard Worker 		return 0;
313*1c60b9acSAndroid Build Coastguard Worker 
314*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->st[ctx->sp - 1].indet)
315*1c60b9acSAndroid Build Coastguard Worker 		return 1;
316*1c60b9acSAndroid Build Coastguard Worker 
317*1c60b9acSAndroid Build Coastguard Worker 	return 0;
318*1c60b9acSAndroid Build Coastguard Worker }
319*1c60b9acSAndroid Build Coastguard Worker 
320*1c60b9acSAndroid Build Coastguard Worker static int
report_raw_cbor(struct lecp_ctx * ctx)321*1c60b9acSAndroid Build Coastguard Worker report_raw_cbor(struct lecp_ctx *ctx)
322*1c60b9acSAndroid Build Coastguard Worker {
323*1c60b9acSAndroid Build Coastguard Worker 	struct _lecp_parsing_stack *pst = &ctx->pst[ctx->pst_sp];
324*1c60b9acSAndroid Build Coastguard Worker 
325*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->cbor_pos)
326*1c60b9acSAndroid Build Coastguard Worker 		return 0;
327*1c60b9acSAndroid Build Coastguard Worker 
328*1c60b9acSAndroid Build Coastguard Worker 	if (pst->cb(ctx, LECPCB_LITERAL_CBOR))
329*1c60b9acSAndroid Build Coastguard Worker 		return 1;
330*1c60b9acSAndroid Build Coastguard Worker 
331*1c60b9acSAndroid Build Coastguard Worker 	ctx->cbor_pos = 0;
332*1c60b9acSAndroid Build Coastguard Worker 
333*1c60b9acSAndroid Build Coastguard Worker 	return 0;
334*1c60b9acSAndroid Build Coastguard Worker }
335*1c60b9acSAndroid Build Coastguard Worker 
336*1c60b9acSAndroid Build Coastguard Worker void
lecp_parse_report_raw(struct lecp_ctx * ctx,int on)337*1c60b9acSAndroid Build Coastguard Worker lecp_parse_report_raw(struct lecp_ctx *ctx, int on)
338*1c60b9acSAndroid Build Coastguard Worker {
339*1c60b9acSAndroid Build Coastguard Worker 	ctx->literal_cbor_report = (uint8_t)on;
340*1c60b9acSAndroid Build Coastguard Worker 	report_raw_cbor(ctx);
341*1c60b9acSAndroid Build Coastguard Worker }
342*1c60b9acSAndroid Build Coastguard Worker 
343*1c60b9acSAndroid Build Coastguard Worker int
lecp_parse_map_is_key(struct lecp_ctx * ctx)344*1c60b9acSAndroid Build Coastguard Worker lecp_parse_map_is_key(struct lecp_ctx *ctx)
345*1c60b9acSAndroid Build Coastguard Worker {
346*1c60b9acSAndroid Build Coastguard Worker 	return lwcp_st_parent(ctx)->opcode == LWS_CBOR_MAJTYP_MAP &&
347*1c60b9acSAndroid Build Coastguard Worker 	       !(lwcp_st_parent(ctx)->ordinal & 1);
348*1c60b9acSAndroid Build Coastguard Worker }
349*1c60b9acSAndroid Build Coastguard Worker 
350*1c60b9acSAndroid Build Coastguard Worker int
lecp_parse_subtree(struct lecp_ctx * ctx,const uint8_t * in,size_t len)351*1c60b9acSAndroid Build Coastguard Worker lecp_parse_subtree(struct lecp_ctx *ctx, const uint8_t *in, size_t len)
352*1c60b9acSAndroid Build Coastguard Worker {
353*1c60b9acSAndroid Build Coastguard Worker 	struct _lecp_stack *st = &ctx->st[++ctx->sp];
354*1c60b9acSAndroid Build Coastguard Worker 	int n;
355*1c60b9acSAndroid Build Coastguard Worker 
356*1c60b9acSAndroid Build Coastguard Worker 	st->s			= 0;
357*1c60b9acSAndroid Build Coastguard Worker 	st->collect_rem		= 0;
358*1c60b9acSAndroid Build Coastguard Worker 	st->intermediate	= 0;
359*1c60b9acSAndroid Build Coastguard Worker 	st->indet		= 0;
360*1c60b9acSAndroid Build Coastguard Worker 	st->ordinal		= 0;
361*1c60b9acSAndroid Build Coastguard Worker 	st->send_new_array_item = 0;
362*1c60b9acSAndroid Build Coastguard Worker 	st->barrier		= 1;
363*1c60b9acSAndroid Build Coastguard Worker 
364*1c60b9acSAndroid Build Coastguard Worker 	n = lecp_parse(ctx, in, len);
365*1c60b9acSAndroid Build Coastguard Worker 	ctx->sp--;
366*1c60b9acSAndroid Build Coastguard Worker 
367*1c60b9acSAndroid Build Coastguard Worker 	return n;
368*1c60b9acSAndroid Build Coastguard Worker }
369*1c60b9acSAndroid Build Coastguard Worker 
370*1c60b9acSAndroid Build Coastguard Worker int
lecp_parse(struct lecp_ctx * ctx,const uint8_t * cbor,size_t len)371*1c60b9acSAndroid Build Coastguard Worker lecp_parse(struct lecp_ctx *ctx, const uint8_t *cbor, size_t len)
372*1c60b9acSAndroid Build Coastguard Worker {
373*1c60b9acSAndroid Build Coastguard Worker 	size_t olen = len;
374*1c60b9acSAndroid Build Coastguard Worker 	int ret;
375*1c60b9acSAndroid Build Coastguard Worker 
376*1c60b9acSAndroid Build Coastguard Worker 	while (len--) {
377*1c60b9acSAndroid Build Coastguard Worker 		struct _lecp_parsing_stack *pst = &ctx->pst[ctx->pst_sp];
378*1c60b9acSAndroid Build Coastguard Worker 		struct _lecp_stack *st = &ctx->st[ctx->sp];
379*1c60b9acSAndroid Build Coastguard Worker 		uint8_t c, sm, o;
380*1c60b9acSAndroid Build Coastguard Worker 		char to;
381*1c60b9acSAndroid Build Coastguard Worker 
382*1c60b9acSAndroid Build Coastguard Worker 		c = *cbor++;
383*1c60b9acSAndroid Build Coastguard Worker 
384*1c60b9acSAndroid Build Coastguard Worker 		/*
385*1c60b9acSAndroid Build Coastguard Worker 		 * for, eg, cose_sign, we sometimes need to collect subtrees of
386*1c60b9acSAndroid Build Coastguard Worker 		 * raw CBOR.  Report buffers of it via the callback if we filled
387*1c60b9acSAndroid Build Coastguard Worker 		 * the buffer, or we stopped collecting.
388*1c60b9acSAndroid Build Coastguard Worker 		 */
389*1c60b9acSAndroid Build Coastguard Worker 
390*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->literal_cbor_report) {
391*1c60b9acSAndroid Build Coastguard Worker 			ctx->cbor[ctx->cbor_pos++] = c;
392*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->cbor_pos == sizeof(ctx->cbor) &&
393*1c60b9acSAndroid Build Coastguard Worker 			    report_raw_cbor(ctx))
394*1c60b9acSAndroid Build Coastguard Worker 				goto reject_callback;
395*1c60b9acSAndroid Build Coastguard Worker 		}
396*1c60b9acSAndroid Build Coastguard Worker 
397*1c60b9acSAndroid Build Coastguard Worker 		switch (st->s) {
398*1c60b9acSAndroid Build Coastguard Worker 		/*
399*1c60b9acSAndroid Build Coastguard Worker 		 * We're getting the nex opcode
400*1c60b9acSAndroid Build Coastguard Worker 		 */
401*1c60b9acSAndroid Build Coastguard Worker 		case LECP_OPC:
402*1c60b9acSAndroid Build Coastguard Worker 			st->opcode = ctx->item.opcode = c & LWS_CBOR_MAJTYP_MASK;
403*1c60b9acSAndroid Build Coastguard Worker 			sm = c & LWS_CBOR_SUBMASK;
404*1c60b9acSAndroid Build Coastguard Worker 			to = 0;
405*1c60b9acSAndroid Build Coastguard Worker 
406*1c60b9acSAndroid Build Coastguard Worker 			lwsl_lecp("%s: %d: OPC %d|%d\n", __func__, ctx->sp,
407*1c60b9acSAndroid Build Coastguard Worker 					c >> 5, sm);
408*1c60b9acSAndroid Build Coastguard Worker 
409*1c60b9acSAndroid Build Coastguard Worker 			if (c != 0xff && ctx->sp &&
410*1c60b9acSAndroid Build Coastguard Worker 			    ctx->st[ctx->sp - 1].send_new_array_item) {
411*1c60b9acSAndroid Build Coastguard Worker 				ctx->st[ctx->sp - 1].send_new_array_item = 0;
412*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->pst[ctx->pst_sp].cb(ctx,
413*1c60b9acSAndroid Build Coastguard Worker 						LECPCB_ARRAY_ITEM_START))
414*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
415*1c60b9acSAndroid Build Coastguard Worker 			}
416*1c60b9acSAndroid Build Coastguard Worker 
417*1c60b9acSAndroid Build Coastguard Worker 			switch (st->opcode) {
418*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_UINT:
419*1c60b9acSAndroid Build Coastguard Worker 				ctx->present = LECPCB_VAL_NUM_UINT;
420*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_1) {
421*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.i64 = (int64_t)sm;
422*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
423*1c60b9acSAndroid Build Coastguard Worker 				}
424*1c60b9acSAndroid Build Coastguard Worker 				goto i2;
425*1c60b9acSAndroid Build Coastguard Worker 
426*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_INT_NEG:
427*1c60b9acSAndroid Build Coastguard Worker 				ctx->present = LECPCB_VAL_NUM_INT;
428*1c60b9acSAndroid Build Coastguard Worker 				if (sm < 24) {
429*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.i64 = (-1ll) - (int64_t)sm;
430*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
431*1c60b9acSAndroid Build Coastguard Worker 				}
432*1c60b9acSAndroid Build Coastguard Worker i2:
433*1c60b9acSAndroid Build Coastguard Worker 				if (sm >= LWS_CBOR_RESERVED)
434*1c60b9acSAndroid Build Coastguard Worker 					goto bad_coding;
435*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.u.u64 = 0;
436*1c60b9acSAndroid Build Coastguard Worker 				o = (uint8_t)(1 << (sm - LWS_CBOR_1));
437*1c60b9acSAndroid Build Coastguard Worker 				ex(ctx, (uint8_t *)&ctx->item.u.u64, o);
438*1c60b9acSAndroid Build Coastguard Worker 				break;
439*1c60b9acSAndroid Build Coastguard Worker 
440*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_BSTR:
441*1c60b9acSAndroid Build Coastguard Worker 				to = LECPCB_VAL_BLOB_END - LECPCB_VAL_STR_END;
442*1c60b9acSAndroid Build Coastguard Worker 
443*1c60b9acSAndroid Build Coastguard Worker 				/* fallthru */
444*1c60b9acSAndroid Build Coastguard Worker 
445*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_TSTR:
446*1c60b9acSAndroid Build Coastguard Worker 				/*
447*1c60b9acSAndroid Build Coastguard Worker 				 * The first thing is the string length, it's
448*1c60b9acSAndroid Build Coastguard Worker 				 * going to either be a byte count for the
449*1c60b9acSAndroid Build Coastguard Worker 				 * string or the indefinite length marker
450*1c60b9acSAndroid Build Coastguard Worker 				 * followed by determinite-length chunks of the
451*1c60b9acSAndroid Build Coastguard Worker 				 * same MAJTYP
452*1c60b9acSAndroid Build Coastguard Worker 				 */
453*1c60b9acSAndroid Build Coastguard Worker 
454*1c60b9acSAndroid Build Coastguard Worker 				ctx->npos = 0;
455*1c60b9acSAndroid Build Coastguard Worker 				ctx->buf[0] = '\0';
456*1c60b9acSAndroid Build Coastguard Worker 
457*1c60b9acSAndroid Build Coastguard Worker 				if (!sm) {
458*1c60b9acSAndroid Build Coastguard Worker 					if ((!ctx->sp || (ctx->sp &&
459*1c60b9acSAndroid Build Coastguard Worker 					    !ctx->st[ctx->sp - 1].intermediate)) &&
460*1c60b9acSAndroid Build Coastguard Worker 					    pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
461*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
462*1c60b9acSAndroid Build Coastguard Worker 
463*1c60b9acSAndroid Build Coastguard Worker 					if (pst->cb(ctx, (char)(LECPCB_VAL_STR_END + to)))
464*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
465*1c60b9acSAndroid Build Coastguard Worker 					lwcp_completed(ctx, 0);
466*1c60b9acSAndroid Build Coastguard Worker 					break;
467*1c60b9acSAndroid Build Coastguard Worker 				}
468*1c60b9acSAndroid Build Coastguard Worker 
469*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_1) {
470*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = (uint64_t)sm;
471*1c60b9acSAndroid Build Coastguard Worker 					if ((!ctx->sp || (ctx->sp &&
472*1c60b9acSAndroid Build Coastguard Worker 					    !ctx->st[ctx->sp - 1].intermediate)) &&
473*1c60b9acSAndroid Build Coastguard Worker 					    pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
474*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
475*1c60b9acSAndroid Build Coastguard Worker 
476*1c60b9acSAndroid Build Coastguard Worker 					st->indet = 0;
477*1c60b9acSAndroid Build Coastguard Worker 					st->collect_rem = sm;
478*1c60b9acSAndroid Build Coastguard Worker 					st->s = LECP_COLLATE;
479*1c60b9acSAndroid Build Coastguard Worker 					break;
480*1c60b9acSAndroid Build Coastguard Worker 				}
481*1c60b9acSAndroid Build Coastguard Worker 
482*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_RESERVED)
483*1c60b9acSAndroid Build Coastguard Worker 					goto i2;
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 				if (sm != LWS_CBOR_INDETERMINITE)
486*1c60b9acSAndroid Build Coastguard Worker 					goto bad_coding;
487*1c60b9acSAndroid Build Coastguard Worker 
488*1c60b9acSAndroid Build Coastguard Worker 				if ((!ctx->sp || (ctx->sp &&
489*1c60b9acSAndroid Build Coastguard Worker 				    !ctx->st[ctx->sp - 1].intermediate)) &&
490*1c60b9acSAndroid Build Coastguard Worker 				    pst->cb(ctx, (char)(LECPCB_VAL_STR_START + to)))
491*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
492*1c60b9acSAndroid Build Coastguard Worker 
493*1c60b9acSAndroid Build Coastguard Worker 				st->indet = 1;
494*1c60b9acSAndroid Build Coastguard Worker 
495*1c60b9acSAndroid Build Coastguard Worker 				st->p = pst->ppos;
496*1c60b9acSAndroid Build Coastguard Worker 				lecp_push(ctx, 0, (char)(LECPCB_VAL_STR_END + to),
497*1c60b9acSAndroid Build Coastguard Worker 						  LECP_ONLY_SAME);
498*1c60b9acSAndroid Build Coastguard Worker 				break;
499*1c60b9acSAndroid Build Coastguard Worker 
500*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_ARRAY:
501*1c60b9acSAndroid Build Coastguard Worker 				ctx->npos = 0;
502*1c60b9acSAndroid Build Coastguard Worker 				ctx->buf[0] = '\0';
503*1c60b9acSAndroid Build Coastguard Worker 
504*1c60b9acSAndroid Build Coastguard Worker 				if (pst->ppos + 3u >= sizeof(ctx->path))
505*1c60b9acSAndroid Build Coastguard Worker 					goto reject_overflow;
506*1c60b9acSAndroid Build Coastguard Worker 
507*1c60b9acSAndroid Build Coastguard Worker 				st->p = pst->ppos;
508*1c60b9acSAndroid Build Coastguard Worker 				ctx->path[pst->ppos++] = '[';
509*1c60b9acSAndroid Build Coastguard Worker 				ctx->path[pst->ppos++] = ']';
510*1c60b9acSAndroid Build Coastguard Worker 				ctx->path[pst->ppos] = '\0';
511*1c60b9acSAndroid Build Coastguard Worker 
512*1c60b9acSAndroid Build Coastguard Worker 				lecp_check_path_match(ctx);
513*1c60b9acSAndroid Build Coastguard Worker 
514*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->ipos + 1u >= LWS_ARRAY_SIZE(ctx->i))
515*1c60b9acSAndroid Build Coastguard Worker 					goto reject_overflow;
516*1c60b9acSAndroid Build Coastguard Worker 
517*1c60b9acSAndroid Build Coastguard Worker 				ctx->i[ctx->ipos++] = 0;
518*1c60b9acSAndroid Build Coastguard Worker 
519*1c60b9acSAndroid Build Coastguard Worker 				if (pst->cb(ctx, LECPCB_ARRAY_START))
520*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
521*1c60b9acSAndroid Build Coastguard Worker 
522*1c60b9acSAndroid Build Coastguard Worker 				if (!sm) {
523*1c60b9acSAndroid Build Coastguard Worker 					if (pst->cb(ctx, LECPCB_ARRAY_END))
524*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
525*1c60b9acSAndroid Build Coastguard Worker 					pst->ppos = st->p;
526*1c60b9acSAndroid Build Coastguard Worker 					ctx->path[pst->ppos] = '\0';
527*1c60b9acSAndroid Build Coastguard Worker 					ctx->ipos--;
528*1c60b9acSAndroid Build Coastguard Worker 					lecp_check_path_match(ctx);
529*1c60b9acSAndroid Build Coastguard Worker 					lwcp_completed(ctx, 0);
530*1c60b9acSAndroid Build Coastguard Worker 					break;
531*1c60b9acSAndroid Build Coastguard Worker 				}
532*1c60b9acSAndroid Build Coastguard Worker 
533*1c60b9acSAndroid Build Coastguard Worker 				ctx->st[ctx->sp].send_new_array_item = 1;
534*1c60b9acSAndroid Build Coastguard Worker 
535*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_1) {
536*1c60b9acSAndroid Build Coastguard Worker 					st->indet = 0;
537*1c60b9acSAndroid Build Coastguard Worker 					st->collect_rem = sm;
538*1c60b9acSAndroid Build Coastguard Worker 					goto push_a;
539*1c60b9acSAndroid Build Coastguard Worker 				}
540*1c60b9acSAndroid Build Coastguard Worker 
541*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_RESERVED)
542*1c60b9acSAndroid Build Coastguard Worker 					goto i2;
543*1c60b9acSAndroid Build Coastguard Worker 
544*1c60b9acSAndroid Build Coastguard Worker 				if (sm != LWS_CBOR_INDETERMINITE)
545*1c60b9acSAndroid Build Coastguard Worker 					goto bad_coding;
546*1c60b9acSAndroid Build Coastguard Worker 
547*1c60b9acSAndroid Build Coastguard Worker 				st->indet = 1;
548*1c60b9acSAndroid Build Coastguard Worker push_a:
549*1c60b9acSAndroid Build Coastguard Worker 				lecp_push(ctx, 0, LECPCB_ARRAY_END, LECP_OPC);
550*1c60b9acSAndroid Build Coastguard Worker 				break;
551*1c60b9acSAndroid Build Coastguard Worker 
552*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_MAP:
553*1c60b9acSAndroid Build Coastguard Worker 				ctx->npos = 0;
554*1c60b9acSAndroid Build Coastguard Worker 				ctx->buf[0] = '\0';
555*1c60b9acSAndroid Build Coastguard Worker 
556*1c60b9acSAndroid Build Coastguard Worker 				if (pst->ppos + 1u >= sizeof(ctx->path))
557*1c60b9acSAndroid Build Coastguard Worker 					goto reject_overflow;
558*1c60b9acSAndroid Build Coastguard Worker 
559*1c60b9acSAndroid Build Coastguard Worker 				st->p = pst->ppos;
560*1c60b9acSAndroid Build Coastguard Worker 				ctx->path[pst->ppos++] = '.';
561*1c60b9acSAndroid Build Coastguard Worker 				ctx->path[pst->ppos] = '\0';
562*1c60b9acSAndroid Build Coastguard Worker 
563*1c60b9acSAndroid Build Coastguard Worker 				lecp_check_path_match(ctx);
564*1c60b9acSAndroid Build Coastguard Worker 
565*1c60b9acSAndroid Build Coastguard Worker 				if (pst->cb(ctx, LECPCB_OBJECT_START))
566*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
567*1c60b9acSAndroid Build Coastguard Worker 
568*1c60b9acSAndroid Build Coastguard Worker 				if (!sm) {
569*1c60b9acSAndroid Build Coastguard Worker 					if (pst->cb(ctx, LECPCB_OBJECT_END))
570*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
571*1c60b9acSAndroid Build Coastguard Worker 					pst->ppos = st->p;
572*1c60b9acSAndroid Build Coastguard Worker 					ctx->path[pst->ppos] = '\0';
573*1c60b9acSAndroid Build Coastguard Worker 					lecp_check_path_match(ctx);
574*1c60b9acSAndroid Build Coastguard Worker 					lwcp_completed(ctx, 0);
575*1c60b9acSAndroid Build Coastguard Worker 					break;
576*1c60b9acSAndroid Build Coastguard Worker 				}
577*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_1) {
578*1c60b9acSAndroid Build Coastguard Worker 					st->indet = 0;
579*1c60b9acSAndroid Build Coastguard Worker 					st->collect_rem = (uint64_t)(sm * 2);
580*1c60b9acSAndroid Build Coastguard Worker 					goto push_m;
581*1c60b9acSAndroid Build Coastguard Worker 				}
582*1c60b9acSAndroid Build Coastguard Worker 
583*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_RESERVED)
584*1c60b9acSAndroid Build Coastguard Worker 					goto i2;
585*1c60b9acSAndroid Build Coastguard Worker 
586*1c60b9acSAndroid Build Coastguard Worker 				if (sm != LWS_CBOR_INDETERMINITE)
587*1c60b9acSAndroid Build Coastguard Worker 					goto bad_coding;
588*1c60b9acSAndroid Build Coastguard Worker 
589*1c60b9acSAndroid Build Coastguard Worker 				st->indet = 1;
590*1c60b9acSAndroid Build Coastguard Worker push_m:
591*1c60b9acSAndroid Build Coastguard Worker 				lecp_push(ctx, 0, LECPCB_OBJECT_END, LECP_OPC);
592*1c60b9acSAndroid Build Coastguard Worker 				break;
593*1c60b9acSAndroid Build Coastguard Worker 
594*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_TAG:
595*1c60b9acSAndroid Build Coastguard Worker 				/* tag has one or another kind of int first */
596*1c60b9acSAndroid Build Coastguard Worker 				if (sm < LWS_CBOR_1) {
597*1c60b9acSAndroid Build Coastguard Worker 					/*
598*1c60b9acSAndroid Build Coastguard Worker 					 * We have a literal tag number, push
599*1c60b9acSAndroid Build Coastguard Worker 					 * to decode the tag body
600*1c60b9acSAndroid Build Coastguard Worker 					 */
601*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = st->tag = (uint64_t)sm;
602*1c60b9acSAndroid Build Coastguard Worker 					goto start_tag_enclosure;
603*1c60b9acSAndroid Build Coastguard Worker 				}
604*1c60b9acSAndroid Build Coastguard Worker 				/*
605*1c60b9acSAndroid Build Coastguard Worker 				 * We have to do more stuff to get the tag
606*1c60b9acSAndroid Build Coastguard Worker 				 * number...
607*1c60b9acSAndroid Build Coastguard Worker 				 */
608*1c60b9acSAndroid Build Coastguard Worker 				goto i2;
609*1c60b9acSAndroid Build Coastguard Worker 
610*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_FLOAT:
611*1c60b9acSAndroid Build Coastguard Worker 				/*
612*1c60b9acSAndroid Build Coastguard Worker 				 * This can also be a bunch of specials as well
613*1c60b9acSAndroid Build Coastguard Worker 				 * as sizes of float...
614*1c60b9acSAndroid Build Coastguard Worker 				 */
615*1c60b9acSAndroid Build Coastguard Worker 				sm = c & LWS_CBOR_SUBMASK;
616*1c60b9acSAndroid Build Coastguard Worker 
617*1c60b9acSAndroid Build Coastguard Worker 				switch (sm) {
618*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_SWK_FALSE:
619*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_FALSE;
620*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
621*1c60b9acSAndroid Build Coastguard Worker 
622*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_SWK_TRUE:
623*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_TRUE;
624*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
625*1c60b9acSAndroid Build Coastguard Worker 
626*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_SWK_NULL:
627*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_NULL;
628*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
629*1c60b9acSAndroid Build Coastguard Worker 
630*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_SWK_UNDEFINED:
631*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_UNDEFINED;
632*1c60b9acSAndroid Build Coastguard Worker 					goto issue;
633*1c60b9acSAndroid Build Coastguard Worker 
634*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_M7_SUBTYP_SIMPLE_X8:
635*1c60b9acSAndroid Build Coastguard Worker 					st->s = LECP_SIMPLEX8;
636*1c60b9acSAndroid Build Coastguard Worker 					break;
637*1c60b9acSAndroid Build Coastguard Worker 
638*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_M7_SUBTYP_FLOAT16:
639*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_FLOAT16;
640*1c60b9acSAndroid Build Coastguard Worker 					ex(ctx, &ctx->item.u.hf, 2);
641*1c60b9acSAndroid Build Coastguard Worker 					break;
642*1c60b9acSAndroid Build Coastguard Worker 
643*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_M7_SUBTYP_FLOAT32:
644*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_FLOAT32;
645*1c60b9acSAndroid Build Coastguard Worker 					ex(ctx, &ctx->item.u.f, 4);
646*1c60b9acSAndroid Build Coastguard Worker 					break;
647*1c60b9acSAndroid Build Coastguard Worker 
648*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_M7_SUBTYP_FLOAT64:
649*1c60b9acSAndroid Build Coastguard Worker 					ctx->present = LECPCB_VAL_FLOAT64;
650*1c60b9acSAndroid Build Coastguard Worker 					ex(ctx, &ctx->item.u.d, 8);
651*1c60b9acSAndroid Build Coastguard Worker 					break;
652*1c60b9acSAndroid Build Coastguard Worker 
653*1c60b9acSAndroid Build Coastguard Worker 				case LWS_CBOR_M7_BREAK:
654*1c60b9acSAndroid Build Coastguard Worker 					if (!ctx->sp ||
655*1c60b9acSAndroid Build Coastguard Worker 					    !ctx->st[ctx->sp - 1].indet)
656*1c60b9acSAndroid Build Coastguard Worker 						goto bad_coding;
657*1c60b9acSAndroid Build Coastguard Worker 
658*1c60b9acSAndroid Build Coastguard Worker 					lwcp_completed(ctx, 1);
659*1c60b9acSAndroid Build Coastguard Worker 					break;
660*1c60b9acSAndroid Build Coastguard Worker 
661*1c60b9acSAndroid Build Coastguard Worker 				default:
662*1c60b9acSAndroid Build Coastguard Worker 					/* handle as simple */
663*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = (uint64_t)sm;
664*1c60b9acSAndroid Build Coastguard Worker 					if (pst->cb(ctx, LECPCB_VAL_SIMPLE))
665*1c60b9acSAndroid Build Coastguard Worker 						goto reject_callback;
666*1c60b9acSAndroid Build Coastguard Worker 					break;
667*1c60b9acSAndroid Build Coastguard Worker 				}
668*1c60b9acSAndroid Build Coastguard Worker 				break;
669*1c60b9acSAndroid Build Coastguard Worker 			}
670*1c60b9acSAndroid Build Coastguard Worker 			break;
671*1c60b9acSAndroid Build Coastguard Worker 
672*1c60b9acSAndroid Build Coastguard Worker 		/*
673*1c60b9acSAndroid Build Coastguard Worker 		 * We're collecting int / float pieces
674*1c60b9acSAndroid Build Coastguard Worker 		 */
675*1c60b9acSAndroid Build Coastguard Worker 		case LECP_COLLECT:
676*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->be)
677*1c60b9acSAndroid Build Coastguard Worker 				*ctx->collect_tgt++ = c;
678*1c60b9acSAndroid Build Coastguard Worker 			else
679*1c60b9acSAndroid Build Coastguard Worker 				*ctx->collect_tgt-- = c;
680*1c60b9acSAndroid Build Coastguard Worker 
681*1c60b9acSAndroid Build Coastguard Worker 			if (--st->collect_rem)
682*1c60b9acSAndroid Build Coastguard Worker 				break;
683*1c60b9acSAndroid Build Coastguard Worker 
684*1c60b9acSAndroid Build Coastguard Worker 			/*
685*1c60b9acSAndroid Build Coastguard Worker 			 * We collected whatever it was...
686*1c60b9acSAndroid Build Coastguard Worker 			 */
687*1c60b9acSAndroid Build Coastguard Worker 
688*1c60b9acSAndroid Build Coastguard Worker 			ctx->npos = 0;
689*1c60b9acSAndroid Build Coastguard Worker 			ctx->buf[0] = '\0';
690*1c60b9acSAndroid Build Coastguard Worker 
691*1c60b9acSAndroid Build Coastguard Worker 			switch (st->opcode) {
692*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_BSTR:
693*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_TSTR:
694*1c60b9acSAndroid Build Coastguard Worker 				st->collect_rem = ctx->item.u.u64;
695*1c60b9acSAndroid Build Coastguard Worker 				if ((!ctx->sp || (ctx->sp &&
696*1c60b9acSAndroid Build Coastguard Worker 				    !ctx->st[ctx->sp - 1].intermediate)) &&
697*1c60b9acSAndroid Build Coastguard Worker 				    pst->cb(ctx, (char)((st->opcode ==
698*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_TSTR) ?
699*1c60b9acSAndroid Build Coastguard Worker 							LECPCB_VAL_STR_START :
700*1c60b9acSAndroid Build Coastguard Worker 							LECPCB_VAL_BLOB_START)))
701*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
702*1c60b9acSAndroid Build Coastguard Worker 				st->s = LECP_COLLATE;
703*1c60b9acSAndroid Build Coastguard Worker 				break;
704*1c60b9acSAndroid Build Coastguard Worker 
705*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_ARRAY:
706*1c60b9acSAndroid Build Coastguard Worker 				st->collect_rem = ctx->item.u.u64;
707*1c60b9acSAndroid Build Coastguard Worker 				lecp_push(ctx, 0, LECPCB_ARRAY_END, LECP_OPC);
708*1c60b9acSAndroid Build Coastguard Worker 				break;
709*1c60b9acSAndroid Build Coastguard Worker 
710*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_MAP:
711*1c60b9acSAndroid Build Coastguard Worker 				st->collect_rem = ctx->item.u.u64 * 2;
712*1c60b9acSAndroid Build Coastguard Worker 				lecp_push(ctx, 0, LECPCB_OBJECT_END, LECP_OPC);
713*1c60b9acSAndroid Build Coastguard Worker 				break;
714*1c60b9acSAndroid Build Coastguard Worker 
715*1c60b9acSAndroid Build Coastguard Worker 			case LWS_CBOR_MAJTYP_TAG:
716*1c60b9acSAndroid Build Coastguard Worker 				st->tag = ctx->item.u.u64;
717*1c60b9acSAndroid Build Coastguard Worker 				goto start_tag_enclosure;
718*1c60b9acSAndroid Build Coastguard Worker 
719*1c60b9acSAndroid Build Coastguard Worker 			default:
720*1c60b9acSAndroid Build Coastguard Worker 				/*
721*1c60b9acSAndroid Build Coastguard Worker 				 * ... then issue what we collected as a
722*1c60b9acSAndroid Build Coastguard Worker 				 * literal
723*1c60b9acSAndroid Build Coastguard Worker 				 */
724*1c60b9acSAndroid Build Coastguard Worker 
725*1c60b9acSAndroid Build Coastguard Worker 				if (st->opcode == LWS_CBOR_MAJTYP_INT_NEG)
726*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.i64 = (-1ll) - ctx->item.u.i64;
727*1c60b9acSAndroid Build Coastguard Worker 
728*1c60b9acSAndroid Build Coastguard Worker 				goto issue;
729*1c60b9acSAndroid Build Coastguard Worker 			}
730*1c60b9acSAndroid Build Coastguard Worker 			break;
731*1c60b9acSAndroid Build Coastguard Worker 
732*1c60b9acSAndroid Build Coastguard Worker 		case LECP_SIMPLEX8:
733*1c60b9acSAndroid Build Coastguard Worker 			/*
734*1c60b9acSAndroid Build Coastguard Worker 			 * Extended SIMPLE byte for 7|24 opcode, no uses
735*1c60b9acSAndroid Build Coastguard Worker 			 * for it in RFC8949
736*1c60b9acSAndroid Build Coastguard Worker 			 */
737*1c60b9acSAndroid Build Coastguard Worker 			if (c <= LWS_CBOR_INDETERMINITE)
738*1c60b9acSAndroid Build Coastguard Worker 				/*
739*1c60b9acSAndroid Build Coastguard Worker 				 * Duplication of implicit simple values is
740*1c60b9acSAndroid Build Coastguard Worker 				 * denied by RFC8949 3.3
741*1c60b9acSAndroid Build Coastguard Worker 				 */
742*1c60b9acSAndroid Build Coastguard Worker 				goto bad_coding;
743*1c60b9acSAndroid Build Coastguard Worker 
744*1c60b9acSAndroid Build Coastguard Worker 			ctx->item.u.u64 = (uint64_t)c;
745*1c60b9acSAndroid Build Coastguard Worker 			if (pst->cb(ctx, LECPCB_VAL_SIMPLE))
746*1c60b9acSAndroid Build Coastguard Worker 				goto reject_callback;
747*1c60b9acSAndroid Build Coastguard Worker 
748*1c60b9acSAndroid Build Coastguard Worker 			lwcp_completed(ctx, 0);
749*1c60b9acSAndroid Build Coastguard Worker 			break;
750*1c60b9acSAndroid Build Coastguard Worker 
751*1c60b9acSAndroid Build Coastguard Worker 		case LECP_COLLATE:
752*1c60b9acSAndroid Build Coastguard Worker 			/*
753*1c60b9acSAndroid Build Coastguard Worker 			 * let's grab b/t string content into the context
754*1c60b9acSAndroid Build Coastguard Worker 			 * buffer, and issue chunks from there
755*1c60b9acSAndroid Build Coastguard Worker 			 */
756*1c60b9acSAndroid Build Coastguard Worker 
757*1c60b9acSAndroid Build Coastguard Worker 			ctx->buf[ctx->npos++] = (char)c;
758*1c60b9acSAndroid Build Coastguard Worker 			if (st->collect_rem)
759*1c60b9acSAndroid Build Coastguard Worker 				st->collect_rem--;
760*1c60b9acSAndroid Build Coastguard Worker 
761*1c60b9acSAndroid Build Coastguard Worker 			/* spill at chunk boundaries, or if we filled the buf */
762*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->npos != sizeof(ctx->buf) - 1 &&
763*1c60b9acSAndroid Build Coastguard Worker 			    st->collect_rem)
764*1c60b9acSAndroid Build Coastguard Worker 				break;
765*1c60b9acSAndroid Build Coastguard Worker 
766*1c60b9acSAndroid Build Coastguard Worker 			/* spill */
767*1c60b9acSAndroid Build Coastguard Worker 			ctx->buf[ctx->npos] = '\0';
768*1c60b9acSAndroid Build Coastguard Worker 
769*1c60b9acSAndroid Build Coastguard Worker 			/* if it's a map name, deal with the path */
770*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->sp && lecp_parse_map_is_key(ctx)) {
771*1c60b9acSAndroid Build Coastguard Worker 				if (lwcp_st_parent(ctx)->ordinal)
772*1c60b9acSAndroid Build Coastguard Worker 					pst->ppos = st->p;
773*1c60b9acSAndroid Build Coastguard Worker 				st->p = pst->ppos;
774*1c60b9acSAndroid Build Coastguard Worker 				if (pst->ppos + ctx->npos > sizeof(ctx->path))
775*1c60b9acSAndroid Build Coastguard Worker 					goto reject_overflow;
776*1c60b9acSAndroid Build Coastguard Worker 				memcpy(&ctx->path[pst->ppos], ctx->buf,
777*1c60b9acSAndroid Build Coastguard Worker 				       (size_t)(ctx->npos + 1));
778*1c60b9acSAndroid Build Coastguard Worker 				pst->ppos = (uint8_t)(pst->ppos + ctx->npos);
779*1c60b9acSAndroid Build Coastguard Worker 				lecp_check_path_match(ctx);
780*1c60b9acSAndroid Build Coastguard Worker 			}
781*1c60b9acSAndroid Build Coastguard Worker 
782*1c60b9acSAndroid Build Coastguard Worker 			to = 0;
783*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->item.opcode == LWS_CBOR_MAJTYP_BSTR)
784*1c60b9acSAndroid Build Coastguard Worker 				to = LECPCB_VAL_BLOB_END - LECPCB_VAL_STR_END;
785*1c60b9acSAndroid Build Coastguard Worker 
786*1c60b9acSAndroid Build Coastguard Worker 			o = (uint8_t)(LECPCB_VAL_STR_END + to);
787*1c60b9acSAndroid Build Coastguard Worker 			c = (st->collect_rem /* more to come at this layer */ ||
788*1c60b9acSAndroid Build Coastguard Worker 			    /* we or direct parent is indeterminite */
789*1c60b9acSAndroid Build Coastguard Worker 			    lwcp_is_indet_string(ctx));
790*1c60b9acSAndroid Build Coastguard Worker 
791*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->sp)
792*1c60b9acSAndroid Build Coastguard Worker 				ctx->st[ctx->sp - 1].intermediate = !!c;
793*1c60b9acSAndroid Build Coastguard Worker 			if (c)
794*1c60b9acSAndroid Build Coastguard Worker 				o--;
795*1c60b9acSAndroid Build Coastguard Worker 
796*1c60b9acSAndroid Build Coastguard Worker 			if (pst->cb(ctx, (char)o))
797*1c60b9acSAndroid Build Coastguard Worker 				goto reject_callback;
798*1c60b9acSAndroid Build Coastguard Worker 			ctx->npos = 0;
799*1c60b9acSAndroid Build Coastguard Worker 			ctx->buf[0] = '\0';
800*1c60b9acSAndroid Build Coastguard Worker 
801*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->sp && lwcp_st_parent(ctx)->indet)
802*1c60b9acSAndroid Build Coastguard Worker 				st->s = LECP_OPC;
803*1c60b9acSAndroid Build Coastguard Worker 			if (o == LECPCB_VAL_STR_END + to)
804*1c60b9acSAndroid Build Coastguard Worker 				lwcp_completed(ctx, 0);
805*1c60b9acSAndroid Build Coastguard Worker 
806*1c60b9acSAndroid Build Coastguard Worker 			break;
807*1c60b9acSAndroid Build Coastguard Worker 
808*1c60b9acSAndroid Build Coastguard Worker 		case LECP_ONLY_SAME:
809*1c60b9acSAndroid Build Coastguard Worker 			/*
810*1c60b9acSAndroid Build Coastguard Worker 			 * deterministic sized chunks same MAJTYP as parent
811*1c60b9acSAndroid Build Coastguard Worker 			 * level only (BSTR and TSTR frags inside interderminite
812*1c60b9acSAndroid Build Coastguard Worker 			 * BSTR or TSTR)
813*1c60b9acSAndroid Build Coastguard Worker 			 *
814*1c60b9acSAndroid Build Coastguard Worker 			 * Clean end when we see M7|31
815*1c60b9acSAndroid Build Coastguard Worker 			 */
816*1c60b9acSAndroid Build Coastguard Worker 			if (!ctx->sp) {
817*1c60b9acSAndroid Build Coastguard Worker 				/*
818*1c60b9acSAndroid Build Coastguard Worker 				 * We should only come here by pushing on stack
819*1c60b9acSAndroid Build Coastguard Worker 				 */
820*1c60b9acSAndroid Build Coastguard Worker 				assert(0);
821*1c60b9acSAndroid Build Coastguard Worker 				return LECP_STACK_OVERFLOW;
822*1c60b9acSAndroid Build Coastguard Worker 			}
823*1c60b9acSAndroid Build Coastguard Worker 
824*1c60b9acSAndroid Build Coastguard Worker 			if (c == (LWS_CBOR_MAJTYP_FLOAT | LWS_CBOR_M7_BREAK)) {
825*1c60b9acSAndroid Build Coastguard Worker 				/* if's the end of an interdetminite list */
826*1c60b9acSAndroid Build Coastguard Worker 				if (!ctx->sp || !ctx->st[ctx->sp - 1].indet)
827*1c60b9acSAndroid Build Coastguard Worker 					/*
828*1c60b9acSAndroid Build Coastguard Worker 					 * Can't have a break without an
829*1c60b9acSAndroid Build Coastguard Worker 					 * indeterminite parent
830*1c60b9acSAndroid Build Coastguard Worker 					 */
831*1c60b9acSAndroid Build Coastguard Worker 					goto bad_coding;
832*1c60b9acSAndroid Build Coastguard Worker 
833*1c60b9acSAndroid Build Coastguard Worker 				if (lwcp_completed(ctx, 1))
834*1c60b9acSAndroid Build Coastguard Worker 					goto reject_callback;
835*1c60b9acSAndroid Build Coastguard Worker 				break;
836*1c60b9acSAndroid Build Coastguard Worker 			}
837*1c60b9acSAndroid Build Coastguard Worker 
838*1c60b9acSAndroid Build Coastguard Worker 			if (st->opcode != lwcp_st_parent(ctx)->opcode)
839*1c60b9acSAndroid Build Coastguard Worker 				/*
840*1c60b9acSAndroid Build Coastguard Worker 				 * Fragments have to be of the same type as the
841*1c60b9acSAndroid Build Coastguard Worker 				 * outer opcode
842*1c60b9acSAndroid Build Coastguard Worker 				 */
843*1c60b9acSAndroid Build Coastguard Worker 				goto bad_coding;
844*1c60b9acSAndroid Build Coastguard Worker 
845*1c60b9acSAndroid Build Coastguard Worker 			sm = c & LWS_CBOR_SUBMASK;
846*1c60b9acSAndroid Build Coastguard Worker 
847*1c60b9acSAndroid Build Coastguard Worker 			if (sm == LWS_CBOR_INDETERMINITE)
848*1c60b9acSAndroid Build Coastguard Worker 				/* indeterminite length frags not allowed */
849*1c60b9acSAndroid Build Coastguard Worker 				goto bad_coding;
850*1c60b9acSAndroid Build Coastguard Worker 
851*1c60b9acSAndroid Build Coastguard Worker 			if (sm < LWS_CBOR_1) {
852*1c60b9acSAndroid Build Coastguard Worker 				st->indet = 0;
853*1c60b9acSAndroid Build Coastguard Worker 				st->collect_rem = (uint64_t)sm;
854*1c60b9acSAndroid Build Coastguard Worker 				st->s = LECP_COLLATE;
855*1c60b9acSAndroid Build Coastguard Worker 				break;
856*1c60b9acSAndroid Build Coastguard Worker 			}
857*1c60b9acSAndroid Build Coastguard Worker 
858*1c60b9acSAndroid Build Coastguard Worker 			if (sm >= LWS_CBOR_RESERVED)
859*1c60b9acSAndroid Build Coastguard Worker 				goto bad_coding;
860*1c60b9acSAndroid Build Coastguard Worker 
861*1c60b9acSAndroid Build Coastguard Worker 			goto i2;
862*1c60b9acSAndroid Build Coastguard Worker 
863*1c60b9acSAndroid Build Coastguard Worker 		default:
864*1c60b9acSAndroid Build Coastguard Worker 			assert(0);
865*1c60b9acSAndroid Build Coastguard Worker 			return -1;
866*1c60b9acSAndroid Build Coastguard Worker 		}
867*1c60b9acSAndroid Build Coastguard Worker 
868*1c60b9acSAndroid Build Coastguard Worker 		continue;
869*1c60b9acSAndroid Build Coastguard Worker 
870*1c60b9acSAndroid Build Coastguard Worker start_tag_enclosure:
871*1c60b9acSAndroid Build Coastguard Worker 		st->p = pst->ppos;
872*1c60b9acSAndroid Build Coastguard Worker 		ret = lecp_push(ctx, LECPCB_TAG_START, LECPCB_TAG_END, LECP_OPC);
873*1c60b9acSAndroid Build Coastguard Worker 		if (ret)
874*1c60b9acSAndroid Build Coastguard Worker 			return ret;
875*1c60b9acSAndroid Build Coastguard Worker 
876*1c60b9acSAndroid Build Coastguard Worker 		continue;
877*1c60b9acSAndroid Build Coastguard Worker 
878*1c60b9acSAndroid Build Coastguard Worker issue:
879*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->item.opcode == LWS_CBOR_MAJTYP_TAG) {
880*1c60b9acSAndroid Build Coastguard Worker 			st->tag = ctx->item.u.u64;
881*1c60b9acSAndroid Build Coastguard Worker 			goto start_tag_enclosure;
882*1c60b9acSAndroid Build Coastguard Worker 		}
883*1c60b9acSAndroid Build Coastguard Worker 
884*1c60b9acSAndroid Build Coastguard Worker 		/* we are just a number */
885*1c60b9acSAndroid Build Coastguard Worker 
886*1c60b9acSAndroid Build Coastguard Worker 		if (pst->cb(ctx, ctx->present))
887*1c60b9acSAndroid Build Coastguard Worker 			goto reject_callback;
888*1c60b9acSAndroid Build Coastguard Worker 
889*1c60b9acSAndroid Build Coastguard Worker 		lwcp_completed(ctx, 0);
890*1c60b9acSAndroid Build Coastguard Worker 
891*1c60b9acSAndroid Build Coastguard Worker 	}
892*1c60b9acSAndroid Build Coastguard Worker 
893*1c60b9acSAndroid Build Coastguard Worker 	ctx->used_in = olen - len;
894*1c60b9acSAndroid Build Coastguard Worker 
895*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->sp && ctx->st[0].s == LECP_OPC)
896*1c60b9acSAndroid Build Coastguard Worker 		return 0;
897*1c60b9acSAndroid Build Coastguard Worker 
898*1c60b9acSAndroid Build Coastguard Worker 	return LECP_CONTINUE;
899*1c60b9acSAndroid Build Coastguard Worker 
900*1c60b9acSAndroid Build Coastguard Worker reject_overflow:
901*1c60b9acSAndroid Build Coastguard Worker 	ret = LECP_STACK_OVERFLOW;
902*1c60b9acSAndroid Build Coastguard Worker 	goto reject;
903*1c60b9acSAndroid Build Coastguard Worker 
904*1c60b9acSAndroid Build Coastguard Worker bad_coding:
905*1c60b9acSAndroid Build Coastguard Worker 	ret = LECP_REJECT_BAD_CODING;
906*1c60b9acSAndroid Build Coastguard Worker 	goto reject;
907*1c60b9acSAndroid Build Coastguard Worker 
908*1c60b9acSAndroid Build Coastguard Worker reject_callback:
909*1c60b9acSAndroid Build Coastguard Worker 	ret = LECP_REJECT_CALLBACK;
910*1c60b9acSAndroid Build Coastguard Worker 
911*1c60b9acSAndroid Build Coastguard Worker reject:
912*1c60b9acSAndroid Build Coastguard Worker 	ctx->pst[ctx->pst_sp].cb(ctx, LECPCB_FAILED);
913*1c60b9acSAndroid Build Coastguard Worker 
914*1c60b9acSAndroid Build Coastguard Worker 	return ret;
915*1c60b9acSAndroid Build Coastguard Worker }
916*1c60b9acSAndroid Build Coastguard Worker 
917*1c60b9acSAndroid Build Coastguard Worker 
918*1c60b9acSAndroid Build Coastguard Worker 
919*1c60b9acSAndroid Build Coastguard Worker void
lws_lec_init(lws_lec_pctx_t * ctx,uint8_t * buf,size_t len)920*1c60b9acSAndroid Build Coastguard Worker lws_lec_init(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len)
921*1c60b9acSAndroid Build Coastguard Worker {
922*1c60b9acSAndroid Build Coastguard Worker 	memset(ctx, 0, sizeof(*ctx));
923*1c60b9acSAndroid Build Coastguard Worker 	ctx->start = ctx->buf = buf;
924*1c60b9acSAndroid Build Coastguard Worker 	ctx->end = ctx->start + len;
925*1c60b9acSAndroid Build Coastguard Worker 	ctx->fmt_pos = 0;
926*1c60b9acSAndroid Build Coastguard Worker }
927*1c60b9acSAndroid Build Coastguard Worker 
928*1c60b9acSAndroid Build Coastguard Worker void
lws_lec_setbuf(lws_lec_pctx_t * ctx,uint8_t * buf,size_t len)929*1c60b9acSAndroid Build Coastguard Worker lws_lec_setbuf(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len)
930*1c60b9acSAndroid Build Coastguard Worker {
931*1c60b9acSAndroid Build Coastguard Worker 	ctx->start = ctx->buf = buf;
932*1c60b9acSAndroid Build Coastguard Worker 	ctx->end = ctx->start + len;
933*1c60b9acSAndroid Build Coastguard Worker 	ctx->used = 0;
934*1c60b9acSAndroid Build Coastguard Worker 	ctx->vaa_pos = 0;
935*1c60b9acSAndroid Build Coastguard Worker }
936*1c60b9acSAndroid Build Coastguard Worker 
937*1c60b9acSAndroid Build Coastguard Worker enum lws_lec_pctx_ret
lws_lec_printf(lws_lec_pctx_t * ctx,const char * format,...)938*1c60b9acSAndroid Build Coastguard Worker lws_lec_printf(lws_lec_pctx_t *ctx, const char *format, ...)
939*1c60b9acSAndroid Build Coastguard Worker {
940*1c60b9acSAndroid Build Coastguard Worker 	enum lws_lec_pctx_ret r;
941*1c60b9acSAndroid Build Coastguard Worker 	va_list ap;
942*1c60b9acSAndroid Build Coastguard Worker 
943*1c60b9acSAndroid Build Coastguard Worker 	va_start(ap, format);
944*1c60b9acSAndroid Build Coastguard Worker 	r = lws_lec_vsprintf(ctx, format, ap);
945*1c60b9acSAndroid Build Coastguard Worker 	va_end(ap);
946*1c60b9acSAndroid Build Coastguard Worker 
947*1c60b9acSAndroid Build Coastguard Worker 	return r;
948*1c60b9acSAndroid Build Coastguard Worker }
949*1c60b9acSAndroid Build Coastguard Worker 
950*1c60b9acSAndroid Build Coastguard Worker /*
951*1c60b9acSAndroid Build Coastguard Worker  * Report how many next-level elements inbetween fmt[0] and the matching
952*1c60b9acSAndroid Build Coastguard Worker  * closure, eg, [] returns 0,  [123] would return 1, [123,456] returns 2, and
953*1c60b9acSAndroid Build Coastguard Worker  * [123,{'a':[123,456]}] returns 2.  Counts for { } maps are in pairs, ie,
954*1c60b9acSAndroid Build Coastguard Worker  * {'a':1, 'b': 2} returns 2
955*1c60b9acSAndroid Build Coastguard Worker  *
956*1c60b9acSAndroid Build Coastguard Worker  * If there is no closure in the string it returns -1
957*1c60b9acSAndroid Build Coastguard Worker  *
958*1c60b9acSAndroid Build Coastguard Worker  * We use this to figure out if we should use indeterminite lengths or specific
959*1c60b9acSAndroid Build Coastguard Worker  * lengths for items in the format string
960*1c60b9acSAndroid Build Coastguard Worker  */
961*1c60b9acSAndroid Build Coastguard Worker 
962*1c60b9acSAndroid Build Coastguard Worker #define bump(_r) count[sp]++
963*1c60b9acSAndroid Build Coastguard Worker //; lwsl_notice("%s: count[%d] -> %d\n", _r, sp, count[sp])
964*1c60b9acSAndroid Build Coastguard Worker 
965*1c60b9acSAndroid Build Coastguard Worker static int
format_scan(const char * fmt)966*1c60b9acSAndroid Build Coastguard Worker format_scan(const char *fmt)
967*1c60b9acSAndroid Build Coastguard Worker {
968*1c60b9acSAndroid Build Coastguard Worker 	char stack[12], literal = 0, numeric = 0;
969*1c60b9acSAndroid Build Coastguard Worker 	int count[12], sp = 0, pc = 0, swallow = 0;
970*1c60b9acSAndroid Build Coastguard Worker 
971*1c60b9acSAndroid Build Coastguard Worker 	literal = *fmt == '\'';
972*1c60b9acSAndroid Build Coastguard Worker 	stack[sp] = *fmt++;
973*1c60b9acSAndroid Build Coastguard Worker 	count[sp] = 0;
974*1c60b9acSAndroid Build Coastguard Worker 
975*1c60b9acSAndroid Build Coastguard Worker //	lwsl_notice("%s: start %s\n", __func__, fmt - 1);
976*1c60b9acSAndroid Build Coastguard Worker 
977*1c60b9acSAndroid Build Coastguard Worker 	while (*fmt) {
978*1c60b9acSAndroid Build Coastguard Worker 
979*1c60b9acSAndroid Build Coastguard Worker //		lwsl_notice("%s: %c %d %d\n", __func__, *fmt, sp, literal);
980*1c60b9acSAndroid Build Coastguard Worker 
981*1c60b9acSAndroid Build Coastguard Worker 		if (swallow) {
982*1c60b9acSAndroid Build Coastguard Worker 			swallow--;
983*1c60b9acSAndroid Build Coastguard Worker 			fmt++;
984*1c60b9acSAndroid Build Coastguard Worker 			continue;
985*1c60b9acSAndroid Build Coastguard Worker 		}
986*1c60b9acSAndroid Build Coastguard Worker 
987*1c60b9acSAndroid Build Coastguard Worker 		if (numeric) {
988*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt >= '0' && *fmt <= '9')
989*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
990*1c60b9acSAndroid Build Coastguard Worker 			numeric = 0;
991*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt != '(')
992*1c60b9acSAndroid Build Coastguard Worker 				bump("a");
993*1c60b9acSAndroid Build Coastguard Worker 		}
994*1c60b9acSAndroid Build Coastguard Worker 
995*1c60b9acSAndroid Build Coastguard Worker 		if (literal) {
996*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == '\\' && fmt[1]) {
997*1c60b9acSAndroid Build Coastguard Worker 				fmt += 2;
998*1c60b9acSAndroid Build Coastguard Worker 				continue;
999*1c60b9acSAndroid Build Coastguard Worker 			}
1000*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == '\'') {
1001*1c60b9acSAndroid Build Coastguard Worker 				literal = 0;
1002*1c60b9acSAndroid Build Coastguard Worker 				if (!sp && stack[sp] == '\'')
1003*1c60b9acSAndroid Build Coastguard Worker 					return count[sp];
1004*1c60b9acSAndroid Build Coastguard Worker 
1005*1c60b9acSAndroid Build Coastguard Worker 				if (sp)
1006*1c60b9acSAndroid Build Coastguard Worker 					sp--;
1007*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
1008*1c60b9acSAndroid Build Coastguard Worker 				continue;
1009*1c60b9acSAndroid Build Coastguard Worker 			}
1010*1c60b9acSAndroid Build Coastguard Worker 
1011*1c60b9acSAndroid Build Coastguard Worker 			bump("b");
1012*1c60b9acSAndroid Build Coastguard Worker 			fmt++;
1013*1c60b9acSAndroid Build Coastguard Worker 			continue;
1014*1c60b9acSAndroid Build Coastguard Worker 		}
1015*1c60b9acSAndroid Build Coastguard Worker 
1016*1c60b9acSAndroid Build Coastguard Worker 		if (*fmt == '\'') {
1017*1c60b9acSAndroid Build Coastguard Worker 			bump("c");
1018*1c60b9acSAndroid Build Coastguard Worker 			sp++;
1019*1c60b9acSAndroid Build Coastguard Worker 			literal = 1;
1020*1c60b9acSAndroid Build Coastguard Worker 			fmt++;
1021*1c60b9acSAndroid Build Coastguard Worker 			continue;
1022*1c60b9acSAndroid Build Coastguard Worker 		}
1023*1c60b9acSAndroid Build Coastguard Worker 
1024*1c60b9acSAndroid Build Coastguard Worker 		switch (pc) {
1025*1c60b9acSAndroid Build Coastguard Worker 		case 1:
1026*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == '.') {
1027*1c60b9acSAndroid Build Coastguard Worker 				pc++;
1028*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
1029*1c60b9acSAndroid Build Coastguard Worker 				continue;
1030*1c60b9acSAndroid Build Coastguard Worker 			}
1031*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == 'l') {
1032*1c60b9acSAndroid Build Coastguard Worker 				pc++;
1033*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
1034*1c60b9acSAndroid Build Coastguard Worker 				continue;
1035*1c60b9acSAndroid Build Coastguard Worker 			}
1036*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
1037*1c60b9acSAndroid Build Coastguard Worker 		case 2:
1038*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == '*') {
1039*1c60b9acSAndroid Build Coastguard Worker 				pc++;
1040*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
1041*1c60b9acSAndroid Build Coastguard Worker 				continue;
1042*1c60b9acSAndroid Build Coastguard Worker 			}
1043*1c60b9acSAndroid Build Coastguard Worker 			if (*fmt == 'l') {
1044*1c60b9acSAndroid Build Coastguard Worker 				pc++;
1045*1c60b9acSAndroid Build Coastguard Worker 				fmt++;
1046*1c60b9acSAndroid Build Coastguard Worker 				continue;
1047*1c60b9acSAndroid Build Coastguard Worker 			}
1048*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
1049*1c60b9acSAndroid Build Coastguard Worker 		case 3:
1050*1c60b9acSAndroid Build Coastguard Worker 			bump("pc");
1051*1c60b9acSAndroid Build Coastguard Worker 			pc = 0;
1052*1c60b9acSAndroid Build Coastguard Worker 			fmt++;
1053*1c60b9acSAndroid Build Coastguard Worker 			continue;
1054*1c60b9acSAndroid Build Coastguard Worker 		}
1055*1c60b9acSAndroid Build Coastguard Worker 
1056*1c60b9acSAndroid Build Coastguard Worker 		switch (*fmt) {
1057*1c60b9acSAndroid Build Coastguard Worker 
1058*1c60b9acSAndroid Build Coastguard Worker 		case '<':
1059*1c60b9acSAndroid Build Coastguard Worker 			swallow = 1;
1060*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
1061*1c60b9acSAndroid Build Coastguard Worker 		case '[':
1062*1c60b9acSAndroid Build Coastguard Worker 		case '(':
1063*1c60b9acSAndroid Build Coastguard Worker 		case '{':
1064*1c60b9acSAndroid Build Coastguard Worker 			if (sp == sizeof(stack))
1065*1c60b9acSAndroid Build Coastguard Worker 				return -2;
1066*1c60b9acSAndroid Build Coastguard Worker 
1067*1c60b9acSAndroid Build Coastguard Worker 			bump("d");
1068*1c60b9acSAndroid Build Coastguard Worker 			sp++;
1069*1c60b9acSAndroid Build Coastguard Worker 			stack[sp] = *fmt;
1070*1c60b9acSAndroid Build Coastguard Worker 			count[sp] = 0;
1071*1c60b9acSAndroid Build Coastguard Worker 			break;
1072*1c60b9acSAndroid Build Coastguard Worker 		case ' ':
1073*1c60b9acSAndroid Build Coastguard Worker 			break;
1074*1c60b9acSAndroid Build Coastguard Worker 		case ',':
1075*1c60b9acSAndroid Build Coastguard Worker 			//count[sp]++;
1076*1c60b9acSAndroid Build Coastguard Worker 			break;
1077*1c60b9acSAndroid Build Coastguard Worker 		case ':':
1078*1c60b9acSAndroid Build Coastguard Worker 			if (stack[sp] != '{')
1079*1c60b9acSAndroid Build Coastguard Worker 				goto mismatch;
1080*1c60b9acSAndroid Build Coastguard Worker 			//count[sp]++;
1081*1c60b9acSAndroid Build Coastguard Worker 			break;
1082*1c60b9acSAndroid Build Coastguard Worker 		case '%':
1083*1c60b9acSAndroid Build Coastguard Worker 			pc = 1;
1084*1c60b9acSAndroid Build Coastguard Worker 			break;
1085*1c60b9acSAndroid Build Coastguard Worker 		case ']':
1086*1c60b9acSAndroid Build Coastguard Worker 			if (stack[sp] != '[')
1087*1c60b9acSAndroid Build Coastguard Worker 				goto mismatch;
1088*1c60b9acSAndroid Build Coastguard Worker 			goto pop;
1089*1c60b9acSAndroid Build Coastguard Worker 		case ')':
1090*1c60b9acSAndroid Build Coastguard Worker 			if (stack[sp] != '(')
1091*1c60b9acSAndroid Build Coastguard Worker 				goto mismatch;
1092*1c60b9acSAndroid Build Coastguard Worker 			goto pop;
1093*1c60b9acSAndroid Build Coastguard Worker 		case '}':
1094*1c60b9acSAndroid Build Coastguard Worker 			if (stack[sp] != '{')
1095*1c60b9acSAndroid Build Coastguard Worker 				goto mismatch;
1096*1c60b9acSAndroid Build Coastguard Worker 			goto pop;
1097*1c60b9acSAndroid Build Coastguard Worker 		case '>':
1098*1c60b9acSAndroid Build Coastguard Worker 			if (stack[sp] != '<')
1099*1c60b9acSAndroid Build Coastguard Worker 				goto mismatch;
1100*1c60b9acSAndroid Build Coastguard Worker pop:
1101*1c60b9acSAndroid Build Coastguard Worker 			if (sp) {
1102*1c60b9acSAndroid Build Coastguard Worker 				sp--;
1103*1c60b9acSAndroid Build Coastguard Worker 				break;
1104*1c60b9acSAndroid Build Coastguard Worker 			}
1105*1c60b9acSAndroid Build Coastguard Worker 
1106*1c60b9acSAndroid Build Coastguard Worker 			if (stack[0] == '{') {
1107*1c60b9acSAndroid Build Coastguard Worker 				/* args have to come in pairs */
1108*1c60b9acSAndroid Build Coastguard Worker 				if (count[0] & 1) {
1109*1c60b9acSAndroid Build Coastguard Worker 					lwsl_err("%s: odd map args %d %s\n",
1110*1c60b9acSAndroid Build Coastguard Worker 							__func__, count[0], fmt);
1111*1c60b9acSAndroid Build Coastguard Worker 					return -2;
1112*1c60b9acSAndroid Build Coastguard Worker 				}
1113*1c60b9acSAndroid Build Coastguard Worker 				// lwsl_notice("%s: return %d pairs\n", __func__, count[0] >> 1);
1114*1c60b9acSAndroid Build Coastguard Worker 				/* report how many pairs */
1115*1c60b9acSAndroid Build Coastguard Worker 				return count[0] >> 1;
1116*1c60b9acSAndroid Build Coastguard Worker 			}
1117*1c60b9acSAndroid Build Coastguard Worker 
1118*1c60b9acSAndroid Build Coastguard Worker 			// lwsl_notice("%s: return %d items\n", __func__, count[0]);
1119*1c60b9acSAndroid Build Coastguard Worker 
1120*1c60b9acSAndroid Build Coastguard Worker 			return count[0];
1121*1c60b9acSAndroid Build Coastguard Worker 
1122*1c60b9acSAndroid Build Coastguard Worker 		case '0':
1123*1c60b9acSAndroid Build Coastguard Worker 		case '1':
1124*1c60b9acSAndroid Build Coastguard Worker 		case '2':
1125*1c60b9acSAndroid Build Coastguard Worker 		case '3':
1126*1c60b9acSAndroid Build Coastguard Worker 		case '4':
1127*1c60b9acSAndroid Build Coastguard Worker 		case '5':
1128*1c60b9acSAndroid Build Coastguard Worker 		case '6':
1129*1c60b9acSAndroid Build Coastguard Worker 		case '7':
1130*1c60b9acSAndroid Build Coastguard Worker 		case '8':
1131*1c60b9acSAndroid Build Coastguard Worker 		case '9':
1132*1c60b9acSAndroid Build Coastguard Worker 			numeric = 1;
1133*1c60b9acSAndroid Build Coastguard Worker 
1134*1c60b9acSAndroid Build Coastguard Worker 			break;
1135*1c60b9acSAndroid Build Coastguard Worker 
1136*1c60b9acSAndroid Build Coastguard Worker 		default:
1137*1c60b9acSAndroid Build Coastguard Worker 			bump("e");
1138*1c60b9acSAndroid Build Coastguard Worker 			break;
1139*1c60b9acSAndroid Build Coastguard Worker 		}
1140*1c60b9acSAndroid Build Coastguard Worker 		fmt++;
1141*1c60b9acSAndroid Build Coastguard Worker 	}
1142*1c60b9acSAndroid Build Coastguard Worker 
1143*1c60b9acSAndroid Build Coastguard Worker 	return -1;
1144*1c60b9acSAndroid Build Coastguard Worker 
1145*1c60b9acSAndroid Build Coastguard Worker mismatch:
1146*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("%s: format mismatch %c %c\n", __func__, stack[sp], *fmt);
1147*1c60b9acSAndroid Build Coastguard Worker 
1148*1c60b9acSAndroid Build Coastguard Worker 	return -2;
1149*1c60b9acSAndroid Build Coastguard Worker }
1150*1c60b9acSAndroid Build Coastguard Worker 
1151*1c60b9acSAndroid Build Coastguard Worker void
lws_lec_signed(lws_lec_pctx_t * ctx,int64_t num)1152*1c60b9acSAndroid Build Coastguard Worker lws_lec_signed(lws_lec_pctx_t *ctx, int64_t num)
1153*1c60b9acSAndroid Build Coastguard Worker {
1154*1c60b9acSAndroid Build Coastguard Worker 	if (num < 0)
1155*1c60b9acSAndroid Build Coastguard Worker 		lws_lec_int(ctx, LWS_CBOR_MAJTYP_INT_NEG, 0,
1156*1c60b9acSAndroid Build Coastguard Worker 					(uint64_t)(-1ll - num));
1157*1c60b9acSAndroid Build Coastguard Worker 	else
1158*1c60b9acSAndroid Build Coastguard Worker 		lws_lec_int(ctx, LWS_CBOR_MAJTYP_UINT, 0, (uint64_t)num);
1159*1c60b9acSAndroid Build Coastguard Worker }
1160*1c60b9acSAndroid Build Coastguard Worker 
1161*1c60b9acSAndroid Build Coastguard Worker void
lws_lec_int(lws_lec_pctx_t * ctx,uint8_t opcode,uint8_t indet,uint64_t num)1162*1c60b9acSAndroid Build Coastguard Worker lws_lec_int(lws_lec_pctx_t *ctx, uint8_t opcode, uint8_t indet, uint64_t num)
1163*1c60b9acSAndroid Build Coastguard Worker {
1164*1c60b9acSAndroid Build Coastguard Worker 	uint8_t hint = 0;
1165*1c60b9acSAndroid Build Coastguard Worker 	unsigned int n;
1166*1c60b9acSAndroid Build Coastguard Worker 
1167*1c60b9acSAndroid Build Coastguard Worker 	if (indet) {
1168*1c60b9acSAndroid Build Coastguard Worker 		ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode |
1169*1c60b9acSAndroid Build Coastguard Worker 							LWS_CBOR_INDETERMINITE);
1170*1c60b9acSAndroid Build Coastguard Worker 		return;
1171*1c60b9acSAndroid Build Coastguard Worker 	}
1172*1c60b9acSAndroid Build Coastguard Worker 
1173*1c60b9acSAndroid Build Coastguard Worker 	if ((opcode & LWS_CBOR_MAJTYP_MASK) == LWS_CBOR_MAJTYP_FLOAT) {
1174*1c60b9acSAndroid Build Coastguard Worker 		hint = opcode & LWS_CBOR_SUBMASK;
1175*1c60b9acSAndroid Build Coastguard Worker 		switch (hint) {
1176*1c60b9acSAndroid Build Coastguard Worker 		case LWS_CBOR_M7_SUBTYP_FLOAT16:
1177*1c60b9acSAndroid Build Coastguard Worker 			num <<= 48;
1178*1c60b9acSAndroid Build Coastguard Worker 			break;
1179*1c60b9acSAndroid Build Coastguard Worker 		case LWS_CBOR_M7_SUBTYP_FLOAT32:
1180*1c60b9acSAndroid Build Coastguard Worker 			num <<= 32;
1181*1c60b9acSAndroid Build Coastguard Worker 			break;
1182*1c60b9acSAndroid Build Coastguard Worker 		}
1183*1c60b9acSAndroid Build Coastguard Worker 	} else {
1184*1c60b9acSAndroid Build Coastguard Worker 
1185*1c60b9acSAndroid Build Coastguard Worker 		if (num < LWS_CBOR_1) {
1186*1c60b9acSAndroid Build Coastguard Worker 			ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode | num);
1187*1c60b9acSAndroid Build Coastguard Worker 			return;
1188*1c60b9acSAndroid Build Coastguard Worker 		}
1189*1c60b9acSAndroid Build Coastguard Worker 
1190*1c60b9acSAndroid Build Coastguard Worker 		if (!(num & (uint64_t)(~0xffull))) {
1191*1c60b9acSAndroid Build Coastguard Worker 			hint = LWS_CBOR_1;
1192*1c60b9acSAndroid Build Coastguard Worker 			num <<= 56;
1193*1c60b9acSAndroid Build Coastguard Worker 		} else
1194*1c60b9acSAndroid Build Coastguard Worker 			if (!(num & (uint64_t)(~0xffffull))) {
1195*1c60b9acSAndroid Build Coastguard Worker 				hint = LWS_CBOR_2;
1196*1c60b9acSAndroid Build Coastguard Worker 				num <<= 48;
1197*1c60b9acSAndroid Build Coastguard Worker 			} else
1198*1c60b9acSAndroid Build Coastguard Worker 				if (!(num & (uint64_t)(~0xffffffffull))) {
1199*1c60b9acSAndroid Build Coastguard Worker 					hint = LWS_CBOR_4;
1200*1c60b9acSAndroid Build Coastguard Worker 					num <<= 32;
1201*1c60b9acSAndroid Build Coastguard Worker 				}
1202*1c60b9acSAndroid Build Coastguard Worker 				else
1203*1c60b9acSAndroid Build Coastguard Worker 					hint = LWS_CBOR_8;
1204*1c60b9acSAndroid Build Coastguard Worker 	}
1205*1c60b9acSAndroid Build Coastguard Worker 
1206*1c60b9acSAndroid Build Coastguard Worker 	ctx->scratch[ctx->scratch_len++] = (uint8_t)(opcode | hint);
1207*1c60b9acSAndroid Build Coastguard Worker 	n = 1u << (hint - LWS_CBOR_1);
1208*1c60b9acSAndroid Build Coastguard Worker 	while (n--) {
1209*1c60b9acSAndroid Build Coastguard Worker 		ctx->scratch[ctx->scratch_len++] = (uint8_t)(num >> 56);
1210*1c60b9acSAndroid Build Coastguard Worker 		num <<= 8;
1211*1c60b9acSAndroid Build Coastguard Worker 	}
1212*1c60b9acSAndroid Build Coastguard Worker }
1213*1c60b9acSAndroid Build Coastguard Worker 
1214*1c60b9acSAndroid Build Coastguard Worker enum {
1215*1c60b9acSAndroid Build Coastguard Worker 	NATTYPE_INT,
1216*1c60b9acSAndroid Build Coastguard Worker 	NATTYPE_LONG,
1217*1c60b9acSAndroid Build Coastguard Worker 	NATTYPE_LONG_LONG,
1218*1c60b9acSAndroid Build Coastguard Worker 	NATTYPE_PTR,
1219*1c60b9acSAndroid Build Coastguard Worker 	NATTYPE_DOUBLE,
1220*1c60b9acSAndroid Build Coastguard Worker };
1221*1c60b9acSAndroid Build Coastguard Worker 
1222*1c60b9acSAndroid Build Coastguard Worker int
lws_lec_scratch(lws_lec_pctx_t * ctx)1223*1c60b9acSAndroid Build Coastguard Worker lws_lec_scratch(lws_lec_pctx_t *ctx)
1224*1c60b9acSAndroid Build Coastguard Worker {
1225*1c60b9acSAndroid Build Coastguard Worker 	size_t s;
1226*1c60b9acSAndroid Build Coastguard Worker 
1227*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->scratch_len)
1228*1c60b9acSAndroid Build Coastguard Worker 		return 0;
1229*1c60b9acSAndroid Build Coastguard Worker 
1230*1c60b9acSAndroid Build Coastguard Worker 	s = lws_ptr_diff_size_t(ctx->end, ctx->buf);
1231*1c60b9acSAndroid Build Coastguard Worker 	if (s > (size_t)ctx->scratch_len)
1232*1c60b9acSAndroid Build Coastguard Worker 		s = (size_t)ctx->scratch_len;
1233*1c60b9acSAndroid Build Coastguard Worker 
1234*1c60b9acSAndroid Build Coastguard Worker 	memcpy(ctx->buf, ctx->scratch, s);
1235*1c60b9acSAndroid Build Coastguard Worker 	ctx->buf += s;
1236*1c60b9acSAndroid Build Coastguard Worker 	ctx->scratch_len = (uint8_t)(ctx->scratch_len - (uint8_t)s);
1237*1c60b9acSAndroid Build Coastguard Worker 
1238*1c60b9acSAndroid Build Coastguard Worker 	return ctx->buf == ctx->end;
1239*1c60b9acSAndroid Build Coastguard Worker }
1240*1c60b9acSAndroid Build Coastguard Worker 
1241*1c60b9acSAndroid Build Coastguard Worker enum lws_lec_pctx_ret
lws_lec_vsprintf(lws_lec_pctx_t * ctx,const char * fmt,va_list args)1242*1c60b9acSAndroid Build Coastguard Worker lws_lec_vsprintf(lws_lec_pctx_t *ctx, const char *fmt, va_list args)
1243*1c60b9acSAndroid Build Coastguard Worker {
1244*1c60b9acSAndroid Build Coastguard Worker 	size_t fl = strlen(fmt);
1245*1c60b9acSAndroid Build Coastguard Worker 	uint64_t u64;
1246*1c60b9acSAndroid Build Coastguard Worker 	int64_t i64;
1247*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CBOR_FLOAT)
1248*1c60b9acSAndroid Build Coastguard Worker 	double dbl;
1249*1c60b9acSAndroid Build Coastguard Worker #endif
1250*1c60b9acSAndroid Build Coastguard Worker 	size_t s;
1251*1c60b9acSAndroid Build Coastguard Worker 	char c;
1252*1c60b9acSAndroid Build Coastguard Worker 	int n;
1253*1c60b9acSAndroid Build Coastguard Worker 
1254*1c60b9acSAndroid Build Coastguard Worker 	/*
1255*1c60b9acSAndroid Build Coastguard Worker 	 * We might be being called after the first time, since we had to emit
1256*1c60b9acSAndroid Build Coastguard Worker 	 * output buffer(s) before we could move on in the format string.  For
1257*1c60b9acSAndroid Build Coastguard Worker 	 * this case, reposition ourselves at the vaarg we got to from the last
1258*1c60b9acSAndroid Build Coastguard Worker 	 * call.
1259*1c60b9acSAndroid Build Coastguard Worker 	 */
1260*1c60b9acSAndroid Build Coastguard Worker 
1261*1c60b9acSAndroid Build Coastguard Worker 	for (n = 0; n < ctx->vaa_pos; n++) {
1262*1c60b9acSAndroid Build Coastguard Worker 
1263*1c60b9acSAndroid Build Coastguard Worker 		switch (ctx->vaa[n]) {
1264*1c60b9acSAndroid Build Coastguard Worker 		case NATTYPE_INT:
1265*1c60b9acSAndroid Build Coastguard Worker 			(void)va_arg(args, int);
1266*1c60b9acSAndroid Build Coastguard Worker 			break;
1267*1c60b9acSAndroid Build Coastguard Worker 		case NATTYPE_LONG:
1268*1c60b9acSAndroid Build Coastguard Worker 			(void)va_arg(args, long);
1269*1c60b9acSAndroid Build Coastguard Worker 			break;
1270*1c60b9acSAndroid Build Coastguard Worker 		case NATTYPE_LONG_LONG:
1271*1c60b9acSAndroid Build Coastguard Worker 			(void)va_arg(args, long long);
1272*1c60b9acSAndroid Build Coastguard Worker 			break;
1273*1c60b9acSAndroid Build Coastguard Worker 		case NATTYPE_PTR:
1274*1c60b9acSAndroid Build Coastguard Worker 			(void)va_arg(args, const char *);
1275*1c60b9acSAndroid Build Coastguard Worker 			break;
1276*1c60b9acSAndroid Build Coastguard Worker 		case NATTYPE_DOUBLE:
1277*1c60b9acSAndroid Build Coastguard Worker 			(void)va_arg(args, double);
1278*1c60b9acSAndroid Build Coastguard Worker 			break;
1279*1c60b9acSAndroid Build Coastguard Worker 		}
1280*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->state == CBPS_STRING_BODY)
1281*1c60b9acSAndroid Build Coastguard Worker 			/*
1282*1c60b9acSAndroid Build Coastguard Worker 			 * when copying out text or binary strings, we reload
1283*1c60b9acSAndroid Build Coastguard Worker 			 * the %s or %.*s pointer on subsequent calls, in case
1284*1c60b9acSAndroid Build Coastguard Worker 			 * it was on the stack.  The length and contents should
1285*1c60b9acSAndroid Build Coastguard Worker 			 * not change between calls, but it's OK if the source
1286*1c60b9acSAndroid Build Coastguard Worker 			 * address does.
1287*1c60b9acSAndroid Build Coastguard Worker 			 */
1288*1c60b9acSAndroid Build Coastguard Worker 			ctx->ongoing_src = va_arg(args, uint8_t *);
1289*1c60b9acSAndroid Build Coastguard Worker 	}
1290*1c60b9acSAndroid Build Coastguard Worker 
1291*1c60b9acSAndroid Build Coastguard Worker 	while (ctx->buf != ctx->end) {
1292*1c60b9acSAndroid Build Coastguard Worker 
1293*1c60b9acSAndroid Build Coastguard Worker 		/*
1294*1c60b9acSAndroid Build Coastguard Worker 		 * We write small things into the context scratch array, then
1295*1c60b9acSAndroid Build Coastguard Worker 		 * copy that into the output buffer fragmenting as needed.  Next
1296*1c60b9acSAndroid Build Coastguard Worker 		 * time we will finish emptying the scratch into the output
1297*1c60b9acSAndroid Build Coastguard Worker 		 * buffer preferentially.
1298*1c60b9acSAndroid Build Coastguard Worker 		 *
1299*1c60b9acSAndroid Build Coastguard Worker 		 * Then we don't otherwise have to handle fragmentations in
1300*1c60b9acSAndroid Build Coastguard Worker 		 * order to exactly fill the output buffer, simplifying
1301*1c60b9acSAndroid Build Coastguard Worker 		 * everything else.
1302*1c60b9acSAndroid Build Coastguard Worker 		 */
1303*1c60b9acSAndroid Build Coastguard Worker 
1304*1c60b9acSAndroid Build Coastguard Worker 		if (lws_lec_scratch(ctx))
1305*1c60b9acSAndroid Build Coastguard Worker 			break;
1306*1c60b9acSAndroid Build Coastguard Worker 
1307*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->fmt_pos >= fl) {
1308*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->state == CBPS_IDLE)
1309*1c60b9acSAndroid Build Coastguard Worker 				break;
1310*1c60b9acSAndroid Build Coastguard Worker 			c = 0;
1311*1c60b9acSAndroid Build Coastguard Worker 		} else
1312*1c60b9acSAndroid Build Coastguard Worker 			c = fmt[ctx->fmt_pos];
1313*1c60b9acSAndroid Build Coastguard Worker 
1314*1c60b9acSAndroid Build Coastguard Worker 		// lwsl_notice("%s: %d %d %c\n", __func__, ctx->state, ctx->sp, c);
1315*1c60b9acSAndroid Build Coastguard Worker 
1316*1c60b9acSAndroid Build Coastguard Worker 		switch (ctx->state) {
1317*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_IDLE:
1318*1c60b9acSAndroid Build Coastguard Worker 			ctx->scratch_len = 0;
1319*1c60b9acSAndroid Build Coastguard Worker 			switch (c) {
1320*1c60b9acSAndroid Build Coastguard Worker 			case '[':
1321*1c60b9acSAndroid Build Coastguard Worker 				n = format_scan(&fmt[ctx->fmt_pos]);
1322*1c60b9acSAndroid Build Coastguard Worker 				if (n == -2)
1323*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1324*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_ARRAY, n == -1,
1325*1c60b9acSAndroid Build Coastguard Worker 							(uint64_t)n);
1326*1c60b9acSAndroid Build Coastguard Worker 				goto stack_push;
1327*1c60b9acSAndroid Build Coastguard Worker 			case '{':
1328*1c60b9acSAndroid Build Coastguard Worker 				n = format_scan(&fmt[ctx->fmt_pos]);
1329*1c60b9acSAndroid Build Coastguard Worker 				if (n == -2)
1330*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1331*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_MAP, n == -1,
1332*1c60b9acSAndroid Build Coastguard Worker 							(uint64_t)n);
1333*1c60b9acSAndroid Build Coastguard Worker 				goto stack_push;
1334*1c60b9acSAndroid Build Coastguard Worker 			case '(':
1335*1c60b9acSAndroid Build Coastguard Worker 				/* must be preceded by a number */
1336*1c60b9acSAndroid Build Coastguard Worker 				goto fail;
1337*1c60b9acSAndroid Build Coastguard Worker 
1338*1c60b9acSAndroid Build Coastguard Worker 			case '<': /* <t or <b */
1339*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_CONTYPE;
1340*1c60b9acSAndroid Build Coastguard Worker 				break;
1341*1c60b9acSAndroid Build Coastguard Worker 
1342*1c60b9acSAndroid Build Coastguard Worker 			case ']':
1343*1c60b9acSAndroid Build Coastguard Worker 				if (!ctx->sp || ctx->stack[ctx->sp - 1] != '[')
1344*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1345*1c60b9acSAndroid Build Coastguard Worker 				ctx->sp--;
1346*1c60b9acSAndroid Build Coastguard Worker 				break;
1347*1c60b9acSAndroid Build Coastguard Worker 			case '}':
1348*1c60b9acSAndroid Build Coastguard Worker 				if (!ctx->sp || ctx->stack[ctx->sp - 1] != '{')
1349*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1350*1c60b9acSAndroid Build Coastguard Worker 				ctx->sp--;
1351*1c60b9acSAndroid Build Coastguard Worker 				break;
1352*1c60b9acSAndroid Build Coastguard Worker 			case ')':
1353*1c60b9acSAndroid Build Coastguard Worker 				if (!ctx->sp || ctx->stack[ctx->sp - 1] != '(') {
1354*1c60b9acSAndroid Build Coastguard Worker 					lwsl_notice("bad tag end %d %c\n",
1355*1c60b9acSAndroid Build Coastguard Worker 						ctx->sp, ctx->stack[ctx->sp - 1]);
1356*1c60b9acSAndroid Build Coastguard Worker 					goto fail;
1357*1c60b9acSAndroid Build Coastguard Worker 				}
1358*1c60b9acSAndroid Build Coastguard Worker 				ctx->sp--;
1359*1c60b9acSAndroid Build Coastguard Worker 				break;
1360*1c60b9acSAndroid Build Coastguard Worker 			case '>':
1361*1c60b9acSAndroid Build Coastguard Worker 				if (!ctx->sp || ctx->stack[ctx->sp - 1] != '<')
1362*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1363*1c60b9acSAndroid Build Coastguard Worker 				ctx->scratch[ctx->scratch_len++] =
1364*1c60b9acSAndroid Build Coastguard Worker 						(uint8_t)(LWS_CBOR_MAJTYP_FLOAT |
1365*1c60b9acSAndroid Build Coastguard Worker 							LWS_CBOR_M7_BREAK);
1366*1c60b9acSAndroid Build Coastguard Worker 				ctx->sp--;
1367*1c60b9acSAndroid Build Coastguard Worker 				break;
1368*1c60b9acSAndroid Build Coastguard Worker 			case '\'':
1369*1c60b9acSAndroid Build Coastguard Worker 				n = format_scan(&fmt[ctx->fmt_pos]);
1370*1c60b9acSAndroid Build Coastguard Worker 				// lwsl_notice("%s: quote fs %d\n", __func__, n);
1371*1c60b9acSAndroid Build Coastguard Worker 				if (n < 0)
1372*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1373*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_TSTR, 0,
1374*1c60b9acSAndroid Build Coastguard Worker 								(uint64_t)n);
1375*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_STRING_LIT;
1376*1c60b9acSAndroid Build Coastguard Worker 				break;
1377*1c60b9acSAndroid Build Coastguard Worker 			case '%':
1378*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->vaa_pos >= sizeof(ctx->vaa) - 1) {
1379*1c60b9acSAndroid Build Coastguard Worker 					lwsl_err("%s: too many %%\n", __func__);
1380*1c60b9acSAndroid Build Coastguard Worker 					goto fail;
1381*1c60b9acSAndroid Build Coastguard Worker 				}
1382*1c60b9acSAndroid Build Coastguard Worker 				ctx->_long = 0;
1383*1c60b9acSAndroid Build Coastguard Worker 				ctx->dotstar = 0;
1384*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_PC1;
1385*1c60b9acSAndroid Build Coastguard Worker 				break;
1386*1c60b9acSAndroid Build Coastguard Worker 			case ':':
1387*1c60b9acSAndroid Build Coastguard Worker 				break;
1388*1c60b9acSAndroid Build Coastguard Worker 			case ',':
1389*1c60b9acSAndroid Build Coastguard Worker 				break;
1390*1c60b9acSAndroid Build Coastguard Worker 			case '-':
1391*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.opcode = LWS_CBOR_MAJTYP_INT_NEG;
1392*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.u.i64 = 0;
1393*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_NUM_LIT;
1394*1c60b9acSAndroid Build Coastguard Worker 				break;
1395*1c60b9acSAndroid Build Coastguard Worker 			case '0':
1396*1c60b9acSAndroid Build Coastguard Worker 			case '1':
1397*1c60b9acSAndroid Build Coastguard Worker 			case '2':
1398*1c60b9acSAndroid Build Coastguard Worker 			case '3':
1399*1c60b9acSAndroid Build Coastguard Worker 			case '4':
1400*1c60b9acSAndroid Build Coastguard Worker 			case '5':
1401*1c60b9acSAndroid Build Coastguard Worker 			case '6':
1402*1c60b9acSAndroid Build Coastguard Worker 			case '7':
1403*1c60b9acSAndroid Build Coastguard Worker 			case '8':
1404*1c60b9acSAndroid Build Coastguard Worker 			case '9':
1405*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.opcode = LWS_CBOR_MAJTYP_UINT;
1406*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.u.u64 = (uint64_t)(c - '0');
1407*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_NUM_LIT;
1408*1c60b9acSAndroid Build Coastguard Worker 				break;
1409*1c60b9acSAndroid Build Coastguard Worker 			}
1410*1c60b9acSAndroid Build Coastguard Worker 			break;
1411*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_PC1:
1412*1c60b9acSAndroid Build Coastguard Worker 			if (c == 'l') {
1413*1c60b9acSAndroid Build Coastguard Worker 				ctx->_long++;
1414*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_PC2;
1415*1c60b9acSAndroid Build Coastguard Worker 				break;
1416*1c60b9acSAndroid Build Coastguard Worker 			}
1417*1c60b9acSAndroid Build Coastguard Worker 			if (c == '.') {
1418*1c60b9acSAndroid Build Coastguard Worker 				ctx->dotstar++;
1419*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_PC2;
1420*1c60b9acSAndroid Build Coastguard Worker 				break;
1421*1c60b9acSAndroid Build Coastguard Worker 			}
1422*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
1423*1c60b9acSAndroid Build Coastguard Worker 
1424*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_PC2:
1425*1c60b9acSAndroid Build Coastguard Worker 			if (c == 'l') {
1426*1c60b9acSAndroid Build Coastguard Worker 				ctx->_long++;
1427*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_PC3;
1428*1c60b9acSAndroid Build Coastguard Worker 				break;
1429*1c60b9acSAndroid Build Coastguard Worker 			}
1430*1c60b9acSAndroid Build Coastguard Worker 			if (c == '*') {
1431*1c60b9acSAndroid Build Coastguard Worker 				ctx->dotstar++;
1432*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_PC3;
1433*1c60b9acSAndroid Build Coastguard Worker 				break;
1434*1c60b9acSAndroid Build Coastguard Worker 			}
1435*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
1436*1c60b9acSAndroid Build Coastguard Worker 
1437*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_PC3:
1438*1c60b9acSAndroid Build Coastguard Worker 			switch (c) {
1439*1c60b9acSAndroid Build Coastguard Worker 			case 'd':
1440*1c60b9acSAndroid Build Coastguard Worker 				switch (ctx->_long) {
1441*1c60b9acSAndroid Build Coastguard Worker 				case 0:
1442*1c60b9acSAndroid Build Coastguard Worker 					i64 = (int64_t)va_arg(args, int);
1443*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
1444*1c60b9acSAndroid Build Coastguard Worker 					break;
1445*1c60b9acSAndroid Build Coastguard Worker 				case 1:
1446*1c60b9acSAndroid Build Coastguard Worker 					i64 = (int64_t)va_arg(args, long);
1447*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
1448*1c60b9acSAndroid Build Coastguard Worker 					break;
1449*1c60b9acSAndroid Build Coastguard Worker 				case 2:
1450*1c60b9acSAndroid Build Coastguard Worker 					i64 = (int64_t)va_arg(args, long long);
1451*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
1452*1c60b9acSAndroid Build Coastguard Worker 					break;
1453*1c60b9acSAndroid Build Coastguard Worker 				}
1454*1c60b9acSAndroid Build Coastguard Worker 				if (i64 < 0)
1455*1c60b9acSAndroid Build Coastguard Worker 					lws_lec_int(ctx,
1456*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_INT_NEG, 0,
1457*1c60b9acSAndroid Build Coastguard Worker 						    (uint64_t)(-1ll - i64));
1458*1c60b9acSAndroid Build Coastguard Worker 				else
1459*1c60b9acSAndroid Build Coastguard Worker 					lws_lec_int(ctx,
1460*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_UINT, 0,
1461*1c60b9acSAndroid Build Coastguard Worker 						    (uint64_t)i64);
1462*1c60b9acSAndroid Build Coastguard Worker 				break;
1463*1c60b9acSAndroid Build Coastguard Worker 			case 'u':
1464*1c60b9acSAndroid Build Coastguard Worker 				switch (ctx->_long) {
1465*1c60b9acSAndroid Build Coastguard Worker 				case 0:
1466*1c60b9acSAndroid Build Coastguard Worker 					u64 = (uint64_t)va_arg(args, unsigned int);
1467*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
1468*1c60b9acSAndroid Build Coastguard Worker 					break;
1469*1c60b9acSAndroid Build Coastguard Worker 				case 1:
1470*1c60b9acSAndroid Build Coastguard Worker 					u64 = (uint64_t)va_arg(args, unsigned long);
1471*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
1472*1c60b9acSAndroid Build Coastguard Worker 					break;
1473*1c60b9acSAndroid Build Coastguard Worker 				case 2:
1474*1c60b9acSAndroid Build Coastguard Worker 					u64 = (uint64_t)va_arg(args, unsigned long long);
1475*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
1476*1c60b9acSAndroid Build Coastguard Worker 					break;
1477*1c60b9acSAndroid Build Coastguard Worker 				}
1478*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_UINT, 0, u64);
1479*1c60b9acSAndroid Build Coastguard Worker 				break;
1480*1c60b9acSAndroid Build Coastguard Worker 			case 's': /* text string */
1481*1c60b9acSAndroid Build Coastguard Worker 				ctx->ongoing_done = 0;
1482*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->dotstar == 2) {
1483*1c60b9acSAndroid Build Coastguard Worker 					ctx->ongoing_len = (uint64_t)va_arg(args, int);
1484*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
1485*1c60b9acSAndroid Build Coastguard Worker 				}
1486*1c60b9acSAndroid Build Coastguard Worker 				/* vaa for ptr done at end of body copy */
1487*1c60b9acSAndroid Build Coastguard Worker 				ctx->ongoing_src = va_arg(args, uint8_t *);
1488*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->dotstar != 2)
1489*1c60b9acSAndroid Build Coastguard Worker 					ctx->ongoing_len = (uint64_t)strlen(
1490*1c60b9acSAndroid Build Coastguard Worker 						(const char *)ctx->ongoing_src);
1491*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_TSTR, 0, ctx->ongoing_len);
1492*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_STRING_BODY;
1493*1c60b9acSAndroid Build Coastguard Worker 				ctx->fmt_pos++;
1494*1c60b9acSAndroid Build Coastguard Worker 				continue;
1495*1c60b9acSAndroid Build Coastguard Worker 			case 'b': /* binary string (%.*b only) */
1496*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->dotstar != 2)
1497*1c60b9acSAndroid Build Coastguard Worker 					goto fail;
1498*1c60b9acSAndroid Build Coastguard Worker 				ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
1499*1c60b9acSAndroid Build Coastguard Worker 				ctx->ongoing_done = 0;
1500*1c60b9acSAndroid Build Coastguard Worker 				ctx->ongoing_len = (uint64_t)va_arg(args, int);
1501*1c60b9acSAndroid Build Coastguard Worker 				/* vaa for ptr done at end of body copy */
1502*1c60b9acSAndroid Build Coastguard Worker 				ctx->ongoing_src = va_arg(args, uint8_t *);
1503*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_BSTR, 0, ctx->ongoing_len);
1504*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_STRING_BODY;
1505*1c60b9acSAndroid Build Coastguard Worker 				ctx->fmt_pos++;
1506*1c60b9acSAndroid Build Coastguard Worker 				continue;
1507*1c60b9acSAndroid Build Coastguard Worker 			case 't': /* dynamic tag */
1508*1c60b9acSAndroid Build Coastguard Worker 				switch (ctx->_long) {
1509*1c60b9acSAndroid Build Coastguard Worker 				case 0:
1510*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = (uint64_t)va_arg(args, int);
1511*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_INT;
1512*1c60b9acSAndroid Build Coastguard Worker 					break;
1513*1c60b9acSAndroid Build Coastguard Worker 				case 1:
1514*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = (uint64_t)va_arg(args, long);
1515*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG;
1516*1c60b9acSAndroid Build Coastguard Worker 					break;
1517*1c60b9acSAndroid Build Coastguard Worker 				case 2:
1518*1c60b9acSAndroid Build Coastguard Worker 					ctx->item.u.u64 = (uint64_t)va_arg(args, long long);
1519*1c60b9acSAndroid Build Coastguard Worker 					ctx->vaa[ctx->vaa_pos++] = NATTYPE_LONG_LONG;
1520*1c60b9acSAndroid Build Coastguard Worker 					break;
1521*1c60b9acSAndroid Build Coastguard Worker 				}
1522*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.opcode = LWS_CBOR_MAJTYP_UINT;
1523*1c60b9acSAndroid Build Coastguard Worker 				ctx->fmt_pos++;
1524*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->fmt_pos >= fl)
1525*1c60b9acSAndroid Build Coastguard Worker 					continue;
1526*1c60b9acSAndroid Build Coastguard Worker 				c = fmt[ctx->fmt_pos];
1527*1c60b9acSAndroid Build Coastguard Worker 				if (c != '(')
1528*1c60b9acSAndroid Build Coastguard Worker 					goto fail;
1529*1c60b9acSAndroid Build Coastguard Worker 				goto tag_body;
1530*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CBOR_FLOAT)
1531*1c60b9acSAndroid Build Coastguard Worker 			case 'f': /* floating point double */
1532*1c60b9acSAndroid Build Coastguard Worker 				dbl = va_arg(args, double);
1533*1c60b9acSAndroid Build Coastguard Worker 
1534*1c60b9acSAndroid Build Coastguard Worker 				if (dbl == (float)dbl) {
1535*1c60b9acSAndroid Build Coastguard Worker 					uint16_t hf;
1536*1c60b9acSAndroid Build Coastguard Worker 					union {
1537*1c60b9acSAndroid Build Coastguard Worker 						uint32_t ui;
1538*1c60b9acSAndroid Build Coastguard Worker 						float f;
1539*1c60b9acSAndroid Build Coastguard Worker 					} u1, u2;
1540*1c60b9acSAndroid Build Coastguard Worker 
1541*1c60b9acSAndroid Build Coastguard Worker 					u1.f = (float)dbl;
1542*1c60b9acSAndroid Build Coastguard Worker 					lws_singles2halfp(&hf, u1.ui);
1543*1c60b9acSAndroid Build Coastguard Worker 					lws_halfp2singles(&u2.ui, hf);
1544*1c60b9acSAndroid Build Coastguard Worker 
1545*1c60b9acSAndroid Build Coastguard Worker 					if ((isinf(u1.f) && isinf(u2.f)) ||
1546*1c60b9acSAndroid Build Coastguard Worker 					    (isnan(u1.f) && isnan(u2.f)) ||
1547*1c60b9acSAndroid Build Coastguard Worker 					    u1.f == u2.f) {
1548*1c60b9acSAndroid Build Coastguard Worker 						lws_lec_int(ctx,
1549*1c60b9acSAndroid Build Coastguard Worker 							    LWS_CBOR_MAJTYP_FLOAT |
1550*1c60b9acSAndroid Build Coastguard Worker 							    LWS_CBOR_M7_SUBTYP_FLOAT16,
1551*1c60b9acSAndroid Build Coastguard Worker 							    0, hf);
1552*1c60b9acSAndroid Build Coastguard Worker 						break;
1553*1c60b9acSAndroid Build Coastguard Worker 					}
1554*1c60b9acSAndroid Build Coastguard Worker 					/* do it as 32-bit float */
1555*1c60b9acSAndroid Build Coastguard Worker 					lws_lec_int(ctx,
1556*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_FLOAT |
1557*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_M7_SUBTYP_FLOAT32,
1558*1c60b9acSAndroid Build Coastguard Worker 						    0, u1.ui);
1559*1c60b9acSAndroid Build Coastguard Worker 					break;
1560*1c60b9acSAndroid Build Coastguard Worker 				}
1561*1c60b9acSAndroid Build Coastguard Worker 
1562*1c60b9acSAndroid Build Coastguard Worker 				/* do it as 64-bit double */
1563*1c60b9acSAndroid Build Coastguard Worker 
1564*1c60b9acSAndroid Build Coastguard Worker 				{
1565*1c60b9acSAndroid Build Coastguard Worker 					union {
1566*1c60b9acSAndroid Build Coastguard Worker 						uint64_t ui;
1567*1c60b9acSAndroid Build Coastguard Worker 						double f;
1568*1c60b9acSAndroid Build Coastguard Worker 					} u3;
1569*1c60b9acSAndroid Build Coastguard Worker 
1570*1c60b9acSAndroid Build Coastguard Worker 					u3.f = dbl;
1571*1c60b9acSAndroid Build Coastguard Worker 					lws_lec_int(ctx,
1572*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_FLOAT |
1573*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_M7_SUBTYP_FLOAT64,
1574*1c60b9acSAndroid Build Coastguard Worker 						    0, u3.ui);
1575*1c60b9acSAndroid Build Coastguard Worker 				}
1576*1c60b9acSAndroid Build Coastguard Worker 				break;
1577*1c60b9acSAndroid Build Coastguard Worker #else
1578*1c60b9acSAndroid Build Coastguard Worker 			case 'f':
1579*1c60b9acSAndroid Build Coastguard Worker 				lwsl_err("%s: no FP support\n", __func__);
1580*1c60b9acSAndroid Build Coastguard Worker 				goto fail;
1581*1c60b9acSAndroid Build Coastguard Worker #endif
1582*1c60b9acSAndroid Build Coastguard Worker 			}
1583*1c60b9acSAndroid Build Coastguard Worker 			ctx->state = CBPS_IDLE;
1584*1c60b9acSAndroid Build Coastguard Worker 			break;
1585*1c60b9acSAndroid Build Coastguard Worker 
1586*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_STRING_BODY:
1587*1c60b9acSAndroid Build Coastguard Worker 			s = lws_ptr_diff_size_t(ctx->end, ctx->buf);
1588*1c60b9acSAndroid Build Coastguard Worker 			if (s > (size_t)(ctx->ongoing_len - ctx->ongoing_done))
1589*1c60b9acSAndroid Build Coastguard Worker 				s = (size_t)(ctx->ongoing_len - ctx->ongoing_done);
1590*1c60b9acSAndroid Build Coastguard Worker 			memcpy(ctx->buf, ctx->ongoing_src + ctx->ongoing_done, s);
1591*1c60b9acSAndroid Build Coastguard Worker 			ctx->buf += s;
1592*1c60b9acSAndroid Build Coastguard Worker 			ctx->ongoing_done += s;
1593*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->ongoing_len == ctx->ongoing_done) {
1594*1c60b9acSAndroid Build Coastguard Worker 				/* vaa for ptr */
1595*1c60b9acSAndroid Build Coastguard Worker 				ctx->vaa[ctx->vaa_pos++] = NATTYPE_PTR;
1596*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_IDLE;
1597*1c60b9acSAndroid Build Coastguard Worker 			}
1598*1c60b9acSAndroid Build Coastguard Worker 			continue;
1599*1c60b9acSAndroid Build Coastguard Worker 
1600*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_NUM_LIT:
1601*1c60b9acSAndroid Build Coastguard Worker 			if (c >= '0' && c <= '9') {
1602*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.u.u64 = (ctx->item.u.u64 * 10) +
1603*1c60b9acSAndroid Build Coastguard Worker 								(uint64_t)(c - '0');
1604*1c60b9acSAndroid Build Coastguard Worker 				break;
1605*1c60b9acSAndroid Build Coastguard Worker 			}
1606*1c60b9acSAndroid Build Coastguard Worker 
1607*1c60b9acSAndroid Build Coastguard Worker 			if (ctx->item.opcode == LWS_CBOR_MAJTYP_INT_NEG)
1608*1c60b9acSAndroid Build Coastguard Worker 				ctx->item.u.i64--;
1609*1c60b9acSAndroid Build Coastguard Worker 
1610*1c60b9acSAndroid Build Coastguard Worker 			if (c == '(') { /* tag qualifier */
1611*1c60b9acSAndroid Build Coastguard Worker tag_body:
1612*1c60b9acSAndroid Build Coastguard Worker 				n = format_scan(&fmt[ctx->fmt_pos]);
1613*1c60b9acSAndroid Build Coastguard Worker 				if (n == -2)
1614*1c60b9acSAndroid Build Coastguard Worker 					goto fail;
1615*1c60b9acSAndroid Build Coastguard Worker 				/*
1616*1c60b9acSAndroid Build Coastguard Worker 				 * inteterminite length not possible for tag,
1617*1c60b9acSAndroid Build Coastguard Worker 				 * take it to mean that the closure is in a
1618*1c60b9acSAndroid Build Coastguard Worker 				 * later format string
1619*1c60b9acSAndroid Build Coastguard Worker 				 */
1620*1c60b9acSAndroid Build Coastguard Worker 
1621*1c60b9acSAndroid Build Coastguard Worker 				lws_lec_int(ctx, LWS_CBOR_MAJTYP_TAG, 0,
1622*1c60b9acSAndroid Build Coastguard Worker 							ctx->item.u.u64);
1623*1c60b9acSAndroid Build Coastguard Worker 
1624*1c60b9acSAndroid Build Coastguard Worker stack_push:
1625*1c60b9acSAndroid Build Coastguard Worker 				if (ctx->sp >= sizeof(ctx->stack))
1626*1c60b9acSAndroid Build Coastguard Worker 					return LWS_LECPCTX_RET_FAIL;
1627*1c60b9acSAndroid Build Coastguard Worker 				ctx->stack[ctx->sp] = (uint8_t)c;
1628*1c60b9acSAndroid Build Coastguard Worker 				ctx->indet[ctx->sp++] = (uint8_t)(n == -1);
1629*1c60b9acSAndroid Build Coastguard Worker 				// lwsl_notice("%s: pushed %c\n", __func__, c);
1630*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_IDLE;
1631*1c60b9acSAndroid Build Coastguard Worker 				break;
1632*1c60b9acSAndroid Build Coastguard Worker 			}
1633*1c60b9acSAndroid Build Coastguard Worker 
1634*1c60b9acSAndroid Build Coastguard Worker 			lws_lec_int(ctx, ctx->item.opcode, 0, ctx->item.u.u64);
1635*1c60b9acSAndroid Build Coastguard Worker 
1636*1c60b9acSAndroid Build Coastguard Worker 			ctx->state = CBPS_IDLE;
1637*1c60b9acSAndroid Build Coastguard Worker 			/* deal with the terminating char fresh */
1638*1c60b9acSAndroid Build Coastguard Worker 			continue;
1639*1c60b9acSAndroid Build Coastguard Worker 
1640*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_STRING_LIT:
1641*1c60b9acSAndroid Build Coastguard Worker 			if (!ctx->escflag && c == '\\') {
1642*1c60b9acSAndroid Build Coastguard Worker 				ctx->escflag = 1;
1643*1c60b9acSAndroid Build Coastguard Worker 				break;
1644*1c60b9acSAndroid Build Coastguard Worker 			}
1645*1c60b9acSAndroid Build Coastguard Worker 			if (!ctx->escflag && c == '\'') {
1646*1c60b9acSAndroid Build Coastguard Worker 				ctx->state = CBPS_IDLE;
1647*1c60b9acSAndroid Build Coastguard Worker 				break;
1648*1c60b9acSAndroid Build Coastguard Worker 			}
1649*1c60b9acSAndroid Build Coastguard Worker 
1650*1c60b9acSAndroid Build Coastguard Worker 			*ctx->buf++ = (uint8_t)c;
1651*1c60b9acSAndroid Build Coastguard Worker 			ctx->escflag = 0;
1652*1c60b9acSAndroid Build Coastguard Worker 
1653*1c60b9acSAndroid Build Coastguard Worker 			break;
1654*1c60b9acSAndroid Build Coastguard Worker 
1655*1c60b9acSAndroid Build Coastguard Worker 		case CBPS_CONTYPE:
1656*1c60b9acSAndroid Build Coastguard Worker 			if (c != 't' && c != 'b')
1657*1c60b9acSAndroid Build Coastguard Worker 				return LWS_LECPCTX_RET_FAIL;
1658*1c60b9acSAndroid Build Coastguard Worker 
1659*1c60b9acSAndroid Build Coastguard Worker 			lws_lec_int(ctx, c == 't' ? LWS_CBOR_MAJTYP_TSTR :
1660*1c60b9acSAndroid Build Coastguard Worker 						    LWS_CBOR_MAJTYP_BSTR, 1, 0);
1661*1c60b9acSAndroid Build Coastguard Worker 			c = '<';
1662*1c60b9acSAndroid Build Coastguard Worker 			n = 0;
1663*1c60b9acSAndroid Build Coastguard Worker 			goto stack_push;
1664*1c60b9acSAndroid Build Coastguard Worker 		}
1665*1c60b9acSAndroid Build Coastguard Worker 
1666*1c60b9acSAndroid Build Coastguard Worker 		ctx->fmt_pos++;
1667*1c60b9acSAndroid Build Coastguard Worker 	}
1668*1c60b9acSAndroid Build Coastguard Worker 
1669*1c60b9acSAndroid Build Coastguard Worker 	ctx->used = lws_ptr_diff_size_t(ctx->buf, ctx->start);
1670*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_notice("%s: ctx->used %d\n", __func__, (int)ctx->used);
1671*1c60b9acSAndroid Build Coastguard Worker 
1672*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->buf == ctx->end || ctx->scratch_len)
1673*1c60b9acSAndroid Build Coastguard Worker 		return LWS_LECPCTX_RET_AGAIN;
1674*1c60b9acSAndroid Build Coastguard Worker 
1675*1c60b9acSAndroid Build Coastguard Worker 	ctx->fmt_pos = 0;
1676*1c60b9acSAndroid Build Coastguard Worker 	ctx->vaa_pos = 0;
1677*1c60b9acSAndroid Build Coastguard Worker 
1678*1c60b9acSAndroid Build Coastguard Worker 	return LWS_LECPCTX_RET_FINISHED;
1679*1c60b9acSAndroid Build Coastguard Worker 
1680*1c60b9acSAndroid Build Coastguard Worker fail:
1681*1c60b9acSAndroid Build Coastguard Worker 	lwsl_notice("%s: failed\n", __func__);
1682*1c60b9acSAndroid Build Coastguard Worker 
1683*1c60b9acSAndroid Build Coastguard Worker 	ctx->fmt_pos = 0;
1684*1c60b9acSAndroid Build Coastguard Worker 
1685*1c60b9acSAndroid Build Coastguard Worker 	return LWS_LECPCTX_RET_FAIL;
1686*1c60b9acSAndroid Build Coastguard Worker }
1687