leptris 1.9.29 → 1.9.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/Rakefile +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document.rb +2 -1
- data/lib/leptris/xml/ffi.rb +14 -0
- data/lib/leptris/xml/parse_options.rb +20 -0
- data/lib/leptris/xml/processing_instruction.rb +2 -1
- data/lib/leptris/xml/pull.rb +10 -7
- data/lib/leptris/xml/sax/parser.rb +2 -1
- data/lib/leptris/xml/sax/recorder.rb +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 61af1b12021e7a1cf22f04004ea36d27df6f740ff135d039854c51497abf87f3
|
|
4
|
+
data.tar.gz: 0a842331a02a988b8bfce2920f8878b87c5ff5fdbd4c471f2f04694f4a1b3465
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e832da72a4e2fe0ddede057023c1e981705a41f196d85e7d7e5d61051d524bddfc2305065fef940ef60af48b87e978bc46be7e61030d598de83fb916db8bba3e
|
|
7
|
+
data.tar.gz: 7a266c15d5983229591bf414ad0dde95cc93018ba01388bf721f98977c026c164797e1dc805fc9a46625a6b2037c7709a65cb0e0640ca5ed6c46f40614dd37c0
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.31] - 2026-08-28
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **PI data consumes the leading whitespace run (leptris-ruby#85,
|
|
13
|
+
libxml2 parity)**: the engine retains the full whitespace run
|
|
14
|
+
after the PI target as data where libxml2 consumes it at parse
|
|
15
|
+
time — every Ruby-facing PI-data read now normalizes through one
|
|
16
|
+
seam helper (`FFI.read_pi_data`): `PI#content`,
|
|
17
|
+
`Document#processing_instructions` pairs, the SAX
|
|
18
|
+
`processing_instruction` callback, pull `:pi` events, and
|
|
19
|
+
recorder `:pi` events. Whitespace-only data reads as `""`, so
|
|
20
|
+
"pi-without-data" PIs report empty consistently; trailing
|
|
21
|
+
whitespace is kept (libxml2 trims only the leading run).
|
|
22
|
+
Read-time only — `PI#data=` still stores verbatim.
|
|
23
|
+
|
|
24
|
+
## [1.9.30] - 2026-08-28
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **DTD ATTLIST defaults no longer injected by default** (vendored
|
|
29
|
+
libleptris 1.9.8, leptris/leptris#606): raw parses leave ATTLIST
|
|
30
|
+
default attributes out — the libxml2/Nokogiri default the ecosystem
|
|
31
|
+
compares against, and what W3C C14N 1.1 example 3.3's canonical
|
|
32
|
+
form assumes. New `Leptris::XML::ParseOptions::DTDATTR` /
|
|
33
|
+
`.dtdattr` / `#dtdattr?` / `#dtdattr=` opts in (libxml2
|
|
34
|
+
XML_PARSE_DTDATTR parity).
|
|
35
|
+
|
|
8
36
|
## [1.9.29] - 2026-08-28
|
|
9
37
|
|
|
10
38
|
### Fixed
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.8"
|
|
12
12
|
|
|
13
13
|
CMAKE_FLAGS = %w[
|
|
14
14
|
-DCMAKE_BUILD_TYPE=Release
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/document.rb
CHANGED
|
@@ -295,7 +295,8 @@ class Leptris::XML::Document
|
|
|
295
295
|
count = Leptris::XML::FFI.leptris_document_pi_count(@c_ptr)
|
|
296
296
|
result = count.times.map do |i|
|
|
297
297
|
[Leptris::XML::FFI.leptris_document_pi_target(@c_ptr, i),
|
|
298
|
-
Leptris::XML::FFI.
|
|
298
|
+
Leptris::XML::FFI.read_pi_data(
|
|
299
|
+
Leptris::XML::FFI.leptris_document_pi_data(@c_ptr, i)).to_s]
|
|
299
300
|
end
|
|
300
301
|
@processing_instructions = result
|
|
301
302
|
@pi_version = @version
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -734,6 +734,10 @@ module Leptris
|
|
|
734
734
|
|
|
735
735
|
LEPTRIS_PARSE_DEFAULT = 0
|
|
736
736
|
LEPTRIS_PARSE_DROP_WS_TEXT = 1
|
|
737
|
+
# libleptris >= 1.9.8 (#606): apply DTD ATTLIST default (and
|
|
738
|
+
# #FIXED) attribute values at parse time — libxml2
|
|
739
|
+
# XML_PARSE_DTDATTR opt-in parity.
|
|
740
|
+
LEPTRIS_PARSE_DTDATTR = 2
|
|
737
741
|
|
|
738
742
|
# The headers' contract is UTF-8 for every C string, but FFI's
|
|
739
743
|
# read_string hands back ASCII-8BIT — the platform default
|
|
@@ -920,6 +924,16 @@ module Leptris
|
|
|
920
924
|
[raw, status.read_int]
|
|
921
925
|
end
|
|
922
926
|
|
|
927
|
+
# libxml2 consumes the whole whitespace run following the PI
|
|
928
|
+
# target when parsing; the engine retains it as data
|
|
929
|
+
# (leptris-ruby#85). Every Ruby-facing PI-data read normalizes
|
|
930
|
+
# here — whitespace-only data becomes "" so
|
|
931
|
+
# "pi-without-data" PIs report empty consistently. Read-time
|
|
932
|
+
# only: PI#data= stores verbatim.
|
|
933
|
+
def self.read_pi_data(data)
|
|
934
|
+
data&.sub(/\A[ \t\r\n]+/, "")
|
|
935
|
+
end
|
|
936
|
+
|
|
923
937
|
# Thread-local scratch buffers for batch handle fetches (round
|
|
924
938
|
# XX): the per-call MemoryPointer new/free was pure cold-path
|
|
925
939
|
# overhead — two allocations and a GC visit per children() /
|
|
@@ -9,6 +9,14 @@ class Leptris::XML::ParseOptions
|
|
|
9
9
|
# way do not round-trip pretty-printed formatting byte-for-byte.
|
|
10
10
|
NOBLANKS = Leptris::XML::FFI::LEPTRIS_PARSE_DROP_WS_TEXT
|
|
11
11
|
|
|
12
|
+
# Apply DTD ATTLIST default (and #FIXED) attribute values at parse
|
|
13
|
+
# time (libleptris >= 1.9.8, leptris/leptris#606). Matches libxml2's
|
|
14
|
+
# XML_PARSE_DTDATTR and Nokogiri's dtdload+dtdattr semantics. Off by
|
|
15
|
+
# default: the ecosystem compares against libxml2's no-DTDATTR
|
|
16
|
+
# default, and W3C C14N 1.1 example 3.3's canonical form excludes
|
|
17
|
+
# defaulted attributes.
|
|
18
|
+
DTDATTR = Leptris::XML::FFI::LEPTRIS_PARSE_DTDATTR
|
|
19
|
+
|
|
12
20
|
attr_reader :flags
|
|
13
21
|
|
|
14
22
|
# Recover (libleptris 1.9.0, #547): a parse failure returns an
|
|
@@ -36,6 +44,18 @@ class Leptris::XML::ParseOptions
|
|
|
36
44
|
@flags & NOBLANKS != 0
|
|
37
45
|
end
|
|
38
46
|
|
|
47
|
+
def self.dtdattr
|
|
48
|
+
new(DTDATTR)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def dtdattr?
|
|
52
|
+
@flags & DTDATTR != 0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def dtdattr=(value)
|
|
56
|
+
if value then @flags |= DTDATTR else @flags &= ~DTDATTR end
|
|
57
|
+
end
|
|
58
|
+
|
|
39
59
|
def recover?
|
|
40
60
|
@recover == true
|
|
41
61
|
end
|
|
@@ -16,7 +16,8 @@ class Leptris::XML::ProcessingInstruction < Leptris::XML::Node
|
|
|
16
16
|
def content
|
|
17
17
|
return @content if memo_hit?(@content_version)
|
|
18
18
|
ensure_alive!
|
|
19
|
-
result = Leptris::XML::FFI.
|
|
19
|
+
result = Leptris::XML::FFI.read_pi_data(
|
|
20
|
+
Leptris::XML::FFI.leptris_pi_node_get_data(@c_ptr)).to_s
|
|
20
21
|
if @document
|
|
21
22
|
@content = result
|
|
22
23
|
@content_version = @document.version
|
data/lib/leptris/xml/pull.rb
CHANGED
|
@@ -84,13 +84,14 @@ module Leptris::XML::Pull
|
|
|
84
84
|
base = i * stride
|
|
85
85
|
name_ptr = buffer.get_pointer(base + name_off)
|
|
86
86
|
text_ptr = buffer.get_pointer(base + text_off)
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
type = TYPES[buffer.get_int(base + type_off)]
|
|
88
|
+
text = text_ptr.null? ? nil :
|
|
89
|
+
text_ptr.read_string.force_encoding(Encoding::UTF_8)
|
|
90
|
+
text = Leptris::XML::FFI.read_pi_data(text) if type == :pi
|
|
91
|
+
Event.new(type,
|
|
89
92
|
name_ptr.null? ? nil :
|
|
90
93
|
name_ptr.read_string.force_encoding(Encoding::UTF_8),
|
|
91
|
-
|
|
92
|
-
text_ptr.read_string.force_encoding(Encoding::UTF_8),
|
|
93
|
-
nil
|
|
94
|
+
text, nil
|
|
94
95
|
)
|
|
95
96
|
end
|
|
96
97
|
# The attr mirror holds the batch's most recent start.
|
|
@@ -125,11 +126,13 @@ module Leptris::XML::Pull
|
|
|
125
126
|
name_ptr = raw.get_pointer(NAME_OFFSET)
|
|
126
127
|
text_ptr = raw.get_pointer(TEXT_OFFSET)
|
|
127
128
|
attrs = type == :start_element ? capture_attrs : nil
|
|
129
|
+
text = text_ptr.null? ? nil :
|
|
130
|
+
text_ptr.read_string.force_encoding(Encoding::UTF_8)
|
|
131
|
+
text = Leptris::XML::FFI.read_pi_data(text) if type == :pi
|
|
128
132
|
Event.new(
|
|
129
133
|
type,
|
|
130
134
|
name_ptr.null? ? nil : name_ptr.read_string.force_encoding(Encoding::UTF_8),
|
|
131
|
-
|
|
132
|
-
attrs
|
|
135
|
+
text, attrs
|
|
133
136
|
)
|
|
134
137
|
end
|
|
135
138
|
|
|
@@ -149,7 +149,8 @@ class Leptris::XML::SAX::Parser
|
|
|
149
149
|
|
|
150
150
|
if overridden?(:processing_instruction)
|
|
151
151
|
s[:processing_instruction] = callback(:void, [:pointer, :string, :string]) do |_, target, data|
|
|
152
|
-
handler.processing_instruction(
|
|
152
|
+
handler.processing_instruction(
|
|
153
|
+
utf8(target), Leptris::XML::FFI.read_pi_data(utf8(data)))
|
|
153
154
|
end
|
|
154
155
|
end
|
|
155
156
|
|
|
@@ -122,9 +122,11 @@ class Leptris::XML::SAX::Recorder
|
|
|
122
122
|
kind = KIND_BY_CODE[fields[i * 9]]
|
|
123
123
|
if kind && (wanted.nil? || wanted[kind])
|
|
124
124
|
base = i * 9 + 1
|
|
125
|
+
text = slice(arena, fields[base + 2], fields[base + 3])
|
|
126
|
+
text = Leptris::XML::FFI.read_pi_data(text) if kind == :pi
|
|
125
127
|
yield kind,
|
|
126
128
|
slice(arena, fields[base], fields[base + 1]),
|
|
127
|
-
|
|
129
|
+
text,
|
|
128
130
|
attrs_from(arena, fields[base + 4], fields[base + 5]),
|
|
129
131
|
fields[base + 6], fields[base + 7]
|
|
130
132
|
end
|