Coverage Report

Created: 2026-11-06 11:29

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