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