aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/expat/Changes128
-rw-r--r--contrib/expat/Makefile.in3
-rw-r--r--contrib/expat/README.md2
-rw-r--r--contrib/expat/configure.ac27
-rw-r--r--contrib/expat/doc/Makefile.in3
-rw-r--r--contrib/expat/doc/reference.html754
-rw-r--r--contrib/expat/doc/xmlwf.12
-rw-r--r--contrib/expat/doc/xmlwf.xml2
-rw-r--r--contrib/expat/examples/Makefile.in3
-rw-r--r--contrib/expat/examples/element_declarations.c14
-rw-r--r--contrib/expat/examples/elements.c14
-rw-r--r--contrib/expat/examples/outline.c14
-rw-r--r--contrib/expat/expat_config.h.in4
-rw-r--r--contrib/expat/fuzz/xml_parse_fuzzer.c2
-rw-r--r--contrib/expat/fuzz/xml_parsebuffer_fuzzer.c2
-rw-r--r--contrib/expat/lib/Makefile.am3
-rw-r--r--contrib/expat/lib/Makefile.in43
-rw-r--r--contrib/expat/lib/expat.h99
-rw-r--r--contrib/expat/lib/expat_external.h3
-rw-r--r--contrib/expat/lib/internal.h12
-rw-r--r--contrib/expat/lib/libexpat.map.in17
-rw-r--r--contrib/expat/lib/xcs.c90
-rw-r--r--contrib/expat/lib/xcs.h (renamed from contrib/expat/lib/xcsinc.c)34
-rw-r--r--contrib/expat/lib/xmlparse.c549
-rw-r--r--contrib/expat/lib/xmltok.c276
-rw-r--r--contrib/expat/lib/xmltok_impl.c2
-rw-r--r--contrib/expat/tests/Makefile.am6
-rw-r--r--contrib/expat/tests/Makefile.in23
-rw-r--r--contrib/expat/tests/acc_tests.c37
-rw-r--r--contrib/expat/tests/alloc_tests.c59
-rw-r--r--contrib/expat/tests/basic_tests.c170
-rw-r--r--contrib/expat/tests/benchmark/Makefile.in3
-rw-r--r--contrib/expat/tests/benchmark/benchmark.c19
-rw-r--r--contrib/expat/tests/chardata.c4
-rw-r--r--contrib/expat/tests/common.c11
-rw-r--r--contrib/expat/tests/common.h6
-rw-r--r--contrib/expat/tests/handlers.c115
-rw-r--r--contrib/expat/tests/misc_tests.c114
-rw-r--r--contrib/expat/tests/props_tests.c790
-rw-r--r--contrib/expat/tests/props_tests.h41
-rw-r--r--contrib/expat/tests/runtests.c20
-rw-r--r--contrib/expat/tests/structdata.c11
-rw-r--r--contrib/expat/tests/xcs_tests.c86
-rw-r--r--contrib/expat/tests/xcs_tests.h41
-rw-r--r--contrib/expat/xmlwf/Makefile.am3
-rw-r--r--contrib/expat/xmlwf/Makefile.in46
-rw-r--r--contrib/expat/xmlwf/xmlfile.c9
-rw-r--r--contrib/expat/xmlwf/xmlfile.h8
-rw-r--r--contrib/expat/xmlwf/xmlwf.c31
-rw-r--r--lib/libexpat/Makefile2
-rw-r--r--lib/libexpat/expat_config.h6
-rw-r--r--lib/libexpat/libbsdxml.34
52 files changed, 2942 insertions, 825 deletions
diff --git a/contrib/expat/Changes b/contrib/expat/Changes
index bf94e9db5616..91513379bb49 100644
--- a/contrib/expat/Changes
+++ b/contrib/expat/Changes
@@ -5,21 +5,108 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!! <blink>Expat has UNFIXED SECURITY ISSUES!</blink> !!
-!! Please see https://github.com/libexpat/libexpat/issues/1160 for details. !!
-!! !!
-!! Starting 2026-08-01, for up to six months my work maintaining libexpat !!
-!! will be funded by the City of Munich as part of their !!
-!! Open Source Sabbatical (https://opensource.muenchen.de/sabbatical.html) !!
-!! — thank you! !!
-!! !!
-!! If your business relies on Expat beyond January 2027, please consider !!
-!! funding the maintenance of Expat to ensure its health and security for !!
-!! you and others. Thank you! !!
-!! !!
-!! Sebastian Pipping -- Berlin, 2026-09-22 !!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+///////////////////////////////////////////////////////////////////////////////
+// <blink>Expat has UNFIXED SECURITY ISSUES!</blink> //
+// Please see https://github.com/libexpat/libexpat/issues/1160 for details. //
+// //
+// Starting 2026-08-01, for up to six months my work maintaining libexpat //
+// will be funded by the City of Munich as part of their //
+// Open Source Sabbatical (https://opensource.muenchen.de/sabbatical.html) //
+// — thank you! //
+// //
+// If your business relies on Expat beyond January 2027, please consider //
+// funding the maintenance of Expat to ensure its health and security for //
+// you and others. Thank you! //
+// //
+// Sebastian Pipping -- Berlin, 2026-09-22 //
+///////////////////////////////////////////////////////////////////////////////
+
+Release 2.9.0 Mon October 5 2026
+ Security fixes:
+ #1392 CVE-2026-102633 -- Integer overflow in function
+ expat_realloc on 32bit platforms
+ #1393 CVE-2026-77214 -- Validate parameter `len` against available
+ buffer capacity in XML_ParseBuffer
+
+ Bug fixes:
+ #1387 lib: Handle OOM when copying encodingName in XML_ParserReset
+
+ New features:
+ #1327 lib: Introduce new "Properties API" to get and set
+ scalar properties for a single parser instance.
+ There are six new functions:
+ - XML_GetPropertyBool
+ - XML_GetPropertyDouble
+ - XML_GetPropertyUInt64
+ - XML_SetPropertyBool
+ - XML_SetPropertyDouble
+ - XML_SetPropertyUInt64
+ And two new enums:
+ - XML_Prop_Error
+ - XML_Parser_Property
+ #1323 lib: Introduce five new 64bit location API functions:
+ - XML_GetCurrentByteCount64
+ - XML_GetCurrentByteIndex64
+ - XML_GetCurrentColumnNumber64
+ - XML_GetCurrentLineNumber64
+ - XML_GetInputContext64
+ These five functions closely mirror their predecessors
+ but are not prone to 32bit integer wrap-around.
+
+ Other changes:
+ #1391 docs: Document the scope of function XML_GetErrorCode
+ #1395 docs: Document length expectations for XML_ParseBuffer
+ #1394 lib: Call unknown encoding release before parser teardown
+ #1370 #1373 lib: Drop (disabled-by-default) attribute info feature
+ These things are now gone:
+ - Public function XML_GetAttributeInfo
+ - Public struct XML_AttrInfo
+ - Macro XML_ATTR_INFO
+ These things are now causing build errors:
+ - Configure option --enable-xml-attr-info
+ - CMake option -DEXPAT_ATTR_INFO=ON
+ #1379 #1382 lib: Drop (disabled-by-default) minimum size feature
+ These things are now gone:
+ - Macro XML_MIN_SIZE
+ These things are now causing build errors:
+ - Configuring with -DXML_MIN_SIZE for CPPFLAGS/CFLAGS
+ - CMake option -DEXPAT_MIN_SIZE=ON
+ #1323 #1411 lib: Deprecate macro XML_LARGE_SIZE (use the new 64bit
+ location API functions instead please)
+ #1323 lib: Deprecate five location API functions that are cursed
+ with integer wrap-around:
+ - XML_GetCurrentByteCount
+ - XML_GetCurrentByteIndex
+ - XML_GetCurrentColumnNumber
+ - XML_GetCurrentLineNumber
+ - XML_GetInputContext
+ #1399 lib: Guard against out-of-handler use of XML_DefaultCurrent
+ #1400 lib: Use size_t for bytesAllocated and peakBytesAllocated
+ #1401 #1402 ..
+ #1404 #1405 lib|xmlwf|tests: Unify use of xcslen, xcscmp and xcsncmp
+ #1406 xmlwf: Add missing `#include "expat.h"`
+ #1389 #1396 Version info bumped from 13:5:12 (libexpat*.so.1.12.5)
+ to 14:0:13 (libexpat*.so.1.13.0); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #1386 CI: Bump MinGW Clang from 23.1.1 to 23.1.2
+ #1410 CI: Bump Fil-C from 0.685 to 0.686
+ #1388 CI: Adapt to breaking changes regarding windows-11-arm image
+ #1403 CI: Limit package cache download runtime
+
+ Special thanks to:
+ Bénédikt Tran
+ Berkay Eren Ürün
+ Fabian Wahle (Hap Security)
+ Filippo Tedeschi
+ Junki Lee
+ Matthew Fernandez
+ Scott Moore
+ Wade Sparks III
+ and
+ City of Munich Open Source Sabbatical
+ VulnCheck
Release 2.8.5 Tue September 22 2026
Security fixes:
@@ -33,17 +120,6 @@ Release 2.8.5 Tue September 22 2026
Upstream CVSS 3.1 vector:
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (CVSS score: 9.8)
-///////////////////////////////////////////////////////////////////////////////
-// The next release will drop two (disabled-by-default) features: //
-// //
-// - ATTR_INFO (-DXML_ATTR_INFO, -DEXPAT_ATTR_INFO, --enable-xml-attr-info, //
-// function XML_GetAttributeInfo, struct XML_AttrInfo) //
-// - MIN_SIZE (-DXML_MIN_SIZE, -DEXPAT_MIN_SIZE) //
-// //
-// If you need them in 2026 and beyond, please share your scenario at //
-// GitHub issues #1370 (for ATTR_INFO) and/or #1379 (for MIN_SIZE). Thanks! //
-///////////////////////////////////////////////////////////////////////////////
-
Bug fixes:
#1346 lib: Fix OOM-related memory leak on a failed overflow check
#1371 lib: Fix memory alignment for architectures with 128bit
diff --git a/contrib/expat/Makefile.in b/contrib/expat/Makefile.in
index c0a0eefc47ac..999ed2b231dc 100644
--- a/contrib/expat/Makefile.in
+++ b/contrib/expat/Makefile.in
@@ -345,12 +345,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -405,7 +403,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
diff --git a/contrib/expat/README.md b/contrib/expat/README.md
index 36e46a90fd23..1951645e8285 100644
--- a/contrib/expat/README.md
+++ b/contrib/expat/README.md
@@ -17,7 +17,7 @@
> Thank you! :heart: :pray:
-# Expat, Release 2.8.5
+# Expat, Release 2.9.0
This is Expat, a C99 library for parsing
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
diff --git a/contrib/expat/configure.ac b/contrib/expat/configure.ac
index e8562dbc5fc1..6d80021cf0a9 100644
--- a/contrib/expat/configure.ac
+++ b/contrib/expat/configure.ac
@@ -103,9 +103,9 @@ dnl
dnl If the API changes incompatibly set LIBAGE back to 0
dnl
-LIBCURRENT=13 # sync
-LIBREVISION=5 # with
-LIBAGE=12 # CMakeLists.txt!
+LIBCURRENT=14 # sync
+LIBREVISION=0 # with
+LIBAGE=13 # CMakeLists.txt!
AC_CONFIG_HEADERS([expat_config.h])
AH_TOP([#ifndef EXPAT_CONFIG_H
@@ -226,9 +226,11 @@ AM_CONDITIONAL([MINGW], [test x${EXPATCFG_ON_MINGW} = xyes])
dnl Note: Prefix "_INTERNAL_" here means exclusive use inside of file configure.ac
AM_CONDITIONAL([UNICODE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE >/dev/null])
AM_CONDITIONAL([_INTERNAL_UNICODE_WCHAR_T], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE_WCHAR_T >/dev/null])
-AM_CONDITIONAL([_INTERNAL_MIN_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_MIN_SIZE >/dev/null])
AM_CONDITIONAL([_INTERNAL_LARGE_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_LARGE_SIZE >/dev/null])
+AS_IF([echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_MIN_SIZE >/dev/null],
+ [AC_MSG_ERROR([Feature XML_MIN_SIZE has been removed. Please open a GitHub issue if you need it back.])])
+
LT_LIB_M
AC_ARG_WITH([arc4random],
@@ -428,13 +430,11 @@ AS_IF([test "x${with_dev_urandom}" = "xyes"],
AC_ARG_ENABLE([xml-attr-info],
- [AS_HELP_STRING([--enable-xml-attr-info],
- [Enable retrieving the byte offsets for attribute names and values @<:@default=no@:>@])],
+ [],
[],
[enable_xml_attr_info=no])
AS_IF([test "x${enable_xml_attr_info}" = "xyes"],
- [AC_DEFINE([XML_ATTR_INFO], 1,
- [Define to allow retrieving the byte offsets for attribute names and values.])])
+ [AC_MSG_ERROR([Feature --enable-xml-attr-info has been removed. Please open a GitHub issue if you need it back.])])
AC_ARG_ENABLE([xml-context],
AS_HELP_STRING([--enable-xml-context @<:@COUNT@:>@],
@@ -495,21 +495,12 @@ dnl Configure CMake file templates
dnl NOTE: The *_TRUE variables read here are Automake conditionals
dnl that are either set to "" when enabled or to "#" when disabled
dnl (because they are used to dynamically comment out certain things)
-AS_IF([test "x${enable_xml_attr_info}" = xyes],
- [EXPAT_ATTR_INFO=ON
- _EXPAT_COMMENT_ATTR_INFO=" "],
- [EXPAT_ATTR_INFO=OFF
- _EXPAT_COMMENT_ATTR_INFO="#"])
-AC_SUBST([_EXPAT_COMMENT_ATTR_INFO])
EXPAT_DTD=ON
_EXPAT_COMMENT_DTD_OR_GE=" "
AC_SUBST([_EXPAT_COMMENT_DTD_OR_GE])
AS_IF([test "x${_INTERNAL_LARGE_SIZE_TRUE}" = x],
[EXPAT_LARGE_SIZE=ON],
[EXPAT_LARGE_SIZE=OFF])
-AS_IF([test "x${_INTERNAL_MIN_SIZE_TRUE}" = x],
- [EXPAT_MIN_SIZE=ON],
- [EXPAT_MIN_SIZE=OFF])
EXPAT_NS=ON
AS_IF([test "x${enable_xml_context}" != xno],
[EXPAT_CONTEXT_BYTES=${enable_xml_context}],
@@ -525,10 +516,8 @@ LIBDIR_BASENAME="$(basename "${libdir}")"
SO_MAJOR="$(expr "${LIBCURRENT}" - "${LIBAGE}")"
SO_MINOR="${LIBAGE}"
SO_PATCH="${LIBREVISION}"
-AC_SUBST([EXPAT_ATTR_INFO])
AC_SUBST([EXPAT_DTD])
AC_SUBST([EXPAT_LARGE_SIZE])
-AC_SUBST([EXPAT_MIN_SIZE])
AC_SUBST([EXPAT_NS])
AC_SUBST([EXPAT_CONTEXT_BYTES])
AC_SUBST([EXPAT_CHAR_TYPE])
diff --git a/contrib/expat/doc/Makefile.in b/contrib/expat/doc/Makefile.in
index 52a18ffb673f..afe0b8d5c814 100644
--- a/contrib/expat/doc/Makefile.in
+++ b/contrib/expat/doc/Makefile.in
@@ -234,12 +234,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -294,7 +292,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
diff --git a/contrib/expat/doc/reference.html b/contrib/expat/doc/reference.html
index 5bd9150ea78a..2f892fd20b82 100644
--- a/contrib/expat/doc/reference.html
+++ b/contrib/expat/doc/reference.html
@@ -53,7 +53,7 @@
<body>
<div>
<h1>
- The Expat XML Parser <small>Release 2.8.5</small>
+ The Expat XML Parser <small>Release 2.9.0</small>
</h1>
</div>
@@ -309,22 +309,76 @@
<li>
<a href="#XML_GetCurrentByteIndex">XML_GetCurrentByteIndex</a>
+ (deprecated)
+ </li>
+
+ <li>
+ <a href="#XML_GetCurrentByteIndex64">XML_GetCurrentByteIndex64</a>
</li>
<li>
<a href="#XML_GetCurrentLineNumber">XML_GetCurrentLineNumber</a>
+ (deprecated)
+ </li>
+
+ <li>
+ <a href="#XML_GetCurrentLineNumber64">XML_GetCurrentLineNumber64</a>
</li>
<li>
<a href="#XML_GetCurrentColumnNumber">XML_GetCurrentColumnNumber</a>
+ (deprecated)
+ </li>
+
+ <li>
+ <a href=
+ "#XML_GetCurrentColumnNumber64">XML_GetCurrentColumnNumber64</a>
</li>
<li>
<a href="#XML_GetCurrentByteCount">XML_GetCurrentByteCount</a>
+ (deprecated)
+ </li>
+
+ <li>
+ <a href="#XML_GetCurrentByteCount64">XML_GetCurrentByteCount64</a>
</li>
<li>
- <a href="#XML_GetInputContext">XML_GetInputContext</a>
+ <a href="#XML_GetInputContext">XML_GetInputContext</a> (deprecated)
+ </li>
+
+ <li>
+ <a href="#XML_GetInputContext64">XML_GetInputContext64</a>
+ </li>
+ </ul>
+ </li>
+
+ <li>
+ <a href="#properties">Properties / Security Tuning</a>
+ <ul>
+ <li>
+ <a href="#XML_GetPropertyBool">XML_GetPropertyBool</a>
+ </li>
+
+ <li>
+ <a href="#XML_GetPropertyDouble">XML_GetPropertyDouble</a>
+ </li>
+
+ <li>
+ <a href="#XML_GetPropertyUInt64">XML_GetPropertyUInt64</a>
+ </li>
+
+ <li>
+ <a href="#XML_SetPropertyBool">XML_SetPropertyBool</a>
+ </li>
+
+ <li>
+ <a href="#XML_SetPropertyDouble">XML_SetPropertyDouble</a>
+ </li>
+
+ <li>
+ <a href="#XML_SetPropertyUInt64">XML_SetPropertyUInt64</a>
</li>
</ul>
</li>
@@ -392,10 +446,6 @@
</li>
<li>
- <a href="#XML_GetAttributeInfo">XML_GetAttributeInfo</a>
- </li>
-
- <li>
<a href="#XML_SetEncoding">XML_SetEncoding</a>
</li>
@@ -751,19 +801,59 @@ make install
</dd>
<dt>
- <a id="XML_LARGE_SIZE" name="XML_LARGE_SIZE">XML_LARGE_SIZE</a>
+ <a id="XML_LARGE_SIZE" name="XML_LARGE_SIZE">XML_LARGE_SIZE</a> (deprecated)
</dt>
<dd>
- If defined, causes the <code>XML_Size</code> and <code>XML_Index</code> integer
- types to be at least 64 bits in size. This is intended to support processing of
- very large input streams, where the return values of <code><a href=
- "#XML_GetCurrentByteIndex">XML_GetCurrentByteIndex</a></code>, <code><a href=
- "#XML_GetCurrentLineNumber">XML_GetCurrentLineNumber</a></code> and
- <code><a href=
- "#XML_GetCurrentColumnNumber">XML_GetCurrentColumnNumber</a></code> could
- overflow. It may not be supported by all compilers, and is turned off by
- default.
+ <p>
+ If defined, causes the <code>XML_Size</code> and <code>XML_Index</code>
+ integer types to be at least 64 bits in size. This is intended to support
+ processing of very large input streams, where the return values of
+ <code><a href="#XML_GetCurrentByteIndex">XML_GetCurrentByteIndex</a></code>,
+ <code><a href="#XML_GetCurrentLineNumber">XML_GetCurrentLineNumber</a></code>
+ and <code><a href=
+ "#XML_GetCurrentColumnNumber">XML_GetCurrentColumnNumber</a></code> could
+ overflow. It may not be supported by all compilers, and is turned off by
+ default.
+ </p>
+
+ <p>
+ Starting with Expat 2.9.0, there are 64bit versions of these functions, so
+ that relying on (non-default and uncommon) macro <code>XML_LARGE_SIZE</code>
+ is no longer needed. These functions are:
+ </p>
+
+ <ul>
+ <li>
+ <code><a href=
+ "#XML_GetCurrentByteIndex64">XML_GetCurrentByteIndex64</a></code>
+ </li>
+
+ <li>
+ <code><a href=
+ "#XML_GetCurrentColumnNumber64">XML_GetCurrentColumnNumber64</a></code>
+ </li>
+
+ <li>
+ <code><a href=
+ "#XML_GetCurrentLineNumber64">XML_GetCurrentLineNumber64</a></code>
+ </li>
+ </ul>
+
+ <p>
+ And there are two more that <code>XML_LARGE_SIZE</code> was not covering:
+ </p>
+
+ <ul>
+ <li>
+ <code><a href=
+ "#XML_GetCurrentByteCount64">XML_GetCurrentByteCount64</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_GetInputContext64">XML_GetInputContext64</a></code>
+ </li>
+ </ul>
</dd>
<dt>
@@ -790,16 +880,6 @@ make install
the code that calls it; this is required to get all the right MSVC magic
annotations correct. This is ignored on other platforms.
</dd>
-
- <dt>
- <a id="XML_ATTR_INFO" name="XML_ATTR_INFO">XML_ATTR_INFO</a>
- </dt>
-
- <dd>
- If defined, makes the additional function <code><a href=
- "#XML_GetAttributeInfo">XML_GetAttributeInfo</a></code> available for reporting
- attribute byte offsets.
- </dd>
</dl>
<hr />
@@ -1708,6 +1788,17 @@ XML_ParseBuffer(XML_Parser p,
</p>
<p>
+ <strong>Note:</strong> It is the responsibility of the application code to pass
+ a value for <code>len</code> that does not exceed the length of the remaining
+ unparsed XML content that was previously copied into the buffer obtained from
+ <code><a href="#XML_GetBuffer">XML_GetBuffer</a></code>. The documentation of
+ <code><a href="#XML_GetBuffer">XML_GetBuffer</a></code> below has an <a href=
+ "#XML_GetBuffer">example of typical use</a> of functions <code><a href=
+ "#XML_GetBuffer">XML_GetBuffer</a></code> and <code><a href=
+ "#XML_ParseBuffer">XML_ParseBuffer</a></code> in tandem.
+ </p>
+
+ <p>
Negative values for <code>len</code> are rejected since Expat 2.6.3.
</p>
</div>
@@ -2889,7 +2980,40 @@ enum XML_Error XMLCALL
XML_GetErrorCode(XML_Parser p);
</pre>
<div class="fcndef">
- Return what type of error has occurred.
+ <p>
+ Return what type of error has occurred inside the main Expat parsing machinery.
+ </p>
+
+ <p>
+ Only the following functions record the type of error for retrivial via
+ <code>XML_GetErrorCode</code>:
+ </p>
+
+ <ul>
+ <li>
+ <code><a href="#XML_GetBuffer">XML_GetBuffer</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_Parse">XML_Parse</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_ParseBuffer">XML_ParseBuffer</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_ParserReset">XML_ParserReset</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_ResumeParser">XML_ResumeParser</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_StopParser">XML_StopParser</a></code>
+ </li>
+ </ul>
</div>
<h4 id="XML_ErrorString">
@@ -2907,13 +3031,18 @@ XML_ErrorString(enum XML_Error code);
</div>
<h4 id="XML_GetCurrentByteIndex">
- XML_GetCurrentByteIndex
+ XML_GetCurrentByteIndex (deprecated)
</h4>
<pre class="fcndec">
XML_Index XMLCALL
XML_GetCurrentByteIndex(XML_Parser p);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_GetCurrentByteIndex64">XML_GetCurrentByteIndex64</a></code>, instead.
+ </p>
+
<div class="fcndef">
Return the byte offset of the position. This always corresponds to the values
returned by <code><a href=
@@ -2928,14 +3057,36 @@ XML_GetCurrentByteIndex(XML_Parser p);
"#XML_LARGE_SIZE">XML_LARGE_SIZE</a></code>.
</p>
+ <h4 id="XML_GetCurrentByteIndex64">
+ XML_GetCurrentByteIndex64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+int64_t XMLCALL
+XML_GetCurrentByteIndex64(XML_Parser p);
+</pre>
+ <div class="fcndef">
+ Return the byte offset of the position. This always corresponds to the values
+ returned by <code><a href=
+ "#XML_GetCurrentLineNumber64">XML_GetCurrentLineNumber64</a></code> and
+ <code><a href=
+ "#XML_GetCurrentColumnNumber64">XML_GetCurrentColumnNumber64</a></code>.
+ </div>
+
<h4 id="XML_GetCurrentLineNumber">
- XML_GetCurrentLineNumber
+ XML_GetCurrentLineNumber (deprecated)
</h4>
<pre class="fcndec">
XML_Size XMLCALL
XML_GetCurrentLineNumber(XML_Parser p);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_GetCurrentLineNumber64">XML_GetCurrentLineNumber64</a></code>, instead.
+ </p>
+
<div class="fcndef">
Return the line number of the position. The first line is reported as
<code>1</code>.
@@ -2948,14 +3099,33 @@ XML_GetCurrentLineNumber(XML_Parser p);
"#XML_LARGE_SIZE">XML_LARGE_SIZE</a></code>.
</p>
+ <h4 id="XML_GetCurrentLineNumber64">
+ XML_GetCurrentLineNumber64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+uint64_t XMLCALL
+XML_GetCurrentLineNumber64(XML_Parser p);
+</pre>
+ <div class="fcndef">
+ Return the line number of the position. The first line is reported as
+ <code>1</code>.
+ </div>
+
<h4 id="XML_GetCurrentColumnNumber">
- XML_GetCurrentColumnNumber
+ XML_GetCurrentColumnNumber (deprecated)
</h4>
<pre class="fcndec">
XML_Size XMLCALL
XML_GetCurrentColumnNumber(XML_Parser p);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_GetCurrentColumnNumber64">XML_GetCurrentColumnNumber64</a></code>, instead.
+ </p>
+
<div class="fcndef">
Return the <em>offset</em>, from the beginning of the current line, of the
position. The first column is reported as <code>0</code>.
@@ -2968,14 +3138,54 @@ XML_GetCurrentColumnNumber(XML_Parser p);
"#XML_LARGE_SIZE">XML_LARGE_SIZE</a></code>.
</p>
+ <h4 id="XML_GetCurrentColumnNumber64">
+ XML_GetCurrentColumnNumber64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+uint64_t XMLCALL
+XML_GetCurrentColumnNumber64(XML_Parser p);
+</pre>
+ <div class="fcndef">
+ Return the <em>offset</em>, from the beginning of the current line, of the
+ position. The first column is reported as <code>0</code>.
+ </div>
+
<h4 id="XML_GetCurrentByteCount">
- XML_GetCurrentByteCount
+ XML_GetCurrentByteCount (deprecated)
</h4>
<pre class="fcndec">
int XMLCALL
XML_GetCurrentByteCount(XML_Parser p);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_GetCurrentByteCount64">XML_GetCurrentByteCount64</a></code>, instead.
+ </p>
+
+ <div class="fcndef">
+ Return the number of bytes in the current event. Returns <code>0</code> if the
+ event is inside a reference to an internal entity and for the end-tag event for
+ empty element tags (the later can be used to distinguish empty-element tags from
+ empty elements using separate start and end tags).
+ </div>
+
+ <p>
+ <strong>Note:</strong> Type <code>int</code> is known to wrap around (on both
+ 32bit platforms and 64bit platforms).
+ </p>
+
+ <h4 id="XML_GetCurrentByteCount64">
+ XML_GetCurrentByteCount64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+uint64_t XMLCALL
+XML_GetCurrentByteCount64(XML_Parser p);
+</pre>
<div class="fcndef">
Return the number of bytes in the current event. Returns <code>0</code> if the
event is inside a reference to an internal entity and for the end-tag event for
@@ -2984,7 +3194,7 @@ XML_GetCurrentByteCount(XML_Parser p);
</div>
<h4 id="XML_GetInputContext">
- XML_GetInputContext
+ XML_GetInputContext (deprecated)
</h4>
<pre class="fcndec">
@@ -2993,6 +3203,53 @@ XML_GetInputContext(XML_Parser p,
int *offset,
int *size);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_GetInputContext64">XML_GetInputContext64</a></code>, instead.
+ </p>
+
+ <div class="fcndef">
+ <p>
+ Returns the parser's input buffer, sets the integer pointed at by
+ <code>offset</code> to the offset within this buffer of the current parse
+ position, and set the integer pointed at by <code>size</code> to the size of
+ the returned buffer.
+ </p>
+
+ <p>
+ This should only be called from within a handler during an active parse and the
+ returned buffer should only be referred to from within the handler that made
+ the call. This input buffer contains the untranslated bytes of the input.
+ </p>
+
+ <p>
+ Only a limited amount of context is kept, so if the event triggering a call
+ spans over a very large amount of input, the actual parse position may be
+ before the beginning of the buffer.
+ </p>
+
+ <p>
+ If <code>XML_CONTEXT_BYTES</code> is zero, this will always return
+ <code>NULL</code>.
+ </p>
+
+ <p>
+ <strong>Note:</strong> Type <code>int</code> is known to wrap around (on both
+ 32bit platforms and 64bit platforms).
+ </p>
+ </div>
+
+ <h4 id="XML_GetInputContext64">
+ XML_GetInputContext64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+const char * XMLCALL
+XML_GetInputContext64(XML_Parser p,
+ int64_t *offset,
+ zint64_t *size);
+</pre>
<div class="fcndef">
<p>
Returns the parser's input buffer, sets the integer pointed at by
@@ -3020,10 +3277,389 @@ XML_GetInputContext(XML_Parser p,
</div>
<h3>
+ <a id="properties" name="properties">Properties / Security Tuning</a>
+ </h3>
+
+ <p>
+ Expat 2.9.0 introduced a new Properties API. Think of properties as the control
+ knobs of a parser. The key motivations behind its introduction are:
+ </p>
+
+ <ul>
+ <li>to allow Expat to add more properties — both security-related and non-
+ security ones — in the future (without need to also add new related getter and
+ setter functions for each of them as was the case in the past),
+ </li>
+
+ <li>to allow users to read (not just to set) the current values, and
+ </li>
+
+ <li>to allow users to distinuish the different sources of error beyond a mere
+ "did not work".
+ </li>
+ </ul>
+
+ <p>
+ There is one setter function and one getter function — a pair — per supported
+ data type:
+ </p>
+
+ <ul>
+ <li>For <code>XML_Bool</code>:
+ <ul>
+ <li>
+ <code><a href="#XML_GetPropertyBool">XML_GetPropertyBool</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_SetPropertyBool">XML_SetPropertyBool</a></code>
+ </li>
+ </ul>
+ </li>
+
+ <li>For <code>double</code>:
+ <ul>
+ <li>
+ <code><a href="#XML_GetPropertyDouble">XML_GetPropertyDouble</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_SetPropertyDouble">XML_SetPropertyDouble</a></code>
+ </li>
+ </ul>
+ </li>
+
+ <li>For <code>uint64_t</code>:
+ <ul>
+ <li>
+ <code><a href="#XML_GetPropertyUInt64">XML_GetPropertyUInt64</a></code>
+ </li>
+
+ <li>
+ <code><a href="#XML_SetPropertyUInt64">XML_SetPropertyUInt64</a></code>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>
+ They all share these two key enums:
+ </p>
+
+ <h4 id="XML_Parser_Property">
+ XML_Parser_Property
+ </h4>
+
+ <pre>
+/* Added in Expat 2.9.0. */
+enum XML_Parser_Property {
+# if XML_GE == 1
+ XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD = 1, // of type `uint64_t`
+ XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION = 2, // of type `double`
+ XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD = 3, // of type `uint64_t`
+ XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION = 4, // of type `double`
+# endif
+ XML_PROP_REPARSE_DEFERRAL_ENABLED = 5, // of type `XML_Bool`
+ /* more properties upcoming here */
+};</pre>
+ <h4 id="XML_Prop_Error">
+ XML_Prop_Error
+ </h4>
+
+ <pre>
+/* Added in 2.9.0. */
+enum XML_Prop_Error {
+ XML_PROP_ERROR_NONE = 0, // i.e. success
+
+ XML_PROP_ERROR_INVALID_KEY = 1, // i.e. the property is not known at all
+ XML_PROP_ERROR_INVALID_TYPE = 2, // i.e. the property is known but expects a
+ // different type (so a different
+ // getter/setter would need to be called)
+ XML_PROP_ERROR_INVALID_VALUE = 3, // i.e. the value is invalid (with a setter
+ // function) or a NULL-pointer (with a
+ // getter function)
+
+ XML_PROP_ERROR_PARSER_NULL = 4, // i.e. the parser argument is NULL
+ XML_PROP_ERROR_PARSER_NOT_ROOT = 5, // i.e. the parser is not a root parser
+ // but a subparser (and a root parser is
+ // needed)
+
+ /* potentially more error codes upcoming here */
+};</pre>
+ <p>
+ Let us look at these functions in more detail:
+ </p>
+
+ <h4 id="XML_GetPropertyBool">
+ XML_GetPropertyBool
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_GetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool *value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Writes the current value of boolean property <code>property</code> of parser
+ <code>parser</code> to output variable <code>value</code>. Supported properties
+ are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_REPARSE_DEFERRAL_ENABLED</code> — whether <a href=
+ "#XML_SetReparseDeferralEnabled">reparse deferral</a> is active or not
+ </li>
+ </ul>
+
+ <p>
+ Both parameters <code>parser</code> and <code>value</code> must be
+ non-<code>NULL</code>. On success <code>XML_PROP_ERROR_NONE</code> is returned;
+ on error one of the other variants of <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
+ <h4 id="XML_GetPropertyDouble">
+ XML_GetPropertyDouble
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_GetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double *value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Writes the current value of floating point property <code>property</code> of
+ parser <code>parser</code> to output variable <code>value</code>. Supported
+ properties are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION</code> — the maximum
+ tolerated amplification with the <a href=
+ "#XML_SetAllocTrackerMaximumAmplification">allocation tracker</a>
+ </li>
+
+ <li>
+ <code>XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION</code> — the maximum
+ tolerated amplification with <a href=
+ "#XML_SetBillionLaughsAttackProtectionMaximumAmplification">billion laughs
+ attack protection</a>
+ </li>
+ </ul>
+
+ <p>
+ Both parameters <code>parser</code> and <code>value</code> must be
+ non-<code>NULL</code>. On success <code>XML_PROP_ERROR_NONE</code> is returned;
+ on error one of the other variants of <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
+ <h4 id="XML_GetPropertyUInt64">
+ XML_GetPropertyUInt64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_GetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t *value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Writes the current value of integral property <code>property</code> of parser
+ <code>parser</code> to output variable <code>value</code>. Supported properties
+ are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD</code> — the activation
+ threshold in bytes with the <a href=
+ "#XML_SetAllocTrackerActivationThreshold">allocation tracker</a>
+ </li>
+
+ <li>
+ <code>XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD</code> — the activation
+ threshold in bytes with <a href=
+ "#XML_SetBillionLaughsAttackProtectionActivationThreshold">billion laughs
+ attack protection</a>
+ </li>
+ </ul>
+
+ <p>
+ Both parameters <code>parser</code> and <code>value</code> must be
+ non-<code>NULL</code>. On success <code>XML_PROP_ERROR_NONE</code> is returned;
+ on error one of the other variants of <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
+ <h3>
<a id="attack-protection" name="attack-protection">Attack Protection</a><a id=
"billion-laughs" name="billion-laughs"></a>
</h3>
+ <h4 id="XML_SetPropertyBool">
+ XML_SetPropertyBool
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_SetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Applies the given value <code>value</code> to boolean property
+ <code>property</code> of parser <code>parser</code>. Supported properties are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_REPARSE_DEFERRAL_ENABLED</code> — whether <a href=
+ "#XML_SetReparseDeferralEnabled">reparse deferral</a> is active or not
+ </li>
+ </ul>
+
+ <p>
+ Parameter <code>parser</code> must be non-<code>NULL</code>. On success
+ <code>XML_PROP_ERROR_NONE</code> is returned; on error one of the other
+ variants of <a href="#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
+ <h4 id="XML_SetPropertyDouble">
+ XML_SetPropertyDouble
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_SetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Applies the given value <code>value</code> to floating point property
+ <code>property</code> of parser <code>parser</code>. Supported properties are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION</code> — the maximum
+ tolerated amplification with the <a href=
+ "#XML_SetAllocTrackerMaximumAmplification">allocation tracker</a>
+ </li>
+
+ <li>
+ <code>XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION</code> — the maximum
+ tolerated amplification with <a href=
+ "#XML_SetBillionLaughsAttackProtectionMaximumAmplification">billion laughs
+ attack protection</a>
+ </li>
+ </ul>
+
+ <p>
+ Value <code>value</code> may or may not be cast to <code>float</code>
+ internally.
+ </p>
+
+ <p>
+ Parameter <code>parser</code> must be non-<code>NULL</code>. On success
+ <code>XML_PROP_ERROR_NONE</code> is returned; on error one of the other
+ variants of <a href="#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
+ <h4 id="XML_SetPropertyUInt64">
+ XML_SetPropertyUInt64
+ </h4>
+
+ <pre class="fcndec">
+/* Added in Expat 2.9.0. */
+enum XML_Prop_Error
+XML_SetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t value);
+</pre>
+ <div class="fcndef">
+ <p>
+ Applies the given value <code>value</code> to integral property
+ <code>property</code> of parser <code>parser</code>. Supported properties are:
+ </p>
+
+ <ul>
+ <li>
+ <code>XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD</code> — the activation
+ threshold in bytes with the <a href=
+ "#XML_SetAllocTrackerActivationThreshold">allocation tracker</a>
+ </li>
+
+ <li>
+ <code>XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD</code> — the activation
+ threshold in bytes with <a href=
+ "#XML_SetBillionLaughsAttackProtectionActivationThreshold">billion laughs
+ attack protection</a>
+ </li>
+ </ul>
+
+ <p>
+ Parameter <code>parser</code> must be non-<code>NULL</code>. On success
+ <code>XML_PROP_ERROR_NONE</code> is returned; on error one of the other
+ variants of <a href="#XML_Prop_Error">XML_Prop_Error</a> is returned.
+ </p>
+
+ <p>
+ <strong>Note:</strong> There may be more error codes introduced into <a href=
+ "#XML_Prop_Error">XML_Prop_Error</a> in the future, so user code must be robust
+ towards error codes from the future at runtime that were not known at compile
+ time.
+ </p>
+ </div>
+
<h4 id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">
XML_SetBillionLaughsAttackProtectionMaximumAmplification
</h4>
@@ -3405,38 +4041,6 @@ XML_GetIdAttributeIndex(XML_Parser p);
means the current call.
</div>
- <h4 id="XML_GetAttributeInfo">
- XML_GetAttributeInfo
- </h4>
-
- <pre class="fcndec">
-const XML_AttrInfo * XMLCALL
-XML_GetAttributeInfo(XML_Parser parser);
-</pre>
-
- <pre class="signature">
-typedef struct {
- XML_Index nameStart; /* Offset to beginning of the attribute name. */
- XML_Index nameEnd; /* Offset after the attribute name's last byte. */
- XML_Index valueStart; /* Offset to beginning of the attribute value. */
- XML_Index valueEnd; /* Offset after the attribute value's last byte. */
-} XML_AttrInfo;
-</pre>
- <div class="fcndef">
- Returns an array of <code>XML_AttrInfo</code> structures for the attribute/value
- pairs passed in the last call to the <code>XML_StartElementHandler</code> that
- were specified in the start-tag rather than defaulted. Each attribute/value pair
- counts as 1; thus the number of entries in the array is
- <code>XML_GetSpecifiedAttributeCount(parser) / 2</code>.
- </div>
-
- <p>
- <strong>Note:</strong> Type <code>XML_Index</code> is known to wrap around on
- 32bit platforms and 64bit Windows unless Expat has been compiled with
- (non-default and uncommon) macro <code><a href=
- "#XML_LARGE_SIZE">XML_LARGE_SIZE</a></code>.
- </p>
-
<h4 id="XML_SetEncoding">
XML_SetEncoding
</h4>
@@ -3495,6 +4099,11 @@ int XMLCALL
XML_SetHashSalt(XML_Parser parser,
unsigned long hash_salt);
</pre>
+ <p>
+ <b>Note:</b> This function is deprecated, please use function <code><a href=
+ "#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></code>, instead.
+ </p>
+
<div class="fcndef">
Sets the hash salt to use for internal hash calculations. Helps in preventing DoS
attacks based on predicting hash function behavior. In order to have an effect
@@ -3502,15 +4111,13 @@ XML_SetHashSalt(XML_Parser parser,
called after <code>XML_Parse</code> or <code>XML_ParseBuffer</code> or when
<code>parser</code> is <code>NULL</code>.
<p>
- <b>Note:</b> Function <code>XML_SetHashSalt</code> is
- <strong>deprecated</strong>. Please use function <code><a href=
- "#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></code> instead for better
- security. <code>XML_SetHashSalt</code> only provides 4 to 8 bytes of entropy
- (depending on the size of type <code>unsigned long</code>) while the SipHash
- implementation used by Expat can leverage up to 16 bytes of entropy — at least
- twice as much. Function <code><a href=
+ <b>Note:</b> Function <code>XML_SetHashSalt</code> only provides 4 to 8 bytes
+ of entropy (depending on the size of type <code>unsigned long</code>) while the
+ SipHash implementation used by Expat can leverage up to 16 bytes of entropy —
+ at least twice as much. Function <code><a href=
"#XML_SetHashSalt16Bytes">XML_SetHashSalt16Bytes</a></code> of Expat &gt;=2.8.0
- (and where backported) matches the amount of entropy supported by SipHash.
+ (and where backported) with better security matches the amount of entropy
+ supported by SipHash.
</p>
<p>
@@ -3710,6 +4317,7 @@ enum XML_FeatureEnum {
XML_FEATURE_UNICODE_WCHAR_T,
XML_FEATURE_DTD,
XML_FEATURE_CONTEXT_BYTES,
+ /* Added in Expat 1.95.5, removed in Expat 2.9.0. */
XML_FEATURE_MIN_SIZE,
XML_FEATURE_SIZEOF_XML_CHAR,
XML_FEATURE_SIZEOF_XML_LCHAR,
@@ -3717,7 +4325,7 @@ enum XML_FeatureEnum {
XML_FEATURE_NS,
/* Added in Expat 2.0.1. */
XML_FEATURE_LARGE_SIZE,
- /* Added in Expat 2.1.0. */
+ /* Added in Expat 2.1.0, removed in Expat 2.9.0. */
XML_FEATURE_ATTR_INFO,
/* Added in Expat 2.4.0. */
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
diff --git a/contrib/expat/doc/xmlwf.1 b/contrib/expat/doc/xmlwf.1
index e9b6a2fe4610..22ca1d387b5f 100644
--- a/contrib/expat/doc/xmlwf.1
+++ b/contrib/expat/doc/xmlwf.1
@@ -5,7 +5,7 @@
\\$2 \(la\\$1\(ra\\$3
..
.if \n(.g .mso www.tmac
-.TH XMLWF 1 "September 22, 2026" "" ""
+.TH XMLWF 1 "October 5, 2026" "" ""
.SH NAME
xmlwf \- Determines if an XML document is well-formed
.SH SYNOPSIS
diff --git a/contrib/expat/doc/xmlwf.xml b/contrib/expat/doc/xmlwf.xml
index e7a2664b7e42..06880749583b 100644
--- a/contrib/expat/doc/xmlwf.xml
+++ b/contrib/expat/doc/xmlwf.xml
@@ -21,7 +21,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
<!ENTITY dhsurname "<surname>Bronson</surname>">
- <!ENTITY dhdate "<date>September 22, 2026</date>">
+ <!ENTITY dhdate "<date>October 5, 2026</date>">
<!-- Please adjust this^^ date whenever cutting a new release. -->
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
<!ENTITY dhemail "<email>bronson@rinspin.com</email>">
diff --git a/contrib/expat/examples/Makefile.in b/contrib/expat/examples/Makefile.in
index 4ef878f7867c..d1973eeab7b0 100644
--- a/contrib/expat/examples/Makefile.in
+++ b/contrib/expat/examples/Makefile.in
@@ -262,12 +262,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -322,7 +320,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
diff --git a/contrib/expat/examples/element_declarations.c b/contrib/expat/examples/element_declarations.c
index ea790f4932b4..3d010d341cdc 100644
--- a/contrib/expat/examples/element_declarations.c
+++ b/contrib/expat/examples/element_declarations.c
@@ -12,7 +12,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
- Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
Copyright (c) 2024 Hanno Böck <hanno@gentoo.org>
@@ -41,17 +41,12 @@
SPDX-License-Identifier: MIT
*/
+#include <inttypes.h> // PRIu64
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <expat.h>
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
#ifdef XML_UNICODE_WCHAR_T
# define XML_FMT_STR "ls"
#else
@@ -225,9 +220,8 @@ main(void) {
if (errorCode == XML_ERROR_ABORTED) {
errorCode = XML_ERROR_NO_MEMORY;
}
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser), XML_ErrorString(errorCode));
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser), XML_ErrorString(errorCode));
XML_ParserFree(parser);
return 1;
}
diff --git a/contrib/expat/examples/elements.c b/contrib/expat/examples/elements.c
index ef7baeae5646..7df0d1940a19 100644
--- a/contrib/expat/examples/elements.c
+++ b/contrib/expat/examples/elements.c
@@ -14,7 +14,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2004-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
- Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2019 Zhongyuan Zhou <zhouzhongyuan@huawei.com>
Licensed under the MIT license:
@@ -41,15 +41,10 @@
SPDX-License-Identifier: MIT
*/
+#include <inttypes.h> // PRIu64
#include <stdio.h>
#include <expat.h>
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
#ifdef XML_UNICODE_WCHAR_T
# define XML_FMT_STR "ls"
#else
@@ -109,9 +104,8 @@ main(void) {
done = feof(stdin);
if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser),
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 1;
diff --git a/contrib/expat/examples/outline.c b/contrib/expat/examples/outline.c
index 3168fab612cc..ba9bea447599 100644
--- a/contrib/expat/examples/outline.c
+++ b/contrib/expat/examples/outline.c
@@ -12,7 +12,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2006 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
@@ -38,15 +38,10 @@
SPDX-License-Identifier: MIT
*/
+#include <inttypes.h> // PRIu64
#include <stdio.h>
#include <expat.h>
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
#ifdef XML_UNICODE_WCHAR_T
# define XML_FMT_STR "ls"
#else
@@ -112,9 +107,8 @@ main(void) {
done = feof(stdin);
if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser),
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 1;
diff --git a/contrib/expat/expat_config.h.in b/contrib/expat/expat_config.h.in
index 4d7d732e8052..b786029da5e8 100644
--- a/contrib/expat/expat_config.h.in
+++ b/contrib/expat/expat_config.h.in
@@ -113,10 +113,6 @@
# endif
#endif
-/* Define to allow retrieving the byte offsets for attribute names and values.
- */
-#undef XML_ATTR_INFO
-
/* Define to specify how much context to retain around the current parse
point, 0 to disable. */
#undef XML_CONTEXT_BYTES
diff --git a/contrib/expat/fuzz/xml_parse_fuzzer.c b/contrib/expat/fuzz/xml_parse_fuzzer.c
index 1eb0ad299628..8e9dfd79513d 100644
--- a/contrib/expat/fuzz/xml_parse_fuzzer.c
+++ b/contrib/expat/fuzz/xml_parse_fuzzer.c
@@ -79,7 +79,7 @@ ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
if (XML_Parse(p, (const XML_Char *)data, (int)size, 1) == XML_STATUS_ERROR) {
XML_ErrorString(XML_GetErrorCode(p));
}
- XML_GetCurrentLineNumber(p);
+ XML_GetCurrentLineNumber64(p);
if (size % 2) {
XML_ParserReset(p, NULL);
}
diff --git a/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c b/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c
index a854f6706396..eec39241e222 100644
--- a/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c
+++ b/contrib/expat/fuzz/xml_parsebuffer_fuzzer.c
@@ -87,7 +87,7 @@ ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
if (XML_ParseBuffer(p, (int)size, 1) == XML_STATUS_ERROR) {
XML_ErrorString(XML_GetErrorCode(p));
}
- XML_GetCurrentLineNumber(p);
+ XML_GetCurrentLineNumber64(p);
if (size % 2) {
XML_ParserReset(p, NULL);
}
diff --git a/contrib/expat/lib/Makefile.am b/contrib/expat/lib/Makefile.am
index 6b0d0af4e3c5..e4211b4dd3f9 100644
--- a/contrib/expat/lib/Makefile.am
+++ b/contrib/expat/lib/Makefile.am
@@ -53,6 +53,7 @@ libexpat_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@builddir@/libexpat.map
endif
libexpat_la_SOURCES = \
+ xcs.c \
xmlparse.c \
xmltok.c \
xmlrole.c
@@ -125,7 +126,7 @@ EXTRA_DIST = \
siphash.h \
utf8tab.h \
winconfig.h \
- xcsinc.c \
+ xcs.h \
xmlrole.h \
xmltok.h \
xmltok_impl.c \
diff --git a/contrib/expat/lib/Makefile.in b/contrib/expat/lib/Makefile.in
index 58b19912b596..4e5bb0bfd966 100644
--- a/contrib/expat/lib/Makefile.in
+++ b/contrib/expat/lib/Makefile.in
@@ -206,7 +206,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" \
"$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
libexpat_la_LIBADD =
-am__libexpat_la_SOURCES_DIST = xmlparse.c xmltok.c xmlrole.c \
+am__libexpat_la_SOURCES_DIST = xcs.c xmlparse.c xmltok.c xmlrole.c \
random_arc4random.c random_arc4random.h \
random_arc4random_buf.c random_arc4random_buf.h \
random_dev_urandom.c random_dev_urandom.h random_getentropy.c \
@@ -218,7 +218,7 @@ am__libexpat_la_SOURCES_DIST = xmlparse.c xmltok.c xmlrole.c \
@WITH_GETENTROPY_TRUE@am__objects_4 = random_getentropy.lo
@WITH_EITHER_GETRANDOM_TRUE@am__objects_5 = random_getrandom.lo
@MINGW_TRUE@am__objects_6 = random_rand_s.lo
-am_libexpat_la_OBJECTS = xmlparse.lo xmltok.lo xmlrole.lo \
+am_libexpat_la_OBJECTS = xcs.lo xmlparse.lo xmltok.lo xmlrole.lo \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6)
libexpat_la_OBJECTS = $(am_libexpat_la_OBJECTS)
@@ -230,7 +230,7 @@ libexpat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libexpat_la_LDFLAGS) $(LDFLAGS) -o $@
libtestpat_la_LIBADD =
-am__libtestpat_la_SOURCES_DIST = xmlparse.c xmltok.c xmlrole.c \
+am__libtestpat_la_SOURCES_DIST = xcs.c xmlparse.c xmltok.c xmlrole.c \
random_arc4random.c random_arc4random.h \
random_arc4random_buf.c random_arc4random_buf.h \
random_dev_urandom.c random_dev_urandom.h random_getentropy.c \
@@ -245,10 +245,10 @@ am__libtestpat_la_SOURCES_DIST = xmlparse.c xmltok.c xmlrole.c \
@WITH_EITHER_GETRANDOM_TRUE@am__objects_11 = \
@WITH_EITHER_GETRANDOM_TRUE@ libtestpat_la-random_getrandom.lo
@MINGW_TRUE@am__objects_12 = libtestpat_la-random_rand_s.lo
-am__objects_13 = libtestpat_la-xmlparse.lo libtestpat_la-xmltok.lo \
- libtestpat_la-xmlrole.lo $(am__objects_7) $(am__objects_8) \
- $(am__objects_9) $(am__objects_10) $(am__objects_11) \
- $(am__objects_12)
+am__objects_13 = libtestpat_la-xcs.lo libtestpat_la-xmlparse.lo \
+ libtestpat_la-xmltok.lo libtestpat_la-xmlrole.lo \
+ $(am__objects_7) $(am__objects_8) $(am__objects_9) \
+ $(am__objects_10) $(am__objects_11) $(am__objects_12)
@WITH_TESTS_TRUE@am_libtestpat_la_OBJECTS = $(am__objects_13)
libtestpat_la_OBJECTS = $(am_libtestpat_la_OBJECTS)
@WITH_TESTS_TRUE@am_libtestpat_la_rpath =
@@ -273,6 +273,7 @@ am__depfiles_remade = ./$(DEPDIR)/libtestpat_la-random_arc4random.Plo \
./$(DEPDIR)/libtestpat_la-random_getentropy.Plo \
./$(DEPDIR)/libtestpat_la-random_getrandom.Plo \
./$(DEPDIR)/libtestpat_la-random_rand_s.Plo \
+ ./$(DEPDIR)/libtestpat_la-xcs.Plo \
./$(DEPDIR)/libtestpat_la-xmlparse.Plo \
./$(DEPDIR)/libtestpat_la-xmlrole.Plo \
./$(DEPDIR)/libtestpat_la-xmltok.Plo \
@@ -281,8 +282,8 @@ am__depfiles_remade = ./$(DEPDIR)/libtestpat_la-random_arc4random.Plo \
./$(DEPDIR)/random_dev_urandom.Plo \
./$(DEPDIR)/random_getentropy.Plo \
./$(DEPDIR)/random_getrandom.Plo ./$(DEPDIR)/random_rand_s.Plo \
- ./$(DEPDIR)/xmlparse.Plo ./$(DEPDIR)/xmlrole.Plo \
- ./$(DEPDIR)/xmltok.Plo
+ ./$(DEPDIR)/xcs.Plo ./$(DEPDIR)/xmlparse.Plo \
+ ./$(DEPDIR)/xmlrole.Plo ./$(DEPDIR)/xmltok.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -369,12 +370,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -429,7 +428,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -497,9 +495,9 @@ lib_LTLIBRARIES = libexpat.la
@WITH_TESTS_TRUE@noinst_LTLIBRARIES = libtestpat.la
libexpat_la_LDFLAGS = @AM_LDFLAGS@ @LIBM@ -no-undefined -version-info \
@LIBCURRENT@:@LIBREVISION@:@LIBAGE@ $(am__append_1)
-libexpat_la_SOURCES = xmlparse.c xmltok.c xmlrole.c $(am__append_2) \
- $(am__append_3) $(am__append_4) $(am__append_5) \
- $(am__append_6) $(am__append_7)
+libexpat_la_SOURCES = xcs.c xmlparse.c xmltok.c xmlrole.c \
+ $(am__append_2) $(am__append_3) $(am__append_4) \
+ $(am__append_5) $(am__append_6) $(am__append_7)
@WITH_TESTS_TRUE@libtestpat_la_CPPFLAGS = -DXML_TESTING
@WITH_TESTS_TRUE@libtestpat_la_SOURCES = $(libexpat_la_SOURCES)
doc_DATA = \
@@ -522,7 +520,7 @@ EXTRA_DIST = \
siphash.h \
utf8tab.h \
winconfig.h \
- xcsinc.c \
+ xcs.h \
xmlrole.h \
xmltok.h \
xmltok_impl.c \
@@ -625,6 +623,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-random_getentropy.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-random_getrandom.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-random_rand_s.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-xcs.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-xmlparse.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-xmlrole.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestpat_la-xmltok.Plo@am__quote@ # am--include-marker
@@ -634,6 +633,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random_getentropy.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random_getrandom.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random_rand_s.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcs.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlparse.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlrole.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmltok.Plo@am__quote@ # am--include-marker
@@ -668,6 +668,13 @@ am--depfiles: $(am__depfiles_remade)
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+libtestpat_la-xcs.lo: xcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestpat_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libtestpat_la-xcs.lo -MD -MP -MF $(DEPDIR)/libtestpat_la-xcs.Tpo -c -o libtestpat_la-xcs.lo `test -f 'xcs.c' || echo '$(srcdir)/'`xcs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestpat_la-xcs.Tpo $(DEPDIR)/libtestpat_la-xcs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xcs.c' object='libtestpat_la-xcs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestpat_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libtestpat_la-xcs.lo `test -f 'xcs.c' || echo '$(srcdir)/'`xcs.c
+
libtestpat_la-xmlparse.lo: xmlparse.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestpat_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libtestpat_la-xmlparse.lo -MD -MP -MF $(DEPDIR)/libtestpat_la-xmlparse.Tpo -c -o libtestpat_la-xmlparse.lo `test -f 'xmlparse.c' || echo '$(srcdir)/'`xmlparse.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestpat_la-xmlparse.Tpo $(DEPDIR)/libtestpat_la-xmlparse.Plo
@@ -914,6 +921,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libtestpat_la-random_getentropy.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-random_getrandom.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-random_rand_s.Plo
+ -rm -f ./$(DEPDIR)/libtestpat_la-xcs.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmlparse.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmlrole.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmltok.Plo
@@ -923,6 +931,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/random_getentropy.Plo
-rm -f ./$(DEPDIR)/random_getrandom.Plo
-rm -f ./$(DEPDIR)/random_rand_s.Plo
+ -rm -f ./$(DEPDIR)/xcs.Plo
-rm -f ./$(DEPDIR)/xmlparse.Plo
-rm -f ./$(DEPDIR)/xmlrole.Plo
-rm -f ./$(DEPDIR)/xmltok.Plo
@@ -978,6 +987,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libtestpat_la-random_getentropy.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-random_getrandom.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-random_rand_s.Plo
+ -rm -f ./$(DEPDIR)/libtestpat_la-xcs.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmlparse.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmlrole.Plo
-rm -f ./$(DEPDIR)/libtestpat_la-xmltok.Plo
@@ -987,6 +997,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/random_getentropy.Plo
-rm -f ./$(DEPDIR)/random_getrandom.Plo
-rm -f ./$(DEPDIR)/random_rand_s.Plo
+ -rm -f ./$(DEPDIR)/xcs.Plo
-rm -f ./$(DEPDIR)/xmlparse.Plo
-rm -f ./$(DEPDIR)/xmlrole.Plo
-rm -f ./$(DEPDIR)/xmltok.Plo
diff --git a/contrib/expat/lib/expat.h b/contrib/expat/lib/expat.h
index 4c3851d50a5f..1b2852dd76cb 100644
--- a/contrib/expat/lib/expat.h
+++ b/contrib/expat/lib/expat.h
@@ -48,7 +48,7 @@
#ifndef Expat_INCLUDED
# define Expat_INCLUDED 1
-# include <stdint.h> // for uint8_t
+# include <stdint.h> // for int64_t, uint8_t, uint64_t
# include <stdlib.h>
# include "expat_external.h"
@@ -140,6 +140,26 @@ enum XML_Error {
XML_ERROR_NOT_STARTED,
};
+/* Added in 2.9.0. */
+enum XML_Prop_Error {
+ XML_PROP_ERROR_NONE = 0, // i.e. success
+
+ XML_PROP_ERROR_INVALID_KEY = 1, // i.e. the property is not known at all
+ XML_PROP_ERROR_INVALID_TYPE = 2, // i.e. the property is known but expects a
+ // different type (so a different
+ // getter/setter would need to be called)
+ XML_PROP_ERROR_INVALID_VALUE = 3, // i.e. the value is invalid (with a setter
+ // function) or a NULL-pointer (with a
+ // getter function)
+
+ XML_PROP_ERROR_PARSER_NULL = 4, // i.e. the parser argument is NULL
+ XML_PROP_ERROR_PARSER_NOT_ROOT = 5, // i.e. the parser is not a root parser
+ // but a subparser (and a root parser is
+ // needed)
+
+ /* potentially more error codes upcoming here */
+};
+
enum XML_Content_Type {
XML_CTYPE_EMPTY = 1,
XML_CTYPE_ANY,
@@ -757,29 +777,6 @@ XML_GetSpecifiedAttributeCount(XML_Parser parser);
XMLPARSEAPI(int)
XML_GetIdAttributeIndex(XML_Parser parser);
-# ifdef XML_ATTR_INFO
-/* Source file byte offsets for the start and end of attribute names and values.
- The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
- file an attribute value of "blah" will yield:
- info->valueEnd - info->valueStart = 4 bytes.
-*/
-typedef struct {
- XML_Index nameStart; /* Offset to beginning of the attribute name. */
- XML_Index nameEnd; /* Offset after the attribute name's last byte. */
- XML_Index valueStart; /* Offset to beginning of the attribute value. */
- XML_Index valueEnd; /* Offset after the attribute value's last byte. */
-} XML_AttrInfo;
-
-/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
- passed in last call to the XML_StartElementHandler that were specified
- in the start-tag rather than defaulted. Each attribute/value pair counts
- as 1; thus the number of entries in the array is
- XML_GetSpecifiedAttributeCount(parser) / 2.
-*/
-XMLPARSEAPI(const XML_AttrInfo *)
-XML_GetAttributeInfo(XML_Parser parser);
-# endif
-
/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
detected. The last call to XML_Parse must have isFinal true; len
may be zero for this call (or any other).
@@ -964,15 +961,24 @@ XML_GetErrorCode(XML_Parser parser);
return 0 to indicate an error.
Note: XML_GetCurrentByteIndex returns -1 to indicate an error.
*/
+XML_ATTR_DEPRECATED("please use XML_GetCurrentLineNumber64 instead")
XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
+XMLPARSEAPI(uint64_t) XML_GetCurrentLineNumber64(XML_Parser parser);
+XML_ATTR_DEPRECATED("please use XML_GetCurrentColumnNumber64 instead")
XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
+XMLPARSEAPI(uint64_t) XML_GetCurrentColumnNumber64(XML_Parser parser);
+XML_ATTR_DEPRECATED("please use XML_GetCurrentByteIndex64 instead")
XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
+XMLPARSEAPI(int64_t) XML_GetCurrentByteIndex64(XML_Parser parser);
/* Return the number of bytes in the current event.
Returns 0 if the event is in an internal entity.
*/
+XML_ATTR_DEPRECATED("please use XML_GetCurrentByteCount64 instead")
XMLPARSEAPI(int)
XML_GetCurrentByteCount(XML_Parser parser);
+XMLPARSEAPI(uint64_t)
+XML_GetCurrentByteCount64(XML_Parser parser);
/* If XML_CONTEXT_BYTES is >=1, returns the input buffer, sets
the integer pointed to by offset to the offset within this buffer
@@ -984,8 +990,11 @@ XML_GetCurrentByteCount(XML_Parser parser);
NOTE: The character pointer returned should not be used outside
the handler that makes the call.
*/
+XML_ATTR_DEPRECATED("please use XML_GetInputContext64 instead")
XMLPARSEAPI(const char *)
XML_GetInputContext(XML_Parser parser, int *offset, int *size);
+XMLPARSEAPI(const char *)
+XML_GetInputContext64(XML_Parser parser, int64_t *offset, uint64_t *size);
/* For backwards compatibility with previous versions. */
# define XML_GetErrorLineNumber XML_GetCurrentLineNumber
@@ -1040,6 +1049,7 @@ enum XML_FeatureEnum {
XML_FEATURE_UNICODE_WCHAR_T,
XML_FEATURE_DTD,
XML_FEATURE_CONTEXT_BYTES,
+ /* Added in Expat 1.95.5, removed in Expat 2.9.0. */
XML_FEATURE_MIN_SIZE,
XML_FEATURE_SIZEOF_XML_CHAR,
XML_FEATURE_SIZEOF_XML_LCHAR,
@@ -1047,7 +1057,7 @@ enum XML_FeatureEnum {
XML_FEATURE_NS,
/* Added in Expat 2.0.1. */
XML_FEATURE_LARGE_SIZE,
- /* Added in Expat 2.1.0. */
+ /* Added in Expat 2.1.0, removed in Expat 2.9.0. */
XML_FEATURE_ATTR_INFO,
/* Added in Expat 2.4.0. */
XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
@@ -1069,6 +1079,41 @@ typedef struct {
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
+/* Added in Expat 2.9.0. */
+enum XML_Parser_Property {
+# if defined(XML_TESTING)
+ XML_PROP_INVALID = 0,
+# endif
+# if XML_GE == 1
+ XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD = 1, // of type `uint64_t`
+ XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION = 2, // of type `double`
+ XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD = 3, // of type `uint64_t`
+ XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION = 4, // of type `double`
+# endif
+ XML_PROP_REPARSE_DEFERRAL_ENABLED = 5, // of type `XML_Bool`
+ /* more properties upcoming here */
+};
+
+/* Added in Expat 2.9.0. */
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_GetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool *value);
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_GetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double *value);
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_GetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t *value);
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_SetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool value);
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_SetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double value);
+XMLPARSEAPI(enum XML_Prop_Error)
+XML_SetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t value);
+
# if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1)
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
@@ -1101,8 +1146,8 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
See https://semver.org
*/
# define XML_MAJOR_VERSION 2
-# define XML_MINOR_VERSION 8
-# define XML_MICRO_VERSION 5
+# define XML_MINOR_VERSION 9
+# define XML_MICRO_VERSION 0
# ifdef __cplusplus
}
diff --git a/contrib/expat/lib/expat_external.h b/contrib/expat/lib/expat_external.h
index cf80f960d6e1..0620fe47ed3c 100644
--- a/contrib/expat/lib/expat_external.h
+++ b/contrib/expat/lib/expat_external.h
@@ -166,6 +166,9 @@ typedef char XML_LChar;
# endif /* XML_UNICODE */
# ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+# if defined(__clang__) || defined(__GNUC__)
+# warning Macro XML_LARGE_SIZE is deprecated, please use the 64bit location API functions instead.
+# endif
typedef long long XML_Index;
typedef unsigned long long XML_Size;
# else
diff --git a/contrib/expat/lib/internal.h b/contrib/expat/lib/internal.h
index 86655371d290..de34cd7dfc55 100644
--- a/contrib/expat/lib/internal.h
+++ b/contrib/expat/lib/internal.h
@@ -56,13 +56,11 @@
#if ! defined(INTERNAL_H)
# define INTERNAL_H 1
-# ifndef XML_MIN_SIZE
-# if ! defined(inline)
-# ifdef __GNUC__
-# define inline __inline
-# endif /* __GNUC__ */
-# endif
-# endif /* XML_MIN_SIZE */
+# if ! defined(inline)
+# ifdef __GNUC__
+# define inline __inline
+# endif /* __GNUC__ */
+# endif
# ifndef inline
# define inline
diff --git a/contrib/expat/lib/libexpat.map.in b/contrib/expat/lib/libexpat.map.in
index 71a6758fd746..4a683bba360a 100644
--- a/contrib/expat/lib/libexpat.map.in
+++ b/contrib/expat/lib/libexpat.map.in
@@ -97,7 +97,7 @@ LIBEXPAT_1.95.8 {
LIBEXPAT_2.1.0 {
global:
-@_EXPAT_COMMENT_ATTR_INFO@ XML_GetAttributeInfo;
+# XML_GetAttributeInfo;
XML_SetHashSalt;
} LIBEXPAT_1.95.8;
@@ -122,3 +122,18 @@ LIBEXPAT_2.8.0 {
global:
XML_SetHashSalt16Bytes;
} LIBEXPAT_2.7.2;
+
+LIBEXPAT_2.9.0 {
+ global:
+ XML_GetCurrentByteCount64;
+ XML_GetCurrentByteIndex64;
+ XML_GetCurrentColumnNumber64;
+ XML_GetCurrentLineNumber64;
+ XML_GetInputContext64;
+ XML_GetPropertyBool;
+ XML_GetPropertyDouble;
+ XML_GetPropertyUInt64;
+ XML_SetPropertyBool;
+ XML_SetPropertyDouble;
+ XML_SetPropertyUInt64;
+} LIBEXPAT_2.8.0;
diff --git a/contrib/expat/lib/xcs.c b/contrib/expat/lib/xcs.c
new file mode 100644
index 000000000000..ae5e042d778f
--- /dev/null
+++ b/contrib/expat/lib/xcs.c
@@ -0,0 +1,90 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2022-2026 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#include "xcs.h"
+
+#if defined(XML_UNICODE)
+# if defined(XML_UNICODE_WCHAR_T)
+# include <wchar.h> // for wcscmp, wcslen, wcsncmp
+# endif
+#else
+# include <string.h> // for strcmp, strlen, strncmp
+#endif
+
+size_t
+xcslen(const XML_Char *s) {
+#ifdef XML_UNICODE
+# ifdef XML_UNICODE_WCHAR_T
+ return wcslen(s);
+# else
+ // XML_Char is unsigned short
+ size_t len = 0;
+ while (s[len]) {
+ len++;
+ }
+ return len;
+# endif
+#else
+ return strlen(s);
+#endif
+}
+
+int
+xcscmp(const XML_Char *a, const XML_Char *b) {
+#if defined(XML_UNICODE)
+# if defined(XML_UNICODE_WCHAR_T)
+ return wcscmp(a, b);
+# else
+ for (; a[0] && b[0] && a[0] == b[0]; a++, b++)
+ ;
+ return a[0] - b[0];
+# endif
+#else
+ return strcmp(a, b);
+#endif
+}
+
+int
+xcsncmp(const XML_Char *a, const XML_Char *b, size_t len) {
+#if defined(XML_UNICODE)
+# if defined(XML_UNICODE_WCHAR_T)
+ return wcsncmp(a, b, len);
+# else
+ for (; len > 0 && a[0] && b[0] && a[0] == b[0]; len--, a++, b++) {
+ }
+ return (len == 0) ? 0 : (a[0] - b[0]);
+# endif
+#else
+ return strncmp(a, b, len);
+#endif
+}
diff --git a/contrib/expat/lib/xcsinc.c b/contrib/expat/lib/xcs.h
index 675b2844c708..1b942647d333 100644
--- a/contrib/expat/lib/xcsinc.c
+++ b/contrib/expat/lib/xcs.h
@@ -1,4 +1,4 @@
-/* This file is included from other .c files!
+/*
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -6,7 +6,7 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2022-2026 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -31,24 +31,14 @@
SPDX-License-Identifier: MIT
*/
-#if defined(XML_UNICODE) && defined(XML_UNICODE_WCHAR_T)
-# include <wchar.h>
-#endif
+#if ! defined(EXPAT_XCS_H)
-static size_t
-xcslen(const XML_Char *s) {
-#ifdef XML_UNICODE
-# ifdef XML_UNICODE_WCHAR_T
- return wcslen(s);
-# else
- // XML_Char is unsigned short
- size_t len = 0;
- while (s[len]) {
- len++;
- }
- return len;
-# endif
-#else
- return strlen(s);
-#endif
-}
+# include <stddef.h> // size_t
+# include "expat_external.h" // for XML_Char
+
+extern size_t xcslen(const XML_Char *s);
+
+extern int xcscmp(const XML_Char *a, const XML_Char *b);
+extern int xcsncmp(const XML_Char *a, const XML_Char *b, size_t len);
+
+#endif // ! defined(EXPAT_XCS_H)
diff --git a/contrib/expat/lib/xmlparse.c b/contrib/expat/lib/xmlparse.c
index c3642bd52ff9..41288b6ad418 100644
--- a/contrib/expat/lib/xmlparse.c
+++ b/contrib/expat/lib/xmlparse.c
@@ -1,4 +1,4 @@
-/* 0864fe2d216f47b742263b698bc051c865b342e8b820e42c234717098ea507e3 (2.8.5+)
+/* e3ca845466942140c9af531ac57808c4650116df5d6dbeda3b6546d2548a586e (2.9.0+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -56,6 +56,8 @@
Copyright (c) 2026 Zeyou Liu <zeyouliu@tencent.com>
Copyright (c) 2026 Stan Ulbrych <stan@python.org>
Copyright (c) 2026 Braian Plaku <braianplaku@gmail.com>
+ Copyright (c) 2026 Filippo Tedeschi <filippotedeschi98@gmail.com>
+ Copyright (c) 2026 Junki Lee <junkilee80@gmail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -107,6 +109,7 @@
#include <stdint.h> /* SIZE_MAX, UINT64_MAX, uint64_t, uintptr_t */
#include <math.h> /* isnan */
#include <errno.h>
+#include <wchar.h> /* wcsncmp */
#ifdef _WIN32
# define getpid GetCurrentProcessId
@@ -125,7 +128,7 @@
#include "ascii.h"
#include "expat.h"
#include "siphash.h"
-#include "xcsinc.c"
+#include "xcs.h"
#if defined(HAVE_ARC4RANDOM)
# include "random_arc4random.h"
@@ -462,8 +465,8 @@ typedef struct accounting {
} ACCOUNTING;
typedef struct MALLOC_TRACKER {
- XmlBigCount bytesAllocated;
- XmlBigCount peakBytesAllocated; // updated live only for debug level >=2
+ size_t bytesAllocated;
+ size_t peakBytesAllocated; // updated live only for debug level >=2
unsigned long debugLevel;
float maximumAmplificationFactor; // >=1.0
XmlBigCount activationThresholdBytes;
@@ -646,6 +649,25 @@ static bool poolAppendChar(STRING_POOL *pool, XML_Char c);
static bool poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len);
+#if XML_GE == 1
+static enum XML_Prop_Error setBillionLaughsAttackProtectionMaximumAmplification(
+ XML_Parser parser, float maximumAmplificationFactor);
+
+static enum XML_Prop_Error setBillionLaughsAttackProtectionActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes);
+
+static enum XML_Prop_Error
+setAllocTrackerMaximumAmplification(XML_Parser parser,
+ float maximumAmplificationFactor);
+
+static enum XML_Prop_Error
+setAllocTrackerActivationThreshold(XML_Parser parser,
+ unsigned long long activationThresholdBytes);
+#endif /* XML_GE == 1 */
+
+static enum XML_Prop_Error setReparseDeferralEnabled(XML_Parser parser,
+ XML_Bool enabled);
+
#define poolStart(pool) ((pool)->start)
#define poolLength(pool) ((pool)->ptr - (pool)->start)
#define poolChop(pool) ((void)--(pool->ptr))
@@ -785,9 +807,6 @@ struct XML_ParserStruct {
NS_ATT *m_nsAtts;
unsigned long m_nsAttsVersion;
unsigned char m_nsAttsPower;
-#ifdef XML_ATTR_INFO
- XML_AttrInfo *m_attInfo;
-#endif
POSITION m_position;
STRING_POOL m_tempPool;
STRING_POOL m_temp2Pool;
@@ -824,30 +843,30 @@ struct XML_ParserStruct {
#if XML_GE == 1
static void
-expat_heap_stat(XML_Parser rootParser, char operator, XmlBigCount absDiff,
- XmlBigCount newTotal, XmlBigCount peakTotal, int sourceLine) {
+expat_heap_stat(XML_Parser rootParser, char operator, size_t absDiff,
+ size_t newTotal, size_t peakTotal, int sourceLine) {
// NOTE: This can be +infinity or -nan
const float amplification
= (float)newTotal / (float)rootParser->m_accounting.countBytesDirect;
fprintf(
stderr,
- "expat: Allocations(%p): Direct " EXPAT_FMT_ULL("10") ", allocated %c" EXPAT_FMT_ULL(
- "10") " to " EXPAT_FMT_ULL("10") " (" EXPAT_FMT_ULL("10") " peak), amplification %8.2f (xmlparse.c:%d)\n",
+ "expat: Allocations(%p): Direct " EXPAT_FMT_ULL("10") ", allocated %c" EXPAT_FMT_SIZE_T(
+ "10") " to " EXPAT_FMT_SIZE_T("10") " (" EXPAT_FMT_SIZE_T("10") " peak), amplification %8.2f (xmlparse.c:%d)\n",
(void *)rootParser, rootParser->m_accounting.countBytesDirect, operator,
absDiff, newTotal, peakTotal, (double)amplification, sourceLine);
}
static bool
-expat_heap_increase_tolerable(XML_Parser rootParser, XmlBigCount increase,
+expat_heap_increase_tolerable(XML_Parser rootParser, size_t increase,
int sourceLine) {
assert(rootParser != NULL);
assert(increase > 0);
- XmlBigCount newTotal = 0;
+ size_t newTotal = 0;
bool tolerable = true;
// Detect integer overflow
- if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) {
+ if (SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated < increase) {
tolerable = false;
} else {
newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase;
@@ -887,8 +906,7 @@ expat_malloc(XML_Parser parser, size_t size, int sourceLine) {
const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size;
- if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated
- < bytesToAllocate) {
+ if (SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated < bytesToAllocate) {
return NULL; // i.e. signal integer overflow as out-of-memory
}
@@ -998,9 +1016,10 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) {
}
}
- // NOTE: Integer overflow detection has already been done for us
- // by expat_heap_increase_tolerable(..) above
- assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size);
+ // Detect and prevent integer overflow
+ if (size > SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING) {
+ return NULL;
+ }
// Actually allocate
mallocedPtr = parser->m_mem.realloc_fcn(
@@ -1012,8 +1031,7 @@ expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) {
// Update accounting
if (isIncrease) {
- assert((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated
- >= absDiff);
+ assert(SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated >= absDiff);
rootParser->m_alloc_tracker.bytesAllocated += absDiff;
} else { // i.e. decrease
assert(rootParser->m_alloc_tracker.bytesAllocated >= absDiff);
@@ -1389,20 +1407,9 @@ parserCreate(const XML_Char *encodingName,
FREE(parser, parser);
return NULL;
}
-#ifdef XML_ATTR_INFO
- parser->m_attInfo = MALLOC(parser, parser->m_attsSize * sizeof(XML_AttrInfo));
- if (parser->m_attInfo == NULL) {
- FREE(parser, parser->m_atts);
- FREE(parser, parser);
- return NULL;
- }
-#endif
parser->m_dataBuf = MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
if (parser->m_dataBuf == NULL) {
FREE(parser, parser->m_atts);
-#ifdef XML_ATTR_INFO
- FREE(parser, parser->m_attInfo);
-#endif
FREE(parser, parser);
return NULL;
}
@@ -1415,9 +1422,6 @@ parserCreate(const XML_Char *encodingName,
if (parser->m_dtd == NULL) {
FREE(parser, parser->m_dataBuf);
FREE(parser, parser->m_atts);
-#ifdef XML_ATTR_INFO
- FREE(parser, parser->m_attInfo);
-#endif
FREE(parser, parser);
return NULL;
}
@@ -1596,6 +1600,10 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
if (parser->m_parentParser)
return XML_FALSE;
+ // The application-defined release callback may access the parser, so it
+ // must run before any parser state is freed.
+ if (parser->m_unknownEncodingRelease)
+ callUnknownEncodingRelease(parser);
/* move m_tagStack to m_freeTagList */
tStk = parser->m_tagStack;
while (tStk) {
@@ -1616,14 +1624,16 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
moveEntityList(&parser->m_freeEntities, &parser->m_openValueEntities);
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
- if (parser->m_unknownEncodingRelease)
- callUnknownEncodingRelease(parser);
poolClear(&parser->m_tempPool);
poolClear(&parser->m_temp2Pool);
FREE(parser, (void *)parser->m_protocolEncodingName);
parser->m_protocolEncodingName = NULL;
parserInit(parser, encodingName);
dtdReset(parser->m_dtd, parser);
+ if (encodingName && ! parser->m_protocolEncodingName) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ return XML_FALSE;
+ }
return XML_TRUE;
}
@@ -1856,6 +1866,10 @@ XML_ParserFree(XML_Parser parser) {
TAG *tagList;
if ((parser == NULL) || isCalledFromInsideHandler(parser))
return;
+ // The application-defined release callback may access the parser, so it
+ // must run before any parser state is freed.
+ if (parser->m_unknownEncodingRelease)
+ callUnknownEncodingRelease(parser);
/* free m_tagStack and m_freeTagList */
tagList = parser->m_tagStack;
for (;;) {
@@ -1916,9 +1930,6 @@ XML_ParserFree(XML_Parser parser) {
#endif /* XML_DTD */
dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, parser);
FREE(parser, parser->m_atts);
-#ifdef XML_ATTR_INFO
- FREE(parser, parser->m_attInfo);
-#endif
FREE(parser, parser->m_groupConnector);
// NOTE: We are avoiding FREE(..) here because parser->m_buffer
// is not being allocated with MALLOC(..) but with plain
@@ -1927,8 +1938,6 @@ XML_ParserFree(XML_Parser parser) {
FREE(parser, parser->m_dataBuf);
FREE(parser, parser->m_nsAtts);
FREE(parser, parser->m_unknownEncodingMem);
- if (parser->m_unknownEncodingRelease)
- callUnknownEncodingRelease(parser);
FREE(parser, parser);
}
@@ -2009,15 +2018,6 @@ XML_GetIdAttributeIndex(XML_Parser parser) {
return parser->m_idAttIndex;
}
-#ifdef XML_ATTR_INFO
-const XML_AttrInfo *XMLCALL
-XML_GetAttributeInfo(XML_Parser parser) {
- if (parser == NULL)
- return NULL;
- return parser->m_attInfo;
-}
-#endif
-
void XMLCALL
XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start,
XML_EndElementHandler end) {
@@ -2446,6 +2446,11 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
parser->m_parsingStatus.parsing = XML_PARSING;
}
+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
+ parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
+ return XML_STATUS_ERROR;
+ }
+
// Detect and avoid integer overflow
if ((uint64_t)len > UINT64_MAX - parser->m_parseEndByteIndex) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
@@ -2705,41 +2710,57 @@ XML_GetErrorCode(XML_Parser parser) {
return parser->m_errorCode;
}
-XML_Index XMLCALL
-XML_GetCurrentByteIndex(XML_Parser parser) {
+int64_t XMLCALL
+XML_GetCurrentByteIndex64(XML_Parser parser) {
if (parser == NULL)
return -1;
if (parser->m_eventPtr) {
- // NOTE: XML_Index is known to wrap around for >2 GiB content
- // on 32bit machines and 64bit Windows, unless (non-default and
- // uncommon) XML_LARGE_SIZE is defined.
- // That's a bug and it only lives on because we cannot break
- // ABI compatibility of public API.
- return (XML_Index)(parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - parser->m_eventPtr));
+ return (int64_t)(parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - parser->m_eventPtr));
}
return -1;
}
-int XMLCALL
-XML_GetCurrentByteCount(XML_Parser parser) {
+// DEPRECATED since Expat 2.9.0.
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser) {
+ // NOTE: XML_Index is known to wrap around for >2 GiB content
+ // on 32bit machines and 64bit Windows, unless (non-default and
+ // uncommon) XML_LARGE_SIZE is defined.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ return (XML_Index)XML_GetCurrentByteIndex64(parser);
+}
+
+uint64_t XMLCALL
+XML_GetCurrentByteCount64(XML_Parser parser) {
if (parser == NULL)
return 0;
- if (parser->m_eventEndPtr && parser->m_eventPtr)
- return (int)(parser->m_eventEndPtr - parser->m_eventPtr);
+ if (parser->m_eventEndPtr && parser->m_eventPtr) {
+ return parser->m_eventEndPtr - parser->m_eventPtr;
+ }
return 0;
}
+// DEPRECATED since Expat 2.9.0.
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser) {
+ // NOTE: int is known to wrap around for >2 GiB content.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ return (int)XML_GetCurrentByteCount64(parser);
+}
+
const char *XMLCALL
-XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
+XML_GetInputContext64(XML_Parser parser, int64_t *offset, uint64_t *size) {
#if XML_CONTEXT_BYTES > 0
if (parser == NULL)
return NULL;
if (parser->m_eventPtr && parser->m_buffer) {
if (offset != NULL)
- *offset = (int)(parser->m_eventPtr - parser->m_buffer);
+ *offset = parser->m_eventPtr - parser->m_buffer;
if (size != NULL)
- *size = (int)(parser->m_bufferEnd - parser->m_buffer);
+ *size = parser->m_bufferEnd - parser->m_buffer;
return parser->m_buffer;
}
#else
@@ -2750,8 +2771,41 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
return NULL;
}
-XML_Size XMLCALL
-XML_GetCurrentLineNumber(XML_Parser parser) {
+// DEPRECATED since Expat 2.9.0.
+const char *XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
+#if XML_CONTEXT_BYTES > 0
+ if (parser == NULL)
+ return NULL;
+
+ int64_t offset64;
+ uint64_t size64;
+
+ const char *const buffer = XML_GetInputContext64(parser, &offset64, &size64);
+
+ if (buffer == NULL)
+ return NULL;
+
+ // NOTE: int is known to wrap around for >2 GiB content.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ if (offset != NULL)
+ *offset = (int)offset64;
+
+ if (size != NULL)
+ *size = (int)size64;
+
+ return buffer;
+#else
+ (void)parser;
+ (void)offset;
+ (void)size;
+#endif /* XML_CONTEXT_BYTES > 0 */
+ return NULL;
+}
+
+uint64_t XMLCALL
+XML_GetCurrentLineNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
@@ -2759,16 +2813,22 @@ XML_GetCurrentLineNumber(XML_Parser parser) {
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
+ return parser->m_position.lineNumber + 1;
+}
+
+// DEPRECATED since Expat 2.9.0.
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser) {
// NOTE: XML_Size is known to wrap around for >4 GiB content
// on 32bit machines and 64bit Windows, unless (non-default and
// uncommon) XML_LARGE_SIZE is defined.
// That's a bug and it only lives on because we cannot break
// ABI compatibility of public API.
- return (XML_Size)(parser->m_position.lineNumber + 1);
+ return (XML_Size)XML_GetCurrentLineNumber64(parser);
}
-XML_Size XMLCALL
-XML_GetCurrentColumnNumber(XML_Parser parser) {
+uint64_t XMLCALL
+XML_GetCurrentColumnNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
@@ -2776,12 +2836,18 @@ XML_GetCurrentColumnNumber(XML_Parser parser) {
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
+ return parser->m_position.columnNumber;
+}
+
+// DEPRECATED since Expat 2.9.0.
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser) {
// NOTE: XML_Size is known to wrap around for >4 GiB content
// on 32bit machines and 64bit Windows, unless (non-default and
// uncommon) XML_LARGE_SIZE is defined.
// That's a bug and it only lives on because we cannot break
// ABI compatibility of public API.
- return (XML_Size)parser->m_position.columnNumber;
+ return (XML_Size)XML_GetCurrentColumnNumber64(parser);
}
void XMLCALL
@@ -2827,7 +2893,7 @@ XML_MemFree(XML_Parser parser, void *ptr) {
void XMLCALL
XML_DefaultCurrent(XML_Parser parser) {
- if (parser == NULL)
+ if (parser == NULL || ! isCalledFromInsideHandler(parser))
return;
if (parser->m_defaultHandler) {
if (parser->m_openInternalEntities)
@@ -2998,18 +3064,12 @@ XML_GetFeatureList(void) {
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
XML_CONTEXT_BYTES},
#endif
-#ifdef XML_MIN_SIZE
- {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
-#endif
#ifdef XML_NS
{XML_FEATURE_NS, XML_L("XML_NS"), 0},
#endif
#ifdef XML_LARGE_SIZE
{XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
#endif
-#ifdef XML_ATTR_INFO
- {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
-#endif
#if XML_GE == 1
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
@@ -3036,59 +3096,294 @@ XML_GetFeatureList(void) {
}
#if XML_GE == 1
+static enum XML_Prop_Error
+setBillionLaughsAttackProtectionMaximumAmplification(
+ XML_Parser parser, float maximumAmplificationFactor) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ if (isnan(maximumAmplificationFactor) || (maximumAmplificationFactor < 1.0f))
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
+
+ return XML_PROP_ERROR_NONE;
+}
+
XML_Bool XMLCALL
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
XML_Parser parser, float maximumAmplificationFactor) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)
- || isnan(maximumAmplificationFactor)
- || (maximumAmplificationFactor < 1.0f)) {
- return XML_FALSE;
- }
- parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
- return XML_TRUE;
+ return (setBillionLaughsAttackProtectionMaximumAmplification(
+ parser, maximumAmplificationFactor)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setBillionLaughsAttackProtectionActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetBillionLaughsAttackProtectionActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)) {
- return XML_FALSE;
- }
- parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
- return XML_TRUE;
+ return (setBillionLaughsAttackProtectionActivationThreshold(
+ parser, activationThresholdBytes)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setAllocTrackerMaximumAmplification(XML_Parser parser,
+ float maximumAmplificationFactor) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ if (isnan(maximumAmplificationFactor) || (maximumAmplificationFactor < 1.0f))
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_alloc_tracker.maximumAmplificationFactor
+ = maximumAmplificationFactor;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetAllocTrackerMaximumAmplification(XML_Parser parser,
float maximumAmplificationFactor) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)
- || isnan(maximumAmplificationFactor)
- || (maximumAmplificationFactor < 1.0f)) {
- return XML_FALSE;
- }
- parser->m_alloc_tracker.maximumAmplificationFactor
- = maximumAmplificationFactor;
- return XML_TRUE;
+ return (setAllocTrackerMaximumAmplification(parser,
+ maximumAmplificationFactor)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setAllocTrackerActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetAllocTrackerActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)) {
- return XML_FALSE;
- }
- parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes;
- return XML_TRUE;
+ return (setAllocTrackerActivationThreshold(parser, activationThresholdBytes)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
}
#endif /* XML_GE == 1 */
+static enum XML_Prop_Error
+setReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (enabled != XML_TRUE && enabled != XML_FALSE)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_reparseDeferralEnabled = enabled;
+
+ return XML_PROP_ERROR_NONE;
+}
+
XML_Bool XMLCALL
XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
- if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
- parser->m_reparseDeferralEnabled = enabled;
- return XML_TRUE;
+ return (setReparseDeferralEnabled(parser, enabled) == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return XML_PROP_ERROR_INVALID_TYPE;
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return setReparseDeferralEnabled(parser, value);
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+#if XML_GE == 0
+ UNUSED_P(value);
+#endif
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ return setAllocTrackerMaximumAmplification(parser, (float)value);
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return setBillionLaughsAttackProtectionMaximumAmplification(parser,
+ (float)value);
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+#if XML_GE == 0
+ UNUSED_P(value);
+#endif
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ return setAllocTrackerActivationThreshold(parser,
+ (unsigned long long)value);
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ return setBillionLaughsAttackProtectionActivationThreshold(
+ parser, (unsigned long long)value);
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_GetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool *value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (value == NULL)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return XML_PROP_ERROR_INVALID_TYPE;
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ *value = parser->m_reparseDeferralEnabled;
+ break;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ return XML_PROP_ERROR_NONE;
+}
+
+enum XML_Prop_Error XMLCALL
+XML_GetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double *value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (value == NULL)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ *value = (double)parser->m_accounting.maximumAmplificationFactor;
+ break;
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ *value = (double)parser->m_alloc_tracker.maximumAmplificationFactor;
+ break;
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
}
- return XML_FALSE;
+
+ return XML_PROP_ERROR_NONE;
+}
+
+enum XML_Prop_Error XMLCALL
+XML_GetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t *value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (value == NULL)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ *value = parser->m_accounting.activationThresholdBytes;
+ break;
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ *value = parser->m_alloc_tracker.activationThresholdBytes;
+ break;
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ return XML_PROP_ERROR_NONE;
}
/* Initially tag->rawName always points into the parse buffer;
@@ -3901,21 +4196,6 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
return XML_ERROR_NO_MEMORY;
}
parser->m_atts = temp;
-#ifdef XML_ATTR_INFO
- /* Detect and prevent integer overflow. */
- if (parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) {
- parser->m_attsSize = oldAttsSize;
- return XML_ERROR_NO_MEMORY;
- }
-
- XML_AttrInfo *const temp2 = REALLOC(
- parser, parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo));
- if (temp2 == NULL) {
- parser->m_attsSize = oldAttsSize;
- return XML_ERROR_NO_MEMORY;
- }
- parser->m_attInfo = temp2;
-#endif
if (n > oldAttsSize) {
/* Detect and prevent integer overflow. */
if (n > (size_t)INT_MAX)
@@ -3928,33 +4208,12 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
const XML_Char **const appAtts = (const XML_Char **)parser->m_atts;
for (size_t i = 0; i < n; i++) {
ATTRIBUTE *currAtt = &parser->m_atts[i];
-#ifdef XML_ATTR_INFO
- XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
-#endif
/* add the name and value to the attribute list */
ATTRIBUTE_ID *attId
= getAttributeId(parser, enc, currAtt->name,
currAtt->name + XmlNameLength(enc, currAtt->name));
if (! attId)
return XML_ERROR_NO_MEMORY;
-#ifdef XML_ATTR_INFO
- // NOTE: XML_Index is known to wrap around for >2 GiB content
- // on 32bit machines and 64bit Windows, unless (non-default and
- // uncommon) XML_LARGE_SIZE is defined.
- // That's a bug and it only lives on because we cannot break
- // ABI compatibility of public API.
- currAttInfo->nameStart
- = (XML_Index)(parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - currAtt->name));
- currAttInfo->nameEnd
- = currAttInfo->nameStart + XmlNameLength(enc, currAtt->name);
- currAttInfo->valueStart
- = (XML_Index)(parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - currAtt->valuePtr));
- currAttInfo->valueEnd
- = (XML_Index)(parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - currAtt->valueEnd));
-#endif
/* Detect duplicate attributes by their QNames. This does not work when
namespace processing is turned on and different prefixes for the same
namespace are used. For this case we have a check further down.
diff --git a/contrib/expat/lib/xmltok.c b/contrib/expat/lib/xmltok.c
index a3bf5e0e95b0..2f837acc4cbf 100644
--- a/contrib/expat/lib/xmltok.c
+++ b/contrib/expat/lib/xmltok.c
@@ -193,13 +193,6 @@ utf8_isInvalid4(const ENCODING *enc, const char *p) {
struct normal_encoding {
ENCODING enc;
unsigned char type[256];
-#ifdef XML_MIN_SIZE
- int (*byteType)(const ENCODING *, const char *);
- int (*isNameMin)(const ENCODING *, const char *);
- int (*isNmstrtMin)(const ENCODING *, const char *);
- int (*byteToAscii)(const ENCODING *, const char *);
- int (*charMatches)(const ENCODING *, const char *, int);
-#endif /* XML_MIN_SIZE */
int (*isName2)(const ENCODING *, const char *);
int (*isName3)(const ENCODING *, const char *);
int (*isName4)(const ENCODING *, const char *);
@@ -213,16 +206,7 @@ struct normal_encoding {
#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *)(enc))
-#ifdef XML_MIN_SIZE
-
-# define STANDARD_VTABLE(E) \
- E##byteType, E##isNameMin, E##isNmstrtMin, E##byteToAscii, E##charMatches,
-
-#else
-
-# define STANDARD_VTABLE(E) /* as nothing */
-
-#endif
+#define STANDARD_VTABLE(E) /* as nothing */
#define NORMAL_VTABLE(E) \
E##isName2, E##isName3, E##isName4, E##isNmstrt2, E##isNmstrt3, \
@@ -233,93 +217,33 @@ struct normal_encoding {
/* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \
/* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL
-/* Like NULL_VTABLE but with a real isInvalid4 so the UTF-16 encodings reject a
- high surrogate that is not followed by a low surrogate. Only needed for the
- XML_MIN_SIZE build, where the shared tokenizer dispatches through the vtable;
- the regular build inlines the same check via IS_INVALID_CHAR. */
-#ifdef XML_MIN_SIZE
-# define UTF16_NULL_VTABLE(E) \
- /* isName2 */ NULL, /* isName3 */ NULL, /* isName4 */ NULL, \
- /* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \
- /* isInvalid2 */ NULL, /* isInvalid3 */ NULL, E##isInvalid4
-#else
-# define UTF16_NULL_VTABLE(E) NULL_VTABLE
-#endif
+#define UTF16_NULL_VTABLE(E) NULL_VTABLE
static int checkCharRefNumber(int result);
#include "xmltok_impl.h"
#include "ascii.h"
-#ifdef XML_MIN_SIZE
-# define sb_isNameMin isNever
-# define sb_isNmstrtMin isNever
-#endif
-
-#ifdef XML_MIN_SIZE
-# define MINBPC(enc) ((enc)->minBytesPerChar)
-#else
/* minimum bytes per character */
-# define MINBPC(enc) 1
-#endif
+#define MINBPC(enc) 1
#define SB_BYTE_TYPE(enc, p) \
(((const struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
-#ifdef XML_MIN_SIZE
-static int
-sb_byteType(const ENCODING *enc, const char *p) {
- return SB_BYTE_TYPE(enc, p);
-}
-# define BYTE_TYPE(enc, p) (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
-#else
-# define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
-#endif
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
-#ifdef XML_MIN_SIZE
-# define BYTE_TO_ASCII(enc, p) (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
-static int
-sb_byteToAscii(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return *p;
-}
-#else
-# define BYTE_TO_ASCII(enc, p) (*(p))
-#endif
+#define BYTE_TO_ASCII(enc, p) (*(p))
#define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p))
#define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p))
-#ifdef XML_MIN_SIZE
-# define IS_INVALID_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isInvalid##n \
- && AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
-#else
-# define IS_INVALID_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
-#endif
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
-#ifdef XML_MIN_SIZE
-# define IS_NAME_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
-# define IS_NMSTRT_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
-#else
-# define IS_NAME_CHAR_MINBPC(enc, p) (0)
-# define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
-#endif
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
-#ifdef XML_MIN_SIZE
-# define CHAR_MATCHES(enc, p, c) \
- (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
-static int
-sb_charMatches(const ENCODING *enc, const char *p, int c) {
- UNUSED_P(enc);
- return *p == c;
-}
-#else
/* c is an ASCII character */
-# define CHAR_MATCHES(enc, p, c) (*(p) == (c))
-#endif
+#define CHAR_MATCHES(enc, p, c) (*(p) == (c))
#define PREFIX(ident) normal_##ident
#define XML_TOK_IMPL_C
@@ -769,76 +693,32 @@ DEFINE_UTF16_TO_UTF16(big2_)
#define LITTLE2_IS_INVALID_CHAR(p, n) \
((n) == 4 && ((unsigned char)(p)[3] & 0xFC) != 0xDC)
-#ifdef XML_MIN_SIZE
-
-static int
-little2_byteType(const ENCODING *enc, const char *p) {
- return LITTLE2_BYTE_TYPE(enc, p);
-}
-
-static int
-little2_byteToAscii(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_BYTE_TO_ASCII(p);
-}
-
-static int
-little2_charMatches(const ENCODING *enc, const char *p, int c) {
- UNUSED_P(enc);
- return LITTLE2_CHAR_MATCHES(p, c);
-}
-
-static int
-little2_isNameMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_IS_NAME_CHAR_MINBPC(p);
-}
-
-static int
-little2_isNmstrtMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_IS_NMSTRT_CHAR_MINBPC(p);
-}
-
-static int
-little2_isInvalid4(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_IS_INVALID_CHAR(p, 4);
-}
-
-# undef VTABLE
-# define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-# undef PREFIX
-# define PREFIX(ident) little2_##ident
-# define MINBPC(enc) 2
+#undef PREFIX
+#define PREFIX(ident) little2_##ident
+#define MINBPC(enc) 2
/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-# define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
-# define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(p)
-# define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(p, c)
-# define IS_NAME_CHAR(enc, p, n) 0
-# define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(p)
-# define IS_NMSTRT_CHAR(enc, p, n) (0)
-# define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(p)
-# define IS_INVALID_CHAR(enc, p, n) LITTLE2_IS_INVALID_CHAR(p, n)
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(p)
+#define IS_INVALID_CHAR(enc, p, n) LITTLE2_IS_INVALID_CHAR(p, n)
-# define XML_TOK_IMPL_C
-# include "xmltok_impl.c"
-# undef XML_TOK_IMPL_C
-
-# undef MINBPC
-# undef BYTE_TYPE
-# undef BYTE_TO_ASCII
-# undef CHAR_MATCHES
-# undef IS_NAME_CHAR
-# undef IS_NAME_CHAR_MINBPC
-# undef IS_NMSTRT_CHAR
-# undef IS_NMSTRT_CHAR_MINBPC
-# undef IS_INVALID_CHAR
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
-#endif /* not XML_MIN_SIZE */
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
#ifdef XML_NS
@@ -914,76 +794,32 @@ static const struct normal_encoding internal_little2_encoding
#define BIG2_IS_INVALID_CHAR(p, n) \
((n) == 4 && ((unsigned char)(p)[2] & 0xFC) != 0xDC)
-#ifdef XML_MIN_SIZE
-
-static int
-big2_byteType(const ENCODING *enc, const char *p) {
- return BIG2_BYTE_TYPE(enc, p);
-}
-
-static int
-big2_byteToAscii(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_BYTE_TO_ASCII(p);
-}
-
-static int
-big2_charMatches(const ENCODING *enc, const char *p, int c) {
- UNUSED_P(enc);
- return BIG2_CHAR_MATCHES(p, c);
-}
-
-static int
-big2_isNameMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_IS_NAME_CHAR_MINBPC(p);
-}
-
-static int
-big2_isNmstrtMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_IS_NMSTRT_CHAR_MINBPC(p);
-}
-
-static int
-big2_isInvalid4(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_IS_INVALID_CHAR(p, 4);
-}
-
-# undef VTABLE
-# define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-# undef PREFIX
-# define PREFIX(ident) big2_##ident
-# define MINBPC(enc) 2
+#undef PREFIX
+#define PREFIX(ident) big2_##ident
+#define MINBPC(enc) 2
/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-# define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
-# define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(p)
-# define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(p, c)
-# define IS_NAME_CHAR(enc, p, n) 0
-# define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(p)
-# define IS_NMSTRT_CHAR(enc, p, n) (0)
-# define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(p)
-# define IS_INVALID_CHAR(enc, p, n) BIG2_IS_INVALID_CHAR(p, n)
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(p)
+#define IS_INVALID_CHAR(enc, p, n) BIG2_IS_INVALID_CHAR(p, n)
-# define XML_TOK_IMPL_C
-# include "xmltok_impl.c"
-# undef XML_TOK_IMPL_C
-
-# undef MINBPC
-# undef BYTE_TYPE
-# undef BYTE_TO_ASCII
-# undef CHAR_MATCHES
-# undef IS_NAME_CHAR
-# undef IS_NAME_CHAR_MINBPC
-# undef IS_NMSTRT_CHAR
-# undef IS_NMSTRT_CHAR_MINBPC
-# undef IS_INVALID_CHAR
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
-#endif /* not XML_MIN_SIZE */
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
#ifdef XML_NS
diff --git a/contrib/expat/lib/xmltok_impl.c b/contrib/expat/lib/xmltok_impl.c
index a71a2fd88c70..7900e94701e2 100644
--- a/contrib/expat/lib/xmltok_impl.c
+++ b/contrib/expat/lib/xmltok_impl.c
@@ -1,4 +1,4 @@
-/* This file is included (from xmltok.c, 1-3 times depending on XML_MIN_SIZE)!
+/* This file is included (from xmltok.c, 3 times)!
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
diff --git a/contrib/expat/tests/Makefile.am b/contrib/expat/tests/Makefile.am
index 21d8df2c6676..a6cf0d083698 100644
--- a/contrib/expat/tests/Makefile.am
+++ b/contrib/expat/tests/Makefile.am
@@ -55,8 +55,10 @@ runtests_SOURCES = \
misc_tests.c \
ns_tests.c \
nsalloc_tests.c \
+ props_tests.c \
runtests.c \
- structdata.c
+ structdata.c \
+ xcs_tests.c
runtests_LDADD = ../lib/libtestpat.la
@@ -76,8 +78,10 @@ EXTRA_DIST = \
misc_tests.h \
ns_tests.h \
nsalloc_tests.h \
+ props_tests.h \
README.md \
structdata.h \
udiffer.py \
+ xcs_tests.h \
xmltest.log.expected \
xmltest.sh
diff --git a/contrib/expat/tests/Makefile.in b/contrib/expat/tests/Makefile.in
index f81e113c2216..ea8554bd50ba 100644
--- a/contrib/expat/tests/Makefile.in
+++ b/contrib/expat/tests/Makefile.in
@@ -151,8 +151,9 @@ am_runtests_OBJECTS = acc_tests.$(OBJEXT) alloc_tests.$(OBJEXT) \
basic_tests.$(OBJEXT) chardata.$(OBJEXT) common.$(OBJEXT) \
dummy.$(OBJEXT) handlers.$(OBJEXT) hash_tests.$(OBJEXT) \
memcheck.$(OBJEXT) minicheck.$(OBJEXT) misc_tests.$(OBJEXT) \
- ns_tests.$(OBJEXT) nsalloc_tests.$(OBJEXT) runtests.$(OBJEXT) \
- structdata.$(OBJEXT)
+ ns_tests.$(OBJEXT) nsalloc_tests.$(OBJEXT) \
+ props_tests.$(OBJEXT) runtests.$(OBJEXT) structdata.$(OBJEXT) \
+ xcs_tests.$(OBJEXT)
runtests_OBJECTS = $(am_runtests_OBJECTS)
runtests_DEPENDENCIES = ../lib/libtestpat.la
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -184,7 +185,8 @@ am__depfiles_remade = ./$(DEPDIR)/acc_tests.Po \
./$(DEPDIR)/hash_tests.Po ./$(DEPDIR)/memcheck.Po \
./$(DEPDIR)/minicheck.Po ./$(DEPDIR)/misc_tests.Po \
./$(DEPDIR)/ns_tests.Po ./$(DEPDIR)/nsalloc_tests.Po \
- ./$(DEPDIR)/runtests.Po ./$(DEPDIR)/structdata.Po
+ ./$(DEPDIR)/props_tests.Po ./$(DEPDIR)/runtests.Po \
+ ./$(DEPDIR)/structdata.Po ./$(DEPDIR)/xcs_tests.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -519,12 +521,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -579,7 +579,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -656,8 +655,10 @@ runtests_SOURCES = \
misc_tests.c \
ns_tests.c \
nsalloc_tests.c \
+ props_tests.c \
runtests.c \
- structdata.c
+ structdata.c \
+ xcs_tests.c
runtests_LDADD = ../lib/libtestpat.la
runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
@@ -675,9 +676,11 @@ EXTRA_DIST = \
misc_tests.h \
ns_tests.h \
nsalloc_tests.h \
+ props_tests.h \
README.md \
structdata.h \
udiffer.py \
+ xcs_tests.h \
xmltest.log.expected \
xmltest.sh
@@ -742,8 +745,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc_tests.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ns_tests.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsalloc_tests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/props_tests.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtests.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/structdata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcs_tests.Po@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@@ -1186,8 +1191,10 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/misc_tests.Po
-rm -f ./$(DEPDIR)/ns_tests.Po
-rm -f ./$(DEPDIR)/nsalloc_tests.Po
+ -rm -f ./$(DEPDIR)/props_tests.Po
-rm -f ./$(DEPDIR)/runtests.Po
-rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f ./$(DEPDIR)/xcs_tests.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -1246,8 +1253,10 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/misc_tests.Po
-rm -f ./$(DEPDIR)/ns_tests.Po
-rm -f ./$(DEPDIR)/nsalloc_tests.Po
+ -rm -f ./$(DEPDIR)/props_tests.Po
-rm -f ./$(DEPDIR)/runtests.Po
-rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f ./$(DEPDIR)/xcs_tests.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/contrib/expat/tests/acc_tests.c b/contrib/expat/tests/acc_tests.c
index 5e38dee0f5e2..5e2f0f07316e 100644
--- a/contrib/expat/tests/acc_tests.c
+++ b/contrib/expat/tests/acc_tests.c
@@ -359,6 +359,41 @@ START_TEST(test_billion_laughs_attack_protection_api) {
}
END_TEST
+START_TEST(test_billions_laughs_attack_protection_api_float_round_trip) {
+ const float values[] = {1.0f, 1.1f, INFINITY};
+
+ for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+ set_subtest("float %f", (double)i);
+ const float wanted = values[i];
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ // Self-Test: Original value not already at target value
+ double actual = 123.456;
+ assert_true((float)actual != wanted);
+# if XML_GE == 1
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, &actual)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)actual != wanted); // Self-Test
+
+ // Test: Target value applied successfully
+ assert_true(
+ XML_SetBillionLaughsAttackProtectionMaximumAmplification(parser, wanted)
+ == XML_TRUE);
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, &actual)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)actual == wanted);
+# endif // XML_GE == 1
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
START_TEST(test_helper_unsigned_char_to_printable) {
// Smoke test
unsigned char uc = 0;
@@ -451,6 +486,8 @@ make_accounting_test_case(Suite *s) {
tcase_add_test(tc_accounting, test_accounting_precision);
tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
+ tcase_add_test(tc_accounting,
+ test_billions_laughs_attack_protection_api_float_round_trip);
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
tcase_add_test__ifdef_xml_dtd(tc_accounting,
test_amplification_isolated_external_parser);
diff --git a/contrib/expat/tests/alloc_tests.c b/contrib/expat/tests/alloc_tests.c
index c7939708e061..690039bc9ed7 100644
--- a/contrib/expat/tests/alloc_tests.c
+++ b/contrib/expat/tests/alloc_tests.c
@@ -21,6 +21,7 @@
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Copyright (c) 2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
+ Copyright (c) 2026 Filippo Tedeschi <filippotedeschi98@gmail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -563,6 +564,24 @@ START_TEST(test_alloc_explicit_encoding) {
}
END_TEST
+/* Test robustness of XML_ParserReset() with a failing allocator when setting
+ * encoding */
+START_TEST(test_alloc_reset_encoding) {
+ int i;
+ const int max_alloc_count = 5;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ g_allocation_count = i;
+ if (XML_ParserReset(g_parser, XCS("us-ascii")) == XML_TRUE)
+ break;
+ }
+ if (i == 0)
+ fail("Reset with encoding succeeded despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Reset with encoding failed at max allocation count");
+}
+END_TEST
+
/* Test robustness of XML_SetBase against a failing allocator */
START_TEST(test_alloc_set_base) {
const XML_Char *new_base = XCS("/local/file/name.xml");
@@ -2118,6 +2137,10 @@ START_TEST(test_alloc_tracker_size_recorded) {
assert_true(ptr != NULL);
assert_true(sizeRecordedFor(ptr) == 10);
+ assert_true(expat_realloc(parser, ptr, SIZE_MAX, -1) == NULL);
+
+ assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged
+
assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL);
assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged
@@ -2273,6 +2296,40 @@ START_TEST(test_alloc_tracker_api) {
}
END_TEST
+START_TEST(test_alloc_tracker_api_float_round_trip) {
+ const float values[] = {1.0f, 1.1f, INFINITY};
+
+ for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+ set_subtest("float %f", (double)i);
+ const float wanted = values[i];
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ // Self-Test: Original value not already at target value
+ double actual = 123.456;
+ assert_true((float)actual != wanted);
+#if XML_GE == 1
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, &actual)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)actual != wanted); // Self-Test
+
+ // Test: Target value applied successfully
+ assert_true(XML_SetAllocTrackerMaximumAmplification(parser, wanted)
+ == XML_TRUE);
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, &actual)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)actual == wanted);
+#endif // XML_GE == 1
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
START_TEST(test_mem_api_cycle) {
XML_Parser parser = XML_ParserCreate(NULL);
@@ -2336,6 +2393,7 @@ make_alloc_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_parameter_entity);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
+ tcase_add_test(tc_alloc, test_alloc_reset_encoding);
tcase_add_test(tc_alloc, test_alloc_set_base);
tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_ext_entity_realloc_buffer);
@@ -2386,6 +2444,7 @@ make_alloc_test_case(Suite *s) {
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_threshold);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api_float_round_trip);
tcase_add_test(tc_alloc, test_mem_api_cycle);
tcase_add_test__if_xml_ge(tc_alloc, test_mem_api_unlimited);
diff --git a/contrib/expat/tests/basic_tests.c b/contrib/expat/tests/basic_tests.c
index 8f4f0902d5c7..c7fd3d19d28b 100644
--- a/contrib/expat/tests/basic_tests.c
+++ b/contrib/expat/tests/basic_tests.c
@@ -26,6 +26,7 @@
Copyright (c) 2026 Zeyou Liu <zeyouliu@tencent.com>
Copyright (c) 2026 Afonso Januário <afonso-januario@hotmail.com>
Copyright (c) 2026 Braian Plaku <braianplaku@gmail.com>
+ Copyright (c) 2026 Filippo Tedeschi <filippotedeschi98@gmail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -57,7 +58,8 @@
#include "expat_config.h"
#include <assert.h>
-#include <limits.h> // ULONG_MAX
+#include <inttypes.h> // PRIu64
+#include <limits.h> // ULONG_MAX
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
@@ -72,6 +74,7 @@
#include "handlers.h"
#include "siphash.h"
#include "basic_tests.h"
+#include "../lib/xcs.h"
#define EXPAT_TESTS_ASAN 1
@@ -646,16 +649,15 @@ START_TEST(test_line_number_after_parse) {
const char *text = "<tag>\n"
"\n"
"\n</tag>";
- XML_Size lineno;
+ uint64_t lineno;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
- lineno = XML_GetCurrentLineNumber(g_parser);
+ lineno = XML_GetCurrentLineNumber64(g_parser);
if (lineno != 4) {
char buffer[100];
- snprintf(buffer, sizeof(buffer),
- "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ snprintf(buffer, sizeof(buffer), "expected 4 lines, saw %" PRIu64, lineno);
fail(buffer);
}
}
@@ -664,16 +666,16 @@ END_TEST
/* Regression test #2 for SF bug #653180. */
START_TEST(test_column_number_after_parse) {
const char *text = "<tag></tag>";
- XML_Size colno;
+ uint64_t colno;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
- colno = XML_GetCurrentColumnNumber(g_parser);
+ colno = XML_GetCurrentColumnNumber64(g_parser);
if (colno != 11) {
char buffer[100];
- snprintf(buffer, sizeof(buffer),
- "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ snprintf(buffer, sizeof(buffer), "expected 11 columns, saw %" PRIu64,
+ colno);
fail(buffer);
}
}
@@ -716,16 +718,15 @@ START_TEST(test_line_number_after_error) {
const char *text = "<a>\n"
" <b>\n"
" </a>"; /* missing </b> */
- XML_Size lineno;
+ uint64_t lineno;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_ERROR)
fail("Expected a parse error");
- lineno = XML_GetCurrentLineNumber(g_parser);
+ lineno = XML_GetCurrentLineNumber64(g_parser);
if (lineno != 3) {
char buffer[100];
- snprintf(buffer, sizeof(buffer),
- "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ snprintf(buffer, sizeof(buffer), "expected 3 lines, saw %" PRIu64, lineno);
fail(buffer);
}
}
@@ -736,16 +737,15 @@ START_TEST(test_column_number_after_error) {
const char *text = "<a>\n"
" <b>\n"
" </a>"; /* missing </b> */
- XML_Size colno;
+ uint64_t colno;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_ERROR)
fail("Expected a parse error");
- colno = XML_GetCurrentColumnNumber(g_parser);
+ colno = XML_GetCurrentColumnNumber64(g_parser);
if (colno != 4) {
char buffer[100];
- snprintf(buffer, sizeof(buffer),
- "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ snprintf(buffer, sizeof(buffer), "expected 4 columns, saw %" PRIu64, colno);
fail(buffer);
}
}
@@ -921,9 +921,8 @@ check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
for (i = 0; atts[i] != NULL; i += 2) {
const XML_Char *attrname = atts[i];
const XML_Char *value = atts[i + 1];
- if (xcstrcmp(XCS("attr"), attrname) == 0
- || xcstrcmp(XCS("ents"), attrname) == 0
- || xcstrcmp(XCS("refs"), attrname) == 0) {
+ if (xcscmp(XCS("attr"), attrname) == 0 || xcscmp(XCS("ents"), attrname) == 0
+ || xcscmp(XCS("refs"), attrname) == 0) {
if (! is_whitespace_normalized(value, 0)) {
char buffer[256];
snprintf(buffer, sizeof(buffer),
@@ -2598,6 +2597,57 @@ START_TEST(test_default_current) {
}
END_TEST
+/* Test XML_DefaultCurrent does not dereference NULL when outside an event */
+START_TEST(test_default_current_outside_event) {
+ struct handler_record_list handlerCalls;
+ handlerCalls.count = 0;
+
+ set_subtest("NULL parser");
+ XML_DefaultCurrent(NULL);
+
+ set_subtest("before parse");
+ {
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetDefaultHandler(parser, record_default_handler);
+ XML_SetUserData(parser, &handlerCalls);
+
+ XML_DefaultCurrent(parser);
+ assert_true(handlerCalls.count == 0);
+
+ XML_ParserFree(parser);
+ }
+
+ set_subtest("after parse");
+ {
+ const char *text = "<r>hello</r>";
+ XML_Parser parser = XML_ParserCreate(NULL);
+ if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_SetDefaultHandler(parser, record_default_handler);
+ XML_SetUserData(parser, &handlerCalls);
+
+ XML_DefaultCurrent(parser);
+ assert_true(handlerCalls.count == 0);
+
+ XML_ParserFree(parser);
+ }
+
+ set_subtest("explicit encoding before parse");
+ {
+ XML_Parser parser = XML_ParserCreate(XCS("ISO-8859-1"));
+ XML_SetDefaultHandler(parser, record_default_handler);
+ XML_SetUserData(parser, &handlerCalls);
+
+ XML_DefaultCurrent(parser);
+ assert_true(handlerCalls.count == 0);
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
/* Test DTD element parsing code paths */
START_TEST(test_dtd_elements) {
const char *text = "<!DOCTYPE doc [\n"
@@ -2627,7 +2677,7 @@ element_decl_check_model(void *userData, const XML_Char *name,
* [5] (type 4, quant 3, name "xyz")
* [2] (type 4, quant 2, name "zebra")
*/
- errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0));
+ errorFlags |= ((xcscmp(name, XCS("junk")) == 0) ? 0 : (1u << 0));
errorFlags |= ((model != NULL) ? 0 : (1u << 1));
if (model != NULL) {
@@ -2647,26 +2697,25 @@ element_decl_check_model(void *userData, const XML_Char *name,
errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13));
errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14));
errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15));
- errorFlags
- |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16));
+ errorFlags |= ((xcscmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16));
errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17));
errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18));
errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19));
errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20));
- errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21));
+ errorFlags |= ((xcscmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21));
errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22));
errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23));
errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24));
errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25));
- errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26));
+ errorFlags |= ((xcscmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26));
errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27));
errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28));
errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29));
errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30));
- errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31));
+ errorFlags |= ((xcscmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31));
}
XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags);
@@ -2833,7 +2882,7 @@ START_TEST(test_set_base) {
old_base = XML_GetBase(g_parser);
if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
fail("Unable to set base");
- if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
+ if (xcscmp(XML_GetBase(g_parser), new_base) != 0)
fail("Base setting not correct");
if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
fail("Unable to NULL base");
@@ -3160,12 +3209,12 @@ check_second_attr_normalization(void *userData, const XML_Char *name,
for (size_t i = 0; atts[i] != NULL; i += 2) {
const XML_Char *const key = atts[i];
const XML_Char *const value = atts[i + 1];
- if (xcstrcmp(key, XCS("second")) != 0)
+ if (xcscmp(key, XCS("second")) != 0)
continue;
*seen_second = 1;
/* Attribute "second" is not of type CDATA, so leading, trailing and
* repeated whitespace is to be normalized away. */
- if (xcstrcmp(value, XCS("a b")) != 0)
+ if (xcscmp(value, XCS("a b")) != 0)
fail("Attribute of non-CDATA type was not whitespace-normalized");
}
}
@@ -3725,6 +3774,46 @@ START_TEST(test_negative_len_parse_buffer) {
}
END_TEST
+/* Test XML_ParseBuffer rejects calls where len exceeds available buffer */
+START_TEST(test_parse_buffer_exceeds_buffer) {
+ for (int isFinal = 0; isFinal < 2; isFinal++) {
+ set_subtest("isFinal=%d", isFinal);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ /* Calling XML_ParseBuffer without any prior XML_GetBuffer call */
+ if (XML_ParseBuffer(parser, 10, isFinal) != XML_STATUS_ERROR)
+ fail("XML_ParseBuffer without XML_GetBuffer was expected to fail.");
+ if (XML_GetErrorCode(parser) != XML_ERROR_NO_BUFFER)
+ fail("Expected XML_ERROR_NO_BUFFER.");
+
+ /* Acquire a small buffer */
+ void *const buffer = XML_GetBuffer(parser, 10);
+ if (buffer == NULL)
+ fail("XML_GetBuffer failed.");
+
+ /* Calling XML_ParseBuffer with len exceeding available buffer capacity */
+ if (XML_ParseBuffer(parser, 10000, isFinal) != XML_STATUS_ERROR)
+ fail("XML_ParseBuffer with len > capacity was expected to fail.");
+ if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT)
+ fail("Expected XML_ERROR_INVALID_ARGUMENT.");
+
+ /* Valid parse */
+ memcpy(buffer, "<r></r>", 7);
+ if (XML_ParseBuffer(parser, 7, XML_FALSE) != XML_STATUS_OK)
+ xml_failure(parser);
+
+ /* Subsequent XML_ParseBuffer where len exceeds remaining capacity */
+ if (XML_ParseBuffer(parser, 10000, isFinal) != XML_STATUS_ERROR)
+ fail("XML_ParseBuffer on subsequent chunk was expected to fail.");
+ if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT)
+ fail("Expected XML_ERROR_INVALID_ARGUMENT.");
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
/* Test odd corners of the XML_GetBuffer interface */
static enum XML_Status
get_feature(enum XML_FeatureEnum feature_id, long *presult) {
@@ -3907,16 +3996,16 @@ END_TEST
START_TEST(test_byte_info_at_end) {
const char *text = "<doc></doc>";
- if (XML_GetCurrentByteIndex(g_parser) != -1
- || XML_GetCurrentByteCount(g_parser) != 0)
+ if (XML_GetCurrentByteIndex64(g_parser) != -1
+ || XML_GetCurrentByteCount64(g_parser) != 0)
fail("Byte index/count incorrect at start of parse");
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
/* At end, the count will be zero and the index the end of string */
- if (XML_GetCurrentByteCount(g_parser) != 0)
+ if (XML_GetCurrentByteCount64(g_parser) != 0)
fail("Terminal byte count incorrect");
- if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
+ if (XML_GetCurrentByteIndex64(g_parser) != (int64_t)strlen(text))
fail("Terminal byte index incorrect");
}
END_TEST
@@ -3930,9 +4019,9 @@ START_TEST(test_byte_info_at_error) {
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_OK)
fail("Syntax error not faulted");
- if (XML_GetCurrentByteCount(g_parser) != 0)
+ if (XML_GetCurrentByteCount64(g_parser) != 0)
fail("Error byte count incorrect");
- if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
+ if (XML_GetCurrentByteIndex64(g_parser) != strlen(PRE_ERROR_STR))
fail("Error byte index incorrect");
}
END_TEST
@@ -3945,11 +4034,12 @@ END_TEST
#define END_ELEMENT "</e>"
START_TEST(test_byte_info_at_cdata) {
const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
- int offset, size;
+ int64_t offset;
+ uint64_t size;
ByteTestData data;
/* Check initial context is empty */
- if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
+ if (XML_GetInputContext64(g_parser, &offset, &size) != NULL)
fail("Unexpected context at start of parse");
data.start_element_len = (int)strlen(START_ELEMENT);
@@ -4150,7 +4240,7 @@ external_bom_checker(XML_Parser parser, const XML_Char *context,
if (ext_parser == NULL)
fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ if (! xcscmp(systemId, XCS("004-2.ent"))) {
struct bom_testdata *const testdata = XML_GetUserData(parser);
const char *const external = testdata->external;
const int split = testdata->split;
@@ -4161,7 +4251,7 @@ external_bom_checker(XML_Parser parser, const XML_Char *context,
xml_failure(ext_parser);
}
text = external + split; // the parse below will continue where we left off.
- } else if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ } else if (! xcscmp(systemId, XCS("004-1.ent"))) {
text = "<!ELEMENT doc EMPTY>\n"
"<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
"<!ENTITY % e2 '%e1;'>\n";
@@ -7139,6 +7229,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
tcase_add_test(tc_basic, test_memory_allocation);
tcase_add_test__if_xml_ge(tc_basic, test_default_current);
+ tcase_add_test(tc_basic, test_default_current_outside_event);
tcase_add_test(tc_basic, test_dtd_elements);
tcase_add_test(tc_basic, test_dtd_elements_nesting);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
@@ -7181,6 +7272,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_empty_parse);
tcase_add_test(tc_basic, test_negative_len_parse);
tcase_add_test(tc_basic, test_negative_len_parse_buffer);
+ tcase_add_test(tc_basic, test_parse_buffer_exceeds_buffer);
tcase_add_test(tc_basic, test_get_buffer_1);
tcase_add_test(tc_basic, test_get_buffer_2);
#if XML_CONTEXT_BYTES > 0
diff --git a/contrib/expat/tests/benchmark/Makefile.in b/contrib/expat/tests/benchmark/Makefile.in
index 4156629984be..894e6bdbae4f 100644
--- a/contrib/expat/tests/benchmark/Makefile.in
+++ b/contrib/expat/tests/benchmark/Makefile.in
@@ -252,12 +252,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -312,7 +310,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
diff --git a/contrib/expat/tests/benchmark/benchmark.c b/contrib/expat/tests/benchmark/benchmark.c
index a02b84a0131d..48658e5a464e 100644
--- a/contrib/expat/tests/benchmark/benchmark.c
+++ b/contrib/expat/tests/benchmark/benchmark.c
@@ -8,7 +8,7 @@
Copyright (c) 2003-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
- Copyright (c) 2017-2025 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
@@ -40,7 +40,8 @@
# include <unistd.h> // close
#endif
-#include <fcntl.h> // open
+#include <inttypes.h> // PRIu64
+#include <fcntl.h> // open
#include <sys/stat.h>
#include <assert.h>
#include <stddef.h> // ptrdiff_t
@@ -48,12 +49,6 @@
#include <time.h>
#include "expat.h"
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
#ifdef XML_UNICODE_WCHAR_T
# define XML_FMT_STR "ls"
#else
@@ -148,11 +143,11 @@ main(int argc, char *argv[]) {
assert(parseBufferSize <= (ptrdiff_t)bufferSize);
if (! XML_Parse(parser, XMLBufPtr, (int)parseBufferSize, isFinal)) {
fprintf(stderr,
- "error '%" XML_FMT_STR "' at line %" XML_FMT_INT_MOD
- "u character %" XML_FMT_INT_MOD "u\n",
+ "error '%" XML_FMT_STR "' at line %" PRIu64
+ " character %" PRIu64 "\n",
XML_ErrorString(XML_GetErrorCode(parser)),
- XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser));
+ XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser));
free(XMLBuf);
XML_ParserFree(parser);
return 4;
diff --git a/contrib/expat/tests/chardata.c b/contrib/expat/tests/chardata.c
index a36d58c24f36..a9d917f1d0fc 100644
--- a/contrib/expat/tests/chardata.c
+++ b/contrib/expat/tests/chardata.c
@@ -9,7 +9,7 @@
Copyright (c) 2002-2004 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2016 Gilles Espinasse <g.esp@free.fr>
- Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
@@ -49,7 +49,7 @@
#include <string.h>
#include "chardata.h"
-#include "../lib/xcsinc.c"
+#include "../lib/xcs.h"
void
CharData_Init(CharData *storage) {
diff --git a/contrib/expat/tests/common.c b/contrib/expat/tests/common.c
index e2980cbcadbd..51509a7f0a1b 100644
--- a/contrib/expat/tests/common.c
+++ b/contrib/expat/tests/common.c
@@ -48,7 +48,8 @@
#include <assert.h>
#include <errno.h>
-#include <stdint.h> // for SIZE_MAX
+#include <inttypes.h> // for PRIu64
+#include <stdint.h> // for SIZE_MAX
#include <stdio.h>
#include <string.h>
@@ -188,10 +189,10 @@ _xml_failure(XML_Parser parser, const char *file, int line) {
char buffer[1024];
enum XML_Error err = XML_GetErrorCode(parser);
snprintf(buffer, sizeof(buffer),
- " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
- "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
- err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser), file, line);
+ " %d: %" XML_FMT_STR " (line %" PRIu64 ", offset %" PRIu64
+ ")\n reported from %s, line %d\n",
+ err, XML_ErrorString(err), XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser), file, line);
_fail(file, line, buffer);
}
diff --git a/contrib/expat/tests/common.h b/contrib/expat/tests/common.h
index f9bde995e7d2..a7a6bf51ea15 100644
--- a/contrib/expat/tests/common.h
+++ b/contrib/expat/tests/common.h
@@ -59,9 +59,6 @@
#ifdef XML_UNICODE_WCHAR_T
# define XML_FMT_STR "ls"
# include <wchar.h>
-# define xcstrlen(s) wcslen(s)
-# define xcstrcmp(s, t) wcscmp((s), (t))
-# define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
# define XCS(s) _XCS(s)
# define _XCS(s) L##s
#else
@@ -69,9 +66,6 @@
# error "No support for UTF-16 character without wchar_t in tests"
# else
# define XML_FMT_STR "s"
-# define xcstrlen(s) strlen(s)
-# define xcstrcmp(s, t) strcmp((s), (t))
-# define xcstrncmp(s, t, n) strncmp((s), (t), (n))
# define XCS(s) s
# endif /* XML_UNICODE */
#endif /* XML_UNICODE_WCHAR_T */
diff --git a/contrib/expat/tests/handlers.c b/contrib/expat/tests/handlers.c
index 7fc4b7e50cd6..57ca4e51df77 100644
--- a/contrib/expat/tests/handlers.c
+++ b/contrib/expat/tests/handlers.c
@@ -63,6 +63,7 @@
#include "structdata.h"
#include "common.h"
#include "handlers.h"
+#include "../lib/xcs.h"
/* Global variables for user parameter settings tests */
/* Variable holding the expected handler userData */
@@ -95,15 +96,16 @@ start_element_event_handler2(void *userData, const XML_Char *name,
const XML_Char **attr) {
StructData *storage = (StructData *)userData;
UNUSED_P(attr);
- StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber(g_parser),
- (int)XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
+ StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber64(g_parser),
+ (int)XML_GetCurrentLineNumber64(g_parser),
+ STRUCT_START_TAG);
}
void XMLCALL
end_element_event_handler2(void *userData, const XML_Char *name) {
StructData *storage = (StructData *)userData;
- StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber(g_parser),
- (int)XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
+ StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber64(g_parser),
+ (int)XML_GetCurrentLineNumber64(g_parser), STRUCT_END_TAG);
}
void XMLCALL
@@ -116,7 +118,7 @@ counting_start_element_handler(void *userData, const XML_Char *name,
int count, id, i;
while (info->name != NULL) {
- if (! xcstrcmp(name, info->name))
+ if (! xcscmp(name, info->name))
break;
info++;
}
@@ -138,14 +140,14 @@ counting_start_element_handler(void *userData, const XML_Char *name,
fail("ID not present");
return;
}
- if (id != -1 && xcstrcmp(atts[id], info->id_name) != 0) {
+ if (id != -1 && xcscmp(atts[id], info->id_name) != 0) {
fail("ID does not have the correct name");
return;
}
for (i = 0; i < info->attr_count + info->default_attr_count; i++) {
attr = info->attributes;
while (attr->name != NULL) {
- if (! xcstrcmp(atts[0], attr->name))
+ if (! xcscmp(atts[0], attr->name))
break;
attr++;
}
@@ -153,7 +155,7 @@ counting_start_element_handler(void *userData, const XML_Char *name,
fail("Attribute not recognised");
return;
}
- if (xcstrcmp(atts[1], attr->value) != 0) {
+ if (xcscmp(atts[1], attr->value) != 0) {
fail("Attribute has wrong value");
return;
}
@@ -176,9 +178,9 @@ start_element_suspender(void *userData, const XML_Char *name,
const XML_Char **atts) {
UNUSED_P(userData);
UNUSED_P(atts);
- if (! xcstrcmp(name, XCS("suspend")))
+ if (! xcscmp(name, XCS("suspend")))
XML_StopParser(g_parser, XML_TRUE);
- if (! xcstrcmp(name, XCS("abort")))
+ if (! xcscmp(name, XCS("abort")))
XML_StopParser(g_parser, XML_FALSE);
}
@@ -195,12 +197,12 @@ triplet_start_checker(void *userData, const XML_Char *name,
const XML_Char **atts) {
XML_Char **elemstr = (XML_Char **)userData;
char buffer[1024];
- if (xcstrcmp(elemstr[0], name) != 0) {
+ if (xcscmp(elemstr[0], name) != 0) {
snprintf(buffer, sizeof(buffer),
"unexpected start string: '%" XML_FMT_STR "'", name);
fail(buffer);
}
- if (xcstrcmp(elemstr[1], atts[0]) != 0) {
+ if (xcscmp(elemstr[1], atts[0]) != 0) {
snprintf(buffer, sizeof(buffer),
"unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
fail(buffer);
@@ -215,7 +217,7 @@ triplet_start_checker(void *userData, const XML_Char *name,
void XMLCALL
triplet_end_checker(void *userData, const XML_Char *name) {
XML_Char **elemstr = (XML_Char **)userData;
- if (xcstrcmp(elemstr[0], name) != 0) {
+ if (xcscmp(elemstr[0], name) != 0) {
char buffer[1024];
snprintf(buffer, sizeof(buffer),
"unexpected end string: '%" XML_FMT_STR "'", name);
@@ -291,7 +293,7 @@ int XMLCALL
UnknownEncodingHandler(void *data, const XML_Char *encoding,
XML_Encoding *info) {
UNUSED_P(data);
- if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
+ if (xcscmp(encoding, XCS("unsupported-encoding")) == 0) {
int i;
for (i = 0; i < 256; ++i)
info->map[i] = i;
@@ -323,7 +325,7 @@ int XMLCALL
unknown_released_encoding_handler(void *data, const XML_Char *encoding,
XML_Encoding *info) {
UNUSED_P(data);
- if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
+ if (! xcscmp(encoding, XCS("unsupported-encoding"))) {
int i;
for (i = 0; i < 256; i++)
@@ -359,12 +361,12 @@ MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
int i;
int high_map = -2; /* Assume a 2-byte sequence */
- if (! xcstrcmp(encoding, XCS("invalid-9"))
- || ! xcstrcmp(encoding, XCS("ascii-like"))
- || ! xcstrcmp(encoding, XCS("invalid-len"))
- || ! xcstrcmp(encoding, XCS("invalid-a"))
- || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
- || ! xcstrcmp(encoding, XCS("invalid-high")))
+ if (! xcscmp(encoding, XCS("invalid-9"))
+ || ! xcscmp(encoding, XCS("ascii-like"))
+ || ! xcscmp(encoding, XCS("invalid-len"))
+ || ! xcscmp(encoding, XCS("invalid-a"))
+ || ! xcscmp(encoding, XCS("invalid-surrogate"))
+ || ! xcscmp(encoding, XCS("invalid-high")))
high_map = -1;
for (i = 0; i < 128; ++i)
@@ -373,28 +375,28 @@ MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
info->map[i] = high_map;
/* If required, put an invalid value in the ASCII entries */
- if (! xcstrcmp(encoding, XCS("invalid-9")))
+ if (! xcscmp(encoding, XCS("invalid-9")))
info->map[9] = 5;
/* If required, have a top-bit set character starts a 5-byte sequence */
- if (! xcstrcmp(encoding, XCS("invalid-len")))
+ if (! xcscmp(encoding, XCS("invalid-len")))
info->map[0x81] = -5;
/* If required, make a top-bit set character a valid ASCII character */
- if (! xcstrcmp(encoding, XCS("invalid-a")))
+ if (! xcscmp(encoding, XCS("invalid-a")))
info->map[0x82] = 'a';
/* If required, give a top-bit set character a forbidden value,
* what would otherwise be the first of a surrogate pair.
*/
- if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
+ if (! xcscmp(encoding, XCS("invalid-surrogate")))
info->map[0x83] = 0xd801;
/* If required, give a top-bit set character too high a value */
- if (! xcstrcmp(encoding, XCS("invalid-high")))
+ if (! xcscmp(encoding, XCS("invalid-high")))
info->map[0x84] = 0x010101;
info->data = data;
info->release = NULL;
- if (! xcstrcmp(encoding, XCS("failing-conv")))
+ if (! xcscmp(encoding, XCS("failing-conv")))
info->convert = failing_converter;
- else if (! xcstrcmp(encoding, XCS("prefix-conv")))
+ else if (! xcscmp(encoding, XCS("prefix-conv")))
info->convert = prefix_converter;
else
info->convert = NULL;
@@ -437,7 +439,7 @@ external_entity_optioner(XML_Parser parser, const XML_Char *context,
UNUSED_P(base);
UNUSED_P(publicId);
while (options->parse_text != NULL) {
- if (! xcstrcmp(systemId, options->system_id)) {
+ if (! xcscmp(systemId, options->system_id)) {
enum XML_Status rc;
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
@@ -874,13 +876,13 @@ external_entity_param(XML_Parser parser, const XML_Char *context,
if (ext_parser == NULL)
fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (! xcscmp(systemId, XCS("004-1.ent"))) {
if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
!= XML_STATUS_ERROR)
fail("Inner DTD with invalid tag not rejected");
if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
xml_failure(ext_parser);
- } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ } else if (! xcscmp(systemId, XCS("004-2.ent"))) {
if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
!= XML_STATUS_ERROR)
fail("Invalid tag in external param not rejected");
@@ -984,11 +986,11 @@ external_entity_valuer(XML_Parser parser, const XML_Char *context,
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (! xcscmp(systemId, XCS("004-1.ent"))) {
if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(ext_parser);
- } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ } else if (! xcscmp(systemId, XCS("004-2.ent"))) {
ExtFaults *fault = XML_GetUserData(parser);
enum XML_Status status;
enum XML_Error error;
@@ -1030,7 +1032,7 @@ external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("foo"))) {
+ if (! xcscmp(systemId, XCS("foo"))) {
XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
!= XML_STATUS_ERROR)
@@ -1040,7 +1042,7 @@ external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
XML_SetNotStandaloneHandler(ext_parser, NULL);
XML_ParserFree(ext_parser);
return XML_STATUS_ERROR;
- } else if (! xcstrcmp(systemId, XCS("bar"))) {
+ } else if (! xcscmp(systemId, XCS("bar"))) {
if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(ext_parser);
@@ -1068,12 +1070,12 @@ external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
fail("Could not create external entity parser");
- if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (! xcscmp(systemId, XCS("004-1.ent"))) {
if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(ext_parser);
}
- if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ if (! xcscmp(systemId, XCS("004-2.ent"))) {
XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
XML_SetUserData(ext_parser, ext_parser);
if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
@@ -1101,9 +1103,9 @@ external_entity_public(XML_Parser parser, const XML_Char *context,
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
return XML_STATUS_ERROR;
- if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
+ if (systemId != NULL && ! xcscmp(systemId, XCS("http://example.org/"))) {
text = text1;
- } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
+ } else if (publicId != NULL && ! xcscmp(publicId, XCS("foo"))) {
text = text2;
} else
fail("Unexpected parameters to external entity parser");
@@ -1126,9 +1128,9 @@ external_entity_devaluer(XML_Parser parser, const XML_Char *context,
UNUSED_P(base);
UNUSED_P(publicId);
- if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
+ if (systemId == NULL || ! xcscmp(systemId, XCS("bar")))
return XML_STATUS_OK;
- if (xcstrcmp(systemId, XCS("foo")) != 0)
+ if (xcscmp(systemId, XCS("foo")) != 0)
fail("Unexpected system ID");
ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
if (ext_parser == NULL)
@@ -1527,9 +1529,9 @@ accounting_external_entity_ref_handler(XML_Parser parser,
const struct AccountingTestCase *const testCase = XML_GetUserData(parser);
const char *externalText = NULL;
- if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
+ if (xcscmp(systemId, XCS("first.ent")) == 0) {
externalText = testCase->firstExternalText;
- } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
+ } else if (xcscmp(systemId, XCS("second.ent")) == 0) {
externalText = testCase->secondExternalText;
} else {
assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
@@ -1569,16 +1571,16 @@ verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
const XML_Char *default_value, int is_required) {
AttTest *at = (AttTest *)userData;
- if (xcstrcmp(element_name, at->element_name) != 0)
+ if (xcscmp(element_name, at->element_name) != 0)
fail("Unexpected element name in attribute declaration");
- if (xcstrcmp(attr_name, at->attr_name) != 0)
+ if (xcscmp(attr_name, at->attr_name) != 0)
fail("Unexpected attribute name in attribute declaration");
- if (xcstrcmp(attr_type, at->attr_type) != 0)
+ if (xcscmp(attr_type, at->attr_type) != 0)
fail("Unexpected attribute type in attribute declaration");
if ((default_value == NULL && at->default_value != NULL)
|| (default_value != NULL && at->default_value == NULL)
|| (default_value != NULL
- && xcstrcmp(default_value, at->default_value) != 0))
+ && xcscmp(default_value, at->default_value) != 0))
fail("Unexpected default value in attribute declaration");
if (is_required != at->is_required)
fail("Requirement mismatch in attribute declaration");
@@ -1649,23 +1651,24 @@ rsqb_handler(void *userData, const XML_Char *s, int len) {
void XMLCALL
byte_character_handler(void *userData, const XML_Char *s, int len) {
#if XML_CONTEXT_BYTES > 0
- int offset, size;
+ int64_t offset;
+ uint64_t size;
const char *buffer;
ByteTestData *data = (ByteTestData *)userData;
UNUSED_P(s);
- buffer = XML_GetInputContext(g_parser, &offset, &size);
+ buffer = XML_GetInputContext64(g_parser, &offset, &size);
if (buffer == NULL)
fail("Failed to get context buffer");
if (offset != data->start_element_len)
fail("Context offset in unexpected position");
if (len != data->cdata_len)
fail("CDATA length reported incorrectly");
- if (size != data->total_string_len)
+ if (size != (uint64_t)data->total_string_len)
fail("Context size is not full buffer");
- if (XML_GetCurrentByteIndex(g_parser) != offset)
+ if (XML_GetCurrentByteIndex64(g_parser) != offset)
fail("Character byte index incorrect");
- if (XML_GetCurrentByteCount(g_parser) != len)
+ if (XML_GetCurrentByteCount64(g_parser) != (uint64_t)len)
fail("Character byte count incorrect");
#else
UNUSED_P(s);
@@ -1723,7 +1726,7 @@ void XMLCALL
record_element_start_handler(void *userData, const XML_Char *name,
const XML_Char **atts) {
UNUSED_P(atts);
- CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
+ CharData_AppendXMLChars((CharData *)userData, name, (int)xcslen(name));
}
void XMLCALL
@@ -1763,13 +1766,13 @@ param_entity_match_handler(void *userData, const XML_Char *entityName,
|| entity_value_to_match == NULL) {
return;
}
- if (! xcstrcmp(entityName, entity_name_to_match)) {
+ if (! xcscmp(entityName, entity_name_to_match)) {
/* The cast here is safe because we control the horizontal and
* the vertical, and we therefore know our strings are never
* going to overflow an int.
*/
- if (value_length != (int)xcstrlen(entity_value_to_match)
- || xcstrncmp(value, entity_value_to_match, value_length) != 0) {
+ if (value_length != (int)xcslen(entity_value_to_match)
+ || xcsncmp(value, entity_value_to_match, value_length) != 0) {
entity_match_flag = ENTITY_MATCH_FAIL;
} else {
entity_match_flag = ENTITY_MATCH_SUCCESS;
diff --git a/contrib/expat/tests/misc_tests.c b/contrib/expat/tests/misc_tests.c
index 717cc2dd31aa..f5d1e3473887 100644
--- a/contrib/expat/tests/misc_tests.c
+++ b/contrib/expat/tests/misc_tests.c
@@ -24,6 +24,7 @@
Copyright (c) 2026 Kartik Kenchi <netliomax25@gmail.com>
Copyright (c) 2026 Evgeny Kotkov <kotkov@apache.org>
Copyright (c) 2026 Darren Carreras <carrerasdarren@gmail.com>
+ Copyright (c) 2026 Junki Lee <junkilee80@gmail.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -55,6 +56,8 @@
#include "expat_config.h"
#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include "expat.h"
@@ -65,6 +68,7 @@
#include "ascii.h" /* for ASCII_xxx */
#include "handlers.h"
#include "misc_tests.h"
+#include "../lib/xcs.h"
void XMLCALL accumulate_characters_ext_handler(void *userData,
const XML_Char *s, int len);
@@ -218,7 +222,7 @@ START_TEST(test_misc_version) {
if (! versions_equal(&read_version, &parsed_version))
fail("Version mismatch");
- if (xcstrcmp(version_text, XCS("expat_2.8.5"))
+ if (xcscmp(version_text, XCS("expat_2.9.0"))
!= 0) /* needs bump on releases */
fail("XML_*_VERSION in expat.h out of sync?\n");
}
@@ -394,8 +398,8 @@ START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
XML_Parser parser;
enum XML_Status parseResult;
int setParamEntityResult;
- XML_Size lineNumber;
- XML_Size columnNumber;
+ uint64_t lineNumber;
+ uint64_t columnNumber;
parser = XML_ParserCreate(NULL);
setParamEntityResult
@@ -444,13 +448,13 @@ START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
fail("Error code does not match XML_ERROR_INVALID_TOKEN");
- lineNumber = XML_GetCurrentLineNumber(parser);
+ lineNumber = XML_GetCurrentLineNumber64(parser);
if (lineNumber != 6)
- fail("XML_GetCurrentLineNumber does not work as expected.");
+ fail("XML_GetCurrentLineNumber64 does not work as expected.");
- columnNumber = XML_GetCurrentColumnNumber(parser);
+ columnNumber = XML_GetCurrentColumnNumber64(parser);
if (columnNumber != 0)
- fail("XML_GetCurrentColumnNumber does not work as expected.");
+ fail("XML_GetCurrentColumnNumber64 does not work as expected.");
XML_ParserFree(parser);
}
@@ -629,22 +633,23 @@ END_TEST
// Inspired by function XML_OriginalString of Perl's XML::Parser
static char *
dup_original_string(XML_Parser parser) {
- const int byte_count = XML_GetCurrentByteCount(parser);
+ const uint64_t byte_count = XML_GetCurrentByteCount64(parser);
- assert_true(byte_count >= 0);
+ int64_t offset64 = -1;
+ uint64_t size64 = UINT64_MAX;
- int offset = -1;
- int size = -1;
-
- const char *const context = XML_GetInputContext(parser, &offset, &size);
+ const char *const context64
+ = XML_GetInputContext64(parser, &offset64, &size64);
#if XML_CONTEXT_BYTES > 0
- assert_true(context != NULL);
- assert_true(offset >= 0);
- assert_true(size >= 0);
- return portable_strndup(context + offset, byte_count);
+ assert_true(context64 != NULL);
+ assert_true(offset64 != -1);
+ assert_true(size64 != UINT64_MAX);
+
+ return portable_strndup(context64 + offset64, byte_count);
#else
- assert_true(context == NULL);
+ UNUSED_P(byte_count);
+ assert_true(context64 == NULL);
return NULL;
#endif
}
@@ -709,8 +714,8 @@ START_TEST(test_misc_async_entity_rejected) {
const char *doc;
enum XML_Status expectedStatusNoGE;
enum XML_Error expectedErrorNoGE;
- XML_Size expectedErrorLine;
- XML_Size expectedErrorColumn;
+ uint64_t expectedErrorLine;
+ uint16_t expectedErrorColumn;
};
const struct test_case cases[] = {
// Opened by one entity, closed by another
@@ -769,8 +774,9 @@ START_TEST(test_misc_async_entity_rejected) {
== expectedStatus);
assert_true(XML_GetErrorCode(parser) == expectedError);
#if XML_GE == 1
- assert_true(XML_GetCurrentLineNumber(parser) == testCase.expectedErrorLine);
- assert_true(XML_GetCurrentColumnNumber(parser)
+ assert_true(XML_GetCurrentLineNumber64(parser)
+ == testCase.expectedErrorLine);
+ assert_true(XML_GetCurrentColumnNumber64(parser)
== testCase.expectedErrorColumn);
#endif
XML_ParserFree(parser);
@@ -894,6 +900,66 @@ START_TEST(test_misc_unknown_encoding_callbacks_protected) {
}
END_TEST
+typedef struct {
+ XML_Parser parser;
+ int releaseCallCount;
+ uint64_t lineAtRelease;
+} EncodingReleaseData;
+
+static void XMLCALL
+position_reading_encoding_release(void *userData) {
+ EncodingReleaseData *const data = userData;
+ data->releaseCallCount++;
+ data->lineAtRelease = XML_GetCurrentLineNumber64(data->parser);
+}
+
+static int XMLCALL
+position_reading_encoding_handler(void *userData, const XML_Char *name,
+ XML_Encoding *info) {
+ UNUSED_P(name);
+
+ for (int i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->data = userData;
+ info->convert = NULL;
+ info->release = position_reading_encoding_release;
+ return XML_STATUS_OK;
+}
+
+static void
+run_unknown_encoding_release_getter_test(bool resetParser) {
+ const char *const doc = "<?xml version='1.0' encoding='release-order'?>\n"
+ "<root>\n"
+ " <unclosed>\n"
+ "</root>\n";
+ XML_Parser parser = XML_ParserCreate(NULL);
+ EncodingReleaseData data = {parser, 0, 0};
+
+ assert_true(parser != NULL);
+ XML_SetUnknownEncodingHandler(parser, position_reading_encoding_handler,
+ &data);
+ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
+ == XML_STATUS_ERROR);
+ assert_true(XML_GetErrorCode(parser) == XML_ERROR_TAG_MISMATCH);
+
+ if (resetParser)
+ assert_true(XML_ParserReset(parser, NULL) == XML_TRUE);
+ XML_ParserFree(parser);
+
+ assert_true(data.releaseCallCount == 1);
+ assert_true(data.lineAtRelease == 4);
+}
+
+START_TEST(test_misc_unknown_encoding_release_getter_parser_free) {
+ run_unknown_encoding_release_getter_test(false);
+}
+END_TEST
+
+START_TEST(test_misc_unknown_encoding_release_getter_parser_reset) {
+ run_unknown_encoding_release_getter_test(true);
+}
+END_TEST
+
// General attack payload idea by Jason Kratzer of Mozilla
START_TEST(test_misc_low_surrogate_mozilla_bug_2053153) {
const char doc_before[] = "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
@@ -992,6 +1058,10 @@ make_miscellaneous_test_case(Suite *s) {
tcase_add_test(tc_misc, test_misc_calls_forbidden_from_handlers);
tcase_add_test(tc_misc, test_misc_resume_parser_forbidden_from_handler);
tcase_add_test(tc_misc, test_misc_unknown_encoding_callbacks_protected);
+ tcase_add_test(tc_misc,
+ test_misc_unknown_encoding_release_getter_parser_free);
+ tcase_add_test(tc_misc,
+ test_misc_unknown_encoding_release_getter_parser_reset);
tcase_add_test(tc_misc, test_misc_input_2gb);
tcase_add_test(tc_misc, test_misc_low_surrogate_mozilla_bug_2053153);
}
diff --git a/contrib/expat/tests/props_tests.c b/contrib/expat/tests/props_tests.c
new file mode 100644
index 000000000000..fe0eb0697b79
--- /dev/null
+++ b/contrib/expat/tests/props_tests.c
@@ -0,0 +1,790 @@
+/* Tests related to the public properties API of Expat
+__ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#include "expat_config.h"
+
+#include "props_tests.h"
+
+#include "common.h" // for g_chunkSize
+#include "expat.h"
+#include "internal.h" // for e.g. EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT
+
+#include <math.h>
+#include <stdbool.h>
+
+enum ExpectedType {
+ TYPE_BOOL,
+ TYPE_DOUBLE,
+ TYPE_UINT64,
+};
+
+START_TEST(test_props_getter_defaults) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+#if XML_GE == 1
+ // Case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD
+ {
+ uint64_t actionThresholdBytes1 = 123;
+ assert_true(XML_GetPropertyUInt64(
+ parser, XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD,
+ &actionThresholdBytes1)
+ == XML_PROP_ERROR_NONE);
+ assert_true(actionThresholdBytes1
+ == EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT);
+ }
+
+ // Case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION
+ {
+ double maximumAmplification1 = 123.456;
+ assert_true(XML_GetPropertyDouble(
+ parser, XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION,
+ &maximumAmplification1)
+ == XML_PROP_ERROR_NONE);
+ assert_true(maximumAmplification1
+ == (double)EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT);
+ }
+
+ // Case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD
+ {
+ uint64_t actionThresholdBytes2 = 123;
+ assert_true(XML_GetPropertyUInt64(
+ parser, XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD,
+ &actionThresholdBytes2)
+ == XML_PROP_ERROR_NONE);
+ assert_true(
+ actionThresholdBytes2
+ == EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT);
+ }
+
+ // Case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION
+ {
+ double maximumAmplification2 = 123.456;
+ assert_true(XML_GetPropertyDouble(
+ parser, XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION,
+ &maximumAmplification2)
+ == XML_PROP_ERROR_NONE);
+ assert_true(
+ maximumAmplification2
+ == (double)
+ EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT);
+ }
+#endif
+
+ // Case XML_PROP_REPARSE_DEFERRAL_ENABLED
+ XML_Bool reparseDeferralEnabled = XML_FALSE;
+ assert_true(XML_GetPropertyBool(parser, XML_PROP_REPARSE_DEFERRAL_ENABLED,
+ &reparseDeferralEnabled)
+ == XML_PROP_ERROR_NONE);
+ assert_true(reparseDeferralEnabled == g_reparseDeferralEnabledDefault);
+
+ // Case XML_PROP_INVALID
+ XML_Bool dummyBool = XML_FALSE;
+ double dummyDouble = 123.456;
+ uint64_t dummyUInt64 = 123;
+ assert_true(XML_GetPropertyBool(parser, XML_PROP_INVALID, &dummyBool)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_GetPropertyDouble(parser, XML_PROP_INVALID, &dummyDouble)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_GetPropertyUInt64(parser, XML_PROP_INVALID, &dummyUInt64)
+ == XML_PROP_ERROR_INVALID_KEY);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_getter_error_parser_null) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ XML_Parser parserNonNull = XML_ParserCreate(NULL);
+ XML_Parser parsers[] = {parserNonNull, NULL};
+ assert_true(parserNonNull != NULL);
+
+ for (size_t i = 0; i < sizeof(parsers) / sizeof(parsers[0]); i++) {
+ XML_Parser parser = parsers[i];
+ const enum XML_Prop_Error validKeyExpectedError
+ = (parser == NULL) ? XML_PROP_ERROR_PARSER_NULL : XML_PROP_ERROR_NONE;
+ // NOTE: Currently the parser is checked for being `NULL` before the key is
+ // being checked for being valid.
+ // That precedence among errors is not considered part of the API
+ // contract: either error would be fine to return.
+ const enum XML_Prop_Error invalidKeyExpectedError
+ = (parser == NULL) ? XML_PROP_ERROR_PARSER_NULL
+ : XML_PROP_ERROR_INVALID_KEY;
+
+ XML_Bool dummyBool = XML_FALSE;
+ double dummyDouble = 123.456;
+ uint64_t dummyUInt64 = 123;
+
+#if XML_GE == 1
+ assert_true(
+ XML_GetPropertyUInt64(
+ parser, XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, &dummyUInt64)
+ == validKeyExpectedError);
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, &dummyDouble)
+ == validKeyExpectedError);
+ assert_true(
+ XML_GetPropertyUInt64(
+ parser, XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, &dummyUInt64)
+ == validKeyExpectedError);
+ assert_true(
+ XML_GetPropertyDouble(
+ parser, XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, &dummyDouble)
+ == validKeyExpectedError);
+#endif
+ assert_true(XML_GetPropertyBool(parser, XML_PROP_REPARSE_DEFERRAL_ENABLED,
+ &dummyBool)
+ == validKeyExpectedError);
+
+ assert_true(XML_GetPropertyBool(parser, XML_PROP_INVALID, &dummyBool)
+ == invalidKeyExpectedError);
+ assert_true(XML_GetPropertyDouble(parser, XML_PROP_INVALID, &dummyDouble)
+ == invalidKeyExpectedError);
+ assert_true(XML_GetPropertyUInt64(parser, XML_PROP_INVALID, &dummyUInt64)
+ == invalidKeyExpectedError);
+ }
+
+ XML_ParserFree(parserNonNull);
+}
+END_TEST
+
+START_TEST(test_props_getter_error_invalid_key) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ XML_Bool dummyBool = XML_FALSE;
+ double dummyDouble = 123.456;
+ uint64_t dummyUInt64 = 123;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ assert_true(XML_GetPropertyBool(parser, XML_PROP_INVALID, &dummyBool)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_GetPropertyDouble(parser, XML_PROP_INVALID, &dummyDouble)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_GetPropertyUInt64(parser, XML_PROP_INVALID, &dummyUInt64)
+ == XML_PROP_ERROR_INVALID_KEY);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_getter_error_invalid_type) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL},
+ };
+
+ XML_Bool dummyBool = XML_FALSE;
+ double dummyDouble = 123.456;
+ uint64_t dummyUInt64 = 123;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ set_subtest("property %d", (int)testCase->key);
+
+ const enum XML_Prop_Error expectedBoolError
+ = (testCase->expectedType == TYPE_BOOL) ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE;
+ const enum XML_Prop_Error expectedDoubleError
+ = (testCase->expectedType == TYPE_DOUBLE) ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE;
+ const enum XML_Prop_Error expectedUInt64Error
+ = (testCase->expectedType == TYPE_UINT64) ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE;
+
+ assert_true(XML_GetPropertyBool(parser, testCase->key, &dummyBool)
+ == expectedBoolError);
+ assert_true(XML_GetPropertyDouble(parser, testCase->key, &dummyDouble)
+ == expectedDoubleError);
+ assert_true(XML_GetPropertyUInt64(parser, testCase->key, &dummyUInt64)
+ == expectedUInt64Error);
+ }
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_getter_error_invalid_value) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ enum XML_Parser_Property keys[] = {
+#if XML_GE == 1
+ XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD,
+ XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION,
+ XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD,
+ XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION,
+#endif
+ XML_PROP_REPARSE_DEFERRAL_ENABLED,
+ };
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
+ const enum XML_Parser_Property key = keys[i];
+ set_subtest("property %d", (int)key);
+
+ // NOTE: Currently the value output pointer is checked for being `NULL`
+ // before the key is being checked for being valid.
+ // That precedence among errors is not considered part of the API
+ // contract: either error would be fine to return.
+ assert_true(XML_GetPropertyBool(parser, key, NULL)
+ == XML_PROP_ERROR_INVALID_VALUE);
+ assert_true(XML_GetPropertyDouble(parser, key, NULL)
+ == XML_PROP_ERROR_INVALID_VALUE);
+ assert_true(XML_GetPropertyUInt64(parser, key, NULL)
+ == XML_PROP_ERROR_INVALID_VALUE);
+ }
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_effective) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL},
+ };
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ set_subtest("property %d", (int)testCase->key);
+
+ switch (testCase->expectedType) {
+ case TYPE_BOOL: {
+ // Get original value
+ XML_Bool valueOne = ! g_reparseDeferralEnabledDefault;
+ assert_true(XML_GetPropertyBool(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const XML_Bool valueTwo = ((valueOne == XML_TRUE) ? XML_FALSE : XML_TRUE);
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyBool(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ XML_Bool valueThree = valueOne;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyBool(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true(valueThree == valueTwo);
+ break;
+ }
+ case TYPE_DOUBLE: {
+ // Get original value
+ double valueOne = 1.23;
+ assert_true(XML_GetPropertyDouble(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const double valueTwo = 4.56;
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyDouble(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ double valueThree = 7.89;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyDouble(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)valueThree == (float)valueTwo);
+ break;
+ }
+ case TYPE_UINT64: {
+ // Get original value
+ uint64_t valueOne = 123;
+ assert_true(XML_GetPropertyUInt64(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const uint64_t valueTwo = 456;
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyUInt64(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ uint64_t valueThree = 789;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyUInt64(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true(valueThree == valueTwo);
+ break;
+ }
+ default:
+ fail("unsupported type");
+ }
+ }
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_parser_null) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL},
+ };
+
+ XML_Parser parserNonNull = XML_ParserCreate(NULL);
+ XML_Parser parsers[] = {parserNonNull, NULL};
+ assert_true(parserNonNull != NULL);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ for (size_t j = 0; j < sizeof(parsers) / sizeof(parsers[0]); j++) {
+ XML_Parser parser = parsers[j];
+ set_subtest("property %d, parser %s", (int)testCase->key,
+ (parser == NULL) ? "NULL" : "non-NULL");
+
+ const enum XML_Prop_Error expected
+ = ((parser == NULL) ? XML_PROP_ERROR_PARSER_NULL
+ : XML_PROP_ERROR_NONE);
+
+ enum XML_Prop_Error actual
+ = XML_PROP_ERROR_INVALID_TYPE; // i.e. some value unequal to
+ // `expected`
+ // above
+ assert_true(actual != expected); // self-test
+
+ switch (testCase->expectedType) {
+ case TYPE_BOOL:
+ actual = XML_SetPropertyBool(parser, testCase->key,
+ ! g_reparseDeferralEnabledDefault);
+ break;
+ case TYPE_DOUBLE:
+ actual = XML_SetPropertyDouble(parser, testCase->key, 456.789);
+ break;
+ case TYPE_UINT64:
+ actual = XML_SetPropertyUInt64(parser, testCase->key, 456);
+ break;
+ default:
+ fail("unsupported type");
+ }
+ assert_true(actual == expected);
+ }
+ }
+
+ XML_ParserFree(parserNonNull);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_parser_not_root) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ bool needsRootParser;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64, true},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE, true},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64, true},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE, true},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL, false},
+ };
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ XML_Parser subParser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
+#if defined(XML_DTD)
+ assert_true(subParser != NULL);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ set_subtest("property %d", (int)testCase->key);
+
+ const enum XML_Prop_Error expected
+ = (testCase->needsRootParser ? XML_PROP_ERROR_PARSER_NOT_ROOT
+ : XML_PROP_ERROR_NONE);
+
+ enum XML_Prop_Error actual
+ = XML_PROP_ERROR_INVALID_TYPE; // i.e. some value unequal to `expected`
+ // above
+ assert_true(actual != expected); // self-test
+
+ switch (testCase->expectedType) {
+ case TYPE_BOOL:
+ actual = XML_SetPropertyBool(subParser, testCase->key,
+ ! g_reparseDeferralEnabledDefault);
+ break;
+ case TYPE_DOUBLE:
+ actual = XML_SetPropertyDouble(subParser, testCase->key, 456.789);
+ break;
+ case TYPE_UINT64:
+ actual = XML_SetPropertyUInt64(subParser, testCase->key, 456);
+ break;
+ default:
+ fail("unsupported type");
+ }
+
+ assert_true(actual == expected);
+ }
+
+ XML_ParserFree(subParser);
+#else // ! defined(XML_DTD)
+ assert_true(subParser == NULL);
+ UNUSED_P(cases);
+#endif
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_parser_started) {
+ // The test is not doing any (real) parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL},
+ };
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ // Get the parser into state "parsing started"
+ XML_ParsingStatus parsingStatus;
+ XML_GetParsingStatus(parser, &parsingStatus);
+ assert_true(parsingStatus.parsing == XML_INITIALIZED); // Self-test
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, "", 0, /*isFInal=*/XML_FALSE)
+ == XML_STATUS_OK);
+ XML_GetParsingStatus(parser, &parsingStatus);
+ assert_true(parsingStatus.parsing == XML_PARSING);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ set_subtest("property %d", (int)testCase->key);
+
+ switch (testCase->expectedType) {
+ case TYPE_BOOL: {
+ // Get original value
+ XML_Bool valueOne = ! g_reparseDeferralEnabledDefault;
+ assert_true(XML_GetPropertyBool(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const XML_Bool valueTwo = ((valueOne == XML_TRUE) ? XML_FALSE : XML_TRUE);
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyBool(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ XML_Bool valueThree = valueOne;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyBool(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true(valueThree == valueTwo); // i.e. new value applied
+ break;
+ }
+ case TYPE_DOUBLE: {
+ // Get original value
+ double valueOne = 1.23;
+ assert_true(XML_GetPropertyDouble(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const double valueTwo = 4.56;
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyDouble(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ double valueThree = 7.89;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyDouble(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true((float)valueThree
+ == (float)valueTwo); // i.e. new value applied
+ break;
+ }
+ case TYPE_UINT64: {
+ // Get original value
+ uint64_t valueOne = 123;
+ assert_true(XML_GetPropertyUInt64(parser, testCase->key, &valueOne)
+ == XML_PROP_ERROR_NONE);
+ const uint64_t valueTwo = 456;
+ assert_true(valueTwo != valueOne); // self-test
+
+ // Test: Set with reported success
+ assert_true(XML_SetPropertyUInt64(parser, testCase->key, valueTwo)
+ == XML_PROP_ERROR_NONE);
+ uint64_t valueThree = 789;
+ assert_true(valueThree != valueTwo); // self-test
+
+ // Test: Whether the new value has become effective
+ assert_true(XML_GetPropertyUInt64(parser, testCase->key, &valueThree)
+ == XML_PROP_ERROR_NONE);
+ assert_true(valueThree == valueTwo); // i.e. new value applied
+ break;
+ }
+ default:
+ fail("unsupported type");
+ }
+ }
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_invalid_key) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ assert_true(XML_SetPropertyBool(parser, XML_PROP_INVALID,
+ ! g_reparseDeferralEnabledDefault)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_SetPropertyDouble(parser, XML_PROP_INVALID, 123.456)
+ == XML_PROP_ERROR_INVALID_KEY);
+ assert_true(XML_SetPropertyUInt64(parser, XML_PROP_INVALID, 123)
+ == XML_PROP_ERROR_INVALID_KEY);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_invalid_type) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ struct TestCase {
+ enum XML_Parser_Property key;
+ enum ExpectedType expectedType;
+ };
+
+ struct TestCase cases[] = {
+#if XML_GE == 1
+ {XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+ {XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, TYPE_UINT64},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, TYPE_DOUBLE},
+#endif
+ {XML_PROP_REPARSE_DEFERRAL_ENABLED, TYPE_BOOL},
+ };
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ set_subtest("property %d", (int)testCase->key);
+
+ const enum XML_Prop_Error expectedErrorBool
+ = ((testCase->expectedType == TYPE_BOOL) ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE);
+ const enum XML_Prop_Error expectedErrorDouble
+ = ((testCase->expectedType == TYPE_DOUBLE)
+ ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE);
+ const enum XML_Prop_Error expectedErrorUInt64
+ = ((testCase->expectedType == TYPE_UINT64)
+ ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_TYPE);
+
+ assert_true(XML_SetPropertyBool(parser, testCase->key,
+ ! g_reparseDeferralEnabledDefault)
+ == expectedErrorBool);
+ assert_true(XML_SetPropertyDouble(parser, testCase->key, 456.789)
+ == expectedErrorDouble);
+ assert_true(XML_SetPropertyUInt64(parser, testCase->key, 456)
+ == expectedErrorUInt64);
+ }
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_props_setter_error_invalid_value) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+#if XML_GE == 1
+ struct TestCase {
+ enum XML_Parser_Property key;
+ // NOTE: Neither `uint64_t`- nor `XML_Bool`-based properties have any
+ // invalid in-dimension values, so we are only testing `double`-based
+ // property values here.
+ double value;
+ bool valueValid;
+ };
+
+ struct TestCase cases[] = {
+ // XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, -HUGE_VAL, false},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, -1.0, false},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, -0.9, false},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, 0.0, false},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, 0.9, false},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, 1.0, true},
+ {XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION, HUGE_VAL, true},
+ // XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, -HUGE_VAL, false},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, -1.0, false},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, -0.9, false},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, 0.0, false},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, 0.9, false},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, 1.0, true},
+ {XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, HUGE_VAL, true},
+ };
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ struct TestCase *const testCase = cases + i;
+ const enum XML_Prop_Error expected
+ = (testCase->valueValid ? XML_PROP_ERROR_NONE
+ : XML_PROP_ERROR_INVALID_VALUE);
+ assert_true(XML_SetPropertyDouble(parser, testCase->key, testCase->value)
+ == expected);
+ }
+#endif
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+void
+make_props_test_case(Suite *s) {
+ TCase *const tc_props = tcase_create("properties tests");
+ suite_add_tcase(s, tc_props);
+
+ tcase_add_test(tc_props, test_props_getter_defaults);
+ tcase_add_test(tc_props, test_props_getter_error_parser_null);
+ tcase_add_test(tc_props, test_props_getter_error_invalid_key);
+ tcase_add_test(tc_props, test_props_getter_error_invalid_type);
+ tcase_add_test(tc_props, test_props_getter_error_invalid_value);
+
+ tcase_add_test(tc_props, test_props_setter_effective);
+ tcase_add_test(tc_props, test_props_setter_error_parser_null);
+ tcase_add_test(tc_props, test_props_setter_error_parser_not_root);
+ tcase_add_test(tc_props, test_props_setter_error_parser_started);
+ tcase_add_test(tc_props, test_props_setter_error_invalid_key);
+ tcase_add_test(tc_props, test_props_setter_error_invalid_type);
+ tcase_add_test(tc_props, test_props_setter_error_invalid_value);
+}
diff --git a/contrib/expat/tests/props_tests.h b/contrib/expat/tests/props_tests.h
new file mode 100644
index 000000000000..c429e4c06bf0
--- /dev/null
+++ b/contrib/expat/tests/props_tests.h
@@ -0,0 +1,41 @@
+/* Tests related to the public properties API of Expat
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#ifndef XML_PROPS_TESTS_H
+#define XML_PROPS_TESTS_H
+
+#include "minicheck.h"
+
+extern void make_props_test_case(Suite *s);
+
+#endif /* XML_PROPS_TESTS_H */
diff --git a/contrib/expat/tests/runtests.c b/contrib/expat/tests/runtests.c
index 12f8c36c12e3..4bfff4e976a9 100644
--- a/contrib/expat/tests/runtests.c
+++ b/contrib/expat/tests/runtests.c
@@ -54,13 +54,15 @@
#include "minicheck.h"
#include "common.h"
+#include "acc_tests.h"
+#include "alloc_tests.h"
#include "basic_tests.h"
#include "hash_tests.h"
-#include "ns_tests.h"
#include "misc_tests.h"
-#include "alloc_tests.h"
+#include "ns_tests.h"
#include "nsalloc_tests.h"
-#include "acc_tests.h"
+#include "props_tests.h"
+#include "xcs_tests.h"
XML_Parser g_parser = NULL;
@@ -68,15 +70,17 @@ static Suite *
make_suite(void) {
Suite *s = suite_create("basic");
+#if XML_GE == 1
+ make_accounting_test_case(s);
+#endif
+ make_alloc_test_case(s);
make_basic_test_case(s);
make_hash_test_case(s);
- make_namespace_test_case(s);
make_miscellaneous_test_case(s);
- make_alloc_test_case(s);
+ make_namespace_test_case(s);
make_nsalloc_test_case(s);
-#if XML_GE == 1
- make_accounting_test_case(s);
-#endif
+ make_props_test_case(s);
+ make_xcs_test_case(s);
return s;
}
diff --git a/contrib/expat/tests/structdata.c b/contrib/expat/tests/structdata.c
index b39c6cfb779b..77268a99d95f 100644
--- a/contrib/expat/tests/structdata.c
+++ b/contrib/expat/tests/structdata.c
@@ -7,7 +7,7 @@
|_| XML parser
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
- Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2026 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
Licensed under the MIT license:
@@ -47,23 +47,20 @@
#include "structdata.h"
#include "minicheck.h"
+#include "../lib/xcs.h"
#define STRUCT_EXTENSION_COUNT 8
#ifdef XML_UNICODE_WCHAR_T
# include <wchar.h>
# define XML_FMT_STR "ls"
-# define xcstrlen(s) wcslen(s)
-# define xcstrcmp(s, t) wcscmp((s), (t))
#else
# define XML_FMT_STR "s"
-# define xcstrlen(s) strlen(s)
-# define xcstrcmp(s, t) strcmp((s), (t))
#endif
static XML_Char *
xmlstrdup(const XML_Char *s) {
- size_t byte_count = (xcstrlen(s) + 1) * sizeof(XML_Char);
+ size_t byte_count = (xcslen(s) + 1) * sizeof(XML_Char);
XML_Char *const dup = malloc(byte_count);
assert(dup != NULL);
@@ -128,7 +125,7 @@ StructData_CheckItems(StructData *storage, const StructDataEntry *expected,
assert(got != NULL);
assert(want != NULL);
- if (xcstrcmp(got->str, want->str) != 0) {
+ if (xcscmp(got->str, want->str) != 0) {
StructData_Dispose(storage);
fail("structure got bad string");
} else {
diff --git a/contrib/expat/tests/xcs_tests.c b/contrib/expat/tests/xcs_tests.c
new file mode 100644
index 000000000000..3d756b043dde
--- /dev/null
+++ b/contrib/expat/tests/xcs_tests.c
@@ -0,0 +1,86 @@
+/* Tests related to the XCS (XML character string) functionality
+__ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#include "xcs_tests.h"
+
+#include "ascii.h"
+#include "common.h" // for g_chunkSize
+#include "xcs.h" // for xcslen, xcscmp, xcsncmp
+
+static const XML_Char empty[] = {'\0'};
+static const XML_Char test[] = {ASCII_T, ASCII_E, ASCII_S, ASCII_T, '\0'};
+static const XML_Char testing[]
+ = {ASCII_T, ASCII_E, ASCII_S, ASCII_T, ASCII_I, ASCII_N, ASCII_G, '\0'};
+
+START_TEST(test_xcs_len) {
+ if (g_chunkSize != 0)
+ return;
+
+ assert_true(xcslen(empty) == 0);
+ assert_true(xcslen(test) == 4);
+}
+END_TEST
+
+START_TEST(test_xcs_cmp) {
+ if (g_chunkSize != 0)
+ return;
+
+ assert_true(xcscmp(test, test) == 0);
+ assert_true(xcscmp(test, testing) < 0);
+ assert_true(xcscmp(testing, test) > 0);
+}
+END_TEST
+
+START_TEST(test_xcs_ncmp) {
+ if (g_chunkSize != 0)
+ return;
+
+ assert_true(xcsncmp(test, test, 0) == 0);
+ assert_true(xcsncmp(test, test, 4) == 0);
+
+ assert_true(xcsncmp(test, testing, 4) == 0);
+ assert_true(xcsncmp(testing, test, 4) == 0);
+
+ assert_true(xcsncmp(test, testing, 5) < 0);
+ assert_true(xcsncmp(testing, test, 5) > 0);
+}
+END_TEST
+
+void
+make_xcs_test_case(Suite *s) {
+ TCase *const tc_xcs = tcase_create("xcs tests");
+ suite_add_tcase(s, tc_xcs);
+ tcase_add_test(tc_xcs, test_xcs_len);
+ tcase_add_test(tc_xcs, test_xcs_cmp);
+ tcase_add_test(tc_xcs, test_xcs_ncmp);
+}
diff --git a/contrib/expat/tests/xcs_tests.h b/contrib/expat/tests/xcs_tests.h
new file mode 100644
index 000000000000..52015f14a63e
--- /dev/null
+++ b/contrib/expat/tests/xcs_tests.h
@@ -0,0 +1,41 @@
+/* Tests related to the XCS (XML character string) functionality
+__ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping <sebastian@pipping.org>
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#ifndef XML_XCS_TESTS_H
+#define XML_XCS_TESTS_H
+
+#include "minicheck.h"
+
+extern void make_xcs_test_case(Suite *s);
+
+#endif /* XML_XCS_TESTS_H */
diff --git a/contrib/expat/xmlwf/Makefile.am b/contrib/expat/xmlwf/Makefile.am
index c7eebd1eeec2..52d73a12e896 100644
--- a/contrib/expat/xmlwf/Makefile.am
+++ b/contrib/expat/xmlwf/Makefile.am
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2026 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -32,6 +32,7 @@ bin_PROGRAMS = xmlwf
xmlwf_LDADD = ../lib/libexpat.la
xmlwf_SOURCES = \
+ ../lib/xcs.c \
xmlwf.c \
xmlfile.c \
codepage.c \
diff --git a/contrib/expat/xmlwf/Makefile.in b/contrib/expat/xmlwf/Makefile.in
index 7c4ff12ef536..22968b148a65 100644
--- a/contrib/expat/xmlwf/Makefile.in
+++ b/contrib/expat/xmlwf/Makefile.in
@@ -22,7 +22,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2026 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -148,8 +148,10 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
-am_xmlwf_OBJECTS = xmlwf-xmlwf.$(OBJEXT) xmlwf-xmlfile.$(OBJEXT) \
- xmlwf-codepage.$(OBJEXT) xmlwf-@FILEMAP@.$(OBJEXT)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_xmlwf_OBJECTS = ../lib/xmlwf-xcs.$(OBJEXT) xmlwf-xmlwf.$(OBJEXT) \
+ xmlwf-xmlfile.$(OBJEXT) xmlwf-codepage.$(OBJEXT) \
+ xmlwf-@FILEMAP@.$(OBJEXT)
xmlwf_OBJECTS = $(am_xmlwf_OBJECTS)
xmlwf_DEPENDENCIES = ../lib/libexpat.la
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -174,9 +176,9 @@ am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/xmlwf-@FILEMAP@.Po \
- ./$(DEPDIR)/xmlwf-codepage.Po ./$(DEPDIR)/xmlwf-xmlfile.Po \
- ./$(DEPDIR)/xmlwf-xmlwf.Po
+am__depfiles_remade = ../lib/$(DEPDIR)/xmlwf-xcs.Po \
+ ./$(DEPDIR)/xmlwf-@FILEMAP@.Po ./$(DEPDIR)/xmlwf-codepage.Po \
+ ./$(DEPDIR)/xmlwf-xmlfile.Po ./$(DEPDIR)/xmlwf-xmlwf.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -260,12 +262,10 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
-EXPAT_ATTR_INFO = @EXPAT_ATTR_INFO@
EXPAT_CHAR_TYPE = @EXPAT_CHAR_TYPE@
EXPAT_CONTEXT_BYTES = @EXPAT_CONTEXT_BYTES@
EXPAT_DTD = @EXPAT_DTD@
EXPAT_LARGE_SIZE = @EXPAT_LARGE_SIZE@
-EXPAT_MIN_SIZE = @EXPAT_MIN_SIZE@
EXPAT_NS = @EXPAT_NS@
FGREP = @FGREP@
FILECMD = @FILECMD@
@@ -320,7 +320,6 @@ SO_PATCH = @SO_PATCH@
STRIP = @STRIP@
VERSION = @VERSION@
VSCRIPT_LDFLAGS = @VSCRIPT_LDFLAGS@
-_EXPAT_COMMENT_ATTR_INFO = @_EXPAT_COMMENT_ATTR_INFO@
_EXPAT_COMMENT_DTD_OR_GE = @_EXPAT_COMMENT_DTD_OR_GE@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -381,6 +380,7 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
xmlwf_LDADD = ../lib/libexpat.la
xmlwf_SOURCES = \
+ ../lib/xcs.c \
xmlwf.c \
xmlfile.c \
codepage.c \
@@ -477,6 +477,14 @@ uninstall-binPROGRAMS:
clean-binPROGRAMS:
$(am__rm_f) $(bin_PROGRAMS)
test -z "$(EXEEXT)" || $(am__rm_f) $(bin_PROGRAMS:$(EXEEXT)=)
+../lib/$(am__dirstamp):
+ @$(MKDIR_P) ../lib
+ @: >>../lib/$(am__dirstamp)
+../lib/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ../lib/$(DEPDIR)
+ @: >>../lib/$(DEPDIR)/$(am__dirstamp)
+../lib/xmlwf-xcs.$(OBJEXT): ../lib/$(am__dirstamp) \
+ ../lib/$(DEPDIR)/$(am__dirstamp)
xmlwf$(EXEEXT): $(xmlwf_OBJECTS) $(xmlwf_DEPENDENCIES) $(EXTRA_xmlwf_DEPENDENCIES)
@rm -f xmlwf$(EXEEXT)
@@ -484,10 +492,12 @@ xmlwf$(EXEEXT): $(xmlwf_OBJECTS) $(xmlwf_DEPENDENCIES) $(EXTRA_xmlwf_DEPENDENCIE
mostlyclean-compile:
-rm -f *.$(OBJEXT)
+ -rm -f ../lib/*.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/xmlwf-xcs.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-@FILEMAP@.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-codepage.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-xmlfile.Po@am__quote@ # am--include-marker
@@ -523,6 +533,20 @@ am--depfiles: $(am__depfiles_remade)
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+../lib/xmlwf-xcs.o: ../lib/xcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../lib/xmlwf-xcs.o -MD -MP -MF ../lib/$(DEPDIR)/xmlwf-xcs.Tpo -c -o ../lib/xmlwf-xcs.o `test -f '../lib/xcs.c' || echo '$(srcdir)/'`../lib/xcs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/xmlwf-xcs.Tpo ../lib/$(DEPDIR)/xmlwf-xcs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/xcs.c' object='../lib/xmlwf-xcs.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../lib/xmlwf-xcs.o `test -f '../lib/xcs.c' || echo '$(srcdir)/'`../lib/xcs.c
+
+../lib/xmlwf-xcs.obj: ../lib/xcs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ../lib/xmlwf-xcs.obj -MD -MP -MF ../lib/$(DEPDIR)/xmlwf-xcs.Tpo -c -o ../lib/xmlwf-xcs.obj `if test -f '../lib/xcs.c'; then $(CYGPATH_W) '../lib/xcs.c'; else $(CYGPATH_W) '$(srcdir)/../lib/xcs.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ../lib/$(DEPDIR)/xmlwf-xcs.Tpo ../lib/$(DEPDIR)/xmlwf-xcs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../lib/xcs.c' object='../lib/xmlwf-xcs.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ../lib/xmlwf-xcs.obj `if test -f '../lib/xcs.c'; then $(CYGPATH_W) '../lib/xcs.c'; else $(CYGPATH_W) '$(srcdir)/../lib/xcs.c'; fi`
+
xmlwf-xmlwf.o: xmlwf.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-xmlwf.o -MD -MP -MF $(DEPDIR)/xmlwf-xmlwf.Tpo -c -o xmlwf-xmlwf.o `test -f 'xmlwf.c' || echo '$(srcdir)/'`xmlwf.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-xmlwf.Tpo $(DEPDIR)/xmlwf-xmlwf.Po
@@ -704,6 +728,8 @@ clean-generic:
distclean-generic:
-$(am__rm_f) $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
+ -$(am__rm_f) ../lib/$(DEPDIR)/$(am__dirstamp)
+ -$(am__rm_f) ../lib/$(am__dirstamp)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -713,6 +739,7 @@ clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
+ -rm -f ../lib/$(DEPDIR)/xmlwf-xcs.Po
-rm -f ./$(DEPDIR)/xmlwf-@FILEMAP@.Po
-rm -f ./$(DEPDIR)/xmlwf-codepage.Po
-rm -f ./$(DEPDIR)/xmlwf-xmlfile.Po
@@ -762,6 +789,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
+ -rm -f ../lib/$(DEPDIR)/xmlwf-xcs.Po
-rm -f ./$(DEPDIR)/xmlwf-@FILEMAP@.Po
-rm -f ./$(DEPDIR)/xmlwf-codepage.Po
-rm -f ./$(DEPDIR)/xmlwf-xmlfile.Po
diff --git a/contrib/expat/xmlwf/xmlfile.c b/contrib/expat/xmlwf/xmlfile.c
index 85e5dc582827..f3662dc570c9 100644
--- a/contrib/expat/xmlwf/xmlfile.c
+++ b/contrib/expat/xmlwf/xmlfile.c
@@ -45,6 +45,7 @@
#include "expat_config.h"
+#include <inttypes.h> // PRIu64
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -98,11 +99,9 @@ reportError(XML_Parser parser, const XML_Char *filename) {
enum XML_Error code = XML_GetErrorCode(parser);
const XML_Char *message = XML_ErrorString(code);
if (message)
- ftprintf(stdout,
- T("%s") T(":%") T(XML_FMT_INT_MOD) T("u") T(":%")
- T(XML_FMT_INT_MOD) T("u") T(": %s\n"),
- filename, XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser), message);
+ ftprintf(stdout, T("%s") T(":%") T(PRIu64) T(":%") T(PRIu64) T(": %s\n"),
+ filename, XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser), message);
else
ftprintf(stderr, T("%s: (unknown message %u)\n"), filename,
(unsigned int)code);
diff --git a/contrib/expat/xmlwf/xmlfile.h b/contrib/expat/xmlwf/xmlfile.h
index 7eb4811103c2..0039badb70f8 100644
--- a/contrib/expat/xmlwf/xmlfile.h
+++ b/contrib/expat/xmlwf/xmlfile.h
@@ -37,15 +37,11 @@
#include <stdbool.h>
+#include "expat.h" // for XML_Parser, XML_Char
+
#define XML_MAP_FILE 01
#define XML_EXTERNAL_ENTITIES 02
-#ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-#else
-# define XML_FMT_INT_MOD "l"
-#endif
-
extern int g_read_size_bytes;
extern bool XML_ProcessFile(XML_Parser parser, const XML_Char *filename,
diff --git a/contrib/expat/xmlwf/xmlwf.c b/contrib/expat/xmlwf/xmlwf.c
index 892732cb0729..aec099e41758 100644
--- a/contrib/expat/xmlwf/xmlwf.c
+++ b/contrib/expat/xmlwf/xmlwf.c
@@ -50,6 +50,7 @@
#include "expat_config.h"
#include <assert.h>
+#include <inttypes.h> // for PRIu64
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -72,7 +73,7 @@
# include <wchar.h>
#endif
-#include "../lib/xcsinc.c"
+#include "../lib/xcs.h"
enum ExitCode {
XMLWF_EXIT_SUCCESS = 0,
@@ -360,23 +361,6 @@ cleanupUserData(XmlwfUserData *userData) {
}
static int
-xcscmp(const XML_Char *xs, const XML_Char *xt) {
- while (*xs != 0 && *xt != 0) {
- if (*xs < *xt)
- return -1;
- if (*xs > *xt)
- return 1;
- xs++;
- xt++;
- }
- if (*xs < *xt)
- return -1;
- if (*xs > *xt)
- return 1;
- return 0;
-}
-
-static int
notationCmp(const void *a, const void *b) {
const NotationList *const n1 = *(const NotationList *const *)a;
const NotationList *const n2 = *(const NotationList *const *)b;
@@ -587,12 +571,11 @@ metaLocation(XML_Parser parser) {
puttc(T('"'), fp);
}
ftprintf(fp,
- T(" byte=\"%") T(XML_FMT_INT_MOD) T("d\"") T(" nbytes=\"%d\"")
- T(" line=\"%") T(XML_FMT_INT_MOD) T("u\"") T(" col=\"%")
- T(XML_FMT_INT_MOD) T("u\""),
- XML_GetCurrentByteIndex(parser), XML_GetCurrentByteCount(parser),
- XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser));
+ T(" byte=\"%") T(PRId64) T("\"") T(" nbytes=\"%") T(PRIu64) T("\"")
+ T(" line=\"%") T(PRIu64) T("\"") T(" col=\"%") T(PRIu64) T("\""),
+ XML_GetCurrentByteIndex64(parser), XML_GetCurrentByteCount64(parser),
+ XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser));
}
static void
diff --git a/lib/libexpat/Makefile b/lib/libexpat/Makefile
index 1c5be3659eba..ccc1adaf65c4 100644
--- a/lib/libexpat/Makefile
+++ b/lib/libexpat/Makefile
@@ -4,7 +4,7 @@ EXPAT= ${SRCTOP}/contrib/expat
LIB= bsdxml
SHLIBDIR?= /lib
SHLIB_MAJOR= 4
-SRCS= random_arc4random_buf.c xmlparse.c xmlrole.c xmltok.c
+SRCS= random_arc4random_buf.c xcs.c xmlparse.c xmlrole.c xmltok.c
INCS= bsdxml.h bsdxml_external.h
MAN= libbsdxml.3
diff --git a/lib/libexpat/expat_config.h b/lib/libexpat/expat_config.h
index 1f84d179bcb7..91fb9fd550e5 100644
--- a/lib/libexpat/expat_config.h
+++ b/lib/libexpat/expat_config.h
@@ -89,7 +89,7 @@
#define PACKAGE_NAME "expat"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.8.5"
+#define PACKAGE_STRING "expat 2.9.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "expat"
@@ -98,7 +98,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.8.5"
+#define PACKAGE_VERSION "2.9.0"
/* Define to 1 if all of the C89 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
@@ -106,7 +106,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "2.8.5"
+#define VERSION "2.9.0"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
diff --git a/lib/libexpat/libbsdxml.3 b/lib/libexpat/libbsdxml.3
index ffacc9898bc2..bfdc4457093b 100644
--- a/lib/libexpat/libbsdxml.3
+++ b/lib/libexpat/libbsdxml.3
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"/
-.Dd September 22, 2026
+.Dd October 5, 2026
.Dt LIBBSDXML 3
.Os
.Sh NAME
@@ -34,7 +34,7 @@
.Sh DESCRIPTION
The
.Nm
-library is a verbatim copy of the eXpat XML library version 2.8.5.
+library is a verbatim copy of the eXpat XML library version 2.9.0.
.Pp
The
.Nm