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