mini_racer 0.17.0.pre5 → 0.17.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +4 -0
- data/ext/mini_racer_extension/extconf.rb +2 -0
- data/ext/mini_racer_extension/mini_racer_extension.c +1564 -0
- data/ext/mini_racer_extension/mini_racer_v8.cc +840 -0
- data/ext/mini_racer_extension/mini_racer_v8.h +56 -0
- data/ext/mini_racer_extension/serde.c +747 -0
- data/lib/mini_racer/truffleruby.rb +31 -4
- data/lib/mini_racer/version.rb +1 -1
- data/lib/mini_racer.rb +14 -387
- metadata +10 -7
- data/ext/mini_racer_extension/mini_racer_extension.cc +0 -1942
@@ -0,0 +1,747 @@
|
|
1
|
+
#include <err.h>
|
2
|
+
#include <math.h>
|
3
|
+
#include <stdbool.h>
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <stdlib.h>
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <string.h>
|
8
|
+
|
9
|
+
static void des_null(void *arg);
|
10
|
+
static void des_undefined(void *arg);
|
11
|
+
static void des_bool(void *arg, int v);
|
12
|
+
static void des_int(void *arg, int64_t v);
|
13
|
+
static void des_num(void *arg, double v);
|
14
|
+
static void des_date(void *arg, double v);
|
15
|
+
// des_bigint: |p| points to |n|/8 quadwords in little-endian order
|
16
|
+
// des_bigint: |p| is not quadword aligned
|
17
|
+
// des_bigint: |n| is in bytes, not quadwords
|
18
|
+
// des_bigint: |n| is zero when bigint is zero
|
19
|
+
// des_bigint: |sign| is 1 or -1
|
20
|
+
static void des_bigint(void *arg, const void *p, size_t n, int sign);
|
21
|
+
static void des_string(void *arg, const char *s, size_t n);
|
22
|
+
static void des_string8(void *arg, const uint8_t *s, size_t n);
|
23
|
+
// des_string16: |s| is not word aligned
|
24
|
+
// des_string16: |n| is in bytes, not code points
|
25
|
+
static void des_string16(void *arg, const void *s, size_t n);
|
26
|
+
static void des_arraybuffer(void *arg, const void *s, size_t n);
|
27
|
+
static void des_array_begin(void *arg);
|
28
|
+
static void des_array_end(void *arg);
|
29
|
+
// called if e.g. an array object has named properties
|
30
|
+
static void des_named_props_begin(void *arg);
|
31
|
+
static void des_named_props_end(void *arg);
|
32
|
+
static void des_object_begin(void *arg);
|
33
|
+
static void des_object_end(void *arg);
|
34
|
+
static void des_object_ref(void *arg, uint32_t id);
|
35
|
+
// des_error_begin: followed by des_object_begin + des_object_end calls
|
36
|
+
static void des_error_begin(void *arg);
|
37
|
+
static void des_error_end(void *arg);
|
38
|
+
|
39
|
+
// dynamically sized buffer with inline storage so we don't
|
40
|
+
// have to worry about allocation failures for small payloads
|
41
|
+
typedef struct Buf {
|
42
|
+
uint8_t *buf;
|
43
|
+
uint32_t len, cap;
|
44
|
+
uint8_t buf_s[48];
|
45
|
+
} Buf;
|
46
|
+
|
47
|
+
typedef struct Ser {
|
48
|
+
Buf b;
|
49
|
+
char err[64];
|
50
|
+
} Ser;
|
51
|
+
|
52
|
+
static const uint8_t the_nan[8] = {0,0,0,0,0,0,0xF8,0x7F}; // canonical nan
|
53
|
+
|
54
|
+
// note: returns |v| if v in [0,1,2]
|
55
|
+
static inline uint32_t next_power_of_two(uint32_t v) {
|
56
|
+
v -= 1;
|
57
|
+
v |= v >> 1;
|
58
|
+
v |= v >> 2;
|
59
|
+
v |= v >> 4;
|
60
|
+
v |= v >> 8;
|
61
|
+
v |= v >> 16;
|
62
|
+
v += 1;
|
63
|
+
return v;
|
64
|
+
}
|
65
|
+
|
66
|
+
static inline void buf_init(Buf *b)
|
67
|
+
{
|
68
|
+
b->len = 0;
|
69
|
+
b->buf = b->buf_s;
|
70
|
+
b->cap = sizeof(b->buf_s);
|
71
|
+
}
|
72
|
+
|
73
|
+
static inline void buf_reset(Buf *b)
|
74
|
+
{
|
75
|
+
if (b->buf != b->buf_s)
|
76
|
+
free(b->buf);
|
77
|
+
buf_init(b);
|
78
|
+
}
|
79
|
+
|
80
|
+
static inline void buf_move(Buf *s, Buf *d)
|
81
|
+
{
|
82
|
+
if (s == d)
|
83
|
+
return;
|
84
|
+
*d = *s;
|
85
|
+
if (s->buf == s->buf_s)
|
86
|
+
d->buf = d->buf_s;
|
87
|
+
buf_init(s);
|
88
|
+
}
|
89
|
+
|
90
|
+
static inline int buf_grow(Buf *b, size_t n)
|
91
|
+
{
|
92
|
+
void *p;
|
93
|
+
|
94
|
+
if ((uint64_t)n + b->len > UINT32_MAX)
|
95
|
+
return -1;
|
96
|
+
n += b->len;
|
97
|
+
if (n < b->cap)
|
98
|
+
return 0;
|
99
|
+
n = next_power_of_two(n);
|
100
|
+
p = NULL;
|
101
|
+
if (b->buf != b->buf_s)
|
102
|
+
p = b->buf;
|
103
|
+
p = realloc(p, n);
|
104
|
+
if (!p)
|
105
|
+
return -1;
|
106
|
+
if (b->buf == b->buf_s)
|
107
|
+
memcpy(p, b->buf_s, b->len);
|
108
|
+
b->buf = p;
|
109
|
+
b->cap = n;
|
110
|
+
return 0;
|
111
|
+
}
|
112
|
+
|
113
|
+
static inline int buf_put(Buf *b, const void *p, size_t n)
|
114
|
+
{
|
115
|
+
if (n == 0)
|
116
|
+
return 0;
|
117
|
+
if (buf_grow(b, n))
|
118
|
+
return -1;
|
119
|
+
memcpy(&b->buf[b->len], p, n);
|
120
|
+
b->len += n;
|
121
|
+
return 0;
|
122
|
+
}
|
123
|
+
|
124
|
+
static inline int buf_putc(Buf *b, uint8_t c)
|
125
|
+
{
|
126
|
+
return buf_put(b, &c, 1);
|
127
|
+
}
|
128
|
+
|
129
|
+
static inline void w(Ser *s, const void *p, size_t n)
|
130
|
+
{
|
131
|
+
if (*s->err)
|
132
|
+
return;
|
133
|
+
if (buf_put(&s->b, p, n))
|
134
|
+
snprintf(s->err, sizeof(s->err), "out of memory");
|
135
|
+
}
|
136
|
+
|
137
|
+
static inline void w_byte(Ser *s, uint8_t c)
|
138
|
+
{
|
139
|
+
w(s, &c, 1);
|
140
|
+
}
|
141
|
+
|
142
|
+
static inline void w_varint(Ser *s, uint64_t v)
|
143
|
+
{
|
144
|
+
uint8_t b[10]; // 10 == 1 + 64/7
|
145
|
+
size_t n;
|
146
|
+
|
147
|
+
for (n = 0; v > 127; v >>= 7)
|
148
|
+
b[n++] = 128 | (v & 127);
|
149
|
+
b[n++] = v;
|
150
|
+
w(s, b, n);
|
151
|
+
}
|
152
|
+
|
153
|
+
static inline void w_zigzag(Ser *s, int64_t v)
|
154
|
+
{
|
155
|
+
uint64_t t;
|
156
|
+
|
157
|
+
if (v < 0) {
|
158
|
+
t = -v;
|
159
|
+
} else {
|
160
|
+
t = v;
|
161
|
+
}
|
162
|
+
t += t;
|
163
|
+
t -= (v < 0);
|
164
|
+
w_varint(s, t);
|
165
|
+
}
|
166
|
+
|
167
|
+
static inline int r_varint(const uint8_t **p, const uint8_t *pe, uint64_t *r)
|
168
|
+
{
|
169
|
+
int i, k;
|
170
|
+
|
171
|
+
for (i = 0; i < 5; i++) {
|
172
|
+
if (*p+i == pe)
|
173
|
+
return -1;
|
174
|
+
if ((*p)[i] < 128)
|
175
|
+
goto ok;
|
176
|
+
}
|
177
|
+
return -1;
|
178
|
+
ok:
|
179
|
+
*r = 0;
|
180
|
+
for (k = 0; k <= i; k++, (*p)++)
|
181
|
+
*r |= (uint64_t)(**p & 127) << 7*k;
|
182
|
+
return 0;
|
183
|
+
}
|
184
|
+
|
185
|
+
static inline int r_zigzag(const uint8_t **p, const uint8_t *pe, int64_t *r)
|
186
|
+
{
|
187
|
+
uint64_t v;
|
188
|
+
|
189
|
+
if (r_varint(p, pe, &v))
|
190
|
+
return -1;
|
191
|
+
*r = v&1 ? -(v/2)-1 : v/2;
|
192
|
+
return 0;
|
193
|
+
}
|
194
|
+
|
195
|
+
static inline void ser_init(Ser *s)
|
196
|
+
{
|
197
|
+
memset(s, 0, sizeof(*s));
|
198
|
+
buf_init(&s->b);
|
199
|
+
w(s, "\xFF\x0F", 2);
|
200
|
+
}
|
201
|
+
|
202
|
+
static void ser_init1(Ser *s, uint8_t c)
|
203
|
+
{
|
204
|
+
memset(s, 0, sizeof(*s));
|
205
|
+
buf_init(&s->b);
|
206
|
+
w_byte(s, c);
|
207
|
+
w(s, "\xFF\x0F", 2);
|
208
|
+
}
|
209
|
+
|
210
|
+
static void ser_reset(Ser *s)
|
211
|
+
{
|
212
|
+
buf_reset(&s->b);
|
213
|
+
}
|
214
|
+
|
215
|
+
static void ser_null(Ser *s)
|
216
|
+
{
|
217
|
+
w_byte(s, '0');
|
218
|
+
}
|
219
|
+
|
220
|
+
static void ser_undefined(Ser *s)
|
221
|
+
{
|
222
|
+
w_byte(s, '_');
|
223
|
+
}
|
224
|
+
|
225
|
+
static void ser_bool(Ser *s, int v)
|
226
|
+
{
|
227
|
+
w_byte(s, "TF"[!v]);
|
228
|
+
}
|
229
|
+
|
230
|
+
static void ser_num(Ser *s, double v)
|
231
|
+
{
|
232
|
+
w_byte(s, 'N');
|
233
|
+
if (isnan(v)) {
|
234
|
+
w(s, the_nan, sizeof(the_nan));
|
235
|
+
} else {
|
236
|
+
w(s, &v, sizeof(v));
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
static void ser_int(Ser *s, int64_t v)
|
241
|
+
{
|
242
|
+
if (*s->err)
|
243
|
+
return;
|
244
|
+
if (v < INT32_MIN || v > INT32_MAX) {
|
245
|
+
if (v > INT64_MIN/1024)
|
246
|
+
if (v <= INT64_MAX/1024)
|
247
|
+
return ser_num(s, v);
|
248
|
+
snprintf(s->err, sizeof(s->err), "out of range: %lld", (long long)v);
|
249
|
+
} else {
|
250
|
+
w_byte(s, 'I');
|
251
|
+
w_zigzag(s, v);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
// |v| is the timestamp in milliseconds since the UNIX epoch
|
256
|
+
static void ser_date(Ser *s, double v)
|
257
|
+
{
|
258
|
+
w_byte(s, 'D');
|
259
|
+
if (isfinite(v)) {
|
260
|
+
w(s, &v, sizeof(v));
|
261
|
+
} else {
|
262
|
+
w(s, the_nan, sizeof(the_nan));
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
// ser_bigint: |n| is in bytes, not quadwords
|
267
|
+
static void ser_bigint(Ser *s, const uint64_t *p, size_t n, int sign)
|
268
|
+
{
|
269
|
+
if (*s->err)
|
270
|
+
return;
|
271
|
+
if (n % 8) {
|
272
|
+
snprintf(s->err, sizeof(s->err), "bad bigint");
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
w_byte(s, 'Z');
|
276
|
+
// chop off high all-zero words
|
277
|
+
n /= 8;
|
278
|
+
while (n--)
|
279
|
+
if (p[n])
|
280
|
+
break;
|
281
|
+
if (n == (size_t)-1) {
|
282
|
+
w_byte(s, 0); // normalized zero
|
283
|
+
} else {
|
284
|
+
n = 8*n + 8;
|
285
|
+
w_varint(s, 2*n + (sign < 0));
|
286
|
+
w(s, p, n);
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
// string must be utf8
|
291
|
+
static void ser_string(Ser *s, const char *p, size_t n)
|
292
|
+
{
|
293
|
+
w_byte(s, 'S');
|
294
|
+
w_varint(s, n);
|
295
|
+
w(s, p, n);
|
296
|
+
}
|
297
|
+
|
298
|
+
// string must be latin1
|
299
|
+
static void ser_string8(Ser *s, const uint8_t *p, size_t n)
|
300
|
+
{
|
301
|
+
w_byte(s, '"');
|
302
|
+
w_varint(s, n);
|
303
|
+
w(s, p, n);
|
304
|
+
}
|
305
|
+
|
306
|
+
static void ser_object_begin(Ser *s)
|
307
|
+
{
|
308
|
+
w_byte(s, 'o');
|
309
|
+
}
|
310
|
+
|
311
|
+
// |count| is the property count
|
312
|
+
static void ser_object_end(Ser *s, uint32_t count)
|
313
|
+
{
|
314
|
+
w_byte(s, '{');
|
315
|
+
w_varint(s, count);
|
316
|
+
}
|
317
|
+
|
318
|
+
static void ser_object_ref(Ser *s, uint32_t id)
|
319
|
+
{
|
320
|
+
w_byte(s, '^');
|
321
|
+
w_varint(s, id);
|
322
|
+
}
|
323
|
+
|
324
|
+
static void ser_array_begin(Ser *s, uint32_t count)
|
325
|
+
{
|
326
|
+
w_byte(s, 'A'); // 'A'=dense, 'a'=sparse
|
327
|
+
w_varint(s, count); // element count
|
328
|
+
}
|
329
|
+
|
330
|
+
// |count| is the element count
|
331
|
+
static void ser_array_end(Ser *s, uint32_t count)
|
332
|
+
{
|
333
|
+
w_byte(s, '$');
|
334
|
+
w_varint(s, 0); // property count, always zero
|
335
|
+
w_varint(s, count); // element count
|
336
|
+
}
|
337
|
+
|
338
|
+
static int bail(char (*err)[64], const char *str)
|
339
|
+
{
|
340
|
+
snprintf(*err, sizeof(*err), "%s", str);
|
341
|
+
return -1;
|
342
|
+
}
|
343
|
+
|
344
|
+
static int des1_num(const uint8_t **p, const uint8_t *pe, double *d)
|
345
|
+
{
|
346
|
+
if (pe-*p < (int)sizeof(*d))
|
347
|
+
return -1;
|
348
|
+
memcpy(d, *p, sizeof(*d));
|
349
|
+
*p += sizeof(*d);
|
350
|
+
if (isnan(*d))
|
351
|
+
memcpy(d, the_nan, sizeof(the_nan));
|
352
|
+
return 0;
|
353
|
+
}
|
354
|
+
|
355
|
+
static int des1(char (*err)[64], const uint8_t **p, const uint8_t *pe,
|
356
|
+
void *arg, int depth)
|
357
|
+
{
|
358
|
+
uint64_t s, t, u;
|
359
|
+
uint8_t c;
|
360
|
+
int64_t i;
|
361
|
+
double d;
|
362
|
+
|
363
|
+
if (depth < 0)
|
364
|
+
return bail(err, "too much recursion");
|
365
|
+
if (*p >= pe)
|
366
|
+
goto too_short;
|
367
|
+
switch ((c = *(*p)++)) {
|
368
|
+
default:
|
369
|
+
if (c > 32 && c < 127) {
|
370
|
+
snprintf(*err, sizeof(*err), "bad tag: %c", c);
|
371
|
+
} else {
|
372
|
+
snprintf(*err, sizeof(*err), "bad tag: %02x", c);
|
373
|
+
}
|
374
|
+
return -1;
|
375
|
+
case '\0': // padding
|
376
|
+
break;
|
377
|
+
case '^':
|
378
|
+
if (r_varint(p, pe, &u))
|
379
|
+
goto bad_varint;
|
380
|
+
des_object_ref(arg, u);
|
381
|
+
// object refs can (but need not be) followed by a typed array
|
382
|
+
// that is a view over the arraybufferview
|
383
|
+
goto typed_array;
|
384
|
+
case '0':
|
385
|
+
des_null(arg);
|
386
|
+
break;
|
387
|
+
case '_':
|
388
|
+
des_undefined(arg);
|
389
|
+
break;
|
390
|
+
case 'A': // dense array
|
391
|
+
if (r_varint(p, pe, &u))
|
392
|
+
goto bad_varint;
|
393
|
+
t = u;
|
394
|
+
des_array_begin(arg);
|
395
|
+
while (u--) {
|
396
|
+
if (*p >= pe)
|
397
|
+
goto too_short;
|
398
|
+
// '-' is 'the hole', a marker for representing absent
|
399
|
+
// elements that is inserted when a dense array turns
|
400
|
+
// sparse during serialization; we replace it with undefined
|
401
|
+
if (**p == '-') {
|
402
|
+
(*p)++;
|
403
|
+
des_undefined(arg);
|
404
|
+
} else {
|
405
|
+
if (des1(err, p, pe, arg, depth-1))
|
406
|
+
return -1;
|
407
|
+
}
|
408
|
+
}
|
409
|
+
for (s = 0; /*empty*/; s++) {
|
410
|
+
if (*p >= pe)
|
411
|
+
goto too_short;
|
412
|
+
if (**p == '$')
|
413
|
+
break;
|
414
|
+
if (s < 1)
|
415
|
+
des_named_props_begin(arg);
|
416
|
+
if (des1(err, p, pe, arg, depth-1)) // key
|
417
|
+
return -1;
|
418
|
+
if (des1(err, p, pe, arg, depth-1)) // value
|
419
|
+
return -1;
|
420
|
+
}
|
421
|
+
(*p)++;
|
422
|
+
if (s > 0)
|
423
|
+
des_named_props_end(arg);
|
424
|
+
if (r_varint(p, pe, &u))
|
425
|
+
goto bad_varint;
|
426
|
+
if (s != u)
|
427
|
+
return bail(err, "array property count mismatch");
|
428
|
+
if (r_varint(p, pe, &u))
|
429
|
+
goto bad_varint;
|
430
|
+
if (t != u)
|
431
|
+
return bail(err, "array element count mismatch");
|
432
|
+
des_array_end(arg);
|
433
|
+
break;
|
434
|
+
case 'B': // arraybuffer
|
435
|
+
case '~': // resizable arraybuffer (RAB)
|
436
|
+
if (r_varint(p, pe, &u))
|
437
|
+
goto bad_varint;
|
438
|
+
if (c == '~')
|
439
|
+
if (r_varint(p, pe, &t)) // maxByteLength, unused
|
440
|
+
goto bad_varint;
|
441
|
+
if (pe-*p < (int64_t)u)
|
442
|
+
goto too_short;
|
443
|
+
des_arraybuffer(arg, *p, u);
|
444
|
+
*p += u;
|
445
|
+
// arraybuffers can (but need not be) followed by a typed array
|
446
|
+
// that is a view over the arraybufferview
|
447
|
+
// typed arrays aren't efficiently representable in ruby, and the
|
448
|
+
// concept of a memory view is wholly unrepresentable, so we
|
449
|
+
// simply skip over them; callers get just the arraybuffer
|
450
|
+
typed_array:
|
451
|
+
if (pe-*p < 2)
|
452
|
+
break;
|
453
|
+
if (**p != 'V')
|
454
|
+
break;
|
455
|
+
(*p)++;
|
456
|
+
c = *(*p)++;
|
457
|
+
// ? DataView
|
458
|
+
// B Uint8Array
|
459
|
+
// C Uint8ClampedArray
|
460
|
+
// D Uint32Array
|
461
|
+
// F Float64Array
|
462
|
+
// Q BigUint64Array
|
463
|
+
// W Uint16Array
|
464
|
+
// b Int8Array
|
465
|
+
// d Int32Array
|
466
|
+
// f Float32Array
|
467
|
+
// h Float16Array
|
468
|
+
// q BigInt64Array
|
469
|
+
// w Int16Array
|
470
|
+
if (!strchr("?BCDFQWbdfhqw", **p))
|
471
|
+
return bail(err, "bad typed array");
|
472
|
+
if (r_varint(p, pe, &t)) // byteOffset
|
473
|
+
goto bad_varint;
|
474
|
+
if (r_varint(p, pe, &t)) // byteLength
|
475
|
+
goto bad_varint;
|
476
|
+
if (r_varint(p, pe, &t)) // flags, only non-zero when backed by RAB
|
477
|
+
goto bad_varint;
|
478
|
+
break;
|
479
|
+
case 'a': // sparse array
|
480
|
+
// total element count; ignored because we drop sparse entries
|
481
|
+
if (r_varint(p, pe, &t))
|
482
|
+
goto bad_varint;
|
483
|
+
des_array_begin(arg);
|
484
|
+
for (u = s = 0;;) {
|
485
|
+
if (*p >= pe)
|
486
|
+
goto too_short;
|
487
|
+
c = **p;
|
488
|
+
if (c == '@')
|
489
|
+
break;
|
490
|
+
if (c == 'I' && !s) {
|
491
|
+
u++, (*p)++;
|
492
|
+
if (r_zigzag(p, pe, &i)) // array index, ignored
|
493
|
+
goto bad_varint;
|
494
|
+
if (des1(err, p, pe, arg, depth-1))
|
495
|
+
return -1;
|
496
|
+
} else {
|
497
|
+
if (!s++)
|
498
|
+
des_named_props_begin(arg);
|
499
|
+
if (des1(err, p, pe, arg, depth-1)) // key
|
500
|
+
return -1;
|
501
|
+
if (des1(err, p, pe, arg, depth-1)) // value
|
502
|
+
return -1;
|
503
|
+
}
|
504
|
+
}
|
505
|
+
(*p)++;
|
506
|
+
if (s > 0)
|
507
|
+
des_named_props_end(arg);
|
508
|
+
if (r_varint(p, pe, &t))
|
509
|
+
goto bad_varint;
|
510
|
+
if (t != u+s)
|
511
|
+
return bail(err, "element count mismatch");
|
512
|
+
// total element count; ignored because we drop sparse entries
|
513
|
+
if (r_varint(p, pe, &t))
|
514
|
+
goto bad_varint;
|
515
|
+
des_array_end(arg);
|
516
|
+
break;
|
517
|
+
case 'D':
|
518
|
+
if (des1_num(p, pe, &d))
|
519
|
+
goto too_short;
|
520
|
+
des_date(arg, d);
|
521
|
+
break;
|
522
|
+
case 'F': // primitive boolean
|
523
|
+
case 'x': // new Boolean(...)
|
524
|
+
des_bool(arg, 0);
|
525
|
+
break;
|
526
|
+
case 'T': // primitive boolean
|
527
|
+
case 'y': // new Boolean(...)
|
528
|
+
des_bool(arg, 1);
|
529
|
+
break;
|
530
|
+
case 'I':
|
531
|
+
if (r_zigzag(p, pe, &i))
|
532
|
+
goto bad_varint;
|
533
|
+
des_int(arg, i);
|
534
|
+
break;
|
535
|
+
case 'N': // primitive number
|
536
|
+
case 'n': // new Number(...)
|
537
|
+
if (des1_num(p, pe, &d))
|
538
|
+
goto too_short;
|
539
|
+
des_num(arg, d);
|
540
|
+
break;
|
541
|
+
case 'Z':
|
542
|
+
if (r_varint(p, pe, &u))
|
543
|
+
goto bad_varint;
|
544
|
+
t = u & 1;
|
545
|
+
u = u >> 1;
|
546
|
+
if (u & 7)
|
547
|
+
return bail(err, "bad bigint");
|
548
|
+
// V8's serializer never emits -0n;
|
549
|
+
// its deserializer rejects it with DataCloneError
|
550
|
+
if (t && !u)
|
551
|
+
return bail(err, "negative zero bigint");
|
552
|
+
if (pe-*p < (int64_t)u)
|
553
|
+
goto too_short;
|
554
|
+
des_bigint(arg, *p, u, 1-2*t);
|
555
|
+
*p += u;
|
556
|
+
break;
|
557
|
+
case 'R': // RegExp, deserialized as string
|
558
|
+
if (*p >= pe)
|
559
|
+
goto too_short;
|
560
|
+
switch (**p) {
|
561
|
+
default:
|
562
|
+
return bail(err, "bad regexp");
|
563
|
+
case '"':
|
564
|
+
case 'S':
|
565
|
+
case 'c':
|
566
|
+
break;
|
567
|
+
}
|
568
|
+
if (des1(err, p, pe, arg, depth-1)) // pattern
|
569
|
+
return -1;
|
570
|
+
if (r_varint(p, pe, &t)) // flags; ignored
|
571
|
+
goto bad_varint;
|
572
|
+
break;
|
573
|
+
case 's': // string object, decoded as primitive string
|
574
|
+
if (*p >= pe)
|
575
|
+
goto too_short;
|
576
|
+
switch (*(*p)++) {
|
577
|
+
case '"':
|
578
|
+
goto s_string8;
|
579
|
+
case 'S':
|
580
|
+
goto s_string;
|
581
|
+
case 'c':
|
582
|
+
goto s_string16;
|
583
|
+
}
|
584
|
+
return bail(err, "bad string object");
|
585
|
+
case '"': // ascii/latin1
|
586
|
+
s_string8:
|
587
|
+
if (r_varint(p, pe, &u))
|
588
|
+
goto bad_varint;
|
589
|
+
if (pe-*p < (int64_t)u)
|
590
|
+
goto too_short;
|
591
|
+
des_string8(arg, *p, u);
|
592
|
+
*p += u;
|
593
|
+
break;
|
594
|
+
case 'S': // utf8
|
595
|
+
s_string:
|
596
|
+
if (r_varint(p, pe, &u))
|
597
|
+
goto bad_varint;
|
598
|
+
if (pe-*p < (int64_t)u)
|
599
|
+
goto too_short;
|
600
|
+
des_string(arg, (void *)*p, u);
|
601
|
+
*p += u;
|
602
|
+
break;
|
603
|
+
case 'c': // utf16-le
|
604
|
+
s_string16:
|
605
|
+
if (r_varint(p, pe, &u))
|
606
|
+
goto bad_varint;
|
607
|
+
if (pe-*p < (int64_t)u)
|
608
|
+
goto too_short;
|
609
|
+
if (u & 1)
|
610
|
+
return bail(err, "bad utf16 string size");
|
611
|
+
des_string16(arg, *p, u);
|
612
|
+
*p += u;
|
613
|
+
break;
|
614
|
+
case 'o':
|
615
|
+
des_object_begin(arg);
|
616
|
+
for (u = 0;; u++) {
|
617
|
+
if (pe-*p < 1)
|
618
|
+
goto too_short;
|
619
|
+
if (**p == '{')
|
620
|
+
break;
|
621
|
+
if (des1(err, p, pe, arg, depth-1)) // key
|
622
|
+
return -1;
|
623
|
+
if (des1(err, p, pe, arg, depth-1)) // value
|
624
|
+
return -1;
|
625
|
+
}
|
626
|
+
(*p)++;
|
627
|
+
if (r_varint(p, pe, &t))
|
628
|
+
goto bad_varint;
|
629
|
+
if (t != u)
|
630
|
+
return bail(err, "object properties count mismatch");
|
631
|
+
des_object_end(arg);
|
632
|
+
break;
|
633
|
+
case ';': // Map
|
634
|
+
des_object_begin(arg);
|
635
|
+
for (u = 0; /*empty*/; u++) {
|
636
|
+
if (*p >= pe)
|
637
|
+
goto too_short;
|
638
|
+
if (**p == ':')
|
639
|
+
break;
|
640
|
+
if (des1(err, p, pe, arg, depth-1)) // key
|
641
|
+
return -1;
|
642
|
+
if (des1(err, p, pe, arg, depth-1)) // value
|
643
|
+
return -1;
|
644
|
+
}
|
645
|
+
(*p)++;
|
646
|
+
if (r_varint(p, pe, &t))
|
647
|
+
goto bad_varint;
|
648
|
+
if (t != 2*u)
|
649
|
+
return bail(err, "map element count mismatch");
|
650
|
+
des_object_end(arg);
|
651
|
+
break;
|
652
|
+
case '\'': // Set
|
653
|
+
des_array_begin(arg);
|
654
|
+
for (u = 0; /*empty*/; u++) {
|
655
|
+
if (*p >= pe)
|
656
|
+
goto too_short;
|
657
|
+
if (**p == ',')
|
658
|
+
break;
|
659
|
+
if (des1(err, p, pe, arg, depth-1)) // value
|
660
|
+
return -1;
|
661
|
+
}
|
662
|
+
(*p)++;
|
663
|
+
if (r_varint(p, pe, &t))
|
664
|
+
goto bad_varint;
|
665
|
+
if (t != u)
|
666
|
+
return bail(err, "set element count mismatch");
|
667
|
+
des_array_end(arg);
|
668
|
+
break;
|
669
|
+
case 'r':
|
670
|
+
// shortest error is /r[.]/ - Error with no message, cause, or stack
|
671
|
+
// longest error is /r[EFRSTU]m<string>c<any>s<string>[.]/ where
|
672
|
+
// EFRSTU is one of {Eval,Reference,Range,Syntax,Type,URI}Error
|
673
|
+
des_error_begin(arg);
|
674
|
+
des_object_begin(arg);
|
675
|
+
if (*p >= pe)
|
676
|
+
goto too_short;
|
677
|
+
c = *(*p)++;
|
678
|
+
if (!strchr("EFRSTU", c))
|
679
|
+
goto r_message;
|
680
|
+
if (*p >= pe)
|
681
|
+
goto too_short;
|
682
|
+
c = *(*p)++;
|
683
|
+
r_message:
|
684
|
+
if (c != 'm')
|
685
|
+
goto r_stack;
|
686
|
+
des_string(arg, "message", sizeof("message")-1);
|
687
|
+
if (*p >= pe)
|
688
|
+
goto too_short;
|
689
|
+
if (!strchr("\"Sc", **p))
|
690
|
+
return bail(err, "error .message is not a string");
|
691
|
+
if (des1(err, p, pe, arg, depth-1))
|
692
|
+
return -1;
|
693
|
+
if (*p >= pe)
|
694
|
+
goto too_short;
|
695
|
+
c = *(*p)++;
|
696
|
+
r_stack:
|
697
|
+
if (c != 's')
|
698
|
+
goto r_cause;
|
699
|
+
des_string(arg, "stack", sizeof("stack")-1);
|
700
|
+
if (*p >= pe)
|
701
|
+
goto too_short;
|
702
|
+
if (!strchr("\"Sc", **p))
|
703
|
+
return bail(err, "error .stack is not a string");
|
704
|
+
if (des1(err, p, pe, arg, depth-1))
|
705
|
+
return -1;
|
706
|
+
if (*p >= pe)
|
707
|
+
goto too_short;
|
708
|
+
c = *(*p)++;
|
709
|
+
r_cause:
|
710
|
+
if (c != 'c')
|
711
|
+
goto r_end;
|
712
|
+
des_string(arg, "cause", sizeof("cause")-1);
|
713
|
+
if (des1(err, p, pe, arg, depth-1))
|
714
|
+
return -1;
|
715
|
+
if (*p >= pe)
|
716
|
+
goto too_short;
|
717
|
+
c = *(*p)++;
|
718
|
+
r_end:
|
719
|
+
if (c != '.')
|
720
|
+
return bail(err, "bad error object");
|
721
|
+
des_object_end(arg);
|
722
|
+
des_error_end(arg);
|
723
|
+
break;
|
724
|
+
}
|
725
|
+
return 0;
|
726
|
+
too_short:
|
727
|
+
return bail(err, "input too short");
|
728
|
+
bad_varint:
|
729
|
+
return bail(err, "bad varint");
|
730
|
+
}
|
731
|
+
|
732
|
+
int des(char (*err)[64], const void *b, size_t n, void *arg)
|
733
|
+
{
|
734
|
+
const uint8_t *p, *pe;
|
735
|
+
|
736
|
+
p = b, pe = p + n;
|
737
|
+
if (n < 2)
|
738
|
+
return bail(err, "input too short");
|
739
|
+
if (*p++ != 255)
|
740
|
+
return bail(err, "bad header");
|
741
|
+
if (*p++ != 15)
|
742
|
+
return bail(err, "bad version");
|
743
|
+
while (p < pe)
|
744
|
+
if (des1(err, &p, pe, arg, /*depth*/96))
|
745
|
+
return -1;
|
746
|
+
return 0;
|
747
|
+
}
|