/functions.c

http://github.com/fizx/parsley · C · 368 lines · 307 code · 42 blank · 19 comment · 101 complexity · 94c9f19fc4277f6deec1653024243e21 MD5 · raw file

  1. #include <stdbool.h>
  2. #include <libxml/xpath.h>
  3. #include <libxml/xpathInternals.h>
  4. #include <libxml/parserInternals.h>
  5. #include <libxml/uri.h>
  6. #include <libxml/xpointer.h>
  7. #include <libxml/xinclude.h>
  8. #include <libxml/HTMLparser.h>
  9. #include <libxml/HTMLtree.h>
  10. #include <libxslt/xslt.h>
  11. #include <libxslt/imports.h>
  12. #include <libxslt/xsltInternals.h>
  13. #include <libxslt/security.h>
  14. #include <libxslt/xsltutils.h>
  15. #include <libxslt/transform.h>
  16. #include <libxslt/extensions.h>
  17. #include <libxslt/documents.h>
  18. #include "functions.h"
  19. void parsley_register_all(){
  20. xsltRegisterExtModuleFunction ((const xmlChar *) "html-document", "http://parselets.com/stdlib",
  21. xsltHtmlDocumentFunction);
  22. xsltRegisterExtModuleFunction ((const xmlChar *) "outer-xml", "http://parselets.com/stdlib",
  23. xsltOuterXmlFunction);
  24. xsltRegisterExtModuleFunction ((const xmlChar *) "inner-xml", "http://parselets.com/stdlib",
  25. xsltInnerXmlFunction);
  26. }
  27. static void
  28. xsltStarXMLFunction(xmlXPathParserContextPtr ctxt, int nargs, bool is_inner) {
  29. if (nargs != 1) {
  30. xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
  31. "outer-xml() : invalid number of args %d\n",
  32. nargs);
  33. ctxt->error = XPATH_INVALID_ARITY;
  34. return;
  35. }
  36. if (ctxt->value->type == XPATH_NODESET) {
  37. xmlXPathObjectPtr obj, newobj;
  38. obj = valuePop(ctxt);
  39. xmlBufferPtr buf = xmlBufferCreate();
  40. int n = obj->nodesetval->nodeNr;
  41. for(int i = 0; i < n; i++) {
  42. xmlNodePtr node = obj->nodesetval->nodeTab[i];
  43. xmlDocPtr doc = node->doc;
  44. if(is_inner){
  45. xmlNodePtr child = node->children;
  46. while(child != NULL) {
  47. xmlNodeDump(buf, doc, child, 0, 0);
  48. child = child->next;
  49. }
  50. } else {
  51. xmlNodeDump(buf, doc, node, 0, 0);
  52. }
  53. }
  54. newobj = xmlXPathNewCString(xmlBufferContent(buf));
  55. xmlBufferFree(buf);
  56. valuePush(ctxt, newobj);
  57. }
  58. }
  59. void
  60. xsltInnerXmlFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  61. xsltStarXMLFunction(ctxt, nargs, true);
  62. }
  63. void
  64. xsltOuterXmlFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  65. xsltStarXMLFunction(ctxt, nargs, false);
  66. }
  67. void
  68. xsltHtmlDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
  69. {
  70. xmlXPathObjectPtr obj, obj2 = NULL;
  71. xmlChar *base = NULL, *URI;
  72. if ((nargs < 1) || (nargs > 2)) {
  73. xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
  74. "document() : invalid number of args %d\n",
  75. nargs);
  76. ctxt->error = XPATH_INVALID_ARITY;
  77. return;
  78. }
  79. if (ctxt->value == NULL) {
  80. xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
  81. "document() : invalid arg value\n");
  82. ctxt->error = XPATH_INVALID_TYPE;
  83. return;
  84. }
  85. if (nargs == 2) {
  86. if (ctxt->value->type != XPATH_NODESET) {
  87. xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
  88. "document() : invalid arg expecting a nodeset\n");
  89. ctxt->error = XPATH_INVALID_TYPE;
  90. return;
  91. }
  92. obj2 = valuePop(ctxt);
  93. }
  94. if (ctxt->value->type == XPATH_NODESET) {
  95. int i;
  96. xmlXPathObjectPtr newobj, ret;
  97. obj = valuePop(ctxt);
  98. ret = xmlXPathNewNodeSet(NULL);
  99. if (obj->nodesetval) {
  100. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  101. valuePush(ctxt,
  102. xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
  103. xmlXPathStringFunction(ctxt, 1);
  104. if (nargs == 2) {
  105. valuePush(ctxt, xmlXPathObjectCopy(obj2));
  106. } else {
  107. valuePush(ctxt,
  108. xmlXPathNewNodeSet(obj->nodesetval->
  109. nodeTab[i]));
  110. }
  111. xsltHtmlDocumentFunction(ctxt, 2);
  112. newobj = valuePop(ctxt);
  113. ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
  114. newobj->nodesetval);
  115. xmlXPathFreeObject(newobj);
  116. }
  117. }
  118. xmlXPathFreeObject(obj);
  119. if (obj2 != NULL)
  120. xmlXPathFreeObject(obj2);
  121. valuePush(ctxt, ret);
  122. return;
  123. }
  124. /*
  125. * Make sure it's converted to a string
  126. */
  127. xmlXPathStringFunction(ctxt, 1);
  128. if (ctxt->value->type != XPATH_STRING) {
  129. xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
  130. "document() : invalid arg expecting a string\n");
  131. ctxt->error = XPATH_INVALID_TYPE;
  132. if (obj2 != NULL)
  133. xmlXPathFreeObject(obj2);
  134. return;
  135. }
  136. obj = valuePop(ctxt);
  137. if (obj->stringval == NULL) {
  138. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  139. } else {
  140. if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
  141. (obj2->nodesetval->nodeNr > 0) &&
  142. IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
  143. xmlNodePtr target;
  144. target = obj2->nodesetval->nodeTab[0];
  145. if ((target->type == XML_ATTRIBUTE_NODE) ||
  146. (target->type == XML_PI_NODE)) {
  147. target = ((xmlAttrPtr) target)->parent;
  148. }
  149. base = xmlNodeGetBase(target->doc, target);
  150. } else {
  151. xsltTransformContextPtr tctxt;
  152. tctxt = xsltXPathGetTransformContext(ctxt);
  153. if ((tctxt != NULL) && (tctxt->inst != NULL)) {
  154. base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
  155. } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
  156. (tctxt->style->doc != NULL)) {
  157. base = xmlNodeGetBase(tctxt->style->doc,
  158. (xmlNodePtr) tctxt->style->doc);
  159. }
  160. }
  161. URI = xmlBuildURI(obj->stringval, base);
  162. if (base != NULL)
  163. xmlFree(base);
  164. if (URI == NULL) {
  165. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  166. } else {
  167. xsltHtmlDocumentFunctionLoadDocument( ctxt, URI );
  168. xmlFree(URI);
  169. }
  170. }
  171. xmlXPathFreeObject(obj);
  172. if (obj2 != NULL)
  173. xmlXPathFreeObject(obj2);
  174. }
  175. static void
  176. xsltHtmlDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
  177. {
  178. xsltTransformContextPtr tctxt;
  179. xmlURIPtr uri;
  180. xmlChar *fragment;
  181. xsltDocumentPtr idoc; /* document info */
  182. xmlDocPtr doc;
  183. xmlXPathContextPtr xptrctxt = NULL;
  184. xmlXPathObjectPtr resObj = NULL;
  185. tctxt = xsltXPathGetTransformContext(ctxt);
  186. if (tctxt == NULL) {
  187. xsltTransformError(NULL, NULL, NULL,
  188. "document() : internal error tctxt == NULL\n");
  189. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  190. return;
  191. }
  192. uri = xmlParseURI((const char *) URI);
  193. if (uri == NULL) {
  194. xsltTransformError(tctxt, NULL, NULL,
  195. "document() : failed to parse URI\n");
  196. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  197. return;
  198. }
  199. /*
  200. * check for and remove fragment identifier
  201. */
  202. fragment = (xmlChar *)uri->fragment;
  203. if (fragment != NULL) {
  204. xmlChar *newURI;
  205. uri->fragment = NULL;
  206. newURI = xmlSaveUri(uri);
  207. idoc = xsltLoadHtmlDocument(tctxt, newURI);
  208. xmlFree(newURI);
  209. } else
  210. idoc = xsltLoadHtmlDocument(tctxt, URI);
  211. xmlFreeURI(uri);
  212. if (idoc == NULL) {
  213. if ((URI == NULL) ||
  214. (URI[0] == '#') ||
  215. ((tctxt->style->doc != NULL) &&
  216. (xmlStrEqual(tctxt->style->doc->URL, URI))))
  217. {
  218. /*
  219. * This selects the stylesheet's doc itself.
  220. */
  221. doc = tctxt->style->doc;
  222. } else {
  223. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  224. if (fragment != NULL)
  225. xmlFree(fragment);
  226. return;
  227. }
  228. } else
  229. doc = idoc->doc;
  230. if (fragment == NULL) {
  231. valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
  232. return;
  233. }
  234. /* use XPointer of HTML location for fragment ID */
  235. #ifdef LIBXML_XPTR_ENABLED
  236. xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
  237. if (xptrctxt == NULL) {
  238. xsltTransformError(tctxt, NULL, NULL,
  239. "document() : internal error xptrctxt == NULL\n");
  240. goto out_fragment;
  241. }
  242. resObj = xmlXPtrEval(fragment, xptrctxt);
  243. xmlXPathFreeContext(xptrctxt);
  244. #endif
  245. xmlFree(fragment);
  246. if (resObj == NULL)
  247. goto out_fragment;
  248. switch (resObj->type) {
  249. case XPATH_NODESET:
  250. break;
  251. case XPATH_UNDEFINED:
  252. case XPATH_BOOLEAN:
  253. case XPATH_NUMBER:
  254. case XPATH_STRING:
  255. case XPATH_POINT:
  256. case XPATH_USERS:
  257. case XPATH_XSLT_TREE:
  258. case XPATH_RANGE:
  259. case XPATH_LOCATIONSET:
  260. xsltTransformError(tctxt, NULL, NULL,
  261. "document() : XPointer does not select a node set: #%s\n",
  262. fragment);
  263. goto out_object;
  264. }
  265. valuePush(ctxt, resObj);
  266. return;
  267. out_object:
  268. xmlXPathFreeObject(resObj);
  269. out_fragment:
  270. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  271. }
  272. xsltDocumentPtr
  273. xsltLoadHtmlDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
  274. xsltDocumentPtr ret;
  275. xmlDocPtr doc;
  276. if ((ctxt == NULL) || (URI == NULL))
  277. return(NULL);
  278. /*
  279. * Security framework check
  280. */
  281. if (ctxt->sec != NULL) {
  282. int res;
  283. res = xsltCheckRead(ctxt->sec, ctxt, URI);
  284. if (res == 0) {
  285. xsltTransformError(ctxt, NULL, NULL,
  286. "xsltLoadHtmlDocument: read rights for %s denied\n",
  287. URI);
  288. return(NULL);
  289. }
  290. }
  291. /*
  292. * Walk the context list to find the document if preparsed
  293. */
  294. ret = ctxt->docList;
  295. while (ret != NULL) {
  296. if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
  297. (xmlStrEqual(ret->doc->URL, URI)))
  298. return(ret);
  299. ret = ret->next;
  300. }
  301. doc = htmlReadFile(URI, NULL, ctxt->parserOptions | HTML_PARSE_RECOVER | HTML_PARSE_NOERROR |HTML_PARSE_NOWARNING);
  302. if (doc == NULL)
  303. return(NULL);
  304. if (ctxt->xinclude != 0) {
  305. #ifdef LIBXML_XINCLUDE_ENABLED
  306. #if LIBXML_VERSION >= 20603
  307. xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
  308. #else
  309. xmlXIncludeProcess(doc);
  310. #endif
  311. #else
  312. xsltTransformError(ctxt, NULL, NULL,
  313. "xsltLoadHtmlDocument(%s) : XInclude processing not compiled in\n",
  314. URI);
  315. #endif
  316. }
  317. /*
  318. * Apply white-space stripping if asked for
  319. */
  320. if (xsltNeedElemSpaceHandling(ctxt))
  321. xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
  322. if (ctxt->debugStatus == XSLT_DEBUG_NONE)
  323. xmlXPathOrderDocElems(doc);
  324. ret = xsltNewDocument(ctxt, doc);
  325. return(ret);
  326. }