Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493/* * xinclude.c : Code to implement XInclude processing * * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003 * http://www.w3.org/TR/2003/WD-xinclude-20031110 * * See Copyright for the status of this software. * * daniel@veillard.com */
#define IN_LIBXML#include "libxml.h"
#include <string.h>#include <libxml/xmlmemory.h>#include <libxml/tree.h>#include <libxml/parser.h>#include <libxml/uri.h>#include <libxml/xpath.h>#include <libxml/xpointer.h>#include <libxml/parserInternals.h>#include <libxml/xmlerror.h>#include <libxml/encoding.h>
#ifdef LIBXML_XINCLUDE_ENABLED#include <libxml/xinclude.h>
#include "private/buf.h"#include "private/error.h"#include "private/tree.h"#include "private/xinclude.h"
#define XINCLUDE_MAX_DEPTH 40
/************************************************************************ * * * XInclude context handling * * * ************************************************************************/
/* * An XInclude context */typedef xmlChar *xmlURL;
typedef struct _xmlXIncludeRef xmlXIncludeRef;typedef xmlXIncludeRef *xmlXIncludeRefPtr;struct _xmlXIncludeRef { xmlChar *URI; /* the fully resolved resource URL */ xmlChar *fragment; /* the fragment in the URI */ xmlNodePtr elem; /* the xi:include element */ xmlNodePtr inc; /* the included copy */ int xml; /* xml or txt */ int fallback; /* fallback was loaded */ int emptyFb; /* flag to show fallback empty */ int expanding; /* flag to detect inclusion loops */ int replace; /* should the node be replaced? */};
typedef struct _xmlXIncludeDoc xmlXIncludeDoc;typedef xmlXIncludeDoc *xmlXIncludeDocPtr;struct _xmlXIncludeDoc { xmlDocPtr doc; /* the parsed document */ xmlChar *url; /* the URL */ int expanding; /* flag to detect inclusion loops */};
typedef struct _xmlXIncludeTxt xmlXIncludeTxt;typedef xmlXIncludeTxt *xmlXIncludeTxtPtr;struct _xmlXIncludeTxt { xmlChar *text; /* text string */ xmlChar *url; /* the URL */};
struct _xmlXIncludeCtxt { xmlDocPtr doc; /* the source document */ int incNr; /* number of includes */ int incMax; /* size of includes tab */ xmlXIncludeRefPtr *incTab; /* array of included references */
int txtNr; /* number of unparsed documents */ int txtMax; /* size of unparsed documents tab */ xmlXIncludeTxt *txtTab; /* array of unparsed documents */
int urlNr; /* number of documents stacked */ int urlMax; /* size of document stack */ xmlXIncludeDoc *urlTab; /* document stack */
int nbErrors; /* the number of errors detected */ int fatalErr; /* abort processing */ int legacy; /* using XINCLUDE_OLD_NS */ int parseFlags; /* the flags used for parsing XML documents */ xmlChar * base; /* the current xml:base */
void *_private; /* application data */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION unsigned long incTotal; /* total number of processed inclusions */#endif int depth; /* recursion depth */ int isStream; /* streaming mode */};
static xmlXIncludeRefPtrxmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node);
static intxmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref);
static intxmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree);
/************************************************************************ * * * XInclude error handler * * * ************************************************************************/
/** * xmlXIncludeErrMemory: * @extra: extra information * * Handle an out of memory condition */static voidxmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, const char *extra){ if (ctxt != NULL) ctxt->nbErrors++; __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, "Memory allocation failed : %s\n", extra);}
/** * xmlXIncludeErr: * @ctxt: the XInclude context * @node: the context node * @msg: the error message * @extra: extra information * * Handle an XInclude error */static void LIBXML_ATTR_FORMAT(4,0)xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra){ if (ctxt != NULL) ctxt->nbErrors++; __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 0/** * xmlXIncludeWarn: * @ctxt: the XInclude context * @node: the context node * @msg: the error message * @extra: extra information * * Emit an XInclude warning. */static void LIBXML_ATTR_FORMAT(4,0)xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra){ __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, error, XML_ERR_WARNING, NULL, 0, (const char *) extra, NULL, NULL, 0, 0, msg, (const char *) extra);}#endif
/** * xmlXIncludeGetProp: * @ctxt: the XInclude context * @cur: the node * @name: the attribute name * * Get an XInclude attribute * * Returns the value (to be freed) or NULL if not found */static xmlChar *xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *name) { xmlChar *ret;
ret = xmlGetNsProp(cur, XINCLUDE_NS, name); if (ret != NULL) return(ret); if (ctxt->legacy != 0) { ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); if (ret != NULL) return(ret); } ret = xmlGetProp(cur, name); return(ret);}/** * xmlXIncludeFreeRef: * @ref: the XInclude reference * * Free an XInclude reference */static voidxmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { if (ref == NULL) return; if (ref->URI != NULL) xmlFree(ref->URI); if (ref->fragment != NULL) xmlFree(ref->fragment); xmlFree(ref);}
/** * xmlXIncludeNewRef: * @ctxt: the XInclude context * @URI: the resource URI * @elem: the xi:include element * * Creates a new reference within an XInclude context * * Returns the new set */static xmlXIncludeRefPtrxmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, xmlNodePtr elem) { xmlXIncludeRefPtr ret;
ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); if (ret == NULL) { xmlXIncludeErrMemory(ctxt, elem, "growing XInclude context"); return(NULL); } memset(ret, 0, sizeof(xmlXIncludeRef)); if (URI == NULL) ret->URI = NULL; else ret->URI = xmlStrdup(URI); ret->fragment = NULL; ret->elem = elem; ret->xml = 0; ret->inc = NULL; if (ctxt->incNr >= ctxt->incMax) { xmlXIncludeRefPtr *tmp;#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 1;#else size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 4;#endif
tmp = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, newSize * sizeof(ctxt->incTab[0])); if (tmp == NULL) { xmlXIncludeErrMemory(ctxt, elem, "growing XInclude context"); xmlXIncludeFreeRef(ret); return(NULL); } ctxt->incTab = tmp; ctxt->incMax = newSize; } ctxt->incTab[ctxt->incNr++] = ret; return(ret);}
/** * xmlXIncludeNewContext: * @doc: an XML Document * * Creates a new XInclude context * * Returns the new set */xmlXIncludeCtxtPtrxmlXIncludeNewContext(xmlDocPtr doc) { xmlXIncludeCtxtPtr ret;
if (doc == NULL) return(NULL); ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); if (ret == NULL) { xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, "creating XInclude context"); return(NULL); } memset(ret, 0, sizeof(xmlXIncludeCtxt)); ret->doc = doc; ret->incNr = 0; ret->incMax = 0; ret->incTab = NULL; ret->nbErrors = 0; return(ret);}
/** * xmlXIncludeFreeContext: * @ctxt: the XInclude context * * Free an XInclude context */voidxmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { int i;
if (ctxt == NULL) return; if (ctxt->urlTab != NULL) { for (i = 0; i < ctxt->urlNr; i++) { xmlFreeDoc(ctxt->urlTab[i].doc); xmlFree(ctxt->urlTab[i].url); } xmlFree(ctxt->urlTab); } for (i = 0;i < ctxt->incNr;i++) { if (ctxt->incTab[i] != NULL) xmlXIncludeFreeRef(ctxt->incTab[i]); } if (ctxt->incTab != NULL) xmlFree(ctxt->incTab); if (ctxt->txtTab != NULL) { for (i = 0;i < ctxt->txtNr;i++) { xmlFree(ctxt->txtTab[i].text); xmlFree(ctxt->txtTab[i].url); } xmlFree(ctxt->txtTab); } if (ctxt->base != NULL) { xmlFree(ctxt->base); } xmlFree(ctxt);}
/** * xmlXIncludeParseFile: * @ctxt: the XInclude context * @URL: the URL or file path * * parse a document for XInclude */static xmlDocPtrxmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlDocPtr ret; xmlParserCtxtPtr pctxt; xmlParserInputPtr inputStream;
xmlInitParser();
pctxt = xmlNewParserCtxt(); if (pctxt == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); return(NULL); }
/* * pass in the application data to the parser context. */ pctxt->_private = ctxt->_private;
/* * try to ensure that new documents included are actually * built with the same dictionary as the including document. */ if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) { if (pctxt->dict != NULL) xmlDictFree(pctxt->dict); pctxt->dict = ctxt->doc->dict; xmlDictReference(pctxt->dict); }
xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
/* Don't read from stdin. */ if ((URL != NULL) && (strcmp(URL, "-") == 0)) URL = "./-";
inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); if (inputStream == NULL) { xmlFreeParserCtxt(pctxt); return(NULL); }
inputPush(pctxt, inputStream);
if (pctxt->directory == NULL) pctxt->directory = xmlParserGetDirectory(URL);
pctxt->loadsubset |= XML_DETECT_IDS;
xmlParseDocument(pctxt);
if (pctxt->wellFormed) { ret = pctxt->myDoc; } else { ret = NULL; if (pctxt->myDoc != NULL) xmlFreeDoc(pctxt->myDoc); pctxt->myDoc = NULL; } xmlFreeParserCtxt(pctxt);
return(ret);}
/** * xmlXIncludeAddNode: * @ctxt: the XInclude context * @cur: the new node * * Add a new node to process to an XInclude context */static xmlXIncludeRefPtrxmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { xmlXIncludeRefPtr ref; xmlURIPtr uri; xmlChar *URL; xmlChar *fragment = NULL; xmlChar *href; xmlChar *parse; xmlChar *base; xmlChar *URI; int xml = 1; int local = 0;
if (ctxt == NULL) return(NULL); if (cur == NULL) return(NULL);
/* * read the attributes */ 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); 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(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); } fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
/* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)URI); if (uri == NULL) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", URI); if (fragment != NULL) xmlFree(fragment); xmlFree(URI); return(NULL); }
if (uri->fragment != NULL) { if (ctxt->legacy != 0) { if (fragment == NULL) { fragment = (xmlChar *) uri->fragment; } else { xmlFree(uri->fragment); } } else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, "Invalid fragment identifier in URI %s use the xpointer attribute\n", URI); if (fragment != NULL) xmlFree(fragment); xmlFreeURI(uri); xmlFree(URI); return(NULL); } uri->fragment = NULL; } URL = xmlSaveUri(uri); xmlFreeURI(uri); if (URL == NULL) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", URI); if (fragment != NULL) xmlFree(fragment); xmlFree(URI); return(NULL); } xmlFree(URI);
if (xmlStrEqual(URL, ctxt->doc->URL)) local = 1;
/* * If local and xml then we need a fragment */ if ((local == 1) && (xml == 1) && ((fragment == NULL) || (fragment[0] == 0))) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, "detected a local recursion with no xpointer in %s\n", URL); xmlFree(URL); xmlFree(fragment); return(NULL); }
ref = xmlXIncludeNewRef(ctxt, URL, cur); xmlFree(URL); if (ref == NULL) { xmlFree(fragment); return(NULL); } ref->fragment = fragment; ref->xml = xml; return(ref);}
/** * xmlXIncludeRecurseDoc: * @ctxt: the XInclude context * @doc: the new document * @url: the associated URL * * The XInclude recursive nature is handled at this point. */static voidxmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url ATTRIBUTE_UNUSED) { xmlDocPtr oldDoc; xmlXIncludeRefPtr *oldIncTab; int oldIncMax, oldIncNr, oldIsStream; int i;
oldDoc = ctxt->doc; oldIncMax = ctxt->incMax; oldIncNr = ctxt->incNr; oldIncTab = ctxt->incTab; oldIsStream = ctxt->isStream; ctxt->doc = doc; ctxt->incMax = 0; ctxt->incNr = 0; ctxt->incTab = NULL; ctxt->isStream = 0;
xmlXIncludeDoProcess(ctxt, xmlDocGetRootElement(doc));
if (ctxt->incTab != NULL) { for (i = 0; i < ctxt->incNr; i++) xmlXIncludeFreeRef(ctxt->incTab[i]); xmlFree(ctxt->incTab); }
ctxt->doc = oldDoc; ctxt->incMax = oldIncMax; ctxt->incNr = oldIncNr; ctxt->incTab = oldIncTab; ctxt->isStream = oldIsStream;}
/************************************************************************ * * * Node copy with specific semantic * * * ************************************************************************/
/** * xmlXIncludeCopyNode: * @ctxt: the XInclude context * @elem: the element * @copyChildren: copy children instead of node if true * * Make a copy of the node while expanding nested XIncludes. * * Returns a node list, not a single node. */static xmlNodePtrxmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, int copyChildren) { xmlNodePtr result = NULL; xmlNodePtr insertParent = NULL; xmlNodePtr insertLast = NULL; xmlNodePtr cur;
if (copyChildren) { cur = elem->children; if (cur == NULL) return(NULL); } else { cur = elem; }
while (1) { xmlNodePtr copy = NULL; int recurse = 0;
if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_DTD_NODE)) { ; } else if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) && (xmlStrEqual(cur->name, XINCLUDE_NODE)) && ((xmlStrEqual(cur->ns->href, XINCLUDE_NS)) || (xmlStrEqual(cur->ns->href, XINCLUDE_OLD_NS)))) { xmlXIncludeRefPtr ref = xmlXIncludeExpandNode(ctxt, cur);
if (ref == NULL) goto error; /* * TODO: Insert XML_XINCLUDE_START and XML_XINCLUDE_END nodes */ if (ref->inc != NULL) { copy = xmlStaticCopyNodeList(ref->inc, ctxt->doc, insertParent); if (copy == NULL) goto error; } } else { copy = xmlStaticCopyNode(cur, ctxt->doc, insertParent, 2); if (copy == NULL) goto error;
recurse = (cur->type != XML_ENTITY_REF_NODE) && (cur->children != NULL); }
if (copy != NULL) { if (result == NULL) result = copy; if (insertLast != NULL) { insertLast->next = copy; copy->prev = insertLast; } else if (insertParent != NULL) { insertParent->children = copy; } insertLast = copy; while (insertLast->next != NULL) { insertLast = insertLast->next; } }
if (recurse) { cur = cur->children; insertParent = insertLast; insertLast = NULL; continue; }
if (cur == elem) return(result);
while (cur->next == NULL) { if (insertParent != NULL) insertParent->last = insertLast; cur = cur->parent; if (cur == elem) return(result); insertLast = insertParent; insertParent = insertParent->parent; }
cur = cur->next; }
error: xmlFreeNodeList(result); return(NULL);}
#ifdef LIBXML_XPTR_LOCS_ENABLED/** * xmlXIncludeGetNthChild: * @cur: the node * @no: the child number * * Returns the @n'th element child of @cur or NULL */static xmlNodePtrxmlXIncludeGetNthChild(xmlNodePtr cur, int no) { int i; if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(NULL); cur = cur->children; for (i = 0;i <= no;cur = cur->next) { if (cur == NULL) return(cur); if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { i++; if (i == no) break; } } return(cur);}
xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c *//** * xmlXIncludeCopyRange: * @ctxt: the XInclude context * @obj: the XPointer result from the evaluation. * * Build a node list tree copy of the XPointer result. * * Returns an xmlNodePtr list or NULL. * The caller has to free the node tree. */static xmlNodePtrxmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr range) { /* pointers to generated nodes */ xmlNodePtr list = NULL, last = NULL, listParent = NULL; xmlNodePtr tmp, tmp2; /* pointers to traversal nodes */ xmlNodePtr start, cur, end; int index1, index2; int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
if ((ctxt == NULL) || (range == NULL)) return(NULL); if (range->type != XPATH_RANGE) return(NULL); start = (xmlNodePtr) range->user;
if ((start == NULL) || (start->type == XML_NAMESPACE_DECL)) return(NULL); end = range->user2; if (end == NULL) return(xmlDocCopyNode(start, ctxt->doc, 1)); if (end->type == XML_NAMESPACE_DECL) return(NULL);
cur = start; index1 = range->index; index2 = range->index2; /* * level is depth of the current node under consideration * list is the pointer to the root of the output tree * listParent is a pointer to the parent of output tree (within the included file) in case we need to add another level * last is a pointer to the last node added to the output tree * lastLevel is the depth of last (relative to the root) */ while (cur != NULL) { /* * Check if our output tree needs a parent */ if (level < 0) { while (level < 0) { /* copy must include namespaces and properties */ tmp2 = xmlDocCopyNode(listParent, ctxt->doc, 2); xmlAddChild(tmp2, list); list = tmp2; listParent = listParent->parent; level++; } last = list; lastLevel = 0; } /* * Check whether we need to change our insertion point */ while (level < lastLevel) { last = last->parent; lastLevel --; } if (cur == end) { /* Are we at the end of the range? */ if (cur->type == XML_TEXT_NODE) { const xmlChar *content = cur->content; int len;
if (content == NULL) { tmp = xmlNewDocTextLen(ctxt->doc, NULL, 0); } else { len = index2; if ((cur == start) && (index1 > 1)) { content += (index1 - 1); len -= (index1 - 1); } else { len = index2; } tmp = xmlNewDocTextLen(ctxt->doc, content, len); } /* single sub text node selection */ if (list == NULL) return(tmp); /* prune and return full set */ if (level == lastLevel) xmlAddNextSibling(last, tmp); else xmlAddChild(last, tmp); return(list); } else { /* ending node not a text node */ endLevel = level; /* remember the level of the end node */ endFlag = 1; /* last node - need to take care of properties + namespaces */ tmp = xmlDocCopyNode(cur, ctxt->doc, 2); if (list == NULL) { list = tmp; listParent = cur->parent; last = tmp; } else { if (level == lastLevel) last = xmlAddNextSibling(last, tmp); else { last = xmlAddChild(last, tmp); lastLevel = level; } }
if (index2 > 1) { end = xmlXIncludeGetNthChild(cur, index2 - 1); index2 = 0; } if ((cur == start) && (index1 > 1)) { cur = xmlXIncludeGetNthChild(cur, index1 - 1); index1 = 0; } else { cur = cur->children; } level++; /* increment level to show change */ /* * Now gather the remaining nodes from cur to end */ continue; /* while */ } } else if (cur == start) { /* Not at the end, are we at start? */ if ((cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { const xmlChar *content = cur->content;
if (content == NULL) { tmp = xmlNewDocTextLen(ctxt->doc, NULL, 0); } else { if (index1 > 1) { content += (index1 - 1); index1 = 0; } tmp = xmlNewDocText(ctxt->doc, content); } last = list = tmp; listParent = cur->parent; } else { /* Not text node */ /* * start of the range - need to take care of * properties and namespaces */ tmp = xmlDocCopyNode(cur, ctxt->doc, 2); list = last = tmp; listParent = cur->parent; if (index1 > 1) { /* Do we need to position? */ cur = xmlXIncludeGetNthChild(cur, index1 - 1); level = lastLevel = 1; index1 = 0; /* * Now gather the remaining nodes from cur to end */ continue; /* while */ } } } else { tmp = NULL; switch (cur->type) { case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_NODE: /* Do not copy DTD information */ break; case XML_ENTITY_DECL: /* handle crossing entities -> stack needed */ break; case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* don't consider it part of the tree content */ break; case XML_ATTRIBUTE_NODE: /* Humm, should not happen ! */ break; default: /* * Middle of the range - need to take care of * properties and namespaces */ tmp = xmlDocCopyNode(cur, ctxt->doc, 2); break; } if (tmp != NULL) { if (level == lastLevel) last = xmlAddNextSibling(last, tmp); else { last = xmlAddChild(last, tmp); lastLevel = level; } } } /* * Skip to next node in document order */ cur = xmlXPtrAdvanceNode(cur, &level); if (endFlag && (level >= endLevel)) break; } return(list);}#endif /* LIBXML_XPTR_LOCS_ENABLED */
/** * xmlXIncludeCopyXPointer: * @ctxt: the XInclude context * @obj: the XPointer result from the evaluation. * * Build a node list tree copy of the XPointer result. * This will drop Attributes and Namespace declarations. * * Returns an xmlNodePtr list or NULL. * the caller has to free the node tree. */static xmlNodePtrxmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { xmlNodePtr list = NULL, last = NULL, copy; int i;
if ((ctxt == NULL) || (obj == NULL)) return(NULL); switch (obj->type) { case XPATH_NODESET: { xmlNodeSetPtr set = obj->nodesetval; if (set == NULL) return(NULL); for (i = 0;i < set->nodeNr;i++) { xmlNodePtr node;
if (set->nodeTab[i] == NULL) continue; switch (set->nodeTab[i]->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: node = xmlDocGetRootElement( (xmlDocPtr) set->nodeTab[i]); if (node == NULL) { xmlXIncludeErr(ctxt, set->nodeTab[i], XML_ERR_INTERNAL_ERROR, "document without root\n", NULL); continue; } break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: node = set->nodeTab[i]; break; default: xmlXIncludeErr(ctxt, set->nodeTab[i], XML_XINCLUDE_XPTR_RESULT, "invalid node type in XPtr result\n", NULL); continue; /* for */ } /* * OPTIMIZE TODO: External documents should already be * expanded, so xmlDocCopyNode should work as well. * xmlXIncludeCopyNode is only required for the initial * document. */ copy = xmlXIncludeCopyNode(ctxt, node, 0); if (copy == NULL) { xmlFreeNodeList(list); return(NULL); } if (last == NULL) { list = copy; } else { while (last->next != NULL) last = last->next; copy->prev = last; last->next = copy; } last = copy; } break; }#ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_LOCATIONSET: { xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; if (set == NULL) return(NULL); for (i = 0;i < set->locNr;i++) { if (last == NULL) list = last = xmlXIncludeCopyXPointer(ctxt, set->locTab[i]); else xmlAddNextSibling(last, xmlXIncludeCopyXPointer(ctxt, set->locTab[i])); if (last != NULL) { while (last->next != NULL) last = last->next; } } break; } case XPATH_RANGE: return(xmlXIncludeCopyRange(ctxt, obj)); case XPATH_POINT: /* points are ignored in XInclude */ break;#endif default: break; } return(list);}/************************************************************************ * * * XInclude I/O handling * * * ************************************************************************/
typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;struct _xmlXIncludeMergeData { xmlDocPtr doc; xmlXIncludeCtxtPtr ctxt;};
/** * xmlXIncludeMergeOneEntity: * @ent: the entity * @doc: the including doc * @name: the entity name * * Implements the merge of one entity */static voidxmlXIncludeMergeEntity(void *payload, void *vdata, const xmlChar *name ATTRIBUTE_UNUSED) { xmlEntityPtr ent = (xmlEntityPtr) payload; xmlXIncludeMergeDataPtr data = (xmlXIncludeMergeDataPtr) vdata; xmlEntityPtr ret, prev; xmlDocPtr doc; xmlXIncludeCtxtPtr ctxt;
if ((ent == NULL) || (data == NULL)) return; ctxt = data->ctxt; doc = data->doc; if ((ctxt == NULL) || (doc == NULL)) return; switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: case XML_INTERNAL_PREDEFINED_ENTITY: return; case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, ent->SystemID, ent->content); if (ret != NULL) { if (ent->URI != NULL) ret->URI = xmlStrdup(ent->URI); } else { prev = xmlGetDocEntity(doc, ent->name); if (prev != NULL) { if (ent->etype != prev->etype) goto error;
if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { if (!xmlStrEqual(ent->SystemID, prev->SystemID)) goto error; } else if ((ent->ExternalID != NULL) && (prev->ExternalID != NULL)) { if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) goto error; } else if ((ent->content != NULL) && (prev->content != NULL)) { if (!xmlStrEqual(ent->content, prev->content)) goto error; } else { goto error; }
} } return;error: switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: case XML_INTERNAL_PREDEFINED_ENTITY: case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: return; case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH, "mismatch in redefinition of entity %s\n", ent->name);}
/** * xmlXIncludeMergeEntities: * @ctxt: an XInclude context * @doc: the including doc * @from: the included doc * * Implements the entity merge * * Returns 0 if merge succeeded, -1 if some processing failed */static intxmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlDocPtr from) { xmlNodePtr cur; xmlDtdPtr target, source;
if (ctxt == NULL) return(-1);
if ((from == NULL) || (from->intSubset == NULL)) return(0);
target = doc->intSubset; if (target == NULL) { cur = xmlDocGetRootElement(doc); if (cur == NULL) return(-1); target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); if (target == NULL) return(-1); }
source = from->intSubset; if ((source != NULL) && (source->entities != NULL)) { xmlXIncludeMergeData data;
data.ctxt = ctxt; data.doc = doc;
xmlHashScan((xmlHashTablePtr) source->entities, xmlXIncludeMergeEntity, &data); } source = from->extSubset; if ((source != NULL) && (source->entities != NULL)) { xmlXIncludeMergeData data;
data.ctxt = ctxt; data.doc = doc;
/* * don't duplicate existing stuff when external subsets are the same */ if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) && (!xmlStrEqual(target->SystemID, source->SystemID))) { xmlHashScan((xmlHashTablePtr) source->entities, xmlXIncludeMergeEntity, &data); } } return(0);}
/** * xmlXIncludeLoadDoc: * @ctxt: the XInclude context * @url: the associated URL * @ref: an XMLXincludeRefPtr * * Load the document, and store the result in the XInclude context * * Returns 0 in case of success, -1 in case of failure */static intxmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, xmlXIncludeRefPtr ref) { xmlXIncludeDocPtr cache; xmlDocPtr doc; xmlURIPtr uri; xmlChar *URL = NULL; xmlChar *fragment = NULL; int i = 0; int ret = -1; int cacheNr;#ifdef LIBXML_XPTR_ENABLED int saveFlags;#endif
/* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)url); if (uri == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); goto error; } if (uri->fragment != NULL) { fragment = (xmlChar *) uri->fragment; uri->fragment = NULL; } if (ref->fragment != NULL) { if (fragment != NULL) xmlFree(fragment); fragment = xmlStrdup(ref->fragment); } URL = xmlSaveUri(uri); xmlFreeURI(uri); if (URL == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); goto error; }
/* * Handling of references to the local document are done * directly through ctxt->doc. */ if ((URL[0] == 0) || (URL[0] == '#') || ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) { doc = ctxt->doc; goto loaded; }
/* * Prevent reloading the document twice. */ for (i = 0; i < ctxt->urlNr; i++) { if (xmlStrEqual(URL, ctxt->urlTab[i].url)) { if (ctxt->urlTab[i].expanding) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_RECURSION, "inclusion loop detected\n", NULL); goto error; } doc = ctxt->urlTab[i].doc; if (doc == NULL) goto error; goto loaded; } }
/* * Load it. */#ifdef LIBXML_XPTR_ENABLED /* * If this is an XPointer evaluation, we want to assure that * all entities have been resolved prior to processing the * referenced document */ saveFlags = ctxt->parseFlags; if (fragment != NULL) { /* if this is an XPointer eval */ ctxt->parseFlags |= XML_PARSE_NOENT; }#endif
doc = xmlXIncludeParseFile(ctxt, (const char *)URL);#ifdef LIBXML_XPTR_ENABLED ctxt->parseFlags = saveFlags;#endif
/* Also cache NULL docs */ if (ctxt->urlNr >= ctxt->urlMax) { xmlXIncludeDoc *tmp;#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION size_t newSize = ctxt->urlMax ? ctxt->urlMax * 2 : 1;#else size_t newSize = ctxt->urlMax ? ctxt->urlMax * 2 : 8;#endif
tmp = xmlRealloc(ctxt->urlTab, sizeof(xmlXIncludeDoc) * newSize); if (tmp == NULL) { xmlXIncludeErrMemory(ctxt, ref->elem, "growing XInclude URL table"); xmlFreeDoc(doc); goto error; } ctxt->urlMax = newSize; ctxt->urlTab = tmp; } cacheNr = ctxt->urlNr++; cache = &ctxt->urlTab[cacheNr]; cache->doc = doc; cache->url = xmlStrdup(URL); cache->expanding = 0;
if (doc == NULL) goto error; /* * It's possible that the requested URL has been mapped to a * completely different location (e.g. through a catalog entry). * To check for this, we compare the URL with that of the doc * and change it if they disagree (bug 146988). */ if (!xmlStrEqual(URL, doc->URL)) { xmlFree(URL); URL = xmlStrdup(doc->URL); }
/* * Make sure we have all entities fixed up */ xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
/* * We don't need the DTD anymore, free up space if (doc->intSubset != NULL) { xmlUnlinkNode((xmlNodePtr) doc->intSubset); xmlFreeNode((xmlNodePtr) doc->intSubset); doc->intSubset = NULL; } if (doc->extSubset != NULL) { xmlUnlinkNode((xmlNodePtr) doc->extSubset); xmlFreeNode((xmlNodePtr) doc->extSubset); doc->extSubset = NULL; } */ cache->expanding = 1; xmlXIncludeRecurseDoc(ctxt, doc, URL); /* urlTab might be reallocated. */ cache = &ctxt->urlTab[cacheNr]; cache->expanding = 0;
loaded: if (fragment == NULL) { /* * Add the top children list as the replacement copy. */ ref->inc = xmlDocCopyNode(xmlDocGetRootElement(doc), ctxt->doc, 1); }#ifdef LIBXML_XPTR_ENABLED else { /* * Computes the XPointer expression and make a copy used * as the replacement copy. */ xmlXPathObjectPtr xptr; xmlXPathContextPtr xptrctxt; xmlNodeSetPtr set;
if (ctxt->isStream && doc == ctxt->doc) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, "XPointer expressions not allowed in streaming" " mode\n", NULL); goto error; }
xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); if (xptrctxt == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, "could not create XPointer context\n", NULL); goto error; } xptr = xmlXPtrEval(fragment, xptrctxt); if (xptr == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, "XPointer evaluation failed: #%s\n", fragment); xmlXPathFreeContext(xptrctxt); goto error; } switch (xptr->type) { case XPATH_UNDEFINED: case XPATH_BOOLEAN: case XPATH_NUMBER: case XPATH_STRING:#ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT:#endif case XPATH_USERS: case XPATH_XSLT_TREE: xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer is not a range: #%s\n", fragment); xmlXPathFreeObject(xptr); xmlXPathFreeContext(xptrctxt); goto error; case XPATH_NODESET: if ((xptr->nodesetval == NULL) || (xptr->nodesetval->nodeNr <= 0)) { xmlXPathFreeObject(xptr); xmlXPathFreeContext(xptrctxt); goto error; }
#ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_RANGE: case XPATH_LOCATIONSET: break;#endif } set = xptr->nodesetval; if (set != NULL) { for (i = 0;i < set->nodeNr;i++) { if (set->nodeTab[i] == NULL) continue; switch (set->nodeTab[i]->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: continue;
case XML_ATTRIBUTE_NODE: xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer selects an attribute: #%s\n", fragment); set->nodeTab[i] = NULL; continue; case XML_NAMESPACE_DECL: xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer selects a namespace: #%s\n", fragment); set->nodeTab[i] = NULL; continue; case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_RESULT, "XPointer selects unexpected nodes: #%s\n", fragment); set->nodeTab[i] = NULL; set->nodeTab[i] = NULL; continue; /* for */ } } } ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr); xmlXPathFreeObject(xptr); xmlXPathFreeContext(xptrctxt); }#endif
/* * Do the xml:base fixup if needed */ if ((doc != NULL) && (URL != NULL) && (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) && (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) { xmlNodePtr node; xmlChar *base; xmlChar *curBase;
/* * The base is only adjusted if "necessary", i.e. if the xinclude node * has a base specified, or the URL is relative */ base = xmlGetNsProp(ref->elem, BAD_CAST "base", XML_XML_NAMESPACE); if (base == NULL) { /* * No xml:base on the xinclude node, so we check whether the * URI base is different than (relative to) the context base */ curBase = xmlBuildRelativeURI(URL, ctxt->base); if (curBase == NULL) { /* Error return */ xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "trying to build relative URI from %s\n", URL); } else { /* If the URI doesn't contain a slash, it's not relative */ if (!xmlStrchr(curBase, '/')) xmlFree(curBase); else base = curBase; } } if (base != NULL) { /* Adjustment may be needed */ node = ref->inc; while (node != NULL) { /* Only work on element nodes */ if (node->type == XML_ELEMENT_NODE) { curBase = xmlNodeGetBase(node->doc, node); /* If no current base, set it */ if (curBase == NULL) { xmlNodeSetBase(node, base); } else { /* * If the current base is the same as the * URL of the document, then reset it to be * the specified xml:base or the relative URI */ if (xmlStrEqual(curBase, node->doc->URL)) { xmlNodeSetBase(node, base); } else { /* * If the element already has an xml:base * set, then relativise it if necessary */ xmlChar *xmlBase; xmlBase = xmlGetNsProp(node, BAD_CAST "base", XML_XML_NAMESPACE); if (xmlBase != NULL) { xmlChar *relBase; relBase = xmlBuildURI(xmlBase, base); if (relBase == NULL) { /* error */ xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "trying to rebuild base from %s\n", xmlBase); } else { xmlNodeSetBase(node, relBase); xmlFree(relBase); } xmlFree(xmlBase); } } xmlFree(curBase); } } node = node->next; } xmlFree(base); } } ret = 0;
error: xmlFree(URL); xmlFree(fragment); return(ret);}
/** * xmlXIncludeLoadTxt: * @ctxt: the XInclude context * @url: the associated URL * @ref: an XMLXincludeRefPtr * * Load the content, and store the result in the XInclude context * * Returns 0 in case of success, -1 in case of failure */static intxmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, xmlXIncludeRefPtr ref) { xmlParserInputBufferPtr buf; xmlNodePtr node = NULL; xmlURIPtr uri = NULL; xmlChar *URL = NULL; int i; int ret = -1; xmlChar *encoding = NULL; xmlCharEncoding enc = (xmlCharEncoding) 0; xmlParserCtxtPtr pctxt = NULL; xmlParserInputPtr inputStream = NULL; int len; const xmlChar *content;
/* Don't read from stdin. */ if (xmlStrcmp(url, BAD_CAST "-") == 0) url = BAD_CAST "./-";
/* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)url); if (uri == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); goto error; } if (uri->fragment != NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_TEXT_FRAGMENT, "fragment identifier forbidden for text: %s\n", (const xmlChar *) uri->fragment); goto error; } URL = xmlSaveUri(uri); if (URL == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); goto error; }
/* * Handling of references to the local document are done * directly through ctxt->doc. */ if (URL[0] == 0) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_TEXT_DOCUMENT, "text serialization of document not available\n", NULL); goto error; }
/* * Prevent reloading the document twice. */ for (i = 0; i < ctxt->txtNr; i++) { if (xmlStrEqual(URL, ctxt->txtTab[i].url)) { node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i].text); goto loaded; } }
/* * Try to get the encoding if available */ if (ref->elem != NULL) { encoding = xmlGetProp(ref->elem, XINCLUDE_PARSE_ENCODING); } if (encoding != NULL) { /* * TODO: we should not have to remap to the xmlCharEncoding * predefined set, a better interface than * xmlParserInputBufferCreateFilename should allow any * encoding supported by iconv */ enc = xmlParseCharEncoding((const char *) encoding); if (enc == XML_CHAR_ENCODING_ERROR) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING, "encoding %s not supported\n", encoding); goto error; } }
/* * Load it. */ pctxt = xmlNewParserCtxt(); inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt); if(inputStream == NULL) goto error; buf = inputStream->buf; if (buf == NULL) goto error; if (buf->encoder) xmlCharEncCloseFunc(buf->encoder); buf->encoder = xmlGetCharEncodingHandler(enc); node = xmlNewDocText(ctxt->doc, NULL); if (node == NULL) { xmlXIncludeErrMemory(ctxt, ref->elem, NULL); goto error; }
/* * Scan all chars from the resource and add the to the node */ while (xmlParserInputBufferRead(buf, 4096) > 0) ;
content = xmlBufContent(buf->buffer); len = xmlBufLength(buf->buffer); for (i = 0; i < len;) { int cur; int l;
l = len - i; cur = xmlGetUTF8Char(&content[i], &l); if ((cur < 0) || (!IS_CHAR(cur))) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_INVALID_CHAR, "%s contains invalid char\n", URL); goto error; }
i += l; }
xmlNodeAddContentLen(node, content, len);
if (ctxt->txtNr >= ctxt->txtMax) { xmlXIncludeTxt *tmp;#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION size_t newSize = ctxt->txtMax ? ctxt->txtMax * 2 : 1;#else size_t newSize = ctxt->txtMax ? ctxt->txtMax * 2 : 8;#endif
tmp = xmlRealloc(ctxt->txtTab, sizeof(xmlXIncludeTxt) * newSize); if (tmp == NULL) { xmlXIncludeErrMemory(ctxt, ref->elem, "growing XInclude text table"); goto error; } ctxt->txtMax = newSize; ctxt->txtTab = tmp; } ctxt->txtTab[ctxt->txtNr].text = xmlStrdup(node->content); ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(URL); ctxt->txtNr++;
loaded: /* * Add the element as the replacement copy. */ ref->inc = node; node = NULL; ret = 0;
error: xmlFreeNode(node); xmlFreeInputStream(inputStream); xmlFreeParserCtxt(pctxt); xmlFree(encoding); xmlFreeURI(uri); xmlFree(URL); return(ret);}
/** * xmlXIncludeLoadFallback: * @ctxt: the XInclude context * @fallback: the fallback node * @ref: an XMLXincludeRefPtr * * Load the content of the fallback node, and store the result * in the XInclude context * * Returns 0 in case of success, -1 in case of failure */static intxmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, xmlXIncludeRefPtr ref) { int ret = 0; int oldNbErrors;
if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) || (ctxt == NULL)) return(-1); if (fallback->children != NULL) { /* * It's possible that the fallback also has 'includes' * (Bug 129969), so we re-process the fallback just in case */ oldNbErrors = ctxt->nbErrors; ref->inc = xmlXIncludeCopyNode(ctxt, fallback, 1); if (ctxt->nbErrors > oldNbErrors) ret = -1; else if (ref->inc == NULL) ref->emptyFb = 1; } else { ref->inc = NULL; ref->emptyFb = 1; /* flag empty callback */ } ref->fallback = 1; return(ret);}
/************************************************************************ * * * XInclude Processing * * * ************************************************************************/
/** * xmlXIncludeExpandNode: * @ctxt: an XInclude context * @node: an XInclude node * * If the XInclude node wasn't processed yet, create a new RefPtr, * add it to ctxt->incTab and load the included items. * * Returns the new or existing xmlXIncludeRefPtr, or NULL in case of error. */static xmlXIncludeRefPtrxmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { xmlXIncludeRefPtr ref; int i;
if (ctxt->fatalErr) return(NULL); if (ctxt->depth >= XINCLUDE_MAX_DEPTH) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_RECURSION, "maximum recursion depth exceeded\n", NULL); ctxt->fatalErr = 1; return(NULL); }
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* * The XInclude engine offers no protection against exponential * expansion attacks similar to "billion laughs". Avoid timeouts by * limiting the total number of replacements when fuzzing. * * Unfortuately, a single XInclude can already result in quadratic * behavior: * * <doc xmlns:xi="http://www.w3.org/2001/XInclude"> * <xi:include xpointer="xpointer(//e)"/> * <e> * <e> * <e> * <!-- more nested elements --> * </e> * </e> * </e> * </doc> */ if (ctxt->incTotal >= 20) return(NULL); ctxt->incTotal++;#endif
for (i = 0; i < ctxt->incNr; i++) { if (ctxt->incTab[i]->elem == node) { if (ctxt->incTab[i]->expanding) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_RECURSION, "inclusion loop detected\n", NULL); return(NULL); } return(ctxt->incTab[i]); } }
ref = xmlXIncludeAddNode(ctxt, node); if (ref == NULL) return(NULL); ref->expanding = 1; ctxt->depth++; xmlXIncludeLoadNode(ctxt, ref); ctxt->depth--; ref->expanding = 0;
return(ref);}
/** * xmlXIncludeLoadNode: * @ctxt: an XInclude context * @ref: an xmlXIncludeRefPtr * * Find and load the infoset replacement for the given node. * * Returns 0 if substitution succeeded, -1 if some processing failed */static intxmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlNodePtr cur; xmlChar *href; xmlChar *parse; xmlChar *base; xmlChar *oldBase; xmlChar *URI; int xml = 1; /* default Issue 64 */ int ret;
if ((ctxt == NULL) || (ref == NULL)) return(-1); cur = ref->elem; if (cur == NULL) return(-1);
/* * read the attributes */ 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); } 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 (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); }
/* * Save the base for this include (saving the current one) */ oldBase = ctxt->base; ctxt->base = base;
if (xml) { ret = xmlXIncludeLoadDoc(ctxt, URI, ref); /* xmlXIncludeGetFragment(ctxt, cur, URI); */ } else { ret = xmlXIncludeLoadTxt(ctxt, URI, ref); }
/* * Restore the original base before checking for fallback */ ctxt->base = oldBase;
if (ret < 0) { xmlNodePtr children;
/* * Time to try a fallback if available */ children = cur->children; while (children != NULL) { if ((children->type == XML_ELEMENT_NODE) && (children->ns != NULL) && (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { ret = xmlXIncludeLoadFallback(ctxt, children, ref); break; } children = children->next; } } if (ret < 0) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_FALLBACK, "could not load %s, and no fallback was found\n", URI); }
/* * Cleanup */ if (URI != NULL) xmlFree(URI); if (parse != NULL) xmlFree(parse); if (href != NULL) xmlFree(href); if (base != NULL) xmlFree(base); return(0);}
/** * xmlXIncludeIncludeNode: * @ctxt: an XInclude context * @ref: an xmlXIncludeRefPtr * * Implement the infoset replacement for the given node * * Returns 0 if substitution succeeded, -1 if some processing failed */static intxmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlNodePtr cur, end, list, tmp;
if ((ctxt == NULL) || (ref == NULL)) return(-1); cur = ref->elem; if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(-1);
list = ref->inc; ref->inc = NULL; ref->emptyFb = 0;
/* * Check against the risk of generating a multi-rooted document */ if ((cur->parent != NULL) && (cur->parent->type != XML_ELEMENT_NODE)) { int nb_elem = 0;
tmp = list; while (tmp != NULL) { if (tmp->type == XML_ELEMENT_NODE) nb_elem++; tmp = tmp->next; } if (nb_elem > 1) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_MULTIPLE_ROOT, "XInclude error: would result in multiple root nodes\n", NULL); xmlFreeNodeList(list); return(-1); } }
if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { /* * Add the list of nodes */ while (list != NULL) { end = list; list = list->next;
xmlAddPrevSibling(cur, end); } /* * FIXME: xmlUnlinkNode doesn't coalesce text nodes. */ xmlUnlinkNode(cur); xmlFreeNode(cur); } else { xmlNodePtr child, next;
/* * Change the current node as an XInclude start one, and add an * XInclude end one */ if (ref->fallback) xmlUnsetProp(cur, BAD_CAST "href"); cur->type = XML_XINCLUDE_START; /* Remove fallback children */ for (child = cur->children; child != NULL; child = next) { next = child->next; xmlUnlinkNode(child); xmlFreeNode(child); } end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); if (end == NULL) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_BUILD_FAILED, "failed to build node\n", NULL); xmlFreeNodeList(list); return(-1); } end->type = XML_XINCLUDE_END; xmlAddNextSibling(cur, end);
/* * Add the list of nodes */ while (list != NULL) { cur = list; list = list->next;
xmlAddPrevSibling(end, cur); } }
return(0);}
/** * xmlXIncludeTestNode: * @ctxt: the XInclude processing context * @node: an XInclude node * * test if the node is an XInclude node * * Returns 1 true, 0 otherwise */static intxmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { if (node == NULL) return(0); if (node->type != XML_ELEMENT_NODE) return(0); if (node->ns == NULL) return(0); if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) || (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) { if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) { if (ctxt->legacy == 0) {#if 0 /* wait for the XML Core Working Group to get something stable ! */ xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS, "Deprecated XInclude namespace found, use %s", XINCLUDE_NS);#endif ctxt->legacy = 1; } } if (xmlStrEqual(node->name, XINCLUDE_NODE)) { xmlNodePtr child = node->children; int nb_fallback = 0;
while (child != NULL) { if ((child->type == XML_ELEMENT_NODE) && (child->ns != NULL) && ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) || (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) { if (xmlStrEqual(child->name, XINCLUDE_NODE)) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_INCLUDE_IN_INCLUDE, "%s has an 'include' child\n", XINCLUDE_NODE); return(0); } if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) { nb_fallback++; } } child = child->next; } if (nb_fallback > 1) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE, "%s has multiple fallback children\n", XINCLUDE_NODE); return(0); } return(1); } if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) { if ((node->parent == NULL) || (node->parent->type != XML_ELEMENT_NODE) || (node->parent->ns == NULL) || ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) && (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) || (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, "%s is not the child of an 'include'\n", XINCLUDE_FALLBACK); } } } return(0);}
/** * xmlXIncludeDoProcess: * @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 intxmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { xmlXIncludeRefPtr ref; xmlNodePtr cur; int ret = 0; 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 */ start = ctxt->incNr; cur = tree; do { /* TODO: need to work on entities -> stack */ if (xmlXIncludeTestNode(ctxt, cur) == 1) { ref = xmlXIncludeExpandNode(ctxt, cur); /* * Mark direct includes. */ if (ref != NULL) ref->replace = 1; } else if ((cur->children != NULL) && ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_ELEMENT_NODE))) { cur = cur->children; continue; } do { if (cur == tree) break; if (cur->next != NULL) { cur = cur->next; break; } cur = cur->parent; } while (cur != NULL); } while ((cur != NULL) && (cur != tree));
/* * Second phase: extend the original document infoset. */ for (i = start; i < ctxt->incNr; i++) { if (ctxt->incTab[i]->replace != 0) { if ((ctxt->incTab[i]->inc != NULL) || (ctxt->incTab[i]->emptyFb != 0)) { /* (empty fallback) */ xmlXIncludeIncludeNode(ctxt, ctxt->incTab[i]); } ctxt->incTab[i]->replace = 0; } else { /* * Ignore includes which were added indirectly, for example * inside xi:fallback elements. */ if (ctxt->incTab[i]->inc != NULL) { xmlFreeNodeList(ctxt->incTab[i]->inc); ctxt->incTab[i]->inc = NULL; } } ret++; }
if (ctxt->isStream) { /* * incTab references nodes which will eventually be deleted in * streaming mode. The table is only required for XPointer * expressions which aren't allowed in streaming mode. */ for (i = 0;i < ctxt->incNr;i++) { xmlXIncludeFreeRef(ctxt->incTab[i]); } ctxt->incNr = 0; }
return(ret);}
/** * xmlXIncludeSetFlags: * @ctxt: an XInclude processing context * @flags: a set of xmlParserOption used for parsing XML includes * * Set the flags used for further processing of XML resources. * * Returns 0 in case of success and -1 in case of error. */intxmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { if (ctxt == NULL) return(-1); ctxt->parseFlags = flags; return(0);}
/** * xmlXIncludeSetStreamingMode: * @ctxt: an XInclude processing context * @mode: whether streaming mode should be enabled * * In streaming mode, XPointer expressions aren't allowed. * * Returns 0 in case of success and -1 in case of error. */intxmlXIncludeSetStreamingMode(xmlXIncludeCtxtPtr ctxt, int mode) { if (ctxt == NULL) return(-1); ctxt->isStream = !!mode; return(0);}
/** * xmlXIncludeProcessTreeFlagsData: * @tree: an XML node * @flags: a set of xmlParserOption used for parsing XML includes * @data: application data that will be passed to the parser context * in the _private field of the parser context(s) * * Implement the XInclude substitution on the XML node @tree * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */
intxmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { xmlXIncludeCtxtPtr ctxt; int ret = 0;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) || (tree->doc == NULL)) return(-1);
ctxt = xmlXIncludeNewContext(tree->doc); if (ctxt == NULL) return(-1); ctxt->_private = data; ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); xmlXIncludeSetFlags(ctxt, flags); ret = xmlXIncludeDoProcess(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1;
xmlXIncludeFreeContext(ctxt); return(ret);}
/** * xmlXIncludeProcessFlagsData: * @doc: an XML document * @flags: a set of xmlParserOption used for parsing XML includes * @data: application data that will be passed to the parser context * in the _private field of the parser context(s) * * 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. */intxmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) { xmlNodePtr tree;
if (doc == NULL) return(-1); tree = xmlDocGetRootElement(doc); if (tree == NULL) return(-1); return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));}
/** * xmlXIncludeProcessFlags: * @doc: an XML document * @flags: a set of xmlParserOption used for parsing XML includes * * 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. */intxmlXIncludeProcessFlags(xmlDocPtr doc, int flags) { return xmlXIncludeProcessFlagsData(doc, flags, NULL);}
/** * xmlXIncludeProcess: * @doc: an XML document * * 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. */intxmlXIncludeProcess(xmlDocPtr doc) { return(xmlXIncludeProcessFlags(doc, 0));}
/** * xmlXIncludeProcessTreeFlags: * @tree: a node in an XML document * @flags: a set of xmlParserOption used for parsing XML includes * * Implement the XInclude substitution for the given subtree * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */intxmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { xmlXIncludeCtxtPtr ctxt; int ret = 0;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) || (tree->doc == NULL)) return(-1); ctxt = xmlXIncludeNewContext(tree->doc); if (ctxt == NULL) return(-1); ctxt->base = xmlNodeGetBase(tree->doc, tree); xmlXIncludeSetFlags(ctxt, flags); ret = xmlXIncludeDoProcess(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1;
xmlXIncludeFreeContext(ctxt); return(ret);}
/** * xmlXIncludeProcessTree: * @tree: a node in an XML document * * Implement the XInclude substitution for the given subtree * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */intxmlXIncludeProcessTree(xmlNodePtr tree) { return(xmlXIncludeProcessTreeFlags(tree, 0));}
/** * xmlXIncludeProcessNode: * @ctxt: an existing XInclude context * @node: a node in an XML document * * Implement the XInclude substitution for the given subtree reusing * the information and data coming from the given context. * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */intxmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { int ret = 0;
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (node->doc == NULL) || (ctxt == NULL)) return(-1); ret = xmlXIncludeDoProcess(ctxt, node); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; return(ret);}
#else /* !LIBXML_XINCLUDE_ENABLED */#endif