Coverage Report

Created: 2026-07-30 07:17

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