blob: 01c46b10e9e449e9482ef551382401d6d3f324c2 [file] [log] [blame]
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001/*
2 * "Canonical XML" implementation
3 * http://www.w3.org/TR/xml-c14n
4 *
5 * "Exclusive XML Canonicalization" implementation
6 * http://www.w3.org/TR/xml-exc-c14n
7 *
8 * See Copyright for the status of this software.
9 *
10 * Author: Aleksey Sanin <aleksey@aleksey.com>
11 */
Daniel Veillard34ce8be2002-03-18 19:37:11 +000012#define IN_LIBXML
Daniel Veillard044fc6b2002-03-04 17:09:44 +000013#include "libxml.h"
14#ifdef LIBXML_C14N_ENABLED
Daniel Veillarda9cce9c2003-09-29 13:20:24 +000015#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard044fc6b2002-03-04 17:09:44 +000016
17#ifdef HAVE_STDLIB_H
18#include <stdlib.h>
19#endif
20#include <string.h>
21
22#include <libxml/tree.h>
23#include <libxml/parser.h>
Daniel Veillard9ff88172002-03-11 09:15:32 +000024#include <libxml/uri.h>
Daniel Veillard044fc6b2002-03-04 17:09:44 +000025#include <libxml/xmlerror.h>
26#include <libxml/globals.h>
27#include <libxml/xpathInternals.h>
28#include <libxml/c14n.h>
29
30/************************************************************************
31 * *
32 * Some declaration better left private ATM *
33 * *
34 ************************************************************************/
35
Daniel Veillard9ff88172002-03-11 09:15:32 +000036typedef enum {
37 XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
38 XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
39 XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
Daniel Veillard044fc6b2002-03-04 17:09:44 +000040} xmlC14NPosition;
41
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000042typedef struct _xmlC14NVisibleNsStack {
Aleksey Sanin2c135a12002-08-01 06:31:50 +000043 int nsCurEnd; /* number of nodes in the set */
44 int nsPrevStart; /* the begginning of the stack for previous visible node */
45 int nsPrevEnd; /* the end of the stack for previous visible node */
46 int nsMax; /* size of the array as allocated */
47 xmlNsPtr *nsTab; /* array of ns in no particular order */
48 xmlNodePtr *nodeTab;/* array of nodes in no particular order */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000049} xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
Aleksey Sanindffd5c82002-05-31 04:24:13 +000050
Daniel Veillard044fc6b2002-03-04 17:09:44 +000051typedef struct _xmlC14NCtx {
52 /* input parameters */
Daniel Veillard9ff88172002-03-11 09:15:32 +000053 xmlDocPtr doc;
Aleksey Sanin2c135a12002-08-01 06:31:50 +000054 xmlC14NIsVisibleCallback is_visible_callback;
55 void* user_data;
Daniel Veillard9ff88172002-03-11 09:15:32 +000056 int with_comments;
57 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000058
59 /* position in the XML document */
Daniel Veillard9ff88172002-03-11 09:15:32 +000060 xmlC14NPosition pos;
61 int parent_is_doc;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000062 xmlC14NVisibleNsStackPtr ns_rendered;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000063
64 /* exclusive canonicalization */
Daniel Veillard9ff88172002-03-11 09:15:32 +000065 int exclusive;
Daniel Veillard9ff88172002-03-11 09:15:32 +000066 xmlChar **inclusive_ns_prefixes;
Daniel Veillardd96cce12003-10-10 12:30:37 +000067
68 /* error number */
69 int error;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000070} xmlC14NCtx, *xmlC14NCtxPtr;
71
Aleksey Sanin2c135a12002-08-01 06:31:50 +000072static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
73static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
74static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
75 xmlNsPtr ns,
76 xmlNodePtr node);
77static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
78 xmlC14NVisibleNsStackPtr state);
79static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
80 xmlC14NVisibleNsStackPtr state);
81static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
82static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
83 xmlNsPtr ns);
84static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
85 xmlNsPtr ns,
86 xmlC14NCtxPtr ctx);
87
88static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes,
89 xmlNodePtr node,
90 xmlNodePtr parent);
91
92
Daniel Veillard044fc6b2002-03-04 17:09:44 +000093
Daniel Veillard9ff88172002-03-11 09:15:32 +000094static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
95static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000096typedef enum {
Daniel Veillard9ff88172002-03-11 09:15:32 +000097 XMLC14N_NORMALIZE_ATTR = 0,
98 XMLC14N_NORMALIZE_COMMENT = 1,
99 XMLC14N_NORMALIZE_PI = 2,
100 XMLC14N_NORMALIZE_TEXT = 3
101} xmlC14NNormalizationMode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000102
Daniel Veillard9ff88172002-03-11 09:15:32 +0000103static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
104 xmlC14NNormalizationMode mode);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000105
106#define xmlC11NNormalizeAttr( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000107 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000108#define xmlC11NNormalizeComment( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000109 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000110#define xmlC11NNormalizePI( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000111 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000112#define xmlC11NNormalizeText( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000113 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000114
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000115#define xmlC14NIsVisible( ctx, node, parent ) \
116 (((ctx)->is_visible_callback != NULL) ? \
117 (ctx)->is_visible_callback((ctx)->user_data, \
118 (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
Daniel Veillardd96cce12003-10-10 12:30:37 +0000119
120/************************************************************************
121 * *
122 * Some factorized error routines *
123 * *
124 ************************************************************************/
125
126/**
127 * xmlC14NErrMemory:
128 * @extra: extra informations
129 *
130 * Handle a redefinition of attribute error
131 */
132static void
133xmlC14NErrMemory(const char *extra)
134{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000135 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
Daniel Veillardd96cce12003-10-10 12:30:37 +0000136 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
137 NULL, NULL, 0, 0,
138 "Memory allocation failed : %s\n", extra);
139}
140
141/**
142 * xmlC14NErr:
143 * @ctxt: a C14N evaluation context
144 * @node: the context node
145 * @error: the erorr code
146 * @msg: the message
147 * @extra: extra informations
148 *
149 * Handle a redefinition of attribute error
150 */
151static void
152xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error,
153 const char * msg)
154{
155 if (ctxt != NULL)
156 ctxt->error = error;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000157 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96cce12003-10-10 12:30:37 +0000158 ctxt, node, XML_FROM_C14N, error,
159 XML_ERR_ERROR, NULL, 0,
160 NULL, NULL, NULL, 0, 0, msg);
161}
162
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000163/************************************************************************
164 * *
165 * The implementation internals *
166 * *
167 ************************************************************************/
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000168#define XML_NAMESPACES_DEFAULT 16
169
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000170static int
171xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
172 if((nodes != NULL) && (node != NULL)) {
173 if(node->type != XML_NAMESPACE_DECL) {
174 return(xmlXPathNodeSetContains(nodes, node));
175 } else {
176 xmlNs ns;
177
178 memcpy(&ns, node, sizeof(ns));
179 ns.next = (xmlNsPtr)parent; /* this is a libxml hack! check xpath.c for details */
180
181 /*
182 * If the input is an XPath node-set, then the node-set must explicitly
183 * contain every node to be rendered to the canonical form.
184 */
185 return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
186 }
187 }
188 return(1);
189}
190
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000191static xmlC14NVisibleNsStackPtr
192xmlC14NVisibleNsStackCreate(void) {
193 xmlC14NVisibleNsStackPtr ret;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000194
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000195 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000196 if (ret == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000197 xmlC14NErrMemory("creating stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000198 return(NULL);
199 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000200 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000201 return(ret);
202}
203
204static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000205xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000206 if(cur == NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000207#ifdef DEBUG_C14N
208 xmlGenericError(xmlGenericErrorContext,
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000209 "xmlC14NVisibleNsStackDestroy: cur is null.\n");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000210#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000211 return;
212 }
213 if(cur->nsTab != NULL) {
214 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
215 xmlFree(cur->nsTab);
216 }
Aleksey Saninea4272a2002-08-02 23:50:03 +0000217 if(cur->nodeTab != NULL) {
218 memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
219 xmlFree(cur->nodeTab);
220 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000221 memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000222 xmlFree(cur);
223
224}
225
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000226static void
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000227xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
228 if((cur == NULL) ||
229 ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
230 ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000231#ifdef DEBUG_C14N
232 xmlGenericError(xmlGenericErrorContext,
233 "xmlC14NVisibleNsStackAdd: cur is null.\n");
234#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000235 return;
236 }
237
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000238 if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000239 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000240 cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
241 if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000242 xmlC14NErrMemory("adding node to stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000243 return;
244 }
245 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000246 memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000247 cur->nsMax = XML_NAMESPACES_DEFAULT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000248 } else if(cur->nsMax == cur->nsCurEnd) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000249 void *tmp;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000250 int tmpSize;
251
252 tmpSize = 2 * cur->nsMax;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000253 tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000254 if (tmp == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000255 xmlC14NErrMemory("adding node to stack");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000256 return;
257 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000258 cur->nsTab = (xmlNsPtr*)tmp;
259
260 tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
261 if (tmp == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +0000262 xmlC14NErrMemory("adding node to stack");
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000263 return;
264 }
265 cur->nodeTab = (xmlNodePtr*)tmp;
266
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000267 cur->nsMax = tmpSize;
268 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000269 cur->nsTab[cur->nsCurEnd] = ns;
270 cur->nodeTab[cur->nsCurEnd] = node;
271
272 ++cur->nsCurEnd;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000273}
274
275static void
276xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
277 if((cur == NULL) || (state == NULL)) {
278#ifdef DEBUG_C14N
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlC14NVisibleNsStackSave: cur or state is null.\n");
281#endif
282 return;
283 }
284
285 state->nsCurEnd = cur->nsCurEnd;
286 state->nsPrevStart = cur->nsPrevStart;
287 state->nsPrevEnd = cur->nsPrevEnd;
288}
289
290static void
291xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
292 if((cur == NULL) || (state == NULL)) {
293#ifdef DEBUG_C14N
294 xmlGenericError(xmlGenericErrorContext,
295 "xmlC14NVisibleNsStackRestore: cur or state is null.\n");
296#endif
297 return;
298 }
299 cur->nsCurEnd = state->nsCurEnd;
300 cur->nsPrevStart = state->nsPrevStart;
301 cur->nsPrevEnd = state->nsPrevEnd;
302}
303
304static void
305xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
306 if(cur == NULL) {
307#ifdef DEBUG_C14N
308 xmlGenericError(xmlGenericErrorContext,
309 "xmlC14NVisibleNsStackRestore: cur is null.\n");
310#endif
311 return;
312 }
313 cur->nsPrevStart = cur->nsPrevEnd;
314 cur->nsPrevEnd = cur->nsCurEnd;
315}
316
317static int
318xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
319 if (str1 == str2) return(1);
320 if (str1 == NULL) return((*str2) == '\0');
321 if (str2 == NULL) return((*str1) == '\0');
322 do {
323 if (*str1++ != *str2) return(0);
324 } while (*str2++);
325 return(1);
326}
327
328/**
329 * xmlC14NVisibleNsStackFind:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000330 * @ctx: the C14N context
331 * @ns: the namespace to check
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000332 *
333 * Checks whether the given namespace was already rendered or not
334 *
335 * Returns 1 if we already wrote this namespace or 0 otherwise
336 */
337static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000338xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000339{
340 int i;
341 const xmlChar *prefix;
342 const xmlChar *href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000343 int has_empty_ns;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000344
345 if(cur == NULL) {
346#ifdef DEBUG_C14N
347 xmlGenericError(xmlGenericErrorContext,
348 "xmlC14NVisibleNsStackFind: cur is null.\n");
349#endif
350 return (0);
351 }
352
353 /*
354 * if the default namespace xmlns="" is not defined yet then
355 * we do not want to print it out
356 */
357 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
358 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000359 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
360
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000361 if (cur->nsTab != NULL) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000362 int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000363 for (i = cur->nsCurEnd - 1; i >= start; --i) {
364 xmlNsPtr ns1 = cur->nsTab[i];
365
366 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
367 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
368 }
369 }
370 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000371 return(has_empty_ns);
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000372}
373
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000374static int
375xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
376 int i;
377 const xmlChar *prefix;
378 const xmlChar *href;
379 int has_empty_ns;
380
381 if(cur == NULL) {
382#ifdef DEBUG_C14N
383 xmlGenericError(xmlGenericErrorContext,
384 "xmlExcC14NVisibleNsStackFind: cur is null.\n");
385#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000386 return (0);
387 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000388
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000389 /*
390 * if the default namespace xmlns="" is not defined yet then
391 * we do not want to print it out
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000392 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000393 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
394 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
395 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000396
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000397 if (cur->nsTab != NULL) {
398 int start = 0;
399 for (i = cur->nsCurEnd - 1; i >= start; --i) {
400 xmlNsPtr ns1 = cur->nsTab[i];
401
402 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
403 if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
404 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
405 } else {
406 return(0);
407 }
408 }
409 }
410 }
411 return(has_empty_ns);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000412}
413
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000414
415
416
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000417/**
418 * xmlC14NIsXmlNs:
419 * @ns: the namespace to check
420 *
421 * Checks whether the given namespace is a default "xml:" namespace
422 * with href="http://www.w3.org/XML/1998/namespace"
423 *
424 * Returns 1 if the node is default or 0 otherwise
425 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000426
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000427/* todo: make it a define? */
428static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000429xmlC14NIsXmlNs(xmlNsPtr ns)
430{
431 return ((ns != NULL) &&
432 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
433 (xmlStrEqual(ns->href,
434 BAD_CAST
435 "http://www.w3.org/XML/1998/namespace")));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000436}
437
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000438
439/**
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000440 * xmlC14NNsCompare:
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000441 * @ns1: the pointer to first namespace
442 * @ns2: the pointer to second namespace
443 *
444 * Compares the namespaces by names (prefixes).
445 *
446 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
447 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000448static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000449xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000450{
451 if (ns1 == ns2)
452 return (0);
453 if (ns1 == NULL)
454 return (-1);
455 if (ns2 == NULL)
456 return (1);
457
458 return (xmlStrcmp(ns1->prefix, ns2->prefix));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000459}
460
461
462/**
463 * xmlC14NPrintNamespaces:
464 * @ns: the pointer to namespace
465 * @ctx: the C14N context
466 *
467 * Prints the given namespace to the output buffer from C14N context.
468 *
469 * Returns 1 on success or 0 on fail.
470 */
471static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000472xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
473{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000474
Daniel Veillard9ff88172002-03-11 09:15:32 +0000475 if ((ns == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000476#ifdef DEBUG_C14N
477 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000478 "xmlC14NPrintNamespace: namespace or context pointer is null\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000479#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000480 return 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000481 }
482
Daniel Veillard9ff88172002-03-11 09:15:32 +0000483 if (ns->prefix != NULL) {
484 xmlOutputBufferWriteString(ctx->buf, " xmlns:");
485 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
486 xmlOutputBufferWriteString(ctx->buf, "=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000487 } else {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000488 xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000489 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000490 if(ns->href != NULL) {
491 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
492 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000493 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000494 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000495}
496
497/**
498 * xmlC14NProcessNamespacesAxis:
499 * @ctx: the C14N context
500 * @node: the current node
501 *
502 * Prints out canonical namespace axis of the current node to the
503 * buffer from C14N context as follows
504 *
505 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
506 *
507 * Namespace Axis
508 * Consider a list L containing only namespace nodes in the
509 * axis and in the node-set in lexicographic order (ascending). To begin
510 * processing L, if the first node is not the default namespace node (a node
511 * with no namespace URI and no local name), then generate a space followed
512 * by xmlns="" if and only if the following conditions are met:
513 * - the element E that owns the axis is in the node-set
514 * - The nearest ancestor element of E in the node-set has a default
515 * namespace node in the node-set (default namespace nodes always
516 * have non-empty values in XPath)
517 * The latter condition eliminates unnecessary occurrences of xmlns="" in
518 * the canonical form since an element only receives an xmlns="" if its
519 * default namespace is empty and if it has an immediate parent in the
520 * canonical form that has a non-empty default namespace. To finish
521 * processing L, simply process every namespace node in L, except omit
522 * namespace node with local name xml, which defines the xml prefix,
523 * if its string value is http://www.w3.org/XML/1998/namespace.
524 *
525 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
526 * Canonical XML applied to a document subset requires the search of the
527 * ancestor nodes of each orphan element node for attributes in the xml
528 * namespace, such as xml:lang and xml:space. These are copied into the
529 * element node except if a declaration of the same attribute is already
530 * in the attribute axis of the element (whether or not it is included in
531 * the document subset). This search and copying are omitted from the
532 * Exclusive XML Canonicalization method.
533 *
534 * Returns 0 on success or -1 on fail.
535 */
536static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000537xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000538{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000539 xmlNodePtr n;
540 xmlNsPtr ns, tmp;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000541 xmlListPtr list;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000542 int already_rendered;
543 int has_empty_ns = 0;
Daniel Veillard5c396542002-03-15 07:57:50 +0000544
Daniel Veillard9ff88172002-03-11 09:15:32 +0000545 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
546#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000548 "xmlC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
549#endif
550 return (-1);
551 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000552
553 /*
554 * Create a sorted list to store element namespaces
555 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000556 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000557 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000558#ifdef DEBUG_C14N
559 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000560 "xmlC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000561#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000562 return (-1);
563 }
564
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000565 /* check all namespaces */
566 for(n = cur; n != NULL; n = n->parent) {
567 for(ns = n->nsDef; ns != NULL; ns = ns->next) {
568 tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
569
570 if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
571 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
572 if(visible) {
573 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
574 }
575 if(!already_rendered) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000576 xmlListInsert(list, ns);
577 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000578 if(xmlStrlen(ns->prefix) == 0) {
579 has_empty_ns = 1;
580 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000581 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000582 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000583 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000584
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000585 /**
586 * if the first node is not the default namespace node (a node with no
587 * namespace URI and no local name), then generate a space followed by
588 * xmlns="" if and only if the following conditions are met:
589 * - the element E that owns the axis is in the node-set
590 * - the nearest ancestor element of E in the node-set has a default
591 * namespace node in the node-set (default namespace nodes always
592 * have non-empty values in XPath)
593 */
594 if(visible && !has_empty_ns) {
595 static xmlNs ns_default;
596
597 memset(&ns_default, 0, sizeof(ns_default));
598 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
599 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000600 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000601 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000602
603
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000604 /*
605 * print out all elements from list
606 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000607 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000608
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000609 /*
610 * Cleanup
611 */
612 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000613 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000614}
615
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000616
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000617/**
618 * xmlExcC14NProcessNamespacesAxis:
619 * @ctx: the C14N context
620 * @node: the current node
621 *
622 * Prints out exclusive canonical namespace axis of the current node to the
623 * buffer from C14N context as follows
624 *
625 * Exclusive XML Canonicalization
626 * http://www.w3.org/TR/xml-exc-c14n
627 *
628 * If the element node is in the XPath subset then output the node in
629 * accordance with Canonical XML except for namespace nodes which are
630 * rendered as follows:
631 *
632 * 1. Render each namespace node iff:
633 * * it is visibly utilized by the immediate parent element or one of
634 * its attributes, or is present in InclusiveNamespaces PrefixList, and
635 * * its prefix and value do not appear in ns_rendered. ns_rendered is
636 * obtained by popping the state stack in order to obtain a list of
637 * prefixes and their values which have already been rendered by
638 * an output ancestor of the namespace node's parent element.
639 * 2. Append the rendered namespace node to the list ns_rendered of namespace
640 * nodes rendered by output ancestors. Push ns_rendered on state stack and
641 * recurse.
642 * 3. After the recursion returns, pop thestate stack.
643 *
644 *
645 * Returns 0 on success or -1 on fail.
646 */
647static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000648xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000649{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000650 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000651 xmlListPtr list;
652 xmlAttrPtr attr;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000653 int already_rendered;
654 int has_empty_ns = 0;
655 int has_visibly_utilized_empty_ns = 0;
656 int has_empty_ns_in_inclusive_list = 0;
657
Daniel Veillard9ff88172002-03-11 09:15:32 +0000658 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
659#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000660 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000661 "xmlExcC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
662#endif
663 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000664 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000665
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000666 if(!ctx->exclusive) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000667#ifdef DEBUG_C14N
668 xmlGenericError(xmlGenericErrorContext,
669 "xmlExcC14NProcessNamespacesAxis: called for non-exclusive canonization or rendered stack is NULL.\n");
670#endif
671 return (-1);
672
673 }
674
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000675 /*
676 * Create a sorted list to store element namespaces
677 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000678 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000679 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000680#ifdef DEBUG_C14N
681 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000682 "xmlExcC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000683#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000684 return (-1);
685 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000686
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000687 /*
688 * process inclusive namespaces:
689 * All namespace nodes appearing on inclusive ns list are
690 * handled as provided in Canonical XML
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000691 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000692 if(ctx->inclusive_ns_prefixes != NULL) {
693 xmlChar *prefix;
694 int i;
695
696 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
697 prefix = ctx->inclusive_ns_prefixes[i];
698 /*
699 * Special values for namespace with empty prefix
700 */
701 if (xmlStrEqual(prefix, BAD_CAST "#default")
702 || xmlStrEqual(prefix, BAD_CAST "")) {
703 prefix = NULL;
704 has_empty_ns_in_inclusive_list = 1;
705 }
706
707 ns = xmlSearchNs(cur->doc, cur, prefix);
708 if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
709 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
710 if(visible) {
711 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
712 }
713 if(!already_rendered) {
714 xmlListInsert(list, ns);
715 }
716 if(xmlStrlen(ns->prefix) == 0) {
717 has_empty_ns = 1;
718 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000719 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000720 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000721 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000722
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000723 /* add node namespace */
724 if(cur->ns != NULL) {
725 ns = cur->ns;
726 } else {
727 ns = xmlSearchNs(cur->doc, cur, NULL);
728 has_visibly_utilized_empty_ns = 1;
729 }
730 if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
731 if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
732 if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
733 xmlListInsert(list, ns);
734 }
735 }
736 if(visible) {
737 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
738 }
739 if(xmlStrlen(ns->prefix) == 0) {
740 has_empty_ns = 1;
741 }
742 }
743
744
745 /* add attributes */
746 for(attr = cur->properties; attr != NULL; attr = attr->next) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000747 /*
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000748 * we need to check that attribute is visible and has non
749 * default namespace (XML Namespaces: "default namespaces
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000750 * do not apply directly to attributes")
Daniel Veillard9ff88172002-03-11 09:15:32 +0000751 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000752 if((attr->ns != NULL) && xmlC14NIsVisible(ctx, attr, cur)) {
753 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
754 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, (xmlNodePtr)attr);
755 if(!already_rendered && visible) {
756 xmlListInsert(list, attr->ns);
757 }
758 if(xmlStrlen(attr->ns->prefix) == 0) {
759 has_empty_ns = 1;
760 }
761 } else if(attr->ns == NULL) {
762 has_visibly_utilized_empty_ns = 1;
763 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000764 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000765
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000766 /*
767 * Process xmlns=""
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000768 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000769 if(visible && has_visibly_utilized_empty_ns &&
770 !has_empty_ns && !has_empty_ns_in_inclusive_list) {
771 static xmlNs ns_default;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000772
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000773 memset(&ns_default, 0, sizeof(ns_default));
774
775 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
776 if(!already_rendered) {
777 xmlC14NPrintNamespaces(&ns_default, ctx);
778 }
779 } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
780 static xmlNs ns_default;
781
782 memset(&ns_default, 0, sizeof(ns_default));
783 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
784 xmlC14NPrintNamespaces(&ns_default, ctx);
785 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000786 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000787
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000788
789
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000790 /*
791 * print out all elements from list
792 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000793 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000794
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000795 /*
796 * Cleanup
797 */
798 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000799 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000800}
801
802
803/**
804 * xmlC14NAttrsCompare:
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000805 * @attr1: the pointer tls o first attr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000806 * @attr2: the pointer to second attr
807 *
808 * Prints the given attribute to the output buffer from C14N context.
809 *
810 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
811 */
812static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000813xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
814{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000815 int ret = 0;
816
817 /*
818 * Simple cases
819 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000820 if (attr1 == attr2)
821 return (0);
822 if (attr1 == NULL)
823 return (-1);
824 if (attr2 == NULL)
825 return (1);
826 if (attr1->ns == attr2->ns) {
827 return (xmlStrcmp(attr1->name, attr2->name));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000828 }
829
830 /*
831 * Attributes in the default namespace are first
832 * because the default namespace is not applied to
833 * unqualified attributes
834 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000835 if (attr1->ns == NULL)
836 return (-1);
837 if (attr2->ns == NULL)
838 return (1);
839 if (attr1->ns->prefix == NULL)
840 return (-1);
841 if (attr2->ns->prefix == NULL)
842 return (1);
843
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000844 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000845 if (ret == 0) {
846 ret = xmlStrcmp(attr1->name, attr2->name);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000847 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000848 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000849}
850
851
852/**
853 * xmlC14NPrintAttrs:
854 * @attr: the pointer to attr
855 * @ctx: the C14N context
856 *
857 * Prints out canonical attribute urrent node to the
858 * buffer from C14N context as follows
859 *
860 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
861 *
862 * Returns 1 on success or 0 on fail.
863 */
864static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000865xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
866{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000867 xmlChar *value;
868 xmlChar *buffer;
869
Daniel Veillard9ff88172002-03-11 09:15:32 +0000870 if ((attr == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000871#ifdef DEBUG_C14N
872 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000873 "xmlC14NPrintAttrs: attr == NULL or ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000874#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000875 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000876 }
877
878 xmlOutputBufferWriteString(ctx->buf, " ");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000879 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
880 xmlOutputBufferWriteString(ctx->buf,
881 (const char *) attr->ns->prefix);
882 xmlOutputBufferWriteString(ctx->buf, ":");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000883 }
884 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
885 xmlOutputBufferWriteString(ctx->buf, "=\"");
886
887 value = xmlNodeListGetString(attr->doc, attr->children, 1);
888 /* todo: should we log an error if value==NULL ? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000889 if (value != NULL) {
890 buffer = xmlC11NNormalizeAttr(value);
891 xmlFree(value);
892 if (buffer != NULL) {
893 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
894 xmlFree(buffer);
895 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000896#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +0000897 xmlGenericError(xmlGenericErrorContext,
898 "xmlC14NPrintAttrs: xmlC11NNormalizeAttr failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000899#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000900 return (0);
901 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000902 }
903 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000904 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000905}
906
907/**
908 * xmlC14NProcessAttrsAxis:
909 * @ctx: the C14N context
910 * @cur: the current node
911 *
912 * Prints out canonical attribute axis of the current node to the
913 * buffer from C14N context as follows
914 *
915 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
916 *
917 * Attribute Axis
918 * In lexicographic order (ascending), process each node that
919 * is in the element's attribute axis and in the node-set.
920 *
921 * The processing of an element node E MUST be modified slightly
922 * when an XPath node-set is given as input and the element's
923 * parent is omitted from the node-set.
924 *
925 *
926 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
927 *
928 * Canonical XML applied to a document subset requires the search of the
929 * ancestor nodes of each orphan element node for attributes in the xml
930 * namespace, such as xml:lang and xml:space. These are copied into the
931 * element node except if a declaration of the same attribute is already
932 * in the attribute axis of the element (whether or not it is included in
933 * the document subset). This search and copying are omitted from the
934 * Exclusive XML Canonicalization method.
935 *
936 * Returns 0 on success or -1 on fail.
937 */
938static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000939xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur)
940{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000941 xmlAttrPtr attr;
942 xmlListPtr list;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000943
944 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
945#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000946 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000947 "xmlC14NProcessAttrsAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
948#endif
949 return (-1);
950 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000951
952 /*
953 * Create a sorted list to store element attributes
954 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000955 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
956 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000957#ifdef DEBUG_C14N
958 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000959 "xmlC14NProcessAttrsAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000960#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000961 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000962 }
963
964 /*
965 * Add all visible attributes from current node.
966 */
967 attr = cur->properties;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000968 while (attr != NULL) {
969 /* check that attribute is visible */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000970 if (xmlC14NIsVisible(ctx, attr, cur)) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000971 xmlListInsert(list, attr);
972 }
973 attr = attr->next;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000974 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000975
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000976 /*
977 * include attributes in "xml" namespace defined in ancestors
978 * (only for non-exclusive XML Canonicalization)
979 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000980 if ((!ctx->exclusive) && (cur->parent != NULL)
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000981 && (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000982 /*
Daniel Veillard9ff88172002-03-11 09:15:32 +0000983 * If XPath node-set is not specified then the parent is always
984 * visible!
985 */
986 cur = cur->parent;
987 while (cur != NULL) {
988 attr = cur->properties;
989 while (attr != NULL) {
990 if ((attr->ns != NULL)
991 && (xmlStrEqual(attr->ns->prefix, BAD_CAST "xml"))) {
992 if (xmlListSearch(list, attr) == NULL) {
993 xmlListInsert(list, attr);
994 }
995 }
996 attr = attr->next;
997 }
998 cur = cur->parent;
999 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001000 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001001
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001002 /*
1003 * print out all elements from list
1004 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001005 xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001006
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001007 /*
1008 * Cleanup
1009 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001010 xmlListDelete(list);
1011 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001012}
1013
1014/**
1015 * xmlC14NCheckForRelativeNamespaces:
1016 * @ctx: the C14N context
1017 * @cur: the current element node
1018 *
1019 * Checks that current element node has no relative namespaces defined
1020 *
1021 * Returns 0 if the node has no relative namespaces or -1 otherwise.
1022 */
1023static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001024xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1025{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001026 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001027
Daniel Veillard9ff88172002-03-11 09:15:32 +00001028 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1029#ifdef DEBUG_C14N
1030 xmlGenericError(xmlGenericErrorContext,
1031 "xmlC14NCheckForRelativeNamespaces: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
1032#endif
1033 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001034 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001035
1036 ns = cur->nsDef;
1037 while (ns != NULL) {
1038 if (xmlStrlen(ns->href) > 0) {
1039 xmlURIPtr uri;
1040
1041 uri = xmlParseURI((const char *) ns->href);
1042 if (uri == NULL) {
1043#ifdef DEBUG_C14N
1044 xmlGenericError(xmlGenericErrorContext,
1045 "xmlC14NCheckForRelativeNamespaces: unable to parse uri=\"%s\".\n",
1046 ns->href);
1047#endif
1048 return (-1);
1049 }
1050 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
1051 xmlFreeURI(uri);
1052 return (-1);
1053 }
1054 if ((!xmlStrEqual
1055 ((const xmlChar *) uri->scheme, BAD_CAST "urn"))
1056 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
1057 xmlFreeURI(uri);
1058 return (-1);
1059 }
1060 xmlFreeURI(uri);
1061 }
1062 ns = ns->next;
1063 }
1064 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001065}
1066
1067/**
1068 * xmlC14NProcessElementNode:
1069 * @ctx: the pointer to C14N context object
1070 * @cur: the node to process
1071 *
1072 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1073 *
1074 * Element Nodes
1075 * If the element is not in the node-set, then the result is obtained
1076 * by processing the namespace axis, then the attribute axis, then
1077 * processing the child nodes of the element that are in the node-set
1078 * (in document order). If the element is in the node-set, then the result
1079 * is an open angle bracket (<), the element QName, the result of
1080 * processing the namespace axis, the result of processing the attribute
1081 * axis, a close angle bracket (>), the result of processing the child
1082 * nodes of the element that are in the node-set (in document order), an
1083 * open angle bracket, a forward slash (/), the element QName, and a close
1084 * angle bracket.
1085 *
1086 * Returns non-negative value on success or negative value on fail
1087 */
1088static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001089xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1090{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001091 int ret;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001092 xmlC14NVisibleNsStack state;
Daniel Veillard6f293b12002-03-15 09:42:33 +00001093 int parent_is_doc = 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001094
Daniel Veillard9ff88172002-03-11 09:15:32 +00001095 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1096#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001097 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001098 "xmlC14NProcessElementNode: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
1099#endif
1100 return (-1);
1101 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001102
1103 /*
1104 * Check relative relative namespaces:
1105 * implementations of XML canonicalization MUST report an operation
1106 * failure on documents containing relative namespace URIs.
1107 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001108 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1109#ifdef DEBUG_C14N
1110 xmlGenericError(xmlGenericErrorContext,
1111 "xmlC14NProcessElementNode: xmlC14NCheckForRelativeNamespaces failed.\n");
1112#endif
1113 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001114 }
1115
1116
1117 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001118 * Save ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001119 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001120 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001121
Daniel Veillard6f293b12002-03-15 09:42:33 +00001122 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001123 if (ctx->parent_is_doc) {
Daniel Veillard6f293b12002-03-15 09:42:33 +00001124 /* save this flag into the stack */
1125 parent_is_doc = ctx->parent_is_doc;
1126 ctx->parent_is_doc = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001127 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1128 }
1129 xmlOutputBufferWriteString(ctx->buf, "<");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001130
Daniel Veillard9ff88172002-03-11 09:15:32 +00001131 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1132 xmlOutputBufferWriteString(ctx->buf,
1133 (const char *) cur->ns->prefix);
1134 xmlOutputBufferWriteString(ctx->buf, ":");
1135 }
1136 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001137 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001138
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001139 if (!ctx->exclusive) {
1140 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1141 } else {
1142 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1143 }
1144 if (ret < 0) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001145#ifdef DEBUG_C14N
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001146 xmlGenericError(xmlGenericErrorContext,
1147 "xmlC14NProcessElementNode: xmlC14NProcessNamespacesAxis failed.\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001148#endif
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001149 return (-1);
1150 }
1151 /* todo: shouldn't this go to "visible only"? */
1152 if(visible) {
1153 xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1154 }
1155
1156 if(visible) {
1157 ret = xmlC14NProcessAttrsAxis(ctx, cur);
1158 if (ret < 0) {
1159#ifdef DEBUG_C14N
1160 xmlGenericError(xmlGenericErrorContext,
1161 "xmlC14NProcessElementNode: xmlC14NProcessAttrsAxis failed.\n");
1162#endif
1163 return (-1);
Aleksey Saninc57f9c12002-05-31 19:14:57 +00001164 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001165 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001166
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001167 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001168 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001169 }
1170 if (cur->children != NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001171 ret = xmlC14NProcessNodeList(ctx, cur->children);
1172 if (ret < 0) {
1173#ifdef DEBUG_C14N
1174 xmlGenericError(xmlGenericErrorContext,
1175 "xmlC14NProcessElementNode: xmlC14NProcessNodeList failed.\n");
1176#endif
1177 return (-1);
1178 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001179 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001180 if (visible) {
1181 xmlOutputBufferWriteString(ctx->buf, "</");
1182 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1183 xmlOutputBufferWriteString(ctx->buf,
1184 (const char *) cur->ns->prefix);
1185 xmlOutputBufferWriteString(ctx->buf, ":");
1186 }
1187 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1188 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard6f293b12002-03-15 09:42:33 +00001189 if (parent_is_doc) {
1190 /* restore this flag from the stack for next node */
1191 ctx->parent_is_doc = parent_is_doc;
1192 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001193 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001194 }
1195
1196 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001197 * Restore ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001198 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001199 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001200 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001201}
1202
1203/**
1204 * xmlC14NProcessNode:
1205 * @ctx: the pointer to C14N context object
1206 * @cur: the node to process
1207 *
1208 * Processes the given node
1209 *
1210 * Returns non-negative value on success or negative value on fail
1211 */
1212static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001213xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1214{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001215 int ret = 0;
1216 int visible;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001217
1218 if ((ctx == NULL) || (cur == NULL)) {
1219#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001220 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001221 "xmlC14NProcessNode: Null context or node pointer.\n");
1222#endif
1223 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001224 }
1225
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001226 visible = xmlC14NIsVisible(ctx, cur, cur->parent);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001227 switch (cur->type) {
1228 case XML_ELEMENT_NODE:
1229 ret = xmlC14NProcessElementNode(ctx, cur, visible);
1230 break;
1231 case XML_CDATA_SECTION_NODE:
1232 case XML_TEXT_NODE:
1233 /*
1234 * Text Nodes
1235 * the string value, except all ampersands are replaced
1236 * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1237 * angle brackets (>) are replaced by &gt;, and all #xD characters are
1238 * replaced by &#xD;.
1239 */
1240 /* cdata sections are processed as text nodes */
1241 /* todo: verify that cdata sections are included in XPath nodes set */
1242 if ((visible) && (cur->content != NULL)) {
1243 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001244
Daniel Veillard9ff88172002-03-11 09:15:32 +00001245 buffer = xmlC11NNormalizeText(cur->content);
1246 if (buffer != NULL) {
1247 xmlOutputBufferWriteString(ctx->buf,
1248 (const char *) buffer);
1249 xmlFree(buffer);
1250 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001251#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001252 xmlGenericError(xmlGenericErrorContext,
1253 "xmlC14NProcessNode: xmlC11NNormalizeText() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001254#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001255 return (-1);
1256 }
1257 }
1258 break;
1259 case XML_PI_NODE:
1260 /*
1261 * Processing Instruction (PI) Nodes-
1262 * The opening PI symbol (<?), the PI target name of the node,
1263 * a leading space and the string value if it is not empty, and
1264 * the closing PI symbol (?>). If the string value is empty,
1265 * then the leading space is not added. Also, a trailing #xA is
1266 * rendered after the closing PI symbol for PI children of the
1267 * root node with a lesser document order than the document
1268 * element, and a leading #xA is rendered before the opening PI
1269 * symbol of PI children of the root node with a greater document
1270 * order than the document element.
1271 */
1272 if (visible) {
1273 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1274 xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1275 } else {
1276 xmlOutputBufferWriteString(ctx->buf, "<?");
1277 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001278
Daniel Veillard9ff88172002-03-11 09:15:32 +00001279 xmlOutputBufferWriteString(ctx->buf,
1280 (const char *) cur->name);
1281 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1282 xmlChar *buffer;
1283
1284 xmlOutputBufferWriteString(ctx->buf, " ");
1285
1286 /* todo: do we need to normalize pi? */
1287 buffer = xmlC11NNormalizePI(cur->content);
1288 if (buffer != NULL) {
1289 xmlOutputBufferWriteString(ctx->buf,
1290 (const char *) buffer);
1291 xmlFree(buffer);
1292 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001293#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001294 xmlGenericError(xmlGenericErrorContext,
1295 "xmlC14NProcessNode: xmlC11NNormalizePI() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001296#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001297 return (-1);
1298 }
1299 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001300
Daniel Veillard9ff88172002-03-11 09:15:32 +00001301 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1302 xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1303 } else {
1304 xmlOutputBufferWriteString(ctx->buf, "?>");
1305 }
1306 }
1307 break;
1308 case XML_COMMENT_NODE:
1309 /*
1310 * Comment Nodes
1311 * Nothing if generating canonical XML without comments. For
1312 * canonical XML with comments, generate the opening comment
1313 * symbol (<!--), the string value of the node, and the
1314 * closing comment symbol (-->). Also, a trailing #xA is rendered
1315 * after the closing comment symbol for comment children of the
1316 * root node with a lesser document order than the document
1317 * element, and a leading #xA is rendered before the opening
1318 * comment symbol of comment children of the root node with a
1319 * greater document order than the document element. (Comment
1320 * children of the root node represent comments outside of the
1321 * top-level document element and outside of the document type
1322 * declaration).
1323 */
1324 if (visible && ctx->with_comments) {
1325 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1326 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1327 } else {
1328 xmlOutputBufferWriteString(ctx->buf, "<!--");
1329 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001330
Daniel Veillard9ff88172002-03-11 09:15:32 +00001331 if (cur->content != NULL) {
1332 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001333
Daniel Veillard9ff88172002-03-11 09:15:32 +00001334 /* todo: do we need to normalize comment? */
1335 buffer = xmlC11NNormalizeComment(cur->content);
1336 if (buffer != NULL) {
1337 xmlOutputBufferWriteString(ctx->buf,
1338 (const char *) buffer);
1339 xmlFree(buffer);
1340 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001341#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001342 xmlGenericError(xmlGenericErrorContext,
1343 "xmlC14NProcessNode: xmlC11NNormalizeComment() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001344#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001345 return (-1);
1346 }
1347 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001348
Daniel Veillard9ff88172002-03-11 09:15:32 +00001349 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1350 xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1351 } else {
1352 xmlOutputBufferWriteString(ctx->buf, "-->");
1353 }
1354 }
1355 break;
1356 case XML_DOCUMENT_NODE:
1357 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001358#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001359 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001360#endif
1361#ifdef LIBXML_HTML_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001362 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001363#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001364 if (cur->children != NULL) {
1365 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1366 ctx->parent_is_doc = 1;
1367 ret = xmlC14NProcessNodeList(ctx, cur->children);
1368 }
1369 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001370
Daniel Veillard9ff88172002-03-11 09:15:32 +00001371 case XML_ATTRIBUTE_NODE:
Daniel Veillardd96cce12003-10-10 12:30:37 +00001372 xmlC14NErr(ctx, cur, XML_C14N_INVALID_NODE,
1373 "xmlC14NProcessNode: XML_ATTRIBUTE_NODE is illegal here\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001374 return (-1);
1375 case XML_NAMESPACE_DECL:
Daniel Veillardd96cce12003-10-10 12:30:37 +00001376 xmlC14NErr(ctx, cur, XML_C14N_INVALID_NODE,
1377 "xmlC14NProcessNode: XML_NAMESPACE_DECL is illegal here\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001378 return (-1);
1379 case XML_ENTITY_REF_NODE:
Daniel Veillardd96cce12003-10-10 12:30:37 +00001380 xmlC14NErr(ctx, cur, XML_C14N_INVALID_NODE,
1381 "xmlC14NProcessNode: XML_ENTITY_REF_NODE is illegal here\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001382 return (-1);
1383 case XML_ENTITY_NODE:
Daniel Veillardd96cce12003-10-10 12:30:37 +00001384 xmlC14NErr(ctx, cur, XML_C14N_INVALID_NODE,
1385 "xmlC14NProcessNode: XML_ENTITY_NODE is illegal here\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001386 return (-1);
1387
1388 case XML_DOCUMENT_TYPE_NODE:
1389 case XML_NOTATION_NODE:
1390 case XML_DTD_NODE:
1391 case XML_ELEMENT_DECL:
1392 case XML_ATTRIBUTE_DECL:
1393 case XML_ENTITY_DECL:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001394#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001395 case XML_XINCLUDE_START:
1396 case XML_XINCLUDE_END:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001397#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001398 /*
1399 * should be ignored according to "W3C Canonical XML"
1400 */
1401 break;
1402 default:
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001403#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001404 xmlGenericError(xmlGenericErrorContext,
1405 "xmlC14NProcessNode: unknown node type = %d\n",
1406 cur->type);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001407#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001408 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001409 }
1410
Daniel Veillard9ff88172002-03-11 09:15:32 +00001411 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001412}
1413
1414/**
1415 * xmlC14NProcessNodeList:
1416 * @ctx: the pointer to C14N context object
1417 * @cur: the node to start from
1418 *
1419 * Processes all nodes in the row starting from cur.
1420 *
1421 * Returns non-negative value on success or negative value on fail
1422 */
1423static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001424xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1425{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001426 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001427
1428 if (ctx == NULL) {
1429#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001431 "xmlC14NProcessNodeList: Null context pointer.\n");
1432#endif
1433 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001434 }
1435
Daniel Veillard9ff88172002-03-11 09:15:32 +00001436 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1437 ret = xmlC14NProcessNode(ctx, cur);
1438 }
1439 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001440}
1441
1442
1443/**
1444 * xmlC14NFreeCtx:
1445 * @ctx: the pointer to C14N context object
1446 *
1447 * Cleanups the C14N context object.
1448 */
1449
1450static void
Daniel Veillard9ff88172002-03-11 09:15:32 +00001451xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1452{
1453 if (ctx == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001454#ifdef DEBUG_C14N
1455 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001456 "xmlC14NFreeCtx: ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001457#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001458 return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001459 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001460
1461 if (ctx->ns_rendered != NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001462 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001463 }
1464 xmlFree(ctx);
1465}
1466
1467/**
1468 * xmlC14NNewCtx:
1469 * @doc: the XML document for canonization
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001470 * @is_visible_callback:the function to use to determine is node visible
1471 * or not
1472 * @user_data: the first parameter for @is_visible_callback function
1473 * (in most cases, it is nodes set)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001474 * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1475 * ended with a NULL or NULL if there is no
1476 * inclusive namespaces (only for exclusive
1477 * canonicalization)
1478 * @with_comments: include comments in the result (!=0) or not (==0)
1479 * @buf: the output buffer to store canonical XML; this
1480 * buffer MUST have encoder==NULL because C14N requires
1481 * UTF-8 output
1482 *
1483 * Creates new C14N context object to store C14N parameters.
1484 *
1485 * Returns pointer to newly created object (success) or NULL (fail)
1486 */
1487static xmlC14NCtxPtr
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001488xmlC14NNewCtx(xmlDocPtr doc,
1489 xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001490 int exclusive, xmlChar ** inclusive_ns_prefixes,
1491 int with_comments, xmlOutputBufferPtr buf)
1492{
Daniel Veillard659e71e2003-10-10 14:10:40 +00001493 xmlC14NCtxPtr ctx = NULL;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001494
Daniel Veillard9ff88172002-03-11 09:15:32 +00001495 if ((doc == NULL) || (buf == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001496#ifdef DEBUG_C14N
1497 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001498 "xmlC14NNewCtx: pointer to document or output buffer is NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001499#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001500 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001501 }
1502
1503 /*
1504 * Validate the encoding output buffer encoding
1505 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001506 if (buf->encoder != NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001507 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1508"xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001509 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001510 }
1511
1512 /*
1513 * Validate the XML document encoding value, if provided.
1514 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001515 if (doc->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001516 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1517 "xmlC14NNewCtx: source document not in UTF8\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001518 return (NULL);
1519 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001520
1521 /*
1522 * Allocate a new xmlC14NCtxPtr and fill the fields.
1523 */
1524 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1525 if (ctx == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001526 xmlC14NErrMemory("creating context");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001527 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001528 }
1529 memset(ctx, 0, sizeof(xmlC14NCtx));
1530
1531 /*
1532 * initialize C14N context
Daniel Veillard9ff88172002-03-11 09:15:32 +00001533 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001534 ctx->doc = doc;
1535 ctx->with_comments = with_comments;
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001536 ctx->is_visible_callback = is_visible_callback;
1537 ctx->user_data = user_data;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001538 ctx->buf = buf;
1539 ctx->parent_is_doc = 1;
1540 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001541 ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1542
1543 if(ctx->ns_rendered == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001544 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
1545 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001546 xmlC14NFreeCtx(ctx);
1547 return (NULL);
1548 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001549
1550 /*
1551 * Set "exclusive" flag, create a nodes set for namespaces
1552 * stack and remember list of incluseve prefixes
1553 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001554 if (exclusive) {
1555 ctx->exclusive = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001556 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1557 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001558 return (ctx);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001559}
1560
1561/**
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001562 * xmlC14NExecute:
1563 * @doc: the XML document for canonization
1564 * @is_visible_callback:the function to use to determine is node visible
1565 * or not
1566 * @user_data: the first parameter for @is_visible_callback function
1567 * (in most cases, it is nodes set)
1568 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1569 * otherwise - exclusive canonicalization)
1570 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1571 * ended with a NULL or NULL if there is no
1572 * inclusive namespaces (only for exclusive
1573 * canonicalization, ignored otherwise)
1574 * @with_comments: include comments in the result (!=0) or not (==0)
1575 * @buf: the output buffer to store canonical XML; this
1576 * buffer MUST have encoder==NULL because C14N requires
1577 * UTF-8 output
1578 *
1579 * Dumps the canonized image of given XML document into the provided buffer.
1580 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1581 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1582 *
1583 * Returns non-negative value on success or a negative value on fail
1584 */
1585int
1586xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
1587 void* user_data, int exclusive, xmlChar **inclusive_ns_prefixes,
1588 int with_comments, xmlOutputBufferPtr buf) {
1589
1590 xmlC14NCtxPtr ctx;
1591 int ret;
1592
1593 if ((buf == NULL) || (doc == NULL)) {
1594#ifdef DEBUG_C14N
1595 xmlGenericError(xmlGenericErrorContext,
1596 "xmlC14NExecute: null return buffer or doc pointer\n");
1597#endif
1598 return (-1);
1599 }
1600
1601 /*
1602 * Validate the encoding output buffer encoding
1603 */
1604 if (buf->encoder != NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001605 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1606"xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001607 return (-1);
1608 }
1609
1610 ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
1611 exclusive, inclusive_ns_prefixes,
1612 with_comments, buf);
1613 if (ctx == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001614 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
1615 "xmlC14NExecute: unable to create C14N context\n");
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001616 return (-1);
1617 }
1618
1619
1620
1621 /*
1622 * Root Node
1623 * The root node is the parent of the top-level document element. The
1624 * result of processing each of its child nodes that is in the node-set
1625 * in document order. The root node does not generate a byte order mark,
1626 * XML declaration, nor anything from within the document type
1627 * declaration.
1628 */
1629 if (doc->children != NULL) {
1630 ret = xmlC14NProcessNodeList(ctx, doc->children);
1631 if (ret < 0) {
1632#ifdef DEBUG_C14N
1633 xmlGenericError(xmlGenericErrorContext,
1634 "xmlC14NExecute: process childrens' list failed.\n");
1635#endif
1636 xmlC14NFreeCtx(ctx);
1637 return (-1);
1638 }
1639 }
1640
1641 /*
1642 * Flush buffer to get number of bytes written
1643 */
1644 ret = xmlOutputBufferFlush(buf);
1645 if (ret < 0) {
1646#ifdef DEBUG_C14N
1647 xmlGenericError(xmlGenericErrorContext,
1648 "xmlC14NExecute: buffer flush failed.\n");
1649#endif
1650 xmlC14NFreeCtx(ctx);
1651 return (-1);
1652 }
1653
1654 /*
1655 * Cleanup
1656 */
1657 xmlC14NFreeCtx(ctx);
1658 return (ret);
1659}
1660
1661/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001662 * xmlC14NDocSaveTo:
1663 * @doc: the XML document for canonization
1664 * @nodes: the nodes set to be included in the canonized image
1665 * or NULL if all document nodes should be included
1666 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1667 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001668 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001669 * ended with a NULL or NULL if there is no
1670 * inclusive namespaces (only for exclusive
1671 * canonicalization, ignored otherwise)
1672 * @with_comments: include comments in the result (!=0) or not (==0)
1673 * @buf: the output buffer to store canonical XML; this
1674 * buffer MUST have encoder==NULL because C14N requires
1675 * UTF-8 output
1676 *
1677 * Dumps the canonized image of given XML document into the provided buffer.
1678 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1679 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1680 *
1681 * Returns non-negative value on success or a negative value on fail
1682 */
1683int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001684xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1685 int exclusive, xmlChar ** inclusive_ns_prefixes,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001686 int with_comments, xmlOutputBufferPtr buf) {
1687 return(xmlC14NExecute(doc,
1688 (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1689 nodes,
1690 exclusive,
1691 inclusive_ns_prefixes,
1692 with_comments,
1693 buf));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001694}
1695
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001696
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001697/**
1698 * xmlC14NDocDumpMemory:
1699 * @doc: the XML document for canonization
1700 * @nodes: the nodes set to be included in the canonized image
1701 * or NULL if all document nodes should be included
1702 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1703 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001704 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001705 * ended with a NULL or NULL if there is no
1706 * inclusive namespaces (only for exclusive
1707 * canonicalization, ignored otherwise)
1708 * @with_comments: include comments in the result (!=0) or not (==0)
1709 * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
1710 * the caller of this functions is responsible for calling
1711 * xmlFree() to free allocated memory
1712 *
1713 * Dumps the canonized image of given XML document into memory.
1714 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1715 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1716 *
1717 * Returns the number of bytes written on success or a negative value on fail
1718 */
1719int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001720xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
1721 int exclusive, xmlChar ** inclusive_ns_prefixes,
1722 int with_comments, xmlChar ** doc_txt_ptr)
1723{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001724 int ret;
1725 xmlOutputBufferPtr buf;
1726
1727 if (doc_txt_ptr == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001728#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001729 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001730 "xmlC14NDocDumpMemory: null return buffer pointer\n");
1731#endif
1732 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001733 }
1734
1735 *doc_txt_ptr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001736
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 /*
1738 * create memory buffer with UTF8 (default) encoding
1739 */
1740 buf = xmlAllocOutputBuffer(NULL);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001741 if (buf == NULL) {
1742#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001743 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001744 "xmlC14NDocDumpMemory: failed to allocate output buffer.\n");
1745#endif
1746 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001747 }
1748
1749 /*
1750 * canonize document and write to buffer
1751 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001752 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1753 with_comments, buf);
1754 if (ret < 0) {
1755#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001756 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001757 "xmlC14NDocDumpMemory: xmlC14NDocSaveTo failed.\n");
1758#endif
1759 (void) xmlOutputBufferClose(buf);
1760 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001761 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762
Daniel Veillard9ff88172002-03-11 09:15:32 +00001763 ret = buf->buffer->use;
1764 if (ret > 0) {
1765 *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
1766 }
1767 (void) xmlOutputBufferClose(buf);
1768
1769 if ((*doc_txt_ptr == NULL) && (ret > 0)) {
1770#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001772 "xmlC14NDocDumpMemory: failed to allocate memory for document text representation\n");
1773#endif
1774 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001776 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001777}
1778
1779/**
1780 * xmlC14NDocSave:
1781 * @doc: the XML document for canonization
1782 * @nodes: the nodes set to be included in the canonized image
1783 * or NULL if all document nodes should be included
1784 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1785 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001786 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 * ended with a NULL or NULL if there is no
1788 * inclusive namespaces (only for exclusive
1789 * canonicalization, ignored otherwise)
1790 * @with_comments: include comments in the result (!=0) or not (==0)
1791 * @filename: the filename to store canonical XML image
1792 * @compression: the compression level (zlib requred):
1793 * -1 - libxml default,
1794 * 0 - uncompressed,
1795 * >0 - compression level
1796 *
1797 * Dumps the canonized image of given XML document into the file.
1798 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1799 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1800 *
1801 * Returns the number of bytes written success or a negative value on fail
1802 */
1803int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001804xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
1805 int exclusive, xmlChar ** inclusive_ns_prefixes,
1806 int with_comments, const char *filename, int compression)
1807{
1808 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001809 int ret;
1810
Daniel Veillard9ff88172002-03-11 09:15:32 +00001811 if (filename == NULL) {
1812#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001813 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001814 "xmlC14NDocSave: filename is NULL\n");
1815#endif
1816 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001817 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001818#ifdef HAVE_ZLIB_H
Daniel Veillard9ff88172002-03-11 09:15:32 +00001819 if (compression < 0)
1820 compression = xmlGetCompressMode();
1821#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001822
1823 /*
1824 * save the content to a temp buffer, use default UTF8 encoding.
1825 */
1826 buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
1827 if (buf == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001828#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001830 "xmlC14NDocSave: unable to create buffer for file=\"%s\" with compressin=%d\n",
1831 filename, compression);
1832#endif
1833 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001834 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001835
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001836 /*
1837 * canonize document and write to buffer
1838 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001839 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1840 with_comments, buf);
1841 if (ret < 0) {
1842#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001843 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001844 "xmlC14NDocSave: xmlC14NDocSaveTo failed.\n");
1845#endif
1846 (void) xmlOutputBufferClose(buf);
1847 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001848 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001849
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001850 /*
1851 * get the numbers of bytes written
1852 */
1853 ret = xmlOutputBufferClose(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001854 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855}
1856
1857
1858
1859/*
1860 * Macro used to grow the current buffer.
1861 */
1862#define growBufferReentrant() { \
1863 buffer_size *= 2; \
1864 buffer = (xmlChar *) \
1865 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
1866 if (buffer == NULL) { \
Daniel Veillardd96cce12003-10-10 12:30:37 +00001867 xmlC14NErrMemory("growing buffer"); \
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 return(NULL); \
1869 } \
1870}
1871
1872/**
1873 * xmlC11NNormalizeString:
1874 * @input: the input string
1875 * @mode: the normalization mode (attribute, comment, PI or text)
1876 *
1877 * Converts a string to a canonical (normalized) format. The code is stolen
1878 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
1879 * and the @mode parameter
1880 *
1881 * Returns a normalized string (caller is responsible for calling xmlFree())
1882 * or NULL if an error occurs
1883 */
1884static xmlChar *
Daniel Veillard9ff88172002-03-11 09:15:32 +00001885xmlC11NNormalizeString(const xmlChar * input,
1886 xmlC14NNormalizationMode mode)
1887{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001888 const xmlChar *cur = input;
1889 xmlChar *buffer = NULL;
1890 xmlChar *out = NULL;
1891 int buffer_size = 0;
1892
Daniel Veillard9ff88172002-03-11 09:15:32 +00001893 if (input == NULL)
1894 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001895
1896 /*
1897 * allocate an translation buffer.
1898 */
1899 buffer_size = 1000;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001900 buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001901 if (buffer == NULL) {
Daniel Veillardd96cce12003-10-10 12:30:37 +00001902 xmlC14NErrMemory("allocating buffer");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001903 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001904 }
1905 out = buffer;
1906
1907 while (*cur != '\0') {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001908 if ((out - buffer) > (buffer_size - 10)) {
1909 int indx = out - buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001910
Daniel Veillard9ff88172002-03-11 09:15:32 +00001911 growBufferReentrant();
1912 out = &buffer[indx];
1913 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001914
Daniel Veillard9ff88172002-03-11 09:15:32 +00001915 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1916 (mode == XMLC14N_NORMALIZE_TEXT))) {
1917 *out++ = '&';
1918 *out++ = 'l';
1919 *out++ = 't';
1920 *out++ = ';';
1921 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
1922 *out++ = '&';
1923 *out++ = 'g';
1924 *out++ = 't';
1925 *out++ = ';';
1926 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1927 (mode == XMLC14N_NORMALIZE_TEXT))) {
1928 *out++ = '&';
1929 *out++ = 'a';
1930 *out++ = 'm';
1931 *out++ = 'p';
1932 *out++ = ';';
1933 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1934 *out++ = '&';
1935 *out++ = 'q';
1936 *out++ = 'u';
1937 *out++ = 'o';
1938 *out++ = 't';
1939 *out++ = ';';
1940 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1941 *out++ = '&';
1942 *out++ = '#';
1943 *out++ = 'x';
1944 *out++ = '9';
1945 *out++ = ';';
1946 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1947 *out++ = '&';
1948 *out++ = '#';
1949 *out++ = 'x';
1950 *out++ = 'A';
1951 *out++ = ';';
1952 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1953 (mode == XMLC14N_NORMALIZE_TEXT) ||
1954 (mode == XMLC14N_NORMALIZE_COMMENT) ||
1955 (mode == XMLC14N_NORMALIZE_PI))) {
1956 *out++ = '&';
1957 *out++ = '#';
1958 *out++ = 'x';
1959 *out++ = 'D';
1960 *out++ = ';';
1961 } else {
1962 /*
1963 * Works because on UTF-8, all extended sequences cannot
1964 * result in bytes in the ASCII range.
1965 */
1966 *out++ = *cur;
1967 }
1968 cur++;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001969 }
1970 *out++ = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001971 return (buffer);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001972}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001973#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974#endif /* LIBXML_C14N_ENABLED */