Return the line number of the position. The first line is reported as
.
@@ -2944,14 +3099,33 @@
"#XML_LARGE_SIZE">XML_LARGE_SIZE.
+
+ Return the line number of the position. The first line is reported as
+ 1.
+
@@ -3491,6 +4099,11 @@
XML_SetHashSalt(XML_Parser parser,
unsigned long hash_salt);
+
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
@@ -3498,15 +4111,13 @@
called after
XML_Parse or
XML_ParseBuffer or when
parser is
NULL.
- Note: Function XML_SetHashSalt is
- deprecated. Please use function XML_SetHashSalt16Bytes instead for better
- security. XML_SetHashSalt only provides 4 to 8 bytes of entropy
- (depending on the size of type unsigned long) while the SipHash
- implementation used by Expat can leverage up to 16 bytes of entropy — at least
- twice as much. Function Note: Function XML_SetHashSalt only provides 4 to 8 bytes
+ of entropy (depending on the size of type unsigned long) while the
+ SipHash implementation used by Expat can leverage up to 16 bytes of entropy —
+ at least twice as much. Function XML_SetHashSalt16Bytes of Expat >=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.
@@ -3706,11 +4317,24 @@
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,
+ /* Added in Expat 2.0.0. */
XML_FEATURE_NS,
- XML_FEATURE_LARGE_SIZE
+ /* Added in Expat 2.0.1. */
+ XML_FEATURE_LARGE_SIZE,
+ /* 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,
+ XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
+ /* Added in Expat 2.6.0. */
+ XML_FEATURE_GE,
+ /* Added in Expat 2.7.2. */
+ XML_FEATURE_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT,
+ XML_FEATURE_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT,
};
typedef struct {
diff -Nru expat-2.8.3/expat/doc/xmlwf.xml expat-2.9.0/expat/doc/xmlwf.xml
--- expat-2.8.3/expat/doc/xmlwf.xml 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/doc/xmlwf.xml 2026-10-05 15:43:59.000000000 +0000
@@ -21,7 +21,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
Scott">
Bronson">
- August 10, 2026">
+ October 5, 2026">
1">
bronson@rinspin.com">
diff -Nru expat-2.8.3/expat/examples/element_declarations.c expat-2.9.0/expat/examples/element_declarations.c
--- expat-2.8.3/expat/examples/element_declarations.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/examples/element_declarations.c 2026-10-05 15:43:59.000000000 +0000
@@ -12,7 +12,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr.
Copyright (c) 2004-2006 Karl Waclawek
Copyright (c) 2005-2007 Steven Solie
- Copyright (c) 2016-2024 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2019 Zhongyuan Zhou
Copyright (c) 2024 Hanno Böck
@@ -41,17 +41,12 @@
SPDX-License-Identifier: MIT
*/
+#include // PRIu64
#include
#include
#include
#include
-#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 @@
if (errorCode == XML_ERROR_ABORTED) {
errorCode = XML_ERROR_NO_MEMORY;
}
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser), XML_ErrorString(errorCode));
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser), XML_ErrorString(errorCode));
XML_ParserFree(parser);
return 1;
}
diff -Nru expat-2.8.3/expat/examples/elements.c expat-2.9.0/expat/examples/elements.c
--- expat-2.8.3/expat/examples/elements.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/examples/elements.c 2026-10-05 15:43:59.000000000 +0000
@@ -14,7 +14,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr.
Copyright (c) 2004-2006 Karl Waclawek
Copyright (c) 2005-2007 Steven Solie
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2019 Zhongyuan Zhou
Licensed under the MIT license:
@@ -41,15 +41,10 @@
SPDX-License-Identifier: MIT
*/
+#include // PRIu64
#include
#include
-#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 @@
done = feof(stdin);
if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser),
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 1;
diff -Nru expat-2.8.3/expat/examples/outline.c expat-2.9.0/expat/examples/outline.c
--- expat-2.8.3/expat/examples/outline.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/examples/outline.c 2026-10-05 15:43:59.000000000 +0000
@@ -12,7 +12,7 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr.
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2006 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Licensed under the MIT license:
@@ -38,15 +38,10 @@
SPDX-License-Identifier: MIT
*/
+#include // PRIu64
#include
#include
-#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 @@
done = feof(stdin);
if (XML_ParseBuffer(parser, (int)len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
- XML_GetCurrentLineNumber(parser),
+ fprintf(stderr, "Parse error at line %" PRIu64 ":\n%" XML_FMT_STR "\n",
+ XML_GetCurrentLineNumber64(parser),
XML_ErrorString(XML_GetErrorCode(parser)));
XML_ParserFree(parser);
return 1;
diff -Nru expat-2.8.3/expat/expat_config.h.cmake expat-2.9.0/expat/expat_config.h.cmake
--- expat-2.8.3/expat/expat_config.h.cmake 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/expat_config.h.cmake 2026-10-05 15:43:59.000000000 +0000
@@ -89,10 +89,6 @@
/* whether byteorder is bigendian */
#cmakedefine WORDS_BIGENDIAN
-/* Define to allow retrieving the byte offsets for attribute names and values.
- */
-#cmakedefine XML_ATTR_INFO
-
/* Define to specify how much context to retain around the current parse
point, 0 to disable. */
# define XML_CONTEXT_BYTES @XML_CONTEXT_BYTES@
diff -Nru expat-2.8.3/expat/fix-xmltest-log.sh expat-2.9.0/expat/fix-xmltest-log.sh
--- expat-2.8.3/expat/fix-xmltest-log.sh 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/fix-xmltest-log.sh 2026-10-05 15:43:59.000000000 +0000
@@ -38,6 +38,9 @@
-e '# convert DOS line endings to Unix without resorting to dos2unix' \
-e $'s/\r//' \
\
+ -e '# Filter out "unhandled instruction" lines from AddressSanitizer' \
+ -e '/^==[0-9]\+==interception_win: unhandled instruction at /d' \
+ \
-e 's/^wine: Call .* msvcrt\.dll\._wperror, aborting$/ibm49i02.dtd: No such file or directory/' \
\
-e '/^wine: /d' \
diff -Nru expat-2.8.3/expat/fuzz/xml_lpm_fuzzer.cpp expat-2.9.0/expat/fuzz/xml_lpm_fuzzer.cpp
--- expat-2.8.3/expat/fuzz/xml_lpm_fuzzer.cpp 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/fuzz/xml_lpm_fuzzer.cpp 2026-10-05 15:43:59.000000000 +0000
@@ -8,6 +8,7 @@
Copyright (c) 2022 Mark Brand
Copyright (c) 2025 Sebastian Pipping
+ Copyright (c) 2026 Braian Plaku
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -383,7 +384,9 @@
void
InitializeParser(XML_Parser parser) {
XML_SetUserData(parser, (void *)parser);
- XML_SetHashSalt(parser, 0x41414141);
+ const uint8_t entropy[16] = {0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41};
+ XML_SetHashSalt16Bytes(parser, entropy);
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
XML_SetElementDeclHandler(parser, ElementDeclHandler);
diff -Nru expat-2.8.3/expat/fuzz/xml_parse_fuzzer.c expat-2.9.0/expat/fuzz/xml_parse_fuzzer.c
--- expat-2.8.3/expat/fuzz/xml_parse_fuzzer.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/fuzz/xml_parse_fuzzer.c 2026-10-05 15:43:59.000000000 +0000
@@ -17,6 +17,7 @@
#include
#include // for INT_MAX
#include
+#include
#include "expat.h"
#include "siphash.h"
@@ -34,7 +35,8 @@
#endif
// 16-byte deterministic hash key.
-static unsigned char hash_key[16] = "FUZZING IS FUN!";
+static unsigned char hash_key_1[16] = "FUZZING IS FUN?";
+static unsigned char hash_key_2[16] = "FUZZING IS FUN!";
static void XMLCALL
start(void *userData, const XML_Char *name, const XML_Char **atts) {
@@ -59,8 +61,14 @@
static void
ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
// Set the hash salt using siphash to generate a deterministic hash.
- struct sipkey *key = sip_keyof(hash_key);
- XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
+ // The salt is 16 bytes and siphash24 produces 8, so the input is hashed
+ // under two keys.
+ const uint64_t first = siphash24(data, size, sip_keyof(hash_key_1));
+ const uint64_t second = siphash24(data, size, sip_keyof(hash_key_2));
+ uint8_t entropy[16];
+ memcpy(entropy, &first, sizeof(first));
+ memcpy(entropy + sizeof(first), &second, sizeof(second));
+ XML_SetHashSalt16Bytes(p, entropy);
(void)sip24_valid;
XML_SetUserData(p, p);
@@ -71,7 +79,7 @@
if (XML_Parse(p, (const XML_Char *)data, (int)size, 1) == XML_STATUS_ERROR) {
XML_ErrorString(XML_GetErrorCode(p));
}
- XML_GetCurrentLineNumber(p);
+ XML_GetCurrentLineNumber64(p);
if (size % 2) {
XML_ParserReset(p, NULL);
}
diff -Nru expat-2.8.3/expat/fuzz/xml_parsebuffer_fuzzer.c expat-2.9.0/expat/fuzz/xml_parsebuffer_fuzzer.c
--- expat-2.8.3/expat/fuzz/xml_parsebuffer_fuzzer.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/fuzz/xml_parsebuffer_fuzzer.c 2026-10-05 15:43:59.000000000 +0000
@@ -35,7 +35,8 @@
#endif
// 16-byte deterministic hash key.
-static unsigned char hash_key[16] = "FUZZING IS FUN!";
+static unsigned char hash_key_1[16] = "FUZZING IS FUN?";
+static unsigned char hash_key_2[16] = "FUZZING IS FUN!";
static void XMLCALL
start(void *userData, const XML_Char *name, const XML_Char **atts) {
@@ -60,8 +61,14 @@
static void
ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) {
// Set the hash salt using siphash to generate a deterministic hash.
- struct sipkey *key = sip_keyof(hash_key);
- XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key));
+ // The salt is 16 bytes and siphash24 produces 8, so the input is hashed
+ // under two keys.
+ const uint64_t first = siphash24(data, size, sip_keyof(hash_key_1));
+ const uint64_t second = siphash24(data, size, sip_keyof(hash_key_2));
+ uint8_t entropy[16];
+ memcpy(entropy, &first, sizeof(first));
+ memcpy(entropy + sizeof(first), &second, sizeof(second));
+ XML_SetHashSalt16Bytes(p, entropy);
(void)sip24_valid;
XML_SetUserData(p, p);
@@ -80,7 +87,7 @@
if (XML_ParseBuffer(p, (int)size, 1) == XML_STATUS_ERROR) {
XML_ErrorString(XML_GetErrorCode(p));
}
- XML_GetCurrentLineNumber(p);
+ XML_GetCurrentLineNumber64(p);
if (size % 2) {
XML_ParserReset(p, NULL);
}
diff -Nru expat-2.8.3/expat/lib/.gitignore expat-2.9.0/expat/lib/.gitignore
--- expat-2.8.3/expat/lib/.gitignore 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/.gitignore 2026-10-05 15:43:59.000000000 +0000
@@ -1,3 +1,4 @@
+/libexpat.map
Makefile
.libs
*.lo
diff -Nru expat-2.8.3/expat/lib/Makefile.am expat-2.9.0/expat/lib/Makefile.am
--- expat-2.8.3/expat/lib/Makefile.am 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/Makefile.am 2026-10-05 15:43:59.000000000 +0000
@@ -53,6 +53,7 @@
endif
libexpat_la_SOURCES = \
+ xcs.c \
xmlparse.c \
xmltok.c \
xmlrole.c
@@ -115,6 +116,7 @@
expat_external.h \
expat.h \
fallthrough.h \
+ hash_table.h \
iasciitab.h \
internal.h \
latin1tab.h \
@@ -124,7 +126,7 @@
siphash.h \
utf8tab.h \
winconfig.h \
- xcsinc.c \
+ xcs.h \
xmlrole.h \
xmltok.h \
xmltok_impl.c \
diff -Nru expat-2.8.3/expat/lib/expat.h expat-2.9.0/expat/lib/expat.h
--- expat-2.8.3/expat/lib/expat.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/expat.h 2026-10-05 15:43:59.000000000 +0000
@@ -20,6 +20,7 @@
Copyright (c) 2023 Sony Corporation / Snild Dolkow
Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp>
Copyright (c) 2025 Matthew Fernandez
+ Copyright (c) 2026 Braian Plaku
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -47,7 +48,7 @@
#ifndef Expat_INCLUDED
# define Expat_INCLUDED 1
-# include // for uint8_t
+# include // for int64_t, uint8_t, uint64_t
# include
# include "expat_external.h"
@@ -139,6 +140,26 @@
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,
@@ -756,29 +777,6 @@
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).
@@ -921,7 +919,9 @@
Returns 1 if successful, 0 when called after parsing has started.
Note: If parser == NULL, the function will do nothing and return 0.
DEPRECATED since Expat 2.8.0.
+ Please use XML_SetHashSalt16Bytes instead.
*/
+XML_ATTR_DEPRECATED("please use XML_SetHashSalt16Bytes instead")
XMLPARSEAPI(int)
XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt);
@@ -961,15 +961,24 @@
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
@@ -981,8 +990,11 @@
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
@@ -1037,11 +1049,15 @@
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,
+ /* Added in Expat 2.0.0. */
XML_FEATURE_NS,
+ /* Added in Expat 2.0.1. */
XML_FEATURE_LARGE_SIZE,
+ /* 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,
@@ -1063,6 +1079,41 @@
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. */
@@ -1095,8 +1146,8 @@
See https://semver.org
*/
# define XML_MAJOR_VERSION 2
-# define XML_MINOR_VERSION 8
-# define XML_MICRO_VERSION 3
+# define XML_MINOR_VERSION 9
+# define XML_MICRO_VERSION 0
# ifdef __cplusplus
}
diff -Nru expat-2.8.3/expat/lib/expat_external.h expat-2.9.0/expat/lib/expat_external.h
--- expat-2.8.3/expat/lib/expat_external.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/expat_external.h 2026-10-05 15:43:59.000000000 +0000
@@ -16,6 +16,7 @@
Copyright (c) 2017 Rhodri James
Copyright (c) 2018 Yury Gribov
Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Braian Plaku
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -125,6 +126,17 @@
# define XML_ATTR_ALLOC_SIZE(x)
# endif
+/* Marks a function that Expat still provides but that callers should move off
+ of. */
+# if defined(__clang__) || defined(__GNUC__)
+# define XML_ATTR_DEPRECATED(message) \
+ __attribute__((__deprecated__(message)))
+# elif defined(_MSC_VER)
+# define XML_ATTR_DEPRECATED(message) __declspec(deprecated(message))
+# else
+# define XML_ATTR_DEPRECATED(message) // empty i.e. no deprecation
+# endif
+
# define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
# ifdef __cplusplus
@@ -154,6 +166,9 @@
# endif /* XML_UNICODE */
# ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+# if defined(__clang__) || defined(__GNUC__)
+# warning Macro XML_LARGE_SIZE is deprecated, please use the 64bit location API functions instead.
+# endif
typedef long long XML_Index;
typedef unsigned long long XML_Size;
# else
diff -Nru expat-2.8.3/expat/lib/hash_table.h expat-2.9.0/expat/lib/hash_table.h
--- expat-2.8.3/expat/lib/hash_table.h 1970-01-01 00:00:00.000000000 +0000
+++ expat-2.9.0/expat/lib/hash_table.h 2026-10-05 15:43:59.000000000 +0000
@@ -0,0 +1,78 @@
+/* Hash table related internal API
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping
+ 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
+*/
+
+#if ! defined(HASH_TABLE_H)
+# define HASH_TABLE_H 1
+
+# include "expat.h" // for XML_Bool, XML_Parser
+# include "internal.h" // for XML_NONTESTING_STATIC
+
+# include // for size_t
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+ KEY name;
+} NAMED;
+
+typedef struct {
+ NAMED **v;
+ unsigned char power;
+ size_t size;
+ size_t used;
+ XML_Parser parser;
+} HASH_TABLE;
+
+typedef struct {
+ NAMED **p;
+ NAMED **end;
+} HASH_TABLE_ITER;
+
+XML_NONTESTING_STATIC NAMED *lookupWithLength(XML_Parser parser,
+ HASH_TABLE *table, KEY name,
+ size_t nameLen,
+ size_t createSize);
+XML_NONTESTING_STATIC NAMED *lookup(XML_Parser parser, HASH_TABLE *table,
+ KEY name, size_t createSize);
+
+XML_NONTESTING_STATIC void hashTableInit(HASH_TABLE *table, XML_Parser parser);
+XML_NONTESTING_STATIC void hashTableClear(HASH_TABLE *table);
+XML_NONTESTING_STATIC void hashTableDestroy(HASH_TABLE *table);
+XML_NONTESTING_STATIC void hashTableIterInit(HASH_TABLE_ITER *iter,
+ const HASH_TABLE *table);
+XML_NONTESTING_STATIC NAMED *hashTableIterNext(HASH_TABLE_ITER *iter);
+
+XML_NONTESTING_STATIC XML_Bool keyeq(KEY s1, size_t s1len, KEY s2);
+XML_NONTESTING_STATIC size_t keylen(KEY s);
+
+#endif // ! defined(HASH_TABLE_H)
diff -Nru expat-2.8.3/expat/lib/internal.h expat-2.9.0/expat/lib/internal.h
--- expat-2.8.3/expat/lib/internal.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/internal.h 2026-10-05 15:43:59.000000000 +0000
@@ -6,13 +6,6 @@
The following calling convention macros are defined for frequently
called functions:
- FASTCALL - Used for those internal functions that have a simple
- body and a low number of arguments and local variables.
-
- PTRCALL - Used for functions called though function pointers.
-
- PTRFASTCALL - Like PTRCALL, but for low number of arguments.
-
inline - Used for selected internal functions for which inlining
may improve performance on some platforms.
@@ -33,6 +26,9 @@
Copyright (c) 2019 David Loffredo
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp>
+ Copyright (c) 2026 Matthew Wozniczka
+ Copyright (c) 2026 Braian Plaku
+ Copyright (c) 2026 Florian Schmaus
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -57,132 +53,102 @@
SPDX-License-Identifier: MIT
*/
-#if defined(__GNUC__) && defined(__i386__) && ! defined(__MINGW32__)
-/* We'll use this version by default only where we know it helps.
-
- regparm() generates warnings on Solaris boxes. See SF bug #692878.
-
- Instability reported with egcs on a RedHat Linux 7.3.
- Let's comment out:
- #define FASTCALL __attribute__((stdcall, regparm(3)))
- and let's try this:
-*/
-# define FASTCALL __attribute__((regparm(3)))
-# define PTRFASTCALL __attribute__((regparm(3)))
-#endif
-
-/* Using __fastcall seems to have an unexpected negative effect under
- MS VC++, especially for function pointers, so we won't use it for
- now on that platform. It may be reconsidered for a future release
- if it can be made more effective.
- Likely reason: __fastcall on Windows is like stdcall, therefore
- the compiler cannot perform stack optimizations for call clusters.
-*/
-
-/* Make sure all of these are defined if they aren't already. */
+#if ! defined(INTERNAL_H)
+# define INTERNAL_H 1
-#ifndef FASTCALL
-# define FASTCALL
-#endif
-
-#ifndef PTRCALL
-# define PTRCALL
-#endif
-
-#ifndef PTRFASTCALL
-# define PTRFASTCALL
-#endif
-
-#ifndef XML_MIN_SIZE
-# if ! defined(__cplusplus) && ! defined(inline)
+# if ! defined(inline)
# ifdef __GNUC__
# define inline __inline
# endif /* __GNUC__ */
# endif
-#endif /* XML_MIN_SIZE */
-#ifdef __cplusplus
-# define inline inline
-#else
# ifndef inline
# define inline
# endif
-#endif
-#include // ULONG_MAX
-#include // size_t
+# if ! defined(XML_NONTESTING_STATIC)
+# if defined(XML_TESTING)
+# define XML_NONTESTING_STATIC // empty i.e. not static
+# else
+# define XML_NONTESTING_STATIC static
+# endif
+# endif
-#if defined(_WIN32) \
- && (! defined(__USE_MINGW_ANSI_STDIO) \
- || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0))
-# define EXPAT_FMT_LLX(midpart) "%" midpart "I64x"
-# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
-# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u"
+# include // ULONG_MAX
+# include // size_t
+
+# if defined(_WIN32) \
+ && (! defined(__USE_MINGW_ANSI_STDIO) \
+ || (1 - __USE_MINGW_ANSI_STDIO - 1 == 0))
+# define EXPAT_FMT_LLX(midpart) "%" midpart "I64x"
+# define EXPAT_FMT_ULL(midpart) "%" midpart "I64u"
+# if defined(_WIN64) // Note: modifiers "td" and "zu" do not work for MinGW
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "I64d"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "I64u"
+# else
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+# endif
# else
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+# include // PRIdPTR, PRIuPTR
+# define EXPAT_FMT_LLX(midpart) "%" midpart "llx"
+# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart PRIdPTR
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart PRIuPTR
+# endif
+
+# ifndef UNUSED_P
+# define UNUSED_P(p) (void)p
# endif
-#else
-# include // PRIdPTR, PRIuPTR
-# define EXPAT_FMT_LLX(midpart) "%" midpart "llx"
-# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart PRIdPTR
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart PRIuPTR
-#endif
-
-#ifndef UNUSED_P
-# define UNUSED_P(p) (void)p
-#endif
/* NOTE BEGIN If you ever patch these defaults to greater values
for non-attack XML payload in your environment,
please file a bug report with libexpat. Thank you!
*/
-#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT \
- 100.0f
-#define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
- 8388608 // 8 MiB, 2^23
-
-#define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f
-#define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \
- 67108864 // 64 MiB, 2^26
+# define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT \
+ 100.0f
+# define EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT \
+ 8388608 // 8 MiB, 2^23
+
+# define EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT 100.0f
+# define EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT \
+ 67108864 // 64 MiB, 2^26
// NOTE: If function expat_alloc was user facing, EXPAT_MALLOC_ALIGNMENT would
// have to take sizeof(long double) into account
-#define EXPAT_MALLOC_ALIGNMENT sizeof(long long) // largest parser (sub)member
-#define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t))
+union expat_align {
+ long long l;
+ void *p;
+};
+# define EXPAT_MALLOC_ALIGNMENT sizeof(union expat_align)
+# define EXPAT_MALLOC_PADDING ((EXPAT_MALLOC_ALIGNMENT) - sizeof(size_t))
/* NOTE END */
-#include "expat.h" // so we can use type XML_Parser below
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+# include "expat.h" // so we can use type XML_Parser below
void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
const char **fromLimRef);
-#if defined(XML_GE) && XML_GE == 1
+# if defined(XML_GE) && XML_GE == 1
unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
const char *unsignedCharToPrintable(unsigned char c);
-#endif
+# endif
extern
-#if ! defined(XML_TESTING)
+# if ! defined(XML_TESTING)
const
-#endif
+# endif
XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
-#if defined(XML_TESTING)
+# if defined(XML_TESTING)
+
+int xmlSetHashSalt(XML_Parser parser, unsigned long hash_salt);
+
void *expat_malloc(XML_Parser parser, size_t size, int sourceLine);
void expat_free(XML_Parser parser, void *ptr, int sourceLine);
void *expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine);
extern unsigned int g_bytesScanned; // used for testing only
-#endif
+# endif
-#ifdef __cplusplus
-}
-#endif
+#endif // not defined INTERNAL_H
diff -Nru expat-2.8.3/expat/lib/libexpat.def.cmake expat-2.9.0/expat/lib/libexpat.def.cmake
--- expat-2.8.3/expat/lib/libexpat.def.cmake 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/libexpat.def.cmake 2026-10-05 15:43:59.000000000 +0000
@@ -72,7 +72,7 @@
XML_ResumeParser @64
XML_GetParsingStatus @65
; added with version 2.1.0
-@_EXPAT_COMMENT_ATTR_INFO@ XML_GetAttributeInfo @66
+; XML_GetAttributeInfo @66
XML_SetHashSalt @67
; internal @68 removed with version 2.3.1
; added with version 2.4.0
@@ -85,3 +85,15 @@
@_EXPAT_COMMENT_DTD_OR_GE@ XML_SetAllocTrackerActivationThreshold @73
; added with version 2.8.0
XML_SetHashSalt16Bytes @74
+; added with version 2.9.0
+ XML_GetCurrentByteCount64 @75
+ XML_GetCurrentByteIndex64 @76
+ XML_GetCurrentColumnNumber64 @77
+ XML_GetCurrentLineNumber64 @78
+ XML_GetInputContext64 @79
+ XML_GetPropertyBool @80
+ XML_GetPropertyDouble @81
+ XML_GetPropertyUInt64 @82
+ XML_SetPropertyBool @83
+ XML_SetPropertyDouble @84
+ XML_SetPropertyUInt64 @85
diff -Nru expat-2.8.3/expat/lib/libexpat.map.in expat-2.9.0/expat/lib/libexpat.map.in
--- expat-2.8.3/expat/lib/libexpat.map.in 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/libexpat.map.in 2026-10-05 15:43:59.000000000 +0000
@@ -97,7 +97,7 @@
LIBEXPAT_2.1.0 {
global:
-@_EXPAT_COMMENT_ATTR_INFO@ XML_GetAttributeInfo;
+# XML_GetAttributeInfo;
XML_SetHashSalt;
} LIBEXPAT_1.95.8;
@@ -122,3 +122,18 @@
global:
XML_SetHashSalt16Bytes;
} LIBEXPAT_2.7.2;
+
+LIBEXPAT_2.9.0 {
+ global:
+ XML_GetCurrentByteCount64;
+ XML_GetCurrentByteIndex64;
+ XML_GetCurrentColumnNumber64;
+ XML_GetCurrentLineNumber64;
+ XML_GetInputContext64;
+ XML_GetPropertyBool;
+ XML_GetPropertyDouble;
+ XML_GetPropertyUInt64;
+ XML_SetPropertyBool;
+ XML_SetPropertyDouble;
+ XML_SetPropertyUInt64;
+} LIBEXPAT_2.8.0;
diff -Nru expat-2.8.3/expat/lib/random_getentropy.c expat-2.9.0/expat/lib/random_getentropy.c
--- expat-2.8.3/expat/lib/random_getentropy.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/random_getentropy.c 2026-10-05 15:43:59.000000000 +0000
@@ -54,7 +54,7 @@
bool
writeRandomBytes_getentropy(void *target, size_t count) {
errno = 0;
- const bool success = getentropy(target, count);
+ const bool success = (getentropy(target, count) == 0);
// MSan does not understand `getentropy`, so explain its effects
if (success)
MSAN_UNPOISON(target, count);
diff -Nru expat-2.8.3/expat/lib/xcs.c expat-2.9.0/expat/lib/xcs.c
--- expat-2.8.3/expat/lib/xcs.c 1970-01-01 00:00:00.000000000 +0000
+++ expat-2.9.0/expat/lib/xcs.c 2026-10-05 15:43:59.000000000 +0000
@@ -0,0 +1,90 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2022-2026 Sebastian Pipping
+ 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 // for wcscmp, wcslen, wcsncmp
+# endif
+#else
+# include // for strcmp, strlen, strncmp
+#endif
+
+size_t
+xcslen(const XML_Char *s) {
+#ifdef XML_UNICODE
+# ifdef XML_UNICODE_WCHAR_T
+ return wcslen(s);
+# else
+ // XML_Char is unsigned short
+ size_t len = 0;
+ while (s[len]) {
+ len++;
+ }
+ return len;
+# endif
+#else
+ return strlen(s);
+#endif
+}
+
+int
+xcscmp(const XML_Char *a, const XML_Char *b) {
+#if defined(XML_UNICODE)
+# if defined(XML_UNICODE_WCHAR_T)
+ return wcscmp(a, b);
+# else
+ for (; a[0] && b[0] && a[0] == b[0]; a++, b++)
+ ;
+ return a[0] - b[0];
+# endif
+#else
+ return strcmp(a, b);
+#endif
+}
+
+int
+xcsncmp(const XML_Char *a, const XML_Char *b, size_t len) {
+#if defined(XML_UNICODE)
+# if defined(XML_UNICODE_WCHAR_T)
+ return wcsncmp(a, b, len);
+# else
+ for (; len > 0 && a[0] && b[0] && a[0] == b[0]; len--, a++, b++) {
+ }
+ return (len == 0) ? 0 : (a[0] - b[0]);
+# endif
+#else
+ return strncmp(a, b, len);
+#endif
+}
diff -Nru expat-2.8.3/expat/lib/xcs.h expat-2.9.0/expat/lib/xcs.h
--- expat-2.8.3/expat/lib/xcs.h 1970-01-01 00:00:00.000000000 +0000
+++ expat-2.9.0/expat/lib/xcs.h 2026-10-05 15:43:59.000000000 +0000
@@ -0,0 +1,44 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping
+ 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
+*/
+
+#if ! defined(EXPAT_XCS_H)
+
+# include // size_t
+# include "expat_external.h" // for XML_Char
+
+extern size_t xcslen(const XML_Char *s);
+
+extern int xcscmp(const XML_Char *a, const XML_Char *b);
+extern int xcsncmp(const XML_Char *a, const XML_Char *b, size_t len);
+
+#endif // ! defined(EXPAT_XCS_H)
diff -Nru expat-2.8.3/expat/lib/xcsinc.c expat-2.9.0/expat/lib/xcsinc.c
--- expat-2.8.3/expat/lib/xcsinc.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xcsinc.c 1970-01-01 00:00:00.000000000 +0000
@@ -1,54 +0,0 @@
-/* This file is included from other .c files!
- __ __ _
- ___\ \/ /_ __ __ _| |_
- / _ \\ /| '_ \ / _` | __|
- | __// \| |_) | (_| | |_
- \___/_/\_\ .__/ \__,_|\__|
- |_| XML parser
-
- Copyright (c) 2022-2026 Sebastian Pipping
- 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
-*/
-
-#if defined(XML_UNICODE) && defined(XML_UNICODE_WCHAR_T)
-# include
-#endif
-
-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
-}
diff -Nru expat-2.8.3/expat/lib/xmlparse.c expat-2.9.0/expat/lib/xmlparse.c
--- expat-2.8.3/expat/lib/xmlparse.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmlparse.c 2026-10-05 15:43:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* ee5f82c3ffd57c5224394ba46f348dbce466d34d6c925a527ae46b1cfe6adf1d (2.8.3+)
+/* e3ca845466942140c9af531ac57808c4650116df5d6dbeda3b6546d2548a586e (2.9.0+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -51,6 +51,13 @@
Copyright (c) 2026 Kartik Kenchi
Copyright (c) 2026 Haris Hussain
Copyright (c) 2026 Evgeny Kotkov
+ Copyright (c) 2026 Darren Carreras
+ Copyright (c) 2026 Alberto Maschietto
+ Copyright (c) 2026 Zeyou Liu
+ Copyright (c) 2026 Stan Ulbrych
+ Copyright (c) 2026 Braian Plaku
+ Copyright (c) 2026 Filippo Tedeschi
+ Copyright (c) 2026 Junki Lee
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -102,6 +109,7 @@
#include /* SIZE_MAX, UINT64_MAX, uint64_t, uintptr_t */
#include /* isnan */
#include
+#include /* wcsncmp */
#ifdef _WIN32
# define getpid GetCurrentProcessId
@@ -120,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"
@@ -223,25 +231,10 @@
#define EXPAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
#include "internal.h"
+#include "hash_table.h"
#include "xmltok.h"
#include "xmlrole.h"
-typedef const XML_Char *KEY;
-
-typedef struct {
- KEY name;
-} NAMED;
-
-typedef struct {
- NAMED **v;
- unsigned char power;
- size_t size;
- size_t used;
- XML_Parser parser;
-} HASH_TABLE;
-
-static size_t keylen(KEY s);
-
static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key);
/* For probing (after a collision) we need a step size relative prime
@@ -257,11 +250,6 @@
#define PROBE_STEP(hash, mask, power) \
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
-typedef struct {
- NAMED **p;
- NAMED **end;
-} HASH_TABLE_ITER;
-
#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
#define INIT_DATA_BUF_SIZE 1024
#define INIT_ATTS_SIZE 16
@@ -330,13 +318,13 @@
const XML_Char *base;
const XML_Char *publicId;
const XML_Char *notation;
- XML_Bool open;
- XML_Bool hasMore; /* true if entity has not been completely processed */
- /* An entity can be open while being already completely processed (hasMore ==
- XML_FALSE). The reason is the delayed closing of entities until their inner
+ bool open;
+ bool hasMore; /* true if entity has not been completely processed */
+ /* An entity can be open while being already completely processed (!hasMore).
+ The reason is the delayed closing of entities until their inner
entities are processed and closed */
- XML_Bool is_param;
- XML_Bool is_internal; /* true if declared in internal subset outside PE */
+ bool is_param;
+ bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;
typedef struct {
@@ -371,8 +359,8 @@
typedef struct attribute_id {
XML_Char *name;
PREFIX *prefix;
- XML_Bool maybeTokenized;
- XML_Bool xmlns;
+ bool maybeTokenized;
+ bool xmlns;
} ATTRIBUTE_ID;
typedef struct {
@@ -381,6 +369,22 @@
const XML_Char *value;
} DEFAULT_ATTRIBUTE;
+// This structure allows mapping attribute names to instances of
+// `DEFAULT_ATTRIBUTE`.
+typedef struct {
+ // Member `name` goes first to make this structure compatible with structure
+ // `NAMED` (further up), which is needed to support use of structure
+ // `NAME_AND_DEFAULT_ATTRIBUTE` in a hash table as implemented by function
+ // `lookup` (further down).
+ const XML_Char *name;
+ // We would store a `DEFAULT_ATTRIBUTE *` here but the backing array
+ // can be reallocated which would invalidate the pointer. Using an index
+ // into the array instead, avoids that problem.
+ size_t attIndex;
+ // This is set to `false` by function `lookup`.
+ bool initialized;
+} NAME_AND_DEFAULT_ATTRIBUTE;
+
typedef struct {
unsigned long version;
unsigned long hash;
@@ -394,7 +398,7 @@
size_t nDefaultAtts;
size_t allocDefaultAtts;
DEFAULT_ATTRIBUTE *defaultAtts;
- HASH_TABLE defaultAttsNames;
+ HASH_TABLE defaultAttForName;
} ELEMENT_TYPE;
typedef struct {
@@ -412,12 +416,12 @@
XML_Bool standalone;
#ifdef XML_DTD
/* indicates if external PE has been read */
- XML_Bool paramEntityRead;
+ bool paramEntityRead;
HASH_TABLE paramEntities;
#endif /* XML_DTD */
PREFIX defaultPrefix;
/* === scaffolding for building content model === */
- XML_Bool in_eldecl;
+ bool in_eldecl;
CONTENT_SCAFFOLD *scaffold;
unsigned contentStringLen;
unsigned scaffSize;
@@ -439,7 +443,7 @@
struct open_internal_entity *next;
ENTITY *entity;
int startTagLevel;
- XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ bool betweenDecl; /* WFC: PE Between Declarations */
enum EntityType type;
} OPEN_INTERNAL_ENTITY;
@@ -461,8 +465,8 @@
} 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;
@@ -476,8 +480,8 @@
} ENTITY_STATS;
#endif /* XML_GE == 1 */
-typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
- const char *end, const char **endPtr);
+typedef enum XML_Error Processor(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr);
static Processor prologProcessor;
static Processor prologInitProcessor;
@@ -509,7 +513,7 @@
XML_Bool haveMore, XML_Bool allowClosingDoctype,
enum XML_Account account);
static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl, enum EntityType type);
+ bool betweenDecl, enum EntityType type);
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
@@ -569,7 +573,7 @@
static const XML_Char *getContext(XML_Parser parser);
static XML_Bool setContext(XML_Parser parser, const XML_Char *context);
-static void FASTCALL normalizePublicId(XML_Char *s);
+static void normalizePublicId(XML_Char *s);
static DTD *dtdCreate(XML_Parser parser);
/* do not call if m_parentParser != NULL */
@@ -579,34 +583,24 @@
XML_Parser parser);
static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
STRING_POOL *newPool, const HASH_TABLE *oldTable);
-static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
- size_t createSize);
-static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser);
-static void FASTCALL hashTableClear(HASH_TABLE *table);
-static void FASTCALL hashTableDestroy(HASH_TABLE *table);
-static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter,
- const HASH_TABLE *table);
-static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter);
-
-static void FASTCALL poolInit(STRING_POOL *pool, XML_Parser parser);
-static void FASTCALL poolClear(STRING_POOL *pool);
-static void FASTCALL poolDestroy(STRING_POOL *pool);
+
+static void poolInit(STRING_POOL *pool, XML_Parser parser);
+static void poolClear(STRING_POOL *pool);
+static void poolDestroy(STRING_POOL *pool);
static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
const char *ptr, const char *end);
static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
const char *ptr, const char *end);
-static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
-static bool FASTCALL poolGrowUntil(STRING_POOL *pool, size_t needed);
-static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
- const XML_Char *s);
-static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool,
- const XML_Char *s);
+static XML_Bool poolGrow(STRING_POOL *pool);
+static bool poolGrowUntil(STRING_POOL *pool, size_t needed);
+static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *poolCopyStringNoFinish(STRING_POOL *pool,
+ const XML_Char *s);
static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s,
int n);
-static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool,
- const XML_Char *s);
+static const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s);
-static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static int nextScaffoldPart(XML_Parser parser);
static XML_Content *build_model(XML_Parser parser);
static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc,
const char *ptr, const char *end);
@@ -655,6 +649,25 @@
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))
@@ -755,6 +768,8 @@
void *m_unknownEncodingMem;
void *m_unknownEncodingData;
void *m_unknownEncodingHandlerData;
+ // Application callback invoked by callUnknownEncodingConvert.
+ int(XMLCALL *m_unknownEncodingConvert)(void *, const char *);
void(XMLCALL *m_unknownEncodingRelease)(void *);
PROLOG_STATE m_prologState;
Processor *m_processor;
@@ -792,9 +807,6 @@
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;
@@ -831,30 +843,30 @@
#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;
@@ -894,8 +906,7 @@
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
}
@@ -1005,9 +1016,10 @@
}
}
- // 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(
@@ -1019,8 +1031,7 @@
// 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);
@@ -1177,6 +1188,25 @@
return parser->m_handlerCallDepth > 0;
}
+static void
+callUnknownEncodingRelease(XML_Parser parser) {
+ beforeHandler(parser);
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ afterHandler(parser);
+ parser->m_unknownEncodingRelease = NULL;
+ parser->m_unknownEncodingData = NULL;
+}
+
+static int XMLCALL
+callUnknownEncodingConvert(void *data, const char *p) {
+ XML_Parser parser = data;
+ beforeHandler(parser);
+ const int result
+ = parser->m_unknownEncodingConvert(parser->m_unknownEncodingData, p);
+ afterHandler(parser);
+ return result;
+}
+
static enum XML_Error
callProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
@@ -1377,20 +1407,9 @@
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;
}
@@ -1403,9 +1422,6 @@
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;
}
@@ -1524,6 +1540,7 @@
parser->m_inheritedBindings = NULL;
parser->m_nSpecifiedAtts = 0;
parser->m_unknownEncodingMem = NULL;
+ parser->m_unknownEncodingConvert = NULL;
parser->m_unknownEncodingRelease = NULL;
parser->m_unknownEncodingData = NULL;
parser->m_parsingStatus.parsing = XML_INITIALIZED;
@@ -1553,7 +1570,7 @@
}
/* moves list of bindings to m_freeBindingList */
-static void FASTCALL
+static void
moveToFreeBindingList(XML_Parser parser, BINDING *bindings) {
while (bindings) {
BINDING *b = bindings;
@@ -1583,6 +1600,10 @@
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) {
@@ -1603,14 +1624,16 @@
moveEntityList(&parser->m_freeEntities, &parser->m_openValueEntities);
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
- if (parser->m_unknownEncodingRelease)
- parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
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;
}
@@ -1826,7 +1849,7 @@
return parser;
}
-static void FASTCALL
+static void
destroyBindings(BINDING *bindings, XML_Parser parser) {
for (;;) {
BINDING *b = bindings;
@@ -1843,6 +1866,10 @@
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 (;;) {
@@ -1903,9 +1930,6 @@
#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
@@ -1914,8 +1938,6 @@
FREE(parser, parser->m_dataBuf);
FREE(parser, parser->m_nsAtts);
FREE(parser, parser->m_unknownEncodingMem);
- if (parser->m_unknownEncodingRelease)
- parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
FREE(parser, parser);
}
@@ -1996,15 +2018,6 @@
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) {
@@ -2225,9 +2238,10 @@
#endif
}
-// DEPRECATED since Expat 2.8.0.
-int XMLCALL
-XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
+/* The body of XML_SetHashSalt, so that Expat's own tests can reach it
+ without tripping the deprecation of the public function. */
+XML_NONTESTING_STATIC int
+xmlSetHashSalt(XML_Parser parser, unsigned long hash_salt) {
if (parser == NULL)
return 0;
@@ -2253,6 +2267,12 @@
return 1;
}
+// DEPRECATED since Expat 2.8.0.
+int XMLCALL
+XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
+ return xmlSetHashSalt(parser, hash_salt);
+}
+
XML_Bool XMLCALL
XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]) {
if (parser == NULL)
@@ -2426,6 +2446,11 @@
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;
@@ -2685,41 +2710,57 @@
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
@@ -2730,8 +2771,41 @@
return NULL;
}
-XML_Size XMLCALL
-XML_GetCurrentLineNumber(XML_Parser parser) {
+// DEPRECATED since Expat 2.9.0.
+const char *XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
+#if XML_CONTEXT_BYTES > 0
+ if (parser == NULL)
+ return NULL;
+
+ int64_t offset64;
+ uint64_t size64;
+
+ const char *const buffer = XML_GetInputContext64(parser, &offset64, &size64);
+
+ if (buffer == NULL)
+ return NULL;
+
+ // NOTE: int is known to wrap around for >2 GiB content.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ if (offset != NULL)
+ *offset = (int)offset64;
+
+ if (size != NULL)
+ *size = (int)size64;
+
+ return buffer;
+#else
+ (void)parser;
+ (void)offset;
+ (void)size;
+#endif /* XML_CONTEXT_BYTES > 0 */
+ return NULL;
+}
+
+uint64_t XMLCALL
+XML_GetCurrentLineNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
@@ -2739,16 +2813,22 @@
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
- // NOTE: XML_Size is known to wrap around for >2 4iB content
+ return parser->m_position.lineNumber + 1;
+}
+
+// DEPRECATED since Expat 2.9.0.
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser) {
+ // NOTE: XML_Size is known to wrap around for >4 GiB content
// on 32bit machines and 64bit Windows, unless (non-default and
// uncommon) XML_LARGE_SIZE is defined.
// That's a bug and it only lives on because we cannot break
// ABI compatibility of public API.
- return (XML_Size)(parser->m_position.lineNumber + 1);
+ return (XML_Size)XML_GetCurrentLineNumber64(parser);
}
-XML_Size XMLCALL
-XML_GetCurrentColumnNumber(XML_Parser parser) {
+uint64_t XMLCALL
+XML_GetCurrentColumnNumber64(XML_Parser parser) {
if (parser == NULL)
return 0;
if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
@@ -2756,12 +2836,18 @@
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
- // NOTE: XML_Size is known to wrap around for >2 4iB content
+ return parser->m_position.columnNumber;
+}
+
+// DEPRECATED since Expat 2.9.0.
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser) {
+ // NOTE: XML_Size is known to wrap around for >4 GiB content
// on 32bit machines and 64bit Windows, unless (non-default and
// uncommon) XML_LARGE_SIZE is defined.
// That's a bug and it only lives on because we cannot break
// ABI compatibility of public API.
- return (XML_Size)parser->m_position.columnNumber;
+ return (XML_Size)XML_GetCurrentColumnNumber64(parser);
}
void XMLCALL
@@ -2807,7 +2893,7 @@
void XMLCALL
XML_DefaultCurrent(XML_Parser parser) {
- if (parser == NULL)
+ if (parser == NULL || ! isCalledFromInsideHandler(parser))
return;
if (parser->m_defaultHandler) {
if (parser->m_openInternalEntities)
@@ -2978,18 +3064,12 @@
{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. */
@@ -3016,59 +3096,294 @@
}
#if XML_GE == 1
+static enum XML_Prop_Error
+setBillionLaughsAttackProtectionMaximumAmplification(
+ XML_Parser parser, float maximumAmplificationFactor) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ if (isnan(maximumAmplificationFactor) || (maximumAmplificationFactor < 1.0f))
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
+
+ return XML_PROP_ERROR_NONE;
+}
+
XML_Bool XMLCALL
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
XML_Parser parser, float maximumAmplificationFactor) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)
- || isnan(maximumAmplificationFactor)
- || (maximumAmplificationFactor < 1.0f)) {
- return XML_FALSE;
- }
- parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
- return XML_TRUE;
+ return (setBillionLaughsAttackProtectionMaximumAmplification(
+ parser, maximumAmplificationFactor)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setBillionLaughsAttackProtectionActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetBillionLaughsAttackProtectionActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)) {
- return XML_FALSE;
- }
- parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
- return XML_TRUE;
+ return (setBillionLaughsAttackProtectionActivationThreshold(
+ parser, activationThresholdBytes)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setAllocTrackerMaximumAmplification(XML_Parser parser,
+ float maximumAmplificationFactor) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ if (isnan(maximumAmplificationFactor) || (maximumAmplificationFactor < 1.0f))
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_alloc_tracker.maximumAmplificationFactor
+ = maximumAmplificationFactor;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetAllocTrackerMaximumAmplification(XML_Parser parser,
float maximumAmplificationFactor) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)
- || isnan(maximumAmplificationFactor)
- || (maximumAmplificationFactor < 1.0f)) {
- return XML_FALSE;
- }
- parser->m_alloc_tracker.maximumAmplificationFactor
- = maximumAmplificationFactor;
- return XML_TRUE;
+ return (setAllocTrackerMaximumAmplification(parser,
+ maximumAmplificationFactor)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+static enum XML_Prop_Error
+setAllocTrackerActivationThreshold(
+ XML_Parser parser, unsigned long long activationThresholdBytes) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (parser->m_parentParser != NULL)
+ return XML_PROP_ERROR_PARSER_NOT_ROOT;
+
+ parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes;
+
+ return XML_PROP_ERROR_NONE;
}
XML_Bool XMLCALL
XML_SetAllocTrackerActivationThreshold(
XML_Parser parser, unsigned long long activationThresholdBytes) {
- if ((parser == NULL) || (parser->m_parentParser != NULL)) {
- return XML_FALSE;
- }
- parser->m_alloc_tracker.activationThresholdBytes = activationThresholdBytes;
- return XML_TRUE;
+ return (setAllocTrackerActivationThreshold(parser, activationThresholdBytes)
+ == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
}
#endif /* XML_GE == 1 */
+static enum XML_Prop_Error
+setReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (enabled != XML_TRUE && enabled != XML_FALSE)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ parser->m_reparseDeferralEnabled = enabled;
+
+ return XML_PROP_ERROR_NONE;
+}
+
XML_Bool XMLCALL
XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
- if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
- parser->m_reparseDeferralEnabled = enabled;
- return XML_TRUE;
+ return (setReparseDeferralEnabled(parser, enabled) == XML_PROP_ERROR_NONE)
+ ? XML_TRUE
+ : XML_FALSE;
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return XML_PROP_ERROR_INVALID_TYPE;
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return setReparseDeferralEnabled(parser, value);
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+#if XML_GE == 0
+ UNUSED_P(value);
+#endif
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ return setAllocTrackerMaximumAmplification(parser, (float)value);
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return setBillionLaughsAttackProtectionMaximumAmplification(parser,
+ (float)value);
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_SetPropertyUInt64(XML_Parser parser, enum XML_Parser_Property property,
+ uint64_t value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+#if XML_GE == 0
+ UNUSED_P(value);
+#endif
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ return setAllocTrackerActivationThreshold(parser,
+ (unsigned long long)value);
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ return setBillionLaughsAttackProtectionActivationThreshold(
+ parser, (unsigned long long)value);
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ assert(0 && "considered unreachable");
+}
+
+enum XML_Prop_Error XMLCALL
+XML_GetPropertyBool(XML_Parser parser, enum XML_Parser_Property property,
+ XML_Bool *value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (value == NULL)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ return XML_PROP_ERROR_INVALID_TYPE;
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ *value = parser->m_reparseDeferralEnabled;
+ break;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ return XML_PROP_ERROR_NONE;
+}
+
+enum XML_Prop_Error XMLCALL
+XML_GetPropertyDouble(XML_Parser parser, enum XML_Parser_Property property,
+ double *value) {
+ if (parser == NULL)
+ return XML_PROP_ERROR_PARSER_NULL;
+
+ if (value == NULL)
+ return XML_PROP_ERROR_INVALID_VALUE;
+
+ switch (property) {
+#if XML_GE == 1
+ case XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION:
+ *value = (double)parser->m_accounting.maximumAmplificationFactor;
+ break;
+ case XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION:
+ *value = (double)parser->m_alloc_tracker.maximumAmplificationFactor;
+ break;
+ case XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD:
+ case XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD:
+#endif /* XML_GE == 1 */
+ case XML_PROP_REPARSE_DEFERRAL_ENABLED:
+ return XML_PROP_ERROR_INVALID_TYPE;
+ default:
+ return XML_PROP_ERROR_INVALID_KEY;
+ }
+
+ return XML_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_FALSE;
+
+ return XML_PROP_ERROR_NONE;
}
/* Initially tag->rawName always points into the parse buffer;
@@ -3125,7 +3440,7 @@
return XML_TRUE;
}
-static enum XML_Error PTRCALL
+static enum XML_Error
contentProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
enum XML_Error result = doContent(
@@ -3139,7 +3454,7 @@
return result;
}
-static enum XML_Error PTRCALL
+static enum XML_Error
externalEntityInitProcessor(XML_Parser parser, const char *start,
const char *end, const char **endPtr) {
enum XML_Error result = initializeEncoding(parser);
@@ -3149,7 +3464,7 @@
return externalEntityInitProcessor2(parser, start, end, endPtr);
}
-static enum XML_Error PTRCALL
+static enum XML_Error
externalEntityInitProcessor2(XML_Parser parser, const char *start,
const char *end, const char **endPtr) {
const char *next = start; /* XmlContentTok doesn't always set the last arg */
@@ -3194,7 +3509,7 @@
return externalEntityInitProcessor3(parser, start, end, endPtr);
}
-static enum XML_Error PTRCALL
+static enum XML_Error
externalEntityInitProcessor3(XML_Parser parser, const char *start,
const char *end, const char **endPtr) {
int tok;
@@ -3246,7 +3561,7 @@
return externalEntityContentProcessor(parser, start, end, endPtr);
}
-static enum XML_Error PTRCALL
+static enum XML_Error
externalEntityContentProcessor(XML_Parser parser, const char *start,
const char *end, const char **endPtr) {
enum XML_Error result
@@ -3410,9 +3725,9 @@
return result;
} else if (parser->m_externalEntityRefHandler) {
const XML_Char *context;
- entity->open = XML_TRUE;
+ entity->open = true;
context = getContext(parser);
- entity->open = XML_FALSE;
+ entity->open = false;
if (! context)
return XML_ERROR_NO_MEMORY;
beforeHandler(parser);
@@ -3837,8 +4152,8 @@
sizeof(ELEMENT_TYPE));
if (! elementType)
return XML_ERROR_NO_MEMORY;
- if (! elementType->defaultAttsNames.parser)
- hashTableInit(&(elementType->defaultAttsNames), parser);
+ if (! elementType->defaultAttForName.parser)
+ hashTableInit(&(elementType->defaultAttForName), parser);
if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
@@ -3881,21 +4196,6 @@
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)
@@ -3908,33 +4208,12 @@
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.
@@ -3951,11 +4230,14 @@
/* figure out whether declared as other than CDATA */
if (attId->maybeTokenized) {
- for (size_t j = 0; j < nDefaultAtts; j++) {
- if (attId == elementType->defaultAtts[j].id) {
- isCdata = elementType->defaultAtts[j].isCdata;
- break;
- }
+ NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
+ = (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
+ parser, &(elementType->defaultAttForName), attId->name, 0);
+ if (nameAndDefaultAttribute != NULL) {
+ assert(nameAndDefaultAttribute->attIndex < elementType->nDefaultAtts);
+ const DEFAULT_ATTRIBUTE *const att
+ = elementType->defaultAtts + nameAndDefaultAttribute->attIndex;
+ isCdata = att->isCdata;
}
}
@@ -4046,8 +4328,8 @@
unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
- if ((nPrefixes << 1)
- >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
+ if (parser->m_nsAttsPower == 0
+ || (nPrefixes >> (parser->m_nsAttsPower - 1))) {
/* hash table size must also be a power of 2 and >= 8 */
while (nPrefixes >> parser->m_nsAttsPower++)
;
@@ -4505,6 +4787,7 @@
/* Detect and prevent integer overflow */
if (len > SIZE_MAX - EXPAND_SPARE
|| len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
+ FREE(parser, b);
return XML_ERROR_NO_MEMORY;
}
@@ -4542,7 +4825,7 @@
/* The idea here is to avoid using stack for each CDATA section when
the whole file is parsed with one call.
*/
-static enum XML_Error PTRCALL
+static enum XML_Error
cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
enum XML_Error result = doCdataSection(
@@ -4708,7 +4991,7 @@
/* The idea here is to avoid using stack for each IGNORE section when
the whole file is parsed with one call.
*/
-static enum XML_Error PTRCALL
+static enum XML_Error
ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
enum XML_Error result
@@ -4946,30 +5229,39 @@
const int status = parser->m_unknownEncodingHandler(
parser->m_unknownEncodingHandlerData, encodingName, &info);
afterHandler(parser);
+
+ parser->m_unknownEncodingRelease = info.release;
+ parser->m_unknownEncodingData = info.data;
+
if (status) {
ENCODING *enc;
parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
if (! parser->m_unknownEncodingMem) {
- if (info.release)
- info.release(info.data);
+ if (parser->m_unknownEncodingRelease)
+ callUnknownEncodingRelease(parser);
+ else
+ parser->m_unknownEncodingData = NULL;
return XML_ERROR_NO_MEMORY;
}
+ parser->m_unknownEncodingConvert = info.convert;
enc = (parser->m_ns ? XmlInitUnknownEncodingNS : XmlInitUnknownEncoding)(
- parser->m_unknownEncodingMem, info.map, info.convert, info.data);
+ parser->m_unknownEncodingMem, info.map,
+ info.convert ? callUnknownEncodingConvert : NULL, parser);
if (enc) {
- parser->m_unknownEncodingData = info.data;
- parser->m_unknownEncodingRelease = info.release;
parser->m_encoding = enc;
return XML_ERROR_NONE;
}
+ parser->m_unknownEncodingConvert = NULL;
}
- if (info.release != NULL)
- info.release(info.data);
+ if (parser->m_unknownEncodingRelease != NULL)
+ callUnknownEncodingRelease(parser);
+ else
+ parser->m_unknownEncodingData = NULL;
}
return XML_ERROR_UNKNOWN_ENCODING;
}
-static enum XML_Error PTRCALL
+static enum XML_Error
prologInitProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
enum XML_Error result = initializeEncoding(parser);
@@ -4981,7 +5273,7 @@
#ifdef XML_DTD
-static enum XML_Error PTRCALL
+static enum XML_Error
externalParEntInitProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
enum XML_Error result = initializeEncoding(parser);
@@ -4990,7 +5282,7 @@
/* we know now that XML_Parse(Buffer) has been called,
so we consider the external parameter entity read */
- parser->m_dtd->paramEntityRead = XML_TRUE;
+ parser->m_dtd->paramEntityRead = true;
if (parser->m_prologState.inEntityValue) {
parser->m_processor = entityValueInitProcessor;
@@ -5001,7 +5293,7 @@
}
}
-static enum XML_Error PTRCALL
+static enum XML_Error
entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
int tok;
@@ -5085,7 +5377,7 @@
}
}
-static enum XML_Error PTRCALL
+static enum XML_Error
externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
const char *next = s;
@@ -5131,7 +5423,7 @@
XML_ACCOUNT_DIRECT);
}
-static enum XML_Error PTRCALL
+static enum XML_Error
entityValueProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
const char *start = s;
@@ -5178,7 +5470,7 @@
#endif /* XML_DTD */
-static enum XML_Error PTRCALL
+static enum XML_Error
prologProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
const char *next = s;
@@ -5424,7 +5716,7 @@
}
if (parser->m_useForeignDTD)
entity->base = parser->m_curBase;
- dtd->paramEntityRead = XML_FALSE;
+ dtd->paramEntityRead = false;
beforeHandler(parser);
const int status = parser->m_externalEntityRefHandler(
parser->m_externalEntityRefHandlerArg, 0, entity->base,
@@ -5474,7 +5766,7 @@
if (! entity)
return XML_ERROR_NO_MEMORY;
entity->base = parser->m_curBase;
- dtd->paramEntityRead = XML_FALSE;
+ dtd->paramEntityRead = false;
beforeHandler(parser);
const int status = parser->m_externalEntityRefHandler(
parser->m_externalEntityRefHandlerArg, 0, entity->base,
@@ -5817,7 +6109,7 @@
} else {
poolFinish(&dtd->pool);
parser->m_declEntity->publicId = NULL;
- parser->m_declEntity->is_param = XML_FALSE;
+ parser->m_declEntity->is_param = false;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
@@ -5847,7 +6139,7 @@
} else {
poolFinish(&dtd->pool);
parser->m_declEntity->publicId = NULL;
- parser->m_declEntity->is_param = XML_TRUE;
+ parser->m_declEntity->is_param = true;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
@@ -6082,8 +6374,7 @@
return XML_ERROR_RECURSIVE_ENTITY_REF;
if (entity->textPtr) {
enum XML_Error result;
- XML_Bool betweenDecl
- = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+ bool betweenDecl = (role == XML_ROLE_PARAM_ENTITY_REF);
result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL);
if (result != XML_ERROR_NONE)
return result;
@@ -6091,8 +6382,8 @@
break;
}
if (parser->m_externalEntityRefHandler) {
- dtd->paramEntityRead = XML_FALSE;
- entity->open = XML_TRUE;
+ dtd->paramEntityRead = false;
+ entity->open = true;
entityTrackingOnOpen(parser, entity, __LINE__);
beforeHandler(parser);
const int status = parser->m_externalEntityRefHandler(
@@ -6101,11 +6392,11 @@
afterHandler(parser);
if (! status) {
entityTrackingOnClose(parser, entity, __LINE__);
- entity->open = XML_FALSE;
+ entity->open = false;
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
}
entityTrackingOnClose(parser, entity, __LINE__);
- entity->open = XML_FALSE;
+ entity->open = false;
handleDefault = XML_FALSE;
if (! dtd->paramEntityRead) {
dtd->keepProcessing = dtd->standalone;
@@ -6135,7 +6426,7 @@
return XML_ERROR_NO_MEMORY;
dtd->scaffLevel = 0;
dtd->scaffCount = 0;
- dtd->in_eldecl = XML_TRUE;
+ dtd->in_eldecl = true;
handleDefault = XML_FALSE;
}
break;
@@ -6164,7 +6455,7 @@
afterHandler(parser);
handleDefault = XML_FALSE;
}
- dtd->in_eldecl = XML_FALSE;
+ dtd->in_eldecl = false;
}
break;
@@ -6246,7 +6537,7 @@
parser->m_handlerArg, parser->m_declElementType->name, model);
afterHandler(parser);
}
- dtd->in_eldecl = XML_FALSE;
+ dtd->in_eldecl = false;
dtd->contentStringLen = 0;
}
}
@@ -6315,7 +6606,7 @@
/* not reached */
}
-static enum XML_Error PTRCALL
+static enum XML_Error
epilogProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
parser->m_processor = epilogProcessor;
@@ -6394,7 +6685,7 @@
}
static enum XML_Error
-processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
+processEntity(XML_Parser parser, ENTITY *entity, bool betweenDecl,
enum EntityType type) {
OPEN_INTERNAL_ENTITY *openEntity, **openEntityList;
OPEN_INTERNAL_ENTITY **const freeEntityList = &parser->m_freeEntities;
@@ -6429,8 +6720,8 @@
if (! openEntity)
return XML_ERROR_NO_MEMORY;
}
- entity->open = XML_TRUE;
- entity->hasMore = XML_TRUE;
+ entity->open = true;
+ entity->hasMore = true;
#if XML_GE == 1
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
@@ -6452,7 +6743,7 @@
return XML_ERROR_NONE;
}
-static enum XML_Error PTRCALL
+static enum XML_Error
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
UNUSED_P(s);
@@ -6502,7 +6793,7 @@
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openInternalEntities during doProlog or doContent calls above)
- entity->hasMore = XML_FALSE;
+ entity->hasMore = false;
if (! entity->is_param
&& (openEntity->startTagLevel != parser->m_tagLevel)) {
return XML_ERROR_ASYNC_ENTITY;
@@ -6520,7 +6811,7 @@
// to false. This means we can directly remove the head of
// m_openInternalEntities
assert(parser->m_openInternalEntities == openEntity);
- entity->open = XML_FALSE;
+ entity->open = false;
parser->m_openInternalEntities = parser->m_openInternalEntities->next;
/* put openEntity back in list of free instances */
@@ -6534,7 +6825,7 @@
return XML_ERROR_NONE;
}
-static enum XML_Error PTRCALL
+static enum XML_Error
errorProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
UNUSED_P(s);
@@ -6585,7 +6876,7 @@
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openAttributeEntities during appendAttributeValue)
- entity->hasMore = XML_FALSE;
+ entity->hasMore = false;
continue;
} // End of entity processing, "if" block skips the rest
@@ -6598,7 +6889,7 @@
// with hasMore set to false. This means we can directly remove the head
// of m_openAttributeEntities
assert(parser->m_openAttributeEntities == openEntity);
- entity->open = XML_FALSE;
+ entity->open = false;
parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
/* put openEntity back in list of free instances */
@@ -6893,8 +7184,8 @@
}
if (entity->systemId) {
if (parser->m_externalEntityRefHandler) {
- dtd->paramEntityRead = XML_FALSE;
- entity->open = XML_TRUE;
+ dtd->paramEntityRead = false;
+ entity->open = true;
entityTrackingOnOpen(parser, entity, __LINE__);
beforeHandler(parser);
const int status = parser->m_externalEntityRefHandler(
@@ -6903,12 +7194,12 @@
afterHandler(parser);
if (! status) {
entityTrackingOnClose(parser, entity, __LINE__);
- entity->open = XML_FALSE;
+ entity->open = false;
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
goto endEntityValue;
}
entityTrackingOnClose(parser, entity, __LINE__);
- entity->open = XML_FALSE;
+ entity->open = false;
if (! dtd->paramEntityRead)
dtd->keepProcessing = dtd->standalone;
} else
@@ -7045,7 +7336,7 @@
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openValueEntities during storeEntityValue)
- entity->hasMore = XML_FALSE;
+ entity->hasMore = false;
continue;
} // End of entity processing, "if" block skips the rest
@@ -7058,7 +7349,7 @@
// with hasMore set to false. This means we can directly remove the head
// of m_openValueEntities
assert(parser->m_openValueEntities == openEntity);
- entity->open = XML_FALSE;
+ entity->open = false;
parser->m_openValueEntities = parser->m_openValueEntities->next;
/* put openEntity back in list of free instances */
@@ -7107,7 +7398,7 @@
#endif /* XML_GE == 0 */
-static void FASTCALL
+static void
normalizeLines(XML_Char *s) {
XML_Char *p;
for (;; s++) {
@@ -7239,7 +7530,7 @@
/* The handling of default attributes gets messed up if we have
a default which duplicates a non-default. */
NAMED *const nameFound
- = lookup(parser, &(type->defaultAttsNames), attId->name, 0);
+ = lookup(parser, &(type->defaultAttForName), attId->name, 0);
if (nameFound)
return 1;
if (isId && ! type->idAtt && ! attId->xmlns)
@@ -7273,13 +7564,26 @@
att->value = value;
att->isCdata = isCdata;
if (! isCdata)
- attId->maybeTokenized = XML_TRUE;
+ attId->maybeTokenized = true;
- NAMED *const nameAddedOrFound
- = lookup(parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED));
- if (! nameAddedOrFound)
+ NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
+ = (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
+ parser, &(type->defaultAttForName), attId->name,
+ sizeof(NAME_AND_DEFAULT_ATTRIBUTE));
+ if (! nameAndDefaultAttribute)
return 0;
+ assert(nameAndDefaultAttribute->name == attId->name);
+
+ // NOTE: The XML 1.0r4 spec says:
+ // "When more than one definition is provided for the same attribute of a
+ // given element type, the first declaration is binding and later
+ // declarations are ignored."
+ if (! nameAndDefaultAttribute->initialized) {
+ nameAndDefaultAttribute->attIndex = type->nDefaultAtts;
+ nameAndDefaultAttribute->initialized = true;
+ }
+
type->nDefaultAtts += 1;
return 1;
}
@@ -7345,7 +7649,7 @@
else
id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6,
sizeof(PREFIX));
- id->xmlns = XML_TRUE;
+ id->xmlns = true;
} else {
int i;
for (i = 0; name[i]; i++) {
@@ -7480,7 +7784,7 @@
e = (ENTITY *)lookup(parser, &dtd->generalEntities,
poolStart(&parser->m_tempPool), 0);
if (e)
- e->open = XML_TRUE;
+ e->open = true;
if (*s != XML_T('\0'))
s++;
context = s;
@@ -7535,7 +7839,7 @@
return XML_TRUE;
}
-static void FASTCALL
+static void
normalizePublicId(XML_Char *publicId) {
XML_Char *p = publicId;
XML_Char *s;
@@ -7568,13 +7872,13 @@
hashTableInit(&(p->attributeIds), parser);
hashTableInit(&(p->prefixes), parser);
#ifdef XML_DTD
- p->paramEntityRead = XML_FALSE;
+ p->paramEntityRead = false;
hashTableInit(&(p->paramEntities), parser);
#endif /* XML_DTD */
p->defaultPrefix.name = NULL;
p->defaultPrefix.binding = NULL;
- p->in_eldecl = XML_FALSE;
+ p->in_eldecl = false;
p->scaffIndex = NULL;
p->scaffIndexSize = 0;
p->scaffold = NULL;
@@ -7597,12 +7901,12 @@
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
- hashTableDestroy(&(e->defaultAttsNames));
+ hashTableDestroy(&(e->defaultAttForName));
FREE(parser, e->defaultAtts);
}
hashTableClear(&(p->generalEntities));
#ifdef XML_DTD
- p->paramEntityRead = XML_FALSE;
+ p->paramEntityRead = false;
hashTableClear(&(p->paramEntities));
#endif /* XML_DTD */
hashTableClear(&(p->elementTypes));
@@ -7613,7 +7917,7 @@
p->defaultPrefix.name = NULL;
p->defaultPrefix.binding = NULL;
- p->in_eldecl = XML_FALSE;
+ p->in_eldecl = false;
FREE(parser, p->scaffIndex);
p->scaffIndex = NULL;
@@ -7639,7 +7943,7 @@
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
- hashTableDestroy(&(e->defaultAttsNames));
+ hashTableDestroy(&(e->defaultAttForName));
FREE(parser, e->defaultAtts);
}
hashTableDestroy(&(p->generalEntities));
@@ -7732,8 +8036,8 @@
if (! newE)
return 0;
- if (! newE->defaultAttsNames.parser)
- hashTableInit(&(newE->defaultAttsNames), parser);
+ if (! newE->defaultAttForName.parser)
+ hashTableInit(&(newE->defaultAttForName), parser);
if (oldE->nDefaultAtts) {
/* Detect and prevent integer overflow. */
@@ -7766,11 +8070,22 @@
} else
newE->defaultAtts[i].value = NULL;
- NAMED *const nameAddedOrFound = lookup(parser, &(newE->defaultAttsNames),
- attributeName, sizeof(NAMED));
- if (! nameAddedOrFound) {
+ NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
+ = (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
+ parser, &(newE->defaultAttForName), attributeName,
+ sizeof(NAME_AND_DEFAULT_ATTRIBUTE));
+ if (! nameAndDefaultAttribute) {
return 0;
}
+
+ // NOTE: The XML 1.0r4 spec says:
+ // "When more than one definition is provided for the same attribute of a
+ // given element type, the first declaration is binding and later
+ // declarations are ignored."
+ if (! nameAndDefaultAttribute->initialized) {
+ nameAndDefaultAttribute->attIndex = i;
+ nameAndDefaultAttribute->initialized = true;
+ }
}
}
@@ -7867,23 +8182,27 @@
#define INIT_POWER 6
-static XML_Bool FASTCALL
-keyeq(KEY s1, KEY s2) {
+// Compares two strings `s1` and `s2` whereas:
+// - `s2` is zero-terminated but
+// - `s1` is made up of exactly (not just up to) `s1len` non-zero characters.
+XML_NONTESTING_STATIC XML_Bool
+keyeq(KEY s1, size_t s1len, KEY s2) {
#ifdef XML_UNICODE
# ifdef XML_UNICODE_WCHAR_T
- return (wcscmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
+ return (wcsncmp(s1, s2, s1len) == 0 && s2[s1len] == L'\0') ? XML_TRUE
+ : XML_FALSE;
# else
- for (; *s1 == *s2; s1++, s2++)
- if (*s1 == 0)
- return XML_TRUE;
- return XML_FALSE;
+ for (; s1len > 0 && *s1 == *s2; s1len--, s1++, s2++)
+ ; /* no loop body! */
+ return ((s1len == 0) && (*s2 == 0)) ? XML_TRUE : XML_FALSE;
# endif
#else
- return (strcmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
+ return (strncmp(s1, s2, s1len) == 0 && s2[s1len] == '\0') ? XML_TRUE
+ : XML_FALSE;
#endif
}
-static size_t
+XML_NONTESTING_STATIC size_t
keylen(KEY s) {
return xcslen(s);
}
@@ -7896,19 +8215,39 @@
*key = rootParser->m_hash_secret_salt_128;
}
-static unsigned long FASTCALL
-hash(XML_Parser parser, KEY s) {
+static unsigned long
+hash(XML_Parser parser, KEY s, size_t keyLen) {
struct siphash state;
struct sipkey key;
(void)sip24_valid;
copy_salt_to_sipkey(parser, &key);
sip24_init(&state, &key);
- sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
+ sip24_update(&state, s, keyLen * sizeof(XML_Char));
return (unsigned long)sip24_final(&state);
}
-static NAMED *
-lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
+// Function `lookupWithLength` can be used to either…
+//
+// a) check whether an element with key `name` exists in the given hash table
+// (read-only mode where `createSize == 0`) or
+//
+// b) check whether an element with key `name` exists in the given hash table
+// *and* insert it if missing (i.e. read-write mode where `createSize != 0`.
+//
+// When inserting, a block of `createSize` number of bytes will be allocated
+// and set to zero, and the resulting block of memory will be considered
+// to start with a `NAMED` structure, and `->name = name;` is performed.
+// The fact that all other bytes in the structure are initially zero can
+// be used to tell cases "existed and found" and "newly inserted" apart
+// with the structure returned.
+//
+// NOTE: Read-only lookup does not need zero-terminated keys but
+// read-write mode does, because keys can be re-hashed later and the
+// hash table does not store key length information.
+//
+XML_NONTESTING_STATIC NAMED *
+lookupWithLength(XML_Parser parser, HASH_TABLE *table, KEY name, size_t nameLen,
+ size_t createSize) {
size_t i;
if (table->size == 0) {
size_t tsize;
@@ -7924,14 +8263,14 @@
return NULL;
}
memset(table->v, 0, tsize);
- i = hash(parser, name) & ((unsigned long)table->size - 1);
+ i = hash(parser, name, nameLen) & ((unsigned long)table->size - 1);
} else {
- unsigned long h = hash(parser, name);
+ unsigned long h = hash(parser, name, nameLen);
unsigned long mask = (unsigned long)table->size - 1;
unsigned char step = 0;
i = h & mask;
while (table->v[i]) {
- if (keyeq(name, table->v[i]->name))
+ if (keyeq(name, nameLen, table->v[i]->name))
return table->v[i];
if (! step)
step = PROBE_STEP(h, mask, table->power);
@@ -7964,7 +8303,8 @@
memset(newV, 0, tsize);
for (i = 0; i < table->size; i++)
if (table->v[i]) {
- unsigned long newHash = hash(parser, table->v[i]->name);
+ KEY const key = table->v[i]->name;
+ unsigned long newHash = hash(parser, key, keylen(key));
size_t j = newHash & newMask;
step = 0;
while (newV[j]) {
@@ -7987,16 +8327,37 @@
}
}
}
+ assert(createSize >= sizeof(NAMED));
table->v[i] = MALLOC(table->parser, createSize);
if (! table->v[i])
return NULL;
memset(table->v[i], 0, createSize);
- table->v[i]->name = name;
+ table->v[i]->name = name; // NOTE: This requires and assumes zero termination!
(table->used)++;
return table->v[i];
}
-static void FASTCALL
+// Function `lookup` can be used to either…
+//
+// a) check whether an element with key `name` exists in the given hash table
+// (read-only mode where `createSize == 0`) or
+//
+// b) check whether an element with key `name` exists in the given hash table
+// *and* insert it if missing (i.e. read-write mode where `createSize != 0`.
+//
+// When inserting, a block of `createSize` number of bytes will be allocated
+// and set to zero, and the resulting block of memory will be considered
+// to start with a `NAMED` structure, and `->name = name;` is performed.
+// The fact that all other bytes in the structure are initially zero can
+// be used to tell cases "existed and found" and "newly inserted" apart
+// with the structure returned.
+//
+XML_NONTESTING_STATIC NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
+ return lookupWithLength(parser, table, name, keylen(name), createSize);
+}
+
+XML_NONTESTING_STATIC void
hashTableClear(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++) {
@@ -8006,7 +8367,7 @@
table->used = 0;
}
-static void FASTCALL
+XML_NONTESTING_STATIC void
hashTableDestroy(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++)
@@ -8014,7 +8375,7 @@
FREE(table->parser, table->v);
}
-static void FASTCALL
+XML_NONTESTING_STATIC void
hashTableInit(HASH_TABLE *p, XML_Parser parser) {
p->power = 0;
p->size = 0;
@@ -8023,13 +8384,13 @@
p->parser = parser;
}
-static void FASTCALL
+XML_NONTESTING_STATIC void
hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) {
iter->p = table->v;
iter->end = iter->p ? iter->p + table->size : NULL;
}
-static NAMED *FASTCALL
+XML_NONTESTING_STATIC NAMED *
hashTableIterNext(HASH_TABLE_ITER *iter) {
while (iter->p != iter->end) {
NAMED *tem = *(iter->p)++;
@@ -8039,7 +8400,7 @@
return NULL;
}
-static void FASTCALL
+static void
poolInit(STRING_POOL *pool, XML_Parser parser) {
pool->blocks = NULL;
pool->freeBlocks = NULL;
@@ -8049,7 +8410,7 @@
pool->parser = parser;
}
-static void FASTCALL
+static void
poolClear(STRING_POOL *pool) {
if (! pool->freeBlocks)
pool->freeBlocks = pool->blocks;
@@ -8068,7 +8429,7 @@
pool->end = NULL;
}
-static void FASTCALL
+static void
poolDestroy(STRING_POOL *pool) {
BLOCK *p = pool->blocks;
while (p) {
@@ -8101,7 +8462,7 @@
return pool->start;
}
-static const XML_Char *FASTCALL
+static const XML_Char *
poolCopyString(STRING_POOL *pool, const XML_Char *s) {
if (! poolAppendChars(pool, s, xcslen(s) + /*null terminator*/ 1))
return NULL;
@@ -8112,7 +8473,7 @@
// A version of `poolCopyString` that does not call `poolFinish`
// and reverts any partial advancement upon failure.
-static const XML_Char *FASTCALL
+static const XML_Char *
poolCopyStringNoFinish(STRING_POOL *pool, const XML_Char *s) {
const XML_Char *const original = s;
do {
@@ -8150,7 +8511,7 @@
return s;
}
-static const XML_Char *FASTCALL
+static const XML_Char *
poolAppendString(STRING_POOL *pool, const XML_Char *s) {
if (! poolAppendChars(pool, s, xcslen(s)))
return NULL;
@@ -8195,7 +8556,7 @@
}
}
-static XML_Bool FASTCALL
+static XML_Bool
poolGrow(STRING_POOL *pool) {
if (pool->freeBlocks) {
if (pool->start == NULL) {
@@ -8300,7 +8661,7 @@
return XML_TRUE;
}
-static bool FASTCALL
+static bool
poolGrowUntil(STRING_POOL *pool, size_t needed) {
for (;;) {
const size_t available = pool->end - pool->ptr;
@@ -8313,7 +8674,7 @@
}
}
-static int FASTCALL
+static int
nextScaffoldPart(XML_Parser parser) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
CONTENT_SCAFFOLD *me;
@@ -8535,8 +8896,8 @@
sizeof(ELEMENT_TYPE));
if (! ret)
return NULL;
- if (! ret->defaultAttsNames.parser)
- hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL));
+ if (! ret->defaultAttForName.parser)
+ hashTableInit(&(ret->defaultAttForName), getRootParserOf(parser, NULL));
if (ret->name != name)
poolDiscard(&dtd->pool);
else {
diff -Nru expat-2.8.3/expat/lib/xmlrole.c expat-2.9.0/expat/lib/xmlrole.c
--- expat-2.8.3/expat/lib/xmlrole.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmlrole.c 2026-10-05 15:43:59.000000000 +0000
@@ -12,7 +12,7 @@
Copyright (c) 2002-2006 Karl Waclawek
Copyright (c) 2002-2003 Fred L. Drake, Jr.
Copyright (c) 2005-2009 Steven Solie
- Copyright (c) 2016-2023 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2019 David Loffredo
Copyright (c) 2021 Donghee Na
@@ -121,9 +121,8 @@
# define setTopLevel(state) ((state)->handler = internalSubset)
#endif /* not XML_DTD */
-typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, int tok,
- const char *ptr, const char *end,
- const ENCODING *enc);
+typedef int PROLOG_HANDLER(PROLOG_STATE *state, int tok, const char *ptr,
+ const char *end, const ENCODING *enc);
static PROLOG_HANDLER prolog0, prolog1, prolog2, doctype0, doctype1, doctype2,
doctype3, doctype4, doctype5, internalSubset, entity0, entity1, entity2,
@@ -137,9 +136,9 @@
#endif /* XML_DTD */
declClose, error;
-static int FASTCALL common(PROLOG_STATE *state, int tok);
+static int common(PROLOG_STATE *state, int tok);
-static int PTRCALL
+static int
prolog0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -170,7 +169,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
prolog1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -202,7 +201,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
prolog2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -222,7 +221,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -239,7 +238,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -265,7 +264,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -281,7 +280,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -297,7 +296,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -316,7 +315,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
doctype5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -332,7 +331,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
internalSubset(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -377,7 +376,7 @@
#ifdef XML_DTD
-static int PTRCALL
+static int
externalSubset0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
state->handler = externalSubset1;
@@ -386,7 +385,7 @@
return externalSubset1(state, tok, ptr, end, enc);
}
-static int PTRCALL
+static int
externalSubset1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -414,7 +413,7 @@
#endif /* XML_DTD */
-static int PTRCALL
+static int
entity0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -433,7 +432,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -449,7 +448,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -473,7 +472,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -489,7 +488,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -505,7 +504,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -524,7 +523,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -541,7 +540,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -565,7 +564,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity8(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -581,7 +580,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity9(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -597,7 +596,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
entity10(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -613,7 +612,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
notation0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -629,7 +628,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
notation1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -649,7 +648,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
notation2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -665,7 +664,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
notation3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -682,7 +681,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
notation4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -702,7 +701,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -719,7 +718,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -739,7 +738,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -769,7 +768,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -787,7 +786,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -806,7 +805,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -822,7 +821,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -838,7 +837,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -858,7 +857,7 @@
}
/* default value */
-static int PTRCALL
+static int
attlist8(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -888,7 +887,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
attlist9(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -904,7 +903,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -921,7 +920,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -947,7 +946,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -981,7 +980,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1005,7 +1004,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1022,7 +1021,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1042,7 +1041,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1071,7 +1070,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
element7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1120,7 +1119,7 @@
#ifdef XML_DTD
-static int PTRCALL
+static int
condSect0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
switch (tok) {
@@ -1140,7 +1139,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
condSect1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1157,7 +1156,7 @@
return common(state, tok);
}
-static int PTRCALL
+static int
condSect2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1175,7 +1174,7 @@
#endif /* XML_DTD */
-static int PTRCALL
+static int
declClose(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(ptr);
@@ -1211,7 +1210,7 @@
*
* LCOV_EXCL_START
*/
-static int PTRCALL
+static int
error(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
const ENCODING *enc) {
UNUSED_P(state);
@@ -1223,7 +1222,7 @@
}
/* LCOV_EXCL_STOP */
-static int FASTCALL
+static int
common(PROLOG_STATE *state, int tok) {
#ifdef XML_DTD
if (! state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
diff -Nru expat-2.8.3/expat/lib/xmlrole.h expat-2.9.0/expat/lib/xmlrole.h
--- expat-2.8.3/expat/lib/xmlrole.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmlrole.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2000 Clark Cooper
Copyright (c) 2002 Karl Waclawek
Copyright (c) 2002 Fred L. Drake, Jr.
- Copyright (c) 2017-2025 Sebastian Pipping
+ Copyright (c) 2017-2026 Sebastian Pipping
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -40,10 +40,6 @@
# include "xmltok.h"
-# ifdef __cplusplus
-extern "C" {
-# endif
-
enum {
XML_ROLE_ERROR = -1,
XML_ROLE_NONE = 0,
@@ -112,8 +108,8 @@
};
typedef struct prolog_state {
- int(PTRCALL *handler)(struct prolog_state *state, int tok, const char *ptr,
- const char *end, const ENCODING *enc);
+ int (*handler)(struct prolog_state *state, int tok, const char *ptr,
+ const char *end, const ENCODING *enc);
unsigned level;
int role_none;
# ifdef XML_DTD
@@ -131,8 +127,4 @@
# define XmlTokenRole(state, tok, ptr, end, enc) \
(((state)->handler)(state, tok, ptr, end, enc))
-# ifdef __cplusplus
-}
-# endif
-
#endif /* not XmlRole_INCLUDED */
diff -Nru expat-2.8.3/expat/lib/xmltok.c expat-2.9.0/expat/lib/xmltok.c
--- expat-2.8.3/expat/lib/xmltok.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmltok.c 2026-10-05 15:43:59.000000000 +0000
@@ -27,6 +27,7 @@
Copyright (c) 2025 Alfonso Gregory
Copyright (c) 2026 Nick Begg
Copyright (c) 2026 Kartik Kenchi
+ Copyright (c) 2026 Afonso Januário
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -136,20 +137,20 @@
: ((p)[1] & 0x80) == 0 \
|| ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
-static int PTRFASTCALL
+static int
isNever(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
UNUSED_P(p);
return 0;
}
-static int PTRFASTCALL
+static int
utf8_isName2(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
}
-static int PTRFASTCALL
+static int
utf8_isName3(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
@@ -157,13 +158,13 @@
#define utf8_isName4 isNever
-static int PTRFASTCALL
+static int
utf8_isNmstrt2(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
}
-static int PTRFASTCALL
+static int
utf8_isNmstrt3(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
@@ -171,19 +172,19 @@
#define utf8_isNmstrt4 isNever
-static int PTRFASTCALL
+static int
utf8_isInvalid2(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_INVALID2((const unsigned char *)p);
}
-static int PTRFASTCALL
+static int
utf8_isInvalid3(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_INVALID3((const unsigned char *)p);
}
-static int PTRFASTCALL
+static int
utf8_isInvalid4(const ENCODING *enc, const char *p) {
UNUSED_P(enc);
return UTF8_INVALID4((const unsigned char *)p);
@@ -192,36 +193,20 @@
struct normal_encoding {
ENCODING enc;
unsigned char type[256];
-#ifdef XML_MIN_SIZE
- int(PTRFASTCALL *byteType)(const ENCODING *, const char *);
- int(PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
- int(PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
- int(PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
- int(PTRCALL *charMatches)(const ENCODING *, const char *, int);
-#endif /* XML_MIN_SIZE */
- int(PTRFASTCALL *isName2)(const ENCODING *, const char *);
- int(PTRFASTCALL *isName3)(const ENCODING *, const char *);
- int(PTRFASTCALL *isName4)(const ENCODING *, const char *);
- int(PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
- int(PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
- int(PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
- int(PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
- int(PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
- int(PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+ int (*isName2)(const ENCODING *, const char *);
+ int (*isName3)(const ENCODING *, const char *);
+ int (*isName4)(const ENCODING *, const char *);
+ int (*isNmstrt2)(const ENCODING *, const char *);
+ int (*isNmstrt3)(const ENCODING *, const char *);
+ int (*isNmstrt4)(const ENCODING *, const char *);
+ int (*isInvalid2)(const ENCODING *, const char *);
+ int (*isInvalid3)(const ENCODING *, const char *);
+ int (*isInvalid4)(const ENCODING *, const char *);
};
#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, \
@@ -232,80 +217,33 @@
/* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \
/* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL
-static int FASTCALL checkCharRefNumber(int result);
+#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 PTRFASTCALL
-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 PTRFASTCALL
-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 PTRCALL
-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
@@ -368,7 +306,7 @@
*fromLimRef = fromLim;
}
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
utf8_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
char **toP, const char *toLim) {
bool input_incomplete = false;
@@ -407,7 +345,7 @@
return XML_CONVERT_COMPLETED;
}
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
unsigned short **toP, const unsigned short *toLim) {
enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
@@ -505,7 +443,7 @@
},
STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)};
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
latin1_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
char **toP, const char *toLim) {
UNUSED_P(enc);
@@ -528,7 +466,7 @@
}
}
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
latin1_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
unsigned short **toP, const unsigned short *toLim) {
UNUSED_P(enc);
@@ -563,7 +501,7 @@
},
STANDARD_VTABLE(sb_) NULL_VTABLE};
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
ascii_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
char **toP, const char *toLim) {
UNUSED_P(enc);
@@ -598,7 +536,7 @@
},
STANDARD_VTABLE(sb_) NULL_VTABLE};
-static int PTRFASTCALL
+static int
unicode_byte_type(char hi, char lo) {
switch ((unsigned char)hi) {
/* 0xD800-0xDBFF first 16-bit code unit or high surrogate (W1) */
@@ -625,7 +563,7 @@
}
#define DEFINE_UTF16_TO_UTF8(E) \
- static enum XML_Convert_Result PTRCALL E##toUtf8( \
+ static enum XML_Convert_Result E##toUtf8( \
const ENCODING *enc, const char **fromP, const char *fromLim, \
char **toP, const char *toLim) { \
const char *from = *fromP; \
@@ -702,7 +640,7 @@
}
#define DEFINE_UTF16_TO_UTF16(E) \
- static enum XML_Convert_Result PTRCALL E##toUtf16( \
+ static enum XML_Convert_Result E##toUtf16( \
const ENCODING *enc, const char **fromP, const char *fromLim, \
unsigned short **toP, const unsigned short *toLim) { \
enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
@@ -749,70 +687,38 @@
UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \
UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+/* A 4-byte UTF-16 character is a surrogate pair; byteType only reports BT_LEAD4
+ for a high surrogate, so the pair is invalid unless the second unit is a low
+ surrogate (U+DC00..U+DFFF, i.e. high byte 0xDC..0xDF). */
+#define LITTLE2_IS_INVALID_CHAR(p, n) \
+ ((n) == 4 && ((unsigned char)(p)[3] & 0xFC) != 0xDC)
-#ifdef XML_MIN_SIZE
-
-static int PTRFASTCALL
-little2_byteType(const ENCODING *enc, const char *p) {
- return LITTLE2_BYTE_TYPE(enc, p);
-}
-
-static int PTRFASTCALL
-little2_byteToAscii(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_BYTE_TO_ASCII(p);
-}
-
-static int PTRCALL
-little2_charMatches(const ENCODING *enc, const char *p, int c) {
- UNUSED_P(enc);
- return LITTLE2_CHAR_MATCHES(p, c);
-}
-
-static int PTRFASTCALL
-little2_isNameMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_IS_NAME_CHAR_MINBPC(p);
-}
-
-static int PTRFASTCALL
-little2_isNmstrtMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return LITTLE2_IS_NMSTRT_CHAR_MINBPC(p);
-}
-
-# 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 XML_TOK_IMPL_C
-# include "xmltok_impl.c"
-# undef XML_TOK_IMPL_C
-
-# undef MINBPC
-# undef BYTE_TYPE
-# undef BYTE_TO_ASCII
-# undef CHAR_MATCHES
-# undef IS_NAME_CHAR
-# undef IS_NAME_CHAR_MINBPC
-# undef IS_NMSTRT_CHAR
-# undef IS_NMSTRT_CHAR_MINBPC
-# undef IS_INVALID_CHAR
+#define 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)
-#endif /* not XML_MIN_SIZE */
+#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
#ifdef XML_NS
@@ -828,7 +734,7 @@
# include "asciitab.h"
# include "latin1tab.h"
},
- STANDARD_VTABLE(little2_) NULL_VTABLE};
+ STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)};
#endif
@@ -846,7 +752,7 @@
#undef BT_COLON
#include "latin1tab.h"
},
- STANDARD_VTABLE(little2_) NULL_VTABLE};
+ STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)};
#if BYTEORDER != 4321
@@ -858,7 +764,7 @@
# include "iasciitab.h"
# include "latin1tab.h"
},
- STANDARD_VTABLE(little2_) NULL_VTABLE};
+ STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)};
# endif
@@ -870,7 +776,7 @@
# undef BT_COLON
# include "latin1tab.h"
},
- STANDARD_VTABLE(little2_) NULL_VTABLE};
+ STANDARD_VTABLE(little2_) UTF16_NULL_VTABLE(little2_)};
#endif
@@ -882,70 +788,38 @@
UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
#define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \
UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+/* A 4-byte UTF-16 character is a surrogate pair; byteType only reports BT_LEAD4
+ for a high surrogate, so the pair is invalid unless the second unit is a low
+ surrogate (U+DC00..U+DFFF, i.e. high byte 0xDC..0xDF). */
+#define BIG2_IS_INVALID_CHAR(p, n) \
+ ((n) == 4 && ((unsigned char)(p)[2] & 0xFC) != 0xDC)
-#ifdef XML_MIN_SIZE
-
-static int PTRFASTCALL
-big2_byteType(const ENCODING *enc, const char *p) {
- return BIG2_BYTE_TYPE(enc, p);
-}
-
-static int PTRFASTCALL
-big2_byteToAscii(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_BYTE_TO_ASCII(p);
-}
-
-static int PTRCALL
-big2_charMatches(const ENCODING *enc, const char *p, int c) {
- UNUSED_P(enc);
- return BIG2_CHAR_MATCHES(p, c);
-}
-
-static int PTRFASTCALL
-big2_isNameMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_IS_NAME_CHAR_MINBPC(p);
-}
-
-static int PTRFASTCALL
-big2_isNmstrtMin(const ENCODING *enc, const char *p) {
- UNUSED_P(enc);
- return BIG2_IS_NMSTRT_CHAR_MINBPC(p);
-}
-
-# 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 XML_TOK_IMPL_C
-# include "xmltok_impl.c"
-# undef XML_TOK_IMPL_C
-
-# undef MINBPC
-# undef BYTE_TYPE
-# undef BYTE_TO_ASCII
-# undef CHAR_MATCHES
-# undef IS_NAME_CHAR
-# undef IS_NAME_CHAR_MINBPC
-# undef IS_NMSTRT_CHAR
-# undef IS_NMSTRT_CHAR_MINBPC
-# undef IS_INVALID_CHAR
+#define 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
-#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
@@ -961,7 +835,7 @@
# include "asciitab.h"
# include "latin1tab.h"
},
- STANDARD_VTABLE(big2_) NULL_VTABLE};
+ STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)};
#endif
@@ -979,7 +853,7 @@
#undef BT_COLON
#include "latin1tab.h"
},
- STANDARD_VTABLE(big2_) NULL_VTABLE};
+ STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)};
#if BYTEORDER != 1234
@@ -991,7 +865,7 @@
# include "iasciitab.h"
# include "latin1tab.h"
},
- STANDARD_VTABLE(big2_) NULL_VTABLE};
+ STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)};
# endif
@@ -1003,13 +877,13 @@
# undef BT_COLON
# include "latin1tab.h"
},
- STANDARD_VTABLE(big2_) NULL_VTABLE};
+ STANDARD_VTABLE(big2_) UTF16_NULL_VTABLE(big2_)};
#endif
#undef PREFIX
-static int FASTCALL
+static int
streqci(const char *s1, const char *s2) {
for (;;) {
char c1 = *s1++;
@@ -1030,7 +904,7 @@
return 1;
}
-static void PTRCALL
+static void
initUpdatePosition(const ENCODING *enc, const char *ptr, const char *end,
POSITION *pos) {
UNUSED_P(enc);
@@ -1048,7 +922,7 @@
return buf[0];
}
-static int FASTCALL
+static int
isSpace(int c) {
switch (c) {
case 0x20:
@@ -1154,6 +1028,34 @@
static const char KW_no[] = {ASCII_n, ASCII_o, '\0'};
+static const char KW_1_dot[] = {ASCII_1, ASCII_PERIOD, '\0'};
+
+/* Checks a version pseudo-attribute value against the VersionNum production.
+ XML 1.0 Fourth Edition only allows the literal "1.0", but the Fifth
+ Edition relaxed this to "1." followed by one or more digits, since Expat
+ only implements 1.0 itself but plans to track the Fifth Edition's laxer
+ grammar here so that "1.1" and similar aren't rejected only to have that
+ rejection reverted later. Returns true for a value matching "1.[0-9]+".
+ val/valEnd bound the value itself; valEnd is the upper bound used when
+ decoding the individual characters between them. */
+static bool
+checkXmlDeclVersionNum(const ENCODING *enc, const char *val,
+ const char *valEnd) {
+ if (valEnd - val < 2 * enc->minBytesPerChar
+ || ! XmlNameMatchesAscii(enc, val, val + 2 * enc->minBytesPerChar,
+ KW_1_dot))
+ return false;
+ val += 2 * enc->minBytesPerChar;
+ if (val == valEnd)
+ return false;
+ for (; val != valEnd; val += enc->minBytesPerChar) {
+ int c = toAscii(enc, val, valEnd);
+ if (c < ASCII_0 || c > ASCII_9)
+ return false;
+ }
+ return true;
+}
+
static int
doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, const char *,
const char *),
@@ -1188,6 +1090,15 @@
*badPtr = val;
return 0;
}
+ /* Expat implements XML 1.0 only, so any version outside the "1.0"/"1.x"
+ family is rejected. Following the Fifth Edition's VersionNum
+ production (rather than the Fourth Edition's exact "1.0") avoids
+ rejecting "1.1" now only to have to revert that once Expat tracks
+ the newer edition. */
+ if (! checkXmlDeclVersionNum(enc, val, ptr - enc->minBytesPerChar)) {
+ *badPtr = val;
+ return 0;
+ }
if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
*badPtr = ptr;
return 0;
@@ -1242,7 +1153,7 @@
return 1;
}
-static int FASTCALL
+static int
checkCharRefNumber(int result) {
switch (result >> 8) {
case 0xD8:
@@ -1266,7 +1177,7 @@
return result;
}
-int FASTCALL
+int
XmlUtf8Encode(int c, char *buf) {
enum {
/* minN is minimum legal resulting value for N byte sequence */
@@ -1302,7 +1213,7 @@
return 0; /* LCOV_EXCL_LINE: this case too is eliminated before calling */
}
-int FASTCALL
+int
XmlUtf16Encode(int charNum, unsigned short *buf) {
if (charNum < 0)
return 0;
@@ -1334,7 +1245,7 @@
return sizeof(struct unknown_encoding);
}
-static int PTRFASTCALL
+static int
unknown_isName(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
@@ -1343,7 +1254,7 @@
return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
}
-static int PTRFASTCALL
+static int
unknown_isNmstrt(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
@@ -1352,14 +1263,14 @@
return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
}
-static int PTRFASTCALL
+static int
unknown_isInvalid(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
}
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
unknown_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
char **toP, const char *toLim) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
@@ -1389,7 +1300,7 @@
}
}
-static enum XML_Convert_Result PTRCALL
+static enum XML_Convert_Result
unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
unsigned short **toP, const unsigned short *toLim) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
@@ -1513,7 +1424,7 @@
= {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1,
ASCII_6, ASCII_L, ASCII_E, '\0'};
-static int FASTCALL
+static int
getEncodingIndex(const char *name) {
static const char *const encodingNames[] = {
KW_ISO_8859_1, KW_US_ASCII, KW_UTF_8, KW_UTF_16, KW_UTF_16BE, KW_UTF_16LE,
diff -Nru expat-2.8.3/expat/lib/xmltok.h expat-2.9.0/expat/lib/xmltok.h
--- expat-2.8.3/expat/lib/xmltok.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmltok.h 2026-10-05 15:43:59.000000000 +0000
@@ -41,10 +41,6 @@
# include // uint64_t
-# ifdef __cplusplus
-extern "C" {
-# endif
-
/* The following token may be returned by XmlContentTok */
# define XML_TOK_TRAILING_RSQB \
-5 /* ] or ]] at the end of the scan; might be \
@@ -163,41 +159,40 @@
struct encoding;
typedef struct encoding ENCODING;
-typedef int(PTRCALL *SCANNER)(const ENCODING *, const char *, const char *,
- const char **);
+typedef int (*SCANNER)(const ENCODING *, const char *, const char *,
+ const char **);
enum XML_Convert_Result {
XML_CONVERT_COMPLETED = 0,
XML_CONVERT_INPUT_INCOMPLETE = 1,
- XML_CONVERT_OUTPUT_EXHAUSTED
- = 2 /* and therefore potentially input remaining as well */
+ XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining
+ as well */
};
struct encoding {
SCANNER scanners[XML_N_STATES];
SCANNER literalScanners[XML_N_LITERAL_TYPES];
- int(PTRCALL *nameMatchesAscii)(const ENCODING *, const char *, const char *,
- const char *);
- int(PTRFASTCALL *nameLength)(const ENCODING *, const char *);
- const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
- int(PTRCALL *getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
- ATTRIBUTE *atts);
- int(PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
- int(PTRCALL *predefinedEntityName)(const ENCODING *, const char *,
- const char *);
- void(PTRCALL *updatePosition)(const ENCODING *, const char *ptr,
- const char *end, POSITION *);
- int(PTRCALL *isPublicId)(const ENCODING *enc, const char *ptr,
- const char *end, const char **badPtr);
- enum XML_Convert_Result(PTRCALL *utf8Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim, char **toP,
- const char *toLim);
- enum XML_Convert_Result(PTRCALL *utf16Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim,
- unsigned short **toP,
- const unsigned short *toLim);
+ int (*nameMatchesAscii)(const ENCODING *, const char *, const char *,
+ const char *);
+ int (*nameLength)(const ENCODING *, const char *);
+ const char *(*skipS)(const ENCODING *, const char *);
+ int (*getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
+ ATTRIBUTE *atts);
+ int (*charRefNumber)(const ENCODING *enc, const char *ptr);
+ int (*predefinedEntityName)(const ENCODING *, const char *, const char *);
+ void (*updatePosition)(const ENCODING *, const char *ptr, const char *end,
+ POSITION *);
+ int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr);
+ enum XML_Convert_Result (*utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim, char **toP,
+ const char *toLim);
+ enum XML_Convert_Result (*utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
int minBytesPerChar;
char isUtf8;
char isUtf16;
@@ -297,8 +292,8 @@
const char *name);
const ENCODING *XmlGetUtf8InternalEncoding(void);
const ENCODING *XmlGetUtf16InternalEncoding(void);
-int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
-int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
+int XmlUtf8Encode(int charNumber, char *buf);
+int XmlUtf16Encode(int charNumber, unsigned short *buf);
int XmlSizeOfUnknownEncoding(void);
typedef int(XMLCALL *CONVERTER)(void *userData, const char *p);
@@ -318,8 +313,5 @@
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
ENCODING *XmlInitUnknownEncodingNS(void *mem, const int *table,
CONVERTER convert, void *userData);
-# ifdef __cplusplus
-}
-# endif
#endif /* not XmlTok_INCLUDED */
diff -Nru expat-2.8.3/expat/lib/xmltok_impl.c expat-2.9.0/expat/lib/xmltok_impl.c
--- expat-2.8.3/expat/lib/xmltok_impl.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmltok_impl.c 2026-10-05 15:43:59.000000000 +0000
@@ -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)!
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -10,7 +10,7 @@
Copyright (c) 2000 Clark Cooper
Copyright (c) 2002 Fred L. Drake, Jr.
Copyright (c) 2002-2016 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2018 Benjamin Peterson
Copyright (c) 2018 Anton Maklakov
@@ -18,6 +18,7 @@
Copyright (c) 2020 Boris Kolpackov
Copyright (c) 2022 Martin Ettl
Copyright (c) 2026 Nick Begg
+ Copyright (c) 2026 Kartik Kenchi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -44,10 +45,6 @@
#ifdef XML_TOK_IMPL_C
-# ifndef IS_INVALID_CHAR // i.e. for UTF-16 and XML_MIN_SIZE not defined
-# define IS_INVALID_CHAR(enc, ptr, n) (0)
-# endif
-
# define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
case BT_LEAD##n: \
if (end - ptr < n) \
@@ -144,7 +141,7 @@
/* ptr points to character following "= end)
@@ -430,7 +427,7 @@
/* ptr points to character following "" */
-static int PTRCALL
+static int
PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
REQUIRE_CHAR(enc, ptr, end);
@@ -481,7 +478,7 @@
/* ptr points to character following "" */
-static int PTRCALL
+static int
PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
if (HAS_CHAR(enc, ptr, end)) {
@@ -512,7 +509,7 @@
/* ptr points to character following "" */
-static int PTRCALL
+static int
PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
if (HAS_CHAR(enc, ptr, end)) {
@@ -543,7 +540,7 @@
/* ptr points to character following "&" */
-static int PTRCALL
+static int
PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
REQUIRE_CHAR(enc, ptr, end);
@@ -571,7 +568,7 @@
/* ptr points to character following first character of attribute name */
-static int PTRCALL
+static int
PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
# ifdef XML_NS
@@ -724,7 +721,7 @@
/* ptr points to character following "<" */
-static int PTRCALL
+static int
PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
# ifdef XML_NS
@@ -822,7 +819,7 @@
return XML_TOK_PARTIAL;
}
-static int PTRCALL
+static int
PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
if (ptr >= end)
@@ -922,7 +919,7 @@
/* ptr points to character following "%" */
-static int PTRCALL
+static int
PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
REQUIRE_CHAR(enc, ptr, end);
@@ -952,7 +949,7 @@
return XML_TOK_PARTIAL;
}
-static int PTRCALL
+static int
PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
REQUIRE_CHAR(enc, ptr, end);
@@ -982,7 +979,7 @@
return -XML_TOK_POUND_NAME;
}
-static int PTRCALL
+static int
PREFIX(scanLit)(int open, const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
while (HAS_CHAR(enc, ptr, end)) {
@@ -1016,7 +1013,7 @@
return XML_TOK_PARTIAL;
}
-static int PTRCALL
+static int
PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
int tok;
@@ -1260,7 +1257,7 @@
return -tok;
}
-static int PTRCALL
+static int
PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
const char *start;
@@ -1329,7 +1326,7 @@
return XML_TOK_DATA_CHARS;
}
-static int PTRCALL
+static int
PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
const char *start;
@@ -1396,7 +1393,7 @@
# ifdef XML_DTD
-static int PTRCALL
+static int
PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
int level = 0;
@@ -1448,7 +1445,7 @@
# endif /* XML_DTD */
-static int PTRCALL
+static int
PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
const char **badPtr) {
ptr += MINBPC(enc);
@@ -1508,7 +1505,7 @@
first attsMax attributes are stored in atts.
*/
-static int PTRCALL
+static int
PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
ATTRIBUTE *atts) {
enum { other, inName, inValue } state = inName;
@@ -1601,7 +1598,7 @@
/* not reached */
}
-static int PTRFASTCALL
+static int
PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) {
int result = 0;
/* skip */
@@ -1659,7 +1656,7 @@
return checkCharRefNumber(result);
}
-static int PTRCALL
+static int
PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
const char *end) {
UNUSED_P(enc);
@@ -1713,7 +1710,7 @@
return 0;
}
-static int PTRCALL
+static int
PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
const char *end1, const char *ptr2) {
UNUSED_P(enc);
@@ -1732,7 +1729,7 @@
return ptr1 == end1;
}
-static int PTRFASTCALL
+static int
PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
const char *start = ptr;
for (;;) {
@@ -1762,7 +1759,7 @@
}
}
-static const char *PTRFASTCALL
+static const char *
PREFIX(skipS)(const ENCODING *enc, const char *ptr) {
for (;;) {
switch (BYTE_TYPE(enc, ptr)) {
@@ -1777,7 +1774,7 @@
}
}
-static void PTRCALL
+static void
PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
POSITION *pos) {
while (HAS_CHAR(enc, ptr, end)) {
diff -Nru expat-2.8.3/expat/lib/xmltok_ns.c expat-2.9.0/expat/lib/xmltok_ns.c
--- expat-2.8.3/expat/lib/xmltok_ns.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/lib/xmltok_ns.c 2026-10-05 15:43:59.000000000 +0000
@@ -11,7 +11,7 @@
Copyright (c) 2002 Greg Stein
Copyright (c) 2002 Fred L. Drake, Jr.
Copyright (c) 2002-2006 Karl Waclawek
- Copyright (c) 2017-2021 Sebastian Pipping
+ Copyright (c) 2017-2026 Sebastian Pipping
Copyright (c) 2025 Alfonso Gregory
Licensed under the MIT license:
@@ -64,14 +64,14 @@
&ns(utf8_encoding).enc /* NO_ENC */
};
-static int PTRCALL
+static int
NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE,
ptr, end, nextTokPtr);
}
-static int PTRCALL
+static int
NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
const char **nextTokPtr) {
return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE,
diff -Nru expat-2.8.3/expat/tests/Makefile.am expat-2.9.0/expat/tests/Makefile.am
--- expat-2.8.3/expat/tests/Makefile.am 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/Makefile.am 2026-10-05 15:43:59.000000000 +0000
@@ -49,13 +49,16 @@
common.c \
dummy.c \
handlers.c \
+ hash_tests.c \
memcheck.c \
minicheck.c \
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
@@ -69,13 +72,16 @@
common.h \
dummy.h \
handlers.h \
+ hash_tests.h \
+ memcheck.h \
+ minicheck.h \
misc_tests.h \
ns_tests.h \
nsalloc_tests.h \
- structdata.h \
- minicheck.h \
- memcheck.h \
+ props_tests.h \
README.md \
+ structdata.h \
udiffer.py \
+ xcs_tests.h \
xmltest.log.expected \
xmltest.sh
diff -Nru expat-2.8.3/expat/tests/acc_tests.c expat-2.9.0/expat/tests/acc_tests.c
--- expat-2.8.3/expat/tests/acc_tests.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/acc_tests.c 2026-10-05 15:43:59.000000000 +0000
@@ -359,6 +359,41 @@
}
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 @@
tcase_add_test(tc_accounting, test_accounting_precision);
tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
+ tcase_add_test(tc_accounting,
+ test_billions_laughs_attack_protection_api_float_round_trip);
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
tcase_add_test__ifdef_xml_dtd(tc_accounting,
test_amplification_isolated_external_parser);
diff -Nru expat-2.8.3/expat/tests/acc_tests.h expat-2.9.0/expat/tests/acc_tests.h
--- expat-2.8.3/expat/tests/acc_tests.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/acc_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -42,17 +42,9 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_ACC_TESTS_H
-# define XML_ACC_TESTS_H
+#define XML_ACC_TESTS_H
extern void make_accounting_test_case(Suite *s);
#endif /* XML_ACC_TESTS_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/alloc_tests.c expat-2.9.0/expat/tests/alloc_tests.c
--- expat-2.8.3/expat/tests/alloc_tests.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/alloc_tests.c 2026-10-05 15:43:59.000000000 +0000
@@ -21,6 +21,7 @@
Copyright (c) 2023 Sony Corporation / Snild Dolkow
Copyright (c) 2025 Berkay Eren Ürün
Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Filippo Tedeschi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -563,6 +564,24 @@
}
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 @@
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 @@
}
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 @@
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 @@
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_threshold);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited);
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api);
+ tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api_float_round_trip);
tcase_add_test(tc_alloc, test_mem_api_cycle);
tcase_add_test__if_xml_ge(tc_alloc, test_mem_api_unlimited);
diff -Nru expat-2.8.3/expat/tests/alloc_tests.h expat-2.9.0/expat/tests/alloc_tests.h
--- expat-2.8.3/expat/tests/alloc_tests.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/alloc_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -42,17 +42,9 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_ALLOC_TESTS_H
-# define XML_ALLOC_TESTS_H
+#define XML_ALLOC_TESTS_H
extern void make_alloc_test_case(Suite *s);
#endif /* XML_ALLOC_TESTS_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/basic_tests.c expat-2.9.0/expat/tests/basic_tests.c
--- expat-2.8.3/expat/tests/basic_tests.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/basic_tests.c 2026-10-05 15:43:59.000000000 +0000
@@ -23,6 +23,10 @@
Copyright (c) 2026 Francesco Bertolaccini
Copyright (c) 2026 Matthew Fernandez
Copyright (c) 2026 Kartik Kenchi
+ Copyright (c) 2026 Zeyou Liu
+ Copyright (c) 2026 Afonso Januário
+ Copyright (c) 2026 Braian Plaku
+ Copyright (c) 2026 Filippo Tedeschi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -54,7 +58,8 @@
#include "expat_config.h"
#include
-#include // ULONG_MAX
+#include // PRIu64
+#include // ULONG_MAX
#include
#include
#include
@@ -69,6 +74,7 @@
#include "handlers.h"
#include "siphash.h"
#include "basic_tests.h"
+#include "../lib/xcs.h"
#define EXPAT_TESTS_ASAN 1
@@ -213,7 +219,7 @@
"This triggers the table growth and collides with b2\n"
"\n";
- XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
+ xmlSetHashSalt(g_parser, COLLIDING_HASH_SALT);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
@@ -643,16 +649,15 @@
const char *text = "\n"
"\n"
"\n";
- 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);
}
}
@@ -661,16 +666,16 @@
/* Regression test #2 for SF bug #653180. */
START_TEST(test_column_number_after_parse) {
const char *text = "";
- 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);
}
}
@@ -713,16 +718,15 @@
const char *text = "\n"
" \n"
" "; /* missing */
- 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);
}
}
@@ -733,16 +737,15 @@
const char *text = "\n"
" \n"
" "; /* missing */
- 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);
}
}
@@ -918,9 +921,8 @@
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),
@@ -997,6 +999,50 @@
}
END_TEST
+/* Regression test for GH #967: Expat only implements XML 1.0 Fourth
+ Edition, so a declared version outside the "1.x" family must be
+ rejected rather than silently accepted. A version matching the Fifth
+ Edition's VersionNum production ("1." followed by one or more digits)
+ is accepted even though Expat itself only implements 1.0 Fourth
+ Edition, per GH #967's review thread: rejecting "1.1" now would just
+ have to be reverted once Expat tracks the Fifth Edition, so it's let
+ through rather than blocked twice. */
+START_TEST(test_xmldecl_wrong_version_number) {
+ const char *const badVersions[] = {"2.3", "0.9", "10", "1.", "1", " 1.0 "};
+
+ for (size_t i = 0; i < sizeof(badVersions) / sizeof(badVersions[0]); i++) {
+ char doc[64];
+ snprintf(doc, sizeof(doc), "\n", badVersions[i]);
+ set_subtest("version='%s'", badVersions[i]);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
+ == XML_STATUS_ERROR);
+ assert_true(XML_GetErrorCode(parser) == XML_ERROR_XML_DECL);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+/* GH #967's review pointed out that XML 1.0 Fifth Edition relaxed
+ VersionNum to "1." followed by one or more digits, so versions like
+ "1.1" and "1.123" should parse rather than being rejected. */
+START_TEST(test_xmldecl_accepts_1_x_version) {
+ const char *const goodVersions[] = {"1.1", "1.123"};
+
+ for (size_t i = 0; i < sizeof(goodVersions) / sizeof(goodVersions[0]); i++) {
+ char doc[64];
+ snprintf(doc, sizeof(doc), "\n", goodVersions[i]);
+ set_subtest("version='%s'", goodVersions[i]);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
+ == XML_STATUS_OK);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
/* Regression test for SF bug #584832. */
START_TEST(test_unknown_encoding_internal_entity) {
const char *text = "\n"
@@ -1845,6 +1891,301 @@
}
END_TEST
+// Helper that creates a UTF-16LE copy of UTF-16BE literal input and vice versa
+static char *
+utf16_dup_flipped(const char *text, size_t lenBytes) {
+ assert_true(lenBytes < SIZE_MAX);
+ assert_true(lenBytes % 2 == 0);
+ char *const buffer = malloc(lenBytes + 1);
+ assert_true(buffer != NULL);
+
+ for (size_t i = 0; i < lenBytes; i++) {
+ // This maps 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, 4 -> 5, ..
+ size_t j = i + ((i % 2 == 0) ? +1 : -1);
+ assert_true(j < lenBytes);
+ buffer[j] = text[i];
+ }
+
+ buffer[lenBytes] = '\0';
+
+ return buffer;
+}
+
+/* Tests that invalid combinations of surrogates are detected when decoding
+ UTF-16, both little-endian and big-endian.
+ Previously, a high surrogate not followed by a low surrogate slipped
+ through. Without validation the high would consume the next
+ code unit as a fake low, hiding e.g. a following '<' from the
+ tokenizer. */
+START_TEST(test_utf16_surrogate_pairs) {
+ struct TestCase {
+ const char *idea;
+ const char *content;
+ bool expectedSuccess;
+ };
+
+ struct TestCase testCases[] = {
+ // Group {smallest high - 1}{*}
+ {"{smallest high - 1}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ true},
+ {"{smallest high - 1}{smallest high}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high - 1}{largest high}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high - 1}{smallest low}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high - 1}{largest low}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high - 1}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xD7\xFF"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ true},
+ // Group {smallest high}{*}
+ {"{smallest high}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high}{smallest high}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high}{largest high}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest high}{smallest low}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ true},
+ {"{smallest high}{largest low}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ true},
+ {"{smallest high}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xD8\x00"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ false},
+ // Group {largest high}{*}
+ {"{largest high}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest high}{smallest high}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest high}{largest high}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest high}{smallest low}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ true},
+ {"{largest high}{largest low}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ true},
+ {"{largest high}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xDB\xFF"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ false},
+ // Group {smallest low}{*}
+ {"{smallest low}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest low}{smallest high}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest low}{largest high}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest low}{smallest low}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest low}{largest low}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{smallest low}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xDC\x00"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ false},
+ // Group {largest low}{*}
+ {"{largest low}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low}{smallest high}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low}{largest high}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low}{smallest low}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low}{largest low}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xDF\xFF"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ false},
+ // Group {largest low + 1}{*}
+ {"{largest low + 1}{smallest high - 1}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xD7\xFF"
+ "\0<\0/\0a\0>",
+ true},
+ {"{largest low + 1}{smallest high}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xD8\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low + 1}{largest high}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xDB\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low + 1}{smallest low}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xDC\x00"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low + 1}{largest low}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xDF\xFF"
+ "\0<\0/\0a\0>",
+ false},
+ {"{largest low + 1}{largest low + 1}",
+ "\0<\0a\0>"
+ "\xE0\x00"
+ "\xE0\x00"
+ "\0<\0/\0a\0>",
+ true},
+ };
+
+ for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
+ set_subtest("%s", testCases[i].idea);
+
+ const int lenBytes = /**/ 6 + /*first*/ 2 + /*second*/ 2 + /**/ 8;
+ const bool expectedSuccess = testCases[i].expectedSuccess;
+ const enum XML_Status expectedStatus
+ = (expectedSuccess ? XML_STATUS_OK : XML_STATUS_ERROR);
+
+ const char *const bigEndian = testCases[i].content;
+ char *const littleEndian = utf16_dup_flipped(bigEndian, lenBytes);
+ assert_true(littleEndian != NULL);
+ const char *endianCases[] = {bigEndian, littleEndian};
+
+ for (size_t j = 0; j < sizeof(endianCases) / sizeof(endianCases[0]); j++) {
+ const char *text = endianCases[j];
+
+ assert_true(text[lenBytes] == '\0'); // self-test
+ assert_true((text[0] == '\0')
+ != (text[lenBytes - 1] == '\0')); // self-test
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, text, lenBytes, XML_TRUE)
+ == expectedStatus);
+ if (! expectedSuccess) {
+ assert_true(XML_GetErrorCode(parser) == XML_ERROR_INVALID_TOKEN);
+ }
+
+ XML_ParserFree(parser);
+ }
+
+ free(littleEndian);
+ }
+}
+END_TEST
+
START_TEST(test_bad_cdata) {
struct CaseData {
const char *text;
@@ -2256,6 +2597,57 @@
}
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 = "hello";
+ 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 = "", NULL, NULL};
/* Check hash salt is passed through too */
- XML_SetHashSalt(g_parser, 0x12345678);
+ xmlSetHashSalt(g_parser, 0x12345678);
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
XML_SetUserData(g_parser, &test_data);
XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
@@ -2376,7 +2767,7 @@
!= XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
fail("Failed to reject late foreign DTD setting");
/* Ditto for the hash salt */
- if (XML_SetHashSalt(g_parser, 0x23456789))
+ if (xmlSetHashSalt(g_parser, 0x23456789))
fail("Failed to reject late hash salt change");
/* Now finish the parse */
@@ -2427,7 +2818,7 @@
ExtTest test_data = {"", NULL, NULL};
/* Check hash salt is passed through too */
- XML_SetHashSalt(g_parser, 0x12345678);
+ xmlSetHashSalt(g_parser, 0x12345678);
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
XML_SetUserData(g_parser, &test_data);
XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
@@ -2446,7 +2837,7 @@
!= XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
fail("Failed to reject late foreign DTD setting");
/* Ditto for the hash salt */
- if (XML_SetHashSalt(g_parser, 0x23456789))
+ if (xmlSetHashSalt(g_parser, 0x23456789))
fail("Failed to reject late hash salt change");
/* Now finish the parse */
@@ -2491,7 +2882,7 @@
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");
@@ -2809,6 +3200,79 @@
}
END_TEST
+static void XMLCALL
+check_second_attr_normalization(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ int *const seen_second = userData;
+ UNUSED_P(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 (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 (xcscmp(value, XCS("a b")) != 0)
+ fail("Attribute of non-CDATA type was not whitespace-normalized");
+ }
+}
+
+static int XMLCALL
+external_entity_attr_checker(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *const text = "";
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+
+ XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_default_attr_index_after_dtd_copy) {
+ /* Function storeAtts resolves member .attIndex of structure
+ * NAME_AND_DEFAULT_ATTRIBUTE to tell whether an attribute value needs
+ * whitespace normalization, so function dtdCopy needs to carry that index
+ * over to the copy. Attribute "first" is declared before attribute
+ * "second" so that a mixed-up index resolves to the wrong declaration.
+ */
+ const char *text = "\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "]>\n"
+ "&e;\n";
+ int seen_second = 0;
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+ XML_SetUserData(parser, &seen_second);
+ XML_SetExternalEntityRefHandler(parser, external_entity_attr_checker);
+ XML_SetStartElementHandler(parser, check_second_attr_normalization);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+ if (! seen_second)
+ fail("Attribute \"second\" has not been reported");
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
/* Test reset works correctly in the middle of processing an internal
* entity. Exercises some obscure code in XML_ParserReset().
*/
@@ -3310,6 +3774,46 @@
}
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, "", 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) {
@@ -3440,6 +3944,8 @@
maxbuf = maxbuf / 2;
fprintf(stderr, "Reducing maxbuf to %d...\n", maxbuf);
}
+#else
+ UNUSED_P(maxbuf);
#endif
for (int i = 0; i < num_prefixes; ++i) {
@@ -3463,6 +3969,8 @@
// The limit should be consistent; no prefix should allow us to
// reach above the max buffer size.
assert_true(XML_GetBuffer(parser, maxbuf + 1) == NULL);
+#else
+ UNUSED_P(maxbuf);
#endif
XML_ParserFree(parser);
@@ -3488,16 +3996,16 @@
START_TEST(test_byte_info_at_end) {
const char *text = "";
- 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
@@ -3511,9 +4019,9 @@
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
@@ -3526,11 +4034,12 @@
#define END_ELEMENT ""
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);
@@ -3731,7 +4240,7 @@
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;
@@ -3742,7 +4251,7 @@
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 = "\n"
"\n"
"\n";
@@ -6678,6 +7187,8 @@
tcase_add_test(tc_basic, test_xmldecl_missing_attr);
tcase_add_test(tc_basic, test_xmldecl_missing_value);
tcase_add_test(tc_basic, test_xmldecl_empty_version);
+ tcase_add_test(tc_basic, test_xmldecl_wrong_version_number);
+ tcase_add_test(tc_basic, test_xmldecl_accepts_1_x_version);
tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity);
tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
@@ -6711,12 +7222,14 @@
tcase_add_test(tc_basic, test_long_cdata_utf16);
tcase_add_test(tc_basic, test_multichar_cdata_utf16);
tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
+ tcase_add_test(tc_basic, test_utf16_surrogate_pairs);
tcase_add_test(tc_basic, test_bad_cdata);
tcase_add_test(tc_basic, test_bad_cdata_utf16);
tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
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);
@@ -6737,6 +7250,7 @@
tcase_add_test(tc_basic,
test_duplicate_cdata_attribute_multiple_attlistdecl_3);
tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl);
+ tcase_add_test__if_xml_ge(tc_basic, test_default_attr_index_after_dtd_copy);
tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity);
tcase_add_test(tc_basic, test_resume_invalid_parse);
tcase_add_test(tc_basic, test_resume_resuspended);
@@ -6758,6 +7272,7 @@
tcase_add_test(tc_basic, test_empty_parse);
tcase_add_test(tc_basic, test_negative_len_parse);
tcase_add_test(tc_basic, test_negative_len_parse_buffer);
+ tcase_add_test(tc_basic, test_parse_buffer_exceeds_buffer);
tcase_add_test(tc_basic, test_get_buffer_1);
tcase_add_test(tc_basic, test_get_buffer_2);
#if XML_CONTEXT_BYTES > 0
diff -Nru expat-2.8.3/expat/tests/basic_tests.h expat-2.9.0/expat/tests/basic_tests.h
--- expat-2.8.3/expat/tests/basic_tests.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/basic_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -42,17 +42,9 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_BASIC_TESTS_H
-# define XML_BASIC_TESTS_H
+#define XML_BASIC_TESTS_H
extern void make_basic_test_case(Suite *s);
#endif /* XML_BASIC_TESTS_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/benchmark/benchmark.c expat-2.9.0/expat/tests/benchmark/benchmark.c
--- expat-2.8.3/expat/tests/benchmark/benchmark.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/benchmark/benchmark.c 2026-10-05 15:43:59.000000000 +0000
@@ -8,7 +8,7 @@
Copyright (c) 2003-2006 Karl Waclawek
Copyright (c) 2005-2007 Steven Solie
- Copyright (c) 2017-2025 Sebastian Pipping
+ Copyright (c) 2017-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Licensed under the MIT license:
@@ -40,7 +40,8 @@
# include // close
#endif
-#include // open
+#include // PRIu64
+#include // open
#include
#include
#include // ptrdiff_t
@@ -48,12 +49,6 @@
#include
#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 @@
assert(parseBufferSize <= (ptrdiff_t)bufferSize);
if (! XML_Parse(parser, XMLBufPtr, (int)parseBufferSize, isFinal)) {
fprintf(stderr,
- "error '%" XML_FMT_STR "' at line %" XML_FMT_INT_MOD
- "u character %" XML_FMT_INT_MOD "u\n",
+ "error '%" XML_FMT_STR "' at line %" PRIu64
+ " character %" PRIu64 "\n",
XML_ErrorString(XML_GetErrorCode(parser)),
- XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser));
+ XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser));
free(XMLBuf);
XML_ParserFree(parser);
return 4;
diff -Nru expat-2.8.3/expat/tests/chardata.c expat-2.9.0/expat/tests/chardata.c
--- expat-2.8.3/expat/tests/chardata.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/chardata.c 2026-10-05 15:43:59.000000000 +0000
@@ -9,7 +9,7 @@
Copyright (c) 2002-2004 Fred L. Drake, Jr.
Copyright (c) 2003 Greg Stein
Copyright (c) 2016 Gilles Espinasse
- Copyright (c) 2016-2023 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 Rhodri James
Copyright (c) 2022 Sean McBride
@@ -49,7 +49,7 @@
#include
#include "chardata.h"
-#include "../lib/xcsinc.c"
+#include "../lib/xcs.h"
void
CharData_Init(CharData *storage) {
diff -Nru expat-2.8.3/expat/tests/chardata.h expat-2.9.0/expat/tests/chardata.h
--- expat-2.8.3/expat/tests/chardata.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/chardata.h 2026-10-05 15:43:59.000000000 +0000
@@ -9,7 +9,7 @@
Copyright (c) 2002-2004 Fred L. Drake, Jr.
Copyright (c) 2017 Rhodri James
- Copyright (c) 2017 Sebastian Pipping
+ Copyright (c) 2017-2026 Sebastian Pipping
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -34,10 +34,6 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_CHARDATA_H
# define XML_CHARDATA_H 1
@@ -57,7 +53,3 @@
int CharData_CheckXMLChars(CharData *storage, const XML_Char *s);
#endif /* XML_CHARDATA_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/common.c expat-2.9.0/expat/tests/common.c
--- expat-2.8.3/expat/tests/common.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/common.c 2026-10-05 15:43:59.000000000 +0000
@@ -48,7 +48,8 @@
#include
#include
-#include // for SIZE_MAX
+#include // for PRIu64
+#include // for SIZE_MAX
#include
#include
@@ -188,10 +189,10 @@
char buffer[1024];
enum XML_Error err = XML_GetErrorCode(parser);
snprintf(buffer, sizeof(buffer),
- " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
- "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
- err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser), file, line);
+ " %d: %" XML_FMT_STR " (line %" PRIu64 ", offset %" PRIu64
+ ")\n reported from %s, line %d\n",
+ err, XML_ErrorString(err), XML_GetCurrentLineNumber64(parser),
+ XML_GetCurrentColumnNumber64(parser), file, line);
_fail(file, line, buffer);
}
diff -Nru expat-2.8.3/expat/tests/common.h expat-2.9.0/expat/tests/common.h
--- expat-2.8.3/expat/tests/common.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/common.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -43,42 +43,32 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_COMMON_H
-# define XML_COMMON_H
+#define XML_COMMON_H
-# include "expat_config.h"
-# include "minicheck.h"
-# include "chardata.h"
-
-# ifdef XML_LARGE_SIZE
-# define XML_FMT_INT_MOD "ll"
-# else
-# define XML_FMT_INT_MOD "l"
-# endif
+#include "expat_config.h"
+#include "minicheck.h"
+#include "chardata.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"
-# include
-# 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
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
+# include
+# define XCS(s) _XCS(s)
+# define _XCS(s) L##s
+#else
+# ifdef XML_UNICODE
+# error "No support for UTF-16 character without wchar_t in tests"
# else
-# ifdef XML_UNICODE
-# 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 */
+# define XML_FMT_STR "s"
+# define XCS(s) s
+# endif /* XML_UNICODE */
+#endif /* XML_UNICODE_WCHAR_T */
extern XML_Parser g_parser;
@@ -98,7 +88,7 @@
extern void _xml_failure(XML_Parser parser, const char *file, int line);
-# define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
+#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
extern enum XML_Status _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s,
int len, int isFinal);
@@ -107,8 +97,8 @@
const char *errorMessage, const char *file,
int lineno);
-# define expect_failure(text, errorCode, errorMessage) \
- _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
+#define expect_failure(text, errorCode, errorMessage) \
+ _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
/* Support functions for handlers to collect up character and attribute data.
*/
@@ -116,14 +106,14 @@
extern void _run_character_check(const char *text, const XML_Char *expected,
const char *file, int line);
-# define run_character_check(text, expected) \
- _run_character_check(text, expected, __FILE__, __LINE__)
+#define run_character_check(text, expected) \
+ _run_character_check(text, expected, __FILE__, __LINE__)
extern void _run_attribute_check(const char *text, const XML_Char *expected,
const char *file, int line);
-# define run_attribute_check(text, expected) \
- _run_attribute_check(text, expected, __FILE__, __LINE__)
+#define run_attribute_check(text, expected) \
+ _run_attribute_check(text, expected, __FILE__, __LINE__)
typedef struct ExtTest {
const char *parse_text;
@@ -135,11 +125,11 @@
const XML_Char *expected, const char *file,
int line);
-# define run_ext_character_check(text, test_data, expected) \
- _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
+#define run_ext_character_check(text, test_data, expected) \
+ _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
-# define ALLOC_ALWAYS_SUCCEED (-1)
-# define REALLOC_ALWAYS_SUCCEED (-1)
+#define ALLOC_ALWAYS_SUCCEED (-1)
+#define REALLOC_ALWAYS_SUCCEED (-1)
extern int g_allocation_count;
extern int g_reallocation_count;
@@ -151,7 +141,3 @@
extern char *portable_strndup(const char *s, size_t n);
#endif /* XML_COMMON_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/dummy.h expat-2.9.0/expat/tests/dummy.h
--- expat-2.8.3/expat/tests/dummy.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/dummy.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -42,31 +42,27 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_DUMMY_H
-# define XML_DUMMY_H
+#define XML_DUMMY_H
-# define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
-# define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
-# define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
-# define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
-# define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
-# define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
-# define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
-# define DUMMY_PI_HANDLER_FLAG (1UL << 7)
-# define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
-# define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
-# define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
-# define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
-# define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
-# define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
-# define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
-# define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
-# define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
-# define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
+#define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
+#define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
+#define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
+#define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
+#define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
+#define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
+#define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
+#define DUMMY_PI_HANDLER_FLAG (1UL << 7)
+#define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
+#define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
+#define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
+#define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
+#define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
+#define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
+#define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
+#define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
+#define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
+#define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
extern void init_dummy_handlers(void);
extern unsigned long get_dummy_handler_flags(void);
@@ -146,7 +142,3 @@
int is_parameter_entity);
#endif /* XML_DUMMY_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/handlers.c expat-2.9.0/expat/tests/handlers.c
--- expat-2.8.3/expat/tests/handlers.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/handlers.c 2026-10-05 15:43:59.000000000 +0000
@@ -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 @@
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 @@
int count, id, i;
while (info->name != NULL) {
- if (! xcstrcmp(name, info->name))
+ if (! xcscmp(name, info->name))
break;
info++;
}
@@ -138,14 +140,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
|| entity_value_to_match == NULL) {
return;
}
- if (! xcstrcmp(entityName, entity_name_to_match)) {
+ if (! xcscmp(entityName, entity_name_to_match)) {
/* The cast here is safe because we control the horizontal and
* the vertical, and we therefore know our strings are never
* going to overflow an int.
*/
- if (value_length != (int)xcstrlen(entity_value_to_match)
- || xcstrncmp(value, entity_value_to_match, value_length) != 0) {
+ if (value_length != (int)xcslen(entity_value_to_match)
+ || xcsncmp(value, entity_value_to_match, value_length) != 0) {
entity_match_flag = ENTITY_MATCH_FAIL;
} else {
entity_match_flag = ENTITY_MATCH_SUCCESS;
diff -Nru expat-2.8.3/expat/tests/handlers.h expat-2.9.0/expat/tests/handlers.h
--- expat-2.8.3/expat/tests/handlers.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/handlers.h 2026-10-05 15:43:59.000000000 +0000
@@ -45,16 +45,12 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_HANDLERS_H
-# define XML_HANDLERS_H
+#define XML_HANDLERS_H
-# include "expat_config.h"
+#include "expat_config.h"
-# include "expat.h"
+#include "expat.h"
/* Variable holding the expected handler userData */
extern const void *g_handler_data;
@@ -74,8 +70,8 @@
extern void XMLCALL end_element_event_handler(void *userData,
const XML_Char *name);
-# define STRUCT_START_TAG 0
-# define STRUCT_END_TAG 1
+#define STRUCT_START_TAG 0
+#define STRUCT_END_TAG 1
extern void XMLCALL start_element_event_handler2(void *userData,
const XML_Char *name,
@@ -516,22 +512,21 @@
_handler_record_get(const struct handler_record_list *storage, int index,
const char *file, int line);
-# define handler_record_get(storage, index) \
- _handler_record_get((storage), (index), __FILE__, __LINE__)
+#define handler_record_get(storage, index) \
+ _handler_record_get((storage), (index), __FILE__, __LINE__)
-# define assert_record_handler_called(storage, index, expected_name, \
- expected_arg) \
- do { \
- const struct handler_record_entry *e \
- = handler_record_get(storage, index); \
- assert_true(strcmp(e->name, expected_name) == 0); \
- assert_true(e->arg == (expected_arg)); \
- } while (0)
+#define assert_record_handler_called(storage, index, expected_name, \
+ expected_arg) \
+ do { \
+ const struct handler_record_entry *e = handler_record_get(storage, index); \
+ assert_true(strcmp(e->name, expected_name) == 0); \
+ assert_true(e->arg == (expected_arg)); \
+ } while (0)
/* Entity Declaration Handlers */
-# define ENTITY_MATCH_FAIL (-1)
-# define ENTITY_MATCH_NOT_FOUND (0)
-# define ENTITY_MATCH_SUCCESS (1)
+#define ENTITY_MATCH_FAIL (-1)
+#define ENTITY_MATCH_NOT_FOUND (0)
+#define ENTITY_MATCH_SUCCESS (1)
extern void XMLCALL param_entity_match_handler(
void *userData, const XML_Char *entityName, int is_parameter_entity,
@@ -630,7 +625,3 @@
int len);
#endif /* XML_HANDLERS_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/hash_tests.c expat-2.9.0/expat/tests/hash_tests.c
--- expat-2.8.3/expat/tests/hash_tests.c 1970-01-01 00:00:00.000000000 +0000
+++ expat-2.9.0/expat/tests/hash_tests.c 2026-10-05 15:43:59.000000000 +0000
@@ -0,0 +1,157 @@
+/* Tests related to the hash tables used inside Expat
+__ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping
+ 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 "hash_tests.h"
+
+#include "common.h" // for XCS
+#include "expat.h"
+#include "hash_table.h"
+#include "minicheck.h"
+
+#include
+#include // for memcmp
+
+START_TEST(test_hash_table) {
+ // The test is not doing any parsing, so a single run
+ // (with `g_chunkSize == 0`) is enough
+ if (g_chunkSize != 0)
+ return;
+
+ typedef struct {
+ const XML_Char *name;
+ bool initialized;
+ } NAME_AND_FLAG;
+
+ HASH_TABLE table;
+ XML_Parser parser = XML_ParserCreate(NULL);
+ hashTableInit(&table, parser);
+
+ const XML_Char *const key1 = XCS("key1");
+ const XML_Char *const key2 = XCS("key2");
+ const XML_Char *const key3 = XCS("key1overlap");
+
+ // Self-test: `key3` starts with `key1` but is different from it
+ assert_true(memcmp(key1, key3, keylen(key1)) == 0);
+ assert_true(keyeq(key1, keylen(key1), key3) == XML_FALSE);
+
+ // Test: Look up false for all keys because the table is empty
+ assert_true(lookup(parser, &table, key1, 0) == NULL);
+ assert_true(lookup(parser, &table, key2, 0) == NULL);
+ assert_true(lookup(parser, &table, key3, 0) == NULL);
+
+ // Test: Iteration yields 0 items initially
+ {
+ HASH_TABLE_ITER iter1;
+ hashTableIterInit(&iter1, &table);
+ assert_true(hashTableIterNext(&iter1) == NULL);
+ }
+
+ // Test: Insertion works (including initialization to zero)
+ NAME_AND_FLAG *const inserted1
+ = (NAME_AND_FLAG *)lookup(parser, &table, key1, sizeof(NAME_AND_FLAG));
+ assert_true(inserted1 != NULL);
+ assert_true(inserted1->name == key1);
+ assert_true(! inserted1->initialized);
+
+ // Make it possible to tell the struct apart from a freshly inserted version
+ inserted1->initialized = true;
+
+ // Test: Only present keys can be looked up
+ assert_true(lookup(parser, &table, key1, 0) != NULL);
+ assert_true(lookup(parser, &table, key2, 0) == NULL);
+ assert_true(lookup(parser, &table, key3, 0) == NULL);
+
+ // Test: Key length works without false positives
+ assert_true(lookupWithLength(parser, &table, key3, /*nameLen=*/3, 0) == NULL);
+ assert_true(lookupWithLength(parser, &table, key3, /*nameLen=*/4, 0) != NULL);
+ assert_true(lookupWithLength(parser, &table, key3, /*nameLen=*/5, 0) == NULL);
+
+ // TEST: Lookup does not reset existing entries to zeros
+ NAME_AND_FLAG *const found
+ = (NAME_AND_FLAG *)lookup(parser, &table, key1, sizeof(NAME_AND_FLAG));
+ assert_true(found != NULL);
+ assert_true(found->name == key1);
+ assert_true(found->initialized); // this is key
+
+ // Test: Insertion of a second item works
+ assert_true(lookup(parser, &table, key2, 0) == NULL);
+ assert_true(lookup(parser, &table, key2, sizeof(NAME_AND_FLAG)) != NULL);
+ assert_true(lookup(parser, &table, key2, 0) != NULL);
+
+ // Test: Iteration yields nothing but the two expected items
+ {
+ HASH_TABLE_ITER iter2;
+ hashTableIterInit(&iter2, &table);
+ size_t itemCount = 0;
+ while (true) {
+ const NAME_AND_FLAG *const item
+ = (const NAME_AND_FLAG *)hashTableIterNext(&iter2);
+ if (item == NULL)
+ break;
+
+ itemCount++;
+
+ if (keyeq(key1, keylen(key1), item->name) == XML_TRUE)
+ assert_true(item->initialized);
+ else if (keyeq(key2, keylen(key2), item->name) == XML_TRUE)
+ assert_true(! item->initialized);
+ else
+ fail("unexpected item .name");
+ }
+ assert_true(itemCount == 2);
+ }
+
+ // Test: After clearing all lookups fail
+ hashTableClear(&table);
+ assert_true(lookup(parser, &table, key1, 0) == NULL);
+ assert_true(lookup(parser, &table, key2, 0) == NULL);
+ assert_true(lookup(parser, &table, key3, 0) == NULL);
+
+ // Test: After clearing iteration yields 0 items again
+ {
+ HASH_TABLE_ITER iter3;
+ hashTableIterInit(&iter3, &table);
+ assert_true(hashTableIterNext(&iter3) == NULL);
+ }
+
+ hashTableDestroy(&table);
+ XML_ParserFree(parser);
+}
+END_TEST
+
+void
+make_hash_test_case(Suite *s) {
+ TCase *const tc_hash = tcase_create("hash tests");
+ suite_add_tcase(s, tc_hash);
+ tcase_add_test(tc_hash, test_hash_table);
+}
diff -Nru expat-2.8.3/expat/tests/hash_tests.h expat-2.9.0/expat/tests/hash_tests.h
--- expat-2.8.3/expat/tests/hash_tests.h 1970-01-01 00:00:00.000000000 +0000
+++ expat-2.9.0/expat/tests/hash_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -0,0 +1,41 @@
+/* Tests related to the hash tables used inside Expat
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 2026 Sebastian Pipping
+ 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_HASH_TESTS_H
+#define XML_HASH_TESTS_H
+
+#include "minicheck.h"
+
+extern void make_hash_test_case(Suite *s);
+
+#endif /* XML_HASH_TESTS_H */
diff -Nru expat-2.8.3/expat/tests/memcheck.c expat-2.9.0/expat/tests/memcheck.c
--- expat-2.8.3/expat/tests/memcheck.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/memcheck.c 2026-10-05 15:43:59.000000000 +0000
@@ -10,6 +10,7 @@
Copyright (c) 2017-2023 Sebastian Pipping
Copyright (c) 2022 Sean McBride
Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Leo Camus
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -117,7 +118,7 @@
if (entry->next != NULL)
entry->next->prev = entry->prev;
else
- alloc_tail = entry->next;
+ alloc_tail = entry->prev;
free(entry);
} else {
printf("Attempting to free unallocated memory at %p\n", ptr);
diff -Nru expat-2.8.3/expat/tests/memcheck.h expat-2.9.0/expat/tests/memcheck.h
--- expat-2.8.3/expat/tests/memcheck.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/memcheck.h 2026-10-05 15:43:59.000000000 +0000
@@ -7,8 +7,8 @@
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
- Copyright (c) 2017 Rhodri James
- Copyright (c) 2017 Sebastian Pipping
+ Copyright (c) 2017 Rhodri James
+ Copyright (c) 2017-2026 Sebastian Pipping
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -33,10 +33,6 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_MEMCHECK_H
# define XML_MEMCHECK_H 1
@@ -53,7 +49,3 @@
int tracking_report(void);
#endif /* XML_MEMCHECK_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/minicheck.h expat-2.9.0/expat/tests/minicheck.h
--- expat-2.8.3/expat/tests/minicheck.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/minicheck.h 2026-10-05 15:43:59.000000000 +0000
@@ -14,7 +14,7 @@
Copyright (c) 2004-2006 Fred L. Drake, Jr.
Copyright (c) 2006-2012 Karl Waclawek
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2022 Rhodri James
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
Licensed under the MIT license:
@@ -41,27 +41,15 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_MINICHECK_H
-# define XML_MINICHECK_H
+#define XML_MINICHECK_H
-# define CK_NOFORK 0
-# define CK_FORK 1
+#define CK_NOFORK 0
+#define CK_FORK 1
-# define CK_SILENT 0
-# define CK_NORMAL 1
-# define CK_VERBOSE 2
-
-/* Workaround for Microsoft's compiler and Tru64 Unix systems where the
- C compiler has a working __func__, but the C++ compiler only has a
- working __FUNCTION__. This could be fixed in configure.in, but it's
- not worth it right now. */
-# if defined(_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
-# define __func__ __FUNCTION__
-# endif
+#define CK_SILENT 0
+#define CK_NORMAL 1
+#define CK_VERBOSE 2
/* PRINTF_LIKE has two effects:
1. Make clang's -Wformat-nonliteral stop warning about non-literal format
@@ -69,30 +57,30 @@
2. Make both clang and gcc's -Wformat-nonliteral warn about *callers* of
the annotated function that use a non-literal format string.
*/
-# if defined(__GNUC__)
-# define PRINTF_LIKE(fmtpos, argspos) \
- __attribute__((format(printf, fmtpos, argspos)))
-# else
-# define PRINTF_LIKE(fmtpos, argspos)
-# endif
+#if defined(__GNUC__)
+# define PRINTF_LIKE(fmtpos, argspos) \
+ __attribute__((format(printf, fmtpos, argspos)))
+#else
+# define PRINTF_LIKE(fmtpos, argspos)
+#endif
-# define START_TEST(testname) \
- static void testname(void) { \
- _check_set_test_info(__func__, __FILE__, __LINE__); \
- {
-# define END_TEST \
- } \
- }
+#define START_TEST(testname) \
+ static void testname(void) { \
+ _check_set_test_info(__func__, __FILE__, __LINE__); \
+ {
+#define END_TEST \
+ } \
+ }
void PRINTF_LIKE(1, 2) set_subtest(char const *fmt, ...);
-# define fail(msg) _fail(__FILE__, __LINE__, msg)
-# define assert_true(cond) \
- do { \
- if (! (cond)) { \
- _fail(__FILE__, __LINE__, "check failed: " #cond); \
- } \
- } while (0)
+#define fail(msg) _fail(__FILE__, __LINE__, msg)
+#define assert_true(cond) \
+ do { \
+ if (! (cond)) { \
+ _fail(__FILE__, __LINE__, "check failed: " #cond); \
+ } \
+ } while (0)
typedef void (*tcase_setup_function)(void);
typedef void (*tcase_teardown_function)(void);
@@ -131,11 +119,11 @@
* Prototypes for the actual implementation.
*/
-# if defined(__has_attribute)
-# if __has_attribute(noreturn)
+#if defined(__has_attribute)
+# if __has_attribute(noreturn)
__attribute__((noreturn))
-# endif
# endif
+#endif
void _fail(const char *file, int line, const char *msg);
Suite *suite_create(const char *name);
TCase *tcase_create(const char *name);
@@ -150,7 +138,3 @@
void srunner_free(SRunner *runner);
#endif /* XML_MINICHECK_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/misc_tests.c expat-2.9.0/expat/tests/misc_tests.c
--- expat-2.8.3/expat/tests/misc_tests.c 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/misc_tests.c 2026-10-05 15:43:59.000000000 +0000
@@ -23,6 +23,8 @@
Copyright (c) 2026 Matthew Fernandez
Copyright (c) 2026 Kartik Kenchi
Copyright (c) 2026 Evgeny Kotkov
+ Copyright (c) 2026 Darren Carreras
+ Copyright (c) 2026 Junki Lee
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -54,6 +56,8 @@
#include "expat_config.h"
#include
+#include
+#include
#include
#include "expat.h"
@@ -64,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);
@@ -217,7 +222,7 @@
if (! versions_equal(&read_version, &parsed_version))
fail("Version mismatch");
- if (xcstrcmp(version_text, XCS("expat_2.8.3"))
+ if (xcscmp(version_text, XCS("expat_2.9.0"))
!= 0) /* needs bump on releases */
fail("XML_*_VERSION in expat.h out of sync?\n");
}
@@ -393,8 +398,8 @@
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
@@ -443,13 +448,13 @@
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);
}
@@ -628,22 +633,23 @@
// 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
}
@@ -708,8 +714,8 @@
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
@@ -768,8 +774,9 @@
== 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);
@@ -839,6 +846,120 @@
}
END_TEST
+typedef struct {
+ XML_Parser parser;
+ int converterCallCount;
+ int releaseCallCount;
+} EncodingCallbackData;
+
+static int XMLCALL
+reentrant_encoding_converter(void *userData, const char *s) {
+ EncodingCallbackData *const data = userData;
+ UNUSED_P(s);
+ data->converterCallCount++;
+ forbidden_calls_character_handler(data->parser, NULL, 0);
+ return 'A';
+}
+
+static void XMLCALL
+reentrant_encoding_release(void *userData) {
+ EncodingCallbackData *const data = userData;
+ data->releaseCallCount++;
+ forbidden_calls_character_handler(data->parser, NULL, 0);
+}
+
+static int XMLCALL
+reentrant_encoding_handler(void *userData, const XML_Char *name,
+ XML_Encoding *info) {
+ EncodingCallbackData *const data = userData;
+ UNUSED_P(name);
+
+ for (int i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->map[0x80] = -2; // Route byte 0x80 through the custom converter.
+ info->data = data;
+ info->convert = reentrant_encoding_converter;
+ info->release = reentrant_encoding_release;
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_misc_unknown_encoding_callbacks_protected) {
+ const char *const doc
+ = "\x80\x80";
+ XML_Parser parser = XML_ParserCreate(NULL);
+ EncodingCallbackData data = {parser, 0, 0};
+ XML_SetUnknownEncodingHandler(parser, reentrant_encoding_handler, &data);
+
+ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
+ == XML_STATUS_OK);
+ assert_true(data.converterCallCount > 0);
+ assert_true(data.releaseCallCount == 0); // Released by XML_ParserFree below.
+
+ XML_ParserFree(parser);
+ assert_true(data.releaseCallCount == 1);
+}
+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 = "\n"
+ "\n"
+ " \n"
+ "\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"
@@ -936,6 +1057,11 @@
tcase_add_test(tc_misc, test_misc_no_infinite_loop_issue_1161);
tcase_add_test(tc_misc, test_misc_calls_forbidden_from_handlers);
tcase_add_test(tc_misc, test_misc_resume_parser_forbidden_from_handler);
+ tcase_add_test(tc_misc, test_misc_unknown_encoding_callbacks_protected);
+ tcase_add_test(tc_misc,
+ test_misc_unknown_encoding_release_getter_parser_free);
+ tcase_add_test(tc_misc,
+ test_misc_unknown_encoding_release_getter_parser_reset);
tcase_add_test(tc_misc, test_misc_input_2gb);
tcase_add_test(tc_misc, test_misc_low_surrogate_mozilla_bug_2053153);
}
diff -Nru expat-2.8.3/expat/tests/misc_tests.h expat-2.9.0/expat/tests/misc_tests.h
--- expat-2.8.3/expat/tests/misc_tests.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/misc_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -42,17 +42,9 @@
SPDX-License-Identifier: MIT
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifndef XML_MISC_TESTS_H
-# define XML_MISC_TESTS_H
+#define XML_MISC_TESTS_H
extern void make_miscellaneous_test_case(Suite *s);
#endif /* XML_MISC_TESTS_H */
-
-#ifdef __cplusplus
-}
-#endif
diff -Nru expat-2.8.3/expat/tests/ns_tests.h expat-2.9.0/expat/tests/ns_tests.h
--- expat-2.8.3/expat/tests/ns_tests.h 2026-08-10 21:49:33.000000000 +0000
+++ expat-2.9.0/expat/tests/ns_tests.h 2026-10-05 15:43:59.000000000 +0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2022 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James