1 /*
2  *  CBOR bindings.
3  *
4  *  http://cbor.io/
5  *  https://tools.ietf.org/html/rfc7049
6  */
7 
8 #include "duk_internal.h"
9 
10 #if defined(DUK_USE_CBOR_SUPPORT)
11 
12 /* #define DUK_CBOR_STRESS */
13 
14 /* Default behavior for encoding strings: use CBOR text string if string
15  * is UTF-8 compatible, otherwise use CBOR byte string.  These defines
16  * can be used to force either type for all strings.  Using text strings
17  * for non-UTF-8 data is technically invalid CBOR.
18  */
19 /* #define DUK_CBOR_TEXT_STRINGS */
20 /* #define DUK_CBOR_BYTE_STRINGS */
21 
22 /* Misc. defines. */
23 /* #define DUK_CBOR_PREFER_SIZE */
24 /* #define DUK_CBOR_DOUBLE_AS_IS */
25 /* #define DUK_CBOR_DECODE_FASTPATH */
26 
27 typedef struct {
28 	duk_hthread *thr;
29 	duk_uint8_t *ptr;
30 	duk_uint8_t *buf;
31 	duk_uint8_t *buf_end;
32 	duk_size_t len;
33 	duk_idx_t idx_buf;
34 	duk_uint_t recursion_depth;
35 	duk_uint_t recursion_limit;
36 } duk_cbor_encode_context;
37 
38 typedef struct {
39 	duk_hthread *thr;
40 	const duk_uint8_t *buf;
41 	duk_size_t off;
42 	duk_size_t len;
43 	duk_uint_t recursion_depth;
44 	duk_uint_t recursion_limit;
45 } duk_cbor_decode_context;
46 
47 DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx);
48 DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx);
49 
50 /*
51  *  Misc
52  */
53 
duk__cbor_double_to_uint32(double d)54 DUK_LOCAL duk_uint32_t duk__cbor_double_to_uint32(double d) {
55 	/* Out of range casts are undefined behavior, so caller must avoid. */
56 	DUK_ASSERT(d >= 0.0 && d <= 4294967295.0);
57 	return (duk_uint32_t) d;
58 }
59 
60 /*
61  *  Encoding
62  */
63 
duk__cbor_encode_error(duk_cbor_encode_context * enc_ctx)64 DUK_LOCAL void duk__cbor_encode_error(duk_cbor_encode_context *enc_ctx) {
65 	(void) duk_type_error(enc_ctx->thr, "cbor encode error");
66 }
67 
duk__cbor_encode_req_stack(duk_cbor_encode_context * enc_ctx)68 DUK_LOCAL void duk__cbor_encode_req_stack(duk_cbor_encode_context *enc_ctx) {
69 	duk_require_stack(enc_ctx->thr, 4);
70 }
71 
duk__cbor_encode_objarr_entry(duk_cbor_encode_context * enc_ctx)72 DUK_LOCAL void duk__cbor_encode_objarr_entry(duk_cbor_encode_context *enc_ctx) {
73 	duk_hthread *thr = enc_ctx->thr;
74 
75 	/* Native stack check in object/array recursion. */
76 	duk_native_stack_check(thr);
77 
78 	/* When working with deeply recursive structures, this is important
79 	 * to ensure there's no effective depth limit.
80 	 */
81 	duk__cbor_encode_req_stack(enc_ctx);
82 
83 	DUK_ASSERT(enc_ctx->recursion_depth <= enc_ctx->recursion_limit);
84 	if (enc_ctx->recursion_depth >= enc_ctx->recursion_limit) {
85 		DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT);
86 		DUK_WO_NORETURN(return;);
87 	}
88 	enc_ctx->recursion_depth++;
89 }
90 
duk__cbor_encode_objarr_exit(duk_cbor_encode_context * enc_ctx)91 DUK_LOCAL void duk__cbor_encode_objarr_exit(duk_cbor_encode_context *enc_ctx) {
92 	DUK_ASSERT(enc_ctx->recursion_depth > 0);
93 	enc_ctx->recursion_depth--;
94 }
95 
96 /* Check that a size_t is in uint32 range to avoid out-of-range casts. */
duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context * enc_ctx,duk_size_t len)97 DUK_LOCAL void duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
98 	if (DUK_UNLIKELY(sizeof(duk_size_t) > sizeof(duk_uint32_t) && len > (duk_size_t) DUK_UINT32_MAX)) {
99 		duk__cbor_encode_error(enc_ctx);
100 	}
101 }
102 
duk__cbor_encode_ensure_slowpath(duk_cbor_encode_context * enc_ctx,duk_size_t len)103 DUK_LOCAL DUK_NOINLINE void duk__cbor_encode_ensure_slowpath(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
104 	duk_size_t oldlen;
105 	duk_size_t minlen;
106 	duk_size_t newlen;
107 	duk_uint8_t *p_new;
108 	duk_size_t old_data_len;
109 
110 	DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf);
111 	DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->ptr);
112 	DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->buf);
113 
114 	/* Overflow check.
115 	 *
116 	 * Limit example: 0xffffffffUL / 2U = 0x7fffffffUL, we reject >= 0x80000000UL.
117 	 */
118 	oldlen = enc_ctx->len;
119 	minlen = oldlen + len;
120 	if (DUK_UNLIKELY(oldlen > DUK_SIZE_MAX / 2U || minlen < oldlen)) {
121 		duk__cbor_encode_error(enc_ctx);
122 	}
123 
124 #if defined(DUK_CBOR_STRESS)
125 	newlen = oldlen + 1U;
126 #else
127 	newlen = oldlen * 2U;
128 #endif
129 	DUK_ASSERT(newlen >= oldlen);
130 
131 	if (minlen > newlen) {
132 		newlen = minlen;
133 	}
134 	DUK_ASSERT(newlen >= oldlen);
135 	DUK_ASSERT(newlen >= minlen);
136 	DUK_ASSERT(newlen > 0U);
137 
138 	DUK_DD(DUK_DDPRINT("cbor encode buffer resized to %ld", (long) newlen));
139 
140 	p_new = (duk_uint8_t *) duk_resize_buffer(enc_ctx->thr, enc_ctx->idx_buf, newlen);
141 	DUK_ASSERT(p_new != NULL);
142 	old_data_len = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf);
143 	enc_ctx->buf = p_new;
144 	enc_ctx->buf_end = p_new + newlen;
145 	enc_ctx->ptr = p_new + old_data_len;
146 	enc_ctx->len = newlen;
147 }
148 
duk__cbor_encode_ensure(duk_cbor_encode_context * enc_ctx,duk_size_t len)149 DUK_LOCAL DUK_INLINE void duk__cbor_encode_ensure(duk_cbor_encode_context *enc_ctx, duk_size_t len) {
150 	if (DUK_LIKELY((duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr) >= len)) {
151 		return;
152 	}
153 	duk__cbor_encode_ensure_slowpath(enc_ctx, len);
154 }
155 
duk__cbor_get_reserve(duk_cbor_encode_context * enc_ctx)156 DUK_LOCAL duk_size_t duk__cbor_get_reserve(duk_cbor_encode_context *enc_ctx) {
157 	DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf);
158 	DUK_ASSERT(enc_ctx->ptr <= enc_ctx->buf_end);
159 	return (duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr);
160 }
161 
duk__cbor_encode_uint32(duk_cbor_encode_context * enc_ctx,duk_uint32_t u,duk_uint8_t base)162 DUK_LOCAL void duk__cbor_encode_uint32(duk_cbor_encode_context *enc_ctx, duk_uint32_t u, duk_uint8_t base) {
163 	duk_uint8_t *p;
164 
165 	/* Caller must ensure space. */
166 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 4);
167 
168 	p = enc_ctx->ptr;
169 	if (DUK_LIKELY(u <= 23U)) {
170 		*p++ = (duk_uint8_t) (base + (duk_uint8_t) u);
171 	} else if (u <= 0xffUL) {
172 		*p++ = base + 0x18U;
173 		*p++ = (duk_uint8_t) u;
174 	} else if (u <= 0xffffUL) {
175 		*p++ = base + 0x19U;
176 		DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) u);
177 	} else {
178 		*p++ = base + 0x1aU;
179 		DUK_RAW_WRITEINC_U32_BE(p, u);
180 	}
181 	enc_ctx->ptr = p;
182 }
183 
184 #if defined(DUK_CBOR_DOUBLE_AS_IS)
duk__cbor_encode_double(duk_cbor_encode_context * enc_ctx,double d)185 DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) {
186 	duk_uint8_t *p;
187 
188 	/* Caller must ensure space. */
189 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
190 
191 	p = enc_ctx->ptr;
192 	*p++ = 0xfbU;
193 	DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
194 	p += 8;
195 	enc_ctx->ptr = p;
196 }
197 #else  /* DUK_CBOR_DOUBLE_AS_IS */
duk__cbor_encode_double_fp(duk_cbor_encode_context * enc_ctx,double d)198 DUK_LOCAL void duk__cbor_encode_double_fp(duk_cbor_encode_context *enc_ctx, double d) {
199 	duk_double_union u;
200 	duk_uint16_t u16;
201 	duk_int16_t expt;
202 	duk_uint8_t *p;
203 
204 	DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO);
205 
206 	/* Caller must ensure space. */
207 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
208 
209 	/* Organize into little endian (no-op if platform is little endian). */
210 	u.d = d;
211 	duk_dblunion_host_to_little(&u);
212 
213 	/* Check if 'd' can represented as a normal half-float.
214 	 * Denormal half-floats could also be used, but that check
215 	 * isn't done now (denormal half-floats are decoded of course).
216 	 * So just check exponent range and that at most 10 significant
217 	 * bits (excluding implicit leading 1) are used in 'd'.
218 	 */
219 	u16 = (((duk_uint16_t) u.uc[7]) << 8) | ((duk_uint16_t) u.uc[6]);
220 	expt = (duk_int16_t) ((u16 & 0x7ff0U) >> 4) - 1023;
221 
222 	if (expt >= -14 && expt <= 15) {
223 		/* Half-float normal exponents (excl. denormals).
224 		 *
225 		 *          7        6        5        4        3        2        1        0  (LE index)
226 		 * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
227 		 * half:         seeeee mmmm mmmmmm00 00000000 00000000 00000000 00000000 00000000
228 		 */
229 		duk_bool_t use_half_float;
230 
231 		use_half_float =
232 		    (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && u.uc[3] == 0 &&
233 		     u.uc[4] == 0 && (u.uc[5] & 0x03U) == 0);
234 
235 		if (use_half_float) {
236 			duk_uint32_t t;
237 
238 			expt += 15;
239 			t = (duk_uint32_t) (u.uc[7] & 0x80U) << 8;
240 			t += (duk_uint32_t) expt << 10;
241 			t += ((duk_uint32_t) u.uc[6] & 0x0fU) << 6;
242 			t += ((duk_uint32_t) u.uc[5]) >> 2;
243 
244 			/* seeeeemm mmmmmmmm */
245 			p = enc_ctx->ptr;
246 			*p++ = 0xf9U;
247 			DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) t);
248 			enc_ctx->ptr = p;
249 			return;
250 		}
251 	}
252 
253 	/* Same check for plain float.  Also no denormal support here. */
254 	if (expt >= -126 && expt <= 127) {
255 		/* Float normal exponents (excl. denormals).
256 		 *
257 		 * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
258 		 * float:     seeee eeeemmmm mmmmmmmm mmmmmmmm mmm00000 00000000 00000000 00000000
259 		 */
260 		duk_bool_t use_float;
261 		duk_float_t d_float;
262 
263 		/* We could do this explicit mantissa check, but doing
264 		 * a double-float-double cast is fine because we've
265 		 * already verified that the exponent is in range so
266 		 * that the narrower cast is not undefined behavior.
267 		 */
268 #if 0
269 		use_float =
270 		    (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && (u.uc[3] & 0xe0U) == 0);
271 #endif
272 		d_float = (duk_float_t) d;
273 		use_float = duk_double_equals((duk_double_t) d_float, d);
274 		if (use_float) {
275 			p = enc_ctx->ptr;
276 			*p++ = 0xfaU;
277 			DUK_RAW_WRITEINC_FLOAT_BE(p, d_float);
278 			enc_ctx->ptr = p;
279 			return;
280 		}
281 	}
282 
283 	/* Special handling for NaN and Inf which we want to encode as
284 	 * half-floats.  They share the same (maximum) exponent.
285 	 */
286 	if (expt == 1024) {
287 		DUK_ASSERT(DUK_ISNAN(d) || DUK_ISINF(d));
288 		p = enc_ctx->ptr;
289 		*p++ = 0xf9U;
290 		if (DUK_ISNAN(d)) {
291 			/* Shortest NaN encoding is using a half-float.  Lose the
292 			 * exact NaN bits in the process.  IEEE double would be
293 			 * 7ff8 0000 0000 0000, i.e. a quiet NaN in most architectures
294 			 * (https://en.wikipedia.org/wiki/NaN#Encoding).  The
295 			 * equivalent half float is 7e00.
296 			 */
297 			*p++ = 0x7eU;
298 		} else {
299 			/* Shortest +/- Infinity encoding is using a half-float. */
300 			if (DUK_SIGNBIT(d)) {
301 				*p++ = 0xfcU;
302 			} else {
303 				*p++ = 0x7cU;
304 			}
305 		}
306 		*p++ = 0x00U;
307 		enc_ctx->ptr = p;
308 		return;
309 	}
310 
311 	/* Cannot use half-float or float, encode as full IEEE double. */
312 	p = enc_ctx->ptr;
313 	*p++ = 0xfbU;
314 	DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
315 	enc_ctx->ptr = p;
316 }
317 
duk__cbor_encode_double(duk_cbor_encode_context * enc_ctx,double d)318 DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) {
319 	duk_uint8_t *p;
320 	double d_floor;
321 
322 	/* Integers and floating point values of all types are conceptually
323 	 * equivalent in CBOR.  Try to always choose the shortest encoding
324 	 * which is not always immediately obvious.  For example, NaN and Inf
325 	 * can be most compactly represented as a half-float (assuming NaN
326 	 * bits are not preserved), and 0x1'0000'0000 as a single precision
327 	 * float.  Shortest forms in preference order (prefer integer over
328 	 * float when equal length):
329 	 *
330 	 *   uint        1 byte    [0,23] (not -0)
331 	 *   sint        1 byte    [-24,-1]
332 	 *   uint+1      2 bytes   [24,255]
333 	 *   sint+1      2 bytes   [-256,-25]
334 	 *   uint+2      3 bytes   [256,65535]
335 	 *   sint+2      3 bytes   [-65536,-257]
336 	 *   half-float  3 bytes   -0, NaN, +/- Infinity, range [-65504,65504]
337 	 *   uint+4      5 bytes   [65536,4294967295]
338 	 *   sint+4      5 bytes   [-4294967296,-258]
339 	 *   float       5 bytes   range [-(1 - 2^(-24)) * 2^128, (1 - 2^(-24)) * 2^128]
340 	 *   uint+8      9 bytes   [4294967296,18446744073709551615]
341 	 *   sint+8      9 bytes   [-18446744073709551616,-4294967297]
342 	 *   double      9 bytes
343 	 *
344 	 * For whole numbers (compatible with integers):
345 	 *   - 1-byte or 2-byte uint/sint representation is preferred for
346 	 *     [-256,255].
347 	 *   - 3-byte uint/sint is preferred for [-65536,65535].  Half floats
348 	 *     are never preferred because they have the same length.
349 	 *   - 5-byte uint/sint is preferred for [-4294967296,4294967295].
350 	 *     Single precision floats are never preferred, and half-floats
351 	 *     don't reach above the 3-byte uint/sint range so they're never
352 	 *     preferred.
353 	 *   - So, for all integers up to signed/unsigned 32-bit range the
354 	 *     preferred encoding is always an integer uint/sint.
355 	 *   - For integers above 32 bits the situation is more complicated.
356 	 *     Half-floats are never useful for them because of their limited
357 	 *     range, but IEEE single precision floats (5 bytes encoded) can
358 	 *     represent some integers between the 32-bit and 64-bit ranges
359 	 *     which require 9 bytes as a uint/sint.
360 	 *
361 	 * For floating point values not compatible with integers, the
362 	 * preferred encoding is quite clear:
363 	 *   - For +Inf/-Inf use half-float.
364 	 *   - For NaN use a half-float, assuming NaN bits ("payload") is
365 	 *     not worth preserving.  Duktape doesn't in general guarantee
366 	 *     preservation of the NaN payload so using a half-float seems
367 	 *     consistent with that.
368 	 *   - For remaining values, prefer the shortest form which doesn't
369 	 *     lose any precision.  For normal half-floats and single precision
370 	 *     floats this is simple: just check exponent and mantissa bits
371 	 *     using a fixed mask.  For denormal half-floats and single
372 	 *     precision floats the check is a bit more complicated: a normal
373 	 *     IEEE double can sometimes be represented as a denormal
374 	 *     half-float or single precision float.
375 	 *
376 	 * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#IEEE_754_half-precision_binary_floating-point_format:_binary16
377 	 */
378 
379 	/* Caller must ensure space. */
380 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
381 
382 	/* Most important path is integers.  The floor() test will be true
383 	 * for Inf too (but not NaN).
384 	 */
385 	d_floor = DUK_FLOOR(d);  /* identity if d is +/- 0.0, NaN, or +/- Infinity */
386 	if (DUK_LIKELY(duk_double_equals(d_floor, d) != 0)) {
387 		DUK_ASSERT(!DUK_ISNAN(d));  /* NaN == NaN compares false. */
388 		if (DUK_SIGNBIT(d)) {
389 			if (d >= -4294967296.0) {
390 				d = -1.0 - d;
391 				if (d >= 0.0) {
392 					DUK_ASSERT(d >= 0.0);
393 					duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x20U);
394 					return;
395 				}
396 
397 				/* Input was negative zero, d == -1.0 < 0.0.
398 				 * Shortest -0 is using half-float.
399 				 */
400 				p = enc_ctx->ptr;
401 				*p++ = 0xf9U;
402 				*p++ = 0x80U;
403 				*p++ = 0x00U;
404 				enc_ctx->ptr = p;
405 				return;
406 			}
407 		} else {
408 			if (d <= 4294967295.0) {
409 				/* Positive zero needs no special handling. */
410 				DUK_ASSERT(d >= 0.0);
411 				duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x00U);
412 				return;
413 			}
414 		}
415 	}
416 
417 	/* 64-bit integers are not supported at present.  So
418 	 * we also don't need to deal with choosing between a
419 	 * 64-bit uint/sint representation vs. IEEE double or
420 	 * float.
421 	 */
422 
423 	DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO);
424 	duk__cbor_encode_double_fp(enc_ctx, d);
425 }
426 #endif  /* DUK_CBOR_DOUBLE_AS_IS */
427 
duk__cbor_encode_string_top(duk_cbor_encode_context * enc_ctx)428 DUK_LOCAL void duk__cbor_encode_string_top(duk_cbor_encode_context *enc_ctx) {
429 	const duk_uint8_t *str;
430 	duk_size_t len;
431 	duk_uint8_t *p;
432 
433 	/* CBOR differentiates between UTF-8 text strings and byte strings.
434 	 * Text strings MUST be valid UTF-8, so not all Duktape strings can
435 	 * be encoded as valid CBOR text strings.  Possible behaviors:
436 	 *
437 	 *   1. Use text string when input is valid UTF-8, otherwise use
438 	 *      byte string (maybe tagged to indicate it was an extended
439 	 *      UTF-8 string).
440 	 *   2. Always use text strings, but sanitize input string so that
441 	 *      invalid UTF-8 is replaced with U+FFFD for example.  Combine
442 	 *      surrogates whenever possible.
443 	 *   3. Always use byte strings.  This is simple and produces valid
444 	 *      CBOR, but isn't ideal for interoperability.
445 	 *   4. Always use text strings, even for invalid UTF-8 such as
446 	 *      codepoints in the surrogate pair range.  This is simple but
447 	 *      produces technically invalid CBOR for non-UTF-8 strings which
448 	 *      may affect interoperability.
449 	 *
450 	 * Current default is 1; can be changed with defines.
451 	 */
452 
453 	/* Caller must ensure space. */
454 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
455 
456 	str = (const duk_uint8_t *) duk_require_lstring(enc_ctx->thr, -1, &len);
457 	if (duk_is_symbol(enc_ctx->thr, -1)) {
458 		/* Symbols, encode as an empty table for now.  This matches
459 		 * the behavior of cbor-js.
460 		 *
461 		 * XXX: Maybe encode String() coercion with a tag?
462 		 * XXX: Option to keep enough information to recover
463 		 * Symbols when decoding (this is not always desirable).
464 		 */
465 		p = enc_ctx->ptr;
466 		*p++ = 0xa0U;
467 		enc_ctx->ptr = p;
468 		return;
469 	}
470 
471 	duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
472 #if defined(DUK_CBOR_TEXT_STRINGS)
473 	duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x60U);
474 #elif defined(DUK_CBOR_BYTE_STRINGS)
475 	duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
476 #else
477 	duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len,
478 	                        (DUK_LIKELY(duk_unicode_is_utf8_compatible(str, len) != 0) ? 0x60U : 0x40U));
479 #endif
480 	duk__cbor_encode_ensure(enc_ctx, len);
481 	p = enc_ctx->ptr;
482 	duk_memcpy((void *) p, (const void *) str, len);
483 	p += len;
484 	enc_ctx->ptr = p;
485 }
486 
duk__cbor_encode_object(duk_cbor_encode_context * enc_ctx)487 DUK_LOCAL void duk__cbor_encode_object(duk_cbor_encode_context *enc_ctx) {
488 	duk_uint8_t *buf;
489 	duk_size_t len;
490 	duk_uint8_t *p;
491 	duk_size_t i;
492 	duk_size_t off_ib;
493 	duk_uint32_t count;
494 
495 	/* Caller must ensure space. */
496 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
497 
498 	duk__cbor_encode_objarr_entry(enc_ctx);
499 
500 	/* XXX: Support for specific built-ins like Date and RegExp. */
501 	if (duk_is_array(enc_ctx->thr, -1)) {
502 		/* Shortest encoding for arrays >= 256 in length is actually
503 		 * the indefinite length one (3 or more bytes vs. 2 bytes).
504 		 * We still use the definite length version because it is
505 		 * more decoding friendly.
506 		 */
507 		len = duk_get_length(enc_ctx->thr, -1);
508 		duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
509 		duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x80U);
510 		for (i = 0; i < len; i++) {
511 			duk_get_prop_index(enc_ctx->thr, -1, (duk_uarridx_t) i);
512 			duk__cbor_encode_value(enc_ctx);
513 		}
514 	} else if (duk_is_buffer_data(enc_ctx->thr, -1)) {
515 		/* XXX: Tag buffer data?
516 		 * XXX: Encode typed arrays as integer arrays rather
517 		 * than buffer data as is?
518 		 */
519 		buf = (duk_uint8_t *) duk_require_buffer_data(enc_ctx->thr, -1, &len);
520 		duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
521 		duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
522 		duk__cbor_encode_ensure(enc_ctx, len);
523 		p = enc_ctx->ptr;
524 		duk_memcpy_unsafe((void *) p, (const void *) buf, len);
525 		p += len;
526 		enc_ctx->ptr = p;
527 	} else {
528 		/* We don't know the number of properties in advance
529 		 * but would still like to encode at least small
530 		 * objects without indefinite length.  Emit an
531 		 * indefinite length byte initially, and if the final
532 		 * property count is small enough to also fit in one
533 		 * byte, backpatch it later.  Otherwise keep the
534 		 * indefinite length.  This works well up to 23
535 		 * properties which is practical and good enough.
536 		 */
537 		off_ib = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf);  /* XXX: get_offset? */
538 		count = 0U;
539 		p = enc_ctx->ptr;
540 		*p++ = 0xa0U + 0x1fU;  /* indefinite length */
541 		enc_ctx->ptr = p;
542 		duk_enum(enc_ctx->thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);
543 		while (duk_next(enc_ctx->thr, -1, 1 /*get_value*/)) {
544 			duk_insert(enc_ctx->thr, -2);  /* [ ... key value ] -> [ ... value key ] */
545 			duk__cbor_encode_value(enc_ctx);
546 			duk__cbor_encode_value(enc_ctx);
547 			count++;
548 			if (count == 0U) {
549 				duk__cbor_encode_error(enc_ctx);
550 			}
551 		}
552 		duk_pop(enc_ctx->thr);
553 		if (count <= 0x17U) {
554 			DUK_ASSERT(off_ib < enc_ctx->len);
555 			enc_ctx->buf[off_ib] = 0xa0U + (duk_uint8_t) count;
556 		} else {
557 			duk__cbor_encode_ensure(enc_ctx, 1);
558 			p = enc_ctx->ptr;
559 			*p++ = 0xffU;  /* break */
560 			enc_ctx->ptr = p;
561 		}
562 	}
563 
564 	duk__cbor_encode_objarr_exit(enc_ctx);
565 }
566 
duk__cbor_encode_buffer(duk_cbor_encode_context * enc_ctx)567 DUK_LOCAL void duk__cbor_encode_buffer(duk_cbor_encode_context *enc_ctx) {
568 	duk_uint8_t *buf;
569 	duk_size_t len;
570 	duk_uint8_t *p;
571 
572 	/* Caller must ensure space. */
573 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
574 
575 	/* Tag buffer data? */
576 	buf = (duk_uint8_t *) duk_require_buffer(enc_ctx->thr, -1, &len);
577 	duk__cbor_encode_sizet_uint32_check(enc_ctx, len);
578 	duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U);
579 	duk__cbor_encode_ensure(enc_ctx, len);
580 	p = enc_ctx->ptr;
581 	duk_memcpy_unsafe((void *) p, (const void *) buf, len);
582 	p += len;
583 	enc_ctx->ptr = p;
584 }
585 
duk__cbor_encode_pointer(duk_cbor_encode_context * enc_ctx)586 DUK_LOCAL void duk__cbor_encode_pointer(duk_cbor_encode_context *enc_ctx) {
587 	/* Pointers (void *) are challenging to encode.  They can't
588 	 * be relied to be even 64-bit integer compatible (there are
589 	 * pointer models larger than that), nor can floats encode
590 	 * them.  They could be encoded as strings (%p format) but
591 	 * that's not portable.  They could be encoded as direct memory
592 	 * representations.  Recovering pointers is non-portable in any
593 	 * case but it would be nice to be able to detect and recover
594 	 * compatible pointers.
595 	 *
596 	 * For now, encode as "(%p)" string, matching JX.  There doesn't
597 	 * seem to be an appropriate tag, so pointers don't currently
598 	 * survive a CBOR encode/decode roundtrip intact.
599 	 */
600 	const char *ptr;
601 
602 	ptr = duk_to_string(enc_ctx->thr, -1);
603 	DUK_ASSERT(ptr != NULL);
604 	duk_push_sprintf(enc_ctx->thr, "(%s)", ptr);
605 	duk_remove(enc_ctx->thr, -2);
606 	duk__cbor_encode_string_top(enc_ctx);
607 }
608 
duk__cbor_encode_lightfunc(duk_cbor_encode_context * enc_ctx)609 DUK_LOCAL void duk__cbor_encode_lightfunc(duk_cbor_encode_context *enc_ctx) {
610 	duk_uint8_t *p;
611 
612 	/* Caller must ensure space. */
613 	DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8);
614 
615 	/* For now encode as an empty object. */
616 	p = enc_ctx->ptr;
617 	*p++ = 0xa0U;
618 	enc_ctx->ptr = p;
619 }
620 
duk__cbor_encode_value(duk_cbor_encode_context * enc_ctx)621 DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx) {
622 	duk_uint8_t *p;
623 
624 	/* Encode/decode cycle currently loses some type information.
625 	 * This can be improved by registering custom tags with IANA.
626 	 */
627 
628 	/* Reserve space for up to 64-bit types (1 initial byte + 8
629 	 * followup bytes).  This allows encoding of integers, floats,
630 	 * string/buffer length fields, etc without separate checks
631 	 * in each code path.
632 	 */
633 	duk__cbor_encode_ensure(enc_ctx, 1 + 8);
634 
635 	switch (duk_get_type(enc_ctx->thr, -1)) {
636 	case DUK_TYPE_UNDEFINED: {
637 		p = enc_ctx->ptr;
638 		*p++ = 0xf7;
639 		enc_ctx->ptr = p;
640 		break;
641 	}
642 	case DUK_TYPE_NULL: {
643 		p = enc_ctx->ptr;
644 		*p++ = 0xf6;
645 		enc_ctx->ptr = p;
646 		break;
647 	}
648 	case DUK_TYPE_BOOLEAN: {
649 		duk_uint8_t u8 = duk_get_boolean(enc_ctx->thr, -1) ? 0xf5U : 0xf4U;
650 		p = enc_ctx->ptr;
651 		*p++ = u8;
652 		enc_ctx->ptr = p;
653 		break;
654 	}
655 	case DUK_TYPE_NUMBER: {
656 		duk__cbor_encode_double(enc_ctx, duk_get_number(enc_ctx->thr, -1));
657 		break;
658 	}
659 	case DUK_TYPE_STRING: {
660 		duk__cbor_encode_string_top(enc_ctx);
661 		break;
662 	}
663 	case DUK_TYPE_OBJECT: {
664 		duk__cbor_encode_object(enc_ctx);
665 		break;
666 	}
667 	case DUK_TYPE_BUFFER: {
668 		duk__cbor_encode_buffer(enc_ctx);
669 		break;
670 	}
671 	case DUK_TYPE_POINTER: {
672 		duk__cbor_encode_pointer(enc_ctx);
673 		break;
674 	}
675 	case DUK_TYPE_LIGHTFUNC: {
676 		duk__cbor_encode_lightfunc(enc_ctx);
677 		break;
678 	}
679 	case DUK_TYPE_NONE:
680 	default:
681 		goto fail;
682 	}
683 
684 	duk_pop(enc_ctx->thr);
685 	return;
686 
687  fail:
688 	duk__cbor_encode_error(enc_ctx);
689 }
690 
691 /*
692  *  Decoding
693  */
694 
duk__cbor_decode_error(duk_cbor_decode_context * dec_ctx)695 DUK_LOCAL void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) {
696 	(void) duk_type_error(dec_ctx->thr, "cbor decode error");
697 }
698 
duk__cbor_decode_req_stack(duk_cbor_decode_context * dec_ctx)699 DUK_LOCAL void duk__cbor_decode_req_stack(duk_cbor_decode_context *dec_ctx) {
700 	duk_require_stack(dec_ctx->thr, 4);
701 }
702 
duk__cbor_decode_objarr_entry(duk_cbor_decode_context * dec_ctx)703 DUK_LOCAL void duk__cbor_decode_objarr_entry(duk_cbor_decode_context *dec_ctx) {
704 	duk_hthread *thr = dec_ctx->thr;
705 
706 	/* Native stack check in object/array recursion. */
707 	duk_native_stack_check(thr);
708 
709 	duk__cbor_decode_req_stack(dec_ctx);
710 
711 	DUK_ASSERT(dec_ctx->recursion_depth <= dec_ctx->recursion_limit);
712 	if (dec_ctx->recursion_depth >= dec_ctx->recursion_limit) {
713 		DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT);
714 		DUK_WO_NORETURN(return;);
715 	}
716 	dec_ctx->recursion_depth++;
717 }
718 
duk__cbor_decode_objarr_exit(duk_cbor_decode_context * dec_ctx)719 DUK_LOCAL void duk__cbor_decode_objarr_exit(duk_cbor_decode_context *dec_ctx) {
720 	DUK_ASSERT(dec_ctx->recursion_depth > 0);
721 	dec_ctx->recursion_depth--;
722 }
723 
duk__cbor_decode_readbyte(duk_cbor_decode_context * dec_ctx)724 DUK_LOCAL duk_uint8_t duk__cbor_decode_readbyte(duk_cbor_decode_context *dec_ctx) {
725 	DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
726 	if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 1U)) {
727 		duk__cbor_decode_error(dec_ctx);
728 	}
729 	return dec_ctx->buf[dec_ctx->off++];
730 }
731 
duk__cbor_decode_read_u16(duk_cbor_decode_context * dec_ctx)732 DUK_LOCAL duk_uint16_t duk__cbor_decode_read_u16(duk_cbor_decode_context *dec_ctx) {
733 	duk_uint16_t res;
734 
735 	DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
736 	if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 2U)) {
737 		duk__cbor_decode_error(dec_ctx);
738 	}
739 	res = DUK_RAW_READ_U16_BE(dec_ctx->buf + dec_ctx->off);
740 	dec_ctx->off += 2;
741 	return res;
742 }
743 
duk__cbor_decode_read_u32(duk_cbor_decode_context * dec_ctx)744 DUK_LOCAL duk_uint32_t duk__cbor_decode_read_u32(duk_cbor_decode_context *dec_ctx) {
745 	duk_uint32_t res;
746 
747 	DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
748 	if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 4U)) {
749 		duk__cbor_decode_error(dec_ctx);
750 	}
751 	res = DUK_RAW_READ_U32_BE(dec_ctx->buf + dec_ctx->off);
752 	dec_ctx->off += 4;
753 	return res;
754 }
755 
duk__cbor_decode_peekbyte(duk_cbor_decode_context * dec_ctx)756 DUK_LOCAL duk_uint8_t duk__cbor_decode_peekbyte(duk_cbor_decode_context *dec_ctx) {
757 	if (DUK_UNLIKELY(dec_ctx->off >= dec_ctx->len)) {
758 		duk__cbor_decode_error(dec_ctx);
759 	}
760 	return dec_ctx->buf[dec_ctx->off];
761 }
762 
duk__cbor_decode_rewind(duk_cbor_decode_context * dec_ctx,duk_size_t len)763 DUK_LOCAL void duk__cbor_decode_rewind(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
764 	DUK_ASSERT(len <= dec_ctx->off);  /* Caller must ensure. */
765 	dec_ctx->off -= len;
766 }
767 
768 #if 0
769 DUK_LOCAL void duk__cbor_decode_ensure(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
770 	if (dec_ctx->off + len > dec_ctx->len) {
771 		duk__cbor_decode_error(dec_ctx);
772 	}
773 }
774 #endif
775 
duk__cbor_decode_consume(duk_cbor_decode_context * dec_ctx,duk_size_t len)776 DUK_LOCAL const duk_uint8_t *duk__cbor_decode_consume(duk_cbor_decode_context *dec_ctx, duk_size_t len) {
777 	DUK_ASSERT(dec_ctx->off <= dec_ctx->len);
778 	if (DUK_LIKELY(dec_ctx->len - dec_ctx->off >= len)) {
779 		const duk_uint8_t *res = dec_ctx->buf + dec_ctx->off;
780 		dec_ctx->off += len;
781 		return res;
782 	}
783 
784 	duk__cbor_decode_error(dec_ctx);  /* Not enough input. */
785 	return NULL;
786 }
787 
duk__cbor_decode_checkbreak(duk_cbor_decode_context * dec_ctx)788 DUK_LOCAL int duk__cbor_decode_checkbreak(duk_cbor_decode_context *dec_ctx) {
789 	if (duk__cbor_decode_peekbyte(dec_ctx) == 0xffU) {
790 		DUK_ASSERT(dec_ctx->off < dec_ctx->len);
791 		dec_ctx->off++;
792 #if 0
793 		(void) duk__cbor_decode_readbyte(dec_ctx);
794 #endif
795 		return 1;
796 	}
797 	return 0;
798 }
799 
duk__cbor_decode_push_aival_int(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib,duk_bool_t negative)800 DUK_LOCAL void duk__cbor_decode_push_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_bool_t negative) {
801 	duk_uint8_t ai;
802 	duk_uint32_t t, t1, t2;
803 #if 0
804 	duk_uint64_t t3;
805 #endif
806 	duk_double_t d1, d2;
807 	duk_double_t d;
808 
809 	ai = ib & 0x1fU;
810 	if (ai <= 0x17U) {
811 		t = ai;
812 		goto shared_exit;
813 	}
814 
815 	switch (ai) {
816 	case 0x18U:  /* 1 byte */
817 		t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx);
818 		goto shared_exit;
819 	case 0x19U:  /* 2 byte */
820 		t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx);
821 		goto shared_exit;
822 	case 0x1aU:  /* 4 byte */
823 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
824 		goto shared_exit;
825 	case 0x1bU:  /* 8 byte */
826 		/* For uint64 it's important to handle the -1.0 part before
827 		 * casting to double: otherwise the adjustment might be lost
828 		 * in the cast.  Uses: -1.0 - d <=> -(d + 1.0).
829 		 */
830 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
831 		t2 = t;
832 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
833 		t1 = t;
834 #if 0
835 		t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1;
836 		if (negative) {
837 			if (t3 == DUK_UINT64_MAX) {
838 				/* -(0xffff'ffff'ffff'ffffULL + 1) =
839 				 * -0x1'0000'0000'0000'0000
840 				 *
841 				 * >>> -0x10000000000000000
842 				 * -18446744073709551616L
843 				 */
844 				return -18446744073709551616.0;
845 			} else {
846 				return -((duk_double_t) (t3 + DUK_U64_CONSTANT(1)));
847 			}
848 		} else {
849 			return (duk_double_t) t3;  /* XXX: cast helper */
850 		}
851 #endif
852 #if 0
853 		t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1;
854 		if (negative) {
855 			/* Simpler version: take advantage of the fact that
856 			 * 0xffff'ffff'ffff'ffff and 0x1'0000'0000'0000'0000
857 			 * both round to 0x1'0000'0000'0000'0000:
858 			 * > (0xffffffffffffffff).toString(16)
859 			 * '10000000000000000'
860 			 * > (0x10000000000000000).toString(16)
861 			 * '10000000000000000'
862 			 *
863 			 * For the DUK_UINT64_MAX case we just skip the +1
864 			 * increment to avoid wrapping; the result still
865 			 * comes out right for an IEEE double cast.
866 			 */
867 			if (t3 != DUK_UINT64_MAX) {
868 				t3++;
869 			}
870 			return -((duk_double_t) t3);
871 		} else {
872 			return (duk_double_t) t3;  /* XXX: cast helper */
873 		}
874 #endif
875 #if 1
876 		/* Use two double parts, avoids dependency on 64-bit type.
877 		 * Avoid precision loss carefully, especially when dealing
878 		 * with the required +1 for negative values.
879 		 *
880 		 * No fastint check for this path at present.
881 		 */
882 		d1 = (duk_double_t) t1;  /* XXX: cast helpers */
883 		d2 = (duk_double_t) t2 * 4294967296.0;
884 		if (negative) {
885 			d1 += 1.0;
886 		}
887 		d = d2 + d1;
888 		if (negative) {
889 			d = -d;
890 		}
891 #endif
892 		/* XXX: a push and check for fastint API would be nice */
893 		duk_push_number(dec_ctx->thr, d);
894 		return;
895 	}
896 
897 	duk__cbor_decode_error(dec_ctx);
898 	return;
899 
900  shared_exit:
901 	if (negative) {
902 		/* XXX: a push and check for fastint API would be nice */
903 		if ((duk_uint_t) t <= (duk_uint_t) -(DUK_INT_MIN + 1)) {
904 			duk_push_int(dec_ctx->thr, -1 - ((duk_int_t) t));
905 		} else {
906 			duk_push_number(dec_ctx->thr, -1.0 - (duk_double_t) t);
907 		}
908 	} else {
909 		duk_push_uint(dec_ctx->thr, (duk_uint_t) t);
910 	}
911 }
912 
duk__cbor_decode_skip_aival_int(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib)913 DUK_LOCAL void duk__cbor_decode_skip_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) {
914 	const duk_int8_t skips[32] = {
915 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
916 		0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, -1, -1, -1, -1
917 	};
918 	duk_uint8_t ai;
919 	duk_int8_t skip;
920 
921 	ai = ib & 0x1fU;
922 	skip = skips[ai];
923 	if (DUK_UNLIKELY(skip < 0)) {
924 		duk__cbor_decode_error(dec_ctx);
925 	}
926 	duk__cbor_decode_consume(dec_ctx, (duk_size_t) skip);
927 	return;
928 }
929 
duk__cbor_decode_aival_uint32(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib)930 DUK_LOCAL duk_uint32_t duk__cbor_decode_aival_uint32(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) {
931 	duk_uint8_t ai;
932 	duk_uint32_t t;
933 
934 	ai = ib & 0x1fU;
935 	if (ai <= 0x17U) {
936 		return (duk_uint32_t) ai;
937 	}
938 
939 	switch (ai) {
940 	case 0x18U:  /* 1 byte */
941 		t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx);
942 		return t;
943 	case 0x19U:  /* 2 byte */
944 		t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx);
945 		return t;
946 	case 0x1aU:  /* 4 byte */
947 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
948 		return t;
949 	case 0x1bU:  /* 8 byte */
950 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
951 		if (t != 0U) {
952 			break;
953 		}
954 		t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx);
955 		return t;
956 	}
957 
958 	duk__cbor_decode_error(dec_ctx);
959 	return 0U;
960 }
961 
duk__cbor_decode_buffer(duk_cbor_decode_context * dec_ctx,duk_uint8_t expected_base)962 DUK_LOCAL void duk__cbor_decode_buffer(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) {
963 	duk_uint32_t len;
964 	duk_uint8_t *buf;
965 	const duk_uint8_t *inp;
966 	duk_uint8_t ib;
967 
968 	ib = duk__cbor_decode_readbyte(dec_ctx);
969 	if ((ib & 0xe0U) != expected_base) {
970 		duk__cbor_decode_error(dec_ctx);
971 	}
972 	/* Indefinite format is rejected by the following on purpose. */
973 	len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
974 	inp = duk__cbor_decode_consume(dec_ctx, len);
975 	/* XXX: duk_push_fixed_buffer_with_data() would be a nice API addition. */
976 	buf = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, (duk_size_t) len);
977 	duk_memcpy((void *) buf, (const void *) inp, (size_t) len);
978 }
979 
duk__cbor_decode_join_buffers(duk_cbor_decode_context * dec_ctx,duk_idx_t count)980 DUK_LOCAL void duk__cbor_decode_join_buffers(duk_cbor_decode_context *dec_ctx, duk_idx_t count) {
981 	duk_size_t total_size = 0;
982 	duk_idx_t top = duk_get_top(dec_ctx->thr);
983 	duk_idx_t base = top - count;  /* count is >= 1 */
984 	duk_idx_t idx;
985 	duk_uint8_t *p = NULL;
986 
987 	DUK_ASSERT(count >= 1);
988 	DUK_ASSERT(top >= count);
989 
990 	for (;;) {
991 		/* First round: compute total size.
992 		 * Second round: copy into place.
993 		 */
994 		for (idx = base; idx < top; idx++) {
995 			duk_uint8_t *buf_data;
996 			duk_size_t buf_size;
997 
998 			buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, idx, &buf_size);
999 			if (p != NULL) {
1000 				duk_memcpy_unsafe((void *) p, (const void *) buf_data, buf_size);
1001 				p += buf_size;
1002 			} else {
1003 				total_size += buf_size;
1004 				if (DUK_UNLIKELY(total_size < buf_size)) {  /* Wrap check. */
1005 					duk__cbor_decode_error(dec_ctx);
1006 				}
1007 			}
1008 		}
1009 
1010 		if (p != NULL) {
1011 			break;
1012 		} else {
1013 			p = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, total_size);
1014 			DUK_ASSERT(p != NULL);
1015 		}
1016 	}
1017 
1018 	duk_replace(dec_ctx->thr, base);
1019 	duk_pop_n(dec_ctx->thr, count - 1);
1020 }
1021 
duk__cbor_decode_and_join_strbuf(duk_cbor_decode_context * dec_ctx,duk_uint8_t expected_base)1022 DUK_LOCAL void duk__cbor_decode_and_join_strbuf(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) {
1023 	duk_idx_t count = 0;
1024 	for (;;) {
1025 		if (duk__cbor_decode_checkbreak(dec_ctx)) {
1026 			break;
1027 		}
1028 		duk_require_stack(dec_ctx->thr, 1);
1029 		duk__cbor_decode_buffer(dec_ctx, expected_base);
1030 		count++;
1031 		if (DUK_UNLIKELY(count <= 0)) {  /* Wrap check. */
1032 			duk__cbor_decode_error(dec_ctx);
1033 		}
1034 	}
1035 	if (count == 0) {
1036 		(void) duk_push_fixed_buffer(dec_ctx->thr, 0);
1037 	} else if (count > 1) {
1038 		duk__cbor_decode_join_buffers(dec_ctx, count);
1039 	}
1040 }
1041 
duk__cbor_decode_half_float(duk_cbor_decode_context * dec_ctx)1042 DUK_LOCAL duk_double_t duk__cbor_decode_half_float(duk_cbor_decode_context *dec_ctx) {
1043 	duk_double_union u;
1044 	const duk_uint8_t *inp;
1045 	duk_int_t expt;
1046 	duk_uint_t u16;
1047 	duk_uint_t tmp;
1048 	duk_double_t res;
1049 
1050 	inp = duk__cbor_decode_consume(dec_ctx, 2);
1051 	u16 = ((duk_uint_t) inp[0] << 8) + (duk_uint_t) inp[1];
1052 	expt = (duk_int_t) ((u16 >> 10) & 0x1fU) - 15;
1053 
1054 	/* Reconstruct IEEE double into little endian order first, then convert
1055 	 * to host order.
1056 	 */
1057 
1058 	duk_memzero((void *) &u, sizeof(u));
1059 
1060 	if (expt == -15) {
1061 		/* Zero or denormal; but note that half float
1062 		 * denormals become double normals.
1063 		 */
1064 		if ((u16 & 0x03ffU) == 0) {
1065 			u.uc[7] = inp[0] & 0x80U;
1066 		} else {
1067 			/* Create denormal by first creating a double that
1068 			 * contains the denormal bits and a leading implicit
1069 			 * 1-bit.  Then subtract away the implicit 1-bit.
1070 			 *
1071 			 *    0.mmmmmmmmmm * 2^-14
1072 			 *    1.mmmmmmmmmm 0.... * 2^-14
1073 			 *   -1.0000000000 0.... * 2^-14
1074 			 *
1075 			 * Double exponent: -14 + 1023 = 0x3f1
1076 			 */
1077 			u.uc[7] = 0x3fU;
1078 			u.uc[6] = 0x10U + (duk_uint8_t) ((u16 >> 6) & 0x0fU);
1079 			u.uc[5] = (duk_uint8_t) ((u16 << 2) & 0xffU);  /* Mask is really 0xfcU */
1080 
1081 			duk_dblunion_little_to_host(&u);
1082 			res = u.d - 0.00006103515625;  /* 2^(-14) */
1083 			if (u16 & 0x8000U) {
1084 				res = -res;
1085 			}
1086 			return res;
1087 		}
1088 	} else if (expt == 16) {
1089 		/* +/- Inf or NaN. */
1090 		if ((u16 & 0x03ffU) == 0) {
1091 			u.uc[7] = (inp[0] & 0x80U) + 0x7fU;
1092 			u.uc[6] = 0xf0U;
1093 		} else {
1094 			/* Create a 'quiet NaN' with highest
1095 			 * bit set (there are some platforms
1096 			 * where the NaN payload convention is
1097 			 * the opposite).  Keep sign.
1098 			 */
1099 			u.uc[7] = (inp[0] & 0x80U) + 0x7fU;
1100 			u.uc[6] = 0xf8U;
1101 		}
1102 	} else {
1103 		/* Normal. */
1104 		tmp = (inp[0] & 0x80U) ? 0x80000000UL : 0UL;
1105 		tmp += (duk_uint_t) (expt + 1023) << 20;
1106 		tmp += (duk_uint_t) (inp[0] & 0x03U) << 18;
1107 		tmp += (duk_uint_t) (inp[1] & 0xffU) << 10;
1108 		u.uc[7] = (tmp >> 24) & 0xffU;
1109 		u.uc[6] = (tmp >> 16) & 0xffU;
1110 		u.uc[5] = (tmp >> 8) & 0xffU;
1111 		u.uc[4] = (tmp >> 0) & 0xffU;
1112 	}
1113 
1114 	duk_dblunion_little_to_host(&u);
1115 	return u.d;
1116 }
1117 
duk__cbor_decode_string(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib,duk_uint8_t ai)1118 DUK_LOCAL void duk__cbor_decode_string(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
1119 	/* If the CBOR string data is not valid UTF-8 it is technically
1120 	 * invalid CBOR.  Possible behaviors at least:
1121 	 *
1122 	 *   1. Reject the input, i.e. throw TypeError.
1123 	 *
1124 	 *   2. Accept the input, but sanitize non-UTF-8 data into UTF-8
1125 	 *      using U+FFFD replacements.  Also it might make sense to
1126 	 *      decode non-BMP codepoints into surrogates for better
1127 	 *      ECMAScript compatibility.
1128 	 *
1129 	 *   3. Accept the input as a Duktape string (which are not always
1130 	 *      valid UTF-8), but reject any input that would create a
1131 	 *      Symbol representation.
1132 	 *
1133 	 * Current behavior is 3.
1134 	 */
1135 
1136 	if (ai == 0x1fU) {
1137 		duk_uint8_t *buf_data;
1138 		duk_size_t buf_size;
1139 
1140 		duk__cbor_decode_and_join_strbuf(dec_ctx, 0x60U);
1141 		buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, -1, &buf_size);
1142 		(void) duk_push_lstring(dec_ctx->thr, (const char *) buf_data, buf_size);
1143 		duk_remove(dec_ctx->thr, -2);
1144 	} else {
1145 		duk_uint32_t len;
1146 		const duk_uint8_t *inp;
1147 
1148 		len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
1149 		inp = duk__cbor_decode_consume(dec_ctx, len);
1150 		(void) duk_push_lstring(dec_ctx->thr, (const char *) inp, (duk_size_t) len);
1151 	}
1152 	if (duk_is_symbol(dec_ctx->thr, -1)) {
1153 		/* Refuse to create Symbols when decoding. */
1154 		duk__cbor_decode_error(dec_ctx);
1155 	}
1156 
1157 	/* XXX: Here a Duktape API call to convert input -> utf-8 with
1158 	 * replacements would be nice.
1159 	 */
1160 }
1161 
duk__cbor_decode_array(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib,duk_uint8_t ai)1162 DUK_LOCAL duk_bool_t duk__cbor_decode_array(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
1163 	duk_uint32_t idx, len;
1164 
1165 	duk__cbor_decode_objarr_entry(dec_ctx);
1166 
1167 	/* Support arrays up to 0xfffffffeU in length.  0xffffffff is
1168 	 * used as an indefinite length marker.
1169 	 */
1170 	if (ai == 0x1fU) {
1171 		len = 0xffffffffUL;
1172 	} else {
1173 		len = duk__cbor_decode_aival_uint32(dec_ctx, ib);
1174 		if (len == 0xffffffffUL) {
1175 			goto failure;
1176 		}
1177 	}
1178 
1179 	/* XXX: use bare array? */
1180 	duk_push_array(dec_ctx->thr);
1181 	for (idx = 0U; ;) {
1182 		if (len == 0xffffffffUL && duk__cbor_decode_checkbreak(dec_ctx)) {
1183 			break;
1184 		}
1185 		if (idx == len) {
1186 			if (ai == 0x1fU) {
1187 				goto failure;
1188 			}
1189 			break;
1190 		}
1191 		duk__cbor_decode_value(dec_ctx);
1192 		duk_put_prop_index(dec_ctx->thr, -2, (duk_uarridx_t) idx);
1193 		idx++;
1194 		if (idx == 0U) {
1195 			goto failure;  /* wrapped */
1196 		}
1197 	}
1198 
1199 #if 0
1200  success:
1201 #endif
1202 	duk__cbor_decode_objarr_exit(dec_ctx);
1203 	return 1;
1204 
1205  failure:
1206 	/* No need to unwind recursion checks, caller will throw. */
1207 	return 0;
1208 }
1209 
duk__cbor_decode_map(duk_cbor_decode_context * dec_ctx,duk_uint8_t ib,duk_uint8_t ai)1210 DUK_LOCAL duk_bool_t duk__cbor_decode_map(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) {
1211 	duk_uint32_t count;
1212 
1213 	duk__cbor_decode_objarr_entry(dec_ctx);
1214 
1215 	if (ai == 0x1fU) {
1216 		count = 0xffffffffUL;
1217 	} else {
1218 		count = duk__cbor_decode_aival_uint32(dec_ctx, ib);
1219 		if (count == 0xffffffffUL) {
1220 			goto failure;
1221 		}
1222 	}
1223 
1224 	/* XXX: use bare object? */
1225 	duk_push_object(dec_ctx->thr);
1226 	for (;;) {
1227 		if (count == 0xffffffffUL) {
1228 			if (duk__cbor_decode_checkbreak(dec_ctx)) {
1229 				break;
1230 			}
1231 		} else {
1232 			if (count == 0UL) {
1233 				break;
1234 			}
1235 			count--;
1236 		}
1237 
1238 		/* Non-string keys are coerced to strings,
1239 		 * possibly leading to overwriting previous
1240 		 * keys.  Last key of a certain coerced name
1241 		 * wins.  If key is an object, it will coerce
1242 		 * to '[object Object]' which is consistent
1243 		 * but potentially misleading.  One alternative
1244 		 * would be to skip non-string keys.
1245 		 */
1246 		duk__cbor_decode_value(dec_ctx);
1247 		duk__cbor_decode_value(dec_ctx);
1248 		duk_put_prop(dec_ctx->thr, -3);
1249 	}
1250 
1251 #if 0
1252  success:
1253 #endif
1254 	duk__cbor_decode_objarr_exit(dec_ctx);
1255 	return 1;
1256 
1257  failure:
1258 	/* No need to unwind recursion checks, caller will throw. */
1259 	return 0;
1260 }
1261 
duk__cbor_decode_float(duk_cbor_decode_context * dec_ctx)1262 DUK_LOCAL duk_double_t duk__cbor_decode_float(duk_cbor_decode_context *dec_ctx) {
1263 	duk_float_union u;
1264 	const duk_uint8_t *inp;
1265 	inp = duk__cbor_decode_consume(dec_ctx, 4);
1266 	duk_memcpy((void *) u.uc, (const void *) inp, 4);
1267 	duk_fltunion_big_to_host(&u);
1268 	return (duk_double_t) u.f;
1269 }
1270 
duk__cbor_decode_double(duk_cbor_decode_context * dec_ctx)1271 DUK_LOCAL duk_double_t duk__cbor_decode_double(duk_cbor_decode_context *dec_ctx) {
1272 	duk_double_union u;
1273 	const duk_uint8_t *inp;
1274 	inp = duk__cbor_decode_consume(dec_ctx, 8);
1275 	duk_memcpy((void *) u.uc, (const void *) inp, 8);
1276 	duk_dblunion_big_to_host(&u);
1277 	return u.d;
1278 }
1279 
1280 #if defined(DUK_CBOR_DECODE_FASTPATH)
1281 #define DUK__CBOR_AI  (ib & 0x1fU)
1282 
duk__cbor_decode_value(duk_cbor_decode_context * dec_ctx)1283 DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) {
1284 	duk_uint8_t ib;
1285 
1286 	/* Any paths potentially recursing back to duk__cbor_decode_value()
1287 	 * must perform a Duktape value stack growth check.  Avoid the check
1288 	 * here for simple paths like primitive values.
1289 	 */
1290 
1291  reread_initial_byte:
1292 	DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld", (long) dec_ctx->off, (long) dec_ctx->len));
1293 
1294 	ib = duk__cbor_decode_readbyte(dec_ctx);
1295 
1296 	/* Full initial byte switch, footprint cost over baseline is ~+1kB. */
1297 	/* XXX: Force full switch with no range check. */
1298 
1299 	switch (ib) {
1300 	case 0x00U: case 0x01U: case 0x02U: case 0x03U: case 0x04U: case 0x05U: case 0x06U: case 0x07U:
1301 	case 0x08U: case 0x09U: case 0x0aU: case 0x0bU: case 0x0cU: case 0x0dU: case 0x0eU: case 0x0fU:
1302 	case 0x10U: case 0x11U: case 0x12U: case 0x13U: case 0x14U: case 0x15U: case 0x16U: case 0x17U:
1303 		duk_push_uint(dec_ctx->thr, ib);
1304 		break;
1305 	case 0x18U: case 0x19U: case 0x1aU: case 0x1bU:
1306 		duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/);
1307 		break;
1308 	case 0x1cU: case 0x1dU: case 0x1eU: case 0x1fU:
1309 		goto format_error;
1310 	case 0x20U: case 0x21U: case 0x22U: case 0x23U: case 0x24U: case 0x25U: case 0x26U: case 0x27U:
1311 	case 0x28U: case 0x29U: case 0x2aU: case 0x2bU: case 0x2cU: case 0x2dU: case 0x2eU: case 0x2fU:
1312 	case 0x30U: case 0x31U: case 0x32U: case 0x33U: case 0x34U: case 0x35U: case 0x36U: case 0x37U:
1313 		duk_push_int(dec_ctx->thr, -((duk_int_t) ((ib - 0x20U) + 1U)));
1314 		break;
1315 	case 0x38U: case 0x39U: case 0x3aU: case 0x3bU:
1316 		duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/);
1317 		break;
1318 	case 0x3cU: case 0x3dU: case 0x3eU: case 0x3fU:
1319 		goto format_error;
1320 	case 0x40U: case 0x41U: case 0x42U: case 0x43U: case 0x44U: case 0x45U: case 0x46U: case 0x47U:
1321 	case 0x48U: case 0x49U: case 0x4aU: case 0x4bU: case 0x4cU: case 0x4dU: case 0x4eU: case 0x4fU:
1322 	case 0x50U: case 0x51U: case 0x52U: case 0x53U: case 0x54U: case 0x55U: case 0x56U: case 0x57U:
1323 		/* XXX: Avoid rewind, we know the length already. */
1324 		DUK_ASSERT(dec_ctx->off > 0U);
1325 		dec_ctx->off--;
1326 		duk__cbor_decode_buffer(dec_ctx, 0x40U);
1327 		break;
1328 	case 0x58U: case 0x59U: case 0x5aU: case 0x5bU:
1329 		/* XXX: Avoid rewind, decode length inline. */
1330 		DUK_ASSERT(dec_ctx->off > 0U);
1331 		dec_ctx->off--;
1332 		duk__cbor_decode_buffer(dec_ctx, 0x40U);
1333 		break;
1334 	case 0x5cU: case 0x5dU: case 0x5eU:
1335 		goto format_error;
1336 	case 0x5fU:
1337 		duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U);
1338 		break;
1339 	case 0x60U: case 0x61U: case 0x62U: case 0x63U: case 0x64U: case 0x65U: case 0x66U: case 0x67U:
1340 	case 0x68U: case 0x69U: case 0x6aU: case 0x6bU: case 0x6cU: case 0x6dU: case 0x6eU: case 0x6fU:
1341 	case 0x70U: case 0x71U: case 0x72U: case 0x73U: case 0x74U: case 0x75U: case 0x76U: case 0x77U:
1342 		/* XXX: Avoid double decode of length. */
1343 		duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
1344 		break;
1345 	case 0x78U: case 0x79U: case 0x7aU: case 0x7bU:
1346 		/* XXX: Avoid double decode of length. */
1347 		duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
1348 		break;
1349 	case 0x7cU: case 0x7dU: case 0x7eU:
1350 		goto format_error;
1351 	case 0x7fU:
1352 		duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI);
1353 		break;
1354 	case 0x80U: case 0x81U: case 0x82U: case 0x83U: case 0x84U: case 0x85U: case 0x86U: case 0x87U:
1355 	case 0x88U: case 0x89U: case 0x8aU: case 0x8bU: case 0x8cU: case 0x8dU: case 0x8eU: case 0x8fU:
1356 	case 0x90U: case 0x91U: case 0x92U: case 0x93U: case 0x94U: case 0x95U: case 0x96U: case 0x97U:
1357 		if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1358 			goto format_error;
1359 		}
1360 		break;
1361 	case 0x98U: case 0x99U: case 0x9aU: case 0x9bU:
1362 		if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1363 			goto format_error;
1364 		}
1365 		break;
1366 	case 0x9cU: case 0x9dU: case 0x9eU:
1367 		goto format_error;
1368 	case 0x9fU:
1369 		if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1370 			goto format_error;
1371 		}
1372 		break;
1373 	case 0xa0U: case 0xa1U: case 0xa2U: case 0xa3U: case 0xa4U: case 0xa5U: case 0xa6U: case 0xa7U:
1374 	case 0xa8U: case 0xa9U: case 0xaaU: case 0xabU: case 0xacU: case 0xadU: case 0xaeU: case 0xafU:
1375 	case 0xb0U: case 0xb1U: case 0xb2U: case 0xb3U: case 0xb4U: case 0xb5U: case 0xb6U: case 0xb7U:
1376 		if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1377 			goto format_error;
1378 		}
1379 		break;
1380 	case 0xb8U: case 0xb9U: case 0xbaU: case 0xbbU:
1381 		if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1382 			goto format_error;
1383 		}
1384 		break;
1385 	case 0xbcU: case 0xbdU: case 0xbeU:
1386 		goto format_error;
1387 	case 0xbfU:
1388 		if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) {
1389 			goto format_error;
1390 		}
1391 		break;
1392 	case 0xc0U: case 0xc1U: case 0xc2U: case 0xc3U: case 0xc4U: case 0xc5U: case 0xc6U: case 0xc7U:
1393 	case 0xc8U: case 0xc9U: case 0xcaU: case 0xcbU: case 0xccU: case 0xcdU: case 0xceU: case 0xcfU:
1394 	case 0xd0U: case 0xd1U: case 0xd2U: case 0xd3U: case 0xd4U: case 0xd5U: case 0xd6U: case 0xd7U:
1395 		/* Tag 0-23: drop. */
1396 		goto reread_initial_byte;
1397 	case 0xd8U: case 0xd9U: case 0xdaU: case 0xdbU:
1398 		duk__cbor_decode_skip_aival_int(dec_ctx, ib);
1399 		goto reread_initial_byte;
1400 	case 0xdcU: case 0xddU: case 0xdeU: case 0xdfU:
1401 		goto format_error;
1402 	case 0xe0U:
1403 		goto format_error;
1404 	case 0xe1U:
1405 		goto format_error;
1406 	case 0xe2U:
1407 		goto format_error;
1408 	case 0xe3U:
1409 		goto format_error;
1410 	case 0xe4U:
1411 		goto format_error;
1412 	case 0xe5U:
1413 		goto format_error;
1414 	case 0xe6U:
1415 		goto format_error;
1416 	case 0xe7U:
1417 		goto format_error;
1418 	case 0xe8U:
1419 		goto format_error;
1420 	case 0xe9U:
1421 		goto format_error;
1422 	case 0xeaU:
1423 		goto format_error;
1424 	case 0xebU:
1425 		goto format_error;
1426 	case 0xecU:
1427 		goto format_error;
1428 	case 0xedU:
1429 		goto format_error;
1430 	case 0xeeU:
1431 		goto format_error;
1432 	case 0xefU:
1433 		goto format_error;
1434 	case 0xf0U:
1435 		goto format_error;
1436 	case 0xf1U:
1437 		goto format_error;
1438 	case 0xf2U:
1439 		goto format_error;
1440 	case 0xf3U:
1441 		goto format_error;
1442 	case 0xf4U:
1443 		duk_push_false(dec_ctx->thr);
1444 		break;
1445 	case 0xf5U:
1446 		duk_push_true(dec_ctx->thr);
1447 		break;
1448 	case 0xf6U:
1449 		duk_push_null(dec_ctx->thr);
1450 		break;
1451 	case 0xf7U:
1452 		duk_push_undefined(dec_ctx->thr);
1453 		break;
1454 	case 0xf8U:
1455 		/* Simple value 32-255, nothing defined yet, so reject. */
1456 		goto format_error;
1457 	case 0xf9U: {
1458 		duk_double_t d;
1459 		d = duk__cbor_decode_half_float(dec_ctx);
1460 		duk_push_number(dec_ctx->thr, d);
1461 		break;
1462 	}
1463 	case 0xfaU: {
1464 		duk_double_t d;
1465 		d = duk__cbor_decode_float(dec_ctx);
1466 		duk_push_number(dec_ctx->thr, d);
1467 		break;
1468 	}
1469 	case 0xfbU: {
1470 		duk_double_t d;
1471 		d = duk__cbor_decode_double(dec_ctx);
1472 		duk_push_number(dec_ctx->thr, d);
1473 		break;
1474 	}
1475 	case 0xfcU:
1476 	case 0xfdU:
1477 	case 0xfeU:
1478 	case 0xffU:
1479 		goto format_error;
1480 	}  /* end switch */
1481 
1482 	return;
1483 
1484  format_error:
1485 	duk__cbor_decode_error(dec_ctx);
1486 }
1487 #else  /* DUK_CBOR_DECODE_FASTPATH */
duk__cbor_decode_value(duk_cbor_decode_context * dec_ctx)1488 DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) {
1489 	duk_uint8_t ib, mt, ai;
1490 
1491 	/* Any paths potentially recursing back to duk__cbor_decode_value()
1492 	 * must perform a Duktape value stack growth check.  Avoid the check
1493 	 * here for simple paths like primitive values.
1494 	 */
1495 
1496  reread_initial_byte:
1497 	DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld", (long) dec_ctx->off, (long) dec_ctx->len));
1498 
1499 	ib = duk__cbor_decode_readbyte(dec_ctx);
1500 	mt = ib >> 5U;
1501 	ai = ib & 0x1fU;
1502 
1503 	/* Additional information in [24,27] = [0x18,0x1b] has relatively
1504 	 * uniform handling for all major types: read 1/2/4/8 additional
1505 	 * bytes.  For major type 7 the 1-byte value is a 'simple type', and
1506 	 * 2/4/8-byte values are floats.  For other major types the 1/2/4/8
1507 	 * byte values are integers.  The lengths are uniform, but the typing
1508 	 * is not.
1509 	 */
1510 
1511 	switch (mt) {
1512 	case 0U: {  /* unsigned integer */
1513 		duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/);
1514 		break;
1515 	}
1516 	case 1U: {  /* negative integer */
1517 		duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/);
1518 		break;
1519 	}
1520 	case 2U: {  /* byte string */
1521 		if (ai == 0x1fU) {
1522 			duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U);
1523 		} else {
1524 			duk__cbor_decode_rewind(dec_ctx, 1U);
1525 			duk__cbor_decode_buffer(dec_ctx, 0x40U);
1526 		}
1527 		break;
1528 	}
1529 	case 3U: {  /* text string */
1530 		duk__cbor_decode_string(dec_ctx, ib, ai);
1531 		break;
1532 	}
1533 	case 4U: {  /* array of data items */
1534 		if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, ai) == 0)) {
1535 			goto format_error;
1536 		}
1537 		break;
1538 	}
1539 	case 5U: {  /* map of pairs of data items */
1540 		if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, ai) == 0)) {
1541 			goto format_error;
1542 		}
1543 		break;
1544 	}
1545 	case 6U: {  /* semantic tagging */
1546 		/* Tags are ignored now, re-read initial byte.  A tagged
1547 		 * value may itself be tagged (an unlimited number of times)
1548 		 * so keep on peeling away tags.
1549 		 */
1550 		duk__cbor_decode_skip_aival_int(dec_ctx, ib);
1551 		goto reread_initial_byte;
1552 	}
1553 	case 7U: {  /* floating point numbers, simple data types, break; other */
1554 		switch (ai) {
1555 		case 0x14U: {
1556 			duk_push_false(dec_ctx->thr);
1557 			break;
1558 		}
1559 		case 0x15U: {
1560 			duk_push_true(dec_ctx->thr);
1561 			break;
1562 		}
1563 		case 0x16U: {
1564 			duk_push_null(dec_ctx->thr);
1565 			break;
1566 		}
1567 		case 0x17U: {
1568 			duk_push_undefined(dec_ctx->thr);
1569 			break;
1570 		}
1571 		case 0x18U: {  /* more simple values (1 byte) */
1572 			/* Simple value encoded in additional byte (none
1573 			 * are defined so far).  RFC 7049 states that the
1574 			 * follow-up byte must be 32-255 to minimize
1575 			 * confusion.  So, a non-shortest encoding like
1576 			 * f815 (= true, shortest encoding f5) must be
1577 			 * rejected.  cbor.me tester rejects f815, but
1578 			 * e.g. Python CBOR binding decodes it as true.
1579 			 */
1580 			goto format_error;
1581 		}
1582 		case 0x19U: {  /* half-float (2 bytes) */
1583 			duk_double_t d;
1584 			d = duk__cbor_decode_half_float(dec_ctx);
1585 			duk_push_number(dec_ctx->thr, d);
1586 			break;
1587 		}
1588 		case 0x1aU: {  /* float (4 bytes) */
1589 			duk_double_t d;
1590 			d = duk__cbor_decode_float(dec_ctx);
1591 			duk_push_number(dec_ctx->thr, d);
1592 			break;
1593 		}
1594 		case 0x1bU: {  /* double (8 bytes) */
1595 			duk_double_t d;
1596 			d = duk__cbor_decode_double(dec_ctx);
1597 			duk_push_number(dec_ctx->thr, d);
1598 			break;
1599 		}
1600 		case 0xffU:  /* unexpected break */
1601 		default: {
1602 			goto format_error;
1603 		}
1604 		}  /* end switch */
1605 		break;
1606 	}
1607 	default: {
1608 		goto format_error;  /* will never actually occur */
1609 	}
1610 	}  /* end switch */
1611 
1612 	return;
1613 
1614  format_error:
1615 	duk__cbor_decode_error(dec_ctx);
1616 }
1617 #endif  /* DUK_CBOR_DECODE_FASTPATH */
1618 
duk__cbor_encode(duk_hthread * thr,duk_idx_t idx,duk_uint_t encode_flags)1619 DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
1620 	duk_cbor_encode_context enc_ctx;
1621 	duk_uint8_t *buf;
1622 
1623 	DUK_UNREF(encode_flags);
1624 
1625 	idx = duk_require_normalize_index(thr, idx);
1626 
1627 	enc_ctx.thr = thr;
1628 	enc_ctx.idx_buf = duk_get_top(thr);
1629 
1630 	enc_ctx.len = 64;
1631 	buf = (duk_uint8_t *) duk_push_dynamic_buffer(thr, enc_ctx.len);
1632 	enc_ctx.ptr = buf;
1633 	enc_ctx.buf = buf;
1634 	enc_ctx.buf_end = buf + enc_ctx.len;
1635 
1636 	enc_ctx.recursion_depth = 0;
1637 	enc_ctx.recursion_limit = DUK_USE_CBOR_ENC_RECLIMIT;
1638 
1639 	duk_dup(thr, idx);
1640 	duk__cbor_encode_req_stack(&enc_ctx);
1641 	duk__cbor_encode_value(&enc_ctx);
1642 	DUK_ASSERT(enc_ctx.recursion_depth == 0);
1643 	duk_resize_buffer(enc_ctx.thr, enc_ctx.idx_buf, (duk_size_t) (enc_ctx.ptr - enc_ctx.buf));
1644 	duk_replace(thr, idx);
1645 }
1646 
duk__cbor_decode(duk_hthread * thr,duk_idx_t idx,duk_uint_t decode_flags)1647 DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
1648 	duk_cbor_decode_context dec_ctx;
1649 
1650 	DUK_UNREF(decode_flags);
1651 
1652 	/* Suppress compile warnings for functions only needed with e.g.
1653 	 * asserts enabled.
1654 	 */
1655 	DUK_UNREF(duk__cbor_get_reserve);
1656 
1657 	idx = duk_require_normalize_index(thr, idx);
1658 
1659 	dec_ctx.thr = thr;
1660 	dec_ctx.buf = (const duk_uint8_t *) duk_require_buffer_data(thr, idx, &dec_ctx.len);
1661 	dec_ctx.off = 0;
1662 	/* dec_ctx.len: set above */
1663 
1664 	dec_ctx.recursion_depth = 0;
1665 	dec_ctx.recursion_limit = DUK_USE_CBOR_DEC_RECLIMIT;
1666 
1667 	duk__cbor_decode_req_stack(&dec_ctx);
1668 	duk__cbor_decode_value(&dec_ctx);
1669 	DUK_ASSERT(dec_ctx.recursion_depth == 0);
1670 	if (dec_ctx.off != dec_ctx.len) {
1671 		(void) duk_type_error(thr, "trailing garbage");
1672 	}
1673 
1674 	duk_replace(thr, idx);
1675 }
1676 
1677 #else  /* DUK_USE_CBOR_SUPPORT */
1678 
duk__cbor_encode(duk_hthread * thr,duk_idx_t idx,duk_uint_t encode_flags)1679 DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
1680 	DUK_UNREF(idx);
1681 	DUK_UNREF(encode_flags);
1682 	DUK_ERROR_UNSUPPORTED(thr);
1683 }
1684 
duk__cbor_decode(duk_hthread * thr,duk_idx_t idx,duk_uint_t decode_flags)1685 DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
1686 	DUK_UNREF(idx);
1687 	DUK_UNREF(decode_flags);
1688 	DUK_ERROR_UNSUPPORTED(thr);
1689 }
1690 
1691 #endif  /* DUK_USE_CBOR_SUPPORT */
1692 
1693 /*
1694  *  Public APIs
1695  */
1696 
duk_cbor_encode(duk_hthread * thr,duk_idx_t idx,duk_uint_t encode_flags)1697 DUK_EXTERNAL void duk_cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) {
1698 	DUK_ASSERT_API_ENTRY(thr);
1699 	duk__cbor_encode(thr, idx, encode_flags);
1700 }
duk_cbor_decode(duk_hthread * thr,duk_idx_t idx,duk_uint_t decode_flags)1701 DUK_EXTERNAL void duk_cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) {
1702 	DUK_ASSERT_API_ENTRY(thr);
1703 	duk__cbor_decode(thr, idx, decode_flags);
1704 }
1705 
1706 #if defined(DUK_USE_CBOR_BUILTIN)
1707 #if defined(DUK_USE_CBOR_SUPPORT)
duk_bi_cbor_encode(duk_hthread * thr)1708 DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) {
1709 	DUK_ASSERT_TOP(thr, 1);
1710 
1711 	duk__cbor_encode(thr, -1, 0 /*flags*/);
1712 
1713 	/* Produce an ArrayBuffer by first decoding into a plain buffer which
1714 	 * mimics a Uint8Array and gettings its .buffer property.
1715 	 */
1716 	/* XXX: shortcut */
1717 	(void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_LC_BUFFER);
1718 	return 1;
1719 }
1720 
duk_bi_cbor_decode(duk_hthread * thr)1721 DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) {
1722 	DUK_ASSERT_TOP(thr, 1);
1723 
1724 	duk__cbor_decode(thr, -1, 0 /*flags*/);
1725 	return 1;
1726 }
1727 #else  /* DUK_USE_CBOR_SUPPORT */
duk_bi_cbor_encode(duk_hthread * thr)1728 DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) {
1729 	DUK_ERROR_UNSUPPORTED(thr);
1730 	DUK_WO_NORETURN(return 0;);
1731 }
duk_bi_cbor_decode(duk_hthread * thr)1732 DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) {
1733 	DUK_ERROR_UNSUPPORTED(thr);
1734 	DUK_WO_NORETURN(return 0;);
1735 }
1736 #endif  /* DUK_USE_CBOR_SUPPORT */
1737 #endif  /* DUK_USE_CBOR_BUILTIN */
1738