leptris 1.9.232.0 → 1.9.237.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Rakefile +1 -1
  4. data/ext/leptris/native/native.c +144 -3
  5. data/lib/leptris/vendor/aarch64-linux/libleptris.so +0 -0
  6. data/lib/leptris/vendor/aarch64-linux-musl/libleptris.so +0 -0
  7. data/lib/leptris/vendor/arm-linux/libleptris.so +0 -0
  8. data/lib/leptris/vendor/arm-linux-musl/libleptris.so +0 -0
  9. data/lib/leptris/vendor/arm64-darwin/libleptris.dylib +0 -0
  10. data/lib/leptris/vendor/ppc64le-linux/libleptris.so +0 -0
  11. data/lib/leptris/vendor/s390x-linux-musl/libleptris.so +0 -0
  12. data/lib/leptris/vendor/x86_64-darwin/libleptris.dylib +0 -0
  13. data/lib/leptris/vendor/x86_64-linux/libleptris.so +0 -0
  14. data/lib/leptris/vendor/x86_64-linux-musl/libleptris.so +0 -0
  15. data/lib/leptris/version.rb +1 -1
  16. data/lib/leptris/xml/document.rb +20 -3
  17. data/lib/leptris/xml/ffi.rb +91 -62
  18. data/vendor-src/README.md +1 -1
  19. data/vendor-src/libleptris/CHANGELOG.md +113 -4
  20. data/vendor-src/libleptris/CMakeLists.txt +1 -1
  21. data/vendor-src/libleptris/benchmarks/dom/bench_leptris.c +14 -6
  22. data/vendor-src/libleptris/src/include/leptris.h +27 -0
  23. data/vendor-src/libleptris/src/leptris/dom/element_modify.c +20 -0
  24. data/vendor-src/libleptris/src/leptris/leptris_internal.h +5 -0
  25. data/vendor-src/libleptris/src/leptris/xpath/evaluator.c +7 -0
  26. data/vendor-src/libleptris/src/leptris/xpath/evaluator_operators.c +38 -4
  27. data/vendor-src/libleptris/src/leptris/xpath/evaluator_types.c +5 -1
  28. data/vendor-src/libleptris/src/leptris/xpath/functions.c +86 -7
  29. data/vendor-src/libleptris/src/leptris/xpath/functions_ext31.c +237 -24
  30. data/vendor-src/libleptris/src/leptris/xpath/xpath_public.c +16 -1
  31. data/vendor-src/libleptris/test/dom/test_dom.cpp +80 -0
  32. data/vendor-src/libleptris/test/xquery/qt3/fn/count.xml +3117 -0
  33. data/vendor-src/libleptris/test/xquery/qt3/fn/empty.xml +502 -0
  34. data/vendor-src/libleptris/test/xquery/qt3/fn/exists.xml +537 -0
  35. data/vendor-src/libleptris/test/xquery/qt3/fn/head.xml +90 -0
  36. data/vendor-src/libleptris/test/xquery/qt3/fn/tail.xml +68 -0
  37. data/vendor-src/libleptris/test/xquery/test_qt3.cpp +124 -93
  38. data/vendor-src/libleptris/test/xquery/test_xquery.cpp +28 -0
  39. data/vendor-src/libleptris/vcpkg.json +1 -1
  40. metadata +6 -1
@@ -7,6 +7,28 @@ module Leptris
7
7
  module FFI
8
8
  extend ::FFI::Library
9
9
 
10
+ # FFI's :string return type always tags returned bytes
11
+ # ASCII-8BIT, but libleptris produces character data (UTF-8,
12
+ # the XML default encoding). Every string-returning function
13
+ # therefore uses this converter: same NUL-terminated copy
14
+ # semantics as :string, tagged UTF-8. Input arguments keep
15
+ # plain :string (Ruby-to-C reads bytes regardless of tag).
16
+ UTF8_STRING = Class.new do
17
+ include ::FFI::DataConverter
18
+
19
+ def from_native(ptr, _ctx)
20
+ return nil if ptr.null? || ptr.address.zero?
21
+
22
+ ptr.read_string.force_encoding(Encoding::UTF_8)
23
+ end
24
+
25
+ def to_native(value, _ctx)
26
+ return nil if value.nil?
27
+
28
+ ::FFI::MemoryPointer.from_string(value.to_s)
29
+ end
30
+ end.new.tap { |c| c.native_type(::FFI::Type::POINTER) }
31
+
10
32
  # The per-OS vendor directory of the ruby-platform gem
11
33
  # (zero-setup TruffleRuby/JRuby, #160): binaries for the
12
34
  # common engines' OSes under lib/leptris/vendor/<platform>/.
@@ -321,11 +343,11 @@ module Leptris
321
343
  attach_function :leptris_plan_value_kind,
322
344
  [:leptris_plan_result], :int
323
345
  attach_function :leptris_plan_value_name,
324
- [:leptris_plan_result], :string
346
+ [:leptris_plan_result], UTF8_STRING
325
347
  attach_function :leptris_plan_value_type_tag,
326
348
  [:leptris_plan_result], :uint8
327
349
  attach_function :leptris_plan_value_string,
328
- [:leptris_plan_result], :string
350
+ [:leptris_plan_result], UTF8_STRING
329
351
  attach_function :leptris_plan_value_length,
330
352
  [:leptris_plan_result], :size_t
331
353
  attach_function :leptris_plan_value_position,
@@ -335,7 +357,7 @@ module Leptris
335
357
  attach_function :leptris_plan_value_at,
336
358
  [:leptris_plan_result, :size_t], :leptris_plan_result
337
359
  attach_function :leptris_plan_value_attribute,
338
- [:leptris_plan_result, :string], :string
360
+ [:leptris_plan_result, :string], UTF8_STRING
339
361
  # #1254 (leptris 1.9.216): one-call flat attribute read —
340
362
  # parallel name/value/handle arrays, capacity-bounded; total
341
363
  # count returned (min(total, max_count) copied). Also the
@@ -367,7 +389,7 @@ module Leptris
367
389
  [:string, :size_t, :leptris_plan, :pointer],
368
390
  :leptris_plan_result
369
391
 
370
- attach_function :leptris_version, [], :string
392
+ attach_function :leptris_version, [], UTF8_STRING
371
393
  attach_function :leptris_version_components, [:pointer, :pointer, :pointer], :void
372
394
 
373
395
  # Tolerant HTML4/5 parse into the STANDARD DOM (libleptris
@@ -424,9 +446,9 @@ attach_function :leptris_parse_string,
424
446
  attach_function :leptris_entity_ref_node_create,
425
447
  [:leptris_document, :string], :leptris_node_ref
426
448
  attach_function :leptris_entity_ref_node_name,
427
- [:leptris_node_ref], :string
449
+ [:leptris_node_ref], UTF8_STRING
428
450
  attach_function :leptris_document_version,
429
- [:leptris_document], :string
451
+ [:leptris_document], UTF8_STRING
430
452
  attach_function :leptris_document_standalone,
431
453
  [:leptris_document], :int
432
454
  attach_function :leptris_document_set_version,
@@ -456,9 +478,9 @@ attach_function :leptris_parse_string,
456
478
  attach_function :leptris_document_pi_count,
457
479
  [:leptris_document], :size_t
458
480
  attach_function :leptris_document_pi_target,
459
- [:leptris_document, :size_t], :string
481
+ [:leptris_document, :size_t], UTF8_STRING
460
482
  attach_function :leptris_document_pi_data,
461
- [:leptris_document, :size_t], :string
483
+ [:leptris_document, :size_t], UTF8_STRING
462
484
  # Document-level PI removal by target or index (1.9.9, #612):
463
485
  # unlinks from the child chain; the node is pool-owned and
464
486
  # stays valid until document free.
@@ -476,13 +498,13 @@ attach_function :leptris_parse_string,
476
498
  attach_function :leptris_document_comment_count,
477
499
  [:leptris_document], :size_t
478
500
  attach_function :leptris_document_comment_content,
479
- [:leptris_document, :size_t], :string
501
+ [:leptris_document, :size_t], UTF8_STRING
480
502
  # Options-struct parse (v1.6.0): supersedes the flags variants;
481
503
  # the flags path remains bound for compatibility.
482
504
  attach_function :leptris_parse_string_ex,
483
505
  [:string, :size_t, :pointer, :pointer], :leptris_document
484
506
  attach_function :leptris_document_encoding,
485
- [:leptris_document], :string
507
+ [:leptris_document], UTF8_STRING
486
508
  attach_function :leptris_document_finalize_strings,
487
509
  [:leptris_document], :int
488
510
  attach_function :leptris_document_adopt_child,
@@ -505,10 +527,10 @@ attach_function :leptris_parse_string,
505
527
  [:leptris_element], :int
506
528
  attach_function :leptris_xinclude_is_fallback_element,
507
529
  [:leptris_element], :int
508
- attach_function :leptris_xinclude_get_href, [:leptris_element], :string
509
- attach_function :leptris_xinclude_get_parse, [:leptris_element], :string
510
- attach_function :leptris_xinclude_get_xpointer, [:leptris_element], :string
511
- attach_function :leptris_xinclude_get_encoding, [:leptris_element], :string
530
+ attach_function :leptris_xinclude_get_href, [:leptris_element], UTF8_STRING
531
+ attach_function :leptris_xinclude_get_parse, [:leptris_element], UTF8_STRING
532
+ attach_function :leptris_xinclude_get_xpointer, [:leptris_element], UTF8_STRING
533
+ attach_function :leptris_xinclude_get_encoding, [:leptris_element], UTF8_STRING
512
534
 
513
535
  attach_function :leptris_node_get_type,
514
536
  [:leptris_node_ref], :int
@@ -570,15 +592,15 @@ attach_function :leptris_parse_string,
570
592
  [:leptris_node_ref, :int, :pointer, :pointer], :int
571
593
 
572
594
  attach_function :leptris_text_node_get_content,
573
- [:leptris_node_ref], :string
595
+ [:leptris_node_ref], UTF8_STRING
574
596
  attach_function :leptris_comment_node_get_content,
575
- [:leptris_node_ref], :string
597
+ [:leptris_node_ref], UTF8_STRING
576
598
  attach_function :leptris_cdata_node_get_content,
577
- [:leptris_node_ref], :string
599
+ [:leptris_node_ref], UTF8_STRING
578
600
  attach_function :leptris_pi_node_get_target,
579
- [:leptris_node_ref], :string
601
+ [:leptris_node_ref], UTF8_STRING
580
602
  attach_function :leptris_pi_node_get_data,
581
- [:leptris_node_ref], :string
603
+ [:leptris_node_ref], UTF8_STRING
582
604
  attach_function :leptris_text_node_create,
583
605
  [:leptris_document, :string], :leptris_node_ref
584
606
  attach_function :leptris_comment_node_create,
@@ -599,9 +621,9 @@ attach_function :leptris_parse_string,
599
621
  [:leptris_node_ref, :string], :leptris_status
600
622
 
601
623
  attach_function :leptris_element_name,
602
- [:leptris_element], :string
624
+ [:leptris_element], UTF8_STRING
603
625
  attach_function :leptris_element_text,
604
- [:leptris_element], :string
626
+ [:leptris_element], UTF8_STRING
605
627
  attach_function :leptris_element_text_int,
606
628
  [:leptris_element, :int], :int
607
629
  attach_function :leptris_element_text_uint,
@@ -613,9 +635,9 @@ attach_function :leptris_parse_string,
613
635
  attach_function :leptris_element_text_bool,
614
636
  [:leptris_element, :int], :int
615
637
  attach_function :leptris_element_attribute,
616
- [:leptris_element, :string], :string
638
+ [:leptris_element, :string], UTF8_STRING
617
639
  attach_function :leptris_element_attribute_string,
618
- [:leptris_element, :string, :string], :string
640
+ [:leptris_element, :string, :string], UTF8_STRING
619
641
  attach_function :leptris_element_attribute_int,
620
642
  [:leptris_element, :string, :int], :int
621
643
  attach_function :leptris_element_attribute_uint,
@@ -632,32 +654,32 @@ attach_function :leptris_parse_string,
632
654
  # XML Namespaces 1.0 semantics; NULL/"" uri matches only
633
655
  # no-namespace attributes, xmlns declarations never match.
634
656
  attach_function :leptris_element_attribute_ns,
635
- [:leptris_element, :string, :string], :string
657
+ [:leptris_element, :string, :string], UTF8_STRING
636
658
  attach_function :leptris_element_has_attribute_ns,
637
659
  [:leptris_element, :string, :string], :int
638
660
  # libleptris 1.8.0: per-attribute prefix (name-derived) and
639
661
  # namespace URI (resolved through the owning element's
640
662
  # in-scope declarations at read time).
641
663
  attach_function :leptris_attribute_prefix,
642
- [:leptris_attribute], :string
664
+ [:leptris_attribute], UTF8_STRING
643
665
  attach_function :leptris_attribute_namespace_uri,
644
- [:leptris_attribute], :string
666
+ [:leptris_attribute], UTF8_STRING
645
667
  attach_function :leptris_element_first_attribute,
646
668
  [:leptris_element], :leptris_attribute
647
669
  attach_function :leptris_attribute_next,
648
670
  [:leptris_attribute], :leptris_attribute
649
671
  attach_function :leptris_attribute_get_name,
650
- [:leptris_attribute], :string
672
+ [:leptris_attribute], UTF8_STRING
651
673
  attach_function :leptris_attribute_get_value,
652
- [:leptris_element, :leptris_attribute], :string
674
+ [:leptris_element, :leptris_attribute], UTF8_STRING
653
675
  attach_function :leptris_element_prefix,
654
- [:leptris_element], :string
676
+ [:leptris_element], UTF8_STRING
655
677
  attach_function :leptris_element_attribute_count,
656
678
  [:leptris_element], :size_t
657
679
  attach_function :leptris_element_attribute_name_at,
658
- [:leptris_element, :size_t], :string
680
+ [:leptris_element, :size_t], UTF8_STRING
659
681
  attach_function :leptris_element_attribute_value_at,
660
- [:leptris_element, :size_t], :string
682
+ [:leptris_element, :size_t], UTF8_STRING
661
683
  attach_function :leptris_element_remove_all_attributes,
662
684
  [:leptris_element], :leptris_status
663
685
 
@@ -670,7 +692,7 @@ attach_function :leptris_parse_string,
670
692
  attach_function :leptris_element_root,
671
693
  [:leptris_element], :leptris_element
672
694
  attach_function :leptris_element_child_value,
673
- [:leptris_element], :string
695
+ [:leptris_element], UTF8_STRING
674
696
  attach_function :leptris_element_hash_value,
675
697
  [:leptris_element], :size_t
676
698
  attach_function :leptris_element_find_child,
@@ -694,6 +716,13 @@ attach_function :leptris_parse_string,
694
716
  attach_function :leptris_element_previous_sibling_any,
695
717
  [:leptris_element], :leptris_element
696
718
 
719
+ # Single-crossing element construction (libleptris 1.9.237,
720
+ # #1344): element + every attribute in one C call. The name
721
+ # and value arrays are count-bounded char** (the NULL
722
+ # terminators CStringArray appends are simply never read).
723
+ attach_function :leptris_element_new_with_attributes,
724
+ [:leptris_document, :string, :pointer, :pointer, :size_t],
725
+ :leptris_element
697
726
  attach_function :leptris_element_create,
698
727
  [:leptris_document, :string], :leptris_element
699
728
  attach_function :leptris_element_set_name,
@@ -756,23 +785,23 @@ attach_function :leptris_parse_string,
756
785
  attach_function :leptris_element_set_namespace,
757
786
  [:leptris_element, :string], :leptris_status
758
787
  attach_function :leptris_element_namespace,
759
- [:leptris_element], :string
788
+ [:leptris_element], UTF8_STRING
760
789
  attach_function :leptris_element_namespace_for_prefix,
761
- [:leptris_element, :string], :string
790
+ [:leptris_element, :string], UTF8_STRING
762
791
  attach_function :leptris_element_namespace_count,
763
792
  [:leptris_element], :size_t
764
793
  attach_function :leptris_element_namespace_decl_prefix,
765
- [:leptris_element, :size_t], :string
794
+ [:leptris_element, :size_t], UTF8_STRING
766
795
  attach_function :leptris_element_namespace_decl_uri,
767
- [:leptris_element, :size_t], :string
796
+ [:leptris_element, :size_t], UTF8_STRING
768
797
  attach_function :leptris_element_add_namespace_definition,
769
798
  [:leptris_element, :string, :string], :leptris_status
770
799
  attach_function :leptris_element_set_default_namespace,
771
800
  [:leptris_element, :string], :leptris_status
772
801
  attach_function :leptris_element_remove_namespace_definition,
773
802
  [:leptris_element, :string], :leptris_status
774
- attach_function :leptris_namespace_uri, [:string], :string
775
- attach_function :leptris_namespace_prefix, [:string], :string
803
+ attach_function :leptris_namespace_uri, [:string], UTF8_STRING
804
+ attach_function :leptris_namespace_prefix, [:string], UTF8_STRING
776
805
 
777
806
  attach_function :leptris_xpath_eval,
778
807
  [:leptris_document, :leptris_element, :string], :leptris_xpath_result
@@ -807,9 +836,9 @@ attach_function :leptris_parse_string,
807
836
  attach_function :leptris_xpath_result_get_node,
808
837
  [:leptris_xpath_result, :size_t], :leptris_node_ref
809
838
  attach_function :leptris_xpath_result_node_name,
810
- [:leptris_xpath_result, :size_t], :string
839
+ [:leptris_xpath_result, :size_t], UTF8_STRING
811
840
  attach_function :leptris_xpath_result_node_value,
812
- [:leptris_xpath_result, :size_t], :string
841
+ [:leptris_xpath_result, :size_t], UTF8_STRING
813
842
  # Document-scoped custom XPath functions. The callback receives
814
843
  # (const char* const* args, int argc, void* user_data) and returns
815
844
  # a heap string the library frees.
@@ -877,7 +906,7 @@ attach_function :leptris_parse_string,
877
906
  :leptris_xpath_result
878
907
  # Source text of a compiled expression (owned by the handle).
879
908
  attach_function :leptris_xpath_compiled_text,
880
- [:leptris_xpath_compiled], :string
909
+ [:leptris_xpath_compiled], UTF8_STRING
881
910
  attach_function :leptris_xpath_compiled_free,
882
911
 
883
912
  [:leptris_xpath_compiled], :void
@@ -922,9 +951,9 @@ attach_function :leptris_parse_string,
922
951
  attach_function :leptris_pull_attr_count,
923
952
  [:leptris_pull_parser], :size_t
924
953
  attach_function :leptris_pull_attr_name,
925
- [:leptris_pull_parser, :size_t], :string
954
+ [:leptris_pull_parser, :size_t], UTF8_STRING
926
955
  attach_function :leptris_pull_attr_value,
927
- [:leptris_pull_parser, :size_t], :string
956
+ [:leptris_pull_parser, :size_t], UTF8_STRING
928
957
  attach_function :leptris_pull_attrs,
929
958
  [:leptris_pull_parser, :pointer, :size_t], :size_t
930
959
  attach_function :leptris_pull_free,
@@ -948,9 +977,9 @@ attach_function :leptris_parse_string,
948
977
  attach_function :leptris_iterparse_ns_count,
949
978
  [:leptris_iterparse], :size_t
950
979
  attach_function :leptris_iterparse_ns_uri,
951
- [:leptris_iterparse, :string], :string
980
+ [:leptris_iterparse, :string], UTF8_STRING
952
981
  attach_function :leptris_iterparse_error,
953
- [:leptris_iterparse], :string
982
+ [:leptris_iterparse], UTF8_STRING
954
983
  attach_function :leptris_iterparse_free,
955
984
  [:leptris_iterparse], :void
956
985
 
@@ -1020,7 +1049,7 @@ attach_function :leptris_parse_string,
1020
1049
  attach_function :leptris_sax_records_data, [:pointer], :pointer
1021
1050
  attach_function :leptris_sax_records_attrs,
1022
1051
  [:pointer, :pointer], :pointer
1023
- attach_function :leptris_sax_records_buffer, [:pointer], :string
1052
+ attach_function :leptris_sax_records_buffer, [:pointer], UTF8_STRING
1024
1053
  attach_function :leptris_sax_records_free, [:pointer], :void
1025
1054
  # XSLT 1.0 engine (libleptris 1.9.1): compile once, apply many.
1026
1055
  # XQuery 1.0 core (libleptris 1.9.64-1.9.66): orchestration
@@ -1061,7 +1090,7 @@ attach_function :leptris_parse_string,
1061
1090
  attach_function :leptris_schematron_validate,
1062
1091
  [:leptris_schematron, :leptris_document], :leptris_document
1063
1092
  attach_function :leptris_schematron_error,
1064
- [:leptris_schematron], :string
1093
+ [:leptris_schematron], UTF8_STRING
1065
1094
 
1066
1095
  # Tree diff (libleptris >= 1.9.126 family): equal subtrees
1067
1096
  # prune in O(1) by the #869 Merkle digest; diverging regions
@@ -1074,13 +1103,13 @@ attach_function :leptris_parse_string,
1074
1103
  attach_function :leptris_diff_op_type,
1075
1104
  [:leptris_diff, :size_t], :int
1076
1105
  attach_function :leptris_diff_op_name,
1077
- [:leptris_diff, :size_t], :string
1106
+ [:leptris_diff, :size_t], UTF8_STRING
1078
1107
  attach_function :leptris_diff_op_path,
1079
- [:leptris_diff, :size_t], :string
1108
+ [:leptris_diff, :size_t], UTF8_STRING
1080
1109
  attach_function :leptris_diff_op_before,
1081
- [:leptris_diff, :size_t], :string
1110
+ [:leptris_diff, :size_t], UTF8_STRING
1082
1111
  attach_function :leptris_diff_op_after,
1083
- [:leptris_diff, :size_t], :string
1112
+ [:leptris_diff, :size_t], UTF8_STRING
1084
1113
  attach_function :leptris_diff_serialize,
1085
1114
  [:leptris_diff], :pointer
1086
1115
 
@@ -1127,14 +1156,14 @@ attach_function :leptris_parse_string,
1127
1156
  attach_function :leptris_rng_validate,
1128
1157
  [:leptris_relaxng, :leptris_document], :int
1129
1158
  attach_function :leptris_rng_error,
1130
- [:leptris_relaxng], :string
1159
+ [:leptris_relaxng], UTF8_STRING
1131
1160
  # Accumulated validation errors (libleptris 1.9.179, #878):
1132
1161
  # the validator no longer stops at the first failure;
1133
1162
  # leptris_rng_error keeps returning the first (back-compat).
1134
1163
  attach_function :leptris_rng_error_count,
1135
1164
  [:leptris_relaxng], :size_t
1136
1165
  attach_function :leptris_rng_error_message,
1137
- [:leptris_relaxng, :size_t], :string
1166
+ [:leptris_relaxng, :size_t], UTF8_STRING
1138
1167
  attach_function :leptris_rng_error_line,
1139
1168
  [:leptris_relaxng, :size_t], :int
1140
1169
  attach_function :leptris_rng_error_column,
@@ -1182,15 +1211,15 @@ attach_function :leptris_parse_string,
1182
1211
  attach_function :leptris_document_internal_subset,
1183
1212
  [:leptris_document], :leptris_doctype
1184
1213
  attach_function :leptris_doctype_get_name,
1185
- [:leptris_doctype], :string
1214
+ [:leptris_doctype], UTF8_STRING
1186
1215
  attach_function :leptris_doctype_get_root_name,
1187
- [:leptris_doctype], :string
1216
+ [:leptris_doctype], UTF8_STRING
1188
1217
  attach_function :leptris_doctype_get_public_id,
1189
- [:leptris_doctype], :string
1218
+ [:leptris_doctype], UTF8_STRING
1190
1219
  attach_function :leptris_doctype_get_system_id,
1191
- [:leptris_doctype], :string
1220
+ [:leptris_doctype], UTF8_STRING
1192
1221
  attach_function :leptris_doctype_get_internal_subset,
1193
- [:leptris_doctype], :string
1222
+ [:leptris_doctype], UTF8_STRING
1194
1223
 
1195
1224
  attach_function :leptris_free_string, [:pointer], :void
1196
1225
  attach_function :leptris_explicit_cleanup, [], :void
@@ -1200,8 +1229,8 @@ attach_function :leptris_parse_string,
1200
1229
  attach_function :leptris_get_memory_deallocation_function, [], :pointer
1201
1230
  attach_function :leptris_document_set_allocators,
1202
1231
  [:leptris_document, :pointer, :pointer], :leptris_status
1203
- attach_function :leptris_status_string, [:leptris_status], :string
1204
- attach_function :leptris_error_message, [:leptris_status], :string
1232
+ attach_function :leptris_status_string, [:leptris_status], UTF8_STRING
1233
+ attach_function :leptris_error_message, [:leptris_status], UTF8_STRING
1205
1234
  # Engine surface adopted with libleptris 1.9.206 (the FFI
1206
1235
  # mirror audit keeps attachments and exports in lockstep):
1207
1236
  # recover diagnostics (#1200), the standalone DTD family
@@ -1235,9 +1264,9 @@ attach_function :leptris_parse_string,
1235
1264
  [:pointer, :pointer], :void
1236
1265
  # Thread-local since v1.3.0; reliable under the
1237
1266
  # one-document-per-thread contract.
1238
- attach_function :leptris_last_error, [], :string
1267
+ attach_function :leptris_last_error, [], UTF8_STRING
1239
1268
  attach_function :leptris_document_last_error,
1240
- [:leptris_document], :string
1269
+ [:leptris_document], UTF8_STRING
1241
1270
  # Optional: release per-thread registry entries when a worker
1242
1271
  # thread exits (long-lived threads never need it).
1243
1272
  attach_function :leptris_thread_cleanup, [], :void
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.232
4
+ - libleptris v1.9.237
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,102 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.237] - 2026-09-24
4
+
5
+ <!-- Edit this section with the actual release notes. -->
6
+ <!-- See https://keepachangelog.com for format guidance. -->
7
+
8
+ ### Added
9
+
10
+ - dom: `leptris_element_new_with_attributes` — single-crossing
11
+ element construction (#1344). One call creates the element in the
12
+ document arena with every attribute attached — identical per-pair
13
+ semantics to leptris_element_set_attribute (duplicate names
14
+ replace, last wins; NULL values store the empty string). Builder
15
+ paths collapse from 1 + N crossings plus wrapper allocations per
16
+ node to a single crossing.
17
+
18
+
19
+ ## [1.9.236] - 2026-09-24
20
+
21
+ ### Added
22
+
23
+ - xpath: fn:subsequence implements the F&O window in position space —
24
+ NaN start/length yields empty, the window is NaN-safe including
25
+ -INF + INF = NaN, positions are never clamped to 1, the 2-arg form
26
+ is unbounded, and start/length round half-up like fn:round
27
+ (cbcl-subsequence-001..009, K2-5).
28
+ - xpath: boolean and xs:decimal sequence members carry their type
29
+ (\x03B/\x03D markers) — a false boolean stays falsy through
30
+ fn:subsequence/fn:remove round-trips (EBV reads the marker) and
31
+ xs:decimal equality compares lexically where the double carrier
32
+ cannot hold 30 significant digits.
33
+ - xpath: fn:subsequence and fn:remove preserve member types, so
34
+ `instance of`, deep-equal and effective boolean value agree across
35
+ the round-trip.
36
+ - QT3 runner: assert-permutation evaluates expected items as
37
+ expressions.
38
+
39
+ ### Fixed
40
+
41
+ - QT3 corpus: subsequence 51→61, distinct-values 84→87, remove
42
+ 21→23 adopted; typed-atom pins 86→67.
43
+
44
+
45
+
46
+ ## [1.9.235] - 2026-09-24
47
+
48
+ ### Added
49
+
50
+ - xpath: typed atoms for QT3 equality — an atomic_type channel on
51
+ XPath results (typed constructors carry interned type names),
52
+ float32 precision for xs:float (float(1.01) ne double(1.01) while
53
+ decimal-vs-float promotes per F&O rank), typed \x03F sequence
54
+ markers, and the missing constructor surface (xs:untypedAtomic,
55
+ xs:hexBinary, xs:base64Binary, xs:gYear/gYearMonth/gMonthDay/
56
+ gMonth/gDay).
57
+
58
+ ### Fixed
59
+
60
+ - xpath: per-function equality semantics — fn:index-of never matches
61
+ NaN and does not coerce numbers to strings; fn:distinct-values
62
+ dedups NaN with itself and keeps the first spelling
63
+ (distinct((1, 2.0, 3, 2)) = 1, 2.0, 3); fn:reverse, fn:index-of and
64
+ fn:distinct-values preserve sequence-member types.
65
+ - xpath: fn:deep-equal ignores comment/PI children (F&O 3.0),
66
+ compares typed string classes (xs:date vs string = false), and
67
+ accepts the 3-argument collation form.
68
+ - QT3 corpus: deep-equal 180→192, distinct-values 74→84, index-of
69
+ 34→42, reverse 53→57 adopted (125 typed-atom pins → 86).
70
+
71
+
72
+
73
+ ## [1.9.234] - 2026-09-24
74
+
75
+ ### Fixed
76
+
77
+ - benchmarks: the DOM Tree Traversal row now walks the documented
78
+ O(1) iteration shape (`leptris_element_first_child_any` +
79
+ `leptris_element_next_sibling_any`). The previous shape used
80
+ `child_count()` + indexed `child(elem, i)` — O(N^2/2) re-seeking
81
+ per parent — which measured the indexed-lookup algorithm instead of
82
+ per-hop engine cost, overstating the libxml2 gap at 1.8-4.2x.
83
+ Matched-shape gap vs libxml2 is 1.5-1.7x (#1341, closed as the
84
+ structural cost of the 64-byte compact node design).
85
+
86
+
87
+
88
+ ## [1.9.233] - 2026-09-24
89
+
90
+ ### Added
91
+
92
+ - QT3 corpus slice 3 — empty/exists/head/tail/count, 405 gated cases (xquery)
93
+
94
+ ### Fixed
95
+
96
+ - initialize registry_borrowed on every context init (xpath)
97
+
98
+
99
+
3
100
  ## [1.9.232] - 2026-09-24
4
101
 
5
102
  ### Added
@@ -591,9 +688,15 @@ W3C QT3 suite as the gate:
591
688
  <!-- Edit this section with the actual release notes. -->
592
689
  <!-- See https://keepachangelog.com for format guidance. -->
593
690
 
594
- ### Changed
691
+ ### Added
595
692
 
596
- - (describe changes here)
693
+ - dom: `leptris_element_new_with_attributes` — single-crossing
694
+ element construction (#1344). One call creates the element in the
695
+ document arena with every attribute attached — identical per-pair
696
+ semantics to leptris_element_set_attribute (duplicate names
697
+ replace, last wins; NULL values store the empty string). Builder
698
+ paths collapse from 1 + N crossings plus wrapper allocations per
699
+ node to a single crossing.
597
700
 
598
701
 
599
702
  ## [1.9.200] - 2026-09-18
@@ -8293,9 +8396,15 @@ fall back to the legacy parser.
8293
8396
  <!-- Edit this section with the actual release notes. -->
8294
8397
  <!-- See https://keepachangelog.com for format guidance. -->
8295
8398
 
8296
- ### Changed
8399
+ ### Added
8297
8400
 
8298
- - (describe changes here)
8401
+ - dom: `leptris_element_new_with_attributes` — single-crossing
8402
+ element construction (#1344). One call creates the element in the
8403
+ document arena with every attribute attached — identical per-pair
8404
+ semantics to leptris_element_set_attribute (duplicate names
8405
+ replace, last wins; NULL values store the empty string). Builder
8406
+ paths collapse from 1 + N crossings plus wrapper allocations per
8407
+ node to a single crossing.
8299
8408
 
8300
8409
 
8301
8410
  All notable changes to Leptris will be documented in this file.
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.232
6
+ VERSION 1.9.237
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -35,7 +35,14 @@ typedef struct {
35
35
  LeptrisDocument doc;
36
36
  } doc_ctx_t;
37
37
 
38
- /* Recursive tree traversal helper */
38
+ /* Recursive tree traversal helper.
39
+ *
40
+ * Walks the same shape as the libxml2 bench (hop EVERY child via the
41
+ * sibling link, recurse into elements): first_child_any +
42
+ * next_sibling_any is the documented O(1)-per-step iteration. The
43
+ * previous shape — child_count() + child(elem, i) — re-seeked the
44
+ * child list from its head per access, O(N²/2) hops per parent, which
45
+ * measured the indexed-lookup algorithm, not per-hop engine cost. */
39
46
  static void traverse_tree(LeptrisElement elem) {
40
47
  if (!elem) return;
41
48
 
@@ -43,11 +50,12 @@ static void traverse_tree(LeptrisElement elem) {
43
50
  const char* name = leptris_element_name(elem);
44
51
  (void)name;
45
52
 
46
- /* Traverse children */
47
- size_t child_count = leptris_element_child_count(elem);
48
- for (size_t i = 0; i < child_count; i++) {
49
- LeptrisElement child = leptris_element_child(elem, i);
50
- traverse_tree(child);
53
+ /* Traverse children (hop every child; recurse into elements) */
54
+ for (LeptrisElement child = leptris_element_first_child_any(elem);
55
+ child; child = leptris_element_next_sibling_any(child)) {
56
+ if (leptris_node_get_type((LeptrisNodeRef)child) ==
57
+ LEPTRIS_NODE_TYPE_ELEMENT)
58
+ traverse_tree(child);
51
59
  }
52
60
  }
53
61
 
@@ -1984,6 +1984,33 @@ LEPTRIS_API size_t leptris_element_hash_value(LeptrisElement elem);
1984
1984
  */
1985
1985
  LEPTRIS_API LeptrisElement leptris_element_create(LeptrisDocument doc, const char* name);
1986
1986
 
1987
+ /**
1988
+ * Create a new element with attributes set in one call (#1344)
1989
+ *
1990
+ * The fused twin of create + N x set_attribute: one crossing
1991
+ * builds the element with every attribute attached — the
1992
+ * builder-shape answer for programmatic document construction.
1993
+ * Attribute semantics are identical to leptris_element_set_attribute
1994
+ * per pair (same name handling, same value copy); a duplicate name
1995
+ * replaces, last wins.
1996
+ *
1997
+ * @param doc Document that will own the element
1998
+ * @param name Element name (QName prefixes handled like
1999
+ * leptris_element_create)
2000
+ * @param attr_names Attribute names; may be NULL when attr_count
2001
+ * is 0. A NULL element or NULL name string fails
2002
+ * the call.
2003
+ * @param attr_values Attribute values; a NULL entry stores the
2004
+ * empty string
2005
+ * @param attr_count Number of name/value pairs
2006
+ * @return New element or NULL on error
2007
+ *
2008
+ * Memory: Element owned by document, freed when document freed
2009
+ */
2010
+ LEPTRIS_API LeptrisElement leptris_element_new_with_attributes(
2011
+ LeptrisDocument doc, const char* name, const char** attr_names,
2012
+ const char** attr_values, size_t attr_count);
2013
+
1987
2014
  /**
1988
2015
  * Set element name (rename element tag)
1989
2016
  *
@@ -232,6 +232,26 @@ LeptrisElement leptris_element_create(LeptrisDocument doc, const char* name) {
232
232
  return elem;
233
233
  }
234
234
 
235
+ /* #1344: fused create + attribute-set — one crossing for the
236
+ * builder path. Identical per-pair semantics to
237
+ * leptris_element_set_attribute. */
238
+ LeptrisElement leptris_element_new_with_attributes(
239
+ LeptrisDocument doc, const char* name, const char** attr_names,
240
+ const char** attr_values, size_t attr_count) {
241
+ LeptrisElement elem = leptris_element_create(doc, name);
242
+ if (!elem) return NULL;
243
+ if (attr_count && !attr_names) return NULL;
244
+ for (size_t i = 0; i < attr_count; i++) {
245
+ if (!attr_names[i]) return NULL;
246
+ if (leptris_element_set_attribute(
247
+ elem, attr_names[i],
248
+ (attr_values && attr_values[i]) ? attr_values[i] : "") !=
249
+ LEPTRIS_OK)
250
+ return NULL;
251
+ }
252
+ return elem;
253
+ }
254
+
235
255
  /**
236
256
  * Append child element (Public API)
237
257
  */
@@ -649,6 +649,11 @@ struct leptris_xpath_result {
649
649
  * free-list. */
650
650
  int is_int;
651
651
  long long int_value;
652
+ /* Typed-atom tag (QT3 slice): interned type name ("xs:date",
653
+ * "xs:float", ...) when the atom came from a typed constructor,
654
+ * NULL for the untyped/string class. NOT owned — static
655
+ * literals only. Cleared in result_new (free-list recycle). */
656
+ const char* atomic_type;
652
657
  };
653
658
 
654
659
  /* Namespace mapping for XPath context (v0.8.0) */