xinclude.c 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655
  1. /*
  2. * xinclude.c : Code to implement XInclude processing
  3. *
  4. * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003
  5. * http://www.w3.org/TR/2003/WD-xinclude-20031110
  6. *
  7. * See Copyright for the status of this software.
  8. *
  9. * daniel@veillard.com
  10. */
  11. #define IN_LIBXML
  12. #include "libxml.h"
  13. #include <string.h>
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/tree.h>
  16. #include <libxml/parser.h>
  17. #include <libxml/uri.h>
  18. #include <libxml/xpath.h>
  19. #include <libxml/xpointer.h>
  20. #include <libxml/parserInternals.h>
  21. #include <libxml/xmlerror.h>
  22. #include <libxml/encoding.h>
  23. #include <libxml/globals.h>
  24. #ifdef LIBXML_XINCLUDE_ENABLED
  25. #include <libxml/xinclude.h>
  26. #include "buf.h"
  27. #define XINCLUDE_MAX_DEPTH 40
  28. /* #define DEBUG_XINCLUDE */
  29. #ifdef DEBUG_XINCLUDE
  30. #ifdef LIBXML_DEBUG_ENABLED
  31. #include <libxml/debugXML.h>
  32. #endif
  33. #endif
  34. /************************************************************************
  35. * *
  36. * XInclude context handling *
  37. * *
  38. ************************************************************************/
  39. /*
  40. * An XInclude context
  41. */
  42. typedef xmlChar *xmlURL;
  43. typedef struct _xmlXIncludeRef xmlXIncludeRef;
  44. typedef xmlXIncludeRef *xmlXIncludeRefPtr;
  45. struct _xmlXIncludeRef {
  46. xmlChar *URI; /* the fully resolved resource URL */
  47. xmlChar *fragment; /* the fragment in the URI */
  48. xmlDocPtr doc; /* the parsed document */
  49. xmlNodePtr ref; /* the node making the reference in the source */
  50. xmlNodePtr inc; /* the included copy */
  51. int xml; /* xml or txt */
  52. int count; /* how many refs use that specific doc */
  53. int fallback; /* fallback was loaded */
  54. int emptyFb; /* flag to show fallback empty */
  55. };
  56. struct _xmlXIncludeCtxt {
  57. xmlDocPtr doc; /* the source document */
  58. int incBase; /* the first include for this document */
  59. int incNr; /* number of includes */
  60. int incMax; /* size of includes tab */
  61. xmlXIncludeRefPtr *incTab; /* array of included references */
  62. int txtNr; /* number of unparsed documents */
  63. int txtMax; /* size of unparsed documents tab */
  64. xmlChar * *txtTab; /* array of unparsed text strings */
  65. xmlURL *txturlTab; /* array of unparsed text URLs */
  66. xmlChar * url; /* the current URL processed */
  67. int urlNr; /* number of URLs stacked */
  68. int urlMax; /* size of URL stack */
  69. xmlChar * *urlTab; /* URL stack */
  70. int nbErrors; /* the number of errors detected */
  71. int legacy; /* using XINCLUDE_OLD_NS */
  72. int parseFlags; /* the flags used for parsing XML documents */
  73. xmlChar * base; /* the current xml:base */
  74. void *_private; /* application data */
  75. unsigned long incTotal; /* total number of processed inclusions */
  76. };
  77. static int
  78. xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
  79. int skipRoot);
  80. /************************************************************************
  81. * *
  82. * XInclude error handler *
  83. * *
  84. ************************************************************************/
  85. /**
  86. * xmlXIncludeErrMemory:
  87. * @extra: extra information
  88. *
  89. * Handle an out of memory condition
  90. */
  91. static void
  92. xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
  93. const char *extra)
  94. {
  95. if (ctxt != NULL)
  96. ctxt->nbErrors++;
  97. __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
  98. XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
  99. extra, NULL, NULL, 0, 0,
  100. "Memory allocation failed : %s\n", extra);
  101. }
  102. /**
  103. * xmlXIncludeErr:
  104. * @ctxt: the XInclude context
  105. * @node: the context node
  106. * @msg: the error message
  107. * @extra: extra information
  108. *
  109. * Handle an XInclude error
  110. */
  111. static void LIBXML_ATTR_FORMAT(4,0)
  112. xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
  113. const char *msg, const xmlChar *extra)
  114. {
  115. if (ctxt != NULL)
  116. ctxt->nbErrors++;
  117. __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
  118. error, XML_ERR_ERROR, NULL, 0,
  119. (const char *) extra, NULL, NULL, 0, 0,
  120. msg, (const char *) extra);
  121. }
  122. #if 0
  123. /**
  124. * xmlXIncludeWarn:
  125. * @ctxt: the XInclude context
  126. * @node: the context node
  127. * @msg: the error message
  128. * @extra: extra information
  129. *
  130. * Emit an XInclude warning.
  131. */
  132. static void LIBXML_ATTR_FORMAT(4,0)
  133. xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
  134. const char *msg, const xmlChar *extra)
  135. {
  136. __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
  137. error, XML_ERR_WARNING, NULL, 0,
  138. (const char *) extra, NULL, NULL, 0, 0,
  139. msg, (const char *) extra);
  140. }
  141. #endif
  142. /**
  143. * xmlXIncludeGetProp:
  144. * @ctxt: the XInclude context
  145. * @cur: the node
  146. * @name: the attribute name
  147. *
  148. * Get an XInclude attribute
  149. *
  150. * Returns the value (to be freed) or NULL if not found
  151. */
  152. static xmlChar *
  153. xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
  154. const xmlChar *name) {
  155. xmlChar *ret;
  156. ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
  157. if (ret != NULL)
  158. return(ret);
  159. if (ctxt->legacy != 0) {
  160. ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
  161. if (ret != NULL)
  162. return(ret);
  163. }
  164. ret = xmlGetProp(cur, name);
  165. return(ret);
  166. }
  167. /**
  168. * xmlXIncludeFreeRef:
  169. * @ref: the XInclude reference
  170. *
  171. * Free an XInclude reference
  172. */
  173. static void
  174. xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
  175. if (ref == NULL)
  176. return;
  177. #ifdef DEBUG_XINCLUDE
  178. xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
  179. #endif
  180. if (ref->doc != NULL) {
  181. #ifdef DEBUG_XINCLUDE
  182. xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
  183. #endif
  184. xmlFreeDoc(ref->doc);
  185. }
  186. if (ref->URI != NULL)
  187. xmlFree(ref->URI);
  188. if (ref->fragment != NULL)
  189. xmlFree(ref->fragment);
  190. xmlFree(ref);
  191. }
  192. /**
  193. * xmlXIncludeNewRef:
  194. * @ctxt: the XInclude context
  195. * @URI: the resource URI
  196. *
  197. * Creates a new reference within an XInclude context
  198. *
  199. * Returns the new set
  200. */
  201. static xmlXIncludeRefPtr
  202. xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
  203. xmlNodePtr ref) {
  204. xmlXIncludeRefPtr ret;
  205. #ifdef DEBUG_XINCLUDE
  206. xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
  207. #endif
  208. ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
  209. if (ret == NULL) {
  210. xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
  211. return(NULL);
  212. }
  213. memset(ret, 0, sizeof(xmlXIncludeRef));
  214. if (URI == NULL)
  215. ret->URI = NULL;
  216. else
  217. ret->URI = xmlStrdup(URI);
  218. ret->fragment = NULL;
  219. ret->ref = ref;
  220. ret->doc = NULL;
  221. ret->count = 0;
  222. ret->xml = 0;
  223. ret->inc = NULL;
  224. if (ctxt->incMax == 0) {
  225. ctxt->incMax = 4;
  226. ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
  227. sizeof(ctxt->incTab[0]));
  228. if (ctxt->incTab == NULL) {
  229. xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
  230. xmlXIncludeFreeRef(ret);
  231. return(NULL);
  232. }
  233. }
  234. if (ctxt->incNr >= ctxt->incMax) {
  235. ctxt->incMax *= 2;
  236. ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
  237. ctxt->incMax * sizeof(ctxt->incTab[0]));
  238. if (ctxt->incTab == NULL) {
  239. xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
  240. xmlXIncludeFreeRef(ret);
  241. return(NULL);
  242. }
  243. }
  244. ctxt->incTab[ctxt->incNr++] = ret;
  245. return(ret);
  246. }
  247. /**
  248. * xmlXIncludeNewContext:
  249. * @doc: an XML Document
  250. *
  251. * Creates a new XInclude context
  252. *
  253. * Returns the new set
  254. */
  255. xmlXIncludeCtxtPtr
  256. xmlXIncludeNewContext(xmlDocPtr doc) {
  257. xmlXIncludeCtxtPtr ret;
  258. #ifdef DEBUG_XINCLUDE
  259. xmlGenericError(xmlGenericErrorContext, "New context\n");
  260. #endif
  261. if (doc == NULL)
  262. return(NULL);
  263. ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
  264. if (ret == NULL) {
  265. xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
  266. "creating XInclude context");
  267. return(NULL);
  268. }
  269. memset(ret, 0, sizeof(xmlXIncludeCtxt));
  270. ret->doc = doc;
  271. ret->incNr = 0;
  272. ret->incBase = 0;
  273. ret->incMax = 0;
  274. ret->incTab = NULL;
  275. ret->nbErrors = 0;
  276. return(ret);
  277. }
  278. /**
  279. * xmlXIncludeURLPush:
  280. * @ctxt: the parser context
  281. * @value: the url
  282. *
  283. * Pushes a new url on top of the url stack
  284. *
  285. * Returns -1 in case of error, the index in the stack otherwise
  286. */
  287. static int
  288. xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
  289. const xmlChar *value)
  290. {
  291. if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
  292. xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
  293. "detected a recursion in %s\n", value);
  294. return(-1);
  295. }
  296. if (ctxt->urlTab == NULL) {
  297. ctxt->urlMax = 4;
  298. ctxt->urlNr = 0;
  299. ctxt->urlTab = (xmlChar * *) xmlMalloc(
  300. ctxt->urlMax * sizeof(ctxt->urlTab[0]));
  301. if (ctxt->urlTab == NULL) {
  302. xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
  303. return (-1);
  304. }
  305. }
  306. if (ctxt->urlNr >= ctxt->urlMax) {
  307. ctxt->urlMax *= 2;
  308. ctxt->urlTab =
  309. (xmlChar * *) xmlRealloc(ctxt->urlTab,
  310. ctxt->urlMax *
  311. sizeof(ctxt->urlTab[0]));
  312. if (ctxt->urlTab == NULL) {
  313. xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
  314. return (-1);
  315. }
  316. }
  317. ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
  318. return (ctxt->urlNr++);
  319. }
  320. /**
  321. * xmlXIncludeURLPop:
  322. * @ctxt: the parser context
  323. *
  324. * Pops the top URL from the URL stack
  325. */
  326. static void
  327. xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
  328. {
  329. xmlChar * ret;
  330. if (ctxt->urlNr <= 0)
  331. return;
  332. ctxt->urlNr--;
  333. if (ctxt->urlNr > 0)
  334. ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
  335. else
  336. ctxt->url = NULL;
  337. ret = ctxt->urlTab[ctxt->urlNr];
  338. ctxt->urlTab[ctxt->urlNr] = NULL;
  339. if (ret != NULL)
  340. xmlFree(ret);
  341. }
  342. /**
  343. * xmlXIncludeFreeContext:
  344. * @ctxt: the XInclude context
  345. *
  346. * Free an XInclude context
  347. */
  348. void
  349. xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
  350. int i;
  351. #ifdef DEBUG_XINCLUDE
  352. xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
  353. #endif
  354. if (ctxt == NULL)
  355. return;
  356. while (ctxt->urlNr > 0)
  357. xmlXIncludeURLPop(ctxt);
  358. if (ctxt->urlTab != NULL)
  359. xmlFree(ctxt->urlTab);
  360. for (i = 0;i < ctxt->incNr;i++) {
  361. if (ctxt->incTab[i] != NULL)
  362. xmlXIncludeFreeRef(ctxt->incTab[i]);
  363. }
  364. if (ctxt->incTab != NULL)
  365. xmlFree(ctxt->incTab);
  366. if (ctxt->txtTab != NULL) {
  367. for (i = 0;i < ctxt->txtNr;i++) {
  368. if (ctxt->txtTab[i] != NULL)
  369. xmlFree(ctxt->txtTab[i]);
  370. }
  371. xmlFree(ctxt->txtTab);
  372. }
  373. if (ctxt->txturlTab != NULL) {
  374. for (i = 0;i < ctxt->txtNr;i++) {
  375. if (ctxt->txturlTab[i] != NULL)
  376. xmlFree(ctxt->txturlTab[i]);
  377. }
  378. xmlFree(ctxt->txturlTab);
  379. }
  380. if (ctxt->base != NULL) {
  381. xmlFree(ctxt->base);
  382. }
  383. xmlFree(ctxt);
  384. }
  385. /**
  386. * xmlXIncludeParseFile:
  387. * @ctxt: the XInclude context
  388. * @URL: the URL or file path
  389. *
  390. * parse a document for XInclude
  391. */
  392. static xmlDocPtr
  393. xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
  394. xmlDocPtr ret;
  395. xmlParserCtxtPtr pctxt;
  396. xmlParserInputPtr inputStream;
  397. xmlInitParser();
  398. pctxt = xmlNewParserCtxt();
  399. if (pctxt == NULL) {
  400. xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
  401. return(NULL);
  402. }
  403. /*
  404. * pass in the application data to the parser context.
  405. */
  406. pctxt->_private = ctxt->_private;
  407. /*
  408. * try to ensure that new documents included are actually
  409. * built with the same dictionary as the including document.
  410. */
  411. if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) {
  412. if (pctxt->dict != NULL)
  413. xmlDictFree(pctxt->dict);
  414. pctxt->dict = ctxt->doc->dict;
  415. xmlDictReference(pctxt->dict);
  416. }
  417. xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
  418. /* Don't read from stdin. */
  419. if ((URL != NULL) && (strcmp(URL, "-") == 0))
  420. URL = "./-";
  421. inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
  422. if (inputStream == NULL) {
  423. xmlFreeParserCtxt(pctxt);
  424. return(NULL);
  425. }
  426. inputPush(pctxt, inputStream);
  427. if (pctxt->directory == NULL)
  428. pctxt->directory = xmlParserGetDirectory(URL);
  429. pctxt->loadsubset |= XML_DETECT_IDS;
  430. xmlParseDocument(pctxt);
  431. if (pctxt->wellFormed) {
  432. ret = pctxt->myDoc;
  433. }
  434. else {
  435. ret = NULL;
  436. if (pctxt->myDoc != NULL)
  437. xmlFreeDoc(pctxt->myDoc);
  438. pctxt->myDoc = NULL;
  439. }
  440. xmlFreeParserCtxt(pctxt);
  441. return(ret);
  442. }
  443. /**
  444. * xmlXIncludeAddNode:
  445. * @ctxt: the XInclude context
  446. * @cur: the new node
  447. *
  448. * Add a new node to process to an XInclude context
  449. */
  450. static int
  451. xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
  452. xmlXIncludeRefPtr ref;
  453. xmlURIPtr uri;
  454. xmlChar *URL;
  455. xmlChar *fragment = NULL;
  456. xmlChar *href;
  457. xmlChar *parse;
  458. xmlChar *base;
  459. xmlChar *URI;
  460. int xml = 1, i; /* default Issue 64 */
  461. int local = 0;
  462. if (ctxt == NULL)
  463. return(-1);
  464. if (cur == NULL)
  465. return(-1);
  466. #ifdef DEBUG_XINCLUDE
  467. xmlGenericError(xmlGenericErrorContext, "Add node\n");
  468. #endif
  469. /*
  470. * read the attributes
  471. */
  472. href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
  473. if (href == NULL) {
  474. href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
  475. if (href == NULL)
  476. return(-1);
  477. }
  478. if ((href[0] == '#') || (href[0] == 0))
  479. local = 1;
  480. parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
  481. if (parse != NULL) {
  482. if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
  483. xml = 1;
  484. else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
  485. xml = 0;
  486. else {
  487. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
  488. "invalid value %s for 'parse'\n", parse);
  489. if (href != NULL)
  490. xmlFree(href);
  491. if (parse != NULL)
  492. xmlFree(parse);
  493. return(-1);
  494. }
  495. }
  496. /*
  497. * compute the URI
  498. */
  499. base = xmlNodeGetBase(ctxt->doc, cur);
  500. if (base == NULL) {
  501. URI = xmlBuildURI(href, ctxt->doc->URL);
  502. } else {
  503. URI = xmlBuildURI(href, base);
  504. }
  505. if (URI == NULL) {
  506. xmlChar *escbase;
  507. xmlChar *eschref;
  508. /*
  509. * Some escaping may be needed
  510. */
  511. escbase = xmlURIEscape(base);
  512. eschref = xmlURIEscape(href);
  513. URI = xmlBuildURI(eschref, escbase);
  514. if (escbase != NULL)
  515. xmlFree(escbase);
  516. if (eschref != NULL)
  517. xmlFree(eschref);
  518. }
  519. if (parse != NULL)
  520. xmlFree(parse);
  521. if (href != NULL)
  522. xmlFree(href);
  523. if (base != NULL)
  524. xmlFree(base);
  525. if (URI == NULL) {
  526. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
  527. "failed build URL\n", NULL);
  528. return(-1);
  529. }
  530. fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
  531. /*
  532. * Check the URL and remove any fragment identifier
  533. */
  534. uri = xmlParseURI((const char *)URI);
  535. if (uri == NULL) {
  536. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
  537. "invalid value URI %s\n", URI);
  538. if (fragment != NULL)
  539. xmlFree(fragment);
  540. xmlFree(URI);
  541. return(-1);
  542. }
  543. if (uri->fragment != NULL) {
  544. if (ctxt->legacy != 0) {
  545. if (fragment == NULL) {
  546. fragment = (xmlChar *) uri->fragment;
  547. } else {
  548. xmlFree(uri->fragment);
  549. }
  550. } else {
  551. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
  552. "Invalid fragment identifier in URI %s use the xpointer attribute\n",
  553. URI);
  554. if (fragment != NULL)
  555. xmlFree(fragment);
  556. xmlFreeURI(uri);
  557. xmlFree(URI);
  558. return(-1);
  559. }
  560. uri->fragment = NULL;
  561. }
  562. URL = xmlSaveUri(uri);
  563. xmlFreeURI(uri);
  564. xmlFree(URI);
  565. if (URL == NULL) {
  566. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
  567. "invalid value URI %s\n", URI);
  568. if (fragment != NULL)
  569. xmlFree(fragment);
  570. return(-1);
  571. }
  572. /*
  573. * If local and xml then we need a fragment
  574. */
  575. if ((local == 1) && (xml == 1) &&
  576. ((fragment == NULL) || (fragment[0] == 0))) {
  577. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
  578. "detected a local recursion with no xpointer in %s\n",
  579. URL);
  580. xmlFree(URL);
  581. xmlFree(fragment);
  582. return(-1);
  583. }
  584. /*
  585. * Check the URL against the stack for recursions
  586. */
  587. if ((!local) && (xml == 1)) {
  588. for (i = 0;i < ctxt->urlNr;i++) {
  589. if (xmlStrEqual(URL, ctxt->urlTab[i])) {
  590. xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
  591. "detected a recursion in %s\n", URL);
  592. xmlFree(URL);
  593. xmlFree(fragment);
  594. return(-1);
  595. }
  596. }
  597. }
  598. ref = xmlXIncludeNewRef(ctxt, URL, cur);
  599. xmlFree(URL);
  600. if (ref == NULL) {
  601. return(-1);
  602. }
  603. ref->fragment = fragment;
  604. ref->doc = NULL;
  605. ref->xml = xml;
  606. ref->count = 1;
  607. return(0);
  608. }
  609. /**
  610. * xmlXIncludeRecurseDoc:
  611. * @ctxt: the XInclude context
  612. * @doc: the new document
  613. * @url: the associated URL
  614. *
  615. * The XInclude recursive nature is handled at this point.
  616. */
  617. static void
  618. xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
  619. const xmlURL url ATTRIBUTE_UNUSED) {
  620. xmlXIncludeCtxtPtr newctxt;
  621. int i;
  622. /*
  623. * Avoid recursion in already substituted resources
  624. for (i = 0;i < ctxt->urlNr;i++) {
  625. if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
  626. return;
  627. }
  628. */
  629. #ifdef DEBUG_XINCLUDE
  630. xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
  631. #endif
  632. /*
  633. * Handle recursion here.
  634. */
  635. newctxt = xmlXIncludeNewContext(doc);
  636. if (newctxt != NULL) {
  637. /*
  638. * Copy the private user data
  639. */
  640. newctxt->_private = ctxt->_private;
  641. /*
  642. * Copy the existing document set
  643. */
  644. newctxt->incMax = ctxt->incMax;
  645. newctxt->incNr = ctxt->incNr;
  646. newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
  647. sizeof(newctxt->incTab[0]));
  648. if (newctxt->incTab == NULL) {
  649. xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
  650. xmlFree(newctxt);
  651. return;
  652. }
  653. /*
  654. * copy the urlTab
  655. */
  656. newctxt->urlMax = ctxt->urlMax;
  657. newctxt->urlNr = ctxt->urlNr;
  658. newctxt->urlTab = ctxt->urlTab;
  659. /*
  660. * Inherit the existing base
  661. */
  662. newctxt->base = xmlStrdup(ctxt->base);
  663. /*
  664. * Inherit the documents already in use by other includes
  665. */
  666. newctxt->incBase = ctxt->incNr;
  667. for (i = 0;i < ctxt->incNr;i++) {
  668. newctxt->incTab[i] = ctxt->incTab[i];
  669. newctxt->incTab[i]->count++; /* prevent the recursion from
  670. freeing it */
  671. }
  672. /*
  673. * The new context should also inherit the Parse Flags
  674. * (bug 132597)
  675. */
  676. newctxt->parseFlags = ctxt->parseFlags;
  677. newctxt->incTotal = ctxt->incTotal;
  678. xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc), 0);
  679. ctxt->incTotal = newctxt->incTotal;
  680. for (i = 0;i < ctxt->incNr;i++) {
  681. newctxt->incTab[i]->count--;
  682. newctxt->incTab[i] = NULL;
  683. }
  684. /* urlTab may have been reallocated */
  685. ctxt->urlTab = newctxt->urlTab;
  686. ctxt->urlMax = newctxt->urlMax;
  687. newctxt->urlMax = 0;
  688. newctxt->urlNr = 0;
  689. newctxt->urlTab = NULL;
  690. xmlXIncludeFreeContext(newctxt);
  691. }
  692. #ifdef DEBUG_XINCLUDE
  693. xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
  694. #endif
  695. }
  696. /**
  697. * xmlXIncludeAddTxt:
  698. * @ctxt: the XInclude context
  699. * @txt: the new text node
  700. * @url: the associated URL
  701. *
  702. * Add a new text node to the list
  703. */
  704. static void
  705. xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt,
  706. const xmlURL url) {
  707. #ifdef DEBUG_XINCLUDE
  708. xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
  709. #endif
  710. if (ctxt->txtMax == 0) {
  711. ctxt->txtMax = 4;
  712. ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
  713. sizeof(ctxt->txtTab[0]));
  714. if (ctxt->txtTab == NULL) {
  715. xmlXIncludeErrMemory(ctxt, NULL, "processing text");
  716. return;
  717. }
  718. ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
  719. sizeof(ctxt->txturlTab[0]));
  720. if (ctxt->txturlTab == NULL) {
  721. xmlXIncludeErrMemory(ctxt, NULL, "processing text");
  722. return;
  723. }
  724. }
  725. if (ctxt->txtNr >= ctxt->txtMax) {
  726. ctxt->txtMax *= 2;
  727. ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab,
  728. ctxt->txtMax * sizeof(ctxt->txtTab[0]));
  729. if (ctxt->txtTab == NULL) {
  730. xmlXIncludeErrMemory(ctxt, NULL, "processing text");
  731. return;
  732. }
  733. ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
  734. ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
  735. if (ctxt->txturlTab == NULL) {
  736. xmlXIncludeErrMemory(ctxt, NULL, "processing text");
  737. return;
  738. }
  739. }
  740. ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
  741. ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
  742. ctxt->txtNr++;
  743. }
  744. /************************************************************************
  745. * *
  746. * Node copy with specific semantic *
  747. * *
  748. ************************************************************************/
  749. static xmlNodePtr
  750. xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
  751. xmlDocPtr source, xmlNodePtr elem);
  752. /**
  753. * xmlXIncludeCopyNode:
  754. * @ctxt: the XInclude context
  755. * @target: the document target
  756. * @source: the document source
  757. * @elem: the element
  758. *
  759. * Make a copy of the node while preserving the XInclude semantic
  760. * of the Infoset copy
  761. */
  762. static xmlNodePtr
  763. xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
  764. xmlDocPtr source, xmlNodePtr elem) {
  765. xmlNodePtr result = NULL;
  766. if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
  767. (elem == NULL))
  768. return(NULL);
  769. if (elem->type == XML_DTD_NODE)
  770. return(NULL);
  771. if (elem->type == XML_DOCUMENT_NODE)
  772. result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
  773. else
  774. result = xmlDocCopyNode(elem, target, 1);
  775. return(result);
  776. }
  777. /**
  778. * xmlXIncludeCopyNodeList:
  779. * @ctxt: the XInclude context
  780. * @target: the document target
  781. * @source: the document source
  782. * @elem: the element list
  783. *
  784. * Make a copy of the node list while preserving the XInclude semantic
  785. * of the Infoset copy
  786. */
  787. static xmlNodePtr
  788. xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
  789. xmlDocPtr source, xmlNodePtr elem) {
  790. xmlNodePtr cur, res, result = NULL, last = NULL;
  791. if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
  792. (elem == NULL))
  793. return(NULL);
  794. cur = elem;
  795. while (cur != NULL) {
  796. res = xmlXIncludeCopyNode(ctxt, target, source, cur);
  797. if (res != NULL) {
  798. if (result == NULL) {
  799. result = last = res;
  800. } else {
  801. last->next = res;
  802. res->prev = last;
  803. last = res;
  804. }
  805. }
  806. cur = cur->next;
  807. }
  808. return(result);
  809. }
  810. /**
  811. * xmlXIncludeGetNthChild:
  812. * @cur: the node
  813. * @no: the child number
  814. *
  815. * Returns the @n'th element child of @cur or NULL
  816. */
  817. static xmlNodePtr
  818. xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
  819. int i;
  820. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  821. return(NULL);
  822. cur = cur->children;
  823. for (i = 0;i <= no;cur = cur->next) {
  824. if (cur == NULL)
  825. return(cur);
  826. if ((cur->type == XML_ELEMENT_NODE) ||
  827. (cur->type == XML_DOCUMENT_NODE) ||
  828. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  829. i++;
  830. if (i == no)
  831. break;
  832. }
  833. }
  834. return(cur);
  835. }
  836. xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
  837. /**
  838. * xmlXIncludeCopyRange:
  839. * @ctxt: the XInclude context
  840. * @target: the document target
  841. * @source: the document source
  842. * @obj: the XPointer result from the evaluation.
  843. *
  844. * Build a node list tree copy of the XPointer result.
  845. *
  846. * Returns an xmlNodePtr list or NULL.
  847. * The caller has to free the node tree.
  848. */
  849. static xmlNodePtr
  850. xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
  851. xmlDocPtr source, xmlXPathObjectPtr range) {
  852. /* pointers to generated nodes */
  853. xmlNodePtr list = NULL, last = NULL, listParent = NULL;
  854. xmlNodePtr tmp, tmp2;
  855. /* pointers to traversal nodes */
  856. xmlNodePtr start, cur, end;
  857. int index1, index2;
  858. int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
  859. if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
  860. (range == NULL))
  861. return(NULL);
  862. if (range->type != XPATH_RANGE)
  863. return(NULL);
  864. start = (xmlNodePtr) range->user;
  865. if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
  866. return(NULL);
  867. end = range->user2;
  868. if (end == NULL)
  869. return(xmlDocCopyNode(start, target, 1));
  870. if (end->type == XML_NAMESPACE_DECL)
  871. return(NULL);
  872. cur = start;
  873. index1 = range->index;
  874. index2 = range->index2;
  875. /*
  876. * level is depth of the current node under consideration
  877. * list is the pointer to the root of the output tree
  878. * listParent is a pointer to the parent of output tree (within
  879. the included file) in case we need to add another level
  880. * last is a pointer to the last node added to the output tree
  881. * lastLevel is the depth of last (relative to the root)
  882. */
  883. while (cur != NULL) {
  884. /*
  885. * Check if our output tree needs a parent
  886. */
  887. if (level < 0) {
  888. while (level < 0) {
  889. /* copy must include namespaces and properties */
  890. tmp2 = xmlDocCopyNode(listParent, target, 2);
  891. xmlAddChild(tmp2, list);
  892. list = tmp2;
  893. listParent = listParent->parent;
  894. level++;
  895. }
  896. last = list;
  897. lastLevel = 0;
  898. }
  899. /*
  900. * Check whether we need to change our insertion point
  901. */
  902. while (level < lastLevel) {
  903. last = last->parent;
  904. lastLevel --;
  905. }
  906. if (cur == end) { /* Are we at the end of the range? */
  907. if (cur->type == XML_TEXT_NODE) {
  908. const xmlChar *content = cur->content;
  909. int len;
  910. if (content == NULL) {
  911. tmp = xmlNewTextLen(NULL, 0);
  912. } else {
  913. len = index2;
  914. if ((cur == start) && (index1 > 1)) {
  915. content += (index1 - 1);
  916. len -= (index1 - 1);
  917. } else {
  918. len = index2;
  919. }
  920. tmp = xmlNewTextLen(content, len);
  921. }
  922. /* single sub text node selection */
  923. if (list == NULL)
  924. return(tmp);
  925. /* prune and return full set */
  926. if (level == lastLevel)
  927. xmlAddNextSibling(last, tmp);
  928. else
  929. xmlAddChild(last, tmp);
  930. return(list);
  931. } else { /* ending node not a text node */
  932. endLevel = level; /* remember the level of the end node */
  933. endFlag = 1;
  934. /* last node - need to take care of properties + namespaces */
  935. tmp = xmlDocCopyNode(cur, target, 2);
  936. if (list == NULL) {
  937. list = tmp;
  938. listParent = cur->parent;
  939. last = tmp;
  940. } else {
  941. if (level == lastLevel)
  942. last = xmlAddNextSibling(last, tmp);
  943. else {
  944. last = xmlAddChild(last, tmp);
  945. lastLevel = level;
  946. }
  947. }
  948. if (index2 > 1) {
  949. end = xmlXIncludeGetNthChild(cur, index2 - 1);
  950. index2 = 0;
  951. }
  952. if ((cur == start) && (index1 > 1)) {
  953. cur = xmlXIncludeGetNthChild(cur, index1 - 1);
  954. index1 = 0;
  955. } else {
  956. cur = cur->children;
  957. }
  958. level++; /* increment level to show change */
  959. /*
  960. * Now gather the remaining nodes from cur to end
  961. */
  962. continue; /* while */
  963. }
  964. } else if (cur == start) { /* Not at the end, are we at start? */
  965. if ((cur->type == XML_TEXT_NODE) ||
  966. (cur->type == XML_CDATA_SECTION_NODE)) {
  967. const xmlChar *content = cur->content;
  968. if (content == NULL) {
  969. tmp = xmlNewTextLen(NULL, 0);
  970. } else {
  971. if (index1 > 1) {
  972. content += (index1 - 1);
  973. index1 = 0;
  974. }
  975. tmp = xmlNewText(content);
  976. }
  977. last = list = tmp;
  978. listParent = cur->parent;
  979. } else { /* Not text node */
  980. /*
  981. * start of the range - need to take care of
  982. * properties and namespaces
  983. */
  984. tmp = xmlDocCopyNode(cur, target, 2);
  985. list = last = tmp;
  986. listParent = cur->parent;
  987. if (index1 > 1) { /* Do we need to position? */
  988. cur = xmlXIncludeGetNthChild(cur, index1 - 1);
  989. level = lastLevel = 1;
  990. index1 = 0;
  991. /*
  992. * Now gather the remaining nodes from cur to end
  993. */
  994. continue; /* while */
  995. }
  996. }
  997. } else {
  998. tmp = NULL;
  999. switch (cur->type) {
  1000. case XML_DTD_NODE:
  1001. case XML_ELEMENT_DECL:
  1002. case XML_ATTRIBUTE_DECL:
  1003. case XML_ENTITY_NODE:
  1004. /* Do not copy DTD information */
  1005. break;
  1006. case XML_ENTITY_DECL:
  1007. /* handle crossing entities -> stack needed */
  1008. break;
  1009. case XML_XINCLUDE_START:
  1010. case XML_XINCLUDE_END:
  1011. /* don't consider it part of the tree content */
  1012. break;
  1013. case XML_ATTRIBUTE_NODE:
  1014. /* Humm, should not happen ! */
  1015. break;
  1016. default:
  1017. /*
  1018. * Middle of the range - need to take care of
  1019. * properties and namespaces
  1020. */
  1021. tmp = xmlDocCopyNode(cur, target, 2);
  1022. break;
  1023. }
  1024. if (tmp != NULL) {
  1025. if (level == lastLevel)
  1026. last = xmlAddNextSibling(last, tmp);
  1027. else {
  1028. last = xmlAddChild(last, tmp);
  1029. lastLevel = level;
  1030. }
  1031. }
  1032. }
  1033. /*
  1034. * Skip to next node in document order
  1035. */
  1036. cur = xmlXPtrAdvanceNode(cur, &level);
  1037. if (endFlag && (level >= endLevel))
  1038. break;
  1039. }
  1040. return(list);
  1041. }
  1042. /**
  1043. * xmlXIncludeBuildNodeList:
  1044. * @ctxt: the XInclude context
  1045. * @target: the document target
  1046. * @source: the document source
  1047. * @obj: the XPointer result from the evaluation.
  1048. *
  1049. * Build a node list tree copy of the XPointer result.
  1050. * This will drop Attributes and Namespace declarations.
  1051. *
  1052. * Returns an xmlNodePtr list or NULL.
  1053. * the caller has to free the node tree.
  1054. */
  1055. static xmlNodePtr
  1056. xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
  1057. xmlDocPtr source, xmlXPathObjectPtr obj) {
  1058. xmlNodePtr list = NULL, last = NULL;
  1059. int i;
  1060. if (source == NULL)
  1061. source = ctxt->doc;
  1062. if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
  1063. (obj == NULL))
  1064. return(NULL);
  1065. switch (obj->type) {
  1066. case XPATH_NODESET: {
  1067. xmlNodeSetPtr set = obj->nodesetval;
  1068. if (set == NULL)
  1069. return(NULL);
  1070. for (i = 0;i < set->nodeNr;i++) {
  1071. if (set->nodeTab[i] == NULL)
  1072. continue;
  1073. switch (set->nodeTab[i]->type) {
  1074. case XML_TEXT_NODE:
  1075. case XML_CDATA_SECTION_NODE:
  1076. case XML_ELEMENT_NODE:
  1077. case XML_ENTITY_REF_NODE:
  1078. case XML_ENTITY_NODE:
  1079. case XML_PI_NODE:
  1080. case XML_COMMENT_NODE:
  1081. case XML_DOCUMENT_NODE:
  1082. case XML_HTML_DOCUMENT_NODE:
  1083. #ifdef LIBXML_DOCB_ENABLED
  1084. case XML_DOCB_DOCUMENT_NODE:
  1085. #endif
  1086. case XML_XINCLUDE_END:
  1087. break;
  1088. case XML_XINCLUDE_START: {
  1089. xmlNodePtr tmp, cur = set->nodeTab[i];
  1090. cur = cur->next;
  1091. while (cur != NULL) {
  1092. switch(cur->type) {
  1093. case XML_TEXT_NODE:
  1094. case XML_CDATA_SECTION_NODE:
  1095. case XML_ELEMENT_NODE:
  1096. case XML_ENTITY_REF_NODE:
  1097. case XML_ENTITY_NODE:
  1098. case XML_PI_NODE:
  1099. case XML_COMMENT_NODE:
  1100. tmp = xmlXIncludeCopyNode(ctxt, target,
  1101. source, cur);
  1102. if (last == NULL) {
  1103. list = last = tmp;
  1104. } else {
  1105. last = xmlAddNextSibling(last, tmp);
  1106. }
  1107. cur = cur->next;
  1108. continue;
  1109. default:
  1110. break;
  1111. }
  1112. break;
  1113. }
  1114. continue;
  1115. }
  1116. case XML_ATTRIBUTE_NODE:
  1117. case XML_NAMESPACE_DECL:
  1118. case XML_DOCUMENT_TYPE_NODE:
  1119. case XML_DOCUMENT_FRAG_NODE:
  1120. case XML_NOTATION_NODE:
  1121. case XML_DTD_NODE:
  1122. case XML_ELEMENT_DECL:
  1123. case XML_ATTRIBUTE_DECL:
  1124. case XML_ENTITY_DECL:
  1125. continue; /* for */
  1126. }
  1127. if (last == NULL)
  1128. list = last = xmlXIncludeCopyNode(ctxt, target, source,
  1129. set->nodeTab[i]);
  1130. else {
  1131. xmlAddNextSibling(last,
  1132. xmlXIncludeCopyNode(ctxt, target, source,
  1133. set->nodeTab[i]));
  1134. if (last->next != NULL)
  1135. last = last->next;
  1136. }
  1137. }
  1138. break;
  1139. }
  1140. #ifdef LIBXML_XPTR_ENABLED
  1141. case XPATH_LOCATIONSET: {
  1142. xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
  1143. if (set == NULL)
  1144. return(NULL);
  1145. for (i = 0;i < set->locNr;i++) {
  1146. if (last == NULL)
  1147. list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
  1148. set->locTab[i]);
  1149. else
  1150. xmlAddNextSibling(last,
  1151. xmlXIncludeCopyXPointer(ctxt, target, source,
  1152. set->locTab[i]));
  1153. if (last != NULL) {
  1154. while (last->next != NULL)
  1155. last = last->next;
  1156. }
  1157. }
  1158. break;
  1159. }
  1160. case XPATH_RANGE:
  1161. return(xmlXIncludeCopyRange(ctxt, target, source, obj));
  1162. #endif
  1163. case XPATH_POINT:
  1164. /* points are ignored in XInclude */
  1165. break;
  1166. default:
  1167. break;
  1168. }
  1169. return(list);
  1170. }
  1171. /************************************************************************
  1172. * *
  1173. * XInclude I/O handling *
  1174. * *
  1175. ************************************************************************/
  1176. typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
  1177. typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
  1178. struct _xmlXIncludeMergeData {
  1179. xmlDocPtr doc;
  1180. xmlXIncludeCtxtPtr ctxt;
  1181. };
  1182. /**
  1183. * xmlXIncludeMergeOneEntity:
  1184. * @ent: the entity
  1185. * @doc: the including doc
  1186. * @nr: the entity name
  1187. *
  1188. * Implements the merge of one entity
  1189. */
  1190. static void
  1191. xmlXIncludeMergeEntity(void *payload, void *vdata,
  1192. const xmlChar *name ATTRIBUTE_UNUSED) {
  1193. xmlEntityPtr ent = (xmlEntityPtr) payload;
  1194. xmlXIncludeMergeDataPtr data = (xmlXIncludeMergeDataPtr) vdata;
  1195. xmlEntityPtr ret, prev;
  1196. xmlDocPtr doc;
  1197. xmlXIncludeCtxtPtr ctxt;
  1198. if ((ent == NULL) || (data == NULL))
  1199. return;
  1200. ctxt = data->ctxt;
  1201. doc = data->doc;
  1202. if ((ctxt == NULL) || (doc == NULL))
  1203. return;
  1204. switch (ent->etype) {
  1205. case XML_INTERNAL_PARAMETER_ENTITY:
  1206. case XML_EXTERNAL_PARAMETER_ENTITY:
  1207. case XML_INTERNAL_PREDEFINED_ENTITY:
  1208. return;
  1209. case XML_INTERNAL_GENERAL_ENTITY:
  1210. case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
  1211. case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
  1212. break;
  1213. }
  1214. ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
  1215. ent->SystemID, ent->content);
  1216. if (ret != NULL) {
  1217. if (ent->URI != NULL)
  1218. ret->URI = xmlStrdup(ent->URI);
  1219. } else {
  1220. prev = xmlGetDocEntity(doc, ent->name);
  1221. if (prev != NULL) {
  1222. if (ent->etype != prev->etype)
  1223. goto error;
  1224. if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
  1225. if (!xmlStrEqual(ent->SystemID, prev->SystemID))
  1226. goto error;
  1227. } else if ((ent->ExternalID != NULL) &&
  1228. (prev->ExternalID != NULL)) {
  1229. if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
  1230. goto error;
  1231. } else if ((ent->content != NULL) && (prev->content != NULL)) {
  1232. if (!xmlStrEqual(ent->content, prev->content))
  1233. goto error;
  1234. } else {
  1235. goto error;
  1236. }
  1237. }
  1238. }
  1239. return;
  1240. error:
  1241. switch (ent->etype) {
  1242. case XML_INTERNAL_PARAMETER_ENTITY:
  1243. case XML_EXTERNAL_PARAMETER_ENTITY:
  1244. case XML_INTERNAL_PREDEFINED_ENTITY:
  1245. case XML_INTERNAL_GENERAL_ENTITY:
  1246. case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
  1247. return;
  1248. case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
  1249. break;
  1250. }
  1251. xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
  1252. "mismatch in redefinition of entity %s\n",
  1253. ent->name);
  1254. }
  1255. /**
  1256. * xmlXIncludeMergeEntities:
  1257. * @ctxt: an XInclude context
  1258. * @doc: the including doc
  1259. * @from: the included doc
  1260. *
  1261. * Implements the entity merge
  1262. *
  1263. * Returns 0 if merge succeeded, -1 if some processing failed
  1264. */
  1265. static int
  1266. xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
  1267. xmlDocPtr from) {
  1268. xmlNodePtr cur;
  1269. xmlDtdPtr target, source;
  1270. if (ctxt == NULL)
  1271. return(-1);
  1272. if ((from == NULL) || (from->intSubset == NULL))
  1273. return(0);
  1274. target = doc->intSubset;
  1275. if (target == NULL) {
  1276. cur = xmlDocGetRootElement(doc);
  1277. if (cur == NULL)
  1278. return(-1);
  1279. target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
  1280. if (target == NULL)
  1281. return(-1);
  1282. }
  1283. source = from->intSubset;
  1284. if ((source != NULL) && (source->entities != NULL)) {
  1285. xmlXIncludeMergeData data;
  1286. data.ctxt = ctxt;
  1287. data.doc = doc;
  1288. xmlHashScan((xmlHashTablePtr) source->entities,
  1289. xmlXIncludeMergeEntity, &data);
  1290. }
  1291. source = from->extSubset;
  1292. if ((source != NULL) && (source->entities != NULL)) {
  1293. xmlXIncludeMergeData data;
  1294. data.ctxt = ctxt;
  1295. data.doc = doc;
  1296. /*
  1297. * don't duplicate existing stuff when external subsets are the same
  1298. */
  1299. if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
  1300. (!xmlStrEqual(target->SystemID, source->SystemID))) {
  1301. xmlHashScan((xmlHashTablePtr) source->entities,
  1302. xmlXIncludeMergeEntity, &data);
  1303. }
  1304. }
  1305. return(0);
  1306. }
  1307. /**
  1308. * xmlXIncludeLoadDoc:
  1309. * @ctxt: the XInclude context
  1310. * @url: the associated URL
  1311. * @nr: the xinclude node number
  1312. *
  1313. * Load the document, and store the result in the XInclude context
  1314. *
  1315. * Returns 0 in case of success, -1 in case of failure
  1316. */
  1317. static int
  1318. xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
  1319. xmlDocPtr doc;
  1320. xmlURIPtr uri;
  1321. xmlChar *URL;
  1322. xmlChar *fragment = NULL;
  1323. int i = 0;
  1324. #ifdef LIBXML_XPTR_ENABLED
  1325. int saveFlags;
  1326. #endif
  1327. #ifdef DEBUG_XINCLUDE
  1328. xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
  1329. #endif
  1330. /*
  1331. * Check the URL and remove any fragment identifier
  1332. */
  1333. uri = xmlParseURI((const char *)url);
  1334. if (uri == NULL) {
  1335. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1336. XML_XINCLUDE_HREF_URI,
  1337. "invalid value URI %s\n", url);
  1338. return(-1);
  1339. }
  1340. if (uri->fragment != NULL) {
  1341. fragment = (xmlChar *) uri->fragment;
  1342. uri->fragment = NULL;
  1343. }
  1344. if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
  1345. (ctxt->incTab[nr]->fragment != NULL)) {
  1346. if (fragment != NULL) xmlFree(fragment);
  1347. fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
  1348. }
  1349. URL = xmlSaveUri(uri);
  1350. xmlFreeURI(uri);
  1351. if (URL == NULL) {
  1352. if (ctxt->incTab != NULL)
  1353. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1354. XML_XINCLUDE_HREF_URI,
  1355. "invalid value URI %s\n", url);
  1356. else
  1357. xmlXIncludeErr(ctxt, NULL,
  1358. XML_XINCLUDE_HREF_URI,
  1359. "invalid value URI %s\n", url);
  1360. if (fragment != NULL)
  1361. xmlFree(fragment);
  1362. return(-1);
  1363. }
  1364. /*
  1365. * Handling of references to the local document are done
  1366. * directly through ctxt->doc.
  1367. */
  1368. if ((URL[0] == 0) || (URL[0] == '#') ||
  1369. ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
  1370. doc = ctxt->doc;
  1371. goto loaded;
  1372. }
  1373. /*
  1374. * Prevent reloading twice the document.
  1375. */
  1376. for (i = 0; i < ctxt->incNr; i++) {
  1377. if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
  1378. (ctxt->incTab[i]->doc != NULL)) {
  1379. doc = ctxt->incTab[i]->doc;
  1380. #ifdef DEBUG_XINCLUDE
  1381. printf("Already loaded %s\n", URL);
  1382. #endif
  1383. goto loaded;
  1384. }
  1385. }
  1386. /*
  1387. * Load it.
  1388. */
  1389. #ifdef DEBUG_XINCLUDE
  1390. printf("loading %s\n", URL);
  1391. #endif
  1392. #ifdef LIBXML_XPTR_ENABLED
  1393. /*
  1394. * If this is an XPointer evaluation, we want to assure that
  1395. * all entities have been resolved prior to processing the
  1396. * referenced document
  1397. */
  1398. saveFlags = ctxt->parseFlags;
  1399. if (fragment != NULL) { /* if this is an XPointer eval */
  1400. ctxt->parseFlags |= XML_PARSE_NOENT;
  1401. }
  1402. #endif
  1403. doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
  1404. #ifdef LIBXML_XPTR_ENABLED
  1405. ctxt->parseFlags = saveFlags;
  1406. #endif
  1407. if (doc == NULL) {
  1408. xmlFree(URL);
  1409. if (fragment != NULL)
  1410. xmlFree(fragment);
  1411. return(-1);
  1412. }
  1413. ctxt->incTab[nr]->doc = doc;
  1414. /*
  1415. * It's possible that the requested URL has been mapped to a
  1416. * completely different location (e.g. through a catalog entry).
  1417. * To check for this, we compare the URL with that of the doc
  1418. * and change it if they disagree (bug 146988).
  1419. */
  1420. if (!xmlStrEqual(URL, doc->URL)) {
  1421. xmlFree(URL);
  1422. URL = xmlStrdup(doc->URL);
  1423. }
  1424. for (i = nr + 1; i < ctxt->incNr; i++) {
  1425. if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
  1426. ctxt->incTab[nr]->count++;
  1427. #ifdef DEBUG_XINCLUDE
  1428. printf("Increasing %s count since reused\n", URL);
  1429. #endif
  1430. break;
  1431. }
  1432. }
  1433. /*
  1434. * Make sure we have all entities fixed up
  1435. */
  1436. xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
  1437. /*
  1438. * We don't need the DTD anymore, free up space
  1439. if (doc->intSubset != NULL) {
  1440. xmlUnlinkNode((xmlNodePtr) doc->intSubset);
  1441. xmlFreeNode((xmlNodePtr) doc->intSubset);
  1442. doc->intSubset = NULL;
  1443. }
  1444. if (doc->extSubset != NULL) {
  1445. xmlUnlinkNode((xmlNodePtr) doc->extSubset);
  1446. xmlFreeNode((xmlNodePtr) doc->extSubset);
  1447. doc->extSubset = NULL;
  1448. }
  1449. */
  1450. xmlXIncludeRecurseDoc(ctxt, doc, URL);
  1451. loaded:
  1452. if (fragment == NULL) {
  1453. /*
  1454. * Add the top children list as the replacement copy.
  1455. */
  1456. ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
  1457. doc, doc->children);
  1458. }
  1459. #ifdef LIBXML_XPTR_ENABLED
  1460. else {
  1461. /*
  1462. * Computes the XPointer expression and make a copy used
  1463. * as the replacement copy.
  1464. */
  1465. xmlXPathObjectPtr xptr;
  1466. xmlXPathContextPtr xptrctxt;
  1467. xmlNodeSetPtr set;
  1468. xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
  1469. if (xptrctxt == NULL) {
  1470. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1471. XML_XINCLUDE_XPTR_FAILED,
  1472. "could not create XPointer context\n", NULL);
  1473. xmlFree(URL);
  1474. xmlFree(fragment);
  1475. return(-1);
  1476. }
  1477. xptr = xmlXPtrEval(fragment, xptrctxt);
  1478. if (xptr == NULL) {
  1479. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1480. XML_XINCLUDE_XPTR_FAILED,
  1481. "XPointer evaluation failed: #%s\n",
  1482. fragment);
  1483. xmlXPathFreeContext(xptrctxt);
  1484. xmlFree(URL);
  1485. xmlFree(fragment);
  1486. return(-1);
  1487. }
  1488. switch (xptr->type) {
  1489. case XPATH_UNDEFINED:
  1490. case XPATH_BOOLEAN:
  1491. case XPATH_NUMBER:
  1492. case XPATH_STRING:
  1493. case XPATH_POINT:
  1494. case XPATH_USERS:
  1495. case XPATH_XSLT_TREE:
  1496. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1497. XML_XINCLUDE_XPTR_RESULT,
  1498. "XPointer is not a range: #%s\n",
  1499. fragment);
  1500. xmlXPathFreeObject(xptr);
  1501. xmlXPathFreeContext(xptrctxt);
  1502. xmlFree(URL);
  1503. xmlFree(fragment);
  1504. return(-1);
  1505. case XPATH_NODESET:
  1506. if ((xptr->nodesetval == NULL) ||
  1507. (xptr->nodesetval->nodeNr <= 0)) {
  1508. xmlXPathFreeObject(xptr);
  1509. xmlXPathFreeContext(xptrctxt);
  1510. xmlFree(URL);
  1511. xmlFree(fragment);
  1512. return(-1);
  1513. }
  1514. case XPATH_RANGE:
  1515. case XPATH_LOCATIONSET:
  1516. break;
  1517. }
  1518. set = xptr->nodesetval;
  1519. if (set != NULL) {
  1520. for (i = 0;i < set->nodeNr;i++) {
  1521. if (set->nodeTab[i] == NULL)
  1522. continue;
  1523. switch (set->nodeTab[i]->type) {
  1524. case XML_ELEMENT_NODE:
  1525. case XML_TEXT_NODE:
  1526. case XML_CDATA_SECTION_NODE:
  1527. case XML_ENTITY_REF_NODE:
  1528. case XML_ENTITY_NODE:
  1529. case XML_PI_NODE:
  1530. case XML_COMMENT_NODE:
  1531. case XML_DOCUMENT_NODE:
  1532. case XML_HTML_DOCUMENT_NODE:
  1533. #ifdef LIBXML_DOCB_ENABLED
  1534. case XML_DOCB_DOCUMENT_NODE:
  1535. #endif
  1536. continue;
  1537. case XML_ATTRIBUTE_NODE:
  1538. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1539. XML_XINCLUDE_XPTR_RESULT,
  1540. "XPointer selects an attribute: #%s\n",
  1541. fragment);
  1542. set->nodeTab[i] = NULL;
  1543. continue;
  1544. case XML_NAMESPACE_DECL:
  1545. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1546. XML_XINCLUDE_XPTR_RESULT,
  1547. "XPointer selects a namespace: #%s\n",
  1548. fragment);
  1549. set->nodeTab[i] = NULL;
  1550. continue;
  1551. case XML_DOCUMENT_TYPE_NODE:
  1552. case XML_DOCUMENT_FRAG_NODE:
  1553. case XML_NOTATION_NODE:
  1554. case XML_DTD_NODE:
  1555. case XML_ELEMENT_DECL:
  1556. case XML_ATTRIBUTE_DECL:
  1557. case XML_ENTITY_DECL:
  1558. case XML_XINCLUDE_START:
  1559. case XML_XINCLUDE_END:
  1560. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1561. XML_XINCLUDE_XPTR_RESULT,
  1562. "XPointer selects unexpected nodes: #%s\n",
  1563. fragment);
  1564. set->nodeTab[i] = NULL;
  1565. set->nodeTab[i] = NULL;
  1566. continue; /* for */
  1567. }
  1568. }
  1569. }
  1570. ctxt->incTab[nr]->inc =
  1571. xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
  1572. xmlXPathFreeObject(xptr);
  1573. xmlXPathFreeContext(xptrctxt);
  1574. xmlFree(fragment);
  1575. }
  1576. #endif
  1577. /*
  1578. * Do the xml:base fixup if needed
  1579. */
  1580. if ((doc != NULL) && (URL != NULL) &&
  1581. (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
  1582. (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
  1583. xmlNodePtr node;
  1584. xmlChar *base;
  1585. xmlChar *curBase;
  1586. /*
  1587. * The base is only adjusted if "necessary", i.e. if the xinclude node
  1588. * has a base specified, or the URL is relative
  1589. */
  1590. base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
  1591. XML_XML_NAMESPACE);
  1592. if (base == NULL) {
  1593. /*
  1594. * No xml:base on the xinclude node, so we check whether the
  1595. * URI base is different than (relative to) the context base
  1596. */
  1597. curBase = xmlBuildRelativeURI(URL, ctxt->base);
  1598. if (curBase == NULL) { /* Error return */
  1599. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1600. XML_XINCLUDE_HREF_URI,
  1601. "trying to build relative URI from %s\n", URL);
  1602. } else {
  1603. /* If the URI doesn't contain a slash, it's not relative */
  1604. if (!xmlStrchr(curBase, (xmlChar) '/'))
  1605. xmlFree(curBase);
  1606. else
  1607. base = curBase;
  1608. }
  1609. }
  1610. if (base != NULL) { /* Adjustment may be needed */
  1611. node = ctxt->incTab[nr]->inc;
  1612. while (node != NULL) {
  1613. /* Only work on element nodes */
  1614. if (node->type == XML_ELEMENT_NODE) {
  1615. curBase = xmlNodeGetBase(node->doc, node);
  1616. /* If no current base, set it */
  1617. if (curBase == NULL) {
  1618. xmlNodeSetBase(node, base);
  1619. } else {
  1620. /*
  1621. * If the current base is the same as the
  1622. * URL of the document, then reset it to be
  1623. * the specified xml:base or the relative URI
  1624. */
  1625. if (xmlStrEqual(curBase, node->doc->URL)) {
  1626. xmlNodeSetBase(node, base);
  1627. } else {
  1628. /*
  1629. * If the element already has an xml:base
  1630. * set, then relativise it if necessary
  1631. */
  1632. xmlChar *xmlBase;
  1633. xmlBase = xmlGetNsProp(node,
  1634. BAD_CAST "base",
  1635. XML_XML_NAMESPACE);
  1636. if (xmlBase != NULL) {
  1637. xmlChar *relBase;
  1638. relBase = xmlBuildURI(xmlBase, base);
  1639. if (relBase == NULL) { /* error */
  1640. xmlXIncludeErr(ctxt,
  1641. ctxt->incTab[nr]->ref,
  1642. XML_XINCLUDE_HREF_URI,
  1643. "trying to rebuild base from %s\n",
  1644. xmlBase);
  1645. } else {
  1646. xmlNodeSetBase(node, relBase);
  1647. xmlFree(relBase);
  1648. }
  1649. xmlFree(xmlBase);
  1650. }
  1651. }
  1652. xmlFree(curBase);
  1653. }
  1654. }
  1655. node = node->next;
  1656. }
  1657. xmlFree(base);
  1658. }
  1659. }
  1660. if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
  1661. (ctxt->incTab[nr]->count <= 1)) {
  1662. #ifdef DEBUG_XINCLUDE
  1663. printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
  1664. #endif
  1665. xmlFreeDoc(ctxt->incTab[nr]->doc);
  1666. ctxt->incTab[nr]->doc = NULL;
  1667. }
  1668. xmlFree(URL);
  1669. return(0);
  1670. }
  1671. /**
  1672. * xmlXIncludeLoadTxt:
  1673. * @ctxt: the XInclude context
  1674. * @url: the associated URL
  1675. * @nr: the xinclude node number
  1676. *
  1677. * Load the content, and store the result in the XInclude context
  1678. *
  1679. * Returns 0 in case of success, -1 in case of failure
  1680. */
  1681. static int
  1682. xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
  1683. xmlParserInputBufferPtr buf;
  1684. xmlNodePtr node;
  1685. xmlURIPtr uri;
  1686. xmlChar *URL;
  1687. int i;
  1688. xmlChar *encoding = NULL;
  1689. xmlCharEncoding enc = (xmlCharEncoding) 0;
  1690. xmlParserCtxtPtr pctxt;
  1691. xmlParserInputPtr inputStream;
  1692. int xinclude_multibyte_fallback_used = 0;
  1693. /* Don't read from stdin. */
  1694. if (xmlStrcmp(url, BAD_CAST "-") == 0)
  1695. url = BAD_CAST "./-";
  1696. /*
  1697. * Check the URL and remove any fragment identifier
  1698. */
  1699. uri = xmlParseURI((const char *)url);
  1700. if (uri == NULL) {
  1701. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
  1702. "invalid value URI %s\n", url);
  1703. return(-1);
  1704. }
  1705. if (uri->fragment != NULL) {
  1706. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
  1707. "fragment identifier forbidden for text: %s\n",
  1708. (const xmlChar *) uri->fragment);
  1709. xmlFreeURI(uri);
  1710. return(-1);
  1711. }
  1712. URL = xmlSaveUri(uri);
  1713. xmlFreeURI(uri);
  1714. if (URL == NULL) {
  1715. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
  1716. "invalid value URI %s\n", url);
  1717. return(-1);
  1718. }
  1719. /*
  1720. * Handling of references to the local document are done
  1721. * directly through ctxt->doc.
  1722. */
  1723. if (URL[0] == 0) {
  1724. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1725. XML_XINCLUDE_TEXT_DOCUMENT,
  1726. "text serialization of document not available\n", NULL);
  1727. xmlFree(URL);
  1728. return(-1);
  1729. }
  1730. /*
  1731. * Prevent reloading twice the document.
  1732. */
  1733. for (i = 0; i < ctxt->txtNr; i++) {
  1734. if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
  1735. node = xmlNewText(ctxt->txtTab[i]);
  1736. goto loaded;
  1737. }
  1738. }
  1739. /*
  1740. * Try to get the encoding if available
  1741. */
  1742. if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
  1743. encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
  1744. }
  1745. if (encoding != NULL) {
  1746. /*
  1747. * TODO: we should not have to remap to the xmlCharEncoding
  1748. * predefined set, a better interface than
  1749. * xmlParserInputBufferCreateFilename should allow any
  1750. * encoding supported by iconv
  1751. */
  1752. enc = xmlParseCharEncoding((const char *) encoding);
  1753. if (enc == XML_CHAR_ENCODING_ERROR) {
  1754. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1755. XML_XINCLUDE_UNKNOWN_ENCODING,
  1756. "encoding %s not supported\n", encoding);
  1757. xmlFree(encoding);
  1758. xmlFree(URL);
  1759. return(-1);
  1760. }
  1761. xmlFree(encoding);
  1762. }
  1763. /*
  1764. * Load it.
  1765. */
  1766. pctxt = xmlNewParserCtxt();
  1767. inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
  1768. if(inputStream == NULL) {
  1769. xmlFreeParserCtxt(pctxt);
  1770. xmlFree(URL);
  1771. return(-1);
  1772. }
  1773. buf = inputStream->buf;
  1774. if (buf == NULL) {
  1775. xmlFreeInputStream (inputStream);
  1776. xmlFreeParserCtxt(pctxt);
  1777. xmlFree(URL);
  1778. return(-1);
  1779. }
  1780. if (buf->encoder)
  1781. xmlCharEncCloseFunc(buf->encoder);
  1782. buf->encoder = xmlGetCharEncodingHandler(enc);
  1783. node = xmlNewText(NULL);
  1784. /*
  1785. * Scan all chars from the resource and add the to the node
  1786. */
  1787. xinclude_multibyte_fallback:
  1788. while (xmlParserInputBufferRead(buf, 128) > 0) {
  1789. int len;
  1790. const xmlChar *content;
  1791. content = xmlBufContent(buf->buffer);
  1792. len = xmlBufLength(buf->buffer);
  1793. for (i = 0;i < len;) {
  1794. int cur;
  1795. int l;
  1796. cur = xmlStringCurrentChar(NULL, &content[i], &l);
  1797. if (!IS_CHAR(cur)) {
  1798. /* Handle split multibyte char at buffer boundary */
  1799. if (((len - i) < 4) && (!xinclude_multibyte_fallback_used)) {
  1800. xinclude_multibyte_fallback_used = 1;
  1801. xmlBufShrink(buf->buffer, i);
  1802. goto xinclude_multibyte_fallback;
  1803. } else {
  1804. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1805. XML_XINCLUDE_INVALID_CHAR,
  1806. "%s contains invalid char\n", URL);
  1807. xmlFreeParserCtxt(pctxt);
  1808. xmlFreeParserInputBuffer(buf);
  1809. xmlFree(URL);
  1810. return(-1);
  1811. }
  1812. } else {
  1813. xinclude_multibyte_fallback_used = 0;
  1814. xmlNodeAddContentLen(node, &content[i], l);
  1815. }
  1816. i += l;
  1817. }
  1818. xmlBufShrink(buf->buffer, len);
  1819. }
  1820. xmlFreeParserCtxt(pctxt);
  1821. xmlXIncludeAddTxt(ctxt, node->content, URL);
  1822. xmlFreeInputStream(inputStream);
  1823. loaded:
  1824. /*
  1825. * Add the element as the replacement copy.
  1826. */
  1827. ctxt->incTab[nr]->inc = node;
  1828. xmlFree(URL);
  1829. return(0);
  1830. }
  1831. /**
  1832. * xmlXIncludeLoadFallback:
  1833. * @ctxt: the XInclude context
  1834. * @fallback: the fallback node
  1835. * @nr: the xinclude node number
  1836. *
  1837. * Load the content of the fallback node, and store the result
  1838. * in the XInclude context
  1839. *
  1840. * Returns 0 in case of success, -1 in case of failure
  1841. */
  1842. static int
  1843. xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
  1844. xmlXIncludeCtxtPtr newctxt;
  1845. int ret = 0;
  1846. int oldNbErrors = ctxt->nbErrors;
  1847. if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) ||
  1848. (ctxt == NULL))
  1849. return(-1);
  1850. if (fallback->children != NULL) {
  1851. /*
  1852. * It's possible that the fallback also has 'includes'
  1853. * (Bug 129969), so we re-process the fallback just in case
  1854. */
  1855. newctxt = xmlXIncludeNewContext(ctxt->doc);
  1856. if (newctxt == NULL)
  1857. return (-1);
  1858. newctxt->_private = ctxt->_private;
  1859. newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */
  1860. xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
  1861. newctxt->incTotal = ctxt->incTotal;
  1862. if (xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback, 1) < 0)
  1863. ret = -1;
  1864. ctxt->incTotal = newctxt->incTotal;
  1865. if (ctxt->nbErrors > oldNbErrors)
  1866. ret = -1;
  1867. xmlXIncludeFreeContext(newctxt);
  1868. ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
  1869. fallback->children);
  1870. if (ctxt->incTab[nr]->inc == NULL)
  1871. ctxt->incTab[nr]->emptyFb = 1;
  1872. } else {
  1873. ctxt->incTab[nr]->inc = NULL;
  1874. ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
  1875. }
  1876. ctxt->incTab[nr]->fallback = 1;
  1877. return(ret);
  1878. }
  1879. /************************************************************************
  1880. * *
  1881. * XInclude Processing *
  1882. * *
  1883. ************************************************************************/
  1884. /**
  1885. * xmlXIncludePreProcessNode:
  1886. * @ctxt: an XInclude context
  1887. * @node: an XInclude node
  1888. *
  1889. * Implement the XInclude preprocessing, currently just adding the element
  1890. * for further processing.
  1891. *
  1892. * Returns the result list or NULL in case of error
  1893. */
  1894. static xmlNodePtr
  1895. xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
  1896. xmlXIncludeAddNode(ctxt, node);
  1897. return(NULL);
  1898. }
  1899. /**
  1900. * xmlXIncludeLoadNode:
  1901. * @ctxt: an XInclude context
  1902. * @nr: the node number
  1903. *
  1904. * Find and load the infoset replacement for the given node.
  1905. *
  1906. * Returns 0 if substitution succeeded, -1 if some processing failed
  1907. */
  1908. static int
  1909. xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
  1910. xmlNodePtr cur;
  1911. xmlChar *href;
  1912. xmlChar *parse;
  1913. xmlChar *base;
  1914. xmlChar *oldBase;
  1915. xmlChar *URI;
  1916. int xml = 1; /* default Issue 64 */
  1917. int ret;
  1918. if (ctxt == NULL)
  1919. return(-1);
  1920. if ((nr < 0) || (nr >= ctxt->incNr))
  1921. return(-1);
  1922. cur = ctxt->incTab[nr]->ref;
  1923. if (cur == NULL)
  1924. return(-1);
  1925. /*
  1926. * read the attributes
  1927. */
  1928. href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
  1929. if (href == NULL) {
  1930. href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
  1931. if (href == NULL)
  1932. return(-1);
  1933. }
  1934. parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
  1935. if (parse != NULL) {
  1936. if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
  1937. xml = 1;
  1938. else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
  1939. xml = 0;
  1940. else {
  1941. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1942. XML_XINCLUDE_PARSE_VALUE,
  1943. "invalid value %s for 'parse'\n", parse);
  1944. if (href != NULL)
  1945. xmlFree(href);
  1946. if (parse != NULL)
  1947. xmlFree(parse);
  1948. return(-1);
  1949. }
  1950. }
  1951. /*
  1952. * compute the URI
  1953. */
  1954. base = xmlNodeGetBase(ctxt->doc, cur);
  1955. if (base == NULL) {
  1956. URI = xmlBuildURI(href, ctxt->doc->URL);
  1957. } else {
  1958. URI = xmlBuildURI(href, base);
  1959. }
  1960. if (URI == NULL) {
  1961. xmlChar *escbase;
  1962. xmlChar *eschref;
  1963. /*
  1964. * Some escaping may be needed
  1965. */
  1966. escbase = xmlURIEscape(base);
  1967. eschref = xmlURIEscape(href);
  1968. URI = xmlBuildURI(eschref, escbase);
  1969. if (escbase != NULL)
  1970. xmlFree(escbase);
  1971. if (eschref != NULL)
  1972. xmlFree(eschref);
  1973. }
  1974. if (URI == NULL) {
  1975. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  1976. XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
  1977. if (parse != NULL)
  1978. xmlFree(parse);
  1979. if (href != NULL)
  1980. xmlFree(href);
  1981. if (base != NULL)
  1982. xmlFree(base);
  1983. return(-1);
  1984. }
  1985. #ifdef DEBUG_XINCLUDE
  1986. xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
  1987. xml ? "xml": "text");
  1988. xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
  1989. #endif
  1990. /*
  1991. * Save the base for this include (saving the current one)
  1992. */
  1993. oldBase = ctxt->base;
  1994. ctxt->base = base;
  1995. if (xml) {
  1996. ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
  1997. /* xmlXIncludeGetFragment(ctxt, cur, URI); */
  1998. } else {
  1999. ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
  2000. }
  2001. /*
  2002. * Restore the original base before checking for fallback
  2003. */
  2004. ctxt->base = oldBase;
  2005. if (ret < 0) {
  2006. xmlNodePtr children;
  2007. /*
  2008. * Time to try a fallback if available
  2009. */
  2010. #ifdef DEBUG_XINCLUDE
  2011. xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
  2012. #endif
  2013. children = cur->children;
  2014. while (children != NULL) {
  2015. if ((children->type == XML_ELEMENT_NODE) &&
  2016. (children->ns != NULL) &&
  2017. (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
  2018. ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
  2019. (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
  2020. ret = xmlXIncludeLoadFallback(ctxt, children, nr);
  2021. break;
  2022. }
  2023. children = children->next;
  2024. }
  2025. }
  2026. if (ret < 0) {
  2027. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  2028. XML_XINCLUDE_NO_FALLBACK,
  2029. "could not load %s, and no fallback was found\n",
  2030. URI);
  2031. }
  2032. /*
  2033. * Cleanup
  2034. */
  2035. if (URI != NULL)
  2036. xmlFree(URI);
  2037. if (parse != NULL)
  2038. xmlFree(parse);
  2039. if (href != NULL)
  2040. xmlFree(href);
  2041. if (base != NULL)
  2042. xmlFree(base);
  2043. return(0);
  2044. }
  2045. /**
  2046. * xmlXIncludeIncludeNode:
  2047. * @ctxt: an XInclude context
  2048. * @nr: the node number
  2049. *
  2050. * Implement the infoset replacement for the given node
  2051. *
  2052. * Returns 0 if substitution succeeded, -1 if some processing failed
  2053. */
  2054. static int
  2055. xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
  2056. xmlNodePtr cur, end, list, tmp;
  2057. if (ctxt == NULL)
  2058. return(-1);
  2059. if ((nr < 0) || (nr >= ctxt->incNr))
  2060. return(-1);
  2061. cur = ctxt->incTab[nr]->ref;
  2062. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  2063. return(-1);
  2064. list = ctxt->incTab[nr]->inc;
  2065. ctxt->incTab[nr]->inc = NULL;
  2066. ctxt->incTab[nr]->emptyFb = 0;
  2067. /*
  2068. * Check against the risk of generating a multi-rooted document
  2069. */
  2070. if ((cur->parent != NULL) &&
  2071. (cur->parent->type != XML_ELEMENT_NODE)) {
  2072. int nb_elem = 0;
  2073. tmp = list;
  2074. while (tmp != NULL) {
  2075. if (tmp->type == XML_ELEMENT_NODE)
  2076. nb_elem++;
  2077. tmp = tmp->next;
  2078. }
  2079. if (nb_elem > 1) {
  2080. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  2081. XML_XINCLUDE_MULTIPLE_ROOT,
  2082. "XInclude error: would result in multiple root nodes\n",
  2083. NULL);
  2084. xmlFreeNodeList(list);
  2085. return(-1);
  2086. }
  2087. }
  2088. if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
  2089. /*
  2090. * Add the list of nodes
  2091. */
  2092. while (list != NULL) {
  2093. end = list;
  2094. list = list->next;
  2095. xmlAddPrevSibling(cur, end);
  2096. }
  2097. xmlUnlinkNode(cur);
  2098. xmlFreeNode(cur);
  2099. } else {
  2100. xmlNodePtr child, next;
  2101. /*
  2102. * Change the current node as an XInclude start one, and add an
  2103. * XInclude end one
  2104. */
  2105. if (ctxt->incTab[nr]->fallback)
  2106. xmlUnsetProp(cur, BAD_CAST "href");
  2107. cur->type = XML_XINCLUDE_START;
  2108. /* Remove fallback children */
  2109. for (child = cur->children; child != NULL; child = next) {
  2110. next = child->next;
  2111. xmlUnlinkNode(child);
  2112. xmlFreeNode(child);
  2113. }
  2114. end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
  2115. if (end == NULL) {
  2116. xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
  2117. XML_XINCLUDE_BUILD_FAILED,
  2118. "failed to build node\n", NULL);
  2119. xmlFreeNodeList(list);
  2120. return(-1);
  2121. }
  2122. end->type = XML_XINCLUDE_END;
  2123. xmlAddNextSibling(cur, end);
  2124. /*
  2125. * Add the list of nodes
  2126. */
  2127. while (list != NULL) {
  2128. cur = list;
  2129. list = list->next;
  2130. xmlAddPrevSibling(end, cur);
  2131. }
  2132. }
  2133. return(0);
  2134. }
  2135. /**
  2136. * xmlXIncludeTestNode:
  2137. * @ctxt: the XInclude processing context
  2138. * @node: an XInclude node
  2139. *
  2140. * test if the node is an XInclude node
  2141. *
  2142. * Returns 1 true, 0 otherwise
  2143. */
  2144. static int
  2145. xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
  2146. if (node == NULL)
  2147. return(0);
  2148. if (node->type != XML_ELEMENT_NODE)
  2149. return(0);
  2150. if (node->ns == NULL)
  2151. return(0);
  2152. if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
  2153. (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
  2154. if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
  2155. if (ctxt->legacy == 0) {
  2156. #if 0 /* wait for the XML Core Working Group to get something stable ! */
  2157. xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
  2158. "Deprecated XInclude namespace found, use %s",
  2159. XINCLUDE_NS);
  2160. #endif
  2161. ctxt->legacy = 1;
  2162. }
  2163. }
  2164. if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
  2165. xmlNodePtr child = node->children;
  2166. int nb_fallback = 0;
  2167. while (child != NULL) {
  2168. if ((child->type == XML_ELEMENT_NODE) &&
  2169. (child->ns != NULL) &&
  2170. ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
  2171. (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
  2172. if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
  2173. xmlXIncludeErr(ctxt, node,
  2174. XML_XINCLUDE_INCLUDE_IN_INCLUDE,
  2175. "%s has an 'include' child\n",
  2176. XINCLUDE_NODE);
  2177. return(0);
  2178. }
  2179. if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
  2180. nb_fallback++;
  2181. }
  2182. }
  2183. child = child->next;
  2184. }
  2185. if (nb_fallback > 1) {
  2186. xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
  2187. "%s has multiple fallback children\n",
  2188. XINCLUDE_NODE);
  2189. return(0);
  2190. }
  2191. return(1);
  2192. }
  2193. if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
  2194. if ((node->parent == NULL) ||
  2195. (node->parent->type != XML_ELEMENT_NODE) ||
  2196. (node->parent->ns == NULL) ||
  2197. ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
  2198. (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
  2199. (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
  2200. xmlXIncludeErr(ctxt, node,
  2201. XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
  2202. "%s is not the child of an 'include'\n",
  2203. XINCLUDE_FALLBACK);
  2204. }
  2205. }
  2206. }
  2207. return(0);
  2208. }
  2209. /**
  2210. * xmlXIncludeDoProcess:
  2211. * @ctxt: the XInclude processing context
  2212. * @doc: an XML document
  2213. * @tree: the top of the tree to process
  2214. * @skipRoot: don't process the root node of the tree
  2215. *
  2216. * Implement the XInclude substitution on the XML document @doc
  2217. *
  2218. * Returns 0 if no substitution were done, -1 if some processing failed
  2219. * or the number of substitutions done.
  2220. */
  2221. static int
  2222. xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree,
  2223. int skipRoot) {
  2224. xmlNodePtr cur;
  2225. int ret = 0;
  2226. int i, start;
  2227. if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
  2228. return(-1);
  2229. if ((skipRoot) && (tree->children == NULL))
  2230. return(-1);
  2231. if (ctxt == NULL)
  2232. return(-1);
  2233. if (doc->URL != NULL) {
  2234. ret = xmlXIncludeURLPush(ctxt, doc->URL);
  2235. if (ret < 0)
  2236. return(-1);
  2237. }
  2238. start = ctxt->incNr;
  2239. /*
  2240. * TODO: The phases must run separately for recursive inclusions.
  2241. *
  2242. * - Phase 1 should start with top-level XInclude nodes, load documents,
  2243. * execute XPointer expressions, then process only the result nodes
  2244. * (not whole document, see bug #324081) and only for phase 1
  2245. * recursively. We will need a backreference from xmlNodes to
  2246. * xmlIncludeRefs to detect references that were already visited.
  2247. * This can also be used for proper cycle detection, see bug #344240.
  2248. *
  2249. * - Phase 2 should visit all top-level XInclude nodes and expand
  2250. * possible subreferences in the replacement recursively.
  2251. *
  2252. * - Phase 3 should finally replace the top-level XInclude nodes.
  2253. * It could also be run together with phase 2.
  2254. */
  2255. /*
  2256. * First phase: lookup the elements in the document
  2257. */
  2258. if (skipRoot)
  2259. cur = tree->children;
  2260. else
  2261. cur = tree;
  2262. do {
  2263. /* TODO: need to work on entities -> stack */
  2264. if (xmlXIncludeTestNode(ctxt, cur) == 1) {
  2265. #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  2266. /*
  2267. * Avoid superlinear expansion by limiting the total number
  2268. * of replacements.
  2269. */
  2270. if (ctxt->incTotal >= 20)
  2271. return(-1);
  2272. #endif
  2273. ctxt->incTotal++;
  2274. xmlXIncludePreProcessNode(ctxt, cur);
  2275. } else if ((cur->children != NULL) &&
  2276. ((cur->type == XML_DOCUMENT_NODE) ||
  2277. (cur->type == XML_ELEMENT_NODE))) {
  2278. cur = cur->children;
  2279. continue;
  2280. }
  2281. do {
  2282. if (cur == tree)
  2283. break;
  2284. if (cur->next != NULL) {
  2285. cur = cur->next;
  2286. break;
  2287. }
  2288. cur = cur->parent;
  2289. } while (cur != NULL);
  2290. } while ((cur != NULL) && (cur != tree));
  2291. /*
  2292. * Second Phase : collect the infosets fragments
  2293. */
  2294. for (i = start;i < ctxt->incNr; i++) {
  2295. xmlXIncludeLoadNode(ctxt, i);
  2296. ret++;
  2297. }
  2298. /*
  2299. * Third phase: extend the original document infoset.
  2300. *
  2301. * Originally we bypassed the inclusion if there were any errors
  2302. * encountered on any of the XIncludes. A bug was raised (bug
  2303. * 132588) requesting that we output the XIncludes without error,
  2304. * so the check for inc!=NULL || xptr!=NULL was put in. This may
  2305. * give some other problems in the future, but for now it seems to
  2306. * work ok.
  2307. *
  2308. */
  2309. for (i = ctxt->incBase;i < ctxt->incNr; i++) {
  2310. if ((ctxt->incTab[i]->inc != NULL) ||
  2311. (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
  2312. xmlXIncludeIncludeNode(ctxt, i);
  2313. }
  2314. if (doc->URL != NULL)
  2315. xmlXIncludeURLPop(ctxt);
  2316. return(ret);
  2317. }
  2318. /**
  2319. * xmlXIncludeSetFlags:
  2320. * @ctxt: an XInclude processing context
  2321. * @flags: a set of xmlParserOption used for parsing XML includes
  2322. *
  2323. * Set the flags used for further processing of XML resources.
  2324. *
  2325. * Returns 0 in case of success and -1 in case of error.
  2326. */
  2327. int
  2328. xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
  2329. if (ctxt == NULL)
  2330. return(-1);
  2331. ctxt->parseFlags = flags;
  2332. return(0);
  2333. }
  2334. /**
  2335. * xmlXIncludeProcessTreeFlagsData:
  2336. * @tree: an XML node
  2337. * @flags: a set of xmlParserOption used for parsing XML includes
  2338. * @data: application data that will be passed to the parser context
  2339. * in the _private field of the parser context(s)
  2340. *
  2341. * Implement the XInclude substitution on the XML node @tree
  2342. *
  2343. * Returns 0 if no substitution were done, -1 if some processing failed
  2344. * or the number of substitutions done.
  2345. */
  2346. int
  2347. xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
  2348. xmlXIncludeCtxtPtr ctxt;
  2349. int ret = 0;
  2350. if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
  2351. (tree->doc == NULL))
  2352. return(-1);
  2353. ctxt = xmlXIncludeNewContext(tree->doc);
  2354. if (ctxt == NULL)
  2355. return(-1);
  2356. ctxt->_private = data;
  2357. ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
  2358. xmlXIncludeSetFlags(ctxt, flags);
  2359. ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
  2360. if ((ret >= 0) && (ctxt->nbErrors > 0))
  2361. ret = -1;
  2362. xmlXIncludeFreeContext(ctxt);
  2363. return(ret);
  2364. }
  2365. /**
  2366. * xmlXIncludeProcessFlagsData:
  2367. * @doc: an XML document
  2368. * @flags: a set of xmlParserOption used for parsing XML includes
  2369. * @data: application data that will be passed to the parser context
  2370. * in the _private field of the parser context(s)
  2371. *
  2372. * Implement the XInclude substitution on the XML document @doc
  2373. *
  2374. * Returns 0 if no substitution were done, -1 if some processing failed
  2375. * or the number of substitutions done.
  2376. */
  2377. int
  2378. xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
  2379. xmlNodePtr tree;
  2380. if (doc == NULL)
  2381. return(-1);
  2382. tree = xmlDocGetRootElement(doc);
  2383. if (tree == NULL)
  2384. return(-1);
  2385. return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
  2386. }
  2387. /**
  2388. * xmlXIncludeProcessFlags:
  2389. * @doc: an XML document
  2390. * @flags: a set of xmlParserOption used for parsing XML includes
  2391. *
  2392. * Implement the XInclude substitution on the XML document @doc
  2393. *
  2394. * Returns 0 if no substitution were done, -1 if some processing failed
  2395. * or the number of substitutions done.
  2396. */
  2397. int
  2398. xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
  2399. return xmlXIncludeProcessFlagsData(doc, flags, NULL);
  2400. }
  2401. /**
  2402. * xmlXIncludeProcess:
  2403. * @doc: an XML document
  2404. *
  2405. * Implement the XInclude substitution on the XML document @doc
  2406. *
  2407. * Returns 0 if no substitution were done, -1 if some processing failed
  2408. * or the number of substitutions done.
  2409. */
  2410. int
  2411. xmlXIncludeProcess(xmlDocPtr doc) {
  2412. return(xmlXIncludeProcessFlags(doc, 0));
  2413. }
  2414. /**
  2415. * xmlXIncludeProcessTreeFlags:
  2416. * @tree: a node in an XML document
  2417. * @flags: a set of xmlParserOption used for parsing XML includes
  2418. *
  2419. * Implement the XInclude substitution for the given subtree
  2420. *
  2421. * Returns 0 if no substitution were done, -1 if some processing failed
  2422. * or the number of substitutions done.
  2423. */
  2424. int
  2425. xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
  2426. xmlXIncludeCtxtPtr ctxt;
  2427. int ret = 0;
  2428. if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
  2429. (tree->doc == NULL))
  2430. return(-1);
  2431. ctxt = xmlXIncludeNewContext(tree->doc);
  2432. if (ctxt == NULL)
  2433. return(-1);
  2434. ctxt->base = xmlNodeGetBase(tree->doc, tree);
  2435. xmlXIncludeSetFlags(ctxt, flags);
  2436. ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree, 0);
  2437. if ((ret >= 0) && (ctxt->nbErrors > 0))
  2438. ret = -1;
  2439. xmlXIncludeFreeContext(ctxt);
  2440. return(ret);
  2441. }
  2442. /**
  2443. * xmlXIncludeProcessTree:
  2444. * @tree: a node in an XML document
  2445. *
  2446. * Implement the XInclude substitution for the given subtree
  2447. *
  2448. * Returns 0 if no substitution were done, -1 if some processing failed
  2449. * or the number of substitutions done.
  2450. */
  2451. int
  2452. xmlXIncludeProcessTree(xmlNodePtr tree) {
  2453. return(xmlXIncludeProcessTreeFlags(tree, 0));
  2454. }
  2455. /**
  2456. * xmlXIncludeProcessNode:
  2457. * @ctxt: an existing XInclude context
  2458. * @node: a node in an XML document
  2459. *
  2460. * Implement the XInclude substitution for the given subtree reusing
  2461. * the information and data coming from the given context.
  2462. *
  2463. * Returns 0 if no substitution were done, -1 if some processing failed
  2464. * or the number of substitutions done.
  2465. */
  2466. int
  2467. xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
  2468. int ret = 0;
  2469. if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
  2470. (node->doc == NULL) || (ctxt == NULL))
  2471. return(-1);
  2472. ret = xmlXIncludeDoProcess(ctxt, node->doc, node, 0);
  2473. if ((ret >= 0) && (ctxt->nbErrors > 0))
  2474. ret = -1;
  2475. return(ret);
  2476. }
  2477. #else /* !LIBXML_XINCLUDE_ENABLED */
  2478. #endif
  2479. #define bottom_xinclude
  2480. #include "elfgcchack.h"