leptris 1.9.231.0 → 1.9.232.0
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/CHANGELOG.md +19 -0
- data/Rakefile +1 -1
- data/ext/leptris/native/native.c +39 -0
- data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
- data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
- data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/ffi.rb +4 -0
- data/lib/leptris/xml/node.rb +28 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +15 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/include/leptris/descriptor.h +5 -1
- data/vendor-src/libleptris/src/include/leptris.h +17 -0
- data/vendor-src/libleptris/src/leptris/descriptor/plan.c +26 -6
- data/vendor-src/libleptris/src/leptris/dom/node.c +24 -7
- data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +22 -8
- data/vendor-src/libleptris/src/leptris/xpath/functions.c +29 -8
- data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +30 -1
- data/vendor-src/libleptris/src/leptris/xpath/parser.c +106 -6
- data/vendor-src/libleptris/test/abi/test_descriptor.cpp +68 -0
- data/vendor-src/libleptris/test/dom/test_dom.cpp +56 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/codepoints-to-string.xml +808 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/deep-equal.xml +2709 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/distinct-values.xml +1223 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/index-of.xml +493 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/insert-before.xml +399 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/remove.xml +480 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/reverse.xml +653 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/string-to-codepoints.xml +452 -0
- data/vendor-src/libleptris/test/xquery/qt3/fn/subsequence.xml +1041 -0
- data/vendor-src/libleptris/test/xquery/test_qt3.cpp +179 -1
- data/vendor-src/libleptris/test/xquery/test_xquery.cpp +27 -0
- data/vendor-src/libleptris/vcpkg.json +1 -1
- metadata +11 -2
|
@@ -2382,6 +2382,98 @@ static XPathASTNode* parse_switch_expr(XPathParser* parser) {
|
|
|
2382
2382
|
}
|
|
2383
2383
|
}
|
|
2384
2384
|
}
|
|
2385
|
+
|
|
2386
|
+
/* String literal body -> decoded value (malloc'd). XQuery 3.1
|
|
2387
|
+
* 3.1.1: character references (
, A, 😀) expand to
|
|
2388
|
+
* the referenced codepoint -- EXEMPT from line-end normalization
|
|
2389
|
+
* (QT3 K-CodepointToStringFunc-13) -- and the five predefined
|
|
2390
|
+
* entity refs expand likewise. A '&' that is not a well-formed
|
|
2391
|
+
* reference stays literal (the text-path leniency). Codepoints are
|
|
2392
|
+
* UTF-8 encoded, so astral refs work. */
|
|
2393
|
+
static char* decode_string_literal(const char* p, size_t n) {
|
|
2394
|
+
char* out = (char*)malloc(n + 1);
|
|
2395
|
+
if (!out) return NULL;
|
|
2396
|
+
size_t o = 0;
|
|
2397
|
+
const char* pe = p + n;
|
|
2398
|
+
while (p < pe) {
|
|
2399
|
+
if (*p != '&') {
|
|
2400
|
+
out[o++] = *p++;
|
|
2401
|
+
continue;
|
|
2402
|
+
}
|
|
2403
|
+
const char* semi = memchr(p, ';', (size_t)(pe - p));
|
|
2404
|
+
static const char* const k_predef[] = { "amp", "lt", "gt",
|
|
2405
|
+
"quot", "apos" };
|
|
2406
|
+
static const char k_predef_ch[] = { '&', '<', '>', '"', '\'' };
|
|
2407
|
+
int handled = 0;
|
|
2408
|
+
if (semi && (size_t)(semi - p) <= 12) {
|
|
2409
|
+
size_t rl = (size_t)(semi - p - 1);
|
|
2410
|
+
const char* r = p + 1;
|
|
2411
|
+
if (*r == '#') {
|
|
2412
|
+
r++;
|
|
2413
|
+
int hex = 0;
|
|
2414
|
+
if (r < semi && (*r == 'x' || *r == 'X')) {
|
|
2415
|
+
hex = 1;
|
|
2416
|
+
r++;
|
|
2417
|
+
}
|
|
2418
|
+
unsigned long cp = 0;
|
|
2419
|
+
const char* ds = r;
|
|
2420
|
+
while (r < semi) {
|
|
2421
|
+
char c = *r;
|
|
2422
|
+
int dv = hex ? (c >= '0' && c <= '9')
|
|
2423
|
+
? c - '0'
|
|
2424
|
+
: (c >= 'a' && c <= 'f')
|
|
2425
|
+
? c - 'a' + 10
|
|
2426
|
+
: (c >= 'A' && c <= 'F')
|
|
2427
|
+
? c - 'A' + 10
|
|
2428
|
+
: -1
|
|
2429
|
+
: (c >= '0' && c <= '9') ? c - '0' : -1;
|
|
2430
|
+
if (dv < 0) break;
|
|
2431
|
+
cp = cp * (hex ? 16ul : 10ul) + (unsigned long)dv;
|
|
2432
|
+
if (cp > 0x110000ul) cp = 0x110001ul;
|
|
2433
|
+
r++;
|
|
2434
|
+
}
|
|
2435
|
+
if (r == semi && r > ds &&
|
|
2436
|
+
(cp == 0x9ul || cp == 0xAul || cp == 0xDul ||
|
|
2437
|
+
(cp >= 0x20ul && cp <= 0x10FFFFul)) &&
|
|
2438
|
+
(cp < 0xD800ul || cp > 0xDFFFul)) {
|
|
2439
|
+
if (cp < 0x80ul) {
|
|
2440
|
+
out[o++] = (char)cp;
|
|
2441
|
+
} else if (cp < 0x800ul) {
|
|
2442
|
+
out[o++] = (char)(0xC0 | (cp >> 6));
|
|
2443
|
+
out[o++] = (char)(0x80 | (cp & 0x3F));
|
|
2444
|
+
} else if (cp < 0x10000ul) {
|
|
2445
|
+
out[o++] = (char)(0xE0 | (cp >> 12));
|
|
2446
|
+
out[o++] = (char)(0x80 | ((cp >> 6) & 0x3F));
|
|
2447
|
+
out[o++] = (char)(0x80 | (cp & 0x3F));
|
|
2448
|
+
} else {
|
|
2449
|
+
out[o++] = (char)(0xF0 | (cp >> 18));
|
|
2450
|
+
out[o++] = (char)(0x80 | ((cp >> 12) & 0x3F));
|
|
2451
|
+
out[o++] = (char)(0x80 | ((cp >> 6) & 0x3F));
|
|
2452
|
+
out[o++] = (char)(0x80 | (cp & 0x3F));
|
|
2453
|
+
}
|
|
2454
|
+
handled = 1;
|
|
2455
|
+
}
|
|
2456
|
+
} else {
|
|
2457
|
+
for (int i = 0; i < 5; i++) {
|
|
2458
|
+
if (rl == strlen(k_predef[i]) &&
|
|
2459
|
+
memcmp(r, k_predef[i], rl) == 0) {
|
|
2460
|
+
out[o++] = k_predef_ch[i];
|
|
2461
|
+
handled = 1;
|
|
2462
|
+
break;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
if (handled) {
|
|
2468
|
+
p = semi + 1;
|
|
2469
|
+
} else {
|
|
2470
|
+
out[o++] = *p++;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
out[o] = '\0';
|
|
2474
|
+
return out;
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2385
2477
|
static XPathASTNode* parse_primary_expr(XPathParser* parser) {
|
|
2386
2478
|
XPathToken* tok = current_token(parser);
|
|
2387
2479
|
if (!tok) {
|
|
@@ -2423,13 +2515,21 @@ static XPathASTNode* parse_primary_expr(XPathParser* parser) {
|
|
|
2423
2515
|
XPathASTNode* node = ast_node_new(XPATH_AST_STRING);
|
|
2424
2516
|
if (!node) return NULL;
|
|
2425
2517
|
|
|
2426
|
-
/* Remove quotes
|
|
2518
|
+
/* Remove quotes; expand references when present. The scan
|
|
2519
|
+
* for '&' keeps the plain-literal path a memcpy (the common
|
|
2520
|
+
* case pays nothing). */
|
|
2427
2521
|
if (tok->value_len >= 2) {
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
if (
|
|
2431
|
-
|
|
2432
|
-
|
|
2522
|
+
const char* bp = tok->value + 1;
|
|
2523
|
+
size_t blen = tok->value_len - 2;
|
|
2524
|
+
if (blen && memchr(bp, '&', blen)) {
|
|
2525
|
+
node->value = decode_string_literal(bp, blen);
|
|
2526
|
+
}
|
|
2527
|
+
if (!node->value) {
|
|
2528
|
+
node->value = LEPTRIS_ALLOC_N(char, blen + 1);
|
|
2529
|
+
if (node->value) {
|
|
2530
|
+
memcpy(node->value, bp, blen);
|
|
2531
|
+
node->value[blen] = '\0';
|
|
2532
|
+
}
|
|
2433
2533
|
}
|
|
2434
2534
|
}
|
|
2435
2535
|
advance_token(parser);
|
|
@@ -386,6 +386,74 @@ TEST(PlanWalk, NamespaceFormsAndLeniency) {
|
|
|
386
386
|
leptris_document_free(doc);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
+
/* XSD-002 fallout class: child rows whose wire_name is the PREFIXED
|
|
390
|
+
* form ("w:b") — exactly what the ABI doc promises ("XML element
|
|
391
|
+
* name as it appears on the wire") — must bind namespaced elements.
|
|
392
|
+
* The matcher historically compared the LOCAL name only, so every
|
|
393
|
+
* prefixed row silently matched nothing: hosts hydrated empty
|
|
394
|
+
* subtrees (attributes read NULL, elements fell back to defaults)
|
|
395
|
+
* and re-serialized without them. Local-name rows keep binding. */
|
|
396
|
+
TEST(PlanWalk, PrefixedWireNamesBindNamespacedElements) {
|
|
397
|
+
LeptrisDocument doc = parse(
|
|
398
|
+
"<w:document xmlns:w=\"urn:w\">"
|
|
399
|
+
"<w:r><w:b w:val=\"false\"/></w:r>"
|
|
400
|
+
"</w:document>");
|
|
401
|
+
ASSERT_NE(doc, nullptr);
|
|
402
|
+
LeptrisElement root = leptris_document_root(doc);
|
|
403
|
+
|
|
404
|
+
leptris_attr_plan b_attrs[] = {
|
|
405
|
+
{"w:val", LEPTRIS_PLAN_KIND_SCALAR, 7, 0, 0, nullptr},
|
|
406
|
+
};
|
|
407
|
+
leptris_child_plan b_row = {};
|
|
408
|
+
b_row.wire_name = "w:b";
|
|
409
|
+
b_row.kind = LEPTRIS_PLAN_KIND_NESTED;
|
|
410
|
+
b_row.child_plan_index = 2;
|
|
411
|
+
b_row.ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
412
|
+
leptris_child_plan r_row = {};
|
|
413
|
+
r_row.wire_name = "w:r";
|
|
414
|
+
r_row.kind = LEPTRIS_PLAN_KIND_NESTED;
|
|
415
|
+
r_row.child_plan_index = 1;
|
|
416
|
+
r_row.ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
417
|
+
leptris_element_plan plans[3] = {};
|
|
418
|
+
plans[0].element_name = "document";
|
|
419
|
+
plans[0].ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
420
|
+
plans[0].child_count = 1;
|
|
421
|
+
plans[0].child_plans = &r_row;
|
|
422
|
+
plans[1].element_name = "r";
|
|
423
|
+
plans[1].ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
424
|
+
plans[1].child_count = 1;
|
|
425
|
+
plans[1].child_plans = &b_row;
|
|
426
|
+
plans[2].element_name = "b";
|
|
427
|
+
plans[2].ns_form = LEPTRIS_PLAN_NS_ANY;
|
|
428
|
+
plans[2].attribute_count = 1;
|
|
429
|
+
plans[2].attribute_plans = b_attrs;
|
|
430
|
+
|
|
431
|
+
leptris_plan_spec spec = {};
|
|
432
|
+
spec.abi_version = leptris_plan_abi_version();
|
|
433
|
+
spec.plan_count = 3;
|
|
434
|
+
spec.plans = plans;
|
|
435
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
436
|
+
LeptrisPlan plan = leptris_plan_build(&spec, &st);
|
|
437
|
+
ASSERT_NE(plan, nullptr);
|
|
438
|
+
LeptrisPlanResult r = leptris_plan_walk(doc, root, plan, &st);
|
|
439
|
+
ASSERT_NE(r, nullptr);
|
|
440
|
+
ASSERT_EQ(leptris_plan_value_count(r), 1u);
|
|
441
|
+
LeptrisPlanResult rcoll = leptris_plan_value_at(r, 0);
|
|
442
|
+
ASSERT_NE(rcoll, nullptr);
|
|
443
|
+
/* the nested w:r row binds its element value */
|
|
444
|
+
ASSERT_EQ(leptris_plan_value_kind(rcoll), LEPTRIS_PLAN_VALUE_ELEMENT);
|
|
445
|
+
ASSERT_EQ(leptris_plan_value_count(rcoll), 1u);
|
|
446
|
+
LeptrisPlanResult bval = leptris_plan_value_at(rcoll, 0);
|
|
447
|
+
ASSERT_NE(bval, nullptr);
|
|
448
|
+
ASSERT_EQ(leptris_plan_value_kind(bval), LEPTRIS_PLAN_VALUE_ELEMENT);
|
|
449
|
+
const char* val = leptris_plan_value_attribute(bval, "w:val");
|
|
450
|
+
ASSERT_NE(val, nullptr);
|
|
451
|
+
EXPECT_STREQ(val, "false");
|
|
452
|
+
leptris_plan_result_free(r);
|
|
453
|
+
leptris_plan_free(plan);
|
|
454
|
+
leptris_document_free(doc);
|
|
455
|
+
}
|
|
456
|
+
|
|
389
457
|
TEST(PlanBuild, CopiesTheSpecStrings) {
|
|
390
458
|
LeptrisDocument doc = parse("<doc><t>v</t></doc>");
|
|
391
459
|
ASSERT_NE(doc, nullptr);
|
|
@@ -2234,6 +2234,62 @@ TEST(DomBasics, NodeVisitWalksSubtreeEnterLeave) {
|
|
|
2234
2234
|
leptris_document_free(doc);
|
|
2235
2235
|
}
|
|
2236
2236
|
|
|
2237
|
+
/* Issue #1332: entering-only visit mode — one callback per node, on
|
|
2238
|
+
* entering. Halves the C-callback invocations for consumers that
|
|
2239
|
+
* discard the leaving half (family walks bind lazily on enter).
|
|
2240
|
+
* Same walk order and depths as leptris_node_visit. */
|
|
2241
|
+
TEST(DomBasics, NodeVisitEnteringFiresOncePerNode) {
|
|
2242
|
+
const char xml[] = "<r><a>t1</a><b><!--c--></b></r>";
|
|
2243
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
2244
|
+
LeptrisDocument doc = leptris_parse_string(xml, std::strlen(xml), &st);
|
|
2245
|
+
ASSERT_NE(doc, nullptr);
|
|
2246
|
+
LeptrisElement root = leptris_document_root(doc);
|
|
2247
|
+
ASSERT_NE(root, nullptr);
|
|
2248
|
+
|
|
2249
|
+
VisitLog log;
|
|
2250
|
+
leptris_node_visit_entering((LeptrisNodeRef)root, &VisitLog::visit,
|
|
2251
|
+
&log);
|
|
2252
|
+
/* 5 nodes (r, a, text, b, comment) — the 3 leaving events of
|
|
2253
|
+
* the full mode are gone. The event list has no L* entries. */
|
|
2254
|
+
ASSERT_EQ(log.events.size(), 5u);
|
|
2255
|
+
EXPECT_EQ(log.events[0], "Er:0");
|
|
2256
|
+
EXPECT_EQ(log.events[1], "Ea:1");
|
|
2257
|
+
EXPECT_EQ(log.events[2], "T:2");
|
|
2258
|
+
EXPECT_EQ(log.events[3], "Eb:1");
|
|
2259
|
+
EXPECT_EQ(log.events[4], "O:2");
|
|
2260
|
+
|
|
2261
|
+
/* Document-node walk behaves identically to the full mode. */
|
|
2262
|
+
VisitLog dlog;
|
|
2263
|
+
leptris_node_visit_entering(leptris_document_node(doc),
|
|
2264
|
+
&VisitLog::visit, &dlog);
|
|
2265
|
+
ASSERT_EQ(dlog.events.size(), 5u);
|
|
2266
|
+
EXPECT_EQ(dlog.events[0], "Er:0");
|
|
2267
|
+
leptris_document_free(doc);
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
TEST(DomBasics, NodeVisitEnteringHalvesTheCallbackCount) {
|
|
2271
|
+
/* The moxml-walk contract (#1332): elements visit TWICE in the
|
|
2272
|
+
* full mode, ONCE here. */
|
|
2273
|
+
const char xml[] =
|
|
2274
|
+
"<r><a><b/><c><d/></c></a><e/><f><g><h/></g></f></r>";
|
|
2275
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
2276
|
+
LeptrisDocument doc = leptris_parse_string(xml, std::strlen(xml), &st);
|
|
2277
|
+
ASSERT_NE(doc, nullptr);
|
|
2278
|
+
|
|
2279
|
+
int full_calls = 0, entering_calls = 0;
|
|
2280
|
+
auto counter = +[](void* ud, LeptrisNodeRef, int, int) {
|
|
2281
|
+
++*static_cast<int*>(ud);
|
|
2282
|
+
};
|
|
2283
|
+
leptris_node_visit((LeptrisNodeRef)leptris_document_root(doc),
|
|
2284
|
+
counter, &full_calls);
|
|
2285
|
+
leptris_node_visit_entering(
|
|
2286
|
+
(LeptrisNodeRef)leptris_document_root(doc), counter,
|
|
2287
|
+
&entering_calls);
|
|
2288
|
+
EXPECT_EQ(full_calls, 18); /* 9 elements * 2 */
|
|
2289
|
+
EXPECT_EQ(entering_calls, 9); /* 9 elements, once */
|
|
2290
|
+
leptris_document_free(doc);
|
|
2291
|
+
}
|
|
2292
|
+
|
|
2237
2293
|
TEST(DomBasics, NodeChildrenExCarriesKinds) {
|
|
2238
2294
|
const char xml[] =
|
|
2239
2295
|
"<r>text<!--c--><a/><?pi x?></r>";
|