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