This is an automated email from the ASF dual-hosted git repository. ardovm pushed a commit to branch AOO42X in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 804fb957cd5ee43efe8001da727033b297a199d8 Author: Arrigo Marchiori <ard...@yahoo.it> AuthorDate: Wed Mar 9 21:11:35 2022 +0100 Produce expat-2.2.13, derived from 2.4.7 (cherry picked from commit 84b800346361a798f2dacc3e03dc6b4a6358f3cf) --- main/expat/expat-2.2.10.patch | 888 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 786 insertions(+), 102 deletions(-) diff --git a/main/expat/expat-2.2.10.patch b/main/expat/expat-2.2.10.patch index b6413d6..0de7936 100644 --- a/main/expat/expat-2.2.10.patch +++ b/main/expat/expat-2.2.10.patch @@ -360,7 +360,7 @@ diff -ru misc/expat-2.2.10/doc/xmlwf.xml misc/build/expat-2.2.10/doc/xmlwf.xml </para> diff -ru misc/expat-2.2.10/lib/expat.h misc/build/expat-2.2.10/lib/expat.h --- misc/expat-2.2.10/lib/expat.h 2020-10-03 17:14:57.000000000 +0200 -+++ misc/build/expat-2.2.10/lib/expat.h 2022-03-05 12:25:27.583396678 +0100 ++++ misc/build/expat-2.2.10/lib/expat.h 2022-03-09 20:25:36.712575539 +0100 @@ -115,7 +115,10 @@ XML_ERROR_RESERVED_PREFIX_XMLNS, XML_ERROR_RESERVED_NAMESPACE_URI, @@ -408,7 +408,7 @@ diff -ru misc/expat-2.2.10/lib/expat.h misc/build/expat-2.2.10/lib/expat.h #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 2 -#define XML_MICRO_VERSION 10 -+#define XML_MICRO_VERSION 12 ++#define XML_MICRO_VERSION 13 #ifdef __cplusplus } @@ -520,7 +520,7 @@ diff -ru misc/expat-2.2.10/lib/Makefile.in misc/build/expat-2.2.10/lib/Makefile. srcdir = @srcdir@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c --- misc/expat-2.2.10/lib/xmlparse.c 2020-10-03 17:14:57.000000000 +0200 -+++ misc/build/expat-2.2.10/lib/xmlparse.c 2022-03-05 12:25:27.583396678 +0100 ++++ misc/build/expat-2.2.10/lib/xmlparse.c 2022-03-09 20:25:36.712575539 +0100 @@ -47,6 +47,7 @@ #include <limits.h> /* UINT_MAX */ #include <stdio.h> /* fprintf */ @@ -540,6 +540,15 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c #elif defined(HAVE_EXPAT_CONFIG_H) # include <expat_config.h> #endif /* ndef _WIN32 */ +@@ -116,7 +121,7 @@ + * BSD / macOS (including <10.7) (arc4random): HAVE_ARC4RANDOM, \ + * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \ + * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \ +- * Linux (including <3.17) / BSD / macOS (including <10.7) (/dev/urandom): XML_DEV_URANDOM, \ ++ * Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \ + * Windows >=Vista (rand_s): _WIN32. \ + \ + If insist on not using any of these, bypass this error by defining \ @@ -382,6 +387,31 @@ XML_Bool betweenDecl; /* WFC: PE Between Declarations */ } OPEN_INTERNAL_ENTITY; @@ -672,7 +681,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c }; #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s))) -@@ -640,6 +708,7 @@ +@@ -640,9 +708,11 @@ XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) { XML_Char tmp[2]; *tmp = nsSep; @@ -680,7 +689,11 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c return XML_ParserCreate_MM(encodingName, NULL, tmp); } -@@ -809,9 +878,8 @@ ++// "xml=http://www.w3.org/XML/1998/namespace" + static const XML_Char implicitContext[] + = {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, + ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, +@@ -809,9 +879,8 @@ static unsigned long ENTROPY_DEBUG(const char *label, unsigned long entropy) { @@ -692,7 +705,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy)); } return entropy; -@@ -855,7 +923,7 @@ +@@ -855,7 +924,7 @@ return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647); } else { return ENTROPY_DEBUG("fallback(8)", @@ -701,7 +714,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } #endif } -@@ -1073,6 +1141,18 @@ +@@ -1073,6 +1142,18 @@ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #endif parser->m_hash_secret_salt = 0; @@ -720,7 +733,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } /* moves list of bindings to m_freeBindingList */ -@@ -1255,6 +1335,7 @@ +@@ -1255,6 +1336,7 @@ if (parser->m_ns) { XML_Char tmp[2]; *tmp = parser->m_namespaceSeparator; @@ -728,7 +741,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); } else { parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); -@@ -1893,6 +1974,12 @@ +@@ -1893,6 +1975,12 @@ parser->m_errorCode = XML_ERROR_FINISHED; return XML_STATUS_ERROR; case XML_INITIALIZED: @@ -741,7 +754,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (parser->m_parentParser == NULL && ! startParsing(parser)) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return XML_STATUS_ERROR; -@@ -1971,6 +2058,11 @@ +@@ -1971,6 +2059,11 @@ keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer); if (keep > XML_CONTEXT_BYTES) keep = XML_CONTEXT_BYTES; @@ -753,7 +766,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c neededSize += keep; #endif /* defined XML_CONTEXT_BYTES */ if (neededSize -@@ -2337,6 +2429,13 @@ +@@ -2337,6 +2430,13 @@ /* Added in 2.2.5. */ case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */ return XML_L("invalid argument"); @@ -767,7 +780,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } return NULL; } -@@ -2373,41 +2472,75 @@ +@@ -2373,41 +2473,75 @@ const XML_Feature *XMLCALL XML_GetFeatureList(void) { @@ -858,7 +871,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c /* Initially tag->rawName always points into the parse buffer; for those TAG instances opened while the current parse buffer was processed, and not yet closed, we need to store tag->rawName in a more -@@ -2419,6 +2552,7 @@ +@@ -2419,6 +2553,7 @@ while (tag) { int bufSize; int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); @@ -866,7 +879,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c char *rawNameBuf = tag->buf + nameLen; /* Stop if already stored. Since m_tagStack is a stack, we can stop at the first entry that has already been copied; everything -@@ -2430,7 +2564,11 @@ +@@ -2430,7 +2565,11 @@ /* For re-use purposes we need to ensure that the size of tag->buf is a multiple of sizeof(XML_Char). */ @@ -879,7 +892,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (bufSize > tag->bufEnd - tag->buf) { char *temp = (char *)REALLOC(parser, tag->buf, bufSize); if (temp == NULL) -@@ -2460,9 +2598,9 @@ +@@ -2460,9 +2599,9 @@ static enum XML_Error PTRCALL contentProcessor(XML_Parser parser, const char *start, const char *end, const char **endPtr) { @@ -892,7 +905,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result == XML_ERROR_NONE) { if (! storeRawNames(parser)) return XML_ERROR_NO_MEMORY; -@@ -2487,6 +2625,14 @@ +@@ -2487,6 +2626,14 @@ int tok = XmlContentTok(parser->m_encoding, start, end, &next); switch (tok) { case XML_TOK_BOM: @@ -907,7 +920,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c /* If we are at the end of the buffer, this would cause the next stage, i.e. externalEntityInitProcessor3, to pass control directly to doContent (by detecting XML_TOK_NONE) without processing any xml text -@@ -2524,6 +2670,10 @@ +@@ -2524,6 +2671,10 @@ const char *next = start; /* XmlContentTok doesn't always set the last arg */ parser->m_eventPtr = start; tok = XmlContentTok(parser->m_encoding, start, end, &next); @@ -918,7 +931,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser->m_eventEndPtr = next; switch (tok) { -@@ -2565,7 +2715,8 @@ +@@ -2565,7 +2716,8 @@ const char *end, const char **endPtr) { enum XML_Error result = doContent(parser, 1, parser->m_encoding, start, end, endPtr, @@ -928,7 +941,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result == XML_ERROR_NONE) { if (! storeRawNames(parser)) return XML_ERROR_NO_MEMORY; -@@ -2576,7 +2727,7 @@ +@@ -2576,7 +2728,7 @@ static enum XML_Error doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, const char *s, const char *end, const char **nextPtr, @@ -937,7 +950,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c /* save one level of indirection */ DTD *const dtd = parser->m_dtd; -@@ -2594,6 +2745,17 @@ +@@ -2594,6 +2746,17 @@ for (;;) { const char *next = s; /* XmlContentTok doesn't always set the last arg */ int tok = XmlContentTok(enc, s, end, &next); @@ -955,7 +968,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c *eventEndPP = next; switch (tok) { case XML_TOK_TRAILING_CR: -@@ -2649,6 +2811,14 @@ +@@ -2649,6 +2812,14 @@ XML_Char ch = (XML_Char)XmlPredefinedEntityName( enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (ch) { @@ -970,7 +983,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (parser->m_characterDataHandler) parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1); else if (parser->m_defaultHandler) -@@ -2767,7 +2937,7 @@ +@@ -2767,7 +2938,7 @@ } tag->name.str = (XML_Char *)tag->buf; *toPtr = XML_T('\0'); @@ -979,7 +992,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result) return result; if (parser->m_startElementHandler) -@@ -2791,7 +2961,8 @@ +@@ -2791,7 +2962,8 @@ if (! name.str) return XML_ERROR_NO_MEMORY; poolFinish(&parser->m_tempPool); @@ -989,7 +1002,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result != XML_ERROR_NONE) { freeBindings(parser, bindings); return result; -@@ -2926,7 +3097,7 @@ +@@ -2926,7 +3098,7 @@ /* END disabled code */ else if (parser->m_defaultHandler) reportDefault(parser, enc, s, next); @@ -998,7 +1011,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result != XML_ERROR_NONE) return result; else if (! next) { -@@ -3055,7 +3226,8 @@ +@@ -3055,7 +3227,8 @@ */ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, @@ -1008,7 +1021,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c DTD *const dtd = parser->m_dtd; /* save one level of indirection */ ELEMENT_TYPE *elementType; int nDefaultAtts; -@@ -3087,13 +3259,38 @@ +@@ -3087,13 +3260,38 @@ /* get the attributes from the tokenizer */ n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts); @@ -1047,7 +1060,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts, parser->m_attsSize * sizeof(ATTRIBUTE)); if (temp == NULL) { -@@ -3102,6 +3299,17 @@ +@@ -3102,6 +3300,17 @@ } parser->m_atts = temp; #ifdef XML_ATTR_INFO @@ -1065,7 +1078,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo)); if (temp2 == NULL) { -@@ -3165,7 +3373,7 @@ +@@ -3165,7 +3374,7 @@ /* normalize the attribute value */ result = storeAttributeValue( parser, enc, isCdata, parser->m_atts[i].valuePtr, @@ -1074,7 +1087,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result) return result; appAtts[attIndex] = poolStart(&parser->m_tempPool); -@@ -3240,8 +3448,16 @@ +@@ -3240,8 +3449,16 @@ if (nPrefixes) { int j; /* hash table index */ unsigned long version = parser->m_nsAttsVersion; @@ -1093,7 +1106,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c /* size of hash table must be at least 2 * (# of prefixed attributes) */ if ((nPrefixes << 1) >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */ -@@ -3251,7 +3467,28 @@ +@@ -3251,7 +3468,28 @@ ; if (parser->m_nsAttsPower < 3) parser->m_nsAttsPower = 3; @@ -1123,7 +1136,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT)); if (! temp) { -@@ -3409,9 +3646,31 @@ +@@ -3409,9 +3647,31 @@ tagNamePtr->prefixLen = prefixLen; for (i = 0; localPart[i++];) ; /* i includes null terminator */ @@ -1155,25 +1168,170 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char)); if (! uri) return XML_ERROR_NO_MEMORY; -@@ -3491,6 +3750,17 @@ +@@ -3436,12 +3696,124 @@ + return XML_ERROR_NONE; + } + ++static XML_Bool ++is_rfc3986_uri_char(XML_Char candidate) { ++ // For the RFC 3986 ANBF grammar see ++ // https://datatracker.ietf.org/doc/html/rfc3986#appendix-A ++ ++ switch (candidate) { ++ // From rule "ALPHA" (uppercase half) ++ case 'A': ++ case 'B': ++ case 'C': ++ case 'D': ++ case 'E': ++ case 'F': ++ case 'G': ++ case 'H': ++ case 'I': ++ case 'J': ++ case 'K': ++ case 'L': ++ case 'M': ++ case 'N': ++ case 'O': ++ case 'P': ++ case 'Q': ++ case 'R': ++ case 'S': ++ case 'T': ++ case 'U': ++ case 'V': ++ case 'W': ++ case 'X': ++ case 'Y': ++ case 'Z': ++ ++ // From rule "ALPHA" (lowercase half) ++ case 'a': ++ case 'b': ++ case 'c': ++ case 'd': ++ case 'e': ++ case 'f': ++ case 'g': ++ case 'h': ++ case 'i': ++ case 'j': ++ case 'k': ++ case 'l': ++ case 'm': ++ case 'n': ++ case 'o': ++ case 'p': ++ case 'q': ++ case 'r': ++ case 's': ++ case 't': ++ case 'u': ++ case 'v': ++ case 'w': ++ case 'x': ++ case 'y': ++ case 'z': ++ ++ // From rule "DIGIT" ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ ++ // From rule "pct-encoded" ++ case '%': ++ ++ // From rule "unreserved" ++ case '-': ++ case '.': ++ case '_': ++ case '~': ++ ++ // From rule "gen-delims" ++ case ':': ++ case '/': ++ case '?': ++ case '#': ++ case '[': ++ case ']': ++ case '@': ++ ++ // From rule "sub-delims" ++ case '!': ++ case '$': ++ case '&': ++ case '\'': ++ case '(': ++ case ')': ++ case '*': ++ case '+': ++ case ',': ++ case ';': ++ case '=': ++ return XML_TRUE; ++ ++ default: ++ return XML_FALSE; ++ } ++} ++ + /* addBinding() overwrites the value of prefix->binding without checking. + Therefore one must keep track of the old value outside of addBinding(). + */ + static enum XML_Error + addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr) { ++ // "http://www.w3.org/XML/1998/namespace" + static const XML_Char xmlNamespace[] + = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, + ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, +@@ -3452,6 +3824,7 @@ + ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, + ASCII_e, '\0'}; + static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1; ++ // "http://www.w3.org/2000/xmlns/" + static const XML_Char xmlnsNamespace[] + = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, + ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, +@@ -3491,6 +3864,29 @@ if (! mustBeXML && isXMLNS && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) isXMLNS = XML_FALSE; + -+ // NOTE: While Expat does not validate namespace URIs against RFC 3986, -+ // we have to at least make sure that the XML processor on top of -+ // Expat (that is splitting tag names by namespace separator into -+ // 2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused -+ // by an attacker putting additional namespace separator characters -+ // into namespace declarations. That would be ambiguous and not to -+ // be expected. -+ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) { ++ // NOTE: While Expat does not validate namespace URIs against RFC 3986 ++ // today (and is not REQUIRED to do so with regard to the XML 1.0 ++ // namespaces specification) we have to at least make sure, that ++ // the application on top of Expat (that is likely splitting expanded ++ // element names ("qualified names") of form ++ // "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces ++ // in its element handler code) cannot be confused by an attacker ++ // putting additional namespace separator characters into namespace ++ // declarations. That would be ambiguous and not to be expected. ++ // ++ // While the HTML API docs of function XML_ParserCreateNS have been ++ // advising against use of a namespace separator character that can ++ // appear in a URI for >20 years now, some widespread applications ++ // are using URI characters (':' (colon) in particular) for a ++ // namespace separator, in practice. To keep these applications ++ // functional, we only reject namespaces URIs containing the ++ // application-chosen namespace separator if the chosen separator ++ // is a non-URI character with regard to RFC 3986. ++ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator) ++ && ! is_rfc3986_uri_char(uri[len])) { + return XML_ERROR_SYNTAX; + } } isXML = isXML && len == xmlLen; isXMLNS = isXMLNS && len == xmlnsLen; -@@ -3507,7 +3777,24 @@ +@@ -3507,7 +3903,24 @@ if (parser->m_freeBindingList) { b = parser->m_freeBindingList; if (len > b->uriAlloc) { @@ -1199,7 +1357,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (temp == NULL) return XML_ERROR_NO_MEMORY; -@@ -3519,6 +3806,21 @@ +@@ -3519,6 +3932,21 @@ b = (BINDING *)MALLOC(parser, sizeof(BINDING)); if (! b) return XML_ERROR_NO_MEMORY; @@ -1221,7 +1379,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c b->uri = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (! b->uri) { -@@ -3556,7 +3858,7 @@ +@@ -3556,7 +3984,7 @@ const char **endPtr) { enum XML_Error result = doCdataSection(parser, parser->m_encoding, &start, end, endPtr, @@ -1230,7 +1388,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result != XML_ERROR_NONE) return result; if (start) { -@@ -3576,7 +3878,8 @@ +@@ -3576,7 +4004,8 @@ */ static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr, @@ -1240,7 +1398,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c const char *s = *startPtr; const char **eventPP; const char **eventEndPP; -@@ -3594,6 +3897,12 @@ +@@ -3594,6 +4023,12 @@ for (;;) { const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */ int tok = XmlCdataSectionTok(enc, s, end, &next); @@ -1253,7 +1411,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c *eventEndPP = next; switch (tok) { case XML_TOK_CDATA_SECT_CLOSE: -@@ -3738,6 +4047,13 @@ +@@ -3738,6 +4173,13 @@ *eventPP = s; *startPtr = NULL; tok = XmlIgnoreSectionTok(enc, s, end, &next); @@ -1267,7 +1425,16 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c *eventEndPP = next; switch (tok) { case XML_TOK_IGNORE_SECT: -@@ -3822,6 +4138,15 @@ +@@ -3787,7 +4229,7 @@ + const char *s; + #ifdef XML_UNICODE + char encodingBuf[128]; +- /* See comments abount `protoclEncodingName` in parserInit() */ ++ /* See comments about `protocolEncodingName` in parserInit() */ + if (! parser->m_protocolEncodingName) + s = NULL; + else { +@@ -3822,6 +4264,15 @@ const char *versionend; const XML_Char *storedversion = NULL; int standalone = -1; @@ -1283,7 +1450,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)( isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr, &version, &versionend, &encodingName, &newEncoding, &standalone)) { -@@ -3971,6 +4296,10 @@ +@@ -3971,6 +4422,10 @@ for (;;) { tok = XmlPrologTok(parser->m_encoding, start, end, &next); @@ -1294,7 +1461,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser->m_eventEndPtr = next; if (tok <= 0) { if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) { -@@ -3989,7 +4318,8 @@ +@@ -3989,7 +4444,8 @@ break; } /* found end of entity value - can store it now */ @@ -1304,7 +1471,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } else if (tok == XML_TOK_XML_DECL) { enum XML_Error result; result = processXmlDecl(parser, 0, start, next); -@@ -4016,6 +4346,14 @@ +@@ -4016,6 +4472,14 @@ */ else if (tok == XML_TOK_BOM && next == end && ! parser->m_parsingStatus.finalBuffer) { @@ -1319,7 +1486,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c *nextPtr = next; return XML_ERROR_NONE; } -@@ -4058,16 +4396,24 @@ +@@ -4058,16 +4522,24 @@ } /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. However, when parsing an external subset, doProlog will not accept a BOM @@ -1346,7 +1513,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } static enum XML_Error PTRCALL -@@ -4080,6 +4426,9 @@ +@@ -4080,6 +4552,9 @@ for (;;) { tok = XmlPrologTok(enc, start, end, &next); @@ -1356,7 +1523,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (tok <= 0) { if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) { *nextPtr = s; -@@ -4097,7 +4446,7 @@ +@@ -4097,7 +4572,7 @@ break; } /* found end of entity value - can store it now */ @@ -1365,7 +1532,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } start = next; } -@@ -4111,13 +4460,14 @@ +@@ -4111,13 +4586,14 @@ const char *next = s; int tok = XmlPrologTok(parser->m_encoding, s, end, &next); return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, @@ -1382,7 +1549,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c #ifdef XML_DTD static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'}; #endif /* XML_DTD */ -@@ -4144,6 +4494,10 @@ +@@ -4144,6 +4620,10 @@ static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'}; static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'}; @@ -1393,7 +1560,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c /* save one level of indirection */ DTD *const dtd = parser->m_dtd; -@@ -4208,6 +4562,19 @@ +@@ -4208,6 +4688,19 @@ } } role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc); @@ -1413,7 +1580,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c switch (role) { case XML_ROLE_XML_DECL: { enum XML_Error result = processXmlDecl(parser, 0, s, next); -@@ -4483,7 +4850,8 @@ +@@ -4483,7 +4976,8 @@ const XML_Char *attVal; enum XML_Error result = storeAttributeValue( parser, enc, parser->m_declAttributeIsCdata, @@ -1423,7 +1590,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result) return result; attVal = poolStart(&dtd->pool); -@@ -4516,8 +4884,9 @@ +@@ -4516,8 +5010,9 @@ break; case XML_ROLE_ENTITY_VALUE: if (dtd->keepProcessing) { @@ -1435,7 +1602,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (parser->m_declEntity) { parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool); parser->m_declEntity->textLen -@@ -4776,7 +5145,13 @@ +@@ -4776,7 +5271,13 @@ if (parser->m_prologState.level >= parser->m_groupSize) { if (parser->m_groupSize) { { @@ -1450,7 +1617,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser, parser->m_groupConnector, parser->m_groupSize *= 2); if (new_connector == NULL) { parser->m_groupSize /= 2; -@@ -4786,7 +5161,18 @@ +@@ -4786,7 +5287,18 @@ } if (dtd->scaffIndex) { @@ -1470,7 +1637,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); if (new_scaff_index == NULL) return XML_ERROR_NO_MEMORY; -@@ -4907,12 +5293,15 @@ +@@ -4907,12 +5419,15 @@ if (parser->m_externalEntityRefHandler) { dtd->paramEntityRead = XML_FALSE; entity->open = XML_TRUE; @@ -1486,7 +1653,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; handleDefault = XML_FALSE; if (! dtd->paramEntityRead) { -@@ -4991,7 +5380,7 @@ +@@ -4991,7 +5506,7 @@ if (dtd->in_eldecl) { ELEMENT_TYPE *el; const XML_Char *name; @@ -1495,7 +1662,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c const char *nxt = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar); int myindex = nextScaffoldPart(parser); -@@ -5007,7 +5396,13 @@ +@@ -5007,7 +5522,13 @@ nameLen = 0; for (; name[nameLen++];) ; @@ -1510,7 +1677,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (parser->m_elementDeclHandler) handleDefault = XML_FALSE; } -@@ -5110,6 +5505,13 @@ +@@ -5110,6 +5631,13 @@ for (;;) { const char *next = NULL; int tok = XmlPrologTok(parser->m_encoding, s, end, &next); @@ -1524,7 +1691,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c parser->m_eventEndPtr = next; switch (tok) { /* report partial linebreak - it might be the last token */ -@@ -5183,6 +5585,9 @@ +@@ -5183,6 +5711,9 @@ return XML_ERROR_NO_MEMORY; } entity->open = XML_TRUE; @@ -1534,7 +1701,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->processed = 0; openEntity->next = parser->m_openInternalEntities; parser->m_openInternalEntities = openEntity; -@@ -5201,17 +5606,22 @@ +@@ -5201,17 +5732,22 @@ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, @@ -1559,7 +1726,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; parser->m_openInternalEntities = openEntity->next; /* put openEntity back in list of free instances */ -@@ -5244,12 +5654,13 @@ +@@ -5244,12 +5780,13 @@ int tok = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next); result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd, @@ -1575,7 +1742,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result != XML_ERROR_NONE) return result; -@@ -5258,6 +5669,9 @@ +@@ -5258,6 +5795,9 @@ entity->processed = (int)(next - (const char *)entity->textPtr); return result; } else { @@ -1585,7 +1752,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; parser->m_openInternalEntities = openEntity->next; /* put openEntity back in list of free instances */ -@@ -5271,7 +5685,8 @@ +@@ -5271,7 +5811,8 @@ parser->m_processor = prologProcessor; tok = XmlPrologTok(parser->m_encoding, s, end, &next); return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr, @@ -1595,7 +1762,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } else #endif /* XML_DTD */ { -@@ -5279,7 +5694,8 @@ +@@ -5279,7 +5820,8 @@ /* see externalEntityContentProcessor vs contentProcessor */ return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, s, end, nextPtr, @@ -1605,7 +1772,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c } } -@@ -5294,9 +5710,10 @@ +@@ -5294,9 +5836,10 @@ static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, @@ -1618,7 +1785,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (result) return result; if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) -@@ -5308,11 +5725,23 @@ +@@ -5308,11 +5851,23 @@ static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, @@ -1644,7 +1811,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c switch (tok) { case XML_TOK_NONE: return XML_ERROR_NONE; -@@ -5372,6 +5801,14 @@ +@@ -5372,6 +5927,14 @@ XML_Char ch = (XML_Char)XmlPredefinedEntityName( enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar); if (ch) { @@ -1659,7 +1826,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (! poolAppendChar(pool, ch)) return XML_ERROR_NO_MEMORY; break; -@@ -5449,9 +5886,16 @@ +@@ -5449,9 +6012,16 @@ enum XML_Error result; const XML_Char *textEnd = entity->textPtr + entity->textLen; entity->open = XML_TRUE; @@ -1677,7 +1844,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; if (result) return result; -@@ -5481,13 +5925,16 @@ +@@ -5481,13 +6051,16 @@ static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc, @@ -1695,7 +1862,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c #endif /* XML_DTD */ /* never return Null for the value argument in EntityDeclHandler, since this would indicate an external entity; therefore we -@@ -5498,8 +5945,19 @@ +@@ -5498,8 +6071,19 @@ } for (;;) { @@ -1716,7 +1883,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c switch (tok) { case XML_TOK_PARAM_ENTITY_REF: #ifdef XML_DTD -@@ -5535,13 +5993,16 @@ +@@ -5535,13 +6119,16 @@ if (parser->m_externalEntityRefHandler) { dtd->paramEntityRead = XML_FALSE; entity->open = XML_TRUE; @@ -1733,7 +1900,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; if (! dtd->paramEntityRead) dtd->keepProcessing = dtd->standalone; -@@ -5549,9 +6010,12 @@ +@@ -5549,9 +6136,12 @@ dtd->keepProcessing = dtd->standalone; } else { entity->open = XML_TRUE; @@ -1747,7 +1914,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c entity->open = XML_FALSE; if (result) goto endEntityValue; -@@ -5784,7 +6248,25 @@ +@@ -5784,7 +6374,25 @@ } } else { DEFAULT_ATTRIBUTE *temp; @@ -1774,7 +1941,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); if (temp == NULL) -@@ -6435,10 +6917,26 @@ +@@ -6435,10 +7043,26 @@ /* check for overflow (table is half full) */ if (table->used >> (table->power - 1)) { unsigned char newPower = table->power + 1; @@ -1805,7 +1972,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c if (! newV) return NULL; memset(newV, 0, tsize); -@@ -6786,6 +7284,20 @@ +@@ -6786,6 +7410,20 @@ if (dtd->scaffCount >= dtd->scaffSize) { CONTENT_SCAFFOLD *temp; if (dtd->scaffold) { @@ -1826,7 +1993,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c temp = (CONTENT_SCAFFOLD *)REALLOC( parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); if (temp == NULL) -@@ -6817,55 +7329,130 @@ +@@ -6817,55 +7455,134 @@ return next; } @@ -1864,6 +2031,10 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c - static XML_Content * build_model(XML_Parser parser) { ++ /* Function build_model transforms the existing parser->m_dtd->scaffold ++ * array of CONTENT_SCAFFOLD tree nodes into a new array of ++ * XML_Content tree nodes followed by a gapless list of zero-terminated ++ * strings. */ DTD *const dtd = parser->m_dtd; /* save one level of indirection */ XML_Content *ret; - XML_Content *cpos; @@ -1996,7 +2167,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c return ret; } -@@ -6894,7 +7481,7 @@ +@@ -6894,7 +7611,7 @@ static XML_Char * copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { @@ -2005,7 +2176,7 @@ diff -ru misc/expat-2.2.10/lib/xmlparse.c misc/build/expat-2.2.10/lib/xmlparse.c XML_Char *result; /* First determine how long the string is */ -@@ -6912,3 +7499,766 @@ +@@ -6912,3 +7629,766 @@ memcpy(result, s, charsRequired * sizeof(XML_Char)); return result; } @@ -2954,7 +3125,7 @@ diff -ru misc/expat-2.2.10/tests/minicheck.c misc/build/expat-2.2.10/tests/minic fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n"); diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtests.c --- misc/expat-2.2.10/tests/runtests.c 2020-10-03 17:14:57.000000000 +0200 -+++ misc/build/expat-2.2.10/tests/runtests.c 2022-03-05 12:25:27.583396678 +0100 ++++ misc/build/expat-2.2.10/tests/runtests.c 2022-03-09 20:25:36.716575629 +0100 @@ -45,6 +45,7 @@ #include <stddef.h> /* ptrdiff_t */ #include <ctype.h> @@ -2972,7 +3143,307 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes #include "minicheck.h" #include "memcheck.h" #include "siphash.h" -@@ -11231,6 +11232,381 @@ +@@ -2677,6 +2678,82 @@ + } + END_TEST + ++static void XMLCALL ++element_decl_check_model(void *userData, const XML_Char *name, ++ XML_Content *model) { ++ uint32_t errorFlags = 0; ++ UNUSED_P(userData); ++ ++ /* Expected model array structure is this: ++ * [0] (type 6, quant 0) ++ * [1] (type 5, quant 0) ++ * [3] (type 4, quant 0, name "bar") ++ * [4] (type 4, quant 0, name "foo") ++ * [5] (type 4, quant 3, name "xyz") ++ * [2] (type 4, quant 2, name "zebra") ++ */ ++ errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0)); ++ errorFlags |= ((model != NULL) ? 0 : (1u << 1)); ++ ++ errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2)); ++ errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3)); ++ errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4)); ++ errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5)); ++ errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6)); ++ ++ errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7)); ++ errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8)); ++ errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9)); ++ errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10)); ++ errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11)); ++ ++ errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12)); ++ errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13)); ++ errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14)); ++ errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15)); ++ errorFlags |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16)); ++ ++ errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17)); ++ errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18)); ++ errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19)); ++ errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20)); ++ errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21)); ++ ++ errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22)); ++ errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23)); ++ errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24)); ++ errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25)); ++ errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26)); ++ ++ errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27)); ++ errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28)); ++ errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29)); ++ errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30)); ++ errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31)); ++ ++ XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags); ++ XML_FreeContentModel(g_parser, model); ++} ++ ++START_TEST(test_dtd_elements_nesting) { ++ // Payload inspired by a test in Perl's XML::Parser ++ const char *text = "<!DOCTYPE foo [\n" ++ "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n" ++ "]>\n" ++ "<foo/>"; ++ ++ XML_SetUserData(g_parser, (void *)(uintptr_t)-1); ++ ++ XML_SetElementDeclHandler(g_parser, element_decl_check_model); ++ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) ++ == XML_STATUS_ERROR) ++ xml_failure(g_parser); ++ ++ if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0) ++ fail("Element declaration model regression detected"); ++} ++END_TEST ++ + /* Test foreign DTD handling */ + START_TEST(test_set_foreign_dtd) { + const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"; +@@ -3860,6 +3937,30 @@ + } + END_TEST + ++/* Test for signed integer overflow CVE-2022-23852 */ ++#if defined(XML_CONTEXT_BYTES) ++START_TEST(test_get_buffer_3_overflow) { ++ XML_Parser parser = XML_ParserCreate(NULL); ++ ++ const char *const text = "\n"; ++ const int expectedKeepValue = (int)strlen(text); ++ ++ assert(parser != NULL); ++ // After this call, variable "keep" in XML_GetBuffer will ++ // have value expectedKeepValue ++ if (XML_Parse(parser, text, (int)strlen(text), XML_FALSE /* isFinal */) ++ == XML_STATUS_ERROR) ++ xml_failure(parser); ++ ++ assert(expectedKeepValue > 0); ++ if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL) ++ fail("enlarging buffer not failed"); ++ ++ XML_ParserFree(parser); ++} ++END_TEST ++#endif // defined(XML_CONTEXT_BYTES) ++ + /* Test position information macros */ + START_TEST(test_byte_info_at_end) { + const char *text = "<doc></doc>"; +@@ -5987,6 +6088,107 @@ + } + END_TEST + ++START_TEST(test_utf8_in_start_tags) { ++ struct test_case { ++ bool goodName; ++ bool goodNameStart; ++ const char *tagName; ++ }; ++ ++ // The idea with the tests below is this: ++ // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences ++ // go to isNever and are hence not a concern. ++ // ++ // We start with a character that is a valid name character ++ // (or even name-start character, see XML 1.0r4 spec) and then we flip ++ // single bits at places where (1) the result leaves the UTF-8 encoding space ++ // and (2) we stay in the same n-byte sequence family. ++ // ++ // The flipped bits are highlighted in angle brackets in comments, ++ // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped ++ // the most significant bit to 1 to leave UTF-8 encoding space. ++ struct test_case cases[] = { ++ // 1-byte UTF-8: [0xxx xxxx] ++ {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':' ++ {false, false, "\xBA"}, // [<1>011 1010] ++ {true, false, "\x39"}, // [0011 1001] = ASCII nine '9' ++ {false, false, "\xB9"}, // [<1>011 1001] ++ ++ // 2-byte UTF-8: [110x xxxx] [10xx xxxx] ++ {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] = ++ // Arabic small waw U+06E5 ++ {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101] ++ {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101] ++ {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101] ++ {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] = ++ // combining char U+0301 ++ {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001] ++ {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001] ++ {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001] ++ ++ // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx] ++ {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] = ++ // Devanagari Letter A U+0905 ++ {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101] ++ {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101] ++ {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101] ++ {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101] ++ {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101] ++ {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] = ++ // combining char U+0901 ++ {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001] ++ {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001] ++ {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001] ++ {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001] ++ {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001] ++ }; ++ const bool atNameStart[] = {true, false}; ++ ++ size_t i = 0; ++ char doc[1024]; ++ size_t failCount = 0; ++ ++ for (; i < sizeof(cases) / sizeof(cases[0]); i++) { ++ size_t j = 0; ++ for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) { ++ const bool expectedSuccess ++ = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName; ++ XML_Parser parser = XML_ParserCreate(NULL); ++ enum XML_Status status; ++ bool success; ++ sprintf(doc, "<%s%s><!--", atNameStart[j] ? "" : "a", cases[i].tagName); ++ ++ status ++ = XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE); ++ ++ success = true; ++ if ((status == XML_STATUS_OK) != expectedSuccess) { ++ success = false; ++ } ++ if ((status == XML_STATUS_ERROR) ++ && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) { ++ success = false; ++ } ++ ++ if (! success) { ++ fprintf( ++ stderr, ++ "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n", ++ (unsigned)i + 1u, atNameStart[j] ? " " : "not ", ++ (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser)); ++ failCount++; ++ } ++ ++ XML_ParserFree(parser); ++ } ++ } ++ ++ if (failCount > 0) { ++ fail("UTF-8 regression detected"); ++ } ++} ++END_TEST ++ + /* Test trailing spaces in elements are accepted */ + static void XMLCALL + record_element_end_handler(void *userData, const XML_Char *name) { +@@ -6164,6 +6366,14 @@ + } + END_TEST + ++START_TEST(test_bad_doctype_utf8) { ++ const char *text = "<!DOCTYPE \xDB\x25" ++ "doc><doc/>"; // [1101 1011] [<0>010 0101] ++ expect_failure(text, XML_ERROR_INVALID_TOKEN, ++ "Invalid UTF-8 in DOCTYPE not faulted"); ++} ++END_TEST ++ + START_TEST(test_bad_doctype_utf16) { + const char text[] = + /* <!DOCTYPE doc [ \x06f2 ]><doc/> +@@ -7209,6 +7419,37 @@ + } + END_TEST + ++START_TEST(test_ns_separator_in_uri) { ++ struct test_case { ++ enum XML_Status expectedStatus; ++ const char *doc; ++ XML_Char namesep; ++ }; ++ struct test_case cases[] = { ++ {XML_STATUS_OK, "<doc xmlns='one_two' />", XCS('\n')}, ++ {XML_STATUS_ERROR, "<doc xmlns='one
two' />", XCS('\n')}, ++ {XML_STATUS_OK, "<doc xmlns='one:two' />", XCS(':')}, ++ }; ++ ++ size_t i = 0; ++ size_t failCount = 0; ++ for (; i < sizeof(cases) / sizeof(cases[0]); i++) { ++ XML_Parser parser = XML_ParserCreateNS(NULL, cases[i].namesep); ++ XML_SetElementHandler(parser, dummy_start_element, dummy_end_element); ++ if (XML_Parse(parser, cases[i].doc, (int)strlen(cases[i].doc), ++ /*isFinal*/ XML_TRUE) ++ != cases[i].expectedStatus) { ++ failCount++; ++ } ++ XML_ParserFree(parser); ++ } ++ ++ if (failCount) { ++ fail("Namespace separator handling is broken"); ++ } ++} ++END_TEST ++ + /* Control variable; the number of times duff_allocator() will successfully + * allocate */ + #define ALLOC_ALWAYS_SUCCEED (-1) +@@ -7365,7 +7606,7 @@ + fail("Version mismatch"); + + #if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) +- if (xcstrcmp(version_text, XCS("expat_2.2.10"))) /* needs bump on releases */ ++ if (xcstrcmp(version_text, XCS("expat_2.2.13"))) /* needs bump on releases */ + fail("XML_*_VERSION in expat.h out of sync?\n"); + #else + /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T +@@ -9851,6 +10092,15 @@ + + /* Try a parse before the start of the world */ + /* (Exercises new code path) */ ++ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR) ++ fail("Pre-init XML_ParseBuffer not faulted"); ++ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_BUFFER) ++ fail("Pre-init XML_ParseBuffer faulted for wrong reason"); ++ ++ buffer = XML_GetBuffer(g_parser, 1 /* any small number greater than 0 */); ++ if (buffer == NULL) ++ fail("Could not acquire parse buffer"); ++ + allocation_count = 0; + if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR) + fail("Pre-init XML_ParseBuffer not faulted"); +@@ -11231,6 +11481,401 @@ } END_TEST @@ -3068,6 +3539,16 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes + + /* CDATA */ + {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later}, ++ /* The following is the essence of this OSS-Fuzz finding: ++ https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34302 ++ https://oss-fuzz.com/testcase-detail/4860575394955264 ++ */ ++ {"<!DOCTYPE r [\n" ++ "<!ENTITY e \"111<![CDATA[2 <= 2]]>333\">\n" ++ "]>\n" ++ "<r>&e;</r>\n", ++ NULL, NULL, sizeof(XML_Char) * strlen("111<![CDATA[2 <= 2]]>333"), ++ filled_later}, + + /* Conditional sections */ + {"<!DOCTYPE r [\n" @@ -3265,6 +3746,16 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes +} +END_TEST + ++static float ++portableNAN() { ++ return strtof("nan", NULL); ++} ++ ++static float ++portableINFINITY() { ++ return strtof("infinity", NULL); ++} ++ +START_TEST(test_billion_laughs_attack_protection_api) { + XML_Parser parserWithoutParent = XML_ParserCreate(NULL); + XML_Parser parserWithParent @@ -3283,7 +3774,7 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes + == XML_TRUE) + fail("Call with non-root parser is NOT supposed to succeed"); + if (XML_SetBillionLaughsAttackProtectionMaximumAmplification( -+ parserWithoutParent, NAN) ++ parserWithoutParent, portableNAN()) + == XML_TRUE) + fail("Call with NaN limit is NOT supposed to succeed"); + if (XML_SetBillionLaughsAttackProtectionMaximumAmplification( @@ -3305,7 +3796,7 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes + == XML_FALSE) + fail("Call with positive limit >=1.0 is supposed to succeed"); + if (XML_SetBillionLaughsAttackProtectionMaximumAmplification( -+ parserWithoutParent, INFINITY) ++ parserWithoutParent, portableINFINITY()) + == XML_FALSE) + fail("Call with positive limit >=1.0 is supposed to succeed"); + @@ -3354,7 +3845,7 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes static Suite * make_suite(void) { Suite *s = suite_create("basic"); -@@ -11239,6 +11615,9 @@ +@@ -11239,6 +11884,9 @@ TCase *tc_misc = tcase_create("miscellaneous tests"); TCase *tc_alloc = tcase_create("allocation tests"); TCase *tc_nsalloc = tcase_create("namespace allocation tests"); @@ -3364,7 +3855,49 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes suite_add_tcase(s, tc_basic); tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown); -@@ -11603,6 +11982,13 @@ +@@ -11325,6 +11973,7 @@ + tcase_add_test(tc_basic, test_memory_allocation); + tcase_add_test(tc_basic, test_default_current); + 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); + tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone); + tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd); +@@ -11353,6 +12002,9 @@ + tcase_add_test(tc_basic, test_empty_parse); + tcase_add_test(tc_basic, test_get_buffer_1); + tcase_add_test(tc_basic, test_get_buffer_2); ++#if defined(XML_CONTEXT_BYTES) ++ tcase_add_test(tc_basic, test_get_buffer_3_overflow); ++#endif + tcase_add_test(tc_basic, test_byte_info_at_end); + tcase_add_test(tc_basic, test_byte_info_at_error); + tcase_add_test(tc_basic, test_byte_info_at_cdata); +@@ -11436,6 +12088,7 @@ + tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom); + tcase_add_test(tc_basic, test_utf8_in_cdata_section); + tcase_add_test(tc_basic, test_utf8_in_cdata_section_2); ++ tcase_add_test(tc_basic, test_utf8_in_start_tags); + tcase_add_test(tc_basic, test_trailing_spaces_in_elements); + tcase_add_test(tc_basic, test_utf16_attribute); + tcase_add_test(tc_basic, test_utf16_second_attr); +@@ -11444,6 +12097,7 @@ + tcase_add_test(tc_basic, test_bad_attr_desc_keyword); + tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16); + tcase_add_test(tc_basic, test_bad_doctype); ++ tcase_add_test(tc_basic, test_bad_doctype_utf8); + tcase_add_test(tc_basic, test_bad_doctype_utf16); + tcase_add_test(tc_basic, test_bad_doctype_plus); + tcase_add_test(tc_basic, test_bad_doctype_star); +@@ -11500,6 +12154,7 @@ + tcase_add_test(tc_namespace, test_ns_utf16_doctype); + tcase_add_test(tc_namespace, test_ns_invalid_doctype); + tcase_add_test(tc_namespace, test_ns_double_colon_doctype); ++ tcase_add_test(tc_namespace, test_ns_separator_in_uri); + + suite_add_tcase(s, tc_misc); + tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); +@@ -11603,6 +12258,13 @@ tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext); tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element); @@ -3378,6 +3911,18 @@ diff -ru misc/expat-2.2.10/tests/runtests.c misc/build/expat-2.2.10/tests/runtes return s; } +diff -ru misc/expat-2.2.10/win32/expat.iss misc/build/expat-2.2.10/win32/expat.iss +--- misc/expat-2.2.10/win32/expat.iss 2020-10-03 17:14:57.000000000 +0200 ++++ misc/build/expat-2.2.10/win32/expat.iss 2022-03-09 20:25:36.720575719 +0100 +@@ -4,7 +4,7 @@ + ; This script was contributed by Tim Peters. + ; It was designed for Inno Setup 2.0.19 but works with later versions as well. + +-#define expatVer "2.2.10" ++#define expatVer "2.2.13" + + [Setup] + AppName=Expat diff -ru misc/expat-2.2.10/xmlwf/Makefile.in misc/build/expat-2.2.10/xmlwf/Makefile.in --- misc/expat-2.2.10/xmlwf/Makefile.in 2020-10-03 17:37:06.000000000 +0200 +++ misc/build/expat-2.2.10/xmlwf/Makefile.in 2022-03-05 12:25:27.583396678 +0100 @@ -3401,7 +3946,7 @@ diff -ru misc/expat-2.2.10/xmlwf/Makefile.in misc/build/expat-2.2.10/xmlwf/Makef srcdir = @srcdir@ diff -ru misc/expat-2.2.10/xmlwf/xmltchar.h misc/build/expat-2.2.10/xmlwf/xmltchar.h --- misc/expat-2.2.10/xmlwf/xmltchar.h 2020-09-25 19:47:39.000000000 +0200 -+++ misc/build/expat-2.2.10/xmlwf/xmltchar.h 2022-03-05 12:25:27.583396678 +0100 ++++ misc/build/expat-2.2.10/xmlwf/xmltchar.h 2022-03-09 20:25:36.720575719 +0100 @@ -54,6 +54,8 @@ # define tmain wmain # define tremove _wremove @@ -3420,7 +3965,7 @@ diff -ru misc/expat-2.2.10/xmlwf/xmltchar.h misc/build/expat-2.2.10/xmlwf/xmltch #endif /* not XML_UNICODE */ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c --- misc/expat-2.2.10/xmlwf/xmlwf.c 2020-09-25 19:47:39.000000000 +0200 -+++ misc/build/expat-2.2.10/xmlwf/xmlwf.c 2022-03-05 12:25:27.583396678 +0100 ++++ misc/build/expat-2.2.10/xmlwf/xmlwf.c 2022-03-09 20:25:36.720575719 +0100 @@ -30,11 +30,15 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. */ @@ -3452,7 +3997,43 @@ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c /* Structures for handler user data */ typedef struct NotationList { struct NotationList *next; -@@ -875,6 +887,12 @@ +@@ -322,6 +334,13 @@ + data->notationListHead = NULL; + } + ++static void ++cleanupUserData(XmlwfUserData *userData) { ++ free((void *)userData->currentDoctypeName); ++ userData->currentDoctypeName = NULL; ++ freeNotations(userData); ++} ++ + static int + xcscmp(const XML_Char *xs, const XML_Char *xt) { + while (*xs != 0 && *xt != 0) { +@@ -850,9 +869,10 @@ + * $ xmlwf/xmlwf_helpgen.sh + */ + /* clang-format off */ +- T("usage: %s [-s] [-n] [-p] [-x] [-e ENCODING] [-w] [-r] [-d DIRECTORY]\n") +- T(" [-c | -m | -t] [-N]\n") +- T(" [FILE [FILE ...]]\n") ++ T("usage:\n") ++ T(" %s [OPTIONS] [FILE ...]\n") ++ T(" %s -h\n") ++ T(" %s -v\n") + T("\n") + T("xmlwf - Determines if an XML document is well-formed\n") + T("\n") +@@ -867,6 +887,7 @@ + T(" -e ENCODING override any in-document [e]ncoding declaration\n") + T(" -w enable support for [W]indows code pages\n") + T(" -r disable memory-mapping and use normal file [r]ead IO calls instead\n") ++ T(" -k when processing multiple files, [k]eep processing after first file with error\n") + T("\n") + T("output control arguments:\n") + T(" -d DIRECTORY output [d]estination directory\n") +@@ -875,14 +896,27 @@ T(" -t write no XML output for [t]iming of plain parsing\n") T(" -N enable adding doctype and [n]otation declarations\n") T("\n") @@ -3465,7 +4046,23 @@ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c T("info arguments:\n") T(" -h show this [h]elp message and exit\n") T(" -v show program's [v]ersion number and exit\n") -@@ -891,6 +909,19 @@ + T("\n") ++ T("exit status:\n") ++ T(" 0 the input files are well-formed and the output (if requested) was written successfully\n") ++ T(" 1 could not allocate data structures, signals a serious problem with execution environment\n") ++ T(" 2 one or more input files were not well-formed\n") ++ T(" 3 could not create an output file\n") ++ T(" 4 command-line argument error\n") ++ T("\n") + T("xmlwf of libexpat is software libre, licensed under the MIT license.\n") + T("Please report bugs at https://github.com/libexpat/libexpat/issues. Thank you!\n") + , /* clang-format on */ +- prog); ++ prog, prog, prog); + exit(rc); + } + +@@ -891,6 +925,19 @@ int wmain(int argc, XML_Char **argv); #endif @@ -3485,22 +4082,56 @@ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c int tmain(int argc, XML_Char **argv) { int i, j; -@@ -902,6 +933,11 @@ +@@ -902,6 +949,13 @@ int useNamespaces = 0; int requireStandalone = 0; int requiresNotations = 0; ++ int continueOnError = 0; + + float attackMaximumAmplification = -1.0f; /* signaling "not set" */ + unsigned long long attackThresholdBytes; + XML_Bool attackThresholdGiven = XML_FALSE; + ++ int exitCode = XMLWF_EXIT_SUCCESS; enum XML_ParamEntityParsing paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; int useStdin = 0; -@@ -990,6 +1026,49 @@ +@@ -965,31 +1019,64 @@ + j++; + break; + case T('d'): +- if (argv[i][j + 1] == T('\0')) { +- if (++i == argc) +- usage(argv[0], 2); +- outputDir = argv[i]; +- } else +- outputDir = argv[i] + j + 1; +- i++; +- j = 0; ++ XMLWF_SHIFT_ARG_INTO(outputDir, argc, argv, i, j); + break; + case T('e'): +- if (argv[i][j + 1] == T('\0')) { +- if (++i == argc) +- usage(argv[0], 2); +- encoding = argv[i]; +- } else +- encoding = argv[i] + j + 1; +- i++; +- j = 0; ++ XMLWF_SHIFT_ARG_INTO(encoding, argc, argv, i, j); + break; + case T('h'): +- usage(argv[0], 0); ++ usage(argv[0], XMLWF_EXIT_SUCCESS); + return 0; case T('v'): showVersion(argv[0]); return 0; ++ case T('k'): ++ continueOnError = 1; ++ j++; ++ break; + case T('a'): { + const XML_Char *valueText = NULL; + XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j); @@ -3547,10 +4178,23 @@ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c case T('\0'): if (j > 1) { i++; -@@ -1020,6 +1099,19 @@ - exit(1); +@@ -998,7 +1085,7 @@ + } + /* fall through */ + default: +- usage(argv[0], 2); ++ usage(argv[0], XMLWF_EXIT_USAGE_ERROR); } + } + if (i == argc) { +@@ -1017,7 +1104,22 @@ + if (! parser) { + tperror(T("Could not instantiate parser")); +- exit(1); ++ exit(XMLWF_EXIT_INTERNAL_ERROR); ++ } ++ + if (attackMaximumAmplification != -1.0f) { +#ifdef XML_DTD + XML_SetBillionLaughsAttackProtectionMaximumAmplification( @@ -3561,12 +4205,52 @@ diff -ru misc/expat-2.2.10/xmlwf/xmlwf.c misc/build/expat-2.2.10/xmlwf/xmlwf.c +#ifdef XML_DTD + XML_SetBillionLaughsAttackProtectionActivationThreshold( + parser, attackThresholdBytes); ++#else ++ (void)attackThresholdBytes; // silence -Wunused-but-set-variable +#endif -+ } -+ + } + if (requireStandalone) - XML_SetNotStandaloneHandler(parser, notStandalone); - XML_SetParamEntityParsing(parser, paramEntityParsing); +@@ -1053,7 +1155,7 @@ + * sizeof(XML_Char)); + if (! outName) { + tperror(T("Could not allocate memory")); +- exit(1); ++ exit(XMLWF_EXIT_INTERNAL_ERROR); + } + tcscpy(outName, outputDir); + tcscat(outName, delim); +@@ -1061,7 +1163,14 @@ + userData.fp = tfopen(outName, T("wb")); + if (! userData.fp) { + tperror(outName); +- exit(3); ++ exitCode = XMLWF_EXIT_OUTPUT_ERROR; ++ free(outName); ++ XML_ParserFree(parser); ++ if (continueOnError) { ++ continue; ++ } else { ++ break; ++ } + } + setvbuf(userData.fp, NULL, _IOFBF, 16384); + #ifdef XML_UNICODE +@@ -1123,8 +1232,12 @@ + } + XML_ParserFree(parser); + if (! result) { +- exit(2); ++ exitCode = XMLWF_EXIT_NOT_WELLFORMED; ++ cleanupUserData(&userData); ++ if (! continueOnError) { ++ break; ++ } + } + } +- return 0; ++ return exitCode; + } diff -ru misc/expat-2.2.10/xmlwf/xmlwf_helpgen.py misc/build/expat-2.2.10/xmlwf/xmlwf_helpgen.py --- misc/expat-2.2.10/xmlwf/xmlwf_helpgen.py 2020-09-25 19:47:39.000000000 +0200 +++ misc/build/expat-2.2.10/xmlwf/xmlwf_helpgen.py 2022-03-05 12:25:27.583396678 +0100