leptris 1.9.319.0-aarch64-linux → 1.9.321.0-aarch64-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: 542a7b955fc1001eaadb8fc9a95c3329ac77a95be86b093fb362ac75c30e09f5
4
- data.tar.gz: 6144d1995e97c24928a3741d35b065bf5f79390bf32a9fb26be64077c6252251
3
+ metadata.gz: db9055121618343dff8b5e698e7c92d47dbd434db73fe6d8339dc46a0be73c82
4
+ data.tar.gz: 3e7cf86ffa532fff238034f21f55dbc7117a85398fd1aed4bf3ade5d0c7c3b4e
5
5
  SHA512:
6
- metadata.gz: 8f7846f8a6740d0f6dd6c5888cdadb139be91690c579faa20fe3e992417cf88b21a303c3e933cd20411710074fa31e00f0ecc2bbae12c8cc0d1999d40081c242
7
- data.tar.gz: 461aec2637d97b509bc4caf28e5344a9daa3f59b2a79ed6900e564e91285374ba757cb178dc8c759d0a003e1d670c04a34accc70fe0300294a6c2d3287bde787
6
+ metadata.gz: 3a625fa0c0ef2ac0e64244b09872d64e6f2f6c9a0610c8b65a1c931b69006755e7ce6afe380a0a0a4c8980916e2aeb57dfebbf9b0fde1baf7a5d298dfb866c36
7
+ data.tar.gz: 4607ae9d6d1952a36f2d9b100417e97c77bca875aeee0dafa5736168d3b6a2966f6ead5a59d1384d8f8ec3adebd542ff05e41ce2fc632767fa466fcf539538cb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## [1.9.321.0] - 2026-10-08
2
+
3
+ ### Added — engine sync (libleptris 1.9.321)
4
+
5
+ - **XSD instance validation, slices 3-4 (#1075)**:
6
+ `Schema#valid?` walks the whole document — element declarations,
7
+ attribute rows (required + typed + lenient qualified spellings),
8
+ text lexical checks, child content models through a Thompson NFA
9
+ (linear in children x states, no backtracking blowup);
10
+ `Schema#validate_errors` enumerates every failure (the engine
11
+ replaces the list per run); `Schema#content_valid?` evaluates a
12
+ child sequence directly against a top-level declaration's model.
13
+ The -1 contract raises (unknown declaration never masquerades as
14
+ invalid input). Pins use the named-ref shape — the inline-
15
+ anonymous complexType capture gap is filed upstream
16
+ (leptris#1592).
17
+
18
+ ## [1.9.320.0] - 2026-10-08
19
+
20
+ ### Fixed — engine sync (libleptris 1.9.320)
21
+
22
+ - **Exact-URI child rows survive build-anchor GC (#1585)**: the
23
+ engine's plan build let child-row `ns_uri` ride a pointer into
24
+ the caller's build buffers instead of deep-copying — bindings
25
+ GC their anchors after build, so exact-URI child rows
26
+ deterministically stopped matching (uniword's
27
+ dc:title/dc:creator/dc:description hydrated nil). The engine
28
+ retains the URI; pinned with build + GC + walk.
29
+ - **Plain attribute rows match any qualification (#1586)**:
30
+ ns-unset attr rows try the exact wire spelling first, then any
31
+ qualification by local name (#758 parity) — plain rows bind
32
+ `w:name`/`w:val` exactly as the interpretive path does, top
33
+ level and nested; exact-URI rows keep their #1486 precedence.
34
+ Pinned at both depths.
35
+
1
36
  ## [1.9.319.0] - 2026-10-08
2
37
 
3
38
  ### Added — engine sync (libleptris 1.9.319)
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.319"
11
+ LIBLEPTRIS_VERSION = "1.9.321"
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.319.0"
4
+ VERSION = "1.9.321.0"
5
5
  end
@@ -1304,6 +1304,21 @@ attach_function :leptris_parse_string,
1304
1304
  [:string, :string], :int
1305
1305
  attach_function :leptris_xsd_simple_valid,
1306
1306
  [:leptris_xsd_schema, :string, :string], :int
1307
+ # Slices 3-4 (libleptris 1.9.321, #1075): content models via
1308
+ # Thompson NFA (linear in children x states) and whole-
1309
+ # instance validation — element declarations, attribute rows
1310
+ # (required + typed + lenient qualified spellings), text
1311
+ # lexical checks, child content models. Failures enumerate
1312
+ # behind error_count/_at (schema-owned; the next validate
1313
+ # run replaces them).
1314
+ attach_function :leptris_xsd_content_valid,
1315
+ [:leptris_xsd_schema, :string, :pointer, :pointer, :size_t], :int
1316
+ attach_function :leptris_xsd_validate,
1317
+ [:leptris_xsd_schema, :leptris_document], :int
1318
+ attach_function :leptris_xsd_error_count,
1319
+ [:leptris_xsd_schema], :size_t
1320
+ attach_function :leptris_xsd_error_at,
1321
+ [:leptris_xsd_schema, :size_t], UTF8_STRING
1307
1322
 
1308
1323
  attach_function :leptris_rng_parse,
1309
1324
  [:string, :size_t, :pointer], :leptris_relaxng
@@ -79,14 +79,66 @@ module Leptris::XML::XSD
79
79
  # name) — restriction chains validate every hop's facets,
80
80
  # cycle-guarded. Unknown type names raise (the -1 contract).
81
81
  def simple_valid?(type_name, lexical)
82
- r = Leptris::XML::FFI.leptris_xsd_simple_valid(
83
- @handle, type_name.to_s, lexical.to_s)
84
- case r
82
+ tri_state(
83
+ Leptris::XML::FFI.leptris_xsd_simple_valid(
84
+ @handle, type_name.to_s, lexical.to_s),
85
+ "#{type_name.inspect} is not a simpleType in this schema")
86
+ end
87
+
88
+ # Slices 3-4 (libleptris 1.9.321, #1075): whole-instance
89
+ # validation — element declarations, attribute rows (required
90
+ # + typed + lenient qualified spellings), text lexical checks,
91
+ # and child content models through the Thompson NFA. Returns
92
+ # true/false.
93
+ def valid?(document)
94
+ tri_state(
95
+ Leptris::XML::FFI.leptris_xsd_validate(
96
+ @handle, document.c_ptr), "invalid document handle")
97
+ end
98
+
99
+ # The enumerated failure list of the last #validate run
100
+ # (empty when valid; the NEXT validate replaces the list).
101
+ def validate_errors(document)
102
+ valid?(document)
103
+ Leptris::XML::FFI.leptris_xsd_error_count(@handle).times.map do |i|
104
+ Leptris::XML::FFI.leptris_xsd_error_at(@handle, i)
105
+ end
106
+ end
107
+
108
+ # Slice 3 direct face: a child SEQUENCE against a top-level
109
+ # element declaration's compiled content model (occurrence
110
+ # bounds, xs:any wildcards). +children+ are child Nodes (name
111
+ # + effective namespace extracted per child). Unknown element
112
+ # declarations raise (the -1 contract).
113
+ def content_valid?(element_name, children)
114
+ kids = children.to_a
115
+ nb, na = Leptris::XML::CStringArray.to_c(
116
+ kids.map { |c| c.name.to_s })
117
+ ub, ua = Leptris::XML::CStringArray.to_c(
118
+ kids.map { |c| child_ns_uri(c) })
119
+ tri_state(
120
+ Leptris::XML::FFI.leptris_xsd_content_valid(
121
+ @handle, element_name.to_s, nb, ub, kids.size),
122
+ "#{element_name.inspect} is not a top-level element declaration")
123
+ end
124
+
125
+ private
126
+
127
+ # A child's effective namespace URI (nil = none) — read
128
+ # through its own c_ptr, so docless wrappers work.
129
+ def child_ns_uri(node)
130
+ uri = Leptris::XML::FFI.leptris_element_namespace(node.c_ptr)
131
+ uri.nil? || uri.empty? ? "" : uri
132
+ end
133
+
134
+ # The C faces' 1/0/-1 contract: true/false, with -1 raising —
135
+ # a silent false would mean "no such declaration/type", which
136
+ # callers must never confuse with "invalid input".
137
+ def tri_state(code, unknown_message)
138
+ case code
85
139
  when 1 then true
86
140
  when 0 then false
87
- else
88
- raise ArgumentError,
89
- "#{type_name.inspect} is not a simpleType in this schema"
141
+ else raise ArgumentError, unknown_message
90
142
  end
91
143
  end
92
144
  end
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.319
4
+ - libleptris v1.9.321
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,50 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.321] - 2026-10-08
4
+
5
+ ### Added
6
+
7
+ - **XSD validation, tier 1, slices 3–4 (#1075, PRs #1589/#1590).**
8
+ Slice 3 — content models: the compiler captures top-level
9
+ `xs:element` declarations and named `xs:complexType` models
10
+ (sequence/choice/all, occurrence bounds incl. unbounded, element
11
+ name/ref particles, `xs:any` wildcards with the full
12
+ namespace-filter grammar); `leptris_xsd_content_valid` evaluates
13
+ a child sequence through a Thompson NFA — linear in children x
14
+ states, no backtracking blowup on nested choices. Slice 4 —
15
+ instance validation: `leptris_xsd_validate(schema, document)`
16
+ walks element declarations, complexType attribute rows
17
+ (required + typed + lenient qualified spellings), child content
18
+ models, and lexical text checks for simple-typed elements
19
+ (particles carry type refs); failures enumerate behind
20
+ `leptris_xsd_error_count/_at`. The libxml2 corpus gate holds at
21
+ 163/163; full suite 1911/1911.
22
+
23
+
24
+
25
+ ## [1.9.320] - 2026-10-08
26
+
27
+ ### Fixed
28
+
29
+ - **Descriptor: child-row exact-URI `ns_uri` retained at build
30
+ (#1585, PR #1587).** The build deep-copied child `ns_prefix` but
31
+ let `ns_uri` ride the struct copy — a pointer into the caller's
32
+ build buffers. Bindings GC their anchors (a warm walk plus one GC
33
+ makes it deterministic), after which exact-URI child rows
34
+ silently stopped matching and hydration answered nil (uniword's
35
+ `dc:title`/`dc:creator`/`dc:description`). The spec trashes the
36
+ caller's buffer after build and asserts the row still binds.
37
+ - **Descriptor: plain attribute rows match any qualification
38
+ (#1586, PR #1587).** `dp_attr_value`'s ns-unset path now mirrors
39
+ #758 — the exact wire spelling first, then any qualification by
40
+ local name — so plain rows bind `w:name`/`w:val` exactly as the
41
+ interpretive path does, top level and nested. Exact-URI rows keep
42
+ their #1486 precedence. A NESTED row's binding also consults the
43
+ TARGET plan's `ns_lenient` now (the #1115-consistent authority)
44
+ instead of the outer plan's.
45
+
46
+
47
+
3
48
  ## [1.9.319] - 2026-10-08
4
49
 
5
50
  ### Added
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.319
6
+ VERSION 1.9.321
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -29,6 +29,8 @@ set(LEPTRIS_SOURCES
29
29
  leptris/rng/parse.c
30
30
  leptris/xsd/compile.c
31
31
  leptris/xsd/datatypes.c
32
+ leptris/xsd/content_model.c
33
+ leptris/xsd/validate.c
32
34
  leptris/rng/rng_public.c
33
35
  leptris/rng/rng_regex.c
34
36
  leptris/rng/validate.c
@@ -920,6 +920,28 @@ LEPTRIS_API int leptris_xsd_builtin_valid(const char* builtin,
920
920
  LEPTRIS_API int leptris_xsd_simple_valid(LeptrisXsdSchema schema,
921
921
  const char* type_name,
922
922
  const char* lexical);
923
+ /* Slice 3 — content models. Validates a child sequence against the
924
+ * compiled content model of a top-level element declaration (its
925
+ * type's sequence/choice/all with occurrence bounds and xs:any
926
+ * wildcards). 1 valid, 0 invalid, -1 unknown element. child_ns may
927
+ * be NULL (all children unqualified). */
928
+ LEPTRIS_API int leptris_xsd_content_valid(
929
+ LeptrisXsdSchema schema, const char* element_name,
930
+ const char* const* child_names, const char* const* child_ns,
931
+ size_t child_count);
932
+ /* Slice 4 — instance validation. Walks the document against the
933
+ * compiled schema: element declarations by name, attribute rows
934
+ * (required use + typed values, lenient qualified spellings),
935
+ * text lexical checks for simple-typed elements, child content
936
+ * models (slice 3). Returns 1 valid, 0 invalid, -1 bad args.
937
+ * Errors accumulate — leptris_xsd_error_count/_at enumerate them
938
+ * (schema-owned; the next validate run replaces them; freed with
939
+ * the schema). */
940
+ LEPTRIS_API int leptris_xsd_validate(LeptrisXsdSchema schema,
941
+ LeptrisDocument doc);
942
+ LEPTRIS_API size_t leptris_xsd_error_count(LeptrisXsdSchema schema);
943
+ LEPTRIS_API const char* leptris_xsd_error_at(LeptrisXsdSchema schema,
944
+ size_t i);
923
945
  /* Validate an instance document against the parsed schema
924
946
  * (phase-2 core subset: element/attribute/text/data/value/
925
947
  * choice/group/interleave/repeats/ref). Returns 1 valid; on 0,
@@ -285,6 +285,7 @@ static void dp_plan_free(LeptrisPlan p) {
285
285
  for (uint32_t c = 0; c < d->child_count; c++) {
286
286
  free((char *)d->child_plans[c].wire_name);
287
287
  free((char *)d->child_plans[c].ns_prefix);
288
+ free((char *)d->child_plans[c].ns_uri);
288
289
  for (uint16_t pi = 0;
289
290
  pi < d->child_plans[c].predicate_count; pi++) {
290
291
  free((char*)d->child_plans[c]
@@ -481,6 +482,15 @@ LEPTRIS_API LeptrisPlan leptris_plan_build(const leptris_plan_spec* spec,
481
482
  sc->ns_prefix ? dp_strdup(sc->ns_prefix) : NULL;
482
483
  if (sc->ns_prefix && !d->child_plans[c].ns_prefix)
483
484
  goto oom;
485
+ /* #1585: ns_uri rides the struct copy otherwise —
486
+ * a dangling pointer into the caller's build
487
+ * buffers once they are reclaimed (bindings GC
488
+ * their anchors; the descriptor must outlive
489
+ * them). Same retention as attr rows (#1486). */
490
+ d->child_plans[c].ns_uri =
491
+ sc->ns_uri ? dp_strdup(sc->ns_uri) : NULL;
492
+ if (sc->ns_uri && !d->child_plans[c].ns_uri)
493
+ goto oom;
484
494
  uint16_t pc = sc->predicate_count;
485
495
  if (pc) {
486
496
  if (!sc->predicates) goto oom;
@@ -598,8 +608,25 @@ static int dp_walk_children(LeptrisElement elem, const dp_plan* plan,
598
608
  * namespace (XML namespaces §5.2) — EXACT never binds them. */
599
609
  static const char* dp_attr_value(LeptrisElement elem,
600
610
  const leptris_attr_plan* ap) {
601
- if (!ap->ns_form)
602
- return leptris_element_attribute(elem, ap->wire_name);
611
+ if (!ap->ns_form) {
612
+ /* #1586, the plan-path mirror of #758: the exact wire
613
+ * spelling first, then any qualification by local name —
614
+ * plain rows are lenient exactly like element rows under
615
+ * ns_lenient. Exact-URI rows keep their #1486 semantics. */
616
+ const char* exact =
617
+ leptris_element_attribute(elem, ap->wire_name);
618
+ if (exact) return exact;
619
+ for (LeptrisAttribute at = leptris_element_first_attribute(elem);
620
+ at; at = leptris_attribute_next(at)) {
621
+ const char* qn = leptris_attribute_get_name(at);
622
+ if (!qn) continue;
623
+ const char* colon = strchr(qn, ':');
624
+ const char* local = colon ? colon + 1 : qn;
625
+ if (strcmp(local, ap->wire_name) == 0)
626
+ return leptris_attribute_get_value(elem, at);
627
+ }
628
+ return NULL;
629
+ }
603
630
  for (LeptrisAttribute at = leptris_element_first_attribute(elem);
604
631
  at; at = leptris_attribute_next(at)) {
605
632
  const char* qn = leptris_attribute_get_name(at);
@@ -832,8 +859,13 @@ static int dp_walk_children(LeptrisElement elem, const dp_plan* plan,
832
859
  LeptrisElement child = (LeptrisElement)n;
833
860
  if (!dp_wire_name_matches(child, row->wire_name))
834
861
  continue;
862
+ /* The TARGET plan's form governs (#1115) — so its
863
+ * lenient flag governs the leniency, not the outer
864
+ * plan's (#1586: a namespaced child under a plan
865
+ * that declares ns_lenient binds by local name). */
835
866
  if (!dp_ns_binds(child, target->ns_form, target->ns_uri,
836
- lenient))
867
+ (target->flags &
868
+ LEPTRIS_PLAN_FLAG_NS_LENIENT) != 0))
837
869
  continue;
838
870
  /* Claim the element against later same-wire rows
839
871
  * (predicate partitioning). */