blob: 951dce7a305189a67eda31e63174f3c5e542284a [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
Daniel Veillardfe8aab92002-12-22 10:25:41 +000044static xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +000045load_xpath_expr (xmlDocPtr parent_doc, const char* filename);
46
Daniel Veillardfe8aab92002-12-22 10:25:41 +000047static xmlChar **parse_list(xmlChar *str);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000048
Daniel Veillardfe8aab92002-12-22 10:25:41 +000049static void 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
Daniel Veillard01c13b52002-12-10 15:19:08 +0000182static xmlChar **
183parse_list(xmlChar *str) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000184 xmlChar **buffer;
185 xmlChar **out = NULL;
186 int buffer_size = 0;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000187 int len;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000188
189 if(str == NULL) {
190 return(NULL);
191 }
192
Daniel Veillard118aed72002-09-24 14:13:13 +0000193 len = xmlStrlen(str);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000194 if((str[0] == '\'') && (str[len - 1] == '\'')) {
195 str[len - 1] = '\0';
196 str++;
197 len -= 2;
198 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000199 /*
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
Daniel Veillard01c13b52002-12-10 15:19:08 +0000225static xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000226load_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 = xmlParseFile(filename);
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
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000308 /* print_xpath_nodes(xpath->nodesetval); */
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000309
310 xmlFree(expr);
311 xmlXPathFreeContext(ctx);
312 xmlFreeDoc(doc);
313 return(xpath);
314}
315
Daniel Veillard01c13b52002-12-10 15:19:08 +0000316static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000317print_xpath_nodes(xmlNodeSetPtr nodes) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000318 xmlNodePtr cur;
319 int i;
320
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000321 if(nodes == NULL ){
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000322 fprintf(stderr, "Error: no nodes set defined\n");
323 return;
324 }
325
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000326 fprintf(stderr, "Nodes Set:\n-----\n");
327 for(i = 0; i < nodes->nodeNr; ++i) {
328 if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
329 xmlNsPtr ns;
330
331 ns = (xmlNsPtr)nodes->nodeTab[i];
332 cur = (xmlNodePtr)ns->next;
333 fprintf(stderr, "namespace \"%s\"=\"%s\" for node %s:%s\n",
334 ns->prefix, ns->href,
335 (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
336 } else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
337 cur = nodes->nodeTab[i];
338 fprintf(stderr, "element node \"%s:%s\"\n",
339 (cur->ns) ? cur->ns->prefix : BAD_CAST "", cur->name);
340 } else {
341 cur = nodes->nodeTab[i];
342 fprintf(stderr, "node \"%s\": type %d\n", cur->name, cur->type);
343 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000344 }
345}
346
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000347
348
349
350
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000351#else
352#include <stdio.h>
353int main(int argc, char **argv) {
354 printf("%s : XPath/Canonicalization support not compiled in\n", argv[0]);
355 return(0);
356}
357#endif /* LIBXML_C14N_ENABLED */
358
359