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