leptris 1.9.197.2-arm-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 +7 -0
- data/CHANGELOG.md +3890 -0
- data/CLAUDE.md +115 -0
- data/CONTEXT.md +39 -0
- data/LICENSE.md +33 -0
- data/README.adoc +755 -0
- data/Rakefile +407 -0
- data/TODO.perf/01-ext-accelerated-default-reads.md +28 -0
- data/TODO.perf/02-auto-enable-native-layer.md +19 -0
- data/TODO.perf/03-bulk-xpath-result-materialization.md +18 -0
- data/TODO.perf/04-ext-bound-serialization.md +15 -0
- data/TODO.perf/05-native-surface-completion.md +19 -0
- data/TODO.perf/06-perf-battery-native-legs.md +16 -0
- data/TODO.perf/07-native-read-floor.md +31 -0
- data/TODO.perf/08-version-coherent-native-mutations.md +24 -0
- data/TODO.perf/09-adoption-lift-fast-path.md +38 -0
- data/TODO.perf/10-bulk-attribute-materialization.md +20 -0
- data/TODO.perf/11-moxml-gap-battery.md +18 -0
- data/TODO.perf/12-document-lifetime-in-c.md +47 -0
- data/TODO.perf/13-structural-memos.md +49 -0
- data/TODO.perf/14-insert-family-c-bound.md +31 -0
- data/TODO.perf/15-compiled-expression-cache.md +35 -0
- data/TODO.perf/16-at-xpath-single-result-seam.md +38 -0
- data/TODO.perf/17-precomputed-fast-path-flags.md +35 -0
- data/TODO.perf/18-inner-html-one-c-pass.md +32 -0
- data/TODO.perf/19-lazy-node-pointer.md +39 -0
- data/TODO.perf/20-css-translation-cache.md +24 -0
- data/TODO.perf/21-key-memo-consult.md +20 -0
- data/TODO.perf/22-eager-nodeset-materialization.md +30 -0
- data/TODO.perf/23-cbound-value-mutations.md +27 -0
- data/TODO.perf/24-immutable-read-lanes.md +22 -0
- data/TODO.perf/25-scope-owned-bulk-path.md +39 -0
- data/TODO.perf/26-post-mutation-memo-seeding.md +26 -0
- data/TODO.perf/27-c-yield-traversal.md +38 -0
- data/TODO.perf/28-address-fills.md +25 -0
- data/TODO.perf/29-ns-xpath-compiled.md +23 -0
- data/TODO.perf/30-copy-and-element-child-faces.md +31 -0
- data/TODO.perf/31-battery-rounds-4-8.md +23 -0
- data/TODO.perf/32-clean-host-floor-table.md +29 -0
- data/TODO.perf/33-cbound-root-set.md +29 -0
- data/TODO.perf/34-fragment-fast-lane.md +41 -0
- data/TODO.perf/35-parse-default-c-face.md +24 -0
- data/TODO.perf/36-raise-in-c-serializer-encoding.md +34 -0
- data/TODO.perf/37-document-lazy-pointer.md +28 -0
- data/TODO.perf/38-bulk-walk-and-bench-gate.md +23 -0
- data/TODO.restructure/01-constraint-compliance-audit.md +40 -0
- data/TODO.restructure/02-deep-copy-seam.md +21 -0
- data/TODO.restructure/03-evaluation-context-seam.md +18 -0
- data/TODO.restructure/04-spec-mece-restructure.md +20 -0
- data/TODO.restructure/05-memory-documentation.md +13 -0
- data/TODO.restructure/06-architecture-map-refresh.md +12 -0
- data/TODO.restructure/07-external-gates.md +16 -0
- data/TODO.restructure/08-new-code-audit-and-ext-memo.md +11 -0
- data/TODO.restructure/09-iteration-scope.md +29 -0
- data/TODO.restructure/10-cold-attr-read-diet.md +19 -0
- data/TODO.restructure/11-construction-factory-diet.md +16 -0
- data/TODO.restructure/12-resultattr-merge.md +12 -0
- data/TODO.restructure/13-spec-mece-followup.md +9 -0
- data/TODO.restructure/14-constraint-audit-refresh.md +15 -0
- data/TODO.restructure/15-readme-feature-documentation.md +10 -0
- data/TODO.restructure/16-claudemd-map-refresh.md +5 -0
- data/TODO.restructure/17-perf-drift-record.md +12 -0
- data/TODO.restructure/18-audit-spec-doubles-and-gem-contents.md +12 -0
- data/TODO.restructure/19-gitignore-hygiene.md +10 -0
- data/TODO.restructure/20-utf8proc-enablement.md +34 -0
- data/TODO.restructure/21-typeddata-variant-prototype.md +42 -0
- data/TODO.restructure/22-sax-drain-bulk-strip.md +28 -0
- data/docs/adr/0001-lockstep-mirror.md +17 -0
- data/docs/adr/0002-utf8-at-the-seam.md +19 -0
- data/docs/adr/0003-readonly-memoization-pattern.md +34 -0
- data/docs/adr/0004-lifetime-guard.md +21 -0
- data/docs/adr/0005-autoload-manifest-ordering.md +19 -0
- data/docs/adr/0006-ruby-variant-policy.md +25 -0
- data/ext/build_windows_native.rb +42 -0
- data/ext/leptris/native/extconf.rb +55 -0
- data/ext/leptris/native/native.c +2646 -0
- data/leptris.gemspec +43 -0
- data/lib/leptris/version.rb +5 -0
- data/lib/leptris/xml/attr.rb +76 -0
- data/lib/leptris/xml/c_string_array.rb +37 -0
- data/lib/leptris/xml/cdata.rb +27 -0
- data/lib/leptris/xml/comment.rb +27 -0
- data/lib/leptris/xml/css_to_xpath.rb +192 -0
- data/lib/leptris/xml/descriptor.rb +214 -0
- data/lib/leptris/xml/diff.rb +74 -0
- data/lib/leptris/xml/doc_type.rb +54 -0
- data/lib/leptris/xml/document.rb +716 -0
- data/lib/leptris/xml/document_fragment.rb +63 -0
- data/lib/leptris/xml/element.rb +771 -0
- data/lib/leptris/xml/entity_reference.rb +13 -0
- data/lib/leptris/xml/evaluation_context.rb +32 -0
- data/lib/leptris/xml/ffi.rb +1527 -0
- data/lib/leptris/xml/iteration_scope.rb +56 -0
- data/lib/leptris/xml/iterparse.rb +144 -0
- data/lib/leptris/xml/namespace.rb +43 -0
- data/lib/leptris/xml/native.so +0 -0
- data/lib/leptris/xml/native_layer.rb +92 -0
- data/lib/leptris/xml/node.rb +686 -0
- data/lib/leptris/xml/node_set.rb +212 -0
- data/lib/leptris/xml/parse_options.rb +97 -0
- data/lib/leptris/xml/plan_value.rb +121 -0
- data/lib/leptris/xml/processing_instruction.rb +90 -0
- data/lib/leptris/xml/pull.rb +212 -0
- data/lib/leptris/xml/relaxng.rb +126 -0
- data/lib/leptris/xml/result_attr.rb +39 -0
- data/lib/leptris/xml/result_text.rb +36 -0
- data/lib/leptris/xml/sax/document.rb +45 -0
- data/lib/leptris/xml/sax/dom_dispatch.rb +144 -0
- data/lib/leptris/xml/sax/parser.rb +326 -0
- data/lib/leptris/xml/sax/recorder.rb +374 -0
- data/lib/leptris/xml/sax.rb +14 -0
- data/lib/leptris/xml/schematron.rb +88 -0
- data/lib/leptris/xml/searchable.rb +361 -0
- data/lib/leptris/xml/serialization.rb +180 -0
- data/lib/leptris/xml/text.rb +32 -0
- data/lib/leptris/xml/xpath.rb +89 -0
- data/lib/leptris/xml/xquery.rb +77 -0
- data/lib/leptris/xml/xslt.rb +85 -0
- data/lib/leptris/xml.rb +108 -0
- data/lib/leptris.rb +53 -0
- data/lib/libleptris.so +0 -0
- data/lib/libutf8proc.so.3 +0 -0
- data/scripts/gem_smoke.rb +36 -0
- metadata +214 -0
|
@@ -0,0 +1,1527 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ffi"
|
|
4
|
+
|
|
5
|
+
module Leptris
|
|
6
|
+
module XML
|
|
7
|
+
module FFI
|
|
8
|
+
extend ::FFI::Library
|
|
9
|
+
|
|
10
|
+
# The per-OS vendor directory of the ruby-platform gem
|
|
11
|
+
# (zero-setup TruffleRuby/JRuby, #160): binaries for the
|
|
12
|
+
# common engines' OSes under lib/leptris/vendor/<platform>/.
|
|
13
|
+
# Returns [] in platform gems (no vendor tree) and on
|
|
14
|
+
# OSes the variant does not carry.
|
|
15
|
+
# Dir-name candidates for a RUBY_PLATFORM string, in
|
|
16
|
+
# preference order (glibc before musl — dlopen falls through
|
|
17
|
+
# on musl hosts).
|
|
18
|
+
def self.vendor_platforms_for(ruby_platform)
|
|
19
|
+
case ruby_platform
|
|
20
|
+
when /arm64.*darwin|aarch64.*darwin/ then %w[arm64-darwin]
|
|
21
|
+
when /x86_64.*darwin/ then %w[x86_64-darwin]
|
|
22
|
+
when /aarch64.*linux/ then %w[aarch64-linux aarch64-linux-musl]
|
|
23
|
+
when /x86_64.*linux/ then %w[x86_64-linux x86_64-linux-musl]
|
|
24
|
+
# 32-bit ARM (armv[567l]: "arm-linux", "armv7l-linux",
|
|
25
|
+
# "armeb-linux", ...). Never matches aarch64 ("aarch" has
|
|
26
|
+
# no "arm" substring).
|
|
27
|
+
when /arm.*linux/ then %w[arm-linux arm-linux-musl]
|
|
28
|
+
# POWER8+ little-endian and IBM Z (qemu-built platform gems)
|
|
29
|
+
when /ppc64le.*linux/ then %w[ppc64le-linux]
|
|
30
|
+
when /s390x.*linux/ then %w[s390x-linux s390x-linux-musl]
|
|
31
|
+
else []
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.vendor_dirs
|
|
36
|
+
vendor_platforms_for(RUBY_PLATFORM)
|
|
37
|
+
.map { |d| File.expand_path("../../leptris/vendor/#{d}", __dir__) }
|
|
38
|
+
.select { |dir| File.directory?(dir) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# THE libleptris candidate list, in order — shared with the
|
|
42
|
+
# native read layer's resolve!. Single source of truth is
|
|
43
|
+
# load-bearing: two differently-pathed copies of the library
|
|
44
|
+
# load as two images with split per-document state.
|
|
45
|
+
def self.libleptris_candidates
|
|
46
|
+
[
|
|
47
|
+
ENV["LEPTRIS_LIB_PATH"],
|
|
48
|
+
*vendor_dirs.flat_map { |d|
|
|
49
|
+
%w[libleptris.dylib libleptris.so libleptris.dll]
|
|
50
|
+
.map { |n| File.join(d, n) }
|
|
51
|
+
},
|
|
52
|
+
File.expand_path("../../libleptris.dylib", __dir__),
|
|
53
|
+
File.expand_path("../../libleptris.so", __dir__),
|
|
54
|
+
File.expand_path("../../libleptris.dll", __dir__),
|
|
55
|
+
"/usr/local/lib/libleptris.dylib",
|
|
56
|
+
"/usr/local/lib/libleptris.so",
|
|
57
|
+
"leptris",
|
|
58
|
+
].compact
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# libleptris links utf8proc via @rpath (TODO.restructure/20
|
|
62
|
+
# — fn:normalize-unicode). dlopen the VENDORED utf8proc
|
|
63
|
+
# FIRST: once its install name is loaded, dyld resolves
|
|
64
|
+
# libleptris's dependent image from this image instead of
|
|
65
|
+
# searching system paths. Absent (pure-ruby fallback gem,
|
|
66
|
+
# UTF8PROC-less custom builds) is not an error — the loader
|
|
67
|
+
# tries and moves on, and libleptris without the dependency
|
|
68
|
+
# never consults it.
|
|
69
|
+
begin
|
|
70
|
+
ffi_lib [
|
|
71
|
+
*Leptris::XML::FFI.vendor_dirs.flat_map { |d|
|
|
72
|
+
%w[libutf8proc.3.dylib libutf8proc.so.3 libutf8proc.so
|
|
73
|
+
utf8proc.dll].map { |n| File.join(d, n) }
|
|
74
|
+
},
|
|
75
|
+
File.expand_path("../../libutf8proc.3.dylib", __dir__),
|
|
76
|
+
File.expand_path("../../libutf8proc.so.3", __dir__),
|
|
77
|
+
File.expand_path("../../libutf8proc.so", __dir__),
|
|
78
|
+
File.expand_path("../../utf8proc.dll", __dir__),
|
|
79
|
+
].compact
|
|
80
|
+
rescue LoadError
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Issue leptris-ruby#49: name the remedy when the library is
|
|
85
|
+
# missing (ruby-platform gem without a vendored libleptris).
|
|
86
|
+
begin
|
|
87
|
+
ffi_lib Leptris::XML::FFI.libleptris_candidates
|
|
88
|
+
rescue LoadError => e
|
|
89
|
+
raise LoadError, <<~MSG
|
|
90
|
+
leptris: cannot load the vendored libleptris library.
|
|
91
|
+
You may have installed the ruby-platform variant of this
|
|
92
|
+
gem (#{Gem.loaded_specs["leptris"]&.full_name rescue "unknown"}),
|
|
93
|
+
which does not vendor the native library. Fix:
|
|
94
|
+
|
|
95
|
+
bundle update leptris # force platform gems
|
|
96
|
+
# or: gem install leptris --platform ruby is unsupported
|
|
97
|
+
# or: set LEPTRIS_LIB_PATH=/path/to/libleptris.so
|
|
98
|
+
|
|
99
|
+
Original error: #{e.message}
|
|
100
|
+
MSG
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
typedef :pointer, :leptris_document
|
|
104
|
+
typedef :pointer, :leptris_element
|
|
105
|
+
typedef :pointer, :leptris_node_ref
|
|
106
|
+
typedef :pointer, :leptris_attribute
|
|
107
|
+
typedef :pointer, :leptris_doctype
|
|
108
|
+
typedef :pointer, :leptris_xpath_result
|
|
109
|
+
typedef :pointer, :leptris_xpath_ns_set
|
|
110
|
+
typedef :pointer, :leptris_xpath_compiled
|
|
111
|
+
typedef :pointer, :leptris_relaxng
|
|
112
|
+
typedef :pointer, :leptris_xslt
|
|
113
|
+
typedef :pointer, :leptris_xquery
|
|
114
|
+
typedef :pointer, :leptris_schematron
|
|
115
|
+
typedef :pointer, :leptris_diff
|
|
116
|
+
typedef :pointer, :leptris_plan
|
|
117
|
+
typedef :pointer, :leptris_plan_result
|
|
118
|
+
typedef :pointer, :leptris_sax_recorder
|
|
119
|
+
typedef :pointer, :leptris_pull_parser
|
|
120
|
+
typedef :pointer, :leptris_iterparse
|
|
121
|
+
typedef :pointer, :leptris_xpath_var_set
|
|
122
|
+
typedef :pointer, :leptris_sax_parser
|
|
123
|
+
typedef :int, :leptris_status
|
|
124
|
+
|
|
125
|
+
class SAXHandler < ::FFI::Struct
|
|
126
|
+
layout \
|
|
127
|
+
:start_document, :pointer,
|
|
128
|
+
:end_document, :pointer,
|
|
129
|
+
:start_element, :pointer,
|
|
130
|
+
:end_element, :pointer,
|
|
131
|
+
:characters, :pointer,
|
|
132
|
+
:comment, :pointer,
|
|
133
|
+
:cdata, :pointer,
|
|
134
|
+
:processing_instruction, :pointer,
|
|
135
|
+
:start_prefix_mapping, :pointer,
|
|
136
|
+
:end_prefix_mapping, :pointer,
|
|
137
|
+
:error, :pointer
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class SerializeOptions < ::FFI::Struct
|
|
141
|
+
layout \
|
|
142
|
+
:indent, :int,
|
|
143
|
+
:xml_declaration, :int,
|
|
144
|
+
:encoding, :pointer
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# LeptrisSerializeExtOptions (1.9.9 #129 display form; 1.9.22
|
|
148
|
+
# #633/#109 indent unit): knobs beyond the ABI-frozen options
|
|
149
|
+
# struct. MAY grow — always pass its size through the sized
|
|
150
|
+
# entry.
|
|
151
|
+
class SerializeExtStruct < ::FFI::Struct
|
|
152
|
+
layout :indent_text, :int,
|
|
153
|
+
:indent_unit, :pointer,
|
|
154
|
+
:expand_empty, :int
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Mirrors LeptrisParseOptions (libleptris >= 1.9.0 carries the
|
|
158
|
+
# recover field; earlier fields unchanged since v1.6.0).
|
|
159
|
+
class ParseOptionsStruct < ::FFI::Struct
|
|
160
|
+
layout \
|
|
161
|
+
:flags, :int,
|
|
162
|
+
:strict_mode, :int,
|
|
163
|
+
:max_depth, :int,
|
|
164
|
+
:recover, :int
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# LeptrisSaxEventRecord (types.h, issue #585): fixed layout the
|
|
168
|
+
# header explicitly freezes for FFI mirrors. Strings are NOT
|
|
169
|
+
# inline — name/text/attrs slice the recorder's arena.
|
|
170
|
+
class SaxEventRecord < ::FFI::Struct
|
|
171
|
+
layout :kind, :uint8,
|
|
172
|
+
:reserved, [:uint8, 7],
|
|
173
|
+
:name_off, :uint32, :name_len, :uint32,
|
|
174
|
+
:text_off, :uint32, :text_len, :uint32,
|
|
175
|
+
:attrs_off, :uint32, :attr_count, :uint32,
|
|
176
|
+
:line, :uint32, :column, :uint32
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
SAX_EVENT_START_DOCUMENT = 0
|
|
180
|
+
SAX_EVENT_END_DOCUMENT = 1
|
|
181
|
+
SAX_EVENT_START_ELEMENT = 2
|
|
182
|
+
SAX_EVENT_END_ELEMENT = 3
|
|
183
|
+
SAX_EVENT_CHARACTERS = 4
|
|
184
|
+
SAX_EVENT_COMMENT = 5
|
|
185
|
+
SAX_EVENT_CDATA = 6
|
|
186
|
+
SAX_EVENT_PI = 7
|
|
187
|
+
SAX_EVENT_START_PREFIX = 8
|
|
188
|
+
SAX_EVENT_END_PREFIX = 9
|
|
189
|
+
SAX_EVENT_ERROR = 10
|
|
190
|
+
|
|
191
|
+
ITERPARSE_TOP_LEVEL = 0
|
|
192
|
+
ITERPARSE_FULL_DOCUMENT = 1
|
|
193
|
+
|
|
194
|
+
# struct LeptrisPullEvent (leptris/sax.h): FFI::Struct derives
|
|
195
|
+
# the field offsets from the layout, so ABI changes are a
|
|
196
|
+
# one-line edit here instead of silent offset drift in callers.
|
|
197
|
+
class PullEventStruct < ::FFI::Struct
|
|
198
|
+
layout \
|
|
199
|
+
:type, :int,
|
|
200
|
+
:name, :pointer,
|
|
201
|
+
:text, :pointer,
|
|
202
|
+
:text_len, :size_t
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Tree-shaped schema-descriptor materialization (1.9.162,
|
|
206
|
+
# upstream #1039): hosts compile a plan tree once, then
|
|
207
|
+
# leptris_plan_walk materializes a whole subtree in one
|
|
208
|
+
# native pass. The plan/result structs mirror descriptor.h
|
|
209
|
+
# — POD, ABI-frozen at v1 (leptris_plan_abi_version).
|
|
210
|
+
class AttrPlan < ::FFI::Struct
|
|
211
|
+
layout :wire_name, :pointer,
|
|
212
|
+
:kind, :uint8,
|
|
213
|
+
:type_tag, :uint8
|
|
214
|
+
end
|
|
215
|
+
class ChildPlan < ::FFI::Struct
|
|
216
|
+
layout :wire_name, :pointer,
|
|
217
|
+
:kind, :uint8,
|
|
218
|
+
:type_tag, :uint8,
|
|
219
|
+
:child_plan_index, :int32,
|
|
220
|
+
# libleptris 1.9.178 (#1114/#1115): rule-level ns
|
|
221
|
+
# forms on ChildPlan (additive to the frozen v1 ABI).
|
|
222
|
+
:ns_form, :uint8,
|
|
223
|
+
:pad0, :uint8,
|
|
224
|
+
:ns_uri, :pointer
|
|
225
|
+
end
|
|
226
|
+
class ElementPlan < ::FFI::Struct
|
|
227
|
+
layout :element_name, :pointer,
|
|
228
|
+
:ns_form, :uint8,
|
|
229
|
+
:pad0, :uint8,
|
|
230
|
+
:ns_uri, :pointer,
|
|
231
|
+
:attribute_count, :uint32,
|
|
232
|
+
:child_count, :uint32,
|
|
233
|
+
:attribute_plans, :pointer,
|
|
234
|
+
:child_plans, :pointer,
|
|
235
|
+
:flags, :uint16,
|
|
236
|
+
:pad1, :uint16
|
|
237
|
+
end
|
|
238
|
+
class PlanSpec < ::FFI::Struct
|
|
239
|
+
layout :abi_version, :uint32,
|
|
240
|
+
:plan_count, :uint32,
|
|
241
|
+
:plans, :pointer
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
PLAN_ABI_VERSION = 1
|
|
245
|
+
|
|
246
|
+
PLAN_KIND_SCALAR = 1
|
|
247
|
+
PLAN_KIND_COLLECTION = 2
|
|
248
|
+
PLAN_KIND_NESTED = 3
|
|
249
|
+
PLAN_KIND_RAW = 4
|
|
250
|
+
PLAN_KIND_CONTENT = 5
|
|
251
|
+
PLAN_KIND_CALLBACK = 6
|
|
252
|
+
|
|
253
|
+
PLAN_FLAG_MIXED_CONTENT = 0x1
|
|
254
|
+
PLAN_FLAG_ORDERED = 0x2
|
|
255
|
+
PLAN_FLAG_CDATA = 0x4
|
|
256
|
+
PLAN_FLAG_NS_LENIENT = 0x8
|
|
257
|
+
|
|
258
|
+
PLAN_NS_NONE = 0
|
|
259
|
+
PLAN_NS_EXACT = 1
|
|
260
|
+
PLAN_NS_ANY = 2
|
|
261
|
+
|
|
262
|
+
PLAN_VALUE_ELEMENT = 0
|
|
263
|
+
PLAN_VALUE_SCALAR = 1
|
|
264
|
+
PLAN_VALUE_COLLECTION = 2
|
|
265
|
+
PLAN_VALUE_RAW = 3
|
|
266
|
+
PLAN_VALUE_CALLBACK = 4
|
|
267
|
+
|
|
268
|
+
# Byte offset of parse-created nodes (1.9.162, #1039): the
|
|
269
|
+
# position descriptor CALLBACK rows echo; 0 when unknown.
|
|
270
|
+
attach_function :leptris_node_byte_offset,
|
|
271
|
+
[:leptris_node_ref], :size_t
|
|
272
|
+
|
|
273
|
+
attach_function :leptris_plan_abi_version, [], :uint32
|
|
274
|
+
attach_function :leptris_plan_build,
|
|
275
|
+
[:pointer, :pointer], :leptris_plan
|
|
276
|
+
attach_function :leptris_plan_free, [:leptris_plan], :void
|
|
277
|
+
attach_function :leptris_plan_walk,
|
|
278
|
+
[:leptris_document, :leptris_element, :leptris_plan, :pointer],
|
|
279
|
+
:leptris_plan_result
|
|
280
|
+
attach_function :leptris_plan_result_free,
|
|
281
|
+
[:leptris_plan_result], :void
|
|
282
|
+
attach_function :leptris_plan_value_kind,
|
|
283
|
+
[:leptris_plan_result], :int
|
|
284
|
+
attach_function :leptris_plan_value_name,
|
|
285
|
+
[:leptris_plan_result], :string
|
|
286
|
+
attach_function :leptris_plan_value_type_tag,
|
|
287
|
+
[:leptris_plan_result], :uint8
|
|
288
|
+
attach_function :leptris_plan_value_string,
|
|
289
|
+
[:leptris_plan_result], :string
|
|
290
|
+
attach_function :leptris_plan_value_length,
|
|
291
|
+
[:leptris_plan_result], :size_t
|
|
292
|
+
attach_function :leptris_plan_value_position,
|
|
293
|
+
[:leptris_plan_result], :size_t
|
|
294
|
+
attach_function :leptris_plan_value_count,
|
|
295
|
+
[:leptris_plan_result], :size_t
|
|
296
|
+
attach_function :leptris_plan_value_at,
|
|
297
|
+
[:leptris_plan_result, :size_t], :leptris_plan_result
|
|
298
|
+
attach_function :leptris_plan_value_attribute,
|
|
299
|
+
[:leptris_plan_result, :string], :string
|
|
300
|
+
|
|
301
|
+
attach_function :leptris_version, [], :string
|
|
302
|
+
attach_function :leptris_version_components, [:pointer, :pointer, :pointer], :void
|
|
303
|
+
|
|
304
|
+
# Tolerant HTML4/5 parse into the STANDARD DOM (libleptris
|
|
305
|
+
# 1.9.75, #659): implied end tags, void elements, raw-text
|
|
306
|
+
# script/style, case-insensitive (lowercased) names, the HTML
|
|
307
|
+
# named-entity table. Document shape — html/head/body
|
|
308
|
+
# synthesized; no implied tbody. Malformed input never fails
|
|
309
|
+
# the parse; only an entirely empty result is an error.
|
|
310
|
+
attach_function :leptris_parse_html_string,
|
|
311
|
+
[:string, :size_t, :pointer], :leptris_document
|
|
312
|
+
# HTML4/libxml2-compatibility mode (1.9.104, #659): the same
|
|
313
|
+
# tolerant tokenizer and Nokogiri document shape, except
|
|
314
|
+
# leading script/style stay in <body> (libxml2's shape —
|
|
315
|
+
# title/meta/link/base still lift). Bindings matching
|
|
316
|
+
# Nokogiri byte-for-byte pin this; _html_string is the
|
|
317
|
+
# WHATWG-conformant engine (implied-head full set, foster
|
|
318
|
+
# parenting from 1.9.105).
|
|
319
|
+
attach_function :leptris_parse_html4_string,
|
|
320
|
+
[:string, :size_t, :pointer], :leptris_document
|
|
321
|
+
|
|
322
|
+
attach_function :leptris_parse_string,
|
|
323
|
+
[:string, :size_t, :pointer], :leptris_document
|
|
324
|
+
attach_function :leptris_parse_string_flags,
|
|
325
|
+
[:string, :size_t, :uint, :pointer], :leptris_document
|
|
326
|
+
attach_function :leptris_parse_string_inplace,
|
|
327
|
+
[:pointer, :size_t, :pointer], :leptris_document
|
|
328
|
+
attach_function :leptris_parse_string_with_encoding,
|
|
329
|
+
[:string, :size_t, :pointer], :leptris_document
|
|
330
|
+
attach_function :leptris_parse_file,
|
|
331
|
+
[:string, :pointer], :leptris_document
|
|
332
|
+
attach_function :leptris_load_file,
|
|
333
|
+
[:string, :pointer], :pointer
|
|
334
|
+
attach_function :leptris_document_free,
|
|
335
|
+
[:leptris_document], :void
|
|
336
|
+
attach_function :leptris_document_create,
|
|
337
|
+
[], :leptris_document
|
|
338
|
+
attach_function :leptris_document_set_root,
|
|
339
|
+
[:leptris_document, :leptris_element], :leptris_status
|
|
340
|
+
attach_function :leptris_document_root,
|
|
341
|
+
[:leptris_document], :leptris_element
|
|
342
|
+
# The document node — navigation head over the whole tree
|
|
343
|
+
# chain [prolog comments/PIs, root, epilog...] (libleptris
|
|
344
|
+
# 1.9.7, upstream #580; the libxml2 model).
|
|
345
|
+
attach_function :leptris_document_node,
|
|
346
|
+
[:leptris_document], :leptris_node_ref
|
|
347
|
+
# First node of the document child chain in one call — the
|
|
348
|
+
# prolog head (libleptris 1.9.174; document_node +
|
|
349
|
+
# node_first_child without the intermediate handle).
|
|
350
|
+
attach_function :leptris_document_first_child,
|
|
351
|
+
[:leptris_document], :leptris_node_ref
|
|
352
|
+
# Node-surface parity (libleptris 1.9.176, upstream #1094,
|
|
353
|
+
# leptris-ruby#212): entity references, the XML declaration,
|
|
354
|
+
# programmatic DOCTYPE, and document-PI identity/removal.
|
|
355
|
+
attach_function :leptris_entity_ref_node_create,
|
|
356
|
+
[:leptris_document, :string], :leptris_node_ref
|
|
357
|
+
attach_function :leptris_entity_ref_node_name,
|
|
358
|
+
[:leptris_node_ref], :string
|
|
359
|
+
attach_function :leptris_document_version,
|
|
360
|
+
[:leptris_document], :string
|
|
361
|
+
attach_function :leptris_document_standalone,
|
|
362
|
+
[:leptris_document], :int
|
|
363
|
+
attach_function :leptris_document_set_version,
|
|
364
|
+
[:leptris_document, :string], :leptris_status
|
|
365
|
+
attach_function :leptris_document_set_encoding,
|
|
366
|
+
[:leptris_document, :string], :leptris_status
|
|
367
|
+
attach_function :leptris_document_set_standalone,
|
|
368
|
+
[:leptris_document, :int], :leptris_status
|
|
369
|
+
attach_function :leptris_document_set_doctype,
|
|
370
|
+
[:leptris_document, :string, :string, :string], :leptris_doctype
|
|
371
|
+
attach_function :leptris_document_append_pi,
|
|
372
|
+
[:leptris_document, :string, :string], :leptris_node_ref
|
|
373
|
+
attach_function :leptris_document_remove_child,
|
|
374
|
+
[:leptris_document, :leptris_node_ref], :leptris_status
|
|
375
|
+
# Wrap-free subtree visitation (1.9.20, upstream #645a):
|
|
376
|
+
# enter/leave pairs for elements, depth from the walk's root,
|
|
377
|
+
# one C call — no NodeSet/Array churn per level. The document
|
|
378
|
+
# node walks the document child chain.
|
|
379
|
+
attach_function :leptris_node_visit,
|
|
380
|
+
[:leptris_node_ref, :pointer, :pointer], :void
|
|
381
|
+
# Document-level PIs (v1.6.0): not tree nodes — enumerate via
|
|
382
|
+
# these accessors only.
|
|
383
|
+
attach_function :leptris_document_pi_count,
|
|
384
|
+
[:leptris_document], :size_t
|
|
385
|
+
attach_function :leptris_document_pi_target,
|
|
386
|
+
[:leptris_document, :size_t], :string
|
|
387
|
+
attach_function :leptris_document_pi_data,
|
|
388
|
+
[:leptris_document, :size_t], :string
|
|
389
|
+
# Document-level PI removal by target or index (1.9.9, #612):
|
|
390
|
+
# unlinks from the child chain; the node is pool-owned and
|
|
391
|
+
# stays valid until document free.
|
|
392
|
+
attach_function :leptris_document_remove_pi,
|
|
393
|
+
[:leptris_document, :string, :size_t], :leptris_node_ref
|
|
394
|
+
attach_function :leptris_document_add_pi,
|
|
395
|
+
[:leptris_document, :string, :string], :pointer
|
|
396
|
+
# Document-level comment writer (libleptris 1.9.160, #1032):
|
|
397
|
+
# epilog append, the add_pi shape.
|
|
398
|
+
attach_function :leptris_document_add_comment,
|
|
399
|
+
[:leptris_document, :string], :leptris_node_ref
|
|
400
|
+
# Document-level comments (libleptris 1.9.3, #578): parsed
|
|
401
|
+
# <!-- ... --> outside the root, prolog then epilog, in
|
|
402
|
+
# document order. Read-only surface (no add_comment yet).
|
|
403
|
+
attach_function :leptris_document_comment_count,
|
|
404
|
+
[:leptris_document], :size_t
|
|
405
|
+
attach_function :leptris_document_comment_content,
|
|
406
|
+
[:leptris_document, :size_t], :string
|
|
407
|
+
# Options-struct parse (v1.6.0): supersedes the flags variants;
|
|
408
|
+
# the flags path remains bound for compatibility.
|
|
409
|
+
attach_function :leptris_parse_string_ex,
|
|
410
|
+
[:string, :size_t, :pointer, :pointer], :leptris_document
|
|
411
|
+
attach_function :leptris_document_encoding,
|
|
412
|
+
[:leptris_document], :string
|
|
413
|
+
attach_function :leptris_document_finalize_strings,
|
|
414
|
+
[:leptris_document], :int
|
|
415
|
+
attach_function :leptris_document_adopt_child,
|
|
416
|
+
[:leptris_document, :leptris_document], :void
|
|
417
|
+
attach_function :leptris_document_set_strict,
|
|
418
|
+
[:leptris_document, :int], :leptris_status
|
|
419
|
+
attach_function :leptris_document_get_strict,
|
|
420
|
+
[:leptris_document], :int
|
|
421
|
+
attach_function :leptris_document_freeze,
|
|
422
|
+
[:leptris_document], :leptris_status
|
|
423
|
+
attach_function :leptris_document_is_frozen,
|
|
424
|
+
[:leptris_document], :int
|
|
425
|
+
attach_function :leptris_set_strict_mode, [:int], :void
|
|
426
|
+
attach_function :leptris_get_strict_mode, [], :int
|
|
427
|
+
attach_function :leptris_set_max_depth, [:int], :void
|
|
428
|
+
attach_function :leptris_get_max_depth, [], :int
|
|
429
|
+
attach_function :leptris_xinclude_process,
|
|
430
|
+
[:leptris_document, :string], :leptris_status
|
|
431
|
+
attach_function :leptris_xinclude_is_include_element,
|
|
432
|
+
[:leptris_element], :int
|
|
433
|
+
attach_function :leptris_xinclude_is_fallback_element,
|
|
434
|
+
[:leptris_element], :int
|
|
435
|
+
attach_function :leptris_xinclude_get_href, [:leptris_element], :string
|
|
436
|
+
attach_function :leptris_xinclude_get_parse, [:leptris_element], :string
|
|
437
|
+
attach_function :leptris_xinclude_get_xpointer, [:leptris_element], :string
|
|
438
|
+
attach_function :leptris_xinclude_get_encoding, [:leptris_element], :string
|
|
439
|
+
|
|
440
|
+
attach_function :leptris_node_get_type,
|
|
441
|
+
[:leptris_node_ref], :int
|
|
442
|
+
attach_function :leptris_node_first_child,
|
|
443
|
+
[:leptris_node_ref], :leptris_node_ref
|
|
444
|
+
attach_function :leptris_node_last_child,
|
|
445
|
+
[:leptris_node_ref], :leptris_node_ref
|
|
446
|
+
attach_function :leptris_node_next_sibling,
|
|
447
|
+
[:leptris_node_ref], :leptris_node_ref
|
|
448
|
+
attach_function :leptris_node_previous_sibling,
|
|
449
|
+
[:leptris_node_ref], :leptris_node_ref
|
|
450
|
+
attach_function :leptris_node_child_count,
|
|
451
|
+
[:leptris_node_ref], :size_t
|
|
452
|
+
# libleptris 1.7.0: all-kind child batch — out_nodes=NULL is a
|
|
453
|
+
# count-only query returning the TOTAL across every child kind.
|
|
454
|
+
attach_function :leptris_node_children,
|
|
455
|
+
[:leptris_node_ref, :pointer, :size_t], :size_t
|
|
456
|
+
# Children with out_kinds (1.9.18, upstream #617): the kind
|
|
457
|
+
# rides the batch, so wrappers skip the per-child get_type.
|
|
458
|
+
attach_function :leptris_node_children_ex,
|
|
459
|
+
[:leptris_node_ref, :pointer, :pointer, :size_t], :size_t
|
|
460
|
+
# Element-only batch; mirror-only — fetch_children rides the
|
|
461
|
+
# all-kind node_children above.
|
|
462
|
+
# Raw qname-ordered attribute list INCLUDING xmlns
|
|
463
|
+
# declarations at their byte positions (1.9.18, upstream
|
|
464
|
+
# #635) — the streaming SAX contract's mixed view.
|
|
465
|
+
attach_function :leptris_element_attributes_raw,
|
|
466
|
+
[:leptris_element, :pointer, :pointer, :size_t], :size_t
|
|
467
|
+
attach_function :leptris_element_children,
|
|
468
|
+
[:leptris_element, :pointer, :size_t], :size_t
|
|
469
|
+
attach_function :leptris_node_as_element,
|
|
470
|
+
[:leptris_node_ref], :leptris_element
|
|
471
|
+
attach_function :leptris_element_as_node,
|
|
472
|
+
[:leptris_element], :leptris_node_ref
|
|
473
|
+
attach_function :leptris_node_get_binding_wrapper,
|
|
474
|
+
[:leptris_node_ref], :pointer
|
|
475
|
+
attach_function :leptris_node_set_binding_wrapper,
|
|
476
|
+
[:leptris_node_ref, :pointer], :void
|
|
477
|
+
attach_function :leptris_node_parent,
|
|
478
|
+
[:leptris_node_ref], :leptris_element
|
|
479
|
+
attach_function :leptris_node_unlink,
|
|
480
|
+
[:leptris_node_ref], :leptris_status
|
|
481
|
+
attach_function :leptris_node_line,
|
|
482
|
+
[:leptris_node_ref], :int
|
|
483
|
+
# Parser-recorded source position (libleptris 1.9.180,
|
|
484
|
+
# #1124): {line, col_start, col_end} — Jing's diagnostic
|
|
485
|
+
# convention (column after the start tag's '>' / the
|
|
486
|
+
# element's final '>').
|
|
487
|
+
class SourcePosition < ::FFI::Struct
|
|
488
|
+
layout :line, :int,
|
|
489
|
+
:col_start, :int,
|
|
490
|
+
:col_end, :int
|
|
491
|
+
end
|
|
492
|
+
attach_function :leptris_node_source_position,
|
|
493
|
+
[:leptris_node_ref, :pointer], :void
|
|
494
|
+
attach_function :leptris_node_compare,
|
|
495
|
+
[:leptris_node_ref, :leptris_node_ref], :int
|
|
496
|
+
attach_function :leptris_node_traverse,
|
|
497
|
+
[:leptris_node_ref, :int, :pointer, :pointer], :int
|
|
498
|
+
|
|
499
|
+
attach_function :leptris_text_node_get_content,
|
|
500
|
+
[:leptris_node_ref], :string
|
|
501
|
+
attach_function :leptris_comment_node_get_content,
|
|
502
|
+
[:leptris_node_ref], :string
|
|
503
|
+
attach_function :leptris_cdata_node_get_content,
|
|
504
|
+
[:leptris_node_ref], :string
|
|
505
|
+
attach_function :leptris_pi_node_get_target,
|
|
506
|
+
[:leptris_node_ref], :string
|
|
507
|
+
attach_function :leptris_pi_node_get_data,
|
|
508
|
+
[:leptris_node_ref], :string
|
|
509
|
+
attach_function :leptris_text_node_create,
|
|
510
|
+
[:leptris_document, :string], :leptris_node_ref
|
|
511
|
+
attach_function :leptris_comment_node_create,
|
|
512
|
+
[:leptris_document, :string], :leptris_node_ref
|
|
513
|
+
attach_function :leptris_cdata_node_create,
|
|
514
|
+
[:leptris_document, :string], :leptris_node_ref
|
|
515
|
+
attach_function :leptris_pi_node_create,
|
|
516
|
+
[:leptris_document, :string, :string], :leptris_node_ref
|
|
517
|
+
attach_function :leptris_text_node_set_content,
|
|
518
|
+
[:leptris_node_ref, :string], :leptris_status
|
|
519
|
+
attach_function :leptris_comment_node_set_content,
|
|
520
|
+
[:leptris_node_ref, :string], :leptris_status
|
|
521
|
+
attach_function :leptris_cdata_node_set_content,
|
|
522
|
+
[:leptris_node_ref, :string], :leptris_status
|
|
523
|
+
attach_function :leptris_pi_node_set_target,
|
|
524
|
+
[:leptris_node_ref, :string], :leptris_status
|
|
525
|
+
attach_function :leptris_pi_node_set_data,
|
|
526
|
+
[:leptris_node_ref, :string], :leptris_status
|
|
527
|
+
|
|
528
|
+
attach_function :leptris_element_name,
|
|
529
|
+
[:leptris_element], :string
|
|
530
|
+
attach_function :leptris_element_text,
|
|
531
|
+
[:leptris_element], :string
|
|
532
|
+
attach_function :leptris_element_text_int,
|
|
533
|
+
[:leptris_element, :int], :int
|
|
534
|
+
attach_function :leptris_element_text_uint,
|
|
535
|
+
[:leptris_element, :uint], :uint
|
|
536
|
+
attach_function :leptris_element_text_double,
|
|
537
|
+
[:leptris_element, :double], :double
|
|
538
|
+
attach_function :leptris_element_text_float,
|
|
539
|
+
[:leptris_element, :float], :float
|
|
540
|
+
attach_function :leptris_element_text_bool,
|
|
541
|
+
[:leptris_element, :int], :int
|
|
542
|
+
attach_function :leptris_element_attribute,
|
|
543
|
+
[:leptris_element, :string], :string
|
|
544
|
+
attach_function :leptris_element_attribute_string,
|
|
545
|
+
[:leptris_element, :string, :string], :string
|
|
546
|
+
attach_function :leptris_element_attribute_int,
|
|
547
|
+
[:leptris_element, :string, :int], :int
|
|
548
|
+
attach_function :leptris_element_attribute_uint,
|
|
549
|
+
[:leptris_element, :string, :uint], :uint
|
|
550
|
+
attach_function :leptris_element_attribute_double,
|
|
551
|
+
[:leptris_element, :string, :double], :double
|
|
552
|
+
attach_function :leptris_element_attribute_float,
|
|
553
|
+
[:leptris_element, :string, :float], :float
|
|
554
|
+
attach_function :leptris_element_attribute_bool,
|
|
555
|
+
[:leptris_element, :string, :int], :int
|
|
556
|
+
attach_function :leptris_element_has_attribute,
|
|
557
|
+
[:leptris_element, :string], :int
|
|
558
|
+
# libleptris 1.8.0: expanded-name lookup — (uri, local) with
|
|
559
|
+
# XML Namespaces 1.0 semantics; NULL/"" uri matches only
|
|
560
|
+
# no-namespace attributes, xmlns declarations never match.
|
|
561
|
+
attach_function :leptris_element_attribute_ns,
|
|
562
|
+
[:leptris_element, :string, :string], :string
|
|
563
|
+
attach_function :leptris_element_has_attribute_ns,
|
|
564
|
+
[:leptris_element, :string, :string], :int
|
|
565
|
+
# libleptris 1.8.0: per-attribute prefix (name-derived) and
|
|
566
|
+
# namespace URI (resolved through the owning element's
|
|
567
|
+
# in-scope declarations at read time).
|
|
568
|
+
attach_function :leptris_attribute_prefix,
|
|
569
|
+
[:leptris_attribute], :string
|
|
570
|
+
attach_function :leptris_attribute_namespace_uri,
|
|
571
|
+
[:leptris_attribute], :string
|
|
572
|
+
attach_function :leptris_element_first_attribute,
|
|
573
|
+
[:leptris_element], :leptris_attribute
|
|
574
|
+
attach_function :leptris_attribute_next,
|
|
575
|
+
[:leptris_attribute], :leptris_attribute
|
|
576
|
+
attach_function :leptris_attribute_get_name,
|
|
577
|
+
[:leptris_attribute], :string
|
|
578
|
+
attach_function :leptris_attribute_get_value,
|
|
579
|
+
[:leptris_element, :leptris_attribute], :string
|
|
580
|
+
attach_function :leptris_element_prefix,
|
|
581
|
+
[:leptris_element], :string
|
|
582
|
+
attach_function :leptris_element_attribute_count,
|
|
583
|
+
[:leptris_element], :size_t
|
|
584
|
+
attach_function :leptris_element_attribute_name_at,
|
|
585
|
+
[:leptris_element, :size_t], :string
|
|
586
|
+
attach_function :leptris_element_attribute_value_at,
|
|
587
|
+
[:leptris_element, :size_t], :string
|
|
588
|
+
attach_function :leptris_element_remove_all_attributes,
|
|
589
|
+
[:leptris_element], :leptris_status
|
|
590
|
+
|
|
591
|
+
attach_function :leptris_element_child_count,
|
|
592
|
+
[:leptris_element], :size_t
|
|
593
|
+
attach_function :leptris_element_child,
|
|
594
|
+
[:leptris_element, :size_t], :leptris_element
|
|
595
|
+
attach_function :leptris_element_parent,
|
|
596
|
+
[:leptris_element], :leptris_element
|
|
597
|
+
attach_function :leptris_element_root,
|
|
598
|
+
[:leptris_element], :leptris_element
|
|
599
|
+
attach_function :leptris_element_child_value,
|
|
600
|
+
[:leptris_element], :string
|
|
601
|
+
attach_function :leptris_element_hash_value,
|
|
602
|
+
[:leptris_element], :size_t
|
|
603
|
+
attach_function :leptris_element_find_child,
|
|
604
|
+
[:leptris_element, :string], :leptris_element
|
|
605
|
+
attach_function :leptris_element_find_child_by_attr,
|
|
606
|
+
[:leptris_element, :string, :string, :string], :leptris_element
|
|
607
|
+
attach_function :leptris_element_next_sibling,
|
|
608
|
+
[:leptris_element, :string], :leptris_element
|
|
609
|
+
attach_function :leptris_element_previous_sibling,
|
|
610
|
+
[:leptris_element, :string], :leptris_element
|
|
611
|
+
attach_function :leptris_element_first_child,
|
|
612
|
+
[:leptris_element, :string], :leptris_element
|
|
613
|
+
attach_function :leptris_element_last_child,
|
|
614
|
+
[:leptris_element, :string], :leptris_element
|
|
615
|
+
attach_function :leptris_element_first_child_any,
|
|
616
|
+
[:leptris_element], :leptris_element
|
|
617
|
+
attach_function :leptris_element_last_child_any,
|
|
618
|
+
[:leptris_element], :leptris_element
|
|
619
|
+
attach_function :leptris_element_next_sibling_any,
|
|
620
|
+
[:leptris_element], :leptris_element
|
|
621
|
+
attach_function :leptris_element_previous_sibling_any,
|
|
622
|
+
[:leptris_element], :leptris_element
|
|
623
|
+
|
|
624
|
+
attach_function :leptris_element_create,
|
|
625
|
+
[:leptris_document, :string], :leptris_element
|
|
626
|
+
attach_function :leptris_element_set_name,
|
|
627
|
+
[:leptris_element, :string], :leptris_status
|
|
628
|
+
attach_function :leptris_element_set_text,
|
|
629
|
+
[:leptris_element, :string], :leptris_status
|
|
630
|
+
attach_function :leptris_element_set_attribute,
|
|
631
|
+
[:leptris_element, :string, :string], :leptris_status
|
|
632
|
+
attach_function :leptris_element_set_attribute_bool,
|
|
633
|
+
[:leptris_element, :string, :int], :leptris_status
|
|
634
|
+
attach_function :leptris_element_set_attribute_double,
|
|
635
|
+
[:leptris_element, :string, :double], :leptris_status
|
|
636
|
+
attach_function :leptris_element_set_attribute_float,
|
|
637
|
+
[:leptris_element, :string, :float], :leptris_status
|
|
638
|
+
attach_function :leptris_element_set_attribute_int,
|
|
639
|
+
[:leptris_element, :string, :int], :leptris_status
|
|
640
|
+
attach_function :leptris_element_set_attribute_uint,
|
|
641
|
+
[:leptris_element, :string, :uint], :leptris_status
|
|
642
|
+
attach_function :leptris_element_remove_attribute,
|
|
643
|
+
[:leptris_element, :string], :leptris_status
|
|
644
|
+
attach_function :leptris_element_append_child,
|
|
645
|
+
[:leptris_element, :leptris_element], :leptris_status
|
|
646
|
+
# Fused create+append (libleptris 1.9.153): one document
|
|
647
|
+
# resolution, identical tree semantics to the two-call pair.
|
|
648
|
+
attach_function :leptris_element_create_child,
|
|
649
|
+
[:leptris_element, :string], :leptris_element
|
|
650
|
+
attach_function :leptris_element_prepend_child,
|
|
651
|
+
[:leptris_element, :leptris_element], :leptris_status
|
|
652
|
+
attach_function :leptris_element_insert_before,
|
|
653
|
+
[:leptris_element, :leptris_element], :leptris_status
|
|
654
|
+
attach_function :leptris_element_insert_after,
|
|
655
|
+
[:leptris_element, :leptris_element], :leptris_status
|
|
656
|
+
attach_function :leptris_element_remove_child,
|
|
657
|
+
[:leptris_element, :leptris_element], :leptris_status
|
|
658
|
+
attach_function :leptris_element_remove_children,
|
|
659
|
+
[:leptris_element], :leptris_status
|
|
660
|
+
attach_function :leptris_element_append_copy,
|
|
661
|
+
[:leptris_element, :leptris_element], :leptris_element
|
|
662
|
+
attach_function :leptris_element_prepend_copy,
|
|
663
|
+
[:leptris_element, :leptris_element], :leptris_element
|
|
664
|
+
attach_function :leptris_element_insert_copy_before,
|
|
665
|
+
[:leptris_element, :leptris_element], :leptris_element
|
|
666
|
+
attach_function :leptris_element_insert_copy_after,
|
|
667
|
+
[:leptris_element, :leptris_element], :leptris_element
|
|
668
|
+
|
|
669
|
+
attach_function :leptris_element_copy,
|
|
670
|
+
[:leptris_element, :leptris_document], :leptris_element
|
|
671
|
+
attach_function :leptris_document_copy,
|
|
672
|
+
[:leptris_document], :leptris_document
|
|
673
|
+
attach_function :leptris_node_get_xpath,
|
|
674
|
+
[:leptris_node_ref], :pointer
|
|
675
|
+
attach_function :leptris_parse_fragment,
|
|
676
|
+
[:string, :size_t, :leptris_document, :pointer], :leptris_element
|
|
677
|
+
|
|
678
|
+
# Nokogiri node.namespace= parity (libleptris 1.9.76, #817):
|
|
679
|
+
# NULL (or "") detaches — link + prefix clear, xmlns=""
|
|
680
|
+
# undeclaration added; a URI rebinds to an IN-SCOPE
|
|
681
|
+
# declaration carrying it (NOT_FOUND if there is none — this
|
|
682
|
+
# entry does not invent declarations).
|
|
683
|
+
attach_function :leptris_element_set_namespace,
|
|
684
|
+
[:leptris_element, :string], :leptris_status
|
|
685
|
+
attach_function :leptris_element_namespace,
|
|
686
|
+
[:leptris_element], :string
|
|
687
|
+
attach_function :leptris_element_namespace_for_prefix,
|
|
688
|
+
[:leptris_element, :string], :string
|
|
689
|
+
attach_function :leptris_element_namespace_count,
|
|
690
|
+
[:leptris_element], :size_t
|
|
691
|
+
attach_function :leptris_element_namespace_decl_prefix,
|
|
692
|
+
[:leptris_element, :size_t], :string
|
|
693
|
+
attach_function :leptris_element_namespace_decl_uri,
|
|
694
|
+
[:leptris_element, :size_t], :string
|
|
695
|
+
attach_function :leptris_element_add_namespace_definition,
|
|
696
|
+
[:leptris_element, :string, :string], :leptris_status
|
|
697
|
+
attach_function :leptris_element_set_default_namespace,
|
|
698
|
+
[:leptris_element, :string], :leptris_status
|
|
699
|
+
attach_function :leptris_element_remove_namespace_definition,
|
|
700
|
+
[:leptris_element, :string], :leptris_status
|
|
701
|
+
attach_function :leptris_namespace_uri, [:string], :string
|
|
702
|
+
attach_function :leptris_namespace_prefix, [:string], :string
|
|
703
|
+
|
|
704
|
+
attach_function :leptris_xpath_eval,
|
|
705
|
+
[:leptris_document, :leptris_element, :string], :leptris_xpath_result
|
|
706
|
+
attach_function :leptris_xpath_eval_with_vars,
|
|
707
|
+
[:leptris_document, :string, :leptris_xpath_var_set], :leptris_xpath_result
|
|
708
|
+
# Union semantics (NodeSet#xpath): N contexts, ONE call — the
|
|
709
|
+
# engine merges the per-context results into a de-duplicated,
|
|
710
|
+
# document-ordered nodeset (libleptris 1.9.7, upstream #589).
|
|
711
|
+
attach_function :leptris_xpath_eval_nodeset,
|
|
712
|
+
[:leptris_document, :pointer, :size_t, :string], :leptris_xpath_result
|
|
713
|
+
attach_function :leptris_xpath_compiled_eval_nodeset,
|
|
714
|
+
[:leptris_document, :pointer, :size_t, :leptris_xpath_compiled],
|
|
715
|
+
:leptris_xpath_result
|
|
716
|
+
attach_function :leptris_xpath_eval_with_vars_context,
|
|
717
|
+
[:leptris_document, :leptris_element, :string, :leptris_xpath_var_set],
|
|
718
|
+
:leptris_xpath_result
|
|
719
|
+
attach_function :leptris_xpath_result_type,
|
|
720
|
+
[:leptris_xpath_result], :int
|
|
721
|
+
attach_function :leptris_xpath_result_count,
|
|
722
|
+
[:leptris_xpath_result], :size_t
|
|
723
|
+
# Mixed nodesets (v1.1.0): unlike result_get (elements only),
|
|
724
|
+
# get_node returns the node whatever its kind; node_kind reports
|
|
725
|
+
# which (element / synthetic attribute / text / other).
|
|
726
|
+
attach_function :leptris_xpath_result_node_kind,
|
|
727
|
+
[:leptris_xpath_result, :size_t], :int
|
|
728
|
+
# Pre-_ex variants, superseded by xpath_result_get_nodes_ex /
|
|
729
|
+
# xpath_result_get_node; mirror-only (ADR 0001).
|
|
730
|
+
attach_function :leptris_xpath_result_get,
|
|
731
|
+
[:leptris_xpath_result, :size_t], :leptris_element
|
|
732
|
+
attach_function :leptris_xpath_result_get_nodes,
|
|
733
|
+
[:leptris_xpath_result, :pointer, :size_t], :size_t
|
|
734
|
+
attach_function :leptris_xpath_result_get_node,
|
|
735
|
+
[:leptris_xpath_result, :size_t], :leptris_node_ref
|
|
736
|
+
attach_function :leptris_xpath_result_node_name,
|
|
737
|
+
[:leptris_xpath_result, :size_t], :string
|
|
738
|
+
attach_function :leptris_xpath_result_node_value,
|
|
739
|
+
[:leptris_xpath_result, :size_t], :string
|
|
740
|
+
# Document-scoped custom XPath functions. The callback receives
|
|
741
|
+
# (const char* const* args, int argc, void* user_data) and returns
|
|
742
|
+
# a heap string the library frees.
|
|
743
|
+
attach_function :leptris_xpath_register_function,
|
|
744
|
+
[:leptris_document, :string, :pointer, :pointer], :leptris_status
|
|
745
|
+
# v1.3.0: copies ALL node kinds in one call, optionally
|
|
746
|
+
# reporting per-entry kinds.
|
|
747
|
+
attach_function :leptris_xpath_result_get_nodes_ex,
|
|
748
|
+
[:leptris_xpath_result, :pointer, :pointer, :size_t], :size_t
|
|
749
|
+
attach_function :leptris_xpath_result_boolean,
|
|
750
|
+
[:leptris_xpath_result], :int
|
|
751
|
+
attach_function :leptris_xpath_result_number,
|
|
752
|
+
[:leptris_xpath_result], :double
|
|
753
|
+
attach_function :leptris_xpath_result_string,
|
|
754
|
+
[:leptris_xpath_result], :pointer
|
|
755
|
+
attach_function :leptris_xpath_result_free,
|
|
756
|
+
[:leptris_xpath_result], :void
|
|
757
|
+
attach_function :leptris_xpath_function_supported, [:string], :int
|
|
758
|
+
attach_function :leptris_xpath_supported_functions, [], :pointer
|
|
759
|
+
|
|
760
|
+
attach_function :leptris_xpath_variable_set_new,
|
|
761
|
+
[], :leptris_xpath_var_set
|
|
762
|
+
attach_function :leptris_xpath_variable_set_free,
|
|
763
|
+
[:leptris_xpath_var_set], :void
|
|
764
|
+
attach_function :leptris_xpath_variable_set_boolean,
|
|
765
|
+
[:leptris_xpath_var_set, :string, :int], :leptris_status
|
|
766
|
+
attach_function :leptris_xpath_variable_set_number,
|
|
767
|
+
[:leptris_xpath_var_set, :string, :double], :leptris_status
|
|
768
|
+
attach_function :leptris_xpath_variable_set_string,
|
|
769
|
+
[:leptris_xpath_var_set, :string, :string], :leptris_status
|
|
770
|
+
|
|
771
|
+
# Namespace-bound XPath (v1.2.0): expression prefixes resolve to
|
|
772
|
+
# caller-supplied URIs regardless of the document's declarations.
|
|
773
|
+
attach_function :leptris_xpath_ns_set_new,
|
|
774
|
+
[], :leptris_xpath_ns_set
|
|
775
|
+
attach_function :leptris_xpath_ns_set_free,
|
|
776
|
+
[:leptris_xpath_ns_set], :void
|
|
777
|
+
# One-call constructor: flat array of 2*pair_count alternating
|
|
778
|
+
# prefix/URI strings.
|
|
779
|
+
# Per-pair add; superseded by ns_set_new_from_pairs (one call);
|
|
780
|
+
# mirror-only (ADR 0001).
|
|
781
|
+
attach_function :leptris_xpath_ns_set_add,
|
|
782
|
+
[:leptris_xpath_ns_set, :string, :string], :leptris_status
|
|
783
|
+
attach_function :leptris_xpath_ns_set_new_from_pairs,
|
|
784
|
+
[:pointer, :size_t], :leptris_xpath_ns_set
|
|
785
|
+
attach_function :leptris_xpath_eval_ns,
|
|
786
|
+
[:leptris_document, :leptris_element, :string, :leptris_xpath_ns_set],
|
|
787
|
+
:leptris_xpath_result
|
|
788
|
+
# Compiled expressions (v1.6.0): parse once, evaluate many.
|
|
789
|
+
attach_function :leptris_xpath_compile,
|
|
790
|
+
[:string], :leptris_xpath_compiled
|
|
791
|
+
attach_function :leptris_xpath_compiled_eval,
|
|
792
|
+
[:leptris_xpath_compiled, :leptris_document, :leptris_element],
|
|
793
|
+
:leptris_xpath_result
|
|
794
|
+
attach_function :leptris_xpath_compiled_eval_ns,
|
|
795
|
+
[:leptris_xpath_compiled, :leptris_document, :leptris_element,
|
|
796
|
+
:leptris_xpath_ns_set], :leptris_xpath_result
|
|
797
|
+
attach_function :leptris_xpath_compiled_eval_vars,
|
|
798
|
+
[:leptris_xpath_compiled, :leptris_document, :leptris_element,
|
|
799
|
+
:leptris_xpath_var_set], :leptris_xpath_result
|
|
800
|
+
# Combined namespaces + variables (1.9.18, upstream #608).
|
|
801
|
+
attach_function :leptris_xpath_compiled_eval_ns_vars,
|
|
802
|
+
[:leptris_xpath_compiled, :leptris_document, :leptris_element,
|
|
803
|
+
:leptris_xpath_ns_set, :leptris_xpath_var_set],
|
|
804
|
+
:leptris_xpath_result
|
|
805
|
+
# Source text of a compiled expression (owned by the handle).
|
|
806
|
+
attach_function :leptris_xpath_compiled_text,
|
|
807
|
+
[:leptris_xpath_compiled], :string
|
|
808
|
+
attach_function :leptris_xpath_compiled_free,
|
|
809
|
+
|
|
810
|
+
[:leptris_xpath_compiled], :void
|
|
811
|
+
attach_function :leptris_sax_parse,
|
|
812
|
+
[:string, :size_t, :pointer, :pointer], :int
|
|
813
|
+
attach_function :leptris_sax_parser_create,
|
|
814
|
+
[:pointer, :pointer], :leptris_sax_parser
|
|
815
|
+
attach_function :leptris_sax_parser_feed,
|
|
816
|
+
[:leptris_sax_parser, :string, :size_t, :int], :int
|
|
817
|
+
# Chunked event recorder (libleptris 1.9.4, #585): buffers
|
|
818
|
+
# events C-side (fixed records + packed arena); the host
|
|
819
|
+
# drains in bulk — callbacks become O(chunks), not O(events).
|
|
820
|
+
attach_function :leptris_sax_recorder_new,
|
|
821
|
+
[], :leptris_sax_recorder
|
|
822
|
+
attach_function :leptris_sax_recorder_feed,
|
|
823
|
+
[:leptris_sax_recorder, :string, :size_t, :int], :int
|
|
824
|
+
attach_function :leptris_sax_recorder_records,
|
|
825
|
+
[:leptris_sax_recorder, :pointer], :pointer
|
|
826
|
+
attach_function :leptris_sax_recorder_arena,
|
|
827
|
+
[:leptris_sax_recorder, :pointer], :pointer
|
|
828
|
+
# Reuse across documents (1.9.10, #594): swaps in fresh parser
|
|
829
|
+
# state, RETAINS the record/arena buffers — a
|
|
830
|
+
# one-document-per-parse loop stops paying new/free churn.
|
|
831
|
+
attach_function :leptris_sax_recorder_reset,
|
|
832
|
+
[:leptris_sax_recorder], :int
|
|
833
|
+
attach_function :leptris_sax_recorder_free,
|
|
834
|
+
[:leptris_sax_recorder], :void
|
|
835
|
+
attach_function :leptris_sax_parser_free,
|
|
836
|
+
[:leptris_sax_parser], :void
|
|
837
|
+
attach_function :leptris_sax_parser_set_streaming,
|
|
838
|
+
[:leptris_sax_parser, :int], :int
|
|
839
|
+
|
|
840
|
+
# Pull parsing (v1.6.0): StAX-style cursor over a document.
|
|
841
|
+
attach_function :leptris_pull_new,
|
|
842
|
+
[:string, :size_t], :leptris_pull_parser
|
|
843
|
+
attach_function :leptris_pull_new_file,
|
|
844
|
+
[:string], :leptris_pull_parser
|
|
845
|
+
attach_function :leptris_pull_next,
|
|
846
|
+
[:leptris_pull_parser], :pointer
|
|
847
|
+
attach_function :leptris_pull_next_batch,
|
|
848
|
+
[:leptris_pull_parser, :pointer, :size_t], :size_t
|
|
849
|
+
attach_function :leptris_pull_attr_count,
|
|
850
|
+
[:leptris_pull_parser], :size_t
|
|
851
|
+
attach_function :leptris_pull_attr_name,
|
|
852
|
+
[:leptris_pull_parser, :size_t], :string
|
|
853
|
+
attach_function :leptris_pull_attr_value,
|
|
854
|
+
[:leptris_pull_parser, :size_t], :string
|
|
855
|
+
attach_function :leptris_pull_attrs,
|
|
856
|
+
[:leptris_pull_parser, :pointer, :size_t], :size_t
|
|
857
|
+
attach_function :leptris_pull_free,
|
|
858
|
+
[:leptris_pull_parser], :void
|
|
859
|
+
|
|
860
|
+
# Iterparse (v1.6.0): yields each completed top-level child
|
|
861
|
+
# element; the previous subtree is released on each next call.
|
|
862
|
+
attach_function :leptris_iterparse_new,
|
|
863
|
+
[:string, :size_t], :leptris_iterparse
|
|
864
|
+
attach_function :leptris_iterparse_new_file,
|
|
865
|
+
[:string], :leptris_iterparse
|
|
866
|
+
attach_function :leptris_iterparse_next,
|
|
867
|
+
[:leptris_iterparse], :leptris_element
|
|
868
|
+
# iterparse v2 (libleptris 1.9.4, #586): explicit yield mode
|
|
869
|
+
# (top-level children or full-document post-order), namespace
|
|
870
|
+
# resolution on the last yielded element, error channel.
|
|
871
|
+
attach_function :leptris_iterparse_new_ex,
|
|
872
|
+
[:string, :size_t, :int], :leptris_iterparse
|
|
873
|
+
attach_function :leptris_iterparse_new_file_ex,
|
|
874
|
+
[:string, :int], :leptris_iterparse
|
|
875
|
+
attach_function :leptris_iterparse_ns_count,
|
|
876
|
+
[:leptris_iterparse], :size_t
|
|
877
|
+
attach_function :leptris_iterparse_ns_uri,
|
|
878
|
+
[:leptris_iterparse, :string], :string
|
|
879
|
+
attach_function :leptris_iterparse_error,
|
|
880
|
+
[:leptris_iterparse], :string
|
|
881
|
+
attach_function :leptris_iterparse_free,
|
|
882
|
+
[:leptris_iterparse], :void
|
|
883
|
+
|
|
884
|
+
attach_function :leptris_document_serialize,
|
|
885
|
+
[:leptris_document, :pointer], :pointer
|
|
886
|
+
# Deprecated automatic-options alias (header: prefer
|
|
887
|
+
# leptris_document_serialize); mirror-only.
|
|
888
|
+
attach_function :leptris_serialize_document,
|
|
889
|
+
[:leptris_document], :pointer
|
|
890
|
+
# libleptris >= 1.9.0: caller-buffer serialization with options
|
|
891
|
+
# (leptris#541). buf=NULL is a size query; the size-query +
|
|
892
|
+
# fill pair reuses one serialization through a per-document
|
|
893
|
+
# cache invalidated on mutation.
|
|
894
|
+
# Display-form variant (1.9.9, #129): the ext struct carries
|
|
895
|
+
# indent_text; returns an OWNED string — read via
|
|
896
|
+
# read_owned_string (the seam frees it).
|
|
897
|
+
attach_function :leptris_document_serialize_ext,
|
|
898
|
+
[:leptris_document, :pointer, :pointer], :pointer
|
|
899
|
+
# Sized variant (1.9.19, upstream #644 — leptris-ruby PR #107):
|
|
900
|
+
# passing our ext-struct size keeps the engine from reading
|
|
901
|
+
# past this binding's allocation (the MSVC segfault).
|
|
902
|
+
attach_function :leptris_document_serialize_ext_sized,
|
|
903
|
+
[:leptris_document, :pointer, :pointer, :size_t], :pointer
|
|
904
|
+
attach_function :leptris_document_serialize_into,
|
|
905
|
+
[:leptris_document, :pointer, :size_t, :pointer, :pointer], :size_t
|
|
906
|
+
attach_function :leptris_document_get_dtd,
|
|
907
|
+
[:leptris_document], :pointer
|
|
908
|
+
# Element-level ext serialization (libleptris 1.9.95, #882):
|
|
909
|
+
# the document ext option surface (indent_text, indent_unit,
|
|
910
|
+
# expand_empty) at element level. The sized twin is the
|
|
911
|
+
# FFI-safe form (older ext allocations read within bounds).
|
|
912
|
+
attach_function :leptris_element_serialize_ext,
|
|
913
|
+
[:leptris_element, :pointer, :pointer], :pointer
|
|
914
|
+
attach_function :leptris_element_serialize_ext_sized,
|
|
915
|
+
[:leptris_element, :pointer, :pointer, :size_t], :pointer
|
|
916
|
+
|
|
917
|
+
# Content-defined Merkle digest of a subtree (libleptris
|
|
918
|
+
# 1.9.99, #869): equal flags + equal digests imply structural
|
|
919
|
+
# equivalence (descend to decide on inequality); flags bit 1
|
|
920
|
+
# (DROP_WS_TEXT) skips whitespace-only text nodes.
|
|
921
|
+
attach_function :leptris_node_digest,
|
|
922
|
+
[:leptris_node_ref, :int], :uint64
|
|
923
|
+
|
|
924
|
+
attach_function :leptris_element_serialize,
|
|
925
|
+
[:leptris_element, :pointer], :pointer
|
|
926
|
+
attach_function :leptris_element_serialize_into,
|
|
927
|
+
[:leptris_element, :pointer, :size_t, :pointer, :pointer], :size_t
|
|
928
|
+
attach_function :leptris_document_save_file,
|
|
929
|
+
[:leptris_document, :string, :pointer], :leptris_status
|
|
930
|
+
# XSLT 1.0 engine (libleptris 1.9.1): compile once, apply many.
|
|
931
|
+
# XQuery 1.0 core (libleptris 1.9.64-1.9.66): orchestration
|
|
932
|
+
# over the XPath engine — prolog (declare variable/namespace/
|
|
933
|
+
# function local:*), FLWOR, computed and direct constructors.
|
|
934
|
+
# Results reuse the XPath result handle (free with
|
|
935
|
+
# leptris_xpath_result_free); context_node NULL = document.
|
|
936
|
+
attach_function :leptris_xquery_parse,
|
|
937
|
+
[:string, :size_t], :leptris_xquery
|
|
938
|
+
attach_function :leptris_xquery_eval,
|
|
939
|
+
[:leptris_xquery, :leptris_document, :leptris_element],
|
|
940
|
+
:leptris_xpath_result
|
|
941
|
+
# External-variable XQuery evaluation (libleptris 1.9.133):
|
|
942
|
+
# names[i]/selects[i] bind `declare variable $name external`
|
|
943
|
+
# — each select is an XPath expression in an empty context
|
|
944
|
+
# (QT3 <param select> semantics), overriding any default
|
|
945
|
+
# initializer. An external with neither binding nor default
|
|
946
|
+
# fails evaluation.
|
|
947
|
+
attach_function :leptris_xquery_eval_params,
|
|
948
|
+
[:leptris_xquery, :leptris_document, :leptris_element,
|
|
949
|
+
:pointer, :pointer, :size_t], :leptris_xpath_result
|
|
950
|
+
attach_function :leptris_xquery_free, [:leptris_xquery], :void
|
|
951
|
+
|
|
952
|
+
# Schematron validation (libleptris >= 1.9.126 family):
|
|
953
|
+
# parse once (optionally selecting a PHASE), validate any
|
|
954
|
+
# number of documents — #validate returns the SVRL report as
|
|
955
|
+
# a Document; #valid? answers through the SVRL root name.
|
|
956
|
+
attach_function :leptris_schematron_parse,
|
|
957
|
+
[:string, :size_t, :pointer], :leptris_schematron
|
|
958
|
+
attach_function :leptris_schematron_parse_file,
|
|
959
|
+
[:string, :pointer], :leptris_schematron
|
|
960
|
+
attach_function :leptris_schematron_parse_phase,
|
|
961
|
+
[:string, :size_t, :string, :pointer], :leptris_schematron
|
|
962
|
+
attach_function :leptris_schematron_free,
|
|
963
|
+
[:leptris_schematron], :void
|
|
964
|
+
attach_function :leptris_schematron_valid,
|
|
965
|
+
[:leptris_schematron, :leptris_document], :int
|
|
966
|
+
attach_function :leptris_schematron_validate,
|
|
967
|
+
[:leptris_schematron, :leptris_document], :leptris_document
|
|
968
|
+
attach_function :leptris_schematron_error,
|
|
969
|
+
[:leptris_schematron], :string
|
|
970
|
+
|
|
971
|
+
# Tree diff (libleptris >= 1.9.126 family): equal subtrees
|
|
972
|
+
# prune in O(1) by the #869 Merkle digest; diverging regions
|
|
973
|
+
# align via LCS on child digests, then recurse by name.
|
|
974
|
+
attach_function :leptris_diff,
|
|
975
|
+
[:leptris_document, :leptris_document, :int, :pointer],
|
|
976
|
+
:leptris_diff
|
|
977
|
+
attach_function :leptris_diff_free, [:leptris_diff], :void
|
|
978
|
+
attach_function :leptris_diff_op_count, [:leptris_diff], :size_t
|
|
979
|
+
attach_function :leptris_diff_op_type,
|
|
980
|
+
[:leptris_diff, :size_t], :int
|
|
981
|
+
attach_function :leptris_diff_op_name,
|
|
982
|
+
[:leptris_diff, :size_t], :string
|
|
983
|
+
attach_function :leptris_diff_op_path,
|
|
984
|
+
[:leptris_diff, :size_t], :string
|
|
985
|
+
attach_function :leptris_diff_op_before,
|
|
986
|
+
[:leptris_diff, :size_t], :string
|
|
987
|
+
attach_function :leptris_diff_op_after,
|
|
988
|
+
[:leptris_diff, :size_t], :string
|
|
989
|
+
attach_function :leptris_diff_serialize,
|
|
990
|
+
[:leptris_diff], :pointer
|
|
991
|
+
|
|
992
|
+
# One-call expanded name (libleptris 1.9.144): local name +
|
|
993
|
+
# prefix + resolved namespace URI in a single entry — the
|
|
994
|
+
# FFI-adapter fan-out read.
|
|
995
|
+
attach_function :leptris_element_expanded_name,
|
|
996
|
+
[:leptris_element, :pointer, :pointer, :pointer], :void
|
|
997
|
+
|
|
998
|
+
# Versioned XPath evaluation (libleptris lane 15): XPATH_10
|
|
999
|
+
# keeps the strict 1.0 surface (3.x syntax rejected with
|
|
1000
|
+
# INVALID_ARG); XPATH_31 evaluates the full grammar.
|
|
1001
|
+
attach_function :leptris_xpath_eval_versioned,
|
|
1002
|
+
[:leptris_document, :leptris_element, :string, :int, :pointer],
|
|
1003
|
+
:leptris_xpath_result
|
|
1004
|
+
XPATH_10 = 1 # strict XPath 1.0: the 3.x surface is rejected
|
|
1005
|
+
XPATH_31 = 3 # the full grammar (the default entry's surface)
|
|
1006
|
+
|
|
1007
|
+
# One-pass entity pre-scan (libleptris 1.9.62, leptris#745):
|
|
1008
|
+
# 1 when the buffer holds a named entity that is not one of
|
|
1009
|
+
# the five predefined XML entities (nor numeric) — the moxml
|
|
1010
|
+
# pre-scan at C speed instead of a Ruby regex.
|
|
1011
|
+
attach_function :leptris_str_has_nonstandard_entity,
|
|
1012
|
+
[:string, :size_t], :int
|
|
1013
|
+
|
|
1014
|
+
attach_function :leptris_rng_parse,
|
|
1015
|
+
[:string, :size_t, :pointer], :leptris_relaxng
|
|
1016
|
+
attach_function :leptris_rng_parse_file,
|
|
1017
|
+
[:string, :pointer], :leptris_relaxng
|
|
1018
|
+
attach_function :leptris_rng_free,
|
|
1019
|
+
[:leptris_relaxng], :void
|
|
1020
|
+
# 1 valid; 0 invalid (detail via leptris_rng_error)
|
|
1021
|
+
attach_function :leptris_rng_validate,
|
|
1022
|
+
[:leptris_relaxng, :leptris_document], :int
|
|
1023
|
+
attach_function :leptris_rng_error,
|
|
1024
|
+
[:leptris_relaxng], :string
|
|
1025
|
+
# Accumulated validation errors (libleptris 1.9.179, #878):
|
|
1026
|
+
# the validator no longer stops at the first failure;
|
|
1027
|
+
# leptris_rng_error keeps returning the first (back-compat).
|
|
1028
|
+
attach_function :leptris_rng_error_count,
|
|
1029
|
+
[:leptris_relaxng], :size_t
|
|
1030
|
+
attach_function :leptris_rng_error_message,
|
|
1031
|
+
[:leptris_relaxng, :size_t], :string
|
|
1032
|
+
attach_function :leptris_rng_error_line,
|
|
1033
|
+
[:leptris_relaxng, :size_t], :int
|
|
1034
|
+
attach_function :leptris_rng_error_column,
|
|
1035
|
+
[:leptris_relaxng, :size_t], :int
|
|
1036
|
+
|
|
1037
|
+
# Whole-report face (libleptris 1.9.190): one call returns
|
|
1038
|
+
# every record — kind (the #1126 failure-class taxonomy) and
|
|
1039
|
+
# offender were unreachable through the per-index accessors.
|
|
1040
|
+
# Record array is handle-owned; strings live until the next
|
|
1041
|
+
# validate call or leptris_rng_free.
|
|
1042
|
+
class RngErrorRecord < ::FFI::Struct
|
|
1043
|
+
layout :kind, :string,
|
|
1044
|
+
:message, :string,
|
|
1045
|
+
:offender, :string,
|
|
1046
|
+
:line, :uint,
|
|
1047
|
+
:column, :uint
|
|
1048
|
+
end
|
|
1049
|
+
attach_function :leptris_rng_error_report,
|
|
1050
|
+
[:leptris_relaxng, :pointer], :size_t
|
|
1051
|
+
|
|
1052
|
+
attach_function :leptris_xslt_parse,
|
|
1053
|
+
[:string, :size_t], :leptris_xslt
|
|
1054
|
+
attach_function :leptris_xslt_parse_file,
|
|
1055
|
+
[:string], :leptris_xslt
|
|
1056
|
+
attach_function :leptris_xslt_free,
|
|
1057
|
+
[:leptris_xslt], :void
|
|
1058
|
+
# Result tree is a document (free with document_free); errors
|
|
1059
|
+
# surface via document_last_error on NULL.
|
|
1060
|
+
attach_function :leptris_xslt_apply,
|
|
1061
|
+
[:leptris_xslt, :leptris_document], :leptris_document
|
|
1062
|
+
# apply + serialize in one call, keeping top-level text nodes
|
|
1063
|
+
# and result fragments the tree API would flatten.
|
|
1064
|
+
attach_function :leptris_xslt_apply_string,
|
|
1065
|
+
[:leptris_xslt, :leptris_document], :pointer
|
|
1066
|
+
attach_function :leptris_c14n_canonicalize,
|
|
1067
|
+
|
|
1068
|
+
[:leptris_document, :int, :int], :pointer
|
|
1069
|
+
attach_function :leptris_c14n_canonicalize_subtree,
|
|
1070
|
+
[:leptris_element, :int, :int], :pointer
|
|
1071
|
+
attach_function :leptris_c14n_canonicalize_ex,
|
|
1072
|
+
[:leptris_document, :int, :int, :pointer, :int], :pointer
|
|
1073
|
+
attach_function :leptris_c14n_canonicalize_subtree_ex,
|
|
1074
|
+
[:leptris_element, :int, :int, :pointer, :int], :pointer
|
|
1075
|
+
|
|
1076
|
+
attach_function :leptris_document_internal_subset,
|
|
1077
|
+
[:leptris_document], :leptris_doctype
|
|
1078
|
+
attach_function :leptris_doctype_get_name,
|
|
1079
|
+
[:leptris_doctype], :string
|
|
1080
|
+
attach_function :leptris_doctype_get_root_name,
|
|
1081
|
+
[:leptris_doctype], :string
|
|
1082
|
+
attach_function :leptris_doctype_get_public_id,
|
|
1083
|
+
[:leptris_doctype], :string
|
|
1084
|
+
attach_function :leptris_doctype_get_system_id,
|
|
1085
|
+
[:leptris_doctype], :string
|
|
1086
|
+
attach_function :leptris_doctype_get_internal_subset,
|
|
1087
|
+
[:leptris_doctype], :string
|
|
1088
|
+
|
|
1089
|
+
attach_function :leptris_free_string, [:pointer], :void
|
|
1090
|
+
attach_function :leptris_explicit_cleanup, [], :void
|
|
1091
|
+
attach_function :leptris_set_memory_management_functions,
|
|
1092
|
+
[:pointer, :pointer], :void
|
|
1093
|
+
attach_function :leptris_get_memory_allocation_function, [], :pointer
|
|
1094
|
+
attach_function :leptris_get_memory_deallocation_function, [], :pointer
|
|
1095
|
+
attach_function :leptris_document_set_allocators,
|
|
1096
|
+
[:leptris_document, :pointer, :pointer], :leptris_status
|
|
1097
|
+
attach_function :leptris_status_string, [:leptris_status], :string
|
|
1098
|
+
attach_function :leptris_error_message, [:leptris_status], :string
|
|
1099
|
+
# Thread-global last-failure position (error.h): companion to
|
|
1100
|
+
# leptris_last_error; populated by recover parses (#547).
|
|
1101
|
+
attach_function :leptris_last_error_position,
|
|
1102
|
+
[:pointer, :pointer], :void
|
|
1103
|
+
# Thread-local since v1.3.0; reliable under the
|
|
1104
|
+
# one-document-per-thread contract.
|
|
1105
|
+
attach_function :leptris_last_error, [], :string
|
|
1106
|
+
attach_function :leptris_document_last_error,
|
|
1107
|
+
[:leptris_document], :string
|
|
1108
|
+
# Optional: release per-thread registry entries when a worker
|
|
1109
|
+
# thread exits (long-lived threads never need it).
|
|
1110
|
+
attach_function :leptris_thread_cleanup, [], :void
|
|
1111
|
+
# First-party EXSLT-style extension pack (str:/set:/math:),
|
|
1112
|
+
# registered natively on one document.
|
|
1113
|
+
attach_function :leptris_exslt_enable,
|
|
1114
|
+
[:leptris_document], :leptris_status
|
|
1115
|
+
|
|
1116
|
+
LEPTRIS_OK = 0
|
|
1117
|
+
LEPTRIS_ERROR_MEMORY = -1
|
|
1118
|
+
LEPTRIS_ERROR_PARSE = -2
|
|
1119
|
+
LEPTRIS_ERROR_XPATH = -3
|
|
1120
|
+
LEPTRIS_ERROR_NULL_ARG = -4
|
|
1121
|
+
LEPTRIS_ERROR_INVALID_ARG = -5
|
|
1122
|
+
LEPTRIS_ERROR_NOT_FOUND = -6
|
|
1123
|
+
LEPTRIS_ERROR_IO = -7
|
|
1124
|
+
LEPTRIS_ERROR_NOT_IMPLEMENTED = -8
|
|
1125
|
+
|
|
1126
|
+
XPATH_NODESET = 0
|
|
1127
|
+
XPATH_BOOLEAN = 1
|
|
1128
|
+
XPATH_NUMBER = 2
|
|
1129
|
+
XPATH_STRING = 3
|
|
1130
|
+
# XPath 3.0 function item (libleptris TODO 07 lane): a closure
|
|
1131
|
+
# or named function reference. Not callable across the FFI
|
|
1132
|
+
# boundary yet — wrap_xpath_result raises explicitly.
|
|
1133
|
+
XPATH_FUNCTION = 4
|
|
1134
|
+
|
|
1135
|
+
XPATH_NODE_ELEMENT = 0
|
|
1136
|
+
XPATH_NODE_ATTRIBUTE = 1
|
|
1137
|
+
XPATH_NODE_TEXT = 2
|
|
1138
|
+
XPATH_NODE_OTHER = 3
|
|
1139
|
+
|
|
1140
|
+
NODE_ELEMENT = 0
|
|
1141
|
+
NODE_TEXT = 1
|
|
1142
|
+
NODE_COMMENT = 2
|
|
1143
|
+
NODE_CDATA = 3
|
|
1144
|
+
NODE_PI = 4
|
|
1145
|
+
NODE_ENTITY_REF = 10
|
|
1146
|
+
# Internal XPath-synthetic text node (leptris/types.h): the
|
|
1147
|
+
# carrier for sequence/map/array items in result nodesets —
|
|
1148
|
+
# readable only through the result handle, so the binding
|
|
1149
|
+
# captures the value at materialization (ResultText).
|
|
1150
|
+
NODE_SYNTHETIC_TEXT = 8
|
|
1151
|
+
# #1094: &name; references stay unexpanded first-class nodes
|
|
1152
|
+
# when this flag parses (character references still expand).
|
|
1153
|
+
LEPTRIS_PARSE_KEEP_ENTITY_REFS = 4
|
|
1154
|
+
NODE_DOCTYPE = 5
|
|
1155
|
+
NODE_ATTRIBUTE = 6
|
|
1156
|
+
|
|
1157
|
+
C14N_1_0 = 0
|
|
1158
|
+
C14N_1_1 = 1
|
|
1159
|
+
|
|
1160
|
+
C14N_MODE_CANONICAL = 0
|
|
1161
|
+
C14N_MODE_EXCLUSIVE = 1
|
|
1162
|
+
|
|
1163
|
+
TRAVERSE_PRE_ORDER = 0
|
|
1164
|
+
TRAVERSE_POST_ORDER = 1
|
|
1165
|
+
|
|
1166
|
+
PULL_START_ELEMENT = 0
|
|
1167
|
+
PULL_END_ELEMENT = 1
|
|
1168
|
+
PULL_TEXT = 2
|
|
1169
|
+
PULL_COMMENT = 3
|
|
1170
|
+
PULL_CDATA = 4
|
|
1171
|
+
PULL_PI = 5
|
|
1172
|
+
PULL_END_DOCUMENT = 6
|
|
1173
|
+
PULL_ERROR = 7
|
|
1174
|
+
# Prefix events (types.h LeptrisPullEventType 8/9): the
|
|
1175
|
+
# default namespace's prefix is legitimately "".
|
|
1176
|
+
PULL_START_PREFIX = 8
|
|
1177
|
+
PULL_END_PREFIX = 9
|
|
1178
|
+
|
|
1179
|
+
LEPTRIS_PARSE_DEFAULT = 0
|
|
1180
|
+
LEPTRIS_PARSE_DROP_WS_TEXT = 1
|
|
1181
|
+
# libleptris >= 1.9.8 (#606): apply DTD ATTLIST default (and
|
|
1182
|
+
# #FIXED) attribute values at parse time — libxml2
|
|
1183
|
+
# XML_PARSE_DTDATTR opt-in parity.
|
|
1184
|
+
LEPTRIS_PARSE_DTDATTR = 2
|
|
1185
|
+
|
|
1186
|
+
# The headers' contract is UTF-8 for every C string, but FFI's
|
|
1187
|
+
# read_string hands back ASCII-8BIT — the platform default
|
|
1188
|
+
# leaks through the seam. Every string-returning attached
|
|
1189
|
+
# function this binding CALLS is wrapped here so its result
|
|
1190
|
+
# arrives as UTF-8; mirror-only attachments stay raw (add the
|
|
1191
|
+
# name here when a call site starts using its string).
|
|
1192
|
+
UTF8_RETURNS = %i[
|
|
1193
|
+
leptris_version
|
|
1194
|
+
leptris_status_string leptris_last_error
|
|
1195
|
+
leptris_document_last_error leptris_document_encoding
|
|
1196
|
+
leptris_document_pi_target leptris_document_pi_data
|
|
1197
|
+
leptris_document_comment_content
|
|
1198
|
+
leptris_element_name leptris_element_text leptris_element_prefix
|
|
1199
|
+
leptris_element_namespace
|
|
1200
|
+
leptris_element_attribute leptris_element_attribute_ns
|
|
1201
|
+
leptris_attribute_get_name leptris_attribute_get_value
|
|
1202
|
+
leptris_attribute_namespace_uri
|
|
1203
|
+
leptris_element_namespace_decl_prefix
|
|
1204
|
+
leptris_element_namespace_decl_uri
|
|
1205
|
+
leptris_text_node_get_content leptris_comment_node_get_content
|
|
1206
|
+
leptris_cdata_node_get_content
|
|
1207
|
+
leptris_pi_node_get_target leptris_pi_node_get_data
|
|
1208
|
+
leptris_pull_attr_name leptris_pull_attr_value
|
|
1209
|
+
].freeze
|
|
1210
|
+
private_constant :UTF8_RETURNS
|
|
1211
|
+
|
|
1212
|
+
UTF8_RETURNS.each do |name|
|
|
1213
|
+
raw = method(name)
|
|
1214
|
+
define_singleton_method(name) do |*args|
|
|
1215
|
+
str = raw.call(*args)
|
|
1216
|
+
str.nil? ? nil : str.force_encoding(Encoding::UTF_8)
|
|
1217
|
+
end
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
# Reads an libleptris-owned char* result and frees it as one unit,
|
|
1221
|
+
# so a call site can neither leak nor double-free.
|
|
1222
|
+
def self.read_owned_string(ptr)
|
|
1223
|
+
return "" if ptr.nil? || ptr.null?
|
|
1224
|
+
ptr.read_string.tap { leptris_free_string(ptr) }
|
|
1225
|
+
.force_encoding(Encoding::UTF_8)
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
# Single status seam: turns a C status code into a Ruby error,
|
|
1229
|
+
# appending the library's last-error detail when present. The
|
|
1230
|
+
# detail is a library-global string, so it can only be treated
|
|
1231
|
+
# as best-effort context.
|
|
1232
|
+
def self.check_status(status)
|
|
1233
|
+
unless status == LEPTRIS_OK
|
|
1234
|
+
raise Leptris::XML::Error, status_message(status)
|
|
1235
|
+
end
|
|
1236
|
+
status
|
|
1237
|
+
end
|
|
1238
|
+
|
|
1239
|
+
def self.status_message(status)
|
|
1240
|
+
base = leptris_status_string(status).to_s
|
|
1241
|
+
detail = leptris_last_error.to_s
|
|
1242
|
+
detail.empty? ? base : "#{base} (#{detail})"
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
# Namespace-binding lifecycle, written once: flatten the
|
|
1246
|
+
# prefix/URI hash into the alternating CStringArray wire
|
|
1247
|
+
# format and build the C set. Sets are cached per distinct
|
|
1248
|
+
# vocabulary: the XPath VM reads the set as a const map
|
|
1249
|
+
# during evaluation (vm.c) and never mutates it, so one set
|
|
1250
|
+
# serves the process across queries and threads — building
|
|
1251
|
+
# the wire format plus a C set per query cost ~6.7 µs, 2.6×
|
|
1252
|
+
# a no-namespace query on a small document. Cached sets are
|
|
1253
|
+
# never freed (bounded by the process's distinct namespace
|
|
1254
|
+
# vocabularies — the same trade the CSS translation cache
|
|
1255
|
+
# makes). Failed builds raise before caching.
|
|
1256
|
+
NS_SET_CACHE = {}
|
|
1257
|
+
|
|
1258
|
+
def self.with_ns_set(hash)
|
|
1259
|
+
yield ns_set_for(hash)
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
def self.ns_set_for(hash)
|
|
1263
|
+
pairs = hash.map { |prefix, uri| [prefix.to_s, uri.to_s] }
|
|
1264
|
+
key = if pairs.size == 1
|
|
1265
|
+
"#{pairs[0][0]}\x00#{pairs[0][1]}"
|
|
1266
|
+
else
|
|
1267
|
+
pairs.sort.join("\x00")
|
|
1268
|
+
end
|
|
1269
|
+
NS_SET_CACHE.fetch(key) do
|
|
1270
|
+
flat = pairs.flatten
|
|
1271
|
+
buffer, _anchors = Leptris::XML::CStringArray.to_c(flat)
|
|
1272
|
+
set = leptris_xpath_ns_set_new_from_pairs(buffer, flat.length / 2)
|
|
1273
|
+
if set.null?
|
|
1274
|
+
raise Leptris::XML::Error,
|
|
1275
|
+
"leptris_xpath_ns_set_new_from_pairs failed"
|
|
1276
|
+
end
|
|
1277
|
+
NS_SET_CACHE[key] = set
|
|
1278
|
+
end
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1281
|
+
# Caller-buffer serialization cycle: size query (buf=NULL),
|
|
1282
|
+
# allocate exactly, fill, read. Since libleptris 1.9.0 the
|
|
1283
|
+
# pair reuses one serialization through the per-document
|
|
1284
|
+
# cache. +ffi_function+ is leptris_document_serialize_into or
|
|
1285
|
+
# leptris_element_serialize_into. The buffer holds the
|
|
1286
|
+
# serialization + NUL and XML output is NUL-free, so the
|
|
1287
|
+
# bounded read is exact.
|
|
1288
|
+
# snprintf contract (leptris.h #535): the return is ALWAYS the
|
|
1289
|
+
# bytes needed incl. the NUL; the copy happens only when the
|
|
1290
|
+
# buffer fits. So the size probe is paid only when the child
|
|
1291
|
+
# outgrows the grow-only scratch — one dispatch per call on
|
|
1292
|
+
# the fast path instead of two (inner_html serializes each
|
|
1293
|
+
# child; the probe was most of the per-child FFI cost).
|
|
1294
|
+
SERIALIZE_INITIAL = 256
|
|
1295
|
+
private_constant :SERIALIZE_INITIAL
|
|
1296
|
+
|
|
1297
|
+
def self.serialize_into_string(ffi_function, c_ptr, options)
|
|
1298
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1299
|
+
buffer = scratch[:bytes]
|
|
1300
|
+
if buffer.nil?
|
|
1301
|
+
buffer = scratch[:bytes] =
|
|
1302
|
+
::FFI::MemoryPointer.new(:char, SERIALIZE_INITIAL)
|
|
1303
|
+
end
|
|
1304
|
+
needed = ffi_function.call(c_ptr, buffer, buffer.size, nil, options)
|
|
1305
|
+
if needed > buffer.size
|
|
1306
|
+
buffer = scratch_bytes(needed)
|
|
1307
|
+
needed = ffi_function.call(c_ptr, buffer, buffer.size, nil, options)
|
|
1308
|
+
end
|
|
1309
|
+
return "" if needed <= 1
|
|
1310
|
+
buffer.read_string(needed - 1).force_encoding(Encoding::UTF_8)
|
|
1311
|
+
end
|
|
1312
|
+
|
|
1313
|
+
# Byte scratch for serialize-into cycles: the size+fill pair
|
|
1314
|
+
# allocated and freed a buffer per call — inner_html
|
|
1315
|
+
# serializes each child, and the allocation was most of the
|
|
1316
|
+
# per-child cost. Grows to the largest serialization seen;
|
|
1317
|
+
# no Ruby reentrancy during a serialize call.
|
|
1318
|
+
def self.scratch_bytes(need)
|
|
1319
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1320
|
+
ptr = scratch[:bytes]
|
|
1321
|
+
if ptr.nil? || ptr.size < need
|
|
1322
|
+
ptr&.free
|
|
1323
|
+
ptr = scratch[:bytes] = ::FFI::MemoryPointer.new(:char, need)
|
|
1324
|
+
end
|
|
1325
|
+
ptr
|
|
1326
|
+
end
|
|
1327
|
+
|
|
1328
|
+
# All-kind child handle batch (libleptris 1.7.0). Opportunistic
|
|
1329
|
+
# single dispatch: the C call copies up to the capacity handed
|
|
1330
|
+
# it and returns what fit, so the count query is paid only when
|
|
1331
|
+
# the buffer fills exactly (a possible truncation) — families
|
|
1332
|
+
# that fit the scratch buffer cost ONE dispatch, not two.
|
|
1333
|
+
FETCH_INITIAL = 32
|
|
1334
|
+
private_constant :FETCH_INITIAL
|
|
1335
|
+
|
|
1336
|
+
# Returns [pointers, kinds] — the kinds ride the batch
|
|
1337
|
+
# (leptris_node_children_ex, 1.9.18 #617) so wrappers skip
|
|
1338
|
+
# the per-child get_type dispatch.
|
|
1339
|
+
def self.fetch_children(c_ptr)
|
|
1340
|
+
# One thread-local access serves both buffers (the helper
|
|
1341
|
+
# re-looked it up); the kinds buffer sizes from the POINTERS
|
|
1342
|
+
# buffer's capacity — it may have grown past FETCH_INITIAL on
|
|
1343
|
+
# earlier use, and C writes one kind per copied child.
|
|
1344
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1345
|
+
buffer = scratch[:pointers]
|
|
1346
|
+
if buffer.nil?
|
|
1347
|
+
buffer = scratch[:pointers] =
|
|
1348
|
+
::FFI::MemoryPointer.new(:pointer, FETCH_INITIAL)
|
|
1349
|
+
end
|
|
1350
|
+
cap = buffer.size / PTR_BYTES
|
|
1351
|
+
kinds = scratch[:ints]
|
|
1352
|
+
if kinds.nil? || kinds.size / INT_BYTES < cap
|
|
1353
|
+
kinds&.free
|
|
1354
|
+
kinds = scratch[:ints] = ::FFI::MemoryPointer.new(:int, cap)
|
|
1355
|
+
end
|
|
1356
|
+
copied = leptris_node_children_ex(c_ptr, buffer, kinds, cap)
|
|
1357
|
+
if copied == cap
|
|
1358
|
+
total = leptris_node_children_ex(c_ptr, nil, nil, 0)
|
|
1359
|
+
if total > cap
|
|
1360
|
+
buffer.free
|
|
1361
|
+
buffer = scratch[:pointers] =
|
|
1362
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
1363
|
+
kinds.free
|
|
1364
|
+
kinds = scratch[:ints] =
|
|
1365
|
+
::FFI::MemoryPointer.new(:int, total)
|
|
1366
|
+
copied = leptris_node_children_ex(c_ptr, buffer, kinds, total)
|
|
1367
|
+
end
|
|
1368
|
+
end
|
|
1369
|
+
[buffer.get_array_of_pointer(0, copied),
|
|
1370
|
+
kinds.get_array_of_int(0, copied)]
|
|
1371
|
+
end
|
|
1372
|
+
|
|
1373
|
+
# Raw qname-ordered attribute pairs INCLUDING xmlns at their
|
|
1374
|
+
# byte positions (leptris_element_attributes_raw, 1.9.18
|
|
1375
|
+
# #635) — the streaming SAX contract's mixed view.
|
|
1376
|
+
def self.fetch_attributes_raw(el_ptr)
|
|
1377
|
+
total = leptris_element_attributes_raw(el_ptr, nil, nil, 0)
|
|
1378
|
+
return [] if total.zero?
|
|
1379
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1380
|
+
names = scratch[:attr_names]
|
|
1381
|
+
if names.nil? || names.size / PTR_BYTES < total
|
|
1382
|
+
names&.free
|
|
1383
|
+
names = scratch[:attr_names] =
|
|
1384
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
1385
|
+
end
|
|
1386
|
+
values = scratch[:attr_values]
|
|
1387
|
+
if values.nil? || values.size / PTR_BYTES < total
|
|
1388
|
+
values&.free
|
|
1389
|
+
values = scratch[:attr_values] =
|
|
1390
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
1391
|
+
end
|
|
1392
|
+
copied = leptris_element_attributes_raw(
|
|
1393
|
+
el_ptr, names, values, total)
|
|
1394
|
+
Array.new(copied) do |i|
|
|
1395
|
+
[utf8(names.get_pointer(i * PTR_BYTES).read_string),
|
|
1396
|
+
utf8(values.get_pointer(i * PTR_BYTES).read_string)]
|
|
1397
|
+
end
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1400
|
+
# Attribute strings cross the seam UTF-8 on both faces
|
|
1401
|
+
# (ADR-0002).
|
|
1402
|
+
def self.utf8(str)
|
|
1403
|
+
str.nil? ? nil : str.force_encoding(Encoding::UTF_8)
|
|
1404
|
+
end
|
|
1405
|
+
|
|
1406
|
+
# Element-only child batch (the mirror of fetch_children over
|
|
1407
|
+
# leptris_element_children): element receivers skip wrapping —
|
|
1408
|
+
# and paying for — the text/comment children they will filter
|
|
1409
|
+
# out anyway; every wrap carries the ELEMENT hint so the
|
|
1410
|
+
# per-child get_type dispatch disappears too.
|
|
1411
|
+
def self.fetch_element_children(el_ptr)
|
|
1412
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1413
|
+
buffer = scratch[:pointers]
|
|
1414
|
+
if buffer.nil?
|
|
1415
|
+
buffer = scratch[:pointers] =
|
|
1416
|
+
::FFI::MemoryPointer.new(:pointer, FETCH_INITIAL)
|
|
1417
|
+
end
|
|
1418
|
+
cap = buffer.size / PTR_BYTES
|
|
1419
|
+
copied = leptris_element_children(el_ptr, buffer, cap)
|
|
1420
|
+
if copied == cap
|
|
1421
|
+
# leptris_element_children has NO count-only mode (NULL
|
|
1422
|
+
# returns 0, unlike leptris_node_children) — size the
|
|
1423
|
+
# regrow from the dedicated counter.
|
|
1424
|
+
total = leptris_element_child_count(el_ptr)
|
|
1425
|
+
if total > cap
|
|
1426
|
+
buffer.free
|
|
1427
|
+
buffer = scratch[:pointers] =
|
|
1428
|
+
::FFI::MemoryPointer.new(:pointer, total)
|
|
1429
|
+
copied = leptris_element_children(el_ptr, buffer, total)
|
|
1430
|
+
end
|
|
1431
|
+
end
|
|
1432
|
+
buffer.get_array_of_pointer(0, copied)
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
# XPath result-set batch (leptris_xpath_result_get_nodes_ex):
|
|
1436
|
+
# the call fills out_kinds in the 4-value XPATH_NODE space
|
|
1437
|
+
# (ELEMENT/ATTRIBUTE/TEXT/OTHER). ELEMENT is the only value
|
|
1438
|
+
# that maps unambiguously — XPath's data model reports CDATA
|
|
1439
|
+
# as TEXT, so a TEXT hint cannot distinguish Text from CDATA
|
|
1440
|
+
# (different content getters) — everything else falls back to
|
|
1441
|
+
# get_type in the wrapper. Returns [pointers, element_hints].
|
|
1442
|
+
XPATH_KIND_HINT = { XPATH_NODE_ELEMENT => NODE_ELEMENT }.freeze
|
|
1443
|
+
|
|
1444
|
+
# Returns [pointers, element_hints, raw_kinds] — the raw
|
|
1445
|
+
# XPATH_NODE-space kinds ride along so the materializer can
|
|
1446
|
+
# spot TEXT items (synthetic sequence carriers) and capture
|
|
1447
|
+
# their values while the result handle is alive.
|
|
1448
|
+
def self.fetch_result_nodes(result_ptr, count)
|
|
1449
|
+
return [[], nil, nil] if count.zero?
|
|
1450
|
+
buffer = scratch_pointers(count)
|
|
1451
|
+
kinds = scratch_ints(count)
|
|
1452
|
+
copied = leptris_xpath_result_get_nodes_ex(
|
|
1453
|
+
result_ptr, buffer, kinds, count)
|
|
1454
|
+
raw = kinds.get_array_of_int(0, copied)
|
|
1455
|
+
hints = raw.map { |k| XPATH_KIND_HINT[k] }
|
|
1456
|
+
[buffer.get_array_of_pointer(0, copied), hints, raw]
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
# Fragment parse with the status out-param read: returns
|
|
1460
|
+
# [document-or-fragment pointer, status].
|
|
1461
|
+
def self.parse_fragment_with_status(xml, document_ptr)
|
|
1462
|
+
status = ::FFI::MemoryPointer.new(:int)
|
|
1463
|
+
raw = leptris_parse_fragment(
|
|
1464
|
+
xml, xml.bytesize, document_ptr, status)
|
|
1465
|
+
[raw, status.read_int]
|
|
1466
|
+
end
|
|
1467
|
+
|
|
1468
|
+
# libxml2 consumes the whole whitespace run following the PI
|
|
1469
|
+
# target when parsing; the engine retains it as data
|
|
1470
|
+
# (leptris-ruby#85). Every Ruby-facing PI-data read normalizes
|
|
1471
|
+
# here — whitespace-only data becomes "" so
|
|
1472
|
+
# "pi-without-data" PIs report empty consistently. Read-time
|
|
1473
|
+
# only: PI#data= stores verbatim.
|
|
1474
|
+
def self.read_pi_data(data)
|
|
1475
|
+
data&.sub(/\A[ \t\r\n]+/, "")
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
# Thread-local scratch buffers for batch handle fetches (round
|
|
1479
|
+
# XX): the per-call MemoryPointer new/free was pure cold-path
|
|
1480
|
+
# overhead — two allocations and a GC visit per children() /
|
|
1481
|
+
# result-set batch, ~15% of a cold full-tree walk between
|
|
1482
|
+
# 1.9.1 and 1.9.24. The buffers grow to the largest request
|
|
1483
|
+
# seen (bounded by the widest element or result set) and are
|
|
1484
|
+
# reused. Safe: no Ruby reentrancy during the C call, and
|
|
1485
|
+
# per-thread storage keeps concurrent fetches independent.
|
|
1486
|
+
# Never freed — a few KB pinned per thread.
|
|
1487
|
+
PTR_BYTES = ::FFI.type_size(:pointer)
|
|
1488
|
+
private_constant :PTR_BYTES
|
|
1489
|
+
INT_BYTES = ::FFI.type_size(:int)
|
|
1490
|
+
private_constant :INT_BYTES
|
|
1491
|
+
|
|
1492
|
+
def self.scratch_pointers(count)
|
|
1493
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1494
|
+
ptr = scratch[:pointers]
|
|
1495
|
+
if ptr.nil? || ptr.size / PTR_BYTES < count
|
|
1496
|
+
ptr&.free
|
|
1497
|
+
ptr = scratch[:pointers] = ::FFI::MemoryPointer.new(:pointer, count)
|
|
1498
|
+
end
|
|
1499
|
+
ptr
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
def self.scratch_ints(count)
|
|
1503
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1504
|
+
ptr = scratch[:ints]
|
|
1505
|
+
if ptr.nil? || ptr.size / INT_BYTES < count
|
|
1506
|
+
ptr&.free
|
|
1507
|
+
ptr = scratch[:ints] = ::FFI::MemoryPointer.new(:int, count)
|
|
1508
|
+
end
|
|
1509
|
+
ptr
|
|
1510
|
+
end
|
|
1511
|
+
|
|
1512
|
+
# Pull-event staging block for leptris_pull_next_batch (the
|
|
1513
|
+
# #589 bulk transport): LeptrisPullEvent records, stride from
|
|
1514
|
+
# the struct layout that mirrors the ABI.
|
|
1515
|
+
def self.scratch_events(count)
|
|
1516
|
+
need = count * PullEventStruct.size
|
|
1517
|
+
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
1518
|
+
ptr = scratch[:pull_events]
|
|
1519
|
+
if ptr.nil? || ptr.size < need
|
|
1520
|
+
ptr&.free
|
|
1521
|
+
ptr = scratch[:pull_events] = ::FFI::MemoryPointer.new(need)
|
|
1522
|
+
end
|
|
1523
|
+
ptr
|
|
1524
|
+
end
|
|
1525
|
+
end
|
|
1526
|
+
end
|
|
1527
|
+
end
|