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