leptris 1.9.364.1-aarch64-linux → 1.9.365.1-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document.rb +13 -1
- data/lib/leptris/xml/ffi.rb +7 -0
- data/lib/leptris/xml.rb +10 -2
- data/lib/libleptris.so +0 -0
- data/vendor-src/README.md +1 -1
- data/vendor-src/libleptris/CHANGELOG.md +34 -0
- data/vendor-src/libleptris/CMakeLists.txt +1 -1
- data/vendor-src/libleptris/src/include/leptris/types.h +4 -0
- data/vendor-src/libleptris/src/leptris/flat/direct_parse.c +8 -2
- data/vendor-src/libleptris/src/leptris/html/html_parse.c +13 -0
- data/vendor-src/libleptris/test/html/test_html_builder.cpp +40 -0
- data/vendor-src/libleptris/test/parser/test_parser.cpp +14 -2
- data/vendor-src/libleptris/vcpkg.json +1 -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: '09191b1d6e47cb07f20ee17bca8e1dc83969f96f19b92ea218baa1e2957c619d'
|
|
4
|
+
data.tar.gz: 293dddc9db111199bb43df0d66243bc059a83ac5c8f0f21c9a8eca819352fcb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69c108f41af0596b6988d121afeaa92c867d9c6c5e8a3905f2b18bacb6a0866e83bd8b9e48950b822d0a9da64d624927653f6ad1616393c387e9a59f3df74c10
|
|
7
|
+
data.tar.gz: bdfb75ee4ec215661ebda9e71afeee737bb6fe2216fc9495469f2baf70d41bf4eec77eacb5f32ffa8c84ecfb76ca34ba15445b0b862d4fce1b806a206923edb6
|
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.365"
|
|
12
12
|
# Vendored alongside libleptris for fn:normalize-unicode (TODO
|
|
13
13
|
# .restructure/20): built per platform with a RELOCATABLE @rpath
|
|
14
14
|
# install name, loaded by ffi.rb before libleptris so the
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/document.rb
CHANGED
|
@@ -864,6 +864,16 @@ class Leptris::XML::Document
|
|
|
864
864
|
node
|
|
865
865
|
end
|
|
866
866
|
|
|
867
|
+
# #1749: engine diag kind -> SyntaxError severity. FATAL = the
|
|
868
|
+
# classes the strict lane raises on (element still open at EOF;
|
|
869
|
+
# unescaped '<' in text, engine >= 1.9.364); the recover-class
|
|
870
|
+
# records (stray close dropped/implicit close, duplicate attribute,
|
|
871
|
+
# ...) and any future kind read :recoverable.
|
|
872
|
+
DIAG_SEVERITY = {
|
|
873
|
+
Leptris::XML::FFI::DIAG_KIND_UNCLOSED_ELEMENT => :fatal,
|
|
874
|
+
Leptris::XML::FFI::DIAG_KIND_UNESCAPED_LT => :fatal
|
|
875
|
+
}.freeze
|
|
876
|
+
|
|
867
877
|
# Recovered-parse diagnostics (leptris-ruby#465): nokogiri parity
|
|
868
878
|
# for the recover lane — the engine's parse diagnostics as
|
|
869
879
|
# SyntaxError entries, empty for a clean parse. The engine
|
|
@@ -878,7 +888,9 @@ class Leptris::XML::Document
|
|
|
878
888
|
ok = Leptris::XML::FFI.leptris_document_parse_diag(
|
|
879
889
|
c_ptr, i, kind_buf, msg_buf, 512)
|
|
880
890
|
next nil if ok.zero?
|
|
881
|
-
Leptris::XML::SyntaxError.new(
|
|
891
|
+
Leptris::XML::SyntaxError.new(
|
|
892
|
+
msg_buf.read_string.force_encoding(Encoding::UTF_8),
|
|
893
|
+
severity: DIAG_SEVERITY.fetch(kind_buf.read_int, :recoverable))
|
|
882
894
|
end.compact
|
|
883
895
|
end
|
|
884
896
|
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -1520,6 +1520,13 @@ attach_function :leptris_parse_string,
|
|
|
1520
1520
|
[:leptris_document], :leptris_status
|
|
1521
1521
|
attach_function :leptris_document_remove_doctype,
|
|
1522
1522
|
[:leptris_document], :leptris_status
|
|
1523
|
+
# LeptrisDiagKind (engine types.h, append-only): the values the
|
|
1524
|
+
# DOM parse channel records. Document#errors maps these to
|
|
1525
|
+
# SyntaxError severity (#1749) — FATAL kinds are the classes the
|
|
1526
|
+
# strict lane raises on; everything else reads :recoverable.
|
|
1527
|
+
DIAG_KIND_UNCLOSED_ELEMENT = 11
|
|
1528
|
+
DIAG_KIND_UNESCAPED_LT = 12 # engine >= 1.9.364 (#1748/#1749)
|
|
1529
|
+
|
|
1523
1530
|
attach_function :leptris_document_parse_diag_count,
|
|
1524
1531
|
[:leptris_document], :size_t
|
|
1525
1532
|
attach_function :leptris_document_parse_diag,
|
data/lib/leptris/xml.rb
CHANGED
|
@@ -111,14 +111,22 @@ module Leptris
|
|
|
111
111
|
# SyntaxError shape — a message plus optional position — served
|
|
112
112
|
# by Document#errors.
|
|
113
113
|
class SyntaxError < Error
|
|
114
|
-
attr_reader :message, :line, :column
|
|
114
|
+
attr_reader :message, :line, :column, :severity
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
# severity: :fatal (the strict lane raises on this class) or
|
|
117
|
+
# :recoverable (leptris-ruby#1749) — raise-on-fatal /
|
|
118
|
+
# recover-on-recoverable without string matching.
|
|
119
|
+
def initialize(message, line: nil, column: nil, severity: :recoverable)
|
|
117
120
|
@message = message
|
|
118
121
|
@line = line
|
|
119
122
|
@column = column
|
|
123
|
+
@severity = severity
|
|
120
124
|
super(message)
|
|
121
125
|
end
|
|
126
|
+
|
|
127
|
+
def fatal?
|
|
128
|
+
@severity == :fatal
|
|
129
|
+
end
|
|
122
130
|
end
|
|
123
131
|
class ReadOnlyError < Error; end
|
|
124
132
|
class XPathError < Error; end
|
data/lib/libleptris.so
CHANGED
|
Binary file
|
data/vendor-src/README.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.9.365] - 2026-10-16
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **html4: skip the XML-declaration construct in HTML input (#1748, PR #1754).**
|
|
8
|
+
The html4 lane parsed `<?xml ...?>` as a PI node (target `xml`) whose data
|
|
9
|
+
carried the terminator `?`, so serialization emitted
|
|
10
|
+
`<?xml version="1.0" encoding="UTF-8"??>` — and with the serializer's
|
|
11
|
+
`xml_declaration` riding along (the default `to_xml`), the output carried
|
|
12
|
+
two declarations, which canon's XHTML pretty-printer degenerated to
|
|
13
|
+
declaration-only output downstream. libxml2's HTML parser skips the
|
|
14
|
+
XML-declaration construct entirely; the html4 lane now does the same (the
|
|
15
|
+
WHATWG lane keeps its specified bogus-comment shape). Red-first gtest pins
|
|
16
|
+
the contract: `xml_declaration=0` emits no declaration, `1` emits exactly
|
|
17
|
+
the serializer's own — never the input's remnant, never `??`. Engine suite
|
|
18
|
+
2047/2047; canon's battery 9/9.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## [1.9.364] - 2026-10-16
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **parse diagnostics carry severity classification (#1749, PR #1752).**
|
|
26
|
+
Two append-only `LeptrisDiagKind` refinements so embedders can implement
|
|
27
|
+
raise-on-fatal / recover-on-recoverable without string matching:
|
|
28
|
+
`LEPTRIS_DIAG_UNESCAPED_LT` — the #1748 unescaped-`<` recovery is a
|
|
29
|
+
strict-fatal class and now records its own kind instead of the generic
|
|
30
|
+
RECOVER bucket; and the ancestor-implicit-close recovery records
|
|
31
|
+
`LEPTRIS_DIAG_MISMATCHED_TAG` (libxml2 reports the same shape as a tag
|
|
32
|
+
mismatch), reserving `LEPTRIS_DIAG_UNCLOSED_ELEMENT` for the
|
|
33
|
+
still-open-at-EOF fatal class. Record messages unchanged; enum is
|
|
34
|
+
append-only.
|
|
35
|
+
|
|
36
|
+
|
|
3
37
|
## [1.9.363] - 2026-10-16
|
|
4
38
|
|
|
5
39
|
### Fixed
|
|
@@ -290,6 +290,10 @@ typedef enum {
|
|
|
290
290
|
* implicitly), and an element still open at EOF. Append-only. */
|
|
291
291
|
LEPTRIS_DIAG_MISMATCHED_TAG,
|
|
292
292
|
LEPTRIS_DIAG_UNCLOSED_ELEMENT,
|
|
293
|
+
/* leptris#1748: an unescaped '<' in text folded into the run —
|
|
294
|
+
* RECOVERABLE-lane record of a STRICT-FATAL class (the strict
|
|
295
|
+
* path fails the parse; severity mapping: fatal). Append-only. */
|
|
296
|
+
LEPTRIS_DIAG_UNESCAPED_LT,
|
|
293
297
|
LEPTRIS_DIAG_COUNT_
|
|
294
298
|
} LeptrisDiagKind;
|
|
295
299
|
|
|
@@ -1755,7 +1755,7 @@ static struct leptris_document* direct_parse_internal(char* buf, size_t len,
|
|
|
1755
1755
|
leptris_diag_emit(
|
|
1756
1756
|
&p.doc->parse_diags, &p.doc->parse_diag_count,
|
|
1757
1757
|
&p.doc->parse_diag_cap,
|
|
1758
|
-
|
|
1758
|
+
LEPTRIS_DIAG_UNESCAPED_LT, NULL,
|
|
1759
1759
|
"Unescaped < not allowed in a text node");
|
|
1760
1760
|
const char* nq = lt + 1;
|
|
1761
1761
|
const char* nlt =
|
|
@@ -2142,11 +2142,17 @@ static struct leptris_document* direct_parse_internal(char* buf, size_t len,
|
|
|
2142
2142
|
while ((int)p.depth - 1 > anc) {
|
|
2143
2143
|
LeptrisElement ce =
|
|
2144
2144
|
p.open_stack[p.depth - 1];
|
|
2145
|
+
/* #1749 severity: the implicit close
|
|
2146
|
+
* is the MISMATCH recovery (libxml2
|
|
2147
|
+
* reports a tag mismatch; recoverable
|
|
2148
|
+
* class) — UNCLOSED_ELEMENT stays
|
|
2149
|
+
* reserved for the still-open-at-EOF
|
|
2150
|
+
* fatal class. */
|
|
2145
2151
|
leptris_diag_emit(
|
|
2146
2152
|
&p.doc->parse_diags,
|
|
2147
2153
|
&p.doc->parse_diag_count,
|
|
2148
2154
|
&p.doc->parse_diag_cap,
|
|
2149
|
-
|
|
2155
|
+
LEPTRIS_DIAG_MISMATCHED_TAG, NULL,
|
|
2150
2156
|
"Element %s closed implicitly by </%.*s>",
|
|
2151
2157
|
elem_name(ce),
|
|
2152
2158
|
(int)close_local_len, close_local);
|
|
@@ -6685,6 +6685,19 @@ static LeptrisDocument html_parse_shared(
|
|
|
6685
6685
|
size_t dlen = (size_t)(de > ds ? de - ds : 0);
|
|
6686
6686
|
char* tgt = (char*)leptris_pool_alloc(b.pool, tlen + 1);
|
|
6687
6687
|
char* dat = (char*)leptris_pool_alloc(b.pool, dlen + 1);
|
|
6688
|
+
/* libxml2 HTML parity (#1748): the XML-declaration
|
|
6689
|
+
* construct ('<?xml ...?>') is an XML-ism — the HTML
|
|
6690
|
+
* lane skips it entirely. Retaining it as a PI made the
|
|
6691
|
+
* data carry the terminator '?' (serialized
|
|
6692
|
+
* '<?xml ...??>'), and the declaration metadata + PI
|
|
6693
|
+
* doubled when the serializer's xml_declaration rode
|
|
6694
|
+
* along. */
|
|
6695
|
+
if (tlen == 3 && (ts[0] | 0x20) == 'x' &&
|
|
6696
|
+
(ts[1] | 0x20) == 'm' && (ts[2] | 0x20) == 'l') {
|
|
6697
|
+
p = (de < end) ? de + 1 : end;
|
|
6698
|
+
text = p;
|
|
6699
|
+
continue;
|
|
6700
|
+
}
|
|
6688
6701
|
if (tgt && dat) {
|
|
6689
6702
|
memcpy(tgt, ts, tlen);
|
|
6690
6703
|
tgt[tlen] = 0;
|
|
@@ -188,3 +188,43 @@ TEST(HtmlBuilder, RawTextElementNotEscaped) {
|
|
|
188
188
|
EXPECT_EQ(out.find("<"), std::string::npos) << out;
|
|
189
189
|
leptris_document_free(d);
|
|
190
190
|
}
|
|
191
|
+
|
|
192
|
+
/* leptris#1748: the XML-declaration construct ('<?xml ...?>') in
|
|
193
|
+
* HTML input is an XML-ism — libxml2's HTML parser skips it, and
|
|
194
|
+
* retaining it as a PI (data carrying the terminator '?') made
|
|
195
|
+
* serialization emit '<?xml ...??>' and double the declaration when
|
|
196
|
+
* the serializer's own xml_declaration rode along. */
|
|
197
|
+
TEST(HtmlBuilder, Html4DropsXmlDeclarationProlog) {
|
|
198
|
+
const char* html =
|
|
199
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
|
200
|
+
"<html xmlns=\"http://www.w3.org/1999/xhtml\">"
|
|
201
|
+
"<head><title>t</title></head><body><p>x</p></body></html>";
|
|
202
|
+
LeptrisStatus st = LEPTRIS_OK;
|
|
203
|
+
LeptrisDocument d =
|
|
204
|
+
leptris_parse_html4_string(html, strlen(html), &st);
|
|
205
|
+
ASSERT_EQ(st, LEPTRIS_OK);
|
|
206
|
+
ASSERT_NE(d, nullptr);
|
|
207
|
+
for (int decl = 0; decl < 2; decl++) {
|
|
208
|
+
LeptrisSerializeOptions opts;
|
|
209
|
+
memset(&opts, 0, sizeof(opts));
|
|
210
|
+
opts.xml_declaration = decl;
|
|
211
|
+
opts.encoding = "UTF-8";
|
|
212
|
+
char* s = leptris_document_serialize(d, &opts);
|
|
213
|
+
ASSERT_NE(s, nullptr);
|
|
214
|
+
std::string out(s);
|
|
215
|
+
leptris_free_string(s);
|
|
216
|
+
EXPECT_EQ(out.find("??"), std::string::npos)
|
|
217
|
+
<< "decl=" << decl << " got: " << out.substr(0, 90);
|
|
218
|
+
/* decl=0: the prolog never leaks. decl=1: exactly the
|
|
219
|
+
* serializer's own declaration — never two, never the
|
|
220
|
+
* input's remnant. */
|
|
221
|
+
size_t decls = 0;
|
|
222
|
+
for (size_t at = out.find("<?xml"); at != std::string::npos;
|
|
223
|
+
at = out.find("<?xml", at + 1))
|
|
224
|
+
decls++;
|
|
225
|
+
EXPECT_EQ(decls, (size_t)decl)
|
|
226
|
+
<< "decl=" << decl << " got: " << out.substr(0, 90);
|
|
227
|
+
EXPECT_NE(out.find("<html"), std::string::npos) << out;
|
|
228
|
+
}
|
|
229
|
+
leptris_document_free(d);
|
|
230
|
+
}
|
|
@@ -799,8 +799,17 @@ TEST(ParseRecover, MismatchedCloseKeepsTreeAndDropsStray) {
|
|
|
799
799
|
EXPECT_STREQ(leptris_element_text(a), "x");
|
|
800
800
|
/* Two recoveries: the stray </b> drops, and <a> closes
|
|
801
801
|
* implicitly when </root> names the ancestor (libxml2 reports
|
|
802
|
-
* both as well).
|
|
802
|
+
* both as well). Both are MISMATCHED_TAG — the #1749 severity
|
|
803
|
+
* contract keeps UNCLOSED_ELEMENT for the EOF class only. */
|
|
803
804
|
EXPECT_EQ(leptris_document_parse_diag_count(doc), 2u);
|
|
805
|
+
LeptrisDiagKind kind = (LeptrisDiagKind)-1;
|
|
806
|
+
char msg[128] = {0};
|
|
807
|
+
ASSERT_EQ(leptris_document_parse_diag(doc, 0, &kind, msg,
|
|
808
|
+
sizeof(msg)), 1);
|
|
809
|
+
EXPECT_EQ(kind, LEPTRIS_DIAG_MISMATCHED_TAG);
|
|
810
|
+
ASSERT_EQ(leptris_document_parse_diag(doc, 1, &kind, msg,
|
|
811
|
+
sizeof(msg)), 1);
|
|
812
|
+
EXPECT_EQ(kind, LEPTRIS_DIAG_MISMATCHED_TAG);
|
|
804
813
|
leptris_document_free(doc);
|
|
805
814
|
}
|
|
806
815
|
|
|
@@ -867,7 +876,10 @@ TEST(ParseRecover, BareLtInTextKeepsTreeAndRecords) {
|
|
|
867
876
|
char msg[128] = {0};
|
|
868
877
|
ASSERT_EQ(leptris_document_parse_diag(doc, 0, &kind, msg,
|
|
869
878
|
sizeof(msg)), 1);
|
|
870
|
-
|
|
879
|
+
/* #1749: the kind carries the severity — unescaped '<' is a
|
|
880
|
+
* STRICT-FATAL class recovered on the lenient lane, its own
|
|
881
|
+
* kind, not the generic RECOVER bucket. */
|
|
882
|
+
EXPECT_EQ(kind, LEPTRIS_DIAG_UNESCAPED_LT);
|
|
871
883
|
leptris_document_free(doc);
|
|
872
884
|
}
|
|
873
885
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
|
3
3
|
"name": "leptris",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.365",
|
|
5
5
|
"description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
|
|
6
6
|
"homepage": "https://github.com/leptris/leptris",
|
|
7
7
|
"license": "MIT",
|