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