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