contrib/expat: import expat 2.9.0

Changes: https://github.com/libexpat/libexpat/blob/R_2_9_0/expat/Changes

Security:	CVE-2026-102633
Security:	CVE-2026-77214
MFC after:	3 days
This commit is contained in:
Philip Paeps committed 2026-10-07 09:15:49 +08:00
commit 22c3edb312
52 files changed
+2952 -835

No files matched your search

+102 -26
View File
@@ -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
-3
View File
@@ -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@
+1 -1
View File
@@ -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
+8 -19
View File
@@ -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])
-3
View File
@@ -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@
+681 -73
View File
@@ -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_GetInputContext">XML_GetInputContext</a>
<a href="#XML_GetCurrentByteCount64">XML_GetCurrentByteCount64</a>
</li>
<li>
<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>
@@ -391,10 +445,6 @@
<a href="#XML_GetIdAttributeIndex">XML_GetIdAttributeIndex</a>
</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 />
@@ -1707,6 +1787,17 @@ XML_ParseBuffer(XML_Parser p,
application can avoid double copying of the input.
</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>
@@ -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,13 +3138,53 @@ 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
@@ -2984,7 +3194,7 @@ XML_GetCurrentByteCount(XML_Parser p);
</div>
<h4 id="XML_GetInputContext">
XML_GetInputContext
XML_GetInputContext (deprecated)
</h4>
<pre class="fcndec">
@@ -2992,6 +3202,53 @@ const char * XMLCALL
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>
@@ -3019,11 +3276,390 @@ XML_GetInputContext(XML_Parser p,
</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,
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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>[email protected]</email>">
-3
View File
@@ -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@
+4 -10
View File
@@ -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;
}
+4 -10
View File
@@ -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;
+4 -10
View File
@@ -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;
-4
View File
@@ -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
+1 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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);
}
+2 -1
View File
@@ -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 \
+27 -16
View File
@@ -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
+72 -27
View File
@@ -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
}
+3
View File
@@ -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
+5 -7
View File
@@ -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
+16 -1
View File
@@ -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;
+90
View File
@@ -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
}
@@ -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)
+413 -154
View File
@@ -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,25 +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 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
// 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.
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.
return (XML_Size)(parser->m_position.lineNumber + 1);
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;
}
XML_Size XMLCALL
XML_GetCurrentColumnNumber(XML_Parser parser) {
uint64_t XMLCALL
XML_GetCurrentLineNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
@@ -2776,12 +2813,41 @@ XML_GetCurrentColumnNumber(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.columnNumber;
return (XML_Size)XML_GetCurrentLineNumber64(parser);
}
uint64_t XMLCALL
XML_GetCurrentColumnNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
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)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;
}
return XML_FALSE;
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_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.
+56 -220
View File
@@ -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
#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
#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
#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
#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
+1 -1
View File
@@ -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)!
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
+5 -1
View File
@@ -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
+16 -7
View File
@@ -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
+37
View File
@@ -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);
+59
View File
@@ -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);
+131 -39
View File
@@ -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
@@ -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@
+7 -12
View File
@@ -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;
+2 -2
View File
@@ -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) {
+6 -5
View File
@@ -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);
}
-6
View File
@@ -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 */
+59 -56
View File
@@ -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;
+92 -22
View File
@@ -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);
}
+790
View File
@@ -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);
}
+41
View File
@@ -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 */
+13 -9
View File
@@ -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");
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_nsalloc_test_case(s);
#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_miscellaneous_test_case(s);
make_namespace_test_case(s);
make_nsalloc_test_case(s);
make_props_test_case(s);
make_xcs_test_case(s);
return s;
}
+4 -7
View File
@@ -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 {
+86
View File
@@ -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);
}
+41
View File
@@ -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 */
+2 -1
View File
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
# Copyright (c) 2017-2021 Sebastian Pipping <[email protected]>
# Copyright (c) 2017-2026 Sebastian Pipping <[email protected]>
# 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 \
+37 -9
View File
@@ -22,7 +22,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
# Copyright (c) 2017-2021 Sebastian Pipping <[email protected]>
# Copyright (c) 2017-2026 Sebastian Pipping <[email protected]>
# 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-@[email protected]
-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-@[email protected]
-rm -f ./$(DEPDIR)/xmlwf-codepage.Po
-rm -f ./$(DEPDIR)/xmlwf-xmlfile.Po
+4 -5
View File
@@ -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);
+2 -6
View File
@@ -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,
+7 -24
View File
@@ -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,
@@ -359,23 +360,6 @@ cleanupUserData(XmlwfUserData *userData) {
freeNotations(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;
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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). */
+2 -2
View File
@@ -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