leptris 1.9.287.0-ppc64le-linux → 1.9.290.0-ppc64le-linux

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c75b5c08c95ae3b7bad54696d4689aeb99203ea67fe5d122fe7617f2d9cad48
4
- data.tar.gz: 27edf2484a9d4897cad4ae2415ee61b40a0d039fdcac6021d3c859805b055611
3
+ metadata.gz: 505fb9e6093b335b955a6c776e97beb0cd43d9e498d8f44333b3faccc93bee26
4
+ data.tar.gz: 69b07068ad720f0da28fbc713625884621cf067a0fe0134b88bed2eba8549fa5
5
5
  SHA512:
6
- metadata.gz: 13f21fd7388db204aad1adf676cd6fec3c9e03870270075f05f10a0fa16ca1154ee2950dea81fb7bc40029508e742089ccb866b2a1c466bf347d39259c396fb2
7
- data.tar.gz: 7a261ed53220fbeef6006cd7a69548088ac9bb89d5ba43102319608c460c9882320b62dee3afdc87b9c9e36b9a4b921207e3ebfbb9e5ea1f6589e2dfdabfc1ab
6
+ metadata.gz: aba2088b46d2f97563715259e4a8c8f12fa49f5918a42272f849c64030aad24fa0051449e9f29a0e90c5f7e118be49cc8dc9eae14f4575f4c7552c524715205c
7
+ data.tar.gz: ea9d90fb9c71b40bcd3692b81d138752a9e4d5aca9943baa6f6a62769f1136773cb0b54e28ed36e0c7ca4a46c7e40b874351f4d76ebdbf227d64611f38502bad
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.287"
11
+ LIBLEPTRIS_VERSION = "1.9.290"
12
12
  # Vendored alongside libleptris for fn:normalize-unicode (TODO
13
13
  # .restructure/20): built per platform with a RELOCATABLE @rpath
14
14
  # install name, loaded by ffi.rb before libleptris so the
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.287.0"
4
+ VERSION = "1.9.290.0"
5
5
  end
@@ -167,6 +167,18 @@ class Leptris::XML::Descriptor
167
167
  ap[:wire_name] = anchor_string(anchors, row.fetch(:name))
168
168
  ap[:kind] = kind_code(row[:kind] || :scalar)
169
169
  ap[:type_tag] = type_tag_code(row)
170
+ # Attribute-level namespace form (libleptris 1.9.289, #1486):
171
+ # ns rows match by (URI, local) — the wire prefix is irrelevant.
172
+ # Mirrors the child-row packing.
173
+ ap[:ns_form] =
174
+ case row[:ns]
175
+ when :any then Leptris::XML::FFI::PLAN_NS_ANY
176
+ when Hash then Leptris::XML::FFI::PLAN_NS_EXACT
177
+ else Leptris::XML::FFI::PLAN_NS_NONE
178
+ end
179
+ ap[:ns_uri] =
180
+ row[:ns].is_a?(Hash) ?
181
+ anchor_string(anchors, row[:ns].fetch(:exact)) : nil
170
182
  pack_predicates(ap, row, anchors)
171
183
  end
172
184
  ep[:attribute_count] = attrs.size
@@ -299,7 +299,13 @@ module Leptris
299
299
  :type_tag, :uint8,
300
300
  :predicate_count, :uint16,
301
301
  :pad_pred, :uint16,
302
- :predicates, :pointer
302
+ :predicates, :pointer,
303
+ # libleptris 1.9.289 (#1486): attribute-level namespace
304
+ # form — ns rows match by (URI, local), wire_name is the
305
+ # LOCAL name; NONE keeps wire-name-exact matching.
306
+ :ns_form, :uint8,
307
+ :pad_ns, :uint8,
308
+ :ns_uri, :pointer
303
309
  end
304
310
  class ChildPlan < ::FFI::Struct
305
311
  layout :wire_name, :pointer,
data/lib/libleptris.so CHANGED
Binary file
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.287
4
+ - libleptris v1.9.290
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,37 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.290] - 2026-10-02
4
+
5
+ <!-- Edit this section with the actual release notes. -->
6
+ <!-- See https://keepachangelog.com for format guidance. -->
7
+
8
+ ### Added
9
+
10
+ - namespace forms for attribute plan rows — `ns_form`/`ns_uri` on `leptris_attr_plan` (#1486)
11
+ - Extends #1115's child-row pattern to attribute rows: `ns_form = 0` (the zero value) keeps the historical wire-name lookup byte-for-byte and existing aggregate initializers stay valid; `LEPTRIS_PLAN_NS_EXACT` + `ns_uri` makes `wire_name` the LOCAL name and binds the (namespace URI, local) identity through the element's in-scope prefix bindings — prefix-spelling-independent, so a `w14:paraId`-typed row binds whatever prefix the document uses for the Word 2010 URI. `LEPTRIS_PLAN_NS_ANY` matches the local name in any namespace; unprefixed attributes have no namespace and never bind EXACT (XML Namespaces §5.2).
12
+ - Unlocks the plan fast path for typed-attribute models: lutaml-model's `attr_type_ns` opt-out (one `w14:paraId` leaf cascading the WordprocessingML paragraph chain out of the plan path, against a measured 33% parse-CPU saving) can now emit ns-exact attribute rows instead.
13
+ - Build deep-copies `ns_uri`, zero-guards the trailing fields for hosts that `malloc` the spec without value-initialization (#1272 lesson), rejects `EXACT` without a URI as `INVALID_ARG`; free releases the copies. RED-first spec plus the full battery (1773/1773). (#1487)
14
+
15
+ ## [1.9.289] - 2026-10-02
16
+
17
+ ### Performance
18
+
19
+ - open-id compares for the scope/table-context stack walks (#1218 slice 6, tranche 2) (html)
20
+ - The scope walks (p-in-button-scope, button-in-scope, AFE `kn`), the table-context searches, and the table-context dispatch block compare `b->open_id[k]` integers instead of fetching the element name and running case-insensitive literal chains per stack slot. The AFE furthest-block scan deliberately keeps the name fetch — it runs mid-AFE between stack splices, where the id stack is not yet authoritative (webkit02:14). Interleaved A/B vs the tranche-1 tree: 48.2-53.7 -> 51.0-58.2 MB/s (+11% median) on the 2.6MB table-rows shape. (#1485)
21
+ - id-LUT membership for the foster/formatting/stack checks (#1218 slice 6) (html)
22
+ - The classifier table grows the 22 compared-but-unlisted names (HTML4 formatting set + MathML/SVG integration points, inert flags); `h_is_formatting` (14-way) and `h_fosterable` (15-way) become id-LUT lookups; 15 insertion-mode stack checks read `open_id[]` directly. 56.1 -> 59.0 MB/s (+5.2%) interleaved. Cumulative slice 6: ~+15% on the issue's fixture shape; the 3.4-7x deficit the issue reported at 1.9.203 is now a 1.3-1.55x LEAD over htmlReadMemory locally. (#1484)
23
+
24
+
25
+
26
+ ## [1.9.288] - 2026-10-02
27
+
28
+ ### Fixed
29
+
30
+ - top-level param values are XPath expressions (libxslt convention) — follow-up to #1478 (xslt)
31
+ - **Semantics correction to `leptris_xslt_apply_params` / `leptris_xslt_apply_string_params`, released briefly in 1.9.287:** value strings are now evaluated as XPath EXPRESSIONS (libxslt `params` convention; nokogiri's `quote_params` exists for exactly this), not bound as raw strings. Callers pass quoted literals — `{"n", "'7'"}` binds the string `7`; under 1.9.287 the quotes were part of the value. Numbers and source-derived expressions work (`7 * 6` → 42, `string(/r/@v)`), a later pair may reference an earlier one, a global `xsl:variable` may consume a caller value (§11 ordering), undeclared names bind into scope (libxslt parity), and a malformed expression fails the transform. Caller values bind before the globals run and a declared `xsl:param` default whose name a caller supplied never evaluates (§11.4). Specs ported from #1478 plus three RED-first expression cases; 1771/1771 and an external-consumer end-to-end probe. (#1481)
32
+
33
+
34
+
3
35
  ## [1.9.287] - 2026-10-02
4
36
 
5
37
  ### Added
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.287
6
+ VERSION 1.9.290
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -95,6 +95,18 @@ typedef struct {
95
95
  uint16_t predicate_count;
96
96
  uint16_t pad_pred;
97
97
  const leptris_attr_predicate* predicates;
98
+ /* #1486 (additive trailing fields, the #1115 child-row
99
+ * pattern): attribute-level namespace form. A row with
100
+ * ns_form set matches by (namespace URI, local name) —
101
+ * wire_name is the LOCAL name and the prefix spelling on the
102
+ * wire is irrelevant. NONE (0, the zero value) keeps the
103
+ * historical behavior: lookup by wire_name exactly as it
104
+ * appears on the wire (prefixed or bare). Unprefixed
105
+ * attributes have no namespace; EXACT requires a prefixed
106
+ * attribute whose prefix binds to ns_uri. */
107
+ uint8_t ns_form; /* LeptrisPlanNsForm */
108
+ uint8_t pad_ns;
109
+ const char* ns_uri; /* LEPTRIS_PLAN_NS_EXACT only */
98
110
  } leptris_attr_plan;
99
111
 
100
112
  typedef struct {
@@ -3096,20 +3096,6 @@ LEPTRIS_API void leptris_xslt_free(LeptrisXslt xslt);
3096
3096
  */
3097
3097
  LEPTRIS_API LeptrisDocument leptris_xslt_apply(LeptrisXslt xslt,
3098
3098
  LeptrisDocument doc);
3099
- /**
3100
- * Apply a compiled stylesheet with top-level xsl:param overrides
3101
- *
3102
- * `pairs` is a flat name/value array: 2*pair_count entries,
3103
- * pairs[2*i] is the param name, pairs[2*i+1] its string value
3104
- * (bound as an XPath string — consumers doing numeric quoting own
3105
- * that, matching libxslt conventions). A supplied name never
3106
- * evaluates the param's select/@default; absent names keep them.
3107
- * The array is borrowed for the duration of the call only.
3108
- */
3109
- LEPTRIS_API LeptrisDocument leptris_xslt_apply_params(
3110
- LeptrisXslt xslt, LeptrisDocument doc,
3111
- const char* const* pairs, size_t pair_count);
3112
-
3113
3099
  /**
3114
3100
  * Apply a compiled stylesheet and serialize the result
3115
3101
  *
@@ -3123,15 +3109,50 @@ LEPTRIS_API LeptrisDocument leptris_xslt_apply_params(
3123
3109
  */
3124
3110
  LEPTRIS_API char* leptris_xslt_apply_string(LeptrisXslt xslt,
3125
3111
  LeptrisDocument doc);
3112
+
3113
+ /**
3114
+ * Apply a compiled stylesheet with caller-supplied top-level params
3115
+ *
3116
+ * Binds the given xsl:param values BEFORE the stylesheet's globals
3117
+ * run (XSLT §11.4): a caller value replaces the declared default,
3118
+ * unspecified params keep their defaults, and the value expressions
3119
+ * may reference the source document and earlier pairs.
3120
+ *
3121
+ * pairs is a flat name/value array — [name0, value0, name1,
3122
+ * value1, ...] — and count is the number of PAIRS (the array holds
3123
+ * 2*count entries). Each value is an XPath EXPRESSION evaluated
3124
+ * with the source document node as context; callers pre-quote
3125
+ * string literals ("'text'"), matching the libxslt convention.
3126
+ *
3127
+ * @param xslt Compiled stylesheet
3128
+ * @param doc Source document (not modified)
3129
+ * @param pairs Flat name/expression array, or NULL with count 0
3130
+ * @param count Number of name/expression pairs
3131
+ * @return Result tree (free with leptris_document_free), or NULL on
3132
+ * error — including a value expression that fails to
3133
+ * compile (message via leptris_document_last_error)
3134
+ */
3135
+ LEPTRIS_API LeptrisDocument leptris_xslt_apply_params(
3136
+ LeptrisXslt xslt, LeptrisDocument doc,
3137
+ const char* const* pairs, size_t count);
3138
+
3126
3139
  /**
3127
- * Apply with top-level param overrides and serialize the result
3140
+ * Apply with caller-supplied top-level params and serialize
3141
+ *
3142
+ * leptris_xslt_apply_params + the leptris_xslt_apply_string
3143
+ * serialization contract (top-level text nodes and fragments
3144
+ * preserved).
3128
3145
  *
3129
- * Same pair encoding and semantics as leptris_xslt_apply_params;
3130
- * leptris_xslt_apply_string otherwise.
3146
+ * @param xslt Compiled stylesheet
3147
+ * @param doc Source document
3148
+ * @param pairs Flat name/expression array (see
3149
+ * leptris_xslt_apply_params), or NULL with count 0
3150
+ * @param count Number of name/expression pairs
3151
+ * @return Serialized result (free with leptris_free_string), or NULL
3131
3152
  */
3132
3153
  LEPTRIS_API char* leptris_xslt_apply_string_params(
3133
3154
  LeptrisXslt xslt, LeptrisDocument doc,
3134
- const char* const* pairs, size_t pair_count);
3155
+ const char* const* pairs, size_t count);
3135
3156
 
3136
3157
  /**
3137
3158
  * Custom XPath function handler (string-valued).
@@ -246,6 +246,7 @@ static void dp_plan_free(LeptrisPlan p) {
246
246
  dp_plan* d = &p->plans[i];
247
247
  for (uint32_t a = 0; a < d->attribute_count; a++) {
248
248
  free((char *)d->attribute_plans[a].wire_name);
249
+ free((char *)d->attribute_plans[a].ns_uri);
249
250
  for (uint16_t pi = 0;
250
251
  pi < d->attribute_plans[a].predicate_count; pi++) {
251
252
  free((char*)d->attribute_plans[a]
@@ -332,6 +333,32 @@ LEPTRIS_API LeptrisPlan leptris_plan_build(const leptris_plan_spec* spec,
332
333
  d->attribute_plans[a].predicate_count = 0;
333
334
  d->attribute_plans[a].pad_pred = 0;
334
335
  }
336
+ /* #1486 additive-ABI guard (the #1272 lesson): a
337
+ * host that mallocs the spec leaves the trailing
338
+ * ns fields garbage — normalize unset forms so the
339
+ * walker never reads a garbage pointer, and deep-
340
+ * copy EXACT uris. EXACT without a uri cannot
341
+ * express an identity: reject the spec. */
342
+ if (!s->attribute_plans[a].ns_form) {
343
+ d->attribute_plans[a].ns_form = 0;
344
+ d->attribute_plans[a].pad_ns = 0;
345
+ d->attribute_plans[a].ns_uri = NULL;
346
+ } else {
347
+ d->attribute_plans[a].pad_ns = 0;
348
+ if (s->attribute_plans[a].ns_form ==
349
+ LEPTRIS_PLAN_NS_EXACT) {
350
+ if (!s->attribute_plans[a].ns_uri) {
351
+ if (status) *status = LEPTRIS_ERROR_INVALID_ARG;
352
+ dp_plan_free(p);
353
+ return NULL;
354
+ }
355
+ d->attribute_plans[a].ns_uri =
356
+ dp_strdup(s->attribute_plans[a].ns_uri);
357
+ if (!d->attribute_plans[a].ns_uri) goto oom;
358
+ } else {
359
+ d->attribute_plans[a].ns_uri = NULL;
360
+ }
361
+ }
335
362
  if (s->attribute_plans[a].wire_name) {
336
363
  d->attribute_plans[a].wire_name =
337
364
  dp_strdup(s->attribute_plans[a].wire_name);
@@ -491,6 +518,50 @@ static int dp_walk_children(LeptrisElement elem, const dp_plan* plan,
491
518
  const LeptrisPlan pool,
492
519
  struct leptris_plan_result* out);
493
520
 
521
+ /* #1486 attribute-row binding. ns_form 0 = the historical
522
+ * wire-name lookup (the string exactly as it appears on the
523
+ * wire). A set form matches (namespace, local): the row's
524
+ * wire_name is the LOCAL name; each attribute's prefix resolves
525
+ * through the ELEMENT's in-scope bindings, so the identity holds
526
+ * across prefix spellings. Unprefixed attributes have no
527
+ * namespace (XML namespaces §5.2) — EXACT never binds them. */
528
+ static const char* dp_attr_value(LeptrisElement elem,
529
+ const leptris_attr_plan* ap) {
530
+ if (!ap->ns_form)
531
+ return leptris_element_attribute(elem, ap->wire_name);
532
+ for (LeptrisAttribute at = leptris_element_first_attribute(elem);
533
+ at; at = leptris_attribute_next(at)) {
534
+ const char* qn = leptris_attribute_get_name(at);
535
+ if (!qn) continue;
536
+ const char* colon = strchr(qn, ':');
537
+ const char* local = colon ? colon + 1 : qn;
538
+ if (strcmp(local, ap->wire_name) != 0) continue;
539
+ const char* uri = NULL;
540
+ if (colon) {
541
+ char prefix[128];
542
+ size_t plen = (size_t)(colon - qn);
543
+ if (plen >= sizeof(prefix)) continue;
544
+ memcpy(prefix, qn, plen);
545
+ prefix[plen] = 0;
546
+ uri = leptris_element_namespace_for_prefix(elem, prefix);
547
+ }
548
+ switch (ap->ns_form) {
549
+ case LEPTRIS_PLAN_NS_NONE:
550
+ if (uri) continue;
551
+ break;
552
+ case LEPTRIS_PLAN_NS_EXACT:
553
+ if (!uri || !ap->ns_uri ||
554
+ strcmp(uri, ap->ns_uri) != 0)
555
+ continue;
556
+ break;
557
+ default: /* ANY */
558
+ break;
559
+ }
560
+ return leptris_attribute_get_value(elem, at);
561
+ }
562
+ return NULL;
563
+ }
564
+
494
565
  static struct leptris_plan_result* dp_walk_element(LeptrisElement elem,
495
566
  const dp_plan* plan,
496
567
  const LeptrisPlan pool) {
@@ -510,7 +581,7 @@ static struct leptris_plan_result* dp_walk_element(LeptrisElement elem,
510
581
  for (uint32_t a = 0; a < plan->attribute_count; a++) {
511
582
  const leptris_attr_plan* ap = &plan->attribute_plans[a];
512
583
  if (!ap->wire_name) continue;
513
- const char* val = leptris_element_attribute(elem, ap->wire_name);
584
+ const char* val = dp_attr_value(elem, ap);
514
585
  if (!val) continue;
515
586
  v->attr_names[v->attr_count] = dp_strdup(ap->wire_name);
516
587
  v->attr_values[v->attr_count] = dp_strdup(val);