1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-07-12 08:59:34 +03:00

xinclude: Report malloc failures

Fix many places where malloc failures aren't reported.

Introduce a new API function xmlXIncludeGetLastError.
This commit is contained in:
Nick Wellnhofer
2023-12-10 18:15:59 +01:00
parent e58ea29f17
commit 78eab7a130
2 changed files with 341 additions and 249 deletions

View File

@ -115,6 +115,8 @@ XMLPUBFUN xmlXIncludeCtxtPtr
XMLPUBFUN int XMLPUBFUN int
xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt,
int flags); int flags);
XMLPUBFUN int
xmlXIncludeGetLastError (xmlXIncludeCtxtPtr ctxt);
XMLPUBFUN void XMLPUBFUN void
xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt);
XMLPUBFUN int XMLPUBFUN int

View File

@ -89,6 +89,7 @@ struct _xmlXIncludeCtxt {
int nbErrors; /* the number of errors detected */ int nbErrors; /* the number of errors detected */
int fatalErr; /* abort processing */ int fatalErr; /* abort processing */
int errNo; /* error code */
int legacy; /* using XINCLUDE_OLD_NS */ int legacy; /* using XINCLUDE_OLD_NS */
int parseFlags; /* the flags used for parsing XML documents */ int parseFlags; /* the flags used for parsing XML documents */
xmlChar * base; /* the current xml:base */ xmlChar * base; /* the current xml:base */
@ -100,6 +101,8 @@ struct _xmlXIncludeCtxt {
#endif #endif
int depth; /* recursion depth */ int depth; /* recursion depth */
int isStream; /* streaming mode */ int isStream; /* streaming mode */
xmlXPathContextPtr xpctxt;
}; };
static xmlXIncludeRefPtr static xmlXIncludeRefPtr
@ -128,12 +131,13 @@ static void
xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
const char *extra) const char *extra)
{ {
if (ctxt != NULL) ctxt->nbErrors++;
ctxt->nbErrors++;
__xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
extra, NULL, NULL, 0, 0, extra, NULL, NULL, 0, 0,
"Memory allocation failed : %s\n", extra); "Memory allocation failed : %s\n", extra);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->fatalErr = 1;
} }
/** /**
@ -149,12 +153,21 @@ static void LIBXML_ATTR_FORMAT(4,0)
xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
const char *msg, const xmlChar *extra) const char *msg, const xmlChar *extra)
{ {
if (ctxt != NULL) int res;
ctxt->nbErrors++;
__xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, if (ctxt->fatalErr != 0)
error, XML_ERR_ERROR, NULL, 0, return;
(const char *) extra, NULL, NULL, 0, 0, ctxt->nbErrors++;
msg, (const char *) extra); res = __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
error, XML_ERR_ERROR, NULL, 0,
(const char *) extra, NULL, NULL, 0, 0,
msg, (const char *) extra);
if (res < 0) {
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->fatalErr = 1;
} else {
ctxt->errNo = error;
}
} }
#if 0 #if 0
@ -193,15 +206,20 @@ xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
const xmlChar *name) { const xmlChar *name) {
xmlChar *ret; xmlChar *ret;
ret = xmlGetNsProp(cur, XINCLUDE_NS, name); if (xmlNodeGetAttrValue(cur, name, XINCLUDE_NS, &ret) < 0)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
if (ret != NULL) if (ret != NULL)
return(ret); return(ret);
if (ctxt->legacy != 0) { if (ctxt->legacy != 0) {
ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); if (xmlNodeGetAttrValue(cur, name, XINCLUDE_OLD_NS, &ret) < 0)
if (ret != NULL) xmlXIncludeErrMemory(ctxt, NULL, NULL);
return(ret); if (ret != NULL)
return(ret);
} }
ret = xmlGetProp(cur, name);
if (xmlNodeGetAttrValue(cur, name, NULL, &ret) < 0)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
return(ret); return(ret);
} }
/** /**
@ -242,10 +260,16 @@ xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
return(NULL); return(NULL);
} }
memset(ret, 0, sizeof(xmlXIncludeRef)); memset(ret, 0, sizeof(xmlXIncludeRef));
if (URI == NULL) if (URI == NULL) {
ret->URI = NULL; ret->URI = NULL;
else } else {
ret->URI = xmlStrdup(URI); ret->URI = xmlStrdup(URI);
if (ret->URI == NULL) {
xmlXIncludeErrMemory(ctxt, elem, NULL);
xmlXIncludeFreeRef(ret);
return(NULL);
}
}
ret->fragment = NULL; ret->fragment = NULL;
ret->elem = elem; ret->elem = elem;
ret->xml = 0; ret->xml = 0;
@ -287,11 +311,8 @@ xmlXIncludeNewContext(xmlDocPtr doc) {
if (doc == NULL) if (doc == NULL)
return(NULL); return(NULL);
ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
if (ret == NULL) { if (ret == NULL)
xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
"creating XInclude context");
return(NULL); return(NULL);
}
memset(ret, 0, sizeof(xmlXIncludeCtxt)); memset(ret, 0, sizeof(xmlXIncludeCtxt));
ret->doc = doc; ret->doc = doc;
ret->incNr = 0; ret->incNr = 0;
@ -336,9 +357,61 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
if (ctxt->base != NULL) { if (ctxt->base != NULL) {
xmlFree(ctxt->base); xmlFree(ctxt->base);
} }
if (ctxt->xpctxt != NULL)
xmlXPathFreeContext(ctxt->xpctxt);
xmlFree(ctxt); xmlFree(ctxt);
} }
static xmlChar *
xmlXIncludeBuildURI(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
const xmlChar *base, int *xmlOut) {
xmlChar *href = NULL;
xmlChar *parse = NULL;
xmlChar *URI = NULL;
int xml = 1;
/*
* read the attributes
*/
href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
if (href == NULL) {
href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
if (href == NULL) {
xmlXIncludeErrMemory(ctxt, cur, NULL);
goto error;
}
}
parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
if (parse != NULL) {
if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
xml = 1;
else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
xml = 0;
else {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
"invalid value %s for 'parse'\n", parse);
goto error;
}
}
/*
* compute the URI
*/
if (xmlBuildURISafe(href, base, &URI) < 0) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error;
}
if (URI == NULL)
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
"failed build URL\n", NULL);
error:
xmlFree(href);
xmlFree(parse);
*xmlOut = xml;
return(URI);
}
/** /**
* xmlXIncludeParseFile: * xmlXIncludeParseFile:
* @ctxt: the XInclude context * @ctxt: the XInclude context
@ -348,7 +421,7 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
*/ */
static xmlDocPtr static xmlDocPtr
xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
xmlDocPtr ret; xmlDocPtr ret = NULL;
xmlParserCtxtPtr pctxt; xmlParserCtxtPtr pctxt;
xmlParserInputPtr inputStream; xmlParserInputPtr inputStream;
@ -383,15 +456,18 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
URL = "./-"; URL = "./-";
inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
if (inputStream == NULL) { if (inputStream == NULL)
xmlFreeParserCtxt(pctxt); goto error;
return(NULL);
}
inputPush(pctxt, inputStream); inputPush(pctxt, inputStream);
if (pctxt->directory == NULL) if (pctxt->directory == NULL) {
pctxt->directory = xmlParserGetDirectory(URL); pctxt->directory = xmlParserGetDirectory(URL);
if (pctxt->directory == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error;
}
}
pctxt->loadsubset |= XML_DETECT_IDS; pctxt->loadsubset |= XML_DETECT_IDS;
@ -406,6 +482,10 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
xmlFreeDoc(pctxt->myDoc); xmlFreeDoc(pctxt->myDoc);
pctxt->myDoc = NULL; pctxt->myDoc = NULL;
} }
error:
if (pctxt->errNo == XML_ERR_NO_MEMORY)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
xmlFreeParserCtxt(pctxt); xmlFreeParserCtxt(pctxt);
return(ret); return(ret);
@ -424,88 +504,37 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
xmlURIPtr uri; xmlURIPtr uri;
xmlChar *URL; xmlChar *URL;
xmlChar *fragment = NULL; xmlChar *fragment = NULL;
xmlChar *href;
xmlChar *parse;
xmlChar *base; xmlChar *base;
xmlChar *URI; xmlChar *URI;
int xml = 1; int xml;
int local = 0; int local = 0;
int res;
if (ctxt == NULL) if (ctxt == NULL)
return(NULL); return(NULL);
if (cur == NULL) if (cur == NULL)
return(NULL); return(NULL);
/* if (xmlNodeGetBaseSafe(ctxt->doc, cur, &base) < 0) {
* read the attributes xmlXIncludeErrMemory(ctxt, NULL, NULL);
*/ return(NULL);
href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
if (href == NULL) {
href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
if (href == NULL)
return(NULL);
} }
parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); URI = xmlXIncludeBuildURI(ctxt, cur, base, &xml);
if (parse != NULL) { xmlFree(base);
if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) if (URI == NULL)
xml = 1;
else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
xml = 0;
else {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
"invalid value %s for 'parse'\n", parse);
if (href != NULL)
xmlFree(href);
if (parse != NULL)
xmlFree(parse);
return(NULL);
}
}
/*
* compute the URI
*/
base = xmlNodeGetBase(ctxt->doc, cur);
if (base == NULL) {
URI = xmlBuildURI(href, ctxt->doc->URL);
} else {
URI = xmlBuildURI(href, base);
}
if (URI == NULL) {
xmlChar *escbase;
xmlChar *eschref;
/*
* Some escaping may be needed
*/
escbase = xmlURIEscape(base);
eschref = xmlURIEscape(href);
URI = xmlBuildURI(eschref, escbase);
if (escbase != NULL)
xmlFree(escbase);
if (eschref != NULL)
xmlFree(eschref);
}
if (parse != NULL)
xmlFree(parse);
if (href != NULL)
xmlFree(href);
if (base != NULL)
xmlFree(base);
if (URI == NULL) {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
"failed build URL\n", NULL);
return(NULL); return(NULL);
}
fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
/* /*
* Check the URL and remove any fragment identifier * Check the URL and remove any fragment identifier
*/ */
uri = xmlParseURI((const char *)URI); res = xmlParseURISafe((const char *)URI, &uri);
if (uri == NULL) { if (uri == NULL) {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, if (res < 0)
"invalid value URI %s\n", URI); xmlXIncludeErrMemory(ctxt, NULL, NULL);
else
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
"invalid value URI %s\n", URI);
if (fragment != NULL) if (fragment != NULL)
xmlFree(fragment); xmlFree(fragment);
xmlFree(URI); xmlFree(URI);
@ -534,8 +563,7 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
URL = xmlSaveUri(uri); URL = xmlSaveUri(uri);
xmlFreeURI(uri); xmlFreeURI(uri);
if (URL == NULL) { if (URL == NULL) {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, xmlXIncludeErrMemory(ctxt, NULL, NULL);
"invalid value URI %s\n", URI);
if (fragment != NULL) if (fragment != NULL)
xmlFree(fragment); xmlFree(fragment);
xmlFree(URI); xmlFree(URI);
@ -666,13 +694,17 @@ xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem,
if (ref->inc != NULL) { if (ref->inc != NULL) {
copy = xmlStaticCopyNodeList(ref->inc, ctxt->doc, copy = xmlStaticCopyNodeList(ref->inc, ctxt->doc,
insertParent); insertParent);
if (copy == NULL) if (copy == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error; goto error;
}
} }
} else { } else {
copy = xmlStaticCopyNode(cur, ctxt->doc, insertParent, 2); copy = xmlStaticCopyNode(cur, ctxt->doc, insertParent, 2);
if (copy == NULL) if (copy == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error; goto error;
}
recurse = (cur->type != XML_ENTITY_REF_NODE) && recurse = (cur->type != XML_ENTITY_REF_NODE) &&
(cur->children != NULL); (cur->children != NULL);
@ -1112,32 +1144,36 @@ xmlXIncludeMergeEntity(void *payload, void *vdata,
case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
break; break;
} }
ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, prev = xmlGetDocEntity(doc, ent->name);
ent->SystemID, ent->content); if (prev == NULL) {
if (ret != NULL) { ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
if (ent->URI != NULL) ent->SystemID, ent->content);
if (ret == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
return;
}
if (ent->URI != NULL) {
ret->URI = xmlStrdup(ent->URI); ret->URI = xmlStrdup(ent->URI);
if (ret->URI == 0)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
}
} else { } else {
prev = xmlGetDocEntity(doc, ent->name); if (ent->etype != prev->etype)
if (prev != NULL) { goto error;
if (ent->etype != prev->etype)
goto error;
if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
if (!xmlStrEqual(ent->SystemID, prev->SystemID)) if (!xmlStrEqual(ent->SystemID, prev->SystemID))
goto error; goto error;
} else if ((ent->ExternalID != NULL) && } else if ((ent->ExternalID != NULL) &&
(prev->ExternalID != NULL)) { (prev->ExternalID != NULL)) {
if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
goto error; goto error;
} else if ((ent->content != NULL) && (prev->content != NULL)) { } else if ((ent->content != NULL) && (prev->content != NULL)) {
if (!xmlStrEqual(ent->content, prev->content)) if (!xmlStrEqual(ent->content, prev->content))
goto error; goto error;
} else { } else {
goto error; goto error;
} }
}
} }
return; return;
error: error:
@ -1245,7 +1281,10 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
/* /*
* Check the URL and remove any fragment identifier * Check the URL and remove any fragment identifier
*/ */
uri = xmlParseURI((const char *)url); if (xmlParseURISafe((const char *)url, &uri) < 0) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error;
}
if (uri == NULL) { if (uri == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI,
"invalid value URI %s\n", url); "invalid value URI %s\n", url);
@ -1258,12 +1297,14 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
if (ref->fragment != NULL) { if (ref->fragment != NULL) {
if (fragment != NULL) xmlFree(fragment); if (fragment != NULL) xmlFree(fragment);
fragment = xmlStrdup(ref->fragment); fragment = xmlStrdup(ref->fragment);
if (fragment == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
goto error;
}
} }
URL = xmlSaveUri(uri); URL = xmlSaveUri(uri);
xmlFreeURI(uri);
if (URL == NULL) { if (URL == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, xmlXIncludeErrMemory(ctxt, NULL, NULL);
"invalid value URI %s\n", url);
goto error; goto error;
} }
@ -1333,11 +1374,16 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
ctxt->urlMax = newSize; ctxt->urlMax = newSize;
ctxt->urlTab = tmp; ctxt->urlTab = tmp;
} }
cacheNr = ctxt->urlNr++; cache = &ctxt->urlTab[ctxt->urlNr];
cache = &ctxt->urlTab[cacheNr];
cache->doc = doc; cache->doc = doc;
cache->url = xmlStrdup(URL); cache->url = xmlStrdup(URL);
if (cache->url == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
xmlFreeDoc(doc);
goto error;
}
cache->expanding = 0; cache->expanding = 0;
cacheNr = ctxt->urlNr++;
if (doc == NULL) if (doc == NULL)
goto error; goto error;
@ -1347,10 +1393,14 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
* To check for this, we compare the URL with that of the doc * To check for this, we compare the URL with that of the doc
* and change it if they disagree (bug 146988). * and change it if they disagree (bug 146988).
*/ */
if (!xmlStrEqual(URL, doc->URL)) { if ((doc->URL != NULL) && (!xmlStrEqual(URL, doc->URL))) {
xmlFree(URL); xmlFree(URL);
URL = xmlStrdup(doc->URL); URL = xmlStrdup(doc->URL);
} if (URL == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
goto error;
}
}
/* /*
* Make sure we have all entities fixed up * Make sure we have all entities fixed up
@ -1382,6 +1432,9 @@ loaded:
* Add the top children list as the replacement copy. * Add the top children list as the replacement copy.
*/ */
ref->inc = xmlDocCopyNode(xmlDocGetRootElement(doc), ctxt->doc, 1); ref->inc = xmlDocCopyNode(xmlDocGetRootElement(doc), ctxt->doc, 1);
if (ref->inc == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
}
} }
#ifdef LIBXML_XPTR_ENABLED #ifdef LIBXML_XPTR_ENABLED
else { else {
@ -1390,7 +1443,6 @@ loaded:
* as the replacement copy. * as the replacement copy.
*/ */
xmlXPathObjectPtr xptr; xmlXPathObjectPtr xptr;
xmlXPathContextPtr xptrctxt;
xmlNodeSetPtr set; xmlNodeSetPtr set;
if (ctxt->isStream && doc == ctxt->doc) { if (ctxt->isStream && doc == ctxt->doc) {
@ -1400,18 +1452,24 @@ loaded:
goto error; goto error;
} }
xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); if (ctxt->xpctxt == NULL) {
if (xptrctxt == NULL) { ctxt->xpctxt = xmlXPtrNewContext(doc, NULL, NULL);
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, if (ctxt->xpctxt == NULL) {
"could not create XPointer context\n", NULL); xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
goto error; goto error;
} }
xptr = xmlXPtrEval(fragment, xptrctxt); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
ctxt->xpctxt->opLimit = 100000;
#endif
}
xptr = xmlXPtrEval(fragment, ctxt->xpctxt);
if (xptr == NULL) { if (xptr == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, if (ctxt->xpctxt->lastError.code == XML_ERR_NO_MEMORY)
"XPointer evaluation failed: #%s\n", xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
fragment); else
xmlXPathFreeContext(xptrctxt); xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED,
"XPointer evaluation failed: #%s\n",
fragment);
goto error; goto error;
} }
switch (xptr->type) { switch (xptr->type) {
@ -1428,13 +1486,11 @@ loaded:
"XPointer is not a range: #%s\n", "XPointer is not a range: #%s\n",
fragment); fragment);
xmlXPathFreeObject(xptr); xmlXPathFreeObject(xptr);
xmlXPathFreeContext(xptrctxt);
goto error; goto error;
case XPATH_NODESET: case XPATH_NODESET:
if ((xptr->nodesetval == NULL) || if ((xptr->nodesetval == NULL) ||
(xptr->nodesetval->nodeNr <= 0)) { (xptr->nodesetval->nodeNr <= 0)) {
xmlXPathFreeObject(xptr); xmlXPathFreeObject(xptr);
xmlXPathFreeContext(xptrctxt);
goto error; goto error;
} }
@ -1496,7 +1552,6 @@ loaded:
} }
ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr); ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr);
xmlXPathFreeObject(xptr); xmlXPathFreeObject(xptr);
xmlXPathFreeContext(xptrctxt);
} }
#endif #endif
@ -1520,8 +1575,9 @@ loaded:
* No xml:base on the xinclude node, so we check whether the * No xml:base on the xinclude node, so we check whether the
* URI base is different than (relative to) the context base * URI base is different than (relative to) the context base
*/ */
curBase = xmlBuildRelativeURI(URL, ctxt->base); if (xmlBuildRelativeURISafe(URL, ctxt->base, &curBase) < 0) {
if (curBase == NULL) { /* Error return */ xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
} else if (curBase == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI,
"trying to build relative URI from %s\n", URL); "trying to build relative URI from %s\n", URL);
} else { } else {
@ -1537,10 +1593,15 @@ loaded:
while (node != NULL) { while (node != NULL) {
/* Only work on element nodes */ /* Only work on element nodes */
if (node->type == XML_ELEMENT_NODE) { if (node->type == XML_ELEMENT_NODE) {
curBase = xmlNodeGetBase(node->doc, node); int res = 0;
if (xmlNodeGetBaseSafe(node->doc, node, &curBase) < 0) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
break;
}
/* If no current base, set it */ /* If no current base, set it */
if (curBase == NULL) { if (curBase == NULL) {
xmlNodeSetBase(node, base); res = xmlNodeSetBase(node, base);
} else { } else {
/* /*
* If the current base is the same as the * If the current base is the same as the
@ -1548,7 +1609,7 @@ loaded:
* the specified xml:base or the relative URI * the specified xml:base or the relative URI
*/ */
if (xmlStrEqual(curBase, node->doc->URL)) { if (xmlStrEqual(curBase, node->doc->URL)) {
xmlNodeSetBase(node, base); res = xmlNodeSetBase(node, base);
} else { } else {
/* /*
* If the element already has an xml:base * If the element already has an xml:base
@ -1560,15 +1621,17 @@ loaded:
XML_XML_NAMESPACE); XML_XML_NAMESPACE);
if (xmlBase != NULL) { if (xmlBase != NULL) {
xmlChar *relBase; xmlChar *relBase;
relBase = xmlBuildURI(xmlBase, base); res = xmlBuildURISafe(xmlBase, base, &relBase);
if (relBase == NULL) { /* error */ if (res < 0) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
} else if (relBase == NULL) {
xmlXIncludeErr(ctxt, xmlXIncludeErr(ctxt,
ref->elem, ref->elem,
XML_XINCLUDE_HREF_URI, XML_XINCLUDE_HREF_URI,
"trying to rebuild base from %s\n", "trying to rebuild base from %s\n",
xmlBase); xmlBase);
} else { } else {
xmlNodeSetBase(node, relBase); res = xmlNodeSetBase(node, relBase);
xmlFree(relBase); xmlFree(relBase);
} }
xmlFree(xmlBase); xmlFree(xmlBase);
@ -1576,6 +1639,8 @@ loaded:
} }
xmlFree(curBase); xmlFree(curBase);
} }
if (res < 0)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
} }
node = node->next; node = node->next;
} }
@ -1585,6 +1650,7 @@ loaded:
ret = 0; ret = 0;
error: error:
xmlFreeURI(uri);
xmlFree(URL); xmlFree(URL);
xmlFree(fragment); xmlFree(fragment);
return(ret); return(ret);
@ -1610,10 +1676,11 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
int i; int i;
int ret = -1; int ret = -1;
xmlChar *encoding = NULL; xmlChar *encoding = NULL;
xmlCharEncoding enc = (xmlCharEncoding) 0; xmlCharEncodingHandlerPtr handler = NULL;
xmlParserCtxtPtr pctxt = NULL; xmlParserCtxtPtr pctxt = NULL;
xmlParserInputPtr inputStream = NULL; xmlParserInputPtr inputStream = NULL;
int len; int len;
int res;
const xmlChar *content; const xmlChar *content;
@ -1624,10 +1691,13 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
/* /*
* Check the URL and remove any fragment identifier * Check the URL and remove any fragment identifier
*/ */
uri = xmlParseURI((const char *)url); res = xmlParseURISafe((const char *)url, &uri);
if (uri == NULL) { if (uri == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, if (res < 0)
"invalid value URI %s\n", url); xmlXIncludeErrMemory(ctxt, NULL, NULL);
else
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI,
"invalid value URI %s\n", url);
goto error; goto error;
} }
if (uri->fragment != NULL) { if (uri->fragment != NULL) {
@ -1638,8 +1708,7 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
} }
URL = xmlSaveUri(uri); URL = xmlSaveUri(uri);
if (URL == NULL) { if (URL == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, xmlXIncludeErrMemory(ctxt, NULL, NULL);
"invalid value URI %s\n", url);
goto error; goto error;
} }
@ -1659,6 +1728,8 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
for (i = 0; i < ctxt->txtNr; i++) { for (i = 0; i < ctxt->txtNr; i++) {
if (xmlStrEqual(URL, ctxt->txtTab[i].url)) { if (xmlStrEqual(URL, ctxt->txtTab[i].url)) {
node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i].text); node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i].text);
if (node == NULL)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto loaded; goto loaded;
} }
} }
@ -1667,36 +1738,50 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
* Try to get the encoding if available * Try to get the encoding if available
*/ */
if (ref->elem != NULL) { if (ref->elem != NULL) {
encoding = xmlGetProp(ref->elem, XINCLUDE_PARSE_ENCODING); encoding = xmlXIncludeGetProp(ctxt, ref->elem, XINCLUDE_PARSE_ENCODING);
} }
if (encoding != NULL) { if (encoding != NULL) {
/* res = xmlOpenCharEncodingHandler((const char *) encoding, &handler);
* TODO: we should not have to remap to the xmlCharEncoding
* predefined set, a better interface than if (res != 0) {
* xmlParserInputBufferCreateFilename should allow any if (res == XML_ERR_NO_MEMORY) {
* encoding supported by iconv xmlXIncludeErrMemory(ctxt, NULL, NULL);
*/ } else if (res == XML_ERR_UNSUPPORTED_ENCODING) {
enc = xmlParseCharEncoding((const char *) encoding); xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING,
if (enc == XML_CHAR_ENCODING_ERROR) { "encoding %s not supported\n", encoding);
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING, goto error;
"encoding %s not supported\n", encoding); } else {
goto error; xmlXIncludeErr(ctxt, ref->elem, res,
} "unexpected error from iconv or ICU\n", NULL);
goto error;
}
}
} }
/* /*
* Load it. * Load it.
*/ */
pctxt = xmlNewParserCtxt(); pctxt = xmlNewParserCtxt();
if (pctxt == NULL) {
xmlXIncludeErrMemory(ctxt, NULL, NULL);
goto error;
}
inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt); inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
if(inputStream == NULL) if (inputStream == NULL) {
if (pctxt->errNo == XML_ERR_NO_MEMORY)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
else
xmlXIncludeErr(ctxt, NULL, pctxt->errNo, "load error", NULL);
goto error; goto error;
}
buf = inputStream->buf; buf = inputStream->buf;
if (buf == NULL) if (buf == NULL)
goto error; goto error;
if (buf->encoder) if (buf->encoder)
xmlCharEncCloseFunc(buf->encoder); xmlCharEncCloseFunc(buf->encoder);
buf->encoder = xmlGetCharEncodingHandler(enc); buf->encoder = handler;
handler = NULL;
node = xmlNewDocText(ctxt->doc, NULL); node = xmlNewDocText(ctxt->doc, NULL);
if (node == NULL) { if (node == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL); xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
@ -1706,8 +1791,16 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
/* /*
* Scan all chars from the resource and add the to the node * Scan all chars from the resource and add the to the node
*/ */
while (xmlParserInputBufferRead(buf, 4096) > 0) do {
; res = xmlParserInputBufferRead(buf, 4096);
} while (res > 0);
if (res < 0) {
if (buf->error == XML_ERR_NO_MEMORY)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
else
xmlXIncludeErr(ctxt, NULL, buf->error, "read error", NULL);
goto error;
}
content = xmlBufContent(buf->buffer); content = xmlBufContent(buf->buffer);
len = xmlBufLength(buf->buffer); len = xmlBufLength(buf->buffer);
@ -1726,7 +1819,8 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
i += l; i += l;
} }
xmlNodeAddContentLen(node, content, len); if (xmlNodeAddContentLen(node, content, len) < 0)
xmlXIncludeErrMemory(ctxt, NULL, NULL);
if (ctxt->txtNr >= ctxt->txtMax) { if (ctxt->txtNr >= ctxt->txtMax) {
xmlXIncludeTxt *tmp; xmlXIncludeTxt *tmp;
@ -1746,7 +1840,17 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
ctxt->txtTab = tmp; ctxt->txtTab = tmp;
} }
ctxt->txtTab[ctxt->txtNr].text = xmlStrdup(node->content); ctxt->txtTab[ctxt->txtNr].text = xmlStrdup(node->content);
if ((node->content != NULL) &&
(ctxt->txtTab[ctxt->txtNr].text == NULL)) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
goto error;
}
ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(URL); ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(URL);
if (ctxt->txtTab[ctxt->txtNr].url == NULL) {
xmlXIncludeErrMemory(ctxt, ref->elem, NULL);
xmlFree(ctxt->txtTab[ctxt->txtNr].text);
goto error;
}
ctxt->txtNr++; ctxt->txtNr++;
loaded: loaded:
@ -1761,6 +1865,7 @@ error:
xmlFreeNode(node); xmlFreeNode(node);
xmlFreeInputStream(inputStream); xmlFreeInputStream(inputStream);
xmlFreeParserCtxt(pctxt); xmlFreeParserCtxt(pctxt);
xmlCharEncCloseFunc(handler);
xmlFree(encoding); xmlFree(encoding);
xmlFreeURI(uri); xmlFreeURI(uri);
xmlFree(URL); xmlFree(URL);
@ -1896,12 +2001,10 @@ xmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
static int static int
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
xmlNodePtr cur; xmlNodePtr cur;
xmlChar *href;
xmlChar *parse;
xmlChar *base; xmlChar *base;
xmlChar *oldBase; xmlChar *oldBase;
xmlChar *URI; xmlChar *URI;
int xml = 1; /* default Issue 64 */ int xml;
int ret; int ret;
if ((ctxt == NULL) || (ref == NULL)) if ((ctxt == NULL) || (ref == NULL))
@ -1910,64 +2013,13 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
if (cur == NULL) if (cur == NULL)
return(-1); return(-1);
/* if (xmlNodeGetBaseSafe(ctxt->doc, cur, &base) < 0) {
* read the attributes xmlXIncludeErrMemory(ctxt, NULL, NULL);
*/ return(-1);
href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
if (href == NULL) {
href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
if (href == NULL)
return(-1);
}
parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
if (parse != NULL) {
if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
xml = 1;
else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
xml = 0;
else {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
"invalid value %s for 'parse'\n", parse);
if (href != NULL)
xmlFree(href);
if (parse != NULL)
xmlFree(parse);
return(-1);
}
}
/*
* compute the URI
*/
base = xmlNodeGetBase(ctxt->doc, cur);
if (base == NULL) {
URI = xmlBuildURI(href, ctxt->doc->URL);
} else {
URI = xmlBuildURI(href, base);
} }
URI = xmlXIncludeBuildURI(ctxt, cur, base, &xml);
if (URI == NULL) { if (URI == NULL) {
xmlChar *escbase; xmlFree(base);
xmlChar *eschref;
/*
* Some escaping may be needed
*/
escbase = xmlURIEscape(base);
eschref = xmlURIEscape(href);
URI = xmlBuildURI(eschref, escbase);
if (escbase != NULL)
xmlFree(escbase);
if (eschref != NULL)
xmlFree(eschref);
}
if (URI == NULL) {
xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
"failed build URL\n", NULL);
if (parse != NULL)
xmlFree(parse);
if (href != NULL)
xmlFree(href);
if (base != NULL)
xmlFree(base);
return(-1); return(-1);
} }
@ -2019,10 +2071,6 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
*/ */
if (URI != NULL) if (URI != NULL)
xmlFree(URI); xmlFree(URI);
if (parse != NULL)
xmlFree(parse);
if (href != NULL)
xmlFree(href);
if (base != NULL) if (base != NULL)
xmlFree(base); xmlFree(base);
return(0); return(0);
@ -2106,8 +2154,7 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
} }
end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
if (end == NULL) { if (end == NULL) {
xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_BUILD_FAILED, xmlXIncludeErrMemory(ctxt, NULL, NULL);
"failed to build node\n", NULL);
xmlFreeNodeList(list); xmlFreeNodeList(list);
return(-1); return(-1);
} }
@ -2222,11 +2269,6 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) {
int ret = 0; int ret = 0;
int i, start; int i, start;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
return(-1);
if (ctxt == NULL)
return(-1);
/* /*
* First phase: lookup the elements in the document * First phase: lookup the elements in the document
*/ */
@ -2296,6 +2338,56 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) {
return(ret); return(ret);
} }
/**
* xmlXIncludeDoProcessRoot:
* @ctxt: the XInclude processing context
* @tree: the top of the tree to process
*
* Implement the XInclude substitution on the XML document @doc
*
* Returns 0 if no substitution were done, -1 if some processing failed
* or the number of substitutions done.
*/
static int
xmlXIncludeDoProcessRoot(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) {
int ret = 0;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
return(-1);
if (ctxt == NULL)
return(-1);
if ((tree->doc != NULL) && (tree->doc->URL != NULL)) {
ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
if (ctxt->base == NULL) {
xmlXIncludeErrMemory(ctxt, tree, NULL);
return(-1);
}
}
ret = xmlXIncludeDoProcess(ctxt, tree);
if (ctxt->base != NULL) {
xmlFree(ctxt->base);
ctxt->base = NULL;
}
return(ret);
}
/**
* xmlXIncludeGetLastError:
* @ctxt: an XInclude processing context
*
* Returns the last error code.
*/
int
xmlXIncludeGetLastError(xmlXIncludeCtxtPtr ctxt) {
if (ctxt == NULL)
return(XML_ERR_INTERNAL_ERROR);
return(ctxt->errNo);
}
/** /**
* xmlXIncludeSetFlags: * xmlXIncludeSetFlags:
* @ctxt: an XInclude processing context * @ctxt: an XInclude processing context
@ -2356,9 +2448,8 @@ xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
ctxt->_private = data; ctxt->_private = data;
ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
xmlXIncludeSetFlags(ctxt, flags); xmlXIncludeSetFlags(ctxt, flags);
ret = xmlXIncludeDoProcess(ctxt, tree); ret = xmlXIncludeDoProcessRoot(ctxt, tree);
if ((ret >= 0) && (ctxt->nbErrors > 0)) if ((ret >= 0) && (ctxt->nbErrors > 0))
ret = -1; ret = -1;
@ -2440,9 +2531,8 @@ xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
ctxt = xmlXIncludeNewContext(tree->doc); ctxt = xmlXIncludeNewContext(tree->doc);
if (ctxt == NULL) if (ctxt == NULL)
return(-1); return(-1);
ctxt->base = xmlNodeGetBase(tree->doc, tree);
xmlXIncludeSetFlags(ctxt, flags); xmlXIncludeSetFlags(ctxt, flags);
ret = xmlXIncludeDoProcess(ctxt, tree); ret = xmlXIncludeDoProcessRoot(ctxt, tree);
if ((ret >= 0) && (ctxt->nbErrors > 0)) if ((ret >= 0) && (ctxt->nbErrors > 0))
ret = -1; ret = -1;
@ -2482,7 +2572,7 @@ xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
(node->doc == NULL) || (ctxt == NULL)) (node->doc == NULL) || (ctxt == NULL))
return(-1); return(-1);
ret = xmlXIncludeDoProcess(ctxt, node); ret = xmlXIncludeDoProcessRoot(ctxt, node);
if ((ret >= 0) && (ctxt->nbErrors > 0)) if ((ret >= 0) && (ctxt->nbErrors > 0))
ret = -1; ret = -1;
return(ret); return(ret);