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