|
|
|
@@ -1,4 +1,4 @@
|
|
|
|
|
/* a30d2613dcfdef81475a9d1a349134d2d42722172fdaa7d5bb12ed2aa74b9596 (2.4.6+)
|
|
|
|
|
/* 2a14271ad4d35e82bde8ba210b4edb7998794bcbae54deab114046a300f9639a (2.6.2+)
|
|
|
|
|
__ __ _
|
|
|
|
|
___\ \/ /_ __ __ _| |_
|
|
|
|
|
/ _ \\ /| '_ \ / _` | __|
|
|
|
|
@@ -13,13 +13,13 @@
|
|
|
|
|
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
|
|
|
|
|
Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
|
|
|
|
|
Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
|
|
|
|
|
Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
|
|
|
|
|
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
|
|
|
|
|
Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
|
|
|
|
|
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
|
|
|
|
|
Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
|
|
|
|
|
Copyright (c) 2016 Pascal Cuoq <cuoq@trust-in-soft.com>
|
|
|
|
|
Copyright (c) 2016 Ed Schouten <ed@nuxi.nl>
|
|
|
|
|
Copyright (c) 2017-2018 Rhodri James <rhodri@wildebeest.org.uk>
|
|
|
|
|
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
|
|
|
|
|
Copyright (c) 2017 Václav Slavík <vaclav@slavik.io>
|
|
|
|
|
Copyright (c) 2017 Viktor Szakats <commit@vsz.me>
|
|
|
|
|
Copyright (c) 2017 Chanho Park <chanho61.park@samsung.com>
|
|
|
|
@@ -32,8 +32,13 @@
|
|
|
|
|
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
|
|
|
|
Copyright (c) 2019-2020 Ben Wagner <bungeman@chromium.org>
|
|
|
|
|
Copyright (c) 2019 Vadim Zeitlin <vadim@zeitlins.org>
|
|
|
|
|
Copyright (c) 2021 Dong-hee Na <donghee.na@python.org>
|
|
|
|
|
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
|
|
|
|
|
Copyright (c) 2022 Samanta Navarro <ferivoz@riseup.net>
|
|
|
|
|
Copyright (c) 2022 Jeffrey Walton <noloader@gmail.com>
|
|
|
|
|
Copyright (c) 2022 Jann Horn <jannh@google.com>
|
|
|
|
|
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
|
|
|
|
|
Copyright (c) 2023 Owain Davies <owaind@bath.edu>
|
|
|
|
|
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
|
|
|
|
Licensed under the MIT license:
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
@@ -58,10 +63,25 @@
|
|
|
|
|
|
|
|
|
|
#define XML_BUILDING_EXPAT 1
|
|
|
|
|
|
|
|
|
|
#include <expat_config.h>
|
|
|
|
|
#include "expat_config.h"
|
|
|
|
|
|
|
|
|
|
#if ! defined(_GNU_SOURCE)
|
|
|
|
|
# define _GNU_SOURCE 1 /* syscall prototype */
|
|
|
|
|
#if ! defined(XML_GE) || (1 - XML_GE - 1 == 2) || (XML_GE < 0) || (XML_GE > 1)
|
|
|
|
|
# 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)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(XML_DTD) && XML_GE == 0
|
|
|
|
|
# error Either undefine XML_DTD or define XML_GE to 1.
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if ! defined(XML_CONTEXT_BYTES) || (1 - XML_CONTEXT_BYTES - 1 == 2) \
|
|
|
|
|
|| (XML_CONTEXT_BYTES + 0 < 0)
|
|
|
|
|
# error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(HAVE_SYSCALL_GETRANDOM)
|
|
|
|
|
# if ! defined(_GNU_SOURCE)
|
|
|
|
|
# define _GNU_SOURCE 1 /* syscall prototype */
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
@@ -71,6 +91,7 @@
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <string.h> /* memset(), memcpy() */
|
|
|
|
|
#include <assert.h>
|
|
|
|
@@ -129,11 +150,11 @@
|
|
|
|
|
Your options include: \
|
|
|
|
|
* Linux >=3.17 + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
|
|
|
|
|
* Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
|
|
|
|
|
* BSD / macOS >=10.7 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
|
|
|
|
|
* BSD / macOS (including <10.7) (arc4random): HAVE_ARC4RANDOM, \
|
|
|
|
|
* BSD / macOS >=10.7 / glibc >=2.36 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
|
|
|
|
|
* BSD / macOS (including <10.7) / glibc >=2.36 (arc4random): HAVE_ARC4RANDOM, \
|
|
|
|
|
* libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
|
|
|
|
|
* libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
|
|
|
|
|
* Linux (including <3.17) / BSD / macOS (including <10.7) (/dev/urandom): XML_DEV_URANDOM, \
|
|
|
|
|
* Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \
|
|
|
|
|
* Windows >=Vista (rand_s): _WIN32. \
|
|
|
|
|
\
|
|
|
|
|
If insist on not using any of these, bypass this error by defining \
|
|
|
|
@@ -189,11 +210,13 @@ typedef char ICHAR;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Round up n to be a multiple of sz, where sz is a power of 2. */
|
|
|
|
|
#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1))
|
|
|
|
|
#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
|
|
|
|
|
|
|
|
|
|
/* Do safe (NULL-aware) pointer arithmetic */
|
|
|
|
|
#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
|
|
|
|
|
|
|
|
|
|
#define EXPAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
|
#include "xmltok.h"
|
|
|
|
|
#include "xmlrole.h"
|
|
|
|
@@ -225,7 +248,7 @@ static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key);
|
|
|
|
|
it odd, since odd numbers are always relative prime to a power of 2.
|
|
|
|
|
*/
|
|
|
|
|
#define SECOND_HASH(hash, mask, power) \
|
|
|
|
|
((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2))
|
|
|
|
|
((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
|
|
|
|
|
#define PROBE_STEP(hash, mask, power) \
|
|
|
|
|
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
|
|
|
|
|
|
|
|
|
@@ -277,7 +300,7 @@ typedef struct {
|
|
|
|
|
XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
|
|
|
|
|
contain the 'raw' name as well.
|
|
|
|
|
|
|
|
|
|
A parser re-uses these structures, maintaining a list of allocated
|
|
|
|
|
A parser reuses these structures, maintaining a list of allocated
|
|
|
|
|
TAG objects in a free list.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct tag {
|
|
|
|
@@ -406,12 +429,12 @@ enum XML_Account {
|
|
|
|
|
XML_ACCOUNT_NONE /* i.e. do not account, was accounted already */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
typedef unsigned long long XmlBigCount;
|
|
|
|
|
typedef struct accounting {
|
|
|
|
|
XmlBigCount countBytesDirect;
|
|
|
|
|
XmlBigCount countBytesIndirect;
|
|
|
|
|
int debugLevel;
|
|
|
|
|
unsigned long debugLevel;
|
|
|
|
|
float maximumAmplificationFactor; // >=1.0
|
|
|
|
|
unsigned long long activationThresholdBytes;
|
|
|
|
|
} ACCOUNTING;
|
|
|
|
@@ -420,9 +443,9 @@ typedef struct entity_stats {
|
|
|
|
|
unsigned int countEverOpened;
|
|
|
|
|
unsigned int currentDepth;
|
|
|
|
|
unsigned int maximumDepthSeen;
|
|
|
|
|
int debugLevel;
|
|
|
|
|
unsigned long debugLevel;
|
|
|
|
|
} ENTITY_STATS;
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
|
|
|
|
|
typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
|
|
|
|
|
const char *end, const char **endPtr);
|
|
|
|
@@ -462,41 +485,47 @@ static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
|
|
|
|
|
const ENCODING *enc, const char *start,
|
|
|
|
|
const char *end, const char **endPtr,
|
|
|
|
|
XML_Bool haveMore, enum XML_Account account);
|
|
|
|
|
static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
|
|
|
|
|
static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char **startPtr, const char *end,
|
|
|
|
|
const char **nextPtr, XML_Bool haveMore,
|
|
|
|
|
enum XML_Account account);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
|
|
|
|
|
static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char **startPtr, const char *end,
|
|
|
|
|
const char **nextPtr, XML_Bool haveMore);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
|
|
|
|
|
static void freeBindings(XML_Parser parser, BINDING *bindings);
|
|
|
|
|
static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
|
|
|
|
|
const char *s, TAG_NAME *tagNamePtr,
|
|
|
|
|
static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char *attStr, TAG_NAME *tagNamePtr,
|
|
|
|
|
BINDING **bindingsPtr,
|
|
|
|
|
enum XML_Account account);
|
|
|
|
|
static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
|
|
|
|
|
const ATTRIBUTE_ID *attId, const XML_Char *uri,
|
|
|
|
|
BINDING **bindingsPtr);
|
|
|
|
|
static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
|
|
|
|
|
XML_Bool isId, const XML_Char *dfltValue,
|
|
|
|
|
XML_Parser parser);
|
|
|
|
|
static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
|
|
|
|
|
XML_Bool isCdata, const char *,
|
|
|
|
|
const char *, STRING_POOL *,
|
|
|
|
|
static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId,
|
|
|
|
|
XML_Bool isCdata, XML_Bool isId,
|
|
|
|
|
const XML_Char *value, XML_Parser parser);
|
|
|
|
|
static enum XML_Error storeAttributeValue(XML_Parser parser,
|
|
|
|
|
const ENCODING *enc, XML_Bool isCdata,
|
|
|
|
|
const char *ptr, const char *end,
|
|
|
|
|
STRING_POOL *pool,
|
|
|
|
|
enum XML_Account account);
|
|
|
|
|
static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
|
|
|
|
|
XML_Bool isCdata, const char *,
|
|
|
|
|
const char *, STRING_POOL *,
|
|
|
|
|
static enum XML_Error appendAttributeValue(XML_Parser parser,
|
|
|
|
|
const ENCODING *enc,
|
|
|
|
|
XML_Bool isCdata, const char *ptr,
|
|
|
|
|
const char *end, STRING_POOL *pool,
|
|
|
|
|
enum XML_Account account);
|
|
|
|
|
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char *start, const char *end);
|
|
|
|
|
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
|
|
|
|
|
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType);
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char *start, const char *end,
|
|
|
|
|
enum XML_Account account);
|
|
|
|
|
#else
|
|
|
|
|
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
|
|
|
|
|
#endif
|
|
|
|
|
static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char *start, const char *end);
|
|
|
|
|
static int reportComment(XML_Parser parser, const ENCODING *enc,
|
|
|
|
@@ -516,21 +545,22 @@ static void dtdDestroy(DTD *p, XML_Bool isDocEntity,
|
|
|
|
|
const XML_Memory_Handling_Suite *ms);
|
|
|
|
|
static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
|
|
|
|
|
const XML_Memory_Handling_Suite *ms);
|
|
|
|
|
static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *, STRING_POOL *,
|
|
|
|
|
const HASH_TABLE *);
|
|
|
|
|
static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
|
|
|
|
|
STRING_POOL *newPool, const HASH_TABLE *oldTable);
|
|
|
|
|
static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
|
|
|
|
|
size_t createSize);
|
|
|
|
|
static void FASTCALL hashTableInit(HASH_TABLE *,
|
|
|
|
|
static void FASTCALL hashTableInit(HASH_TABLE *table,
|
|
|
|
|
const XML_Memory_Handling_Suite *ms);
|
|
|
|
|
static void FASTCALL hashTableClear(HASH_TABLE *);
|
|
|
|
|
static void FASTCALL hashTableDestroy(HASH_TABLE *);
|
|
|
|
|
static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
|
|
|
|
|
static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
|
|
|
|
|
static void FASTCALL hashTableClear(HASH_TABLE *table);
|
|
|
|
|
static void FASTCALL hashTableDestroy(HASH_TABLE *table);
|
|
|
|
|
static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *iter,
|
|
|
|
|
const HASH_TABLE *table);
|
|
|
|
|
static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *iter);
|
|
|
|
|
|
|
|
|
|
static void FASTCALL poolInit(STRING_POOL *,
|
|
|
|
|
static void FASTCALL poolInit(STRING_POOL *pool,
|
|
|
|
|
const XML_Memory_Handling_Suite *ms);
|
|
|
|
|
static void FASTCALL poolClear(STRING_POOL *);
|
|
|
|
|
static void FASTCALL poolDestroy(STRING_POOL *);
|
|
|
|
|
static void FASTCALL poolClear(STRING_POOL *pool);
|
|
|
|
|
static void FASTCALL poolDestroy(STRING_POOL *pool);
|
|
|
|
|
static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
|
|
|
|
|
const char *ptr, const char *end);
|
|
|
|
|
static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
|
|
|
|
@@ -560,7 +590,7 @@ static XML_Parser parserCreate(const XML_Char *encodingName,
|
|
|
|
|
|
|
|
|
|
static void parserInit(XML_Parser parser, const XML_Char *encodingName);
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
static float accountingGetCurrentAmplification(XML_Parser rootParser);
|
|
|
|
|
static void accountingReportStats(XML_Parser originParser, const char *epilog);
|
|
|
|
|
static void accountingOnAbort(XML_Parser originParser);
|
|
|
|
@@ -583,13 +613,12 @@ static void entityTrackingOnClose(XML_Parser parser, ENTITY *entity,
|
|
|
|
|
|
|
|
|
|
static XML_Parser getRootParserOf(XML_Parser parser,
|
|
|
|
|
unsigned int *outLevelDiff);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
|
|
|
|
|
static unsigned long getDebugLevel(const char *variableName,
|
|
|
|
|
unsigned long defaultDebugLevel);
|
|
|
|
|
|
|
|
|
|
#define poolStart(pool) ((pool)->start)
|
|
|
|
|
#define poolEnd(pool) ((pool)->ptr)
|
|
|
|
|
#define poolLength(pool) ((pool)->ptr - (pool)->start)
|
|
|
|
|
#define poolChop(pool) ((void)--(pool->ptr))
|
|
|
|
|
#define poolLastChar(pool) (((pool)->ptr)[-1])
|
|
|
|
@@ -600,21 +629,41 @@ static unsigned long getDebugLevel(const char *variableName,
|
|
|
|
|
? 0 \
|
|
|
|
|
: ((*((pool)->ptr)++ = c), 1))
|
|
|
|
|
|
|
|
|
|
#if ! defined(XML_TESTING)
|
|
|
|
|
const
|
|
|
|
|
#endif
|
|
|
|
|
XML_Bool g_reparseDeferralEnabledDefault
|
|
|
|
|
= XML_TRUE; // write ONLY in runtests.c
|
|
|
|
|
#if defined(XML_TESTING)
|
|
|
|
|
unsigned int g_bytesScanned = 0; // used for testing only
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct XML_ParserStruct {
|
|
|
|
|
/* The first member must be m_userData so that the XML_GetUserData
|
|
|
|
|
macro works. */
|
|
|
|
|
void *m_userData;
|
|
|
|
|
void *m_handlerArg;
|
|
|
|
|
char *m_buffer;
|
|
|
|
|
|
|
|
|
|
// How the four parse buffer pointers below relate in time and space:
|
|
|
|
|
//
|
|
|
|
|
// m_buffer <= m_bufferPtr <= m_bufferEnd <= m_bufferLim
|
|
|
|
|
// | | | |
|
|
|
|
|
// <--parsed-->| | |
|
|
|
|
|
// <---parsing--->| |
|
|
|
|
|
// <--unoccupied-->|
|
|
|
|
|
// <---------total-malloced/realloced-------->|
|
|
|
|
|
|
|
|
|
|
char *m_buffer; // malloc/realloc base pointer of parse buffer
|
|
|
|
|
const XML_Memory_Handling_Suite m_mem;
|
|
|
|
|
/* first character to be parsed */
|
|
|
|
|
const char *m_bufferPtr;
|
|
|
|
|
/* past last character to be parsed */
|
|
|
|
|
char *m_bufferEnd;
|
|
|
|
|
/* allocated end of m_buffer */
|
|
|
|
|
const char *m_bufferLim;
|
|
|
|
|
const char *m_bufferPtr; // first character to be parsed
|
|
|
|
|
char *m_bufferEnd; // past last character to be parsed
|
|
|
|
|
const char *m_bufferLim; // allocated end of m_buffer
|
|
|
|
|
|
|
|
|
|
XML_Index m_parseEndByteIndex;
|
|
|
|
|
const char *m_parseEndPtr;
|
|
|
|
|
size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
|
|
|
|
|
XML_Bool m_reparseDeferralEnabled;
|
|
|
|
|
int m_lastBufferRequestSize;
|
|
|
|
|
XML_Char *m_dataBuf;
|
|
|
|
|
XML_Char *m_dataBufEnd;
|
|
|
|
|
XML_StartElementHandler m_startElementHandler;
|
|
|
|
@@ -701,7 +750,7 @@ struct XML_ParserStruct {
|
|
|
|
|
enum XML_ParamEntityParsing m_paramEntityParsing;
|
|
|
|
|
#endif
|
|
|
|
|
unsigned long m_hash_secret_salt;
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
ACCOUNTING m_accounting;
|
|
|
|
|
ENTITY_STATS m_entity_stats;
|
|
|
|
|
#endif
|
|
|
|
@@ -722,6 +771,7 @@ XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
|
|
|
|
|
return XML_ParserCreate_MM(encodingName, NULL, tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// "xml=http://www.w3.org/XML/1998/namespace"
|
|
|
|
|
static const XML_Char implicitContext[]
|
|
|
|
|
= {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h,
|
|
|
|
|
ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
|
|
|
|
@@ -945,6 +995,49 @@ get_hash_secret_salt(XML_Parser parser) {
|
|
|
|
|
return parser->m_hash_secret_salt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum XML_Error
|
|
|
|
|
callProcessor(XML_Parser parser, const char *start, const char *end,
|
|
|
|
|
const char **endPtr) {
|
|
|
|
|
const size_t have_now = EXPAT_SAFE_PTR_DIFF(end, start);
|
|
|
|
|
|
|
|
|
|
if (parser->m_reparseDeferralEnabled
|
|
|
|
|
&& ! parser->m_parsingStatus.finalBuffer) {
|
|
|
|
|
// Heuristic: don't try to parse a partial token again until the amount of
|
|
|
|
|
// available data has increased significantly.
|
|
|
|
|
const size_t had_before = parser->m_partialTokenBytesBefore;
|
|
|
|
|
// ...but *do* try anyway if we're close to causing a reallocation.
|
|
|
|
|
size_t available_buffer
|
|
|
|
|
= EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
available_buffer -= EXPAT_MIN(available_buffer, XML_CONTEXT_BYTES);
|
|
|
|
|
#endif
|
|
|
|
|
available_buffer
|
|
|
|
|
+= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd);
|
|
|
|
|
// m_lastBufferRequestSize is never assigned a value < 0, so the cast is ok
|
|
|
|
|
const bool enough
|
|
|
|
|
= (have_now >= 2 * had_before)
|
|
|
|
|
|| ((size_t)parser->m_lastBufferRequestSize > available_buffer);
|
|
|
|
|
|
|
|
|
|
if (! enough) {
|
|
|
|
|
*endPtr = start; // callers may expect this to be set
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#if defined(XML_TESTING)
|
|
|
|
|
g_bytesScanned += (unsigned)have_now;
|
|
|
|
|
#endif
|
|
|
|
|
const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
|
|
|
|
|
if (ret == XML_ERROR_NONE) {
|
|
|
|
|
// if we consumed nothing, remember what we had on this parse attempt.
|
|
|
|
|
if (*endPtr == start) {
|
|
|
|
|
parser->m_partialTokenBytesBefore = have_now;
|
|
|
|
|
} else {
|
|
|
|
|
parser->m_partialTokenBytesBefore = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XML_Bool /* only valid for root parser */
|
|
|
|
|
startParsing(XML_Parser parser) {
|
|
|
|
|
/* hash functions must be initialized before setContext() is called */
|
|
|
|
@@ -1066,6 +1159,14 @@ parserCreate(const XML_Char *encodingName,
|
|
|
|
|
parserInit(parser, encodingName);
|
|
|
|
|
|
|
|
|
|
if (encodingName && ! parser->m_protocolEncodingName) {
|
|
|
|
|
if (dtd) {
|
|
|
|
|
// We need to stop the upcoming call to XML_ParserFree from happily
|
|
|
|
|
// destroying parser->m_dtd because the DTD is shared with the parent
|
|
|
|
|
// parser and the only guard that keeps XML_ParserFree from destroying
|
|
|
|
|
// parser->m_dtd is parser->m_isParamEntity but it will be set to
|
|
|
|
|
// XML_TRUE only later in XML_ExternalEntityParserCreate (or not at all).
|
|
|
|
|
parser->m_dtd = NULL;
|
|
|
|
|
}
|
|
|
|
|
XML_ParserFree(parser);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@@ -1118,6 +1219,9 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
|
|
|
|
|
parser->m_bufferEnd = parser->m_buffer;
|
|
|
|
|
parser->m_parseEndByteIndex = 0;
|
|
|
|
|
parser->m_parseEndPtr = NULL;
|
|
|
|
|
parser->m_partialTokenBytesBefore = 0;
|
|
|
|
|
parser->m_reparseDeferralEnabled = g_reparseDeferralEnabledDefault;
|
|
|
|
|
parser->m_lastBufferRequestSize = 0;
|
|
|
|
|
parser->m_declElementType = NULL;
|
|
|
|
|
parser->m_declAttributeId = NULL;
|
|
|
|
|
parser->m_declEntity = NULL;
|
|
|
|
@@ -1152,7 +1256,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
|
|
|
|
|
#endif
|
|
|
|
|
parser->m_hash_secret_salt = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
memset(&parser->m_accounting, 0, sizeof(ACCOUNTING));
|
|
|
|
|
parser->m_accounting.debugLevel = getDebugLevel("EXPAT_ACCOUNTING_DEBUG", 0u);
|
|
|
|
|
parser->m_accounting.maximumAmplificationFactor
|
|
|
|
@@ -1287,6 +1391,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
|
|
|
|
|
to worry which hash secrets each table has.
|
|
|
|
|
*/
|
|
|
|
|
unsigned long oldhash_secret_salt;
|
|
|
|
|
XML_Bool oldReparseDeferralEnabled;
|
|
|
|
|
|
|
|
|
|
/* Validate the oldParser parameter before we pull everything out of it */
|
|
|
|
|
if (oldParser == NULL)
|
|
|
|
@@ -1331,6 +1436,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
|
|
|
|
|
to worry which hash secrets each table has.
|
|
|
|
|
*/
|
|
|
|
|
oldhash_secret_salt = parser->m_hash_secret_salt;
|
|
|
|
|
oldReparseDeferralEnabled = parser->m_reparseDeferralEnabled;
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
if (! context)
|
|
|
|
@@ -1383,6 +1489,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
|
|
|
|
|
parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
|
|
|
|
|
parser->m_ns_triplets = oldns_triplets;
|
|
|
|
|
parser->m_hash_secret_salt = oldhash_secret_salt;
|
|
|
|
|
parser->m_reparseDeferralEnabled = oldReparseDeferralEnabled;
|
|
|
|
|
parser->m_parentParser = oldParser;
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
parser->m_paramEntityParsing = oldParamEntityParsing;
|
|
|
|
@@ -1837,55 +1944,8 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
|
|
|
|
|
parser->m_parsingStatus.parsing = XML_PARSING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
|
|
|
|
|
if (! isFinal)
|
|
|
|
|
return XML_STATUS_OK;
|
|
|
|
|
parser->m_positionPtr = parser->m_bufferPtr;
|
|
|
|
|
parser->m_parseEndPtr = parser->m_bufferEnd;
|
|
|
|
|
|
|
|
|
|
/* If data are left over from last buffer, and we now know that these
|
|
|
|
|
data are the final chunk of input, then we have to check them again
|
|
|
|
|
to detect errors based on that fact.
|
|
|
|
|
*/
|
|
|
|
|
parser->m_errorCode
|
|
|
|
|
= parser->m_processor(parser, parser->m_bufferPtr,
|
|
|
|
|
parser->m_parseEndPtr, &parser->m_bufferPtr);
|
|
|
|
|
|
|
|
|
|
if (parser->m_errorCode == XML_ERROR_NONE) {
|
|
|
|
|
switch (parser->m_parsingStatus.parsing) {
|
|
|
|
|
case XML_SUSPENDED:
|
|
|
|
|
/* It is hard to be certain, but it seems that this case
|
|
|
|
|
* cannot occur. This code is cleaning up a previous parse
|
|
|
|
|
* with no new data (since len == 0). Changing the parsing
|
|
|
|
|
* state requires getting to execute a handler function, and
|
|
|
|
|
* there doesn't seem to be an opportunity for that while in
|
|
|
|
|
* this circumstance.
|
|
|
|
|
*
|
|
|
|
|
* Given the uncertainty, we retain the code but exclude it
|
|
|
|
|
* from coverage tests.
|
|
|
|
|
*
|
|
|
|
|
* LCOV_EXCL_START
|
|
|
|
|
*/
|
|
|
|
|
XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
|
|
|
|
|
parser->m_bufferPtr, &parser->m_position);
|
|
|
|
|
parser->m_positionPtr = parser->m_bufferPtr;
|
|
|
|
|
return XML_STATUS_SUSPENDED;
|
|
|
|
|
/* LCOV_EXCL_STOP */
|
|
|
|
|
case XML_INITIALIZED:
|
|
|
|
|
case XML_PARSING:
|
|
|
|
|
parser->m_parsingStatus.parsing = XML_FINISHED;
|
|
|
|
|
/* fall through */
|
|
|
|
|
default:
|
|
|
|
|
return XML_STATUS_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
parser->m_eventEndPtr = parser->m_eventPtr;
|
|
|
|
|
parser->m_processor = errorProcessor;
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
#ifndef XML_CONTEXT_BYTES
|
|
|
|
|
else if (parser->m_bufferPtr == parser->m_bufferEnd) {
|
|
|
|
|
#if XML_CONTEXT_BYTES == 0
|
|
|
|
|
if (parser->m_bufferPtr == parser->m_bufferEnd) {
|
|
|
|
|
const char *end;
|
|
|
|
|
int nLeftOver;
|
|
|
|
|
enum XML_Status result;
|
|
|
|
@@ -1896,12 +1956,15 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
|
|
|
|
|
parser->m_processor = errorProcessor;
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
// though this isn't a buffer request, we assume that `len` is the app's
|
|
|
|
|
// preferred buffer fill size, and therefore save it here.
|
|
|
|
|
parser->m_lastBufferRequestSize = len;
|
|
|
|
|
parser->m_parseEndByteIndex += len;
|
|
|
|
|
parser->m_positionPtr = s;
|
|
|
|
|
parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
|
|
|
|
|
|
|
|
|
|
parser->m_errorCode
|
|
|
|
|
= parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
|
|
|
|
|
= callProcessor(parser, s, parser->m_parseEndPtr = s + len, &end);
|
|
|
|
|
|
|
|
|
|
if (parser->m_errorCode != XML_ERROR_NONE) {
|
|
|
|
|
parser->m_eventEndPtr = parser->m_eventPtr;
|
|
|
|
@@ -1928,23 +1991,25 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
|
|
|
|
|
&parser->m_position);
|
|
|
|
|
nLeftOver = s + len - end;
|
|
|
|
|
if (nLeftOver) {
|
|
|
|
|
if (parser->m_buffer == NULL
|
|
|
|
|
|| nLeftOver > parser->m_bufferLim - parser->m_buffer) {
|
|
|
|
|
/* avoid _signed_ integer overflow */
|
|
|
|
|
char *temp = NULL;
|
|
|
|
|
const int bytesToAllocate = (int)((unsigned)len * 2U);
|
|
|
|
|
if (bytesToAllocate > 0) {
|
|
|
|
|
temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
|
|
|
|
|
}
|
|
|
|
|
if (temp == NULL) {
|
|
|
|
|
parser->m_errorCode = XML_ERROR_NO_MEMORY;
|
|
|
|
|
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
|
|
|
|
|
parser->m_processor = errorProcessor;
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
parser->m_buffer = temp;
|
|
|
|
|
parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
|
|
|
|
|
// Back up and restore the parsing status to avoid XML_ERROR_SUSPENDED
|
|
|
|
|
// (and XML_ERROR_FINISHED) from XML_GetBuffer.
|
|
|
|
|
const enum XML_Parsing originalStatus = parser->m_parsingStatus.parsing;
|
|
|
|
|
parser->m_parsingStatus.parsing = XML_PARSING;
|
|
|
|
|
void *const temp = XML_GetBuffer(parser, nLeftOver);
|
|
|
|
|
parser->m_parsingStatus.parsing = originalStatus;
|
|
|
|
|
// GetBuffer may have overwritten this, but we want to remember what the
|
|
|
|
|
// app requested, not how many bytes were left over after parsing.
|
|
|
|
|
parser->m_lastBufferRequestSize = len;
|
|
|
|
|
if (temp == NULL) {
|
|
|
|
|
// NOTE: parser->m_errorCode has already been set by XML_GetBuffer().
|
|
|
|
|
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
|
|
|
|
|
parser->m_processor = errorProcessor;
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
}
|
|
|
|
|
// Since we know that the buffer was empty and XML_CONTEXT_BYTES is 0, we
|
|
|
|
|
// don't have any data to preserve, and can copy straight into the start
|
|
|
|
|
// of the buffer rather than the GetBuffer return pointer (which may be
|
|
|
|
|
// pointing further into the allocated buffer).
|
|
|
|
|
memcpy(parser->m_buffer, end, nLeftOver);
|
|
|
|
|
}
|
|
|
|
|
parser->m_bufferPtr = parser->m_buffer;
|
|
|
|
@@ -1955,16 +2020,15 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
|
|
|
|
|
parser->m_eventEndPtr = parser->m_bufferPtr;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
|
|
|
else {
|
|
|
|
|
void *buff = XML_GetBuffer(parser, len);
|
|
|
|
|
if (buff == NULL)
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
else {
|
|
|
|
|
memcpy(buff, s, len);
|
|
|
|
|
return XML_ParseBuffer(parser, len, isFinal);
|
|
|
|
|
}
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES == 0 */
|
|
|
|
|
void *buff = XML_GetBuffer(parser, len);
|
|
|
|
|
if (buff == NULL)
|
|
|
|
|
return XML_STATUS_ERROR;
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
assert(s != NULL); // make sure s==NULL && len!=0 was rejected above
|
|
|
|
|
memcpy(buff, s, len);
|
|
|
|
|
}
|
|
|
|
|
return XML_ParseBuffer(parser, len, isFinal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum XML_Status XMLCALL
|
|
|
|
@@ -2004,8 +2068,8 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
|
|
|
|
|
parser->m_parseEndByteIndex += len;
|
|
|
|
|
parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
|
|
|
|
|
|
|
|
|
|
parser->m_errorCode = parser->m_processor(
|
|
|
|
|
parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
|
|
|
|
|
parser->m_errorCode = callProcessor(parser, start, parser->m_parseEndPtr,
|
|
|
|
|
&parser->m_bufferPtr);
|
|
|
|
|
|
|
|
|
|
if (parser->m_errorCode != XML_ERROR_NONE) {
|
|
|
|
|
parser->m_eventEndPtr = parser->m_eventPtr;
|
|
|
|
@@ -2050,10 +2114,14 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
default:;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
// whether or not the request succeeds, `len` seems to be the app's preferred
|
|
|
|
|
// buffer fill size; remember it.
|
|
|
|
|
parser->m_lastBufferRequestSize = len;
|
|
|
|
|
if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
|
|
|
|
|
|| parser->m_buffer == NULL) {
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
int keep;
|
|
|
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES > 0 */
|
|
|
|
|
/* Do not invoke signed arithmetic overflow: */
|
|
|
|
|
int neededSize = (int)((unsigned)len
|
|
|
|
|
+ (unsigned)EXPAT_SAFE_PTR_DIFF(
|
|
|
|
@@ -2062,7 +2130,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
parser->m_errorCode = XML_ERROR_NO_MEMORY;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
|
|
|
|
|
if (keep > XML_CONTEXT_BYTES)
|
|
|
|
|
keep = XML_CONTEXT_BYTES;
|
|
|
|
@@ -2072,10 +2140,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
neededSize += keep;
|
|
|
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
|
|
|
if (neededSize
|
|
|
|
|
<= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES > 0 */
|
|
|
|
|
if (parser->m_buffer && parser->m_bufferPtr
|
|
|
|
|
&& neededSize
|
|
|
|
|
<= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
|
|
|
|
|
int offset
|
|
|
|
|
= (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
|
|
|
|
@@ -2088,19 +2157,17 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
parser->m_bufferPtr -= offset;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (parser->m_buffer && parser->m_bufferPtr) {
|
|
|
|
|
memmove(parser->m_buffer, parser->m_bufferPtr,
|
|
|
|
|
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
|
|
|
|
|
parser->m_bufferEnd
|
|
|
|
|
= parser->m_buffer
|
|
|
|
|
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
|
|
|
|
|
parser->m_bufferPtr = parser->m_buffer;
|
|
|
|
|
}
|
|
|
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
|
|
|
memmove(parser->m_buffer, parser->m_bufferPtr,
|
|
|
|
|
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
|
|
|
|
|
parser->m_bufferEnd
|
|
|
|
|
= parser->m_buffer
|
|
|
|
|
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
|
|
|
|
|
parser->m_bufferPtr = parser->m_buffer;
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES > 0 */
|
|
|
|
|
} else {
|
|
|
|
|
char *newBuf;
|
|
|
|
|
int bufferSize
|
|
|
|
|
= (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
|
|
|
|
|
= (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
|
|
|
|
|
if (bufferSize == 0)
|
|
|
|
|
bufferSize = INIT_BUFFER_SIZE;
|
|
|
|
|
do {
|
|
|
|
@@ -2117,7 +2184,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
parser->m_bufferLim = newBuf + bufferSize;
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
if (parser->m_bufferPtr) {
|
|
|
|
|
memcpy(newBuf, &parser->m_bufferPtr[-keep],
|
|
|
|
|
EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
|
|
|
|
@@ -2147,7 +2214,7 @@ XML_GetBuffer(XML_Parser parser, int len) {
|
|
|
|
|
parser->m_bufferEnd = newBuf;
|
|
|
|
|
}
|
|
|
|
|
parser->m_bufferPtr = parser->m_buffer = newBuf;
|
|
|
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES > 0 */
|
|
|
|
|
}
|
|
|
|
|
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
|
|
|
|
|
parser->m_positionPtr = NULL;
|
|
|
|
@@ -2197,7 +2264,7 @@ XML_ResumeParser(XML_Parser parser) {
|
|
|
|
|
}
|
|
|
|
|
parser->m_parsingStatus.parsing = XML_PARSING;
|
|
|
|
|
|
|
|
|
|
parser->m_errorCode = parser->m_processor(
|
|
|
|
|
parser->m_errorCode = callProcessor(
|
|
|
|
|
parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
|
|
|
|
|
|
|
|
|
|
if (parser->m_errorCode != XML_ERROR_NONE) {
|
|
|
|
@@ -2261,7 +2328,7 @@ XML_GetCurrentByteCount(XML_Parser parser) {
|
|
|
|
|
|
|
|
|
|
const char *XMLCALL
|
|
|
|
|
XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
if (parser == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (parser->m_eventPtr && parser->m_buffer) {
|
|
|
|
@@ -2275,7 +2342,7 @@ XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
|
|
|
|
|
(void)parser;
|
|
|
|
|
(void)offset;
|
|
|
|
|
(void)size;
|
|
|
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
|
|
|
#endif /* XML_CONTEXT_BYTES > 0 */
|
|
|
|
|
return (const char *)0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -2495,7 +2562,7 @@ XML_GetFeatureList(void) {
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
{XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_CONTEXT_BYTES
|
|
|
|
|
#if XML_CONTEXT_BYTES > 0
|
|
|
|
|
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
|
|
|
|
|
XML_CONTEXT_BYTES},
|
|
|
|
|
#endif
|
|
|
|
@@ -2511,8 +2578,9 @@ XML_GetFeatureList(void) {
|
|
|
|
|
#ifdef XML_ATTR_INFO
|
|
|
|
|
{XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
/* Added in Expat 2.4.0. */
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
/* Added in Expat 2.4.0 for XML_DTD defined and
|
|
|
|
|
* added in Expat 2.6.0 for XML_GE == 1. */
|
|
|
|
|
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_MAXIMUM_AMPLIFICATION_DEFAULT,
|
|
|
|
|
XML_L("XML_BLAP_MAX_AMP"),
|
|
|
|
|
(long int)
|
|
|
|
@@ -2520,13 +2588,15 @@ XML_GetFeatureList(void) {
|
|
|
|
|
{XML_FEATURE_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT,
|
|
|
|
|
XML_L("XML_BLAP_ACT_THRES"),
|
|
|
|
|
EXPAT_BILLION_LAUGHS_ATTACK_PROTECTION_ACTIVATION_THRESHOLD_DEFAULT},
|
|
|
|
|
/* Added in Expat 2.6.0. */
|
|
|
|
|
{XML_FEATURE_GE, XML_L("XML_GE"), 0},
|
|
|
|
|
#endif
|
|
|
|
|
{XML_FEATURE_END, NULL, 0}};
|
|
|
|
|
|
|
|
|
|
return features;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
XML_Bool XMLCALL
|
|
|
|
|
XML_SetBillionLaughsAttackProtectionMaximumAmplification(
|
|
|
|
|
XML_Parser parser, float maximumAmplificationFactor) {
|
|
|
|
@@ -2548,7 +2618,16 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
|
|
|
|
|
parser->m_accounting.activationThresholdBytes = activationThresholdBytes;
|
|
|
|
|
return XML_TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
|
|
|
|
|
XML_Bool XMLCALL
|
|
|
|
|
XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled) {
|
|
|
|
|
if (parser != NULL && (enabled == XML_TRUE || enabled == XML_FALSE)) {
|
|
|
|
|
parser->m_reparseDeferralEnabled = enabled;
|
|
|
|
|
return XML_TRUE;
|
|
|
|
|
}
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initially tag->rawName always points into the parse buffer;
|
|
|
|
|
for those TAG instances opened while the current parse buffer was
|
|
|
|
@@ -2570,7 +2649,7 @@ storeRawNames(XML_Parser parser) {
|
|
|
|
|
*/
|
|
|
|
|
if (tag->rawName == rawNameBuf)
|
|
|
|
|
break;
|
|
|
|
|
/* For re-use purposes we need to ensure that the
|
|
|
|
|
/* For reuse purposes we need to ensure that the
|
|
|
|
|
size of tag->buf is a multiple of sizeof(XML_Char).
|
|
|
|
|
*/
|
|
|
|
|
rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
|
|
|
|
@@ -2634,13 +2713,13 @@ externalEntityInitProcessor2(XML_Parser parser, const char *start,
|
|
|
|
|
int tok = XmlContentTok(parser->m_encoding, start, end, &next);
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case XML_TOK_BOM:
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, start, next, __LINE__,
|
|
|
|
|
XML_ACCOUNT_DIRECT)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
|
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
|
|
|
|
|
}
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
|
|
|
|
|
/* If we are at the end of the buffer, this would cause the next stage,
|
|
|
|
|
i.e. externalEntityInitProcessor3, to pass control directly to
|
|
|
|
@@ -2754,7 +2833,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
for (;;) {
|
|
|
|
|
const char *next = s; /* XmlContentTok doesn't always set the last arg */
|
|
|
|
|
int tok = XmlContentTok(enc, s, end, &next);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
const char *accountAfter
|
|
|
|
|
= ((tok == XML_TOK_TRAILING_RSQB) || (tok == XML_TOK_TRAILING_CR))
|
|
|
|
|
? (haveMore ? s /* i.e. 0 bytes */ : end)
|
|
|
|
@@ -2820,14 +2899,14 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
|
|
|
|
|
enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
|
|
|
|
|
if (ch) {
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
/* NOTE: We are replacing 4-6 characters original input for 1 character
|
|
|
|
|
* so there is no amplification and hence recording without
|
|
|
|
|
* protection. */
|
|
|
|
|
accountingDiffTolerated(parser, tok, (char *)&ch,
|
|
|
|
|
((char *)&ch) + sizeof(XML_Char), __LINE__,
|
|
|
|
|
XML_ACCOUNT_ENTITY_EXPANSION);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
if (parser->m_characterDataHandler)
|
|
|
|
|
parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
|
|
|
|
|
else if (parser->m_defaultHandler)
|
|
|
|
@@ -3009,9 +3088,6 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
int len;
|
|
|
|
|
const char *rawName;
|
|
|
|
|
TAG *tag = parser->m_tagStack;
|
|
|
|
|
parser->m_tagStack = tag->parent;
|
|
|
|
|
tag->parent = parser->m_freeTagList;
|
|
|
|
|
parser->m_freeTagList = tag;
|
|
|
|
|
rawName = s + enc->minBytesPerChar * 2;
|
|
|
|
|
len = XmlNameLength(enc, rawName);
|
|
|
|
|
if (len != tag->rawNameLength
|
|
|
|
@@ -3019,6 +3095,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
*eventPP = rawName;
|
|
|
|
|
return XML_ERROR_TAG_MISMATCH;
|
|
|
|
|
}
|
|
|
|
|
parser->m_tagStack = tag->parent;
|
|
|
|
|
tag->parent = parser->m_freeTagList;
|
|
|
|
|
parser->m_freeTagList = tag;
|
|
|
|
|
--parser->m_tagLevel;
|
|
|
|
|
if (parser->m_endElementHandler) {
|
|
|
|
|
const XML_Char *localPart;
|
|
|
|
@@ -3028,13 +3107,13 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
if (parser->m_ns && localPart) {
|
|
|
|
|
/* localPart and prefix may have been overwritten in
|
|
|
|
|
tag->name.str, since this points to the binding->uri
|
|
|
|
|
buffer which gets re-used; so we have to add them again
|
|
|
|
|
buffer which gets reused; so we have to add them again
|
|
|
|
|
*/
|
|
|
|
|
uri = (XML_Char *)tag->name.str + tag->name.uriLen;
|
|
|
|
|
/* don't need to check for space - already done in storeAtts() */
|
|
|
|
|
while (*localPart)
|
|
|
|
|
*uri++ = *localPart++;
|
|
|
|
|
prefix = (XML_Char *)tag->name.prefix;
|
|
|
|
|
prefix = tag->name.prefix;
|
|
|
|
|
if (parser->m_ns_triplets && prefix) {
|
|
|
|
|
*uri++ = parser->m_namespaceSeparator;
|
|
|
|
|
while (*prefix)
|
|
|
|
@@ -3101,7 +3180,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
However, now we have a start/endCdataSectionHandler, so it seems
|
|
|
|
|
easier to let the user deal with this.
|
|
|
|
|
*/
|
|
|
|
|
else if (0 && parser->m_characterDataHandler)
|
|
|
|
|
else if ((0) && parser->m_characterDataHandler)
|
|
|
|
|
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
|
|
|
|
|
0);
|
|
|
|
|
/* END disabled code */
|
|
|
|
@@ -3130,8 +3209,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
|
|
|
|
|
} else
|
|
|
|
|
parser->m_characterDataHandler(
|
|
|
|
|
parser->m_handlerArg, (XML_Char *)s,
|
|
|
|
|
(int)((XML_Char *)end - (XML_Char *)s));
|
|
|
|
|
parser->m_handlerArg, (const XML_Char *)s,
|
|
|
|
|
(int)((const XML_Char *)end - (const XML_Char *)s));
|
|
|
|
|
} else if (parser->m_defaultHandler)
|
|
|
|
|
reportDefault(parser, enc, s, end);
|
|
|
|
|
/* We are at the end of the final buffer, should we check for
|
|
|
|
@@ -3164,8 +3243,8 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
|
|
|
*eventPP = s;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
charDataHandler(parser->m_handlerArg, (XML_Char *)s,
|
|
|
|
|
(int)((XML_Char *)next - (XML_Char *)s));
|
|
|
|
|
charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
|
|
|
|
|
(int)((const XML_Char *)next - (const XML_Char *)s));
|
|
|
|
|
} else if (parser->m_defaultHandler)
|
|
|
|
|
reportDefault(parser, enc, s, next);
|
|
|
|
|
} break;
|
|
|
|
@@ -3704,12 +3783,124 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static XML_Bool
|
|
|
|
|
is_rfc3986_uri_char(XML_Char candidate) {
|
|
|
|
|
// For the RFC 3986 ANBF grammar see
|
|
|
|
|
// https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
|
|
|
|
|
|
|
|
|
|
switch (candidate) {
|
|
|
|
|
// From rule "ALPHA" (uppercase half)
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'B':
|
|
|
|
|
case 'C':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'F':
|
|
|
|
|
case 'G':
|
|
|
|
|
case 'H':
|
|
|
|
|
case 'I':
|
|
|
|
|
case 'J':
|
|
|
|
|
case 'K':
|
|
|
|
|
case 'L':
|
|
|
|
|
case 'M':
|
|
|
|
|
case 'N':
|
|
|
|
|
case 'O':
|
|
|
|
|
case 'P':
|
|
|
|
|
case 'Q':
|
|
|
|
|
case 'R':
|
|
|
|
|
case 'S':
|
|
|
|
|
case 'T':
|
|
|
|
|
case 'U':
|
|
|
|
|
case 'V':
|
|
|
|
|
case 'W':
|
|
|
|
|
case 'X':
|
|
|
|
|
case 'Y':
|
|
|
|
|
case 'Z':
|
|
|
|
|
|
|
|
|
|
// From rule "ALPHA" (lowercase half)
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'b':
|
|
|
|
|
case 'c':
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'i':
|
|
|
|
|
case 'j':
|
|
|
|
|
case 'k':
|
|
|
|
|
case 'l':
|
|
|
|
|
case 'm':
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'o':
|
|
|
|
|
case 'p':
|
|
|
|
|
case 'q':
|
|
|
|
|
case 'r':
|
|
|
|
|
case 's':
|
|
|
|
|
case 't':
|
|
|
|
|
case 'u':
|
|
|
|
|
case 'v':
|
|
|
|
|
case 'w':
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'y':
|
|
|
|
|
case 'z':
|
|
|
|
|
|
|
|
|
|
// From rule "DIGIT"
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
|
|
|
|
|
// From rule "pct-encoded"
|
|
|
|
|
case '%':
|
|
|
|
|
|
|
|
|
|
// From rule "unreserved"
|
|
|
|
|
case '-':
|
|
|
|
|
case '.':
|
|
|
|
|
case '_':
|
|
|
|
|
case '~':
|
|
|
|
|
|
|
|
|
|
// From rule "gen-delims"
|
|
|
|
|
case ':':
|
|
|
|
|
case '/':
|
|
|
|
|
case '?':
|
|
|
|
|
case '#':
|
|
|
|
|
case '[':
|
|
|
|
|
case ']':
|
|
|
|
|
case '@':
|
|
|
|
|
|
|
|
|
|
// From rule "sub-delims"
|
|
|
|
|
case '!':
|
|
|
|
|
case '$':
|
|
|
|
|
case '&':
|
|
|
|
|
case '\'':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '*':
|
|
|
|
|
case '+':
|
|
|
|
|
case ',':
|
|
|
|
|
case ';':
|
|
|
|
|
case '=':
|
|
|
|
|
return XML_TRUE;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* addBinding() overwrites the value of prefix->binding without checking.
|
|
|
|
|
Therefore one must keep track of the old value outside of addBinding().
|
|
|
|
|
*/
|
|
|
|
|
static enum XML_Error
|
|
|
|
|
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
const XML_Char *uri, BINDING **bindingsPtr) {
|
|
|
|
|
// "http://www.w3.org/XML/1998/namespace"
|
|
|
|
|
static const XML_Char xmlNamespace[]
|
|
|
|
|
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON,
|
|
|
|
|
ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
|
|
|
|
@@ -3720,6 +3911,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
|
|
|
|
|
ASCII_e, '\0'};
|
|
|
|
|
static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
|
|
|
|
|
// "http://www.w3.org/2000/xmlns/"
|
|
|
|
|
static const XML_Char xmlnsNamespace[]
|
|
|
|
|
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
|
|
|
|
|
ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
|
|
|
|
@@ -3760,14 +3952,26 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
|
|
|
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
|
|
|
|
|
isXMLNS = XML_FALSE;
|
|
|
|
|
|
|
|
|
|
// NOTE: While Expat does not validate namespace URIs against RFC 3986,
|
|
|
|
|
// we have to at least make sure that the XML processor on top of
|
|
|
|
|
// Expat (that is splitting tag names by namespace separator into
|
|
|
|
|
// 2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused
|
|
|
|
|
// by an attacker putting additional namespace separator characters
|
|
|
|
|
// into namespace declarations. That would be ambiguous and not to
|
|
|
|
|
// be expected.
|
|
|
|
|
if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) {
|
|
|
|
|
// NOTE: While Expat does not validate namespace URIs against RFC 3986
|
|
|
|
|
// today (and is not REQUIRED to do so with regard to the XML 1.0
|
|
|
|
|
// namespaces specification) we have to at least make sure, that
|
|
|
|
|
// the application on top of Expat (that is likely splitting expanded
|
|
|
|
|
// element names ("qualified names") of form
|
|
|
|
|
// "[uri sep] local [sep prefix] '\0'" back into 1, 2 or 3 pieces
|
|
|
|
|
// in its element handler code) cannot be confused by an attacker
|
|
|
|
|
// putting additional namespace separator characters into namespace
|
|
|
|
|
// declarations. That would be ambiguous and not to be expected.
|
|
|
|
|
//
|
|
|
|
|
// While the HTML API docs of function XML_ParserCreateNS have been
|
|
|
|
|
// advising against use of a namespace separator character that can
|
|
|
|
|
// appear in a URI for >20 years now, some widespread applications
|
|
|
|
|
// are using URI characters (':' (colon) in particular) for a
|
|
|
|
|
// namespace separator, in practice. To keep these applications
|
|
|
|
|
// functional, we only reject namespaces URIs containing the
|
|
|
|
|
// application-chosen namespace separator if the chosen separator
|
|
|
|
|
// is a non-URI character with regard to RFC 3986.
|
|
|
|
|
if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)
|
|
|
|
|
&& ! is_rfc3986_uri_char(uri[len])) {
|
|
|
|
|
return XML_ERROR_SYNTAX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -3904,7 +4108,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
|
|
|
|
for (;;) {
|
|
|
|
|
const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
|
|
|
|
|
int tok = XmlCdataSectionTok(enc, s, end, &next);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
|
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
|
|
|
|
@@ -3919,7 +4123,7 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
|
|
|
|
parser->m_endCdataSectionHandler(parser->m_handlerArg);
|
|
|
|
|
/* BEGIN disabled code */
|
|
|
|
|
/* see comment under XML_TOK_CDATA_SECT_OPEN */
|
|
|
|
|
else if (0 && parser->m_characterDataHandler)
|
|
|
|
|
else if ((0) && parser->m_characterDataHandler)
|
|
|
|
|
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
|
|
|
|
|
0);
|
|
|
|
|
/* END disabled code */
|
|
|
|
@@ -3955,8 +4159,8 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
|
|
|
|
*eventPP = s;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
charDataHandler(parser->m_handlerArg, (XML_Char *)s,
|
|
|
|
|
(int)((XML_Char *)next - (XML_Char *)s));
|
|
|
|
|
charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
|
|
|
|
|
(int)((const XML_Char *)next - (const XML_Char *)s));
|
|
|
|
|
} else if (parser->m_defaultHandler)
|
|
|
|
|
reportDefault(parser, enc, s, next);
|
|
|
|
|
} break;
|
|
|
|
@@ -4056,7 +4260,7 @@ doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
|
|
|
|
|
*eventPP = s;
|
|
|
|
|
*startPtr = NULL;
|
|
|
|
|
tok = XmlIgnoreSectionTok(enc, s, end, &next);
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
# if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
|
|
|
|
|
XML_ACCOUNT_DIRECT)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
@@ -4144,11 +4348,11 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
|
|
|
|
|
const XML_Char *storedEncName = NULL;
|
|
|
|
|
const ENCODING *newEncoding = NULL;
|
|
|
|
|
const char *version = NULL;
|
|
|
|
|
const char *versionend;
|
|
|
|
|
const char *versionend = NULL;
|
|
|
|
|
const XML_Char *storedversion = NULL;
|
|
|
|
|
int standalone = -1;
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, XML_TOK_XML_DECL, s, next, __LINE__,
|
|
|
|
|
XML_ACCOUNT_DIRECT)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
@@ -4346,16 +4550,16 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
|
parser->m_processor = entityValueProcessor;
|
|
|
|
|
return entityValueProcessor(parser, next, end, nextPtr);
|
|
|
|
|
}
|
|
|
|
|
/* If we are at the end of the buffer, this would cause XmlPrologTok to
|
|
|
|
|
return XML_TOK_NONE on the next call, which would then cause the
|
|
|
|
|
function to exit with *nextPtr set to s - that is what we want for other
|
|
|
|
|
tokens, but not for the BOM - we would rather like to skip it;
|
|
|
|
|
then, when this routine is entered the next time, XmlPrologTok will
|
|
|
|
|
return XML_TOK_INVALID, since the BOM is still in the buffer
|
|
|
|
|
/* XmlPrologTok has now set the encoding based on the BOM it found, and we
|
|
|
|
|
must move s and nextPtr forward to consume the BOM.
|
|
|
|
|
|
|
|
|
|
If we didn't, and got XML_TOK_NONE from the next XmlPrologTok call, we
|
|
|
|
|
would leave the BOM in the buffer and return. On the next call to this
|
|
|
|
|
function, our XmlPrologTok call would return XML_TOK_INVALID, since it
|
|
|
|
|
is not valid to have multiple BOMs.
|
|
|
|
|
*/
|
|
|
|
|
else if (tok == XML_TOK_BOM && next == end
|
|
|
|
|
&& ! parser->m_parsingStatus.finalBuffer) {
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
else if (tok == XML_TOK_BOM) {
|
|
|
|
|
# if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
|
|
|
|
|
XML_ACCOUNT_DIRECT)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
@@ -4364,7 +4568,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
*nextPtr = next;
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
s = next;
|
|
|
|
|
}
|
|
|
|
|
/* If we get this token, we have the start of what might be a
|
|
|
|
|
normal tag, but not a declaration (i.e. it doesn't begin with
|
|
|
|
@@ -4571,11 +4775,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
switch (role) {
|
|
|
|
|
case XML_ROLE_INSTANCE_START: // bytes accounted in contentProcessor
|
|
|
|
|
case XML_ROLE_XML_DECL: // bytes accounted in processXmlDecl
|
|
|
|
|
case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
case XML_ROLE_TEXT_DECL: // bytes accounted in processXmlDecl
|
|
|
|
|
# endif
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__, account)) {
|
|
|
|
@@ -4848,10 +5054,10 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
parser->m_handlerArg, parser->m_declElementType->name,
|
|
|
|
|
parser->m_declAttributeId->name, parser->m_declAttributeType, 0,
|
|
|
|
|
role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
|
|
|
|
|
poolClear(&parser->m_tempPool);
|
|
|
|
|
handleDefault = XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
poolClear(&parser->m_tempPool);
|
|
|
|
|
break;
|
|
|
|
|
case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
|
|
|
|
|
case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
|
|
|
|
@@ -4893,6 +5099,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
break;
|
|
|
|
|
case XML_ROLE_ENTITY_VALUE:
|
|
|
|
|
if (dtd->keepProcessing) {
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
// This will store the given replacement text in
|
|
|
|
|
// parser->m_declEntity->textPtr.
|
|
|
|
|
enum XML_Error result
|
|
|
|
|
= storeEntityValue(parser, enc, s + enc->minBytesPerChar,
|
|
|
|
|
next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
|
|
|
|
@@ -4913,6 +5122,25 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
poolDiscard(&dtd->entityValuePool);
|
|
|
|
|
if (result != XML_ERROR_NONE)
|
|
|
|
|
return result;
|
|
|
|
|
#else
|
|
|
|
|
// This will store "&entity123;" in parser->m_declEntity->textPtr
|
|
|
|
|
// to end up as "&entity123;" in the handler.
|
|
|
|
|
if (parser->m_declEntity != NULL) {
|
|
|
|
|
const enum XML_Error result
|
|
|
|
|
= storeSelfEntityValue(parser, parser->m_declEntity);
|
|
|
|
|
if (result != XML_ERROR_NONE)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
if (parser->m_entityDeclHandler) {
|
|
|
|
|
*eventEndPP = s;
|
|
|
|
|
parser->m_entityDeclHandler(
|
|
|
|
|
parser->m_handlerArg, parser->m_declEntity->name,
|
|
|
|
|
parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
|
|
|
|
|
parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
|
|
|
|
|
handleDefault = XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XML_ROLE_DOCTYPE_SYSTEM_ID:
|
|
|
|
@@ -4971,6 +5199,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case XML_ROLE_ENTITY_COMPLETE:
|
|
|
|
|
#if XML_GE == 0
|
|
|
|
|
// This will store "&entity123;" in entity->textPtr
|
|
|
|
|
// to end up as "&entity123;" in the handler.
|
|
|
|
|
if (parser->m_declEntity != NULL) {
|
|
|
|
|
const enum XML_Error result
|
|
|
|
|
= storeSelfEntityValue(parser, parser->m_declEntity);
|
|
|
|
|
if (result != XML_ERROR_NONE)
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (dtd->keepProcessing && parser->m_declEntity
|
|
|
|
|
&& parser->m_entityDeclHandler) {
|
|
|
|
|
*eventEndPP = s;
|
|
|
|
@@ -5259,7 +5497,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
|
|
|
|
*
|
|
|
|
|
* If 'standalone' is false, the DTD must have no
|
|
|
|
|
* parameter entities or we wouldn't have passed the outer
|
|
|
|
|
* 'if' statement. That measn the only entity in the hash
|
|
|
|
|
* 'if' statement. That means the only entity in the hash
|
|
|
|
|
* table is the external subset name "#" which cannot be
|
|
|
|
|
* given as a parameter entity name in XML syntax, so the
|
|
|
|
|
* lookup must have returned NULL and we don't even reach
|
|
|
|
@@ -5512,7 +5750,7 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
|
for (;;) {
|
|
|
|
|
const char *next = NULL;
|
|
|
|
|
int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, s, next, __LINE__,
|
|
|
|
|
XML_ACCOUNT_DIRECT)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
@@ -5592,7 +5830,7 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
entity->open = XML_TRUE;
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
entityTrackingOnOpen(parser, entity, __LINE__);
|
|
|
|
|
#endif
|
|
|
|
|
entity->processed = 0;
|
|
|
|
@@ -5625,10 +5863,10 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
|
|
|
|
|
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
|
|
|
|
entity->processed = (int)(next - textStart);
|
|
|
|
|
parser->m_processor = internalEntityProcessor;
|
|
|
|
|
} else {
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
} else if (parser->m_openInternalEntities->entity == entity) {
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
entity->open = XML_FALSE;
|
|
|
|
|
parser->m_openInternalEntities = openEntity->next;
|
|
|
|
|
/* put openEntity back in list of free instances */
|
|
|
|
@@ -5671,19 +5909,27 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
|
|
|
|
|
|
if (result != XML_ERROR_NONE)
|
|
|
|
|
return result;
|
|
|
|
|
else if (textEnd != next
|
|
|
|
|
&& parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
|
|
|
|
|
|
|
|
|
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
|
|
|
|
entity->processed = (int)(next - (const char *)entity->textPtr);
|
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
|
|
|
#endif
|
|
|
|
|
entity->open = XML_FALSE;
|
|
|
|
|
parser->m_openInternalEntities = openEntity->next;
|
|
|
|
|
/* put openEntity back in list of free instances */
|
|
|
|
|
openEntity->next = parser->m_freeInternalEntities;
|
|
|
|
|
parser->m_freeInternalEntities = openEntity;
|
|
|
|
|
entity->open = XML_FALSE;
|
|
|
|
|
parser->m_openInternalEntities = openEntity->next;
|
|
|
|
|
/* put openEntity back in list of free instances */
|
|
|
|
|
openEntity->next = parser->m_freeInternalEntities;
|
|
|
|
|
parser->m_freeInternalEntities = openEntity;
|
|
|
|
|
|
|
|
|
|
// If there are more open entities we want to stop right here and have the
|
|
|
|
|
// upcoming call to XML_ResumeParser continue with entity content, or it would
|
|
|
|
|
// be ignored altogether.
|
|
|
|
|
if (parser->m_openInternalEntities != NULL
|
|
|
|
|
&& parser->m_parsingStatus.parsing == XML_SUSPENDED) {
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
@@ -5699,10 +5945,15 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
|
|
|
|
{
|
|
|
|
|
parser->m_processor = contentProcessor;
|
|
|
|
|
/* see externalEntityContentProcessor vs contentProcessor */
|
|
|
|
|
return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
|
|
|
|
|
s, end, nextPtr,
|
|
|
|
|
(XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
|
|
|
|
XML_ACCOUNT_DIRECT);
|
|
|
|
|
result = doContent(parser, parser->m_parentParser ? 1 : 0,
|
|
|
|
|
parser->m_encoding, s, end, nextPtr,
|
|
|
|
|
(XML_Bool)! parser->m_parsingStatus.finalBuffer,
|
|
|
|
|
XML_ACCOUNT_DIRECT);
|
|
|
|
|
if (result == XML_ERROR_NONE) {
|
|
|
|
|
if (! storeRawNames(parser))
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -5743,7 +5994,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
|
|
|
const char *next
|
|
|
|
|
= ptr; /* XmlAttributeValueTok doesn't always set the last arg */
|
|
|
|
|
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, ptr, next, __LINE__, account)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
|
return XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
|
|
|
|
@@ -5808,14 +6059,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
|
|
|
XML_Char ch = (XML_Char)XmlPredefinedEntityName(
|
|
|
|
|
enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
|
|
|
|
|
if (ch) {
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
/* NOTE: We are replacing 4-6 characters original input for 1 character
|
|
|
|
|
* so there is no amplification and hence recording without
|
|
|
|
|
* protection. */
|
|
|
|
|
accountingDiffTolerated(parser, tok, (char *)&ch,
|
|
|
|
|
((char *)&ch) + sizeof(XML_Char), __LINE__,
|
|
|
|
|
XML_ACCOUNT_ENTITY_EXPANSION);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
if (! poolAppendChar(pool, ch))
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
break;
|
|
|
|
@@ -5893,14 +6144,14 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
|
|
|
enum XML_Error result;
|
|
|
|
|
const XML_Char *textEnd = entity->textPtr + entity->textLen;
|
|
|
|
|
entity->open = XML_TRUE;
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
entityTrackingOnOpen(parser, entity, __LINE__);
|
|
|
|
|
#endif
|
|
|
|
|
result = appendAttributeValue(parser, parser->m_internalEncoding,
|
|
|
|
|
isCdata, (const char *)entity->textPtr,
|
|
|
|
|
(const char *)textEnd, pool,
|
|
|
|
|
XML_ACCOUNT_ENTITY_EXPANSION);
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
entityTrackingOnClose(parser, entity, __LINE__);
|
|
|
|
|
#endif
|
|
|
|
|
entity->open = XML_FALSE;
|
|
|
|
@@ -5930,6 +6181,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
|
|
|
|
/* not reached */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
static enum XML_Error
|
|
|
|
|
storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
const char *entityTextPtr, const char *entityTextEnd,
|
|
|
|
@@ -5937,12 +6189,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
|
|
|
|
STRING_POOL *pool = &(dtd->entityValuePool);
|
|
|
|
|
enum XML_Error result = XML_ERROR_NONE;
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
int oldInEntityValue = parser->m_prologState.inEntityValue;
|
|
|
|
|
parser->m_prologState.inEntityValue = 1;
|
|
|
|
|
#else
|
|
|
|
|
# else
|
|
|
|
|
UNUSED_P(account);
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
# endif /* XML_DTD */
|
|
|
|
|
/* never return Null for the value argument in EntityDeclHandler,
|
|
|
|
|
since this would indicate an external entity; therefore we
|
|
|
|
|
have to make sure that entityValuePool.start is not null */
|
|
|
|
@@ -5956,18 +6208,16 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
= entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
|
|
|
|
|
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
if (! accountingDiffTolerated(parser, tok, entityTextPtr, next, __LINE__,
|
|
|
|
|
account)) {
|
|
|
|
|
accountingOnAbort(parser);
|
|
|
|
|
result = XML_ERROR_AMPLIFICATION_LIMIT_BREACH;
|
|
|
|
|
goto endEntityValue;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
switch (tok) {
|
|
|
|
|
case XML_TOK_PARAM_ENTITY_REF:
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
if (parser->m_isParamEntity || enc != parser->m_encoding) {
|
|
|
|
|
const XML_Char *name;
|
|
|
|
|
ENTITY *entity;
|
|
|
|
@@ -5990,7 +6240,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
dtd->keepProcessing = dtd->standalone;
|
|
|
|
|
goto endEntityValue;
|
|
|
|
|
}
|
|
|
|
|
if (entity->open) {
|
|
|
|
|
if (entity->open || (entity == parser->m_declEntity)) {
|
|
|
|
|
if (enc == parser->m_encoding)
|
|
|
|
|
parser->m_eventPtr = entityTextPtr;
|
|
|
|
|
result = XML_ERROR_RECURSIVE_ENTITY_REF;
|
|
|
|
@@ -6029,7 +6279,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
# endif /* XML_DTD */
|
|
|
|
|
/* In the internal subset, PE references are not legal
|
|
|
|
|
within markup declarations, e.g entity values in this case. */
|
|
|
|
|
parser->m_eventPtr = entityTextPtr;
|
|
|
|
@@ -6110,12 +6360,38 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
|
|
|
|
entityTextPtr = next;
|
|
|
|
|
}
|
|
|
|
|
endEntityValue:
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
# ifdef XML_DTD
|
|
|
|
|
parser->m_prologState.inEntityValue = oldInEntityValue;
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
# endif /* XML_DTD */
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* XML_GE == 0 */
|
|
|
|
|
|
|
|
|
|
static enum XML_Error
|
|
|
|
|
storeSelfEntityValue(XML_Parser parser, ENTITY *entity) {
|
|
|
|
|
// This will store "&entity123;" in entity->textPtr
|
|
|
|
|
// to end up as "&entity123;" in the handler.
|
|
|
|
|
const char *const entity_start = "&";
|
|
|
|
|
const char *const entity_end = ";";
|
|
|
|
|
|
|
|
|
|
STRING_POOL *const pool = &(parser->m_dtd->entityValuePool);
|
|
|
|
|
if (! poolAppendString(pool, entity_start)
|
|
|
|
|
|| ! poolAppendString(pool, entity->name)
|
|
|
|
|
|| ! poolAppendString(pool, entity_end)) {
|
|
|
|
|
poolDiscard(pool);
|
|
|
|
|
return XML_ERROR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entity->textPtr = poolStart(pool);
|
|
|
|
|
entity->textLen = (int)(poolLength(pool));
|
|
|
|
|
poolFinish(pool);
|
|
|
|
|
|
|
|
|
|
return XML_ERROR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* XML_GE == 0 */
|
|
|
|
|
|
|
|
|
|
static void FASTCALL
|
|
|
|
|
normalizeLines(XML_Char *s) {
|
|
|
|
|
XML_Char *p;
|
|
|
|
@@ -6226,8 +6502,9 @@ reportDefault(XML_Parser parser, const ENCODING *enc, const char *s,
|
|
|
|
|
} while ((convert_res != XML_CONVERT_COMPLETED)
|
|
|
|
|
&& (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
|
|
|
|
|
} else
|
|
|
|
|
parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s,
|
|
|
|
|
(int)((XML_Char *)end - (XML_Char *)s));
|
|
|
|
|
parser->m_defaultHandler(
|
|
|
|
|
parser->m_handlerArg, (const XML_Char *)s,
|
|
|
|
|
(int)((const XML_Char *)end - (const XML_Char *)s));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
@@ -6331,7 +6608,7 @@ getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
|
|
|
|
|
name = poolStoreString(&dtd->pool, enc, start, end);
|
|
|
|
|
if (! name)
|
|
|
|
|
return NULL;
|
|
|
|
|
/* skip quotation mark - its storage will be re-used (like in name[-1]) */
|
|
|
|
|
/* skip quotation mark - its storage will be reused (like in name[-1]) */
|
|
|
|
|
++name;
|
|
|
|
|
id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name,
|
|
|
|
|
sizeof(ATTRIBUTE_ID));
|
|
|
|
@@ -6481,6 +6758,10 @@ getContext(XML_Parser parser) {
|
|
|
|
|
|
|
|
|
|
static XML_Bool
|
|
|
|
|
setContext(XML_Parser parser, const XML_Char *context) {
|
|
|
|
|
if (context == NULL) {
|
|
|
|
|
return XML_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
|
|
|
|
|
const XML_Char *s = context;
|
|
|
|
|
|
|
|
|
@@ -7071,7 +7352,7 @@ poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
|
|
|
|
|
return NULL;
|
|
|
|
|
for (;;) {
|
|
|
|
|
const enum XML_Convert_Result convert_res = XmlConvert(
|
|
|
|
|
enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
|
|
|
|
|
enc, &ptr, end, (ICHAR **)&(pool->ptr), (const ICHAR *)pool->end);
|
|
|
|
|
if ((convert_res == XML_CONVERT_COMPLETED)
|
|
|
|
|
|| (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
|
|
|
|
|
break;
|
|
|
|
@@ -7502,10 +7783,12 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef XML_DTD
|
|
|
|
|
#if XML_GE == 1
|
|
|
|
|
|
|
|
|
|
static float
|
|
|
|
|
accountingGetCurrentAmplification(XML_Parser rootParser) {
|
|
|
|
|
// 1.........1.........12 => 22
|
|
|
|
|
const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
|
|
|
|
|
const XmlBigCount countBytesOutput
|
|
|
|
|
= rootParser->m_accounting.countBytesDirect
|
|
|
|
|
+ rootParser->m_accounting.countBytesIndirect;
|
|
|
|
@@ -7513,7 +7796,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) {
|
|
|
|
|
= rootParser->m_accounting.countBytesDirect
|
|
|
|
|
? (countBytesOutput
|
|
|
|
|
/ (float)(rootParser->m_accounting.countBytesDirect))
|
|
|
|
|
: 1.0f;
|
|
|
|
|
: ((lenOfShortestInclude
|
|
|
|
|
+ rootParser->m_accounting.countBytesIndirect)
|
|
|
|
|
/ (float)lenOfShortestInclude);
|
|
|
|
|
assert(! rootParser->m_parentParser);
|
|
|
|
|
return amplificationFactor;
|
|
|
|
|
}
|
|
|
|
@@ -7523,7 +7808,7 @@ accountingReportStats(XML_Parser originParser, const char *epilog) {
|
|
|
|
|
const XML_Parser rootParser = getRootParserOf(originParser, NULL);
|
|
|
|
|
assert(! rootParser->m_parentParser);
|
|
|
|
|
|
|
|
|
|
if (rootParser->m_accounting.debugLevel < 1) {
|
|
|
|
|
if (rootParser->m_accounting.debugLevel == 0u) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -7560,7 +7845,7 @@ accountingReportDiff(XML_Parser rootParser,
|
|
|
|
|
|
|
|
|
|
/* Note: Performance is of no concern here */
|
|
|
|
|
const char *walker = before;
|
|
|
|
|
if ((rootParser->m_accounting.debugLevel >= 3)
|
|
|
|
|
if ((rootParser->m_accounting.debugLevel >= 3u)
|
|
|
|
|
|| (after - before)
|
|
|
|
|
<= (ptrdiff_t)(contextLength + ellipsisLength + contextLength)) {
|
|
|
|
|
for (; walker < after; walker++) {
|
|
|
|
@@ -7625,7 +7910,7 @@ accountingDiffTolerated(XML_Parser originParser, int tok, const char *before,
|
|
|
|
|
|| (amplificationFactor
|
|
|
|
|
<= rootParser->m_accounting.maximumAmplificationFactor);
|
|
|
|
|
|
|
|
|
|
if (rootParser->m_accounting.debugLevel >= 2) {
|
|
|
|
|
if (rootParser->m_accounting.debugLevel >= 2u) {
|
|
|
|
|
accountingReportStats(rootParser, "");
|
|
|
|
|
accountingReportDiff(rootParser, levelsAwayFromRootParser, before, after,
|
|
|
|
|
bytesMore, source_line, account);
|
|
|
|
@@ -7652,7 +7937,7 @@ static void
|
|
|
|
|
entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
|
|
|
|
|
const char *action, int sourceLine) {
|
|
|
|
|
assert(! rootParser->m_parentParser);
|
|
|
|
|
if (rootParser->m_entity_stats.debugLevel < 1)
|
|
|
|
|
if (rootParser->m_entity_stats.debugLevel == 0u)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
# if defined(XML_UNICODE)
|
|
|
|
@@ -8233,7 +8518,7 @@ unsignedCharToPrintable(unsigned char c) {
|
|
|
|
|
assert(0); /* never gets here */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* XML_DTD */
|
|
|
|
|
#endif /* XML_GE == 1 */
|
|
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
|
getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
|
|
|
|
@@ -8244,9 +8529,9 @@ getDebugLevel(const char *variableName, unsigned long defaultDebugLevel) {
|
|
|
|
|
const char *const value = valueOrNull;
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
char *afterValue = (char *)value;
|
|
|
|
|
char *afterValue = NULL;
|
|
|
|
|
unsigned long debugLevel = strtoul(value, &afterValue, 10);
|
|
|
|
|
if ((errno != 0) || (afterValue[0] != '\0')) {
|
|
|
|
|
if ((errno != 0) || (afterValue == value) || (afterValue[0] != '\0')) {
|
|
|
|
|
errno = 0;
|
|
|
|
|
return defaultDebugLevel;
|
|
|
|
|
}
|
|
|
|
|