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