testC14N.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /*
  2. * Canonical XML implementation test program
  3. * (http://www.w3.org/TR/2001/REC-xml-c14n-20010315)
  4. *
  5. * See Copyright for the status of this software.
  6. *
  7. * Author: Aleksey Sanin <aleksey@aleksey.com>
  8. */
  9. #include "libxml.h"
  10. #if defined(LIBXML_C14N_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
  11. #include <stdio.h>
  12. #include <string.h>
  13. #ifdef HAVE_UNISTD_H
  14. #include <unistd.h>
  15. #endif
  16. #ifdef HAVE_STDLIB_H
  17. #include <stdlib.h>
  18. #endif
  19. #include <libxml/xmlmemory.h>
  20. #include <libxml/parser.h>
  21. #include <libxml/xpath.h>
  22. #include <libxml/xpathInternals.h>
  23. #include <libxml/c14n.h>
  24. static void usage(const char *name) {
  25. fprintf(stderr,
  26. "Usage: %s <mode> <xml-file> [<xpath-expr>] [<inclusive-ns-list>]\n",
  27. name);
  28. fprintf(stderr, "where <mode> is one of following:\n");
  29. fprintf(stderr,
  30. "--with-comments \t XML file canonicalization v1.0 w comments \n");
  31. fprintf(stderr,
  32. "--without-comments \t XML file canonicalization v1.0 w/o comments\n");
  33. fprintf(stderr,
  34. "--1-1-with-comments \t XML file canonicalization v1.1 w comments\n");
  35. fprintf(stderr,
  36. "--1-1-without-comments \t XML file canonicalization v1.1 w/o comments\n");
  37. fprintf(stderr,
  38. "--exc-with-comments \t Exclusive XML file canonicalization v1.0 w comments\n");
  39. fprintf(stderr,
  40. "--exc-without-comments\t Exclusive XML file canonicalization v1.0 w/o comments\n");
  41. }
  42. static xmlXPathObjectPtr
  43. load_xpath_expr (xmlDocPtr parent_doc, const char* filename);
  44. static xmlChar **parse_list(xmlChar *str);
  45. /* static void print_xpath_nodes(xmlNodeSetPtr nodes); */
  46. static int
  47. test_c14n(const char* xml_filename, int with_comments, int mode,
  48. const char* xpath_filename, xmlChar **inclusive_namespaces) {
  49. xmlDocPtr doc;
  50. xmlXPathObjectPtr xpath = NULL;
  51. xmlChar *result = NULL;
  52. int ret;
  53. /*
  54. * build an XML tree from a the file; we need to add default
  55. * attributes and resolve all character and entities references
  56. */
  57. xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
  58. xmlSubstituteEntitiesDefault(1);
  59. doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
  60. if (doc == NULL) {
  61. fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
  62. return(-1);
  63. }
  64. /*
  65. * Check the document is of the right kind
  66. */
  67. if(xmlDocGetRootElement(doc) == NULL) {
  68. fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
  69. xmlFreeDoc(doc);
  70. return(-1);
  71. }
  72. /*
  73. * load xpath file if specified
  74. */
  75. if(xpath_filename) {
  76. xpath = load_xpath_expr(doc, xpath_filename);
  77. if(xpath == NULL) {
  78. fprintf(stderr,"Error: unable to evaluate xpath expression\n");
  79. xmlFreeDoc(doc);
  80. return(-1);
  81. }
  82. }
  83. /*
  84. * Canonical form
  85. */
  86. /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
  87. ret = xmlC14NDocDumpMemory(doc,
  88. (xpath) ? xpath->nodesetval : NULL,
  89. mode, inclusive_namespaces,
  90. with_comments, &result);
  91. if(ret >= 0) {
  92. if(result != NULL) {
  93. write(1, result, ret);
  94. xmlFree(result);
  95. }
  96. } else {
  97. fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
  98. if(result != NULL) xmlFree(result);
  99. xmlFreeDoc(doc);
  100. return(-1);
  101. }
  102. /*
  103. * Cleanup
  104. */
  105. if(xpath != NULL) xmlXPathFreeObject(xpath);
  106. xmlFreeDoc(doc);
  107. return(ret);
  108. }
  109. int main(int argc, char **argv) {
  110. int ret = -1;
  111. /*
  112. * Init libxml
  113. */
  114. xmlInitParser();
  115. LIBXML_TEST_VERSION
  116. /*
  117. * Parse command line and process file
  118. */
  119. if( argc < 3 ) {
  120. fprintf(stderr, "Error: wrong number of arguments.\n");
  121. usage(argv[0]);
  122. } else if(strcmp(argv[1], "--with-comments") == 0) {
  123. ret = test_c14n(argv[2], 1, XML_C14N_1_0, (argc > 3) ? argv[3] : NULL, NULL);
  124. } else if(strcmp(argv[1], "--without-comments") == 0) {
  125. ret = test_c14n(argv[2], 0, XML_C14N_1_0, (argc > 3) ? argv[3] : NULL, NULL);
  126. } else if(strcmp(argv[1], "--1-1-with-comments") == 0) {
  127. ret = test_c14n(argv[2], 1, XML_C14N_1_1, (argc > 3) ? argv[3] : NULL, NULL);
  128. } else if(strcmp(argv[1], "--1-1-without-comments") == 0) {
  129. ret = test_c14n(argv[2], 0, XML_C14N_1_1, (argc > 3) ? argv[3] : NULL, NULL);
  130. } else if(strcmp(argv[1], "--exc-with-comments") == 0) {
  131. xmlChar **list;
  132. /* load exclusive namespace from command line */
  133. list = (argc > 4) ? parse_list((xmlChar *)argv[4]) : NULL;
  134. ret = test_c14n(argv[2], 1, XML_C14N_EXCLUSIVE_1_0, (argc > 3) ? argv[3] : NULL, list);
  135. if(list != NULL) xmlFree(list);
  136. } else if(strcmp(argv[1], "--exc-without-comments") == 0) {
  137. xmlChar **list;
  138. /* load exclusive namespace from command line */
  139. list = (argc > 4) ? parse_list((xmlChar *)argv[4]) : NULL;
  140. ret = test_c14n(argv[2], 0, XML_C14N_EXCLUSIVE_1_0, (argc > 3) ? argv[3] : NULL, list);
  141. if(list != NULL) xmlFree(list);
  142. } else {
  143. fprintf(stderr, "Error: bad option.\n");
  144. usage(argv[0]);
  145. }
  146. /*
  147. * Shutdown libxml
  148. */
  149. xmlCleanupParser();
  150. xmlMemoryDump();
  151. return((ret >= 0) ? 0 : 1);
  152. }
  153. /*
  154. * Macro used to grow the current buffer.
  155. */
  156. #define growBufferReentrant() { \
  157. buffer_size *= 2; \
  158. buffer = (xmlChar **) \
  159. xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
  160. if (buffer == NULL) { \
  161. perror("realloc failed"); \
  162. return(NULL); \
  163. } \
  164. }
  165. static xmlChar **
  166. parse_list(xmlChar *str) {
  167. xmlChar **buffer;
  168. xmlChar **out = NULL;
  169. int buffer_size = 0;
  170. int len;
  171. if(str == NULL) {
  172. return(NULL);
  173. }
  174. len = xmlStrlen(str);
  175. if((str[0] == '\'') && (str[len - 1] == '\'')) {
  176. str[len - 1] = '\0';
  177. str++;
  178. }
  179. /*
  180. * allocate an translation buffer.
  181. */
  182. buffer_size = 1000;
  183. buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
  184. if (buffer == NULL) {
  185. perror("malloc failed");
  186. return(NULL);
  187. }
  188. out = buffer;
  189. while(*str != '\0') {
  190. if (out - buffer > buffer_size - 10) {
  191. int indx = out - buffer;
  192. growBufferReentrant();
  193. out = &buffer[indx];
  194. }
  195. (*out++) = str;
  196. while(*str != ',' && *str != '\0') ++str;
  197. if(*str == ',') *(str++) = '\0';
  198. }
  199. (*out) = NULL;
  200. return buffer;
  201. }
  202. static xmlXPathObjectPtr
  203. load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
  204. xmlXPathObjectPtr xpath;
  205. xmlDocPtr doc;
  206. xmlChar *expr;
  207. xmlXPathContextPtr ctx;
  208. xmlNodePtr node;
  209. xmlNsPtr ns;
  210. /*
  211. * load XPath expr as a file
  212. */
  213. xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
  214. xmlSubstituteEntitiesDefault(1);
  215. doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
  216. if (doc == NULL) {
  217. fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
  218. return(NULL);
  219. }
  220. /*
  221. * Check the document is of the right kind
  222. */
  223. if(xmlDocGetRootElement(doc) == NULL) {
  224. fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
  225. xmlFreeDoc(doc);
  226. return(NULL);
  227. }
  228. node = doc->children;
  229. while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
  230. node = node->next;
  231. }
  232. if(node == NULL) {
  233. fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
  234. xmlFreeDoc(doc);
  235. return(NULL);
  236. }
  237. expr = xmlNodeGetContent(node);
  238. if(expr == NULL) {
  239. fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
  240. xmlFreeDoc(doc);
  241. return(NULL);
  242. }
  243. ctx = xmlXPathNewContext(parent_doc);
  244. if(ctx == NULL) {
  245. fprintf(stderr,"Error: unable to create new context\n");
  246. xmlFree(expr);
  247. xmlFreeDoc(doc);
  248. return(NULL);
  249. }
  250. /*
  251. * Register namespaces
  252. */
  253. ns = node->nsDef;
  254. while(ns != NULL) {
  255. if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
  256. fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
  257. xmlFree(expr);
  258. xmlXPathFreeContext(ctx);
  259. xmlFreeDoc(doc);
  260. return(NULL);
  261. }
  262. ns = ns->next;
  263. }
  264. /*
  265. * Evaluate xpath
  266. */
  267. xpath = xmlXPathEvalExpression(expr, ctx);
  268. if(xpath == NULL) {
  269. fprintf(stderr,"Error: unable to evaluate xpath expression\n");
  270. xmlFree(expr);
  271. xmlXPathFreeContext(ctx);
  272. xmlFreeDoc(doc);
  273. return(NULL);
  274. }
  275. /* print_xpath_nodes(xpath->nodesetval); */
  276. xmlFree(expr);
  277. xmlXPathFreeContext(ctx);
  278. xmlFreeDoc(doc);
  279. return(xpath);
  280. }
  281. /*
  282. static void
  283. print_xpath_nodes(xmlNodeSetPtr nodes) {
  284. xmlNodePtr cur;
  285. int i;
  286. if(nodes == NULL ){
  287. fprintf(stderr, "Error: no nodes set defined\n");
  288. return;
  289. }
  290. fprintf(stderr, "Nodes Set:\n-----\n");
  291. for(i = 0; i < nodes->nodeNr; ++i) {
  292. if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  293. xmlNsPtr ns;
  294. ns = (xmlNsPtr)nodes->nodeTab[i];
  295. cur = (xmlNodePtr)ns->next;
  296. fprintf(stderr, "namespace \"%s\"=\"%s\" for node %s:%s\n",
  297. ns->prefix, ns->href,
  298. (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
  299. } else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
  300. cur = nodes->nodeTab[i];
  301. fprintf(stderr, "element node \"%s:%s\"\n",
  302. (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
  303. } else {
  304. cur = nodes->nodeTab[i];
  305. fprintf(stderr, "node \"%s\": type %d\n", cur->name, cur->type);
  306. }
  307. }
  308. }
  309. */
  310. #else
  311. #include <stdio.h>
  312. int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
  313. printf("%s : XPath/Canonicalization and output support not compiled in\n", argv[0]);
  314. return(0);
  315. }
  316. #endif /* LIBXML_C14N_ENABLED */