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