documents.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * documents.c: Implementation of the documents handling
  3. *
  4. * See Copyright for the status of this software.
  5. *
  6. * daniel@veillard.com
  7. */
  8. #define IN_LIBXSLT
  9. #include "libxslt.h"
  10. #include <string.h>
  11. #include <libxml/xmlmemory.h>
  12. #include <libxml/tree.h>
  13. #include <libxml/hash.h>
  14. #include <libxml/parser.h>
  15. #include <libxml/parserInternals.h>
  16. #include "xslt.h"
  17. #include "xsltInternals.h"
  18. #include "xsltutils.h"
  19. #include "documents.h"
  20. #include "transform.h"
  21. #include "imports.h"
  22. #include "keys.h"
  23. #include "security.h"
  24. #ifdef LIBXML_XINCLUDE_ENABLED
  25. #include <libxml/xinclude.h>
  26. #endif
  27. #define WITH_XSLT_DEBUG_DOCUMENTS
  28. #ifdef WITH_XSLT_DEBUG
  29. #define WITH_XSLT_DEBUG_DOCUMENTS
  30. #endif
  31. /************************************************************************
  32. * *
  33. * Hooks for the document loader *
  34. * *
  35. ************************************************************************/
  36. /**
  37. * xsltDocDefaultLoaderFunc:
  38. * @URI: the URI of the document to load
  39. * @dict: the dictionary to use when parsing that document
  40. * @options: parsing options, a set of xmlParserOption
  41. * @ctxt: the context, either a stylesheet or a transformation context
  42. * @type: the xsltLoadType indicating the kind of loading required
  43. *
  44. * Default function to load document not provided by the compilation or
  45. * transformation API themselve, for example when an xsl:import,
  46. * xsl:include is found at compilation time or when a document()
  47. * call is made at runtime.
  48. *
  49. * Returns the pointer to the document (which will be modified and
  50. * freed by the engine later), or NULL in case of error.
  51. */
  52. static xmlDocPtr
  53. xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options,
  54. void *ctxt ATTRIBUTE_UNUSED,
  55. xsltLoadType type ATTRIBUTE_UNUSED)
  56. {
  57. xmlParserCtxtPtr pctxt;
  58. xmlParserInputPtr inputStream;
  59. xmlDocPtr doc;
  60. pctxt = xmlNewParserCtxt();
  61. if (pctxt == NULL)
  62. return(NULL);
  63. if ((dict != NULL) && (pctxt->dict != NULL)) {
  64. xmlDictFree(pctxt->dict);
  65. pctxt->dict = NULL;
  66. }
  67. if (dict != NULL) {
  68. pctxt->dict = dict;
  69. xmlDictReference(pctxt->dict);
  70. #ifdef WITH_XSLT_DEBUG
  71. xsltGenericDebug(xsltGenericDebugContext,
  72. "Reusing dictionary for document\n");
  73. #endif
  74. }
  75. xmlCtxtUseOptions(pctxt, options);
  76. inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
  77. if (inputStream == NULL) {
  78. xmlFreeParserCtxt(pctxt);
  79. return(NULL);
  80. }
  81. inputPush(pctxt, inputStream);
  82. if (pctxt->directory == NULL)
  83. pctxt->directory = xmlParserGetDirectory((const char *) URI);
  84. xmlParseDocument(pctxt);
  85. if (pctxt->wellFormed) {
  86. doc = pctxt->myDoc;
  87. }
  88. else {
  89. doc = NULL;
  90. xmlFreeDoc(pctxt->myDoc);
  91. pctxt->myDoc = NULL;
  92. }
  93. xmlFreeParserCtxt(pctxt);
  94. return(doc);
  95. }
  96. xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
  97. /**
  98. * xsltSetLoaderFunc:
  99. * @f: the new function to handle document loading.
  100. *
  101. * Set the new function to load document, if NULL it resets it to the
  102. * default function.
  103. */
  104. void
  105. xsltSetLoaderFunc(xsltDocLoaderFunc f) {
  106. if (f == NULL)
  107. xsltDocDefaultLoader = xsltDocDefaultLoaderFunc;
  108. else
  109. xsltDocDefaultLoader = f;
  110. }
  111. /************************************************************************
  112. * *
  113. * Module interfaces *
  114. * *
  115. ************************************************************************/
  116. /**
  117. * xsltNewDocument:
  118. * @ctxt: an XSLT transformation context (or NULL)
  119. * @doc: a parsed XML document
  120. *
  121. * Register a new document, apply key computations
  122. *
  123. * Returns a handler to the document
  124. */
  125. xsltDocumentPtr
  126. xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
  127. xsltDocumentPtr cur;
  128. cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
  129. if (cur == NULL) {
  130. xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
  131. "xsltNewDocument : malloc failed\n");
  132. return(NULL);
  133. }
  134. memset(cur, 0, sizeof(xsltDocument));
  135. cur->doc = doc;
  136. if (ctxt != NULL) {
  137. if (! XSLT_IS_RES_TREE_FRAG(doc)) {
  138. cur->next = ctxt->docList;
  139. ctxt->docList = cur;
  140. }
  141. /*
  142. * A key with a specific name for a specific document
  143. * will only be computed if there's a call to the key()
  144. * function using that specific name for that specific
  145. * document. I.e. computation of keys will be done in
  146. * xsltGetKey() (keys.c) on an on-demand basis.
  147. *
  148. * xsltInitCtxtKeys(ctxt, cur); not called here anymore
  149. */
  150. }
  151. return(cur);
  152. }
  153. /**
  154. * xsltNewStyleDocument:
  155. * @style: an XSLT style sheet
  156. * @doc: a parsed XML document
  157. *
  158. * Register a new document, apply key computations
  159. *
  160. * Returns a handler to the document
  161. */
  162. xsltDocumentPtr
  163. xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) {
  164. xsltDocumentPtr cur;
  165. cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
  166. if (cur == NULL) {
  167. xsltTransformError(NULL, style, (xmlNodePtr) doc,
  168. "xsltNewStyleDocument : malloc failed\n");
  169. return(NULL);
  170. }
  171. memset(cur, 0, sizeof(xsltDocument));
  172. cur->doc = doc;
  173. if (style != NULL) {
  174. cur->next = style->docList;
  175. style->docList = cur;
  176. }
  177. return(cur);
  178. }
  179. /**
  180. * xsltFreeStyleDocuments:
  181. * @style: an XSLT stylesheet (representing a stylesheet-level)
  182. *
  183. * Frees the node-trees (and xsltDocument structures) of all
  184. * stylesheet-modules of the stylesheet-level represented by
  185. * the given @style.
  186. */
  187. void
  188. xsltFreeStyleDocuments(xsltStylesheetPtr style) {
  189. xsltDocumentPtr doc, cur;
  190. #ifdef XSLT_REFACTORED_XSLT_NSCOMP
  191. xsltNsMapPtr nsMap;
  192. #endif
  193. if (style == NULL)
  194. return;
  195. #ifdef XSLT_REFACTORED_XSLT_NSCOMP
  196. if (XSLT_HAS_INTERNAL_NSMAP(style))
  197. nsMap = XSLT_GET_INTERNAL_NSMAP(style);
  198. else
  199. nsMap = NULL;
  200. #endif
  201. cur = style->docList;
  202. while (cur != NULL) {
  203. doc = cur;
  204. cur = cur->next;
  205. #ifdef XSLT_REFACTORED_XSLT_NSCOMP
  206. /*
  207. * Restore all changed namespace URIs of ns-decls.
  208. */
  209. if (nsMap)
  210. xsltRestoreDocumentNamespaces(nsMap, doc->doc);
  211. #endif
  212. xsltFreeDocumentKeys(doc);
  213. if (!doc->main)
  214. xmlFreeDoc(doc->doc);
  215. xmlFree(doc);
  216. }
  217. }
  218. /**
  219. * xsltFreeDocuments:
  220. * @ctxt: an XSLT transformation context
  221. *
  222. * Free up all the space used by the loaded documents
  223. */
  224. void
  225. xsltFreeDocuments(xsltTransformContextPtr ctxt) {
  226. xsltDocumentPtr doc, cur;
  227. cur = ctxt->docList;
  228. while (cur != NULL) {
  229. doc = cur;
  230. cur = cur->next;
  231. xsltFreeDocumentKeys(doc);
  232. if (!doc->main)
  233. xmlFreeDoc(doc->doc);
  234. xmlFree(doc);
  235. }
  236. cur = ctxt->styleList;
  237. while (cur != NULL) {
  238. doc = cur;
  239. cur = cur->next;
  240. xsltFreeDocumentKeys(doc);
  241. if (!doc->main)
  242. xmlFreeDoc(doc->doc);
  243. xmlFree(doc);
  244. }
  245. }
  246. /**
  247. * xsltLoadDocument:
  248. * @ctxt: an XSLT transformation context
  249. * @URI: the computed URI of the document
  250. *
  251. * Try to load a document (not a stylesheet)
  252. * within the XSLT transformation context
  253. *
  254. * Returns the new xsltDocumentPtr or NULL in case of error
  255. */
  256. xsltDocumentPtr
  257. xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
  258. xsltDocumentPtr ret;
  259. xmlDocPtr doc;
  260. if ((ctxt == NULL) || (URI == NULL))
  261. return(NULL);
  262. /*
  263. * Security framework check
  264. */
  265. if (ctxt->sec != NULL) {
  266. int res;
  267. res = xsltCheckRead(ctxt->sec, ctxt, URI);
  268. if (res <= 0) {
  269. if (res == 0)
  270. xsltTransformError(ctxt, NULL, NULL,
  271. "xsltLoadDocument: read rights for %s denied\n",
  272. URI);
  273. return(NULL);
  274. }
  275. }
  276. /*
  277. * Walk the context list to find the document if preparsed
  278. */
  279. ret = ctxt->docList;
  280. while (ret != NULL) {
  281. if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
  282. (xmlStrEqual(ret->doc->URL, URI)))
  283. return(ret);
  284. ret = ret->next;
  285. }
  286. doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions,
  287. (void *) ctxt, XSLT_LOAD_DOCUMENT);
  288. if (doc == NULL)
  289. return(NULL);
  290. if (ctxt->xinclude != 0) {
  291. #ifdef LIBXML_XINCLUDE_ENABLED
  292. #if LIBXML_VERSION >= 20603
  293. xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
  294. #else
  295. xmlXIncludeProcess(doc);
  296. #endif
  297. #else
  298. xsltTransformError(ctxt, NULL, NULL,
  299. "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
  300. URI);
  301. #endif
  302. }
  303. /*
  304. * Apply white-space stripping if asked for
  305. */
  306. if (xsltNeedElemSpaceHandling(ctxt))
  307. xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
  308. if (ctxt->debugStatus == XSLT_DEBUG_NONE)
  309. xmlXPathOrderDocElems(doc);
  310. ret = xsltNewDocument(ctxt, doc);
  311. return(ret);
  312. }
  313. /**
  314. * xsltLoadStyleDocument:
  315. * @style: an XSLT style sheet
  316. * @URI: the computed URI of the document
  317. *
  318. * Try to load a stylesheet document within the XSLT transformation context
  319. *
  320. * Returns the new xsltDocumentPtr or NULL in case of error
  321. */
  322. xsltDocumentPtr
  323. xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) {
  324. xsltDocumentPtr ret;
  325. xmlDocPtr doc;
  326. xsltSecurityPrefsPtr sec;
  327. if ((style == NULL) || (URI == NULL))
  328. return(NULL);
  329. /*
  330. * Security framework check
  331. */
  332. sec = xsltGetDefaultSecurityPrefs();
  333. if (sec != NULL) {
  334. int res;
  335. res = xsltCheckRead(sec, NULL, URI);
  336. if (res <= 0) {
  337. if (res == 0)
  338. xsltTransformError(NULL, NULL, NULL,
  339. "xsltLoadStyleDocument: read rights for %s denied\n",
  340. URI);
  341. return(NULL);
  342. }
  343. }
  344. /*
  345. * Walk the context list to find the document if preparsed
  346. */
  347. ret = style->docList;
  348. while (ret != NULL) {
  349. if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
  350. (xmlStrEqual(ret->doc->URL, URI)))
  351. return(ret);
  352. ret = ret->next;
  353. }
  354. doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS,
  355. (void *) style, XSLT_LOAD_STYLESHEET);
  356. if (doc == NULL)
  357. return(NULL);
  358. ret = xsltNewStyleDocument(style, doc);
  359. return(ret);
  360. }
  361. /**
  362. * xsltFindDocument:
  363. * @ctxt: an XSLT transformation context
  364. * @doc: a parsed XML document
  365. *
  366. * Try to find a document within the XSLT transformation context.
  367. * This will not find document infos for temporary
  368. * Result Tree Fragments.
  369. *
  370. * Returns the desired xsltDocumentPtr or NULL in case of error
  371. */
  372. xsltDocumentPtr
  373. xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) {
  374. xsltDocumentPtr ret;
  375. if ((ctxt == NULL) || (doc == NULL))
  376. return(NULL);
  377. /*
  378. * Walk the context list to find the document
  379. */
  380. ret = ctxt->docList;
  381. while (ret != NULL) {
  382. if (ret->doc == doc)
  383. return(ret);
  384. ret = ret->next;
  385. }
  386. if (doc == ctxt->style->doc)
  387. return(ctxt->document);
  388. return(NULL);
  389. }