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