Coverage Report

Created: 2026-07-15 07:31

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
609k
#  define XmlConvert XmlUtf8Convert
180
0
#  define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
181
20.7k
#  define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
182
63
#  define XmlEncode XmlUtf8Encode
183
98.8k
#  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
8.18M
#  define XML_T(x) x
210
19.3k
#  define XML_L(x) x
211
212
#endif
213
214
#ifdef XML_LARGE_SIZE
215
#  define XML_INDEX_MAX LLONG_MAX
216
#else
217
20.8k
#  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
124k
#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
225
226
8
#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
264k
  ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
260
#define PROBE_STEP(hash, mask, power)                                          \
261
264k
  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
262
263
typedef struct {
264
  NAMED **p;
265
  NAMED **end;
266
} HASH_TABLE_ITER;
267
268
18.3k
#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
269
20.7k
#define INIT_DATA_BUF_SIZE 1024
270
26.1k
#define INIT_ATTS_SIZE 16
271
3.82k
#define INIT_ATTS_VERSION 0xFFFFFFFF
272
113k
#define INIT_BLOCK_SIZE 1024
273
20.7k
#define INIT_BUFFER_SIZE 1024
274
275
178k
#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
709k
#define poolStart(pool) ((pool)->start)
662
23.3k
#define poolLength(pool) ((pool)->ptr - (pool)->start)
663
0
#define poolChop(pool) ((void)--(pool->ptr))
664
0
#define poolLastChar(pool) (((pool)->ptr)[-1])
665
285k
#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
666
740k
#define poolFinish(pool) ((pool)->start = (pool)->ptr)
667
668
bool
669
2.06M
poolAppendChar(STRING_POOL *pool, XML_Char c) {
670
2.06M
  if (pool->ptr == pool->end && ! poolGrow(pool))
671
0
    return false;
672
673
2.06M
  *(pool->ptr)++ = c;
674
2.06M
  return true;
675
2.06M
}
676
677
bool
678
640k
poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len) {
679
  // Detect and prevent integer overflow
680
640k
  if (len > SIZE_MAX / sizeof(XML_Char))
681
0
    return false;
682
683
640k
  if (! poolGrowUntil(pool, len))
684
0
    return false;
685
686
640k
  memcpy(pool->ptr, s, len * sizeof(XML_Char));
687
640k
  pool->ptr += len;
688
689
640k
  return true;
690
640k
}
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
581k
#  define MALLOC(parser, s) (expat_malloc((parser), (s), __LINE__))
827
6.33k
#  define REALLOC(parser, p, s) (expat_realloc((parser), (p), (s), __LINE__))
828
3.02M
#  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
588k
                              int sourceLine) {
853
588k
  assert(rootParser != NULL);
854
588k
  assert(increase > 0);
855
856
588k
  XmlBigCount newTotal = 0;
857
588k
  bool tolerable = true;
858
859
  // Detect integer overflow
860
588k
  if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated < increase) {
861
0
    tolerable = false;
862
588k
  } else {
863
588k
    newTotal = rootParser->m_alloc_tracker.bytesAllocated + increase;
864
865
588k
    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
588k
  }
876
877
588k
  if (! tolerable && (rootParser->m_alloc_tracker.debugLevel >= 1)) {
878
0
    expat_heap_stat(rootParser, '+', increase, newTotal, newTotal, sourceLine);
879
0
  }
880
881
588k
  return tolerable;
882
588k
}
883
884
#  if defined(XML_TESTING)
885
void *
886
#  else
887
static void *
888
#  endif
889
583k
expat_malloc(XML_Parser parser, size_t size, int sourceLine) {
890
  // Detect integer overflow
891
583k
  if (SIZE_MAX - size < sizeof(size_t) + EXPAT_MALLOC_PADDING) {
892
0
    return NULL;
893
0
  }
894
895
583k
  const XML_Parser rootParser = getRootParserOf(parser, NULL);
896
583k
  assert(rootParser->m_parentParser == NULL);
897
898
583k
  const size_t bytesToAllocate = sizeof(size_t) + EXPAT_MALLOC_PADDING + size;
899
900
583k
  if ((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated
901
583k
      < bytesToAllocate) {
902
0
    return NULL; // i.e. signal integer overflow as out-of-memory
903
0
  }
904
905
583k
  if (! expat_heap_increase_tolerable(rootParser, bytesToAllocate,
906
583k
                                      sourceLine)) {
907
0
    return NULL; // i.e. signal violation as out-of-memory
908
0
  }
909
910
  // Actually allocate
911
583k
  void *const mallocedPtr = parser->m_mem.malloc_fcn(bytesToAllocate);
912
913
583k
  if (mallocedPtr == NULL) {
914
0
    return NULL;
915
0
  }
916
917
  // Update in-block recorded size
918
583k
  *(size_t *)mallocedPtr = size;
919
920
  // Update accounting
921
583k
  rootParser->m_alloc_tracker.bytesAllocated += bytesToAllocate;
922
923
  // Report as needed
924
583k
  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
583k
  return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING;
936
583k
}
937
938
#  if defined(XML_TESTING)
939
void
940
#  else
941
static void
942
#  endif
943
3.02M
expat_free(XML_Parser parser, void *ptr, int sourceLine) {
944
3.02M
  assert(parser != NULL);
945
946
3.02M
  if (ptr == NULL) {
947
2.42M
    return;
948
2.42M
  }
949
950
604k
  const XML_Parser rootParser = getRootParserOf(parser, NULL);
951
604k
  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
604k
  void *const mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t);
956
604k
  const size_t bytesAllocated
957
604k
      = sizeof(size_t) + EXPAT_MALLOC_PADDING + *(size_t *)mallocedPtr;
958
959
  // Update accounting
960
604k
  assert(rootParser->m_alloc_tracker.bytesAllocated >= bytesAllocated);
961
604k
  rootParser->m_alloc_tracker.bytesAllocated -= bytesAllocated;
962
963
  // Report as needed
964
604k
  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
604k
  parser->m_mem.free_fcn(mallocedPtr);
972
604k
}
973
974
#  if defined(XML_TESTING)
975
void *
976
#  else
977
static void *
978
#  endif
979
6.33k
expat_realloc(XML_Parser parser, void *ptr, size_t size, int sourceLine) {
980
6.33k
  assert(parser != NULL);
981
982
6.33k
  if (ptr == NULL) {
983
2.08k
    return expat_malloc(parser, size, sourceLine);
984
2.08k
  }
985
986
4.24k
  if (size == 0) {
987
0
    expat_free(parser, ptr, sourceLine);
988
0
    return NULL;
989
0
  }
990
991
4.24k
  const XML_Parser rootParser = getRootParserOf(parser, NULL);
992
4.24k
  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
4.24k
  void *mallocedPtr = (char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t);
997
4.24k
  const size_t prevSize = *(size_t *)mallocedPtr;
998
999
  // Classify upcoming change
1000
4.24k
  const bool isIncrease = (size > prevSize);
1001
4.24k
  const size_t absDiff
1002
4.24k
      = (size > prevSize) ? (size - prevSize) : (prevSize - size);
1003
1004
  // Ask for permission from accounting
1005
4.24k
  if (isIncrease) {
1006
4.24k
    if (! expat_heap_increase_tolerable(rootParser, absDiff, sourceLine)) {
1007
0
      return NULL; // i.e. signal violation as out-of-memory
1008
0
    }
1009
4.24k
  }
1010
1011
  // NOTE: Integer overflow detection has already been done for us
1012
  //       by expat_heap_increase_tolerable(..) above
1013
4.24k
  assert(SIZE_MAX - sizeof(size_t) - EXPAT_MALLOC_PADDING >= size);
1014
1015
  // Actually allocate
1016
4.24k
  mallocedPtr = parser->m_mem.realloc_fcn(
1017
4.24k
      mallocedPtr, sizeof(size_t) + EXPAT_MALLOC_PADDING + size);
1018
1019
4.24k
  if (mallocedPtr == NULL) {
1020
0
    return NULL;
1021
0
  }
1022
1023
  // Update accounting
1024
4.24k
  if (isIncrease) {
1025
4.24k
    assert((XmlBigCount)-1 - rootParser->m_alloc_tracker.bytesAllocated
1026
4.24k
           >= absDiff);
1027
4.24k
    rootParser->m_alloc_tracker.bytesAllocated += absDiff;
1028
4.24k
  } 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
4.24k
  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
4.24k
  *(size_t *)mallocedPtr = size;
1047
1048
4.24k
  return (char *)mallocedPtr + sizeof(size_t) + EXPAT_MALLOC_PADDING;
1049
4.24k
}
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
20.7k
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
1059
20.7k
  XML_Char tmp[2] = {nsSep, 0};
1060
20.7k
  return XML_ParserCreate_MM(encodingName, NULL, tmp);
1061
20.7k
}
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
20.7k
gather_time_entropy(void) {
1079
#  ifdef _WIN32
1080
  FILETIME ft;
1081
  GetSystemTimeAsFileTime(&ft); /* never fails */
1082
  return ft.dwHighDateTime ^ ft.dwLowDateTime;
1083
#  else
1084
20.7k
  struct timeval tv;
1085
20.7k
  int gettimeofday_res;
1086
1087
20.7k
  gettimeofday_res = gettimeofday(&tv, NULL);
1088
1089
#    if defined(NDEBUG)
1090
  (void)gettimeofday_res;
1091
#    else
1092
20.7k
  assert(gettimeofday_res == 0);
1093
20.7k
#    endif /* defined(NDEBUG) */
1094
1095
  /* Microseconds time is <20 bits entropy */
1096
20.7k
  return tv.tv_usec;
1097
20.7k
#  endif
1098
20.7k
}
1099
1100
#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
1101
1102
static struct sipkey
1103
20.7k
ENTROPY_DEBUG(const char *label, struct sipkey entropy_128) {
1104
20.7k
  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
20.7k
  return entropy_128;
1112
20.7k
}
1113
1114
static struct sipkey
1115
20.7k
generate_hash_secret_salt(void) {
1116
20.7k
  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
20.7k
  if (writeRandomBytes_getentropy(&entropy, sizeof(entropy))) {
1133
0
    return ENTROPY_DEBUG("getentropy", entropy);
1134
0
  }
1135
20.7k
  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
20.7k
  entropy.k[0] = 0;
1149
20.7k
  entropy.k[1] = gather_time_entropy();
1150
20.7k
#  if ! defined(__wasi__)
1151
  /* Process ID is 0 bits entropy if attacker has local access */
1152
20.7k
  entropy.k[1] ^= getpid();
1153
20.7k
#  endif
1154
1155
  /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
1156
20.7k
  if (sizeof(unsigned long) == 4) {
1157
0
    entropy.k[1] *= 2147483647;
1158
0
    return ENTROPY_DEBUG("fallback(4)", entropy);
1159
20.7k
  } else {
1160
20.7k
    entropy.k[1] *= 2305843009213693951ULL;
1161
20.7k
    return ENTROPY_DEBUG("fallback(8)", entropy);
1162
20.7k
  }
1163
20.7k
#endif
1164
20.7k
}
1165
1166
static void
1167
453k
beforeHandler(XML_Parser parser) {
1168
453k
  assert(parser->m_handlerCallDepth < UINT_MAX);
1169
453k
  parser->m_handlerCallDepth++;
1170
453k
}
1171
1172
static void
1173
453k
afterHandler(XML_Parser parser) {
1174
453k
  assert(parser->m_handlerCallDepth > 0);
1175
453k
  parser->m_handlerCallDepth--;
1176
453k
}
1177
1178
static bool
1179
83.2k
isCalledFromInsideHandler(XML_Parser parser) {
1180
83.2k
  return parser->m_handlerCallDepth > 0;
1181
83.2k
}
1182
1183
static enum XML_Error
1184
callProcessor(XML_Parser parser, const char *start, const char *end,
1185
20.8k
              const char **endPtr) {
1186
20.8k
  const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
1187
1188
20.8k
  if (parser->m_reparseDeferralEnabled
1189
20.8k
      && ! 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
8
    const size_t had_before = parser->m_partialTokenBytesBefore;
1193
    // ...but *do* try anyway if we're close to causing a reallocation.
1194
8
    size_t available_buffer
1195
8
        = EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
1196
8
#if XML_CONTEXT_BYTES > 0
1197
8
    available_buffer -= EXPAT_MIN(available_buffer, XML_CONTEXT_BYTES);
1198
8
#endif
1199
8
    available_buffer
1200
8
        += 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
8
    const bool enough
1203
8
        = (have_now >= 2 * had_before)
1204
0
          || ((size_t)parser->m_lastBufferRequestSize > available_buffer);
1205
1206
8
    if (! enough) {
1207
0
      *endPtr = start; // callers may expect this to be set
1208
0
      return XML_ERROR_NONE;
1209
0
    }
1210
8
  }
1211
#if defined(XML_TESTING)
1212
  g_bytesScanned += (unsigned)have_now;
1213
#endif
1214
  // Run in a loop to eliminate dangerous recursion depths
1215
20.8k
  enum XML_Error ret;
1216
20.8k
  *endPtr = start;
1217
20.8k
  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
20.8k
    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
20.8k
    if (parser->m_parsingStatus.parsing != XML_PARSING) {
1225
0
      parser->m_reenter = XML_FALSE;
1226
0
    }
1227
1228
20.8k
    if (! parser->m_reenter) {
1229
20.8k
      break;
1230
20.8k
    }
1231
1232
0
    parser->m_reenter = XML_FALSE;
1233
0
    if (ret != XML_ERROR_NONE)
1234
0
      return ret;
1235
0
  }
1236
1237
20.8k
  if (ret == XML_ERROR_NONE) {
1238
    // if we consumed nothing, remember what we had on this parse attempt.
1239
1.44k
    if (*endPtr == start) {
1240
0
      parser->m_partialTokenBytesBefore = have_now;
1241
1.44k
    } else {
1242
1.44k
      parser->m_partialTokenBytesBefore = 0;
1243
1.44k
    }
1244
1.44k
  }
1245
20.8k
  return ret;
1246
20.8k
}
1247
1248
static XML_Bool /* only valid for root parser */
1249
20.7k
startParsing(XML_Parser parser) {
1250
  /* hash functions must be initialized before setContext() is called */
1251
20.7k
  if (parser->m_hash_secret_salt_set != XML_TRUE) {
1252
20.7k
    parser->m_hash_secret_salt_128 = generate_hash_secret_salt();
1253
20.7k
    parser->m_hash_secret_salt_set = XML_TRUE;
1254
20.7k
  }
1255
20.7k
  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
20.7k
    return setContext(parser, implicitContext);
1260
20.7k
  }
1261
0
  return XML_TRUE;
1262
20.7k
}
1263
1264
XML_Parser XMLCALL
1265
XML_ParserCreate_MM(const XML_Char *encodingName,
1266
                    const XML_Memory_Handling_Suite *memsuite,
1267
20.7k
                    const XML_Char *nameSep) {
1268
20.7k
  return parserCreate(encodingName, memsuite, nameSep, NULL, NULL);
1269
20.7k
}
1270
1271
static XML_Parser
1272
parserCreate(const XML_Char *encodingName,
1273
             const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep,
1274
20.7k
             DTD *dtd, XML_Parser parentParser) {
1275
20.7k
  XML_Parser parser = NULL;
1276
1277
20.7k
#if XML_GE == 1
1278
20.7k
  const size_t increase
1279
20.7k
      = sizeof(size_t) + EXPAT_MALLOC_PADDING + sizeof(struct XML_ParserStruct);
1280
1281
20.7k
  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
20.7k
  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
20.7k
  } else {
1311
20.7k
    XML_Memory_Handling_Suite *mtemp;
1312
20.7k
#if XML_GE == 1
1313
20.7k
    void *const sizeAndParser = malloc(sizeof(size_t) + EXPAT_MALLOC_PADDING
1314
20.7k
                                       + sizeof(struct XML_ParserStruct));
1315
20.7k
    if (sizeAndParser != NULL) {
1316
20.7k
      *(size_t *)sizeAndParser = sizeof(struct XML_ParserStruct);
1317
20.7k
      parser = (XML_Parser)((char *)sizeAndParser + sizeof(size_t)
1318
20.7k
                            + EXPAT_MALLOC_PADDING);
1319
#else
1320
    parser = malloc(sizeof(struct XML_ParserStruct));
1321
    if (parser != NULL) {
1322
#endif
1323
20.7k
      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
1324
20.7k
      mtemp->malloc_fcn = malloc;
1325
20.7k
      mtemp->realloc_fcn = realloc;
1326
20.7k
      mtemp->free_fcn = free;
1327
20.7k
    }
1328
20.7k
  } // cppcheck-suppress[memleak symbolName=sizeAndParser] // Cppcheck >=2.18.0
1329
1330
20.7k
  if (! parser)
1331
0
    return parser;
1332
1333
20.7k
#if XML_GE == 1
1334
  // Initialize .m_alloc_tracker
1335
20.7k
  memset(&parser->m_alloc_tracker, 0, sizeof(MALLOC_TRACKER));
1336
20.7k
  if (parentParser == NULL) {
1337
20.7k
    parser->m_alloc_tracker.debugLevel
1338
20.7k
        = getDebugLevel("EXPAT_MALLOC_DEBUG", 0u);
1339
20.7k
    parser->m_alloc_tracker.maximumAmplificationFactor
1340
20.7k
        = EXPAT_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION_DEFAULT;
1341
20.7k
    parser->m_alloc_tracker.activationThresholdBytes
1342
20.7k
        = 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
20.7k
    parser->m_parentParser = NULL;
1347
20.7k
    parser->m_accounting.countBytesDirect = 0;
1348
20.7k
  } else {
1349
0
    parser->m_parentParser = parentParser;
1350
0
  }
1351
1352
  // Record XML_ParserStruct allocation we did a few lines up before
1353
20.7k
  const XML_Parser rootParser = getRootParserOf(parser, NULL);
1354
20.7k
  assert(rootParser->m_parentParser == NULL);
1355
20.7k
  assert(SIZE_MAX - rootParser->m_alloc_tracker.bytesAllocated >= increase);
1356
20.7k
  rootParser->m_alloc_tracker.bytesAllocated += increase;
1357
1358
  // Report on allocation
1359
20.7k
  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
20.7k
  parser->m_buffer = NULL;
1375
20.7k
  parser->m_bufferLim = NULL;
1376
1377
20.7k
  parser->m_attsSize = INIT_ATTS_SIZE;
1378
20.7k
  parser->m_atts = MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
1379
20.7k
  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
20.7k
  parser->m_dataBuf = MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
1392
20.7k
  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
20.7k
  parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;
1401
1402
20.7k
  if (dtd)
1403
0
    parser->m_dtd = dtd;
1404
20.7k
  else {
1405
20.7k
    parser->m_dtd = dtdCreate(parser);
1406
20.7k
    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
20.7k
  }
1416
1417
20.7k
  parser->m_freeBindingList = NULL;
1418
20.7k
  parser->m_freeTagList = NULL;
1419
20.7k
  parser->m_freeEntities = NULL;
1420
1421
20.7k
  parser->m_groupSize = 0;
1422
20.7k
  parser->m_groupConnector = NULL;
1423
1424
20.7k
  parser->m_unknownEncodingHandler = NULL;
1425
20.7k
  parser->m_unknownEncodingHandlerData = NULL;
1426
1427
20.7k
  parser->m_namespaceSeparator = ASCII_EXCL;
1428
20.7k
  parser->m_ns = XML_FALSE;
1429
20.7k
  parser->m_ns_triplets = XML_FALSE;
1430
1431
20.7k
  parser->m_nsAtts = NULL;
1432
20.7k
  parser->m_nsAttsVersion = 0;
1433
20.7k
  parser->m_nsAttsPower = 0;
1434
1435
20.7k
  parser->m_protocolEncodingName = NULL;
1436
1437
20.7k
  poolInit(&parser->m_tempPool, parser);
1438
20.7k
  poolInit(&parser->m_temp2Pool, parser);
1439
20.7k
  parserInit(parser, encodingName);
1440
1441
20.7k
  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
20.7k
  if (nameSep) {
1455
20.7k
    parser->m_ns = XML_TRUE;
1456
20.7k
    parser->m_internalEncoding = XmlGetInternalEncodingNS();
1457
20.7k
    parser->m_namespaceSeparator = *nameSep;
1458
20.7k
  } else {
1459
0
    parser->m_internalEncoding = XmlGetInternalEncoding();
1460
0
  }
1461
1462
20.7k
  return parser;
1463
20.7k
}
1464
1465
static void
1466
20.7k
parserInit(XML_Parser parser, const XML_Char *encodingName) {
1467
20.7k
  parser->m_processor = prologInitProcessor;
1468
20.7k
  XmlPrologStateInit(&parser->m_prologState);
1469
20.7k
  if (encodingName != NULL) {
1470
0
    parser->m_protocolEncodingName = copyString(encodingName, parser);
1471
0
  }
1472
20.7k
  parser->m_curBase = NULL;
1473
20.7k
  XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
1474
20.7k
  parser->m_userData = NULL;
1475
20.7k
  parser->m_handlerArg = NULL;
1476
20.7k
  parser->m_startElementHandler = NULL;
1477
20.7k
  parser->m_endElementHandler = NULL;
1478
20.7k
  parser->m_characterDataHandler = NULL;
1479
20.7k
  parser->m_processingInstructionHandler = NULL;
1480
20.7k
  parser->m_commentHandler = NULL;
1481
20.7k
  parser->m_startCdataSectionHandler = NULL;
1482
20.7k
  parser->m_endCdataSectionHandler = NULL;
1483
20.7k
  parser->m_defaultHandler = NULL;
1484
20.7k
  parser->m_startDoctypeDeclHandler = NULL;
1485
20.7k
  parser->m_endDoctypeDeclHandler = NULL;
1486
20.7k
  parser->m_unparsedEntityDeclHandler = NULL;
1487
20.7k
  parser->m_notationDeclHandler = NULL;
1488
20.7k
  parser->m_startNamespaceDeclHandler = NULL;
1489
20.7k
  parser->m_endNamespaceDeclHandler = NULL;
1490
20.7k
  parser->m_notStandaloneHandler = NULL;
1491
20.7k
  parser->m_externalEntityRefHandler = NULL;
1492
20.7k
  parser->m_externalEntityRefHandlerArg = parser;
1493
20.7k
  parser->m_skippedEntityHandler = NULL;
1494
20.7k
  parser->m_elementDeclHandler = NULL;
1495
20.7k
  parser->m_attlistDeclHandler = NULL;
1496
20.7k
  parser->m_entityDeclHandler = NULL;
1497
20.7k
  parser->m_xmlDeclHandler = NULL;
1498
20.7k
  parser->m_bufferPtr = parser->m_buffer;
1499
20.7k
  parser->m_bufferEnd = parser->m_buffer;
1500
20.7k
  parser->m_parseEndByteIndex = 0;
1501
20.7k
  parser->m_parseEndPtr = NULL;
1502
20.7k
  parser->m_partialTokenBytesBefore = 0;
1503
20.7k
  parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
1504
20.7k
  parser->m_lastBufferRequestSize = 0;
1505
20.7k
  parser->m_declElementType = NULL;
1506
20.7k
  parser->m_declAttributeId = NULL;
1507
20.7k
  parser->m_declEntity = NULL;
1508
20.7k
  parser->m_doctypeName = NULL;
1509
20.7k
  parser->m_doctypeSysid = NULL;
1510
20.7k
  parser->m_doctypePubid = NULL;
1511
20.7k
  parser->m_declAttributeType = NULL;
1512
20.7k
  parser->m_declNotationName = NULL;
1513
20.7k
  parser->m_declNotationPublicId = NULL;
1514
20.7k
  parser->m_declAttributeIsCdata = XML_FALSE;
1515
20.7k
  parser->m_declAttributeIsId = XML_FALSE;
1516
20.7k
  memset(&parser->m_position, 0, sizeof(POSITION));
1517
20.7k
  parser->m_errorCode = XML_ERROR_NONE;
1518
20.7k
  parser->m_eventPtr = NULL;
1519
20.7k
  parser->m_eventEndPtr = NULL;
1520
20.7k
  parser->m_positionPtr = NULL;
1521
20.7k
  parser->m_openInternalEntities = NULL;
1522
20.7k
  parser->m_openAttributeEntities = NULL;
1523
20.7k
  parser->m_openValueEntities = NULL;
1524
20.7k
  parser->m_defaultExpandInternalEntities = XML_TRUE;
1525
20.7k
  parser->m_tagLevel = 0;
1526
20.7k
  parser->m_tagStack = NULL;
1527
20.7k
  parser->m_inheritedBindings = NULL;
1528
20.7k
  parser->m_nSpecifiedAtts = 0;
1529
20.7k
  parser->m_unknownEncodingMem = NULL;
1530
20.7k
  parser->m_unknownEncodingRelease = NULL;
1531
20.7k
  parser->m_unknownEncodingData = NULL;
1532
20.7k
  parser->m_parsingStatus.parsing = XML_INITIALIZED;
1533
  // Reentry can only be triggered inside m_processor calls
1534
20.7k
  parser->m_reenter = XML_FALSE;
1535
20.7k
  parser->m_handlerCallDepth = 0;
1536
20.7k
#ifdef XML_DTD
1537
20.7k
  parser->m_isParamEntity = XML_FALSE;
1538
20.7k
  parser->m_useForeignDTD = XML_FALSE;
1539
20.7k
  parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
1540
20.7k
#endif
1541
20.7k
  parser->m_hash_secret_salt_128.k[0] = 0;
1542
20.7k
  parser->m_hash_secret_salt_128.k[1] = 0;
1543
20.7k
  parser->m_hash_secret_salt_set = XML_FALSE;
1544
1545
20.7k
#if XML_GE == 1
1546
20.7k
  memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
1547
20.7k
  parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
1548
20.7k
  parser->m_accounting.maximumAmplificationFactor
1549
20.7k
      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT;
1550
20.7k
  parser->m_accounting.activationThresholdBytes
1551
20.7k
      = EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT;
1552
1553
20.7k
  memset(&parser->m_entity_stats, 0, sizeof(ENTITY_STATS));
1554
20.7k
  parser->m_entity_stats.debugLevel = getDebugLevel("EXPAT_ENTITY_DEBUG", 0u);
1555
20.7k
#endif
1556
20.7k
}
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
59.9k
destroyBindings(BINDING *bindings, XML_Parser parser) {
1834
104k
  for (;;) {
1835
104k
    BINDING *b = bindings;
1836
104k
    if (! b)
1837
59.9k
      break;
1838
44.4k
    bindings = b->nextTagBinding;
1839
44.4k
    FREE(parser, b->uri);
1840
44.4k
    FREE(parser, b);
1841
44.4k
  }
1842
59.9k
}
1843
1844
void XMLCALL
1845
20.7k
XML_ParserFree(XML_Parser parser) {
1846
20.7k
  TAG *tagList;
1847
20.7k
  if ((parser == NULL) || isCalledFromInsideHandler(parser))
1848
0
    return;
1849
  /* free m_tagStack and m_freeTagList */
1850
20.7k
  tagList = parser->m_tagStack;
1851
39.1k
  for (;;) {
1852
39.1k
    TAG *p;
1853
39.1k
    if (tagList == NULL) {
1854
22.3k
      if (parser->m_freeTagList == NULL)
1855
20.7k
        break;
1856
1.59k
      tagList = parser->m_freeTagList;
1857
1.59k
      parser->m_freeTagList = NULL;
1858
1.59k
    }
1859
18.3k
    p = tagList;
1860
18.3k
    tagList = tagList->parent;
1861
18.3k
    FREE(parser, p->buf.raw);
1862
18.3k
    destroyBindings(p->bindings, parser);
1863
18.3k
    FREE(parser, p);
1864
18.3k
  }
1865
  /* free m_openInternalEntities */
1866
20.7k
  for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openInternalEntities;
1867
20.7k
       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
20.7k
  for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openAttributeEntities;
1874
20.7k
       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
20.7k
  for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openValueEntities;
1881
20.7k
       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
20.7k
  for (OPEN_INTERNAL_ENTITY *entityList = parser->m_freeEntities;
1888
20.7k
       entityList != NULL;) {
1889
0
    OPEN_INTERNAL_ENTITY *const openEntity = entityList;
1890
0
    entityList = entityList->next;
1891
0
    FREE(parser, openEntity);
1892
0
  }
1893
20.7k
  parser->m_freeEntities = NULL;
1894
20.7k
  destroyBindings(parser->m_freeBindingList, parser);
1895
20.7k
  destroyBindings(parser->m_inheritedBindings, parser);
1896
20.7k
  poolDestroy(&parser->m_tempPool);
1897
20.7k
  poolDestroy(&parser->m_temp2Pool);
1898
20.7k
  FREE(parser, (void *)parser->m_protocolEncodingName);
1899
20.7k
#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
20.7k
  if (! parser->m_isParamEntity && parser->m_dtd)
1904
#else
1905
  if (parser->m_dtd)
1906
#endif /* XML_DTD */
1907
20.7k
    dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser, parser);
1908
20.7k
  FREE(parser, parser->m_atts);
1909
#ifdef XML_ATTR_INFO
1910
  FREE(parser, parser->m_attInfo);
1911
#endif
1912
20.7k
  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
20.7k
  parser->m_mem.free_fcn(parser->m_buffer);
1917
20.7k
  FREE(parser, parser->m_dataBuf);
1918
20.7k
  FREE(parser, parser->m_nsAtts);
1919
20.7k
  FREE(parser, parser->m_unknownEncodingMem);
1920
20.7k
  if (parser->m_unknownEncodingRelease)
1921
0
    parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
1922
20.7k
  FREE(parser, parser);
1923
20.7k
}
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
20.7k
XML_SetUserData(XML_Parser parser, void *p) {
1959
20.7k
  if (parser == NULL)
1960
0
    return;
1961
20.7k
  if (parser->m_handlerArg == parser->m_userData)
1962
20.7k
    parser->m_handlerArg = parser->m_userData = p;
1963
0
  else
1964
0
    parser->m_userData = p;
1965
20.7k
}
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
20.7k
                      XML_EndElementHandler end) {
2014
20.7k
  if (parser == NULL)
2015
0
    return;
2016
20.7k
  parser->m_startElementHandler = start;
2017
20.7k
  parser->m_endElementHandler = end;
2018
20.7k
}
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
720
                            XML_CharacterDataHandler handler) {
2035
720
  if (parser != NULL)
2036
720
    parser->m_characterDataHandler = handler;
2037
720
}
2038
2039
void XMLCALL
2040
XML_SetProcessingInstructionHandler(XML_Parser parser,
2041
720
                                    XML_ProcessingInstructionHandler handler) {
2042
720
  if (parser != NULL)
2043
720
    parser->m_processingInstructionHandler = handler;
2044
720
}
2045
2046
void XMLCALL
2047
720
XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler) {
2048
720
  if (parser != NULL)
2049
720
    parser->m_commentHandler = handler;
2050
720
}
2051
2052
void XMLCALL
2053
XML_SetCdataSectionHandler(XML_Parser parser,
2054
                           XML_StartCdataSectionHandler start,
2055
720
                           XML_EndCdataSectionHandler end) {
2056
720
  if (parser == NULL)
2057
0
    return;
2058
720
  parser->m_startCdataSectionHandler = start;
2059
720
  parser->m_endCdataSectionHandler = end;
2060
720
}
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
20.7k
                               XML_StartDoctypeDeclHandler start) {
2104
20.7k
  if (parser != NULL)
2105
20.7k
    parser->m_startDoctypeDeclHandler = start;
2106
20.7k
}
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
20.7k
                            XML_EndNamespaceDeclHandler end) {
2131
20.7k
  if (parser == NULL)
2132
0
    return;
2133
20.7k
  parser->m_startNamespaceDeclHandler = start;
2134
20.7k
  parser->m_endNamespaceDeclHandler = end;
2135
20.7k
}
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
20.8k
XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
2285
20.8k
  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
20.8k
  if (isCalledFromInsideHandler(parser))
2291
0
    return XML_STATUS_ERROR;
2292
20.8k
  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
7
  case XML_FINISHED:
2297
7
    parser->m_errorCode = XML_ERROR_FINISHED;
2298
7
    return XML_STATUS_ERROR;
2299
20.7k
  case XML_INITIALIZED:
2300
20.7k
    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
20.7k
    EXPAT_FALLTHROUGH;
2305
20.8k
  default:
2306
20.8k
    parser->m_parsingStatus.parsing = XML_PARSING;
2307
20.8k
  }
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
20.8k
  void *buff = XML_GetBuffer(parser, len);
2387
20.8k
  if (buff == NULL)
2388
0
    return XML_STATUS_ERROR;
2389
20.8k
  if (len > 0) {
2390
20.7k
    assert(s != NULL); // make sure s==NULL && len!=0 was rejected above
2391
20.7k
    memcpy(buff, s, len);
2392
20.7k
  }
2393
20.8k
  return XML_ParseBuffer(parser, len, isFinal);
2394
20.8k
}
2395
2396
enum XML_Status XMLCALL
2397
20.8k
XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
2398
20.8k
  const char *start;
2399
20.8k
  enum XML_Status result = XML_STATUS_OK;
2400
2401
20.8k
  if ((parser == NULL) || isCalledFromInsideHandler(parser))
2402
0
    return XML_STATUS_ERROR;
2403
2404
20.8k
  if (len < 0) {
2405
0
    parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
2406
0
    return XML_STATUS_ERROR;
2407
0
  }
2408
2409
20.8k
  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
20.8k
  default:
2429
20.8k
    parser->m_parsingStatus.parsing = XML_PARSING;
2430
20.8k
  }
2431
2432
  // Detect and avoid integer overflow
2433
20.8k
  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
20.8k
  start = parser->m_bufferPtr;
2441
20.8k
  parser->m_positionPtr = start;
2442
20.8k
  parser->m_bufferEnd += len;
2443
20.8k
  parser->m_parseEndPtr = parser->m_bufferEnd;
2444
20.8k
  parser->m_parseEndByteIndex += len;
2445
20.8k
  parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
2446
2447
20.8k
  parser->m_errorCode = callProcessor(parser, start, parser->m_parseEndPtr,
2448
20.8k
                                      &parser->m_bufferPtr);
2449
2450
20.8k
  if (parser->m_errorCode != XML_ERROR_NONE) {
2451
19.3k
    parser->m_eventEndPtr = parser->m_eventPtr;
2452
19.3k
    parser->m_processor = errorProcessor;
2453
19.3k
    return XML_STATUS_ERROR;
2454
19.3k
  } else {
2455
1.44k
    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
1.44k
    case XML_PARSING:
2461
1.44k
      if (isFinal) {
2462
1.43k
        parser->m_parsingStatus.parsing = XML_FINISHED;
2463
1.43k
        return result;
2464
1.43k
      }
2465
8
      break;
2466
8
    default:; /* should not happen */
2467
1.44k
    }
2468
1.44k
  }
2469
2470
8
  XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
2471
8
                    parser->m_bufferPtr, &parser->m_position);
2472
8
  parser->m_positionPtr = parser->m_bufferPtr;
2473
8
  return result;
2474
20.8k
}
2475
2476
/* Modifies `parser`’s buffer to be backed by `newBuf`. */
2477
static void
2478
20.7k
setParserBuffer(XML_Parser parser, char *newBuf, int newBufSize, int keep) {
2479
20.7k
  parser->m_bufferLim = newBuf + newBufSize;
2480
20.7k
  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
20.7k
  } else {
2492
    /* This must be a brand new buffer with no data in it yet */
2493
20.7k
    parser->m_buffer = newBuf;
2494
20.7k
    parser->m_bufferEnd = newBuf;
2495
20.7k
    parser->m_bufferPtr = newBuf;
2496
20.7k
  }
2497
20.7k
}
2498
2499
void *XMLCALL
2500
20.8k
XML_GetBuffer(XML_Parser parser, int len) {
2501
20.8k
  if ((parser == NULL) || isCalledFromInsideHandler(parser))
2502
0
    return NULL;
2503
20.8k
  if (len < 0) {
2504
0
    parser->m_errorCode = XML_ERROR_NO_MEMORY;
2505
0
    return NULL;
2506
0
  }
2507
20.8k
  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
20.8k
  default:;
2515
20.8k
  }
2516
2517
  // whether or not the request succeeds, `len` seems to be the app's preferred
2518
  // buffer fill size; remember it.
2519
20.8k
  parser->m_lastBufferRequestSize = len;
2520
20.8k
  if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
2521
20.7k
      || parser->m_buffer == NULL) {
2522
    /* Do not invoke signed arithmetic overflow: */
2523
20.7k
    int neededSize = (int)((unsigned)len
2524
20.7k
                           + (unsigned)EXPAT_SAFE_PTR_DIFF(
2525
20.7k
                               parser->m_bufferEnd, parser->m_bufferPtr));
2526
20.7k
    if (neededSize < 0) {
2527
0
      parser->m_errorCode = XML_ERROR_NO_MEMORY;
2528
0
      return NULL;
2529
0
    }
2530
20.7k
#if XML_CONTEXT_BYTES > 0
2531
20.7k
    const int parsed
2532
20.7k
        = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
2533
20.7k
    int keep = parsed;
2534
20.7k
    if (keep > XML_CONTEXT_BYTES)
2535
0
      keep = XML_CONTEXT_BYTES;
2536
    /* Detect and prevent integer overflow */
2537
20.7k
    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
20.7k
    neededSize += keep;
2545
20.7k
    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
20.7k
    } else {
2567
20.7k
      int bufferSize
2568
20.7k
          = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
2569
20.7k
      if (bufferSize == 0)
2570
20.7k
        bufferSize = INIT_BUFFER_SIZE;
2571
26.9k
      do {
2572
        /* Do not invoke signed arithmetic overflow: */
2573
26.9k
        bufferSize = (int)(2U * (unsigned)bufferSize);
2574
26.9k
      } while (bufferSize < neededSize && bufferSize > 0);
2575
20.7k
      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
20.7k
      char *const newBuf = parser->m_mem.malloc_fcn(bufferSize);
2582
20.7k
      if (newBuf == NULL) {
2583
0
        parser->m_errorCode = XML_ERROR_NO_MEMORY;
2584
0
        return NULL;
2585
0
      }
2586
20.7k
      setParserBuffer(parser, newBuf, bufferSize, keep);
2587
20.7k
    }
2588
20.7k
    parser->m_eventPtr = parser->m_eventEndPtr = NULL;
2589
20.7k
    parser->m_positionPtr = NULL;
2590
20.7k
  }
2591
20.8k
  return parser->m_bufferEnd;
2592
20.8k
}
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
19.3k
XML_GetErrorCode(XML_Parser parser) {
2686
19.3k
  if (parser == NULL)
2687
0
    return XML_ERROR_INVALID_ARGUMENT;
2688
19.3k
  return parser->m_errorCode;
2689
19.3k
}
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
19.4k
XML_GetCurrentLineNumber(XML_Parser parser) {
2732
19.4k
  if (parser == NULL)
2733
0
    return 0;
2734
19.4k
  if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
2735
19.4k
    XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
2736
19.4k
                      parser->m_eventPtr, &parser->m_position);
2737
19.4k
    parser->m_positionPtr = parser->m_eventPtr;
2738
19.4k
  }
2739
19.4k
  return parser->m_position.lineNumber + 1;
2740
19.4k
}
2741
2742
XML_Size XMLCALL
2743
19.4k
XML_GetCurrentColumnNumber(XML_Parser parser) {
2744
19.4k
  if (parser == NULL)
2745
0
    return 0;
2746
19.4k
  if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
2747
19.4k
    XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
2748
19.4k
                      parser->m_eventPtr, &parser->m_position);
2749
19.4k
    parser->m_positionPtr = parser->m_eventPtr;
2750
19.4k
  }
2751
19.4k
  return parser->m_position.columnNumber;
2752
19.4k
}
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
19.3k
XML_ErrorString(enum XML_Error code) {
2812
19.3k
  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
2.13k
  case XML_ERROR_SYNTAX:
2818
2.13k
    return XML_L("syntax error");
2819
362
  case XML_ERROR_NO_ELEMENTS:
2820
362
    return XML_L("no element found");
2821
12.6k
  case XML_ERROR_INVALID_TOKEN:
2822
12.6k
    return XML_L("not well-formed (invalid token)");
2823
2.46k
  case XML_ERROR_UNCLOSED_TOKEN:
2824
2.46k
    return XML_L("unclosed token");
2825
973
  case XML_ERROR_PARTIAL_CHAR:
2826
973
    return XML_L("partial character");
2827
101
  case XML_ERROR_TAG_MISMATCH:
2828
101
    return XML_L("mismatched tag");
2829
61
  case XML_ERROR_DUPLICATE_ATTRIBUTE:
2830
61
    return XML_L("duplicate attribute");
2831
42
  case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
2832
42
    return XML_L("junk after document element");
2833
16
  case XML_ERROR_PARAM_ENTITY_REF:
2834
16
    return XML_L("illegal parameter entity reference");
2835
17
  case XML_ERROR_UNDEFINED_ENTITY:
2836
17
    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
18
  case XML_ERROR_BAD_CHAR_REF:
2842
18
    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
6
  case XML_ERROR_MISPLACED_XML_PI:
2848
6
    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
433
  case XML_ERROR_UNBOUND_PREFIX:
2869
433
    return XML_L("unbound prefix");
2870
  /* Added in 1.95.8. */
2871
0
  case XML_ERROR_UNDECLARING_PREFIX:
2872
0
    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
43
  case XML_ERROR_XML_DECL:
2876
43
    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
0
  case XML_ERROR_RESERVED_PREFIX_XML:
2893
0
    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
19.3k
  }
2915
0
  return NULL;
2916
19.3k
}
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
1.44k
storeRawNames(XML_Parser parser) {
3068
1.44k
  TAG *tag = parser->m_tagStack;
3069
1.44k
  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
1.44k
  return XML_TRUE;
3113
1.44k
}
3114
3115
static enum XML_Error PTRCALL
3116
contentProcessor(XML_Parser parser, const char *start, const char *end,
3117
9.58k
                 const char **endPtr) {
3118
9.58k
  enum XML_Error result = doContent(
3119
9.58k
      parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, start, end,
3120
9.58k
      endPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer,
3121
9.58k
      XML_ACCOUNT_DIRECT);
3122
9.58k
  if (result == XML_ERROR_NONE) {
3123
1.44k
    if (! storeRawNames(parser))
3124
0
      return XML_ERROR_NO_MEMORY;
3125
1.44k
  }
3126
9.58k
  return result;
3127
9.58k
}
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
9.58k
          XML_Bool haveMore, enum XML_Account account) {
3254
  /* save one level of indirection */
3255
9.58k
  DTD *const dtd = parser->m_dtd;
3256
3257
9.58k
  const char **eventPP;
3258
9.58k
  const char **eventEndPP;
3259
9.58k
  if (enc == parser->m_encoding) {
3260
9.58k
    eventPP = &parser->m_eventPtr;
3261
9.58k
    eventEndPP = &parser->m_eventEndPtr;
3262
9.58k
  } else {
3263
0
    eventPP = &(parser->m_openInternalEntities->internalEventPtr);
3264
0
    eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
3265
0
  }
3266
9.58k
  *eventPP = s;
3267
3268
634k
  for (;;) {
3269
634k
    const char *next = s; /* XmlContentTok doesn't always set the last arg */
3270
634k
    int tok = XmlContentTok(enc, s, end, &next);
3271
634k
#if XML_GE == 1
3272
634k
    const char *accountAfter
3273
634k
        = ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
3274
634k
              ? (haveMore ? s /* i.e. 0 bytes */ : end)
3275
634k
              : next;
3276
634k
    if (! accountingDiffTolerated(parser, tok, s, accountAfter, __LINE__,
3277
634k
                                  account)) {
3278
0
      accountingOnAbort(parser);
3279
0
      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
3280
0
    }
3281
634k
#endif
3282
634k
    *eventEndPP = next;
3283
634k
    switch (tok) {
3284
26
    case XML_TOK_TRAILING_CR:
3285
26
      if (haveMore) {
3286
0
        *nextPtr = s;
3287
0
        return XML_ERROR_NONE;
3288
0
      }
3289
26
      *eventEndPP = end;
3290
26
      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
26
      } 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
26
      if (startTagLevel == 0)
3301
26
        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
137
    case XML_TOK_NONE:
3307
137
      if (haveMore) {
3308
0
        *nextPtr = s;
3309
0
        return XML_ERROR_NONE;
3310
0
      }
3311
137
      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
137
      return XML_ERROR_NO_ELEMENTS;
3318
5.19k
    case XML_TOK_INVALID:
3319
5.19k
      *eventPP = next;
3320
5.19k
      return XML_ERROR_INVALID_TOKEN;
3321
1.41k
    case XML_TOK_PARTIAL:
3322
1.41k
      if (haveMore) {
3323
0
        *nextPtr = s;
3324
0
        return XML_ERROR_NONE;
3325
0
      }
3326
1.41k
      return XML_ERROR_UNCLOSED_TOKEN;
3327
573
    case XML_TOK_PARTIAL_CHAR:
3328
573
      if (haveMore) {
3329
0
        *nextPtr = s;
3330
0
        return XML_ERROR_NONE;
3331
0
      }
3332
573
      return XML_ERROR_PARTIAL_CHAR;
3333
17
    case XML_TOK_ENTITY_REF: {
3334
17
      const XML_Char *name;
3335
17
      ENTITY *entity;
3336
17
      XML_Char ch = (XML_Char)XmlPredefinedEntityName(
3337
17
          enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
3338
17
      if (ch) {
3339
0
#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
0
        accountingDiffTolerated(parser, tok, (char *)&ch,
3344
0
                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
3345
0
                                XML_ACCOUNT_ENTITY_EXPANSION);
3346
0
#endif /* XML_GE == 1 */
3347
0
        if (parser->m_characterDataHandler) {
3348
0
          beforeHandler(parser);
3349
0
          parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
3350
0
          afterHandler(parser);
3351
0
        } else if (parser->m_defaultHandler)
3352
0
          reportDefault(parser, enc, s, next);
3353
0
        break;
3354
0
      }
3355
17
      name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
3356
17
                             next - enc->minBytesPerChar);
3357
17
      if (! name)
3358
0
        return XML_ERROR_NO_MEMORY;
3359
17
      entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
3360
17
      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
17
      if (! dtd->hasParamEntityRefs || dtd->standalone) {
3366
17
        if (! entity)
3367
17
          return XML_ERROR_UNDEFINED_ENTITY;
3368
0
        else if (! entity->is_internal)
3369
0
          return XML_ERROR_ENTITY_DECLARED_IN_PE;
3370
17
      } 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
102k
    case XML_TOK_START_TAG_NO_ATTS:
3418
114k
    case XML_TOK_START_TAG_WITH_ATTS: {
3419
114k
      TAG *tag;
3420
114k
      enum XML_Error result;
3421
114k
      XML_Char *toPtr;
3422
114k
      if (parser->m_freeTagList) {
3423
95.9k
        tag = parser->m_freeTagList;
3424
95.9k
        parser->m_freeTagList = parser->m_freeTagList->parent;
3425
95.9k
      } else {
3426
18.3k
        tag = MALLOC(parser, sizeof(TAG));
3427
18.3k
        if (! tag)
3428
0
          return XML_ERROR_NO_MEMORY;
3429
18.3k
        tag->buf.raw = MALLOC(parser, INIT_TAG_BUF_SIZE);
3430
18.3k
        if (! tag->buf.raw) {
3431
0
          FREE(parser, tag);
3432
0
          return XML_ERROR_NO_MEMORY;
3433
0
        }
3434
18.3k
        tag->bufEnd = tag->buf.raw + INIT_TAG_BUF_SIZE;
3435
18.3k
      }
3436
114k
      tag->bindings = NULL;
3437
114k
      tag->parent = parser->m_tagStack;
3438
114k
      parser->m_tagStack = tag;
3439
114k
      tag->name.localPart = NULL;
3440
114k
      tag->name.prefix = NULL;
3441
114k
      tag->rawName = s + enc->minBytesPerChar;
3442
114k
      tag->rawNameLength = XmlNameLength(enc, tag->rawName);
3443
114k
      ++parser->m_tagLevel;
3444
114k
      {
3445
114k
        const char *rawNameEnd = tag->rawName + tag->rawNameLength;
3446
114k
        const char *fromPtr = tag->rawName;
3447
114k
        toPtr = tag->buf.str;
3448
114k
        for (;;) {
3449
114k
          const enum XML_Convert_Result convert_res
3450
114k
              = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr,
3451
114k
                           (ICHAR *)tag->bufEnd - 1);
3452
114k
          const size_t convLen = (size_t)(toPtr - tag->buf.str);
3453
114k
          if ((fromPtr >= rawNameEnd)
3454
114k
              || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
3455
114k
            tag->name.strLen = convLen;
3456
114k
            break;
3457
114k
          }
3458
530
          if (SIZE_MAX / 2 < (size_t)(tag->bufEnd - tag->buf.raw))
3459
0
            return XML_ERROR_NO_MEMORY;
3460
530
          const size_t bufSize = (size_t)(tag->bufEnd - tag->buf.raw) * 2;
3461
530
          {
3462
530
            char *temp = REALLOC(parser, tag->buf.raw, bufSize);
3463
530
            if (temp == NULL)
3464
0
              return XML_ERROR_NO_MEMORY;
3465
530
            tag->buf.raw = temp;
3466
530
            tag->bufEnd = temp + bufSize;
3467
530
            toPtr = (XML_Char *)temp + convLen;
3468
530
          }
3469
530
        }
3470
114k
      }
3471
114k
      tag->name.str = tag->buf.str;
3472
114k
      *toPtr = XML_T('\0');
3473
114k
      result
3474
114k
          = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
3475
114k
      if (result)
3476
452
        return result;
3477
113k
      if (parser->m_startElementHandler) {
3478
113k
        beforeHandler(parser);
3479
113k
        parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
3480
113k
                                      (const XML_Char **)parser->m_atts);
3481
113k
        afterHandler(parser);
3482
113k
      } else if (parser->m_defaultHandler)
3483
0
        reportDefault(parser, enc, s, next);
3484
113k
      poolClear(&parser->m_tempPool);
3485
113k
      break;
3486
114k
    }
3487
235
    case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
3488
9.03k
    case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: {
3489
9.03k
      const char *rawName = s + enc->minBytesPerChar;
3490
9.03k
      enum XML_Error result;
3491
9.03k
      BINDING *bindings = NULL;
3492
9.03k
      XML_Bool noElmHandlers = XML_TRUE;
3493
9.03k
      TAG_NAME name;
3494
9.03k
      name.str = poolStoreString(&parser->m_tempPool, enc, rawName,
3495
9.03k
                                 rawName + XmlNameLength(enc, rawName));
3496
9.03k
      if (! name.str)
3497
0
        return XML_ERROR_NO_MEMORY;
3498
9.03k
      poolFinish(&parser->m_tempPool);
3499
9.03k
      result = storeAtts(parser, enc, s, &name, &bindings,
3500
9.03k
                         XML_ACCOUNT_NONE /* token spans whole start tag */);
3501
9.03k
      if (result != XML_ERROR_NONE) {
3502
57
        freeBindings(parser, bindings);
3503
57
        return result;
3504
57
      }
3505
8.97k
      poolFinish(&parser->m_tempPool);
3506
8.97k
      if (parser->m_startElementHandler) {
3507
8.97k
        beforeHandler(parser);
3508
8.97k
        parser->m_startElementHandler(parser->m_handlerArg, name.str,
3509
8.97k
                                      (const XML_Char **)parser->m_atts);
3510
8.97k
        afterHandler(parser);
3511
8.97k
        noElmHandlers = XML_FALSE;
3512
8.97k
      }
3513
8.97k
      if (parser->m_endElementHandler) {
3514
8.97k
        if (parser->m_startElementHandler)
3515
8.97k
          *eventPP = *eventEndPP;
3516
8.97k
        beforeHandler(parser);
3517
8.97k
        parser->m_endElementHandler(parser->m_handlerArg, name.str);
3518
8.97k
        afterHandler(parser);
3519
8.97k
        noElmHandlers = XML_FALSE;
3520
8.97k
      }
3521
8.97k
      if (noElmHandlers && parser->m_defaultHandler)
3522
0
        reportDefault(parser, enc, s, next);
3523
8.97k
      poolClear(&parser->m_tempPool);
3524
8.97k
      freeBindings(parser, bindings);
3525
8.97k
    }
3526
8.97k
      if ((parser->m_tagLevel == 0)
3527
177
          && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
3528
177
        if (parser->m_parsingStatus.parsing == XML_SUSPENDED
3529
177
            || (parser->m_parsingStatus.parsing == XML_PARSING
3530
177
                && parser->m_reenter))
3531
0
          parser->m_processor = epilogProcessor;
3532
177
        else
3533
177
          return epilogProcessor(parser, next, end, nextPtr);
3534
177
      }
3535
8.80k
      break;
3536
104k
    case XML_TOK_END_TAG:
3537
104k
      if (parser->m_tagLevel == startTagLevel)
3538
0
        return XML_ERROR_ASYNC_ENTITY;
3539
104k
      else {
3540
104k
        int len;
3541
104k
        const char *rawName;
3542
104k
        TAG *tag = parser->m_tagStack;
3543
104k
        rawName = s + enc->minBytesPerChar * 2;
3544
104k
        len = XmlNameLength(enc, rawName);
3545
104k
        if (len != tag->rawNameLength
3546
104k
            || memcmp(tag->rawName, rawName, len) != 0) {
3547
101
          *eventPP = rawName;
3548
101
          return XML_ERROR_TAG_MISMATCH;
3549
101
        }
3550
104k
        parser->m_tagStack = tag->parent;
3551
104k
        tag->parent = parser->m_freeTagList;
3552
104k
        parser->m_freeTagList = tag;
3553
104k
        --parser->m_tagLevel;
3554
104k
        if (parser->m_endElementHandler) {
3555
104k
          const XML_Char *localPart;
3556
104k
          const XML_Char *prefix;
3557
104k
          XML_Char *uri;
3558
104k
          localPart = tag->name.localPart;
3559
104k
          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
104k
            uri = (XML_Char *)tag->name.str + tag->name.uriLen;
3565
            /* don't need to check for space - already done in storeAtts() */
3566
584k
            while (*localPart)
3567
480k
              *uri++ = *localPart++;
3568
104k
            prefix = tag->name.prefix;
3569
104k
            if (parser->m_ns_triplets && prefix) {
3570
0
              *uri++ = parser->m_namespaceSeparator;
3571
0
              while (*prefix)
3572
0
                *uri++ = *prefix++;
3573
0
            }
3574
104k
            *uri = XML_T('\0');
3575
104k
          }
3576
104k
          beforeHandler(parser);
3577
104k
          parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
3578
104k
          afterHandler(parser);
3579
104k
        } else if (parser->m_defaultHandler)
3580
0
          reportDefault(parser, enc, s, next);
3581
122k
        while (tag->bindings) {
3582
17.6k
          BINDING *b = tag->bindings;
3583
17.6k
          if (parser->m_endNamespaceDeclHandler) {
3584
17.6k
            beforeHandler(parser);
3585
17.6k
            parser->m_endNamespaceDeclHandler(parser->m_handlerArg,
3586
17.6k
                                              b->prefix->name);
3587
17.6k
            afterHandler(parser);
3588
17.6k
          }
3589
17.6k
          tag->bindings = tag->bindings->nextTagBinding;
3590
17.6k
          b->nextTagBinding = parser->m_freeBindingList;
3591
17.6k
          parser->m_freeBindingList = b;
3592
17.6k
          b->prefix->binding = b->prevPrefixBinding;
3593
17.6k
        }
3594
104k
        if ((parser->m_tagLevel == 0)
3595
1.38k
            && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
3596
1.38k
          if (parser->m_parsingStatus.parsing == XML_SUSPENDED
3597
1.38k
              || (parser->m_parsingStatus.parsing == XML_PARSING
3598
1.38k
                  && parser->m_reenter))
3599
0
            parser->m_processor = epilogProcessor;
3600
1.38k
          else
3601
1.38k
            return epilogProcessor(parser, next, end, nextPtr);
3602
1.38k
        }
3603
104k
      }
3604
103k
      break;
3605
103k
    case XML_TOK_CHAR_REF: {
3606
3
      int n = XmlCharRefNumber(enc, s);
3607
3
      if (n < 0)
3608
3
        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
176k
    case XML_TOK_DATA_NEWLINE:
3621
176k
      if (parser->m_characterDataHandler) {
3622
75.9k
        XML_Char c = 0xA;
3623
75.9k
        beforeHandler(parser);
3624
75.9k
        parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
3625
75.9k
        afterHandler(parser);
3626
100k
      } else if (parser->m_defaultHandler)
3627
0
        reportDefault(parser, enc, s, next);
3628
176k
      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
53
    case XML_TOK_TRAILING_RSQB:
3666
53
      if (haveMore) {
3667
0
        *nextPtr = s;
3668
0
        return XML_ERROR_NONE;
3669
0
      }
3670
53
      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
53
      } 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
53
      if (startTagLevel == 0) {
3692
53
        *eventPP = end;
3693
53
        return XML_ERROR_NO_ELEMENTS;
3694
53
      }
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
223k
    case XML_TOK_DATA_CHARS: {
3702
223k
      XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
3703
223k
      if (charDataHandler) {
3704
98.8k
        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
98.8k
        } else {
3720
98.8k
          beforeHandler(parser);
3721
98.8k
          charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
3722
98.8k
                          (int)((const XML_Char *)next - (const XML_Char *)s));
3723
98.8k
          afterHandler(parser);
3724
98.8k
        }
3725
124k
      } else if (parser->m_defaultHandler)
3726
0
        reportDefault(parser, enc, s, next);
3727
223k
    } break;
3728
47
    case XML_TOK_PI:
3729
47
      if (! reportProcessingInstruction(parser, enc, s, next))
3730
0
        return XML_ERROR_NO_MEMORY;
3731
47
      break;
3732
47
    case XML_TOK_COMMENT:
3733
2
      if (! reportComment(parser, enc, s, next))
3734
0
        return XML_ERROR_NO_MEMORY;
3735
2
      break;
3736
2
    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
634k
    }
3749
625k
    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
625k
    case XML_PARSING:
3758
625k
      if (parser->m_reenter) {
3759
0
        *nextPtr = next;
3760
0
        return XML_ERROR_NONE;
3761
0
      }
3762
625k
      EXPAT_FALLTHROUGH;
3763
625k
    default:;
3764
625k
      *eventPP = s = next;
3765
625k
    }
3766
625k
  }
3767
  /* not reached */
3768
9.58k
}
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
9.03k
freeBindings(XML_Parser parser, BINDING *bindings) {
3776
9.51k
  while (bindings) {
3777
482
    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
482
    if (parser->m_endNamespaceDeclHandler) {
3783
482
      beforeHandler(parser);
3784
482
      parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
3785
482
      afterHandler(parser);
3786
482
    }
3787
3788
482
    bindings = bindings->nextTagBinding;
3789
482
    b->nextTagBinding = parser->m_freeBindingList;
3790
482
    parser->m_freeBindingList = b;
3791
482
    b->prefix->binding = b->prevPrefixBinding;
3792
482
  }
3793
9.03k
}
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
123k
          enum XML_Account account) {
3809
123k
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
3810
123k
  int attIndex = 0;
3811
123k
  XML_Char *uri;
3812
123k
  int nPrefixes = 0;
3813
123k
  BINDING *binding;
3814
123k
  const XML_Char *localPart;
3815
3816
  /* lookup the element type name */
3817
123k
  ELEMENT_TYPE *elementType
3818
123k
      = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0);
3819
123k
  if (! elementType) {
3820
42.1k
    const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
3821
42.1k
    if (! name)
3822
0
      return XML_ERROR_NO_MEMORY;
3823
42.1k
    elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
3824
42.1k
                                         sizeof(ELEMENT_TYPE));
3825
42.1k
    if (! elementType)
3826
0
      return XML_ERROR_NO_MEMORY;
3827
42.1k
    if (! elementType->defaultAttsNames.parser)
3828
42.1k
      hashTableInit(&(elementType->defaultAttsNames), parser);
3829
42.1k
    if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
3830
0
      return XML_ERROR_NO_MEMORY;
3831
42.1k
  }
3832
123k
  const size_t nDefaultAtts = elementType->nDefaultAtts;
3833
3834
  /* Detect and prevent integer overflow. */
3835
123k
  if (parser->m_attsSize > (size_t)INT_MAX)
3836
0
    return XML_ERROR_NO_MEMORY;
3837
3838
  /* get the attributes from the tokenizer */
3839
123k
  size_t n = (size_t)XmlGetAttributes(enc, attStr, (int)parser->m_attsSize,
3840
123k
                                      parser->m_atts);
3841
3842
  /* Detect and prevent integer overflow */
3843
123k
  if (n > SIZE_MAX - nDefaultAtts) {
3844
0
    return XML_ERROR_NO_MEMORY;
3845
0
  }
3846
3847
123k
  if (n + nDefaultAtts > parser->m_attsSize) {
3848
1.79k
    size_t oldAttsSize = parser->m_attsSize;
3849
3850
    /* Detect and prevent integer overflow */
3851
1.79k
    if ((nDefaultAtts > SIZE_MAX - INIT_ATTS_SIZE)
3852
1.79k
        || (n > SIZE_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
3853
0
      return XML_ERROR_NO_MEMORY;
3854
0
    }
3855
3856
1.79k
    parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
3857
3858
    /* Detect and prevent integer overflow. */
3859
1.79k
    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
1.79k
    ATTRIBUTE *const temp = REALLOC(parser, parser->m_atts,
3865
1.79k
                                    parser->m_attsSize * sizeof(ATTRIBUTE));
3866
1.79k
    if (temp == NULL) {
3867
0
      parser->m_attsSize = oldAttsSize;
3868
0
      return XML_ERROR_NO_MEMORY;
3869
0
    }
3870
1.79k
    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
1.79k
    if (n > oldAttsSize) {
3887
      /* Detect and prevent integer overflow. */
3888
1.79k
      if (n > (size_t)INT_MAX)
3889
0
        return XML_ERROR_NO_MEMORY;
3890
1.79k
      XmlGetAttributes(enc, attStr, (int)n, parser->m_atts);
3891
1.79k
    }
3892
1.79k
  }
3893
3894
  /* the attribute list for the application */
3895
123k
  const XML_Char **const appAtts = (const XML_Char **)parser->m_atts;
3896
357k
  for (size_t i = 0; i < n; i++) {
3897
234k
    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
234k
    ATTRIBUTE_ID *attId
3903
234k
        = getAttributeId(parser, enc, currAtt->name,
3904
234k
                         currAtt->name + XmlNameLength(enc, currAtt->name));
3905
234k
    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
234k
    if ((attId->name)[-1]) {
3922
61
      if (enc == parser->m_encoding)
3923
61
        parser->m_eventPtr = parser->m_atts[i].name;
3924
61
      return XML_ERROR_DUPLICATE_ATTRIBUTE;
3925
61
    }
3926
234k
    (attId->name)[-1] = 1;
3927
234k
    appAtts[attIndex++] = attId->name;
3928
234k
    if (! parser->m_atts[i].normalized) {
3929
2.57k
      XML_Bool isCdata = XML_TRUE;
3930
3931
      /* figure out whether declared as other than CDATA */
3932
2.57k
      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
2.57k
      const enum XML_Error result = storeAttributeValue(
3943
2.57k
          parser, enc, isCdata, parser->m_atts[i].valuePtr,
3944
2.57k
          parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
3945
2.57k
      if (result)
3946
15
        return result;
3947
2.55k
      appAtts[attIndex] = poolStart(&parser->m_tempPool);
3948
2.55k
      poolFinish(&parser->m_tempPool);
3949
231k
    } else {
3950
      /* the value did not need normalizing */
3951
231k
      appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc,
3952
231k
                                          parser->m_atts[i].valuePtr,
3953
231k
                                          parser->m_atts[i].valueEnd);
3954
231k
      if (appAtts[attIndex] == 0)
3955
0
        return XML_ERROR_NO_MEMORY;
3956
231k
      poolFinish(&parser->m_tempPool);
3957
231k
    }
3958
    /* handle prefixed attribute names */
3959
233k
    if (attId->prefix) {
3960
233k
      if (attId->xmlns) {
3961
        /* deal with namespace declarations here */
3962
23.6k
        enum XML_Error result = addBinding(parser, attId->prefix, attId,
3963
23.6k
                                           appAtts[attIndex], bindingsPtr);
3964
23.6k
        if (result)
3965
0
          return result;
3966
23.6k
        --attIndex;
3967
209k
      } else {
3968
        /* deal with other prefixed names later */
3969
209k
        attIndex++;
3970
209k
        nPrefixes++;
3971
209k
        (attId->name)[-1] = 2;
3972
209k
      }
3973
233k
    } else
3974
617
      attIndex++;
3975
233k
  }
3976
3977
  /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
3978
123k
  parser->m_nSpecifiedAtts = attIndex;
3979
123k
  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
123k
    parser->m_idAttIndex = -1;
3987
3988
  /* do attribute defaulting */
3989
123k
  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
123k
  appAtts[attIndex] = 0;
4012
4013
  /* expand prefixed attribute names, check for duplicates,
4014
     and clear flags that say whether attributes were specified */
4015
123k
  int i = 0;
4016
123k
  if (nPrefixes) {
4017
18.7k
    unsigned int j; /* hash table index */
4018
18.7k
    unsigned long version = parser->m_nsAttsVersion;
4019
4020
    /* Detect and prevent invalid shift */
4021
18.7k
    if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
4022
0
      return XML_ERROR_NO_MEMORY;
4023
0
    }
4024
4025
18.7k
    unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
4026
18.7k
    unsigned char oldNsAttsPower = parser->m_nsAttsPower;
4027
    /* size of hash table must be at least 2 * (# of prefixed attributes) */
4028
18.7k
    if ((nPrefixes << 1)
4029
18.7k
        >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
4030
      /* hash table size must also be a power of 2 and >= 8 */
4031
12.6k
      while (nPrefixes >> parser->m_nsAttsPower++)
4032
8.84k
        ;
4033
3.82k
      if (parser->m_nsAttsPower < 3)
4034
2.03k
        parser->m_nsAttsPower = 3;
4035
4036
      /* Detect and prevent invalid shift */
4037
3.82k
      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
3.82k
      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
3.82k
      NS_ATT *const temp
4058
3.82k
          = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT));
4059
3.82k
      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
3.82k
      parser->m_nsAtts = temp;
4065
3.82k
      version = 0; /* force re-initialization of m_nsAtts hash table */
4066
3.82k
    }
4067
    /* using a version flag saves us from initializing m_nsAtts every time */
4068
18.7k
    if (! version) { /* initialize version flags when version wraps around */
4069
3.82k
      version = INIT_ATTS_VERSION;
4070
434k
      for (j = nsAttsSize; j != 0;)
4071
430k
        parser->m_nsAtts[--j].version = version;
4072
3.82k
    }
4073
18.7k
    parser->m_nsAttsVersion = --version;
4074
4075
    /* expand prefixed names and check for duplicates */
4076
203k
    for (; i < attIndex; i += 2) {
4077
203k
      const XML_Char *s = appAtts[i];
4078
203k
      if (s[-1] == 2) { /* prefixed */
4079
203k
        struct siphash sip_state;
4080
203k
        struct sipkey sip_key;
4081
4082
203k
        copy_salt_to_sipkey(parser, &sip_key);
4083
203k
        sip24_init(&sip_state, &sip_key);
4084
4085
203k
        ((XML_Char *)s)[-1] = 0; /* clear flag */
4086
203k
        ATTRIBUTE_ID *const id
4087
203k
            = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
4088
203k
        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
203k
        const BINDING *const b = id->prefix->binding;
4106
203k
        if (! b)
4107
201
          return XML_ERROR_UNBOUND_PREFIX;
4108
4109
202k
        if (! poolAppendChars(&parser->m_tempPool, b->uri, b->uriLen))
4110
0
          return XML_ERROR_NO_MEMORY;
4111
4112
202k
        sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
4113
4114
916k
        while (*s++ != XML_T(ASCII_COLON))
4115
713k
          ;
4116
4117
202k
        sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
4118
4119
202k
        {
4120
202k
          const size_t len = xcslen(s) + /*null terminator*/ 1;
4121
202k
          if (! poolAppendChars(&parser->m_tempPool, s, len))
4122
0
            return XML_ERROR_NO_MEMORY;
4123
202k
        }
4124
4125
202k
        const unsigned long uriHash = (unsigned long)sip24_final(&sip_state);
4126
4127
202k
        { /* Check hash table for duplicate of expanded name (uriName).
4128
             Derived from code in lookup(parser, HASH_TABLE *table, ...).
4129
          */
4130
202k
          unsigned char step = 0;
4131
202k
          unsigned long mask = nsAttsSize - 1;
4132
202k
          j = uriHash & mask; /* index into hash table */
4133
252k
          while (parser->m_nsAtts[j].version == version) {
4134
            /* for speed we compare stored hash values first */
4135
49.8k
            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
49.8k
            if (! step)
4145
35.2k
              step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower);
4146
49.8k
            j < step ? (j += nsAttsSize - step) : (j -= step);
4147
49.8k
          }
4148
202k
        }
4149
4150
202k
        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
202k
        s = poolStart(&parser->m_tempPool);
4160
202k
        poolFinish(&parser->m_tempPool);
4161
202k
        appAtts[i] = s;
4162
4163
        /* fill empty slot with new version, uriName and hash value */
4164
202k
        parser->m_nsAtts[j].version = version;
4165
202k
        parser->m_nsAtts[j].hash = uriHash;
4166
202k
        parser->m_nsAtts[j].uriName = s;
4167
4168
202k
        if (! --nPrefixes) {
4169
18.5k
          i += 2;
4170
18.5k
          break;
4171
18.5k
        }
4172
202k
      } else                     /* not prefixed */
4173
306
        ((XML_Char *)s)[-1] = 0; /* clear flag */
4174
203k
    }
4175
18.7k
  }
4176
  /* clear flags for the remaining attributes */
4177
123k
  for (; i < attIndex; i += 2)
4178
167
    ((XML_Char *)(appAtts[i]))[-1] = 0;
4179
145k
  for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
4180
22.4k
    binding->attId->name[-1] = 0;
4181
4182
123k
  if (! parser->m_ns)
4183
0
    return XML_ERROR_NONE;
4184
4185
  /* expand the element type name */
4186
123k
  if (elementType->prefix) {
4187
116k
    binding = elementType->prefix->binding;
4188
116k
    if (! binding)
4189
232
      return XML_ERROR_UNBOUND_PREFIX;
4190
115k
    localPart = tagNamePtr->str;
4191
477k
    while (*localPart++ != XML_T(ASCII_COLON))
4192
361k
      ;
4193
115k
  } else if (dtd->defaultPrefix.binding) {
4194
0
    binding = dtd->defaultPrefix.binding;
4195
0
    localPart = tagNamePtr->str;
4196
0
  } else
4197
6.87k
    return XML_ERROR_NONE;
4198
115k
  size_t prefixLen = 0;
4199
115k
  if (parser->m_ns_triplets && binding->prefix->name)
4200
0
    prefixLen = xcslen(binding->prefix->name) + /*null terminator*/ 1;
4201
115k
  tagNamePtr->localPart = localPart;
4202
115k
  tagNamePtr->uriLen = binding->uriLen;
4203
115k
  tagNamePtr->prefix = binding->prefix->name;
4204
115k
  tagNamePtr->prefixLen = prefixLen;
4205
4206
115k
  const size_t localPartLen = xcslen(localPart) + /*null terminator*/ 1;
4207
4208
  /* Detect and prevent integer overflow */
4209
115k
  if (binding->uriLen > SIZE_MAX - prefixLen
4210
115k
      || localPartLen > SIZE_MAX - (binding->uriLen + prefixLen)) {
4211
0
    return XML_ERROR_NO_MEMORY;
4212
0
  }
4213
4214
115k
  const size_t totalLen = localPartLen + binding->uriLen + prefixLen;
4215
115k
  if (totalLen > binding->uriAlloc) {
4216
    /* Detect and prevent integer overflow */
4217
51
    if (totalLen > SIZE_MAX - EXPAND_SPARE
4218
51
        || totalLen + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
4219
0
      return XML_ERROR_NO_MEMORY;
4220
0
    }
4221
4222
51
    uri = MALLOC(parser, (totalLen + EXPAND_SPARE) * sizeof(XML_Char));
4223
51
    if (! uri)
4224
0
      return XML_ERROR_NO_MEMORY;
4225
51
    binding->uriAlloc = totalLen + EXPAND_SPARE;
4226
51
    memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
4227
235
    for (TAG *p = parser->m_tagStack; p; p = p->parent)
4228
184
      if (p->name.str == binding->uri)
4229
16
        p->name.str = uri;
4230
51
    FREE(parser, binding->uri);
4231
51
    binding->uri = uri;
4232
51
  }
4233
  /* if m_namespaceSeparator != '\0' then uri includes it already */
4234
115k
  uri = binding->uri + binding->uriLen;
4235
  /* Detect and prevent integer overflow */
4236
115k
  if (localPartLen > SIZE_MAX / sizeof(XML_Char)) {
4237
0
    return XML_ERROR_NO_MEMORY;
4238
0
  }
4239
115k
  memcpy(uri, localPart, localPartLen * sizeof(XML_Char));
4240
  /* we always have a namespace separator between localPart and prefix */
4241
115k
  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
115k
  tagNamePtr->str = binding->uri;
4247
115k
  return XML_ERROR_NONE;
4248
115k
}
4249
4250
static XML_Bool
4251
705
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
705
  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
705
  case '@':
4341
4342
  // From rule "sub-delims"
4343
705
  case '!':
4344
705
  case '$':
4345
705
  case '&':
4346
705
  case '\'':
4347
705
  case '(':
4348
705
  case ')':
4349
705
  case '*':
4350
705
  case '+':
4351
705
  case ',':
4352
705
  case ';':
4353
705
  case '=':
4354
705
    return XML_TRUE;
4355
4356
0
  default:
4357
0
    return XML_FALSE;
4358
705
  }
4359
705
}
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
44.4k
           const XML_Char *uri, BINDING **bindingsPtr) {
4367
  // "http://www.w3.org/XML/1998/namespace"
4368
44.4k
  static const XML_Char xmlNamespace[]
4369
44.4k
      = {ASCII_h,      ASCII_t,     ASCII_t,     ASCII_p,      ASCII_COLON,
4370
44.4k
         ASCII_SLASH,  ASCII_SLASH, ASCII_w,     ASCII_w,      ASCII_w,
4371
44.4k
         ASCII_PERIOD, ASCII_w,     ASCII_3,     ASCII_PERIOD, ASCII_o,
4372
44.4k
         ASCII_r,      ASCII_g,     ASCII_SLASH, ASCII_X,      ASCII_M,
4373
44.4k
         ASCII_L,      ASCII_SLASH, ASCII_1,     ASCII_9,      ASCII_9,
4374
44.4k
         ASCII_8,      ASCII_SLASH, ASCII_n,     ASCII_a,      ASCII_m,
4375
44.4k
         ASCII_e,      ASCII_s,     ASCII_p,     ASCII_a,      ASCII_c,
4376
44.4k
         ASCII_e,      '\0'};
4377
44.4k
  static const size_t xmlLen = sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
4378
  // "http://www.w3.org/2000/xmlns/"
4379
44.4k
  static const XML_Char xmlnsNamespace[]
4380
44.4k
      = {ASCII_h,     ASCII_t,      ASCII_t, ASCII_p, ASCII_COLON,  ASCII_SLASH,
4381
44.4k
         ASCII_SLASH, ASCII_w,      ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
4382
44.4k
         ASCII_3,     ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,      ASCII_SLASH,
4383
44.4k
         ASCII_2,     ASCII_0,      ASCII_0, ASCII_0, ASCII_SLASH,  ASCII_x,
4384
44.4k
         ASCII_m,     ASCII_l,      ASCII_n, ASCII_s, ASCII_SLASH,  '\0'};
4385
44.4k
  static const size_t xmlnsLen = sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1;
4386
4387
44.4k
  XML_Bool mustBeXML = XML_FALSE;
4388
44.4k
  XML_Bool isXML = XML_TRUE;
4389
44.4k
  XML_Bool isXMLNS = XML_TRUE;
4390
4391
44.4k
  BINDING *b;
4392
44.4k
  size_t len;
4393
4394
  /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
4395
44.4k
  if (*uri == XML_T('\0') && prefix->name)
4396
0
    return XML_ERROR_UNDECLARING_PREFIX;
4397
4398
44.4k
  if (prefix->name && prefix->name[0] == XML_T(ASCII_x)
4399
28.1k
      && prefix->name[1] == XML_T(ASCII_m)
4400
26.1k
      && prefix->name[2] == XML_T(ASCII_l)) {
4401
    /* Not allowed to bind xmlns */
4402
20.7k
    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
20.7k
    if (prefix->name[3] == XML_T('\0'))
4407
20.7k
      mustBeXML = XML_TRUE;
4408
20.7k
  }
4409
4410
1.72M
  for (len = 0; uri[len]; len++) {
4411
    /* Detect and prevent integer overflow */
4412
1.67M
    if (len == SIZE_MAX) {
4413
0
      return XML_ERROR_NO_MEMORY;
4414
0
    }
4415
1.67M
    if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
4416
23.6k
      isXML = XML_FALSE;
4417
4418
1.67M
    if (! mustBeXML && isXMLNS
4419
189k
        && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
4420
23.6k
      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
1.67M
    if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)
4441
705
        && ! is_rfc3986_uri_char(uri[len])) {
4442
0
      return XML_ERROR_SYNTAX;
4443
0
    }
4444
1.67M
  }
4445
44.4k
  isXML = isXML && len == xmlLen;
4446
44.4k
  isXMLNS = isXMLNS && len == xmlnsLen;
4447
4448
44.4k
  if (mustBeXML != isXML)
4449
0
    return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
4450
0
                     : XML_ERROR_RESERVED_NAMESPACE_URI;
4451
4452
44.4k
  if (isXMLNS)
4453
0
    return XML_ERROR_RESERVED_NAMESPACE_URI;
4454
4455
44.4k
  if (parser->m_namespaceSeparator) {
4456
    /* Detect and prevent integer overflow */
4457
44.4k
    if (len == SIZE_MAX) {
4458
0
      return XML_ERROR_NO_MEMORY;
4459
0
    }
4460
44.4k
    len++;
4461
44.4k
  }
4462
44.4k
  if (parser->m_freeBindingList) {
4463
0
    b = parser->m_freeBindingList;
4464
0
    if (len > b->uriAlloc) {
4465
      /* Detect and prevent integer overflow */
4466
0
      if (len > SIZE_MAX - EXPAND_SPARE
4467
0
          || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
4468
0
        return XML_ERROR_NO_MEMORY;
4469
0
      }
4470
4471
0
      XML_Char *temp
4472
0
          = REALLOC(parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
4473
0
      if (temp == NULL)
4474
0
        return XML_ERROR_NO_MEMORY;
4475
0
      b->uri = temp;
4476
0
      b->uriAlloc = len + EXPAND_SPARE;
4477
0
    }
4478
0
    parser->m_freeBindingList = b->nextTagBinding;
4479
44.4k
  } else {
4480
44.4k
    b = MALLOC(parser, sizeof(BINDING));
4481
44.4k
    if (! b)
4482
0
      return XML_ERROR_NO_MEMORY;
4483
4484
    /* Detect and prevent integer overflow */
4485
44.4k
    if (len > SIZE_MAX - EXPAND_SPARE
4486
44.4k
        || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
4487
0
      return XML_ERROR_NO_MEMORY;
4488
0
    }
4489
4490
44.4k
    b->uri = MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
4491
44.4k
    if (! b->uri) {
4492
0
      FREE(parser, b);
4493
0
      return XML_ERROR_NO_MEMORY;
4494
0
    }
4495
44.4k
    b->uriAlloc = len + EXPAND_SPARE;
4496
44.4k
  }
4497
44.4k
  b->uriLen = len;
4498
44.4k
  memcpy(b->uri, uri, len * sizeof(XML_Char));
4499
44.4k
  if (parser->m_namespaceSeparator)
4500
44.4k
    b->uri[len - 1] = parser->m_namespaceSeparator;
4501
44.4k
  b->prefix = prefix;
4502
44.4k
  b->attId = attId;
4503
44.4k
  b->prevPrefixBinding = prefix->binding;
4504
  /* NULL binding when default namespace undeclared */
4505
44.4k
  if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix)
4506
0
    prefix->binding = NULL;
4507
44.4k
  else
4508
44.4k
    prefix->binding = b;
4509
44.4k
  b->nextTagBinding = *bindingsPtr;
4510
44.4k
  *bindingsPtr = b;
4511
  /* if attId == NULL then we are not starting a namespace scope */
4512
44.4k
  if (attId && parser->m_startNamespaceDeclHandler) {
4513
23.6k
    beforeHandler(parser);
4514
23.6k
    parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
4515
23.6k
                                        prefix->binding ? uri : 0);
4516
23.6k
    afterHandler(parser);
4517
23.6k
  }
4518
44.4k
  return XML_ERROR_NONE;
4519
44.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
20.7k
initializeEncoding(XML_Parser parser) {
4792
20.7k
  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
20.7k
  s = parser->m_protocolEncodingName;
4813
20.7k
#endif
4814
20.7k
  if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(
4815
20.7k
          &parser->m_initEncoding, &parser->m_encoding, s))
4816
20.7k
    return XML_ERROR_NONE;
4817
0
  return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
4818
20.7k
}
4819
4820
static enum XML_Error
4821
processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
4822
43
               const char *next) {
4823
43
  const char *encodingName = NULL;
4824
43
  const XML_Char *storedEncName = NULL;
4825
43
  const ENCODING *newEncoding = NULL;
4826
43
  const char *version = NULL;
4827
43
  const char *versionend = NULL;
4828
43
  const XML_Char *storedversion = NULL;
4829
43
  int standalone = -1;
4830
4831
43
#if XML_GE == 1
4832
43
  if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
4833
43
                                XML_ACCOUNT_DIRECT)) {
4834
0
    accountingOnAbort(parser);
4835
0
    return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
4836
0
  }
4837
43
#endif
4838
4839
43
  if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
4840
43
          isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
4841
43
          &version, &versionend, &encodingName, &newEncoding, &standalone)) {
4842
43
    if (isGeneralTextEntity)
4843
0
      return XML_ERROR_TEXT_DECL;
4844
43
    else
4845
43
      return XML_ERROR_XML_DECL;
4846
43
  }
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
20.7k
                    const char **nextPtr) {
4954
20.7k
  enum XML_Error result = initializeEncoding(parser);
4955
20.7k
  if (result != XML_ERROR_NONE)
4956
0
    return result;
4957
20.7k
  parser->m_processor = prologProcessor;
4958
20.7k
  return prologProcessor(parser, s, end, nextPtr);
4959
20.7k
}
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
20.7k
                const char **nextPtr) {
5163
20.7k
  const char *next = s;
5164
20.7k
  int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
5165
20.7k
  return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
5166
20.7k
                  (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
5167
20.7k
                  XML_ACCOUNT_DIRECT);
5168
20.7k
}
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
20.7k
         XML_Bool allowClosingDoctype, enum XML_Account account) {
5174
20.7k
#ifdef XML_DTD
5175
20.7k
  static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
5176
20.7k
#endif /* XML_DTD */
5177
20.7k
  static const XML_Char atypeCDATA[]
5178
20.7k
      = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
5179
20.7k
  static const XML_Char atypeID[] = {ASCII_I, ASCII_D, '\0'};
5180
20.7k
  static const XML_Char atypeIDREF[]
5181
20.7k
      = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'};
5182
20.7k
  static const XML_Char atypeIDREFS[]
5183
20.7k
      = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'};
5184
20.7k
  static const XML_Char atypeENTITY[]
5185
20.7k
      = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'};
5186
20.7k
  static const XML_Char atypeENTITIES[]
5187
20.7k
      = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T,
5188
20.7k
         ASCII_I, ASCII_E, ASCII_S, '\0'};
5189
20.7k
  static const XML_Char atypeNMTOKEN[]
5190
20.7k
      = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'};
5191
20.7k
  static const XML_Char atypeNMTOKENS[]
5192
20.7k
      = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K,
5193
20.7k
         ASCII_E, ASCII_N, ASCII_S, '\0'};
5194
20.7k
  static const XML_Char notationPrefix[]
5195
20.7k
      = {ASCII_N, ASCII_O, ASCII_T, ASCII_A,      ASCII_T,
5196
20.7k
         ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0'};
5197
20.7k
  static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
5198
20.7k
  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
20.7k
  DTD *const dtd = parser->m_dtd;
5206
5207
20.7k
  const char **eventPP;
5208
20.7k
  const char **eventEndPP;
5209
20.7k
  enum XML_Content_Quant quant;
5210
5211
20.7k
  if (enc == parser->m_encoding) {
5212
20.7k
    eventPP = &parser->m_eventPtr;
5213
20.7k
    eventEndPP = &parser->m_eventEndPtr;
5214
20.7k
  } else {
5215
0
    eventPP = &(parser->m_openInternalEntities->internalEventPtr);
5216
0
    eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
5217
0
  }
5218
5219
30.0k
  for (;;) {
5220
30.0k
    int role;
5221
30.0k
    XML_Bool handleDefault = XML_TRUE;
5222
30.0k
    *eventPP = s;
5223
30.0k
    *eventEndPP = next;
5224
30.0k
    if (tok <= 0) {
5225
9.22k
      if (haveMore && tok != XML_TOK_INVALID) {
5226
0
        *nextPtr = s;
5227
0
        return XML_ERROR_NONE;
5228
0
      }
5229
9.22k
      switch (tok) {
5230
7.43k
      case XML_TOK_INVALID:
5231
7.43k
        *eventPP = next;
5232
7.43k
        return XML_ERROR_INVALID_TOKEN;
5233
1.04k
      case XML_TOK_PARTIAL:
5234
1.04k
        return XML_ERROR_UNCLOSED_TOKEN;
5235
386
      case XML_TOK_PARTIAL_CHAR:
5236
386
        return XML_ERROR_PARTIAL_CHAR;
5237
14
      case -XML_TOK_PROLOG_S:
5238
14
        tok = -tok;
5239
14
        break;
5240
146
      case XML_TOK_NONE:
5241
146
#ifdef XML_DTD
5242
        /* for internal PE NOT referenced between declarations */
5243
146
        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
146
        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
146
#endif /* XML_DTD */
5260
146
        return XML_ERROR_NO_ELEMENTS;
5261
205
      default:
5262
205
        tok = -tok;
5263
205
        next = end;
5264
205
        break;
5265
9.22k
      }
5266
9.22k
    }
5267
21.0k
    role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
5268
21.0k
#if XML_GE == 1
5269
21.0k
    switch (role) {
5270
9.58k
    case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
5271
9.63k
    case XML_ROLE_XML_DECL:       // bytes accounted in processXmlDecl
5272
9.63k
#  ifdef XML_DTD
5273
9.63k
    case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
5274
9.63k
#  endif
5275
9.63k
      break;
5276
11.3k
    default:
5277
11.3k
      if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
5278
0
        accountingOnAbort(parser);
5279
0
        return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
5280
0
      }
5281
21.0k
    }
5282
21.0k
#endif
5283
21.0k
    switch (role) {
5284
43
    case XML_ROLE_XML_DECL: {
5285
43
      enum XML_Error result = processXmlDecl(parser, 0, s, next);
5286
43
      if (result != XML_ERROR_NONE)
5287
43
        return result;
5288
0
      enc = parser->m_encoding;
5289
0
      handleDefault = XML_FALSE;
5290
0
    } break;
5291
96
    case XML_ROLE_DOCTYPE_NAME:
5292
96
      if (parser->m_startDoctypeDeclHandler) {
5293
96
        parser->m_doctypeName
5294
96
            = poolStoreString(&parser->m_tempPool, enc, s, next);
5295
96
        if (! parser->m_doctypeName)
5296
0
          return XML_ERROR_NO_MEMORY;
5297
96
        poolFinish(&parser->m_tempPool);
5298
96
        parser->m_doctypePubid = NULL;
5299
96
        handleDefault = XML_FALSE;
5300
96
      }
5301
96
      parser->m_doctypeSysid = NULL; /* always initialize to NULL */
5302
96
      break;
5303
14
    case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
5304
14
      if (parser->m_startDoctypeDeclHandler) {
5305
14
        beforeHandler(parser);
5306
14
        parser->m_startDoctypeDeclHandler(
5307
14
            parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
5308
14
            parser->m_doctypePubid, 1);
5309
14
        afterHandler(parser);
5310
14
        parser->m_doctypeName = NULL;
5311
14
        poolClear(&parser->m_tempPool);
5312
14
        handleDefault = XML_FALSE;
5313
14
      }
5314
14
      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
37
    case XML_ROLE_DOCTYPE_CLOSE:
5370
37
      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
37
      if (parser->m_doctypeName) {
5376
37
        beforeHandler(parser);
5377
37
        parser->m_startDoctypeDeclHandler(
5378
37
            parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
5379
37
            parser->m_doctypePubid, 0);
5380
37
        afterHandler(parser);
5381
37
        poolClear(&parser->m_tempPool);
5382
37
        handleDefault = XML_FALSE;
5383
37
      }
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
37
#ifdef XML_DTD
5389
37
      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
37
#endif /* XML_DTD */
5434
37
      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
37
      break;
5441
9.58k
    case XML_ROLE_INSTANCE_START:
5442
9.58k
#ifdef XML_DTD
5443
      /* if there is no DOCTYPE declaration then now is the
5444
         last chance to read the foreign DTD
5445
      */
5446
9.58k
      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
9.58k
#endif /* XML_DTD */
5483
9.58k
      parser->m_processor = contentProcessor;
5484
9.58k
      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
2.15k
    case XML_ROLE_ERROR:
5904
2.15k
      switch (tok) {
5905
16
      case XML_TOK_PARAM_ENTITY_REF:
5906
        /* PE references in internal subset are
5907
           not allowed within declarations. */
5908
16
        return XML_ERROR_PARAM_ENTITY_REF;
5909
6
      case XML_TOK_XML_DECL:
5910
6
        return XML_ERROR_MISPLACED_XML_PI;
5911
2.13k
      default:
5912
2.13k
        return XML_ERROR_SYNTAX;
5913
2.15k
      }
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
4.19k
    case XML_ROLE_PI:
6236
4.19k
      if (! reportProcessingInstruction(parser, enc, s, next))
6237
0
        return XML_ERROR_NO_MEMORY;
6238
4.19k
      handleDefault = XML_FALSE;
6239
4.19k
      break;
6240
6
    case XML_ROLE_COMMENT:
6241
6
      if (! reportComment(parser, enc, s, next))
6242
0
        return XML_ERROR_NO_MEMORY;
6243
6
      handleDefault = XML_FALSE;
6244
6
      break;
6245
4.49k
    case XML_ROLE_NONE:
6246
4.49k
      switch (tok) {
6247
433
      case XML_TOK_BOM:
6248
433
        handleDefault = XML_FALSE;
6249
433
        break;
6250
4.49k
      }
6251
4.49k
      break;
6252
4.49k
    case XML_ROLE_DOCTYPE_NONE:
6253
391
      if (parser->m_startDoctypeDeclHandler)
6254
391
        handleDefault = XML_FALSE;
6255
391
      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
21.0k
    } /* end of big switch */
6273
6274
9.22k
    if (handleDefault && parser->m_defaultHandler)
6275
0
      reportDefault(parser, enc, s, next);
6276
6277
9.22k
    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
9.22k
    case XML_PARSING:
6284
9.22k
      if (parser->m_reenter) {
6285
0
        *nextPtr = next;
6286
0
        return XML_ERROR_NONE;
6287
0
      }
6288
9.22k
      EXPAT_FALLTHROUGH;
6289
9.22k
    default:
6290
9.22k
      s = next;
6291
9.22k
      tok = XmlPrologTok(enc, s, end, &next);
6292
9.22k
    }
6293
9.22k
  }
6294
  /* not reached */
6295
20.7k
}
6296
6297
static enum XML_Error PTRCALL
6298
epilogProcessor(XML_Parser parser, const char *s, const char *end,
6299
1.56k
                const char **nextPtr) {
6300
1.56k
  parser->m_processor = epilogProcessor;
6301
1.56k
  parser->m_eventPtr = s;
6302
4.01k
  for (;;) {
6303
4.01k
    const char *next = NULL;
6304
4.01k
    int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
6305
4.01k
#if XML_GE == 1
6306
4.01k
    if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
6307
4.01k
                                  XML_ACCOUNT_DIRECT)) {
6308
0
      accountingOnAbort(parser);
6309
0
      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
6310
0
    }
6311
4.01k
#endif
6312
4.01k
    parser->m_eventEndPtr = next;
6313
4.01k
    switch (tok) {
6314
    /* report partial linebreak - it might be the last token */
6315
0
    case -XML_TOK_PROLOG_S:
6316
0
      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
0
      *nextPtr = next;
6322
0
      return XML_ERROR_NONE;
6323
1.44k
    case XML_TOK_NONE:
6324
1.44k
      *nextPtr = s;
6325
1.44k
      return XML_ERROR_NONE;
6326
1.75k
    case XML_TOK_PROLOG_S:
6327
1.75k
      if (parser->m_defaultHandler)
6328
0
        reportDefault(parser, parser->m_encoding, s, next);
6329
1.75k
      break;
6330
692
    case XML_TOK_PI:
6331
692
      if (! reportProcessingInstruction(parser, parser->m_encoding, s, next))
6332
0
        return XML_ERROR_NO_MEMORY;
6333
692
      break;
6334
692
    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
55
    case XML_TOK_INVALID:
6339
55
      parser->m_eventPtr = next;
6340
55
      return XML_ERROR_INVALID_TOKEN;
6341
17
    case XML_TOK_PARTIAL:
6342
17
      if (! parser->m_parsingStatus.finalBuffer) {
6343
0
        *nextPtr = s;
6344
0
        return XML_ERROR_NONE;
6345
0
      }
6346
17
      return XML_ERROR_UNCLOSED_TOKEN;
6347
14
    case XML_TOK_PARTIAL_CHAR:
6348
14
      if (! parser->m_parsingStatus.finalBuffer) {
6349
0
        *nextPtr = s;
6350
0
        return XML_ERROR_NONE;
6351
0
      }
6352
14
      return XML_ERROR_PARTIAL_CHAR;
6353
42
    default:
6354
42
      return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
6355
4.01k
    }
6356
2.44k
    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
2.44k
    case XML_PARSING:
6365
2.44k
      if (parser->m_reenter) {
6366
0
        return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
6367
0
      }
6368
2.44k
      EXPAT_FALLTHROUGH;
6369
2.44k
    default:;
6370
2.44k
      parser->m_eventPtr = s = next;
6371
2.44k
    }
6372
2.44k
  }
6373
1.56k
}
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
2.57k
                    enum XML_Account account) {
6529
2.57k
  const char *next = ptr;
6530
2.57k
  enum XML_Error result = XML_ERROR_NONE;
6531
6532
2.57k
  while (1) {
6533
2.57k
    if (! parser->m_openAttributeEntities) {
6534
2.57k
      result = appendAttributeValue(parser, enc, isCdata, next, end, pool,
6535
2.57k
                                    account, &next);
6536
2.57k
    } 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
2.57k
    if (result || (parser->m_openAttributeEntities == NULL && end == next)) {
6589
2.57k
      break;
6590
2.57k
    }
6591
2.57k
  }
6592
6593
2.57k
  if (result)
6594
15
    return result;
6595
2.55k
  if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
6596
0
    poolChop(pool);
6597
2.55k
  if (! poolAppendChar(pool, XML_T('\0')))
6598
0
    return XML_ERROR_NO_MEMORY;
6599
2.55k
  return XML_ERROR_NONE;
6600
2.55k
}
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
2.57k
                     enum XML_Account account, const char **nextPtr) {
6606
2.57k
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
6607
#ifndef XML_DTD
6608
  UNUSED_P(account);
6609
#endif
6610
6611
72.5k
  for (;;) {
6612
72.5k
    const char *next
6613
72.5k
        = ptr; /* XmlAttributeValueTok doesn't always set the last arg */
6614
72.5k
    int tok = XmlAttributeValueTok(enc, ptr, end, &next);
6615
72.5k
#if XML_GE == 1
6616
72.5k
    if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
6617
0
      accountingOnAbort(parser);
6618
0
      return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
6619
0
    }
6620
72.5k
#endif
6621
72.5k
    switch (tok) {
6622
2.55k
    case XML_TOK_NONE:
6623
2.55k
      if (nextPtr) {
6624
2.55k
        *nextPtr = next;
6625
2.55k
      }
6626
2.55k
      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
78
    case XML_TOK_CHAR_REF: {
6636
78
      XML_Char buf[XML_ENCODE_MAX];
6637
78
      int n = XmlCharRefNumber(enc, ptr);
6638
78
      if (n < 0) {
6639
15
        if (enc == parser->m_encoding)
6640
15
          parser->m_eventPtr = ptr;
6641
15
        return XML_ERROR_BAD_CHAR_REF;
6642
15
      }
6643
63
      if (! isCdata && n == 0x20 /* space */
6644
0
          && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
6645
0
        break;
6646
63
      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
63
      if (! poolAppendChars(pool, buf, n))
6658
0
        return XML_ERROR_NO_MEMORY;
6659
63
    } break;
6660
16.2k
    case XML_TOK_DATA_CHARS:
6661
16.2k
      if (! poolAppend(pool, enc, ptr, next))
6662
0
        return XML_ERROR_NO_MEMORY;
6663
16.2k
      break;
6664
16.2k
    case XML_TOK_TRAILING_CR:
6665
169
      next = ptr + enc->minBytesPerChar;
6666
169
      EXPAT_FALLTHROUGH;
6667
41.9k
    case XML_TOK_ATTRIBUTE_VALUE_S:
6668
53.6k
    case XML_TOK_DATA_NEWLINE:
6669
53.6k
      if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
6670
0
        break;
6671
53.6k
      if (! poolAppendChar(pool, 0x20))
6672
0
        return XML_ERROR_NO_MEMORY;
6673
53.6k
      break;
6674
53.6k
    case XML_TOK_ENTITY_REF: {
6675
0
      const XML_Char *name;
6676
0
      ENTITY *entity;
6677
0
      bool checkEntityDecl;
6678
0
      XML_Char ch = (XML_Char)XmlPredefinedEntityName(
6679
0
          enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
6680
0
      if (ch) {
6681
0
#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
0
        accountingDiffTolerated(parser, tok, (char *)&ch,
6686
0
                                ((char *)&ch) + sizeof(XML_Char), __LINE__,
6687
0
                                XML_ACCOUNT_ENTITY_EXPANSION);
6688
0
#endif /* XML_GE == 1 */
6689
0
        if (! poolAppendChar(pool, ch))
6690
0
          return XML_ERROR_NO_MEMORY;
6691
0
        break;
6692
0
      }
6693
0
      name = poolStoreString(&parser->m_temp2Pool, enc,
6694
0
                             ptr + enc->minBytesPerChar,
6695
0
                             next - enc->minBytesPerChar);
6696
0
      if (! name)
6697
0
        return XML_ERROR_NO_MEMORY;
6698
0
      entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
6699
0
      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
0
      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
0
      else /* if (pool == &parser->m_tempPool): we are called from content */
6711
0
        checkEntityDecl = ! dtd->hasParamEntityRefs || dtd->standalone;
6712
0
      if (checkEntityDecl) {
6713
0
        if (! entity)
6714
0
          return XML_ERROR_UNDEFINED_ENTITY;
6715
0
        else if (! entity->is_internal)
6716
0
          return XML_ERROR_ENTITY_DECLARED_IN_PE;
6717
0
      } 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
72.5k
    }
6791
70.0k
    ptr = next;
6792
70.0k
  }
6793
  /* not reached */
6794
2.57k
}
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
1.00k
normalizeLines(XML_Char *s) {
7090
1.00k
  XML_Char *p;
7091
246k
  for (;; s++) {
7092
246k
    if (*s == XML_T('\0'))
7093
1.00k
      return;
7094
245k
    if (*s == 0xD)
7095
0
      break;
7096
245k
  }
7097
0
  p = s;
7098
0
  do {
7099
0
    if (*s == 0xD) {
7100
0
      *p++ = 0xA;
7101
0
      if (*++s == 0xA)
7102
0
        s++;
7103
0
    } else
7104
0
      *p++ = *s++;
7105
0
  } while (*s);
7106
0
  *p = XML_T('\0');
7107
0
}
7108
7109
static int
7110
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
7111
4.92k
                            const char *start, const char *end) {
7112
4.92k
  const XML_Char *target;
7113
4.92k
  XML_Char *data;
7114
4.92k
  const char *tem;
7115
4.92k
  if (! parser->m_processingInstructionHandler) {
7116
3.92k
    if (parser->m_defaultHandler)
7117
0
      reportDefault(parser, enc, start, end);
7118
3.92k
    return 1;
7119
3.92k
  }
7120
1.00k
  start += enc->minBytesPerChar * 2;
7121
1.00k
  tem = start + XmlNameLength(enc, start);
7122
1.00k
  target = poolStoreString(&parser->m_tempPool, enc, start, tem);
7123
1.00k
  if (! target)
7124
0
    return 0;
7125
1.00k
  poolFinish(&parser->m_tempPool);
7126
1.00k
  data = poolStoreString(&parser->m_tempPool, enc, XmlSkipS(enc, tem),
7127
1.00k
                         end - enc->minBytesPerChar * 2);
7128
1.00k
  if (! data)
7129
0
    return 0;
7130
1.00k
  normalizeLines(data);
7131
1.00k
  beforeHandler(parser);
7132
1.00k
  parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
7133
1.00k
  afterHandler(parser);
7134
1.00k
  poolClear(&parser->m_tempPool);
7135
1.00k
  return 1;
7136
1.00k
}
7137
7138
static int
7139
reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
7140
8
              const char *end) {
7141
8
  XML_Char *data;
7142
8
  if (! parser->m_commentHandler) {
7143
8
    if (parser->m_defaultHandler)
7144
0
      reportDefault(parser, enc, start, end);
7145
8
    return 1;
7146
8
  }
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
42.1k
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) {
7267
42.1k
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
7268
42.1k
  const XML_Char *name;
7269
219k
  for (name = elementType->name; *name; name++) {
7270
215k
    if (*name == XML_T(ASCII_COLON)) {
7271
38.5k
      PREFIX *prefix;
7272
38.5k
      const XML_Char *s;
7273
167k
      for (s = elementType->name; s != name; s++) {
7274
129k
        if (! poolAppendChar(&dtd->pool, *s))
7275
0
          return 0;
7276
129k
      }
7277
38.5k
      if (! poolAppendChar(&dtd->pool, XML_T('\0')))
7278
0
        return 0;
7279
38.5k
      prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
7280
38.5k
                                sizeof(PREFIX));
7281
38.5k
      if (! prefix)
7282
0
        return 0;
7283
38.5k
      if (prefix->name == poolStart(&dtd->pool))
7284
4.34k
        poolFinish(&dtd->pool);
7285
34.2k
      else
7286
34.2k
        poolDiscard(&dtd->pool);
7287
38.5k
      elementType->prefix = prefix;
7288
38.5k
      break;
7289
38.5k
    }
7290
215k
  }
7291
42.1k
  return 1;
7292
42.1k
}
7293
7294
static ATTRIBUTE_ID *
7295
getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
7296
234k
               const char *end) {
7297
234k
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
7298
234k
  ATTRIBUTE_ID *id;
7299
234k
  const XML_Char *name;
7300
234k
  if (! poolAppendChar(&dtd->pool, XML_T('\0')))
7301
0
    return NULL;
7302
234k
  name = poolStoreString(&dtd->pool, enc, start, end);
7303
234k
  if (! name)
7304
0
    return NULL;
7305
  /* skip quotation mark - its storage will be reused (like in name[-1]) */
7306
234k
  ++name;
7307
234k
  id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name,
7308
234k
                              sizeof(ATTRIBUTE_ID));
7309
234k
  if (! id)
7310
0
    return NULL;
7311
234k
  if (id->name != name)
7312
17.1k
    poolDiscard(&dtd->pool);
7313
216k
  else {
7314
216k
    poolFinish(&dtd->pool);
7315
216k
    if (! parser->m_ns)
7316
0
      ;
7317
216k
    else if (name[0] == XML_T(ASCII_x) && name[1] == XML_T(ASCII_m)
7318
40.0k
             && name[2] == XML_T(ASCII_l) && name[3] == XML_T(ASCII_n)
7319
23.4k
             && name[4] == XML_T(ASCII_s)
7320
23.4k
             && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
7321
23.4k
      if (name[5] == XML_T('\0'))
7322
0
        id->prefix = &dtd->defaultPrefix;
7323
23.4k
      else
7324
23.4k
        id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6,
7325
23.4k
                                      sizeof(PREFIX));
7326
23.4k
      id->xmlns = XML_TRUE;
7327
193k
    } else {
7328
193k
      int i;
7329
864k
      for (i = 0; name[i]; i++) {
7330
        /* Detect and prevent signed integer overflow */
7331
863k
        if (i == INT_MAX) {
7332
0
          return NULL;
7333
0
        }
7334
        /* attributes without prefix are *not* in the default namespace */
7335
863k
        if (name[i] == XML_T(ASCII_COLON)) {
7336
192k
          if (! poolAppendChars(&dtd->pool, name, i))
7337
0
            return NULL;
7338
192k
          if (! poolAppendChar(&dtd->pool, XML_T('\0')))
7339
0
            return NULL;
7340
192k
          id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes,
7341
192k
                                        poolStart(&dtd->pool), sizeof(PREFIX));
7342
192k
          if (! id->prefix)
7343
0
            return NULL;
7344
192k
          if (id->prefix->name == poolStart(&dtd->pool))
7345
323
            poolFinish(&dtd->pool);
7346
192k
          else
7347
192k
            poolDiscard(&dtd->pool);
7348
192k
          break;
7349
192k
        }
7350
863k
      }
7351
193k
    }
7352
216k
  }
7353
234k
  return id;
7354
234k
}
7355
7356
852k
#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
20.7k
setContext(XML_Parser parser, const XML_Char *context) {
7446
20.7k
  if (context == NULL) {
7447
0
    return XML_FALSE;
7448
0
  }
7449
7450
20.7k
  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
7451
20.7k
  const XML_Char *s = context;
7452
7453
103k
  while (*context != XML_T('\0')) {
7454
83.1k
    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
83.1k
    } else if (*s == XML_T(ASCII_EQUALS)) {
7467
20.7k
      PREFIX *prefix;
7468
20.7k
      if (poolLength(&parser->m_tempPool) == 0)
7469
0
        prefix = &dtd->defaultPrefix;
7470
20.7k
      else {
7471
20.7k
        if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
7472
0
          return XML_FALSE;
7473
20.7k
        const XML_Char *const prefixName = poolCopyStringNoFinish(
7474
20.7k
            &dtd->pool, poolStart(&parser->m_tempPool));
7475
20.7k
        if (! prefixName) {
7476
0
          return XML_FALSE;
7477
0
        }
7478
7479
20.7k
        prefix = (PREFIX *)lookup(parser, &dtd->prefixes, prefixName,
7480
20.7k
                                  sizeof(PREFIX));
7481
7482
20.7k
        const bool prefixNameUsed = prefix && prefix->name == prefixName;
7483
20.7k
        if (prefixNameUsed)
7484
20.7k
          poolFinish(&dtd->pool);
7485
0
        else
7486
0
          poolDiscard(&dtd->pool);
7487
7488
20.7k
        if (! prefix)
7489
0
          return XML_FALSE;
7490
7491
20.7k
        poolDiscard(&parser->m_tempPool);
7492
20.7k
      }
7493
769k
      for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0');
7494
748k
           context++)
7495
748k
        if (! poolAppendChar(&parser->m_tempPool, *context))
7496
0
          return XML_FALSE;
7497
20.7k
      if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
7498
0
        return XML_FALSE;
7499
20.7k
      if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool),
7500
20.7k
                     &parser->m_inheritedBindings)
7501
20.7k
          != XML_ERROR_NONE)
7502
0
        return XML_FALSE;
7503
20.7k
      poolDiscard(&parser->m_tempPool);
7504
20.7k
      if (*context != XML_T('\0'))
7505
0
        ++context;
7506
20.7k
      s = context;
7507
62.3k
    } else {
7508
62.3k
      if (! poolAppendChar(&parser->m_tempPool, *s))
7509
0
        return XML_FALSE;
7510
62.3k
      s++;
7511
62.3k
    }
7512
83.1k
  }
7513
20.7k
  return XML_TRUE;
7514
20.7k
}
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
20.7k
dtdCreate(XML_Parser parser) {
7539
20.7k
  DTD *p = MALLOC(parser, sizeof(DTD));
7540
20.7k
  if (p == NULL)
7541
0
    return p;
7542
20.7k
  poolInit(&(p->pool), parser);
7543
20.7k
  poolInit(&(p->entityValuePool), parser);
7544
20.7k
  hashTableInit(&(p->generalEntities), parser);
7545
20.7k
  hashTableInit(&(p->elementTypes), parser);
7546
20.7k
  hashTableInit(&(p->attributeIds), parser);
7547
20.7k
  hashTableInit(&(p->prefixes), parser);
7548
20.7k
#ifdef XML_DTD
7549
20.7k
  p->paramEntityRead = XML_FALSE;
7550
20.7k
  hashTableInit(&(p->paramEntities), parser);
7551
20.7k
#endif /* XML_DTD */
7552
20.7k
  p->defaultPrefix.name = NULL;
7553
20.7k
  p->defaultPrefix.binding = NULL;
7554
7555
20.7k
  p->in_eldecl = XML_FALSE;
7556
20.7k
  p->scaffIndex = NULL;
7557
20.7k
  p->scaffIndexSize = 0;
7558
20.7k
  p->scaffold = NULL;
7559
20.7k
  p->scaffLevel = 0;
7560
20.7k
  p->scaffSize = 0;
7561
20.7k
  p->scaffCount = 0;
7562
20.7k
  p->contentStringLen = 0;
7563
7564
20.7k
  p->keepProcessing = XML_TRUE;
7565
20.7k
  p->hasParamEntityRefs = XML_FALSE;
7566
20.7k
  p->standalone = XML_FALSE;
7567
20.7k
  return p;
7568
20.7k
}
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
20.7k
dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) {
7614
20.7k
  HASH_TABLE_ITER iter;
7615
20.7k
  hashTableIterInit(&iter, &(p->elementTypes));
7616
62.9k
  for (;;) {
7617
62.9k
    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
7618
62.9k
    if (! e)
7619
20.7k
      break;
7620
42.1k
    hashTableDestroy(&(e->defaultAttsNames));
7621
42.1k
    FREE(parser, e->defaultAtts);
7622
42.1k
  }
7623
20.7k
  hashTableDestroy(&(p->generalEntities));
7624
20.7k
#ifdef XML_DTD
7625
20.7k
  hashTableDestroy(&(p->paramEntities));
7626
20.7k
#endif /* XML_DTD */
7627
20.7k
  hashTableDestroy(&(p->elementTypes));
7628
20.7k
  hashTableDestroy(&(p->attributeIds));
7629
20.7k
  hashTableDestroy(&(p->prefixes));
7630
20.7k
  poolDestroy(&(p->pool));
7631
20.7k
  poolDestroy(&(p->entityValuePool));
7632
20.7k
  if (isDocEntity) {
7633
20.7k
    FREE(parser, p->scaffIndex);
7634
20.7k
    FREE(parser, p->scaffold);
7635
20.7k
  }
7636
20.7k
  FREE(parser, p);
7637
20.7k
}
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
56.7k
#define INIT_POWER 6
7847
7848
static XML_Bool FASTCALL
7849
811k
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
811k
  return (strcmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
7861
811k
#endif
7862
811k
}
7863
7864
static size_t
7865
1.39M
keylen(KEY s) {
7866
1.39M
  return xcslen(s);
7867
1.39M
}
7868
7869
static void
7870
1.39M
copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) {
7871
1.39M
  const XML_Parser rootParser = getRootParserOf(parser, NULL);
7872
1.39M
  assert(! rootParser->m_parentParser);
7873
7874
1.39M
  *key = rootParser->m_hash_secret_salt_128;
7875
1.39M
}
7876
7877
static unsigned long FASTCALL
7878
1.18M
hash(XML_Parser parser, KEY s) {
7879
1.18M
  struct siphash state;
7880
1.18M
  struct sipkey key;
7881
1.18M
  (void)sip24_valid;
7882
1.18M
  copy_salt_to_sipkey(parser, &key);
7883
1.18M
  sip24_init(&state, &key);
7884
1.18M
  sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
7885
1.18M
  return (unsigned long)sip24_final(&state);
7886
1.18M
}
7887
7888
static NAMED *
7889
878k
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
7890
878k
  size_t i;
7891
878k
  if (table->size == 0) {
7892
33.7k
    size_t tsize;
7893
33.7k
    if (! createSize)
7894
5.34k
      return NULL;
7895
28.3k
    table->power = INIT_POWER;
7896
    /* table->size is a power of 2 */
7897
28.3k
    table->size = (size_t)1 << INIT_POWER;
7898
28.3k
    tsize = table->size * sizeof(NAMED *);
7899
28.3k
    table->v = MALLOC(table->parser, tsize);
7900
28.3k
    if (! table->v) {
7901
0
      table->size = 0;
7902
0
      return NULL;
7903
0
    }
7904
28.3k
    memset(table->v, 0, tsize);
7905
28.3k
    i = hash(parser, name) & ((unsigned long)table->size - 1);
7906
844k
  } else {
7907
844k
    unsigned long h = hash(parser, name);
7908
844k
    unsigned long mask = (unsigned long)table->size - 1;
7909
844k
    unsigned char step = 0;
7910
844k
    i = h & mask;
7911
1.12M
    while (table->v[i]) {
7912
811k
      if (keyeq(name, table->v[i]->name))
7913
532k
        return table->v[i];
7914
279k
      if (! step)
7915
190k
        step = PROBE_STEP(h, mask, table->power);
7916
279k
      i < step ? (i += table->size - step) : (i -= step);
7917
279k
    }
7918
312k
    if (! createSize)
7919
36.8k
      return NULL;
7920
7921
    /* check for overflow (table is half full) */
7922
275k
    if (table->used >> (table->power - 1)) {
7923
4.55k
      unsigned char newPower = table->power + 1;
7924
7925
      /* Detect and prevent invalid shift */
7926
4.55k
      if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
7927
0
        return NULL;
7928
0
      }
7929
7930
4.55k
      size_t newSize = (size_t)1 << newPower;
7931
4.55k
      unsigned long newMask = (unsigned long)newSize - 1;
7932
7933
      /* Detect and prevent integer overflow */
7934
4.55k
      if (newSize > SIZE_MAX / sizeof(NAMED *)) {
7935
0
        return NULL;
7936
0
      }
7937
7938
4.55k
      size_t tsize = newSize * sizeof(NAMED *);
7939
4.55k
      NAMED **newV = MALLOC(table->parser, tsize);
7940
4.55k
      if (! newV)
7941
0
        return NULL;
7942
4.55k
      memset(newV, 0, tsize);
7943
633k
      for (i = 0; i < table->size; i++)
7944
628k
        if (table->v[i]) {
7945
314k
          unsigned long newHash = hash(parser, table->v[i]->name);
7946
314k
          size_t j = newHash & newMask;
7947
314k
          step = 0;
7948
361k
          while (newV[j]) {
7949
46.6k
            if (! step)
7950
37.8k
              step = PROBE_STEP(newHash, newMask, newPower);
7951
46.6k
            j < step ? (j += newSize - step) : (j -= step);
7952
46.6k
          }
7953
314k
          newV[j] = table->v[i];
7954
314k
        }
7955
4.55k
      FREE(table->parser, table->v);
7956
4.55k
      table->v = newV;
7957
4.55k
      table->power = newPower;
7958
4.55k
      table->size = newSize;
7959
4.55k
      i = h & newMask;
7960
4.55k
      step = 0;
7961
6.11k
      while (table->v[i]) {
7962
1.56k
        if (! step)
7963
1.17k
          step = PROBE_STEP(h, newMask, newPower);
7964
1.56k
        i < step ? (i += newSize - step) : (i -= step);
7965
1.56k
      }
7966
4.55k
    }
7967
275k
  }
7968
303k
  table->v[i] = MALLOC(table->parser, createSize);
7969
303k
  if (! table->v[i])
7970
0
    return NULL;
7971
303k
  memset(table->v[i], 0, createSize);
7972
303k
  table->v[i]->name = name;
7973
303k
  (table->used)++;
7974
303k
  return table->v[i];
7975
303k
}
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
146k
hashTableDestroy(HASH_TABLE *table) {
7989
146k
  size_t i;
7990
2.59M
  for (i = 0; i < table->size; i++)
7991
2.44M
    FREE(table->parser, table->v[i]);
7992
146k
  FREE(table->parser, table->v);
7993
146k
}
7994
7995
static void FASTCALL
7996
146k
hashTableInit(HASH_TABLE *p, XML_Parser parser) {
7997
146k
  p->power = 0;
7998
146k
  p->size = 0;
7999
146k
  p->used = 0;
8000
146k
  p->v = NULL;
8001
146k
  p->parser = parser;
8002
146k
}
8003
8004
static void FASTCALL
8005
20.7k
hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) {
8006
20.7k
  iter->p = table->v;
8007
20.7k
  iter->end = iter->p ? iter->p + table->size : NULL;
8008
20.7k
}
8009
8010
static NAMED *FASTCALL
8011
62.9k
hashTableIterNext(HASH_TABLE_ITER *iter) {
8012
361k
  while (iter->p != iter->end) {
8013
341k
    NAMED *tem = *(iter->p)++;
8014
341k
    if (tem)
8015
42.1k
      return tem;
8016
341k
  }
8017
20.7k
  return NULL;
8018
62.9k
}
8019
8020
static void FASTCALL
8021
83.1k
poolInit(STRING_POOL *pool, XML_Parser parser) {
8022
83.1k
  pool->blocks = NULL;
8023
83.1k
  pool->freeBlocks = NULL;
8024
83.1k
  pool->start = NULL;
8025
83.1k
  pool->ptr = NULL;
8026
83.1k
  pool->end = NULL;
8027
83.1k
  pool->parser = parser;
8028
83.1k
}
8029
8030
static void FASTCALL
8031
123k
poolClear(STRING_POOL *pool) {
8032
123k
  if (! pool->freeBlocks)
8033
9.46k
    pool->freeBlocks = pool->blocks;
8034
114k
  else {
8035
114k
    BLOCK *p = pool->blocks;
8036
129k
    while (p) {
8037
15.2k
      BLOCK *tem = p->next;
8038
15.2k
      p->next = pool->freeBlocks;
8039
15.2k
      pool->freeBlocks = p;
8040
15.2k
      p = tem;
8041
15.2k
    }
8042
114k
  }
8043
123k
  pool->blocks = NULL;
8044
123k
  pool->start = NULL;
8045
123k
  pool->ptr = NULL;
8046
123k
  pool->end = NULL;
8047
123k
}
8048
8049
static void FASTCALL
8050
83.1k
poolDestroy(STRING_POOL *pool) {
8051
83.1k
  BLOCK *p = pool->blocks;
8052
124k
  while (p) {
8053
41.1k
    BLOCK *tem = p->next;
8054
41.1k
    FREE(pool->parser, p);
8055
41.1k
    p = tem;
8056
41.1k
  }
8057
83.1k
  p = pool->freeBlocks;
8058
98.9k
  while (p) {
8059
15.7k
    BLOCK *tem = p->next;
8060
15.7k
    FREE(pool->parser, p);
8061
15.7k
    p = tem;
8062
15.7k
  }
8063
83.1k
}
8064
8065
static XML_Char *
8066
poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
8067
492k
           const char *end) {
8068
492k
  if (! pool->ptr && ! poolGrow(pool))
8069
0
    return NULL;
8070
494k
  for (;;) {
8071
494k
    const enum XML_Convert_Result convert_res = XmlConvert(
8072
494k
        enc, &ptr, end, (ICHAR **)&(pool->ptr), (const ICHAR *)pool->end);
8073
494k
    if ((convert_res == XML_CONVERT_COMPLETED)
8074
1.90k
        || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
8075
492k
      break;
8076
1.90k
    if (! poolGrow(pool))
8077
0
      return NULL;
8078
1.90k
  }
8079
492k
  return pool->start;
8080
492k
}
8081
8082
static const XML_Char *FASTCALL
8083
42.1k
poolCopyString(STRING_POOL *pool, const XML_Char *s) {
8084
42.1k
  if (! poolAppendChars(pool, s, xcslen(s) + /*null terminator*/ 1))
8085
0
    return NULL;
8086
42.1k
  s = pool->start;
8087
42.1k
  poolFinish(pool);
8088
42.1k
  return s;
8089
42.1k
}
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
20.7k
poolCopyStringNoFinish(STRING_POOL *pool, const XML_Char *s) {
8095
20.7k
  const XML_Char *const original = s;
8096
83.1k
  do {
8097
83.1k
    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
83.1k
  } while (*s++);
8105
20.7k
  return pool->start;
8106
20.7k
}
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
476k
                const char *end) {
8141
476k
  if (! poolAppend(pool, enc, ptr, end))
8142
0
    return NULL;
8143
476k
  if (! poolAppendChar(pool, 0))
8144
0
    return NULL;
8145
476k
  return pool->start;
8146
476k
}
8147
8148
static size_t
8149
57.0k
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
57.0k
  const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */
8158
8159
57.0k
  if (blockSize <= 0)
8160
0
    return 0;
8161
8162
57.0k
  if (blockSize > (int)(INT_MAX / stretch))
8163
0
    return 0;
8164
8165
57.0k
  {
8166
57.0k
    const int stretchedBlockSize = blockSize * (int)stretch;
8167
57.0k
    const int bytesToAllocate
8168
57.0k
        = (int)(offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
8169
57.0k
    if (bytesToAllocate < 0)
8170
0
      return 0;
8171
8172
57.0k
    return (size_t)bytesToAllocate;
8173
57.0k
  }
8174
57.0k
}
8175
8176
static XML_Bool FASTCALL
8177
76.9k
poolGrow(STRING_POOL *pool) {
8178
76.9k
  if (pool->freeBlocks) {
8179
19.9k
    if (pool->start == NULL) {
8180
19.7k
      pool->blocks = pool->freeBlocks;
8181
19.7k
      pool->freeBlocks = pool->freeBlocks->next;
8182
19.7k
      pool->blocks->next = NULL;
8183
19.7k
      pool->start = pool->blocks->s;
8184
19.7k
      pool->end = pool->start + pool->blocks->size;
8185
19.7k
      pool->ptr = pool->start;
8186
19.7k
      return XML_TRUE;
8187
19.7k
    }
8188
209
    if (pool->end - pool->start < pool->freeBlocks->size) {
8189
101
      BLOCK *tem = pool->freeBlocks->next;
8190
101
      pool->freeBlocks->next = pool->blocks;
8191
101
      pool->blocks = pool->freeBlocks;
8192
101
      pool->freeBlocks = tem;
8193
101
      memcpy(pool->blocks->s, pool->start,
8194
101
             (pool->end - pool->start) * sizeof(XML_Char));
8195
101
      pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
8196
101
      pool->start = pool->blocks->s;
8197
101
      pool->end = pool->start + pool->blocks->size;
8198
101
      return XML_TRUE;
8199
101
    }
8200
209
  }
8201
57.0k
  if (pool->blocks && pool->start == pool->blocks->s) {
8202
185
    BLOCK *temp;
8203
185
    int blockSize = (int)((unsigned)(pool->end - pool->start) * 2U);
8204
185
    size_t bytesToAllocate;
8205
8206
    /* NOTE: Needs to be calculated prior to calling `realloc`
8207
             to avoid dangling pointers: */
8208
185
    const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
8209
8210
185
    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
185
    bytesToAllocate = poolBytesToAllocateFor(blockSize);
8221
185
    if (bytesToAllocate == 0)
8222
0
      return XML_FALSE;
8223
8224
185
    temp = REALLOC(pool->parser, pool->blocks, bytesToAllocate);
8225
185
    if (temp == NULL)
8226
0
      return XML_FALSE;
8227
185
    pool->blocks = temp;
8228
185
    pool->blocks->size = blockSize;
8229
185
    pool->ptr = pool->blocks->s + offsetInsideBlock;
8230
185
    pool->start = pool->blocks->s;
8231
185
    pool->end = pool->start + blockSize;
8232
56.8k
  } else {
8233
56.8k
    BLOCK *tem;
8234
56.8k
    int blockSize = (int)(pool->end - pool->start);
8235
56.8k
    size_t bytesToAllocate;
8236
8237
56.8k
    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
56.8k
    if (blockSize < INIT_BLOCK_SIZE)
8251
56.8k
      blockSize = INIT_BLOCK_SIZE;
8252
0
    else {
8253
      /* Detect overflow, avoiding _signed_ overflow undefined behavior */
8254
0
      if ((int)((unsigned)blockSize * 2U) < 0) {
8255
0
        return XML_FALSE;
8256
0
      }
8257
0
      blockSize *= 2;
8258
0
    }
8259
8260
56.8k
    bytesToAllocate = poolBytesToAllocateFor(blockSize);
8261
56.8k
    if (bytesToAllocate == 0)
8262
0
      return XML_FALSE;
8263
8264
56.8k
    tem = MALLOC(pool->parser, bytesToAllocate);
8265
56.8k
    if (! tem)
8266
0
      return XML_FALSE;
8267
56.8k
    tem->size = blockSize;
8268
56.8k
    tem->next = pool->blocks;
8269
56.8k
    pool->blocks = tem;
8270
56.8k
    if (pool->ptr != pool->start)
8271
4.72k
      memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
8272
56.8k
    pool->ptr = tem->s + (pool->ptr - pool->start);
8273
56.8k
    pool->start = tem->s;
8274
56.8k
    pool->end = tem->s + blockSize;
8275
56.8k
  }
8276
57.0k
  return XML_TRUE;
8277
57.0k
}
8278
8279
static bool FASTCALL
8280
640k
poolGrowUntil(STRING_POOL *pool, size_t needed) {
8281
652k
  for (;;) {
8282
652k
    const size_t available = pool->end - pool->ptr;
8283
652k
    if (available >= needed) {
8284
640k
      return true;
8285
640k
    }
8286
11.7k
    if (! poolGrow(pool)) {
8287
0
      return false;
8288
0
    }
8289
11.7k
  }
8290
640k
}
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
709k
accountingGetCurrentAmplification(XML_Parser rootParser) {
8553
  //                                          1.........1.........12 => 22
8554
709k
  const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
8555
709k
  const XmlBigCount countBytesOutput
8556
709k
      = rootParser->m_accounting.countBytesDirect
8557
709k
        + rootParser->m_accounting.countBytesIndirect;
8558
709k
  const float amplificationFactor
8559
709k
      = rootParser->m_accounting.countBytesDirect
8560
709k
            ? ((float)countBytesOutput
8561
709k
               / (float)(rootParser->m_accounting.countBytesDirect))
8562
709k
            : ((float)(lenOfShortestInclude
8563
0
                       + rootParser->m_accounting.countBytesIndirect)
8564
0
               / (float)lenOfShortestInclude);
8565
709k
  assert(! rootParser->m_parentParser);
8566
709k
  return amplificationFactor;
8567
709k
}
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
722k
                        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
722k
  switch (tok) {
8638
5.25k
  case XML_TOK_INVALID:
8639
6.68k
  case XML_TOK_PARTIAL:
8640
7.26k
  case XML_TOK_PARTIAL_CHAR:
8641
11.4k
  case XML_TOK_NONE:
8642
11.4k
    return XML_TRUE;
8643
722k
  }
8644
8645
711k
  if (account == XML_ACCOUNT_NONE)
8646
1.88k
    return XML_TRUE; /* because these bytes have been accounted for, already */
8647
8648
709k
  unsigned int levelsAwayFromRootParser;
8649
709k
  const XML_Parser rootParser
8650
709k
      = getRootParserOf(originParser, &levelsAwayFromRootParser);
8651
709k
  assert(! rootParser->m_parentParser);
8652
8653
709k
  const int isDirect
8654
709k
      = (account == XML_ACCOUNT_DIRECT) && (originParser == rootParser);
8655
709k
  const ptrdiff_t bytesMore = after - before;
8656
8657
709k
  XmlBigCount *const additionTarget
8658
709k
      = isDirect ? &rootParser->m_accounting.countBytesDirect
8659
709k
                 : &rootParser->m_accounting.countBytesIndirect;
8660
8661
  /* Detect and avoid integer overflow */
8662
709k
  if (*additionTarget > (XmlBigCount)(-1) - (XmlBigCount)bytesMore)
8663
0
    return XML_FALSE;
8664
709k
  *additionTarget += bytesMore;
8665
8666
709k
  const XmlBigCount countBytesOutput
8667
709k
      = rootParser->m_accounting.countBytesDirect
8668
709k
        + rootParser->m_accounting.countBytesIndirect;
8669
709k
  const float amplificationFactor
8670
709k
      = accountingGetCurrentAmplification(rootParser);
8671
709k
  const XML_Bool tolerated
8672
709k
      = (countBytesOutput < rootParser->m_accounting.activationThresholdBytes)
8673
18
        || (amplificationFactor
8674
18
            <= rootParser->m_accounting.maximumAmplificationFactor);
8675
8676
709k
  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
709k
  return tolerated;
8683
709k
}
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
3.31M
getRootParserOf(XML_Parser parser, unsigned int *outLevelDiff) {
8761
3.31M
  XML_Parser rootParser = parser;
8762
3.31M
  unsigned int stepsTakenUpwards = 0;
8763
3.31M
  while (rootParser->m_parentParser) {
8764
0
    rootParser = rootParser->m_parentParser;
8765
0
    stepsTakenUpwards++;
8766
0
  }
8767
3.31M
  assert(! rootParser->m_parentParser);
8768
3.31M
  if (outLevelDiff != NULL) {
8769
709k
    *outLevelDiff = stepsTakenUpwards;
8770
709k
  }
8771
3.31M
  return rootParser;
8772
3.31M
}
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
83.1k
getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
9304
83.1k
  const char *const valueOrNull = getenv(variableName);
9305
83.1k
  if (valueOrNull == NULL) {
9306
83.1k
    return defaultDebugLevel;
9307
83.1k
  }
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
}