You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by ar...@apache.org on 2022/03/17 19:02:01 UTC

[openoffice] branch AOO41X updated (85aaee6 -> fc33a8e)

This is an automated email from the ASF dual-hosted git repository.

ardovm pushed a change to branch AOO41X
in repository https://gitbox.apache.org/repos/asf/openoffice.git.


    from 85aaee6  Changed graphic (About) for this release
     new 1cc17f6  Upgrade expat-2.2.10 into 2.2.12
     new fc33a8e  Produce expat-2.2.13, derived from 2.4.7

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 main/expat/expat-2.2.10.patch | 4188 +++++++++++++++++++++++++++++++++++++++++
 main/expat/expat-2.2.11.patch | 2745 ---------------------------
 main/expat/makefile.mk        |    2 +-
 3 files changed, 4189 insertions(+), 2746 deletions(-)
 delete mode 100644 main/expat/expat-2.2.11.patch

[openoffice] 02/02: Produce expat-2.2.13, derived from 2.4.7

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ardovm pushed a commit to branch AOO41X
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit fc33a8e79fbea019c341dc93e167863910b03cf9
Author: Arrigo Marchiori <ar...@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 6027210f9c9f69912774bd8cb8d0c1709c8a875e)
---
 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&#x0A;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

[openoffice] 01/02: Upgrade expat-2.2.10 into 2.2.12

Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ardovm pushed a commit to branch AOO41X
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 1cc17f6ad4babad198d02cceba3be618937ed9e4
Author: Arrigo Marchiori <ar...@yahoo.it>
AuthorDate: Sat Mar 5 12:36:36 2022 +0100

    Upgrade expat-2.2.10 into 2.2.12
    
    Also use only one patch file named after the base version
    
    (cherry picked from commit b3c6ca9c0c6d662a6b677cbe0eb72ccd48e78f85)
---
 main/expat/expat-2.2.10.patch | 3504 +++++++++++++++++++++++++++++++++++++++++
 main/expat/expat-2.2.11.patch | 2745 --------------------------------
 main/expat/makefile.mk        |    2 +-
 3 files changed, 3505 insertions(+), 2746 deletions(-)

diff --git a/main/expat/expat-2.2.10.patch b/main/expat/expat-2.2.10.patch
index ff1d16a..b6413d6 100644
--- a/main/expat/expat-2.2.10.patch
+++ b/main/expat/expat-2.2.10.patch
@@ -81,3 +81,3507 @@
 +.INCLUDE :  set_wntx64.mk
 +.INCLUDE :	target.mk
 +.INCLUDE :  tg_wntx64.mk
+diff -ru misc/expat-2.2.10/Changes misc/build/expat-2.2.10/Changes
+--- misc/expat-2.2.10/Changes	2020-10-03 17:14:57.000000000 +0200
++++ misc/build/expat-2.2.10/Changes	2022-03-05 12:25:27.575396494 +0100
+@@ -2,6 +2,43 @@
+       https://github.com/libexpat/libexpat/labels/help%20wanted
+       If you can help, please get in touch.  Thanks!
+ 
++
++Release 2.2.11 XXX XXXXX XX XXXX
++        Security fixes:
++        #34 #466  CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
++                    (denial-of-service; flavors targeting CPU time or RAM or both,
++                    leveraging general entities or parameter entities or both)
++                    by tracking and limiting the input amplification factor
++                    (<amplification> := (<direct> + <indirect>) / <direct>).
++                    By conservative default, amplification up to a factor of 100.0
++                    is tolerated and rejection only starts after 8 MiB of output bytes
++                    (=<direct> + <indirect>) have been processed.
++                    A new error code XML_ERROR_AMPLIFICATION_LIMIT_BREACH signals
++                    this condition.
++        New features:
++        #34 #466  Add two new API functions to further tighten billion laughs
++                    protection parameters when desired.
++                    - XML_SetBillionLaughsAttackProtectionMaximumAmplification
++                    - XML_SetBillionLaughsAttackProtectionActivationThreshold
++                    Please see file "doc/reference.html" for more details.
++                    If you ever need to increase the defaults for non-attack XML
++                    payload, please file a bug report with libexpat.
++        #34 #466  Introduce environment switches EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)
++                    and EXPAT_ENTITY_DEBUG=(0|1) for runtime debugging of accounting
++                    and entity processing; specific behavior of these values may
++                    change in the future.
++        #34 #466  xmlwf: Add arguments "-a FACTOR" and "-b BYTES" to further tighten
++                    billion laughs protection parameters when desired.
++                    If you ever need to increase the defaults for non-attack XML
++                    payload, please file a bug report with libexpat.
++
++        Special thanks to:
++            Nick Wellnhofer
++            Yury Gribov
++                 and
++            Clang LeakSan
++            JetBrains
++
+ Release 2.2.10 Sat October 3 2020
+         Bug fixes:
+   #390 #395 #398  Fix undefined behavior during parsing caused by
+diff -ru misc/expat-2.2.10/CMakeLists.txt misc/build/expat-2.2.10/CMakeLists.txt
+--- misc/expat-2.2.10/CMakeLists.txt	2020-10-03 17:14:57.000000000 +0200
++++ misc/build/expat-2.2.10/CMakeLists.txt	2022-03-05 12:25:27.575396494 +0100
+@@ -448,14 +448,12 @@
+         endif()
+     endfunction()
+ 
+-    add_executable(runtests tests/runtests.c ${test_SRCS})
++    add_executable(runtests tests/runtests.c ${test_SRCS} ${expat_SRCS})
+     set_property(TARGET runtests PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
+-    target_link_libraries(runtests expat)
+     expat_add_test(runtests $<TARGET_FILE:runtests>)
+ 
+-    add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS})
++    add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS} ${expat_SRCS})
+     set_property(TARGET runtestspp PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
+-    target_link_libraries(runtestspp expat)
+     expat_add_test(runtestspp $<TARGET_FILE:runtestspp>)
+ endif()
+ 
+diff -ru misc/expat-2.2.10/doc/Makefile.in misc/build/expat-2.2.10/doc/Makefile.in
+--- misc/expat-2.2.10/doc/Makefile.in	2020-10-03 17:37:06.000000000 +0200
++++ misc/build/expat-2.2.10/doc/Makefile.in	2022-03-05 12:25:27.575396494 +0100
+@@ -1,7 +1,7 @@
+-# Makefile.in generated by automake 1.16.2 from Makefile.am.
++# Makefile.in generated by automake 1.16.1 from Makefile.am.
+ # @configure_input@
+ 
+-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
++# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ 
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -314,7 +314,6 @@
+ prefix = @prefix@
+ program_transform_name = @program_transform_name@
+ psdir = @psdir@
+-runstatedir = @runstatedir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
+ srcdir = @srcdir@
+diff -ru misc/expat-2.2.10/doc/reference.html misc/build/expat-2.2.10/doc/reference.html
+--- misc/expat-2.2.10/doc/reference.html	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/doc/reference.html	2022-03-05 12:25:27.575396494 +0100
+@@ -120,6 +120,13 @@
+       <li><a href="#XML_GetInputContext">XML_GetInputContext</a></li>
+     </ul>
+     </li>
++    <li>
++      <a href="#billion-laughs">Billion Laughs Attack Protection</a>
++      <ul>
++        <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li>
++        <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li>
++      </ul>
++    </li>
+     <li><a href="#miscellaneous">Miscellaneous Functions</a>
+     <ul>
+       <li><a href="#XML_SetUserData">XML_SetUserData</a></li>
+@@ -1998,6 +2005,98 @@
+ return NULL.</p>
+ </div>
+ 
++
++
++<h3><a name="billion-laughs">Billion Laughs Attack Protection</a></h3>
++
++<p>The functions in this section configure the built-in
++  protection against various forms of
++  <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>.</p>
++
++<pre class="fcndec" id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">
++/* Added in Expat 2.2.11. */
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(XML_Parser p,
++                                                         float maximumAmplificationFactor);
++</pre>
++<div class="fcndef">
++  <p>
++    Sets the maximum tolerated amplification factor
++    for protection against
++    <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
++    (default: <code>100.0</code>)
++    of parser <code>p</code> to <code>maximumAmplificationFactor</code>, and
++    returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
++  </p>
++
++  The amplification factor is calculated as ..
++  <pre>
++    amplification := (direct + indirect) / direct
++  </pre>
++  .. while parsing, whereas
++  <code>direct</code> is the number of bytes read from the primary document in parsing and
++  <code>indirect</code> is the number of bytes added by expanding entities and reading of external DTD files, combined.
++
++  <p>For a call to <code>XML_SetBillionLaughsAttackProtectionMaximumAmplification</code> to succeed:</p>
++  <ul>
++    <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers) and</li>
++    <li><code>maximumAmplificationFactor</code> must be non-<code>NaN</code> and greater than or equal to <code>1.0</code>.</li>
++  </ul>
++
++  <p>
++    <strong>Note:</strong>
++    If you ever need to increase this value for non-attack payload,
++    please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
++  </p>
++
++  <p>
++    <strong>Note:</strong>
++    Peak amplifications
++    of factor 15,000 for the entire payload and
++    of factor 30,000 in the middle of parsing
++    have been observed with small benign files in practice.
++
++    So if you do reduce the maximum allowed amplification,
++    please make sure that the activation threshold is still big enough
++    to not end up with undesired false positives (i.e. benign files being rejected).
++  </p>
++</div>
++
++<pre class="fcndec" id="XML_SetBillionLaughsAttackProtectionActivationThreshold">
++/* Added in Expat 2.2.11. */
++XML_Bool XMLCALL
++XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p,
++                                                        unsigned long long activationThresholdBytes);
++</pre>
++<div class="fcndef">
++  <p>
++    Sets number of output bytes (including amplification from entity expansion and reading DTD files)
++    needed to activate protection against
++    <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
++    (default: <code>8 MiB</code>)
++    of parser <code>p</code> to <code>activationThresholdBytes</code>, and
++    returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
++  </p>
++
++  <p>For a call to <code>XML_SetBillionLaughsAttackProtectionActivationThreshold</code> to succeed:</p>
++  <ul>
++    <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers).</li>
++  </ul>
++
++  <p>
++    <strong>Note:</strong>
++    If you ever need to increase this value for non-attack payload,
++    please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
++  </p>
++
++  <p>
++    <strong>Note:</strong>
++    Activation thresholds below 4 MiB are known to break support for
++    <a href="https://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">DITA</a> 1.3 payload
++    and are hence not recommended.
++  </p>
++</div>
++
+ <h3><a name="miscellaneous">Miscellaneous functions</a></h3>
+ 
+ <p>The functions in this section either obtain state information from
+diff -ru misc/expat-2.2.10/doc/xmlwf.xml misc/build/expat-2.2.10/doc/xmlwf.xml
+--- misc/expat-2.2.10/doc/xmlwf.xml	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/doc/xmlwf.xml	2022-03-05 12:25:27.575396494 +0100
+@@ -3,7 +3,7 @@
+   <!ENTITY dhfirstname "<firstname>Scott</firstname>">
+   <!ENTITY dhsurname   "<surname>Bronson</surname>">
+   <!-- Please adjust the date whenever revising the manpage. -->
+-  <!ENTITY dhdate      "<date>March 11, 2016</date>">
++  <!ENTITY dhdate      "<date>July 18, 2021</date>">
+   <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
+        allowed: see man(7), man(1). -->
+   <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
+@@ -138,6 +138,52 @@
+ </para>
+ 
+     <variablelist>
++    
++    <variablelist>
++
++      <varlistentry>
++        <term><option>-a</option> <replaceable>factor</replaceable></term>
++        <listitem>
++          <para>
++            Sets the maximum tolerated amplification factor
++            for protection against billion laughs attacks (default: 100.0).
++            The amplification factor is calculated as ..
++          </para>
++          <literallayout>
++            amplification := (direct + indirect) / direct
++          </literallayout>
++          <para>
++            .. while parsing, whereas
++            &lt;direct&gt; is the number of bytes read
++              from the primary document in parsing and
++            &lt;indirect&gt; is the number of bytes
++              added by expanding entities and reading of external DTD files,
++              combined.
++          </para>
++          <para>
++            <emphasis>NOTE</emphasis>:
++            If you ever need to increase this value for non-attack payload,
++            please file a bug report.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term><option>-b</option> <replaceable>bytes</replaceable></term>
++        <listitem>
++          <para>
++            Sets the number of output bytes (including amplification)
++            needed to activate protection against billion laughs attacks
++            (default: 8 MiB).
++            This can be thought of as an &quot;activation threshold&quot;.
++          </para>
++          <para>
++            <emphasis>NOTE</emphasis>:
++            If you ever need to increase this value for non-attack payload,
++            please file a bug report.
++          </para>
++        </listitem>
++      </varlistentry>
+ 
+       <varlistentry>
+         <term><option>-c</option></term>
+@@ -455,6 +501,7 @@
+ <literallayout>
+ The Expat home page:        http://www.libexpat.org/
+ The W3 XML specification:   http://www.w3.org/TR/REC-xml
++Billion laughs attack:      https://en.wikipedia.org/wiki/Billion_laughs_attack
+ </literallayout>
+ 
+ 	</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
+@@ -115,7 +115,10 @@
+   XML_ERROR_RESERVED_PREFIX_XMLNS,
+   XML_ERROR_RESERVED_NAMESPACE_URI,
+   /* Added in 2.2.1. */
+-  XML_ERROR_INVALID_ARGUMENT
++  XML_ERROR_INVALID_ARGUMENT,
++  /* Added in 2.2.11 */
++  XML_ERROR_NO_BUFFER,
++  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
+ };
+ 
+ enum XML_Content_Type {
+@@ -997,7 +1000,10 @@
+   XML_FEATURE_SIZEOF_XML_LCHAR,
+   XML_FEATURE_NS,
+   XML_FEATURE_LARGE_SIZE,
+-  XML_FEATURE_ATTR_INFO
++  XML_FEATURE_ATTR_INFO,
++  /* added in Expat 2.2.11 */
++  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
++  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
+   /* Additional features must be added to the end of this enum. */
+ };
+ 
+@@ -1010,12 +1016,25 @@
+ XMLPARSEAPI(const XML_Feature *)
+ XML_GetFeatureList(void);
+ 
++
++#ifdef XML_DTD
++/* Added in Expat 2.2.11 */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++    XML_Parser parser, float maximumAmplificationFactor);
++
++/* Added in Expat 2.2.11 */
++XMLPARSEAPI(XML_Bool)
++XML_SetBillionLaughsAttackProtectionActivationThreshold(
++    XML_Parser parser, unsigned long long activationThresholdBytes);
++#endif
++
+ /* Expat follows the semantic versioning convention.
+    See http://semver.org.
+ */
+ #define XML_MAJOR_VERSION 2
+ #define XML_MINOR_VERSION 2
+-#define XML_MICRO_VERSION 10
++#define XML_MICRO_VERSION 12
+ 
+ #ifdef __cplusplus
+ }
+diff -ru misc/expat-2.2.10/lib/internal.h misc/build/expat-2.2.10/lib/internal.h
+--- misc/expat-2.2.10/lib/internal.h	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/internal.h	2022-03-05 12:25:27.575396494 +0100
+@@ -101,10 +101,47 @@
+ #  endif
+ #endif
+ 
++#include <limits.h> // ULONG_MAX
++
++#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
++#  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_ULL(midpart) "%" midpart "llu"
++#  if ! defined(ULONG_MAX)
++#    error Compiler did not define ULONG_MAX for us
++#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
++#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
++#  else
++#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
++#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
++#  endif
++#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
++/* NOTE END */
++
++#include "expat.h" // so we can use type XML_Parser below
++
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+@@ -117,6 +154,11 @@
+ void
+ _INTERNAL_trim_to_complete_utf8_characters(const char *from,
+                                            const char **fromLimRef);
++#if defined(XML_DTD)
++unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
++unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
++const char *unsignedCharToPrintable(unsigned char c);
++#endif
+ 
+ #ifdef __cplusplus
+ }
+diff -ru misc/expat-2.2.10/lib/libexpat.def misc/build/expat-2.2.10/lib/libexpat.def
+--- misc/expat-2.2.10/lib/libexpat.def	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/libexpat.def	2022-03-05 12:25:27.575396494 +0100
+@@ -76,3 +76,6 @@
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.2.11
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70  
+\ No newline at end of file
+diff -ru misc/expat-2.2.10/lib/libexpatw.def misc/build/expat-2.2.10/lib/libexpatw.def
+--- misc/expat-2.2.10/lib/libexpatw.def	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/libexpatw.def	2022-03-05 12:25:27.579396586 +0100
+@@ -76,3 +76,6 @@
+   XML_SetHashSalt @67
+ ; added with version 2.2.5
+   _INTERNAL_trim_to_complete_utf8_characters @68
++; added with version 2.2.11
++  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
++  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
+\ No newline at end of file
+diff -ru misc/expat-2.2.10/lib/Makefile.in misc/build/expat-2.2.10/lib/Makefile.in
+--- misc/expat-2.2.10/lib/Makefile.in	2020-10-03 17:37:06.000000000 +0200
++++ misc/build/expat-2.2.10/lib/Makefile.in	2022-03-05 12:25:27.579396586 +0100
+@@ -1,7 +1,7 @@
+-# Makefile.in generated by automake 1.16.2 from Makefile.am.
++# Makefile.in generated by automake 1.16.1 from Makefile.am.
+ # @configure_input@
+ 
+-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
++# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ 
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -372,7 +372,6 @@
+ prefix = @prefix@
+ program_transform_name = @program_transform_name@
+ psdir = @psdir@
+-runstatedir = @runstatedir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
+ 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
+@@ -47,6 +47,7 @@
+ #include <limits.h> /* UINT_MAX */
+ #include <stdio.h>  /* fprintf */
+ #include <stdlib.h> /* getenv, rand_s */
++#include <math.h>   /* isnan */
+ 
+ #if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
+ /* vs2008/9.0 and earlier lack stdint.h; _MSC_VER 1600 is vs2010/10.0 */
+@@ -73,6 +74,10 @@
+ 
+ #ifdef _WIN32
+ #  include "winconfig.h"
++#include <float.h>
++#ifndef isnan
++#define isnan _isnan
++#endif
+ #elif defined(HAVE_EXPAT_CONFIG_H)
+ #  include <expat_config.h>
+ #endif /* ndef _WIN32 */
+@@ -382,6 +387,31 @@
+   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+ } OPEN_INTERNAL_ENTITY;
+ 
++enum XML_Account {
++  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat parser */
++  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
++                                   expansion */
++  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted already */
++};
++
++#ifdef XML_DTD
++typedef unsigned long long XmlBigCount;
++typedef struct accounting {
++  XmlBigCount countBytesDirect;
++  XmlBigCount countBytesIndirect;
++  int debugLevel;
++  float maximumAmplificationFactor; // >=1.0
++  unsigned long long activationThresholdBytes;
++} ACCOUNTING;
++
++typedef struct entity_stats {
++  unsigned int countEverOpened;
++  unsigned int currentDepth;
++  unsigned int maximumDepthSeen;
++  int debugLevel;
++} ENTITY_STATS;
++#endif /* XML_DTD */
++
+ typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
+                                          const char *end, const char **endPtr);
+ 
+@@ -412,16 +442,18 @@
+ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
+                                const char *s, const char *end, int tok,
+                                const char *next, const char **nextPtr,
+-                               XML_Bool haveMore, XML_Bool allowClosingDoctype);
++							   XML_Bool haveMore, XML_Bool allowClosingDoctype,
++							   enum XML_Account account);
+ static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
+                                             XML_Bool betweenDecl);
+ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+                                 const ENCODING *enc, const char *start,
+                                 const char *end, const char **endPtr,
+-                                XML_Bool haveMore);
++								XML_Bool haveMore, enum XML_Account account);
+ static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
+                                      const char **startPtr, const char *end,
+-                                     const char **nextPtr, XML_Bool haveMore);
++                                     const char **nextPtr, XML_Bool haveMore,
++                                     enum XML_Account account);
+ #ifdef XML_DTD
+ static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
+                                       const char **startPtr, const char *end,
+@@ -431,7 +463,8 @@
+ static void freeBindings(XML_Parser parser, BINDING *bindings);
+ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+                                 const char *s, TAG_NAME *tagNamePtr,
+-                                BINDING **bindingsPtr);
++								BINDING **bindingsPtr,
++								enum XML_Account account);
+ static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
+                                  BINDING **bindingsPtr);
+@@ -440,15 +473,18 @@
+                            XML_Parser parser);
+ static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
+                                           XML_Bool isCdata, const char *,
+-                                          const char *, STRING_POOL *);
++                                          const char *, STRING_POOL *,
++                                          enum XML_Account account);
+ static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
+                                            XML_Bool isCdata, const char *,
+-                                           const char *, STRING_POOL *);
++                                           const char *, STRING_POOL *,
++                                           enum XML_Account account);
+ static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
+                                     const char *start, const char *end);
+ static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+ static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                                       const char *start, const char *end);
++                                       const char *start, const char *end,
++                                       enum XML_Account account);
+ static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                                        const char *start, const char *end);
+ static int reportComment(XML_Parser parser, const ENCODING *enc,
+@@ -512,6 +548,34 @@
+ 
+ static void parserInit(XML_Parser parser, const XML_Char *encodingName);
+ 
++#ifdef XML_DTD
++static float accountingGetCurrentAmplification(XML_Parser rootParser);
++static void accountingReportStats(XML_Parser originParser, const char *epilog);
++static void accountingOnAbort(XML_Parser originParser);
++static void accountingReportDiff(XML_Parser rootParser,
++                                 unsigned int levelsAwayFromRootParser,
++                                 const char *before, const char *after,
++                                 ptrdiff_t bytesMore, int source_line,
++                                 enum XML_Account account);
++static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
++                                        const char *before, const char *after,
++                                        int source_line,
++                                        enum XML_Account account);
++
++static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
++                                      const char *action, int sourceLine);
++static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
++                                 int sourceLine);
++static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
++                                  int sourceLine);
++
++static XML_Parser getRootParserOf(XML_Parser parser,
++                                  unsigned int *outLevelDiff);
++#endif /* XML_DTD */
++
++static unsigned long getDebugLevel(const char *variableName,
++                                   unsigned long defaultDebugLevel);
++
+ #define poolStart(pool) ((pool)->start)
+ #define poolEnd(pool) ((pool)->ptr)
+ #define poolLength(pool) ((pool)->ptr - (pool)->start)
+@@ -625,6 +689,10 @@
+   enum XML_ParamEntityParsing m_paramEntityParsing;
+ #endif
+   unsigned long m_hash_secret_salt;
++#ifdef XML_DTD
++  ACCOUNTING m_accounting;
++  ENTITY_STATS m_entity_stats;
++#endif
+ };
+ 
+ #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+@@ -640,6 +708,7 @@
+ XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
+   XML_Char tmp[2];
+   *tmp = nsSep;
++  tmp[1] = 0;
+   return XML_ParserCreate_MM(encodingName, NULL, tmp);
+ }
+ 
+@@ -809,9 +878,8 @@
+ 
+ static unsigned long
+ ENTROPY_DEBUG(const char *label, unsigned long entropy) {
+-  const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
+-  if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
+-    fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
++	  if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) {
++	   fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
+             (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
+   }
+   return entropy;
+@@ -855,7 +923,7 @@
+     return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
+   } else {
+     return ENTROPY_DEBUG("fallback(8)",
+-                         entropy * (unsigned long)2305843009213693951ULL);
++                         entropy * (unsigned long long)2305843009213693951ULL);
+   }
+ #endif
+ }
+@@ -1073,6 +1141,18 @@
+   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ #endif
+   parser->m_hash_secret_salt = 0;
++
++#ifdef XML_DTD
++  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
++  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
++  parser->m_accounting.maximumAmplificationFactor
++      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
++  parser->m_accounting.activationThresholdBytes
++      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
++
++  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
++  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
++#endif
+ }
+ 
+ /* moves list of bindings to m_freeBindingList */
+@@ -1255,6 +1335,7 @@
+   if (parser->m_ns) {
+     XML_Char tmp[2];
+     *tmp = parser->m_namespaceSeparator;
++    tmp[1] = 0;
+     parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+   } else {
+     parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+@@ -1893,6 +1974,12 @@
+     parser->m_errorCode = XML_ERROR_FINISHED;
+     return XML_STATUS_ERROR;
+   case XML_INITIALIZED:
++    /* Has someone called XML_GetBuffer successfully before? */
++    if (! parser->m_bufferPtr) {
++      parser->m_errorCode = XML_ERROR_NO_BUFFER;
++      return XML_STATUS_ERROR;
++    }
++
+     if (parser->m_parentParser == NULL && ! startParsing(parser)) {
+       parser->m_errorCode = XML_ERROR_NO_MEMORY;
+       return XML_STATUS_ERROR;
+@@ -1971,6 +2058,11 @@
+     keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
+     if (keep > XML_CONTEXT_BYTES)
+       keep = XML_CONTEXT_BYTES;
++    /* Detect and prevent integer overflow */
++    if (keep > INT_MAX - neededSize) {
++      parser->m_errorCode = XML_ERROR_NO_MEMORY;
++      return NULL;
++    }
+     neededSize += keep;
+ #endif /* defined XML_CONTEXT_BYTES */
+     if (neededSize
+@@ -2337,6 +2429,13 @@
+   /* Added in 2.2.5. */
+   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
+     return XML_L("invalid argument");
++  /* Added in 2.2.11. */
++  case XML_ERROR_NO_BUFFER:
++    return XML_L(
++        "a successful prior call to function XML_GetBuffer is required");
++  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
++    return XML_L(
++        "limit on input amplification factor (from DTD and entities) breached");
+   }
+   return NULL;
+ }
+@@ -2373,41 +2472,75 @@
+ 
+ const XML_Feature *XMLCALL
+ XML_GetFeatureList(void) {
+-  static const XML_Feature features[]
+-      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+-          sizeof(XML_Char)},
+-         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+-          sizeof(XML_LChar)},
++  static const XML_Feature features[] = {
++	  {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
++	   sizeof(XML_Char)},
++	  {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
++	   sizeof(XML_LChar)},
+ #ifdef XML_UNICODE
+-         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
++      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ #endif
+ #ifdef XML_UNICODE_WCHAR_T
+-         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
++      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ #endif
+ #ifdef XML_DTD
+-         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
++      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ #endif
+ #ifdef XML_CONTEXT_BYTES
+-         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+-          XML_CONTEXT_BYTES},
++      {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},
++      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ #endif
+ #ifdef XML_NS
+-         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
++      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ #endif
+ #ifdef XML_LARGE_SIZE
+-         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
++      {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},
++      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
++#endif
++#ifdef XML_DTD
++      /* Added in Expat 2.2.11. */
++      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
++       XML_L("XML_BLAP_MAX_AMP"),
++       (long int)
++           EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
++      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
++       XML_L("XML_BLAP_ACT_THRES"),
++       EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
+ #endif
+-         {XML_FEATURE_END, NULL, 0}};
++      {XML_FEATURE_END, NULL, 0}};
+ 
+   return features;
+ }
+ 
++#ifdef XML_DTD
++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;
++}
++
++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;
++}
++#endif /* XML_DTD */
++
+ /* 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 @@
+   while (tag) {
+     int bufSize;
+     int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
++    size_t rawNameLen;
+     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 @@
+     /* For re-use purposes we need to ensure that the
+        size of tag->buf is a multiple of sizeof(XML_Char).
+     */
+-    bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
++    rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
++    /* Detect and prevent integer overflow. */
++    if (rawNameLen > (size_t)INT_MAX - nameLen)
++      return XML_FALSE;
++    bufSize = nameLen + (int)rawNameLen;
+     if (bufSize > tag->bufEnd - tag->buf) {
+       char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
+       if (temp == NULL)
+@@ -2460,9 +2598,9 @@
+ static enum XML_Error PTRCALL
+ contentProcessor(XML_Parser parser, const char *start, const char *end,
+                  const char **endPtr) {
+-  enum XML_Error result
+-      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++  enum XML_Error result = doContent(
++      parser, 0, parser->m_encoding, start, end, endPtr,
++	  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2487,6 +2625,14 @@
+   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
+   switch (tok) {
+   case XML_TOK_BOM:
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif /* XML_DTD */
++
+     /* 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 @@
+   const char *next = start; /* XmlContentTok doesn't always set the last arg */
+   parser->m_eventPtr = start;
+   tok = XmlContentTok(parser->m_encoding, start, end, &next);
++  /* Note: These bytes are accounted later in:
++           - processXmlDecl
++           - externalEntityContentProcessor
++  */
+   parser->m_eventEndPtr = next;
+ 
+   switch (tok) {
+@@ -2565,7 +2715,8 @@
+                                const char *end, const char **endPtr) {
+   enum XML_Error result
+       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++              (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++              XML_ACCOUNT_ENTITY_EXPANSION);
+   if (result == XML_ERROR_NONE) {
+     if (! storeRawNames(parser))
+       return XML_ERROR_NO_MEMORY;
+@@ -2576,7 +2727,7 @@
+ static enum XML_Error
+ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+           const char *s, const char *end, const char **nextPtr,
+-          XML_Bool haveMore) {
++          XML_Bool haveMore, enum XML_Account account) {
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -2594,6 +2745,17 @@
+   for (;;) {
+     const char *next = s; /* XmlContentTok doesn't always set the last arg */
+     int tok = XmlContentTok(enc, s, end, &next);
++#ifdef XML_DTD
++    const char *accountAfter
++        = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
++              ? (haveMore ? s /* i.e. 0 bytes */ : end)
++              : next;
++    if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_TRAILING_CR:
+@@ -2649,6 +2811,14 @@
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1 character
++         *       so there is no amplification and hence recording without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (parser->m_characterDataHandler)
+           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
+         else if (parser->m_defaultHandler)
+@@ -2767,7 +2937,7 @@
+       }
+       tag->name.str = (XML_Char *)tag->buf;
+       *toPtr = XML_T('\0');
+-      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
++      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
+       if (result)
+         return result;
+       if (parser->m_startElementHandler)
+@@ -2791,7 +2961,8 @@
+       if (! name.str)
+         return XML_ERROR_NO_MEMORY;
+       poolFinish(&parser->m_tempPool);
+-      result = storeAtts(parser, enc, s, &name, &bindings);
++      result = storeAtts(parser, enc, s, &name, &bindings,
++                         XML_ACCOUNT_NONE /* token spans whole start tag */);
+       if (result != XML_ERROR_NONE) {
+         freeBindings(parser, bindings);
+         return result;
+@@ -2926,7 +3097,7 @@
+       /* END disabled code */
+       else if (parser->m_defaultHandler)
+         reportDefault(parser, enc, s, next);
+-      result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
++      result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
+       if (result != XML_ERROR_NONE)
+         return result;
+       else if (! next) {
+@@ -3055,7 +3226,8 @@
+ */
+ static enum XML_Error
+ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+-          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
++        TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
++        enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   ELEMENT_TYPE *elementType;
+   int nDefaultAtts;
+@@ -3087,13 +3259,38 @@
+ 
+   /* get the attributes from the tokenizer */
+   n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
++
++  /* Detect and prevent integer overflow */
++  if (n > INT_MAX - nDefaultAtts) {
++    return XML_ERROR_NO_MEMORY;
++  }
++
+   if (n + nDefaultAtts > parser->m_attsSize) {
+     int oldAttsSize = parser->m_attsSize;
+     ATTRIBUTE *temp;
+ #ifdef XML_ATTR_INFO
+     XML_AttrInfo *temp2;
+ #endif
++
++    /* Detect and prevent integer overflow */
++    if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
++        || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
++      return XML_ERROR_NO_MEMORY;
++    }
++
+     parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
++
++    /* Detect and prevent integer overflow.
++     * The preprocessor guard addresses the "always false" warning
++     * from -Wtype-limits on platforms where
++     * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++    if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
++      parser->m_attsSize = oldAttsSize;
++      return XML_ERROR_NO_MEMORY;
++    }
++#endif
++
+     temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
+                                 parser->m_attsSize * sizeof(ATTRIBUTE));
+     if (temp == NULL) {
+@@ -3102,6 +3299,17 @@
+     }
+     parser->m_atts = temp;
+ #ifdef XML_ATTR_INFO
++    /* Detect and prevent integer overflow.
++     * The preprocessor guard addresses the "always false" warning
++     * from -Wtype-limits on platforms where
++     * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#  if UINT_MAX >= SIZE_MAX
++    if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
++      parser->m_attsSize = oldAttsSize;
++      return XML_ERROR_NO_MEMORY;
++    }
++#  endif
++
+     temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
+                                     parser->m_attsSize * sizeof(XML_AttrInfo));
+     if (temp2 == NULL) {
+@@ -3165,7 +3373,7 @@
+       /* normalize the attribute value */
+       result = storeAttributeValue(
+           parser, enc, isCdata, parser->m_atts[i].valuePtr,
+-          parser->m_atts[i].valueEnd, &parser->m_tempPool);
++          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
+       if (result)
+         return result;
+       appAtts[attIndex] = poolStart(&parser->m_tempPool);
+@@ -3240,8 +3448,16 @@
+   if (nPrefixes) {
+     int j; /* hash table index */
+     unsigned long version = parser->m_nsAttsVersion;
+-    int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+-    unsigned char oldNsAttsPower = parser->m_nsAttsPower;
++    unsigned int nsAttsSize;
++    unsigned char oldNsAttsPower;
++
++    /* Detect and prevent invalid shift */
++    if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
++      return XML_ERROR_NO_MEMORY;
++    }
++
++    nsAttsSize = 1u << parser->m_nsAttsPower;
++    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 */
+@@ -3251,7 +3467,28 @@
+         ;
+       if (parser->m_nsAttsPower < 3)
+         parser->m_nsAttsPower = 3;
+-      nsAttsSize = (int)1 << parser->m_nsAttsPower;
++
++      /* Detect and prevent invalid shift */
++      if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
++        /* Restore actual size of memory in m_nsAtts */
++        parser->m_nsAttsPower = oldNsAttsPower;
++        return XML_ERROR_NO_MEMORY;
++      }
++
++      nsAttsSize = 1u << parser->m_nsAttsPower;
++
++      /* Detect and prevent integer overflow.
++       * The preprocessor guard addresses the "always false" warning
++       * from -Wtype-limits on platforms where
++       * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++      if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
++        /* Restore actual size of memory in m_nsAtts */
++        parser->m_nsAttsPower = oldNsAttsPower;
++        return XML_ERROR_NO_MEMORY;
++      }
++#endif
++
+       temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
+                                nsAttsSize * sizeof(NS_ATT));
+       if (! temp) {
+@@ -3409,9 +3646,31 @@
+   tagNamePtr->prefixLen = prefixLen;
+   for (i = 0; localPart[i++];)
+     ; /* i includes null terminator */
++
++  /* Detect and prevent integer overflow */
++  if (binding->uriLen > INT_MAX - prefixLen
++      || i > INT_MAX - (binding->uriLen + prefixLen)) {
++    return XML_ERROR_NO_MEMORY;
++  }
++
+   n = i + binding->uriLen + prefixLen;
+   if (n > binding->uriAlloc) {
+     TAG *p;
++
++    /* Detect and prevent integer overflow */
++    if (n > INT_MAX - EXPAND_SPARE) {
++      return XML_ERROR_NO_MEMORY;
++    }
++    /* Detect and prevent integer overflow.
++     * The preprocessor guard addresses the "always false" warning
++     * from -Wtype-limits on platforms where
++     * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++    if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
++      return XML_ERROR_NO_MEMORY;
++    }
++#endif
++
+     uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
+     if (! uri)
+       return XML_ERROR_NO_MEMORY;
+@@ -3491,6 +3750,17 @@
+     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)) {
++      return XML_ERROR_SYNTAX;
++    }
+   }
+   isXML = isXML && len == xmlLen;
+   isXMLNS = isXMLNS && len == xmlnsLen;
+@@ -3507,7 +3777,24 @@
+   if (parser->m_freeBindingList) {
+     b = parser->m_freeBindingList;
+     if (len > b->uriAlloc) {
+-      XML_Char *temp = (XML_Char *)REALLOC(
++
++      XML_Char *temp;
++      /* Detect and prevent integer overflow */
++      if (len > INT_MAX - EXPAND_SPARE) {
++        return XML_ERROR_NO_MEMORY;
++      }
++
++      /* Detect and prevent integer overflow.
++       * The preprocessor guard addresses the "always false" warning
++       * from -Wtype-limits on platforms where
++       * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++      if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
++        return XML_ERROR_NO_MEMORY;
++      }
++#endif
++
++      temp = (XML_Char *)REALLOC(
+           parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
+       if (temp == NULL)
+         return XML_ERROR_NO_MEMORY;
+@@ -3519,6 +3806,21 @@
+     b = (BINDING *)MALLOC(parser, sizeof(BINDING));
+     if (! b)
+       return XML_ERROR_NO_MEMORY;
++
++    /* Detect and prevent integer overflow */
++    if (len > INT_MAX - EXPAND_SPARE) {
++      return XML_ERROR_NO_MEMORY;
++    }
++    /* Detect and prevent integer overflow.
++     * The preprocessor guard addresses the "always false" warning
++     * from -Wtype-limits on platforms where
++     * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++    if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
++      return XML_ERROR_NO_MEMORY;
++    }
++#endif
++
+     b->uri
+         = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
+     if (! b->uri) {
+@@ -3556,7 +3858,7 @@
+                       const char **endPtr) {
+   enum XML_Error result
+       = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
+-                       (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                       (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
+   if (result != XML_ERROR_NONE)
+     return result;
+   if (start) {
+@@ -3576,7 +3878,8 @@
+ */
+ static enum XML_Error
+ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
+-               const char *end, const char **nextPtr, XML_Bool haveMore) {
++               const char *end, const char **nextPtr, XML_Bool haveMore,
++               enum XML_Account account) {
+   const char *s = *startPtr;
+   const char **eventPP;
+   const char **eventEndPP;
+@@ -3594,6 +3897,12 @@
+   for (;;) {
+     const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
+     int tok = XmlCdataSectionTok(enc, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     *eventEndPP = next;
+     switch (tok) {
+     case XML_TOK_CDATA_SECT_CLOSE:
+@@ -3738,6 +4047,13 @@
+   *eventPP = s;
+   *startPtr = NULL;
+   tok = XmlIgnoreSectionTok(enc, s, end, &next);
++#  ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#  endif
+   *eventEndPP = next;
+   switch (tok) {
+   case XML_TOK_IGNORE_SECT:
+@@ -3822,6 +4138,15 @@
+   const char *versionend;
+   const XML_Char *storedversion = NULL;
+   int standalone = -1;
++
++#ifdef XML_DTD
++  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
++                                XML_ACCOUNT_DIRECT)) {
++    accountingOnAbort(parser);
++    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++  }
++#endif
++
+   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
+           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
+@@ -3971,6 +4296,10 @@
+ 
+   for (;;) {
+     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
++    /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
++             - storeEntityValue
++             - processXmlDecl
++    */
+     parser->m_eventEndPtr = next;
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
+@@ -3989,7 +4318,8 @@
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, parser->m_encoding, s, end);
++      return storeEntityValue(parser, parser->m_encoding, s, end,
++                              XML_ACCOUNT_DIRECT);
+     } else if (tok == XML_TOK_XML_DECL) {
+       enum XML_Error result;
+       result = processXmlDecl(parser, 0, start, next);
+@@ -4016,6 +4346,14 @@
+     */
+     else if (tok == XML_TOK_BOM && next == end
+              && ! parser->m_parsingStatus.finalBuffer) {
++#  ifdef XML_DTD
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                    XML_ACCOUNT_DIRECT)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++#  endif
++
+       *nextPtr = next;
+       return XML_ERROR_NONE;
+     }
+@@ -4058,16 +4396,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
+-     as valid, and report a syntax error, so we have to skip the BOM
++     as valid, and report a syntax error, so we have to skip the BOM, and
++     account for the BOM bytes.
+   */
+   else if (tok == XML_TOK_BOM) {
++	if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++	                              XML_ACCOUNT_DIRECT)) {
++	  accountingOnAbort(parser);
++	  return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++	}
++
+     s = next;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+   }
+ 
+   parser->m_processor = prologProcessor;
+   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++          (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++          XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error PTRCALL
+@@ -4080,6 +4426,9 @@
+ 
+   for (;;) {
+     tok = XmlPrologTok(enc, start, end, &next);
++    /* Note: These bytes are accounted later in:
++             - storeEntityValue
++    */
+     if (tok <= 0) {
+       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
+         *nextPtr = s;
+@@ -4097,7 +4446,7 @@
+         break;
+       }
+       /* found end of entity value - can store it now */
+-      return storeEntityValue(parser, enc, s, end);
++      return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
+     }
+     start = next;
+   }
+@@ -4111,13 +4460,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,
+-                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++          (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++          XML_ACCOUNT_DIRECT);
+ }
+ 
+ static enum XML_Error
+ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
+-         XML_Bool allowClosingDoctype) {
++         XML_Bool allowClosingDoctype, enum XML_Account account) {
+ #ifdef XML_DTD
+   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
+ #endif /* XML_DTD */
+@@ -4144,6 +4494,10 @@
+   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
+ 
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   /* save one level of indirection */
+   DTD *const dtd = parser->m_dtd;
+ 
+@@ -4208,6 +4562,19 @@
+       }
+     }
+     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
++#ifdef XML_DTD
++    switch (role) {
++    case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
++    case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
++    case XML_ROLE_TEXT_DECL:      // bytes accounted in processXmlDecl
++      break;
++    default:
++      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
++        accountingOnAbort(parser);
++        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      }
++    }
++#endif
+     switch (role) {
+     case XML_ROLE_XML_DECL: {
+       enum XML_Error result = processXmlDecl(parser, 0, s, next);
+@@ -4483,7 +4850,8 @@
+         const XML_Char *attVal;
+         enum XML_Error result = storeAttributeValue(
+             parser, enc, parser->m_declAttributeIsCdata,
+-            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
++            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
++            XML_ACCOUNT_NONE);
+         if (result)
+           return result;
+         attVal = poolStart(&dtd->pool);
+@@ -4516,8 +4884,9 @@
+       break;
+     case XML_ROLE_ENTITY_VALUE:
+       if (dtd->keepProcessing) {
+-        enum XML_Error result = storeEntityValue(
+-            parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
++          enum XML_Error result
++              = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
++                                 next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
+         if (parser->m_declEntity) {
+           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
+           parser->m_declEntity->textLen
+@@ -4776,7 +5145,13 @@
+       if (parser->m_prologState.level >= parser->m_groupSize) {
+         if (parser->m_groupSize) {
+           {
+-            char *const new_connector = (char *)REALLOC(
++            char * new_connector;
++            /* Detect and prevent integer overflow */
++            if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
++              return XML_ERROR_NO_MEMORY;
++            }
++
++            new_connector = (char *)REALLOC(
+                 parser, parser->m_groupConnector, parser->m_groupSize *= 2);
+             if (new_connector == NULL) {
+               parser->m_groupSize /= 2;
+@@ -4786,7 +5161,18 @@
+           }
+ 
+           if (dtd->scaffIndex) {
+-            int *const new_scaff_index = (int *)REALLOC(
++            int *new_scaff_index;
++            /* Detect and prevent integer overflow.
++             * The preprocessor guard addresses the "always false" warning
++             * from -Wtype-limits on platforms where
++             * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++            if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
++              return XML_ERROR_NO_MEMORY;
++            }
++#endif
++
++            new_scaff_index = (int *)REALLOC(
+                 parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
+             if (new_scaff_index == NULL)
+               return XML_ERROR_NO_MEMORY;
+@@ -4907,12 +5293,15 @@
+         if (parser->m_externalEntityRefHandler) {
+           dtd->paramEntityRead = XML_FALSE;
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           if (! parser->m_externalEntityRefHandler(
+                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
+                   entity->systemId, entity->publicId)) {
++        	entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+           }
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           handleDefault = XML_FALSE;
+           if (! dtd->paramEntityRead) {
+@@ -4991,7 +5380,7 @@
+       if (dtd->in_eldecl) {
+         ELEMENT_TYPE *el;
+         const XML_Char *name;
+-        int nameLen;
++        size_t nameLen;
+         const char *nxt
+             = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
+         int myindex = nextScaffoldPart(parser);
+@@ -5007,7 +5396,13 @@
+         nameLen = 0;
+         for (; name[nameLen++];)
+           ;
+-        dtd->contentStringLen += nameLen;
++
++        /* Detect and prevent integer overflow */
++        if (nameLen > UINT_MAX - dtd->contentStringLen) {
++          return XML_ERROR_NO_MEMORY;
++        }
++
++        dtd->contentStringLen += (unsigned)nameLen;
+         if (parser->m_elementDeclHandler)
+           handleDefault = XML_FALSE;
+       }
+@@ -5110,6 +5505,13 @@
+   for (;;) {
+     const char *next = NULL;
+     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
++                                  XML_ACCOUNT_DIRECT)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     parser->m_eventEndPtr = next;
+     switch (tok) {
+     /* report partial linebreak - it might be the last token */
+@@ -5183,6 +5585,9 @@
+       return XML_ERROR_NO_MEMORY;
+   }
+   entity->open = XML_TRUE;
++#ifdef XML_DTD
++  entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+   entity->processed = 0;
+   openEntity->next = parser->m_openInternalEntities;
+   parser->m_openInternalEntities = openEntity;
+@@ -5201,17 +5606,22 @@
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+-                      tok, next, &next, XML_FALSE, XML_FALSE);
++            tok, next, &next, XML_FALSE, XML_FALSE,
++            XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
+-                       textStart, textEnd, &next, XML_FALSE);
++            textStart, textEnd, &next, XML_FALSE,
++            XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result == XML_ERROR_NONE) {
+     if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+       entity->processed = (int)(next - textStart);
+       parser->m_processor = internalEntityProcessor;
+     } else {
++#ifdef XML_DTD
++      entityTrackingOnClose(parser, entity, __LINE__);
++#endif /* XML_DTD */
+       entity->open = XML_FALSE;
+       parser->m_openInternalEntities = openEntity->next;
+       /* put openEntity back in list of free instances */
+@@ -5244,12 +5654,13 @@
+     int tok
+         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+-                      tok, next, &next, XML_FALSE, XML_TRUE);
++            tok, next, &next, XML_FALSE, XML_TRUE,
++            XML_ACCOUNT_ENTITY_EXPANSION);
+   } else
+ #endif /* XML_DTD */
+     result = doContent(parser, openEntity->startTagLevel,
+                        parser->m_internalEncoding, textStart, textEnd, &next,
+-                       XML_FALSE);
++                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
+ 
+   if (result != XML_ERROR_NONE)
+     return result;
+@@ -5258,6 +5669,9 @@
+     entity->processed = (int)(next - (const char *)entity->textPtr);
+     return result;
+   } else {
++#ifdef XML_DTD
++    entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+     entity->open = XML_FALSE;
+     parser->m_openInternalEntities = openEntity->next;
+     /* put openEntity back in list of free instances */
+@@ -5271,7 +5685,8 @@
+     parser->m_processor = prologProcessor;
+     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+     return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+-                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
++            (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
++            XML_ACCOUNT_DIRECT);
+   } else
+ #endif /* XML_DTD */
+   {
+@@ -5279,7 +5694,8 @@
+     /* see externalEntityContentProcessor vs contentProcessor */
+     return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
+                      s, end, nextPtr,
+-                     (XML_Bool)! parser->m_parsingStatus.finalBuffer);
++                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
++                     XML_ACCOUNT_DIRECT);
+   }
+ }
+ 
+@@ -5294,9 +5710,10 @@
+ 
+ static enum XML_Error
+ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+-                    const char *ptr, const char *end, STRING_POOL *pool) {
++        const char *ptr, const char *end, STRING_POOL *pool,
++        enum XML_Account account) {
+   enum XML_Error result
+-      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
++      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
+   if (result)
+     return result;
+   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+@@ -5308,11 +5725,23 @@
+ 
+ static enum XML_Error
+ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+-                     const char *ptr, const char *end, STRING_POOL *pool) {
++                     const char *ptr, const char *end, STRING_POOL *pool,
++                     enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
++#ifndef XML_DTD
++  UNUSED_P(account);
++#endif
++
+   for (;;) {
+-    const char *next;
++	  const char *next
++	        = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
+     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
++      accountingOnAbort(parser);
++      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++    }
++#endif
+     switch (tok) {
+     case XML_TOK_NONE:
+       return XML_ERROR_NONE;
+@@ -5372,6 +5801,14 @@
+       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
+       if (ch) {
++#ifdef XML_DTD
++        /* NOTE: We are replacing 4-6 characters original input for 1 character
++         *       so there is no amplification and hence recording without
++         *       protection. */
++        accountingDiffTolerated(parser, tok, (char *)&ch,
++                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
++                                XML_ACCOUNT_ENTITY_EXPANSION);
++#endif /* XML_DTD */
+         if (! poolAppendChar(pool, ch))
+           return XML_ERROR_NO_MEMORY;
+         break;
+@@ -5449,9 +5886,16 @@
+         enum XML_Error result;
+         const XML_Char *textEnd = entity->textPtr + entity->textLen;
+         entity->open = XML_TRUE;
++#ifdef XML_DTD
++        entityTrackingOnOpen(parser, entity, __LINE__);
++#endif
+         result = appendAttributeValue(parser, parser->m_internalEncoding,
+                                       isCdata, (const char *)entity->textPtr,
+-                                      (const char *)textEnd, pool);
++                                      (const char *)textEnd, pool,
++                                      XML_ACCOUNT_ENTITY_EXPANSION);
++#ifdef XML_DTD
++        entityTrackingOnClose(parser, entity, __LINE__);
++#endif
+         entity->open = XML_FALSE;
+         if (result)
+           return result;
+@@ -5481,13 +5925,16 @@
+ 
+ static enum XML_Error
+ storeEntityValue(XML_Parser parser, const ENCODING *enc,
+-                 const char *entityTextPtr, const char *entityTextEnd) {
++                 const char *entityTextPtr, const char *entityTextEnd,
++                 enum XML_Account account) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   STRING_POOL *pool = &(dtd->entityValuePool);
+   enum XML_Error result = XML_ERROR_NONE;
+ #ifdef XML_DTD
+   int oldInEntityValue = parser->m_prologState.inEntityValue;
+   parser->m_prologState.inEntityValue = 1;
++#else
++  UNUSED_P(account);
+ #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 @@
+   }
+ 
+   for (;;) {
+-    const char *next;
++	  const char *next
++	      = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
+     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
++
++#ifdef XML_DTD
++    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
++                                  account)) {
++      accountingOnAbort(parser);
++      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
++      goto endEntityValue;
++    }
++#endif
++
+     switch (tok) {
+     case XML_TOK_PARAM_ENTITY_REF:
+ #ifdef XML_DTD
+@@ -5535,13 +5993,16 @@
+           if (parser->m_externalEntityRefHandler) {
+             dtd->paramEntityRead = XML_FALSE;
+             entity->open = XML_TRUE;
++            entityTrackingOnOpen(parser, entity, __LINE__);
+             if (! parser->m_externalEntityRefHandler(
+                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
+                     entity->systemId, entity->publicId)) {
++                entityTrackingOnClose(parser, entity, __LINE__);
+               entity->open = XML_FALSE;
+               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+               goto endEntityValue;
+             }
++            entityTrackingOnClose(parser, entity, __LINE__);
+             entity->open = XML_FALSE;
+             if (! dtd->paramEntityRead)
+               dtd->keepProcessing = dtd->standalone;
+@@ -5549,9 +6010,12 @@
+             dtd->keepProcessing = dtd->standalone;
+         } else {
+           entity->open = XML_TRUE;
++          entityTrackingOnOpen(parser, entity, __LINE__);
+           result = storeEntityValue(
+               parser, parser->m_internalEncoding, (const char *)entity->textPtr,
+-              (const char *)(entity->textPtr + entity->textLen));
++              (const char *)(entity->textPtr + entity->textLen),
++              XML_ACCOUNT_ENTITY_EXPANSION);
++          entityTrackingOnClose(parser, entity, __LINE__);
+           entity->open = XML_FALSE;
+           if (result)
+             goto endEntityValue;
+@@ -5784,7 +6248,25 @@
+       }
+     } else {
+       DEFAULT_ATTRIBUTE *temp;
+-      int count = type->allocDefaultAtts * 2;
++      int count;
++
++      /* Detect and prevent integer overflow */
++      if (type->allocDefaultAtts > INT_MAX / 2) {
++        return 0;
++      }
++
++      count = type->allocDefaultAtts * 2;
++
++      /* Detect and prevent integer overflow.
++       * The preprocessor guard addresses the "always false" warning
++       * from -Wtype-limits on platforms where
++       * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++      if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
++        return 0;
++      }
++#endif
++
+       temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
+                                           (count * sizeof(DEFAULT_ATTRIBUTE)));
+       if (temp == NULL)
+@@ -6435,10 +6917,26 @@
+     /* check for overflow (table is half full) */
+     if (table->used >> (table->power - 1)) {
+       unsigned char newPower = table->power + 1;
+-      size_t newSize = (size_t)1 << newPower;
+-      unsigned long newMask = (unsigned long)newSize - 1;
+-      size_t tsize = newSize * sizeof(NAMED *);
+-      NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
++      size_t newSize;
++      unsigned long newMask;
++      size_t tsize;
++      NAMED **newV;
++
++      /* Detect and prevent invalid shift */
++      if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
++        return NULL;
++      }
++
++      newSize = (size_t)1 << newPower;
++      newMask = (unsigned long)newSize - 1;
++
++      /* Detect and prevent integer overflow */
++      if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
++        return NULL;
++      }
++
++      tsize = newSize * sizeof(NAMED *);
++      newV = (NAMED **)table->mem->malloc_fcn(tsize);
+       if (! newV)
+         return NULL;
+       memset(newV, 0, tsize);
+@@ -6786,6 +7284,20 @@
+   if (dtd->scaffCount >= dtd->scaffSize) {
+     CONTENT_SCAFFOLD *temp;
+     if (dtd->scaffold) {
++      /* Detect and prevent integer overflow */
++      if (dtd->scaffSize > UINT_MAX / 2u) {
++        return -1;
++      }
++      /* Detect and prevent integer overflow.
++       * The preprocessor guard addresses the "always false" warning
++       * from -Wtype-limits on platforms where
++       * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++      if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
++        return -1;
++      }
++#endif
++
+       temp = (CONTENT_SCAFFOLD *)REALLOC(
+           parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+       if (temp == NULL)
+@@ -6817,55 +7329,130 @@
+   return next;
+ }
+ 
+-static void
+-build_node(XML_Parser parser, int src_node, XML_Content *dest,
+-           XML_Content **contpos, XML_Char **strpos) {
+-  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+-  dest->type = dtd->scaffold[src_node].type;
+-  dest->quant = dtd->scaffold[src_node].quant;
+-  if (dest->type == XML_CTYPE_NAME) {
+-    const XML_Char *src;
+-    dest->name = *strpos;
+-    src = dtd->scaffold[src_node].name;
+-    for (;;) {
+-      *(*strpos)++ = *src;
+-      if (! *src)
+-        break;
+-      src++;
+-    }
+-    dest->numchildren = 0;
+-    dest->children = NULL;
+-  } else {
+-    unsigned int i;
+-    int cn;
+-    dest->numchildren = dtd->scaffold[src_node].childcnt;
+-    dest->children = *contpos;
+-    *contpos += dest->numchildren;
+-    for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
+-         i++, cn = dtd->scaffold[cn].nextsib) {
+-      build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+-    }
+-    dest->name = NULL;
+-  }
+-}
+-
+ static XML_Content *
+ build_model(XML_Parser parser) {
+   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+   XML_Content *ret;
+-  XML_Content *cpos;
+-  XML_Char *str;
+-  int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+-                   + (dtd->contentStringLen * sizeof(XML_Char)));
++  XML_Char *str; /* the current string writing location */
++  size_t allocsize;
++  XML_Content *dest; /* tree node writing location, moves upwards */
++  XML_Content *destLimit;
++  XML_Content *jobDest; /* next free writing location in target array */
++
++  /* Detect and prevent integer overflow.
++   * The preprocessor guard addresses the "always false" warning
++   * from -Wtype-limits on platforms where
++   * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
++#if UINT_MAX >= SIZE_MAX
++  if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
++    return NULL;
++  }
++  if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
++    return NULL;
++  }
++#endif
++  if (dtd->scaffCount * sizeof(XML_Content)
++      > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
++    return NULL;
++  }
++
++  allocsize = (dtd->scaffCount * sizeof(XML_Content)
++                            + (dtd->contentStringLen * sizeof(XML_Char)));
+ 
+   ret = (XML_Content *)MALLOC(parser, allocsize);
+   if (! ret)
+     return NULL;
+ 
+-  str = (XML_Char *)(&ret[dtd->scaffCount]);
+-  cpos = &ret[1];
++  /* What follows is an iterative implementation (of what was previously done
++   * recursively in a dedicated function called "build_node".  The old recursive
++   * build_node could be forced into stack exhaustion from input as small as a
++   * few megabyte, and so that was a security issue.  Hence, a function call
++   * stack is avoided now by resolving recursion.)
++   *
++   * The iterative approach works as follows:
++   *
++   * - We have two writing pointers, both walking up the result array; one does
++   *   the work, the other creates "jobs" for its colleague to do, and leads
++   *   the way:
++   *
++   *   - The faster one, pointer jobDest, always leads and writes "what job
++   *     to do" by the other, once they reach that place in the
++   *     array: leader "jobDest" stores the source node array index (relative
++   *     to array dtd->scaffold) in field "numchildren".
++   *
++   *   - The slower one, pointer dest, looks at the value stored in the
++   *     "numchildren" field (which actually holds a source node array index
++   *     at that time) and puts the real data from dtd->scaffold in.
++   *
++   * - Before the loop starts, jobDest writes source array index 0
++   *   (where the root node is located) so that dest will have something to do
++   *   when it starts operation.
++   *
++   * - Whenever nodes with children are encountered, jobDest appends
++   *   them as new jobs, in order.  As a result, tree node siblings are
++   *   adjacent in the resulting array, for example:
++   *
++   *     [0] root, has two children
++   *       [1] first child of 0, has three children
++   *         [3] first child of 1, does not have children
++   *         [4] second child of 1, does not have children
++   *         [5] third child of 1, does not have children
++   *       [2] second child of 0, does not have children
++   *
++   *   Or (the same data) presented in flat array view:
++   *
++   *     [0] root, has two children
++   *
++   *     [1] first child of 0, has three children
++   *     [2] second child of 0, does not have children
++   *
++   *     [3] first child of 1, does not have children
++   *     [4] second child of 1, does not have children
++   *     [5] third child of 1, does not have children
++   *
++   * - The algorithm repeats until all target array indices have been processed.
++   */
++  dest = ret; /* tree node writing location, moves upwards */
++  destLimit = &ret[dtd->scaffCount];
++  jobDest = ret; /* next free writing location in target array */
++  str = (XML_Char *)&ret[dtd->scaffCount];
++
++  /* Add the starting job, the root node (index 0) of the source tree  */
++  (jobDest++)->numchildren = 0;
++
++  for (; dest < destLimit; dest++) {
++    /* Retrieve source tree array index from job storage */
++    const int src_node = (int)dest->numchildren;
++
++    /* Convert item */
++    dest->type = dtd->scaffold[src_node].type;
++    dest->quant = dtd->scaffold[src_node].quant;
++    if (dest->type == XML_CTYPE_NAME) {
++      const XML_Char *src;
++      dest->name = str;
++      src = dtd->scaffold[src_node].name;
++      for (;;) {
++        *str++ = *src;
++        if (! *src)
++          break;
++        src++;
++      }
++      dest->numchildren = 0;
++      dest->children = NULL;
++    } else {
++      unsigned int i;
++      int cn;
++      dest->name = NULL;
++      dest->numchildren = dtd->scaffold[src_node].childcnt;
++      dest->children = jobDest;
++
++      /* Append scaffold indices of children to array */
++      for (i = 0, cn = dtd->scaffold[src_node].firstchild;
++           i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
++        (jobDest++)->numchildren = (unsigned int)cn;
++    }
++  }
+ 
+-  build_node(parser, 0, ret, &cpos, &str);
+   return ret;
+ }
+ 
+@@ -6894,7 +7481,7 @@
+ 
+ static XML_Char *
+ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
+-  int charsRequired = 0;
++  size_t charsRequired = 0;
+   XML_Char *result;
+ 
+   /* First determine how long the string is */
+@@ -6912,3 +7499,766 @@
+   memcpy(result, s, charsRequired * sizeof(XML_Char));
+   return result;
+ }
++#ifdef XML_DTD
++
++static float
++accountingGetCurrentAmplification(XML_Parser rootParser) {
++  const XmlBigCount countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  const float amplificationFactor
++      = rootParser->m_accounting.countBytesDirect
++            ? (countBytesOutput
++               / (float)(rootParser->m_accounting.countBytesDirect))
++            : 1.0f;
++  assert(! rootParser->m_parentParser);
++  return amplificationFactor;
++}
++
++static void
++accountingReportStats(XML_Parser originParser, const char *epilog) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  float amplificationFactor;
++  assert(! rootParser->m_parentParser);
++
++  if (rootParser->m_accounting.debugLevel < 1) {
++    return;
++  }
++
++  amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  fprintf(stderr,
++          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
++              "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
++          (void *)rootParser, rootParser->m_accounting.countBytesDirect,
++          rootParser->m_accounting.countBytesIndirect,
++          (double)amplificationFactor, epilog);
++}
++
++static void
++accountingOnAbort(XML_Parser originParser) {
++  accountingReportStats(originParser, " ABORTING\n");
++}
++
++static void
++accountingReportDiff(XML_Parser rootParser,
++                     unsigned int levelsAwayFromRootParser, const char *before,
++                     const char *after, ptrdiff_t bytesMore, int source_line,
++                     enum XML_Account account) {
++  const char ellipis[] = "[..]";
++  const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
++  const unsigned int contextLength = 10;
++  const char *walker = before;
++
++  assert(! rootParser->m_parentParser);
++
++  fprintf(stderr,
++          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
++          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
++          levelsAwayFromRootParser, source_line, 10, "");
++
++  /* Note: Performance is of no concern here */
++  if ((rootParser->m_accounting.debugLevel >= 3)
++      || (after - before)
++             <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  } else {
++    for (; walker < before + contextLength; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++    fprintf(stderr, ellipis);
++    walker = after - contextLength;
++    for (; walker < after; walker++) {
++      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
++    }
++  }
++  fprintf(stderr, "\"\n");
++}
++
++static XML_Bool
++accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
++                        const char *after, int source_line,
++                        enum XML_Account account) {
++  unsigned int levelsAwayFromRootParser;
++  XML_Parser rootParser;
++  int isDirect;
++  ptrdiff_t bytesMore;
++  XmlBigCount * additionTarget;
++  XmlBigCount countBytesOutput;
++  float amplificationFactor;
++  XML_Bool tolerated;
++  /* Note: We need to check the token type *first* to be sure that
++   *       we can even access variable <after>, safely.
++   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
++  switch (tok) {
++  case XML_TOK_INVALID:
++  case XML_TOK_PARTIAL:
++  case XML_TOK_PARTIAL_CHAR:
++  case XML_TOK_NONE:
++    return XML_TRUE;
++  }
++
++  if (account == XML_ACCOUNT_NONE)
++    return XML_TRUE; /* because these bytes have been accounted for, already */
++
++  rootParser
++      = getRootParserOf(originParser, &levelsAwayFromRootParser);
++  assert(! rootParser->m_parentParser);
++
++  isDirect
++      = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
++  bytesMore = after - before;
++
++  additionTarget
++      = isDirect ? &rootParser->m_accounting.countBytesDirect
++                 : &rootParser->m_accounting.countBytesIndirect;
++
++  /* Detect and avoid integer overflow */
++  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
++    return XML_FALSE;
++  *additionTarget += bytesMore;
++
++  countBytesOutput
++      = rootParser->m_accounting.countBytesDirect
++        + rootParser->m_accounting.countBytesIndirect;
++  amplificationFactor
++      = accountingGetCurrentAmplification(rootParser);
++  tolerated
++      = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
++        || (amplificationFactor
++            <= rootParser->m_accounting.maximumAmplificationFactor);
++
++  if (rootParser->m_accounting.debugLevel >= 2) {
++    accountingReportStats(rootParser, "");
++    accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
++                         bytesMore, source_line, account);
++  }
++
++  return tolerated;
++}
++
++unsigned long long
++testingAccountingGetCountBytesDirect(XML_Parser parser) {
++  if (! parser)
++    return 0;
++  return parser->m_accounting.countBytesDirect;
++}
++
++unsigned long long
++testingAccountingGetCountBytesIndirect(XML_Parser parser) {
++  if (! parser)
++    return 0;
++  return parser->m_accounting.countBytesIndirect;
++}
++
++static void
++entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
++                          const char *action, int sourceLine) {
++  const char * entityName;
++  assert(! rootParser->m_parentParser);
++  if (rootParser->m_entity_stats.debugLevel < 1)
++    return;
++
++#  if defined(XML_UNICODE)
++  entityName = "[..]";
++#  else
++  entityName = entity->name;
++#  endif
++
++  fprintf(
++      stderr,
++      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
++      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
++      rootParser->m_entity_stats.currentDepth,
++      rootParser->m_entity_stats.maximumDepthSeen,
++      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
++      entity->is_param ? "%" : "&", entityName, action, entity->textLen,
++      sourceLine);
++}
++
++static void
++entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  rootParser->m_entity_stats.countEverOpened++;
++  rootParser->m_entity_stats.currentDepth++;
++  if (rootParser->m_entity_stats.currentDepth
++      > rootParser->m_entity_stats.maximumDepthSeen) {
++    rootParser->m_entity_stats.maximumDepthSeen++;
++  }
++
++  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
++}
++
++static void
++entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
++  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
++  assert(! rootParser->m_parentParser);
++
++  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
++  rootParser->m_entity_stats.currentDepth--;
++}
++
++static XML_Parser
++getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
++  XML_Parser rootParser = parser;
++  unsigned int stepsTakenUpwards = 0;
++  while (rootParser->m_parentParser) {
++    rootParser = rootParser->m_parentParser;
++    stepsTakenUpwards++;
++  }
++  assert(! rootParser->m_parentParser);
++  if (outLevelDiff != NULL) {
++    *outLevelDiff = stepsTakenUpwards;
++  }
++  return rootParser;
++}
++
++const char *
++unsignedCharToPrintable(unsigned char c) {
++  switch (c) {
++  case 0:
++    return "\\0";
++  case 1:
++    return "\\x1";
++  case 2:
++    return "\\x2";
++  case 3:
++    return "\\x3";
++  case 4:
++    return "\\x4";
++  case 5:
++    return "\\x5";
++  case 6:
++    return "\\x6";
++  case 7:
++    return "\\x7";
++  case 8:
++    return "\\x8";
++  case 9:
++    return "\\t";
++  case 10:
++    return "\\n";
++  case 11:
++    return "\\xB";
++  case 12:
++    return "\\xC";
++  case 13:
++    return "\\r";
++  case 14:
++    return "\\xE";
++  case 15:
++    return "\\xF";
++  case 16:
++    return "\\x10";
++  case 17:
++    return "\\x11";
++  case 18:
++    return "\\x12";
++  case 19:
++    return "\\x13";
++  case 20:
++    return "\\x14";
++  case 21:
++    return "\\x15";
++  case 22:
++    return "\\x16";
++  case 23:
++    return "\\x17";
++  case 24:
++    return "\\x18";
++  case 25:
++    return "\\x19";
++  case 26:
++    return "\\x1A";
++  case 27:
++    return "\\x1B";
++  case 28:
++    return "\\x1C";
++  case 29:
++    return "\\x1D";
++  case 30:
++    return "\\x1E";
++  case 31:
++    return "\\x1F";
++  case 32:
++    return " ";
++  case 33:
++    return "!";
++  case 34:
++    return "\\\"";
++  case 35:
++    return "#";
++  case 36:
++    return "$";
++  case 37:
++    return "%";
++  case 38:
++    return "&";
++  case 39:
++    return "'";
++  case 40:
++    return "(";
++  case 41:
++    return ")";
++  case 42:
++    return "*";
++  case 43:
++    return "+";
++  case 44:
++    return ",";
++  case 45:
++    return "-";
++  case 46:
++    return ".";
++  case 47:
++    return "/";
++  case 48:
++    return "0";
++  case 49:
++    return "1";
++  case 50:
++    return "2";
++  case 51:
++    return "3";
++  case 52:
++    return "4";
++  case 53:
++    return "5";
++  case 54:
++    return "6";
++  case 55:
++    return "7";
++  case 56:
++    return "8";
++  case 57:
++    return "9";
++  case 58:
++    return ":";
++  case 59:
++    return ";";
++  case 60:
++    return "<";
++  case 61:
++    return "=";
++  case 62:
++    return ">";
++  case 63:
++    return "?";
++  case 64:
++    return "@";
++  case 65:
++    return "A";
++  case 66:
++    return "B";
++  case 67:
++    return "C";
++  case 68:
++    return "D";
++  case 69:
++    return "E";
++  case 70:
++    return "F";
++  case 71:
++    return "G";
++  case 72:
++    return "H";
++  case 73:
++    return "I";
++  case 74:
++    return "J";
++  case 75:
++    return "K";
++  case 76:
++    return "L";
++  case 77:
++    return "M";
++  case 78:
++    return "N";
++  case 79:
++    return "O";
++  case 80:
++    return "P";
++  case 81:
++    return "Q";
++  case 82:
++    return "R";
++  case 83:
++    return "S";
++  case 84:
++    return "T";
++  case 85:
++    return "U";
++  case 86:
++    return "V";
++  case 87:
++    return "W";
++  case 88:
++    return "X";
++  case 89:
++    return "Y";
++  case 90:
++    return "Z";
++  case 91:
++    return "[";
++  case 92:
++    return "\\\\";
++  case 93:
++    return "]";
++  case 94:
++    return "^";
++  case 95:
++    return "_";
++  case 96:
++    return "`";
++  case 97:
++    return "a";
++  case 98:
++    return "b";
++  case 99:
++    return "c";
++  case 100:
++    return "d";
++  case 101:
++    return "e";
++  case 102:
++    return "f";
++  case 103:
++    return "g";
++  case 104:
++    return "h";
++  case 105:
++    return "i";
++  case 106:
++    return "j";
++  case 107:
++    return "k";
++  case 108:
++    return "l";
++  case 109:
++    return "m";
++  case 110:
++    return "n";
++  case 111:
++    return "o";
++  case 112:
++    return "p";
++  case 113:
++    return "q";
++  case 114:
++    return "r";
++  case 115:
++    return "s";
++  case 116:
++    return "t";
++  case 117:
++    return "u";
++  case 118:
++    return "v";
++  case 119:
++    return "w";
++  case 120:
++    return "x";
++  case 121:
++    return "y";
++  case 122:
++    return "z";
++  case 123:
++    return "{";
++  case 124:
++    return "|";
++  case 125:
++    return "}";
++  case 126:
++    return "~";
++  case 127:
++    return "\\x7F";
++  case 128:
++    return "\\x80";
++  case 129:
++    return "\\x81";
++  case 130:
++    return "\\x82";
++  case 131:
++    return "\\x83";
++  case 132:
++    return "\\x84";
++  case 133:
++    return "\\x85";
++  case 134:
++    return "\\x86";
++  case 135:
++    return "\\x87";
++  case 136:
++    return "\\x88";
++  case 137:
++    return "\\x89";
++  case 138:
++    return "\\x8A";
++  case 139:
++    return "\\x8B";
++  case 140:
++    return "\\x8C";
++  case 141:
++    return "\\x8D";
++  case 142:
++    return "\\x8E";
++  case 143:
++    return "\\x8F";
++  case 144:
++    return "\\x90";
++  case 145:
++    return "\\x91";
++  case 146:
++    return "\\x92";
++  case 147:
++    return "\\x93";
++  case 148:
++    return "\\x94";
++  case 149:
++    return "\\x95";
++  case 150:
++    return "\\x96";
++  case 151:
++    return "\\x97";
++  case 152:
++    return "\\x98";
++  case 153:
++    return "\\x99";
++  case 154:
++    return "\\x9A";
++  case 155:
++    return "\\x9B";
++  case 156:
++    return "\\x9C";
++  case 157:
++    return "\\x9D";
++  case 158:
++    return "\\x9E";
++  case 159:
++    return "\\x9F";
++  case 160:
++    return "\\xA0";
++  case 161:
++    return "\\xA1";
++  case 162:
++    return "\\xA2";
++  case 163:
++    return "\\xA3";
++  case 164:
++    return "\\xA4";
++  case 165:
++    return "\\xA5";
++  case 166:
++    return "\\xA6";
++  case 167:
++    return "\\xA7";
++  case 168:
++    return "\\xA8";
++  case 169:
++    return "\\xA9";
++  case 170:
++    return "\\xAA";
++  case 171:
++    return "\\xAB";
++  case 172:
++    return "\\xAC";
++  case 173:
++    return "\\xAD";
++  case 174:
++    return "\\xAE";
++  case 175:
++    return "\\xAF";
++  case 176:
++    return "\\xB0";
++  case 177:
++    return "\\xB1";
++  case 178:
++    return "\\xB2";
++  case 179:
++    return "\\xB3";
++  case 180:
++    return "\\xB4";
++  case 181:
++    return "\\xB5";
++  case 182:
++    return "\\xB6";
++  case 183:
++    return "\\xB7";
++  case 184:
++    return "\\xB8";
++  case 185:
++    return "\\xB9";
++  case 186:
++    return "\\xBA";
++  case 187:
++    return "\\xBB";
++  case 188:
++    return "\\xBC";
++  case 189:
++    return "\\xBD";
++  case 190:
++    return "\\xBE";
++  case 191:
++    return "\\xBF";
++  case 192:
++    return "\\xC0";
++  case 193:
++    return "\\xC1";
++  case 194:
++    return "\\xC2";
++  case 195:
++    return "\\xC3";
++  case 196:
++    return "\\xC4";
++  case 197:
++    return "\\xC5";
++  case 198:
++    return "\\xC6";
++  case 199:
++    return "\\xC7";
++  case 200:
++    return "\\xC8";
++  case 201:
++    return "\\xC9";
++  case 202:
++    return "\\xCA";
++  case 203:
++    return "\\xCB";
++  case 204:
++    return "\\xCC";
++  case 205:
++    return "\\xCD";
++  case 206:
++    return "\\xCE";
++  case 207:
++    return "\\xCF";
++  case 208:
++    return "\\xD0";
++  case 209:
++    return "\\xD1";
++  case 210:
++    return "\\xD2";
++  case 211:
++    return "\\xD3";
++  case 212:
++    return "\\xD4";
++  case 213:
++    return "\\xD5";
++  case 214:
++    return "\\xD6";
++  case 215:
++    return "\\xD7";
++  case 216:
++    return "\\xD8";
++  case 217:
++    return "\\xD9";
++  case 218:
++    return "\\xDA";
++  case 219:
++    return "\\xDB";
++  case 220:
++    return "\\xDC";
++  case 221:
++    return "\\xDD";
++  case 222:
++    return "\\xDE";
++  case 223:
++    return "\\xDF";
++  case 224:
++    return "\\xE0";
++  case 225:
++    return "\\xE1";
++  case 226:
++    return "\\xE2";
++  case 227:
++    return "\\xE3";
++  case 228:
++    return "\\xE4";
++  case 229:
++    return "\\xE5";
++  case 230:
++    return "\\xE6";
++  case 231:
++    return "\\xE7";
++  case 232:
++    return "\\xE8";
++  case 233:
++    return "\\xE9";
++  case 234:
++    return "\\xEA";
++  case 235:
++    return "\\xEB";
++  case 236:
++    return "\\xEC";
++  case 237:
++    return "\\xED";
++  case 238:
++    return "\\xEE";
++  case 239:
++    return "\\xEF";
++  case 240:
++    return "\\xF0";
++  case 241:
++    return "\\xF1";
++  case 242:
++    return "\\xF2";
++  case 243:
++    return "\\xF3";
++  case 244:
++    return "\\xF4";
++  case 245:
++    return "\\xF5";
++  case 246:
++    return "\\xF6";
++  case 247:
++    return "\\xF7";
++  case 248:
++    return "\\xF8";
++  case 249:
++    return "\\xF9";
++  case 250:
++    return "\\xFA";
++  case 251:
++    return "\\xFB";
++  case 252:
++    return "\\xFC";
++  case 253:
++    return "\\xFD";
++  case 254:
++    return "\\xFE";
++  case 255:
++    return "\\xFF";
++  default:
++    assert(0); /* never gets here */
++    return "dead code";
++  }
++  assert(0); /* never gets here */
++}
++
++#endif /* XML_DTD */
++
++static unsigned long
++getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
++  const char *const valueOrNull = getenv(variableName);
++  const char * value;
++  char *afterValue;
++  unsigned long debugLevel;
++  if (valueOrNull == NULL) {
++    return defaultDebugLevel;
++  }
++  value = valueOrNull;
++
++  errno = 0;
++  afterValue = (char *)value;
++  debugLevel = strtoul(value, &afterValue, 10);
++  if ((errno != 0) || (afterValue[0] != '\0')) {
++    errno = 0;
++    return defaultDebugLevel;
++  }
++
++  return debugLevel;
++}
+diff -ru misc/expat-2.2.10/lib/xmltok.c misc/build/expat-2.2.10/lib/xmltok.c
+--- misc/expat-2.2.10/lib/xmltok.c	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/xmltok.c	2022-03-05 12:25:27.583396678 +0100
+@@ -269,8 +269,14 @@
+ 
+ #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))
+-#define IS_INVALID_CHAR(enc, p, n)                                             \
+-  (AS_NORMAL_ENCODING(enc)->isInvalid##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
+ 
+ #ifdef XML_MIN_SIZE
+ #  define IS_NAME_CHAR_MINBPC(enc, p)                                          \
+diff -ru misc/expat-2.2.10/lib/xmltok_impl.c misc/build/expat-2.2.10/lib/xmltok_impl.c
+--- misc/expat-2.2.10/lib/xmltok_impl.c	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/xmltok_impl.c	2022-03-05 12:25:27.583396678 +0100
+@@ -61,7 +61,7 @@
+   case BT_LEAD##n:                                                             \
+     if (end - ptr < n)                                                         \
+       return XML_TOK_PARTIAL_CHAR;                                             \
+-    if (! IS_NAME_CHAR(enc, ptr, n)) {                                         \
++    if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) {         \
+       *nextTokPtr = ptr;                                                       \
+       return XML_TOK_INVALID;                                                  \
+     }                                                                          \
+@@ -90,7 +90,7 @@
+   case BT_LEAD##n:                                                             \
+     if (end - ptr < n)                                                         \
+       return XML_TOK_PARTIAL_CHAR;                                             \
+-    if (! IS_NMSTRT_CHAR(enc, ptr, n)) {                                       \
++    if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) {       \
+       *nextTokPtr = ptr;                                                       \
+       return XML_TOK_INVALID;                                                  \
+     }                                                                          \
+@@ -1134,6 +1134,10 @@
+   case BT_LEAD##n:                                                             \
+     if (end - ptr < n)                                                         \
+       return XML_TOK_PARTIAL_CHAR;                                             \
++    if (IS_INVALID_CHAR(enc, ptr, n)) {                                        \
++      *nextTokPtr = ptr;                                                       \
++      return XML_TOK_INVALID;                                                  \
++    }                                                                          \
+     if (IS_NMSTRT_CHAR(enc, ptr, n)) {                                         \
+       ptr += n;                                                                \
+       tok = XML_TOK_NAME;                                                      \
+diff -ru misc/expat-2.2.10/lib/xmltok_ns.c misc/build/expat-2.2.10/lib/xmltok_ns.c
+--- misc/expat-2.2.10/lib/xmltok_ns.c	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/lib/xmltok_ns.c	2022-03-05 12:25:27.583396678 +0100
+@@ -89,7 +89,7 @@
+ static const ENCODING *
+ NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) {
+ #  define ENCODING_MAX 128
+-  char buf[ENCODING_MAX];
++  char buf[ENCODING_MAX] = "";
+   char *p = buf;
+   int i;
+   XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+diff -ru misc/expat-2.2.10/tests/benchmark/Makefile.in misc/build/expat-2.2.10/tests/benchmark/Makefile.in
+--- misc/expat-2.2.10/tests/benchmark/Makefile.in	2020-10-03 17:37:06.000000000 +0200
++++ misc/build/expat-2.2.10/tests/benchmark/Makefile.in	2022-03-05 12:25:27.579396586 +0100
+@@ -1,7 +1,7 @@
+-# Makefile.in generated by automake 1.16.2 from Makefile.am.
++# Makefile.in generated by automake 1.16.1 from Makefile.am.
+ # @configure_input@
+ 
+-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
++# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ 
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -335,7 +335,6 @@
+ prefix = @prefix@
+ program_transform_name = @program_transform_name@
+ psdir = @psdir@
+-runstatedir = @runstatedir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
+ srcdir = @srcdir@
+diff -ru misc/expat-2.2.10/tests/Makefile.in misc/build/expat-2.2.10/tests/Makefile.in
+--- misc/expat-2.2.10/tests/Makefile.in	2020-10-03 17:37:06.000000000 +0200
++++ misc/build/expat-2.2.10/tests/Makefile.in	2022-03-05 12:25:27.579396586 +0100
+@@ -1,7 +1,7 @@
+-# Makefile.in generated by automake 1.16.2 from Makefile.am.
++# Makefile.in generated by automake 1.16.1 from Makefile.am.
+ # @configure_input@
+ 
+-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
++# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ 
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -616,7 +616,6 @@
+ prefix = @prefix@
+ program_transform_name = @program_transform_name@
+ psdir = @psdir@
+-runstatedir = @runstatedir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
+ srcdir = @srcdir@
+diff -ru misc/expat-2.2.10/tests/minicheck.c misc/build/expat-2.2.10/tests/minicheck.c
+--- misc/expat-2.2.10/tests/minicheck.c	2020-09-25 19:47:39.000000000 +0200
++++ misc/build/expat-2.2.10/tests/minicheck.c	2022-03-05 12:25:27.587396769 +0100
+@@ -141,11 +141,18 @@
+ }
+ 
+ static void
+-add_failure(SRunner *runner, int verbosity) {
+-  runner->nfailures++;
++handle_success(int verbosity) {
+   if (verbosity >= CK_VERBOSE) {
+-    printf("%s:%d: %s\n", _check_current_filename, _check_current_lineno,
+-           _check_current_function);
++    printf("PASS: %s\n", _check_current_function);
++  }
++}
++
++static void
++handle_failure(SRunner *runner, int verbosity, const char *phase_info) {
++  runner->nfailures++;
++  if (verbosity != CK_SILENT) {
++    printf("FAIL: %s (%s at %s:%d)\n", _check_current_function, phase_info,
++           _check_current_filename, _check_current_lineno);
+   }
+ }
+ 
+@@ -164,14 +171,14 @@
+       if (tc->setup != NULL) {
+         /* setup */
+         if (setjmp(env)) {
+-          add_failure(runner, verbosity);
++          handle_failure(runner, verbosity, "during setup");
+           continue;
+         }
+         tc->setup();
+       }
+       /* test */
+       if (setjmp(env)) {
+-        add_failure(runner, verbosity);
++        handle_failure(runner, verbosity, "during actual test");
+         continue;
+       }
+       (tc->tests[i])();
+@@ -179,15 +186,17 @@
+       /* teardown */
+       if (tc->teardown != NULL) {
+         if (setjmp(env)) {
+-          add_failure(runner, verbosity);
++          handle_failure(runner, verbosity, "during teardown");
+           continue;
+         }
+         tc->teardown();
+       }
++
++      handle_success(verbosity);
+     }
+     tc = tc->next_tcase;
+   }
+-  if (verbosity) {
++  if (verbosity != CK_SILENT) {
+     int passed = runner->nchecks - runner->nfailures;
+     double percentage = ((double)passed) / runner->nchecks;
+     int display = (int)(percentage * 100);
+@@ -203,8 +212,8 @@
+      it is.
+   */
+   UNUSED_P(condition);
+-  UNUSED_P(file);
+-  UNUSED_P(line);
++  _check_current_filename = file;
++  _check_current_lineno = line;
+   if (msg != NULL) {
+     const int has_newline = (msg[strlen(msg) - 1] == '\n');
+     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
+@@ -45,6 +45,7 @@
+ #include <stddef.h> /* ptrdiff_t */
+ #include <ctype.h>
+ #include <limits.h>
++#include <math.h>   /* NAN, INFINITY, isnan */
+ 
+ #if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
+ /* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
+@@ -72,7 +73,7 @@
+ #include "expat.h"
+ #include "chardata.h"
+ #include "structdata.h"
+-#include "internal.h" /* for UNUSED_P only */
++#include "internal.h"
+ #include "minicheck.h"
+ #include "memcheck.h"
+ #include "siphash.h"
+@@ -11231,6 +11232,381 @@
+ }
+ END_TEST
+ 
++#if defined(XML_DTD)
++typedef enum XML_Status (*XmlParseFunction)(XML_Parser, const char *, int, int);
++
++struct AccountingTestCase {
++  const char *primaryText;
++  const char *firstExternalText;  /* often NULL */
++  const char *secondExternalText; /* often NULL */
++  const unsigned long long expectedCountBytesIndirectExtra;
++  XML_Bool singleBytesWanted;
++};
++
++static int
++accounting_external_entity_ref_handler(XML_Parser parser,
++                                       const XML_Char *context,
++                                       const XML_Char *base,
++                                       const XML_Char *systemId,
++                                       const XML_Char *publicId) {
++  UNUSED_P(context);
++  UNUSED_P(base);
++  UNUSED_P(publicId);
++
++  const struct AccountingTestCase *const testCase
++      = (const struct AccountingTestCase *)XML_GetUserData(parser);
++
++  const char *externalText = NULL;
++  if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
++    externalText = testCase->firstExternalText;
++  } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
++    externalText = testCase->secondExternalText;
++  } else {
++    assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
++  }
++  assert(externalText);
++
++  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
++  assert(entParser);
++
++  const XmlParseFunction xmlParseFunction
++      = testCase->singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
++
++  const enum XML_Status status = xmlParseFunction(
++      entParser, externalText, (int)strlen(externalText), XML_TRUE);
++
++  XML_ParserFree(entParser);
++  return status;
++}
++
++START_TEST(test_accounting_precision) {
++  const XML_Bool filled_later = XML_TRUE; /* value is arbitrary */
++  struct AccountingTestCase cases[] = {
++      {"<e/>", NULL, NULL, 0, 0},
++      {"<e></e>", NULL, NULL, 0, 0},
++
++      /* Attributes */
++      {"<e k1=\"v2\" k2=\"v2\"/>", NULL, NULL, 0, filled_later},
++      {"<e k1=\"v2\" k2=\"v2\"></e>", NULL, NULL, 0, 0},
++      {"<p:e xmlns:p=\"https://domain.invalid/\" />", NULL, NULL, 0,
++       filled_later},
++      {"<e k=\"&amp;&apos;&gt;&lt;&quot;\" />", NULL, NULL,
++       sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
++      {"<e1 xmlns='https://example.org/'>\n"
++       "  <e2 xmlns=''/>\n"
++       "</e1>",
++       NULL, NULL, 0, filled_later},
++
++      /* Text */
++      {"<e>text</e>", NULL, NULL, 0, filled_later},
++      {"<e1><e2>text1<e3/>text2</e2></e1>", NULL, NULL, 0, filled_later},
++      {"<e>&amp;&apos;&gt;&lt;&quot;</e>", NULL, NULL,
++       sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
++      {"<e>&#65;&#41;</e>", NULL, NULL, 0, filled_later},
++
++      /* Prolog */
++      {"<?xml version=\"1.0\"?><root/>", NULL, NULL, 0, filled_later},
++
++      /* Whitespace */
++      {"  <e1>  <e2>  </e2>  </e1>  ", NULL, NULL, 0, filled_later},
++      {"<e1  ><e2  /></e1  >", NULL, NULL, 0, filled_later},
++      {"<e1><e2 k = \"v\"/><e3 k = 'v'/></e1>", NULL, NULL, 0, filled_later},
++
++      /* Comments */
++      {"<!-- Comment --><e><!-- Comment --></e>", NULL, NULL, 0, filled_later},
++
++      /* Processing instructions */
++      {"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
++       NULL, NULL, 0, filled_later},
++      {"<?pi0?><?pi1 ?><?pi2  ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
++       "<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
++       0, filled_later},
++
++      /* CDATA */
++      {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later},
++
++      /* Conditional sections */
++      {"<!DOCTYPE r [\n"
++       "<!ENTITY % draft 'INCLUDE'>\n"
++       "<!ENTITY % final 'IGNORE'>\n"
++       "<!ENTITY % import SYSTEM \"first.ent\">\n"
++       "%import;\n"
++       "]>\n"
++       "<r/>\n",
++       "<![%draft;[<!--1-->]]>\n"
++       "<![%final;[<!--22-->]]>",
++       NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE")),
++       filled_later},
++
++      /* General entities */
++      {"<!DOCTYPE root [\n"
++       "<!ENTITY nine \"123456789\">\n"
++       "]>\n"
++       "<root>&nine;</root>",
++       NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
++      {"<!DOCTYPE root [\n"
++       "<!ENTITY nine \"123456789\">\n"
++       "]>\n"
++       "<root k1=\"&nine;\"/>",
++       NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
++      {"<!DOCTYPE root [\n"
++       "<!ENTITY nine \"123456789\">\n"
++       "<!ENTITY nine2 \"&nine;&nine;\">\n"
++       "]>\n"
++       "<root>&nine2;&nine2;&nine2;</root>",
++       NULL, NULL,
++       sizeof(XML_Char) * 3 /* calls to &nine2; */ * 2 /* calls to &nine; */
++           * (strlen("&nine;") + strlen("123456789")),
++       filled_later},
++      {"<!DOCTYPE r [\n"
++       "  <!ENTITY five SYSTEM 'first.ent'>\n"
++       "]>\n"
++       "<r>&five;</r>",
++       "12345", NULL, 0, filled_later},
++
++      /* Parameter entities */
++      {"<!DOCTYPE r [\n"
++       "<!ENTITY % comment \"<!---->\">\n"
++       "%comment;\n"
++       "]>\n"
++       "<r/>",
++       NULL, NULL, sizeof(XML_Char) * strlen("<!---->"), filled_later},
++      {"<!DOCTYPE r [\n"
++       "<!ENTITY % ninedef \"&#60;!ENTITY nine &#34;123456789&#34;&#62;\">\n"
++       "%ninedef;\n"
++       "]>\n"
++       "<r>&nine;</r>",
++       NULL, NULL,
++       sizeof(XML_Char)
++           * (strlen("<!ENTITY nine \"123456789\">") + strlen("123456789")),
++       filled_later},
++      {"<!DOCTYPE r [\n"
++       "<!ENTITY % comment \"<!--1-->\">\n"
++       "<!ENTITY % comment2 \"&#37;comment;<!--22-->&#37;comment;\">\n"
++       "%comment2;\n"
++       "]>\n"
++       "<r/>\n",
++       NULL, NULL,
++       sizeof(XML_Char)
++           * (strlen("%comment;<!--22-->%comment;") + 2 * strlen("<!--1-->")),
++       filled_later},
++      {"<!DOCTYPE r [\n"
++       "  <!ENTITY % five \"12345\">\n"
++       "  <!ENTITY % five2def \"&#60;!ENTITY five2 &#34;[&#37;five;][&#37;five;]]]]&#34;&#62;\">\n"
++       "  %five2def;\n"
++       "]>\n"
++       "<r>&five2;</r>",
++       NULL, NULL, /* from "%five2def;": */
++       sizeof(XML_Char)
++           * (strlen("<!ENTITY five2 \"[%five;][%five;]]]]\">")
++              + 2 /* calls to "%five;" */ * strlen("12345")
++              + /* from "&five2;": */ strlen("[12345][12345]]]]")),
++       filled_later},
++      {"<!DOCTYPE r SYSTEM \"first.ent\">\n"
++       "<r/>",
++       "<!ENTITY % comment '<!--1-->'>\n"
++       "<!ENTITY % comment2 '<!--22-->%comment;<!--22-->%comment;<!--22-->'>\n"
++       "%comment2;",
++       NULL,
++       sizeof(XML_Char)
++           * (strlen("<!--22-->%comment;<!--22-->%comment;<!--22-->")
++              + 2 /* calls to "%comment;" */ * strlen("<!---->")),
++       filled_later},
++      {"<!DOCTYPE r SYSTEM 'first.ent'>\n"
++       "<r/>",
++       "<!ENTITY % e1 PUBLIC 'foo' 'second.ent'>\n"
++       "<!ENTITY % e2 '<!--22-->%e1;<!--22-->'>\n"
++       "%e2;\n",
++       "<!--1-->", sizeof(XML_Char) * strlen("<!--22--><!--1--><!--22-->"),
++       filled_later},
++      {
++          "<!DOCTYPE r SYSTEM 'first.ent'>\n"
++          "<r/>",
++          "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
++          "<!ENTITY % e2 '%e1;'>",
++          "<?xml version='1.0' encoding='utf-8'?>\n"
++          "hello\n"
++          "xml" /* without trailing newline! */,
++          0,
++          filled_later,
++      },
++      {
++          "<!DOCTYPE r SYSTEM 'first.ent'>\n"
++          "<r/>",
++          "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
++          "<!ENTITY % e2 '%e1;'>",
++          "<?xml version='1.0' encoding='utf-8'?>\n"
++          "hello\n"
++          "xml\n" /* with trailing newline! */,
++          0,
++          filled_later,
++      },
++      {"<!DOCTYPE doc SYSTEM 'first.ent'>\n"
++       "<doc></doc>\n",
++       "<!ELEMENT doc EMPTY>\n"
++       "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
++       "<!ENTITY % e2 '%e1;'>\n"
++       "%e1;\n",
++       "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
++       strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>"), filled_later},
++      {"<!DOCTYPE r [\n"
++       "  <!ENTITY five SYSTEM 'first.ent'>\n"
++       "]>\n"
++       "<r>&five;</r>",
++       "\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0, filled_later},
++  };
++
++  const size_t countCases = sizeof(cases) / sizeof(cases[0]);
++  size_t u = 0;
++  for (; u < countCases; u++) {
++    size_t v = 0;
++    for (; v < 2; v++) {
++      const XML_Bool singleBytesWanted = (v == 0) ? XML_FALSE : XML_TRUE;
++      const unsigned long long expectedCountBytesDirect
++          = strlen(cases[u].primaryText);
++      const unsigned long long expectedCountBytesIndirect
++          = (cases[u].firstExternalText ? strlen(cases[u].firstExternalText)
++                                        : 0)
++            + (cases[u].secondExternalText ? strlen(cases[u].secondExternalText)
++                                           : 0)
++            + cases[u].expectedCountBytesIndirectExtra;
++
++      XML_Parser parser = XML_ParserCreate(NULL);
++      XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
++      if (cases[u].firstExternalText) {
++        XML_SetExternalEntityRefHandler(parser,
++                                        accounting_external_entity_ref_handler);
++        XML_SetUserData(parser, (void *)&cases[u]);
++        cases[u].singleBytesWanted = singleBytesWanted;
++      }
++
++      const XmlParseFunction xmlParseFunction
++          = singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
++
++      enum XML_Status status
++          = xmlParseFunction(parser, cases[u].primaryText,
++                             (int)strlen(cases[u].primaryText), XML_TRUE);
++      if (status != XML_STATUS_OK) {
++        _xml_failure(parser, __FILE__, __LINE__);
++      }
++
++      const unsigned long long actualCountBytesDirect
++          = testingAccountingGetCountBytesDirect(parser);
++      const unsigned long long actualCountBytesIndirect
++          = testingAccountingGetCountBytesIndirect(parser);
++
++      XML_ParserFree(parser);
++
++      if (actualCountBytesDirect != expectedCountBytesDirect) {
++        fprintf(
++            stderr,
++            "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
++                "") " count direct bytes, got " EXPAT_FMT_ULL("") " instead.\n",
++            u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
++            expectedCountBytesDirect, actualCountBytesDirect);
++        fail("Count of direct bytes is off");
++      }
++
++      if (actualCountBytesIndirect != expectedCountBytesIndirect) {
++        fprintf(
++            stderr,
++            "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
++                "") " count indirect bytes, got " EXPAT_FMT_ULL("") " instead.\n",
++            u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
++            expectedCountBytesIndirect, actualCountBytesIndirect);
++        fail("Count of indirect bytes is off");
++      }
++    }
++  }
++}
++END_TEST
++
++START_TEST(test_billion_laughs_attack_protection_api) {
++  XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
++  XML_Parser parserWithParent
++      = XML_ExternalEntityParserCreate(parserWithoutParent, NULL, NULL);
++  if (parserWithoutParent == NULL)
++    fail("parserWithoutParent is NULL");
++  if (parserWithParent == NULL)
++    fail("parserWithParent is NULL");
++
++  // XML_SetBillionLaughsAttackProtectionMaximumAmplification, error cases
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(NULL, 123.0f)
++      == XML_TRUE)
++    fail("Call with NULL parser is NOT supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(parserWithParent,
++                                                               123.0f)
++      == XML_TRUE)
++    fail("Call with non-root parser is NOT supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, NAN)
++      == XML_TRUE)
++    fail("Call with NaN limit is NOT supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, -1.0f)
++      == XML_TRUE)
++    fail("Call with negative limit is NOT supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, 0.9f)
++      == XML_TRUE)
++    fail("Call with positive limit <1.0 is NOT supposed to succeed");
++
++  // XML_SetBillionLaughsAttackProtectionMaximumAmplification, success cases
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, 1.0f)
++      == XML_FALSE)
++    fail("Call with positive limit >=1.0 is supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, 123456.789f)
++      == XML_FALSE)
++    fail("Call with positive limit >=1.0 is supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parserWithoutParent, INFINITY)
++      == XML_FALSE)
++    fail("Call with positive limit >=1.0 is supposed to succeed");
++
++  // XML_SetBillionLaughsAttackProtectionActivationThreshold, error cases
++  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(NULL, 123)
++      == XML_TRUE)
++    fail("Call with NULL parser is NOT supposed to succeed");
++  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(parserWithParent,
++                                                              123)
++      == XML_TRUE)
++    fail("Call with non-root parser is NOT supposed to succeed");
++
++  // XML_SetBillionLaughsAttackProtectionActivationThreshold, success cases
++  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(
++          parserWithoutParent, 123)
++      == XML_FALSE)
++    fail("Call with non-NULL parentless parser is supposed to succeed");
++
++  XML_ParserFree(parserWithParent);
++  XML_ParserFree(parserWithoutParent);
++}
++END_TEST
++
++START_TEST(test_helper_unsigned_char_to_printable) {
++  // Smoke test
++  unsigned char uc = 0;
++  for (; uc < (unsigned char)-1; uc++) {
++    const char *const printable = unsignedCharToPrintable(uc);
++    if (printable == NULL)
++      fail("unsignedCharToPrintable returned NULL");
++    if (strlen(printable) < (size_t)1)
++      fail("unsignedCharToPrintable returned empty string");
++  }
++
++  // Two concrete samples
++  if (strcmp(unsignedCharToPrintable('A'), "A") != 0)
++    fail("unsignedCharToPrintable result mistaken");
++  if (strcmp(unsignedCharToPrintable('\\'), "\\\\") != 0)
++    fail("unsignedCharToPrintable result mistaken");
++}
++END_TEST
++#endif // defined(XML_DTD)
++
++
++
+ static Suite *
+ make_suite(void) {
+   Suite *s = suite_create("basic");
+@@ -11239,6 +11615,9 @@
+   TCase *tc_misc = tcase_create("miscellaneous tests");
+   TCase *tc_alloc = tcase_create("allocation tests");
+   TCase *tc_nsalloc = tcase_create("namespace allocation tests");
++#if defined(XML_DTD)
++  TCase *tc_accounting = tcase_create("accounting tests");
++#endif
+ 
+   suite_add_tcase(s, tc_basic);
+   tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
+@@ -11603,6 +11982,13 @@
+   tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
+   tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
+ 
++#if defined(XML_DTD)
++  suite_add_tcase(s, tc_accounting);
++  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_helper_unsigned_char_to_printable);
++#endif
++
+   return s;
+ }
+ 
+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
+@@ -1,7 +1,7 @@
+-# Makefile.in generated by automake 1.16.2 from Makefile.am.
++# Makefile.in generated by automake 1.16.1 from Makefile.am.
+ # @configure_input@
+ 
+-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
++# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ 
+ # This Makefile.in is free software; the Free Software Foundation
+ # gives unlimited permission to copy and/or distribute it,
+@@ -344,7 +344,6 @@
+ prefix = @prefix@
+ program_transform_name = @program_transform_name@
+ psdir = @psdir@
+-runstatedir = @runstatedir@
+ sbindir = @sbindir@
+ sharedstatedir = @sharedstatedir@
+ 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
+@@ -54,6 +54,8 @@
+ #  define tmain wmain
+ #  define tremove _wremove
+ #  define tchar wchar_t
++#  define tcstof wcstof
++#  define tcstoull wcstoull
+ #else /* not XML_UNICODE */
+ #  define T(x) x
+ #  define ftprintf fprintf
+@@ -71,4 +73,6 @@
+ #  define tmain main
+ #  define tremove remove
+ #  define tchar char
++#  define tcstof strtof
++#  define tcstoull strtoull
+ #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
+@@ -30,11 +30,15 @@
+    USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
++#include <expat_config.h>
++
+ #include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stddef.h>
+ #include <string.h>
++#include <math.h> /* for isnan */
++#include <errno.h>
+ 
+ #include "expat.h"
+ #include "codepage.h"
+@@ -50,6 +54,14 @@
+ #  include <wchar.h>
+ #endif
+ 
++enum ExitCode {
++  XMLWF_EXIT_SUCCESS = 0,
++  XMLWF_EXIT_INTERNAL_ERROR = 1,
++  XMLWF_EXIT_NOT_WELLFORMED = 2,
++  XMLWF_EXIT_OUTPUT_ERROR = 3,
++  XMLWF_EXIT_USAGE_ERROR = 4,
++};
++
+ /* Structures for handler user data */
+ typedef struct NotationList {
+   struct NotationList *next;
+@@ -875,6 +887,12 @@
+       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")
++      T("billion laughs attack protection:\n")
++      T("  NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
++      T("\n")
++      T("  -a FACTOR     set maximum tolerated [a]mplification factor (default: 100.0)\n")
++      T("  -b BYTES      set number of output [b]ytes needed to activate (default: 8 MiB)\n")
++      T("\n")
+       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 @@
+ int wmain(int argc, XML_Char **argv);
+ #endif
+ 
++#define XMLWF_SHIFT_ARG_INTO(constCharStarTarget, argc, argv, i, j)            \
++  {                                                                            \
++    if (argv[i][j + 1] == T('\0')) {                                           \
++      if (++i == argc)                                                         \
++        usage(argv[0], XMLWF_EXIT_USAGE_ERROR);                                \
++      constCharStarTarget = argv[i];                                           \
++    } else {                                                                   \
++      constCharStarTarget = argv[i] + j + 1;                                   \
++    }                                                                          \
++    i++;                                                                       \
++    j = 0;                                                                     \
++  }
++
+ int
+ tmain(int argc, XML_Char **argv) {
+   int i, j;
+@@ -902,6 +933,11 @@
+   int useNamespaces = 0;
+   int requireStandalone = 0;
+   int requiresNotations = 0;
++
++  float attackMaximumAmplification = -1.0f; /* signaling "not set" */
++  unsigned long long attackThresholdBytes;
++  XML_Bool attackThresholdGiven = XML_FALSE;
++
+   enum XML_ParamEntityParsing paramEntityParsing
+       = XML_PARAM_ENTITY_PARSING_NEVER;
+   int useStdin = 0;
+@@ -990,6 +1026,49 @@
+     case T('v'):
+       showVersion(argv[0]);
+       return 0;
++    case T('a'): {
++      const XML_Char *valueText = NULL;
++      XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
++
++      errno = 0;
++      XML_Char *afterValueText = (XML_Char *)valueText;
++      attackMaximumAmplification = tcstof(valueText, &afterValueText);
++      if ((errno != 0) || (afterValueText[0] != T('\0'))
++          || isnan(attackMaximumAmplification)
++          || (attackMaximumAmplification < 1.0f)) {
++        // This prevents tperror(..) from reporting misleading "[..]: Success"
++        errno = ERANGE;
++        tperror(T("invalid amplification limit") T(
++            " (needs a floating point number greater or equal than 1.0)"));
++        exit(XMLWF_EXIT_USAGE_ERROR);
++      }
++#ifndef XML_DTD
++      ftprintf(stderr, T("Warning: Given amplification limit ignored") T(
++                           ", xmlwf has been compiled without DTD support.\n"));
++#endif
++      break;
++    }
++    case T('b'): {
++      const XML_Char *valueText = NULL;
++      XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
++
++      errno = 0;
++      XML_Char *afterValueText = (XML_Char *)valueText;
++      attackThresholdBytes = tcstoull(valueText, &afterValueText, 10);
++      if ((errno != 0) || (afterValueText[0] != T('\0'))) {
++        // This prevents tperror(..) from reporting misleading "[..]: Success"
++        errno = ERANGE;
++        tperror(T("invalid ignore threshold")
++                    T(" (needs an integer from 0 to 2^64-1)"));
++        exit(XMLWF_EXIT_USAGE_ERROR);
++      }
++      attackThresholdGiven = XML_TRUE;
++#ifndef XML_DTD
++      ftprintf(stderr, T("Warning: Given attack threshold ignored") T(
++                           ", xmlwf has been compiled without DTD support.\n"));
++#endif
++      break;
++    }
+     case T('\0'):
+       if (j > 1) {
+         i++;
+@@ -1020,6 +1099,19 @@
+       exit(1);
+     }
+ 
++    if (attackMaximumAmplification != -1.0f) {
++#ifdef XML_DTD
++      XML_SetBillionLaughsAttackProtectionMaximumAmplification(
++          parser, attackMaximumAmplification);
++#endif
++    }
++    if (attackThresholdGiven) {
++#ifdef XML_DTD
++      XML_SetBillionLaughsAttackProtectionActivationThreshold(
++          parser, attackThresholdBytes);
++#endif
++    }
++
+     if (requireStandalone)
+       XML_SetNotStandaloneHandler(parser, notStandalone);
+     XML_SetParamEntityParsing(parser, paramEntityParsing);
+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
+@@ -57,6 +57,14 @@
+ output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
+ output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
+ 
++billion_laughs = parser.add_argument_group('billion laughs attack protection',
++                                           description='NOTE: '
++                                                       'If you ever need to increase these values '
++                                                       'for non-attack payload, please file a bug report.')
++billion_laughs.add_argument('-a', metavar='FACTOR',
++                            help='set maximum tolerated [a]mplification factor (default: 100.0)')
++billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
++
+ parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
+ 
+ info = parser.add_argument_group('info arguments')
diff --git a/main/expat/expat-2.2.11.patch b/main/expat/expat-2.2.11.patch
deleted file mode 100644
index 289362d..0000000
--- a/main/expat/expat-2.2.11.patch
+++ /dev/null
@@ -1,2745 +0,0 @@
---- misc/expat-2.2.10/Changes	2020-10-03 11:14:57.000000000 -0400
-+++ misc/build/expat-2.2.10/Changes	2021-07-18 17:21:48.000000000 -0400
-@@ -2,6 +2,43 @@
-       https://github.com/libexpat/libexpat/labels/help%20wanted
-       If you can help, please get in touch.  Thanks!
- 
-+
-+Release 2.2.11 XXX XXXXX XX XXXX
-+        Security fixes:
-+        #34 #466  CVE-2013-0340/CWE-776 -- Protect against billion laughs attacks
-+                    (denial-of-service; flavors targeting CPU time or RAM or both,
-+                    leveraging general entities or parameter entities or both)
-+                    by tracking and limiting the input amplification factor
-+                    (<amplification> := (<direct> + <indirect>) / <direct>).
-+                    By conservative default, amplification up to a factor of 100.0
-+                    is tolerated and rejection only starts after 8 MiB of output bytes
-+                    (=<direct> + <indirect>) have been processed.
-+                    A new error code XML_ERROR_AMPLIFICATION_LIMIT_BREACH signals
-+                    this condition.
-+        New features:
-+        #34 #466  Add two new API functions to further tighten billion laughs
-+                    protection parameters when desired.
-+                    - XML_SetBillionLaughsAttackProtectionMaximumAmplification
-+                    - XML_SetBillionLaughsAttackProtectionActivationThreshold
-+                    Please see file "doc/reference.html" for more details.
-+                    If you ever need to increase the defaults for non-attack XML
-+                    payload, please file a bug report with libexpat.
-+        #34 #466  Introduce environment switches EXPAT_ACCOUNTING_DEBUG=(0|1|2|3)
-+                    and EXPAT_ENTITY_DEBUG=(0|1) for runtime debugging of accounting
-+                    and entity processing; specific behavior of these values may
-+                    change in the future.
-+        #34 #466  xmlwf: Add arguments "-a FACTOR" and "-b BYTES" to further tighten
-+                    billion laughs protection parameters when desired.
-+                    If you ever need to increase the defaults for non-attack XML
-+                    payload, please file a bug report with libexpat.
-+
-+        Special thanks to:
-+            Nick Wellnhofer
-+            Yury Gribov
-+                 and
-+            Clang LeakSan
-+            JetBrains
-+
- Release 2.2.10 Sat October 3 2020
-         Bug fixes:
-   #390 #395 #398  Fix undefined behavior during parsing caused by
-diff -ru misc/expat-2.2.10/CMakeLists.txt misc/build/expat-2.2.10/CMakeLists.txt
---- misc/expat-2.2.10/CMakeLists.txt	2020-10-03 11:14:57.000000000 -0400
-+++ misc/build/expat-2.2.10/CMakeLists.txt	2021-08-25 18:35:36.000000000 -0400
-@@ -448,14 +448,12 @@
-         endif()
-     endfunction()
- 
--    add_executable(runtests tests/runtests.c ${test_SRCS})
-+    add_executable(runtests tests/runtests.c ${test_SRCS} ${expat_SRCS})
-     set_property(TARGET runtests PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
--    target_link_libraries(runtests expat)
-     expat_add_test(runtests $<TARGET_FILE:runtests>)
- 
--    add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS})
-+    add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS} ${expat_SRCS})
-     set_property(TARGET runtestspp PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
--    target_link_libraries(runtestspp expat)
-     expat_add_test(runtestspp $<TARGET_FILE:runtestspp>)
- endif()
- 
-diff -ru misc/expat-2.2.10/doc/Makefile.in misc/build/expat-2.2.10/doc/Makefile.in
---- misc/expat-2.2.10/doc/Makefile.in	2020-10-03 11:37:06.000000000 -0400
-+++ misc/build/expat-2.2.10/doc/Makefile.in	2021-07-18 18:17:02.000000000 -0400
-@@ -1,7 +1,7 @@
--# Makefile.in generated by automake 1.16.2 from Makefile.am.
-+# Makefile.in generated by automake 1.16.1 from Makefile.am.
- # @configure_input@
- 
--# Copyright (C) 1994-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
- 
- # This Makefile.in is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -314,7 +314,6 @@
- prefix = @prefix@
- program_transform_name = @program_transform_name@
- psdir = @psdir@
--runstatedir = @runstatedir@
- sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- srcdir = @srcdir@
-diff -ru misc/expat-2.2.10/doc/reference.html misc/build/expat-2.2.10/doc/reference.html
---- misc/expat-2.2.10/doc/reference.html	2020-09-25 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/doc/reference.html	2021-07-18 17:21:48.000000000 -0400
-@@ -120,6 +120,13 @@
-       <li><a href="#XML_GetInputContext">XML_GetInputContext</a></li>
-     </ul>
-     </li>
-+    <li>
-+      <a href="#billion-laughs">Billion Laughs Attack Protection</a>
-+      <ul>
-+        <li><a href="#XML_SetBillionLaughsAttackProtectionMaximumAmplification">XML_SetBillionLaughsAttackProtectionMaximumAmplification</a></li>
-+        <li><a href="#XML_SetBillionLaughsAttackProtectionActivationThreshold">XML_SetBillionLaughsAttackProtectionActivationThreshold</a></li>
-+      </ul>
-+    </li>
-     <li><a href="#miscellaneous">Miscellaneous Functions</a>
-     <ul>
-       <li><a href="#XML_SetUserData">XML_SetUserData</a></li>
-@@ -1998,6 +2005,98 @@
- return NULL.</p>
- </div>
- 
-+
-+
-+<h3><a name="billion-laughs">Billion Laughs Attack Protection</a></h3>
-+
-+<p>The functions in this section configure the built-in
-+  protection against various forms of
-+  <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>.</p>
-+
-+<pre class="fcndec" id="XML_SetBillionLaughsAttackProtectionMaximumAmplification">
-+/* Added in Expat 2.2.11. */
-+XML_Bool XMLCALL
-+XML_SetBillionLaughsAttackProtectionMaximumAmplification(XML_Parser p,
-+                                                         float maximumAmplificationFactor);
-+</pre>
-+<div class="fcndef">
-+  <p>
-+    Sets the maximum tolerated amplification factor
-+    for protection against
-+    <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
-+    (default: <code>100.0</code>)
-+    of parser <code>p</code> to <code>maximumAmplificationFactor</code>, and
-+    returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
-+  </p>
-+
-+  The amplification factor is calculated as ..
-+  <pre>
-+    amplification := (direct + indirect) / direct
-+  </pre>
-+  .. while parsing, whereas
-+  <code>direct</code> is the number of bytes read from the primary document in parsing and
-+  <code>indirect</code> is the number of bytes added by expanding entities and reading of external DTD files, combined.
-+
-+  <p>For a call to <code>XML_SetBillionLaughsAttackProtectionMaximumAmplification</code> to succeed:</p>
-+  <ul>
-+    <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers) and</li>
-+    <li><code>maximumAmplificationFactor</code> must be non-<code>NaN</code> and greater than or equal to <code>1.0</code>.</li>
-+  </ul>
-+
-+  <p>
-+    <strong>Note:</strong>
-+    If you ever need to increase this value for non-attack payload,
-+    please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
-+  </p>
-+
-+  <p>
-+    <strong>Note:</strong>
-+    Peak amplifications
-+    of factor 15,000 for the entire payload and
-+    of factor 30,000 in the middle of parsing
-+    have been observed with small benign files in practice.
-+
-+    So if you do reduce the maximum allowed amplification,
-+    please make sure that the activation threshold is still big enough
-+    to not end up with undesired false positives (i.e. benign files being rejected).
-+  </p>
-+</div>
-+
-+<pre class="fcndec" id="XML_SetBillionLaughsAttackProtectionActivationThreshold">
-+/* Added in Expat 2.2.11. */
-+XML_Bool XMLCALL
-+XML_SetBillionLaughsAttackProtectionActivationThreshold(XML_Parser p,
-+                                                        unsigned long long activationThresholdBytes);
-+</pre>
-+<div class="fcndef">
-+  <p>
-+    Sets number of output bytes (including amplification from entity expansion and reading DTD files)
-+    needed to activate protection against
-+    <a href="https://en.wikipedia.org/wiki/Billion_laughs_attack">billion laughs attacks</a>
-+    (default: <code>8 MiB</code>)
-+    of parser <code>p</code> to <code>activationThresholdBytes</code>, and
-+    returns <code>XML_TRUE</code> upon success and <code>XML_TRUE</code> upon error.
-+  </p>
-+
-+  <p>For a call to <code>XML_SetBillionLaughsAttackProtectionActivationThreshold</code> to succeed:</p>
-+  <ul>
-+    <li>parser <code>p</code> must be a non-<code>NULL</code> root parser (without any parent parsers).</li>
-+  </ul>
-+
-+  <p>
-+    <strong>Note:</strong>
-+    If you ever need to increase this value for non-attack payload,
-+    please <a href="https://github.com/libexpat/libexpat/issues">file a bug report</a>.
-+  </p>
-+
-+  <p>
-+    <strong>Note:</strong>
-+    Activation thresholds below 4 MiB are known to break support for
-+    <a href="https://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">DITA</a> 1.3 payload
-+    and are hence not recommended.
-+  </p>
-+</div>
-+
- <h3><a name="miscellaneous">Miscellaneous functions</a></h3>
- 
- <p>The functions in this section either obtain state information from
-Only in misc/expat-2.2.10/doc: xmlwf.1
-diff -ru misc/expat-2.2.10/doc/xmlwf.xml misc/build/expat-2.2.10/doc/xmlwf.xml
---- misc/expat-2.2.10/doc/xmlwf.xml	2020-09-25 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/doc/xmlwf.xml	2021-07-18 17:21:48.000000000 -0400
-@@ -3,7 +3,7 @@
-   <!ENTITY dhfirstname "<firstname>Scott</firstname>">
-   <!ENTITY dhsurname   "<surname>Bronson</surname>">
-   <!-- Please adjust the date whenever revising the manpage. -->
--  <!ENTITY dhdate      "<date>March 11, 2016</date>">
-+  <!ENTITY dhdate      "<date>July 18, 2021</date>">
-   <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
-        allowed: see man(7), man(1). -->
-   <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
-@@ -138,6 +138,52 @@
- </para>
- 
-     <variablelist>
-+    
-+    <variablelist>
-+
-+      <varlistentry>
-+        <term><option>-a</option> <replaceable>factor</replaceable></term>
-+        <listitem>
-+          <para>
-+            Sets the maximum tolerated amplification factor
-+            for protection against billion laughs attacks (default: 100.0).
-+            The amplification factor is calculated as ..
-+          </para>
-+          <literallayout>
-+            amplification := (direct + indirect) / direct
-+          </literallayout>
-+          <para>
-+            .. while parsing, whereas
-+            &lt;direct&gt; is the number of bytes read
-+              from the primary document in parsing and
-+            &lt;indirect&gt; is the number of bytes
-+              added by expanding entities and reading of external DTD files,
-+              combined.
-+          </para>
-+          <para>
-+            <emphasis>NOTE</emphasis>:
-+            If you ever need to increase this value for non-attack payload,
-+            please file a bug report.
-+          </para>
-+        </listitem>
-+      </varlistentry>
-+
-+      <varlistentry>
-+        <term><option>-b</option> <replaceable>bytes</replaceable></term>
-+        <listitem>
-+          <para>
-+            Sets the number of output bytes (including amplification)
-+            needed to activate protection against billion laughs attacks
-+            (default: 8 MiB).
-+            This can be thought of as an &quot;activation threshold&quot;.
-+          </para>
-+          <para>
-+            <emphasis>NOTE</emphasis>:
-+            If you ever need to increase this value for non-attack payload,
-+            please file a bug report.
-+          </para>
-+        </listitem>
-+      </varlistentry>
- 
-       <varlistentry>
-         <term><option>-c</option></term>
-@@ -455,6 +501,7 @@
- <literallayout>
- The Expat home page:        http://www.libexpat.org/
- The W3 XML specification:   http://www.w3.org/TR/REC-xml
-+Billion laughs attack:      https://en.wikipedia.org/wiki/Billion_laughs_attack
- </literallayout>
- 
- 	</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 11:14:57.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/expat.h	2021-07-18 17:21:48.000000000 -0400
-@@ -115,7 +115,10 @@
-   XML_ERROR_RESERVED_PREFIX_XMLNS,
-   XML_ERROR_RESERVED_NAMESPACE_URI,
-   /* Added in 2.2.1. */
--  XML_ERROR_INVALID_ARGUMENT
-+  XML_ERROR_INVALID_ARGUMENT,
-+  /* Added in 2.2.11 */
-+  XML_ERROR_NO_BUFFER,
-+  XML_ERROR_AMPLIFICATION_LIMIT_BREACH
- };
- 
- enum XML_Content_Type {
-@@ -997,7 +1000,10 @@
-   XML_FEATURE_SIZEOF_XML_LCHAR,
-   XML_FEATURE_NS,
-   XML_FEATURE_LARGE_SIZE,
--  XML_FEATURE_ATTR_INFO
-+  XML_FEATURE_ATTR_INFO,
-+  /* added in Expat 2.2.11 */
-+  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
-+  XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT
-   /* Additional features must be added to the end of this enum. */
- };
- 
-@@ -1010,6 +1016,19 @@
- XMLPARSEAPI(const XML_Feature *)
- XML_GetFeatureList(void);
- 
-+
-+#ifdef XML_DTD
-+/* Added in Expat 2.2.11 */
-+XMLPARSEAPI(XML_Bool)
-+XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+    XML_Parser parser, float maximumAmplificationFactor);
-+
-+/* Added in Expat 2.2.11 */
-+XMLPARSEAPI(XML_Bool)
-+XML_SetBillionLaughsAttackProtectionActivationThreshold(
-+    XML_Parser parser, unsigned long long activationThresholdBytes);
-+#endif
-+
- /* Expat follows the semantic versioning convention.
-    See http://semver.org.
- */
-diff -ru misc/expat-2.2.10/lib/internal.h misc/build/expat-2.2.10/lib/internal.h
---- misc/expat-2.2.10/lib/internal.h	2020-09-25 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/internal.h	2021-07-18 17:21:48.000000000 -0400
-@@ -101,10 +101,47 @@
- #  endif
- #endif
- 
-+#include <limits.h> // ULONG_MAX
-+
-+#if defined(_WIN32) && ! defined(__USE_MINGW_ANSI_STDIO)
-+#  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_ULL(midpart) "%" midpart "llu"
-+#  if ! defined(ULONG_MAX)
-+#    error Compiler did not define ULONG_MAX for us
-+#  elif ULONG_MAX == 18446744073709551615u // 2^64-1
-+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
-+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
-+#  else
-+#    define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
-+#    define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
-+#  endif
-+#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
-+/* NOTE END */
-+
-+#include "expat.h" // so we can use type XML_Parser below
-+
- #ifdef __cplusplus
- extern "C" {
- #endif
-@@ -117,6 +154,11 @@
- void
- _INTERNAL_trim_to_complete_utf8_characters(const char *from,
-                                            const char **fromLimRef);
-+#if defined(XML_DTD)
-+unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
-+unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
-+const char *unsignedCharToPrintable(unsigned char c);
-+#endif
- 
- #ifdef __cplusplus
- }
-diff -ru misc/expat-2.2.10/lib/libexpat.def misc/build/expat-2.2.10/lib/libexpat.def
---- misc/expat-2.2.10/lib/libexpat.def	2020-09-25 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/libexpat.def	2021-07-18 17:21:48.000000000 -0400
-@@ -76,3 +76,6 @@
-   XML_SetHashSalt @67
- ; added with version 2.2.5
-   _INTERNAL_trim_to_complete_utf8_characters @68
-+; added with version 2.2.11
-+  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
-+  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70  
-\ No newline at end of file
-diff -ru misc/expat-2.2.10/lib/libexpatw.def misc/build/expat-2.2.10/lib/libexpatw.def
---- misc/expat-2.2.10/lib/libexpatw.def	2020-09-25 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/libexpatw.def	2021-07-18 17:21:48.000000000 -0400
-@@ -76,3 +76,6 @@
-   XML_SetHashSalt @67
- ; added with version 2.2.5
-   _INTERNAL_trim_to_complete_utf8_characters @68
-+; added with version 2.2.11
-+  XML_SetBillionLaughsAttackProtectionActivationThreshold @69
-+  XML_SetBillionLaughsAttackProtectionMaximumAmplification @70
-\ No newline at end of file
-Only in misc/build/expat-2.2.10/lib: Makefile
-diff -ru misc/expat-2.2.10/lib/Makefile.in misc/build/expat-2.2.10/lib/Makefile.in
---- misc/expat-2.2.10/lib/Makefile.in	2020-10-03 11:37:06.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/Makefile.in	2021-07-18 18:17:02.000000000 -0400
-@@ -1,7 +1,7 @@
--# Makefile.in generated by automake 1.16.2 from Makefile.am.
-+# Makefile.in generated by automake 1.16.1 from Makefile.am.
- # @configure_input@
- 
--# Copyright (C) 1994-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
- 
- # This Makefile.in is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -372,7 +372,6 @@
- prefix = @prefix@
- program_transform_name = @program_transform_name@
- psdir = @psdir@
--runstatedir = @runstatedir@
- sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- 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 11:14:57.000000000 -0400
-+++ misc/build/expat-2.2.10/lib/xmlparse.c	2021-08-28 18:28:18.000000000 -0400
-@@ -47,6 +47,7 @@
- #include <limits.h> /* UINT_MAX */
- #include <stdio.h>  /* fprintf */
- #include <stdlib.h> /* getenv, rand_s */
-+#include <math.h>   /* isnan */
- 
- #if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
- /* vs2008/9.0 and earlier lack stdint.h; _MSC_VER 1600 is vs2010/10.0 */
-@@ -73,6 +74,10 @@
- 
- #ifdef _WIN32
- #  include "winconfig.h"
-+#include <float.h>
-+#ifndef isnan
-+#define isnan _isnan
-+#endif
- #elif defined(HAVE_EXPAT_CONFIG_H)
- #  include <expat_config.h>
- #endif /* ndef _WIN32 */
-@@ -382,6 +387,31 @@
-   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
- } OPEN_INTERNAL_ENTITY;
- 
-+enum XML_Account {
-+  XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat parser */
-+  XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
-+                                   expansion */
-+  XML_ACCOUNT_NONE              /* i.e. do not account, was accounted already */
-+};
-+
-+#ifdef XML_DTD
-+typedef unsigned long long XmlBigCount;
-+typedef struct accounting {
-+  XmlBigCount countBytesDirect;
-+  XmlBigCount countBytesIndirect;
-+  int debugLevel;
-+  float maximumAmplificationFactor; // >=1.0
-+  unsigned long long activationThresholdBytes;
-+} ACCOUNTING;
-+
-+typedef struct entity_stats {
-+  unsigned int countEverOpened;
-+  unsigned int currentDepth;
-+  unsigned int maximumDepthSeen;
-+  int debugLevel;
-+} ENTITY_STATS;
-+#endif /* XML_DTD */
-+
- typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
-                                          const char *end, const char **endPtr);
- 
-@@ -412,13 +442,14 @@
- static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
-                                const char *s, const char *end, int tok,
-                                const char *next, const char **nextPtr,
--                               XML_Bool haveMore, XML_Bool allowClosingDoctype);
-+							   XML_Bool haveMore, XML_Bool allowClosingDoctype,
-+							   enum XML_Account account);
- static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
-                                             XML_Bool betweenDecl);
- static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
-                                 const ENCODING *enc, const char *start,
-                                 const char *end, const char **endPtr,
--                                XML_Bool haveMore);
-+								XML_Bool haveMore, enum XML_Account account);
- static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
-                                      const char **startPtr, const char *end,
-                                      const char **nextPtr, XML_Bool haveMore);
-@@ -431,7 +462,8 @@
- static void freeBindings(XML_Parser parser, BINDING *bindings);
- static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
-                                 const char *s, TAG_NAME *tagNamePtr,
--                                BINDING **bindingsPtr);
-+								BINDING **bindingsPtr,
-+								enum XML_Account account);
- static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
-                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
-                                  BINDING **bindingsPtr);
-@@ -440,15 +472,18 @@
-                            XML_Parser parser);
- static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
-                                           XML_Bool isCdata, const char *,
--                                          const char *, STRING_POOL *);
-+                                          const char *, STRING_POOL *,
-+                                          enum XML_Account account);
- static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
-                                            XML_Bool isCdata, const char *,
--                                           const char *, STRING_POOL *);
-+                                           const char *, STRING_POOL *,
-+                                           enum XML_Account account);
- static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
-                                     const char *start, const char *end);
- static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
- static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
--                                       const char *start, const char *end);
-+                                       const char *start, const char *end,
-+                                       enum XML_Account account);
- static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
-                                        const char *start, const char *end);
- static int reportComment(XML_Parser parser, const ENCODING *enc,
-@@ -512,6 +547,34 @@
- 
- static void parserInit(XML_Parser parser, const XML_Char *encodingName);
- 
-+#ifdef XML_DTD
-+static float accountingGetCurrentAmplification(XML_Parser rootParser);
-+static void accountingReportStats(XML_Parser originParser, const char *epilog);
-+static void accountingOnAbort(XML_Parser originParser);
-+static void accountingReportDiff(XML_Parser rootParser,
-+                                 unsigned int levelsAwayFromRootParser,
-+                                 const char *before, const char *after,
-+                                 ptrdiff_t bytesMore, int source_line,
-+                                 enum XML_Account account);
-+static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
-+                                        const char *before, const char *after,
-+                                        int source_line,
-+                                        enum XML_Account account);
-+
-+static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
-+                                      const char *action, int sourceLine);
-+static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
-+                                 int sourceLine);
-+static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
-+                                  int sourceLine);
-+
-+static XML_Parser getRootParserOf(XML_Parser parser,
-+                                  unsigned int *outLevelDiff);
-+#endif /* XML_DTD */
-+
-+static unsigned long getDebugLevel(const char *variableName,
-+                                   unsigned long defaultDebugLevel);
-+
- #define poolStart(pool) ((pool)->start)
- #define poolEnd(pool) ((pool)->ptr)
- #define poolLength(pool) ((pool)->ptr - (pool)->start)
-@@ -625,6 +688,10 @@
-   enum XML_ParamEntityParsing m_paramEntityParsing;
- #endif
-   unsigned long m_hash_secret_salt;
-+#ifdef XML_DTD
-+  ACCOUNTING m_accounting;
-+  ENTITY_STATS m_entity_stats;
-+#endif
- };
- 
- #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
-@@ -809,9 +876,8 @@
- 
- static unsigned long
- ENTROPY_DEBUG(const char *label, unsigned long entropy) {
--  const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
--  if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
--    fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
-+	  if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) {
-+	   fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
-             (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
-   }
-   return entropy;
-@@ -855,7 +921,7 @@
-     return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
-   } else {
-     return ENTROPY_DEBUG("fallback(8)",
--                         entropy * (unsigned long)2305843009213693951ULL);
-+                         entropy * (unsigned long long)2305843009213693951ULL);
-   }
- #endif
- }
-@@ -1073,6 +1139,18 @@
-   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
- #endif
-   parser->m_hash_secret_salt = 0;
-+
-+#ifdef XML_DTD
-+  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
-+  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
-+  parser->m_accounting.maximumAmplificationFactor
-+      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
-+  parser->m_accounting.activationThresholdBytes
-+      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
-+
-+  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
-+  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
-+#endif
- }
- 
- /* moves list of bindings to m_freeBindingList */
-@@ -2337,6 +2415,13 @@
-   /* Added in 2.2.5. */
-   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
-     return XML_L("invalid argument");
-+  /* Added in 2.2.11. */
-+  case XML_ERROR_NO_BUFFER:
-+    return XML_L(
-+        "a successful prior call to function XML_GetBuffer is required");
-+  case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
-+    return XML_L(
-+        "limit on input amplification factor (from DTD and entities) breached");
-   }
-   return NULL;
- }
-@@ -2373,41 +2458,75 @@
- 
- const XML_Feature *XMLCALL
- XML_GetFeatureList(void) {
--  static const XML_Feature features[]
--      = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
--          sizeof(XML_Char)},
--         {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
--          sizeof(XML_LChar)},
-+  static const XML_Feature features[] = {
-+	  {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
-+	   sizeof(XML_Char)},
-+	  {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
-+	   sizeof(XML_LChar)},
- #ifdef XML_UNICODE
--         {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
-+      {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
- #endif
- #ifdef XML_UNICODE_WCHAR_T
--         {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
-+      {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
- #endif
- #ifdef XML_DTD
--         {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
-+      {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
- #endif
- #ifdef XML_CONTEXT_BYTES
--         {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
--          XML_CONTEXT_BYTES},
-+      {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},
-+      {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
- #endif
- #ifdef XML_NS
--         {XML_FEATURE_NS, XML_L("XML_NS"), 0},
-+      {XML_FEATURE_NS, XML_L("XML_NS"), 0},
- #endif
- #ifdef XML_LARGE_SIZE
--         {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
-+      {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},
-+      {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
- #endif
--         {XML_FEATURE_END, NULL, 0}};
-+#ifdef XML_DTD
-+      /* Added in Expat 2.2.11. */
-+      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
-+       XML_L("XML_BLAP_MAX_AMP"),
-+       (long int)
-+           EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
-+      {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
-+       XML_L("XML_BLAP_ACT_THRES"),
-+       EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
-+#endif
-+      {XML_FEATURE_END, NULL, 0}};
- 
-   return features;
- }
- 
-+#ifdef XML_DTD
-+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;
-+}
-+
-+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;
-+}
-+#endif /* XML_DTD */
-+
- /* 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
-@@ -2460,9 +2579,9 @@
- static enum XML_Error PTRCALL
- contentProcessor(XML_Parser parser, const char *start, const char *end,
-                  const char **endPtr) {
--  enum XML_Error result
--      = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
--                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
-+  enum XML_Error result = doContent(
-+      parser, 0, parser->m_encoding, start, end, endPtr,
-+	  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
-   if (result == XML_ERROR_NONE) {
-     if (! storeRawNames(parser))
-       return XML_ERROR_NO_MEMORY;
-@@ -2487,6 +2606,14 @@
-   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
-   switch (tok) {
-   case XML_TOK_BOM:
-+#ifdef XML_DTD
-+    if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
-+                                  XML_ACCOUNT_DIRECT)) {
-+      accountingOnAbort(parser);
-+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+    }
-+#endif /* XML_DTD */
-+
-     /* 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 +2651,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);
-+  /* Note: These bytes are accounted later in:
-+           - processXmlDecl
-+           - externalEntityContentProcessor
-+  */
-   parser->m_eventEndPtr = next;
- 
-   switch (tok) {
-@@ -2565,7 +2696,8 @@
-                                const char *end, const char **endPtr) {
-   enum XML_Error result
-       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
--                  (XML_Bool)! parser->m_parsingStatus.finalBuffer);
-+              (XML_Bool)! parser->m_parsingStatus.finalBuffer,
-+              XML_ACCOUNT_ENTITY_EXPANSION);
-   if (result == XML_ERROR_NONE) {
-     if (! storeRawNames(parser))
-       return XML_ERROR_NO_MEMORY;
-@@ -2576,7 +2708,7 @@
- static enum XML_Error
- doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
-           const char *s, const char *end, const char **nextPtr,
--          XML_Bool haveMore) {
-+          XML_Bool haveMore, enum XML_Account account) {
-   /* save one level of indirection */
-   DTD *const dtd = parser->m_dtd;
- 
-@@ -2594,6 +2726,17 @@
-   for (;;) {
-     const char *next = s; /* XmlContentTok doesn't always set the last arg */
-     int tok = XmlContentTok(enc, s, end, &next);
-+#ifdef XML_DTD
-+    const char *accountAfter
-+        = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
-+              ? (haveMore ? s /* i.e. 0 bytes */ : end)
-+              : next;
-+    if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
-+                                  account)) {
-+      accountingOnAbort(parser);
-+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+    }
-+#endif
-     *eventEndPP = next;
-     switch (tok) {
-     case XML_TOK_TRAILING_CR:
-@@ -2649,6 +2792,14 @@
-       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
-           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
-       if (ch) {
-+#ifdef XML_DTD
-+        /* NOTE: We are replacing 4-6 characters original input for 1 character
-+         *       so there is no amplification and hence recording without
-+         *       protection. */
-+        accountingDiffTolerated(parser, tok, (char *)&ch,
-+                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
-+                                XML_ACCOUNT_ENTITY_EXPANSION);
-+#endif /* XML_DTD */
-         if (parser->m_characterDataHandler)
-           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
-         else if (parser->m_defaultHandler)
-@@ -2767,7 +2918,7 @@
-       }
-       tag->name.str = (XML_Char *)tag->buf;
-       *toPtr = XML_T('\0');
--      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
-+      result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
-       if (result)
-         return result;
-       if (parser->m_startElementHandler)
-@@ -2791,7 +2942,8 @@
-       if (! name.str)
-         return XML_ERROR_NO_MEMORY;
-       poolFinish(&parser->m_tempPool);
--      result = storeAtts(parser, enc, s, &name, &bindings);
-+      result = storeAtts(parser, enc, s, &name, &bindings,
-+                         XML_ACCOUNT_NONE /* token spans whole start tag */);
-       if (result != XML_ERROR_NONE) {
-         freeBindings(parser, bindings);
-         return result;
-@@ -3055,7 +3207,8 @@
- */
- static enum XML_Error
- storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
--          TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
-+        TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
-+        enum XML_Account account) {
-   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
-   ELEMENT_TYPE *elementType;
-   int nDefaultAtts;
-@@ -3165,7 +3318,7 @@
-       /* normalize the attribute value */
-       result = storeAttributeValue(
-           parser, enc, isCdata, parser->m_atts[i].valuePtr,
--          parser->m_atts[i].valueEnd, &parser->m_tempPool);
-+          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
-       if (result)
-         return result;
-       appAtts[attIndex] = poolStart(&parser->m_tempPool);
-@@ -3594,6 +3747,13 @@
-   for (;;) {
-     const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
-     int tok = XmlCdataSectionTok(enc, s, end, &next);
-+#ifdef XML_DTD
-+    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
-+                                  XML_ACCOUNT_DIRECT)) {
-+      accountingOnAbort(parser);
-+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+    }
-+#endif
-     *eventEndPP = next;
-     switch (tok) {
-     case XML_TOK_CDATA_SECT_CLOSE:
-@@ -3738,6 +3898,13 @@
-   *eventPP = s;
-   *startPtr = NULL;
-   tok = XmlIgnoreSectionTok(enc, s, end, &next);
-+#  ifdef XML_DTD
-+  if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
-+                                XML_ACCOUNT_DIRECT)) {
-+    accountingOnAbort(parser);
-+    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+  }
-+#  endif
-   *eventEndPP = next;
-   switch (tok) {
-   case XML_TOK_IGNORE_SECT:
-@@ -3822,6 +3989,15 @@
-   const char *versionend;
-   const XML_Char *storedversion = NULL;
-   int standalone = -1;
-+
-+#ifdef XML_DTD
-+  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
-+                                XML_ACCOUNT_DIRECT)) {
-+    accountingOnAbort(parser);
-+    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+  }
-+#endif
-+
-   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
-           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
-           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
-@@ -3971,6 +4147,10 @@
- 
-   for (;;) {
-     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
-+    /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
-+             - storeEntityValue
-+             - processXmlDecl
-+    */
-     parser->m_eventEndPtr = next;
-     if (tok <= 0) {
-       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
-@@ -3989,7 +4169,8 @@
-         break;
-       }
-       /* found end of entity value - can store it now */
--      return storeEntityValue(parser, parser->m_encoding, s, end);
-+      return storeEntityValue(parser, parser->m_encoding, s, end,
-+                              XML_ACCOUNT_DIRECT);
-     } else if (tok == XML_TOK_XML_DECL) {
-       enum XML_Error result;
-       result = processXmlDecl(parser, 0, start, next);
-@@ -4016,6 +4197,14 @@
-     */
-     else if (tok == XML_TOK_BOM && next == end
-              && ! parser->m_parsingStatus.finalBuffer) {
-+#  ifdef XML_DTD
-+      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
-+                                    XML_ACCOUNT_DIRECT)) {
-+        accountingOnAbort(parser);
-+        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+      }
-+#  endif
-+
-       *nextPtr = next;
-       return XML_ERROR_NONE;
-     }
-@@ -4058,16 +4247,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
--     as valid, and report a syntax error, so we have to skip the BOM
-+     as valid, and report a syntax error, so we have to skip the BOM, and
-+     account for the BOM bytes.
-   */
-   else if (tok == XML_TOK_BOM) {
-+	if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
-+	                              XML_ACCOUNT_DIRECT)) {
-+	  accountingOnAbort(parser);
-+	  return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+	}
-+
-     s = next;
-     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
-   }
- 
-   parser->m_processor = prologProcessor;
-   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
--                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
-+          (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
-+          XML_ACCOUNT_DIRECT);
- }
- 
- static enum XML_Error PTRCALL
-@@ -4080,6 +4277,9 @@
- 
-   for (;;) {
-     tok = XmlPrologTok(enc, start, end, &next);
-+    /* Note: These bytes are accounted later in:
-+             - storeEntityValue
-+    */
-     if (tok <= 0) {
-       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
-         *nextPtr = s;
-@@ -4097,7 +4297,7 @@
-         break;
-       }
-       /* found end of entity value - can store it now */
--      return storeEntityValue(parser, enc, s, end);
-+      return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
-     }
-     start = next;
-   }
-@@ -4111,13 +4311,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,
--                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
-+          (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
-+          XML_ACCOUNT_DIRECT);
- }
- 
- static enum XML_Error
- doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
-          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
--         XML_Bool allowClosingDoctype) {
-+         XML_Bool allowClosingDoctype, enum XML_Account account) {
- #ifdef XML_DTD
-   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
- #endif /* XML_DTD */
-@@ -4144,6 +4345,10 @@
-   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
-   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
- 
-+#ifndef XML_DTD
-+  UNUSED_P(account);
-+#endif
-+
-   /* save one level of indirection */
-   DTD *const dtd = parser->m_dtd;
- 
-@@ -4208,6 +4413,19 @@
-       }
-     }
-     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
-+#ifdef XML_DTD
-+    switch (role) {
-+    case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
-+    case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
-+    case XML_ROLE_TEXT_DECL:      // bytes accounted in processXmlDecl
-+      break;
-+    default:
-+      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
-+        accountingOnAbort(parser);
-+        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+      }
-+    }
-+#endif
-     switch (role) {
-     case XML_ROLE_XML_DECL: {
-       enum XML_Error result = processXmlDecl(parser, 0, s, next);
-@@ -4483,7 +4701,8 @@
-         const XML_Char *attVal;
-         enum XML_Error result = storeAttributeValue(
-             parser, enc, parser->m_declAttributeIsCdata,
--            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
-+            s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
-+            XML_ACCOUNT_NONE);
-         if (result)
-           return result;
-         attVal = poolStart(&dtd->pool);
-@@ -4516,8 +4735,9 @@
-       break;
-     case XML_ROLE_ENTITY_VALUE:
-       if (dtd->keepProcessing) {
--        enum XML_Error result = storeEntityValue(
--            parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
-+          enum XML_Error result
-+              = storeEntityValue(parser, enc, s + enc->minBytesPerChar,
-+                                 next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
-         if (parser->m_declEntity) {
-           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
-           parser->m_declEntity->textLen
-@@ -4907,12 +5127,15 @@
-         if (parser->m_externalEntityRefHandler) {
-           dtd->paramEntityRead = XML_FALSE;
-           entity->open = XML_TRUE;
-+          entityTrackingOnOpen(parser, entity, __LINE__);
-           if (! parser->m_externalEntityRefHandler(
-                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
-                   entity->systemId, entity->publicId)) {
-+        	entityTrackingOnClose(parser, entity, __LINE__);
-             entity->open = XML_FALSE;
-             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-           }
-+          entityTrackingOnClose(parser, entity, __LINE__);
-           entity->open = XML_FALSE;
-           handleDefault = XML_FALSE;
-           if (! dtd->paramEntityRead) {
-@@ -5110,6 +5333,13 @@
-   for (;;) {
-     const char *next = NULL;
-     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
-+#ifdef XML_DTD
-+    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
-+                                  XML_ACCOUNT_DIRECT)) {
-+      accountingOnAbort(parser);
-+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+    }
-+#endif
-     parser->m_eventEndPtr = next;
-     switch (tok) {
-     /* report partial linebreak - it might be the last token */
-@@ -5183,6 +5413,9 @@
-       return XML_ERROR_NO_MEMORY;
-   }
-   entity->open = XML_TRUE;
-+#ifdef XML_DTD
-+  entityTrackingOnOpen(parser, entity, __LINE__);
-+#endif
-   entity->processed = 0;
-   openEntity->next = parser->m_openInternalEntities;
-   parser->m_openInternalEntities = openEntity;
-@@ -5201,17 +5434,22 @@
-     int tok
-         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
-     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
--                      tok, next, &next, XML_FALSE, XML_FALSE);
-+            tok, next, &next, XML_FALSE, XML_FALSE,
-+            XML_ACCOUNT_ENTITY_EXPANSION);
-   } else
- #endif /* XML_DTD */
-     result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
--                       textStart, textEnd, &next, XML_FALSE);
-+            textStart, textEnd, &next, XML_FALSE,
-+            XML_ACCOUNT_ENTITY_EXPANSION);
- 
-   if (result == XML_ERROR_NONE) {
-     if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
-       entity->processed = (int)(next - textStart);
-       parser->m_processor = internalEntityProcessor;
-     } else {
-+#ifdef XML_DTD
-+      entityTrackingOnClose(parser, entity, __LINE__);
-+#endif /* XML_DTD */
-       entity->open = XML_FALSE;
-       parser->m_openInternalEntities = openEntity->next;
-       /* put openEntity back in list of free instances */
-@@ -5244,12 +5482,13 @@
-     int tok
-         = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
-     result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
--                      tok, next, &next, XML_FALSE, XML_TRUE);
-+            tok, next, &next, XML_FALSE, XML_TRUE,
-+            XML_ACCOUNT_ENTITY_EXPANSION);
-   } else
- #endif /* XML_DTD */
-     result = doContent(parser, openEntity->startTagLevel,
-                        parser->m_internalEncoding, textStart, textEnd, &next,
--                       XML_FALSE);
-+                       XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
- 
-   if (result != XML_ERROR_NONE)
-     return result;
-@@ -5258,6 +5497,9 @@
-     entity->processed = (int)(next - (const char *)entity->textPtr);
-     return result;
-   } else {
-+#ifdef XML_DTD
-+    entityTrackingOnClose(parser, entity, __LINE__);
-+#endif
-     entity->open = XML_FALSE;
-     parser->m_openInternalEntities = openEntity->next;
-     /* put openEntity back in list of free instances */
-@@ -5271,7 +5513,8 @@
-     parser->m_processor = prologProcessor;
-     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
-     return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
--                    (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
-+            (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
-+            XML_ACCOUNT_DIRECT);
-   } else
- #endif /* XML_DTD */
-   {
-@@ -5279,7 +5522,8 @@
-     /* see externalEntityContentProcessor vs contentProcessor */
-     return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
-                      s, end, nextPtr,
--                     (XML_Bool)! parser->m_parsingStatus.finalBuffer);
-+                     (XML_Bool)! parser->m_parsingStatus.finalBuffer,
-+                     XML_ACCOUNT_DIRECT);
-   }
- }
- 
-@@ -5294,9 +5538,10 @@
- 
- static enum XML_Error
- storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
--                    const char *ptr, const char *end, STRING_POOL *pool) {
-+        const char *ptr, const char *end, STRING_POOL *pool,
-+        enum XML_Account account) {
-   enum XML_Error result
--      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
-+      = appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
-   if (result)
-     return result;
-   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
-@@ -5308,11 +5553,23 @@
- 
- static enum XML_Error
- appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
--                     const char *ptr, const char *end, STRING_POOL *pool) {
-+                     const char *ptr, const char *end, STRING_POOL *pool,
-+                     enum XML_Account account) {
-   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
-+#ifndef XML_DTD
-+  UNUSED_P(account);
-+#endif
-+
-   for (;;) {
--    const char *next;
-+	  const char *next
-+	        = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
-     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
-+#ifdef XML_DTD
-+    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
-+      accountingOnAbort(parser);
-+      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+    }
-+#endif
-     switch (tok) {
-     case XML_TOK_NONE:
-       return XML_ERROR_NONE;
-@@ -5372,6 +5629,14 @@
-       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
-           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
-       if (ch) {
-+#ifdef XML_DTD
-+        /* NOTE: We are replacing 4-6 characters original input for 1 character
-+         *       so there is no amplification and hence recording without
-+         *       protection. */
-+        accountingDiffTolerated(parser, tok, (char *)&ch,
-+                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
-+                                XML_ACCOUNT_ENTITY_EXPANSION);
-+#endif /* XML_DTD */
-         if (! poolAppendChar(pool, ch))
-           return XML_ERROR_NO_MEMORY;
-         break;
-@@ -5449,9 +5714,16 @@
-         enum XML_Error result;
-         const XML_Char *textEnd = entity->textPtr + entity->textLen;
-         entity->open = XML_TRUE;
-+#ifdef XML_DTD
-+        entityTrackingOnOpen(parser, entity, __LINE__);
-+#endif
-         result = appendAttributeValue(parser, parser->m_internalEncoding,
-                                       isCdata, (const char *)entity->textPtr,
--                                      (const char *)textEnd, pool);
-+                                      (const char *)textEnd, pool,
-+                                      XML_ACCOUNT_ENTITY_EXPANSION);
-+#ifdef XML_DTD
-+        entityTrackingOnClose(parser, entity, __LINE__);
-+#endif
-         entity->open = XML_FALSE;
-         if (result)
-           return result;
-@@ -5481,13 +5753,16 @@
- 
- static enum XML_Error
- storeEntityValue(XML_Parser parser, const ENCODING *enc,
--                 const char *entityTextPtr, const char *entityTextEnd) {
-+                 const char *entityTextPtr, const char *entityTextEnd,
-+                 enum XML_Account account) {
-   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
-   STRING_POOL *pool = &(dtd->entityValuePool);
-   enum XML_Error result = XML_ERROR_NONE;
- #ifdef XML_DTD
-   int oldInEntityValue = parser->m_prologState.inEntityValue;
-   parser->m_prologState.inEntityValue = 1;
-+#else
-+  UNUSED_P(account);
- #endif /* XML_DTD */
-   /* never return Null for the value argument in EntityDeclHandler,
-      since this would indicate an external entity; therefore we
-@@ -5498,8 +5773,19 @@
-   }
- 
-   for (;;) {
--    const char *next;
-+	  const char *next
-+	      = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
-     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
-+
-+#ifdef XML_DTD
-+    if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
-+                                  account)) {
-+      accountingOnAbort(parser);
-+      result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
-+      goto endEntityValue;
-+    }
-+#endif
-+
-     switch (tok) {
-     case XML_TOK_PARAM_ENTITY_REF:
- #ifdef XML_DTD
-@@ -5535,13 +5821,16 @@
-           if (parser->m_externalEntityRefHandler) {
-             dtd->paramEntityRead = XML_FALSE;
-             entity->open = XML_TRUE;
-+            entityTrackingOnOpen(parser, entity, __LINE__);
-             if (! parser->m_externalEntityRefHandler(
-                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
-                     entity->systemId, entity->publicId)) {
-+                entityTrackingOnClose(parser, entity, __LINE__);
-               entity->open = XML_FALSE;
-               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
-               goto endEntityValue;
-             }
-+            entityTrackingOnClose(parser, entity, __LINE__);
-             entity->open = XML_FALSE;
-             if (! dtd->paramEntityRead)
-               dtd->keepProcessing = dtd->standalone;
-@@ -5549,9 +5838,12 @@
-             dtd->keepProcessing = dtd->standalone;
-         } else {
-           entity->open = XML_TRUE;
-+          entityTrackingOnOpen(parser, entity, __LINE__);
-           result = storeEntityValue(
-               parser, parser->m_internalEncoding, (const char *)entity->textPtr,
--              (const char *)(entity->textPtr + entity->textLen));
-+              (const char *)(entity->textPtr + entity->textLen),
-+              XML_ACCOUNT_ENTITY_EXPANSION);
-+          entityTrackingOnClose(parser, entity, __LINE__);
-           entity->open = XML_FALSE;
-           if (result)
-             goto endEntityValue;
-@@ -6912,3 +7204,766 @@
-   memcpy(result, s, charsRequired * sizeof(XML_Char));
-   return result;
- }
-+#ifdef XML_DTD
-+
-+static float
-+accountingGetCurrentAmplification(XML_Parser rootParser) {
-+  const XmlBigCount countBytesOutput
-+      = rootParser->m_accounting.countBytesDirect
-+        + rootParser->m_accounting.countBytesIndirect;
-+  const float amplificationFactor
-+      = rootParser->m_accounting.countBytesDirect
-+            ? (countBytesOutput
-+               / (float)(rootParser->m_accounting.countBytesDirect))
-+            : 1.0f;
-+  assert(! rootParser->m_parentParser);
-+  return amplificationFactor;
-+}
-+
-+static void
-+accountingReportStats(XML_Parser originParser, const char *epilog) {
-+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
-+  float amplificationFactor;
-+  assert(! rootParser->m_parentParser);
-+
-+  if (rootParser->m_accounting.debugLevel < 1) {
-+    return;
-+  }
-+
-+  amplificationFactor
-+      = accountingGetCurrentAmplification(rootParser);
-+  fprintf(stderr,
-+          "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
-+              "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
-+          (void *)rootParser, rootParser->m_accounting.countBytesDirect,
-+          rootParser->m_accounting.countBytesIndirect,
-+          (double)amplificationFactor, epilog);
-+}
-+
-+static void
-+accountingOnAbort(XML_Parser originParser) {
-+  accountingReportStats(originParser, " ABORTING\n");
-+}
-+
-+static void
-+accountingReportDiff(XML_Parser rootParser,
-+                     unsigned int levelsAwayFromRootParser, const char *before,
-+                     const char *after, ptrdiff_t bytesMore, int source_line,
-+                     enum XML_Account account) {
-+  const char ellipis[] = "[..]";
-+  const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
-+  const unsigned int contextLength = 10;
-+  const char *walker = before;
-+
-+  assert(! rootParser->m_parentParser);
-+
-+  fprintf(stderr,
-+          " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%d, xmlparse.c:%d) %*s\"",
-+          bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
-+          levelsAwayFromRootParser, source_line, 10, "");
-+
-+  /* Note: Performance is of no concern here */
-+  if ((rootParser->m_accounting.debugLevel >= 3)
-+      || (after - before)
-+             <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
-+    for (; walker < after; walker++) {
-+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
-+    }
-+  } else {
-+    for (; walker < before + contextLength; walker++) {
-+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
-+    }
-+    fprintf(stderr, ellipis);
-+    walker = after - contextLength;
-+    for (; walker < after; walker++) {
-+      fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
-+    }
-+  }
-+  fprintf(stderr, "\"\n");
-+}
-+
-+static XML_Bool
-+accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
-+                        const char *after, int source_line,
-+                        enum XML_Account account) {
-+  unsigned int levelsAwayFromRootParser;
-+  XML_Parser rootParser;
-+  int isDirect;
-+  ptrdiff_t bytesMore;
-+  XmlBigCount * additionTarget;
-+  XmlBigCount countBytesOutput;
-+  float amplificationFactor;
-+  XML_Bool tolerated;
-+  /* Note: We need to check the token type *first* to be sure that
-+   *       we can even access variable <after>, safely.
-+   *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
-+  switch (tok) {
-+  case XML_TOK_INVALID:
-+  case XML_TOK_PARTIAL:
-+  case XML_TOK_PARTIAL_CHAR:
-+  case XML_TOK_NONE:
-+    return XML_TRUE;
-+  }
-+
-+  if (account == XML_ACCOUNT_NONE)
-+    return XML_TRUE; /* because these bytes have been accounted for, already */
-+
-+  rootParser
-+      = getRootParserOf(originParser, &levelsAwayFromRootParser);
-+  assert(! rootParser->m_parentParser);
-+
-+  isDirect
-+      = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
-+  bytesMore = after - before;
-+
-+  additionTarget
-+      = isDirect ? &rootParser->m_accounting.countBytesDirect
-+                 : &rootParser->m_accounting.countBytesIndirect;
-+
-+  /* Detect and avoid integer overflow */
-+  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
-+    return XML_FALSE;
-+  *additionTarget += bytesMore;
-+
-+  countBytesOutput
-+      = rootParser->m_accounting.countBytesDirect
-+        + rootParser->m_accounting.countBytesIndirect;
-+  amplificationFactor
-+      = accountingGetCurrentAmplification(rootParser);
-+  tolerated
-+      = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
-+        || (amplificationFactor
-+            <= rootParser->m_accounting.maximumAmplificationFactor);
-+
-+  if (rootParser->m_accounting.debugLevel >= 2) {
-+    accountingReportStats(rootParser, "");
-+    accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
-+                         bytesMore, source_line, account);
-+  }
-+
-+  return tolerated;
-+}
-+
-+unsigned long long
-+testingAccountingGetCountBytesDirect(XML_Parser parser) {
-+  if (! parser)
-+    return 0;
-+  return parser->m_accounting.countBytesDirect;
-+}
-+
-+unsigned long long
-+testingAccountingGetCountBytesIndirect(XML_Parser parser) {
-+  if (! parser)
-+    return 0;
-+  return parser->m_accounting.countBytesIndirect;
-+}
-+
-+static void
-+entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
-+                          const char *action, int sourceLine) {
-+  const char * entityName;
-+  assert(! rootParser->m_parentParser);
-+  if (rootParser->m_entity_stats.debugLevel < 1)
-+    return;
-+
-+#  if defined(XML_UNICODE)
-+  entityName = "[..]";
-+#  else
-+  entityName = entity->name;
-+#  endif
-+
-+  fprintf(
-+      stderr,
-+      "expat: Entities(%p): Count %9d, depth %2d/%2d %*s%s%s; %s length %d (xmlparse.c:%d)\n",
-+      (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
-+      rootParser->m_entity_stats.currentDepth,
-+      rootParser->m_entity_stats.maximumDepthSeen,
-+      (rootParser->m_entity_stats.currentDepth - 1) * 2, "",
-+      entity->is_param ? "%" : "&", entityName, action, entity->textLen,
-+      sourceLine);
-+}
-+
-+static void
-+entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
-+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
-+  assert(! rootParser->m_parentParser);
-+
-+  rootParser->m_entity_stats.countEverOpened++;
-+  rootParser->m_entity_stats.currentDepth++;
-+  if (rootParser->m_entity_stats.currentDepth
-+      > rootParser->m_entity_stats.maximumDepthSeen) {
-+    rootParser->m_entity_stats.maximumDepthSeen++;
-+  }
-+
-+  entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
-+}
-+
-+static void
-+entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
-+  const XML_Parser rootParser = getRootParserOf(originParser, NULL);
-+  assert(! rootParser->m_parentParser);
-+
-+  entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
-+  rootParser->m_entity_stats.currentDepth--;
-+}
-+
-+static XML_Parser
-+getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
-+  XML_Parser rootParser = parser;
-+  unsigned int stepsTakenUpwards = 0;
-+  while (rootParser->m_parentParser) {
-+    rootParser = rootParser->m_parentParser;
-+    stepsTakenUpwards++;
-+  }
-+  assert(! rootParser->m_parentParser);
-+  if (outLevelDiff != NULL) {
-+    *outLevelDiff = stepsTakenUpwards;
-+  }
-+  return rootParser;
-+}
-+
-+const char *
-+unsignedCharToPrintable(unsigned char c) {
-+  switch (c) {
-+  case 0:
-+    return "\\0";
-+  case 1:
-+    return "\\x1";
-+  case 2:
-+    return "\\x2";
-+  case 3:
-+    return "\\x3";
-+  case 4:
-+    return "\\x4";
-+  case 5:
-+    return "\\x5";
-+  case 6:
-+    return "\\x6";
-+  case 7:
-+    return "\\x7";
-+  case 8:
-+    return "\\x8";
-+  case 9:
-+    return "\\t";
-+  case 10:
-+    return "\\n";
-+  case 11:
-+    return "\\xB";
-+  case 12:
-+    return "\\xC";
-+  case 13:
-+    return "\\r";
-+  case 14:
-+    return "\\xE";
-+  case 15:
-+    return "\\xF";
-+  case 16:
-+    return "\\x10";
-+  case 17:
-+    return "\\x11";
-+  case 18:
-+    return "\\x12";
-+  case 19:
-+    return "\\x13";
-+  case 20:
-+    return "\\x14";
-+  case 21:
-+    return "\\x15";
-+  case 22:
-+    return "\\x16";
-+  case 23:
-+    return "\\x17";
-+  case 24:
-+    return "\\x18";
-+  case 25:
-+    return "\\x19";
-+  case 26:
-+    return "\\x1A";
-+  case 27:
-+    return "\\x1B";
-+  case 28:
-+    return "\\x1C";
-+  case 29:
-+    return "\\x1D";
-+  case 30:
-+    return "\\x1E";
-+  case 31:
-+    return "\\x1F";
-+  case 32:
-+    return " ";
-+  case 33:
-+    return "!";
-+  case 34:
-+    return "\\\"";
-+  case 35:
-+    return "#";
-+  case 36:
-+    return "$";
-+  case 37:
-+    return "%";
-+  case 38:
-+    return "&";
-+  case 39:
-+    return "'";
-+  case 40:
-+    return "(";
-+  case 41:
-+    return ")";
-+  case 42:
-+    return "*";
-+  case 43:
-+    return "+";
-+  case 44:
-+    return ",";
-+  case 45:
-+    return "-";
-+  case 46:
-+    return ".";
-+  case 47:
-+    return "/";
-+  case 48:
-+    return "0";
-+  case 49:
-+    return "1";
-+  case 50:
-+    return "2";
-+  case 51:
-+    return "3";
-+  case 52:
-+    return "4";
-+  case 53:
-+    return "5";
-+  case 54:
-+    return "6";
-+  case 55:
-+    return "7";
-+  case 56:
-+    return "8";
-+  case 57:
-+    return "9";
-+  case 58:
-+    return ":";
-+  case 59:
-+    return ";";
-+  case 60:
-+    return "<";
-+  case 61:
-+    return "=";
-+  case 62:
-+    return ">";
-+  case 63:
-+    return "?";
-+  case 64:
-+    return "@";
-+  case 65:
-+    return "A";
-+  case 66:
-+    return "B";
-+  case 67:
-+    return "C";
-+  case 68:
-+    return "D";
-+  case 69:
-+    return "E";
-+  case 70:
-+    return "F";
-+  case 71:
-+    return "G";
-+  case 72:
-+    return "H";
-+  case 73:
-+    return "I";
-+  case 74:
-+    return "J";
-+  case 75:
-+    return "K";
-+  case 76:
-+    return "L";
-+  case 77:
-+    return "M";
-+  case 78:
-+    return "N";
-+  case 79:
-+    return "O";
-+  case 80:
-+    return "P";
-+  case 81:
-+    return "Q";
-+  case 82:
-+    return "R";
-+  case 83:
-+    return "S";
-+  case 84:
-+    return "T";
-+  case 85:
-+    return "U";
-+  case 86:
-+    return "V";
-+  case 87:
-+    return "W";
-+  case 88:
-+    return "X";
-+  case 89:
-+    return "Y";
-+  case 90:
-+    return "Z";
-+  case 91:
-+    return "[";
-+  case 92:
-+    return "\\\\";
-+  case 93:
-+    return "]";
-+  case 94:
-+    return "^";
-+  case 95:
-+    return "_";
-+  case 96:
-+    return "`";
-+  case 97:
-+    return "a";
-+  case 98:
-+    return "b";
-+  case 99:
-+    return "c";
-+  case 100:
-+    return "d";
-+  case 101:
-+    return "e";
-+  case 102:
-+    return "f";
-+  case 103:
-+    return "g";
-+  case 104:
-+    return "h";
-+  case 105:
-+    return "i";
-+  case 106:
-+    return "j";
-+  case 107:
-+    return "k";
-+  case 108:
-+    return "l";
-+  case 109:
-+    return "m";
-+  case 110:
-+    return "n";
-+  case 111:
-+    return "o";
-+  case 112:
-+    return "p";
-+  case 113:
-+    return "q";
-+  case 114:
-+    return "r";
-+  case 115:
-+    return "s";
-+  case 116:
-+    return "t";
-+  case 117:
-+    return "u";
-+  case 118:
-+    return "v";
-+  case 119:
-+    return "w";
-+  case 120:
-+    return "x";
-+  case 121:
-+    return "y";
-+  case 122:
-+    return "z";
-+  case 123:
-+    return "{";
-+  case 124:
-+    return "|";
-+  case 125:
-+    return "}";
-+  case 126:
-+    return "~";
-+  case 127:
-+    return "\\x7F";
-+  case 128:
-+    return "\\x80";
-+  case 129:
-+    return "\\x81";
-+  case 130:
-+    return "\\x82";
-+  case 131:
-+    return "\\x83";
-+  case 132:
-+    return "\\x84";
-+  case 133:
-+    return "\\x85";
-+  case 134:
-+    return "\\x86";
-+  case 135:
-+    return "\\x87";
-+  case 136:
-+    return "\\x88";
-+  case 137:
-+    return "\\x89";
-+  case 138:
-+    return "\\x8A";
-+  case 139:
-+    return "\\x8B";
-+  case 140:
-+    return "\\x8C";
-+  case 141:
-+    return "\\x8D";
-+  case 142:
-+    return "\\x8E";
-+  case 143:
-+    return "\\x8F";
-+  case 144:
-+    return "\\x90";
-+  case 145:
-+    return "\\x91";
-+  case 146:
-+    return "\\x92";
-+  case 147:
-+    return "\\x93";
-+  case 148:
-+    return "\\x94";
-+  case 149:
-+    return "\\x95";
-+  case 150:
-+    return "\\x96";
-+  case 151:
-+    return "\\x97";
-+  case 152:
-+    return "\\x98";
-+  case 153:
-+    return "\\x99";
-+  case 154:
-+    return "\\x9A";
-+  case 155:
-+    return "\\x9B";
-+  case 156:
-+    return "\\x9C";
-+  case 157:
-+    return "\\x9D";
-+  case 158:
-+    return "\\x9E";
-+  case 159:
-+    return "\\x9F";
-+  case 160:
-+    return "\\xA0";
-+  case 161:
-+    return "\\xA1";
-+  case 162:
-+    return "\\xA2";
-+  case 163:
-+    return "\\xA3";
-+  case 164:
-+    return "\\xA4";
-+  case 165:
-+    return "\\xA5";
-+  case 166:
-+    return "\\xA6";
-+  case 167:
-+    return "\\xA7";
-+  case 168:
-+    return "\\xA8";
-+  case 169:
-+    return "\\xA9";
-+  case 170:
-+    return "\\xAA";
-+  case 171:
-+    return "\\xAB";
-+  case 172:
-+    return "\\xAC";
-+  case 173:
-+    return "\\xAD";
-+  case 174:
-+    return "\\xAE";
-+  case 175:
-+    return "\\xAF";
-+  case 176:
-+    return "\\xB0";
-+  case 177:
-+    return "\\xB1";
-+  case 178:
-+    return "\\xB2";
-+  case 179:
-+    return "\\xB3";
-+  case 180:
-+    return "\\xB4";
-+  case 181:
-+    return "\\xB5";
-+  case 182:
-+    return "\\xB6";
-+  case 183:
-+    return "\\xB7";
-+  case 184:
-+    return "\\xB8";
-+  case 185:
-+    return "\\xB9";
-+  case 186:
-+    return "\\xBA";
-+  case 187:
-+    return "\\xBB";
-+  case 188:
-+    return "\\xBC";
-+  case 189:
-+    return "\\xBD";
-+  case 190:
-+    return "\\xBE";
-+  case 191:
-+    return "\\xBF";
-+  case 192:
-+    return "\\xC0";
-+  case 193:
-+    return "\\xC1";
-+  case 194:
-+    return "\\xC2";
-+  case 195:
-+    return "\\xC3";
-+  case 196:
-+    return "\\xC4";
-+  case 197:
-+    return "\\xC5";
-+  case 198:
-+    return "\\xC6";
-+  case 199:
-+    return "\\xC7";
-+  case 200:
-+    return "\\xC8";
-+  case 201:
-+    return "\\xC9";
-+  case 202:
-+    return "\\xCA";
-+  case 203:
-+    return "\\xCB";
-+  case 204:
-+    return "\\xCC";
-+  case 205:
-+    return "\\xCD";
-+  case 206:
-+    return "\\xCE";
-+  case 207:
-+    return "\\xCF";
-+  case 208:
-+    return "\\xD0";
-+  case 209:
-+    return "\\xD1";
-+  case 210:
-+    return "\\xD2";
-+  case 211:
-+    return "\\xD3";
-+  case 212:
-+    return "\\xD4";
-+  case 213:
-+    return "\\xD5";
-+  case 214:
-+    return "\\xD6";
-+  case 215:
-+    return "\\xD7";
-+  case 216:
-+    return "\\xD8";
-+  case 217:
-+    return "\\xD9";
-+  case 218:
-+    return "\\xDA";
-+  case 219:
-+    return "\\xDB";
-+  case 220:
-+    return "\\xDC";
-+  case 221:
-+    return "\\xDD";
-+  case 222:
-+    return "\\xDE";
-+  case 223:
-+    return "\\xDF";
-+  case 224:
-+    return "\\xE0";
-+  case 225:
-+    return "\\xE1";
-+  case 226:
-+    return "\\xE2";
-+  case 227:
-+    return "\\xE3";
-+  case 228:
-+    return "\\xE4";
-+  case 229:
-+    return "\\xE5";
-+  case 230:
-+    return "\\xE6";
-+  case 231:
-+    return "\\xE7";
-+  case 232:
-+    return "\\xE8";
-+  case 233:
-+    return "\\xE9";
-+  case 234:
-+    return "\\xEA";
-+  case 235:
-+    return "\\xEB";
-+  case 236:
-+    return "\\xEC";
-+  case 237:
-+    return "\\xED";
-+  case 238:
-+    return "\\xEE";
-+  case 239:
-+    return "\\xEF";
-+  case 240:
-+    return "\\xF0";
-+  case 241:
-+    return "\\xF1";
-+  case 242:
-+    return "\\xF2";
-+  case 243:
-+    return "\\xF3";
-+  case 244:
-+    return "\\xF4";
-+  case 245:
-+    return "\\xF5";
-+  case 246:
-+    return "\\xF6";
-+  case 247:
-+    return "\\xF7";
-+  case 248:
-+    return "\\xF8";
-+  case 249:
-+    return "\\xF9";
-+  case 250:
-+    return "\\xFA";
-+  case 251:
-+    return "\\xFB";
-+  case 252:
-+    return "\\xFC";
-+  case 253:
-+    return "\\xFD";
-+  case 254:
-+    return "\\xFE";
-+  case 255:
-+    return "\\xFF";
-+  default:
-+    assert(0); /* never gets here */
-+    return "dead code";
-+  }
-+  assert(0); /* never gets here */
-+}
-+
-+#endif /* XML_DTD */
-+
-+static unsigned long
-+getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
-+  const char *const valueOrNull = getenv(variableName);
-+  const char * value;
-+  char *afterValue;
-+  unsigned long debugLevel;
-+  if (valueOrNull == NULL) {
-+    return defaultDebugLevel;
-+  }
-+  value = valueOrNull;
-+
-+  errno = 0;
-+  afterValue = (char *)value;
-+  debugLevel = strtoul(value, &afterValue, 10);
-+  if ((errno != 0) || (afterValue[0] != '\0')) {
-+    errno = 0;
-+    return defaultDebugLevel;
-+  }
-+
-+  return debugLevel;
-+}
-diff -ru misc/expat-2.2.10/tests/benchmark/Makefile.in misc/build/expat-2.2.10/tests/benchmark/Makefile.in
---- misc/expat-2.2.10/tests/benchmark/Makefile.in	2020-10-03 11:37:06.000000000 -0400
-+++ misc/build/expat-2.2.10/tests/benchmark/Makefile.in	2021-07-18 18:17:02.000000000 -0400
-@@ -1,7 +1,7 @@
--# Makefile.in generated by automake 1.16.2 from Makefile.am.
-+# Makefile.in generated by automake 1.16.1 from Makefile.am.
- # @configure_input@
- 
--# Copyright (C) 1994-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
- 
- # This Makefile.in is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -335,7 +335,6 @@
- prefix = @prefix@
- program_transform_name = @program_transform_name@
- psdir = @psdir@
--runstatedir = @runstatedir@
- sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- srcdir = @srcdir@
-diff -ru misc/expat-2.2.10/tests/Makefile.in misc/build/expat-2.2.10/tests/Makefile.in
---- misc/expat-2.2.10/tests/Makefile.in	2020-10-03 11:37:06.000000000 -0400
-+++ misc/build/expat-2.2.10/tests/Makefile.in	2021-07-18 18:17:02.000000000 -0400
-@@ -1,7 +1,7 @@
--# Makefile.in generated by automake 1.16.2 from Makefile.am.
-+# Makefile.in generated by automake 1.16.1 from Makefile.am.
- # @configure_input@
- 
--# Copyright (C) 1994-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
- 
- # This Makefile.in is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -616,7 +616,6 @@
- prefix = @prefix@
- program_transform_name = @program_transform_name@
- psdir = @psdir@
--runstatedir = @runstatedir@
- sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- srcdir = @srcdir@
-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 11:14:57.000000000 -0400
-+++ misc/build/expat-2.2.10/tests/runtests.c	2021-07-18 17:27:08.000000000 -0400
-@@ -45,6 +45,7 @@
- #include <stddef.h> /* ptrdiff_t */
- #include <ctype.h>
- #include <limits.h>
-+#include <math.h>   /* NAN, INFINITY, isnan */
- 
- #if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
- /* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
-@@ -72,7 +73,7 @@
- #include "expat.h"
- #include "chardata.h"
- #include "structdata.h"
--#include "internal.h" /* for UNUSED_P only */
-+#include "internal.h"
- #include "minicheck.h"
- #include "memcheck.h"
- #include "siphash.h"
-@@ -11231,6 +11232,381 @@
- }
- END_TEST
- 
-+#if defined(XML_DTD)
-+typedef enum XML_Status (*XmlParseFunction)(XML_Parser, const char *, int, int);
-+
-+struct AccountingTestCase {
-+  const char *primaryText;
-+  const char *firstExternalText;  /* often NULL */
-+  const char *secondExternalText; /* often NULL */
-+  const unsigned long long expectedCountBytesIndirectExtra;
-+  XML_Bool singleBytesWanted;
-+};
-+
-+static int
-+accounting_external_entity_ref_handler(XML_Parser parser,
-+                                       const XML_Char *context,
-+                                       const XML_Char *base,
-+                                       const XML_Char *systemId,
-+                                       const XML_Char *publicId) {
-+  UNUSED_P(context);
-+  UNUSED_P(base);
-+  UNUSED_P(publicId);
-+
-+  const struct AccountingTestCase *const testCase
-+      = (const struct AccountingTestCase *)XML_GetUserData(parser);
-+
-+  const char *externalText = NULL;
-+  if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
-+    externalText = testCase->firstExternalText;
-+  } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) {
-+    externalText = testCase->secondExternalText;
-+  } else {
-+    assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
-+  }
-+  assert(externalText);
-+
-+  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
-+  assert(entParser);
-+
-+  const XmlParseFunction xmlParseFunction
-+      = testCase->singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
-+
-+  const enum XML_Status status = xmlParseFunction(
-+      entParser, externalText, (int)strlen(externalText), XML_TRUE);
-+
-+  XML_ParserFree(entParser);
-+  return status;
-+}
-+
-+START_TEST(test_accounting_precision) {
-+  const XML_Bool filled_later = XML_TRUE; /* value is arbitrary */
-+  struct AccountingTestCase cases[] = {
-+      {"<e/>", NULL, NULL, 0, 0},
-+      {"<e></e>", NULL, NULL, 0, 0},
-+
-+      /* Attributes */
-+      {"<e k1=\"v2\" k2=\"v2\"/>", NULL, NULL, 0, filled_later},
-+      {"<e k1=\"v2\" k2=\"v2\"></e>", NULL, NULL, 0, 0},
-+      {"<p:e xmlns:p=\"https://domain.invalid/\" />", NULL, NULL, 0,
-+       filled_later},
-+      {"<e k=\"&amp;&apos;&gt;&lt;&quot;\" />", NULL, NULL,
-+       sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
-+      {"<e1 xmlns='https://example.org/'>\n"
-+       "  <e2 xmlns=''/>\n"
-+       "</e1>",
-+       NULL, NULL, 0, filled_later},
-+
-+      /* Text */
-+      {"<e>text</e>", NULL, NULL, 0, filled_later},
-+      {"<e1><e2>text1<e3/>text2</e2></e1>", NULL, NULL, 0, filled_later},
-+      {"<e>&amp;&apos;&gt;&lt;&quot;</e>", NULL, NULL,
-+       sizeof(XML_Char) * 5 /* number of predefined entites */, filled_later},
-+      {"<e>&#65;&#41;</e>", NULL, NULL, 0, filled_later},
-+
-+      /* Prolog */
-+      {"<?xml version=\"1.0\"?><root/>", NULL, NULL, 0, filled_later},
-+
-+      /* Whitespace */
-+      {"  <e1>  <e2>  </e2>  </e1>  ", NULL, NULL, 0, filled_later},
-+      {"<e1  ><e2  /></e1  >", NULL, NULL, 0, filled_later},
-+      {"<e1><e2 k = \"v\"/><e3 k = 'v'/></e1>", NULL, NULL, 0, filled_later},
-+
-+      /* Comments */
-+      {"<!-- Comment --><e><!-- Comment --></e>", NULL, NULL, 0, filled_later},
-+
-+      /* Processing instructions */
-+      {"<?xml-stylesheet type=\"text/xsl\" href=\"https://domain.invalid/\" media=\"all\"?><e/>",
-+       NULL, NULL, 0, filled_later},
-+      {"<?pi0?><?pi1 ?><?pi2  ?><!DOCTYPE r SYSTEM 'first.ent'><r/>",
-+       "<?pi3?><!ENTITY % e1 SYSTEM 'second.ent'><?pi4?>%e1;<?pi5?>", "<?pi6?>",
-+       0, filled_later},
-+
-+      /* CDATA */
-+      {"<e><![CDATA[one two three]]></e>", NULL, NULL, 0, filled_later},
-+
-+      /* Conditional sections */
-+      {"<!DOCTYPE r [\n"
-+       "<!ENTITY % draft 'INCLUDE'>\n"
-+       "<!ENTITY % final 'IGNORE'>\n"
-+       "<!ENTITY % import SYSTEM \"first.ent\">\n"
-+       "%import;\n"
-+       "]>\n"
-+       "<r/>\n",
-+       "<![%draft;[<!--1-->]]>\n"
-+       "<![%final;[<!--22-->]]>",
-+       NULL, sizeof(XML_Char) * (strlen("INCLUDE") + strlen("IGNORE")),
-+       filled_later},
-+
-+      /* General entities */
-+      {"<!DOCTYPE root [\n"
-+       "<!ENTITY nine \"123456789\">\n"
-+       "]>\n"
-+       "<root>&nine;</root>",
-+       NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
-+      {"<!DOCTYPE root [\n"
-+       "<!ENTITY nine \"123456789\">\n"
-+       "]>\n"
-+       "<root k1=\"&nine;\"/>",
-+       NULL, NULL, sizeof(XML_Char) * strlen("123456789"), filled_later},
-+      {"<!DOCTYPE root [\n"
-+       "<!ENTITY nine \"123456789\">\n"
-+       "<!ENTITY nine2 \"&nine;&nine;\">\n"
-+       "]>\n"
-+       "<root>&nine2;&nine2;&nine2;</root>",
-+       NULL, NULL,
-+       sizeof(XML_Char) * 3 /* calls to &nine2; */ * 2 /* calls to &nine; */
-+           * (strlen("&nine;") + strlen("123456789")),
-+       filled_later},
-+      {"<!DOCTYPE r [\n"
-+       "  <!ENTITY five SYSTEM 'first.ent'>\n"
-+       "]>\n"
-+       "<r>&five;</r>",
-+       "12345", NULL, 0, filled_later},
-+
-+      /* Parameter entities */
-+      {"<!DOCTYPE r [\n"
-+       "<!ENTITY % comment \"<!---->\">\n"
-+       "%comment;\n"
-+       "]>\n"
-+       "<r/>",
-+       NULL, NULL, sizeof(XML_Char) * strlen("<!---->"), filled_later},
-+      {"<!DOCTYPE r [\n"
-+       "<!ENTITY % ninedef \"&#60;!ENTITY nine &#34;123456789&#34;&#62;\">\n"
-+       "%ninedef;\n"
-+       "]>\n"
-+       "<r>&nine;</r>",
-+       NULL, NULL,
-+       sizeof(XML_Char)
-+           * (strlen("<!ENTITY nine \"123456789\">") + strlen("123456789")),
-+       filled_later},
-+      {"<!DOCTYPE r [\n"
-+       "<!ENTITY % comment \"<!--1-->\">\n"
-+       "<!ENTITY % comment2 \"&#37;comment;<!--22-->&#37;comment;\">\n"
-+       "%comment2;\n"
-+       "]>\n"
-+       "<r/>\n",
-+       NULL, NULL,
-+       sizeof(XML_Char)
-+           * (strlen("%comment;<!--22-->%comment;") + 2 * strlen("<!--1-->")),
-+       filled_later},
-+      {"<!DOCTYPE r [\n"
-+       "  <!ENTITY % five \"12345\">\n"
-+       "  <!ENTITY % five2def \"&#60;!ENTITY five2 &#34;[&#37;five;][&#37;five;]]]]&#34;&#62;\">\n"
-+       "  %five2def;\n"
-+       "]>\n"
-+       "<r>&five2;</r>",
-+       NULL, NULL, /* from "%five2def;": */
-+       sizeof(XML_Char)
-+           * (strlen("<!ENTITY five2 \"[%five;][%five;]]]]\">")
-+              + 2 /* calls to "%five;" */ * strlen("12345")
-+              + /* from "&five2;": */ strlen("[12345][12345]]]]")),
-+       filled_later},
-+      {"<!DOCTYPE r SYSTEM \"first.ent\">\n"
-+       "<r/>",
-+       "<!ENTITY % comment '<!--1-->'>\n"
-+       "<!ENTITY % comment2 '<!--22-->%comment;<!--22-->%comment;<!--22-->'>\n"
-+       "%comment2;",
-+       NULL,
-+       sizeof(XML_Char)
-+           * (strlen("<!--22-->%comment;<!--22-->%comment;<!--22-->")
-+              + 2 /* calls to "%comment;" */ * strlen("<!---->")),
-+       filled_later},
-+      {"<!DOCTYPE r SYSTEM 'first.ent'>\n"
-+       "<r/>",
-+       "<!ENTITY % e1 PUBLIC 'foo' 'second.ent'>\n"
-+       "<!ENTITY % e2 '<!--22-->%e1;<!--22-->'>\n"
-+       "%e2;\n",
-+       "<!--1-->", sizeof(XML_Char) * strlen("<!--22--><!--1--><!--22-->"),
-+       filled_later},
-+      {
-+          "<!DOCTYPE r SYSTEM 'first.ent'>\n"
-+          "<r/>",
-+          "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
-+          "<!ENTITY % e2 '%e1;'>",
-+          "<?xml version='1.0' encoding='utf-8'?>\n"
-+          "hello\n"
-+          "xml" /* without trailing newline! */,
-+          0,
-+          filled_later,
-+      },
-+      {
-+          "<!DOCTYPE r SYSTEM 'first.ent'>\n"
-+          "<r/>",
-+          "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
-+          "<!ENTITY % e2 '%e1;'>",
-+          "<?xml version='1.0' encoding='utf-8'?>\n"
-+          "hello\n"
-+          "xml\n" /* with trailing newline! */,
-+          0,
-+          filled_later,
-+      },
-+      {"<!DOCTYPE doc SYSTEM 'first.ent'>\n"
-+       "<doc></doc>\n",
-+       "<!ELEMENT doc EMPTY>\n"
-+       "<!ENTITY % e1 SYSTEM 'second.ent'>\n"
-+       "<!ENTITY % e2 '%e1;'>\n"
-+       "%e1;\n",
-+       "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>" /* UTF-8 BOM */,
-+       strlen("\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>"), filled_later},
-+      {"<!DOCTYPE r [\n"
-+       "  <!ENTITY five SYSTEM 'first.ent'>\n"
-+       "]>\n"
-+       "<r>&five;</r>",
-+       "\xEF\xBB\xBF" /* UTF-8 BOM */, NULL, 0, filled_later},
-+  };
-+
-+  const size_t countCases = sizeof(cases) / sizeof(cases[0]);
-+  size_t u = 0;
-+  for (; u < countCases; u++) {
-+    size_t v = 0;
-+    for (; v < 2; v++) {
-+      const XML_Bool singleBytesWanted = (v == 0) ? XML_FALSE : XML_TRUE;
-+      const unsigned long long expectedCountBytesDirect
-+          = strlen(cases[u].primaryText);
-+      const unsigned long long expectedCountBytesIndirect
-+          = (cases[u].firstExternalText ? strlen(cases[u].firstExternalText)
-+                                        : 0)
-+            + (cases[u].secondExternalText ? strlen(cases[u].secondExternalText)
-+                                           : 0)
-+            + cases[u].expectedCountBytesIndirectExtra;
-+
-+      XML_Parser parser = XML_ParserCreate(NULL);
-+      XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
-+      if (cases[u].firstExternalText) {
-+        XML_SetExternalEntityRefHandler(parser,
-+                                        accounting_external_entity_ref_handler);
-+        XML_SetUserData(parser, (void *)&cases[u]);
-+        cases[u].singleBytesWanted = singleBytesWanted;
-+      }
-+
-+      const XmlParseFunction xmlParseFunction
-+          = singleBytesWanted ? _XML_Parse_SINGLE_BYTES : XML_Parse;
-+
-+      enum XML_Status status
-+          = xmlParseFunction(parser, cases[u].primaryText,
-+                             (int)strlen(cases[u].primaryText), XML_TRUE);
-+      if (status != XML_STATUS_OK) {
-+        _xml_failure(parser, __FILE__, __LINE__);
-+      }
-+
-+      const unsigned long long actualCountBytesDirect
-+          = testingAccountingGetCountBytesDirect(parser);
-+      const unsigned long long actualCountBytesIndirect
-+          = testingAccountingGetCountBytesIndirect(parser);
-+
-+      XML_ParserFree(parser);
-+
-+      if (actualCountBytesDirect != expectedCountBytesDirect) {
-+        fprintf(
-+            stderr,
-+            "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
-+                "") " count direct bytes, got " EXPAT_FMT_ULL("") " instead.\n",
-+            u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
-+            expectedCountBytesDirect, actualCountBytesDirect);
-+        fail("Count of direct bytes is off");
-+      }
-+
-+      if (actualCountBytesIndirect != expectedCountBytesIndirect) {
-+        fprintf(
-+            stderr,
-+            "Document " EXPAT_FMT_SIZE_T("") " of " EXPAT_FMT_SIZE_T("") ", %s: Expected " EXPAT_FMT_ULL(
-+                "") " count indirect bytes, got " EXPAT_FMT_ULL("") " instead.\n",
-+            u + 1, countCases, singleBytesWanted ? "single bytes" : "chunks",
-+            expectedCountBytesIndirect, actualCountBytesIndirect);
-+        fail("Count of indirect bytes is off");
-+      }
-+    }
-+  }
-+}
-+END_TEST
-+
-+START_TEST(test_billion_laughs_attack_protection_api) {
-+  XML_Parser parserWithoutParent = XML_ParserCreate(NULL);
-+  XML_Parser parserWithParent
-+      = XML_ExternalEntityParserCreate(parserWithoutParent, NULL, NULL);
-+  if (parserWithoutParent == NULL)
-+    fail("parserWithoutParent is NULL");
-+  if (parserWithParent == NULL)
-+    fail("parserWithParent is NULL");
-+
-+  // XML_SetBillionLaughsAttackProtectionMaximumAmplification, error cases
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(NULL, 123.0f)
-+      == XML_TRUE)
-+    fail("Call with NULL parser is NOT supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(parserWithParent,
-+                                                               123.0f)
-+      == XML_TRUE)
-+    fail("Call with non-root parser is NOT supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, NAN)
-+      == XML_TRUE)
-+    fail("Call with NaN limit is NOT supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, -1.0f)
-+      == XML_TRUE)
-+    fail("Call with negative limit is NOT supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, 0.9f)
-+      == XML_TRUE)
-+    fail("Call with positive limit <1.0 is NOT supposed to succeed");
-+
-+  // XML_SetBillionLaughsAttackProtectionMaximumAmplification, success cases
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, 1.0f)
-+      == XML_FALSE)
-+    fail("Call with positive limit >=1.0 is supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, 123456.789f)
-+      == XML_FALSE)
-+    fail("Call with positive limit >=1.0 is supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parserWithoutParent, INFINITY)
-+      == XML_FALSE)
-+    fail("Call with positive limit >=1.0 is supposed to succeed");
-+
-+  // XML_SetBillionLaughsAttackProtectionActivationThreshold, error cases
-+  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(NULL, 123)
-+      == XML_TRUE)
-+    fail("Call with NULL parser is NOT supposed to succeed");
-+  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(parserWithParent,
-+                                                              123)
-+      == XML_TRUE)
-+    fail("Call with non-root parser is NOT supposed to succeed");
-+
-+  // XML_SetBillionLaughsAttackProtectionActivationThreshold, success cases
-+  if (XML_SetBillionLaughsAttackProtectionActivationThreshold(
-+          parserWithoutParent, 123)
-+      == XML_FALSE)
-+    fail("Call with non-NULL parentless parser is supposed to succeed");
-+
-+  XML_ParserFree(parserWithParent);
-+  XML_ParserFree(parserWithoutParent);
-+}
-+END_TEST
-+
-+START_TEST(test_helper_unsigned_char_to_printable) {
-+  // Smoke test
-+  unsigned char uc = 0;
-+  for (; uc < (unsigned char)-1; uc++) {
-+    const char *const printable = unsignedCharToPrintable(uc);
-+    if (printable == NULL)
-+      fail("unsignedCharToPrintable returned NULL");
-+    if (strlen(printable) < (size_t)1)
-+      fail("unsignedCharToPrintable returned empty string");
-+  }
-+
-+  // Two concrete samples
-+  if (strcmp(unsignedCharToPrintable('A'), "A") != 0)
-+    fail("unsignedCharToPrintable result mistaken");
-+  if (strcmp(unsignedCharToPrintable('\\'), "\\\\") != 0)
-+    fail("unsignedCharToPrintable result mistaken");
-+}
-+END_TEST
-+#endif // defined(XML_DTD)
-+
-+
-+
- static Suite *
- make_suite(void) {
-   Suite *s = suite_create("basic");
-@@ -11239,6 +11615,9 @@
-   TCase *tc_misc = tcase_create("miscellaneous tests");
-   TCase *tc_alloc = tcase_create("allocation tests");
-   TCase *tc_nsalloc = tcase_create("namespace allocation tests");
-+#if defined(XML_DTD)
-+  TCase *tc_accounting = tcase_create("accounting tests");
-+#endif
- 
-   suite_add_tcase(s, tc_basic);
-   tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
-@@ -11603,6 +11982,13 @@
-   tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
-   tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
- 
-+#if defined(XML_DTD)
-+  suite_add_tcase(s, tc_accounting);
-+  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_helper_unsigned_char_to_printable);
-+#endif
-+
-   return s;
- }
- 
-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 11:37:06.000000000 -0400
-+++ misc/build/expat-2.2.10/xmlwf/Makefile.in	2021-07-18 18:17:02.000000000 -0400
-@@ -1,7 +1,7 @@
--# Makefile.in generated by automake 1.16.2 from Makefile.am.
-+# Makefile.in generated by automake 1.16.1 from Makefile.am.
- # @configure_input@
- 
--# Copyright (C) 1994-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
- 
- # This Makefile.in is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -344,7 +344,6 @@
- prefix = @prefix@
- program_transform_name = @program_transform_name@
- psdir = @psdir@
--runstatedir = @runstatedir@
- sbindir = @sbindir@
- sharedstatedir = @sharedstatedir@
- 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 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/xmlwf/xmltchar.h	2021-07-18 17:21:48.000000000 -0400
-@@ -54,6 +54,8 @@
- #  define tmain wmain
- #  define tremove _wremove
- #  define tchar wchar_t
-+#  define tcstof wcstof
-+#  define tcstoull wcstoull
- #else /* not XML_UNICODE */
- #  define T(x) x
- #  define ftprintf fprintf
-@@ -71,4 +73,6 @@
- #  define tmain main
- #  define tremove remove
- #  define tchar char
-+#  define tcstof strtof
-+#  define tcstoull strtoull
- #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 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/xmlwf/xmlwf.c	2021-08-25 18:35:36.000000000 -0400
-@@ -30,11 +30,15 @@
-    USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- 
-+#include <expat_config.h>
-+
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <string.h>
-+#include <math.h> /* for isnan */
-+#include <errno.h>
- 
- #include "expat.h"
- #include "codepage.h"
-@@ -50,6 +54,14 @@
- #  include <wchar.h>
- #endif
- 
-+enum ExitCode {
-+  XMLWF_EXIT_SUCCESS = 0,
-+  XMLWF_EXIT_INTERNAL_ERROR = 1,
-+  XMLWF_EXIT_NOT_WELLFORMED = 2,
-+  XMLWF_EXIT_OUTPUT_ERROR = 3,
-+  XMLWF_EXIT_USAGE_ERROR = 4,
-+};
-+
- /* Structures for handler user data */
- typedef struct NotationList {
-   struct NotationList *next;
-@@ -875,6 +887,12 @@
-       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")
-+      T("billion laughs attack protection:\n")
-+      T("  NOTE: If you ever need to increase these values for non-attack payload, please file a bug report.\n")
-+      T("\n")
-+      T("  -a FACTOR     set maximum tolerated [a]mplification factor (default: 100.0)\n")
-+      T("  -b BYTES      set number of output [b]ytes needed to activate (default: 8 MiB)\n")
-+      T("\n")
-       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 @@
- int wmain(int argc, XML_Char **argv);
- #endif
- 
-+#define XMLWF_SHIFT_ARG_INTO(constCharStarTarget, argc, argv, i, j)            \
-+  {                                                                            \
-+    if (argv[i][j + 1] == T('\0')) {                                           \
-+      if (++i == argc)                                                         \
-+        usage(argv[0], XMLWF_EXIT_USAGE_ERROR);                                \
-+      constCharStarTarget = argv[i];                                           \
-+    } else {                                                                   \
-+      constCharStarTarget = argv[i] + j + 1;                                   \
-+    }                                                                          \
-+    i++;                                                                       \
-+    j = 0;                                                                     \
-+  }
-+
- int
- tmain(int argc, XML_Char **argv) {
-   int i, j;
-@@ -902,6 +933,11 @@
-   int useNamespaces = 0;
-   int requireStandalone = 0;
-   int requiresNotations = 0;
-+
-+  float attackMaximumAmplification = -1.0f; /* signaling "not set" */
-+  unsigned long long attackThresholdBytes;
-+  XML_Bool attackThresholdGiven = XML_FALSE;
-+
-   enum XML_ParamEntityParsing paramEntityParsing
-       = XML_PARAM_ENTITY_PARSING_NEVER;
-   int useStdin = 0;
-@@ -990,6 +1026,49 @@
-     case T('v'):
-       showVersion(argv[0]);
-       return 0;
-+    case T('a'): {
-+      const XML_Char *valueText = NULL;
-+      XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
-+
-+      errno = 0;
-+      XML_Char *afterValueText = (XML_Char *)valueText;
-+      attackMaximumAmplification = tcstof(valueText, &afterValueText);
-+      if ((errno != 0) || (afterValueText[0] != T('\0'))
-+          || isnan(attackMaximumAmplification)
-+          || (attackMaximumAmplification < 1.0f)) {
-+        // This prevents tperror(..) from reporting misleading "[..]: Success"
-+        errno = ERANGE;
-+        tperror(T("invalid amplification limit") T(
-+            " (needs a floating point number greater or equal than 1.0)"));
-+        exit(XMLWF_EXIT_USAGE_ERROR);
-+      }
-+#ifndef XML_DTD
-+      ftprintf(stderr, T("Warning: Given amplification limit ignored") T(
-+                           ", xmlwf has been compiled without DTD support.\n"));
-+#endif
-+      break;
-+    }
-+    case T('b'): {
-+      const XML_Char *valueText = NULL;
-+      XMLWF_SHIFT_ARG_INTO(valueText, argc, argv, i, j);
-+
-+      errno = 0;
-+      XML_Char *afterValueText = (XML_Char *)valueText;
-+      attackThresholdBytes = tcstoull(valueText, &afterValueText, 10);
-+      if ((errno != 0) || (afterValueText[0] != T('\0'))) {
-+        // This prevents tperror(..) from reporting misleading "[..]: Success"
-+        errno = ERANGE;
-+        tperror(T("invalid ignore threshold")
-+                    T(" (needs an integer from 0 to 2^64-1)"));
-+        exit(XMLWF_EXIT_USAGE_ERROR);
-+      }
-+      attackThresholdGiven = XML_TRUE;
-+#ifndef XML_DTD
-+      ftprintf(stderr, T("Warning: Given attack threshold ignored") T(
-+                           ", xmlwf has been compiled without DTD support.\n"));
-+#endif
-+      break;
-+    }
-     case T('\0'):
-       if (j > 1) {
-         i++;
-@@ -1020,6 +1099,19 @@
-       exit(1);
-     }
- 
-+    if (attackMaximumAmplification != -1.0f) {
-+#ifdef XML_DTD
-+      XML_SetBillionLaughsAttackProtectionMaximumAmplification(
-+          parser, attackMaximumAmplification);
-+#endif
-+    }
-+    if (attackThresholdGiven) {
-+#ifdef XML_DTD
-+      XML_SetBillionLaughsAttackProtectionActivationThreshold(
-+          parser, attackThresholdBytes);
-+#endif
-+    }
-+
-     if (requireStandalone)
-       XML_SetNotStandaloneHandler(parser, notStandalone);
-     XML_SetParamEntityParsing(parser, paramEntityParsing);
-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 13:47:39.000000000 -0400
-+++ misc/build/expat-2.2.10/xmlwf/xmlwf_helpgen.py	2021-07-18 17:21:48.000000000 -0400
-@@ -57,6 +57,14 @@
- output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
- output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
- 
-+billion_laughs = parser.add_argument_group('billion laughs attack protection',
-+                                           description='NOTE: '
-+                                                       'If you ever need to increase these values '
-+                                                       'for non-attack payload, please file a bug report.')
-+billion_laughs.add_argument('-a', metavar='FACTOR',
-+                            help='set maximum tolerated [a]mplification factor (default: 100.0)')
-+billion_laughs.add_argument('-b', metavar='BYTES', help='set number of output [b]ytes needed to activate (default: 8 MiB)')
-+
- parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
- 
- info = parser.add_argument_group('info arguments')
diff --git a/main/expat/makefile.mk b/main/expat/makefile.mk
index 901ee9a..20fd92b 100644
--- a/main/expat/makefile.mk
+++ b/main/expat/makefile.mk
@@ -41,7 +41,7 @@ all:
 TARFILE_NAME=expat-2.2.10
 TARFILE_MD5=9d60de01cc0126dfd11121b04838e154
 ADDITIONAL_FILES=lib$/makefile.mk
-PATCH_FILES=$(TARFILE_NAME).patch expat-2.2.11.patch
+PATCH_FILES=$(TARFILE_NAME).patch
 
 CONFIGURE_DIR=
 .IF "$(OS)"=="WNT"