Bug 2062690 - Update to Expat 2.8.4. r=mccr8
Differential Revision: https://phabricator.services.mozilla.com/D322437
This commit is contained in:
committed by
rvandermeulen@mozilla.com
parent
a5566dd1d1
commit
f09cc8bec5
@@ -1096,7 +1096,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
|
||||
*/
|
||||
# define XML_MAJOR_VERSION 2
|
||||
# define XML_MINOR_VERSION 8
|
||||
# define XML_MICRO_VERSION 3
|
||||
# define XML_MICRO_VERSION 4
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
|
||||
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
|
||||
Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp>
|
||||
Copyright (c) 2026 Matthew Wozniczka <mattheww@simba.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* ee5f82c3ffd57c5224394ba46f348dbce466d34d6c925a527ae46b1cfe6adf1d (2.8.3+)
|
||||
/* 13c4e8da8fccffb0e8e599684e0d447ad14c1bb0b48792cf5dd77d8712301871 (2.8.4+)
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
@@ -51,6 +51,9 @@
|
||||
Copyright (c) 2026 Kartik Kenchi <netliomax25@gmail.com>
|
||||
Copyright (c) 2026 Haris Hussain <hextheshadow0x@gmail.com>
|
||||
Copyright (c) 2026 Evgeny Kotkov <kotkov@apache.org>
|
||||
Copyright (c) 2026 Darren Carreras <carrerasdarren@gmail.com>
|
||||
Copyright (c) 2026 Alberto Maschietto <albertomaschietto9@gmail.com>
|
||||
Copyright (c) 2026 Zeyou Liu <zeyouliu@tencent.com>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -340,7 +343,7 @@ typedef struct {
|
||||
const XML_Char *base;
|
||||
const XML_Char *publicId;
|
||||
const XML_Char *notation;
|
||||
XML_Bool open;
|
||||
bool open;
|
||||
XML_Bool hasMore; /* true if entity has not been completely processed */
|
||||
/* An entity can be open while being already completely processed (hasMore ==
|
||||
XML_FALSE). The reason is the delayed closing of entities until their inner
|
||||
@@ -391,6 +394,22 @@ typedef struct {
|
||||
const XML_Char *value;
|
||||
} DEFAULT_ATTRIBUTE;
|
||||
|
||||
// This structure allows mapping attribute names to instances of
|
||||
// `DEFAULT_ATTRIBUTE`.
|
||||
typedef struct {
|
||||
// Member `name` goes first to make this structure compatible with structure
|
||||
// `NAMED` (further up), which is needed to support use of structure
|
||||
// `NAME_AND_DEFAULT_ATTRIBUTE` in a hash table as implemented by function
|
||||
// `lookup` (further down).
|
||||
const XML_Char *name;
|
||||
// We would store a `DEFAULT_ATTRIBUTE *` here but the backing array
|
||||
// can be reallocated which would invalidate the pointer. Using an index
|
||||
// into the array instead, avoids that problem.
|
||||
size_t attIndex;
|
||||
// This is set to `false` by function `lookup`.
|
||||
bool initialized;
|
||||
} NAME_AND_DEFAULT_ATTRIBUTE;
|
||||
|
||||
typedef struct {
|
||||
unsigned long version;
|
||||
unsigned long hash;
|
||||
@@ -404,7 +423,7 @@ typedef struct {
|
||||
size_t nDefaultAtts;
|
||||
size_t allocDefaultAtts;
|
||||
DEFAULT_ATTRIBUTE *defaultAtts;
|
||||
HASH_TABLE defaultAttsNames;
|
||||
HASH_TABLE defaultAttForName;
|
||||
} ELEMENT_TYPE;
|
||||
|
||||
typedef struct {
|
||||
@@ -612,6 +631,8 @@ static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
|
||||
XML_Parser parser);
|
||||
static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
|
||||
STRING_POOL *newPool, const HASH_TABLE *oldTable);
|
||||
static NAMED *lookupWithLength(XML_Parser parser, HASH_TABLE *table, KEY name,
|
||||
size_t nameLen, size_t createSize);
|
||||
static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
|
||||
size_t createSize);
|
||||
static void FASTCALL hashTableInit(HASH_TABLE *table, XML_Parser parser);
|
||||
@@ -804,6 +825,8 @@ struct XML_ParserStruct {
|
||||
void *m_unknownEncodingMem;
|
||||
void *m_unknownEncodingData;
|
||||
void *m_unknownEncodingHandlerData;
|
||||
// Application callback invoked by callUnknownEncodingConvert.
|
||||
int(XMLCALL *m_unknownEncodingConvert)(void *, const char *);
|
||||
void(XMLCALL *m_unknownEncodingRelease)(void *);
|
||||
PROLOG_STATE m_prologState;
|
||||
Processor *m_processor;
|
||||
@@ -1267,6 +1290,25 @@ isCalledFromInsideHandler(XML_Parser parser) {
|
||||
return parser->m_handlerCallDepth > 0;
|
||||
}
|
||||
|
||||
static void
|
||||
callUnknownEncodingRelease(XML_Parser parser) {
|
||||
beforeHandler(parser);
|
||||
parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
|
||||
afterHandler(parser);
|
||||
parser->m_unknownEncodingRelease = NULL;
|
||||
parser->m_unknownEncodingData = NULL;
|
||||
}
|
||||
|
||||
static int XMLCALL
|
||||
callUnknownEncodingConvert(void *data, const char *p) {
|
||||
XML_Parser parser = data;
|
||||
beforeHandler(parser);
|
||||
const int result
|
||||
= parser->m_unknownEncodingConvert(parser->m_unknownEncodingData, p);
|
||||
afterHandler(parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum XML_Error
|
||||
callProcessor(XML_Parser parser, const char *start, const char *end,
|
||||
const char **endPtr) {
|
||||
@@ -1626,6 +1668,7 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
|
||||
parser->m_inheritedBindings = NULL;
|
||||
parser->m_nSpecifiedAtts = 0;
|
||||
parser->m_unknownEncodingMem = NULL;
|
||||
parser->m_unknownEncodingConvert = NULL;
|
||||
parser->m_unknownEncodingRelease = NULL;
|
||||
parser->m_unknownEncodingData = NULL;
|
||||
parser->m_parsingStatus.parsing = XML_INITIALIZED;
|
||||
@@ -1716,7 +1759,7 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
|
||||
moveToFreeBindingList(parser, parser->m_inheritedBindings);
|
||||
FREE(parser, parser->m_unknownEncodingMem);
|
||||
if (parser->m_unknownEncodingRelease)
|
||||
parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
|
||||
callUnknownEncodingRelease(parser);
|
||||
poolClear(&parser->m_tempPool);
|
||||
poolClear(&parser->m_temp2Pool);
|
||||
FREE(parser, (void *)parser->m_protocolEncodingName);
|
||||
@@ -2033,7 +2076,7 @@ XML_ParserFree(XML_Parser parser) {
|
||||
FREE(parser, parser->m_nsAtts);
|
||||
FREE(parser, parser->m_unknownEncodingMem);
|
||||
if (parser->m_unknownEncodingRelease)
|
||||
parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
|
||||
callUnknownEncodingRelease(parser);
|
||||
FREE(parser, parser);
|
||||
}
|
||||
|
||||
@@ -2895,7 +2938,7 @@ XML_GetCurrentLineNumber(XML_Parser parser) {
|
||||
parser->m_eventPtr, &parser->m_position);
|
||||
parser->m_positionPtr = parser->m_eventPtr;
|
||||
}
|
||||
// NOTE: XML_Size is known to wrap around for >2 4iB content
|
||||
// NOTE: XML_Size is known to wrap around for >4 GiB content
|
||||
// on 32bit machines and 64bit Windows, unless (non-default and
|
||||
// uncommon) XML_LARGE_SIZE is defined.
|
||||
// That's a bug and it only lives on because we cannot break
|
||||
@@ -2912,7 +2955,7 @@ XML_GetCurrentColumnNumber(XML_Parser parser) {
|
||||
parser->m_eventPtr, &parser->m_position);
|
||||
parser->m_positionPtr = parser->m_eventPtr;
|
||||
}
|
||||
// NOTE: XML_Size is known to wrap around for >2 4iB content
|
||||
// NOTE: XML_Size is known to wrap around for >4 GiB content
|
||||
// on 32bit machines and 64bit Windows, unless (non-default and
|
||||
// uncommon) XML_LARGE_SIZE is defined.
|
||||
// That's a bug and it only lives on because we cannot break
|
||||
@@ -3600,9 +3643,9 @@ doContentInternal(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
return result;
|
||||
} else if (parser->m_externalEntityRefHandler) {
|
||||
const XML_Char *context;
|
||||
entity->open = XML_TRUE;
|
||||
entity->open = true;
|
||||
context = getContext(parser);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
if (! context)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
beforeHandler(parser);
|
||||
@@ -4057,8 +4100,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
||||
sizeof(ELEMENT_TYPE));
|
||||
if (! elementType)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
if (! elementType->defaultAttsNames.parser)
|
||||
hashTableInit(&(elementType->defaultAttsNames), parser);
|
||||
if (! elementType->defaultAttForName.parser)
|
||||
hashTableInit(&(elementType->defaultAttForName), parser);
|
||||
if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
@@ -4171,11 +4214,14 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
||||
|
||||
/* figure out whether declared as other than CDATA */
|
||||
if (attId->maybeTokenized) {
|
||||
for (size_t j = 0; j < nDefaultAtts; j++) {
|
||||
if (attId == elementType->defaultAtts[j].id) {
|
||||
isCdata = elementType->defaultAtts[j].isCdata;
|
||||
break;
|
||||
}
|
||||
NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
|
||||
= (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
|
||||
parser, &(elementType->defaultAttForName), attId->name, 0);
|
||||
if (nameAndDefaultAttribute != NULL) {
|
||||
assert(nameAndDefaultAttribute->attIndex < elementType->nDefaultAtts);
|
||||
const DEFAULT_ATTRIBUTE *const att
|
||||
= elementType->defaultAtts + nameAndDefaultAttribute->attIndex;
|
||||
isCdata = att->isCdata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4289,8 +4335,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
|
||||
/* END MOZILLA CHANGE */
|
||||
unsigned char oldNsAttsPower = parser->m_nsAttsPower;
|
||||
/* size of hash table must be at least 2 * (# of prefixed attributes) */
|
||||
if ((nPrefixes << 1)
|
||||
>> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
|
||||
if (parser->m_nsAttsPower == 0
|
||||
|| (nPrefixes >> (parser->m_nsAttsPower - 1))) {
|
||||
/* hash table size must also be a power of 2 and >= 8 */
|
||||
while (nPrefixes >> parser->m_nsAttsPower++)
|
||||
;
|
||||
@@ -5245,25 +5291,34 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) {
|
||||
const int status = parser->m_unknownEncodingHandler(
|
||||
parser->m_unknownEncodingHandlerData, encodingName, &info);
|
||||
afterHandler(parser);
|
||||
|
||||
parser->m_unknownEncodingRelease = info.release;
|
||||
parser->m_unknownEncodingData = info.data;
|
||||
|
||||
if (status) {
|
||||
ENCODING *enc;
|
||||
parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
|
||||
if (! parser->m_unknownEncodingMem) {
|
||||
if (info.release)
|
||||
info.release(info.data);
|
||||
if (parser->m_unknownEncodingRelease)
|
||||
callUnknownEncodingRelease(parser);
|
||||
else
|
||||
parser->m_unknownEncodingData = NULL;
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
parser->m_unknownEncodingConvert = info.convert;
|
||||
enc = (parser->m_ns ? XmlInitUnknownEncodingNS : XmlInitUnknownEncoding)(
|
||||
parser->m_unknownEncodingMem, info.map, info.convert, info.data);
|
||||
parser->m_unknownEncodingMem, info.map,
|
||||
info.convert ? callUnknownEncodingConvert : NULL, parser);
|
||||
if (enc) {
|
||||
parser->m_unknownEncodingData = info.data;
|
||||
parser->m_unknownEncodingRelease = info.release;
|
||||
parser->m_encoding = enc;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
parser->m_unknownEncodingConvert = NULL;
|
||||
}
|
||||
if (info.release != NULL)
|
||||
info.release(info.data);
|
||||
if (parser->m_unknownEncodingRelease != NULL)
|
||||
callUnknownEncodingRelease(parser);
|
||||
else
|
||||
parser->m_unknownEncodingData = NULL;
|
||||
}
|
||||
return XML_ERROR_UNKNOWN_ENCODING;
|
||||
}
|
||||
@@ -6391,7 +6446,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
||||
}
|
||||
if (parser->m_externalEntityRefHandler) {
|
||||
dtd->paramEntityRead = XML_FALSE;
|
||||
entity->open = XML_TRUE;
|
||||
entity->open = true;
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
beforeHandler(parser);
|
||||
const int status = parser->m_externalEntityRefHandler(
|
||||
@@ -6406,11 +6461,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
|
||||
afterHandler(parser);
|
||||
if (! status) {
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
|
||||
}
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
handleDefault = XML_FALSE;
|
||||
if (! dtd->paramEntityRead) {
|
||||
dtd->keepProcessing = dtd->standalone;
|
||||
@@ -6734,7 +6789,7 @@ processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
|
||||
if (! openEntity)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
}
|
||||
entity->open = XML_TRUE;
|
||||
entity->open = true;
|
||||
entity->hasMore = XML_TRUE;
|
||||
#if XML_GE == 1
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
@@ -6825,7 +6880,7 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
|
||||
// to false. This means we can directly remove the head of
|
||||
// m_openInternalEntities
|
||||
assert(parser->m_openInternalEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
parser->m_openInternalEntities = parser->m_openInternalEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
@@ -6903,7 +6958,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
|
||||
// with hasMore set to false. This means we can directly remove the head
|
||||
// of m_openAttributeEntities
|
||||
assert(parser->m_openAttributeEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
@@ -7205,7 +7260,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
if (entity->systemId) {
|
||||
if (parser->m_externalEntityRefHandler) {
|
||||
dtd->paramEntityRead = XML_FALSE;
|
||||
entity->open = XML_TRUE;
|
||||
entity->open = true;
|
||||
entityTrackingOnOpen(parser, entity, __LINE__);
|
||||
beforeHandler(parser);
|
||||
const int status = parser->m_externalEntityRefHandler(
|
||||
@@ -7214,12 +7269,12 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
afterHandler(parser);
|
||||
if (! status) {
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
|
||||
goto endEntityValue;
|
||||
}
|
||||
entityTrackingOnClose(parser, entity, __LINE__);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
if (! dtd->paramEntityRead)
|
||||
dtd->keepProcessing = dtd->standalone;
|
||||
} else
|
||||
@@ -7369,7 +7424,7 @@ callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
|
||||
// with hasMore set to false. This means we can directly remove the head
|
||||
// of m_openValueEntities
|
||||
assert(parser->m_openValueEntities == openEntity);
|
||||
entity->open = XML_FALSE;
|
||||
entity->open = false;
|
||||
parser->m_openValueEntities = parser->m_openValueEntities->next;
|
||||
|
||||
/* put openEntity back in list of free instances */
|
||||
@@ -7550,7 +7605,7 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
|
||||
/* The handling of default attributes gets messed up if we have
|
||||
a default which duplicates a non-default. */
|
||||
NAMED *const nameFound
|
||||
= lookup(parser, &(type->defaultAttsNames), attId->name, 0);
|
||||
= lookup(parser, &(type->defaultAttForName), attId->name, 0);
|
||||
if (nameFound)
|
||||
return 1;
|
||||
if (isId && ! type->idAtt && ! attId->xmlns)
|
||||
@@ -7586,11 +7641,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
|
||||
if (! isCdata)
|
||||
attId->maybeTokenized = XML_TRUE;
|
||||
|
||||
NAMED *const nameAddedOrFound
|
||||
= lookup(parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED));
|
||||
if (! nameAddedOrFound)
|
||||
NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
|
||||
= (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
|
||||
parser, &(type->defaultAttForName), attId->name,
|
||||
sizeof(NAME_AND_DEFAULT_ATTRIBUTE));
|
||||
if (! nameAndDefaultAttribute)
|
||||
return 0;
|
||||
|
||||
assert(nameAndDefaultAttribute->name == attId->name);
|
||||
|
||||
// NOTE: The XML 1.0r4 spec says:
|
||||
// "When more than one definition is provided for the same attribute of a
|
||||
// given element type, the first declaration is binding and later
|
||||
// declarations are ignored."
|
||||
if (! nameAndDefaultAttribute->initialized) {
|
||||
nameAndDefaultAttribute->attIndex = type->nDefaultAtts;
|
||||
nameAndDefaultAttribute->initialized = true;
|
||||
}
|
||||
|
||||
type->nDefaultAtts += 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -7791,7 +7859,7 @@ setContext(XML_Parser parser, const XML_Char *context) {
|
||||
e = (ENTITY *)lookup(parser, &dtd->generalEntities,
|
||||
poolStart(&parser->m_tempPool), 0);
|
||||
if (e)
|
||||
e->open = XML_TRUE;
|
||||
e->open = true;
|
||||
if (*s != XML_T('\0'))
|
||||
s++;
|
||||
context = s;
|
||||
@@ -7910,7 +7978,7 @@ dtdReset(DTD *p, XML_Parser parser) {
|
||||
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
|
||||
if (! e)
|
||||
break;
|
||||
hashTableDestroy(&(e->defaultAttsNames));
|
||||
hashTableDestroy(&(e->defaultAttForName));
|
||||
FREE(parser, e->defaultAtts);
|
||||
}
|
||||
hashTableClear(&(p->generalEntities));
|
||||
@@ -7954,7 +8022,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) {
|
||||
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
|
||||
if (! e)
|
||||
break;
|
||||
hashTableDestroy(&(e->defaultAttsNames));
|
||||
hashTableDestroy(&(e->defaultAttForName));
|
||||
FREE(parser, e->defaultAtts);
|
||||
}
|
||||
hashTableDestroy(&(p->generalEntities));
|
||||
@@ -8047,8 +8115,8 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
|
||||
if (! newE)
|
||||
return 0;
|
||||
|
||||
if (! newE->defaultAttsNames.parser)
|
||||
hashTableInit(&(newE->defaultAttsNames), parser);
|
||||
if (! newE->defaultAttForName.parser)
|
||||
hashTableInit(&(newE->defaultAttForName), parser);
|
||||
|
||||
if (oldE->nDefaultAtts) {
|
||||
/* Detect and prevent integer overflow. */
|
||||
@@ -8081,11 +8149,22 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
|
||||
} else
|
||||
newE->defaultAtts[i].value = NULL;
|
||||
|
||||
NAMED *const nameAddedOrFound = lookup(parser, &(newE->defaultAttsNames),
|
||||
attributeName, sizeof(NAMED));
|
||||
if (! nameAddedOrFound) {
|
||||
NAME_AND_DEFAULT_ATTRIBUTE *const nameAndDefaultAttribute
|
||||
= (NAME_AND_DEFAULT_ATTRIBUTE *)lookup(
|
||||
parser, &(newE->defaultAttForName), attributeName,
|
||||
sizeof(NAME_AND_DEFAULT_ATTRIBUTE));
|
||||
if (! nameAndDefaultAttribute) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: The XML 1.0r4 spec says:
|
||||
// "When more than one definition is provided for the same attribute of a
|
||||
// given element type, the first declaration is binding and later
|
||||
// declarations are ignored."
|
||||
if (! nameAndDefaultAttribute->initialized) {
|
||||
nameAndDefaultAttribute->attIndex = i;
|
||||
nameAndDefaultAttribute->initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8182,19 +8261,23 @@ copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
|
||||
|
||||
#define INIT_POWER 6
|
||||
|
||||
// Compares two strings `s1` and `s2` whereas:
|
||||
// - `s2` is zero-terminated but
|
||||
// - `s1` is made up of exactly (not just up to) `s1len` non-zero characters.
|
||||
static XML_Bool FASTCALL
|
||||
keyeq(KEY s1, KEY s2) {
|
||||
keyeq(KEY s1, size_t s1len, KEY s2) {
|
||||
#ifdef XML_UNICODE
|
||||
# ifdef XML_UNICODE_WCHAR_T
|
||||
return (wcscmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
|
||||
return (wcsncmp(s1, s2, s1len) == 0 && s2[s1len] == L'\0') ? XML_TRUE
|
||||
: XML_FALSE;
|
||||
# else
|
||||
for (; *s1 == *s2; s1++, s2++)
|
||||
if (*s1 == 0)
|
||||
return XML_TRUE;
|
||||
return XML_FALSE;
|
||||
for (; s1len > 0 && *s1 == *s2; s1len--, s1++, s2++)
|
||||
; /* no loop body! */
|
||||
return ((s1len == 0) && (*s2 == 0)) ? XML_TRUE : XML_FALSE;
|
||||
# endif
|
||||
#else
|
||||
return (strcmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
|
||||
return (strncmp(s1, s2, s1len) == 0 && s2[s1len] == '\0') ? XML_TRUE
|
||||
: XML_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8212,18 +8295,38 @@ copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) {
|
||||
}
|
||||
|
||||
static unsigned long FASTCALL
|
||||
hash(XML_Parser parser, KEY s) {
|
||||
hash(XML_Parser parser, KEY s, size_t keyLen) {
|
||||
struct siphash state;
|
||||
struct sipkey key;
|
||||
(void)sip24_valid;
|
||||
copy_salt_to_sipkey(parser, &key);
|
||||
sip24_init(&state, &key);
|
||||
sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
|
||||
sip24_update(&state, s, keyLen * sizeof(XML_Char));
|
||||
return (unsigned long)sip24_final(&state);
|
||||
}
|
||||
|
||||
// Function `lookupWithLength` can be used to either…
|
||||
//
|
||||
// a) check whether an element with key `name` exists in the given hash table
|
||||
// (read-only mode where `createSize == 0`) or
|
||||
//
|
||||
// b) check whether an element with key `name` exists in the given hash table
|
||||
// *and* insert it if missing (i.e. read-write mode where `createSize != 0`.
|
||||
//
|
||||
// When inserting, a block of `createSize` number of bytes will be allocated
|
||||
// and set to zero, and the resulting block of memory will be considered
|
||||
// to start with a `NAMED` structure, and `->name = name;` is performed.
|
||||
// The fact that all other bytes in the structure are initially zero can
|
||||
// be used to tell cases "existed and found" and "newly inserted" apart
|
||||
// with the structure returned.
|
||||
//
|
||||
// NOTE: Read-only lookup does not need zero-terminated keys but
|
||||
// read-write mode does, because keys can be re-hashed later and the
|
||||
// hash table does not store key length information.
|
||||
//
|
||||
static NAMED *
|
||||
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
||||
lookupWithLength(XML_Parser parser, HASH_TABLE *table, KEY name, size_t nameLen,
|
||||
size_t createSize) {
|
||||
size_t i;
|
||||
if (table->size == 0) {
|
||||
size_t tsize;
|
||||
@@ -8239,14 +8342,14 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
||||
return NULL;
|
||||
}
|
||||
memset(table->v, 0, tsize);
|
||||
i = hash(parser, name) & ((unsigned long)table->size - 1);
|
||||
i = hash(parser, name, nameLen) & ((unsigned long)table->size - 1);
|
||||
} else {
|
||||
unsigned long h = hash(parser, name);
|
||||
unsigned long h = hash(parser, name, nameLen);
|
||||
unsigned long mask = (unsigned long)table->size - 1;
|
||||
unsigned char step = 0;
|
||||
i = h & mask;
|
||||
while (table->v[i]) {
|
||||
if (keyeq(name, table->v[i]->name))
|
||||
if (keyeq(name, nameLen, table->v[i]->name))
|
||||
return table->v[i];
|
||||
if (! step)
|
||||
step = PROBE_STEP(h, mask, table->power);
|
||||
@@ -8279,7 +8382,8 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
||||
memset(newV, 0, tsize);
|
||||
for (i = 0; i < table->size; i++)
|
||||
if (table->v[i]) {
|
||||
unsigned long newHash = hash(parser, table->v[i]->name);
|
||||
KEY const key = table->v[i]->name;
|
||||
unsigned long newHash = hash(parser, key, keylen(key));
|
||||
size_t j = newHash & newMask;
|
||||
step = 0;
|
||||
while (newV[j]) {
|
||||
@@ -8302,15 +8406,36 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(createSize >= sizeof(NAMED));
|
||||
table->v[i] = MALLOC(table->parser, createSize);
|
||||
if (! table->v[i])
|
||||
return NULL;
|
||||
memset(table->v[i], 0, createSize);
|
||||
table->v[i]->name = name;
|
||||
table->v[i]->name = name; // NOTE: This requires and assumes zero termination!
|
||||
(table->used)++;
|
||||
return table->v[i];
|
||||
}
|
||||
|
||||
// Function `lookup` can be used to either…
|
||||
//
|
||||
// a) check whether an element with key `name` exists in the given hash table
|
||||
// (read-only mode where `createSize == 0`) or
|
||||
//
|
||||
// b) check whether an element with key `name` exists in the given hash table
|
||||
// *and* insert it if missing (i.e. read-write mode where `createSize != 0`.
|
||||
//
|
||||
// When inserting, a block of `createSize` number of bytes will be allocated
|
||||
// and set to zero, and the resulting block of memory will be considered
|
||||
// to start with a `NAMED` structure, and `->name = name;` is performed.
|
||||
// The fact that all other bytes in the structure are initially zero can
|
||||
// be used to tell cases "existed and found" and "newly inserted" apart
|
||||
// with the structure returned.
|
||||
//
|
||||
static NAMED *
|
||||
lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
|
||||
return lookupWithLength(parser, table, name, keylen(name), createSize);
|
||||
}
|
||||
|
||||
/* BEGIN MOZILLA CHANGE (unused API) */
|
||||
#if 0
|
||||
static void FASTCALL
|
||||
@@ -8854,8 +8979,8 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
|
||||
sizeof(ELEMENT_TYPE));
|
||||
if (! ret)
|
||||
return NULL;
|
||||
if (! ret->defaultAttsNames.parser)
|
||||
hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL));
|
||||
if (! ret->defaultAttForName.parser)
|
||||
hashTableInit(&(ret->defaultAttForName), getRootParserOf(parser, NULL));
|
||||
if (ret->name != name)
|
||||
poolDiscard(&dtd->pool);
|
||||
else {
|
||||
|
||||
@@ -169,8 +169,8 @@ typedef int(PTRCALL *SCANNER)(const ENCODING *, const char *, const char *,
|
||||
enum XML_Convert_Result {
|
||||
XML_CONVERT_COMPLETED = 0,
|
||||
XML_CONVERT_INPUT_INCOMPLETE = 1,
|
||||
XML_CONVERT_OUTPUT_EXHAUSTED
|
||||
= 2 /* and therefore potentially input remaining as well */
|
||||
XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining
|
||||
as well */
|
||||
};
|
||||
|
||||
struct encoding {
|
||||
|
||||
@@ -9,8 +9,8 @@ origin:
|
||||
name: libexpat
|
||||
description: Expat is an XML parser.
|
||||
url: https://github.com/libexpat/libexpat
|
||||
release: R_2_8_3 (2026-08-10T23:49:33+02:00).
|
||||
revision: R_2_8_3
|
||||
release: R_2_8_4 (2026-08-31T15:24:26+02:00).
|
||||
revision: R_2_8_4
|
||||
license: MIT
|
||||
license-file: COPYING
|
||||
|
||||
|
||||
Reference in New Issue
Block a user