blob: 14236fa58c30517b95a01f50a66d0eb6791ae3b7 [file] [log] [blame]
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001/*
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)
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
44xmlXPathObjectPtr
45load_xpath_expr (xmlDocPtr parent_doc, const char* filename);
46
47xmlChar **parse_list(xmlChar *str);
48
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000049void print_xpath_nodes(xmlNodeSetPtr nodes);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000050
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 = xmlParseFile(xml_filename);
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
182xmlChar **parse_list(xmlChar *str) {
183 xmlChar **buffer;
184 xmlChar **out = NULL;
185 int buffer_size = 0;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000186 int len;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000187
188 if(str == NULL) {
189 return(NULL);
190 }
191
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000192 len = strlen(str);
193 if((str[0] == '\'') && (str[len - 1] == '\'')) {
194 str[len - 1] = '\0';
195 str++;
196 len -= 2;
197 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000198 /*
199 * allocate an translation buffer.
200 */
201 buffer_size = 1000;
202 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
203 if (buffer == NULL) {
204 perror("malloc failed");
205 return(NULL);
206 }
207 out = buffer;
208
209 while(*str != '\0') {
210 if (out - buffer > buffer_size - 10) {
211 int indx = out - buffer;
212
213 growBufferReentrant();
214 out = &buffer[indx];
215 }
216 (*out++) = str;
217 while(*str != ',' && *str != '\0') ++str;
218 if(*str == ',') *(str++) = '\0';
219 }
220 (*out) = NULL;
221 return buffer;
222}
223
224xmlXPathObjectPtr
225load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
226 xmlXPathObjectPtr xpath;
227 xmlDocPtr doc;
228 xmlChar *expr;
229 xmlXPathContextPtr ctx;
230 xmlNodePtr node;
231 xmlNsPtr ns;
232
233 /*
234 * load XPath expr as a file
235 */
236 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
237 xmlSubstituteEntitiesDefault(1);
238
239 doc = xmlParseFile(filename);
240 if (doc == NULL) {
241 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
242 return(NULL);
243 }
244
245 /*
246 * Check the document is of the right kind
247 */
248 if(xmlDocGetRootElement(doc) == NULL) {
249 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
250 xmlFreeDoc(doc);
251 return(NULL);
252 }
253
254 node = doc->children;
255 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
256 node = node->next;
257 }
258
259 if(node == NULL) {
260 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
261 xmlFreeDoc(doc);
262 return(NULL);
263 }
264
265 expr = xmlNodeGetContent(node);
266 if(expr == NULL) {
267 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
268 xmlFreeDoc(doc);
269 return(NULL);
270 }
271
272 ctx = xmlXPathNewContext(parent_doc);
273 if(ctx == NULL) {
274 fprintf(stderr,"Error: unable to create new context\n");
275 xmlFree(expr);
276 xmlFreeDoc(doc);
277 return(NULL);
278 }
279
280 /*
281 * Register namespaces
282 */
283 ns = node->nsDef;
284 while(ns != NULL) {
285 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
286 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
287 xmlFree(expr);
288 xmlXPathFreeContext(ctx);
289 xmlFreeDoc(doc);
290 return(NULL);
291 }
292 ns = ns->next;
293 }
294
295 /*
296 * Evaluate xpath
297 */
298 xpath = xmlXPathEvalExpression(expr, ctx);
299 if(xpath == NULL) {
300 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
301 xmlFree(expr);
302 xmlXPathFreeContext(ctx);
303 xmlFreeDoc(doc);
304 return(NULL);
305 }
306
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000307 /* print_xpath_nodes(xpath->nodesetval); */
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000308
309 xmlFree(expr);
310 xmlXPathFreeContext(ctx);
311 xmlFreeDoc(doc);
312 return(xpath);
313}
314
315void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000316print_xpath_nodes(xmlNodeSetPtr nodes) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000317 xmlNodePtr cur;
318 int i;
319
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000320 if(nodes == NULL ){
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000321 fprintf(stderr, "Error: no nodes set defined\n");
322 return;
323 }
324
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000325 fprintf(stderr, "Nodes Set:\n-----\n");
326 for(i = 0; i < nodes->nodeNr; ++i) {
327 if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
328 xmlNsPtr ns;
329
330 ns = (xmlNsPtr)nodes->nodeTab[i];
331 cur = (xmlNodePtr)ns->next;
332 fprintf(stderr, "namespace \"%s\"=\"%s\" for node %s:%s\n",
333 ns->prefix, ns->href,
334 (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
335 } else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
336 cur = nodes->nodeTab[i];
337 fprintf(stderr, "element node \"%s:%s\"\n",
338 (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
339 } else {
340 cur = nodes->nodeTab[i];
341 fprintf(stderr, "node \"%s\": type %d\n", cur->name, cur->type);
342 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000343 }
344}
345
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000346
347
348
349
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000350#else
351#include <stdio.h>
352int main(int argc, char **argv) {
353 printf("%s : XPath/Canonicalization support not compiled in\n", argv[0]);
354 return(0);
355}
356#endif /* LIBXML_C14N_ENABLED */
357
358