yeptris 0.6.47.0-arm-linux-eabihf → 0.6.49.0-arm-linux-eabihf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/yeptris_native/version.h +2 -2
- data/lib/yeptris/cbor.rb +32 -0
- data/lib/yeptris/ffi.rb +14 -0
- data/lib/yeptris/json.rb +34 -0
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +1 -1
- data/vendor/libyeptris/src/CMakeLists.txt +2 -1
- data/vendor/libyeptris/src/include/yeptris/cbor.h +24 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +4 -2
- data/vendor/libyeptris/src/include/yeptris/tape.h +5 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +59 -9
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +32 -31
- data/vendor/libyeptris/src/yeptris/cbor/encode_priv.h +32 -0
- data/vendor/libyeptris/src/yeptris/cbor/from_marshal.c +975 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +49 -87
- data/vendor/libyeptris/src/yeptris/emit/style.c +43 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +123 -6
- data/vendor/libyeptris/src/yeptris/parse/engine.c +16 -2
- data/vendor/libyeptris/src/yeptris/parse/engine.h +6 -1
- data/vendor/libyeptris/src/yeptris/parse.c +6 -3
- data/vendor/libyeptris/src/yeptris/tape.c +19 -1
- metadata +3 -1
|
@@ -254,6 +254,52 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
254
254
|
return out;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/* #739: the ONE-pass JSON route — one wet pass into a growable
|
|
258
|
+
* buffer; the dry exact-sizing pass priced the compact lane ~2x
|
|
259
|
+
* (the #352 slice-2 pattern). The estimate starts at the input size
|
|
260
|
+
* (+64) and doubles on demand; shrink-to-fit at the end. Owns the
|
|
261
|
+
* emitter's canon_names cleanup. */
|
|
262
|
+
static char* yep_json_run_growable(yep_emitter* em, size_t* len) {
|
|
263
|
+
size_t est = em->doc->dom->input_len + 64;
|
|
264
|
+
if (est < 256) {
|
|
265
|
+
est = 256;
|
|
266
|
+
}
|
|
267
|
+
char* out = (char*)malloc(est);
|
|
268
|
+
if (out == NULL) {
|
|
269
|
+
if (em->canon_names.sys != NULL) {
|
|
270
|
+
yep_nametab_free(&em->canon_names);
|
|
271
|
+
}
|
|
272
|
+
return NULL;
|
|
273
|
+
}
|
|
274
|
+
em->w.p = out;
|
|
275
|
+
em->w.cap = est;
|
|
276
|
+
em->w.grow = 1;
|
|
277
|
+
size_t wrote = yep_emit_run(em, 0);
|
|
278
|
+
em->w.grow = 0;
|
|
279
|
+
out = em->w.p; /* wr_grow reallocs through w->p — the local is stale */
|
|
280
|
+
if (em->w.oom || em->w.unserializable) {
|
|
281
|
+
free(out);
|
|
282
|
+
if (em->canon_names.sys != NULL) {
|
|
283
|
+
yep_nametab_free(&em->canon_names);
|
|
284
|
+
}
|
|
285
|
+
return NULL;
|
|
286
|
+
}
|
|
287
|
+
if (em->w.cap - (wrote + 1) > em->w.cap / 8) {
|
|
288
|
+
char* tight = (char*)realloc(out, wrote + 1);
|
|
289
|
+
if (tight != NULL) {
|
|
290
|
+
out = tight;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (em->canon_names.sys != NULL) {
|
|
294
|
+
yep_nametab_free(&em->canon_names);
|
|
295
|
+
}
|
|
296
|
+
out[wrote] = '\0';
|
|
297
|
+
if (len != NULL) {
|
|
298
|
+
*len = wrote;
|
|
299
|
+
}
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
|
|
257
303
|
YEPTRIS_API char* yeptris_serialize_json(YeptrisDocument handle, size_t* len) {
|
|
258
304
|
if (handle == NULL) {
|
|
259
305
|
return NULL;
|
|
@@ -290,51 +336,7 @@ YEPTRIS_API char* yeptris_serialize_json(YeptrisDocument handle, size_t* len) {
|
|
|
290
336
|
em.w.sink_aborted = 0;
|
|
291
337
|
em.w.flushed = 0;
|
|
292
338
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
293
|
-
|
|
294
|
-
return NULL;
|
|
295
|
-
}
|
|
296
|
-
/* #739: ONE wet pass into a growable buffer — the dry exact-sizing
|
|
297
|
-
* pass priced ~2x on the json lane (the #352 slice-2 pattern);
|
|
298
|
-
* the estimate starts at the input size (+64) and doubles on
|
|
299
|
-
* demand, shrink-to-fit at the end. */
|
|
300
|
-
size_t est = em.doc->dom->input_len + 64;
|
|
301
|
-
if (est < 256) {
|
|
302
|
-
est = 256;
|
|
303
|
-
}
|
|
304
|
-
char* out = (char*)malloc(est);
|
|
305
|
-
if (out == NULL) {
|
|
306
|
-
if (em.canon_names.sys != NULL) {
|
|
307
|
-
yep_nametab_free(&em.canon_names);
|
|
308
|
-
}
|
|
309
|
-
return NULL;
|
|
310
|
-
}
|
|
311
|
-
em.w.p = out;
|
|
312
|
-
em.w.cap = est;
|
|
313
|
-
em.w.grow = 1;
|
|
314
|
-
size_t wrote = yep_emit_run(&em, 0);
|
|
315
|
-
em.w.grow = 0;
|
|
316
|
-
out = em.w.p; /* wr_grow reallocs through w->p — the local is stale */
|
|
317
|
-
if (em.w.oom || em.w.unserializable) {
|
|
318
|
-
free(out);
|
|
319
|
-
if (em.canon_names.sys != NULL) {
|
|
320
|
-
yep_nametab_free(&em.canon_names);
|
|
321
|
-
}
|
|
322
|
-
return NULL;
|
|
323
|
-
}
|
|
324
|
-
if (em.w.cap - (wrote + 1) > em.w.cap / 8) {
|
|
325
|
-
char* tight = (char*)realloc(out, wrote + 1);
|
|
326
|
-
if (tight != NULL) {
|
|
327
|
-
out = tight;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
if (em.canon_names.sys != NULL) {
|
|
331
|
-
yep_nametab_free(&em.canon_names);
|
|
332
|
-
}
|
|
333
|
-
out[wrote] = '\0';
|
|
334
|
-
if (len != NULL) {
|
|
335
|
-
*len = wrote;
|
|
336
|
-
}
|
|
337
|
-
return out;
|
|
339
|
+
return yep_json_run_growable(&em, len);
|
|
338
340
|
}
|
|
339
341
|
|
|
340
342
|
YEPTRIS_API char* yeptris_serialize_json_ex(YeptrisDocument handle, size_t* len, int compact) {
|
|
@@ -376,27 +378,7 @@ YEPTRIS_API char* yeptris_serialize_json_ex(YeptrisDocument handle, size_t* len,
|
|
|
376
378
|
em.w.sink_aborted = 0;
|
|
377
379
|
em.w.flushed = 0;
|
|
378
380
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
379
|
-
|
|
380
|
-
return NULL;
|
|
381
|
-
}
|
|
382
|
-
size_t need = yep_emit_run(&em, 1);
|
|
383
|
-
char* out = malloc(need + 1);
|
|
384
|
-
if (out == NULL) {
|
|
385
|
-
if (em.canon_names.sys != NULL) {
|
|
386
|
-
yep_nametab_free(&em.canon_names);
|
|
387
|
-
}
|
|
388
|
-
return NULL;
|
|
389
|
-
}
|
|
390
|
-
em.w.p = out;
|
|
391
|
-
size_t wrote = yep_emit_run(&em, 0);
|
|
392
|
-
if (em.canon_names.sys != NULL) {
|
|
393
|
-
yep_nametab_free(&em.canon_names);
|
|
394
|
-
}
|
|
395
|
-
out[wrote] = '\0';
|
|
396
|
-
if (len != NULL) {
|
|
397
|
-
*len = wrote;
|
|
398
|
-
}
|
|
399
|
-
return out;
|
|
381
|
+
return yep_json_run_growable(&em, len);
|
|
400
382
|
}
|
|
401
383
|
|
|
402
384
|
YEPTRIS_API char* yeptris_serialize_json_pretty(YeptrisDocument handle, size_t* len,
|
|
@@ -440,27 +422,7 @@ char* yep_serialize_json_compact(const yeptris_document* doc, size_t* len) {
|
|
|
440
422
|
em.w.sink_aborted = 0;
|
|
441
423
|
em.w.flushed = 0;
|
|
442
424
|
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
443
|
-
|
|
444
|
-
return NULL;
|
|
445
|
-
}
|
|
446
|
-
size_t need = yep_emit_run(&em, 1);
|
|
447
|
-
char* out = malloc(need + 1);
|
|
448
|
-
if (out == NULL) {
|
|
449
|
-
if (em.canon_names.sys != NULL) {
|
|
450
|
-
yep_nametab_free(&em.canon_names);
|
|
451
|
-
}
|
|
452
|
-
return NULL;
|
|
453
|
-
}
|
|
454
|
-
em.w.p = out;
|
|
455
|
-
size_t wrote = yep_emit_run(&em, 0);
|
|
456
|
-
if (em.canon_names.sys != NULL) {
|
|
457
|
-
yep_nametab_free(&em.canon_names);
|
|
458
|
-
}
|
|
459
|
-
out[wrote] = '\0';
|
|
460
|
-
if (len != NULL) {
|
|
461
|
-
*len = wrote;
|
|
462
|
-
}
|
|
463
|
-
return out;
|
|
425
|
+
return yep_json_run_growable(&em, len);
|
|
464
426
|
}
|
|
465
427
|
|
|
466
428
|
char* yep_serialize_json_pretty(const yeptris_document* doc, size_t* len) {
|
|
@@ -75,6 +75,49 @@ int yep_style_plain_safe(const char* p, uint32_t len) {
|
|
|
75
75
|
const uint64_t HIGH = 0x8080808080808080ull;
|
|
76
76
|
#define YST_ZDET(w, ch) \
|
|
77
77
|
((((w) ^ (uint64_t)(ch) * ONES) - ONES) & ~((w) ^ (uint64_t)(ch) * ONES) & HIGH)
|
|
78
|
+
/* the all-boring accept (#742): a span of pure [0-9A-Za-z_]
|
|
79
|
+
* makes EVERY rule in this function vacuous — no indicators
|
|
80
|
+
* (the head switch), no blanks at the ends, no BOM, no
|
|
81
|
+
* ': '/' #' adjacency, no breaks, and no ---/... marker — so
|
|
82
|
+
* one range test per word accepts without the six-mask walk.
|
|
83
|
+
* Anything else falls through to the exact scan below. */
|
|
84
|
+
{
|
|
85
|
+
uint32_t bi = 0;
|
|
86
|
+
int boring = 1;
|
|
87
|
+
while (bi + 8 <= len) {
|
|
88
|
+
uint64_t bw;
|
|
89
|
+
memcpy(&bw, p + bi, 8);
|
|
90
|
+
if (bw & HIGH) {
|
|
91
|
+
boring = 0;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
/* per-lane unsigned range checks via borrow bits: alpha
|
|
95
|
+
* is (t - 'a') and ('z' - t) both borrow-free with
|
|
96
|
+
* t = w|0x20 (A-Z fold); digits bound 0x30..0x39 */
|
|
97
|
+
uint64_t t = bw | (ONES * 0x20);
|
|
98
|
+
uint64_t bad = ((t - ONES * 0x61) | (ONES * 0x7A - t)) & HIGH; /* alpha */
|
|
99
|
+
bad |= ((bw - ONES * 0x30) | (ONES * 0x39 - bw)) & HIGH; /* digit */
|
|
100
|
+
bad &= ~YST_ZDET(bw, '_'); /* the one extra boring byte */
|
|
101
|
+
if (bad != 0) {
|
|
102
|
+
boring = 0;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
bi += 8;
|
|
106
|
+
}
|
|
107
|
+
if (boring) {
|
|
108
|
+
for (; bi < len; bi++) {
|
|
109
|
+
char c = p[bi];
|
|
110
|
+
int a = (c | 0x20);
|
|
111
|
+
if (!((c >= '0' && c <= '9') || (a >= 'a' && a <= 'z') || c == '_')) {
|
|
112
|
+
boring = 0;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (boring) {
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
78
121
|
uint32_t i = 0;
|
|
79
122
|
int prev_blank7 = 0;
|
|
80
123
|
while (i + 8 <= len) {
|
|
@@ -528,9 +528,18 @@ static uint8_t sc_route(yep_writer* w, const char* p, uint32_t len, int as_key,
|
|
|
528
528
|
}
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
531
|
+
/* the plain verdict is computed AT MOST ONCE: the case-1 arm below
|
|
532
|
+
* re-tests the same bytes when the head check already ran — the
|
|
533
|
+
* #742 profile's second call site (every plain-UNSAFE scalar paid
|
|
534
|
+
* the walk twice) */
|
|
535
|
+
int plain_ok = 0;
|
|
536
|
+
int plain_checked = 0;
|
|
537
|
+
if ((sty_in == 1) && len > 0) {
|
|
538
|
+
plain_ok = as_key ? yep_style_plain_key_safe(p, len) : yep_style_plain_safe(p, len);
|
|
539
|
+
plain_checked = 1;
|
|
540
|
+
if (plain_ok) {
|
|
541
|
+
return YEP_SC_PLAIN; /* plain-safe implies no breaks: memchr skipped */
|
|
542
|
+
}
|
|
534
543
|
}
|
|
535
544
|
int multiline = (len > 0 && memchr(p, '\n', len) != NULL);
|
|
536
545
|
int blockable = 0;
|
|
@@ -584,7 +593,11 @@ static uint8_t sc_route(yep_writer* w, const char* p, uint32_t len, int as_key,
|
|
|
584
593
|
if (len == 0) {
|
|
585
594
|
return as_key ? YEP_SC_DQ : YEP_SC_NOTHING;
|
|
586
595
|
}
|
|
587
|
-
if (
|
|
596
|
+
if (!plain_checked) {
|
|
597
|
+
plain_ok = as_key ? yep_style_plain_key_safe(p, len) : yep_style_plain_safe(p, len);
|
|
598
|
+
plain_checked = 1;
|
|
599
|
+
}
|
|
600
|
+
if (plain_ok) {
|
|
588
601
|
return YEP_SC_PLAIN;
|
|
589
602
|
}
|
|
590
603
|
if (!multiline) {
|
|
@@ -941,8 +954,16 @@ static int key_written_over_limit(yep_writer* w, const yep_dnode* kn) {
|
|
|
941
954
|
if (w->json) {
|
|
942
955
|
return 0; /* JSON has no simple-key law: every key writes (#739) */
|
|
943
956
|
}
|
|
944
|
-
uint64_t est = 2; /* the quotes */
|
|
945
957
|
yep_view kv_ = wv(w, kn->value);
|
|
958
|
+
if (kn->anchor.len == 0 && kn->tag.len == 0 && kv_.len <= 255) {
|
|
959
|
+
/* the exact bound: even at the factor-4 expansion the walk
|
|
960
|
+
* budgets per byte, 255 raw bytes top out at est = 2 + 1020 —
|
|
961
|
+
* under the law. Table-shaped documents pay the two field
|
|
962
|
+
* checks instead of the byte walk (the #742 profile's 22%
|
|
963
|
+
* lane) */
|
|
964
|
+
return 0;
|
|
965
|
+
}
|
|
966
|
+
uint64_t est = 2; /* the quotes */
|
|
946
967
|
const unsigned char* q = (const unsigned char*)kv_.p;
|
|
947
968
|
uint32_t n = kv_.len;
|
|
948
969
|
/* NO early return on an empty value: the tag arm below must run —
|
|
@@ -1384,6 +1405,98 @@ static void emit_node(yep_emitter* em, uint32_t id, int parent_col, int as_key)
|
|
|
1384
1405
|
emit_scalar(w, n, parent_col, as_key);
|
|
1385
1406
|
}
|
|
1386
1407
|
|
|
1408
|
+
/* ============================================================
|
|
1409
|
+
* yeptris#739 slice 3: JSON's own tree walk. In JSON mode every
|
|
1410
|
+
* collection is flow, the separators are fixed, and the YAML
|
|
1411
|
+
* machinery (props lines, style analysis, explicit-key law,
|
|
1412
|
+
* pretty depth) never fires — yet the generic emit_node ->
|
|
1413
|
+
* emit_flow path re-tests all of it per node and looks every
|
|
1414
|
+
* child up twice. This walk emits the same bytes with one
|
|
1415
|
+
* dispatch per node and two per map pair. Pretty output keeps
|
|
1416
|
+
* the generic path: its depth/indent bookkeeping is the point
|
|
1417
|
+
* there.
|
|
1418
|
+
* ============================================================ */
|
|
1419
|
+
static void emit_json_node(yep_emitter* em, uint32_t id);
|
|
1420
|
+
|
|
1421
|
+
static void emit_json_flow(yep_emitter* em, uint32_t id) {
|
|
1422
|
+
yep_writer* w = &em->w;
|
|
1423
|
+
int saved_flow = w->in_flow;
|
|
1424
|
+
w->in_flow = 1;
|
|
1425
|
+
const yep_dom* d = em->doc->dom;
|
|
1426
|
+
const yep_dnode* n = yep_dom_node(d, id);
|
|
1427
|
+
if (n->tag.len > 0) {
|
|
1428
|
+
emit_tag(w, n);
|
|
1429
|
+
}
|
|
1430
|
+
if (n->anchor.len > 0) {
|
|
1431
|
+
emit_anchor_ex(em, n);
|
|
1432
|
+
}
|
|
1433
|
+
int map = (n->kind == 2);
|
|
1434
|
+
wr_byte(w, map ? '{' : '[');
|
|
1435
|
+
uint32_t child = n->first_child;
|
|
1436
|
+
uint32_t idx = 0;
|
|
1437
|
+
while (child != UINT32_MAX) {
|
|
1438
|
+
const yep_dnode* cn = yep_dom_node(d, child);
|
|
1439
|
+
if (idx > 0) {
|
|
1440
|
+
if (w->json_compact) {
|
|
1441
|
+
wr_byte(w, ',');
|
|
1442
|
+
} else {
|
|
1443
|
+
wr_put(w, ", ", 2);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (map) {
|
|
1447
|
+
/* the one generic-path rule JSON keeps: a non-scalar key
|
|
1448
|
+
* (or one carrying props) rides the explicit "? key : "
|
|
1449
|
+
* form — same bytes emit_flow writes */
|
|
1450
|
+
if (cn->anchor.len > 0 || cn->tag.len > 0 || cn->kind != 0) {
|
|
1451
|
+
wr_put(w, "? ", 2);
|
|
1452
|
+
emit_json_node(em, child);
|
|
1453
|
+
wr_put(w, " : ", 3);
|
|
1454
|
+
} else {
|
|
1455
|
+
emit_json_node(em, child);
|
|
1456
|
+
if (w->json_compact) {
|
|
1457
|
+
wr_byte(w, ':');
|
|
1458
|
+
} else {
|
|
1459
|
+
wr_put(w, ": ", 2);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
uint32_t val = cn->next_sibling;
|
|
1463
|
+
emit_json_node(em, val);
|
|
1464
|
+
const yep_dnode* vn = yep_dom_node(d, val);
|
|
1465
|
+
child = vn != NULL ? vn->next_sibling : UINT32_MAX;
|
|
1466
|
+
} else {
|
|
1467
|
+
emit_json_node(em, child);
|
|
1468
|
+
child = cn->next_sibling;
|
|
1469
|
+
}
|
|
1470
|
+
idx++;
|
|
1471
|
+
}
|
|
1472
|
+
wr_byte(w, map ? '}' : ']');
|
|
1473
|
+
w->in_flow = saved_flow;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
static void emit_json_node(yep_emitter* em, uint32_t id) {
|
|
1477
|
+
yep_writer* w = &em->w;
|
|
1478
|
+
const yep_dom* d = em->doc->dom;
|
|
1479
|
+
const yep_dnode* n = yep_dom_node(d, id);
|
|
1480
|
+
if (n == NULL) {
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (n->kind == 3) { /* alias */
|
|
1484
|
+
emit_alias_ex(em, n);
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
if (n->kind == 1 || n->kind == 2) {
|
|
1488
|
+
emit_json_flow(em, id);
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
if (n->tag.len > 0) {
|
|
1492
|
+
emit_tag(w, n);
|
|
1493
|
+
}
|
|
1494
|
+
if (n->anchor.len > 0) {
|
|
1495
|
+
emit_anchor_ex(em, n);
|
|
1496
|
+
}
|
|
1497
|
+
emit_canonical_scalar(w, n);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1387
1500
|
/* ============================================================
|
|
1388
1501
|
* yeptris-ruby#322: the marshal READER — Ruby Marshal.dump bytes
|
|
1389
1502
|
* to JSON text in one C call (no per-scalar crossings, no object
|
|
@@ -1975,7 +2088,11 @@ size_t yep_emit_run(yep_emitter* em, int dry) {
|
|
|
1975
2088
|
/* JSON has no multi-document streams and no document marker */
|
|
1976
2089
|
if (d->dcount == 1) {
|
|
1977
2090
|
const yep_dnode* root = yep_dom_node(d, d->docs[0]);
|
|
1978
|
-
|
|
2091
|
+
if (w->json_pretty) {
|
|
2092
|
+
emit_node(em, d->docs[0], -2, 0);
|
|
2093
|
+
} else {
|
|
2094
|
+
emit_json_node(em, d->docs[0]);
|
|
2095
|
+
}
|
|
1979
2096
|
if (root != NULL && root->kind != 0 && w->last != '\n') {
|
|
1980
2097
|
wr_byte(w, '\n');
|
|
1981
2098
|
}
|
|
@@ -4192,7 +4192,7 @@ yep_engine* yep_engine_create(const yep_allocator* sys) {
|
|
|
4192
4192
|
* nightly's run 38524928004: "\0\n---\r<U+2028>" whole-parsed as an
|
|
4193
4193
|
* empty stream while the chunked cut skipped the copy). */
|
|
4194
4194
|
static const char* e_normalize_breaks(yep_engine* e, const char* p, size_t len, size_t* out_len) {
|
|
4195
|
-
char* out = yep_engine_normalize_breaks(e->sys, p, len, out_len);
|
|
4195
|
+
char* out = yep_engine_normalize_breaks(e->sys, p, len, out_len, NULL);
|
|
4196
4196
|
if (out == NULL) {
|
|
4197
4197
|
return p;
|
|
4198
4198
|
}
|
|
@@ -4567,7 +4567,10 @@ static yep_norm_tok norm_step(yep_norm_ctx* c, const char* p, size_t len, size_t
|
|
|
4567
4567
|
}
|
|
4568
4568
|
|
|
4569
4569
|
char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_t len,
|
|
4570
|
-
size_t* out_len) {
|
|
4570
|
+
size_t* out_len, int* kept_raw) {
|
|
4571
|
+
if (kept_raw != NULL) {
|
|
4572
|
+
*kept_raw = 0;
|
|
4573
|
+
}
|
|
4571
4574
|
const unsigned char* q = (const unsigned char*)p;
|
|
4572
4575
|
const yep_text_kernels* k = yep_text_active();
|
|
4573
4576
|
size_t i = 0;
|
|
@@ -4597,6 +4600,9 @@ char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_
|
|
|
4597
4600
|
j += t.n;
|
|
4598
4601
|
}
|
|
4599
4602
|
if (!found) {
|
|
4603
|
+
if (kept_raw != NULL) {
|
|
4604
|
+
*kept_raw = 1; /* every exotic byte rides raw */
|
|
4605
|
+
}
|
|
4600
4606
|
return NULL; /* the exotic bytes all ride inside quoted regions:
|
|
4601
4607
|
* the zero-copy path keeps them raw (the fix) */
|
|
4602
4608
|
}
|
|
@@ -4611,6 +4617,14 @@ char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_
|
|
|
4611
4617
|
for (size_t j = 0; j < len;) {
|
|
4612
4618
|
yep_norm_tok t = norm_step(&cp, p, len, j);
|
|
4613
4619
|
if (t.fold_off < 0) {
|
|
4620
|
+
if (kept_raw != NULL && *kept_raw == 0) {
|
|
4621
|
+
for (size_t m = 0; m + 1 < t.n; m++) {
|
|
4622
|
+
if (yep_scan_mb_break_len(p + j + m, t.n - m, 0) > 0) {
|
|
4623
|
+
*kept_raw = 1;
|
|
4624
|
+
break;
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4614
4628
|
memcpy(out + o, p + j, t.n);
|
|
4615
4629
|
o += t.n;
|
|
4616
4630
|
} else {
|
|
@@ -76,8 +76,13 @@ const yep_error* yep_engine_error(const yep_engine* e);
|
|
|
76
76
|
* the stopset kernel). One-shot parse runs this BEFORE the engine so
|
|
77
77
|
* the copy owns the document's transcoded slot; the engine's per-feed
|
|
78
78
|
* copy (norm_buf) stays for the streaming feeds. */
|
|
79
|
+
/* kept_raw (nullable) reports whether raw NEL/LS/PS SURVIVED the
|
|
80
|
+
* quote-aware walk (they ride inside quoted regions). The packed-tape
|
|
81
|
+
* fused runner predates the multibyte break cut — a document still
|
|
82
|
+
* carrying raw sequences parses on the engine route instead (the
|
|
83
|
+
* nightly's r75). */
|
|
79
84
|
char* yep_engine_normalize_breaks(const yep_allocator* sys, const char* p, size_t len,
|
|
80
|
-
size_t* out_len);
|
|
85
|
+
size_t* out_len, int* kept_raw);
|
|
81
86
|
|
|
82
87
|
#ifdef __cplusplus
|
|
83
88
|
}
|
|
@@ -244,6 +244,9 @@ static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisPars
|
|
|
244
244
|
unsigned char* transcoded = NULL;
|
|
245
245
|
size_t transcoded_len = 0;
|
|
246
246
|
yep_encoding enc = YEP_ENC_UNKNOWN;
|
|
247
|
+
int norm_kept_raw = 0; /* raw NEL/LS/PS survived the quote-aware
|
|
248
|
+
* walk: the engine route owns the document
|
|
249
|
+
* (the tape runner predates the cut) */
|
|
247
250
|
|
|
248
251
|
if (json_mode) {
|
|
249
252
|
/* JSON mode validated grammar and UTF-8 well-formedness at the
|
|
@@ -307,7 +310,7 @@ static YeptrisDocument parse_impl(const char* buf, size_t len, const YeptrisPars
|
|
|
307
310
|
* U+0085 raw inside strings, only the YAML reader normalizes. */
|
|
308
311
|
{
|
|
309
312
|
size_t nlen = 0;
|
|
310
|
-
char* norm = yep_engine_normalize_breaks(sys, data, data_len, &nlen);
|
|
313
|
+
char* norm = yep_engine_normalize_breaks(sys, data, data_len, &nlen, &norm_kept_raw);
|
|
311
314
|
if (norm != NULL) {
|
|
312
315
|
yep_free(sys, transcoded);
|
|
313
316
|
transcoded = (unsigned char*)norm;
|
|
@@ -410,12 +413,12 @@ engine_enter:
|
|
|
410
413
|
.on_block_item = dom_on_block_item};
|
|
411
414
|
}
|
|
412
415
|
int rc = 0;
|
|
413
|
-
if (have_tape && ytap_flow_rooted(&yt) == 0) {
|
|
416
|
+
if (have_tape && !norm_kept_raw && ytap_flow_rooted(&yt) == 0) {
|
|
414
417
|
/* a pure flow-rooted document: the classification ran once and
|
|
415
418
|
* the scaffolding landed — neither runner nor engine runs */
|
|
416
419
|
yep_engine_destroy(eng);
|
|
417
420
|
eng = NULL;
|
|
418
|
-
} else if (have_tape &&
|
|
421
|
+
} else if (have_tape && !norm_kept_raw &&
|
|
419
422
|
ytap_fused_run(&yt, (opts != NULL && opts->schema == YEPTRIS_SCHEMA_11_COMPAT)
|
|
420
423
|
? yep_resolver_compat11()
|
|
421
424
|
: yep_resolver_core12()) == 0) {
|
|
@@ -74,6 +74,8 @@ static YeptrisStatus tape_carve(yeptris_json_tape* t, size_t len) {
|
|
|
74
74
|
t->int_min = 0;
|
|
75
75
|
t->_rec_primary = 0;
|
|
76
76
|
t->_cols_ready = 0;
|
|
77
|
+
t->_long_key_known = 0;
|
|
78
|
+
t->_long_key = 0;
|
|
77
79
|
return YEPTRIS_OK;
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -695,6 +697,9 @@ static TAPE_NUM_OK_INLINE int tape_num_ok(const char* p, size_t len) {
|
|
|
695
697
|
* a long simple key, so the fast parse defers to the engine's clean
|
|
696
698
|
* error — the nightly's run 38143486175). */
|
|
697
699
|
int yep_tape_long_simple_key(const yeptris_json_tape* s) {
|
|
700
|
+
if (s->_long_key_known) {
|
|
701
|
+
return s->_long_key; /* settled during the lenient walk */
|
|
702
|
+
}
|
|
698
703
|
struct {
|
|
699
704
|
uint8_t map;
|
|
700
705
|
uint8_t key_next;
|
|
@@ -758,6 +763,8 @@ YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open
|
|
|
758
763
|
t->_srclen >= len + 2) {
|
|
759
764
|
t->_cols_ready = 0;
|
|
760
765
|
t->_rec_primary = 1;
|
|
766
|
+
t->_long_key_known = 0;
|
|
767
|
+
t->_long_key = 0;
|
|
761
768
|
} else if (tape_carve(t, len) != YEPTRIS_OK) {
|
|
762
769
|
return YEPTRIS_ERROR_MEMORY;
|
|
763
770
|
}
|
|
@@ -997,7 +1004,18 @@ lmap: /* a member MUST follow (after ','): JW_KEY — a closer rejects */
|
|
|
997
1004
|
goto lreject;
|
|
998
1005
|
}
|
|
999
1006
|
lmapkey: { LSTR_SCAN(lmapcolon); }
|
|
1000
|
-
lmapcolon:
|
|
1007
|
+
lmapcolon: { /* the key verdict rides the walk: the just-emitted record IS the
|
|
1008
|
+
* key — a >1024-byte candidate pays the char-budget check once
|
|
1009
|
+
* instead of a post-parse full-tape re-walk (#739) */
|
|
1010
|
+
uint64_t kr_ = recs[count - 1];
|
|
1011
|
+
uint32_t kl_ = (uint32_t)(kr_ >> 8) & 0xFFFFFFu;
|
|
1012
|
+
if (kl_ + 2u > 1024u && !t->_long_key_known) {
|
|
1013
|
+
t->_long_key_known = 1;
|
|
1014
|
+
t->_long_key =
|
|
1015
|
+
(unsigned char)(yep_simple_key_chars(p + (size_t)(uint32_t)(kr_ >> 32), kl_) + 2 >
|
|
1016
|
+
1024);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1001
1019
|
if (i < len && p[i] == ':') {
|
|
1002
1020
|
i++;
|
|
1003
1021
|
/* compact fast path: the value byte follows the colon with no
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yeptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.
|
|
4
|
+
version: 0.6.49.0
|
|
5
5
|
platform: arm-linux-eabihf
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -93,6 +93,8 @@ files:
|
|
|
93
93
|
- vendor/libyeptris/src/yeptris/cbor/cbor.h
|
|
94
94
|
- vendor/libyeptris/src/yeptris/cbor/decode.c
|
|
95
95
|
- vendor/libyeptris/src/yeptris/cbor/encode.c
|
|
96
|
+
- vendor/libyeptris/src/yeptris/cbor/encode_priv.h
|
|
97
|
+
- vendor/libyeptris/src/yeptris/cbor/from_marshal.c
|
|
96
98
|
- vendor/libyeptris/src/yeptris/cbor/sink.h
|
|
97
99
|
- vendor/libyeptris/src/yeptris/common/chartype.c
|
|
98
100
|
- vendor/libyeptris/src/yeptris/common/chartype.h
|