yeptris 0.6.29.2 → 0.6.31.1
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/lib/yeptris.rb +1 -1
- data/vendor/libyeptris/CMakeLists.txt +20 -6
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +5 -0
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +15 -3
- data/vendor/libyeptris/src/yeptris/emit/emit.c +63 -24
- data/vendor/libyeptris/src/yeptris/emit/writer.c +128 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +60 -8
- data/vendor/libyeptris/src/yeptris/scan/scan.c +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 944eb6ddb09530a26c295a550eef46c41485243c50dc0c9a966fc48dc5640338
|
|
4
|
+
data.tar.gz: 782a73ac7a8e21f7bf7269186360caaed28a7d8d7c445796eb8adee8d468a6bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9dc853f4a4a6009c5968d48d8a6d9152dcd097bd0931943b0e3365d3e6844acaa66356ec4e7e1dfc3e9f6c613358cf795037e86bf65ad00ea3cf72cac2045cf2
|
|
7
|
+
data.tar.gz: 768c7b473eda6aa1c8150539bfda46b87c091a99690553d719b545b764b7f1cadbe7c6d1a6f906e47237344f431f11c3bb771afe55b00f8dbe07992c46c3252f
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.
|
|
6
|
+
VERSION = "0.6.31.1".freeze
|
|
7
7
|
|
|
8
8
|
# Informational notices are OPT-IN (yeptris-ruby#217): consumers
|
|
9
9
|
# embed yeptris inside CLIs that assert clean stderr, and a
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
cmake_minimum_required(VERSION 3.20)
|
|
4
4
|
|
|
5
5
|
project(yeptris
|
|
6
|
-
VERSION 0.6.
|
|
6
|
+
VERSION 0.6.31
|
|
7
7
|
DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
|
|
8
8
|
LANGUAGES C CXX
|
|
9
9
|
)
|
|
@@ -100,8 +100,12 @@ endif()
|
|
|
100
100
|
|
|
101
101
|
# libFuzzer implies ASAN (libleptris TODO 40 pattern).
|
|
102
102
|
if(YEPTRIS_ENABLE_FUZZING)
|
|
103
|
+
# instrument everything, but link the fuzzer MAIN only into the
|
|
104
|
+
# harnesses: a global -fsanitize=fuzzer link option demands
|
|
105
|
+
# LLVMFuzzerTestOneInput from every executable (the CLI and the
|
|
106
|
+
# test binaries died on it once CXX also pinned to clang++)
|
|
103
107
|
add_compile_options(-fsanitize=fuzzer-no-link,address -fno-omit-frame-pointer -g)
|
|
104
|
-
add_link_options(-fsanitize=
|
|
108
|
+
add_link_options(-fsanitize=address)
|
|
105
109
|
message(STATUS "libFuzzer: ENABLED (implies ASAN)")
|
|
106
110
|
endif()
|
|
107
111
|
|
|
@@ -206,10 +210,20 @@ endif()
|
|
|
206
210
|
# config; relative paths keep relocatable installs.
|
|
207
211
|
include(GNUInstallDirs)
|
|
208
212
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
if(TARGET yeptris_static)
|
|
214
|
+
install(TARGETS yeptris_static
|
|
215
|
+
EXPORT yeptris-targets
|
|
216
|
+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
217
|
+
)
|
|
218
|
+
endif()
|
|
219
|
+
if(TARGET yeptris_shared)
|
|
220
|
+
install(TARGETS yeptris_shared
|
|
221
|
+
EXPORT yeptris-targets
|
|
222
|
+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
223
|
+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
224
|
+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
225
|
+
)
|
|
226
|
+
endif()
|
|
213
227
|
if(TARGET yeptris_jsonc)
|
|
214
228
|
install(TARGETS yeptris_jsonc
|
|
215
229
|
EXPORT yeptris-targets
|
|
@@ -179,6 +179,11 @@ static ptrdiff_t yep_avx2_quote_scan(const char* s, size_t len, char q, int* has
|
|
|
179
179
|
}
|
|
180
180
|
return (ptrdiff_t)(i + k);
|
|
181
181
|
}
|
|
182
|
+
if (i >= len) {
|
|
183
|
+
break; /* an escape at the boundary consumed the rest: unterminated
|
|
184
|
+
* (a lone '\' as the last byte pushed i past len; the tail
|
|
185
|
+
* call would underflow len - i and read out of bounds) */
|
|
186
|
+
}
|
|
182
187
|
if (i + YEP_AVX2_CHUNK > len) {
|
|
183
188
|
int tail_esc = 0;
|
|
184
189
|
ptrdiff_t r = yep_text_quote_scan_scalar(s + i, len - i, q, &tail_esc);
|
|
@@ -1422,7 +1422,8 @@ static int yt_f_run(yt_fused* F) {
|
|
|
1422
1422
|
(line_stop + 1 >= line_end || p[line_stop + 1] == ' ' ||
|
|
1423
1423
|
p[line_stop + 1] == '\t') &&
|
|
1424
1424
|
!(c == '&' || c == '!' || c == '*' || c == '\'' || c == '"' || c == '[' ||
|
|
1425
|
-
c == '{' || c == '|' || c == '>' || c == '%' || c == '?' || c == '-')
|
|
1425
|
+
c == '{' || c == '|' || c == '>' || c == '%' || c == '?' || c == '-') &&
|
|
1426
|
+
yep_plain_first_ok((unsigned char)c)) {
|
|
1426
1427
|
uint32_t kend = line_stop;
|
|
1427
1428
|
while (kend > t0 && (p[kend - 1] == ' ' || p[kend - 1] == '\t')) {
|
|
1428
1429
|
kend--;
|
|
@@ -1450,6 +1451,10 @@ static int yt_f_run(yt_fused* F) {
|
|
|
1450
1451
|
}
|
|
1451
1452
|
aoff = (uint32_t)(vt + 1);
|
|
1452
1453
|
alen = (uint32_t)(ne - vt - 1);
|
|
1454
|
+
if (alen == 0) {
|
|
1455
|
+
return 1; /* an anchor needs a name (libyaml):
|
|
1456
|
+
the engine owns the error */
|
|
1457
|
+
}
|
|
1453
1458
|
F->anchor_seq++;
|
|
1454
1459
|
aid = F->anchor_seq;
|
|
1455
1460
|
if (!yt_anchor_table(F)) {
|
|
@@ -1810,13 +1815,20 @@ static int yt_f_run(yt_fused* F) {
|
|
|
1810
1815
|
goto line_done;
|
|
1811
1816
|
}
|
|
1812
1817
|
if (vc == '"' || vc == '\'' || vc == '|' || vc == '>' || vc == '[' ||
|
|
1813
|
-
vc == '{' || vc == '!' || vc == '%') {
|
|
1814
|
-
return 1; /* quoted/block/flow/tag values:
|
|
1818
|
+
vc == '{' || vc == '!' || vc == '%' || vc == '&' || vc == '*') {
|
|
1819
|
+
return 1; /* quoted/block/flow/tag/anchor/alias values:
|
|
1820
|
+
the engine */
|
|
1815
1821
|
}
|
|
1816
1822
|
if ((vc == '-' || vc == '?') && (vt + 1 >= line_end || p[vt + 1] == ' ' ||
|
|
1817
1823
|
p[vt + 1] == '\t' || p[vt + 1] == '#')) {
|
|
1818
1824
|
return 1; /* an indicator-as-value: the engine errors */
|
|
1819
1825
|
}
|
|
1826
|
+
if (!yep_plain_first_ok(vc)) {
|
|
1827
|
+
return 1; /* '}' ']' ',' '@' '`' '%': no node
|
|
1828
|
+
* content can start there (the nightly's
|
|
1829
|
+
* fuzz_roundtrip crasher, "u: }") — the engine
|
|
1830
|
+
* errors cleanly */
|
|
1831
|
+
}
|
|
1820
1832
|
/* a terminating ':' inside the value is the
|
|
1821
1833
|
* mapping-values error — the engine owns it */
|
|
1822
1834
|
for (const char* h = (const char*)memchr(p + vt, ':', line_end - vt);
|
|
@@ -65,24 +65,31 @@ YEPTRIS_API size_t yeptris_serialize_into_ex(YeptrisDocument handle,
|
|
|
65
65
|
em.w.watermark = 0;
|
|
66
66
|
em.w.sink_aborted = 0;
|
|
67
67
|
em.w.flushed = 0;
|
|
68
|
-
|
|
68
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
69
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
69
70
|
return 0;
|
|
70
71
|
}
|
|
71
72
|
em.w.sc_dec = (uint8_t*)malloc(em.doc->dom->ncount > 0 ? em.doc->dom->ncount : 1);
|
|
72
73
|
if (em.w.sc_dec == NULL) {
|
|
73
|
-
|
|
74
|
+
if (em.canon_names.sys != NULL) {
|
|
75
|
+
yep_nametab_free(&em.canon_names);
|
|
76
|
+
}
|
|
74
77
|
return 0;
|
|
75
78
|
}
|
|
76
79
|
size_t need = yep_emit_run(&em, 1);
|
|
77
80
|
if (buf == NULL || cap < need + 1) {
|
|
78
81
|
free(em.w.sc_dec);
|
|
79
|
-
|
|
82
|
+
if (em.canon_names.sys != NULL) {
|
|
83
|
+
yep_nametab_free(&em.canon_names);
|
|
84
|
+
}
|
|
80
85
|
return need;
|
|
81
86
|
}
|
|
82
87
|
em.w.p = buf;
|
|
83
88
|
size_t wrote = yep_emit_run(&em, 0);
|
|
84
89
|
free(em.w.sc_dec);
|
|
85
|
-
|
|
90
|
+
if (em.canon_names.sys != NULL) {
|
|
91
|
+
yep_nametab_free(&em.canon_names);
|
|
92
|
+
}
|
|
86
93
|
buf[wrote] = '\0';
|
|
87
94
|
return wrote;
|
|
88
95
|
}
|
|
@@ -123,7 +130,8 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
123
130
|
em.w.watermark = 0;
|
|
124
131
|
em.w.sink_aborted = 0;
|
|
125
132
|
em.w.flushed = 0;
|
|
126
|
-
|
|
133
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
134
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
127
135
|
return NULL;
|
|
128
136
|
}
|
|
129
137
|
/* #352 slice 2: ONE wet pass into a growable buffer — the dry
|
|
@@ -138,7 +146,9 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
138
146
|
}
|
|
139
147
|
char* out = (char*)malloc(est);
|
|
140
148
|
if (out == NULL) {
|
|
141
|
-
|
|
149
|
+
if (em.canon_names.sys != NULL) {
|
|
150
|
+
yep_nametab_free(&em.canon_names);
|
|
151
|
+
}
|
|
142
152
|
return NULL;
|
|
143
153
|
}
|
|
144
154
|
em.w.p = out;
|
|
@@ -152,16 +162,20 @@ YEPTRIS_API char* yeptris_serialize_ex(YeptrisDocument handle, const yeptris_emi
|
|
|
152
162
|
out = em.w.p;
|
|
153
163
|
if (em.w.oom) {
|
|
154
164
|
free(out);
|
|
155
|
-
|
|
165
|
+
if (em.canon_names.sys != NULL) {
|
|
166
|
+
yep_nametab_free(&em.canon_names);
|
|
167
|
+
}
|
|
156
168
|
return NULL;
|
|
157
169
|
}
|
|
158
|
-
if (wrote + 1
|
|
170
|
+
if (em.w.cap - (wrote + 1) > em.w.cap / 8) {
|
|
159
171
|
char* tight = (char*)realloc(out, wrote + 1);
|
|
160
172
|
if (tight != NULL) {
|
|
161
173
|
out = tight;
|
|
162
174
|
}
|
|
163
175
|
}
|
|
164
|
-
|
|
176
|
+
if (em.canon_names.sys != NULL) {
|
|
177
|
+
yep_nametab_free(&em.canon_names);
|
|
178
|
+
}
|
|
165
179
|
out[wrote] = '\0';
|
|
166
180
|
if (len != NULL) {
|
|
167
181
|
*len = wrote;
|
|
@@ -200,18 +214,23 @@ YEPTRIS_API char* yeptris_serialize_json(YeptrisDocument handle, size_t* len) {
|
|
|
200
214
|
em.w.watermark = 0;
|
|
201
215
|
em.w.sink_aborted = 0;
|
|
202
216
|
em.w.flushed = 0;
|
|
203
|
-
|
|
217
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
218
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
204
219
|
return NULL;
|
|
205
220
|
}
|
|
206
221
|
size_t need = yep_emit_run(&em, 1);
|
|
207
222
|
char* out = malloc(need + 1);
|
|
208
223
|
if (out == NULL) {
|
|
209
|
-
|
|
224
|
+
if (em.canon_names.sys != NULL) {
|
|
225
|
+
yep_nametab_free(&em.canon_names);
|
|
226
|
+
}
|
|
210
227
|
return NULL;
|
|
211
228
|
}
|
|
212
229
|
em.w.p = out;
|
|
213
230
|
size_t wrote = yep_emit_run(&em, 0);
|
|
214
|
-
|
|
231
|
+
if (em.canon_names.sys != NULL) {
|
|
232
|
+
yep_nametab_free(&em.canon_names);
|
|
233
|
+
}
|
|
215
234
|
out[wrote] = '\0';
|
|
216
235
|
if (len != NULL) {
|
|
217
236
|
*len = wrote;
|
|
@@ -253,18 +272,23 @@ YEPTRIS_API char* yeptris_serialize_json_ex(YeptrisDocument handle, size_t* len,
|
|
|
253
272
|
em.w.watermark = 0;
|
|
254
273
|
em.w.sink_aborted = 0;
|
|
255
274
|
em.w.flushed = 0;
|
|
256
|
-
|
|
275
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
276
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
257
277
|
return NULL;
|
|
258
278
|
}
|
|
259
279
|
size_t need = yep_emit_run(&em, 1);
|
|
260
280
|
char* out = malloc(need + 1);
|
|
261
281
|
if (out == NULL) {
|
|
262
|
-
|
|
282
|
+
if (em.canon_names.sys != NULL) {
|
|
283
|
+
yep_nametab_free(&em.canon_names);
|
|
284
|
+
}
|
|
263
285
|
return NULL;
|
|
264
286
|
}
|
|
265
287
|
em.w.p = out;
|
|
266
288
|
size_t wrote = yep_emit_run(&em, 0);
|
|
267
|
-
|
|
289
|
+
if (em.canon_names.sys != NULL) {
|
|
290
|
+
yep_nametab_free(&em.canon_names);
|
|
291
|
+
}
|
|
268
292
|
out[wrote] = '\0';
|
|
269
293
|
if (len != NULL) {
|
|
270
294
|
*len = wrote;
|
|
@@ -300,18 +324,23 @@ char* yep_serialize_json_compact(const yeptris_document* doc, size_t* len) {
|
|
|
300
324
|
em.w.watermark = 0;
|
|
301
325
|
em.w.sink_aborted = 0;
|
|
302
326
|
em.w.flushed = 0;
|
|
303
|
-
|
|
327
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
328
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
304
329
|
return NULL;
|
|
305
330
|
}
|
|
306
331
|
size_t need = yep_emit_run(&em, 1);
|
|
307
332
|
char* out = malloc(need + 1);
|
|
308
333
|
if (out == NULL) {
|
|
309
|
-
|
|
334
|
+
if (em.canon_names.sys != NULL) {
|
|
335
|
+
yep_nametab_free(&em.canon_names);
|
|
336
|
+
}
|
|
310
337
|
return NULL;
|
|
311
338
|
}
|
|
312
339
|
em.w.p = out;
|
|
313
340
|
size_t wrote = yep_emit_run(&em, 0);
|
|
314
|
-
|
|
341
|
+
if (em.canon_names.sys != NULL) {
|
|
342
|
+
yep_nametab_free(&em.canon_names);
|
|
343
|
+
}
|
|
315
344
|
out[wrote] = '\0';
|
|
316
345
|
if (len != NULL) {
|
|
317
346
|
*len = wrote;
|
|
@@ -347,18 +376,23 @@ char* yep_serialize_json_pretty(const yeptris_document* doc, size_t* len) {
|
|
|
347
376
|
em.w.watermark = 0;
|
|
348
377
|
em.w.sink_aborted = 0;
|
|
349
378
|
em.w.flushed = 0;
|
|
350
|
-
|
|
379
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
380
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
351
381
|
return NULL;
|
|
352
382
|
}
|
|
353
383
|
size_t need = yep_emit_run(&em, 1);
|
|
354
384
|
char* out = malloc(need + 1);
|
|
355
385
|
if (out == NULL) {
|
|
356
|
-
|
|
386
|
+
if (em.canon_names.sys != NULL) {
|
|
387
|
+
yep_nametab_free(&em.canon_names);
|
|
388
|
+
}
|
|
357
389
|
return NULL;
|
|
358
390
|
}
|
|
359
391
|
em.w.p = out;
|
|
360
392
|
size_t wrote = yep_emit_run(&em, 0);
|
|
361
|
-
|
|
393
|
+
if (em.canon_names.sys != NULL) {
|
|
394
|
+
yep_nametab_free(&em.canon_names);
|
|
395
|
+
}
|
|
362
396
|
out[wrote] = '\0';
|
|
363
397
|
if (len != NULL) {
|
|
364
398
|
*len = wrote;
|
|
@@ -409,13 +443,16 @@ YEPTRIS_API size_t yeptris_serialize_stream(YeptrisDocument handle,
|
|
|
409
443
|
em.w.sink = sink;
|
|
410
444
|
em.w.sink_ctx = ctx;
|
|
411
445
|
em.w.watermark = YEP_EMIT_WATERMARK;
|
|
412
|
-
|
|
446
|
+
memset(&em.canon_names, 0, sizeof(em.canon_names));
|
|
447
|
+
if (em.w.canonical && !yep_nametab_init(&em.canon_names, yep_system_allocator())) {
|
|
413
448
|
return 0;
|
|
414
449
|
}
|
|
415
450
|
/* one scratch window; the writer flushes it when it fills */
|
|
416
451
|
char* window = malloc(YEP_EMIT_WATERMARK * 2);
|
|
417
452
|
if (window == NULL) {
|
|
418
|
-
|
|
453
|
+
if (em.canon_names.sys != NULL) {
|
|
454
|
+
yep_nametab_free(&em.canon_names);
|
|
455
|
+
}
|
|
419
456
|
return 0;
|
|
420
457
|
}
|
|
421
458
|
em.w.p = window;
|
|
@@ -429,6 +466,8 @@ YEPTRIS_API size_t yeptris_serialize_stream(YeptrisDocument handle,
|
|
|
429
466
|
}
|
|
430
467
|
}
|
|
431
468
|
free(window);
|
|
432
|
-
|
|
469
|
+
if (em.canon_names.sys != NULL) {
|
|
470
|
+
yep_nametab_free(&em.canon_names);
|
|
471
|
+
}
|
|
433
472
|
return em.w.sink_aborted ? 0 : total;
|
|
434
473
|
}
|
|
@@ -142,6 +142,45 @@ static void emit_dq(yep_writer* w, const char* p, uint32_t n) {
|
|
|
142
142
|
uint32_t run = 0;
|
|
143
143
|
for (uint32_t i = 0; i < n; i++) {
|
|
144
144
|
unsigned char c = (unsigned char)p[i];
|
|
145
|
+
/* U+0085 (NEL) is a BREAK in YAML: raw it would fold on
|
|
146
|
+
* re-parse. Escape it ('\N' replaces the exact UTF-8 pair, so
|
|
147
|
+
* lengths stay equal). The nightly's fuzz_roundtrip
|
|
148
|
+
* byte-instability crasher, "\"1 \\N\"". */
|
|
149
|
+
if (c == 0xc2 && i + 1 < n && (unsigned char)p[i + 1] == 0x85) {
|
|
150
|
+
if (run) {
|
|
151
|
+
wr_put(w, p + i - run, run);
|
|
152
|
+
run = 0;
|
|
153
|
+
}
|
|
154
|
+
wr_put(w, "\\N", 2);
|
|
155
|
+
i++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
/* LS/PS (U+2028/U+2029) are libyaml breaks: raw, re-parse
|
|
159
|
+
* folds them (the nightly's ";\\P" catch). 2-char escapes of
|
|
160
|
+
* 3-byte sequences: the one-pass dry count sizes them. */
|
|
161
|
+
if (c == 0xe2 && i + 2 < n && (unsigned char)p[i + 1] == 0x80 &&
|
|
162
|
+
((unsigned char)p[i + 2] == 0xa8 || (unsigned char)p[i + 2] == 0xa9)) {
|
|
163
|
+
if (run) {
|
|
164
|
+
wr_put(w, p + i - run, run);
|
|
165
|
+
run = 0;
|
|
166
|
+
}
|
|
167
|
+
wr_put(w, (unsigned char)p[i + 2] == 0xa8 ? "\\L" : "\\P", 2);
|
|
168
|
+
i += 2;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
/* U+FEFF must never ride raw: at the buffer head it IS the
|
|
172
|
+
* BOM and re-parse would strip it (the nightly's UTF-32LE
|
|
173
|
+
* catch); Psych escapes it everywhere ("") */
|
|
174
|
+
if (c == 0xef && i + 2 < n && (unsigned char)p[i + 1] == 0xbb &&
|
|
175
|
+
(unsigned char)p[i + 2] == 0xbf) {
|
|
176
|
+
if (run) {
|
|
177
|
+
wr_put(w, p + i - run, run);
|
|
178
|
+
run = 0;
|
|
179
|
+
}
|
|
180
|
+
wr_put(w, "\\uFEFF", 6);
|
|
181
|
+
i += 2;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
145
184
|
if (c >= 0x20 && c != '"' && c != '\\' && c != 0x7f) {
|
|
146
185
|
run++;
|
|
147
186
|
continue;
|
|
@@ -330,6 +369,34 @@ enum { YEP_SC_NOTHING = 0, YEP_SC_PLAIN, YEP_SC_SQ, YEP_SC_DQ, YEP_SC_LITERAL };
|
|
|
330
369
|
|
|
331
370
|
static uint8_t sc_route(yep_writer* w, const char* p, uint32_t len, int as_key, uint8_t sty_in,
|
|
332
371
|
int has_tag) {
|
|
372
|
+
/* U+0085 is a break (only its \\N escape is byte-stable) and U+FEFF
|
|
373
|
+
* raw is the BOM (re-parse would strip it): both force the
|
|
374
|
+
* double-quoted route BEFORE the plain fast path can take them
|
|
375
|
+
* (the nightly's fuzz_roundtrip crashers). The NEL scan matches
|
|
376
|
+
* the UTF-8 PAIR only — a lone 0x85 is a continuation byte
|
|
377
|
+
* (U+315B = E3 85 9B). */
|
|
378
|
+
int has_nel = 0;
|
|
379
|
+
int has_bom = 0;
|
|
380
|
+
for (uint32_t k = 0; k + 1 < len; k++) {
|
|
381
|
+
if ((unsigned char)p[k] == 0xc2 && (unsigned char)p[k + 1] == 0x85) {
|
|
382
|
+
has_nel = 1;
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
/* LS/PS are breaks like NEL: only their escapes are stable */
|
|
386
|
+
if ((unsigned char)p[k] == 0xe2 && k + 2 < len && (unsigned char)p[k + 1] == 0x80 &&
|
|
387
|
+
((unsigned char)p[k + 2] == 0xa8 || (unsigned char)p[k + 2] == 0xa9)) {
|
|
388
|
+
has_nel = 1;
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
if ((unsigned char)p[k] == 0xef && k + 2 < len && (unsigned char)p[k + 1] == 0xbb &&
|
|
392
|
+
(unsigned char)p[k + 2] == 0xbf) {
|
|
393
|
+
has_bom = 1;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (has_nel || has_bom) {
|
|
398
|
+
return YEP_SC_DQ;
|
|
399
|
+
}
|
|
333
400
|
if ((sty_in == 1) && len > 0 &&
|
|
334
401
|
(as_key ? yep_style_plain_key_safe(p, len) : yep_style_plain_safe(p, len))) {
|
|
335
402
|
return YEP_SC_PLAIN; /* plain-safe implies no breaks: memchr skipped */
|
|
@@ -611,6 +678,67 @@ static void emit_block_map(yep_emitter* em, uint32_t id, int content_col) {
|
|
|
611
678
|
uint32_t child = n->first_child;
|
|
612
679
|
uint32_t pair = 0;
|
|
613
680
|
while (child != UINT32_MAX) {
|
|
681
|
+
/* #352: the flat plain member specialist — tiny scalar pairs
|
|
682
|
+
* pay dispatch and props checks, not byte work. Strictly
|
|
683
|
+
* narrower than the general body below: plain unpropertied
|
|
684
|
+
* key, plain unpropertied scalar value, both safety-proven by
|
|
685
|
+
* the exact predicates sc_route consults (no memo touch, so
|
|
686
|
+
* the dry/wet sc_i streams stay aligned). Anything else falls
|
|
687
|
+
* through untouched — parity by construction. */
|
|
688
|
+
const yep_dnode* kn0 = yep_dom_node(d, child);
|
|
689
|
+
const yep_dnode* vn0 = yep_dom_node(d, kn0->next_sibling);
|
|
690
|
+
if (!w->canonical && !w->json && !w->force_flow && vn0 != NULL && kn0->kind == 0 &&
|
|
691
|
+
kn0->style == 1 && kn0->anchor.len == 0 && kn0->tag.len == 0 && kn0->count == 0 &&
|
|
692
|
+
vn0->kind == 0 && vn0->style == 1 && vn0->anchor.len == 0 && vn0->tag.len == 0 &&
|
|
693
|
+
vn0->count == 0) {
|
|
694
|
+
yep_view kv = wv(w, kn0->value);
|
|
695
|
+
yep_view vv = wv(w, vn0->value);
|
|
696
|
+
if (kv.len > 0 && yep_style_plain_key_safe((const char*)kv.p, kv.len) &&
|
|
697
|
+
(vv.len == 0 || yep_style_plain_safe((const char*)vv.p, vv.len))) {
|
|
698
|
+
/* fused member write: plain-safe spans carry no breaks,
|
|
699
|
+
* so the col scan is arithmetic and one reservation
|
|
700
|
+
* covers the whole member (line + key + ':' + value) */
|
|
701
|
+
uint32_t ind = pair > 0 ? (uint32_t)content_col : 0u;
|
|
702
|
+
uint32_t nl = (pair > 0 && w->last != '\n') ? 1u : 0u;
|
|
703
|
+
uint32_t total = nl + ind + kv.len + 1u + (vv.len > 0 ? vv.len + 1u : 0u);
|
|
704
|
+
w->last = vv.len > 0 ? (char)vv.p[vv.len - 1] : ':';
|
|
705
|
+
if (nl) {
|
|
706
|
+
w->col = (int)(total - 1u); /* the break resets, then the line */
|
|
707
|
+
} else {
|
|
708
|
+
w->col += (int)total;
|
|
709
|
+
}
|
|
710
|
+
if (w->dry) {
|
|
711
|
+
w->len += total;
|
|
712
|
+
} else {
|
|
713
|
+
if (w->grow && w->len + total + 1 > w->cap) {
|
|
714
|
+
wr_grow(w, total);
|
|
715
|
+
}
|
|
716
|
+
if (w->oom) {
|
|
717
|
+
w->len += total; /* keep counting: the caller fails on oom */
|
|
718
|
+
} else {
|
|
719
|
+
char* q = w->p + w->len;
|
|
720
|
+
if (nl) {
|
|
721
|
+
*q++ = '\n';
|
|
722
|
+
}
|
|
723
|
+
for (uint32_t i = 0; i < ind; i++) {
|
|
724
|
+
*q++ = ' ';
|
|
725
|
+
}
|
|
726
|
+
memcpy(q, kv.p, kv.len);
|
|
727
|
+
q += kv.len;
|
|
728
|
+
*q++ = ':';
|
|
729
|
+
if (vv.len > 0) {
|
|
730
|
+
*q++ = ' ';
|
|
731
|
+
memcpy(q, vv.p, vv.len);
|
|
732
|
+
}
|
|
733
|
+
w->len += total;
|
|
734
|
+
wr_maybe_flush(w);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
pair++;
|
|
738
|
+
child = vn0->next_sibling;
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
614
742
|
const yep_dnode* kn = yep_dom_node(d, child);
|
|
615
743
|
const yep_dnode* vn = yep_dom_node(d, kn->next_sibling);
|
|
616
744
|
if (pair > 0) {
|
|
@@ -119,6 +119,11 @@ struct yep_engine {
|
|
|
119
119
|
char* norm_buf; /* owned input copy with exotic breaks normalized */
|
|
120
120
|
const struct yep_resolver* resolver; /* implicit-typing schema (10) */
|
|
121
121
|
int max_depth; /* runtime nesting limit (options) */
|
|
122
|
+
uint16_t rec; /* e_node<->e_parse_value call depth:
|
|
123
|
+
the props/value-line chain opens NO
|
|
124
|
+
container frame, so e->depth cannot
|
|
125
|
+
bound it (the nightly's stack
|
|
126
|
+
overflow crasher) */
|
|
122
127
|
int last_root_flow; /* a root-level flow node just completed */
|
|
123
128
|
int tag_undef; /* an unresolved !handle! was seen (QLJ7) */
|
|
124
129
|
int doc_inline; /* content node opened on the --- line */
|
|
@@ -1090,16 +1095,32 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
|
|
|
1090
1095
|
e->pos = yep_scan_prop_end(e->p, e->len, start);
|
|
1091
1096
|
anchor->p = e->p + start;
|
|
1092
1097
|
anchor->len = (uint32_t)(e->pos - start);
|
|
1098
|
+
if (anchor->len == 0) {
|
|
1099
|
+
/* libyaml requires one or more anchor characters
|
|
1100
|
+
* ("did not find expected alphabetic or numeric
|
|
1101
|
+
* character"); the nightly fuzz_roundtrip crasher,
|
|
1102
|
+
* a lone '&' */
|
|
1103
|
+
e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1093
1106
|
} else if (c == '!') {
|
|
1094
1107
|
size_t start = e->pos;
|
|
1095
1108
|
e->pos++;
|
|
1096
1109
|
if (e->pos < e->len && e->p[e->pos] == '<') {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1110
|
+
/* a verbatim tag closes '>' on the same line, with no
|
|
1111
|
+
* interior space and non-empty content — libyaml errors
|
|
1112
|
+
* otherwise ("did not find expected '>'"; the nightly's
|
|
1113
|
+
* fuzz_roundtrip byte-instability crasher, "!<") */
|
|
1114
|
+
size_t gt = e->pos + 1;
|
|
1115
|
+
while (gt < e->len && e->p[gt] != '>' && e->p[gt] != '\n' && e->p[gt] != '\r' &&
|
|
1116
|
+
e->p[gt] != ' ' && e->p[gt] != '\t') {
|
|
1117
|
+
gt++;
|
|
1118
|
+
}
|
|
1119
|
+
if (gt >= e->len || e->p[gt] != '>' || gt == e->pos + 1) {
|
|
1120
|
+
e_fail(e, YEP_ERR_UNEXPECTED, start);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
e->pos = gt + 1;
|
|
1103
1124
|
} else {
|
|
1104
1125
|
while (e->pos < e->len && yep_scan_prop_char((unsigned char)e->p[e->pos])) {
|
|
1105
1126
|
e->pos++;
|
|
@@ -1282,6 +1303,9 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
|
|
|
1282
1303
|
ev->col = e_col(e, e->pos) + 1;
|
|
1283
1304
|
yep_view anchor = {0}, tag = {0};
|
|
1284
1305
|
e_props(e, &anchor, &tag);
|
|
1306
|
+
if (e->err.code != YEP_ERR_NONE) {
|
|
1307
|
+
return -1; /* e_props failed (empty anchor name, unresolved tag) */
|
|
1308
|
+
}
|
|
1285
1309
|
ev->anchor = anchor;
|
|
1286
1310
|
ev->tag = tag;
|
|
1287
1311
|
if (!yep_view_is_empty(anchor)) {
|
|
@@ -1290,10 +1314,17 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
|
|
|
1290
1314
|
if (e_flow_ws(e) != 0) {
|
|
1291
1315
|
return -1;
|
|
1292
1316
|
}
|
|
1317
|
+
if (e->pos >= e->len) {
|
|
1318
|
+
/* props at EOF: no node follows the properties (the entry
|
|
1319
|
+
* guard above cannot cover this — e_props consumed to the
|
|
1320
|
+
* end; found by fuzz_parse, input "[!<<\r\n!]" x8) */
|
|
1321
|
+
return e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
|
|
1322
|
+
}
|
|
1293
1323
|
c = (unsigned char)e->p[e->pos];
|
|
1294
1324
|
if ((c == ',' || c == ']' || c == '}' || c == ':') &&
|
|
1295
1325
|
(!yep_view_is_empty(anchor) || !yep_view_is_empty(tag))) {
|
|
1296
1326
|
ev->implicit = 1; /* properties with no node: a tagged null */
|
|
1327
|
+
ev->style = YEP_STYLE_PLAIN;
|
|
1297
1328
|
e_pos_mark(e, e->pos, &ev->end_line, &ev->end_col);
|
|
1298
1329
|
return 1;
|
|
1299
1330
|
}
|
|
@@ -1813,6 +1844,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
1813
1844
|
/* '? : v' / '?' at the boundary: an EMPTY explicit key */
|
|
1814
1845
|
e_event_init(&ev, YEP_EV_SCALAR);
|
|
1815
1846
|
ev.implicit = 1;
|
|
1847
|
+
ev.style = YEP_STYLE_PLAIN;
|
|
1816
1848
|
ev.line = e->line;
|
|
1817
1849
|
ev.col = e_col(e, e->pos) + 1;
|
|
1818
1850
|
rc = 1;
|
|
@@ -1984,6 +2016,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
1984
2016
|
yep_event nv;
|
|
1985
2017
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
1986
2018
|
nv.implicit = 1;
|
|
2019
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
1987
2020
|
if (emit_now(e, &nv) != 0) {
|
|
1988
2021
|
return -2;
|
|
1989
2022
|
}
|
|
@@ -2026,6 +2059,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
2026
2059
|
yep_event nv;
|
|
2027
2060
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
2028
2061
|
nv.implicit = 1;
|
|
2062
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
2029
2063
|
if (emit_now(e, &nv) != 0) {
|
|
2030
2064
|
return -2;
|
|
2031
2065
|
}
|
|
@@ -2059,6 +2093,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
2059
2093
|
yep_event nv;
|
|
2060
2094
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
2061
2095
|
nv.implicit = 1;
|
|
2096
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
2062
2097
|
if (emit_now(e, &nv) != 0) {
|
|
2063
2098
|
return -2;
|
|
2064
2099
|
}
|
|
@@ -2076,6 +2111,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
2076
2111
|
yep_event nv;
|
|
2077
2112
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
2078
2113
|
nv.implicit = 1;
|
|
2114
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
2079
2115
|
if (emit_now(e, &nv) != 0) {
|
|
2080
2116
|
return -2;
|
|
2081
2117
|
}
|
|
@@ -2104,6 +2140,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
2104
2140
|
yep_event nv;
|
|
2105
2141
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
2106
2142
|
nv.implicit = 1;
|
|
2143
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
2107
2144
|
if (emit_now(e, &nv) != 0) {
|
|
2108
2145
|
return -2;
|
|
2109
2146
|
}
|
|
@@ -2114,6 +2151,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
|
|
|
2114
2151
|
yep_event nv;
|
|
2115
2152
|
e_event_init(&nv, YEP_EV_SCALAR);
|
|
2116
2153
|
nv.implicit = 1;
|
|
2154
|
+
nv.style = YEP_STYLE_PLAIN;
|
|
2117
2155
|
if (emit_now(e, &nv) != 0) {
|
|
2118
2156
|
return -2;
|
|
2119
2157
|
}
|
|
@@ -2657,7 +2695,13 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
2657
2695
|
e->pend_anchor_id = anchor_ordinal;
|
|
2658
2696
|
e->pend_tag = node_t;
|
|
2659
2697
|
e->doc_inline = 0; /* the node starts on a later line */
|
|
2660
|
-
|
|
2698
|
+
if (++e->rec >= e->max_depth) {
|
|
2699
|
+
e->rec--;
|
|
2700
|
+
return e_fail(e, YEP_ERR_DEPTH, e->pos);
|
|
2701
|
+
}
|
|
2702
|
+
int rc = e_parse_value(e, ctx, floor_col);
|
|
2703
|
+
e->rec--;
|
|
2704
|
+
return rc;
|
|
2661
2705
|
/* (ctx stays: AFTER_COLON converts to VALUE_LINE at the break) */
|
|
2662
2706
|
}
|
|
2663
2707
|
|
|
@@ -3069,7 +3113,15 @@ static int e_parse_value(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
|
|
|
3069
3113
|
(vctx == YEP_CTX_VALUE_LINE && (li.first == '|' || li.first == '>') &&
|
|
3070
3114
|
li.indent == floor_col)) {
|
|
3071
3115
|
e->pos += li.indent;
|
|
3072
|
-
|
|
3116
|
+
if (++e->rec >= e->max_depth) {
|
|
3117
|
+
e->rec--;
|
|
3118
|
+
return e_fail(e, YEP_ERR_DEPTH, e->pos);
|
|
3119
|
+
}
|
|
3120
|
+
{
|
|
3121
|
+
int rc = e_node(e, vctx, floor_col);
|
|
3122
|
+
e->rec--;
|
|
3123
|
+
return rc;
|
|
3124
|
+
}
|
|
3073
3125
|
}
|
|
3074
3126
|
/* indentless sequence as a mapping value; under a sequence frame
|
|
3075
3127
|
* a dash at the same column is a SIBLING, not a continuation */
|
|
@@ -199,6 +199,10 @@ static void shape_value(const char* p, size_t len, const yep_line_info* li, size
|
|
|
199
199
|
}
|
|
200
200
|
if (c == '&') {
|
|
201
201
|
size_t a_end = yep_scan_prop_end(p, len, vt + 1);
|
|
202
|
+
if (a_end == vt + 1) {
|
|
203
|
+
return; /* an anchor needs a name (libyaml): the general
|
|
204
|
+
* chain owns the error */
|
|
205
|
+
}
|
|
202
206
|
size_t t = a_end;
|
|
203
207
|
while (t < len && (p[t] == ' ' || p[t] == '\t')) {
|
|
204
208
|
t++;
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.31.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|