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