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