Home | History | Annotate | Line # | Download | only in lib
xmlparse.c revision 1.1.1.9
      1 /* d19ae032c224863c1527ba44d228cc34b99192c3a4c5a27af1f4e054d45ee031 (2.7.1+)
      2                             __  __            _
      3                          ___\ \/ /_ __   __ _| |_
      4                         / _ \\  /| '_ \ / _` | __|
      5                        |  __//  \| |_) | (_| | |_
      6                         \___/_/\_\ .__/ \__,_|\__|
      7                                  |_| XML parser
      8 
      9    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
     10    Copyright (c) 2000      Clark Cooper <coopercc (at) users.sourceforge.net>
     11    Copyright (c) 2000-2006 Fred L. Drake, Jr. <fdrake (at) users.sourceforge.net>
     12    Copyright (c) 2001-2002 Greg Stein <gstein (at) users.sourceforge.net>
     13    Copyright (c) 2002-2016 Karl Waclawek <karl (at) waclawek.net>
     14    Copyright (c) 2005-2009 Steven Solie <steven (at) solie.ca>
     15    Copyright (c) 2016      Eric Rahm <erahm (at) mozilla.com>
     16    Copyright (c) 2016-2025 Sebastian Pipping <sebastian (at) pipping.org>
     17    Copyright (c) 2016      Gaurav <g.gupta (at) samsung.com>
     18    Copyright (c) 2016      Thomas Beutlich <tc (at) tbeu.de>
     19    Copyright (c) 2016      Gustavo Grieco <gustavo.grieco (at) imag.fr>
     20    Copyright (c) 2016      Pascal Cuoq <cuoq (at) trust-in-soft.com>
     21    Copyright (c) 2016      Ed Schouten <ed (at) nuxi.nl>
     22    Copyright (c) 2017-2022 Rhodri James <rhodri (at) wildebeest.org.uk>
     23    Copyright (c) 2017      Vclav Slavk <vaclav (at) slavik.io>
     24    Copyright (c) 2017      Viktor Szakats <commit (at) vsz.me>
     25    Copyright (c) 2017      Chanho Park <chanho61.park (at) samsung.com>
     26    Copyright (c) 2017      Rolf Eike Beer <eike (at) sf-mail.de>
     27    Copyright (c) 2017      Hans Wennborg <hans (at) chromium.org>
     28    Copyright (c) 2018      Anton Maklakov <antmak.pub (at) gmail.com>
     29    Copyright (c) 2018      Benjamin Peterson <benjamin (at) python.org>
     30    Copyright (c) 2018      Marco Maggi <marco.maggi-ipsu (at) poste.it>
     31    Copyright (c) 2018      Mariusz Zaborski <oshogbo (at) vexillium.org>
     32    Copyright (c) 2019      David Loffredo <loffredo (at) steptools.com>
     33    Copyright (c) 2019-2020 Ben Wagner <bungeman (at) chromium.org>
     34    Copyright (c) 2019      Vadim Zeitlin <vadim (at) zeitlins.org>
     35    Copyright (c) 2021      Donghee Na <donghee.na (at) python.org>
     36    Copyright (c) 2022      Samanta Navarro <ferivoz (at) riseup.net>
     37    Copyright (c) 2022      Jeffrey Walton <noloader (at) gmail.com>
     38    Copyright (c) 2022      Jann Horn <jannh (at) google.com>
     39    Copyright (c) 2022      Sean McBride <sean (at) rogue-research.com>
     40    Copyright (c) 2023      Owain Davies <owaind (at) bath.edu>
     41    Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild (at) sony.com>
     42    Copyright (c) 2024-2025 Berkay Eren rn <berkay.ueruen (at) siemens.com>
     43    Copyright (c) 2024      Hanno Bck <hanno (at) gentoo.org>
     44    Licensed under the MIT license:
     45 
     46    Permission is  hereby granted,  free of charge,  to any  person obtaining
     47    a  copy  of  this  software   and  associated  documentation  files  (the
     48    "Software"),  to  deal in  the  Software  without restriction,  including
     49    without  limitation the  rights  to use,  copy,  modify, merge,  publish,
     50    distribute, sublicense, and/or sell copies of the Software, and to permit
     51    persons  to whom  the Software  is  furnished to  do so,  subject to  the
     52    following conditions:
     53 
     54    The above copyright  notice and this permission notice  shall be included
     55    in all copies or substantial portions of the Software.
     56 
     57    THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
     58    EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
     59    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
     60    NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     61    DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
     62    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     63    USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 */
     65 
     66 #define XML_BUILDING_EXPAT 1
     67 
     68 #include "expat_config.h"
     69 
     70 #if ! defined(XML_GE) || (1 - XML_GE - 1 == 2) || (XML_GE < 0) || (XML_GE > 1)
     71 #  error XML_GE (for general entities) must be defined, non-empty, either 1 or 0 (0 to disable, 1 to enable; 1 is a common default)
     72 #endif
     73 
     74 #if defined(XML_DTD) && XML_GE == 0
     75 #  error Either undefine XML_DTD or define XML_GE to 1.
     76 #endif
     77 
     78 #if ! defined(XML_CONTEXT_BYTES) || (1 - XML_CONTEXT_BYTES - 1 == 2)           \
     79     || (XML_CONTEXT_BYTES + 0 < 0)
     80 #  error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
     81 #endif
     82 
     83 #if defined(HAVE_SYSCALL_GETRANDOM)
     84 #  if ! defined(_GNU_SOURCE)
     85 #    define _GNU_SOURCE 1 /* syscall prototype */
     86 #  endif
     87 #endif
     88 
     89 #ifdef _WIN32
     90 /* force stdlib to define rand_s() */
     91 #  if ! defined(_CRT_RAND_S)
     92 #    define _CRT_RAND_S
     93 #  endif
     94 #endif
     95 
     96 #include <stdbool.h>
     97 #include <stddef.h>
     98 #include <string.h> /* memset(), memcpy() */
     99 #include <assert.h>
    100 #include <limits.h> /* UINT_MAX */
    101 #include <stdio.h>  /* fprintf */
    102 #include <stdlib.h> /* getenv, rand_s */
    103 #include <stdint.h> /* uintptr_t */
    104 #include <math.h>   /* isnan */
    105 
    106 #ifdef _WIN32
    107 #  define getpid GetCurrentProcessId
    108 #else
    109 #  include <sys/time.h>  /* gettimeofday() */
    110 #  include <sys/types.h> /* getpid() */
    111 #  include <unistd.h>    /* getpid() */
    112 #  include <fcntl.h>     /* O_RDONLY */
    113 #  include <errno.h>
    114 #endif
    115 
    116 #ifdef _WIN32
    117 #  include "winconfig.h"
    118 #endif
    119 
    120 #include "ascii.h"
    121 #include "expat.h"
    122 #include "siphash.h"
    123 
    124 #if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
    125 #  if defined(HAVE_GETRANDOM)
    126 #    include <sys/random.h> /* getrandom */
    127 #  else
    128 #    include <unistd.h>      /* syscall */
    129 #    include <sys/syscall.h> /* SYS_getrandom */
    130 #  endif
    131 #  if ! defined(GRND_NONBLOCK)
    132 #    define GRND_NONBLOCK 0x0001
    133 #  endif /* defined(GRND_NONBLOCK) */
    134 #endif   /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
    135 
    136 #if defined(HAVE_LIBBSD)                                                       \
    137     && (defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_ARC4RANDOM))
    138 #  include <bsd/stdlib.h>
    139 #endif
    140 
    141 #if defined(_WIN32) && ! defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
    142 #  define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
    143 #endif
    144 
    145 #if ! defined(HAVE_GETRANDOM) && ! defined(HAVE_SYSCALL_GETRANDOM)             \
    146     && ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)            \
    147     && ! defined(XML_DEV_URANDOM) && ! defined(_WIN32)                         \
    148     && ! defined(XML_POOR_ENTROPY)
    149 #  error You do not have support for any sources of high quality entropy \
    150     enabled.  For end user security, that is probably not what you want. \
    151     \
    152     Your options include: \
    153       * Linux >=3.17 + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
    154       * Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
    155       * BSD / macOS >=10.7 / glibc >=2.36 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
    156       * BSD / macOS (including <10.7) / glibc >=2.36 (arc4random): HAVE_ARC4RANDOM, \
    157       * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
    158       * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
    159       * Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \
    160       * Windows >=Vista (rand_s): _WIN32. \
    161     \
    162     If insist on not using any of these, bypass this error by defining \
    163     XML_POOR_ENTROPY; you have been warned. \
    164     \
    165     If you have reasons to patch this detection code away or need changes \
    166     to the build system, please open a bug.  Thank you!
    167 #endif
    168 
    169 #ifdef XML_UNICODE
    170 #  define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
    171 #  define XmlConvert XmlUtf16Convert
    172 #  define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
    173 #  define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
    174 #  define XmlEncode XmlUtf16Encode
    175 #  define MUST_CONVERT(enc, s) (! (enc)->isUtf16 || (((uintptr_t)(s)) & 1))
    176 typedef unsigned short ICHAR;
    177 #else
    178 #  define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
    179 #  define XmlConvert XmlUtf8Convert
    180 #  define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
    181 #  define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
    182 #  define XmlEncode XmlUtf8Encode
    183 #  define MUST_CONVERT(enc, s) (! (enc)->isUtf8)
    184 typedef char ICHAR;
    185 #endif
    186 
    187 #ifndef XML_NS
    188 
    189 #  define XmlInitEncodingNS XmlInitEncoding
    190 #  define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
    191 #  undef XmlGetInternalEncodingNS
    192 #  define XmlGetInternalEncodingNS XmlGetInternalEncoding
    193 #  define XmlParseXmlDeclNS XmlParseXmlDecl
    194 
    195 #endif
    196 
    197 #ifdef XML_UNICODE
    198 
    199 #  ifdef XML_UNICODE_WCHAR_T
    200 #    define XML_T(x) (const wchar_t) x
    201 #    define XML_L(x) L##x
    202 #  else
    203 #    define XML_T(x) (const unsigned short)x
    204 #    define XML_L(x) x
    205 #  endif
    206 
    207 #else
    208 
    209 #  define XML_T(x) x
    210 #  define XML_L(x) x
    211 
    212 #endif
    213 
    214 /* Round up n to be a multiple of sz, where sz is a power of 2. */
    215 #define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
    216 
    217 /* Do safe (NULL-aware) pointer arithmetic */
    218 #define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
    219 
    220 #define EXPAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
    221 
    222 #include "internal.h"
    223 #include "xmltok.h"
    224 #include "xmlrole.h"
    225 
    226 typedef const XML_Char *KEY;
    227 
    228 typedef struct {
    229   KEY name;
    230 } NAMED;
    231 
    232 typedef struct {
    233   NAMED **v;
    234   unsigned char power;
    235   size_t size;
    236   size_t used;
    237   const XML_Memory_Handling_Suite *mem;
    238 } HASH_TABLE;
    239 
    240 static size_t keylen(KEY s);
    241 
    242 static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key);
    243 
    244 /* For probing (after a collision) we need a step size relative prime
    245    to the hash table size, which is a power of 2. We use double-hashing,
    246    since we can calculate a second hash value cheaply by taking those bits
    247    of the first hash value that were discarded (masked out) when the table
    248    index was calculated: index = hash & mask, where mask = table->size - 1.
    249    We limit the maximum step size to table->size / 4 (mask >> 2) and make
    250    it odd, since odd numbers are always relative prime to a power of 2.
    251 */
    252 #define SECOND_HASH(hash, mask, power)                                         \
    253   ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
    254 #define PROBE_STEP(hash, mask, power)                                          \
    255   ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
    256 
    257 typedef struct {
    258   NAMED **p;
    259   NAMED **end;
    260 } HASH_TABLE_ITER;
    261 
    262 #define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
    263 #define INIT_DATA_BUF_SIZE 1024
    264 #define INIT_ATTS_SIZE 16
    265 #define INIT_ATTS_VERSION 0xFFFFFFFF
    266 #define INIT_BLOCK_SIZE 1024
    267 #define INIT_BUFFER_SIZE 1024
    268 
    269 #define EXPAND_SPARE 24
    270 
    271 typedef struct binding {
    272   struct prefix *prefix;
    273   struct binding *nextTagBinding;
    274   struct binding *prevPrefixBinding;
    275   const struct attribute_id *attId;
    276   XML_Char *uri;
    277   int uriLen;
    278   int uriAlloc;
    279 } BINDING;
    280 
    281 typedef struct prefix {
    282   const XML_Char *name;
    283   BINDING *binding;
    284 } PREFIX;
    285 
    286 typedef struct {
    287   const XML_Char *str;
    288   const XML_Char *localPart;
    289   const XML_Char *prefix;
    290   int strLen;
    291   int uriLen;
    292   int prefixLen;
    293 } TAG_NAME;
    294 
    295 /* TAG represents an open element.
    296    The name of the element is stored in both the document and API
    297    encodings.  The memory buffer 'buf' is a separately-allocated
    298    memory area which stores the name.  During the XML_Parse()/
    299    XML_ParseBuffer() when the element is open, the memory for the 'raw'
    300    version of the name (in the document encoding) is shared with the
    301    document buffer.  If the element is open across calls to
    302    XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
    303    contain the 'raw' name as well.
    304 
    305    A parser reuses these structures, maintaining a list of allocated
    306    TAG objects in a free list.
    307 */
    308 typedef struct tag {
    309   struct tag *parent;  /* parent of this element */
    310   const char *rawName; /* tagName in the original encoding */
    311   int rawNameLength;
    312   TAG_NAME name; /* tagName in the API encoding */
    313   char *buf;     /* buffer for name components */
    314   char *bufEnd;  /* end of the buffer */
    315   BINDING *bindings;
    316 } TAG;
    317 
    318 typedef struct {
    319   const XML_Char *name;
    320   const XML_Char *textPtr;
    321   int textLen;   /* length in XML_Chars */
    322   int processed; /* # of processed bytes - when suspended */
    323   const XML_Char *systemId;
    324   const XML_Char *base;
    325   const XML_Char *publicId;
    326   const XML_Char *notation;
    327   XML_Bool open;
    328   XML_Bool hasMore; /* true if entity has not been completely processed */
    329   /* An entity can be open while being already completely processed (hasMore ==
    330     XML_FALSE). The reason is the delayed closing of entities until their inner
    331     entities are processed and closed */
    332   XML_Bool is_param;
    333   XML_Bool is_internal; /* true if declared in internal subset outside PE */
    334 } ENTITY;
    335 
    336 typedef struct {
    337   enum XML_Content_Type type;
    338   enum XML_Content_Quant quant;
    339   const XML_Char *name;
    340   int firstchild;
    341   int lastchild;
    342   int childcnt;
    343   int nextsib;
    344 } CONTENT_SCAFFOLD;
    345 
    346 #define INIT_SCAFFOLD_ELEMENTS 32
    347 
    348 typedef struct block {
    349   struct block *next;
    350   int size;
    351   XML_Char s[1];
    352 } BLOCK;
    353 
    354 typedef struct {
    355   BLOCK *blocks;
    356   BLOCK *freeBlocks;
    357   const XML_Char *end;
    358   XML_Char *ptr;
    359   XML_Char *start;
    360   const XML_Memory_Handling_Suite *mem;
    361 } STRING_POOL;
    362 
    363 /* The XML_Char before the name is used to determine whether
    364    an attribute has been specified. */
    365 typedef struct attribute_id {
    366   XML_Char *name;
    367   PREFIX *prefix;
    368   XML_Bool maybeTokenized;
    369   XML_Bool xmlns;
    370 } ATTRIBUTE_ID;
    371 
    372 typedef struct {
    373   const ATTRIBUTE_ID *id;
    374   XML_Bool isCdata;
    375   const XML_Char *value;
    376 } DEFAULT_ATTRIBUTE;
    377 
    378 typedef struct {
    379   unsigned long version;
    380   unsigned long hash;
    381   const XML_Char *uriName;
    382 } NS_ATT;
    383 
    384 typedef struct {
    385   const XML_Char *name;
    386   PREFIX *prefix;
    387   const ATTRIBUTE_ID *idAtt;
    388   int nDefaultAtts;
    389   int allocDefaultAtts;
    390   DEFAULT_ATTRIBUTE *defaultAtts;
    391 } ELEMENT_TYPE;
    392 
    393 typedef struct {
    394   HASH_TABLE generalEntities;
    395   HASH_TABLE elementTypes;
    396   HASH_TABLE attributeIds;
    397   HASH_TABLE prefixes;
    398   STRING_POOL pool;
    399   STRING_POOL entityValuePool;
    400   /* false once a parameter entity reference has been skipped */
    401   XML_Bool keepProcessing;
    402   /* true once an internal or external PE reference has been encountered;
    403      this includes the reference to an external subset */
    404   XML_Bool hasParamEntityRefs;
    405   XML_Bool standalone;
    406 #ifdef XML_DTD
    407   /* indicates if external PE has been read */
    408   XML_Bool paramEntityRead;
    409   HASH_TABLE paramEntities;
    410 #endif /* XML_DTD */
    411   PREFIX defaultPrefix;
    412   /* === scaffolding for building content model === */
    413   XML_Bool in_eldecl;
    414   CONTENT_SCAFFOLD *scaffold;
    415   unsigned contentStringLen;
    416   unsigned scaffSize;
    417   unsigned scaffCount;
    418   int scaffLevel;
    419   int *scaffIndex;
    420 } DTD;
    421 
    422 enum EntityType {
    423   ENTITY_INTERNAL,
    424   ENTITY_ATTRIBUTE,
    425   ENTITY_VALUE,
    426 };
    427 
    428 typedef struct open_internal_entity {
    429   const char *internalEventPtr;
    430   const char *internalEventEndPtr;
    431   struct open_internal_entity *next;
    432   ENTITY *entity;
    433   int startTagLevel;
    434   XML_Bool betweenDecl; /* WFC: PE Between Declarations */
    435   enum EntityType type;
    436 } OPEN_INTERNAL_ENTITY;
    437 
    438 enum XML_Account {
    439   XML_ACCOUNT_DIRECT,           /* bytes directly passed to the Expat parser */
    440   XML_ACCOUNT_ENTITY_EXPANSION, /* intermediate bytes produced during entity
    441                                    expansion */
    442   XML_ACCOUNT_NONE              /* i.e. do not account, was accounted already */
    443 };
    444 
    445 #if XML_GE == 1
    446 typedef unsigned long long XmlBigCount;
    447 typedef struct accounting {
    448   XmlBigCount countBytesDirect;
    449   XmlBigCount countBytesIndirect;
    450   unsigned long debugLevel;
    451   float maximumAmplificationFactor; // >=1.0
    452   unsigned long long activationThresholdBytes;
    453 } ACCOUNTING;
    454 
    455 typedef struct entity_stats {
    456   unsigned int countEverOpened;
    457   unsigned int currentDepth;
    458   unsigned int maximumDepthSeen;
    459   unsigned long debugLevel;
    460 } ENTITY_STATS;
    461 #endif /* XML_GE == 1 */
    462 
    463 typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
    464                                          const char *end, const char **endPtr);
    465 
    466 static Processor prologProcessor;
    467 static Processor prologInitProcessor;
    468 static Processor contentProcessor;
    469 static Processor cdataSectionProcessor;
    470 #ifdef XML_DTD
    471 static Processor ignoreSectionProcessor;
    472 static Processor externalParEntProcessor;
    473 static Processor externalParEntInitProcessor;
    474 static Processor entityValueProcessor;
    475 static Processor entityValueInitProcessor;
    476 #endif /* XML_DTD */
    477 static Processor epilogProcessor;
    478 static Processor errorProcessor;
    479 static Processor externalEntityInitProcessor;
    480 static Processor externalEntityInitProcessor2;
    481 static Processor externalEntityInitProcessor3;
    482 static Processor externalEntityContentProcessor;
    483 static Processor internalEntityProcessor;
    484 
    485 static enum XML_Error handleUnknownEncoding(XML_Parser parser,
    486                                             const XML_Char *encodingName);
    487 static enum XML_Error processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
    488                                      const char *s, const char *next);
    489 static enum XML_Error initializeEncoding(XML_Parser parser);
    490 static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
    491                                const char *s, const char *end, int tok,
    492                                const char *next, const char **nextPtr,
    493                                XML_Bool haveMore, XML_Bool allowClosingDoctype,
    494                                enum XML_Account account);
    495 static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity,
    496                                     XML_Bool betweenDecl, enum EntityType type);
    497 static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
    498                                 const ENCODING *enc, const char *start,
    499                                 const char *end, const char **endPtr,
    500                                 XML_Bool haveMore, enum XML_Account account);
    501 static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *enc,
    502                                      const char **startPtr, const char *end,
    503                                      const char **nextPtr, XML_Bool haveMore,
    504                                      enum XML_Account account);
    505 #ifdef XML_DTD
    506 static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *enc,
    507                                       const char **startPtr, const char *end,
    508                                       const char **nextPtr, XML_Bool haveMore);
    509 #endif /* XML_DTD */
    510 
    511 static void freeBindings(XML_Parser parser, BINDING *bindings);
    512 static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
    513                                 const char *attStr, TAG_NAME *tagNamePtr,
    514                                 BINDING **bindingsPtr,
    515                                 enum XML_Account account);
    516 static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
    517                                  const ATTRIBUTE_ID *attId, const XML_Char *uri,
    518                                  BINDING **bindingsPtr);
    519 static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId,
    520                            XML_Bool isCdata, XML_Bool isId,
    521                            const XML_Char *value, XML_Parser parser);
    522 static enum XML_Error storeAttributeValue(XML_Parser parser,
    523                                           const ENCODING *enc, XML_Bool isCdata,
    524                                           const char *ptr, const char *end,
    525                                           STRING_POOL *pool,
    526                                           enum XML_Account account);
    527 static enum XML_Error
    528 appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
    529                      const char *ptr, const char *end, STRING_POOL *pool,
    530                      enum XML_Account account, const char **nextPtr);
    531 static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
    532                                     const char *start, const char *end);
    533 static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType);
    534 #if XML_GE == 1
    535 static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
    536                                        const char *start, const char *end,
    537                                        enum XML_Account account,
    538                                        const char **nextPtr);
    539 static enum XML_Error callStoreEntityValue(XML_Parser parser,
    540                                            const ENCODING *enc,
    541                                            const char *start, const char *end,
    542                                            enum XML_Account account);
    543 #else
    544 static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
    545 #endif
    546 static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
    547                                        const char *start, const char *end);
    548 static int reportComment(XML_Parser parser, const ENCODING *enc,
    549                          const char *start, const char *end);
    550 static void reportDefault(XML_Parser parser, const ENCODING *enc,
    551                           const char *start, const char *end);
    552 
    553 static const XML_Char *getContext(XML_Parser parser);
    554 static XML_Bool setContext(XML_Parser parser, const XML_Char *context);
    555 
    556 static void FASTCALL normalizePublicId(XML_Char *s);
    557 
    558 static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms);
    559 /* do not call if m_parentParser != NULL */
    560 static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
    561 static void dtdDestroy(DTD *p, XML_Bool isDocEntity,
    562                        const XML_Memory_Handling_Suite *ms);
    563 static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
    564                    const XML_Memory_Handling_Suite *ms);
    565 static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
    566                            STRING_POOL *newPool, const HASH_TABLE *oldTable);
    567 static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
    568                      size_t createSize);
    569 static void FASTCALL hashTableInit(HASH_TABLE *table,
    570                                    const XML_Memory_Handling_Suite *ms);
    571 static void FASTCALL hashTableClear(HASH_TABLE *table);
    572 static void FASTCALL hashTableDestroy(HASH_TABLE *table);
    573 static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter,
    574                                        const HASH_TABLE *table);
    575 static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter);
    576 
    577 static void FASTCALL poolInit(STRING_POOL *pool,
    578                               const XML_Memory_Handling_Suite *ms);
    579 static void FASTCALL poolClear(STRING_POOL *pool);
    580 static void FASTCALL poolDestroy(STRING_POOL *pool);
    581 static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
    582                             const char *ptr, const char *end);
    583 static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
    584                                  const char *ptr, const char *end);
    585 static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
    586 static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
    587                                                const XML_Char *s);
    588 static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s,
    589                                        int n);
    590 static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool,
    591                                                  const XML_Char *s);
    592 
    593 static int FASTCALL nextScaffoldPart(XML_Parser parser);
    594 static XML_Content *build_model(XML_Parser parser);
    595 static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc,
    596                                     const char *ptr, const char *end);
    597 
    598 static XML_Char *copyString(const XML_Char *s,
    599                             const XML_Memory_Handling_Suite *memsuite);
    600 
    601 static unsigned long generate_hash_secret_salt(XML_Parser parser);
    602 static XML_Bool startParsing(XML_Parser parser);
    603 
    604 static XML_Parser parserCreate(const XML_Char *encodingName,
    605                                const XML_Memory_Handling_Suite *memsuite,
    606                                const XML_Char *nameSep, DTD *dtd);
    607 
    608 static void parserInit(XML_Parser parser, const XML_Char *encodingName);
    609 
    610 #if XML_GE == 1
    611 static float accountingGetCurrentAmplification(XML_Parser rootParser);
    612 static void accountingReportStats(XML_Parser originParser, const char *epilog);
    613 static void accountingOnAbort(XML_Parser originParser);
    614 static void accountingReportDiff(XML_Parser rootParser,
    615                                  unsigned int levelsAwayFromRootParser,
    616                                  const char *before, const char *after,
    617                                  ptrdiff_t bytesMore, int source_line,
    618                                  enum XML_Account account);
    619 static XML_Bool accountingDiffTolerated(XML_Parser originParser, int tok,
    620                                         const char *before, const char *after,
    621                                         int source_line,
    622                                         enum XML_Account account);
    623 
    624 static void entityTrackingReportStats(XML_Parser parser, ENTITY *entity,
    625                                       const char *action, int sourceLine);
    626 static void entityTrackingOnOpen(XML_Parser parser, ENTITY *entity,
    627                                  int sourceLine);
    628 static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
    629                                   int sourceLine);
    630 
    631 static XML_Parser getRootParserOf(XML_Parser parser,
    632                                   unsigned int *outLevelDiff);
    633 #endif /* XML_GE == 1 */
    634 
    635 static unsigned long getDebugLevel(const char *variableName,
    636                                    unsigned long defaultDebugLevel);
    637 
    638 #define poolStart(pool) ((pool)->start)
    639 #define poolLength(pool) ((pool)->ptr - (pool)->start)
    640 #define poolChop(pool) ((void)--(pool->ptr))
    641 #define poolLastChar(pool) (((pool)->ptr)[-1])
    642 #define poolDiscard(pool) ((pool)->ptr = (pool)->start)
    643 #define poolFinish(pool) ((pool)->start = (pool)->ptr)
    644 #define poolAppendChar(pool, c)                                                \
    645   (((pool)->ptr == (pool)->end && ! poolGrow(pool))                            \
    646        ? 0                                                                     \
    647        : ((*((pool)->ptr)++ = c), 1))
    648 
    649 #if ! defined(XML_TESTING)
    650 const
    651 #endif
    652     XML_Bool g_reparseDeferralEnabledDefault
    653     = XML_TRUE; // write ONLY in runtests.c
    654 #if defined(XML_TESTING)
    655 unsigned int g_bytesScanned = 0; // used for testing only
    656 #endif
    657 
    658 struct XML_ParserStruct {
    659   /* The first member must be m_userData so that the XML_GetUserData
    660      macro works. */
    661   void *m_userData;
    662   void *m_handlerArg;
    663 
    664   // How the four parse buffer pointers below relate in time and space:
    665   //
    666   //   m_buffer <= m_bufferPtr <= m_bufferEnd  <= m_bufferLim
    667   //   |           |              |               |
    668   //   <--parsed-->|              |               |
    669   //               <---parsing--->|               |
    670   //                              <--unoccupied-->|
    671   //   <---------total-malloced/realloced-------->|
    672 
    673   char *m_buffer; // malloc/realloc base pointer of parse buffer
    674   const XML_Memory_Handling_Suite m_mem;
    675   const char *m_bufferPtr; // first character to be parsed
    676   char *m_bufferEnd;       // past last character to be parsed
    677   const char *m_bufferLim; // allocated end of m_buffer
    678 
    679   XML_Index m_parseEndByteIndex;
    680   const char *m_parseEndPtr;
    681   size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
    682   XML_Bool m_reparseDeferralEnabled;
    683   int m_lastBufferRequestSize;
    684   XML_Char *m_dataBuf;
    685   XML_Char *m_dataBufEnd;
    686   XML_StartElementHandler m_startElementHandler;
    687   XML_EndElementHandler m_endElementHandler;
    688   XML_CharacterDataHandler m_characterDataHandler;
    689   XML_ProcessingInstructionHandler m_processingInstructionHandler;
    690   XML_CommentHandler m_commentHandler;
    691   XML_StartCdataSectionHandler m_startCdataSectionHandler;
    692   XML_EndCdataSectionHandler m_endCdataSectionHandler;
    693   XML_DefaultHandler m_defaultHandler;
    694   XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
    695   XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
    696   XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
    697   XML_NotationDeclHandler m_notationDeclHandler;
    698   XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
    699   XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
    700   XML_NotStandaloneHandler m_notStandaloneHandler;
    701   XML_ExternalEntityRefHandler m_externalEntityRefHandler;
    702   XML_Parser m_externalEntityRefHandlerArg;
    703   XML_SkippedEntityHandler m_skippedEntityHandler;
    704   XML_UnknownEncodingHandler m_unknownEncodingHandler;
    705   XML_ElementDeclHandler m_elementDeclHandler;
    706   XML_AttlistDeclHandler m_attlistDeclHandler;
    707   XML_EntityDeclHandler m_entityDeclHandler;
    708   XML_XmlDeclHandler m_xmlDeclHandler;
    709   const ENCODING *m_encoding;
    710   INIT_ENCODING m_initEncoding;
    711   const ENCODING *m_internalEncoding;
    712   const XML_Char *m_protocolEncodingName;
    713   XML_Bool m_ns;
    714   XML_Bool m_ns_triplets;
    715   void *m_unknownEncodingMem;
    716   void *m_unknownEncodingData;
    717   void *m_unknownEncodingHandlerData;
    718   void(XMLCALL *m_unknownEncodingRelease)(void *);
    719   PROLOG_STATE m_prologState;
    720   Processor *m_processor;
    721   enum XML_Error m_errorCode;
    722   const char *m_eventPtr;
    723   const char *m_eventEndPtr;
    724   const char *m_positionPtr;
    725   OPEN_INTERNAL_ENTITY *m_openInternalEntities;
    726   OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
    727   OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
    728   OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
    729   OPEN_INTERNAL_ENTITY *m_openValueEntities;
    730   OPEN_INTERNAL_ENTITY *m_freeValueEntities;
    731   XML_Bool m_defaultExpandInternalEntities;
    732   int m_tagLevel;
    733   ENTITY *m_declEntity;
    734   const XML_Char *m_doctypeName;
    735   const XML_Char *m_doctypeSysid;
    736   const XML_Char *m_doctypePubid;
    737   const XML_Char *m_declAttributeType;
    738   const XML_Char *m_declNotationName;
    739   const XML_Char *m_declNotationPublicId;
    740   ELEMENT_TYPE *m_declElementType;
    741   ATTRIBUTE_ID *m_declAttributeId;
    742   XML_Bool m_declAttributeIsCdata;
    743   XML_Bool m_declAttributeIsId;
    744   DTD *m_dtd;
    745   const XML_Char *m_curBase;
    746   TAG *m_tagStack;
    747   TAG *m_freeTagList;
    748   BINDING *m_inheritedBindings;
    749   BINDING *m_freeBindingList;
    750   int m_attsSize;
    751   int m_nSpecifiedAtts;
    752   int m_idAttIndex;
    753   ATTRIBUTE *m_atts;
    754   NS_ATT *m_nsAtts;
    755   unsigned long m_nsAttsVersion;
    756   unsigned char m_nsAttsPower;
    757 #ifdef XML_ATTR_INFO
    758   XML_AttrInfo *m_attInfo;
    759 #endif
    760   POSITION m_position;
    761   STRING_POOL m_tempPool;
    762   STRING_POOL m_temp2Pool;
    763   char *m_groupConnector;
    764   unsigned int m_groupSize;
    765   XML_Char m_namespaceSeparator;
    766   XML_Parser m_parentParser;
    767   XML_ParsingStatus m_parsingStatus;
    768 #ifdef XML_DTD
    769   XML_Bool m_isParamEntity;
    770   XML_Bool m_useForeignDTD;
    771   enum XML_ParamEntityParsing m_paramEntityParsing;
    772 #endif
    773   unsigned long m_hash_secret_salt;
    774 #if XML_GE == 1
    775   ACCOUNTING m_accounting;
    776   ENTITY_STATS m_entity_stats;
    777 #endif
    778   XML_Bool m_reenter;
    779 };
    780 
    781 #define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
    782 #define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s)))
    783 #define FREE(parser, p) (parser->m_mem.free_fcn((p)))
    784 
    785 XML_Parser XMLCALL
    786 XML_ParserCreate(const XML_Char *encodingName) {
    787   return XML_ParserCreate_MM(encodingName, NULL, NULL);
    788 }
    789 
    790 XML_Parser XMLCALL
    791 XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
    792   XML_Char tmp[2] = {nsSep, 0};
    793   return XML_ParserCreate_MM(encodingName, NULL, tmp);
    794 }
    795 
    796 // "xml=http://www.w3.org/XML/1998/namespace"
    797 static const XML_Char implicitContext[]
    798     = {ASCII_x,     ASCII_m,     ASCII_l,      ASCII_EQUALS, ASCII_h,
    799        ASCII_t,     ASCII_t,     ASCII_p,      ASCII_COLON,  ASCII_SLASH,
    800        ASCII_SLASH, ASCII_w,     ASCII_w,      ASCII_w,      ASCII_PERIOD,
    801        ASCII_w,     ASCII_3,     ASCII_PERIOD, ASCII_o,      ASCII_r,
    802        ASCII_g,     ASCII_SLASH, ASCII_X,      ASCII_M,      ASCII_L,
    803        ASCII_SLASH, ASCII_1,     ASCII_9,      ASCII_9,      ASCII_8,
    804        ASCII_SLASH, ASCII_n,     ASCII_a,      ASCII_m,      ASCII_e,
    805        ASCII_s,     ASCII_p,     ASCII_a,      ASCII_c,      ASCII_e,
    806        '\0'};
    807 
    808 /* To avoid warnings about unused functions: */
    809 #if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
    810 
    811 #  if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
    812 
    813 /* Obtain entropy on Linux 3.17+ */
    814 static int
    815 writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
    816   int success = 0; /* full count bytes written? */
    817   size_t bytesWrittenTotal = 0;
    818   const unsigned int getrandomFlags = GRND_NONBLOCK;
    819 
    820   do {
    821     void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
    822     const size_t bytesToWrite = count - bytesWrittenTotal;
    823 
    824     const int bytesWrittenMore =
    825 #    if defined(HAVE_GETRANDOM)
    826         getrandom(currentTarget, bytesToWrite, getrandomFlags);
    827 #    else
    828         syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags);
    829 #    endif
    830 
    831     if (bytesWrittenMore > 0) {
    832       bytesWrittenTotal += bytesWrittenMore;
    833       if (bytesWrittenTotal >= count)
    834         success = 1;
    835     }
    836   } while (! success && (errno == EINTR));
    837 
    838   return success;
    839 }
    840 
    841 #  endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
    842 
    843 #  if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
    844 
    845 /* Extract entropy from /dev/urandom */
    846 static int
    847 writeRandomBytes_dev_urandom(void *target, size_t count) {
    848   int success = 0; /* full count bytes written? */
    849   size_t bytesWrittenTotal = 0;
    850 
    851   const int fd = open("/dev/urandom", O_RDONLY);
    852   if (fd < 0) {
    853     return 0;
    854   }
    855 
    856   do {
    857     void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
    858     const size_t bytesToWrite = count - bytesWrittenTotal;
    859 
    860     const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite);
    861 
    862     if (bytesWrittenMore > 0) {
    863       bytesWrittenTotal += bytesWrittenMore;
    864       if (bytesWrittenTotal >= count)
    865         success = 1;
    866     }
    867   } while (! success && (errno == EINTR));
    868 
    869   close(fd);
    870   return success;
    871 }
    872 
    873 #  endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
    874 
    875 #endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
    876 
    877 #if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF)
    878 
    879 static void
    880 writeRandomBytes_arc4random(void *target, size_t count) {
    881   size_t bytesWrittenTotal = 0;
    882 
    883   while (bytesWrittenTotal < count) {
    884     const uint32_t random32 = arc4random();
    885     size_t i = 0;
    886 
    887     for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
    888          i++, bytesWrittenTotal++) {
    889       const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
    890       ((uint8_t *)target)[bytesWrittenTotal] = random8;
    891     }
    892   }
    893 }
    894 
    895 #endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */
    896 
    897 #ifdef _WIN32
    898 
    899 /* Provide declaration of rand_s() for MinGW-32 (not 64, which has it),
    900    as it didn't declare it in its header prior to version 5.3.0 of its
    901    runtime package (mingwrt, containing stdlib.h).  The upstream fix
    902    was introduced at https://osdn.net/projects/mingw/ticket/39658 . */
    903 #  if defined(__MINGW32__) && defined(__MINGW32_VERSION)                       \
    904       && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR)
    905 __declspec(dllimport) int rand_s(unsigned int *);
    906 #  endif
    907 
    908 /* Obtain entropy on Windows using the rand_s() function which
    909  * generates cryptographically secure random numbers.  Internally it
    910  * uses RtlGenRandom API which is present in Windows XP and later.
    911  */
    912 static int
    913 writeRandomBytes_rand_s(void *target, size_t count) {
    914   size_t bytesWrittenTotal = 0;
    915 
    916   while (bytesWrittenTotal < count) {
    917     unsigned int random32 = 0;
    918     size_t i = 0;
    919 
    920     if (rand_s(&random32))
    921       return 0; /* failure */
    922 
    923     for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
    924          i++, bytesWrittenTotal++) {
    925       const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
    926       ((uint8_t *)target)[bytesWrittenTotal] = random8;
    927     }
    928   }
    929   return 1; /* success */
    930 }
    931 
    932 #endif /* _WIN32 */
    933 
    934 #if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
    935 
    936 static unsigned long
    937 gather_time_entropy(void) {
    938 #  ifdef _WIN32
    939   FILETIME ft;
    940   GetSystemTimeAsFileTime(&ft); /* never fails */
    941   return ft.dwHighDateTime ^ ft.dwLowDateTime;
    942 #  else
    943   struct timeval tv;
    944   int gettimeofday_res;
    945 
    946   gettimeofday_res = gettimeofday(&tv, NULL);
    947 
    948 #    if defined(NDEBUG)
    949   (void)gettimeofday_res;
    950 #    else
    951   assert(gettimeofday_res == 0);
    952 #    endif /* defined(NDEBUG) */
    953 
    954   /* Microseconds time is <20 bits entropy */
    955   return tv.tv_usec;
    956 #  endif
    957 }
    958 
    959 #endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
    960 
    961 static unsigned long
    962 ENTROPY_DEBUG(const char *label, unsigned long entropy) {
    963   if (getDebugLevel("EXPAT_ENTROPY_DEBUG", 0) >= 1u) {
    964     fprintf(stderr, "expat: Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
    965             (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
    966   }
    967   return entropy;
    968 }
    969 
    970 static unsigned long
    971 generate_hash_secret_salt(XML_Parser parser) {
    972   unsigned long entropy;
    973   (void)parser;
    974 
    975   /* "Failproof" high quality providers: */
    976 #if defined(HAVE_ARC4RANDOM_BUF)
    977   arc4random_buf(&entropy, sizeof(entropy));
    978   return ENTROPY_DEBUG("arc4random_buf", entropy);
    979 #elif defined(HAVE_ARC4RANDOM)
    980   writeRandomBytes_arc4random((void *)&entropy, sizeof(entropy));
    981   return ENTROPY_DEBUG("arc4random", entropy);
    982 #else
    983   /* Try high quality providers first .. */
    984 #  ifdef _WIN32
    985   if (writeRandomBytes_rand_s((void *)&entropy, sizeof(entropy))) {
    986     return ENTROPY_DEBUG("rand_s", entropy);
    987   }
    988 #  elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
    989   if (writeRandomBytes_getrandom_nonblock((void *)&entropy, sizeof(entropy))) {
    990     return ENTROPY_DEBUG("getrandom", entropy);
    991   }
    992 #  endif
    993 #  if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
    994   if (writeRandomBytes_dev_urandom((void *)&entropy, sizeof(entropy))) {
    995     return ENTROPY_DEBUG("/dev/urandom", entropy);
    996   }
    997 #  endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
    998   /* .. and self-made low quality for backup: */
    999 
   1000   /* Process ID is 0 bits entropy if attacker has local access */
   1001   entropy = gather_time_entropy() ^ getpid();
   1002 
   1003   /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
   1004   if (sizeof(unsigned long) == 4) {
   1005     return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
   1006   } else {
   1007     return ENTROPY_DEBUG("fallback(8)",
   1008                          entropy * (unsigned long)2305843009213693951ULL);
   1009   }
   1010 #endif
   1011 }
   1012 
   1013 static unsigned long
   1014 get_hash_secret_salt(XML_Parser parser) {
   1015   if (parser->m_parentParser != NULL)
   1016     return get_hash_secret_salt(parser->m_parentParser);
   1017   return parser->m_hash_secret_salt;
   1018 }
   1019 
   1020 static enum XML_Error
   1021 callProcessor(XML_Parser parser, const char *start, const char *end,
   1022               const char **endPtr) {
   1023   const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
   1024 
   1025   if (parser->m_reparseDeferralEnabled
   1026       && ! parser->m_parsingStatus.finalBuffer) {
   1027     // Heuristic: don't try to parse a partial token again until the amount of
   1028     // available data has increased significantly.
   1029     const size_t had_before = parser->m_partialTokenBytesBefore;
   1030     // ...but *do* try anyway if we're close to causing a reallocation.
   1031     size_t available_buffer
   1032         = EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
   1033 #if XML_CONTEXT_BYTES > 0
   1034     available_buffer -= EXPAT_MIN(available_buffer, XML_CONTEXT_BYTES);
   1035 #endif
   1036     available_buffer
   1037         += EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd);
   1038     // m_lastBufferRequestSize is never assigned a value < 0, so the cast is ok
   1039     const bool enough
   1040         = (have_now >= 2 * had_before)
   1041           || ((size_t)parser->m_lastBufferRequestSize > available_buffer);
   1042 
   1043     if (! enough) {
   1044       *endPtr = start; // callers may expect this to be set
   1045       return XML_ERROR_NONE;
   1046     }
   1047   }
   1048 #if defined(XML_TESTING)
   1049   g_bytesScanned += (unsigned)have_now;
   1050 #endif
   1051   // Run in a loop to eliminate dangerous recursion depths
   1052   enum XML_Error ret;
   1053   *endPtr = start;
   1054   while (1) {
   1055     // Use endPtr as the new start in each iteration, since it will
   1056     // be set to the next start point by m_processor.
   1057     ret = parser->m_processor(parser, *endPtr, end, endPtr);
   1058 
   1059     // Make parsing status (and in particular XML_SUSPENDED) take
   1060     // precedence over re-enter flag when they disagree
   1061     if (parser->m_parsingStatus.parsing != XML_PARSING) {
   1062       parser->m_reenter = XML_FALSE;
   1063     }
   1064 
   1065     if (! parser->m_reenter) {
   1066       break;
   1067     }
   1068 
   1069     parser->m_reenter = XML_FALSE;
   1070     if (ret != XML_ERROR_NONE)
   1071       return ret;
   1072   }
   1073 
   1074   if (ret == XML_ERROR_NONE) {
   1075     // if we consumed nothing, remember what we had on this parse attempt.
   1076     if (*endPtr == start) {
   1077       parser->m_partialTokenBytesBefore = have_now;
   1078     } else {
   1079       parser->m_partialTokenBytesBefore = 0;
   1080     }
   1081   }
   1082   return ret;
   1083 }
   1084 
   1085 static XML_Bool /* only valid for root parser */
   1086 startParsing(XML_Parser parser) {
   1087   /* hash functions must be initialized before setContext() is called */
   1088   if (parser->m_hash_secret_salt == 0)
   1089     parser->m_hash_secret_salt = generate_hash_secret_salt(parser);
   1090   if (parser->m_ns) {
   1091     /* implicit context only set for root parser, since child
   1092        parsers (i.e. external entity parsers) will inherit it
   1093     */
   1094     return setContext(parser, implicitContext);
   1095   }
   1096   return XML_TRUE;
   1097 }
   1098 
   1099 XML_Parser XMLCALL
   1100 XML_ParserCreate_MM(const XML_Char *encodingName,
   1101                     const XML_Memory_Handling_Suite *memsuite,
   1102                     const XML_Char *nameSep) {
   1103   return parserCreate(encodingName, memsuite, nameSep, NULL);
   1104 }
   1105 
   1106 static XML_Parser
   1107 parserCreate(const XML_Char *encodingName,
   1108              const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep,
   1109              DTD *dtd) {
   1110   XML_Parser parser;
   1111 
   1112   if (memsuite) {
   1113     XML_Memory_Handling_Suite *mtemp;
   1114     parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
   1115     if (parser != NULL) {
   1116       mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
   1117       mtemp->malloc_fcn = memsuite->malloc_fcn;
   1118       mtemp->realloc_fcn = memsuite->realloc_fcn;
   1119       mtemp->free_fcn = memsuite->free_fcn;
   1120     }
   1121   } else {
   1122     XML_Memory_Handling_Suite *mtemp;
   1123     parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
   1124     if (parser != NULL) {
   1125       mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
   1126       mtemp->malloc_fcn = malloc;
   1127       mtemp->realloc_fcn = realloc;
   1128       mtemp->free_fcn = free;
   1129     }
   1130   }
   1131 
   1132   if (! parser)
   1133     return parser;
   1134 
   1135   parser->m_buffer = NULL;
   1136   parser->m_bufferLim = NULL;
   1137 
   1138   parser->m_attsSize = INIT_ATTS_SIZE;
   1139   parser->m_atts
   1140       = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
   1141   if (parser->m_atts == NULL) {
   1142     FREE(parser, parser);
   1143     return NULL;
   1144   }
   1145 #ifdef XML_ATTR_INFO
   1146   parser->m_attInfo = (XML_AttrInfo *)MALLOC(
   1147       parser, parser->m_attsSize * sizeof(XML_AttrInfo));
   1148   if (parser->m_attInfo == NULL) {
   1149     FREE(parser, parser->m_atts);
   1150     FREE(parser, parser);
   1151     return NULL;
   1152   }
   1153 #endif
   1154   parser->m_dataBuf
   1155       = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
   1156   if (parser->m_dataBuf == NULL) {
   1157     FREE(parser, parser->m_atts);
   1158 #ifdef XML_ATTR_INFO
   1159     FREE(parser, parser->m_attInfo);
   1160 #endif
   1161     FREE(parser, parser);
   1162     return NULL;
   1163   }
   1164   parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;
   1165 
   1166   if (dtd)
   1167     parser->m_dtd = dtd;
   1168   else {
   1169     parser->m_dtd = dtdCreate(&parser->m_mem);
   1170     if (parser->m_dtd == NULL) {
   1171       FREE(parser, parser->m_dataBuf);
   1172       FREE(parser, parser->m_atts);
   1173 #ifdef XML_ATTR_INFO
   1174       FREE(parser, parser->m_attInfo);
   1175 #endif
   1176       FREE(parser, parser);
   1177       return NULL;
   1178     }
   1179   }
   1180 
   1181   parser->m_freeBindingList = NULL;
   1182   parser->m_freeTagList = NULL;
   1183   parser->m_freeInternalEntities = NULL;
   1184   parser->m_freeAttributeEntities = NULL;
   1185   parser->m_freeValueEntities = NULL;
   1186 
   1187   parser->m_groupSize = 0;
   1188   parser->m_groupConnector = NULL;
   1189 
   1190   parser->m_unknownEncodingHandler = NULL;
   1191   parser->m_unknownEncodingHandlerData = NULL;
   1192 
   1193   parser->m_namespaceSeparator = ASCII_EXCL;
   1194   parser->m_ns = XML_FALSE;
   1195   parser->m_ns_triplets = XML_FALSE;
   1196 
   1197   parser->m_nsAtts = NULL;
   1198   parser->m_nsAttsVersion = 0;
   1199   parser->m_nsAttsPower = 0;
   1200 
   1201   parser->m_protocolEncodingName = NULL;
   1202 
   1203   poolInit(&parser->m_tempPool, &(parser->m_mem));
   1204   poolInit(&parser->m_temp2Pool, &(parser->m_mem));
   1205   parserInit(parser, encodingName);
   1206 
   1207   if (encodingName && ! parser->m_protocolEncodingName) {
   1208     if (dtd) {
   1209       // We need to stop the upcoming call to XML_ParserFree from happily
   1210       // destroying parser->m_dtd because the DTD is shared with the parent
   1211       // parser and the only guard that keeps XML_ParserFree from destroying
   1212       // parser->m_dtd is parser->m_isParamEntity but it will be set to
   1213       // XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all).
   1214       parser->m_dtd = NULL;
   1215     }
   1216     XML_ParserFree(parser);
   1217     return NULL;
   1218   }
   1219 
   1220   if (nameSep) {
   1221     parser->m_ns = XML_TRUE;
   1222     parser->m_internalEncoding = XmlGetInternalEncodingNS();
   1223     parser->m_namespaceSeparator = *nameSep;
   1224   } else {
   1225     parser->m_internalEncoding = XmlGetInternalEncoding();
   1226   }
   1227 
   1228   return parser;
   1229 }
   1230 
   1231 static void
   1232 parserInit(XML_Parser parser, const XML_Char *encodingName) {
   1233   parser->m_processor = prologInitProcessor;
   1234   XmlPrologStateInit(&parser->m_prologState);
   1235   if (encodingName != NULL) {
   1236     parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
   1237   }
   1238   parser->m_curBase = NULL;
   1239   XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
   1240   parser->m_userData = NULL;
   1241   parser->m_handlerArg = NULL;
   1242   parser->m_startElementHandler = NULL;
   1243   parser->m_endElementHandler = NULL;
   1244   parser->m_characterDataHandler = NULL;
   1245   parser->m_processingInstructionHandler = NULL;
   1246   parser->m_commentHandler = NULL;
   1247   parser->m_startCdataSectionHandler = NULL;
   1248   parser->m_endCdataSectionHandler = NULL;
   1249   parser->m_defaultHandler = NULL;
   1250   parser->m_startDoctypeDeclHandler = NULL;
   1251   parser->m_endDoctypeDeclHandler = NULL;
   1252   parser->m_unparsedEntityDeclHandler = NULL;
   1253   parser->m_notationDeclHandler = NULL;
   1254   parser->m_startNamespaceDeclHandler = NULL;
   1255   parser->m_endNamespaceDeclHandler = NULL;
   1256   parser->m_notStandaloneHandler = NULL;
   1257   parser->m_externalEntityRefHandler = NULL;
   1258   parser->m_externalEntityRefHandlerArg = parser;
   1259   parser->m_skippedEntityHandler = NULL;
   1260   parser->m_elementDeclHandler = NULL;
   1261   parser->m_attlistDeclHandler = NULL;
   1262   parser->m_entityDeclHandler = NULL;
   1263   parser->m_xmlDeclHandler = NULL;
   1264   parser->m_bufferPtr = parser->m_buffer;
   1265   parser->m_bufferEnd = parser->m_buffer;
   1266   parser->m_parseEndByteIndex = 0;
   1267   parser->m_parseEndPtr = NULL;
   1268   parser->m_partialTokenBytesBefore = 0;
   1269   parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
   1270   parser->m_lastBufferRequestSize = 0;
   1271   parser->m_declElementType = NULL;
   1272   parser->m_declAttributeId = NULL;
   1273   parser->m_declEntity = NULL;
   1274   parser->m_doctypeName = NULL;
   1275   parser->m_doctypeSysid = NULL;
   1276   parser->m_doctypePubid = NULL;
   1277   parser->m_declAttributeType = NULL;
   1278   parser->m_declNotationName = NULL;
   1279   parser->m_declNotationPublicId = NULL;
   1280   parser->m_declAttributeIsCdata = XML_FALSE;
   1281   parser->m_declAttributeIsId = XML_FALSE;
   1282   memset(&parser->m_position, 0, sizeof(POSITION));
   1283   parser->m_errorCode = XML_ERROR_NONE;
   1284   parser->m_eventPtr = NULL;
   1285   parser->m_eventEndPtr = NULL;
   1286   parser->m_positionPtr = NULL;
   1287   parser->m_openInternalEntities = NULL;
   1288   parser->m_openAttributeEntities = NULL;
   1289   parser->m_openValueEntities = NULL;
   1290   parser->m_defaultExpandInternalEntities = XML_TRUE;
   1291   parser->m_tagLevel = 0;
   1292   parser->m_tagStack = NULL;
   1293   parser->m_inheritedBindings = NULL;
   1294   parser->m_nSpecifiedAtts = 0;
   1295   parser->m_unknownEncodingMem = NULL;
   1296   parser->m_unknownEncodingRelease = NULL;
   1297   parser->m_unknownEncodingData = NULL;
   1298   parser->m_parentParser = NULL;
   1299   parser->m_parsingStatus.parsing = XML_INITIALIZED;
   1300   // Reentry can only be triggered inside m_processor calls
   1301   parser->m_reenter = XML_FALSE;
   1302 #ifdef XML_DTD
   1303   parser->m_isParamEntity = XML_FALSE;
   1304   parser->m_useForeignDTD = XML_FALSE;
   1305   parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
   1306 #endif
   1307   parser->m_hash_secret_salt = 0;
   1308 
   1309 #if XML_GE == 1
   1310   memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
   1311   parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
   1312   parser->m_accounting.maximumAmplificationFactor
   1313       = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
   1314   parser->m_accounting.activationThresholdBytes
   1315       = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
   1316 
   1317   memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
   1318   parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
   1319 #endif
   1320 }
   1321 
   1322 /* moves list of bindings to m_freeBindingList */
   1323 static void FASTCALL
   1324 moveToFreeBindingList(XML_Parser parser, BINDING *bindings) {
   1325   while (bindings) {
   1326     BINDING *b = bindings;
   1327     bindings = bindings->nextTagBinding;
   1328     b->nextTagBinding = parser->m_freeBindingList;
   1329     parser->m_freeBindingList = b;
   1330   }
   1331 }
   1332 
   1333 XML_Bool XMLCALL
   1334 XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
   1335   TAG *tStk;
   1336   OPEN_INTERNAL_ENTITY *openEntityList;
   1337 
   1338   if (parser == NULL)
   1339     return XML_FALSE;
   1340 
   1341   if (parser->m_parentParser)
   1342     return XML_FALSE;
   1343   /* move m_tagStack to m_freeTagList */
   1344   tStk = parser->m_tagStack;
   1345   while (tStk) {
   1346     TAG *tag = tStk;
   1347     tStk = tStk->parent;
   1348     tag->parent = parser->m_freeTagList;
   1349     moveToFreeBindingList(parser, tag->bindings);
   1350     tag->bindings = NULL;
   1351     parser->m_freeTagList = tag;
   1352   }
   1353   /* move m_openInternalEntities to m_freeInternalEntities */
   1354   openEntityList = parser->m_openInternalEntities;
   1355   while (openEntityList) {
   1356     OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
   1357     openEntityList = openEntity->next;
   1358     openEntity->next = parser->m_freeInternalEntities;
   1359     parser->m_freeInternalEntities = openEntity;
   1360   }
   1361   /* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
   1362    * for attributes) */
   1363   openEntityList = parser->m_openAttributeEntities;
   1364   while (openEntityList) {
   1365     OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
   1366     openEntityList = openEntity->next;
   1367     openEntity->next = parser->m_freeAttributeEntities;
   1368     parser->m_freeAttributeEntities = openEntity;
   1369   }
   1370   /* move m_openValueEntities to m_freeValueEntities (i.e. same task but
   1371    * for value entities) */
   1372   openEntityList = parser->m_openValueEntities;
   1373   while (openEntityList) {
   1374     OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
   1375     openEntityList = openEntity->next;
   1376     openEntity->next = parser->m_freeValueEntities;
   1377     parser->m_freeValueEntities = openEntity;
   1378   }
   1379   moveToFreeBindingList(parser, parser->m_inheritedBindings);
   1380   FREE(parser, parser->m_unknownEncodingMem);
   1381   if (parser->m_unknownEncodingRelease)
   1382     parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
   1383   poolClear(&parser->m_tempPool);
   1384   poolClear(&parser->m_temp2Pool);
   1385   FREE(parser, (void *)parser->m_protocolEncodingName);
   1386   parser->m_protocolEncodingName = NULL;
   1387   parserInit(parser, encodingName);
   1388   dtdReset(parser->m_dtd, &parser->m_mem);
   1389   return XML_TRUE;
   1390 }
   1391 
   1392 static XML_Bool
   1393 parserBusy(XML_Parser parser) {
   1394   switch (parser->m_parsingStatus.parsing) {
   1395   case XML_PARSING:
   1396   case XML_SUSPENDED:
   1397     return XML_TRUE;
   1398   case XML_INITIALIZED:
   1399   case XML_FINISHED:
   1400   default:
   1401     return XML_FALSE;
   1402   }
   1403 }
   1404 
   1405 enum XML_Status XMLCALL
   1406 XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
   1407   if (parser == NULL)
   1408     return XML_STATUS_ERROR;
   1409   /* Block after XML_Parse()/XML_ParseBuffer() has been called.
   1410      XXX There's no way for the caller to determine which of the
   1411      XXX possible error cases caused the XML_STATUS_ERROR return.
   1412   */
   1413   if (parserBusy(parser))
   1414     return XML_STATUS_ERROR;
   1415 
   1416   /* Get rid of any previous encoding name */
   1417   FREE(parser, (void *)parser->m_protocolEncodingName);
   1418 
   1419   if (encodingName == NULL)
   1420     /* No new encoding name */
   1421     parser->m_protocolEncodingName = NULL;
   1422   else {
   1423     /* Copy the new encoding name into allocated memory */
   1424     parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
   1425     if (! parser->m_protocolEncodingName)
   1426       return XML_STATUS_ERROR;
   1427   }
   1428   return XML_STATUS_OK;
   1429 }
   1430 
   1431 XML_Parser XMLCALL
   1432 XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
   1433                                const XML_Char *encodingName) {
   1434   XML_Parser parser = oldParser;
   1435   DTD *newDtd = NULL;
   1436   DTD *oldDtd;
   1437   XML_StartElementHandler oldStartElementHandler;
   1438   XML_EndElementHandler oldEndElementHandler;
   1439   XML_CharacterDataHandler oldCharacterDataHandler;
   1440   XML_ProcessingInstructionHandler oldProcessingInstructionHandler;
   1441   XML_CommentHandler oldCommentHandler;
   1442   XML_StartCdataSectionHandler oldStartCdataSectionHandler;
   1443   XML_EndCdataSectionHandler oldEndCdataSectionHandler;
   1444   XML_DefaultHandler oldDefaultHandler;
   1445   XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler;
   1446   XML_NotationDeclHandler oldNotationDeclHandler;
   1447   XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler;
   1448   XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler;
   1449   XML_NotStandaloneHandler oldNotStandaloneHandler;
   1450   XML_ExternalEntityRefHandler oldExternalEntityRefHandler;
   1451   XML_SkippedEntityHandler oldSkippedEntityHandler;
   1452   XML_UnknownEncodingHandler oldUnknownEncodingHandler;
   1453   XML_ElementDeclHandler oldElementDeclHandler;
   1454   XML_AttlistDeclHandler oldAttlistDeclHandler;
   1455   XML_EntityDeclHandler oldEntityDeclHandler;
   1456   XML_XmlDeclHandler oldXmlDeclHandler;
   1457   ELEMENT_TYPE *oldDeclElementType;
   1458 
   1459   void *oldUserData;
   1460   void *oldHandlerArg;
   1461   XML_Bool oldDefaultExpandInternalEntities;
   1462   XML_Parser oldExternalEntityRefHandlerArg;
   1463 #ifdef XML_DTD
   1464   enum XML_ParamEntityParsing oldParamEntityParsing;
   1465   int oldInEntityValue;
   1466 #endif
   1467   XML_Bool oldns_triplets;
   1468   /* Note that the new parser shares the same hash secret as the old
   1469      parser, so that dtdCopy and copyEntityTable can lookup values
   1470      from hash tables associated with either parser without us having
   1471      to worry which hash secrets each table has.
   1472   */
   1473   unsigned long oldhash_secret_salt;
   1474   XML_Bool oldReparseDeferralEnabled;
   1475 
   1476   /* Validate the oldParser parameter before we pull everything out of it */
   1477   if (oldParser == NULL)
   1478     return NULL;
   1479 
   1480   /* Stash the original parser contents on the stack */
   1481   oldDtd = parser->m_dtd;
   1482   oldStartElementHandler = parser->m_startElementHandler;
   1483   oldEndElementHandler = parser->m_endElementHandler;
   1484   oldCharacterDataHandler = parser->m_characterDataHandler;
   1485   oldProcessingInstructionHandler = parser->m_processingInstructionHandler;
   1486   oldCommentHandler = parser->m_commentHandler;
   1487   oldStartCdataSectionHandler = parser->m_startCdataSectionHandler;
   1488   oldEndCdataSectionHandler = parser->m_endCdataSectionHandler;
   1489   oldDefaultHandler = parser->m_defaultHandler;
   1490   oldUnparsedEntityDeclHandler = parser->m_unparsedEntityDeclHandler;
   1491   oldNotationDeclHandler = parser->m_notationDeclHandler;
   1492   oldStartNamespaceDeclHandler = parser->m_startNamespaceDeclHandler;
   1493   oldEndNamespaceDeclHandler = parser->m_endNamespaceDeclHandler;
   1494   oldNotStandaloneHandler = parser->m_notStandaloneHandler;
   1495   oldExternalEntityRefHandler = parser->m_externalEntityRefHandler;
   1496   oldSkippedEntityHandler = parser->m_skippedEntityHandler;
   1497   oldUnknownEncodingHandler = parser->m_unknownEncodingHandler;
   1498   oldElementDeclHandler = parser->m_elementDeclHandler;
   1499   oldAttlistDeclHandler = parser->m_attlistDeclHandler;
   1500   oldEntityDeclHandler = parser->m_entityDeclHandler;
   1501   oldXmlDeclHandler = parser->m_xmlDeclHandler;
   1502   oldDeclElementType = parser->m_declElementType;
   1503 
   1504   oldUserData = parser->m_userData;
   1505   oldHandlerArg = parser->m_handlerArg;
   1506   oldDefaultExpandInternalEntities = parser->m_defaultExpandInternalEntities;
   1507   oldExternalEntityRefHandlerArg = parser->m_externalEntityRefHandlerArg;
   1508 #ifdef XML_DTD
   1509   oldParamEntityParsing = parser->m_paramEntityParsing;
   1510   oldInEntityValue = parser->m_prologState.inEntityValue;
   1511 #endif
   1512   oldns_triplets = parser->m_ns_triplets;
   1513   /* Note that the new parser shares the same hash secret as the old
   1514      parser, so that dtdCopy and copyEntityTable can lookup values
   1515      from hash tables associated with either parser without us having
   1516      to worry which hash secrets each table has.
   1517   */
   1518   oldhash_secret_salt = parser->m_hash_secret_salt;
   1519   oldReparseDeferralEnabled = parser->m_reparseDeferralEnabled;
   1520 
   1521 #ifdef XML_DTD
   1522   if (! context)
   1523     newDtd = oldDtd;
   1524 #endif /* XML_DTD */
   1525 
   1526   /* Note that the magical uses of the pre-processor to make field
   1527      access look more like C++ require that `parser' be overwritten
   1528      here.  This makes this function more painful to follow than it
   1529      would be otherwise.
   1530   */
   1531   if (parser->m_ns) {
   1532     XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
   1533     parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
   1534   } else {
   1535     parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
   1536   }
   1537 
   1538   if (! parser)
   1539     return NULL;
   1540 
   1541   parser->m_startElementHandler = oldStartElementHandler;
   1542   parser->m_endElementHandler = oldEndElementHandler;
   1543   parser->m_characterDataHandler = oldCharacterDataHandler;
   1544   parser->m_processingInstructionHandler = oldProcessingInstructionHandler;
   1545   parser->m_commentHandler = oldCommentHandler;
   1546   parser->m_startCdataSectionHandler = oldStartCdataSectionHandler;
   1547   parser->m_endCdataSectionHandler = oldEndCdataSectionHandler;
   1548   parser->m_defaultHandler = oldDefaultHandler;
   1549   parser->m_unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
   1550   parser->m_notationDeclHandler = oldNotationDeclHandler;
   1551   parser->m_startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
   1552   parser->m_endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
   1553   parser->m_notStandaloneHandler = oldNotStandaloneHandler;
   1554   parser->m_externalEntityRefHandler = oldExternalEntityRefHandler;
   1555   parser->m_skippedEntityHandler = oldSkippedEntityHandler;
   1556   parser->m_unknownEncodingHandler = oldUnknownEncodingHandler;
   1557   parser->m_elementDeclHandler = oldElementDeclHandler;
   1558   parser->m_attlistDeclHandler = oldAttlistDeclHandler;
   1559   parser->m_entityDeclHandler = oldEntityDeclHandler;
   1560   parser->m_xmlDeclHandler = oldXmlDeclHandler;
   1561   parser->m_declElementType = oldDeclElementType;
   1562   parser->m_userData = oldUserData;
   1563   if (oldUserData == oldHandlerArg)
   1564     parser->m_handlerArg = parser->m_userData;
   1565   else
   1566     parser->m_handlerArg = parser;
   1567   if (oldExternalEntityRefHandlerArg != oldParser)
   1568     parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
   1569   parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
   1570   parser->m_ns_triplets = oldns_triplets;
   1571   parser->m_hash_secret_salt = oldhash_secret_salt;
   1572   parser->m_reparseDeferralEnabled = oldReparseDeferralEnabled;
   1573   parser->m_parentParser = oldParser;
   1574 #ifdef XML_DTD
   1575   parser->m_paramEntityParsing = oldParamEntityParsing;
   1576   parser->m_prologState.inEntityValue = oldInEntityValue;
   1577   if (context) {
   1578 #endif /* XML_DTD */
   1579     if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem)
   1580         || ! setContext(parser, context)) {
   1581       XML_ParserFree(parser);
   1582       return NULL;
   1583     }
   1584     parser->m_processor = externalEntityInitProcessor;
   1585 #ifdef XML_DTD
   1586   } else {
   1587     /* The DTD instance referenced by parser->m_dtd is shared between the
   1588        document's root parser and external PE parsers, therefore one does not
   1589        need to call setContext. In addition, one also *must* not call
   1590        setContext, because this would overwrite existing prefix->binding
   1591        pointers in parser->m_dtd with ones that get destroyed with the external
   1592        PE parser. This would leave those prefixes with dangling pointers.
   1593     */
   1594     parser->m_isParamEntity = XML_TRUE;
   1595     XmlPrologStateInitExternalEntity(&parser->m_prologState);
   1596     parser->m_processor = externalParEntInitProcessor;
   1597   }
   1598 #endif /* XML_DTD */
   1599   return parser;
   1600 }
   1601 
   1602 static void FASTCALL
   1603 destroyBindings(BINDING *bindings, XML_Parser parser) {
   1604   for (;;) {
   1605     BINDING *b = bindings;
   1606     if (! b)
   1607       break;
   1608     bindings = b->nextTagBinding;
   1609     FREE(parser, b->uri);
   1610     FREE(parser, b);
   1611   }
   1612 }
   1613 
   1614 void XMLCALL
   1615 XML_ParserFree(XML_Parser parser) {
   1616   TAG *tagList;
   1617   OPEN_INTERNAL_ENTITY *entityList;
   1618   if (parser == NULL)
   1619     return;
   1620   /* free m_tagStack and m_freeTagList */
   1621   tagList = parser->m_tagStack;
   1622   for (;;) {
   1623     TAG *p;
   1624     if (tagList == NULL) {
   1625       if (parser->m_freeTagList == NULL)
   1626         break;
   1627       tagList = parser->m_freeTagList;
   1628       parser->m_freeTagList = NULL;
   1629     }
   1630     p = tagList;
   1631     tagList = tagList->parent;
   1632     FREE(parser, p->buf);
   1633     destroyBindings(p->bindings, parser);
   1634     FREE(parser, p);
   1635   }
   1636   /* free m_openInternalEntities and m_freeInternalEntities */
   1637   entityList = parser->m_openInternalEntities;
   1638   for (;;) {
   1639     OPEN_INTERNAL_ENTITY *openEntity;
   1640     if (entityList == NULL) {
   1641       if (parser->m_freeInternalEntities == NULL)
   1642         break;
   1643       entityList = parser->m_freeInternalEntities;
   1644       parser->m_freeInternalEntities = NULL;
   1645     }
   1646     openEntity = entityList;
   1647     entityList = entityList->next;
   1648     FREE(parser, openEntity);
   1649   }
   1650   /* free m_openAttributeEntities and m_freeAttributeEntities */
   1651   entityList = parser->m_openAttributeEntities;
   1652   for (;;) {
   1653     OPEN_INTERNAL_ENTITY *openEntity;
   1654     if (entityList == NULL) {
   1655       if (parser->m_freeAttributeEntities == NULL)
   1656         break;
   1657       entityList = parser->m_freeAttributeEntities;
   1658       parser->m_freeAttributeEntities = NULL;
   1659     }
   1660     openEntity = entityList;
   1661     entityList = entityList->next;
   1662     FREE(parser, openEntity);
   1663   }
   1664   /* free m_openValueEntities and m_freeValueEntities */
   1665   entityList = parser->m_openValueEntities;
   1666   for (;;) {
   1667     OPEN_INTERNAL_ENTITY *openEntity;
   1668     if (entityList == NULL) {
   1669       if (parser->m_freeValueEntities == NULL)
   1670         break;
   1671       entityList = parser->m_freeValueEntities;
   1672       parser->m_freeValueEntities = NULL;
   1673     }
   1674     openEntity = entityList;
   1675     entityList = entityList->next;
   1676     FREE(parser, openEntity);
   1677   }
   1678   destroyBindings(parser->m_freeBindingList, parser);
   1679   destroyBindings(parser->m_inheritedBindings, parser);
   1680   poolDestroy(&parser->m_tempPool);
   1681   poolDestroy(&parser->m_temp2Pool);
   1682   FREE(parser, (void *)parser->m_protocolEncodingName);
   1683 #ifdef XML_DTD
   1684   /* external parameter entity parsers share the DTD structure
   1685      parser->m_dtd with the root parser, so we must not destroy it
   1686   */
   1687   if (! parser->m_isParamEntity && parser->m_dtd)
   1688 #else
   1689   if (parser->m_dtd)
   1690 #endif /* XML_DTD */
   1691     dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser,
   1692                &parser->m_mem);
   1693   FREE(parser, (void *)parser->m_atts);
   1694 #ifdef XML_ATTR_INFO
   1695   FREE(parser, (void *)parser->m_attInfo);
   1696 #endif
   1697   FREE(parser, parser->m_groupConnector);
   1698   FREE(parser, parser->m_buffer);
   1699   FREE(parser, parser->m_dataBuf);
   1700   FREE(parser, parser->m_nsAtts);
   1701   FREE(parser, parser->m_unknownEncodingMem);
   1702   if (parser->m_unknownEncodingRelease)
   1703     parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
   1704   FREE(parser, parser);
   1705 }
   1706 
   1707 void XMLCALL
   1708 XML_UseParserAsHandlerArg(XML_Parser parser) {
   1709   if (parser != NULL)
   1710     parser->m_handlerArg = parser;
   1711 }
   1712 
   1713 enum XML_Error XMLCALL
   1714 XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) {
   1715   if (parser == NULL)
   1716     return XML_ERROR_INVALID_ARGUMENT;
   1717 #ifdef XML_DTD
   1718   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   1719   if (parserBusy(parser))
   1720     return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
   1721   parser->m_useForeignDTD = useDTD;
   1722   return XML_ERROR_NONE;
   1723 #else
   1724   UNUSED_P(useDTD);
   1725   return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
   1726 #endif
   1727 }
   1728 
   1729 void XMLCALL
   1730 XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) {
   1731   if (parser == NULL)
   1732     return;
   1733   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   1734   if (parserBusy(parser))
   1735     return;
   1736   parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
   1737 }
   1738 
   1739 void XMLCALL
   1740 XML_SetUserData(XML_Parser parser, void *p) {
   1741   if (parser == NULL)
   1742     return;
   1743   if (parser->m_handlerArg == parser->m_userData)
   1744     parser->m_handlerArg = parser->m_userData = p;
   1745   else
   1746     parser->m_userData = p;
   1747 }
   1748 
   1749 enum XML_Status XMLCALL
   1750 XML_SetBase(XML_Parser parser, const XML_Char *p) {
   1751   if (parser == NULL)
   1752     return XML_STATUS_ERROR;
   1753   if (p) {
   1754     p = poolCopyString(&parser->m_dtd->pool, p);
   1755     if (! p)
   1756       return XML_STATUS_ERROR;
   1757     parser->m_curBase = p;
   1758   } else
   1759     parser->m_curBase = NULL;
   1760   return XML_STATUS_OK;
   1761 }
   1762 
   1763 const XML_Char *XMLCALL
   1764 XML_GetBase(XML_Parser parser) {
   1765   if (parser == NULL)
   1766     return NULL;
   1767   return parser->m_curBase;
   1768 }
   1769 
   1770 int XMLCALL
   1771 XML_GetSpecifiedAttributeCount(XML_Parser parser) {
   1772   if (parser == NULL)
   1773     return -1;
   1774   return parser->m_nSpecifiedAtts;
   1775 }
   1776 
   1777 int XMLCALL
   1778 XML_GetIdAttributeIndex(XML_Parser parser) {
   1779   if (parser == NULL)
   1780     return -1;
   1781   return parser->m_idAttIndex;
   1782 }
   1783 
   1784 #ifdef XML_ATTR_INFO
   1785 const XML_AttrInfo *XMLCALL
   1786 XML_GetAttributeInfo(XML_Parser parser) {
   1787   if (parser == NULL)
   1788     return NULL;
   1789   return parser->m_attInfo;
   1790 }
   1791 #endif
   1792 
   1793 void XMLCALL
   1794 XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start,
   1795                       XML_EndElementHandler end) {
   1796   if (parser == NULL)
   1797     return;
   1798   parser->m_startElementHandler = start;
   1799   parser->m_endElementHandler = end;
   1800 }
   1801 
   1802 void XMLCALL
   1803 XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler start) {
   1804   if (parser != NULL)
   1805     parser->m_startElementHandler = start;
   1806 }
   1807 
   1808 void XMLCALL
   1809 XML_SetEndElementHandler(XML_Parser parser, XML_EndElementHandler end) {
   1810   if (parser != NULL)
   1811     parser->m_endElementHandler = end;
   1812 }
   1813 
   1814 void XMLCALL
   1815 XML_SetCharacterDataHandler(XML_Parser parser,
   1816                             XML_CharacterDataHandler handler) {
   1817   if (parser != NULL)
   1818     parser->m_characterDataHandler = handler;
   1819 }
   1820 
   1821 void XMLCALL
   1822 XML_SetProcessingInstructionHandler(XML_Parser parser,
   1823                                     XML_ProcessingInstructionHandler handler) {
   1824   if (parser != NULL)
   1825     parser->m_processingInstructionHandler = handler;
   1826 }
   1827 
   1828 void XMLCALL
   1829 XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler) {
   1830   if (parser != NULL)
   1831     parser->m_commentHandler = handler;
   1832 }
   1833 
   1834 void XMLCALL
   1835 XML_SetCdataSectionHandler(XML_Parser parser,
   1836                            XML_StartCdataSectionHandler start,
   1837                            XML_EndCdataSectionHandler end) {
   1838   if (parser == NULL)
   1839     return;
   1840   parser->m_startCdataSectionHandler = start;
   1841   parser->m_endCdataSectionHandler = end;
   1842 }
   1843 
   1844 void XMLCALL
   1845 XML_SetStartCdataSectionHandler(XML_Parser parser,
   1846                                 XML_StartCdataSectionHandler start) {
   1847   if (parser != NULL)
   1848     parser->m_startCdataSectionHandler = start;
   1849 }
   1850 
   1851 void XMLCALL
   1852 XML_SetEndCdataSectionHandler(XML_Parser parser,
   1853                               XML_EndCdataSectionHandler end) {
   1854   if (parser != NULL)
   1855     parser->m_endCdataSectionHandler = end;
   1856 }
   1857 
   1858 void XMLCALL
   1859 XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler) {
   1860   if (parser == NULL)
   1861     return;
   1862   parser->m_defaultHandler = handler;
   1863   parser->m_defaultExpandInternalEntities = XML_FALSE;
   1864 }
   1865 
   1866 void XMLCALL
   1867 XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler) {
   1868   if (parser == NULL)
   1869     return;
   1870   parser->m_defaultHandler = handler;
   1871   parser->m_defaultExpandInternalEntities = XML_TRUE;
   1872 }
   1873 
   1874 void XMLCALL
   1875 XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start,
   1876                           XML_EndDoctypeDeclHandler end) {
   1877   if (parser == NULL)
   1878     return;
   1879   parser->m_startDoctypeDeclHandler = start;
   1880   parser->m_endDoctypeDeclHandler = end;
   1881 }
   1882 
   1883 void XMLCALL
   1884 XML_SetStartDoctypeDeclHandler(XML_Parser parser,
   1885                                XML_StartDoctypeDeclHandler start) {
   1886   if (parser != NULL)
   1887     parser->m_startDoctypeDeclHandler = start;
   1888 }
   1889 
   1890 void XMLCALL
   1891 XML_SetEndDoctypeDeclHandler(XML_Parser parser, XML_EndDoctypeDeclHandler end) {
   1892   if (parser != NULL)
   1893     parser->m_endDoctypeDeclHandler = end;
   1894 }
   1895 
   1896 void XMLCALL
   1897 XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
   1898                                  XML_UnparsedEntityDeclHandler handler) {
   1899   if (parser != NULL)
   1900     parser->m_unparsedEntityDeclHandler = handler;
   1901 }
   1902 
   1903 void XMLCALL
   1904 XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler) {
   1905   if (parser != NULL)
   1906     parser->m_notationDeclHandler = handler;
   1907 }
   1908 
   1909 void XMLCALL
   1910 XML_SetNamespaceDeclHandler(XML_Parser parser,
   1911                             XML_StartNamespaceDeclHandler start,
   1912                             XML_EndNamespaceDeclHandler end) {
   1913   if (parser == NULL)
   1914     return;
   1915   parser->m_startNamespaceDeclHandler = start;
   1916   parser->m_endNamespaceDeclHandler = end;
   1917 }
   1918 
   1919 void XMLCALL
   1920 XML_SetStartNamespaceDeclHandler(XML_Parser parser,
   1921                                  XML_StartNamespaceDeclHandler start) {
   1922   if (parser != NULL)
   1923     parser->m_startNamespaceDeclHandler = start;
   1924 }
   1925 
   1926 void XMLCALL
   1927 XML_SetEndNamespaceDeclHandler(XML_Parser parser,
   1928                                XML_EndNamespaceDeclHandler end) {
   1929   if (parser != NULL)
   1930     parser->m_endNamespaceDeclHandler = end;
   1931 }
   1932 
   1933 void XMLCALL
   1934 XML_SetNotStandaloneHandler(XML_Parser parser,
   1935                             XML_NotStandaloneHandler handler) {
   1936   if (parser != NULL)
   1937     parser->m_notStandaloneHandler = handler;
   1938 }
   1939 
   1940 void XMLCALL
   1941 XML_SetExternalEntityRefHandler(XML_Parser parser,
   1942                                 XML_ExternalEntityRefHandler handler) {
   1943   if (parser != NULL)
   1944     parser->m_externalEntityRefHandler = handler;
   1945 }
   1946 
   1947 void XMLCALL
   1948 XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) {
   1949   if (parser == NULL)
   1950     return;
   1951   if (arg)
   1952     parser->m_externalEntityRefHandlerArg = (XML_Parser)arg;
   1953   else
   1954     parser->m_externalEntityRefHandlerArg = parser;
   1955 }
   1956 
   1957 void XMLCALL
   1958 XML_SetSkippedEntityHandler(XML_Parser parser,
   1959                             XML_SkippedEntityHandler handler) {
   1960   if (parser != NULL)
   1961     parser->m_skippedEntityHandler = handler;
   1962 }
   1963 
   1964 void XMLCALL
   1965 XML_SetUnknownEncodingHandler(XML_Parser parser,
   1966                               XML_UnknownEncodingHandler handler, void *data) {
   1967   if (parser == NULL)
   1968     return;
   1969   parser->m_unknownEncodingHandler = handler;
   1970   parser->m_unknownEncodingHandlerData = data;
   1971 }
   1972 
   1973 void XMLCALL
   1974 XML_SetElementDeclHandler(XML_Parser parser, XML_ElementDeclHandler eldecl) {
   1975   if (parser != NULL)
   1976     parser->m_elementDeclHandler = eldecl;
   1977 }
   1978 
   1979 void XMLCALL
   1980 XML_SetAttlistDeclHandler(XML_Parser parser, XML_AttlistDeclHandler attdecl) {
   1981   if (parser != NULL)
   1982     parser->m_attlistDeclHandler = attdecl;
   1983 }
   1984 
   1985 void XMLCALL
   1986 XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler) {
   1987   if (parser != NULL)
   1988     parser->m_entityDeclHandler = handler;
   1989 }
   1990 
   1991 void XMLCALL
   1992 XML_SetXmlDeclHandler(XML_Parser parser, XML_XmlDeclHandler handler) {
   1993   if (parser != NULL)
   1994     parser->m_xmlDeclHandler = handler;
   1995 }
   1996 
   1997 int XMLCALL
   1998 XML_SetParamEntityParsing(XML_Parser parser,
   1999                           enum XML_ParamEntityParsing peParsing) {
   2000   if (parser == NULL)
   2001     return 0;
   2002   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   2003   if (parserBusy(parser))
   2004     return 0;
   2005 #ifdef XML_DTD
   2006   parser->m_paramEntityParsing = peParsing;
   2007   return 1;
   2008 #else
   2009   return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
   2010 #endif
   2011 }
   2012 
   2013 int XMLCALL
   2014 XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
   2015   if (parser == NULL)
   2016     return 0;
   2017   if (parser->m_parentParser)
   2018     return XML_SetHashSalt(parser->m_parentParser, hash_salt);
   2019   /* block after XML_Parse()/XML_ParseBuffer() has been called */
   2020   if (parserBusy(parser))
   2021     return 0;
   2022   parser->m_hash_secret_salt = hash_salt;
   2023   return 1;
   2024 }
   2025 
   2026 enum XML_Status XMLCALL
   2027 XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
   2028   if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) {
   2029     if (parser != NULL)
   2030       parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
   2031     return XML_STATUS_ERROR;
   2032   }
   2033   switch (parser->m_parsingStatus.parsing) {
   2034   case XML_SUSPENDED:
   2035     parser->m_errorCode = XML_ERROR_SUSPENDED;
   2036     return XML_STATUS_ERROR;
   2037   case XML_FINISHED:
   2038     parser->m_errorCode = XML_ERROR_FINISHED;
   2039     return XML_STATUS_ERROR;
   2040   case XML_INITIALIZED:
   2041     if (parser->m_parentParser == NULL && ! startParsing(parser)) {
   2042       parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2043       return XML_STATUS_ERROR;
   2044     }
   2045     /* fall through */
   2046   default:
   2047     parser->m_parsingStatus.parsing = XML_PARSING;
   2048   }
   2049 
   2050 #if XML_CONTEXT_BYTES == 0
   2051   if (parser->m_bufferPtr == parser->m_bufferEnd) {
   2052     const char *end;
   2053     int nLeftOver;
   2054     enum XML_Status result;
   2055     /* Detect overflow (a+b > MAX <==> b > MAX-a) */
   2056     if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
   2057       parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2058       parser->m_eventPtr = parser->m_eventEndPtr = NULL;
   2059       parser->m_processor = errorProcessor;
   2060       return XML_STATUS_ERROR;
   2061     }
   2062     // though this isn't a buffer request, we assume that `len` is the app's
   2063     // preferred buffer fill size, and therefore save it here.
   2064     parser->m_lastBufferRequestSize = len;
   2065     parser->m_parseEndByteIndex += len;
   2066     parser->m_positionPtr = s;
   2067     parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
   2068 
   2069     parser->m_errorCode
   2070         = callProcessor(parser, s, parser->m_parseEndPtr = s + len, &end);
   2071 
   2072     if (parser->m_errorCode != XML_ERROR_NONE) {
   2073       parser->m_eventEndPtr = parser->m_eventPtr;
   2074       parser->m_processor = errorProcessor;
   2075       return XML_STATUS_ERROR;
   2076     } else {
   2077       switch (parser->m_parsingStatus.parsing) {
   2078       case XML_SUSPENDED:
   2079         result = XML_STATUS_SUSPENDED;
   2080         break;
   2081       case XML_INITIALIZED:
   2082       case XML_PARSING:
   2083         if (isFinal) {
   2084           parser->m_parsingStatus.parsing = XML_FINISHED;
   2085           return XML_STATUS_OK;
   2086         }
   2087       /* fall through */
   2088       default:
   2089         result = XML_STATUS_OK;
   2090       }
   2091     }
   2092 
   2093     XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end,
   2094                       &parser->m_position);
   2095     nLeftOver = s + len - end;
   2096     if (nLeftOver) {
   2097       // Back up and restore the parsing status to avoid XML_ERROR_SUSPENDED
   2098       // (and XML_ERROR_FINISHED) from XML_GetBuffer.
   2099       const enum XML_Parsing originalStatus = parser->m_parsingStatus.parsing;
   2100       parser->m_parsingStatus.parsing = XML_PARSING;
   2101       void *const temp = XML_GetBuffer(parser, nLeftOver);
   2102       parser->m_parsingStatus.parsing = originalStatus;
   2103       // GetBuffer may have overwritten this, but we want to remember what the
   2104       // app requested, not how many bytes were left over after parsing.
   2105       parser->m_lastBufferRequestSize = len;
   2106       if (temp == NULL) {
   2107         // NOTE: parser->m_errorCode has already been set by XML_GetBuffer().
   2108         parser->m_eventPtr = parser->m_eventEndPtr = NULL;
   2109         parser->m_processor = errorProcessor;
   2110         return XML_STATUS_ERROR;
   2111       }
   2112       // Since we know that the buffer was empty and XML_CONTEXT_BYTES is 0, we
   2113       // don't have any data to preserve, and can copy straight into the start
   2114       // of the buffer rather than the GetBuffer return pointer (which may be
   2115       // pointing further into the allocated buffer).
   2116       memcpy(parser->m_buffer, end, nLeftOver);
   2117     }
   2118     parser->m_bufferPtr = parser->m_buffer;
   2119     parser->m_bufferEnd = parser->m_buffer + nLeftOver;
   2120     parser->m_positionPtr = parser->m_bufferPtr;
   2121     parser->m_parseEndPtr = parser->m_bufferEnd;
   2122     parser->m_eventPtr = parser->m_bufferPtr;
   2123     parser->m_eventEndPtr = parser->m_bufferPtr;
   2124     return result;
   2125   }
   2126 #endif /* XML_CONTEXT_BYTES == 0 */
   2127   void *buff = XML_GetBuffer(parser, len);
   2128   if (buff == NULL)
   2129     return XML_STATUS_ERROR;
   2130   if (len > 0) {
   2131     assert(s != NULL); // make sure s==NULL && len!=0 was rejected above
   2132     memcpy(buff, s, len);
   2133   }
   2134   return XML_ParseBuffer(parser, len, isFinal);
   2135 }
   2136 
   2137 enum XML_Status XMLCALL
   2138 XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
   2139   const char *start;
   2140   enum XML_Status result = XML_STATUS_OK;
   2141 
   2142   if (parser == NULL)
   2143     return XML_STATUS_ERROR;
   2144 
   2145   if (len < 0) {
   2146     parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
   2147     return XML_STATUS_ERROR;
   2148   }
   2149 
   2150   switch (parser->m_parsingStatus.parsing) {
   2151   case XML_SUSPENDED:
   2152     parser->m_errorCode = XML_ERROR_SUSPENDED;
   2153     return XML_STATUS_ERROR;
   2154   case XML_FINISHED:
   2155     parser->m_errorCode = XML_ERROR_FINISHED;
   2156     return XML_STATUS_ERROR;
   2157   case XML_INITIALIZED:
   2158     /* Has someone called XML_GetBuffer successfully before? */
   2159     if (! parser->m_bufferPtr) {
   2160       parser->m_errorCode = XML_ERROR_NO_BUFFER;
   2161       return XML_STATUS_ERROR;
   2162     }
   2163 
   2164     if (parser->m_parentParser == NULL && ! startParsing(parser)) {
   2165       parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2166       return XML_STATUS_ERROR;
   2167     }
   2168     /* fall through */
   2169   default:
   2170     parser->m_parsingStatus.parsing = XML_PARSING;
   2171   }
   2172 
   2173   start = parser->m_bufferPtr;
   2174   parser->m_positionPtr = start;
   2175   parser->m_bufferEnd += len;
   2176   parser->m_parseEndPtr = parser->m_bufferEnd;
   2177   parser->m_parseEndByteIndex += len;
   2178   parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
   2179 
   2180   parser->m_errorCode = callProcessor(parser, start, parser->m_parseEndPtr,
   2181                                       &parser->m_bufferPtr);
   2182 
   2183   if (parser->m_errorCode != XML_ERROR_NONE) {
   2184     parser->m_eventEndPtr = parser->m_eventPtr;
   2185     parser->m_processor = errorProcessor;
   2186     return XML_STATUS_ERROR;
   2187   } else {
   2188     switch (parser->m_parsingStatus.parsing) {
   2189     case XML_SUSPENDED:
   2190       result = XML_STATUS_SUSPENDED;
   2191       break;
   2192     case XML_INITIALIZED:
   2193     case XML_PARSING:
   2194       if (isFinal) {
   2195         parser->m_parsingStatus.parsing = XML_FINISHED;
   2196         return result;
   2197       }
   2198     default:; /* should not happen */
   2199     }
   2200   }
   2201 
   2202   XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
   2203                     parser->m_bufferPtr, &parser->m_position);
   2204   parser->m_positionPtr = parser->m_bufferPtr;
   2205   return result;
   2206 }
   2207 
   2208 void *XMLCALL
   2209 XML_GetBuffer(XML_Parser parser, int len) {
   2210   if (parser == NULL)
   2211     return NULL;
   2212   if (len < 0) {
   2213     parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2214     return NULL;
   2215   }
   2216   switch (parser->m_parsingStatus.parsing) {
   2217   case XML_SUSPENDED:
   2218     parser->m_errorCode = XML_ERROR_SUSPENDED;
   2219     return NULL;
   2220   case XML_FINISHED:
   2221     parser->m_errorCode = XML_ERROR_FINISHED;
   2222     return NULL;
   2223   default:;
   2224   }
   2225 
   2226   // whether or not the request succeeds, `len` seems to be the app's preferred
   2227   // buffer fill size; remember it.
   2228   parser->m_lastBufferRequestSize = len;
   2229   if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
   2230       || parser->m_buffer == NULL) {
   2231 #if XML_CONTEXT_BYTES > 0
   2232     int keep;
   2233 #endif /* XML_CONTEXT_BYTES > 0 */
   2234     /* Do not invoke signed arithmetic overflow: */
   2235     int neededSize = (int)((unsigned)len
   2236                            + (unsigned)EXPAT_SAFE_PTR_DIFF(
   2237                                parser->m_bufferEnd, parser->m_bufferPtr));
   2238     if (neededSize < 0) {
   2239       parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2240       return NULL;
   2241     }
   2242 #if XML_CONTEXT_BYTES > 0
   2243     keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
   2244     if (keep > XML_CONTEXT_BYTES)
   2245       keep = XML_CONTEXT_BYTES;
   2246     /* Detect and prevent integer overflow */
   2247     if (keep > INT_MAX - neededSize) {
   2248       parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2249       return NULL;
   2250     }
   2251     neededSize += keep;
   2252 #endif /* XML_CONTEXT_BYTES > 0 */
   2253     if (parser->m_buffer && parser->m_bufferPtr
   2254         && neededSize
   2255                <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
   2256 #if XML_CONTEXT_BYTES > 0
   2257       if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
   2258         int offset
   2259             = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
   2260               - keep;
   2261         /* The buffer pointers cannot be NULL here; we have at least some bytes
   2262          * in the buffer */
   2263         memmove(parser->m_buffer, &parser->m_buffer[offset],
   2264                 parser->m_bufferEnd - parser->m_bufferPtr + keep);
   2265         parser->m_bufferEnd -= offset;
   2266         parser->m_bufferPtr -= offset;
   2267       }
   2268 #else
   2269       memmove(parser->m_buffer, parser->m_bufferPtr,
   2270               EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
   2271       parser->m_bufferEnd
   2272           = parser->m_buffer
   2273             + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
   2274       parser->m_bufferPtr = parser->m_buffer;
   2275 #endif /* XML_CONTEXT_BYTES > 0 */
   2276     } else {
   2277       char *newBuf;
   2278       int bufferSize
   2279           = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
   2280       if (bufferSize == 0)
   2281         bufferSize = INIT_BUFFER_SIZE;
   2282       do {
   2283         /* Do not invoke signed arithmetic overflow: */
   2284         bufferSize = (int)(2U * (unsigned)bufferSize);
   2285       } while (bufferSize < neededSize && bufferSize > 0);
   2286       if (bufferSize <= 0) {
   2287         parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2288         return NULL;
   2289       }
   2290       newBuf = (char *)MALLOC(parser, bufferSize);
   2291       if (newBuf == 0) {
   2292         parser->m_errorCode = XML_ERROR_NO_MEMORY;
   2293         return NULL;
   2294       }
   2295       parser->m_bufferLim = newBuf + bufferSize;
   2296 #if XML_CONTEXT_BYTES > 0
   2297       if (parser->m_bufferPtr) {
   2298         memcpy(newBuf, &parser->m_bufferPtr[-keep],
   2299                EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
   2300                    + keep);
   2301         FREE(parser, parser->m_buffer);
   2302         parser->m_buffer = newBuf;
   2303         parser->m_bufferEnd
   2304             = parser->m_buffer
   2305               + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
   2306               + keep;
   2307         parser->m_bufferPtr = parser->m_buffer + keep;
   2308       } else {
   2309         /* This must be a brand new buffer with no data in it yet */
   2310         parser->m_bufferEnd = newBuf;
   2311         parser->m_bufferPtr = parser->m_buffer = newBuf;
   2312       }
   2313 #else
   2314       if (parser->m_bufferPtr) {
   2315         memcpy(newBuf, parser->m_bufferPtr,
   2316                EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
   2317         FREE(parser, parser->m_buffer);
   2318         parser->m_bufferEnd
   2319             = newBuf
   2320               + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
   2321       } else {
   2322         /* This must be a brand new buffer with no data in it yet */
   2323         parser->m_bufferEnd = newBuf;
   2324       }
   2325       parser->m_bufferPtr = parser->m_buffer = newBuf;
   2326 #endif /* XML_CONTEXT_BYTES > 0 */
   2327     }
   2328     parser->m_eventPtr = parser->m_eventEndPtr = NULL;
   2329     parser->m_positionPtr = NULL;
   2330   }
   2331   return parser->m_bufferEnd;
   2332 }
   2333 
   2334 static void
   2335 triggerReenter(XML_Parser parser) {
   2336   parser->m_reenter = XML_TRUE;
   2337 }
   2338 
   2339 enum XML_Status XMLCALL
   2340 XML_StopParser(XML_Parser parser, XML_Bool resumable) {
   2341   if (parser == NULL)
   2342     return XML_STATUS_ERROR;
   2343   switch (parser->m_parsingStatus.parsing) {
   2344   case XML_INITIALIZED:
   2345     parser->m_errorCode = XML_ERROR_NOT_STARTED;
   2346     return XML_STATUS_ERROR;
   2347   case XML_SUSPENDED:
   2348     if (resumable) {
   2349       parser->m_errorCode = XML_ERROR_SUSPENDED;
   2350       return XML_STATUS_ERROR;
   2351     }
   2352     parser->m_parsingStatus.parsing = XML_FINISHED;
   2353     break;
   2354   case XML_FINISHED:
   2355     parser->m_errorCode = XML_ERROR_FINISHED;
   2356     return XML_STATUS_ERROR;
   2357   case XML_PARSING:
   2358     if (resumable) {
   2359 #ifdef XML_DTD
   2360       if (parser->m_isParamEntity) {
   2361         parser->m_errorCode = XML_ERROR_SUSPEND_PE;
   2362         return XML_STATUS_ERROR;
   2363       }
   2364 #endif
   2365       parser->m_parsingStatus.parsing = XML_SUSPENDED;
   2366     } else
   2367       parser->m_parsingStatus.parsing = XML_FINISHED;
   2368     break;
   2369   default:
   2370     assert(0);
   2371   }
   2372   return XML_STATUS_OK;
   2373 }
   2374 
   2375 enum XML_Status XMLCALL
   2376 XML_ResumeParser(XML_Parser parser) {
   2377   enum XML_Status result = XML_STATUS_OK;
   2378 
   2379   if (parser == NULL)
   2380     return XML_STATUS_ERROR;
   2381   if (parser->m_parsingStatus.parsing != XML_SUSPENDED) {
   2382     parser->m_errorCode = XML_ERROR_NOT_SUSPENDED;
   2383     return XML_STATUS_ERROR;
   2384   }
   2385   parser->m_parsingStatus.parsing = XML_PARSING;
   2386 
   2387   parser->m_errorCode = callProcessor(
   2388       parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
   2389 
   2390   if (parser->m_errorCode != XML_ERROR_NONE) {
   2391     parser->m_eventEndPtr = parser->m_eventPtr;
   2392     parser->m_processor = errorProcessor;
   2393     return XML_STATUS_ERROR;
   2394   } else {
   2395     switch (parser->m_parsingStatus.parsing) {
   2396     case XML_SUSPENDED:
   2397       result = XML_STATUS_SUSPENDED;
   2398       break;
   2399     case XML_INITIALIZED:
   2400     case XML_PARSING:
   2401       if (parser->m_parsingStatus.finalBuffer) {
   2402         parser->m_parsingStatus.parsing = XML_FINISHED;
   2403         return result;
   2404       }
   2405     default:;
   2406     }
   2407   }
   2408 
   2409   XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
   2410                     parser->m_bufferPtr, &parser->m_position);
   2411   parser->m_positionPtr = parser->m_bufferPtr;
   2412   return result;
   2413 }
   2414 
   2415 void XMLCALL
   2416 XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) {
   2417   if (parser == NULL)
   2418     return;
   2419   assert(status != NULL);
   2420   *status = parser->m_parsingStatus;
   2421 }
   2422 
   2423 enum XML_Error XMLCALL
   2424 XML_GetErrorCode(XML_Parser parser) {
   2425   if (parser == NULL)
   2426     return XML_ERROR_INVALID_ARGUMENT;
   2427   return parser->m_errorCode;
   2428 }
   2429 
   2430 XML_Index XMLCALL
   2431 XML_GetCurrentByteIndex(XML_Parser parser) {
   2432   if (parser == NULL)
   2433     return -1;
   2434   if (parser->m_eventPtr)
   2435     return (XML_Index)(parser->m_parseEndByteIndex
   2436                        - (parser->m_parseEndPtr - parser->m_eventPtr));
   2437   return -1;
   2438 }
   2439 
   2440 int XMLCALL
   2441 XML_GetCurrentByteCount(XML_Parser parser) {
   2442   if (parser == NULL)
   2443     return 0;
   2444   if (parser->m_eventEndPtr && parser->m_eventPtr)
   2445     return (int)(parser->m_eventEndPtr - parser->m_eventPtr);
   2446   return 0;
   2447 }
   2448 
   2449 const char *XMLCALL
   2450 XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
   2451 #if XML_CONTEXT_BYTES > 0
   2452   if (parser == NULL)
   2453     return NULL;
   2454   if (parser->m_eventPtr && parser->m_buffer) {
   2455     if (offset != NULL)
   2456       *offset = (int)(parser->m_eventPtr - parser->m_buffer);
   2457     if (size != NULL)
   2458       *size = (int)(parser->m_bufferEnd - parser->m_buffer);
   2459     return parser->m_buffer;
   2460   }
   2461 #else
   2462   (void)parser;
   2463   (void)offset;
   2464   (void)size;
   2465 #endif /* XML_CONTEXT_BYTES > 0 */
   2466   return (const char *)0;
   2467 }
   2468 
   2469 XML_Size XMLCALL
   2470 XML_GetCurrentLineNumber(XML_Parser parser) {
   2471   if (parser == NULL)
   2472     return 0;
   2473   if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
   2474     XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
   2475                       parser->m_eventPtr, &parser->m_position);
   2476     parser->m_positionPtr = parser->m_eventPtr;
   2477   }
   2478   return parser->m_position.lineNumber + 1;
   2479 }
   2480 
   2481 XML_Size XMLCALL
   2482 XML_GetCurrentColumnNumber(XML_Parser parser) {
   2483   if (parser == NULL)
   2484     return 0;
   2485   if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
   2486     XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
   2487                       parser->m_eventPtr, &parser->m_position);
   2488     parser->m_positionPtr = parser->m_eventPtr;
   2489   }
   2490   return parser->m_position.columnNumber;
   2491 }
   2492 
   2493 void XMLCALL
   2494 XML_FreeContentModel(XML_Parser parser, XML_Content *model) {
   2495   if (parser != NULL)
   2496     FREE(parser, model);
   2497 }
   2498 
   2499 void *XMLCALL
   2500 XML_MemMalloc(XML_Parser parser, size_t size) {
   2501   if (parser == NULL)
   2502     return NULL;
   2503   return MALLOC(parser, size);
   2504 }
   2505 
   2506 void *XMLCALL
   2507 XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) {
   2508   if (parser == NULL)
   2509     return NULL;
   2510   return REALLOC(parser, ptr, size);
   2511 }
   2512 
   2513 void XMLCALL
   2514 XML_MemFree(XML_Parser parser, void *ptr) {
   2515   if (parser != NULL)
   2516     FREE(parser, ptr);
   2517 }
   2518 
   2519 void XMLCALL
   2520 XML_DefaultCurrent(XML_Parser parser) {
   2521   if (parser == NULL)
   2522     return;
   2523   if (parser->m_defaultHandler) {
   2524     if (parser->m_openInternalEntities)
   2525       reportDefault(parser, parser->m_internalEncoding,
   2526                     parser->m_openInternalEntities->internalEventPtr,
   2527                     parser->m_openInternalEntities->internalEventEndPtr);
   2528     else
   2529       reportDefault(parser, parser->m_encoding, parser->m_eventPtr,
   2530                     parser->m_eventEndPtr);
   2531   }
   2532 }
   2533 
   2534 const XML_LChar *XMLCALL
   2535 XML_ErrorString(enum XML_Error code) {
   2536   switch (code) {
   2537   case XML_ERROR_NONE:
   2538     return NULL;
   2539   case XML_ERROR_NO_MEMORY:
   2540     return XML_L("out of memory");
   2541   case XML_ERROR_SYNTAX:
   2542     return XML_L("syntax error");
   2543   case XML_ERROR_NO_ELEMENTS:
   2544     return XML_L("no element found");
   2545   case XML_ERROR_INVALID_TOKEN:
   2546     return XML_L("not well-formed (invalid token)");
   2547   case XML_ERROR_UNCLOSED_TOKEN:
   2548     return XML_L("unclosed token");
   2549   case XML_ERROR_PARTIAL_CHAR:
   2550     return XML_L("partial character");
   2551   case XML_ERROR_TAG_MISMATCH:
   2552     return XML_L("mismatched tag");
   2553   case XML_ERROR_DUPLICATE_ATTRIBUTE:
   2554     return XML_L("duplicate attribute");
   2555   case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
   2556     return XML_L("junk after document element");
   2557   case XML_ERROR_PARAM_ENTITY_REF:
   2558     return XML_L("illegal parameter entity reference");
   2559   case XML_ERROR_UNDEFINED_ENTITY:
   2560     return XML_L("undefined entity");
   2561   case XML_ERROR_RECURSIVE_ENTITY_REF:
   2562     return XML_L("recursive entity reference");
   2563   case XML_ERROR_ASYNC_ENTITY:
   2564     return XML_L("asynchronous entity");
   2565   case XML_ERROR_BAD_CHAR_REF:
   2566     return XML_L("reference to invalid character number");
   2567   case XML_ERROR_BINARY_ENTITY_REF:
   2568     return XML_L("reference to binary entity");
   2569   case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
   2570     return XML_L("reference to external entity in attribute");
   2571   case XML_ERROR_MISPLACED_XML_PI:
   2572     return XML_L("XML or text declaration not at start of entity");
   2573   case XML_ERROR_UNKNOWN_ENCODING:
   2574     return XML_L("unknown encoding");
   2575   case XML_ERROR_INCORRECT_ENCODING:
   2576     return XML_L("encoding specified in XML declaration is incorrect");
   2577   case XML_ERROR_UNCLOSED_CDATA_SECTION:
   2578     return XML_L("unclosed CDATA section");
   2579   case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
   2580     return XML_L("error in processing external entity reference");
   2581   case XML_ERROR_NOT_STANDALONE:
   2582     return XML_L("document is not standalone");
   2583   case XML_ERROR_UNEXPECTED_STATE:
   2584     return XML_L("unexpected parser state - please send a bug report");
   2585   case XML_ERROR_ENTITY_DECLARED_IN_PE:
   2586     return XML_L("entity declared in parameter entity");
   2587   case XML_ERROR_FEATURE_REQUIRES_XML_DTD:
   2588     return XML_L("requested feature requires XML_DTD support in Expat");
   2589   case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING:
   2590     return XML_L("cannot change setting once parsing has begun");
   2591   /* Added in 1.95.7. */
   2592   case XML_ERROR_UNBOUND_PREFIX:
   2593     return XML_L("unbound prefix");
   2594   /* Added in 1.95.8. */
   2595   case XML_ERROR_UNDECLARING_PREFIX:
   2596     return XML_L("must not undeclare prefix");
   2597   case XML_ERROR_INCOMPLETE_PE:
   2598     return XML_L("incomplete markup in parameter entity");
   2599   case XML_ERROR_XML_DECL:
   2600     return XML_L("XML declaration not well-formed");
   2601   case XML_ERROR_TEXT_DECL:
   2602     return XML_L("text declaration not well-formed");
   2603   case XML_ERROR_PUBLICID:
   2604     return XML_L("illegal character(s) in public id");
   2605   case XML_ERROR_SUSPENDED:
   2606     return XML_L("parser suspended");
   2607   case XML_ERROR_NOT_SUSPENDED:
   2608     return XML_L("parser not suspended");
   2609   case XML_ERROR_ABORTED:
   2610     return XML_L("parsing aborted");
   2611   case XML_ERROR_FINISHED:
   2612     return XML_L("parsing finished");
   2613   case XML_ERROR_SUSPEND_PE:
   2614     return XML_L("cannot suspend in external parameter entity");
   2615   /* Added in 2.0.0. */
   2616   case XML_ERROR_RESERVED_PREFIX_XML:
   2617     return XML_L(
   2618         "reserved prefix (xml) must not be undeclared or bound to another namespace name");
   2619   case XML_ERROR_RESERVED_PREFIX_XMLNS:
   2620     return XML_L("reserved prefix (xmlns) must not be declared or undeclared");
   2621   case XML_ERROR_RESERVED_NAMESPACE_URI:
   2622     return XML_L(
   2623         "prefix must not be bound to one of the reserved namespace names");
   2624   /* Added in 2.2.5. */
   2625   case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
   2626     return XML_L("invalid argument");
   2627     /* Added in 2.3.0. */
   2628   case XML_ERROR_NO_BUFFER:
   2629     return XML_L(
   2630         "a successful prior call to function XML_GetBuffer is required");
   2631   /* Added in 2.4.0. */
   2632   case XML_ERROR_AMPLIFICATION_LIMIT_BREACH:
   2633     return XML_L(
   2634         "limit on input amplification factor (from DTD and entities) breached");
   2635   /* Added in 2.6.4. */
   2636   case XML_ERROR_NOT_STARTED:
   2637     return XML_L("parser not started");
   2638   }
   2639   return NULL;
   2640 }
   2641 
   2642 const XML_LChar *XMLCALL
   2643 XML_ExpatVersion(void) {
   2644   /* V1 is used to string-ize the version number. However, it would
   2645      string-ize the actual version macro *names* unless we get them
   2646      substituted before being passed to V1. CPP is defined to expand
   2647      a macro, then rescan for more expansions. Thus, we use V2 to expand
   2648      the version macros, then CPP will expand the resulting V1() macro
   2649      with the correct numerals. */
   2650   /* ### I'm assuming cpp is portable in this respect... */
   2651 
   2652 #define V1(a, b, c) XML_L(#a) XML_L(".") XML_L(#b) XML_L(".") XML_L(#c)
   2653 #define V2(a, b, c) XML_L("expat_") V1(a, b, c)
   2654 
   2655   return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
   2656 
   2657 #undef V1
   2658 #undef V2
   2659 }
   2660 
   2661 XML_Expat_Version XMLCALL
   2662 XML_ExpatVersionInfo(void) {
   2663   XML_Expat_Version version;
   2664 
   2665   version.major = XML_MAJOR_VERSION;
   2666   version.minor = XML_MINOR_VERSION;
   2667   version.micro = XML_MICRO_VERSION;
   2668 
   2669   return version;
   2670 }
   2671 
   2672 const XML_Feature *XMLCALL
   2673 XML_GetFeatureList(void) {
   2674   static const XML_Feature features[] = {
   2675       {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
   2676        sizeof(XML_Char)},
   2677       {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
   2678        sizeof(XML_LChar)},
   2679 #ifdef XML_UNICODE
   2680       {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
   2681 #endif
   2682 #ifdef XML_UNICODE_WCHAR_T
   2683       {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
   2684 #endif
   2685 #ifdef XML_DTD
   2686       {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
   2687 #endif
   2688 #if XML_CONTEXT_BYTES > 0
   2689       {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
   2690        XML_CONTEXT_BYTES},
   2691 #endif
   2692 #ifdef XML_MIN_SIZE
   2693       {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
   2694 #endif
   2695 #ifdef XML_NS
   2696       {XML_FEATURE_NS, XML_L("XML_NS"), 0},
   2697 #endif
   2698 #ifdef XML_LARGE_SIZE
   2699       {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
   2700 #endif
   2701 #ifdef XML_ATTR_INFO
   2702       {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
   2703 #endif
   2704 #if XML_GE == 1
   2705       /* Added in Expat 2.4.0 for XML_DTD defined and
   2706        * added in Expat 2.6.0 for XML_GE == 1. */
   2707       {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
   2708        XML_L("XML_BLAP_MAX_AMP"),
   2709        (long int)
   2710            EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT},
   2711       {XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
   2712        XML_L("XML_BLAP_ACT_THRES"),
   2713        EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
   2714       /* Added in Expat 2.6.0. */
   2715       {XML_FEATURE_GE, XML_L("XML_GE"), 0},
   2716 #endif
   2717       {XML_FEATURE_END, NULL, 0}};
   2718 
   2719   return features;
   2720 }
   2721 
   2722 #if XML_GE == 1
   2723 XML_Bool XMLCALL
   2724 XML_SetBillionLaughsAttackProtectionMaximumAmplification(
   2725     XML_Parser parser, float maximumAmplificationFactor) {
   2726   if ((parser == NULL) || (parser->m_parentParser != NULL)
   2727       || isnan(maximumAmplificationFactor)
   2728       || (maximumAmplificationFactor < 1.0f)) {
   2729     return XML_FALSE;
   2730   }
   2731   parser->m_accounting.maximumAmplificationFactor = maximumAmplificationFactor;
   2732   return XML_TRUE;
   2733 }
   2734 
   2735 XML_Bool XMLCALL
   2736 XML_SetBillionLaughsAttackProtectionActivationThreshold(
   2737     XML_Parser parser, unsigned long long activationThresholdBytes) {
   2738   if ((parser == NULL) || (parser->m_parentParser != NULL)) {
   2739     return XML_FALSE;
   2740   }
   2741   parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
   2742   return XML_TRUE;
   2743 }
   2744 #endif /* XML_GE == 1 */
   2745 
   2746 XML_Bool XMLCALL
   2747 XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
   2748   if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
   2749     parser->m_reparseDeferralEnabled = enabled;
   2750     return XML_TRUE;
   2751   }
   2752   return XML_FALSE;
   2753 }
   2754 
   2755 /* Initially tag->rawName always points into the parse buffer;
   2756    for those TAG instances opened while the current parse buffer was
   2757    processed, and not yet closed, we need to store tag->rawName in a more
   2758    permanent location, since the parse buffer is about to be discarded.
   2759 */
   2760 static XML_Bool
   2761 storeRawNames(XML_Parser parser) {
   2762   TAG *tag = parser->m_tagStack;
   2763   while (tag) {
   2764     int bufSize;
   2765     int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
   2766     size_t rawNameLen;
   2767     char *rawNameBuf = tag->buf + nameLen;
   2768     /* Stop if already stored.  Since m_tagStack is a stack, we can stop
   2769        at the first entry that has already been copied; everything
   2770        below it in the stack is already been accounted for in a
   2771        previous call to this function.
   2772     */
   2773     if (tag->rawName == rawNameBuf)
   2774       break;
   2775     /* For reuse purposes we need to ensure that the
   2776        size of tag->buf is a multiple of sizeof(XML_Char).
   2777     */
   2778     rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
   2779     /* Detect and prevent integer overflow. */
   2780     if (rawNameLen > (size_t)INT_MAX - nameLen)
   2781       return XML_FALSE;
   2782     bufSize = nameLen + (int)rawNameLen;
   2783     if (bufSize > tag->bufEnd - tag->buf) {
   2784       char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
   2785       if (temp == NULL)
   2786         return XML_FALSE;
   2787       /* if tag->name.str points to tag->buf (only when namespace
   2788          processing is off) then we have to update it
   2789       */
   2790       if (tag->name.str == (XML_Char *)tag->buf)
   2791         tag->name.str = (XML_Char *)temp;
   2792       /* if tag->name.localPart is set (when namespace processing is on)
   2793          then update it as well, since it will always point into tag->buf
   2794       */
   2795       if (tag->name.localPart)
   2796         tag->name.localPart
   2797             = (XML_Char *)temp + (tag->name.localPart - (XML_Char *)tag->buf);
   2798       tag->buf = temp;
   2799       tag->bufEnd = temp + bufSize;
   2800       rawNameBuf = temp + nameLen;
   2801     }
   2802     memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
   2803     tag->rawName = rawNameBuf;
   2804     tag = tag->parent;
   2805   }
   2806   return XML_TRUE;
   2807 }
   2808 
   2809 static enum XML_Error PTRCALL
   2810 contentProcessor(XML_Parser parser, const char *start, const char *end,
   2811                  const char **endPtr) {
   2812   enum XML_Error result = doContent(
   2813       parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, start, end,
   2814       endPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer,
   2815       XML_ACCOUNT_DIRECT);
   2816   if (result == XML_ERROR_NONE) {
   2817     if (! storeRawNames(parser))
   2818       return XML_ERROR_NO_MEMORY;
   2819   }
   2820   return result;
   2821 }
   2822 
   2823 static enum XML_Error PTRCALL
   2824 externalEntityInitProcessor(XML_Parser parser, const char *start,
   2825                             const char *end, const char **endPtr) {
   2826   enum XML_Error result = initializeEncoding(parser);
   2827   if (result != XML_ERROR_NONE)
   2828     return result;
   2829   parser->m_processor = externalEntityInitProcessor2;
   2830   return externalEntityInitProcessor2(parser, start, end, endPtr);
   2831 }
   2832 
   2833 static enum XML_Error PTRCALL
   2834 externalEntityInitProcessor2(XML_Parser parser, const char *start,
   2835                              const char *end, const char **endPtr) {
   2836   const char *next = start; /* XmlContentTok doesn't always set the last arg */
   2837   int tok = XmlContentTok(parser->m_encoding, start, end, &next);
   2838   switch (tok) {
   2839   case XML_TOK_BOM:
   2840 #if XML_GE == 1
   2841     if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
   2842                                   XML_ACCOUNT_DIRECT)) {
   2843       accountingOnAbort(parser);
   2844       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   2845     }
   2846 #endif /* XML_GE == 1 */
   2847 
   2848     /* If we are at the end of the buffer, this would cause the next stage,
   2849        i.e. externalEntityInitProcessor3, to pass control directly to
   2850        doContent (by detecting XML_TOK_NONE) without processing any xml text
   2851        declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
   2852     */
   2853     if (next == end && ! parser->m_parsingStatus.finalBuffer) {
   2854       *endPtr = next;
   2855       return XML_ERROR_NONE;
   2856     }
   2857     start = next;
   2858     break;
   2859   case XML_TOK_PARTIAL:
   2860     if (! parser->m_parsingStatus.finalBuffer) {
   2861       *endPtr = start;
   2862       return XML_ERROR_NONE;
   2863     }
   2864     parser->m_eventPtr = start;
   2865     return XML_ERROR_UNCLOSED_TOKEN;
   2866   case XML_TOK_PARTIAL_CHAR:
   2867     if (! parser->m_parsingStatus.finalBuffer) {
   2868       *endPtr = start;
   2869       return XML_ERROR_NONE;
   2870     }
   2871     parser->m_eventPtr = start;
   2872     return XML_ERROR_PARTIAL_CHAR;
   2873   }
   2874   parser->m_processor = externalEntityInitProcessor3;
   2875   return externalEntityInitProcessor3(parser, start, end, endPtr);
   2876 }
   2877 
   2878 static enum XML_Error PTRCALL
   2879 externalEntityInitProcessor3(XML_Parser parser, const char *start,
   2880                              const char *end, const char **endPtr) {
   2881   int tok;
   2882   const char *next = start; /* XmlContentTok doesn't always set the last arg */
   2883   parser->m_eventPtr = start;
   2884   tok = XmlContentTok(parser->m_encoding, start, end, &next);
   2885   /* Note: These bytes are accounted later in:
   2886            - processXmlDecl
   2887            - externalEntityContentProcessor
   2888   */
   2889   parser->m_eventEndPtr = next;
   2890 
   2891   switch (tok) {
   2892   case XML_TOK_XML_DECL: {
   2893     enum XML_Error result;
   2894     result = processXmlDecl(parser, 1, start, next);
   2895     if (result != XML_ERROR_NONE)
   2896       return result;
   2897     switch (parser->m_parsingStatus.parsing) {
   2898     case XML_SUSPENDED:
   2899       *endPtr = next;
   2900       return XML_ERROR_NONE;
   2901     case XML_FINISHED:
   2902       return XML_ERROR_ABORTED;
   2903     case XML_PARSING:
   2904       if (parser->m_reenter) {
   2905         return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
   2906       }
   2907       /* Fall through */
   2908     default:
   2909       start = next;
   2910     }
   2911   } break;
   2912   case XML_TOK_PARTIAL:
   2913     if (! parser->m_parsingStatus.finalBuffer) {
   2914       *endPtr = start;
   2915       return XML_ERROR_NONE;
   2916     }
   2917     return XML_ERROR_UNCLOSED_TOKEN;
   2918   case XML_TOK_PARTIAL_CHAR:
   2919     if (! parser->m_parsingStatus.finalBuffer) {
   2920       *endPtr = start;
   2921       return XML_ERROR_NONE;
   2922     }
   2923     return XML_ERROR_PARTIAL_CHAR;
   2924   }
   2925   parser->m_processor = externalEntityContentProcessor;
   2926   parser->m_tagLevel = 1;
   2927   return externalEntityContentProcessor(parser, start, end, endPtr);
   2928 }
   2929 
   2930 static enum XML_Error PTRCALL
   2931 externalEntityContentProcessor(XML_Parser parser, const char *start,
   2932                                const char *end, const char **endPtr) {
   2933   enum XML_Error result
   2934       = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
   2935                   (XML_Bool)! parser->m_parsingStatus.finalBuffer,
   2936                   XML_ACCOUNT_ENTITY_EXPANSION);
   2937   if (result == XML_ERROR_NONE) {
   2938     if (! storeRawNames(parser))
   2939       return XML_ERROR_NO_MEMORY;
   2940   }
   2941   return result;
   2942 }
   2943 
   2944 static enum XML_Error
   2945 doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
   2946           const char *s, const char *end, const char **nextPtr,
   2947           XML_Bool haveMore, enum XML_Account account) {
   2948   /* save one level of indirection */
   2949   DTD *const dtd = parser->m_dtd;
   2950 
   2951   const char **eventPP;
   2952   const char **eventEndPP;
   2953   if (enc == parser->m_encoding) {
   2954     eventPP = &parser->m_eventPtr;
   2955     eventEndPP = &parser->m_eventEndPtr;
   2956   } else {
   2957     eventPP = &(parser->m_openInternalEntities->internalEventPtr);
   2958     eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
   2959   }
   2960   *eventPP = s;
   2961 
   2962   for (;;) {
   2963     const char *next = s; /* XmlContentTok doesn't always set the last arg */
   2964     int tok = XmlContentTok(enc, s, end, &next);
   2965 #if XML_GE == 1
   2966     const char *accountAfter
   2967         = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
   2968               ? (haveMore ? s /* i.e. 0 bytes */ : end)
   2969               : next;
   2970     if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
   2971                                   account)) {
   2972       accountingOnAbort(parser);
   2973       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   2974     }
   2975 #endif
   2976     *eventEndPP = next;
   2977     switch (tok) {
   2978     case XML_TOK_TRAILING_CR:
   2979       if (haveMore) {
   2980         *nextPtr = s;
   2981         return XML_ERROR_NONE;
   2982       }
   2983       *eventEndPP = end;
   2984       if (parser->m_characterDataHandler) {
   2985         XML_Char c = 0xA;
   2986         parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
   2987       } else if (parser->m_defaultHandler)
   2988         reportDefault(parser, enc, s, end);
   2989       /* We are at the end of the final buffer, should we check for
   2990          XML_SUSPENDED, XML_FINISHED?
   2991       */
   2992       if (startTagLevel == 0)
   2993         return XML_ERROR_NO_ELEMENTS;
   2994       if (parser->m_tagLevel != startTagLevel)
   2995         return XML_ERROR_ASYNC_ENTITY;
   2996       *nextPtr = end;
   2997       return XML_ERROR_NONE;
   2998     case XML_TOK_NONE:
   2999       if (haveMore) {
   3000         *nextPtr = s;
   3001         return XML_ERROR_NONE;
   3002       }
   3003       if (startTagLevel > 0) {
   3004         if (parser->m_tagLevel != startTagLevel)
   3005           return XML_ERROR_ASYNC_ENTITY;
   3006         *nextPtr = s;
   3007         return XML_ERROR_NONE;
   3008       }
   3009       return XML_ERROR_NO_ELEMENTS;
   3010     case XML_TOK_INVALID:
   3011       *eventPP = next;
   3012       return XML_ERROR_INVALID_TOKEN;
   3013     case XML_TOK_PARTIAL:
   3014       if (haveMore) {
   3015         *nextPtr = s;
   3016         return XML_ERROR_NONE;
   3017       }
   3018       return XML_ERROR_UNCLOSED_TOKEN;
   3019     case XML_TOK_PARTIAL_CHAR:
   3020       if (haveMore) {
   3021         *nextPtr = s;
   3022         return XML_ERROR_NONE;
   3023       }
   3024       return XML_ERROR_PARTIAL_CHAR;
   3025     case XML_TOK_ENTITY_REF: {
   3026       const XML_Char *name;
   3027       ENTITY *entity;
   3028       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
   3029           enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
   3030       if (ch) {
   3031 #if XML_GE == 1
   3032         /* NOTE: We are replacing 4-6 characters original input for 1 character
   3033          *       so there is no amplification and hence recording without
   3034          *       protection. */
   3035         accountingDiffTolerated(parser, tok, (char *)&ch,
   3036                                 ((char *)&ch) + sizeof(XML_Char), __LINE__,
   3037                                 XML_ACCOUNT_ENTITY_EXPANSION);
   3038 #endif /* XML_GE == 1 */
   3039         if (parser->m_characterDataHandler)
   3040           parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
   3041         else if (parser->m_defaultHandler)
   3042           reportDefault(parser, enc, s, next);
   3043         break;
   3044       }
   3045       name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
   3046                              next - enc->minBytesPerChar);
   3047       if (! name)
   3048         return XML_ERROR_NO_MEMORY;
   3049       entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
   3050       poolDiscard(&dtd->pool);
   3051       /* First, determine if a check for an existing declaration is needed;
   3052          if yes, check that the entity exists, and that it is internal,
   3053          otherwise call the skipped entity or default handler.
   3054       */
   3055       if (! dtd->hasParamEntityRefs || dtd->standalone) {
   3056         if (! entity)
   3057           return XML_ERROR_UNDEFINED_ENTITY;
   3058         else if (! entity->is_internal)
   3059           return XML_ERROR_ENTITY_DECLARED_IN_PE;
   3060       } else if (! entity) {
   3061         if (parser->m_skippedEntityHandler)
   3062           parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
   3063         else if (parser->m_defaultHandler)
   3064           reportDefault(parser, enc, s, next);
   3065         break;
   3066       }
   3067       if (entity->open)
   3068         return XML_ERROR_RECURSIVE_ENTITY_REF;
   3069       if (entity->notation)
   3070         return XML_ERROR_BINARY_ENTITY_REF;
   3071       if (entity->textPtr) {
   3072         enum XML_Error result;
   3073         if (! parser->m_defaultExpandInternalEntities) {
   3074           if (parser->m_skippedEntityHandler)
   3075             parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name,
   3076                                            0);
   3077           else if (parser->m_defaultHandler)
   3078             reportDefault(parser, enc, s, next);
   3079           break;
   3080         }
   3081         result = processEntity(parser, entity, XML_FALSE, ENTITY_INTERNAL);
   3082         if (result != XML_ERROR_NONE)
   3083           return result;
   3084       } else if (parser->m_externalEntityRefHandler) {
   3085         const XML_Char *context;
   3086         entity->open = XML_TRUE;
   3087         context = getContext(parser);
   3088         entity->open = XML_FALSE;
   3089         if (! context)
   3090           return XML_ERROR_NO_MEMORY;
   3091         if (! parser->m_externalEntityRefHandler(
   3092                 parser->m_externalEntityRefHandlerArg, context, entity->base,
   3093                 entity->systemId, entity->publicId))
   3094           return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
   3095         poolDiscard(&parser->m_tempPool);
   3096       } else if (parser->m_defaultHandler)
   3097         reportDefault(parser, enc, s, next);
   3098       break;
   3099     }
   3100     case XML_TOK_START_TAG_NO_ATTS:
   3101       /* fall through */
   3102     case XML_TOK_START_TAG_WITH_ATTS: {
   3103       TAG *tag;
   3104       enum XML_Error result;
   3105       XML_Char *toPtr;
   3106       if (parser->m_freeTagList) {
   3107         tag = parser->m_freeTagList;
   3108         parser->m_freeTagList = parser->m_freeTagList->parent;
   3109       } else {
   3110         tag = (TAG *)MALLOC(parser, sizeof(TAG));
   3111         if (! tag)
   3112           return XML_ERROR_NO_MEMORY;
   3113         tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE);
   3114         if (! tag->buf) {
   3115           FREE(parser, tag);
   3116           return XML_ERROR_NO_MEMORY;
   3117         }
   3118         tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
   3119       }
   3120       tag->bindings = NULL;
   3121       tag->parent = parser->m_tagStack;
   3122       parser->m_tagStack = tag;
   3123       tag->name.localPart = NULL;
   3124       tag->name.prefix = NULL;
   3125       tag->rawName = s + enc->minBytesPerChar;
   3126       tag->rawNameLength = XmlNameLength(enc, tag->rawName);
   3127       ++parser->m_tagLevel;
   3128       {
   3129         const char *rawNameEnd = tag->rawName + tag->rawNameLength;
   3130         const char *fromPtr = tag->rawName;
   3131         toPtr = (XML_Char *)tag->buf;
   3132         for (;;) {
   3133           int bufSize;
   3134           int convLen;
   3135           const enum XML_Convert_Result convert_res
   3136               = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr,
   3137                            (ICHAR *)tag->bufEnd - 1);
   3138           convLen = (int)(toPtr - (XML_Char *)tag->buf);
   3139           if ((fromPtr >= rawNameEnd)
   3140               || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
   3141             tag->name.strLen = convLen;
   3142             break;
   3143           }
   3144           bufSize = (int)(tag->bufEnd - tag->buf) << 1;
   3145           {
   3146             char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
   3147             if (temp == NULL)
   3148               return XML_ERROR_NO_MEMORY;
   3149             tag->buf = temp;
   3150             tag->bufEnd = temp + bufSize;
   3151             toPtr = (XML_Char *)temp + convLen;
   3152           }
   3153         }
   3154       }
   3155       tag->name.str = (XML_Char *)tag->buf;
   3156       *toPtr = XML_T('\0');
   3157       result
   3158           = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
   3159       if (result)
   3160         return result;
   3161       if (parser->m_startElementHandler)
   3162         parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
   3163                                       (const XML_Char **)parser->m_atts);
   3164       else if (parser->m_defaultHandler)
   3165         reportDefault(parser, enc, s, next);
   3166       poolClear(&parser->m_tempPool);
   3167       break;
   3168     }
   3169     case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
   3170       /* fall through */
   3171     case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: {
   3172       const char *rawName = s + enc->minBytesPerChar;
   3173       enum XML_Error result;
   3174       BINDING *bindings = NULL;
   3175       XML_Bool noElmHandlers = XML_TRUE;
   3176       TAG_NAME name;
   3177       name.str = poolStoreString(&parser->m_tempPool, enc, rawName,
   3178                                  rawName + XmlNameLength(enc, rawName));
   3179       if (! name.str)
   3180         return XML_ERROR_NO_MEMORY;
   3181       poolFinish(&parser->m_tempPool);
   3182       result = storeAtts(parser, enc, s, &name, &bindings,
   3183                          XML_ACCOUNT_NONE /* token spans whole start tag */);
   3184       if (result != XML_ERROR_NONE) {
   3185         freeBindings(parser, bindings);
   3186         return result;
   3187       }
   3188       poolFinish(&parser->m_tempPool);
   3189       if (parser->m_startElementHandler) {
   3190         parser->m_startElementHandler(parser->m_handlerArg, name.str,
   3191                                       (const XML_Char **)parser->m_atts);
   3192         noElmHandlers = XML_FALSE;
   3193       }
   3194       if (parser->m_endElementHandler) {
   3195         if (parser->m_startElementHandler)
   3196           *eventPP = *eventEndPP;
   3197         parser->m_endElementHandler(parser->m_handlerArg, name.str);
   3198         noElmHandlers = XML_FALSE;
   3199       }
   3200       if (noElmHandlers && parser->m_defaultHandler)
   3201         reportDefault(parser, enc, s, next);
   3202       poolClear(&parser->m_tempPool);
   3203       freeBindings(parser, bindings);
   3204     }
   3205       if ((parser->m_tagLevel == 0)
   3206           && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
   3207         if (parser->m_parsingStatus.parsing == XML_SUSPENDED
   3208             || (parser->m_parsingStatus.parsing == XML_PARSING
   3209                 && parser->m_reenter))
   3210           parser->m_processor = epilogProcessor;
   3211         else
   3212           return epilogProcessor(parser, next, end, nextPtr);
   3213       }
   3214       break;
   3215     case XML_TOK_END_TAG:
   3216       if (parser->m_tagLevel == startTagLevel)
   3217         return XML_ERROR_ASYNC_ENTITY;
   3218       else {
   3219         int len;
   3220         const char *rawName;
   3221         TAG *tag = parser->m_tagStack;
   3222         rawName = s + enc->minBytesPerChar * 2;
   3223         len = XmlNameLength(enc, rawName);
   3224         if (len != tag->rawNameLength
   3225             || memcmp(tag->rawName, rawName, len) != 0) {
   3226           *eventPP = rawName;
   3227           return XML_ERROR_TAG_MISMATCH;
   3228         }
   3229         parser->m_tagStack = tag->parent;
   3230         tag->parent = parser->m_freeTagList;
   3231         parser->m_freeTagList = tag;
   3232         --parser->m_tagLevel;
   3233         if (parser->m_endElementHandler) {
   3234           const XML_Char *localPart;
   3235           const XML_Char *prefix;
   3236           XML_Char *uri;
   3237           localPart = tag->name.localPart;
   3238           if (parser->m_ns && localPart) {
   3239             /* localPart and prefix may have been overwritten in
   3240                tag->name.str, since this points to the binding->uri
   3241                buffer which gets reused; so we have to add them again
   3242             */
   3243             uri = (XML_Char *)tag->name.str + tag->name.uriLen;
   3244             /* don't need to check for space - already done in storeAtts() */
   3245             while (*localPart)
   3246               *uri++ = *localPart++;
   3247             prefix = tag->name.prefix;
   3248             if (parser->m_ns_triplets && prefix) {
   3249               *uri++ = parser->m_namespaceSeparator;
   3250               while (*prefix)
   3251                 *uri++ = *prefix++;
   3252             }
   3253             *uri = XML_T('\0');
   3254           }
   3255           parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
   3256         } else if (parser->m_defaultHandler)
   3257           reportDefault(parser, enc, s, next);
   3258         while (tag->bindings) {
   3259           BINDING *b = tag->bindings;
   3260           if (parser->m_endNamespaceDeclHandler)
   3261             parser->m_endNamespaceDeclHandler(parser->m_handlerArg,
   3262                                               b->prefix->name);
   3263           tag->bindings = tag->bindings->nextTagBinding;
   3264           b->nextTagBinding = parser->m_freeBindingList;
   3265           parser->m_freeBindingList = b;
   3266           b->prefix->binding = b->prevPrefixBinding;
   3267         }
   3268         if ((parser->m_tagLevel == 0)
   3269             && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
   3270           if (parser->m_parsingStatus.parsing == XML_SUSPENDED
   3271               || (parser->m_parsingStatus.parsing == XML_PARSING
   3272                   && parser->m_reenter))
   3273             parser->m_processor = epilogProcessor;
   3274           else
   3275             return epilogProcessor(parser, next, end, nextPtr);
   3276         }
   3277       }
   3278       break;
   3279     case XML_TOK_CHAR_REF: {
   3280       int n = XmlCharRefNumber(enc, s);
   3281       if (n < 0)
   3282         return XML_ERROR_BAD_CHAR_REF;
   3283       if (parser->m_characterDataHandler) {
   3284         XML_Char buf[XML_ENCODE_MAX];
   3285         parser->m_characterDataHandler(parser->m_handlerArg, buf,
   3286                                        XmlEncode(n, (ICHAR *)buf));
   3287       } else if (parser->m_defaultHandler)
   3288         reportDefault(parser, enc, s, next);
   3289     } break;
   3290     case XML_TOK_XML_DECL:
   3291       return XML_ERROR_MISPLACED_XML_PI;
   3292     case XML_TOK_DATA_NEWLINE:
   3293       if (parser->m_characterDataHandler) {
   3294         XML_Char c = 0xA;
   3295         parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
   3296       } else if (parser->m_defaultHandler)
   3297         reportDefault(parser, enc, s, next);
   3298       break;
   3299     case XML_TOK_CDATA_SECT_OPEN: {
   3300       enum XML_Error result;
   3301       if (parser->m_startCdataSectionHandler)
   3302         parser->m_startCdataSectionHandler(parser->m_handlerArg);
   3303       /* BEGIN disabled code */
   3304       /* Suppose you doing a transformation on a document that involves
   3305          changing only the character data.  You set up a defaultHandler
   3306          and a characterDataHandler.  The defaultHandler simply copies
   3307          characters through.  The characterDataHandler does the
   3308          transformation and writes the characters out escaping them as
   3309          necessary.  This case will fail to work if we leave out the
   3310          following two lines (because & and < inside CDATA sections will
   3311          be incorrectly escaped).
   3312 
   3313          However, now we have a start/endCdataSectionHandler, so it seems
   3314          easier to let the user deal with this.
   3315       */
   3316       else if ((0) && parser->m_characterDataHandler)
   3317         parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
   3318                                        0);
   3319       /* END disabled code */
   3320       else if (parser->m_defaultHandler)
   3321         reportDefault(parser, enc, s, next);
   3322       result
   3323           = doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
   3324       if (result != XML_ERROR_NONE)
   3325         return result;
   3326       else if (! next) {
   3327         parser->m_processor = cdataSectionProcessor;
   3328         return result;
   3329       }
   3330     } break;
   3331     case XML_TOK_TRAILING_RSQB:
   3332       if (haveMore) {
   3333         *nextPtr = s;
   3334         return XML_ERROR_NONE;
   3335       }
   3336       if (parser->m_characterDataHandler) {
   3337         if (MUST_CONVERT(enc, s)) {
   3338           ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
   3339           XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
   3340           parser->m_characterDataHandler(
   3341               parser->m_handlerArg, parser->m_dataBuf,
   3342               (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
   3343         } else
   3344           parser->m_characterDataHandler(
   3345               parser->m_handlerArg, (const XML_Char *)s,
   3346               (int)((const XML_Char *)end - (const XML_Char *)s));
   3347       } else if (parser->m_defaultHandler)
   3348         reportDefault(parser, enc, s, end);
   3349       /* We are at the end of the final buffer, should we check for
   3350          XML_SUSPENDED, XML_FINISHED?
   3351       */
   3352       if (startTagLevel == 0) {
   3353         *eventPP = end;
   3354         return XML_ERROR_NO_ELEMENTS;
   3355       }
   3356       if (parser->m_tagLevel != startTagLevel) {
   3357         *eventPP = end;
   3358         return XML_ERROR_ASYNC_ENTITY;
   3359       }
   3360       *nextPtr = end;
   3361       return XML_ERROR_NONE;
   3362     case XML_TOK_DATA_CHARS: {
   3363       XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
   3364       if (charDataHandler) {
   3365         if (MUST_CONVERT(enc, s)) {
   3366           for (;;) {
   3367             ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
   3368             const enum XML_Convert_Result convert_res = XmlConvert(
   3369                 enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
   3370             *eventEndPP = s;
   3371             charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
   3372                             (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
   3373             if ((convert_res == XML_CONVERT_COMPLETED)
   3374                 || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
   3375               break;
   3376             *eventPP = s;
   3377           }
   3378         } else
   3379           charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
   3380                           (int)((const XML_Char *)next - (const XML_Char *)s));
   3381       } else if (parser->m_defaultHandler)
   3382         reportDefault(parser, enc, s, next);
   3383     } break;
   3384     case XML_TOK_PI:
   3385       if (! reportProcessingInstruction(parser, enc, s, next))
   3386         return XML_ERROR_NO_MEMORY;
   3387       break;
   3388     case XML_TOK_COMMENT:
   3389       if (! reportComment(parser, enc, s, next))
   3390         return XML_ERROR_NO_MEMORY;
   3391       break;
   3392     default:
   3393       /* All of the tokens produced by XmlContentTok() have their own
   3394        * explicit cases, so this default is not strictly necessary.
   3395        * However it is a useful safety net, so we retain the code and
   3396        * simply exclude it from the coverage tests.
   3397        *
   3398        * LCOV_EXCL_START
   3399        */
   3400       if (parser->m_defaultHandler)
   3401         reportDefault(parser, enc, s, next);
   3402       break;
   3403       /* LCOV_EXCL_STOP */
   3404     }
   3405     switch (parser->m_parsingStatus.parsing) {
   3406     case XML_SUSPENDED:
   3407       *eventPP = next;
   3408       *nextPtr = next;
   3409       return XML_ERROR_NONE;
   3410     case XML_FINISHED:
   3411       *eventPP = next;
   3412       return XML_ERROR_ABORTED;
   3413     case XML_PARSING:
   3414       if (parser->m_reenter) {
   3415         *nextPtr = next;
   3416         return XML_ERROR_NONE;
   3417       }
   3418       /* Fall through */
   3419     default:;
   3420       *eventPP = s = next;
   3421     }
   3422   }
   3423   /* not reached */
   3424 }
   3425 
   3426 /* This function does not call free() on the allocated memory, merely
   3427  * moving it to the parser's m_freeBindingList where it can be freed or
   3428  * reused as appropriate.
   3429  */
   3430 static void
   3431 freeBindings(XML_Parser parser, BINDING *bindings) {
   3432   while (bindings) {
   3433     BINDING *b = bindings;
   3434 
   3435     /* m_startNamespaceDeclHandler will have been called for this
   3436      * binding in addBindings(), so call the end handler now.
   3437      */
   3438     if (parser->m_endNamespaceDeclHandler)
   3439       parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
   3440 
   3441     bindings = bindings->nextTagBinding;
   3442     b->nextTagBinding = parser->m_freeBindingList;
   3443     parser->m_freeBindingList = b;
   3444     b->prefix->binding = b->prevPrefixBinding;
   3445   }
   3446 }
   3447 
   3448 /* Precondition: all arguments must be non-NULL;
   3449    Purpose:
   3450    - normalize attributes
   3451    - check attributes for well-formedness
   3452    - generate namespace aware attribute names (URI, prefix)
   3453    - build list of attributes for startElementHandler
   3454    - default attributes
   3455    - process namespace declarations (check and report them)
   3456    - generate namespace aware element name (URI, prefix)
   3457 */
   3458 static enum XML_Error
   3459 storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
   3460           TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
   3461           enum XML_Account account) {
   3462   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   3463   ELEMENT_TYPE *elementType;
   3464   int nDefaultAtts;
   3465   const XML_Char **appAtts; /* the attribute list for the application */
   3466   int attIndex = 0;
   3467   int prefixLen;
   3468   int i;
   3469   int n;
   3470   XML_Char *uri;
   3471   int nPrefixes = 0;
   3472   BINDING *binding;
   3473   const XML_Char *localPart;
   3474 
   3475   /* lookup the element type name */
   3476   elementType
   3477       = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0);
   3478   if (! elementType) {
   3479     const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
   3480     if (! name)
   3481       return XML_ERROR_NO_MEMORY;
   3482     elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
   3483                                          sizeof(ELEMENT_TYPE));
   3484     if (! elementType)
   3485       return XML_ERROR_NO_MEMORY;
   3486     if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
   3487       return XML_ERROR_NO_MEMORY;
   3488   }
   3489   nDefaultAtts = elementType->nDefaultAtts;
   3490 
   3491   /* get the attributes from the tokenizer */
   3492   n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
   3493 
   3494   /* Detect and prevent integer overflow */
   3495   if (n > INT_MAX - nDefaultAtts) {
   3496     return XML_ERROR_NO_MEMORY;
   3497   }
   3498 
   3499   if (n + nDefaultAtts > parser->m_attsSize) {
   3500     int oldAttsSize = parser->m_attsSize;
   3501     ATTRIBUTE *temp;
   3502 #ifdef XML_ATTR_INFO
   3503     XML_AttrInfo *temp2;
   3504 #endif
   3505 
   3506     /* Detect and prevent integer overflow */
   3507     if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
   3508         || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
   3509       return XML_ERROR_NO_MEMORY;
   3510     }
   3511 
   3512     parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
   3513 
   3514     /* Detect and prevent integer overflow.
   3515      * The preprocessor guard addresses the "always false" warning
   3516      * from -Wtype-limits on platforms where
   3517      * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   3518 #if UINT_MAX >= SIZE_MAX
   3519     if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
   3520       parser->m_attsSize = oldAttsSize;
   3521       return XML_ERROR_NO_MEMORY;
   3522     }
   3523 #endif
   3524 
   3525     temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
   3526                                 parser->m_attsSize * sizeof(ATTRIBUTE));
   3527     if (temp == NULL) {
   3528       parser->m_attsSize = oldAttsSize;
   3529       return XML_ERROR_NO_MEMORY;
   3530     }
   3531     parser->m_atts = temp;
   3532 #ifdef XML_ATTR_INFO
   3533     /* Detect and prevent integer overflow.
   3534      * The preprocessor guard addresses the "always false" warning
   3535      * from -Wtype-limits on platforms where
   3536      * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   3537 #  if UINT_MAX >= SIZE_MAX
   3538     if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
   3539       parser->m_attsSize = oldAttsSize;
   3540       return XML_ERROR_NO_MEMORY;
   3541     }
   3542 #  endif
   3543 
   3544     temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
   3545                                     parser->m_attsSize * sizeof(XML_AttrInfo));
   3546     if (temp2 == NULL) {
   3547       parser->m_attsSize = oldAttsSize;
   3548       return XML_ERROR_NO_MEMORY;
   3549     }
   3550     parser->m_attInfo = temp2;
   3551 #endif
   3552     if (n > oldAttsSize)
   3553       XmlGetAttributes(enc, attStr, n, parser->m_atts);
   3554   }
   3555 
   3556   appAtts = (const XML_Char **)parser->m_atts;
   3557   for (i = 0; i < n; i++) {
   3558     ATTRIBUTE *currAtt = &parser->m_atts[i];
   3559 #ifdef XML_ATTR_INFO
   3560     XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
   3561 #endif
   3562     /* add the name and value to the attribute list */
   3563     ATTRIBUTE_ID *attId
   3564         = getAttributeId(parser, enc, currAtt->name,
   3565                          currAtt->name + XmlNameLength(enc, currAtt->name));
   3566     if (! attId)
   3567       return XML_ERROR_NO_MEMORY;
   3568 #ifdef XML_ATTR_INFO
   3569     currAttInfo->nameStart
   3570         = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name);
   3571     currAttInfo->nameEnd
   3572         = currAttInfo->nameStart + XmlNameLength(enc, currAtt->name);
   3573     currAttInfo->valueStart = parser->m_parseEndByteIndex
   3574                               - (parser->m_parseEndPtr - currAtt->valuePtr);
   3575     currAttInfo->valueEnd = parser->m_parseEndByteIndex
   3576                             - (parser->m_parseEndPtr - currAtt->valueEnd);
   3577 #endif
   3578     /* Detect duplicate attributes by their QNames. This does not work when
   3579        namespace processing is turned on and different prefixes for the same
   3580        namespace are used. For this case we have a check further down.
   3581     */
   3582     if ((attId->name)[-1]) {
   3583       if (enc == parser->m_encoding)
   3584         parser->m_eventPtr = parser->m_atts[i].name;
   3585       return XML_ERROR_DUPLICATE_ATTRIBUTE;
   3586     }
   3587     (attId->name)[-1] = 1;
   3588     appAtts[attIndex++] = attId->name;
   3589     if (! parser->m_atts[i].normalized) {
   3590       enum XML_Error result;
   3591       XML_Bool isCdata = XML_TRUE;
   3592 
   3593       /* figure out whether declared as other than CDATA */
   3594       if (attId->maybeTokenized) {
   3595         int j;
   3596         for (j = 0; j < nDefaultAtts; j++) {
   3597           if (attId == elementType->defaultAtts[j].id) {
   3598             isCdata = elementType->defaultAtts[j].isCdata;
   3599             break;
   3600           }
   3601         }
   3602       }
   3603 
   3604       /* normalize the attribute value */
   3605       result = storeAttributeValue(
   3606           parser, enc, isCdata, parser->m_atts[i].valuePtr,
   3607           parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
   3608       if (result)
   3609         return result;
   3610       appAtts[attIndex] = poolStart(&parser->m_tempPool);
   3611       poolFinish(&parser->m_tempPool);
   3612     } else {
   3613       /* the value did not need normalizing */
   3614       appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc,
   3615                                           parser->m_atts[i].valuePtr,
   3616                                           parser->m_atts[i].valueEnd);
   3617       if (appAtts[attIndex] == 0)
   3618         return XML_ERROR_NO_MEMORY;
   3619       poolFinish(&parser->m_tempPool);
   3620     }
   3621     /* handle prefixed attribute names */
   3622     if (attId->prefix) {
   3623       if (attId->xmlns) {
   3624         /* deal with namespace declarations here */
   3625         enum XML_Error result = addBinding(parser, attId->prefix, attId,
   3626                                            appAtts[attIndex], bindingsPtr);
   3627         if (result)
   3628           return result;
   3629         --attIndex;
   3630       } else {
   3631         /* deal with other prefixed names later */
   3632         attIndex++;
   3633         nPrefixes++;
   3634         (attId->name)[-1] = 2;
   3635       }
   3636     } else
   3637       attIndex++;
   3638   }
   3639 
   3640   /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
   3641   parser->m_nSpecifiedAtts = attIndex;
   3642   if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
   3643     for (i = 0; i < attIndex; i += 2)
   3644       if (appAtts[i] == elementType->idAtt->name) {
   3645         parser->m_idAttIndex = i;
   3646         break;
   3647       }
   3648   } else
   3649     parser->m_idAttIndex = -1;
   3650 
   3651   /* do attribute defaulting */
   3652   for (i = 0; i < nDefaultAtts; i++) {
   3653     const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
   3654     if (! (da->id->name)[-1] && da->value) {
   3655       if (da->id->prefix) {
   3656         if (da->id->xmlns) {
   3657           enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
   3658                                              da->value, bindingsPtr);
   3659           if (result)
   3660             return result;
   3661         } else {
   3662           (da->id->name)[-1] = 2;
   3663           nPrefixes++;
   3664           appAtts[attIndex++] = da->id->name;
   3665           appAtts[attIndex++] = da->value;
   3666         }
   3667       } else {
   3668         (da->id->name)[-1] = 1;
   3669         appAtts[attIndex++] = da->id->name;
   3670         appAtts[attIndex++] = da->value;
   3671       }
   3672     }
   3673   }
   3674   appAtts[attIndex] = 0;
   3675 
   3676   /* expand prefixed attribute names, check for duplicates,
   3677      and clear flags that say whether attributes were specified */
   3678   i = 0;
   3679   if (nPrefixes) {
   3680     int j; /* hash table index */
   3681     unsigned long version = parser->m_nsAttsVersion;
   3682 
   3683     /* Detect and prevent invalid shift */
   3684     if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
   3685       return XML_ERROR_NO_MEMORY;
   3686     }
   3687 
   3688     unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
   3689     unsigned char oldNsAttsPower = parser->m_nsAttsPower;
   3690     /* size of hash table must be at least 2 * (# of prefixed attributes) */
   3691     if ((nPrefixes << 1)
   3692         >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
   3693       NS_ATT *temp;
   3694       /* hash table size must also be a power of 2 and >= 8 */
   3695       while (nPrefixes >> parser->m_nsAttsPower++)
   3696         ;
   3697       if (parser->m_nsAttsPower < 3)
   3698         parser->m_nsAttsPower = 3;
   3699 
   3700       /* Detect and prevent invalid shift */
   3701       if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
   3702         /* Restore actual size of memory in m_nsAtts */
   3703         parser->m_nsAttsPower = oldNsAttsPower;
   3704         return XML_ERROR_NO_MEMORY;
   3705       }
   3706 
   3707       nsAttsSize = 1u << parser->m_nsAttsPower;
   3708 
   3709       /* Detect and prevent integer overflow.
   3710        * The preprocessor guard addresses the "always false" warning
   3711        * from -Wtype-limits on platforms where
   3712        * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   3713 #if UINT_MAX >= SIZE_MAX
   3714       if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
   3715         /* Restore actual size of memory in m_nsAtts */
   3716         parser->m_nsAttsPower = oldNsAttsPower;
   3717         return XML_ERROR_NO_MEMORY;
   3718       }
   3719 #endif
   3720 
   3721       temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
   3722                                nsAttsSize * sizeof(NS_ATT));
   3723       if (! temp) {
   3724         /* Restore actual size of memory in m_nsAtts */
   3725         parser->m_nsAttsPower = oldNsAttsPower;
   3726         return XML_ERROR_NO_MEMORY;
   3727       }
   3728       parser->m_nsAtts = temp;
   3729       version = 0; /* force re-initialization of m_nsAtts hash table */
   3730     }
   3731     /* using a version flag saves us from initializing m_nsAtts every time */
   3732     if (! version) { /* initialize version flags when version wraps around */
   3733       version = INIT_ATTS_VERSION;
   3734       for (j = nsAttsSize; j != 0;)
   3735         parser->m_nsAtts[--j].version = version;
   3736     }
   3737     parser->m_nsAttsVersion = --version;
   3738 
   3739     /* expand prefixed names and check for duplicates */
   3740     for (; i < attIndex; i += 2) {
   3741       const XML_Char *s = appAtts[i];
   3742       if (s[-1] == 2) { /* prefixed */
   3743         ATTRIBUTE_ID *id;
   3744         const BINDING *b;
   3745         unsigned long uriHash;
   3746         struct siphash sip_state;
   3747         struct sipkey sip_key;
   3748 
   3749         copy_salt_to_sipkey(parser, &sip_key);
   3750         sip24_init(&sip_state, &sip_key);
   3751 
   3752         ((XML_Char *)s)[-1] = 0; /* clear flag */
   3753         id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
   3754         if (! id || ! id->prefix) {
   3755           /* This code is walking through the appAtts array, dealing
   3756            * with (in this case) a prefixed attribute name.  To be in
   3757            * the array, the attribute must have already been bound, so
   3758            * has to have passed through the hash table lookup once
   3759            * already.  That implies that an entry for it already
   3760            * exists, so the lookup above will return a pointer to
   3761            * already allocated memory.  There is no opportunaity for
   3762            * the allocator to fail, so the condition above cannot be
   3763            * fulfilled.
   3764            *
   3765            * Since it is difficult to be certain that the above
   3766            * analysis is complete, we retain the test and merely
   3767            * remove the code from coverage tests.
   3768            */
   3769           return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
   3770         }
   3771         b = id->prefix->binding;
   3772         if (! b)
   3773           return XML_ERROR_UNBOUND_PREFIX;
   3774 
   3775         for (j = 0; j < b->uriLen; j++) {
   3776           const XML_Char c = b->uri[j];
   3777           if (! poolAppendChar(&parser->m_tempPool, c))
   3778             return XML_ERROR_NO_MEMORY;
   3779         }
   3780 
   3781         sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
   3782 
   3783         while (*s++ != XML_T(ASCII_COLON))
   3784           ;
   3785 
   3786         sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
   3787 
   3788         do { /* copies null terminator */
   3789           if (! poolAppendChar(&parser->m_tempPool, *s))
   3790             return XML_ERROR_NO_MEMORY;
   3791         } while (*s++);
   3792 
   3793         uriHash = (unsigned long)sip24_final(&sip_state);
   3794 
   3795         { /* Check hash table for duplicate of expanded name (uriName).
   3796              Derived from code in lookup(parser, HASH_TABLE *table, ...).
   3797           */
   3798           unsigned char step = 0;
   3799           unsigned long mask = nsAttsSize - 1;
   3800           j = uriHash & mask; /* index into hash table */
   3801           while (parser->m_nsAtts[j].version == version) {
   3802             /* for speed we compare stored hash values first */
   3803             if (uriHash == parser->m_nsAtts[j].hash) {
   3804               const XML_Char *s1 = poolStart(&parser->m_tempPool);
   3805               const XML_Char *s2 = parser->m_nsAtts[j].uriName;
   3806               /* s1 is null terminated, but not s2 */
   3807               for (; *s1 == *s2 && *s1 != 0; s1++, s2++)
   3808                 ;
   3809               if (*s1 == 0)
   3810                 return XML_ERROR_DUPLICATE_ATTRIBUTE;
   3811             }
   3812             if (! step)
   3813               step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower);
   3814             j < step ? (j += nsAttsSize - step) : (j -= step);
   3815           }
   3816         }
   3817 
   3818         if (parser->m_ns_triplets) { /* append namespace separator and prefix */
   3819           parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator;
   3820           s = b->prefix->name;
   3821           do {
   3822             if (! poolAppendChar(&parser->m_tempPool, *s))
   3823               return XML_ERROR_NO_MEMORY;
   3824           } while (*s++);
   3825         }
   3826 
   3827         /* store expanded name in attribute list */
   3828         s = poolStart(&parser->m_tempPool);
   3829         poolFinish(&parser->m_tempPool);
   3830         appAtts[i] = s;
   3831 
   3832         /* fill empty slot with new version, uriName and hash value */
   3833         parser->m_nsAtts[j].version = version;
   3834         parser->m_nsAtts[j].hash = uriHash;
   3835         parser->m_nsAtts[j].uriName = s;
   3836 
   3837         if (! --nPrefixes) {
   3838           i += 2;
   3839           break;
   3840         }
   3841       } else                     /* not prefixed */
   3842         ((XML_Char *)s)[-1] = 0; /* clear flag */
   3843     }
   3844   }
   3845   /* clear flags for the remaining attributes */
   3846   for (; i < attIndex; i += 2)
   3847     ((XML_Char *)(appAtts[i]))[-1] = 0;
   3848   for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
   3849     binding->attId->name[-1] = 0;
   3850 
   3851   if (! parser->m_ns)
   3852     return XML_ERROR_NONE;
   3853 
   3854   /* expand the element type name */
   3855   if (elementType->prefix) {
   3856     binding = elementType->prefix->binding;
   3857     if (! binding)
   3858       return XML_ERROR_UNBOUND_PREFIX;
   3859     localPart = tagNamePtr->str;
   3860     while (*localPart++ != XML_T(ASCII_COLON))
   3861       ;
   3862   } else if (dtd->defaultPrefix.binding) {
   3863     binding = dtd->defaultPrefix.binding;
   3864     localPart = tagNamePtr->str;
   3865   } else
   3866     return XML_ERROR_NONE;
   3867   prefixLen = 0;
   3868   if (parser->m_ns_triplets && binding->prefix->name) {
   3869     for (; binding->prefix->name[prefixLen++];)
   3870       ; /* prefixLen includes null terminator */
   3871   }
   3872   tagNamePtr->localPart = localPart;
   3873   tagNamePtr->uriLen = binding->uriLen;
   3874   tagNamePtr->prefix = binding->prefix->name;
   3875   tagNamePtr->prefixLen = prefixLen;
   3876   for (i = 0; localPart[i++];)
   3877     ; /* i includes null terminator */
   3878 
   3879   /* Detect and prevent integer overflow */
   3880   if (binding->uriLen > INT_MAX - prefixLen
   3881       || i > INT_MAX - (binding->uriLen + prefixLen)) {
   3882     return XML_ERROR_NO_MEMORY;
   3883   }
   3884 
   3885   n = i + binding->uriLen + prefixLen;
   3886   if (n > binding->uriAlloc) {
   3887     TAG *p;
   3888 
   3889     /* Detect and prevent integer overflow */
   3890     if (n > INT_MAX - EXPAND_SPARE) {
   3891       return XML_ERROR_NO_MEMORY;
   3892     }
   3893     /* Detect and prevent integer overflow.
   3894      * The preprocessor guard addresses the "always false" warning
   3895      * from -Wtype-limits on platforms where
   3896      * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   3897 #if UINT_MAX >= SIZE_MAX
   3898     if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
   3899       return XML_ERROR_NO_MEMORY;
   3900     }
   3901 #endif
   3902 
   3903     uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
   3904     if (! uri)
   3905       return XML_ERROR_NO_MEMORY;
   3906     binding->uriAlloc = n + EXPAND_SPARE;
   3907     memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
   3908     for (p = parser->m_tagStack; p; p = p->parent)
   3909       if (p->name.str == binding->uri)
   3910         p->name.str = uri;
   3911     FREE(parser, binding->uri);
   3912     binding->uri = uri;
   3913   }
   3914   /* if m_namespaceSeparator != '\0' then uri includes it already */
   3915   uri = binding->uri + binding->uriLen;
   3916   memcpy(uri, localPart, i * sizeof(XML_Char));
   3917   /* we always have a namespace separator between localPart and prefix */
   3918   if (prefixLen) {
   3919     uri += i - 1;
   3920     *uri = parser->m_namespaceSeparator; /* replace null terminator */
   3921     memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
   3922   }
   3923   tagNamePtr->str = binding->uri;
   3924   return XML_ERROR_NONE;
   3925 }
   3926 
   3927 static XML_Bool
   3928 is_rfc3986_uri_char(XML_Char candidate) {
   3929   // For the RFC 3986 ANBF grammar see
   3930   // https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
   3931 
   3932   switch (candidate) {
   3933   // From rule "ALPHA" (uppercase half)
   3934   case 'A':
   3935   case 'B':
   3936   case 'C':
   3937   case 'D':
   3938   case 'E':
   3939   case 'F':
   3940   case 'G':
   3941   case 'H':
   3942   case 'I':
   3943   case 'J':
   3944   case 'K':
   3945   case 'L':
   3946   case 'M':
   3947   case 'N':
   3948   case 'O':
   3949   case 'P':
   3950   case 'Q':
   3951   case 'R':
   3952   case 'S':
   3953   case 'T':
   3954   case 'U':
   3955   case 'V':
   3956   case 'W':
   3957   case 'X':
   3958   case 'Y':
   3959   case 'Z':
   3960 
   3961   // From rule "ALPHA" (lowercase half)
   3962   case 'a':
   3963   case 'b':
   3964   case 'c':
   3965   case 'd':
   3966   case 'e':
   3967   case 'f':
   3968   case 'g':
   3969   case 'h':
   3970   case 'i':
   3971   case 'j':
   3972   case 'k':
   3973   case 'l':
   3974   case 'm':
   3975   case 'n':
   3976   case 'o':
   3977   case 'p':
   3978   case 'q':
   3979   case 'r':
   3980   case 's':
   3981   case 't':
   3982   case 'u':
   3983   case 'v':
   3984   case 'w':
   3985   case 'x':
   3986   case 'y':
   3987   case 'z':
   3988 
   3989   // From rule "DIGIT"
   3990   case '0':
   3991   case '1':
   3992   case '2':
   3993   case '3':
   3994   case '4':
   3995   case '5':
   3996   case '6':
   3997   case '7':
   3998   case '8':
   3999   case '9':
   4000 
   4001   // From rule "pct-encoded"
   4002   case '%':
   4003 
   4004   // From rule "unreserved"
   4005   case '-':
   4006   case '.':
   4007   case '_':
   4008   case '~':
   4009 
   4010   // From rule "gen-delims"
   4011   case ':':
   4012   case '/':
   4013   case '?':
   4014   case '#':
   4015   case '[':
   4016   case ']':
   4017   case '@':
   4018 
   4019   // From rule "sub-delims"
   4020   case '!':
   4021   case '$':
   4022   case '&':
   4023   case '\'':
   4024   case '(':
   4025   case ')':
   4026   case '*':
   4027   case '+':
   4028   case ',':
   4029   case ';':
   4030   case '=':
   4031     return XML_TRUE;
   4032 
   4033   default:
   4034     return XML_FALSE;
   4035   }
   4036 }
   4037 
   4038 /* addBinding() overwrites the value of prefix->binding without checking.
   4039    Therefore one must keep track of the old value outside of addBinding().
   4040 */
   4041 static enum XML_Error
   4042 addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
   4043            const XML_Char *uri, BINDING **bindingsPtr) {
   4044   // "http://www.w3.org/XML/1998/namespace"
   4045   static const XML_Char xmlNamespace[]
   4046       = {ASCII_h,      ASCII_t,     ASCII_t,     ASCII_p,      ASCII_COLON,
   4047          ASCII_SLASH,  ASCII_SLASH, ASCII_w,     ASCII_w,      ASCII_w,
   4048          ASCII_PERIOD, ASCII_w,     ASCII_3,     ASCII_PERIOD, ASCII_o,
   4049          ASCII_r,      ASCII_g,     ASCII_SLASH, ASCII_X,      ASCII_M,
   4050          ASCII_L,      ASCII_SLASH, ASCII_1,     ASCII_9,      ASCII_9,
   4051          ASCII_8,      ASCII_SLASH, ASCII_n,     ASCII_a,      ASCII_m,
   4052          ASCII_e,      ASCII_s,     ASCII_p,     ASCII_a,      ASCII_c,
   4053          ASCII_e,      '\0'};
   4054   static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
   4055   // "http://www.w3.org/2000/xmlns/"
   4056   static const XML_Char xmlnsNamespace[]
   4057       = {ASCII_h,     ASCII_t,      ASCII_t, ASCII_p, ASCII_COLON,  ASCII_SLASH,
   4058          ASCII_SLASH, ASCII_w,      ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
   4059          ASCII_3,     ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,      ASCII_SLASH,
   4060          ASCII_2,     ASCII_0,      ASCII_0, ASCII_0, ASCII_SLASH,  ASCII_x,
   4061          ASCII_m,     ASCII_l,      ASCII_n, ASCII_s, ASCII_SLASH,  '\0'};
   4062   static const int xmlnsLen
   4063       = (int)sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1;
   4064 
   4065   XML_Bool mustBeXML = XML_FALSE;
   4066   XML_Bool isXML = XML_TRUE;
   4067   XML_Bool isXMLNS = XML_TRUE;
   4068 
   4069   BINDING *b;
   4070   int len;
   4071 
   4072   /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
   4073   if (*uri == XML_T('\0') && prefix->name)
   4074     return XML_ERROR_UNDECLARING_PREFIX;
   4075 
   4076   if (prefix->name && prefix->name[0] == XML_T(ASCII_x)
   4077       && prefix->name[1] == XML_T(ASCII_m)
   4078       && prefix->name[2] == XML_T(ASCII_l)) {
   4079     /* Not allowed to bind xmlns */
   4080     if (prefix->name[3] == XML_T(ASCII_n) && prefix->name[4] == XML_T(ASCII_s)
   4081         && prefix->name[5] == XML_T('\0'))
   4082       return XML_ERROR_RESERVED_PREFIX_XMLNS;
   4083 
   4084     if (prefix->name[3] == XML_T('\0'))
   4085       mustBeXML = XML_TRUE;
   4086   }
   4087 
   4088   for (len = 0; uri[len]; len++) {
   4089     if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
   4090       isXML = XML_FALSE;
   4091 
   4092     if (! mustBeXML && isXMLNS
   4093         && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
   4094       isXMLNS = XML_FALSE;
   4095 
   4096     // NOTE: While Expat does not validate namespace URIs against RFC 3986
   4097     //       today (and is not REQUIRED to do so with regard to the XML 1.0
   4098     //       namespaces specification) we have to at least make sure, that
   4099     //       the application on top of Expat (that is likely splitting expanded
   4100     //       element names ("qualified names") of form
   4101     //       "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces
   4102     //       in its element handler code) cannot be confused by an attacker
   4103     //       putting additional namespace separator characters into namespace
   4104     //       declarations.  That would be ambiguous and not to be expected.
   4105     //
   4106     //       While the HTML API docs of function XML_ParserCreateNS have been
   4107     //       advising against use of a namespace separator character that can
   4108     //       appear in a URI for >20 years now, some widespread applications
   4109     //       are using URI characters (':' (colon) in particular) for a
   4110     //       namespace separator, in practice.  To keep these applications
   4111     //       functional, we only reject namespaces URIs containing the
   4112     //       application-chosen namespace separator if the chosen separator
   4113     //       is a non-URI character with regard to RFC 3986.
   4114     if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)
   4115         && ! is_rfc3986_uri_char(uri[len])) {
   4116       return XML_ERROR_SYNTAX;
   4117     }
   4118   }
   4119   isXML = isXML && len == xmlLen;
   4120   isXMLNS = isXMLNS && len == xmlnsLen;
   4121 
   4122   if (mustBeXML != isXML)
   4123     return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
   4124                      : XML_ERROR_RESERVED_NAMESPACE_URI;
   4125 
   4126   if (isXMLNS)
   4127     return XML_ERROR_RESERVED_NAMESPACE_URI;
   4128 
   4129   if (parser->m_namespaceSeparator)
   4130     len++;
   4131   if (parser->m_freeBindingList) {
   4132     b = parser->m_freeBindingList;
   4133     if (len > b->uriAlloc) {
   4134       /* Detect and prevent integer overflow */
   4135       if (len > INT_MAX - EXPAND_SPARE) {
   4136         return XML_ERROR_NO_MEMORY;
   4137       }
   4138 
   4139       /* Detect and prevent integer overflow.
   4140        * The preprocessor guard addresses the "always false" warning
   4141        * from -Wtype-limits on platforms where
   4142        * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   4143 #if UINT_MAX >= SIZE_MAX
   4144       if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
   4145         return XML_ERROR_NO_MEMORY;
   4146       }
   4147 #endif
   4148 
   4149       XML_Char *temp = (XML_Char *)REALLOC(
   4150           parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
   4151       if (temp == NULL)
   4152         return XML_ERROR_NO_MEMORY;
   4153       b->uri = temp;
   4154       b->uriAlloc = len + EXPAND_SPARE;
   4155     }
   4156     parser->m_freeBindingList = b->nextTagBinding;
   4157   } else {
   4158     b = (BINDING *)MALLOC(parser, sizeof(BINDING));
   4159     if (! b)
   4160       return XML_ERROR_NO_MEMORY;
   4161 
   4162     /* Detect and prevent integer overflow */
   4163     if (len > INT_MAX - EXPAND_SPARE) {
   4164       return XML_ERROR_NO_MEMORY;
   4165     }
   4166     /* Detect and prevent integer overflow.
   4167      * The preprocessor guard addresses the "always false" warning
   4168      * from -Wtype-limits on platforms where
   4169      * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   4170 #if UINT_MAX >= SIZE_MAX
   4171     if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
   4172       return XML_ERROR_NO_MEMORY;
   4173     }
   4174 #endif
   4175 
   4176     b->uri
   4177         = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
   4178     if (! b->uri) {
   4179       FREE(parser, b);
   4180       return XML_ERROR_NO_MEMORY;
   4181     }
   4182     b->uriAlloc = len + EXPAND_SPARE;
   4183   }
   4184   b->uriLen = len;
   4185   memcpy(b->uri, uri, len * sizeof(XML_Char));
   4186   if (parser->m_namespaceSeparator)
   4187     b->uri[len - 1] = parser->m_namespaceSeparator;
   4188   b->prefix = prefix;
   4189   b->attId = attId;
   4190   b->prevPrefixBinding = prefix->binding;
   4191   /* NULL binding when default namespace undeclared */
   4192   if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix)
   4193     prefix->binding = NULL;
   4194   else
   4195     prefix->binding = b;
   4196   b->nextTagBinding = *bindingsPtr;
   4197   *bindingsPtr = b;
   4198   /* if attId == NULL then we are not starting a namespace scope */
   4199   if (attId && parser->m_startNamespaceDeclHandler)
   4200     parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
   4201                                         prefix->binding ? uri : 0);
   4202   return XML_ERROR_NONE;
   4203 }
   4204 
   4205 /* The idea here is to avoid using stack for each CDATA section when
   4206    the whole file is parsed with one call.
   4207 */
   4208 static enum XML_Error PTRCALL
   4209 cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
   4210                       const char **endPtr) {
   4211   enum XML_Error result = doCdataSection(
   4212       parser, parser->m_encoding, &start, end, endPtr,
   4213       (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
   4214   if (result != XML_ERROR_NONE)
   4215     return result;
   4216   if (start) {
   4217     if (parser->m_parentParser) { /* we are parsing an external entity */
   4218       parser->m_processor = externalEntityContentProcessor;
   4219       return externalEntityContentProcessor(parser, start, end, endPtr);
   4220     } else {
   4221       parser->m_processor = contentProcessor;
   4222       return contentProcessor(parser, start, end, endPtr);
   4223     }
   4224   }
   4225   return result;
   4226 }
   4227 
   4228 /* startPtr gets set to non-null if the section is closed, and to null if
   4229    the section is not yet closed.
   4230 */
   4231 static enum XML_Error
   4232 doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
   4233                const char *end, const char **nextPtr, XML_Bool haveMore,
   4234                enum XML_Account account) {
   4235   const char *s = *startPtr;
   4236   const char **eventPP;
   4237   const char **eventEndPP;
   4238   if (enc == parser->m_encoding) {
   4239     eventPP = &parser->m_eventPtr;
   4240     *eventPP = s;
   4241     eventEndPP = &parser->m_eventEndPtr;
   4242   } else {
   4243     eventPP = &(parser->m_openInternalEntities->internalEventPtr);
   4244     eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
   4245   }
   4246   *eventPP = s;
   4247   *startPtr = NULL;
   4248 
   4249   for (;;) {
   4250     const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
   4251     int tok = XmlCdataSectionTok(enc, s, end, &next);
   4252 #if XML_GE == 1
   4253     if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
   4254       accountingOnAbort(parser);
   4255       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4256     }
   4257 #else
   4258     UNUSED_P(account);
   4259 #endif
   4260     *eventEndPP = next;
   4261     switch (tok) {
   4262     case XML_TOK_CDATA_SECT_CLOSE:
   4263       if (parser->m_endCdataSectionHandler)
   4264         parser->m_endCdataSectionHandler(parser->m_handlerArg);
   4265       /* BEGIN disabled code */
   4266       /* see comment under XML_TOK_CDATA_SECT_OPEN */
   4267       else if ((0) && parser->m_characterDataHandler)
   4268         parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
   4269                                        0);
   4270       /* END disabled code */
   4271       else if (parser->m_defaultHandler)
   4272         reportDefault(parser, enc, s, next);
   4273       *startPtr = next;
   4274       *nextPtr = next;
   4275       if (parser->m_parsingStatus.parsing == XML_FINISHED)
   4276         return XML_ERROR_ABORTED;
   4277       else
   4278         return XML_ERROR_NONE;
   4279     case XML_TOK_DATA_NEWLINE:
   4280       if (parser->m_characterDataHandler) {
   4281         XML_Char c = 0xA;
   4282         parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
   4283       } else if (parser->m_defaultHandler)
   4284         reportDefault(parser, enc, s, next);
   4285       break;
   4286     case XML_TOK_DATA_CHARS: {
   4287       XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
   4288       if (charDataHandler) {
   4289         if (MUST_CONVERT(enc, s)) {
   4290           for (;;) {
   4291             ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
   4292             const enum XML_Convert_Result convert_res = XmlConvert(
   4293                 enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
   4294             *eventEndPP = next;
   4295             charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
   4296                             (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
   4297             if ((convert_res == XML_CONVERT_COMPLETED)
   4298                 || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
   4299               break;
   4300             *eventPP = s;
   4301           }
   4302         } else
   4303           charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
   4304                           (int)((const XML_Char *)next - (const XML_Char *)s));
   4305       } else if (parser->m_defaultHandler)
   4306         reportDefault(parser, enc, s, next);
   4307     } break;
   4308     case XML_TOK_INVALID:
   4309       *eventPP = next;
   4310       return XML_ERROR_INVALID_TOKEN;
   4311     case XML_TOK_PARTIAL_CHAR:
   4312       if (haveMore) {
   4313         *nextPtr = s;
   4314         return XML_ERROR_NONE;
   4315       }
   4316       return XML_ERROR_PARTIAL_CHAR;
   4317     case XML_TOK_PARTIAL:
   4318     case XML_TOK_NONE:
   4319       if (haveMore) {
   4320         *nextPtr = s;
   4321         return XML_ERROR_NONE;
   4322       }
   4323       return XML_ERROR_UNCLOSED_CDATA_SECTION;
   4324     default:
   4325       /* Every token returned by XmlCdataSectionTok() has its own
   4326        * explicit case, so this default case will never be executed.
   4327        * We retain it as a safety net and exclude it from the coverage
   4328        * statistics.
   4329        *
   4330        * LCOV_EXCL_START
   4331        */
   4332       *eventPP = next;
   4333       return XML_ERROR_UNEXPECTED_STATE;
   4334       /* LCOV_EXCL_STOP */
   4335     }
   4336 
   4337     switch (parser->m_parsingStatus.parsing) {
   4338     case XML_SUSPENDED:
   4339       *eventPP = next;
   4340       *nextPtr = next;
   4341       return XML_ERROR_NONE;
   4342     case XML_FINISHED:
   4343       *eventPP = next;
   4344       return XML_ERROR_ABORTED;
   4345     case XML_PARSING:
   4346       if (parser->m_reenter) {
   4347         return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
   4348       }
   4349       /* Fall through */
   4350     default:;
   4351       *eventPP = s = next;
   4352     }
   4353   }
   4354   /* not reached */
   4355 }
   4356 
   4357 #ifdef XML_DTD
   4358 
   4359 /* The idea here is to avoid using stack for each IGNORE section when
   4360    the whole file is parsed with one call.
   4361 */
   4362 static enum XML_Error PTRCALL
   4363 ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end,
   4364                        const char **endPtr) {
   4365   enum XML_Error result
   4366       = doIgnoreSection(parser, parser->m_encoding, &start, end, endPtr,
   4367                         (XML_Bool)! parser->m_parsingStatus.finalBuffer);
   4368   if (result != XML_ERROR_NONE)
   4369     return result;
   4370   if (start) {
   4371     parser->m_processor = prologProcessor;
   4372     return prologProcessor(parser, start, end, endPtr);
   4373   }
   4374   return result;
   4375 }
   4376 
   4377 /* startPtr gets set to non-null is the section is closed, and to null
   4378    if the section is not yet closed.
   4379 */
   4380 static enum XML_Error
   4381 doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
   4382                 const char *end, const char **nextPtr, XML_Bool haveMore) {
   4383   const char *next = *startPtr; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
   4384   int tok;
   4385   const char *s = *startPtr;
   4386   const char **eventPP;
   4387   const char **eventEndPP;
   4388   if (enc == parser->m_encoding) {
   4389     eventPP = &parser->m_eventPtr;
   4390     *eventPP = s;
   4391     eventEndPP = &parser->m_eventEndPtr;
   4392   } else {
   4393     /* It's not entirely clear, but it seems the following two lines
   4394      * of code cannot be executed.  The only occasions on which 'enc'
   4395      * is not 'encoding' are when this function is called
   4396      * from the internal entity processing, and IGNORE sections are an
   4397      * error in internal entities.
   4398      *
   4399      * Since it really isn't clear that this is true, we keep the code
   4400      * and just remove it from our coverage tests.
   4401      *
   4402      * LCOV_EXCL_START
   4403      */
   4404     eventPP = &(parser->m_openInternalEntities->internalEventPtr);
   4405     eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
   4406     /* LCOV_EXCL_STOP */
   4407   }
   4408   *eventPP = s;
   4409   *startPtr = NULL;
   4410   tok = XmlIgnoreSectionTok(enc, s, end, &next);
   4411 #  if XML_GE == 1
   4412   if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
   4413                                 XML_ACCOUNT_DIRECT)) {
   4414     accountingOnAbort(parser);
   4415     return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4416   }
   4417 #  endif
   4418   *eventEndPP = next;
   4419   switch (tok) {
   4420   case XML_TOK_IGNORE_SECT:
   4421     if (parser->m_defaultHandler)
   4422       reportDefault(parser, enc, s, next);
   4423     *startPtr = next;
   4424     *nextPtr = next;
   4425     if (parser->m_parsingStatus.parsing == XML_FINISHED)
   4426       return XML_ERROR_ABORTED;
   4427     else
   4428       return XML_ERROR_NONE;
   4429   case XML_TOK_INVALID:
   4430     *eventPP = next;
   4431     return XML_ERROR_INVALID_TOKEN;
   4432   case XML_TOK_PARTIAL_CHAR:
   4433     if (haveMore) {
   4434       *nextPtr = s;
   4435       return XML_ERROR_NONE;
   4436     }
   4437     return XML_ERROR_PARTIAL_CHAR;
   4438   case XML_TOK_PARTIAL:
   4439   case XML_TOK_NONE:
   4440     if (haveMore) {
   4441       *nextPtr = s;
   4442       return XML_ERROR_NONE;
   4443     }
   4444     return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
   4445   default:
   4446     /* All of the tokens that XmlIgnoreSectionTok() returns have
   4447      * explicit cases to handle them, so this default case is never
   4448      * executed.  We keep it as a safety net anyway, and remove it
   4449      * from our test coverage statistics.
   4450      *
   4451      * LCOV_EXCL_START
   4452      */
   4453     *eventPP = next;
   4454     return XML_ERROR_UNEXPECTED_STATE;
   4455     /* LCOV_EXCL_STOP */
   4456   }
   4457   /* not reached */
   4458 }
   4459 
   4460 #endif /* XML_DTD */
   4461 
   4462 static enum XML_Error
   4463 initializeEncoding(XML_Parser parser) {
   4464   const char *s;
   4465 #ifdef XML_UNICODE
   4466   char encodingBuf[128];
   4467   /* See comments about `protocolEncodingName` in parserInit() */
   4468   if (! parser->m_protocolEncodingName)
   4469     s = NULL;
   4470   else {
   4471     int i;
   4472     for (i = 0; parser->m_protocolEncodingName[i]; i++) {
   4473       if (i == sizeof(encodingBuf) - 1
   4474           || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) {
   4475         encodingBuf[0] = '\0';
   4476         break;
   4477       }
   4478       encodingBuf[i] = (char)parser->m_protocolEncodingName[i];
   4479     }
   4480     encodingBuf[i] = '\0';
   4481     s = encodingBuf;
   4482   }
   4483 #else
   4484   s = parser->m_protocolEncodingName;
   4485 #endif
   4486   if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(
   4487           &parser->m_initEncoding, &parser->m_encoding, s))
   4488     return XML_ERROR_NONE;
   4489   return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
   4490 }
   4491 
   4492 static enum XML_Error
   4493 processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
   4494                const char *next) {
   4495   const char *encodingName = NULL;
   4496   const XML_Char *storedEncName = NULL;
   4497   const ENCODING *newEncoding = NULL;
   4498   const char *version = NULL;
   4499   const char *versionend = NULL;
   4500   const XML_Char *storedversion = NULL;
   4501   int standalone = -1;
   4502 
   4503 #if XML_GE == 1
   4504   if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
   4505                                 XML_ACCOUNT_DIRECT)) {
   4506     accountingOnAbort(parser);
   4507     return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4508   }
   4509 #endif
   4510 
   4511   if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
   4512           isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
   4513           &version, &versionend, &encodingName, &newEncoding, &standalone)) {
   4514     if (isGeneralTextEntity)
   4515       return XML_ERROR_TEXT_DECL;
   4516     else
   4517       return XML_ERROR_XML_DECL;
   4518   }
   4519   if (! isGeneralTextEntity && standalone == 1) {
   4520     parser->m_dtd->standalone = XML_TRUE;
   4521 #ifdef XML_DTD
   4522     if (parser->m_paramEntityParsing
   4523         == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
   4524       parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
   4525 #endif /* XML_DTD */
   4526   }
   4527   if (parser->m_xmlDeclHandler) {
   4528     if (encodingName != NULL) {
   4529       storedEncName = poolStoreString(
   4530           &parser->m_temp2Pool, parser->m_encoding, encodingName,
   4531           encodingName + XmlNameLength(parser->m_encoding, encodingName));
   4532       if (! storedEncName)
   4533         return XML_ERROR_NO_MEMORY;
   4534       poolFinish(&parser->m_temp2Pool);
   4535     }
   4536     if (version) {
   4537       storedversion
   4538           = poolStoreString(&parser->m_temp2Pool, parser->m_encoding, version,
   4539                             versionend - parser->m_encoding->minBytesPerChar);
   4540       if (! storedversion)
   4541         return XML_ERROR_NO_MEMORY;
   4542     }
   4543     parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName,
   4544                              standalone);
   4545   } else if (parser->m_defaultHandler)
   4546     reportDefault(parser, parser->m_encoding, s, next);
   4547   if (parser->m_protocolEncodingName == NULL) {
   4548     if (newEncoding) {
   4549       /* Check that the specified encoding does not conflict with what
   4550        * the parser has already deduced.  Do we have the same number
   4551        * of bytes in the smallest representation of a character?  If
   4552        * this is UTF-16, is it the same endianness?
   4553        */
   4554       if (newEncoding->minBytesPerChar != parser->m_encoding->minBytesPerChar
   4555           || (newEncoding->minBytesPerChar == 2
   4556               && newEncoding != parser->m_encoding)) {
   4557         parser->m_eventPtr = encodingName;
   4558         return XML_ERROR_INCORRECT_ENCODING;
   4559       }
   4560       parser->m_encoding = newEncoding;
   4561     } else if (encodingName) {
   4562       enum XML_Error result;
   4563       if (! storedEncName) {
   4564         storedEncName = poolStoreString(
   4565             &parser->m_temp2Pool, parser->m_encoding, encodingName,
   4566             encodingName + XmlNameLength(parser->m_encoding, encodingName));
   4567         if (! storedEncName)
   4568           return XML_ERROR_NO_MEMORY;
   4569       }
   4570       result = handleUnknownEncoding(parser, storedEncName);
   4571       poolClear(&parser->m_temp2Pool);
   4572       if (result == XML_ERROR_UNKNOWN_ENCODING)
   4573         parser->m_eventPtr = encodingName;
   4574       return result;
   4575     }
   4576   }
   4577 
   4578   if (storedEncName || storedversion)
   4579     poolClear(&parser->m_temp2Pool);
   4580 
   4581   return XML_ERROR_NONE;
   4582 }
   4583 
   4584 static enum XML_Error
   4585 handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) {
   4586   if (parser->m_unknownEncodingHandler) {
   4587     XML_Encoding info;
   4588     int i;
   4589     for (i = 0; i < 256; i++)
   4590       info.map[i] = -1;
   4591     info.convert = NULL;
   4592     info.data = NULL;
   4593     info.release = NULL;
   4594     if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData,
   4595                                          encodingName, &info)) {
   4596       ENCODING *enc;
   4597       parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
   4598       if (! parser->m_unknownEncodingMem) {
   4599         if (info.release)
   4600           info.release(info.data);
   4601         return XML_ERROR_NO_MEMORY;
   4602       }
   4603       enc = (parser->m_ns ? XmlInitUnknownEncodingNS : XmlInitUnknownEncoding)(
   4604           parser->m_unknownEncodingMem, info.map, info.convert, info.data);
   4605       if (enc) {
   4606         parser->m_unknownEncodingData = info.data;
   4607         parser->m_unknownEncodingRelease = info.release;
   4608         parser->m_encoding = enc;
   4609         return XML_ERROR_NONE;
   4610       }
   4611     }
   4612     if (info.release != NULL)
   4613       info.release(info.data);
   4614   }
   4615   return XML_ERROR_UNKNOWN_ENCODING;
   4616 }
   4617 
   4618 static enum XML_Error PTRCALL
   4619 prologInitProcessor(XML_Parser parser, const char *s, const char *end,
   4620                     const char **nextPtr) {
   4621   enum XML_Error result = initializeEncoding(parser);
   4622   if (result != XML_ERROR_NONE)
   4623     return result;
   4624   parser->m_processor = prologProcessor;
   4625   return prologProcessor(parser, s, end, nextPtr);
   4626 }
   4627 
   4628 #ifdef XML_DTD
   4629 
   4630 static enum XML_Error PTRCALL
   4631 externalParEntInitProcessor(XML_Parser parser, const char *s, const char *end,
   4632                             const char **nextPtr) {
   4633   enum XML_Error result = initializeEncoding(parser);
   4634   if (result != XML_ERROR_NONE)
   4635     return result;
   4636 
   4637   /* we know now that XML_Parse(Buffer) has been called,
   4638      so we consider the external parameter entity read */
   4639   parser->m_dtd->paramEntityRead = XML_TRUE;
   4640 
   4641   if (parser->m_prologState.inEntityValue) {
   4642     parser->m_processor = entityValueInitProcessor;
   4643     return entityValueInitProcessor(parser, s, end, nextPtr);
   4644   } else {
   4645     parser->m_processor = externalParEntProcessor;
   4646     return externalParEntProcessor(parser, s, end, nextPtr);
   4647   }
   4648 }
   4649 
   4650 static enum XML_Error PTRCALL
   4651 entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
   4652                          const char **nextPtr) {
   4653   int tok;
   4654   const char *start = s;
   4655   const char *next = start;
   4656   parser->m_eventPtr = start;
   4657 
   4658   for (;;) {
   4659     tok = XmlPrologTok(parser->m_encoding, start, end, &next);
   4660     /* Note: Except for XML_TOK_BOM below, these bytes are accounted later in:
   4661              - storeEntityValue
   4662              - processXmlDecl
   4663     */
   4664     parser->m_eventEndPtr = next;
   4665     if (tok <= 0) {
   4666       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
   4667         *nextPtr = s;
   4668         return XML_ERROR_NONE;
   4669       }
   4670       switch (tok) {
   4671       case XML_TOK_INVALID:
   4672         return XML_ERROR_INVALID_TOKEN;
   4673       case XML_TOK_PARTIAL:
   4674         return XML_ERROR_UNCLOSED_TOKEN;
   4675       case XML_TOK_PARTIAL_CHAR:
   4676         return XML_ERROR_PARTIAL_CHAR;
   4677       case XML_TOK_NONE: /* start == end */
   4678       default:
   4679         break;
   4680       }
   4681       /* found end of entity value - can store it now */
   4682       return storeEntityValue(parser, parser->m_encoding, s, end,
   4683                               XML_ACCOUNT_DIRECT, NULL);
   4684     } else if (tok == XML_TOK_XML_DECL) {
   4685       enum XML_Error result;
   4686       result = processXmlDecl(parser, 0, start, next);
   4687       if (result != XML_ERROR_NONE)
   4688         return result;
   4689       /* At this point, m_parsingStatus.parsing cannot be XML_SUSPENDED.  For
   4690        * that to happen, a parameter entity parsing handler must have attempted
   4691        * to suspend the parser, which fails and raises an error.  The parser can
   4692        * be aborted, but can't be suspended.
   4693        */
   4694       if (parser->m_parsingStatus.parsing == XML_FINISHED)
   4695         return XML_ERROR_ABORTED;
   4696       *nextPtr = next;
   4697       /* stop scanning for text declaration - we found one */
   4698       parser->m_processor = entityValueProcessor;
   4699       return entityValueProcessor(parser, next, end, nextPtr);
   4700     }
   4701     /* XmlPrologTok has now set the encoding based on the BOM it found, and we
   4702        must move s and nextPtr forward to consume the BOM.
   4703 
   4704        If we didn't, and got XML_TOK_NONE from the next XmlPrologTok call, we
   4705        would leave the BOM in the buffer and return. On the next call to this
   4706        function, our XmlPrologTok call would return XML_TOK_INVALID, since it
   4707        is not valid to have multiple BOMs.
   4708     */
   4709     else if (tok == XML_TOK_BOM) {
   4710 #  if XML_GE == 1
   4711       if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
   4712                                     XML_ACCOUNT_DIRECT)) {
   4713         accountingOnAbort(parser);
   4714         return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4715       }
   4716 #  endif
   4717 
   4718       *nextPtr = next;
   4719       s = next;
   4720     }
   4721     /* If we get this token, we have the start of what might be a
   4722        normal tag, but not a declaration (i.e. it doesn't begin with
   4723        "<!").  In a DTD context, that isn't legal.
   4724     */
   4725     else if (tok == XML_TOK_INSTANCE_START) {
   4726       *nextPtr = next;
   4727       return XML_ERROR_SYNTAX;
   4728     }
   4729     start = next;
   4730     parser->m_eventPtr = start;
   4731   }
   4732 }
   4733 
   4734 static enum XML_Error PTRCALL
   4735 externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
   4736                         const char **nextPtr) {
   4737   const char *next = s;
   4738   int tok;
   4739 
   4740   tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   4741   if (tok <= 0) {
   4742     if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
   4743       *nextPtr = s;
   4744       return XML_ERROR_NONE;
   4745     }
   4746     switch (tok) {
   4747     case XML_TOK_INVALID:
   4748       return XML_ERROR_INVALID_TOKEN;
   4749     case XML_TOK_PARTIAL:
   4750       return XML_ERROR_UNCLOSED_TOKEN;
   4751     case XML_TOK_PARTIAL_CHAR:
   4752       return XML_ERROR_PARTIAL_CHAR;
   4753     case XML_TOK_NONE: /* start == end */
   4754     default:
   4755       break;
   4756     }
   4757   }
   4758   /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
   4759      However, when parsing an external subset, doProlog will not accept a BOM
   4760      as valid, and report a syntax error, so we have to skip the BOM, and
   4761      account for the BOM bytes.
   4762   */
   4763   else if (tok == XML_TOK_BOM) {
   4764     if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
   4765                                   XML_ACCOUNT_DIRECT)) {
   4766       accountingOnAbort(parser);
   4767       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4768     }
   4769 
   4770     s = next;
   4771     tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   4772   }
   4773 
   4774   parser->m_processor = prologProcessor;
   4775   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
   4776                   (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
   4777                   XML_ACCOUNT_DIRECT);
   4778 }
   4779 
   4780 static enum XML_Error PTRCALL
   4781 entityValueProcessor(XML_Parser parser, const char *s, const char *end,
   4782                      const char **nextPtr) {
   4783   const char *start = s;
   4784   const char *next = s;
   4785   const ENCODING *enc = parser->m_encoding;
   4786   int tok;
   4787 
   4788   for (;;) {
   4789     tok = XmlPrologTok(enc, start, end, &next);
   4790     /* Note: These bytes are accounted later in:
   4791              - storeEntityValue
   4792     */
   4793     if (tok <= 0) {
   4794       if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
   4795         *nextPtr = s;
   4796         return XML_ERROR_NONE;
   4797       }
   4798       switch (tok) {
   4799       case XML_TOK_INVALID:
   4800         return XML_ERROR_INVALID_TOKEN;
   4801       case XML_TOK_PARTIAL:
   4802         return XML_ERROR_UNCLOSED_TOKEN;
   4803       case XML_TOK_PARTIAL_CHAR:
   4804         return XML_ERROR_PARTIAL_CHAR;
   4805       case XML_TOK_NONE: /* start == end */
   4806       default:
   4807         break;
   4808       }
   4809       /* found end of entity value - can store it now */
   4810       return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT, NULL);
   4811     }
   4812     start = next;
   4813   }
   4814 }
   4815 
   4816 #endif /* XML_DTD */
   4817 
   4818 static enum XML_Error PTRCALL
   4819 prologProcessor(XML_Parser parser, const char *s, const char *end,
   4820                 const char **nextPtr) {
   4821   const char *next = s;
   4822   int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   4823   return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
   4824                   (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
   4825                   XML_ACCOUNT_DIRECT);
   4826 }
   4827 
   4828 static enum XML_Error
   4829 doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
   4830          int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
   4831          XML_Bool allowClosingDoctype, enum XML_Account account) {
   4832 #ifdef XML_DTD
   4833   static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
   4834 #endif /* XML_DTD */
   4835   static const XML_Char atypeCDATA[]
   4836       = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
   4837   static const XML_Char atypeID[] = {ASCII_I, ASCII_D, '\0'};
   4838   static const XML_Char atypeIDREF[]
   4839       = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'};
   4840   static const XML_Char atypeIDREFS[]
   4841       = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'};
   4842   static const XML_Char atypeENTITY[]
   4843       = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'};
   4844   static const XML_Char atypeENTITIES[]
   4845       = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T,
   4846          ASCII_I, ASCII_E, ASCII_S, '\0'};
   4847   static const XML_Char atypeNMTOKEN[]
   4848       = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'};
   4849   static const XML_Char atypeNMTOKENS[]
   4850       = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K,
   4851          ASCII_E, ASCII_N, ASCII_S, '\0'};
   4852   static const XML_Char notationPrefix[]
   4853       = {ASCII_N, ASCII_O, ASCII_T, ASCII_A,      ASCII_T,
   4854          ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0'};
   4855   static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
   4856   static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
   4857 
   4858 #ifndef XML_DTD
   4859   UNUSED_P(account);
   4860 #endif
   4861 
   4862   /* save one level of indirection */
   4863   DTD *const dtd = parser->m_dtd;
   4864 
   4865   const char **eventPP;
   4866   const char **eventEndPP;
   4867   enum XML_Content_Quant quant;
   4868 
   4869   if (enc == parser->m_encoding) {
   4870     eventPP = &parser->m_eventPtr;
   4871     eventEndPP = &parser->m_eventEndPtr;
   4872   } else {
   4873     eventPP = &(parser->m_openInternalEntities->internalEventPtr);
   4874     eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
   4875   }
   4876 
   4877   for (;;) {
   4878     int role;
   4879     XML_Bool handleDefault = XML_TRUE;
   4880     *eventPP = s;
   4881     *eventEndPP = next;
   4882     if (tok <= 0) {
   4883       if (haveMore && tok != XML_TOK_INVALID) {
   4884         *nextPtr = s;
   4885         return XML_ERROR_NONE;
   4886       }
   4887       switch (tok) {
   4888       case XML_TOK_INVALID:
   4889         *eventPP = next;
   4890         return XML_ERROR_INVALID_TOKEN;
   4891       case XML_TOK_PARTIAL:
   4892         return XML_ERROR_UNCLOSED_TOKEN;
   4893       case XML_TOK_PARTIAL_CHAR:
   4894         return XML_ERROR_PARTIAL_CHAR;
   4895       case -XML_TOK_PROLOG_S:
   4896         tok = -tok;
   4897         break;
   4898       case XML_TOK_NONE:
   4899 #ifdef XML_DTD
   4900         /* for internal PE NOT referenced between declarations */
   4901         if (enc != parser->m_encoding
   4902             && ! parser->m_openInternalEntities->betweenDecl) {
   4903           *nextPtr = s;
   4904           return XML_ERROR_NONE;
   4905         }
   4906         /* WFC: PE Between Declarations - must check that PE contains
   4907            complete markup, not only for external PEs, but also for
   4908            internal PEs if the reference occurs between declarations.
   4909         */
   4910         if (parser->m_isParamEntity || enc != parser->m_encoding) {
   4911           if (XmlTokenRole(&parser->m_prologState, XML_TOK_NONE, end, end, enc)
   4912               == XML_ROLE_ERROR)
   4913             return XML_ERROR_INCOMPLETE_PE;
   4914           *nextPtr = s;
   4915           return XML_ERROR_NONE;
   4916         }
   4917 #endif /* XML_DTD */
   4918         return XML_ERROR_NO_ELEMENTS;
   4919       default:
   4920         tok = -tok;
   4921         next = end;
   4922         break;
   4923       }
   4924     }
   4925     role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
   4926 #if XML_GE == 1
   4927     switch (role) {
   4928     case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
   4929     case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
   4930 #  ifdef XML_DTD
   4931     case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
   4932 #  endif
   4933       break;
   4934     default:
   4935       if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
   4936         accountingOnAbort(parser);
   4937         return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   4938       }
   4939     }
   4940 #endif
   4941     switch (role) {
   4942     case XML_ROLE_XML_DECL: {
   4943       enum XML_Error result = processXmlDecl(parser, 0, s, next);
   4944       if (result != XML_ERROR_NONE)
   4945         return result;
   4946       enc = parser->m_encoding;
   4947       handleDefault = XML_FALSE;
   4948     } break;
   4949     case XML_ROLE_DOCTYPE_NAME:
   4950       if (parser->m_startDoctypeDeclHandler) {
   4951         parser->m_doctypeName
   4952             = poolStoreString(&parser->m_tempPool, enc, s, next);
   4953         if (! parser->m_doctypeName)
   4954           return XML_ERROR_NO_MEMORY;
   4955         poolFinish(&parser->m_tempPool);
   4956         parser->m_doctypePubid = NULL;
   4957         handleDefault = XML_FALSE;
   4958       }
   4959       parser->m_doctypeSysid = NULL; /* always initialize to NULL */
   4960       break;
   4961     case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
   4962       if (parser->m_startDoctypeDeclHandler) {
   4963         parser->m_startDoctypeDeclHandler(
   4964             parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
   4965             parser->m_doctypePubid, 1);
   4966         parser->m_doctypeName = NULL;
   4967         poolClear(&parser->m_tempPool);
   4968         handleDefault = XML_FALSE;
   4969       }
   4970       break;
   4971 #ifdef XML_DTD
   4972     case XML_ROLE_TEXT_DECL: {
   4973       enum XML_Error result = processXmlDecl(parser, 1, s, next);
   4974       if (result != XML_ERROR_NONE)
   4975         return result;
   4976       enc = parser->m_encoding;
   4977       handleDefault = XML_FALSE;
   4978     } break;
   4979 #endif /* XML_DTD */
   4980     case XML_ROLE_DOCTYPE_PUBLIC_ID:
   4981 #ifdef XML_DTD
   4982       parser->m_useForeignDTD = XML_FALSE;
   4983       parser->m_declEntity = (ENTITY *)lookup(
   4984           parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY));
   4985       if (! parser->m_declEntity)
   4986         return XML_ERROR_NO_MEMORY;
   4987 #endif /* XML_DTD */
   4988       dtd->hasParamEntityRefs = XML_TRUE;
   4989       if (parser->m_startDoctypeDeclHandler) {
   4990         XML_Char *pubId;
   4991         if (! XmlIsPublicId(enc, s, next, eventPP))
   4992           return XML_ERROR_PUBLICID;
   4993         pubId = poolStoreString(&parser->m_tempPool, enc,
   4994                                 s + enc->minBytesPerChar,
   4995                                 next - enc->minBytesPerChar);
   4996         if (! pubId)
   4997           return XML_ERROR_NO_MEMORY;
   4998         normalizePublicId(pubId);
   4999         poolFinish(&parser->m_tempPool);
   5000         parser->m_doctypePubid = pubId;
   5001         handleDefault = XML_FALSE;
   5002         goto alreadyChecked;
   5003       }
   5004       /* fall through */
   5005     case XML_ROLE_ENTITY_PUBLIC_ID:
   5006       if (! XmlIsPublicId(enc, s, next, eventPP))
   5007         return XML_ERROR_PUBLICID;
   5008     alreadyChecked:
   5009       if (dtd->keepProcessing && parser->m_declEntity) {
   5010         XML_Char *tem
   5011             = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
   5012                               next - enc->minBytesPerChar);
   5013         if (! tem)
   5014           return XML_ERROR_NO_MEMORY;
   5015         normalizePublicId(tem);
   5016         parser->m_declEntity->publicId = tem;
   5017         poolFinish(&dtd->pool);
   5018         /* Don't suppress the default handler if we fell through from
   5019          * the XML_ROLE_DOCTYPE_PUBLIC_ID case.
   5020          */
   5021         if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_PUBLIC_ID)
   5022           handleDefault = XML_FALSE;
   5023       }
   5024       break;
   5025     case XML_ROLE_DOCTYPE_CLOSE:
   5026       if (allowClosingDoctype != XML_TRUE) {
   5027         /* Must not close doctype from within expanded parameter entities */
   5028         return XML_ERROR_INVALID_TOKEN;
   5029       }
   5030 
   5031       if (parser->m_doctypeName) {
   5032         parser->m_startDoctypeDeclHandler(
   5033             parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
   5034             parser->m_doctypePubid, 0);
   5035         poolClear(&parser->m_tempPool);
   5036         handleDefault = XML_FALSE;
   5037       }
   5038       /* parser->m_doctypeSysid will be non-NULL in the case of a previous
   5039          XML_ROLE_DOCTYPE_SYSTEM_ID, even if parser->m_startDoctypeDeclHandler
   5040          was not set, indicating an external subset
   5041       */
   5042 #ifdef XML_DTD
   5043       if (parser->m_doctypeSysid || parser->m_useForeignDTD) {
   5044         XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
   5045         dtd->hasParamEntityRefs = XML_TRUE;
   5046         if (parser->m_paramEntityParsing
   5047             && parser->m_externalEntityRefHandler) {
   5048           ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
   5049                                             externalSubsetName, sizeof(ENTITY));
   5050           if (! entity) {
   5051             /* The external subset name "#" will have already been
   5052              * inserted into the hash table at the start of the
   5053              * external entity parsing, so no allocation will happen
   5054              * and lookup() cannot fail.
   5055              */
   5056             return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
   5057           }
   5058           if (parser->m_useForeignDTD)
   5059             entity->base = parser->m_curBase;
   5060           dtd->paramEntityRead = XML_FALSE;
   5061           if (! parser->m_externalEntityRefHandler(
   5062                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
   5063                   entity->systemId, entity->publicId))
   5064             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
   5065           if (dtd->paramEntityRead) {
   5066             if (! dtd->standalone && parser->m_notStandaloneHandler
   5067                 && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
   5068               return XML_ERROR_NOT_STANDALONE;
   5069           }
   5070           /* if we didn't read the foreign DTD then this means that there
   5071              is no external subset and we must reset dtd->hasParamEntityRefs
   5072           */
   5073           else if (! parser->m_doctypeSysid)
   5074             dtd->hasParamEntityRefs = hadParamEntityRefs;
   5075           /* end of DTD - no need to update dtd->keepProcessing */
   5076         }
   5077         parser->m_useForeignDTD = XML_FALSE;
   5078       }
   5079 #endif /* XML_DTD */
   5080       if (parser->m_endDoctypeDeclHandler) {
   5081         parser->m_endDoctypeDeclHandler(parser->m_handlerArg);
   5082         handleDefault = XML_FALSE;
   5083       }
   5084       break;
   5085     case XML_ROLE_INSTANCE_START:
   5086 #ifdef XML_DTD
   5087       /* if there is no DOCTYPE declaration then now is the
   5088          last chance to read the foreign DTD
   5089       */
   5090       if (parser->m_useForeignDTD) {
   5091         XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
   5092         dtd->hasParamEntityRefs = XML_TRUE;
   5093         if (parser->m_paramEntityParsing
   5094             && parser->m_externalEntityRefHandler) {
   5095           ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
   5096                                             externalSubsetName, sizeof(ENTITY));
   5097           if (! entity)
   5098             return XML_ERROR_NO_MEMORY;
   5099           entity->base = parser->m_curBase;
   5100           dtd->paramEntityRead = XML_FALSE;
   5101           if (! parser->m_externalEntityRefHandler(
   5102                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
   5103                   entity->systemId, entity->publicId))
   5104             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
   5105           if (dtd->paramEntityRead) {
   5106             if (! dtd->standalone && parser->m_notStandaloneHandler
   5107                 && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
   5108               return XML_ERROR_NOT_STANDALONE;
   5109           }
   5110           /* if we didn't read the foreign DTD then this means that there
   5111              is no external subset and we must reset dtd->hasParamEntityRefs
   5112           */
   5113           else
   5114             dtd->hasParamEntityRefs = hadParamEntityRefs;
   5115           /* end of DTD - no need to update dtd->keepProcessing */
   5116         }
   5117       }
   5118 #endif /* XML_DTD */
   5119       parser->m_processor = contentProcessor;
   5120       return contentProcessor(parser, s, end, nextPtr);
   5121     case XML_ROLE_ATTLIST_ELEMENT_NAME:
   5122       parser->m_declElementType = getElementType(parser, enc, s, next);
   5123       if (! parser->m_declElementType)
   5124         return XML_ERROR_NO_MEMORY;
   5125       goto checkAttListDeclHandler;
   5126     case XML_ROLE_ATTRIBUTE_NAME:
   5127       parser->m_declAttributeId = getAttributeId(parser, enc, s, next);
   5128       if (! parser->m_declAttributeId)
   5129         return XML_ERROR_NO_MEMORY;
   5130       parser->m_declAttributeIsCdata = XML_FALSE;
   5131       parser->m_declAttributeType = NULL;
   5132       parser->m_declAttributeIsId = XML_FALSE;
   5133       goto checkAttListDeclHandler;
   5134     case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
   5135       parser->m_declAttributeIsCdata = XML_TRUE;
   5136       parser->m_declAttributeType = atypeCDATA;
   5137       goto checkAttListDeclHandler;
   5138     case XML_ROLE_ATTRIBUTE_TYPE_ID:
   5139       parser->m_declAttributeIsId = XML_TRUE;
   5140       parser->m_declAttributeType = atypeID;
   5141       goto checkAttListDeclHandler;
   5142     case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
   5143       parser->m_declAttributeType = atypeIDREF;
   5144       goto checkAttListDeclHandler;
   5145     case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
   5146       parser->m_declAttributeType = atypeIDREFS;
   5147       goto checkAttListDeclHandler;
   5148     case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
   5149       parser->m_declAttributeType = atypeENTITY;
   5150       goto checkAttListDeclHandler;
   5151     case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
   5152       parser->m_declAttributeType = atypeENTITIES;
   5153       goto checkAttListDeclHandler;
   5154     case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
   5155       parser->m_declAttributeType = atypeNMTOKEN;
   5156       goto checkAttListDeclHandler;
   5157     case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
   5158       parser->m_declAttributeType = atypeNMTOKENS;
   5159     checkAttListDeclHandler:
   5160       if (dtd->keepProcessing && parser->m_attlistDeclHandler)
   5161         handleDefault = XML_FALSE;
   5162       break;
   5163     case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
   5164     case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
   5165       if (dtd->keepProcessing && parser->m_attlistDeclHandler) {
   5166         const XML_Char *prefix;
   5167         if (parser->m_declAttributeType) {
   5168           prefix = enumValueSep;
   5169         } else {
   5170           prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE ? notationPrefix
   5171                                                               : enumValueStart);
   5172         }
   5173         if (! poolAppendString(&parser->m_tempPool, prefix))
   5174           return XML_ERROR_NO_MEMORY;
   5175         if (! poolAppend(&parser->m_tempPool, enc, s, next))
   5176           return XML_ERROR_NO_MEMORY;
   5177         parser->m_declAttributeType = parser->m_tempPool.start;
   5178         handleDefault = XML_FALSE;
   5179       }
   5180       break;
   5181     case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
   5182     case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
   5183       if (dtd->keepProcessing) {
   5184         if (! defineAttribute(parser->m_declElementType,
   5185                               parser->m_declAttributeId,
   5186                               parser->m_declAttributeIsCdata,
   5187                               parser->m_declAttributeIsId, 0, parser))
   5188           return XML_ERROR_NO_MEMORY;
   5189         if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
   5190           if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
   5191               || (*parser->m_declAttributeType == XML_T(ASCII_N)
   5192                   && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
   5193             /* Enumerated or Notation type */
   5194             if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
   5195                 || ! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   5196               return XML_ERROR_NO_MEMORY;
   5197             parser->m_declAttributeType = parser->m_tempPool.start;
   5198             poolFinish(&parser->m_tempPool);
   5199           }
   5200           *eventEndPP = s;
   5201           parser->m_attlistDeclHandler(
   5202               parser->m_handlerArg, parser->m_declElementType->name,
   5203               parser->m_declAttributeId->name, parser->m_declAttributeType, 0,
   5204               role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
   5205           handleDefault = XML_FALSE;
   5206         }
   5207       }
   5208       poolClear(&parser->m_tempPool);
   5209       break;
   5210     case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
   5211     case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
   5212       if (dtd->keepProcessing) {
   5213         const XML_Char *attVal;
   5214         enum XML_Error result = storeAttributeValue(
   5215             parser, enc, parser->m_declAttributeIsCdata,
   5216             s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool,
   5217             XML_ACCOUNT_NONE);
   5218         if (result)
   5219           return result;
   5220         attVal = poolStart(&dtd->pool);
   5221         poolFinish(&dtd->pool);
   5222         /* ID attributes aren't allowed to have a default */
   5223         if (! defineAttribute(
   5224                 parser->m_declElementType, parser->m_declAttributeId,
   5225                 parser->m_declAttributeIsCdata, XML_FALSE, attVal, parser))
   5226           return XML_ERROR_NO_MEMORY;
   5227         if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
   5228           if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
   5229               || (*parser->m_declAttributeType == XML_T(ASCII_N)
   5230                   && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
   5231             /* Enumerated or Notation type */
   5232             if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
   5233                 || ! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   5234               return XML_ERROR_NO_MEMORY;
   5235             parser->m_declAttributeType = parser->m_tempPool.start;
   5236             poolFinish(&parser->m_tempPool);
   5237           }
   5238           *eventEndPP = s;
   5239           parser->m_attlistDeclHandler(
   5240               parser->m_handlerArg, parser->m_declElementType->name,
   5241               parser->m_declAttributeId->name, parser->m_declAttributeType,
   5242               attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
   5243           poolClear(&parser->m_tempPool);
   5244           handleDefault = XML_FALSE;
   5245         }
   5246       }
   5247       break;
   5248     case XML_ROLE_ENTITY_VALUE:
   5249       if (dtd->keepProcessing) {
   5250 #if XML_GE == 1
   5251         // This will store the given replacement text in
   5252         // parser->m_declEntity->textPtr.
   5253         enum XML_Error result = callStoreEntityValue(
   5254             parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar,
   5255             XML_ACCOUNT_NONE);
   5256         if (parser->m_declEntity) {
   5257           parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
   5258           parser->m_declEntity->textLen
   5259               = (int)(poolLength(&dtd->entityValuePool));
   5260           poolFinish(&dtd->entityValuePool);
   5261           if (parser->m_entityDeclHandler) {
   5262             *eventEndPP = s;
   5263             parser->m_entityDeclHandler(
   5264                 parser->m_handlerArg, parser->m_declEntity->name,
   5265                 parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
   5266                 parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
   5267             handleDefault = XML_FALSE;
   5268           }
   5269         } else
   5270           poolDiscard(&dtd->entityValuePool);
   5271         if (result != XML_ERROR_NONE)
   5272           return result;
   5273 #else
   5274         // This will store "&amp;entity123;" in parser->m_declEntity->textPtr
   5275         // to end up as "&entity123;" in the handler.
   5276         if (parser->m_declEntity != NULL) {
   5277           const enum XML_Error result
   5278               = storeSelfEntityValue(parser, parser->m_declEntity);
   5279           if (result != XML_ERROR_NONE)
   5280             return result;
   5281 
   5282           if (parser->m_entityDeclHandler) {
   5283             *eventEndPP = s;
   5284             parser->m_entityDeclHandler(
   5285                 parser->m_handlerArg, parser->m_declEntity->name,
   5286                 parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
   5287                 parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
   5288             handleDefault = XML_FALSE;
   5289           }
   5290         }
   5291 #endif
   5292       }
   5293       break;
   5294     case XML_ROLE_DOCTYPE_SYSTEM_ID:
   5295 #ifdef XML_DTD
   5296       parser->m_useForeignDTD = XML_FALSE;
   5297 #endif /* XML_DTD */
   5298       dtd->hasParamEntityRefs = XML_TRUE;
   5299       if (parser->m_startDoctypeDeclHandler) {
   5300         parser->m_doctypeSysid = poolStoreString(&parser->m_tempPool, enc,
   5301                                                  s + enc->minBytesPerChar,
   5302                                                  next - enc->minBytesPerChar);
   5303         if (parser->m_doctypeSysid == NULL)
   5304           return XML_ERROR_NO_MEMORY;
   5305         poolFinish(&parser->m_tempPool);
   5306         handleDefault = XML_FALSE;
   5307       }
   5308 #ifdef XML_DTD
   5309       else
   5310         /* use externalSubsetName to make parser->m_doctypeSysid non-NULL
   5311            for the case where no parser->m_startDoctypeDeclHandler is set */
   5312         parser->m_doctypeSysid = externalSubsetName;
   5313 #endif /* XML_DTD */
   5314       if (! dtd->standalone
   5315 #ifdef XML_DTD
   5316           && ! parser->m_paramEntityParsing
   5317 #endif /* XML_DTD */
   5318           && parser->m_notStandaloneHandler
   5319           && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
   5320         return XML_ERROR_NOT_STANDALONE;
   5321 #ifndef XML_DTD
   5322       break;
   5323 #else  /* XML_DTD */
   5324       if (! parser->m_declEntity) {
   5325         parser->m_declEntity = (ENTITY *)lookup(
   5326             parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY));
   5327         if (! parser->m_declEntity)
   5328           return XML_ERROR_NO_MEMORY;
   5329         parser->m_declEntity->publicId = NULL;
   5330       }
   5331 #endif /* XML_DTD */
   5332       /* fall through */
   5333     case XML_ROLE_ENTITY_SYSTEM_ID:
   5334       if (dtd->keepProcessing && parser->m_declEntity) {
   5335         parser->m_declEntity->systemId
   5336             = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
   5337                               next - enc->minBytesPerChar);
   5338         if (! parser->m_declEntity->systemId)
   5339           return XML_ERROR_NO_MEMORY;
   5340         parser->m_declEntity->base = parser->m_curBase;
   5341         poolFinish(&dtd->pool);
   5342         /* Don't suppress the default handler if we fell through from
   5343          * the XML_ROLE_DOCTYPE_SYSTEM_ID case.
   5344          */
   5345         if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_SYSTEM_ID)
   5346           handleDefault = XML_FALSE;
   5347       }
   5348       break;
   5349     case XML_ROLE_ENTITY_COMPLETE:
   5350 #if XML_GE == 0
   5351       // This will store "&amp;entity123;" in entity->textPtr
   5352       // to end up as "&entity123;" in the handler.
   5353       if (parser->m_declEntity != NULL) {
   5354         const enum XML_Error result
   5355             = storeSelfEntityValue(parser, parser->m_declEntity);
   5356         if (result != XML_ERROR_NONE)
   5357           return result;
   5358       }
   5359 #endif
   5360       if (dtd->keepProcessing && parser->m_declEntity
   5361           && parser->m_entityDeclHandler) {
   5362         *eventEndPP = s;
   5363         parser->m_entityDeclHandler(
   5364             parser->m_handlerArg, parser->m_declEntity->name,
   5365             parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base,
   5366             parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0);
   5367         handleDefault = XML_FALSE;
   5368       }
   5369       break;
   5370     case XML_ROLE_ENTITY_NOTATION_NAME:
   5371       if (dtd->keepProcessing && parser->m_declEntity) {
   5372         parser->m_declEntity->notation
   5373             = poolStoreString(&dtd->pool, enc, s, next);
   5374         if (! parser->m_declEntity->notation)
   5375           return XML_ERROR_NO_MEMORY;
   5376         poolFinish(&dtd->pool);
   5377         if (parser->m_unparsedEntityDeclHandler) {
   5378           *eventEndPP = s;
   5379           parser->m_unparsedEntityDeclHandler(
   5380               parser->m_handlerArg, parser->m_declEntity->name,
   5381               parser->m_declEntity->base, parser->m_declEntity->systemId,
   5382               parser->m_declEntity->publicId, parser->m_declEntity->notation);
   5383           handleDefault = XML_FALSE;
   5384         } else if (parser->m_entityDeclHandler) {
   5385           *eventEndPP = s;
   5386           parser->m_entityDeclHandler(
   5387               parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0,
   5388               parser->m_declEntity->base, parser->m_declEntity->systemId,
   5389               parser->m_declEntity->publicId, parser->m_declEntity->notation);
   5390           handleDefault = XML_FALSE;
   5391         }
   5392       }
   5393       break;
   5394     case XML_ROLE_GENERAL_ENTITY_NAME: {
   5395       if (XmlPredefinedEntityName(enc, s, next)) {
   5396         parser->m_declEntity = NULL;
   5397         break;
   5398       }
   5399       if (dtd->keepProcessing) {
   5400         const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
   5401         if (! name)
   5402           return XML_ERROR_NO_MEMORY;
   5403         parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities,
   5404                                                 name, sizeof(ENTITY));
   5405         if (! parser->m_declEntity)
   5406           return XML_ERROR_NO_MEMORY;
   5407         if (parser->m_declEntity->name != name) {
   5408           poolDiscard(&dtd->pool);
   5409           parser->m_declEntity = NULL;
   5410         } else {
   5411           poolFinish(&dtd->pool);
   5412           parser->m_declEntity->publicId = NULL;
   5413           parser->m_declEntity->is_param = XML_FALSE;
   5414           /* if we have a parent parser or are reading an internal parameter
   5415              entity, then the entity declaration is not considered "internal"
   5416           */
   5417           parser->m_declEntity->is_internal
   5418               = ! (parser->m_parentParser || parser->m_openInternalEntities);
   5419           if (parser->m_entityDeclHandler)
   5420             handleDefault = XML_FALSE;
   5421         }
   5422       } else {
   5423         poolDiscard(&dtd->pool);
   5424         parser->m_declEntity = NULL;
   5425       }
   5426     } break;
   5427     case XML_ROLE_PARAM_ENTITY_NAME:
   5428 #ifdef XML_DTD
   5429       if (dtd->keepProcessing) {
   5430         const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
   5431         if (! name)
   5432           return XML_ERROR_NO_MEMORY;
   5433         parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
   5434                                                 name, sizeof(ENTITY));
   5435         if (! parser->m_declEntity)
   5436           return XML_ERROR_NO_MEMORY;
   5437         if (parser->m_declEntity->name != name) {
   5438           poolDiscard(&dtd->pool);
   5439           parser->m_declEntity = NULL;
   5440         } else {
   5441           poolFinish(&dtd->pool);
   5442           parser->m_declEntity->publicId = NULL;
   5443           parser->m_declEntity->is_param = XML_TRUE;
   5444           /* if we have a parent parser or are reading an internal parameter
   5445              entity, then the entity declaration is not considered "internal"
   5446           */
   5447           parser->m_declEntity->is_internal
   5448               = ! (parser->m_parentParser || parser->m_openInternalEntities);
   5449           if (parser->m_entityDeclHandler)
   5450             handleDefault = XML_FALSE;
   5451         }
   5452       } else {
   5453         poolDiscard(&dtd->pool);
   5454         parser->m_declEntity = NULL;
   5455       }
   5456 #else  /* not XML_DTD */
   5457       parser->m_declEntity = NULL;
   5458 #endif /* XML_DTD */
   5459       break;
   5460     case XML_ROLE_NOTATION_NAME:
   5461       parser->m_declNotationPublicId = NULL;
   5462       parser->m_declNotationName = NULL;
   5463       if (parser->m_notationDeclHandler) {
   5464         parser->m_declNotationName
   5465             = poolStoreString(&parser->m_tempPool, enc, s, next);
   5466         if (! parser->m_declNotationName)
   5467           return XML_ERROR_NO_MEMORY;
   5468         poolFinish(&parser->m_tempPool);
   5469         handleDefault = XML_FALSE;
   5470       }
   5471       break;
   5472     case XML_ROLE_NOTATION_PUBLIC_ID:
   5473       if (! XmlIsPublicId(enc, s, next, eventPP))
   5474         return XML_ERROR_PUBLICID;
   5475       if (parser
   5476               ->m_declNotationName) { /* means m_notationDeclHandler != NULL */
   5477         XML_Char *tem = poolStoreString(&parser->m_tempPool, enc,
   5478                                         s + enc->minBytesPerChar,
   5479                                         next - enc->minBytesPerChar);
   5480         if (! tem)
   5481           return XML_ERROR_NO_MEMORY;
   5482         normalizePublicId(tem);
   5483         parser->m_declNotationPublicId = tem;
   5484         poolFinish(&parser->m_tempPool);
   5485         handleDefault = XML_FALSE;
   5486       }
   5487       break;
   5488     case XML_ROLE_NOTATION_SYSTEM_ID:
   5489       if (parser->m_declNotationName && parser->m_notationDeclHandler) {
   5490         const XML_Char *systemId = poolStoreString(&parser->m_tempPool, enc,
   5491                                                    s + enc->minBytesPerChar,
   5492                                                    next - enc->minBytesPerChar);
   5493         if (! systemId)
   5494           return XML_ERROR_NO_MEMORY;
   5495         *eventEndPP = s;
   5496         parser->m_notationDeclHandler(
   5497             parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
   5498             systemId, parser->m_declNotationPublicId);
   5499         handleDefault = XML_FALSE;
   5500       }
   5501       poolClear(&parser->m_tempPool);
   5502       break;
   5503     case XML_ROLE_NOTATION_NO_SYSTEM_ID:
   5504       if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) {
   5505         *eventEndPP = s;
   5506         parser->m_notationDeclHandler(
   5507             parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
   5508             0, parser->m_declNotationPublicId);
   5509         handleDefault = XML_FALSE;
   5510       }
   5511       poolClear(&parser->m_tempPool);
   5512       break;
   5513     case XML_ROLE_ERROR:
   5514       switch (tok) {
   5515       case XML_TOK_PARAM_ENTITY_REF:
   5516         /* PE references in internal subset are
   5517            not allowed within declarations. */
   5518         return XML_ERROR_PARAM_ENTITY_REF;
   5519       case XML_TOK_XML_DECL:
   5520         return XML_ERROR_MISPLACED_XML_PI;
   5521       default:
   5522         return XML_ERROR_SYNTAX;
   5523       }
   5524 #ifdef XML_DTD
   5525     case XML_ROLE_IGNORE_SECT: {
   5526       enum XML_Error result;
   5527       if (parser->m_defaultHandler)
   5528         reportDefault(parser, enc, s, next);
   5529       handleDefault = XML_FALSE;
   5530       result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
   5531       if (result != XML_ERROR_NONE)
   5532         return result;
   5533       else if (! next) {
   5534         parser->m_processor = ignoreSectionProcessor;
   5535         return result;
   5536       }
   5537     } break;
   5538 #endif /* XML_DTD */
   5539     case XML_ROLE_GROUP_OPEN:
   5540       if (parser->m_prologState.level >= parser->m_groupSize) {
   5541         if (parser->m_groupSize) {
   5542           {
   5543             /* Detect and prevent integer overflow */
   5544             if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
   5545               return XML_ERROR_NO_MEMORY;
   5546             }
   5547 
   5548             char *const new_connector = (char *)REALLOC(
   5549                 parser, parser->m_groupConnector, parser->m_groupSize *= 2);
   5550             if (new_connector == NULL) {
   5551               parser->m_groupSize /= 2;
   5552               return XML_ERROR_NO_MEMORY;
   5553             }
   5554             parser->m_groupConnector = new_connector;
   5555           }
   5556 
   5557           if (dtd->scaffIndex) {
   5558             /* Detect and prevent integer overflow.
   5559              * The preprocessor guard addresses the "always false" warning
   5560              * from -Wtype-limits on platforms where
   5561              * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   5562 #if UINT_MAX >= SIZE_MAX
   5563             if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
   5564               return XML_ERROR_NO_MEMORY;
   5565             }
   5566 #endif
   5567 
   5568             int *const new_scaff_index = (int *)REALLOC(
   5569                 parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
   5570             if (new_scaff_index == NULL)
   5571               return XML_ERROR_NO_MEMORY;
   5572             dtd->scaffIndex = new_scaff_index;
   5573           }
   5574         } else {
   5575           parser->m_groupConnector
   5576               = (char *)MALLOC(parser, parser->m_groupSize = 32);
   5577           if (! parser->m_groupConnector) {
   5578             parser->m_groupSize = 0;
   5579             return XML_ERROR_NO_MEMORY;
   5580           }
   5581         }
   5582       }
   5583       parser->m_groupConnector[parser->m_prologState.level] = 0;
   5584       if (dtd->in_eldecl) {
   5585         int myindex = nextScaffoldPart(parser);
   5586         if (myindex < 0)
   5587           return XML_ERROR_NO_MEMORY;
   5588         assert(dtd->scaffIndex != NULL);
   5589         dtd->scaffIndex[dtd->scaffLevel] = myindex;
   5590         dtd->scaffLevel++;
   5591         dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
   5592         if (parser->m_elementDeclHandler)
   5593           handleDefault = XML_FALSE;
   5594       }
   5595       break;
   5596     case XML_ROLE_GROUP_SEQUENCE:
   5597       if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_PIPE)
   5598         return XML_ERROR_SYNTAX;
   5599       parser->m_groupConnector[parser->m_prologState.level] = ASCII_COMMA;
   5600       if (dtd->in_eldecl && parser->m_elementDeclHandler)
   5601         handleDefault = XML_FALSE;
   5602       break;
   5603     case XML_ROLE_GROUP_CHOICE:
   5604       if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_COMMA)
   5605         return XML_ERROR_SYNTAX;
   5606       if (dtd->in_eldecl
   5607           && ! parser->m_groupConnector[parser->m_prologState.level]
   5608           && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
   5609               != XML_CTYPE_MIXED)) {
   5610         dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
   5611             = XML_CTYPE_CHOICE;
   5612         if (parser->m_elementDeclHandler)
   5613           handleDefault = XML_FALSE;
   5614       }
   5615       parser->m_groupConnector[parser->m_prologState.level] = ASCII_PIPE;
   5616       break;
   5617     case XML_ROLE_PARAM_ENTITY_REF:
   5618 #ifdef XML_DTD
   5619     case XML_ROLE_INNER_PARAM_ENTITY_REF:
   5620       dtd->hasParamEntityRefs = XML_TRUE;
   5621       if (! parser->m_paramEntityParsing)
   5622         dtd->keepProcessing = dtd->standalone;
   5623       else {
   5624         const XML_Char *name;
   5625         ENTITY *entity;
   5626         name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
   5627                                next - enc->minBytesPerChar);
   5628         if (! name)
   5629           return XML_ERROR_NO_MEMORY;
   5630         entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
   5631         poolDiscard(&dtd->pool);
   5632         /* first, determine if a check for an existing declaration is needed;
   5633            if yes, check that the entity exists, and that it is internal,
   5634            otherwise call the skipped entity handler
   5635         */
   5636         if (parser->m_prologState.documentEntity
   5637             && (dtd->standalone ? ! parser->m_openInternalEntities
   5638                                 : ! dtd->hasParamEntityRefs)) {
   5639           if (! entity)
   5640             return XML_ERROR_UNDEFINED_ENTITY;
   5641           else if (! entity->is_internal) {
   5642             /* It's hard to exhaustively search the code to be sure,
   5643              * but there doesn't seem to be a way of executing the
   5644              * following line.  There are two cases:
   5645              *
   5646              * If 'standalone' is false, the DTD must have no
   5647              * parameter entities or we wouldn't have passed the outer
   5648              * 'if' statement.  That means the only entity in the hash
   5649              * table is the external subset name "#" which cannot be
   5650              * given as a parameter entity name in XML syntax, so the
   5651              * lookup must have returned NULL and we don't even reach
   5652              * the test for an internal entity.
   5653              *
   5654              * If 'standalone' is true, it does not seem to be
   5655              * possible to create entities taking this code path that
   5656              * are not internal entities, so fail the test above.
   5657              *
   5658              * Because this analysis is very uncertain, the code is
   5659              * being left in place and merely removed from the
   5660              * coverage test statistics.
   5661              */
   5662             return XML_ERROR_ENTITY_DECLARED_IN_PE; /* LCOV_EXCL_LINE */
   5663           }
   5664         } else if (! entity) {
   5665           dtd->keepProcessing = dtd->standalone;
   5666           /* cannot report skipped entities in declarations */
   5667           if ((role == XML_ROLE_PARAM_ENTITY_REF)
   5668               && parser->m_skippedEntityHandler) {
   5669             parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1);
   5670             handleDefault = XML_FALSE;
   5671           }
   5672           break;
   5673         }
   5674         if (entity->open)
   5675           return XML_ERROR_RECURSIVE_ENTITY_REF;
   5676         if (entity->textPtr) {
   5677           enum XML_Error result;
   5678           XML_Bool betweenDecl
   5679               = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
   5680           result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL);
   5681           if (result != XML_ERROR_NONE)
   5682             return result;
   5683           handleDefault = XML_FALSE;
   5684           break;
   5685         }
   5686         if (parser->m_externalEntityRefHandler) {
   5687           dtd->paramEntityRead = XML_FALSE;
   5688           entity->open = XML_TRUE;
   5689           entityTrackingOnOpen(parser, entity, __LINE__);
   5690           if (! parser->m_externalEntityRefHandler(
   5691                   parser->m_externalEntityRefHandlerArg, 0, entity->base,
   5692                   entity->systemId, entity->publicId)) {
   5693             entityTrackingOnClose(parser, entity, __LINE__);
   5694             entity->open = XML_FALSE;
   5695             return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
   5696           }
   5697           entityTrackingOnClose(parser, entity, __LINE__);
   5698           entity->open = XML_FALSE;
   5699           handleDefault = XML_FALSE;
   5700           if (! dtd->paramEntityRead) {
   5701             dtd->keepProcessing = dtd->standalone;
   5702             break;
   5703           }
   5704         } else {
   5705           dtd->keepProcessing = dtd->standalone;
   5706           break;
   5707         }
   5708       }
   5709 #endif /* XML_DTD */
   5710       if (! dtd->standalone && parser->m_notStandaloneHandler
   5711           && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
   5712         return XML_ERROR_NOT_STANDALONE;
   5713       break;
   5714 
   5715       /* Element declaration stuff */
   5716 
   5717     case XML_ROLE_ELEMENT_NAME:
   5718       if (parser->m_elementDeclHandler) {
   5719         parser->m_declElementType = getElementType(parser, enc, s, next);
   5720         if (! parser->m_declElementType)
   5721           return XML_ERROR_NO_MEMORY;
   5722         dtd->scaffLevel = 0;
   5723         dtd->scaffCount = 0;
   5724         dtd->in_eldecl = XML_TRUE;
   5725         handleDefault = XML_FALSE;
   5726       }
   5727       break;
   5728 
   5729     case XML_ROLE_CONTENT_ANY:
   5730     case XML_ROLE_CONTENT_EMPTY:
   5731       if (dtd->in_eldecl) {
   5732         if (parser->m_elementDeclHandler) {
   5733           XML_Content *content
   5734               = (XML_Content *)MALLOC(parser, sizeof(XML_Content));
   5735           if (! content)
   5736             return XML_ERROR_NO_MEMORY;
   5737           content->quant = XML_CQUANT_NONE;
   5738           content->name = NULL;
   5739           content->numchildren = 0;
   5740           content->children = NULL;
   5741           content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY
   5742                                                           : XML_CTYPE_EMPTY);
   5743           *eventEndPP = s;
   5744           parser->m_elementDeclHandler(
   5745               parser->m_handlerArg, parser->m_declElementType->name, content);
   5746           handleDefault = XML_FALSE;
   5747         }
   5748         dtd->in_eldecl = XML_FALSE;
   5749       }
   5750       break;
   5751 
   5752     case XML_ROLE_CONTENT_PCDATA:
   5753       if (dtd->in_eldecl) {
   5754         dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
   5755             = XML_CTYPE_MIXED;
   5756         if (parser->m_elementDeclHandler)
   5757           handleDefault = XML_FALSE;
   5758       }
   5759       break;
   5760 
   5761     case XML_ROLE_CONTENT_ELEMENT:
   5762       quant = XML_CQUANT_NONE;
   5763       goto elementContent;
   5764     case XML_ROLE_CONTENT_ELEMENT_OPT:
   5765       quant = XML_CQUANT_OPT;
   5766       goto elementContent;
   5767     case XML_ROLE_CONTENT_ELEMENT_REP:
   5768       quant = XML_CQUANT_REP;
   5769       goto elementContent;
   5770     case XML_ROLE_CONTENT_ELEMENT_PLUS:
   5771       quant = XML_CQUANT_PLUS;
   5772     elementContent:
   5773       if (dtd->in_eldecl) {
   5774         ELEMENT_TYPE *el;
   5775         const XML_Char *name;
   5776         size_t nameLen;
   5777         const char *nxt
   5778             = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
   5779         int myindex = nextScaffoldPart(parser);
   5780         if (myindex < 0)
   5781           return XML_ERROR_NO_MEMORY;
   5782         dtd->scaffold[myindex].type = XML_CTYPE_NAME;
   5783         dtd->scaffold[myindex].quant = quant;
   5784         el = getElementType(parser, enc, s, nxt);
   5785         if (! el)
   5786           return XML_ERROR_NO_MEMORY;
   5787         name = el->name;
   5788         dtd->scaffold[myindex].name = name;
   5789         nameLen = 0;
   5790         for (; name[nameLen++];)
   5791           ;
   5792 
   5793         /* Detect and prevent integer overflow */
   5794         if (nameLen > UINT_MAX - dtd->contentStringLen) {
   5795           return XML_ERROR_NO_MEMORY;
   5796         }
   5797 
   5798         dtd->contentStringLen += (unsigned)nameLen;
   5799         if (parser->m_elementDeclHandler)
   5800           handleDefault = XML_FALSE;
   5801       }
   5802       break;
   5803 
   5804     case XML_ROLE_GROUP_CLOSE:
   5805       quant = XML_CQUANT_NONE;
   5806       goto closeGroup;
   5807     case XML_ROLE_GROUP_CLOSE_OPT:
   5808       quant = XML_CQUANT_OPT;
   5809       goto closeGroup;
   5810     case XML_ROLE_GROUP_CLOSE_REP:
   5811       quant = XML_CQUANT_REP;
   5812       goto closeGroup;
   5813     case XML_ROLE_GROUP_CLOSE_PLUS:
   5814       quant = XML_CQUANT_PLUS;
   5815     closeGroup:
   5816       if (dtd->in_eldecl) {
   5817         if (parser->m_elementDeclHandler)
   5818           handleDefault = XML_FALSE;
   5819         dtd->scaffLevel--;
   5820         dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
   5821         if (dtd->scaffLevel == 0) {
   5822           if (! handleDefault) {
   5823             XML_Content *model = build_model(parser);
   5824             if (! model)
   5825               return XML_ERROR_NO_MEMORY;
   5826             *eventEndPP = s;
   5827             parser->m_elementDeclHandler(
   5828                 parser->m_handlerArg, parser->m_declElementType->name, model);
   5829           }
   5830           dtd->in_eldecl = XML_FALSE;
   5831           dtd->contentStringLen = 0;
   5832         }
   5833       }
   5834       break;
   5835       /* End element declaration stuff */
   5836 
   5837     case XML_ROLE_PI:
   5838       if (! reportProcessingInstruction(parser, enc, s, next))
   5839         return XML_ERROR_NO_MEMORY;
   5840       handleDefault = XML_FALSE;
   5841       break;
   5842     case XML_ROLE_COMMENT:
   5843       if (! reportComment(parser, enc, s, next))
   5844         return XML_ERROR_NO_MEMORY;
   5845       handleDefault = XML_FALSE;
   5846       break;
   5847     case XML_ROLE_NONE:
   5848       switch (tok) {
   5849       case XML_TOK_BOM:
   5850         handleDefault = XML_FALSE;
   5851         break;
   5852       }
   5853       break;
   5854     case XML_ROLE_DOCTYPE_NONE:
   5855       if (parser->m_startDoctypeDeclHandler)
   5856         handleDefault = XML_FALSE;
   5857       break;
   5858     case XML_ROLE_ENTITY_NONE:
   5859       if (dtd->keepProcessing && parser->m_entityDeclHandler)
   5860         handleDefault = XML_FALSE;
   5861       break;
   5862     case XML_ROLE_NOTATION_NONE:
   5863       if (parser->m_notationDeclHandler)
   5864         handleDefault = XML_FALSE;
   5865       break;
   5866     case XML_ROLE_ATTLIST_NONE:
   5867       if (dtd->keepProcessing && parser->m_attlistDeclHandler)
   5868         handleDefault = XML_FALSE;
   5869       break;
   5870     case XML_ROLE_ELEMENT_NONE:
   5871       if (parser->m_elementDeclHandler)
   5872         handleDefault = XML_FALSE;
   5873       break;
   5874     } /* end of big switch */
   5875 
   5876     if (handleDefault && parser->m_defaultHandler)
   5877       reportDefault(parser, enc, s, next);
   5878 
   5879     switch (parser->m_parsingStatus.parsing) {
   5880     case XML_SUSPENDED:
   5881       *nextPtr = next;
   5882       return XML_ERROR_NONE;
   5883     case XML_FINISHED:
   5884       return XML_ERROR_ABORTED;
   5885     case XML_PARSING:
   5886       if (parser->m_reenter) {
   5887         *nextPtr = next;
   5888         return XML_ERROR_NONE;
   5889       }
   5890     /* Fall through */
   5891     default:
   5892       s = next;
   5893       tok = XmlPrologTok(enc, s, end, &next);
   5894     }
   5895   }
   5896   /* not reached */
   5897 }
   5898 
   5899 static enum XML_Error PTRCALL
   5900 epilogProcessor(XML_Parser parser, const char *s, const char *end,
   5901                 const char **nextPtr) {
   5902   parser->m_processor = epilogProcessor;
   5903   parser->m_eventPtr = s;
   5904   for (;;) {
   5905     const char *next = NULL;
   5906     int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
   5907 #if XML_GE == 1
   5908     if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
   5909                                   XML_ACCOUNT_DIRECT)) {
   5910       accountingOnAbort(parser);
   5911       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   5912     }
   5913 #endif
   5914     parser->m_eventEndPtr = next;
   5915     switch (tok) {
   5916     /* report partial linebreak - it might be the last token */
   5917     case -XML_TOK_PROLOG_S:
   5918       if (parser->m_defaultHandler) {
   5919         reportDefault(parser, parser->m_encoding, s, next);
   5920         if (parser->m_parsingStatus.parsing == XML_FINISHED)
   5921           return XML_ERROR_ABORTED;
   5922       }
   5923       *nextPtr = next;
   5924       return XML_ERROR_NONE;
   5925     case XML_TOK_NONE:
   5926       *nextPtr = s;
   5927       return XML_ERROR_NONE;
   5928     case XML_TOK_PROLOG_S:
   5929       if (parser->m_defaultHandler)
   5930         reportDefault(parser, parser->m_encoding, s, next);
   5931       break;
   5932     case XML_TOK_PI:
   5933       if (! reportProcessingInstruction(parser, parser->m_encoding, s, next))
   5934         return XML_ERROR_NO_MEMORY;
   5935       break;
   5936     case XML_TOK_COMMENT:
   5937       if (! reportComment(parser, parser->m_encoding, s, next))
   5938         return XML_ERROR_NO_MEMORY;
   5939       break;
   5940     case XML_TOK_INVALID:
   5941       parser->m_eventPtr = next;
   5942       return XML_ERROR_INVALID_TOKEN;
   5943     case XML_TOK_PARTIAL:
   5944       if (! parser->m_parsingStatus.finalBuffer) {
   5945         *nextPtr = s;
   5946         return XML_ERROR_NONE;
   5947       }
   5948       return XML_ERROR_UNCLOSED_TOKEN;
   5949     case XML_TOK_PARTIAL_CHAR:
   5950       if (! parser->m_parsingStatus.finalBuffer) {
   5951         *nextPtr = s;
   5952         return XML_ERROR_NONE;
   5953       }
   5954       return XML_ERROR_PARTIAL_CHAR;
   5955     default:
   5956       return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
   5957     }
   5958     switch (parser->m_parsingStatus.parsing) {
   5959     case XML_SUSPENDED:
   5960       parser->m_eventPtr = next;
   5961       *nextPtr = next;
   5962       return XML_ERROR_NONE;
   5963     case XML_FINISHED:
   5964       parser->m_eventPtr = next;
   5965       return XML_ERROR_ABORTED;
   5966     case XML_PARSING:
   5967       if (parser->m_reenter) {
   5968         return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
   5969       }
   5970     /* Fall through */
   5971     default:;
   5972       parser->m_eventPtr = s = next;
   5973     }
   5974   }
   5975 }
   5976 
   5977 static enum XML_Error
   5978 processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
   5979               enum EntityType type) {
   5980   OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList;
   5981   switch (type) {
   5982   case ENTITY_INTERNAL:
   5983     parser->m_processor = internalEntityProcessor;
   5984     openEntityList = &parser->m_openInternalEntities;
   5985     freeEntityList = &parser->m_freeInternalEntities;
   5986     break;
   5987   case ENTITY_ATTRIBUTE:
   5988     openEntityList = &parser->m_openAttributeEntities;
   5989     freeEntityList = &parser->m_freeAttributeEntities;
   5990     break;
   5991   case ENTITY_VALUE:
   5992     openEntityList = &parser->m_openValueEntities;
   5993     freeEntityList = &parser->m_freeValueEntities;
   5994     break;
   5995     /* default case serves merely as a safety net in case of a
   5996      * wrong entityType. Therefore we exclude the following lines
   5997      * from the test coverage.
   5998      *
   5999      * LCOV_EXCL_START
   6000      */
   6001   default:
   6002     // Should not reach here
   6003     assert(0);
   6004     /* LCOV_EXCL_STOP */
   6005   }
   6006 
   6007   if (*freeEntityList) {
   6008     openEntity = *freeEntityList;
   6009     *freeEntityList = openEntity->next;
   6010   } else {
   6011     openEntity
   6012         = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
   6013     if (! openEntity)
   6014       return XML_ERROR_NO_MEMORY;
   6015   }
   6016   entity->open = XML_TRUE;
   6017   entity->hasMore = XML_TRUE;
   6018 #if XML_GE == 1
   6019   entityTrackingOnOpen(parser, entity, __LINE__);
   6020 #endif
   6021   entity->processed = 0;
   6022   openEntity->next = *openEntityList;
   6023   *openEntityList = openEntity;
   6024   openEntity->entity = entity;
   6025   openEntity->type = type;
   6026   openEntity->startTagLevel = parser->m_tagLevel;
   6027   openEntity->betweenDecl = betweenDecl;
   6028   openEntity->internalEventPtr = NULL;
   6029   openEntity->internalEventEndPtr = NULL;
   6030 
   6031   // Only internal entities make use of the reenter flag
   6032   // therefore no need to set it for other entity types
   6033   if (type == ENTITY_INTERNAL) {
   6034     triggerReenter(parser);
   6035   }
   6036   return XML_ERROR_NONE;
   6037 }
   6038 
   6039 static enum XML_Error PTRCALL
   6040 internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
   6041                         const char **nextPtr) {
   6042   UNUSED_P(s);
   6043   UNUSED_P(end);
   6044   UNUSED_P(nextPtr);
   6045   ENTITY *entity;
   6046   const char *textStart, *textEnd;
   6047   const char *next;
   6048   enum XML_Error result;
   6049   OPEN_INTERNAL_ENTITY *openEntity = parser->m_openInternalEntities;
   6050   if (! openEntity)
   6051     return XML_ERROR_UNEXPECTED_STATE;
   6052 
   6053   entity = openEntity->entity;
   6054 
   6055   // This will return early
   6056   if (entity->hasMore) {
   6057     textStart = ((const char *)entity->textPtr) + entity->processed;
   6058     textEnd = (const char *)(entity->textPtr + entity->textLen);
   6059     /* Set a safe default value in case 'next' does not get set */
   6060     next = textStart;
   6061 
   6062     if (entity->is_param) {
   6063       int tok
   6064           = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
   6065       result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
   6066                         tok, next, &next, XML_FALSE, XML_FALSE,
   6067                         XML_ACCOUNT_ENTITY_EXPANSION);
   6068     } else {
   6069       result = doContent(parser, openEntity->startTagLevel,
   6070                          parser->m_internalEncoding, textStart, textEnd, &next,
   6071                          XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
   6072     }
   6073 
   6074     if (result != XML_ERROR_NONE)
   6075       return result;
   6076     // Check if entity is complete, if not, mark down how much of it is
   6077     // processed
   6078     if (textEnd != next
   6079         && (parser->m_parsingStatus.parsing == XML_SUSPENDED
   6080             || (parser->m_parsingStatus.parsing == XML_PARSING
   6081                 && parser->m_reenter))) {
   6082       entity->processed = (int)(next - (const char *)entity->textPtr);
   6083       return result;
   6084     }
   6085 
   6086     // Entity is complete. We cannot close it here since we need to first
   6087     // process its possible inner entities (which are added to the
   6088     // m_openInternalEntities during doProlog or doContent calls above)
   6089     entity->hasMore = XML_FALSE;
   6090     triggerReenter(parser);
   6091     return result;
   6092   } // End of entity processing, "if" block will return here
   6093 
   6094   // Remove fully processed openEntity from open entity list.
   6095 #if XML_GE == 1
   6096   entityTrackingOnClose(parser, entity, __LINE__);
   6097 #endif
   6098   // openEntity is m_openInternalEntities' head, as we set it at the start of
   6099   // this function and we skipped doProlog and doContent calls with hasMore set
   6100   // to false. This means we can directly remove the head of
   6101   // m_openInternalEntities
   6102   assert(parser->m_openInternalEntities == openEntity);
   6103   entity->open = XML_FALSE;
   6104   parser->m_openInternalEntities = parser->m_openInternalEntities->next;
   6105 
   6106   /* put openEntity back in list of free instances */
   6107   openEntity->next = parser->m_freeInternalEntities;
   6108   parser->m_freeInternalEntities = openEntity;
   6109 
   6110   if (parser->m_openInternalEntities == NULL) {
   6111     parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
   6112   }
   6113   triggerReenter(parser);
   6114   return XML_ERROR_NONE;
   6115 }
   6116 
   6117 static enum XML_Error PTRCALL
   6118 errorProcessor(XML_Parser parser, const char *s, const char *end,
   6119                const char **nextPtr) {
   6120   UNUSED_P(s);
   6121   UNUSED_P(end);
   6122   UNUSED_P(nextPtr);
   6123   return parser->m_errorCode;
   6124 }
   6125 
   6126 static enum XML_Error
   6127 storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
   6128                     const char *ptr, const char *end, STRING_POOL *pool,
   6129                     enum XML_Account account) {
   6130   const char *next = ptr;
   6131   enum XML_Error result = XML_ERROR_NONE;
   6132 
   6133   while (1) {
   6134     if (! parser->m_openAttributeEntities) {
   6135       result = appendAttributeValue(parser, enc, isCdata, next, end, pool,
   6136                                     account, &next);
   6137     } else {
   6138       OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openAttributeEntities;
   6139       if (! openEntity)
   6140         return XML_ERROR_UNEXPECTED_STATE;
   6141 
   6142       ENTITY *const entity = openEntity->entity;
   6143       const char *const textStart
   6144           = ((const char *)entity->textPtr) + entity->processed;
   6145       const char *const textEnd
   6146           = (const char *)(entity->textPtr + entity->textLen);
   6147       /* Set a safe default value in case 'next' does not get set */
   6148       const char *nextInEntity = textStart;
   6149       if (entity->hasMore) {
   6150         result = appendAttributeValue(
   6151             parser, parser->m_internalEncoding, isCdata, textStart, textEnd,
   6152             pool, XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
   6153         if (result != XML_ERROR_NONE)
   6154           break;
   6155         // Check if entity is complete, if not, mark down how much of it is
   6156         // processed. A XML_SUSPENDED check here is not required as
   6157         // appendAttributeValue will never suspend the parser.
   6158         if (textEnd != nextInEntity) {
   6159           entity->processed
   6160               = (int)(nextInEntity - (const char *)entity->textPtr);
   6161           continue;
   6162         }
   6163 
   6164         // Entity is complete. We cannot close it here since we need to first
   6165         // process its possible inner entities (which are added to the
   6166         // m_openAttributeEntities during appendAttributeValue)
   6167         entity->hasMore = XML_FALSE;
   6168         continue;
   6169       } // End of entity processing, "if" block skips the rest
   6170 
   6171       // Remove fully processed openEntity from open entity list.
   6172 #if XML_GE == 1
   6173       entityTrackingOnClose(parser, entity, __LINE__);
   6174 #endif
   6175       // openEntity is m_openAttributeEntities' head, since we set it at the
   6176       // start of this function and because we skipped appendAttributeValue call
   6177       // with hasMore set to false. This means we can directly remove the head
   6178       // of m_openAttributeEntities
   6179       assert(parser->m_openAttributeEntities == openEntity);
   6180       entity->open = XML_FALSE;
   6181       parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
   6182 
   6183       /* put openEntity back in list of free instances */
   6184       openEntity->next = parser->m_freeAttributeEntities;
   6185       parser->m_freeAttributeEntities = openEntity;
   6186     }
   6187 
   6188     // Break if an error occurred or there is nothing left to process
   6189     if (result || (parser->m_openAttributeEntities == NULL && end == next)) {
   6190       break;
   6191     }
   6192   }
   6193 
   6194   if (result)
   6195     return result;
   6196   if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
   6197     poolChop(pool);
   6198   if (! poolAppendChar(pool, XML_T('\0')))
   6199     return XML_ERROR_NO_MEMORY;
   6200   return XML_ERROR_NONE;
   6201 }
   6202 
   6203 static enum XML_Error
   6204 appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
   6205                      const char *ptr, const char *end, STRING_POOL *pool,
   6206                      enum XML_Account account, const char **nextPtr) {
   6207   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   6208 #ifndef XML_DTD
   6209   UNUSED_P(account);
   6210 #endif
   6211 
   6212   for (;;) {
   6213     const char *next
   6214         = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
   6215     int tok = XmlAttributeValueTok(enc, ptr, end, &next);
   6216 #if XML_GE == 1
   6217     if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
   6218       accountingOnAbort(parser);
   6219       return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   6220     }
   6221 #endif
   6222     switch (tok) {
   6223     case XML_TOK_NONE:
   6224       if (nextPtr) {
   6225         *nextPtr = next;
   6226       }
   6227       return XML_ERROR_NONE;
   6228     case XML_TOK_INVALID:
   6229       if (enc == parser->m_encoding)
   6230         parser->m_eventPtr = next;
   6231       return XML_ERROR_INVALID_TOKEN;
   6232     case XML_TOK_PARTIAL:
   6233       if (enc == parser->m_encoding)
   6234         parser->m_eventPtr = ptr;
   6235       return XML_ERROR_INVALID_TOKEN;
   6236     case XML_TOK_CHAR_REF: {
   6237       XML_Char buf[XML_ENCODE_MAX];
   6238       int i;
   6239       int n = XmlCharRefNumber(enc, ptr);
   6240       if (n < 0) {
   6241         if (enc == parser->m_encoding)
   6242           parser->m_eventPtr = ptr;
   6243         return XML_ERROR_BAD_CHAR_REF;
   6244       }
   6245       if (! isCdata && n == 0x20 /* space */
   6246           && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
   6247         break;
   6248       n = XmlEncode(n, (ICHAR *)buf);
   6249       /* The XmlEncode() functions can never return 0 here.  That
   6250        * error return happens if the code point passed in is either
   6251        * negative or greater than or equal to 0x110000.  The
   6252        * XmlCharRefNumber() functions will all return a number
   6253        * strictly less than 0x110000 or a negative value if an error
   6254        * occurred.  The negative value is intercepted above, so
   6255        * XmlEncode() is never passed a value it might return an
   6256        * error for.
   6257        */
   6258       for (i = 0; i < n; i++) {
   6259         if (! poolAppendChar(pool, buf[i]))
   6260           return XML_ERROR_NO_MEMORY;
   6261       }
   6262     } break;
   6263     case XML_TOK_DATA_CHARS:
   6264       if (! poolAppend(pool, enc, ptr, next))
   6265         return XML_ERROR_NO_MEMORY;
   6266       break;
   6267     case XML_TOK_TRAILING_CR:
   6268       next = ptr + enc->minBytesPerChar;
   6269       /* fall through */
   6270     case XML_TOK_ATTRIBUTE_VALUE_S:
   6271     case XML_TOK_DATA_NEWLINE:
   6272       if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
   6273         break;
   6274       if (! poolAppendChar(pool, 0x20))
   6275         return XML_ERROR_NO_MEMORY;
   6276       break;
   6277     case XML_TOK_ENTITY_REF: {
   6278       const XML_Char *name;
   6279       ENTITY *entity;
   6280       char checkEntityDecl;
   6281       XML_Char ch = (XML_Char)XmlPredefinedEntityName(
   6282           enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
   6283       if (ch) {
   6284 #if XML_GE == 1
   6285         /* NOTE: We are replacing 4-6 characters original input for 1 character
   6286          *       so there is no amplification and hence recording without
   6287          *       protection. */
   6288         accountingDiffTolerated(parser, tok, (char *)&ch,
   6289                                 ((char *)&ch) + sizeof(XML_Char), __LINE__,
   6290                                 XML_ACCOUNT_ENTITY_EXPANSION);
   6291 #endif /* XML_GE == 1 */
   6292         if (! poolAppendChar(pool, ch))
   6293           return XML_ERROR_NO_MEMORY;
   6294         break;
   6295       }
   6296       name = poolStoreString(&parser->m_temp2Pool, enc,
   6297                              ptr + enc->minBytesPerChar,
   6298                              next - enc->minBytesPerChar);
   6299       if (! name)
   6300         return XML_ERROR_NO_MEMORY;
   6301       entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
   6302       poolDiscard(&parser->m_temp2Pool);
   6303       /* First, determine if a check for an existing declaration is needed;
   6304          if yes, check that the entity exists, and that it is internal.
   6305       */
   6306       if (pool == &dtd->pool) /* are we called from prolog? */
   6307         checkEntityDecl =
   6308 #ifdef XML_DTD
   6309             parser->m_prologState.documentEntity &&
   6310 #endif /* XML_DTD */
   6311             (dtd->standalone ? ! parser->m_openInternalEntities
   6312                              : ! dtd->hasParamEntityRefs);
   6313       else /* if (pool == &parser->m_tempPool): we are called from content */
   6314         checkEntityDecl = ! dtd->hasParamEntityRefs || dtd->standalone;
   6315       if (checkEntityDecl) {
   6316         if (! entity)
   6317           return XML_ERROR_UNDEFINED_ENTITY;
   6318         else if (! entity->is_internal)
   6319           return XML_ERROR_ENTITY_DECLARED_IN_PE;
   6320       } else if (! entity) {
   6321         /* Cannot report skipped entity here - see comments on
   6322            parser->m_skippedEntityHandler.
   6323         if (parser->m_skippedEntityHandler)
   6324           parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
   6325         */
   6326         /* Cannot call the default handler because this would be
   6327            out of sync with the call to the startElementHandler.
   6328         if ((pool == &parser->m_tempPool) && parser->m_defaultHandler)
   6329           reportDefault(parser, enc, ptr, next);
   6330         */
   6331         break;
   6332       }
   6333       if (entity->open) {
   6334         if (enc == parser->m_encoding) {
   6335           /* It does not appear that this line can be executed.
   6336            *
   6337            * The "if (entity->open)" check catches recursive entity
   6338            * definitions.  In order to be called with an open
   6339            * entity, it must have gone through this code before and
   6340            * been through the recursive call to
   6341            * appendAttributeValue() some lines below.  That call
   6342            * sets the local encoding ("enc") to the parser's
   6343            * internal encoding (internal_utf8 or internal_utf16),
   6344            * which can never be the same as the principle encoding.
   6345            * It doesn't appear there is another code path that gets
   6346            * here with entity->open being TRUE.
   6347            *
   6348            * Since it is not certain that this logic is watertight,
   6349            * we keep the line and merely exclude it from coverage
   6350            * tests.
   6351            */
   6352           parser->m_eventPtr = ptr; /* LCOV_EXCL_LINE */
   6353         }
   6354         return XML_ERROR_RECURSIVE_ENTITY_REF;
   6355       }
   6356       if (entity->notation) {
   6357         if (enc == parser->m_encoding)
   6358           parser->m_eventPtr = ptr;
   6359         return XML_ERROR_BINARY_ENTITY_REF;
   6360       }
   6361       if (! entity->textPtr) {
   6362         if (enc == parser->m_encoding)
   6363           parser->m_eventPtr = ptr;
   6364         return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
   6365       } else {
   6366         enum XML_Error result;
   6367         result = processEntity(parser, entity, XML_FALSE, ENTITY_ATTRIBUTE);
   6368         if ((result == XML_ERROR_NONE) && (nextPtr != NULL)) {
   6369           *nextPtr = next;
   6370         }
   6371         return result;
   6372       }
   6373     } break;
   6374     default:
   6375       /* The only token returned by XmlAttributeValueTok() that does
   6376        * not have an explicit case here is XML_TOK_PARTIAL_CHAR.
   6377        * Getting that would require an entity name to contain an
   6378        * incomplete XML character (e.g. \xE2\x82); however previous
   6379        * tokenisers will have already recognised and rejected such
   6380        * names before XmlAttributeValueTok() gets a look-in.  This
   6381        * default case should be retained as a safety net, but the code
   6382        * excluded from coverage tests.
   6383        *
   6384        * LCOV_EXCL_START
   6385        */
   6386       if (enc == parser->m_encoding)
   6387         parser->m_eventPtr = ptr;
   6388       return XML_ERROR_UNEXPECTED_STATE;
   6389       /* LCOV_EXCL_STOP */
   6390     }
   6391     ptr = next;
   6392   }
   6393   /* not reached */
   6394 }
   6395 
   6396 #if XML_GE == 1
   6397 static enum XML_Error
   6398 storeEntityValue(XML_Parser parser, const ENCODING *enc,
   6399                  const char *entityTextPtr, const char *entityTextEnd,
   6400                  enum XML_Account account, const char **nextPtr) {
   6401   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   6402   STRING_POOL *pool = &(dtd->entityValuePool);
   6403   enum XML_Error result = XML_ERROR_NONE;
   6404 #  ifdef XML_DTD
   6405   int oldInEntityValue = parser->m_prologState.inEntityValue;
   6406   parser->m_prologState.inEntityValue = 1;
   6407 #  else
   6408   UNUSED_P(account);
   6409 #  endif /* XML_DTD */
   6410   /* never return Null for the value argument in EntityDeclHandler,
   6411      since this would indicate an external entity; therefore we
   6412      have to make sure that entityValuePool.start is not null */
   6413   if (! pool->blocks) {
   6414     if (! poolGrow(pool))
   6415       return XML_ERROR_NO_MEMORY;
   6416   }
   6417 
   6418   const char *next;
   6419   for (;;) {
   6420     next
   6421         = entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
   6422     int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
   6423 
   6424     if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
   6425                                   account)) {
   6426       accountingOnAbort(parser);
   6427       result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
   6428       goto endEntityValue;
   6429     }
   6430 
   6431     switch (tok) {
   6432     case XML_TOK_PARAM_ENTITY_REF:
   6433 #  ifdef XML_DTD
   6434       if (parser->m_isParamEntity || enc != parser->m_encoding) {
   6435         const XML_Char *name;
   6436         ENTITY *entity;
   6437         name = poolStoreString(&parser->m_tempPool, enc,
   6438                                entityTextPtr + enc->minBytesPerChar,
   6439                                next - enc->minBytesPerChar);
   6440         if (! name) {
   6441           result = XML_ERROR_NO_MEMORY;
   6442           goto endEntityValue;
   6443         }
   6444         entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
   6445         poolDiscard(&parser->m_tempPool);
   6446         if (! entity) {
   6447           /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
   6448           /* cannot report skipped entity here - see comments on
   6449              parser->m_skippedEntityHandler
   6450           if (parser->m_skippedEntityHandler)
   6451             parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
   6452           */
   6453           dtd->keepProcessing = dtd->standalone;
   6454           goto endEntityValue;
   6455         }
   6456         if (entity->open || (entity == parser->m_declEntity)) {
   6457           if (enc == parser->m_encoding)
   6458             parser->m_eventPtr = entityTextPtr;
   6459           result = XML_ERROR_RECURSIVE_ENTITY_REF;
   6460           goto endEntityValue;
   6461         }
   6462         if (entity->systemId) {
   6463           if (parser->m_externalEntityRefHandler) {
   6464             dtd->paramEntityRead = XML_FALSE;
   6465             entity->open = XML_TRUE;
   6466             entityTrackingOnOpen(parser, entity, __LINE__);
   6467             if (! parser->m_externalEntityRefHandler(
   6468                     parser->m_externalEntityRefHandlerArg, 0, entity->base,
   6469                     entity->systemId, entity->publicId)) {
   6470               entityTrackingOnClose(parser, entity, __LINE__);
   6471               entity->open = XML_FALSE;
   6472               result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
   6473               goto endEntityValue;
   6474             }
   6475             entityTrackingOnClose(parser, entity, __LINE__);
   6476             entity->open = XML_FALSE;
   6477             if (! dtd->paramEntityRead)
   6478               dtd->keepProcessing = dtd->standalone;
   6479           } else
   6480             dtd->keepProcessing = dtd->standalone;
   6481         } else {
   6482           result = processEntity(parser, entity, XML_FALSE, ENTITY_VALUE);
   6483           goto endEntityValue;
   6484         }
   6485         break;
   6486       }
   6487 #  endif /* XML_DTD */
   6488       /* In the internal subset, PE references are not legal
   6489          within markup declarations, e.g entity values in this case. */
   6490       parser->m_eventPtr = entityTextPtr;
   6491       result = XML_ERROR_PARAM_ENTITY_REF;
   6492       goto endEntityValue;
   6493     case XML_TOK_NONE:
   6494       result = XML_ERROR_NONE;
   6495       goto endEntityValue;
   6496     case XML_TOK_ENTITY_REF:
   6497     case XML_TOK_DATA_CHARS:
   6498       if (! poolAppend(pool, enc, entityTextPtr, next)) {
   6499         result = XML_ERROR_NO_MEMORY;
   6500         goto endEntityValue;
   6501       }
   6502       break;
   6503     case XML_TOK_TRAILING_CR:
   6504       next = entityTextPtr + enc->minBytesPerChar;
   6505       /* fall through */
   6506     case XML_TOK_DATA_NEWLINE:
   6507       if (pool->end == pool->ptr && ! poolGrow(pool)) {
   6508         result = XML_ERROR_NO_MEMORY;
   6509         goto endEntityValue;
   6510       }
   6511       *(pool->ptr)++ = 0xA;
   6512       break;
   6513     case XML_TOK_CHAR_REF: {
   6514       XML_Char buf[XML_ENCODE_MAX];
   6515       int i;
   6516       int n = XmlCharRefNumber(enc, entityTextPtr);
   6517       if (n < 0) {
   6518         if (enc == parser->m_encoding)
   6519           parser->m_eventPtr = entityTextPtr;
   6520         result = XML_ERROR_BAD_CHAR_REF;
   6521         goto endEntityValue;
   6522       }
   6523       n = XmlEncode(n, (ICHAR *)buf);
   6524       /* The XmlEncode() functions can never return 0 here.  That
   6525        * error return happens if the code point passed in is either
   6526        * negative or greater than or equal to 0x110000.  The
   6527        * XmlCharRefNumber() functions will all return a number
   6528        * strictly less than 0x110000 or a negative value if an error
   6529        * occurred.  The negative value is intercepted above, so
   6530        * XmlEncode() is never passed a value it might return an
   6531        * error for.
   6532        */
   6533       for (i = 0; i < n; i++) {
   6534         if (pool->end == pool->ptr && ! poolGrow(pool)) {
   6535           result = XML_ERROR_NO_MEMORY;
   6536           goto endEntityValue;
   6537         }
   6538         *(pool->ptr)++ = buf[i];
   6539       }
   6540     } break;
   6541     case XML_TOK_PARTIAL:
   6542       if (enc == parser->m_encoding)
   6543         parser->m_eventPtr = entityTextPtr;
   6544       result = XML_ERROR_INVALID_TOKEN;
   6545       goto endEntityValue;
   6546     case XML_TOK_INVALID:
   6547       if (enc == parser->m_encoding)
   6548         parser->m_eventPtr = next;
   6549       result = XML_ERROR_INVALID_TOKEN;
   6550       goto endEntityValue;
   6551     default:
   6552       /* This default case should be unnecessary -- all the tokens
   6553        * that XmlEntityValueTok() can return have their own explicit
   6554        * cases -- but should be retained for safety.  We do however
   6555        * exclude it from the coverage statistics.
   6556        *
   6557        * LCOV_EXCL_START
   6558        */
   6559       if (enc == parser->m_encoding)
   6560         parser->m_eventPtr = entityTextPtr;
   6561       result = XML_ERROR_UNEXPECTED_STATE;
   6562       goto endEntityValue;
   6563       /* LCOV_EXCL_STOP */
   6564     }
   6565     entityTextPtr = next;
   6566   }
   6567 endEntityValue:
   6568 #  ifdef XML_DTD
   6569   parser->m_prologState.inEntityValue = oldInEntityValue;
   6570 #  endif /* XML_DTD */
   6571   // If 'nextPtr' is given, it should be updated during the processing
   6572   if (nextPtr != NULL) {
   6573     *nextPtr = next;
   6574   }
   6575   return result;
   6576 }
   6577 
   6578 static enum XML_Error
   6579 callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
   6580                      const char *entityTextPtr, const char *entityTextEnd,
   6581                      enum XML_Account account) {
   6582   const char *next = entityTextPtr;
   6583   enum XML_Error result = XML_ERROR_NONE;
   6584   while (1) {
   6585     if (! parser->m_openValueEntities) {
   6586       result
   6587           = storeEntityValue(parser, enc, next, entityTextEnd, account, &next);
   6588     } else {
   6589       OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openValueEntities;
   6590       if (! openEntity)
   6591         return XML_ERROR_UNEXPECTED_STATE;
   6592 
   6593       ENTITY *const entity = openEntity->entity;
   6594       const char *const textStart
   6595           = ((const char *)entity->textPtr) + entity->processed;
   6596       const char *const textEnd
   6597           = (const char *)(entity->textPtr + entity->textLen);
   6598       /* Set a safe default value in case 'next' does not get set */
   6599       const char *nextInEntity = textStart;
   6600       if (entity->hasMore) {
   6601         result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
   6602                                   textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
   6603                                   &nextInEntity);
   6604         if (result != XML_ERROR_NONE)
   6605           break;
   6606         // Check if entity is complete, if not, mark down how much of it is
   6607         // processed. A XML_SUSPENDED check here is not required as
   6608         // appendAttributeValue will never suspend the parser.
   6609         if (textEnd != nextInEntity) {
   6610           entity->processed
   6611               = (int)(nextInEntity - (const char *)entity->textPtr);
   6612           continue;
   6613         }
   6614 
   6615         // Entity is complete. We cannot close it here since we need to first
   6616         // process its possible inner entities (which are added to the
   6617         // m_openValueEntities during storeEntityValue)
   6618         entity->hasMore = XML_FALSE;
   6619         continue;
   6620       } // End of entity processing, "if" block skips the rest
   6621 
   6622       // Remove fully processed openEntity from open entity list.
   6623 #  if XML_GE == 1
   6624       entityTrackingOnClose(parser, entity, __LINE__);
   6625 #  endif
   6626       // openEntity is m_openValueEntities' head, since we set it at the
   6627       // start of this function and because we skipped storeEntityValue call
   6628       // with hasMore set to false. This means we can directly remove the head
   6629       // of m_openValueEntities
   6630       assert(parser->m_openValueEntities == openEntity);
   6631       entity->open = XML_FALSE;
   6632       parser->m_openValueEntities = parser->m_openValueEntities->next;
   6633 
   6634       /* put openEntity back in list of free instances */
   6635       openEntity->next = parser->m_freeValueEntities;
   6636       parser->m_freeValueEntities = openEntity;
   6637     }
   6638 
   6639     // Break if an error occurred or there is nothing left to process
   6640     if (result
   6641         || (parser->m_openValueEntities == NULL && entityTextEnd == next)) {
   6642       break;
   6643     }
   6644   }
   6645 
   6646   return result;
   6647 }
   6648 
   6649 #else /* XML_GE == 0 */
   6650 
   6651 static enum XML_Error
   6652 storeSelfEntityValue(XML_Parser parser, ENTITY *entity) {
   6653   // This will store "&amp;entity123;" in entity->textPtr
   6654   // to end up as "&entity123;" in the handler.
   6655   const char *const entity_start = "&amp;";
   6656   const char *const entity_end = ";";
   6657 
   6658   STRING_POOL *const pool = &(parser->m_dtd->entityValuePool);
   6659   if (! poolAppendString(pool, entity_start)
   6660       || ! poolAppendString(pool, entity->name)
   6661       || ! poolAppendString(pool, entity_end)) {
   6662     poolDiscard(pool);
   6663     return XML_ERROR_NO_MEMORY;
   6664   }
   6665 
   6666   entity->textPtr = poolStart(pool);
   6667   entity->textLen = (int)(poolLength(pool));
   6668   poolFinish(pool);
   6669 
   6670   return XML_ERROR_NONE;
   6671 }
   6672 
   6673 #endif /* XML_GE == 0 */
   6674 
   6675 static void FASTCALL
   6676 normalizeLines(XML_Char *s) {
   6677   XML_Char *p;
   6678   for (;; s++) {
   6679     if (*s == XML_T('\0'))
   6680       return;
   6681     if (*s == 0xD)
   6682       break;
   6683   }
   6684   p = s;
   6685   do {
   6686     if (*s == 0xD) {
   6687       *p++ = 0xA;
   6688       if (*++s == 0xA)
   6689         s++;
   6690     } else
   6691       *p++ = *s++;
   6692   } while (*s);
   6693   *p = XML_T('\0');
   6694 }
   6695 
   6696 static int
   6697 reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
   6698                             const char *start, const char *end) {
   6699   const XML_Char *target;
   6700   XML_Char *data;
   6701   const char *tem;
   6702   if (! parser->m_processingInstructionHandler) {
   6703     if (parser->m_defaultHandler)
   6704       reportDefault(parser, enc, start, end);
   6705     return 1;
   6706   }
   6707   start += enc->minBytesPerChar * 2;
   6708   tem = start + XmlNameLength(enc, start);
   6709   target = poolStoreString(&parser->m_tempPool, enc, start, tem);
   6710   if (! target)
   6711     return 0;
   6712   poolFinish(&parser->m_tempPool);
   6713   data = poolStoreString(&parser->m_tempPool, enc, XmlSkipS(enc, tem),
   6714                          end - enc->minBytesPerChar * 2);
   6715   if (! data)
   6716     return 0;
   6717   normalizeLines(data);
   6718   parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
   6719   poolClear(&parser->m_tempPool);
   6720   return 1;
   6721 }
   6722 
   6723 static int
   6724 reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
   6725               const char *end) {
   6726   XML_Char *data;
   6727   if (! parser->m_commentHandler) {
   6728     if (parser->m_defaultHandler)
   6729       reportDefault(parser, enc, start, end);
   6730     return 1;
   6731   }
   6732   data = poolStoreString(&parser->m_tempPool, enc,
   6733                          start + enc->minBytesPerChar * 4,
   6734                          end - enc->minBytesPerChar * 3);
   6735   if (! data)
   6736     return 0;
   6737   normalizeLines(data);
   6738   parser->m_commentHandler(parser->m_handlerArg, data);
   6739   poolClear(&parser->m_tempPool);
   6740   return 1;
   6741 }
   6742 
   6743 static void
   6744 reportDefault(XML_Parser parser, const ENCODING *enc, const char *s,
   6745               const char *end) {
   6746   if (MUST_CONVERT(enc, s)) {
   6747     enum XML_Convert_Result convert_res;
   6748     const char **eventPP;
   6749     const char **eventEndPP;
   6750     if (enc == parser->m_encoding) {
   6751       eventPP = &parser->m_eventPtr;
   6752       eventEndPP = &parser->m_eventEndPtr;
   6753     } else {
   6754       /* To get here, two things must be true; the parser must be
   6755        * using a character encoding that is not the same as the
   6756        * encoding passed in, and the encoding passed in must need
   6757        * conversion to the internal format (UTF-8 unless XML_UNICODE
   6758        * is defined).  The only occasions on which the encoding passed
   6759        * in is not the same as the parser's encoding are when it is
   6760        * the internal encoding (e.g. a previously defined parameter
   6761        * entity, already converted to internal format).  This by
   6762        * definition doesn't need conversion, so the whole branch never
   6763        * gets executed.
   6764        *
   6765        * For safety's sake we don't delete these lines and merely
   6766        * exclude them from coverage statistics.
   6767        *
   6768        * LCOV_EXCL_START
   6769        */
   6770       eventPP = &(parser->m_openInternalEntities->internalEventPtr);
   6771       eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
   6772       /* LCOV_EXCL_STOP */
   6773     }
   6774     do {
   6775       ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
   6776       convert_res
   6777           = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
   6778       *eventEndPP = s;
   6779       parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf,
   6780                                (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
   6781       *eventPP = s;
   6782     } while ((convert_res != XML_CONVERT_COMPLETED)
   6783              && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
   6784   } else
   6785     parser->m_defaultHandler(
   6786         parser->m_handlerArg, (const XML_Char *)s,
   6787         (int)((const XML_Char *)end - (const XML_Char *)s));
   6788 }
   6789 
   6790 static int
   6791 defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
   6792                 XML_Bool isId, const XML_Char *value, XML_Parser parser) {
   6793   DEFAULT_ATTRIBUTE *att;
   6794   if (value || isId) {
   6795     /* The handling of default attributes gets messed up if we have
   6796        a default which duplicates a non-default. */
   6797     int i;
   6798     for (i = 0; i < type->nDefaultAtts; i++)
   6799       if (attId == type->defaultAtts[i].id)
   6800         return 1;
   6801     if (isId && ! type->idAtt && ! attId->xmlns)
   6802       type->idAtt = attId;
   6803   }
   6804   if (type->nDefaultAtts == type->allocDefaultAtts) {
   6805     if (type->allocDefaultAtts == 0) {
   6806       type->allocDefaultAtts = 8;
   6807       type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(
   6808           parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
   6809       if (! type->defaultAtts) {
   6810         type->allocDefaultAtts = 0;
   6811         return 0;
   6812       }
   6813     } else {
   6814       DEFAULT_ATTRIBUTE *temp;
   6815 
   6816       /* Detect and prevent integer overflow */
   6817       if (type->allocDefaultAtts > INT_MAX / 2) {
   6818         return 0;
   6819       }
   6820 
   6821       int count = type->allocDefaultAtts * 2;
   6822 
   6823       /* Detect and prevent integer overflow.
   6824        * The preprocessor guard addresses the "always false" warning
   6825        * from -Wtype-limits on platforms where
   6826        * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   6827 #if UINT_MAX >= SIZE_MAX
   6828       if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
   6829         return 0;
   6830       }
   6831 #endif
   6832 
   6833       temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
   6834                                           (count * sizeof(DEFAULT_ATTRIBUTE)));
   6835       if (temp == NULL)
   6836         return 0;
   6837       type->allocDefaultAtts = count;
   6838       type->defaultAtts = temp;
   6839     }
   6840   }
   6841   att = type->defaultAtts + type->nDefaultAtts;
   6842   att->id = attId;
   6843   att->value = value;
   6844   att->isCdata = isCdata;
   6845   if (! isCdata)
   6846     attId->maybeTokenized = XML_TRUE;
   6847   type->nDefaultAtts += 1;
   6848   return 1;
   6849 }
   6850 
   6851 static int
   6852 setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) {
   6853   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   6854   const XML_Char *name;
   6855   for (name = elementType->name; *name; name++) {
   6856     if (*name == XML_T(ASCII_COLON)) {
   6857       PREFIX *prefix;
   6858       const XML_Char *s;
   6859       for (s = elementType->name; s != name; s++) {
   6860         if (! poolAppendChar(&dtd->pool, *s))
   6861           return 0;
   6862       }
   6863       if (! poolAppendChar(&dtd->pool, XML_T('\0')))
   6864         return 0;
   6865       prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
   6866                                 sizeof(PREFIX));
   6867       if (! prefix)
   6868         return 0;
   6869       if (prefix->name == poolStart(&dtd->pool))
   6870         poolFinish(&dtd->pool);
   6871       else
   6872         poolDiscard(&dtd->pool);
   6873       elementType->prefix = prefix;
   6874       break;
   6875     }
   6876   }
   6877   return 1;
   6878 }
   6879 
   6880 static ATTRIBUTE_ID *
   6881 getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
   6882                const char *end) {
   6883   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   6884   ATTRIBUTE_ID *id;
   6885   const XML_Char *name;
   6886   if (! poolAppendChar(&dtd->pool, XML_T('\0')))
   6887     return NULL;
   6888   name = poolStoreString(&dtd->pool, enc, start, end);
   6889   if (! name)
   6890     return NULL;
   6891   /* skip quotation mark - its storage will be reused (like in name[-1]) */
   6892   ++name;
   6893   id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name,
   6894                               sizeof(ATTRIBUTE_ID));
   6895   if (! id)
   6896     return NULL;
   6897   if (id->name != name)
   6898     poolDiscard(&dtd->pool);
   6899   else {
   6900     poolFinish(&dtd->pool);
   6901     if (! parser->m_ns)
   6902       ;
   6903     else if (name[0] == XML_T(ASCII_x) && name[1] == XML_T(ASCII_m)
   6904              && name[2] == XML_T(ASCII_l) && name[3] == XML_T(ASCII_n)
   6905              && name[4] == XML_T(ASCII_s)
   6906              && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
   6907       if (name[5] == XML_T('\0'))
   6908         id->prefix = &dtd->defaultPrefix;
   6909       else
   6910         id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6,
   6911                                       sizeof(PREFIX));
   6912       id->xmlns = XML_TRUE;
   6913     } else {
   6914       int i;
   6915       for (i = 0; name[i]; i++) {
   6916         /* attributes without prefix are *not* in the default namespace */
   6917         if (name[i] == XML_T(ASCII_COLON)) {
   6918           int j;
   6919           for (j = 0; j < i; j++) {
   6920             if (! poolAppendChar(&dtd->pool, name[j]))
   6921               return NULL;
   6922           }
   6923           if (! poolAppendChar(&dtd->pool, XML_T('\0')))
   6924             return NULL;
   6925           id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes,
   6926                                         poolStart(&dtd->pool), sizeof(PREFIX));
   6927           if (! id->prefix)
   6928             return NULL;
   6929           if (id->prefix->name == poolStart(&dtd->pool))
   6930             poolFinish(&dtd->pool);
   6931           else
   6932             poolDiscard(&dtd->pool);
   6933           break;
   6934         }
   6935       }
   6936     }
   6937   }
   6938   return id;
   6939 }
   6940 
   6941 #define CONTEXT_SEP XML_T(ASCII_FF)
   6942 
   6943 static const XML_Char *
   6944 getContext(XML_Parser parser) {
   6945   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   6946   HASH_TABLE_ITER iter;
   6947   XML_Bool needSep = XML_FALSE;
   6948 
   6949   if (dtd->defaultPrefix.binding) {
   6950     int i;
   6951     int len;
   6952     if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
   6953       return NULL;
   6954     len = dtd->defaultPrefix.binding->uriLen;
   6955     if (parser->m_namespaceSeparator)
   6956       len--;
   6957     for (i = 0; i < len; i++) {
   6958       if (! poolAppendChar(&parser->m_tempPool,
   6959                            dtd->defaultPrefix.binding->uri[i])) {
   6960         /* Because of memory caching, I don't believe this line can be
   6961          * executed.
   6962          *
   6963          * This is part of a loop copying the default prefix binding
   6964          * URI into the parser's temporary string pool.  Previously,
   6965          * that URI was copied into the same string pool, with a
   6966          * terminating NUL character, as part of setContext().  When
   6967          * the pool was cleared, that leaves a block definitely big
   6968          * enough to hold the URI on the free block list of the pool.
   6969          * The URI copy in getContext() therefore cannot run out of
   6970          * memory.
   6971          *
   6972          * If the pool is used between the setContext() and
   6973          * getContext() calls, the worst it can do is leave a bigger
   6974          * block on the front of the free list.  Given that this is
   6975          * all somewhat inobvious and program logic can be changed, we
   6976          * don't delete the line but we do exclude it from the test
   6977          * coverage statistics.
   6978          */
   6979         return NULL; /* LCOV_EXCL_LINE */
   6980       }
   6981     }
   6982     needSep = XML_TRUE;
   6983   }
   6984 
   6985   hashTableIterInit(&iter, &(dtd->prefixes));
   6986   for (;;) {
   6987     int i;
   6988     int len;
   6989     const XML_Char *s;
   6990     PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
   6991     if (! prefix)
   6992       break;
   6993     if (! prefix->binding) {
   6994       /* This test appears to be (justifiable) paranoia.  There does
   6995        * not seem to be a way of injecting a prefix without a binding
   6996        * that doesn't get errored long before this function is called.
   6997        * The test should remain for safety's sake, so we instead
   6998        * exclude the following line from the coverage statistics.
   6999        */
   7000       continue; /* LCOV_EXCL_LINE */
   7001     }
   7002     if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
   7003       return NULL;
   7004     for (s = prefix->name; *s; s++)
   7005       if (! poolAppendChar(&parser->m_tempPool, *s))
   7006         return NULL;
   7007     if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
   7008       return NULL;
   7009     len = prefix->binding->uriLen;
   7010     if (parser->m_namespaceSeparator)
   7011       len--;
   7012     for (i = 0; i < len; i++)
   7013       if (! poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i]))
   7014         return NULL;
   7015     needSep = XML_TRUE;
   7016   }
   7017 
   7018   hashTableIterInit(&iter, &(dtd->generalEntities));
   7019   for (;;) {
   7020     const XML_Char *s;
   7021     ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
   7022     if (! e)
   7023       break;
   7024     if (! e->open)
   7025       continue;
   7026     if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
   7027       return NULL;
   7028     for (s = e->name; *s; s++)
   7029       if (! poolAppendChar(&parser->m_tempPool, *s))
   7030         return 0;
   7031     needSep = XML_TRUE;
   7032   }
   7033 
   7034   if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   7035     return NULL;
   7036   return parser->m_tempPool.start;
   7037 }
   7038 
   7039 static XML_Bool
   7040 setContext(XML_Parser parser, const XML_Char *context) {
   7041   if (context == NULL) {
   7042     return XML_FALSE;
   7043   }
   7044 
   7045   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   7046   const XML_Char *s = context;
   7047 
   7048   while (*context != XML_T('\0')) {
   7049     if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
   7050       ENTITY *e;
   7051       if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   7052         return XML_FALSE;
   7053       e = (ENTITY *)lookup(parser, &dtd->generalEntities,
   7054                            poolStart(&parser->m_tempPool), 0);
   7055       if (e)
   7056         e->open = XML_TRUE;
   7057       if (*s != XML_T('\0'))
   7058         s++;
   7059       context = s;
   7060       poolDiscard(&parser->m_tempPool);
   7061     } else if (*s == XML_T(ASCII_EQUALS)) {
   7062       PREFIX *prefix;
   7063       if (poolLength(&parser->m_tempPool) == 0)
   7064         prefix = &dtd->defaultPrefix;
   7065       else {
   7066         if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   7067           return XML_FALSE;
   7068         prefix
   7069             = (PREFIX *)lookup(parser, &dtd->prefixes,
   7070                                poolStart(&parser->m_tempPool), sizeof(PREFIX));
   7071         if (! prefix)
   7072           return XML_FALSE;
   7073         if (prefix->name == poolStart(&parser->m_tempPool)) {
   7074           prefix->name = poolCopyString(&dtd->pool, prefix->name);
   7075           if (! prefix->name)
   7076             return XML_FALSE;
   7077         }
   7078         poolDiscard(&parser->m_tempPool);
   7079       }
   7080       for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0');
   7081            context++)
   7082         if (! poolAppendChar(&parser->m_tempPool, *context))
   7083           return XML_FALSE;
   7084       if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
   7085         return XML_FALSE;
   7086       if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool),
   7087                      &parser->m_inheritedBindings)
   7088           != XML_ERROR_NONE)
   7089         return XML_FALSE;
   7090       poolDiscard(&parser->m_tempPool);
   7091       if (*context != XML_T('\0'))
   7092         ++context;
   7093       s = context;
   7094     } else {
   7095       if (! poolAppendChar(&parser->m_tempPool, *s))
   7096         return XML_FALSE;
   7097       s++;
   7098     }
   7099   }
   7100   return XML_TRUE;
   7101 }
   7102 
   7103 static void FASTCALL
   7104 normalizePublicId(XML_Char *publicId) {
   7105   XML_Char *p = publicId;
   7106   XML_Char *s;
   7107   for (s = publicId; *s; s++) {
   7108     switch (*s) {
   7109     case 0x20:
   7110     case 0xD:
   7111     case 0xA:
   7112       if (p != publicId && p[-1] != 0x20)
   7113         *p++ = 0x20;
   7114       break;
   7115     default:
   7116       *p++ = *s;
   7117     }
   7118   }
   7119   if (p != publicId && p[-1] == 0x20)
   7120     --p;
   7121   *p = XML_T('\0');
   7122 }
   7123 
   7124 static DTD *
   7125 dtdCreate(const XML_Memory_Handling_Suite *ms) {
   7126   DTD *p = ms->malloc_fcn(sizeof(DTD));
   7127   if (p == NULL)
   7128     return p;
   7129   poolInit(&(p->pool), ms);
   7130   poolInit(&(p->entityValuePool), ms);
   7131   hashTableInit(&(p->generalEntities), ms);
   7132   hashTableInit(&(p->elementTypes), ms);
   7133   hashTableInit(&(p->attributeIds), ms);
   7134   hashTableInit(&(p->prefixes), ms);
   7135 #ifdef XML_DTD
   7136   p->paramEntityRead = XML_FALSE;
   7137   hashTableInit(&(p->paramEntities), ms);
   7138 #endif /* XML_DTD */
   7139   p->defaultPrefix.name = NULL;
   7140   p->defaultPrefix.binding = NULL;
   7141 
   7142   p->in_eldecl = XML_FALSE;
   7143   p->scaffIndex = NULL;
   7144   p->scaffold = NULL;
   7145   p->scaffLevel = 0;
   7146   p->scaffSize = 0;
   7147   p->scaffCount = 0;
   7148   p->contentStringLen = 0;
   7149 
   7150   p->keepProcessing = XML_TRUE;
   7151   p->hasParamEntityRefs = XML_FALSE;
   7152   p->standalone = XML_FALSE;
   7153   return p;
   7154 }
   7155 
   7156 static void
   7157 dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
   7158   HASH_TABLE_ITER iter;
   7159   hashTableIterInit(&iter, &(p->elementTypes));
   7160   for (;;) {
   7161     ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
   7162     if (! e)
   7163       break;
   7164     if (e->allocDefaultAtts != 0)
   7165       ms->free_fcn(e->defaultAtts);
   7166   }
   7167   hashTableClear(&(p->generalEntities));
   7168 #ifdef XML_DTD
   7169   p->paramEntityRead = XML_FALSE;
   7170   hashTableClear(&(p->paramEntities));
   7171 #endif /* XML_DTD */
   7172   hashTableClear(&(p->elementTypes));
   7173   hashTableClear(&(p->attributeIds));
   7174   hashTableClear(&(p->prefixes));
   7175   poolClear(&(p->pool));
   7176   poolClear(&(p->entityValuePool));
   7177   p->defaultPrefix.name = NULL;
   7178   p->defaultPrefix.binding = NULL;
   7179 
   7180   p->in_eldecl = XML_FALSE;
   7181 
   7182   ms->free_fcn(p->scaffIndex);
   7183   p->scaffIndex = NULL;
   7184   ms->free_fcn(p->scaffold);
   7185   p->scaffold = NULL;
   7186 
   7187   p->scaffLevel = 0;
   7188   p->scaffSize = 0;
   7189   p->scaffCount = 0;
   7190   p->contentStringLen = 0;
   7191 
   7192   p->keepProcessing = XML_TRUE;
   7193   p->hasParamEntityRefs = XML_FALSE;
   7194   p->standalone = XML_FALSE;
   7195 }
   7196 
   7197 static void
   7198 dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
   7199   HASH_TABLE_ITER iter;
   7200   hashTableIterInit(&iter, &(p->elementTypes));
   7201   for (;;) {
   7202     ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
   7203     if (! e)
   7204       break;
   7205     if (e->allocDefaultAtts != 0)
   7206       ms->free_fcn(e->defaultAtts);
   7207   }
   7208   hashTableDestroy(&(p->generalEntities));
   7209 #ifdef XML_DTD
   7210   hashTableDestroy(&(p->paramEntities));
   7211 #endif /* XML_DTD */
   7212   hashTableDestroy(&(p->elementTypes));
   7213   hashTableDestroy(&(p->attributeIds));
   7214   hashTableDestroy(&(p->prefixes));
   7215   poolDestroy(&(p->pool));
   7216   poolDestroy(&(p->entityValuePool));
   7217   if (isDocEntity) {
   7218     ms->free_fcn(p->scaffIndex);
   7219     ms->free_fcn(p->scaffold);
   7220   }
   7221   ms->free_fcn(p);
   7222 }
   7223 
   7224 /* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
   7225    The new DTD has already been initialized.
   7226 */
   7227 static int
   7228 dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
   7229         const XML_Memory_Handling_Suite *ms) {
   7230   HASH_TABLE_ITER iter;
   7231 
   7232   /* Copy the prefix table. */
   7233 
   7234   hashTableIterInit(&iter, &(oldDtd->prefixes));
   7235   for (;;) {
   7236     const XML_Char *name;
   7237     const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
   7238     if (! oldP)
   7239       break;
   7240     name = poolCopyString(&(newDtd->pool), oldP->name);
   7241     if (! name)
   7242       return 0;
   7243     if (! lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
   7244       return 0;
   7245   }
   7246 
   7247   hashTableIterInit(&iter, &(oldDtd->attributeIds));
   7248 
   7249   /* Copy the attribute id table. */
   7250 
   7251   for (;;) {
   7252     ATTRIBUTE_ID *newA;
   7253     const XML_Char *name;
   7254     const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
   7255 
   7256     if (! oldA)
   7257       break;
   7258     /* Remember to allocate the scratch byte before the name. */
   7259     if (! poolAppendChar(&(newDtd->pool), XML_T('\0')))
   7260       return 0;
   7261     name = poolCopyString(&(newDtd->pool), oldA->name);
   7262     if (! name)
   7263       return 0;
   7264     ++name;
   7265     newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
   7266                                   sizeof(ATTRIBUTE_ID));
   7267     if (! newA)
   7268       return 0;
   7269     newA->maybeTokenized = oldA->maybeTokenized;
   7270     if (oldA->prefix) {
   7271       newA->xmlns = oldA->xmlns;
   7272       if (oldA->prefix == &oldDtd->defaultPrefix)
   7273         newA->prefix = &newDtd->defaultPrefix;
   7274       else
   7275         newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
   7276                                         oldA->prefix->name, 0);
   7277     }
   7278   }
   7279 
   7280   /* Copy the element type table. */
   7281 
   7282   hashTableIterInit(&iter, &(oldDtd->elementTypes));
   7283 
   7284   for (;;) {
   7285     int i;
   7286     ELEMENT_TYPE *newE;
   7287     const XML_Char *name;
   7288     const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
   7289     if (! oldE)
   7290       break;
   7291     name = poolCopyString(&(newDtd->pool), oldE->name);
   7292     if (! name)
   7293       return 0;
   7294     newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
   7295                                   sizeof(ELEMENT_TYPE));
   7296     if (! newE)
   7297       return 0;
   7298     if (oldE->nDefaultAtts) {
   7299       /* Detect and prevent integer overflow.
   7300        * The preprocessor guard addresses the "always false" warning
   7301        * from -Wtype-limits on platforms where
   7302        * sizeof(int) < sizeof(size_t), e.g. on x86_64. */
   7303 #if UINT_MAX >= SIZE_MAX
   7304       if ((size_t)oldE->nDefaultAtts
   7305           > ((size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE))) {
   7306         return 0;
   7307       }
   7308 #endif
   7309       newE->defaultAtts
   7310           = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
   7311       if (! newE->defaultAtts) {
   7312         return 0;
   7313       }
   7314     }
   7315     if (oldE->idAtt)
   7316       newE->idAtt = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds),
   7317                                            oldE->idAtt->name, 0);
   7318     newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
   7319     if (oldE->prefix)
   7320       newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
   7321                                       oldE->prefix->name, 0);
   7322     for (i = 0; i < newE->nDefaultAtts; i++) {
   7323       newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(
   7324           oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
   7325       newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
   7326       if (oldE->defaultAtts[i].value) {
   7327         newE->defaultAtts[i].value
   7328             = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
   7329         if (! newE->defaultAtts[i].value)
   7330           return 0;
   7331       } else
   7332         newE->defaultAtts[i].value = NULL;
   7333     }
   7334   }
   7335 
   7336   /* Copy the entity tables. */
   7337   if (! copyEntityTable(oldParser, &(newDtd->generalEntities), &(newDtd->pool),
   7338                         &(oldDtd->generalEntities)))
   7339     return 0;
   7340 
   7341 #ifdef XML_DTD
   7342   if (! copyEntityTable(oldParser, &(newDtd->paramEntities), &(newDtd->pool),
   7343                         &(oldDtd->paramEntities)))
   7344     return 0;
   7345   newDtd->paramEntityRead = oldDtd->paramEntityRead;
   7346 #endif /* XML_DTD */
   7347 
   7348   newDtd->keepProcessing = oldDtd->keepProcessing;
   7349   newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
   7350   newDtd->standalone = oldDtd->standalone;
   7351 
   7352   /* Don't want deep copying for scaffolding */
   7353   newDtd->in_eldecl = oldDtd->in_eldecl;
   7354   newDtd->scaffold = oldDtd->scaffold;
   7355   newDtd->contentStringLen = oldDtd->contentStringLen;
   7356   newDtd->scaffSize = oldDtd->scaffSize;
   7357   newDtd->scaffLevel = oldDtd->scaffLevel;
   7358   newDtd->scaffIndex = oldDtd->scaffIndex;
   7359 
   7360   return 1;
   7361 } /* End dtdCopy */
   7362 
   7363 static int
   7364 copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
   7365                 STRING_POOL *newPool, const HASH_TABLE *oldTable) {
   7366   HASH_TABLE_ITER iter;
   7367   const XML_Char *cachedOldBase = NULL;
   7368   const XML_Char *cachedNewBase = NULL;
   7369 
   7370   hashTableIterInit(&iter, oldTable);
   7371 
   7372   for (;;) {
   7373     ENTITY *newE;
   7374     const XML_Char *name;
   7375     const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
   7376     if (! oldE)
   7377       break;
   7378     name = poolCopyString(newPool, oldE->name);
   7379     if (! name)
   7380       return 0;
   7381     newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
   7382     if (! newE)
   7383       return 0;
   7384     if (oldE->systemId) {
   7385       const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
   7386       if (! tem)
   7387         return 0;
   7388       newE->systemId = tem;
   7389       if (oldE->base) {
   7390         if (oldE->base == cachedOldBase)
   7391           newE->base = cachedNewBase;
   7392         else {
   7393           cachedOldBase = oldE->base;
   7394           tem = poolCopyString(newPool, cachedOldBase);
   7395           if (! tem)
   7396             return 0;
   7397           cachedNewBase = newE->base = tem;
   7398         }
   7399       }
   7400       if (oldE->publicId) {
   7401         tem = poolCopyString(newPool, oldE->publicId);
   7402         if (! tem)
   7403           return 0;
   7404         newE->publicId = tem;
   7405       }
   7406     } else {
   7407       const XML_Char *tem
   7408           = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen);
   7409       if (! tem)
   7410         return 0;
   7411       newE->textPtr = tem;
   7412       newE->textLen = oldE->textLen;
   7413     }
   7414     if (oldE->notation) {
   7415       const XML_Char *tem = poolCopyString(newPool, oldE->notation);
   7416       if (! tem)
   7417         return 0;
   7418       newE->notation = tem;
   7419     }
   7420     newE->is_param = oldE->is_param;
   7421     newE->is_internal = oldE->is_internal;
   7422   }
   7423   return 1;
   7424 }
   7425 
   7426 #define INIT_POWER 6
   7427 
   7428 static XML_Bool FASTCALL
   7429 keyeq(KEY s1, KEY s2) {
   7430   for (; *s1 == *s2; s1++, s2++)
   7431     if (*s1 == 0)
   7432       return XML_TRUE;
   7433   return XML_FALSE;
   7434 }
   7435 
   7436 static size_t
   7437 keylen(KEY s) {
   7438   size_t len = 0;
   7439   for (; *s; s++, len++)
   7440     ;
   7441   return len;
   7442 }
   7443 
   7444 static void
   7445 copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) {
   7446   key->k[0] = 0;
   7447   key->k[1] = get_hash_secret_salt(parser);
   7448 }
   7449 
   7450 static unsigned long FASTCALL
   7451 hash(XML_Parser parser, KEY s) {
   7452   struct siphash state;
   7453   struct sipkey key;
   7454   (void)sip24_valid;
   7455   copy_salt_to_sipkey(parser, &key);
   7456   sip24_init(&state, &key);
   7457   sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
   7458   return (unsigned long)sip24_final(&state);
   7459 }
   7460 
   7461 static NAMED *
   7462 lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
   7463   size_t i;
   7464   if (table->size == 0) {
   7465     size_t tsize;
   7466     if (! createSize)
   7467       return NULL;
   7468     table->power = INIT_POWER;
   7469     /* table->size is a power of 2 */
   7470     table->size = (size_t)1 << INIT_POWER;
   7471     tsize = table->size * sizeof(NAMED *);
   7472     table->v = table->mem->malloc_fcn(tsize);
   7473     if (! table->v) {
   7474       table->size = 0;
   7475       return NULL;
   7476     }
   7477     memset(table->v, 0, tsize);
   7478     i = hash(parser, name) & ((unsigned long)table->size - 1);
   7479   } else {
   7480     unsigned long h = hash(parser, name);
   7481     unsigned long mask = (unsigned long)table->size - 1;
   7482     unsigned char step = 0;
   7483     i = h & mask;
   7484     while (table->v[i]) {
   7485       if (keyeq(name, table->v[i]->name))
   7486         return table->v[i];
   7487       if (! step)
   7488         step = PROBE_STEP(h, mask, table->power);
   7489       i < step ? (i += table->size - step) : (i -= step);
   7490     }
   7491     if (! createSize)
   7492       return NULL;
   7493 
   7494     /* check for overflow (table is half full) */
   7495     if (table->used >> (table->power - 1)) {
   7496       unsigned char newPower = table->power + 1;
   7497 
   7498       /* Detect and prevent invalid shift */
   7499       if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
   7500         return NULL;
   7501       }
   7502 
   7503       size_t newSize = (size_t)1 << newPower;
   7504       unsigned long newMask = (unsigned long)newSize - 1;
   7505 
   7506       /* Detect and prevent integer overflow */
   7507       if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
   7508         return NULL;
   7509       }
   7510 
   7511       size_t tsize = newSize * sizeof(NAMED *);
   7512       NAMED **newV = table->mem->malloc_fcn(tsize);
   7513       if (! newV)
   7514         return NULL;
   7515       memset(newV, 0, tsize);
   7516       for (i = 0; i < table->size; i++)
   7517         if (table->v[i]) {
   7518           unsigned long newHash = hash(parser, table->v[i]->name);
   7519           size_t j = newHash & newMask;
   7520           step = 0;
   7521           while (newV[j]) {
   7522             if (! step)
   7523               step = PROBE_STEP(newHash, newMask, newPower);
   7524             j < step ? (j += newSize - step) : (j -= step);
   7525           }
   7526           newV[j] = table->v[i];
   7527         }
   7528       table->mem->free_fcn(table->v);
   7529       table->v = newV;
   7530       table->power = newPower;
   7531       table->size = newSize;
   7532       i = h & newMask;
   7533       step = 0;
   7534       while (table->v[i]) {
   7535         if (! step)
   7536           step = PROBE_STEP(h, newMask, newPower);
   7537         i < step ? (i += newSize - step) : (i -= step);
   7538       }
   7539     }
   7540   }
   7541   table->v[i] = table->mem->malloc_fcn(createSize);
   7542   if (! table->v[i])
   7543     return NULL;
   7544   memset(table->v[i], 0, createSize);
   7545   table->v[i]->name = name;
   7546   (table->used)++;
   7547   return table->v[i];
   7548 }
   7549 
   7550 static void FASTCALL
   7551 hashTableClear(HASH_TABLE *table) {
   7552   size_t i;
   7553   for (i = 0; i < table->size; i++) {
   7554     table->mem->free_fcn(table->v[i]);
   7555     table->v[i] = NULL;
   7556   }
   7557   table->used = 0;
   7558 }
   7559 
   7560 static void FASTCALL
   7561 hashTableDestroy(HASH_TABLE *table) {
   7562   size_t i;
   7563   for (i = 0; i < table->size; i++)
   7564     table->mem->free_fcn(table->v[i]);
   7565   table->mem->free_fcn(table->v);
   7566 }
   7567 
   7568 static void FASTCALL
   7569 hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) {
   7570   p->power = 0;
   7571   p->size = 0;
   7572   p->used = 0;
   7573   p->v = NULL;
   7574   p->mem = ms;
   7575 }
   7576 
   7577 static void FASTCALL
   7578 hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) {
   7579   iter->p = table->v;
   7580   iter->end = iter->p ? iter->p + table->size : NULL;
   7581 }
   7582 
   7583 static NAMED *FASTCALL
   7584 hashTableIterNext(HASH_TABLE_ITER *iter) {
   7585   while (iter->p != iter->end) {
   7586     NAMED *tem = *(iter->p)++;
   7587     if (tem)
   7588       return tem;
   7589   }
   7590   return NULL;
   7591 }
   7592 
   7593 static void FASTCALL
   7594 poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) {
   7595   pool->blocks = NULL;
   7596   pool->freeBlocks = NULL;
   7597   pool->start = NULL;
   7598   pool->ptr = NULL;
   7599   pool->end = NULL;
   7600   pool->mem = ms;
   7601 }
   7602 
   7603 static void FASTCALL
   7604 poolClear(STRING_POOL *pool) {
   7605   if (! pool->freeBlocks)
   7606     pool->freeBlocks = pool->blocks;
   7607   else {
   7608     BLOCK *p = pool->blocks;
   7609     while (p) {
   7610       BLOCK *tem = p->next;
   7611       p->next = pool->freeBlocks;
   7612       pool->freeBlocks = p;
   7613       p = tem;
   7614     }
   7615   }
   7616   pool->blocks = NULL;
   7617   pool->start = NULL;
   7618   pool->ptr = NULL;
   7619   pool->end = NULL;
   7620 }
   7621 
   7622 static void FASTCALL
   7623 poolDestroy(STRING_POOL *pool) {
   7624   BLOCK *p = pool->blocks;
   7625   while (p) {
   7626     BLOCK *tem = p->next;
   7627     pool->mem->free_fcn(p);
   7628     p = tem;
   7629   }
   7630   p = pool->freeBlocks;
   7631   while (p) {
   7632     BLOCK *tem = p->next;
   7633     pool->mem->free_fcn(p);
   7634     p = tem;
   7635   }
   7636 }
   7637 
   7638 static XML_Char *
   7639 poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
   7640            const char *end) {
   7641   if (! pool->ptr && ! poolGrow(pool))
   7642     return NULL;
   7643   for (;;) {
   7644     const enum XML_Convert_Result convert_res = XmlConvert(
   7645         enc, &ptr, end, (ICHAR **)&(pool->ptr), (const ICHAR *)pool->end);
   7646     if ((convert_res == XML_CONVERT_COMPLETED)
   7647         || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
   7648       break;
   7649     if (! poolGrow(pool))
   7650       return NULL;
   7651   }
   7652   return pool->start;
   7653 }
   7654 
   7655 static const XML_Char *FASTCALL
   7656 poolCopyString(STRING_POOL *pool, const XML_Char *s) {
   7657   do {
   7658     if (! poolAppendChar(pool, *s))
   7659       return NULL;
   7660   } while (*s++);
   7661   s = pool->start;
   7662   poolFinish(pool);
   7663   return s;
   7664 }
   7665 
   7666 static const XML_Char *
   7667 poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) {
   7668   if (! pool->ptr && ! poolGrow(pool)) {
   7669     /* The following line is unreachable given the current usage of
   7670      * poolCopyStringN().  Currently it is called from exactly one
   7671      * place to copy the text of a simple general entity.  By that
   7672      * point, the name of the entity is already stored in the pool, so
   7673      * pool->ptr cannot be NULL.
   7674      *
   7675      * If poolCopyStringN() is used elsewhere as it well might be,
   7676      * this line may well become executable again.  Regardless, this
   7677      * sort of check shouldn't be removed lightly, so we just exclude
   7678      * it from the coverage statistics.
   7679      */
   7680     return NULL; /* LCOV_EXCL_LINE */
   7681   }
   7682   for (; n > 0; --n, s++) {
   7683     if (! poolAppendChar(pool, *s))
   7684       return NULL;
   7685   }
   7686   s = pool->start;
   7687   poolFinish(pool);
   7688   return s;
   7689 }
   7690 
   7691 static const XML_Char *FASTCALL
   7692 poolAppendString(STRING_POOL *pool, const XML_Char *s) {
   7693   while (*s) {
   7694     if (! poolAppendChar(pool, *s))
   7695       return NULL;
   7696     s++;
   7697   }
   7698   return pool->start;
   7699 }
   7700 
   7701 static XML_Char *
   7702 poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
   7703                 const char *end) {
   7704   if (! poolAppend(pool, enc, ptr, end))
   7705     return NULL;
   7706   if (pool->ptr == pool->end && ! poolGrow(pool))
   7707     return NULL;
   7708   *(pool->ptr)++ = 0;
   7709   return pool->start;
   7710 }
   7711 
   7712 static size_t
   7713 poolBytesToAllocateFor(int blockSize) {
   7714   /* Unprotected math would be:
   7715   ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
   7716   **
   7717   ** Detect overflow, avoiding _signed_ overflow undefined behavior
   7718   ** For a + b * c we check b * c in isolation first, so that addition of a
   7719   ** on top has no chance of making us accept a small non-negative number
   7720   */
   7721   const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */
   7722 
   7723   if (blockSize <= 0)
   7724     return 0;
   7725 
   7726   if (blockSize > (int)(INT_MAX / stretch))
   7727     return 0;
   7728 
   7729   {
   7730     const int stretchedBlockSize = blockSize * (int)stretch;
   7731     const int bytesToAllocate
   7732         = (int)(offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
   7733     if (bytesToAllocate < 0)
   7734       return 0;
   7735 
   7736     return (size_t)bytesToAllocate;
   7737   }
   7738 }
   7739 
   7740 static XML_Bool FASTCALL
   7741 poolGrow(STRING_POOL *pool) {
   7742   if (pool->freeBlocks) {
   7743     if (pool->start == 0) {
   7744       pool->blocks = pool->freeBlocks;
   7745       pool->freeBlocks = pool->freeBlocks->next;
   7746       pool->blocks->next = NULL;
   7747       pool->start = pool->blocks->s;
   7748       pool->end = pool->start + pool->blocks->size;
   7749       pool->ptr = pool->start;
   7750       return XML_TRUE;
   7751     }
   7752     if (pool->end - pool->start < pool->freeBlocks->size) {
   7753       BLOCK *tem = pool->freeBlocks->next;
   7754       pool->freeBlocks->next = pool->blocks;
   7755       pool->blocks = pool->freeBlocks;
   7756       pool->freeBlocks = tem;
   7757       memcpy(pool->blocks->s, pool->start,
   7758              (pool->end - pool->start) * sizeof(XML_Char));
   7759       pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
   7760       pool->start = pool->blocks->s;
   7761       pool->end = pool->start + pool->blocks->size;
   7762       return XML_TRUE;
   7763     }
   7764   }
   7765   if (pool->blocks && pool->start == pool->blocks->s) {
   7766     BLOCK *temp;
   7767     int blockSize = (int)((unsigned)(pool->end - pool->start) * 2U);
   7768     size_t bytesToAllocate;
   7769 
   7770     /* NOTE: Needs to be calculated prior to calling `realloc`
   7771              to avoid dangling pointers: */
   7772     const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
   7773 
   7774     if (blockSize < 0) {
   7775       /* This condition traps a situation where either more than
   7776        * INT_MAX/2 bytes have already been allocated.  This isn't
   7777        * readily testable, since it is unlikely that an average
   7778        * machine will have that much memory, so we exclude it from the
   7779        * coverage statistics.
   7780        */
   7781       return XML_FALSE; /* LCOV_EXCL_LINE */
   7782     }
   7783 
   7784     bytesToAllocate = poolBytesToAllocateFor(blockSize);
   7785     if (bytesToAllocate == 0)
   7786       return XML_FALSE;
   7787 
   7788     temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks,
   7789                                            (unsigned)bytesToAllocate);
   7790     if (temp == NULL)
   7791       return XML_FALSE;
   7792     pool->blocks = temp;
   7793     pool->blocks->size = blockSize;
   7794     pool->ptr = pool->blocks->s + offsetInsideBlock;
   7795     pool->start = pool->blocks->s;
   7796     pool->end = pool->start + blockSize;
   7797   } else {
   7798     BLOCK *tem;
   7799     int blockSize = (int)(pool->end - pool->start);
   7800     size_t bytesToAllocate;
   7801 
   7802     if (blockSize < 0) {
   7803       /* This condition traps a situation where either more than
   7804        * INT_MAX bytes have already been allocated (which is prevented
   7805        * by various pieces of program logic, not least this one, never
   7806        * mind the unlikelihood of actually having that much memory) or
   7807        * the pool control fields have been corrupted (which could
   7808        * conceivably happen in an extremely buggy user handler
   7809        * function).  Either way it isn't readily testable, so we
   7810        * exclude it from the coverage statistics.
   7811        */
   7812       return XML_FALSE; /* LCOV_EXCL_LINE */
   7813     }
   7814 
   7815     if (blockSize < INIT_BLOCK_SIZE)
   7816       blockSize = INIT_BLOCK_SIZE;
   7817     else {
   7818       /* Detect overflow, avoiding _signed_ overflow undefined behavior */
   7819       if ((int)((unsigned)blockSize * 2U) < 0) {
   7820         return XML_FALSE;
   7821       }
   7822       blockSize *= 2;
   7823     }
   7824 
   7825     bytesToAllocate = poolBytesToAllocateFor(blockSize);
   7826     if (bytesToAllocate == 0)
   7827       return XML_FALSE;
   7828 
   7829     tem = pool->mem->malloc_fcn(bytesToAllocate);
   7830     if (! tem)
   7831       return XML_FALSE;
   7832     tem->size = blockSize;
   7833     tem->next = pool->blocks;
   7834     pool->blocks = tem;
   7835     if (pool->ptr != pool->start)
   7836       memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
   7837     pool->ptr = tem->s + (pool->ptr - pool->start);
   7838     pool->start = tem->s;
   7839     pool->end = tem->s + blockSize;
   7840   }
   7841   return XML_TRUE;
   7842 }
   7843 
   7844 static int FASTCALL
   7845 nextScaffoldPart(XML_Parser parser) {
   7846   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   7847   CONTENT_SCAFFOLD *me;
   7848   int next;
   7849 
   7850   if (! dtd->scaffIndex) {
   7851     /* Detect and prevent integer overflow.
   7852      * The preprocessor guard addresses the "always false" warning
   7853      * from -Wtype-limits on platforms where
   7854      * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   7855 #if UINT_MAX >= SIZE_MAX
   7856     if (parser->m_groupSize > ((size_t)(-1) / sizeof(int))) {
   7857       return -1;
   7858     }
   7859 #endif
   7860     dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
   7861     if (! dtd->scaffIndex)
   7862       return -1;
   7863     dtd->scaffIndex[0] = 0;
   7864   }
   7865 
   7866   if (dtd->scaffCount >= dtd->scaffSize) {
   7867     CONTENT_SCAFFOLD *temp;
   7868     if (dtd->scaffold) {
   7869       /* Detect and prevent integer overflow */
   7870       if (dtd->scaffSize > UINT_MAX / 2u) {
   7871         return -1;
   7872       }
   7873       /* Detect and prevent integer overflow.
   7874        * The preprocessor guard addresses the "always false" warning
   7875        * from -Wtype-limits on platforms where
   7876        * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   7877 #if UINT_MAX >= SIZE_MAX
   7878       if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
   7879         return -1;
   7880       }
   7881 #endif
   7882 
   7883       temp = (CONTENT_SCAFFOLD *)REALLOC(
   7884           parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
   7885       if (temp == NULL)
   7886         return -1;
   7887       dtd->scaffSize *= 2;
   7888     } else {
   7889       temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS
   7890                                                     * sizeof(CONTENT_SCAFFOLD));
   7891       if (temp == NULL)
   7892         return -1;
   7893       dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
   7894     }
   7895     dtd->scaffold = temp;
   7896   }
   7897   next = dtd->scaffCount++;
   7898   me = &dtd->scaffold[next];
   7899   if (dtd->scaffLevel) {
   7900     CONTENT_SCAFFOLD *parent
   7901         = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]];
   7902     if (parent->lastchild) {
   7903       dtd->scaffold[parent->lastchild].nextsib = next;
   7904     }
   7905     if (! parent->childcnt)
   7906       parent->firstchild = next;
   7907     parent->lastchild = next;
   7908     parent->childcnt++;
   7909   }
   7910   me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
   7911   return next;
   7912 }
   7913 
   7914 static XML_Content *
   7915 build_model(XML_Parser parser) {
   7916   /* Function build_model transforms the existing parser->m_dtd->scaffold
   7917    * array of CONTENT_SCAFFOLD tree nodes into a new array of
   7918    * XML_Content tree nodes followed by a gapless list of zero-terminated
   7919    * strings. */
   7920   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   7921   XML_Content *ret;
   7922   XML_Char *str; /* the current string writing location */
   7923 
   7924   /* Detect and prevent integer overflow.
   7925    * The preprocessor guard addresses the "always false" warning
   7926    * from -Wtype-limits on platforms where
   7927    * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
   7928 #if UINT_MAX >= SIZE_MAX
   7929   if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
   7930     return NULL;
   7931   }
   7932   if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
   7933     return NULL;
   7934   }
   7935 #endif
   7936   if (dtd->scaffCount * sizeof(XML_Content)
   7937       > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
   7938     return NULL;
   7939   }
   7940 
   7941   const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
   7942                             + (dtd->contentStringLen * sizeof(XML_Char)));
   7943 
   7944   ret = (XML_Content *)MALLOC(parser, allocsize);
   7945   if (! ret)
   7946     return NULL;
   7947 
   7948   /* What follows is an iterative implementation (of what was previously done
   7949    * recursively in a dedicated function called "build_node".  The old recursive
   7950    * build_node could be forced into stack exhaustion from input as small as a
   7951    * few megabyte, and so that was a security issue.  Hence, a function call
   7952    * stack is avoided now by resolving recursion.)
   7953    *
   7954    * The iterative approach works as follows:
   7955    *
   7956    * - We have two writing pointers, both walking up the result array; one does
   7957    *   the work, the other creates "jobs" for its colleague to do, and leads
   7958    *   the way:
   7959    *
   7960    *   - The faster one, pointer jobDest, always leads and writes "what job
   7961    *     to do" by the other, once they reach that place in the
   7962    *     array: leader "jobDest" stores the source node array index (relative
   7963    *     to array dtd->scaffold) in field "numchildren".
   7964    *
   7965    *   - The slower one, pointer dest, looks at the value stored in the
   7966    *     "numchildren" field (which actually holds a source node array index
   7967    *     at that time) and puts the real data from dtd->scaffold in.
   7968    *
   7969    * - Before the loop starts, jobDest writes source array index 0
   7970    *   (where the root node is located) so that dest will have something to do
   7971    *   when it starts operation.
   7972    *
   7973    * - Whenever nodes with children are encountered, jobDest appends
   7974    *   them as new jobs, in order.  As a result, tree node siblings are
   7975    *   adjacent in the resulting array, for example:
   7976    *
   7977    *     [0] root, has two children
   7978    *       [1] first child of 0, has three children
   7979    *         [3] first child of 1, does not have children
   7980    *         [4] second child of 1, does not have children
   7981    *         [5] third child of 1, does not have children
   7982    *       [2] second child of 0, does not have children
   7983    *
   7984    *   Or (the same data) presented in flat array view:
   7985    *
   7986    *     [0] root, has two children
   7987    *
   7988    *     [1] first child of 0, has three children
   7989    *     [2] second child of 0, does not have children
   7990    *
   7991    *     [3] first child of 1, does not have children
   7992    *     [4] second child of 1, does not have children
   7993    *     [5] third child of 1, does not have children
   7994    *
   7995    * - The algorithm repeats until all target array indices have been processed.
   7996    */
   7997   XML_Content *dest = ret; /* tree node writing location, moves upwards */
   7998   XML_Content *const destLimit = &ret[dtd->scaffCount];
   7999   XML_Content *jobDest = ret; /* next free writing location in target array */
   8000   str = (XML_Char *)&ret[dtd->scaffCount];
   8001 
   8002   /* Add the starting job, the root node (index 0) of the source tree  */
   8003   (jobDest++)->numchildren = 0;
   8004 
   8005   for (; dest < destLimit; dest++) {
   8006     /* Retrieve source tree array index from job storage */
   8007     const int src_node = (int)dest->numchildren;
   8008 
   8009     /* Convert item */
   8010     dest->type = dtd->scaffold[src_node].type;
   8011     dest->quant = dtd->scaffold[src_node].quant;
   8012     if (dest->type == XML_CTYPE_NAME) {
   8013       const XML_Char *src;
   8014       dest->name = str;
   8015       src = dtd->scaffold[src_node].name;
   8016       for (;;) {
   8017         *str++ = *src;
   8018         if (! *src)
   8019           break;
   8020         src++;
   8021       }
   8022       dest->numchildren = 0;
   8023       dest->children = NULL;
   8024     } else {
   8025       unsigned int i;
   8026       int cn;
   8027       dest->name = NULL;
   8028       dest->numchildren = dtd->scaffold[src_node].childcnt;
   8029       dest->children = jobDest;
   8030 
   8031       /* Append scaffold indices of children to array */
   8032       for (i = 0, cn = dtd->scaffold[src_node].firstchild;
   8033            i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
   8034         (jobDest++)->numchildren = (unsigned int)cn;
   8035     }
   8036   }
   8037 
   8038   return ret;
   8039 }
   8040 
   8041 static ELEMENT_TYPE *
   8042 getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
   8043                const char *end) {
   8044   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   8045   const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
   8046   ELEMENT_TYPE *ret;
   8047 
   8048   if (! name)
   8049     return NULL;
   8050   ret = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
   8051                                sizeof(ELEMENT_TYPE));
   8052   if (! ret)
   8053     return NULL;
   8054   if (ret->name != name)
   8055     poolDiscard(&dtd->pool);
   8056   else {
   8057     poolFinish(&dtd->pool);
   8058     if (! setElementTypePrefix(parser, ret))
   8059       return NULL;
   8060   }
   8061   return ret;
   8062 }
   8063 
   8064 static XML_Char *
   8065 copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
   8066   size_t charsRequired = 0;
   8067   XML_Char *result;
   8068 
   8069   /* First determine how long the string is */
   8070   while (s[charsRequired] != 0) {
   8071     charsRequired++;
   8072   }
   8073   /* Include the terminator */
   8074   charsRequired++;
   8075 
   8076   /* Now allocate space for the copy */
   8077   result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char));
   8078   if (result == NULL)
   8079     return NULL;
   8080   /* Copy the original into place */
   8081   memcpy(result, s, charsRequired * sizeof(XML_Char));
   8082   return result;
   8083 }
   8084 
   8085 #if XML_GE == 1
   8086 
   8087 static float
   8088 accountingGetCurrentAmplification(XML_Parser rootParser) {
   8089   //                                          1.........1.........12 => 22
   8090   const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
   8091   const XmlBigCount countBytesOutput
   8092       = rootParser->m_accounting.countBytesDirect
   8093         + rootParser->m_accounting.countBytesIndirect;
   8094   const float amplificationFactor
   8095       = rootParser->m_accounting.countBytesDirect
   8096             ? (countBytesOutput
   8097                / (float)(rootParser->m_accounting.countBytesDirect))
   8098             : ((lenOfShortestInclude
   8099                 + rootParser->m_accounting.countBytesIndirect)
   8100                / (float)lenOfShortestInclude);
   8101   assert(! rootParser->m_parentParser);
   8102   return amplificationFactor;
   8103 }
   8104 
   8105 static void
   8106 accountingReportStats(XML_Parser originParser, const char *epilog) {
   8107   const XML_Parser rootParser = getRootParserOf(originParser, NULL);
   8108   assert(! rootParser->m_parentParser);
   8109 
   8110   if (rootParser->m_accounting.debugLevel == 0u) {
   8111     return;
   8112   }
   8113 
   8114   const float amplificationFactor
   8115       = accountingGetCurrentAmplification(rootParser);
   8116   fprintf(stderr,
   8117           "expat: Accounting(%p): Direct " EXPAT_FMT_ULL(
   8118               "10") ", indirect " EXPAT_FMT_ULL("10") ", amplification %8.2f%s",
   8119           (void *)rootParser, rootParser->m_accounting.countBytesDirect,
   8120           rootParser->m_accounting.countBytesIndirect,
   8121           (double)amplificationFactor, epilog);
   8122 }
   8123 
   8124 static void
   8125 accountingOnAbort(XML_Parser originParser) {
   8126   accountingReportStats(originParser, " ABORTING\n");
   8127 }
   8128 
   8129 static void
   8130 accountingReportDiff(XML_Parser rootParser,
   8131                      unsigned int levelsAwayFromRootParser, const char *before,
   8132                      const char *after, ptrdiff_t bytesMore, int source_line,
   8133                      enum XML_Account account) {
   8134   assert(! rootParser->m_parentParser);
   8135 
   8136   fprintf(stderr,
   8137           " (+" EXPAT_FMT_PTRDIFF_T("6") " bytes %s|%u, xmlparse.c:%d) %*s\"",
   8138           bytesMore, (account == XML_ACCOUNT_DIRECT) ? "DIR" : "EXP",
   8139           levelsAwayFromRootParser, source_line, 10, "");
   8140 
   8141   const char ellipis[] = "[..]";
   8142   const size_t ellipsisLength = sizeof(ellipis) /* because compile-time */ - 1;
   8143   const unsigned int contextLength = 10;
   8144 
   8145   /* Note: Performance is of no concern here */
   8146   const char *walker = before;
   8147   if ((rootParser->m_accounting.debugLevel >= 3u)
   8148       || (after - before)
   8149              <= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
   8150     for (; walker < after; walker++) {
   8151       fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
   8152     }
   8153   } else {
   8154     for (; walker < before + contextLength; walker++) {
   8155       fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
   8156     }
   8157     fprintf(stderr, ellipis);
   8158     walker = after - contextLength;
   8159     for (; walker < after; walker++) {
   8160       fprintf(stderr, "%s", unsignedCharToPrintable(walker[0]));
   8161     }
   8162   }
   8163   fprintf(stderr, "\"\n");
   8164 }
   8165 
   8166 static XML_Bool
   8167 accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
   8168                         const char *after, int source_line,
   8169                         enum XML_Account account) {
   8170   /* Note: We need to check the token type *first* to be sure that
   8171    *       we can even access variable <after>, safely.
   8172    *       E.g. for XML_TOK_NONE <after> may hold an invalid pointer. */
   8173   switch (tok) {
   8174   case XML_TOK_INVALID:
   8175   case XML_TOK_PARTIAL:
   8176   case XML_TOK_PARTIAL_CHAR:
   8177   case XML_TOK_NONE:
   8178     return XML_TRUE;
   8179   }
   8180 
   8181   if (account == XML_ACCOUNT_NONE)
   8182     return XML_TRUE; /* because these bytes have been accounted for, already */
   8183 
   8184   unsigned int levelsAwayFromRootParser;
   8185   const XML_Parser rootParser
   8186       = getRootParserOf(originParser, &levelsAwayFromRootParser);
   8187   assert(! rootParser->m_parentParser);
   8188 
   8189   const int isDirect
   8190       = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
   8191   const ptrdiff_t bytesMore = after - before;
   8192 
   8193   XmlBigCount *const additionTarget
   8194       = isDirect ? &rootParser->m_accounting.countBytesDirect
   8195                  : &rootParser->m_accounting.countBytesIndirect;
   8196 
   8197   /* Detect and avoid integer overflow */
   8198   if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
   8199     return XML_FALSE;
   8200   *additionTarget += bytesMore;
   8201 
   8202   const XmlBigCount countBytesOutput
   8203       = rootParser->m_accounting.countBytesDirect
   8204         + rootParser->m_accounting.countBytesIndirect;
   8205   const float amplificationFactor
   8206       = accountingGetCurrentAmplification(rootParser);
   8207   const XML_Bool tolerated
   8208       = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
   8209         || (amplificationFactor
   8210             <= rootParser->m_accounting.maximumAmplificationFactor);
   8211 
   8212   if (rootParser->m_accounting.debugLevel >= 2u) {
   8213     accountingReportStats(rootParser, "");
   8214     accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
   8215                          bytesMore, source_line, account);
   8216   }
   8217 
   8218   return tolerated;
   8219 }
   8220 
   8221 unsigned long long
   8222 testingAccountingGetCountBytesDirect(XML_Parser parser) {
   8223   if (! parser)
   8224     return 0;
   8225   return parser->m_accounting.countBytesDirect;
   8226 }
   8227 
   8228 unsigned long long
   8229 testingAccountingGetCountBytesIndirect(XML_Parser parser) {
   8230   if (! parser)
   8231     return 0;
   8232   return parser->m_accounting.countBytesIndirect;
   8233 }
   8234 
   8235 static void
   8236 entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
   8237                           const char *action, int sourceLine) {
   8238   assert(! rootParser->m_parentParser);
   8239   if (rootParser->m_entity_stats.debugLevel == 0u)
   8240     return;
   8241 
   8242 #  if defined(XML_UNICODE)
   8243   const char *const entityName = "[..]";
   8244 #  else
   8245   const char *const entityName = entity->name;
   8246 #  endif
   8247 
   8248   fprintf(
   8249       stderr,
   8250       "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s; %s length %d (xmlparse.c:%d)\n",
   8251       (void *)rootParser, rootParser->m_entity_stats.countEverOpened,
   8252       rootParser->m_entity_stats.currentDepth,
   8253       rootParser->m_entity_stats.maximumDepthSeen,
   8254       ((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "",
   8255       entity->is_param ? "%" : "&", entityName, action, entity->textLen,
   8256       sourceLine);
   8257 }
   8258 
   8259 static void
   8260 entityTrackingOnOpen(XML_Parser originParser, ENTITY *entity, int sourceLine) {
   8261   const XML_Parser rootParser = getRootParserOf(originParser, NULL);
   8262   assert(! rootParser->m_parentParser);
   8263 
   8264   rootParser->m_entity_stats.countEverOpened++;
   8265   rootParser->m_entity_stats.currentDepth++;
   8266   if (rootParser->m_entity_stats.currentDepth
   8267       > rootParser->m_entity_stats.maximumDepthSeen) {
   8268     rootParser->m_entity_stats.maximumDepthSeen++;
   8269   }
   8270 
   8271   entityTrackingReportStats(rootParser, entity, "OPEN ", sourceLine);
   8272 }
   8273 
   8274 static void
   8275 entityTrackingOnClose(XML_Parser originParser, ENTITY *entity, int sourceLine) {
   8276   const XML_Parser rootParser = getRootParserOf(originParser, NULL);
   8277   assert(! rootParser->m_parentParser);
   8278 
   8279   entityTrackingReportStats(rootParser, entity, "CLOSE", sourceLine);
   8280   rootParser->m_entity_stats.currentDepth--;
   8281 }
   8282 
   8283 static XML_Parser
   8284 getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
   8285   XML_Parser rootParser = parser;
   8286   unsigned int stepsTakenUpwards = 0;
   8287   while (rootParser->m_parentParser) {
   8288     rootParser = rootParser->m_parentParser;
   8289     stepsTakenUpwards++;
   8290   }
   8291   assert(! rootParser->m_parentParser);
   8292   if (outLevelDiff != NULL) {
   8293     *outLevelDiff = stepsTakenUpwards;
   8294   }
   8295   return rootParser;
   8296 }
   8297 
   8298 const char *
   8299 unsignedCharToPrintable(unsigned char c) {
   8300   switch (c) {
   8301   case 0:
   8302     return "\\0";
   8303   case 1:
   8304     return "\\x1";
   8305   case 2:
   8306     return "\\x2";
   8307   case 3:
   8308     return "\\x3";
   8309   case 4:
   8310     return "\\x4";
   8311   case 5:
   8312     return "\\x5";
   8313   case 6:
   8314     return "\\x6";
   8315   case 7:
   8316     return "\\x7";
   8317   case 8:
   8318     return "\\x8";
   8319   case 9:
   8320     return "\\t";
   8321   case 10:
   8322     return "\\n";
   8323   case 11:
   8324     return "\\xB";
   8325   case 12:
   8326     return "\\xC";
   8327   case 13:
   8328     return "\\r";
   8329   case 14:
   8330     return "\\xE";
   8331   case 15:
   8332     return "\\xF";
   8333   case 16:
   8334     return "\\x10";
   8335   case 17:
   8336     return "\\x11";
   8337   case 18:
   8338     return "\\x12";
   8339   case 19:
   8340     return "\\x13";
   8341   case 20:
   8342     return "\\x14";
   8343   case 21:
   8344     return "\\x15";
   8345   case 22:
   8346     return "\\x16";
   8347   case 23:
   8348     return "\\x17";
   8349   case 24:
   8350     return "\\x18";
   8351   case 25:
   8352     return "\\x19";
   8353   case 26:
   8354     return "\\x1A";
   8355   case 27:
   8356     return "\\x1B";
   8357   case 28:
   8358     return "\\x1C";
   8359   case 29:
   8360     return "\\x1D";
   8361   case 30:
   8362     return "\\x1E";
   8363   case 31:
   8364     return "\\x1F";
   8365   case 32:
   8366     return " ";
   8367   case 33:
   8368     return "!";
   8369   case 34:
   8370     return "\\\"";
   8371   case 35:
   8372     return "#";
   8373   case 36:
   8374     return "$";
   8375   case 37:
   8376     return "%";
   8377   case 38:
   8378     return "&";
   8379   case 39:
   8380     return "'";
   8381   case 40:
   8382     return "(";
   8383   case 41:
   8384     return ")";
   8385   case 42:
   8386     return "*";
   8387   case 43:
   8388     return "+";
   8389   case 44:
   8390     return ",";
   8391   case 45:
   8392     return "-";
   8393   case 46:
   8394     return ".";
   8395   case 47:
   8396     return "/";
   8397   case 48:
   8398     return "0";
   8399   case 49:
   8400     return "1";
   8401   case 50:
   8402     return "2";
   8403   case 51:
   8404     return "3";
   8405   case 52:
   8406     return "4";
   8407   case 53:
   8408     return "5";
   8409   case 54:
   8410     return "6";
   8411   case 55:
   8412     return "7";
   8413   case 56:
   8414     return "8";
   8415   case 57:
   8416     return "9";
   8417   case 58:
   8418     return ":";
   8419   case 59:
   8420     return ";";
   8421   case 60:
   8422     return "<";
   8423   case 61:
   8424     return "=";
   8425   case 62:
   8426     return ">";
   8427   case 63:
   8428     return "?";
   8429   case 64:
   8430     return "@";
   8431   case 65:
   8432     return "A";
   8433   case 66:
   8434     return "B";
   8435   case 67:
   8436     return "C";
   8437   case 68:
   8438     return "D";
   8439   case 69:
   8440     return "E";
   8441   case 70:
   8442     return "F";
   8443   case 71:
   8444     return "G";
   8445   case 72:
   8446     return "H";
   8447   case 73:
   8448     return "I";
   8449   case 74:
   8450     return "J";
   8451   case 75:
   8452     return "K";
   8453   case 76:
   8454     return "L";
   8455   case 77:
   8456     return "M";
   8457   case 78:
   8458     return "N";
   8459   case 79:
   8460     return "O";
   8461   case 80:
   8462     return "P";
   8463   case 81:
   8464     return "Q";
   8465   case 82:
   8466     return "R";
   8467   case 83:
   8468     return "S";
   8469   case 84:
   8470     return "T";
   8471   case 85:
   8472     return "U";
   8473   case 86:
   8474     return "V";
   8475   case 87:
   8476     return "W";
   8477   case 88:
   8478     return "X";
   8479   case 89:
   8480     return "Y";
   8481   case 90:
   8482     return "Z";
   8483   case 91:
   8484     return "[";
   8485   case 92:
   8486     return "\\\\";
   8487   case 93:
   8488     return "]";
   8489   case 94:
   8490     return "^";
   8491   case 95:
   8492     return "_";
   8493   case 96:
   8494     return "`";
   8495   case 97:
   8496     return "a";
   8497   case 98:
   8498     return "b";
   8499   case 99:
   8500     return "c";
   8501   case 100:
   8502     return "d";
   8503   case 101:
   8504     return "e";
   8505   case 102:
   8506     return "f";
   8507   case 103:
   8508     return "g";
   8509   case 104:
   8510     return "h";
   8511   case 105:
   8512     return "i";
   8513   case 106:
   8514     return "j";
   8515   case 107:
   8516     return "k";
   8517   case 108:
   8518     return "l";
   8519   case 109:
   8520     return "m";
   8521   case 110:
   8522     return "n";
   8523   case 111:
   8524     return "o";
   8525   case 112:
   8526     return "p";
   8527   case 113:
   8528     return "q";
   8529   case 114:
   8530     return "r";
   8531   case 115:
   8532     return "s";
   8533   case 116:
   8534     return "t";
   8535   case 117:
   8536     return "u";
   8537   case 118:
   8538     return "v";
   8539   case 119:
   8540     return "w";
   8541   case 120:
   8542     return "x";
   8543   case 121:
   8544     return "y";
   8545   case 122:
   8546     return "z";
   8547   case 123:
   8548     return "{";
   8549   case 124:
   8550     return "|";
   8551   case 125:
   8552     return "}";
   8553   case 126:
   8554     return "~";
   8555   case 127:
   8556     return "\\x7F";
   8557   case 128:
   8558     return "\\x80";
   8559   case 129:
   8560     return "\\x81";
   8561   case 130:
   8562     return "\\x82";
   8563   case 131:
   8564     return "\\x83";
   8565   case 132:
   8566     return "\\x84";
   8567   case 133:
   8568     return "\\x85";
   8569   case 134:
   8570     return "\\x86";
   8571   case 135:
   8572     return "\\x87";
   8573   case 136:
   8574     return "\\x88";
   8575   case 137:
   8576     return "\\x89";
   8577   case 138:
   8578     return "\\x8A";
   8579   case 139:
   8580     return "\\x8B";
   8581   case 140:
   8582     return "\\x8C";
   8583   case 141:
   8584     return "\\x8D";
   8585   case 142:
   8586     return "\\x8E";
   8587   case 143:
   8588     return "\\x8F";
   8589   case 144:
   8590     return "\\x90";
   8591   case 145:
   8592     return "\\x91";
   8593   case 146:
   8594     return "\\x92";
   8595   case 147:
   8596     return "\\x93";
   8597   case 148:
   8598     return "\\x94";
   8599   case 149:
   8600     return "\\x95";
   8601   case 150:
   8602     return "\\x96";
   8603   case 151:
   8604     return "\\x97";
   8605   case 152:
   8606     return "\\x98";
   8607   case 153:
   8608     return "\\x99";
   8609   case 154:
   8610     return "\\x9A";
   8611   case 155:
   8612     return "\\x9B";
   8613   case 156:
   8614     return "\\x9C";
   8615   case 157:
   8616     return "\\x9D";
   8617   case 158:
   8618     return "\\x9E";
   8619   case 159:
   8620     return "\\x9F";
   8621   case 160:
   8622     return "\\xA0";
   8623   case 161:
   8624     return "\\xA1";
   8625   case 162:
   8626     return "\\xA2";
   8627   case 163:
   8628     return "\\xA3";
   8629   case 164:
   8630     return "\\xA4";
   8631   case 165:
   8632     return "\\xA5";
   8633   case 166:
   8634     return "\\xA6";
   8635   case 167:
   8636     return "\\xA7";
   8637   case 168:
   8638     return "\\xA8";
   8639   case 169:
   8640     return "\\xA9";
   8641   case 170:
   8642     return "\\xAA";
   8643   case 171:
   8644     return "\\xAB";
   8645   case 172:
   8646     return "\\xAC";
   8647   case 173:
   8648     return "\\xAD";
   8649   case 174:
   8650     return "\\xAE";
   8651   case 175:
   8652     return "\\xAF";
   8653   case 176:
   8654     return "\\xB0";
   8655   case 177:
   8656     return "\\xB1";
   8657   case 178:
   8658     return "\\xB2";
   8659   case 179:
   8660     return "\\xB3";
   8661   case 180:
   8662     return "\\xB4";
   8663   case 181:
   8664     return "\\xB5";
   8665   case 182:
   8666     return "\\xB6";
   8667   case 183:
   8668     return "\\xB7";
   8669   case 184:
   8670     return "\\xB8";
   8671   case 185:
   8672     return "\\xB9";
   8673   case 186:
   8674     return "\\xBA";
   8675   case 187:
   8676     return "\\xBB";
   8677   case 188:
   8678     return "\\xBC";
   8679   case 189:
   8680     return "\\xBD";
   8681   case 190:
   8682     return "\\xBE";
   8683   case 191:
   8684     return "\\xBF";
   8685   case 192:
   8686     return "\\xC0";
   8687   case 193:
   8688     return "\\xC1";
   8689   case 194:
   8690     return "\\xC2";
   8691   case 195:
   8692     return "\\xC3";
   8693   case 196:
   8694     return "\\xC4";
   8695   case 197:
   8696     return "\\xC5";
   8697   case 198:
   8698     return "\\xC6";
   8699   case 199:
   8700     return "\\xC7";
   8701   case 200:
   8702     return "\\xC8";
   8703   case 201:
   8704     return "\\xC9";
   8705   case 202:
   8706     return "\\xCA";
   8707   case 203:
   8708     return "\\xCB";
   8709   case 204:
   8710     return "\\xCC";
   8711   case 205:
   8712     return "\\xCD";
   8713   case 206:
   8714     return "\\xCE";
   8715   case 207:
   8716     return "\\xCF";
   8717   case 208:
   8718     return "\\xD0";
   8719   case 209:
   8720     return "\\xD1";
   8721   case 210:
   8722     return "\\xD2";
   8723   case 211:
   8724     return "\\xD3";
   8725   case 212:
   8726     return "\\xD4";
   8727   case 213:
   8728     return "\\xD5";
   8729   case 214:
   8730     return "\\xD6";
   8731   case 215:
   8732     return "\\xD7";
   8733   case 216:
   8734     return "\\xD8";
   8735   case 217:
   8736     return "\\xD9";
   8737   case 218:
   8738     return "\\xDA";
   8739   case 219:
   8740     return "\\xDB";
   8741   case 220:
   8742     return "\\xDC";
   8743   case 221:
   8744     return "\\xDD";
   8745   case 222:
   8746     return "\\xDE";
   8747   case 223:
   8748     return "\\xDF";
   8749   case 224:
   8750     return "\\xE0";
   8751   case 225:
   8752     return "\\xE1";
   8753   case 226:
   8754     return "\\xE2";
   8755   case 227:
   8756     return "\\xE3";
   8757   case 228:
   8758     return "\\xE4";
   8759   case 229:
   8760     return "\\xE5";
   8761   case 230:
   8762     return "\\xE6";
   8763   case 231:
   8764     return "\\xE7";
   8765   case 232:
   8766     return "\\xE8";
   8767   case 233:
   8768     return "\\xE9";
   8769   case 234:
   8770     return "\\xEA";
   8771   case 235:
   8772     return "\\xEB";
   8773   case 236:
   8774     return "\\xEC";
   8775   case 237:
   8776     return "\\xED";
   8777   case 238:
   8778     return "\\xEE";
   8779   case 239:
   8780     return "\\xEF";
   8781   case 240:
   8782     return "\\xF0";
   8783   case 241:
   8784     return "\\xF1";
   8785   case 242:
   8786     return "\\xF2";
   8787   case 243:
   8788     return "\\xF3";
   8789   case 244:
   8790     return "\\xF4";
   8791   case 245:
   8792     return "\\xF5";
   8793   case 246:
   8794     return "\\xF6";
   8795   case 247:
   8796     return "\\xF7";
   8797   case 248:
   8798     return "\\xF8";
   8799   case 249:
   8800     return "\\xF9";
   8801   case 250:
   8802     return "\\xFA";
   8803   case 251:
   8804     return "\\xFB";
   8805   case 252:
   8806     return "\\xFC";
   8807   case 253:
   8808     return "\\xFD";
   8809   case 254:
   8810     return "\\xFE";
   8811   case 255:
   8812     return "\\xFF";
   8813   // LCOV_EXCL_START
   8814   default:
   8815     assert(0); /* never gets here */
   8816     return "dead code";
   8817   }
   8818   assert(0); /* never gets here */
   8819   // LCOV_EXCL_STOP
   8820 }
   8821 
   8822 #endif /* XML_GE == 1 */
   8823 
   8824 static unsigned long
   8825 getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
   8826   const char *const valueOrNull = getenv(variableName);
   8827   if (valueOrNull == NULL) {
   8828     return defaultDebugLevel;
   8829   }
   8830   const char *const value = valueOrNull;
   8831 
   8832   errno = 0;
   8833   char *afterValue = NULL;
   8834   unsigned long debugLevel = strtoul(value, &afterValue, 10);
   8835   if ((errno != 0) || (afterValue == value) || (afterValue[0] != '\0')) {
   8836     errno = 0;
   8837     return defaultDebugLevel;
   8838   }
   8839 
   8840   return debugLevel;
   8841 }
   8842