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