1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2026-10-24 01:09:01 +03:00

Normalize entity values in attr in xmlNodeGetContent

Fix https://gitlab.gnome.org/GNOME/libxml2/-/work_items/1118
This commit is contained in:
Daniel Garcia Moreno
2026-05-12 13:52:12 +02:00
committed by Daniel Garcia Moreno
parent d60b0f747c
commit a3c31b5392
2 changed files with 92 additions and 9 deletions

View File

@@ -5435,6 +5435,48 @@ done:
return ret;
}
static int
xmlEntityValueNormTest(const char *filename ATTRIBUTE_UNUSED,
const char *result ATTRIBUTE_UNUSED,
const char *err ATTRIBUTE_UNUSED,
int options ATTRIBUTE_UNUSED) {
int ret = 0;
xmlAttrPtr prop = NULL;
const char *str = "<!DOCTYPE doc [\n"
"<!ENTITY d '&#xD;'>\n"
"<!ENTITY a '&#xA;'>\n"
"<!ENTITY da '&#xD;&#xA;'>\n"
"<!ENTITY b '&#10;'>\n"
"]>\n"
"<doc a1='&d;' a2='&a;' a3='&da;'\n"
"a4='&d;&d;A&a;&#x20;&a;B&da;'\n"
"a5='&#xd;&#xd;A&#xa;&#xa;B&#xd;&#xa;'\n"
"a6='&b;'\n"
"a7='\n\n&b;xyz'/>";
xmlDoc *doc1 = xmlReadDoc(BAD_CAST str, NULL, NULL, 0);
xmlDoc *doc2 = xmlReadDoc(BAD_CAST str, NULL, NULL, XML_PARSE_NOENT);
prop = doc1->children->next->properties;
while (prop != NULL) {
xmlChar *content1 = xmlGetProp(doc1->children->next, BAD_CAST prop->name);
xmlChar *content2 = xmlGetProp(doc2->children->next, BAD_CAST prop->name);
if (!xmlStrEqual(content1, content2)) {
ret = 1;
fprintf(stderr, "entity resolution differs %s\n", prop->name);
}
xmlFree(content1);
xmlFree(content2);
prop = prop->next;
}
xmlFreeDoc(doc1);
xmlFreeDoc(doc2);
return ret;
}
/************************************************************************
* *
@@ -5684,6 +5726,7 @@ testDesc testDescriptions[] = {
xmlTextReaderReadOuterXmlTest, NULL, NULL, NULL, NULL, 0 },
#endif
{ "xmlCopyEntity children test" , xmlCopyEntityTest, NULL, NULL, NULL, NULL, 0 },
{ "xml Entity values normalization" , xmlEntityValueNormTest, NULL, NULL, NULL, NULL, 0 },
{NULL, NULL, NULL, NULL, NULL, NULL, 0}
};

58
tree.c
View File

@@ -77,7 +77,7 @@ xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
static void
xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree);
xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree, int normalize);
static void
xmlUnlinkNodeInternal(xmlNodePtr cur);
@@ -5122,8 +5122,43 @@ xmlNodeBufGetContent(xmlBuffer *buffer, const xmlNode *cur)
return(0);
}
/**
* TODO: move this to parserInternals?
* TODO: This function should also remove leading and trailing
* whitespaces, and also group whitespaces together, but right
* now the parse doesn't do that with XML_PARSE_NOENT, so this
* replacement is consistent with the parser normalization
*
* Normalize attritube entity values
* Replaces any space character with 0x20
* https://www.w3.org/TR/REC-xml/#AVNormalize
*/
static xmlChar *
xmlAttrNormalize(xmlChar *src)
{
xmlChar *out = NULL;
xmlChar *dst = NULL;
if (src == NULL)
return(NULL);
out = src;
dst = out;
while (*src != 0) {
if (*src < 0x20) {
src++;
*dst++ = 0x20;
} else {
*dst++ = *src++;
}
}
*dst = 0;
return(out);
}
static void
xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) {
xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref, int normalize) {
xmlEntityPtr ent;
if (ref->children != NULL) {
@@ -5149,23 +5184,26 @@ xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) {
return;
ent->flags |= XML_ENT_EXPANDING;
xmlBufGetChildContent(buf, (xmlNodePtr) ent);
xmlBufGetChildContent(buf, (xmlNodePtr) ent, normalize);
ent->flags &= ~XML_ENT_EXPANDING;
}
static void
xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree) {
xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree, int normalize) {
const xmlNode *cur = tree->children;
while (cur != NULL) {
switch (cur->type) {
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
xmlBufCat(buf, cur->content);
if (normalize)
xmlBufCat(buf, xmlAttrNormalize(cur->content));
else
xmlBufCat(buf, cur->content);
break;
case XML_ENTITY_REF_NODE:
xmlBufGetEntityRefContent(buf, cur);
xmlBufGetEntityRefContent(buf, cur, normalize);
break;
default:
@@ -5208,9 +5246,11 @@ xmlBufGetNodeContent(xmlBuf *buf, const xmlNode *cur)
case XML_HTML_DOCUMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
case XML_ENTITY_DECL:
xmlBufGetChildContent(buf, cur);
xmlBufGetChildContent(buf, cur, 0);
break;
case XML_ATTRIBUTE_NODE:
xmlBufGetChildContent(buf, cur, 1);
break;
case XML_CDATA_SECTION_NODE:
@@ -5221,7 +5261,7 @@ xmlBufGetNodeContent(xmlBuf *buf, const xmlNode *cur)
break;
case XML_ENTITY_REF_NODE:
xmlBufGetEntityRefContent(buf, cur);
xmlBufGetEntityRefContent(buf, cur, 0);
break;
case XML_NAMESPACE_DECL: