Coverage Report

Created: 2026-10-14 09:33

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