leptris 1.9.394.0-arm-linux → 1.9.397.0-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.
@@ -0,0 +1,130 @@
1
+ // #1842 A5: the SIMD UTF-8 validator must agree with the scalar DFA
2
+ // on every input — adversarial boundary matrix plus a randomized
3
+ // cross-check over lengths straddling the 16-byte block edge.
4
+ #include "../../src/leptris/common/simd_text.h"
5
+
6
+ #include <gtest/gtest.h>
7
+ #include <cstring>
8
+ #include <cstdlib>
9
+ #include <string>
10
+ #include <utility>
11
+ #include <vector>
12
+
13
+ namespace {
14
+ }
15
+
16
+ TEST(Utf8Simd, SingleByteValues) {
17
+ for (int b = 0; b <= 255; b++) {
18
+ char buf[1] = {(char)b};
19
+ int scalar = leptris_utf8_valid_scalar(buf, 1);
20
+ int simd = leptris_utf8_valid(buf, 1);
21
+ EXPECT_EQ(simd, scalar) << "byte 0x" << std::hex << b << std::dec;
22
+ bool expect = (b < 0x80); /* a lone start byte is truncated */
23
+ EXPECT_EQ(scalar, expect ? 1 : 0)
24
+ << "byte 0x" << std::hex << b << std::dec;
25
+ }
26
+ }
27
+
28
+ TEST(Utf8Simd, SequenceMatrixAcrossBlockEdges) {
29
+ // (case, expected) — corrupt rows must be rejected too.
30
+ const std::vector<std::pair<std::string, int>> cases = {
31
+ // valid
32
+ {{"\xC2\xA0"}, 1}, {{"\xDF\xBF"}, 1}, {{"\xE0\xA0\x80"}, 1},
33
+ {{"\xE1\x80\x80"}, 1}, {{"\xED\x9F\xBF"}, 1}, {{"\xEE\x80\x80"}, 1},
34
+ {{"\xEF\xBF\xBD"}, 1}, {{"\xF0\x90\x80\x80"}, 1},
35
+ {{"\xF1\xBF\xBF\xBF"}, 1}, {{"\xF3\xA0\x80\x80"}, 1},
36
+ {{"\xF4\x8F\xBF\xBF"}, 1},
37
+ // overlong / surrogates / out-of-range
38
+ {{"\xC0\x80"}, 0}, {{"\xC1\xBF"}, 0}, {{"\xE0\x80\x80"}, 0},
39
+ {{"\xE0\x9F\xBF"}, 0}, {{"\xED\xA0\x80"}, 0}, {{"\xED\xBF\xBF"}, 0},
40
+ {{"\xF0\x80\x80\x80"}, 0}, {{"\xF0\x8F\xBF\xBF"}, 0},
41
+ {{"\xF4\x90\x80\x80"}, 0}, {{"\xF5\x80\x80\x80"}, 0},
42
+ // truncated (each prefix)
43
+ {{"\xC2"}, 0}, {{"\xE0\xA0"}, 0}, {{"\xF0\x90\x80"}, 0},
44
+ {{"\xF4\x8F"}, 0},
45
+ // stray continuation
46
+ {{"\x80"}, 0}, {{"a\x80" "b"}, 0}, {{"\xBF"}, 0},
47
+ };
48
+ for (std::vector<std::pair<std::string, int> >::const_iterator
49
+ it = cases.begin();
50
+ it != cases.end(); ++it) {
51
+ const std::string& s = it->first;
52
+ const int expect = it->second;
53
+ for (int pad = 0; pad < 20; pad++) {
54
+ std::string buf((size_t)pad, 'a');
55
+ buf += s;
56
+ int scalar =
57
+ leptris_utf8_valid_scalar(buf.data(), buf.size());
58
+ int simd = leptris_utf8_valid(buf.data(), buf.size());
59
+ EXPECT_EQ(simd, scalar)
60
+ << "case len=" << s.size() << " pad=" << pad;
61
+ EXPECT_EQ(scalar, expect)
62
+ << "verdict drifted: len=" << s.size() << " pad=" << pad;
63
+ }
64
+ }
65
+ }
66
+
67
+ TEST(Utf8Simd, BlockEdgeSizes) {
68
+ for (size_t n = 0; n <= 40; n++) {
69
+ std::string buf(n, 'x');
70
+ buf += "\xC3\xA9";
71
+ ASSERT_EQ(leptris_utf8_valid_scalar(buf.data(), buf.size()), 1);
72
+ ASSERT_EQ(leptris_utf8_valid(buf.data(), buf.size()), 1) << "n=" << n;
73
+ }
74
+ for (size_t n = 0; n <= 40; n++) {
75
+ std::string buf(n, 'x');
76
+ buf += "\xF0\x90\x80";
77
+ ASSERT_EQ(leptris_utf8_valid_scalar(buf.data(), buf.size()), 0);
78
+ ASSERT_EQ(leptris_utf8_valid(buf.data(), buf.size()), 0) << "n=" << n;
79
+ }
80
+ }
81
+
82
+ TEST(Utf8Simd, RandomizedCrossCheck) {
83
+ unsigned seed = 0x1842;
84
+ auto rnd = [&seed]() {
85
+ seed = seed * 1103515245u + 12345u;
86
+ return (seed >> 16) & 0xFF;
87
+ };
88
+ for (int trial = 0; trial < 4000; trial++) {
89
+ size_t len = (size_t)(rnd() % 97);
90
+ std::string buf;
91
+ for (size_t i = 0; i < len; i++) {
92
+ unsigned r = rnd() % 100;
93
+ char c;
94
+ if (r < 55) c = (char)('a' + (r % 26));
95
+ else if (r < 75) c = (char)(0xC0 + (r % 0x40));
96
+ else c = (char)(0x80 + (r % 0x80));
97
+ buf.push_back(c);
98
+ }
99
+ /* The plain corpus rarely produces the boundary shapes that
100
+ * broke the cores (x86-TSAN 2026-10-31): a start byte in the
101
+ * final block lane with a non-continuation after it, and
102
+ * sequences straddling 16/32-byte edges. Append an ASCII
103
+ * tail after a valid-or-not multibyte run so every trial
104
+ * also probes the tail-anchor at a shifted offset. */
105
+ if (trial % 3 == 0) {
106
+ static const char* mids[] = {
107
+ "\xC3\xA9", "\xE4\xB8\xAD", "\xF0\x9F\x98\x80",
108
+ "\xC3", "\xE0\xA0", "\xF0\x90\x80", "\xED\xA0\x80",
109
+ "\xF4\x8F\xBF\xBF", "\xC2\xBF", "\xEF\xBF\xBD"
110
+ };
111
+ buf += mids[trial % 10];
112
+ buf += "zz";
113
+ }
114
+ int scalar = leptris_utf8_valid_scalar(buf.data(), buf.size());
115
+ int simd = leptris_utf8_valid(buf.data(), buf.size());
116
+ EXPECT_EQ(simd, scalar)
117
+ << "trial " << trial << " len " << buf.size();
118
+ }
119
+ }
120
+
121
+ TEST(Utf8Simd, DenseValidDocument) {
122
+ std::string buf;
123
+ buf.reserve(64 * 1024);
124
+ const char* unit = "héllo wörld — 日本語テキスト 🎉 emoji §naïve";
125
+ for (int i = 0; i < 1024; i++) buf += unit;
126
+ EXPECT_EQ(leptris_utf8_valid_scalar(buf.data(), buf.size()), 1);
127
+ EXPECT_EQ(leptris_utf8_valid(buf.data(), buf.size()), 1);
128
+ buf[buf.size() / 2] = (char)0xF5;
129
+ EXPECT_EQ(leptris_utf8_valid(buf.data(), buf.size()), 0);
130
+ }
@@ -3712,7 +3712,9 @@ TEST(XsdCrossNs, AttributeRefIntoImportedUnitResolves) {
3712
3712
  "</xs:schema>";
3713
3713
 
3714
3714
  const char* dir = std::getenv("TMPDIR");
3715
- std::string base = dir ? dir : "/tmp";
3715
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
3716
+ if (!dir) dir = std::getenv("TMP");
3717
+ std::string base = dir ? dir : ".";
3716
3718
  std::string rel_path = base + "/blip_repro_rel.xsd";
3717
3719
  std::string main_path = base + "/blip_repro_main.xsd";
3718
3720
  {
@@ -3771,7 +3773,9 @@ TEST(XsdCrossNs, SingleDocImportChaseResolves) {
3771
3773
  "</xs:schema>";
3772
3774
 
3773
3775
  const char* dir = std::getenv("TMPDIR");
3774
- std::string base = dir ? dir : "/tmp";
3776
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
3777
+ if (!dir) dir = std::getenv("TMP");
3778
+ std::string base = dir ? dir : ".";
3775
3779
  std::string rel_path = base + "/blip_repro_rel.xsd";
3776
3780
  std::string main_path = base + "/blip_repro_main.xsd";
3777
3781
  {
@@ -3832,7 +3836,9 @@ TEST(XsdCrossNs, AttrGroupRefRowResolvedAfterImportChase) {
3832
3836
  "</xs:schema>";
3833
3837
 
3834
3838
  const char* dir = std::getenv("TMPDIR");
3835
- std::string base = dir ? dir : "/tmp";
3839
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
3840
+ if (!dir) dir = std::getenv("TMP");
3841
+ std::string base = dir ? dir : ".";
3836
3842
  std::string rel_path = base + "/ag569_rel.xsd";
3837
3843
  std::string main_path = base + "/ag569_main.xsd";
3838
3844
  {
@@ -3976,7 +3982,9 @@ TEST(Xsd11Gate, OverrideLoadsBaseAndReplacesComponents) {
3976
3982
  "</xs:sequence></xs:complexType>"
3977
3983
  "</xs:override></xs:schema>";
3978
3984
  const char* dir = std::getenv("TMPDIR");
3979
- std::string tmp = dir ? dir : "/tmp";
3985
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
3986
+ if (!dir) dir = std::getenv("TMP");
3987
+ std::string tmp = dir ? dir : ".";
3980
3988
  std::string base_path = tmp + "/ovr1913_base.xsd";
3981
3989
  std::string ovr_path = tmp + "/ovr1913_ovr.xsd";
3982
3990
  {
@@ -4003,3 +4011,175 @@ TEST(Xsd11Gate, OverrideLoadsBaseAndReplacesComponents) {
4003
4011
  std::remove(ovr_path.c_str());
4004
4012
  leptris_xsd_free(s);
4005
4013
  }
4014
+
4015
+ /* leptris#1920: a strict wildcard's declaration lookup must see the
4016
+ * merged set — the imported document's globals. Both vehicles (the
4017
+ * set compile and the single-document import chase) validate the
4018
+ * matched element; pinned so the document-local regression cannot
4019
+ * return silently. */
4020
+ TEST(XsdCrossNs, StrictWildcardSeesImportedDeclarations) {
4021
+ const char* head =
4022
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
4023
+ " targetNamespace=\"http://foobar\" xmlns=\"http://foobar\">"
4024
+ "<xs:import namespace=\"http://foo\""
4025
+ " schemaLocation=\"w1920_decl.xsd\"/>"
4026
+ "<xs:element name=\"foo\"><xs:complexType><xs:sequence>"
4027
+ "<xs:any namespace=\"##any\" processContents=\"strict\"/>"
4028
+ "</xs:sequence></xs:complexType></xs:element></xs:schema>";
4029
+ const char* decl =
4030
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
4031
+ " targetNamespace=\"http://foo\" xmlns=\"http://foo\">"
4032
+ "<xs:element name=\"bar\" type=\"xs:string\"/></xs:schema>";
4033
+ const char* dir = std::getenv("TMPDIR");
4034
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
4035
+ if (!dir) dir = std::getenv("TMP");
4036
+ std::string base = dir ? dir : ".";
4037
+ std::string head_path = base + "/w1920_head.xsd";
4038
+ std::string decl_path = base + "/w1920_decl.xsd";
4039
+ {
4040
+ std::ofstream f(head_path);
4041
+ f << head;
4042
+ }
4043
+ {
4044
+ std::ofstream f(decl_path);
4045
+ f << decl;
4046
+ }
4047
+ const char* paths[2] = {head_path.c_str(), decl_path.c_str()};
4048
+ const char* xml =
4049
+ "<foo xmlns=\"http://foobar\" xmlns:b=\"http://foo\">"
4050
+ "<b:bar>hi</b:bar></foo>";
4051
+ LeptrisStatus st = LEPTRIS_OK;
4052
+ LeptrisXsdSchema s = leptris_xsd_compile_set(paths, 2, &st);
4053
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
4054
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
4055
+ EXPECT_EQ(validate_compiled(s, xml), 1)
4056
+ << "set compile: strict wildcard admits the imported bar: "
4057
+ << leptris_xsd_error(s);
4058
+ leptris_xsd_free(s);
4059
+
4060
+ s = leptris_xsd_compile_file(head_path.c_str(), &st);
4061
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
4062
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
4063
+ EXPECT_EQ(validate_compiled(s, xml), 1)
4064
+ << "single-doc chase: strict wildcard admits the imported bar: "
4065
+ << leptris_xsd_error(s);
4066
+ leptris_xsd_free(s);
4067
+ std::remove(head_path.c_str());
4068
+ std::remove(decl_path.c_str());
4069
+ }
4070
+
4071
+ /* leptris#1923 (W3C msData ctE019, oracle: libxml2 validates): a
4072
+ * chameleon-included document's global attributes — referenced by
4073
+ * the derived type's restriction — must be admitted at validation.
4074
+ * fooType restricts mytype1 keeping attrTest1; the instance carries
4075
+ * attrTest2 as well, and libxml2 admits it (the restriction chain's
4076
+ * declarations remain visible for strict admission). */
4077
+ TEST(XsdCrossNs, ChameleonRestrictionAdmitsBaseChainAttributes) {
4078
+ const char* head =
4079
+ "<?xml version=\"1.0\"?>\n"
4080
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
4081
+ " targetNamespace=\"a\" xmlns=\"a\">"
4082
+ "<xsd:include schemaLocation=\"cte019_b.xsd\"/>"
4083
+ "<xsd:element name=\"doc\" type=\"fooType\"/>"
4084
+ "</xsd:schema>";
4085
+ const char* chameleon =
4086
+ "<?xml version=\"1.0\"?>\n"
4087
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
4088
+ "<xsd:simpleType name=\"myType\">"
4089
+ "<xsd:restriction base=\"xsd:string\"/></xsd:simpleType>"
4090
+ "<xsd:complexType name=\"mytype1\"><xsd:simpleContent>"
4091
+ "<xsd:extension base=\"myType\">"
4092
+ "<xsd:attribute ref=\"attrTest1\"/>"
4093
+ "<xsd:attribute ref=\"attrTest2\"/>"
4094
+ "</xsd:extension></xsd:simpleContent></xsd:complexType>"
4095
+ "<xsd:complexType name=\"fooType\"><xsd:simpleContent>"
4096
+ "<xsd:restriction base=\"mytype1\">"
4097
+ "<xsd:attribute ref=\"attrTest1\"/>"
4098
+ "</xsd:restriction></xsd:simpleContent></xsd:complexType>"
4099
+ "<xsd:attribute name=\"attrTest1\" type=\"xsd:int\"/>"
4100
+ "<xsd:attribute name=\"attrTest2\" type=\"xsd:ID\"/>"
4101
+ "</xsd:schema>";
4102
+ const char* dir = std::getenv("TMPDIR");
4103
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
4104
+ if (!dir) dir = std::getenv("TMP");
4105
+ std::string base = dir ? dir : ".";
4106
+ std::string head_path = base + "/cte019_a.xsd";
4107
+ std::string ch_path = base + "/cte019_b.xsd";
4108
+ {
4109
+ std::ofstream f(head_path);
4110
+ f << head;
4111
+ }
4112
+ {
4113
+ std::ofstream f(ch_path);
4114
+ f << chameleon;
4115
+ }
4116
+ LeptrisStatus st = LEPTRIS_OK;
4117
+ LeptrisXsdSchema s = leptris_xsd_compile_file(head_path.c_str(), &st);
4118
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
4119
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
4120
+ EXPECT_EQ(validate_compiled(s,
4121
+ "<a:doc xmlns:a=\"a\" a:attrTest1=\"1\""
4122
+ " a:attrTest2=\"b\" />"),
4123
+ 1)
4124
+ << "the restriction chain's attribute must be admitted: "
4125
+ << leptris_xsd_error(s);
4126
+ std::remove(head_path.c_str());
4127
+ std::remove(ch_path.c_str());
4128
+ leptris_xsd_free(s);
4129
+ }
4130
+
4131
+ /* leptris#1926 (W3C msData idF030): an xs:redefine that EXTENDS the
4132
+ * redefined type keeps the extension in the compiled model — the
4133
+ * body's own definitions replace the base's name bindings (capture
4134
+ * after the base; the ladder sees the new head), and the body's
4135
+ * extension folds against the base at capture time. Pinned with the
4136
+ * fixture's shape: tabletype(r?) extended by (c); the instance
4137
+ * carries r+c per t. */
4138
+ TEST(XsdCrossNs, RedefineExtensionKeepsTheExtensionModel) {
4139
+ const char* base =
4140
+ "<?xml version=\"1.0\"?>\n"
4141
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
4142
+ "<xsd:complexType name=\"tabletype\"><xsd:sequence>"
4143
+ "<xsd:element name=\"r\" type=\"xsd:string\" minOccurs=\"0\"/>"
4144
+ "</xsd:sequence></xsd:complexType></xsd:schema>";
4145
+ const char* redef =
4146
+ "<?xml version=\"1.0\"?>\n"
4147
+ "<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"
4148
+ "<xsd:redefine schemaLocation=\"f030_base.xsd\">"
4149
+ "<xsd:complexType name=\"tabletype\"><xsd:complexContent>"
4150
+ "<xsd:extension base=\"tabletype\"><xsd:sequence>"
4151
+ "<xsd:element name=\"c\" type=\"xsd:string\"/>"
4152
+ "</xsd:sequence></xsd:extension></xsd:complexContent>"
4153
+ "</xsd:complexType></xsd:redefine>"
4154
+ "<xsd:element name=\"root\"><xsd:complexType><xsd:sequence>"
4155
+ "<xsd:element name=\"t\" type=\"tabletype\""
4156
+ " maxOccurs=\"unbounded\"/>"
4157
+ "</xsd:sequence></xsd:complexType></xsd:element>"
4158
+ "</xsd:schema>";
4159
+ const char* dir = std::getenv("TMPDIR");
4160
+ if (!dir) dir = std::getenv("TEMP"); /* windows runners define TEMP/TMP */
4161
+ if (!dir) dir = std::getenv("TMP");
4162
+ std::string base_p = std::string(dir ? dir : ".") + "/f030_base.xsd";
4163
+ std::string redef_p = std::string(dir ? dir : ".") + "/f030_red.xsd";
4164
+ {
4165
+ std::ofstream f(base_p);
4166
+ f << base;
4167
+ }
4168
+ {
4169
+ std::ofstream f(redef_p);
4170
+ f << redef;
4171
+ }
4172
+ LeptrisStatus st = LEPTRIS_OK;
4173
+ LeptrisXsdSchema s = leptris_xsd_compile_file(redef_p.c_str(), &st);
4174
+ ASSERT_NE(s, (LeptrisXsdSchema)0);
4175
+ ASSERT_EQ(st, LEPTRIS_OK) << leptris_xsd_error(s);
4176
+ EXPECT_EQ(validate_compiled(s,
4177
+ "<root><t><r>1</r><c>1</c></t>"
4178
+ "<t><r>2</r><c>2</c></t></root>"),
4179
+ 1)
4180
+ << "the redefined+extended model admits r and c: "
4181
+ << leptris_xsd_error(s);
4182
+ std::remove(base_p.c_str());
4183
+ std::remove(redef_p.c_str());
4184
+ leptris_xsd_free(s);
4185
+ }
@@ -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.394",
4
+ "version": "1.9.397",
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",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.394.0
4
+ version: 1.9.397.0
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-30 00:00:00.000000000 Z
11
+ date: 2026-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -876,6 +876,7 @@ files:
876
876
  - vendor-src/libleptris/test/parser/test_large_documents.cpp
877
877
  - vendor-src/libleptris/test/parser/test_parser.cpp
878
878
  - vendor-src/libleptris/test/parser/test_simd_count.cpp
879
+ - vendor-src/libleptris/test/parser/test_utf8_simd.cpp
879
880
  - vendor-src/libleptris/test/parser/test_whitespace_shape.cpp
880
881
  - vendor-src/libleptris/test/perf/test_perf.cpp
881
882
  - vendor-src/libleptris/test/perf/test_stress_high_doc_count.cpp