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