Coverage Report

Created: 2026-10-28 07:09

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