blob: 620c9a388bdf29a0a67f327107c0dc88249529cc [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 Veillard044fc6b2002-03-04 17:09:44 +000067} xmlC14NCtx, *xmlC14NCtxPtr;
68
Aleksey Sanin2c135a12002-08-01 06:31:50 +000069static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
70static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
71static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
72 xmlNsPtr ns,
73 xmlNodePtr node);
74static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
75 xmlC14NVisibleNsStackPtr state);
76static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
77 xmlC14NVisibleNsStackPtr state);
78static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
79static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
80 xmlNsPtr ns);
81static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
82 xmlNsPtr ns,
83 xmlC14NCtxPtr ctx);
84
85static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes,
86 xmlNodePtr node,
87 xmlNodePtr parent);
88
89
Daniel Veillard044fc6b2002-03-04 17:09:44 +000090
Daniel Veillard9ff88172002-03-11 09:15:32 +000091static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
92static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000093typedef enum {
Daniel Veillard9ff88172002-03-11 09:15:32 +000094 XMLC14N_NORMALIZE_ATTR = 0,
95 XMLC14N_NORMALIZE_COMMENT = 1,
96 XMLC14N_NORMALIZE_PI = 2,
97 XMLC14N_NORMALIZE_TEXT = 3
98} xmlC14NNormalizationMode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000099
Daniel Veillard9ff88172002-03-11 09:15:32 +0000100static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
101 xmlC14NNormalizationMode mode);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000102
103#define xmlC11NNormalizeAttr( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000104 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000105#define xmlC11NNormalizeComment( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000106 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000107#define xmlC11NNormalizePI( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000108 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000109#define xmlC11NNormalizeText( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000110 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000111
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000112#define xmlC14NIsVisible( ctx, node, parent ) \
113 (((ctx)->is_visible_callback != NULL) ? \
114 (ctx)->is_visible_callback((ctx)->user_data, \
115 (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000116/************************************************************************
117 * *
118 * The implementation internals *
119 * *
120 ************************************************************************/
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000121#define XML_NAMESPACES_DEFAULT 16
122
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000123static int
124xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
125 if((nodes != NULL) && (node != NULL)) {
126 if(node->type != XML_NAMESPACE_DECL) {
127 return(xmlXPathNodeSetContains(nodes, node));
128 } else {
129 xmlNs ns;
130
131 memcpy(&ns, node, sizeof(ns));
132 ns.next = (xmlNsPtr)parent; /* this is a libxml hack! check xpath.c for details */
133
134 /*
135 * If the input is an XPath node-set, then the node-set must explicitly
136 * contain every node to be rendered to the canonical form.
137 */
138 return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
139 }
140 }
141 return(1);
142}
143
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000144static xmlC14NVisibleNsStackPtr
145xmlC14NVisibleNsStackCreate(void) {
146 xmlC14NVisibleNsStackPtr ret;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000147
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000148 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000149 if (ret == NULL) {
150 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000151 "xmlC14NVisibleNsStackCreate: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000152 return(NULL);
153 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000154 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000155 return(ret);
156}
157
158static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000159xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000160 if(cur == NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000161#ifdef DEBUG_C14N
162 xmlGenericError(xmlGenericErrorContext,
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000163 "xmlC14NVisibleNsStackDestroy: cur is null.\n");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000164#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000165 return;
166 }
167 if(cur->nsTab != NULL) {
168 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
169 xmlFree(cur->nsTab);
170 }
Aleksey Saninea4272a2002-08-02 23:50:03 +0000171 if(cur->nodeTab != NULL) {
172 memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
173 xmlFree(cur->nodeTab);
174 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000175 memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000176 xmlFree(cur);
177
178}
179
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000180static void
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000181xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
182 if((cur == NULL) ||
183 ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
184 ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000185#ifdef DEBUG_C14N
186 xmlGenericError(xmlGenericErrorContext,
187 "xmlC14NVisibleNsStackAdd: cur is null.\n");
188#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000189 return;
190 }
191
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000192 if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000193 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000194 cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
195 if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000196 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000197 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000198 return;
199 }
200 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000201 memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000202 cur->nsMax = XML_NAMESPACES_DEFAULT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000203 } else if(cur->nsMax == cur->nsCurEnd) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000204 void *tmp;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000205 int tmpSize;
206
207 tmpSize = 2 * cur->nsMax;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000208 tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000209 if (tmp == NULL) {
210 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000211 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000212 return;
213 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000214 cur->nsTab = (xmlNsPtr*)tmp;
215
216 tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
217 if (tmp == NULL) {
218 xmlGenericError(xmlGenericErrorContext,
219 "xmlC14NVisibleNsStackAdd: out of memory\n");
220 return;
221 }
222 cur->nodeTab = (xmlNodePtr*)tmp;
223
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000224 cur->nsMax = tmpSize;
225 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000226 cur->nsTab[cur->nsCurEnd] = ns;
227 cur->nodeTab[cur->nsCurEnd] = node;
228
229 ++cur->nsCurEnd;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000230}
231
232static void
233xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
234 if((cur == NULL) || (state == NULL)) {
235#ifdef DEBUG_C14N
236 xmlGenericError(xmlGenericErrorContext,
237 "xmlC14NVisibleNsStackSave: cur or state is null.\n");
238#endif
239 return;
240 }
241
242 state->nsCurEnd = cur->nsCurEnd;
243 state->nsPrevStart = cur->nsPrevStart;
244 state->nsPrevEnd = cur->nsPrevEnd;
245}
246
247static void
248xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
249 if((cur == NULL) || (state == NULL)) {
250#ifdef DEBUG_C14N
251 xmlGenericError(xmlGenericErrorContext,
252 "xmlC14NVisibleNsStackRestore: cur or state is null.\n");
253#endif
254 return;
255 }
256 cur->nsCurEnd = state->nsCurEnd;
257 cur->nsPrevStart = state->nsPrevStart;
258 cur->nsPrevEnd = state->nsPrevEnd;
259}
260
261static void
262xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
263 if(cur == NULL) {
264#ifdef DEBUG_C14N
265 xmlGenericError(xmlGenericErrorContext,
266 "xmlC14NVisibleNsStackRestore: cur is null.\n");
267#endif
268 return;
269 }
270 cur->nsPrevStart = cur->nsPrevEnd;
271 cur->nsPrevEnd = cur->nsCurEnd;
272}
273
274static int
275xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
276 if (str1 == str2) return(1);
277 if (str1 == NULL) return((*str2) == '\0');
278 if (str2 == NULL) return((*str1) == '\0');
279 do {
280 if (*str1++ != *str2) return(0);
281 } while (*str2++);
282 return(1);
283}
284
285/**
286 * xmlC14NVisibleNsStackFind:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000287 * @ctx: the C14N context
288 * @ns: the namespace to check
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000289 *
290 * Checks whether the given namespace was already rendered or not
291 *
292 * Returns 1 if we already wrote this namespace or 0 otherwise
293 */
294static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000295xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000296{
297 int i;
298 const xmlChar *prefix;
299 const xmlChar *href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000300 int has_empty_ns;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000301
302 if(cur == NULL) {
303#ifdef DEBUG_C14N
304 xmlGenericError(xmlGenericErrorContext,
305 "xmlC14NVisibleNsStackFind: cur is null.\n");
306#endif
307 return (0);
308 }
309
310 /*
311 * if the default namespace xmlns="" is not defined yet then
312 * we do not want to print it out
313 */
314 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
315 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000316 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
317
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000318 if (cur->nsTab != NULL) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000319 int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000320 for (i = cur->nsCurEnd - 1; i >= start; --i) {
321 xmlNsPtr ns1 = cur->nsTab[i];
322
323 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
324 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
325 }
326 }
327 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000328 return(has_empty_ns);
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000329}
330
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000331static int
332xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
333 int i;
334 const xmlChar *prefix;
335 const xmlChar *href;
336 int has_empty_ns;
337
338 if(cur == NULL) {
339#ifdef DEBUG_C14N
340 xmlGenericError(xmlGenericErrorContext,
341 "xmlExcC14NVisibleNsStackFind: cur is null.\n");
342#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000343 return (0);
344 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000345
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000346 /*
347 * if the default namespace xmlns="" is not defined yet then
348 * we do not want to print it out
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000349 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000350 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
351 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
352 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000353
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000354 if (cur->nsTab != NULL) {
355 int start = 0;
356 for (i = cur->nsCurEnd - 1; i >= start; --i) {
357 xmlNsPtr ns1 = cur->nsTab[i];
358
359 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
360 if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
361 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
362 } else {
363 return(0);
364 }
365 }
366 }
367 }
368 return(has_empty_ns);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000369}
370
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000371
372
373
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000374/**
375 * xmlC14NIsXmlNs:
376 * @ns: the namespace to check
377 *
378 * Checks whether the given namespace is a default "xml:" namespace
379 * with href="http://www.w3.org/XML/1998/namespace"
380 *
381 * Returns 1 if the node is default or 0 otherwise
382 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000383
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000384/* todo: make it a define? */
385static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000386xmlC14NIsXmlNs(xmlNsPtr ns)
387{
388 return ((ns != NULL) &&
389 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
390 (xmlStrEqual(ns->href,
391 BAD_CAST
392 "http://www.w3.org/XML/1998/namespace")));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000393}
394
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000395
396/**
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000397 * xmlC14NNsCompare:
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000398 * @ns1: the pointer to first namespace
399 * @ns2: the pointer to second namespace
400 *
401 * Compares the namespaces by names (prefixes).
402 *
403 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
404 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000405static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000406xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000407{
408 if (ns1 == ns2)
409 return (0);
410 if (ns1 == NULL)
411 return (-1);
412 if (ns2 == NULL)
413 return (1);
414
415 return (xmlStrcmp(ns1->prefix, ns2->prefix));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000416}
417
418
419/**
420 * xmlC14NPrintNamespaces:
421 * @ns: the pointer to namespace
422 * @ctx: the C14N context
423 *
424 * Prints the given namespace to the output buffer from C14N context.
425 *
426 * Returns 1 on success or 0 on fail.
427 */
428static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000429xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
430{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000431
Daniel Veillard9ff88172002-03-11 09:15:32 +0000432 if ((ns == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000433#ifdef DEBUG_C14N
434 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000435 "xmlC14NPrintNamespace: namespace or context pointer is null\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000436#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000437 return 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000438 }
439
Daniel Veillard9ff88172002-03-11 09:15:32 +0000440 if (ns->prefix != NULL) {
441 xmlOutputBufferWriteString(ctx->buf, " xmlns:");
442 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
443 xmlOutputBufferWriteString(ctx->buf, "=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000444 } else {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000445 xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000446 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000447 if(ns->href != NULL) {
448 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
449 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000450 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000451 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000452}
453
454/**
455 * xmlC14NProcessNamespacesAxis:
456 * @ctx: the C14N context
457 * @node: the current node
458 *
459 * Prints out canonical namespace axis of the current node to the
460 * buffer from C14N context as follows
461 *
462 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
463 *
464 * Namespace Axis
465 * Consider a list L containing only namespace nodes in the
466 * axis and in the node-set in lexicographic order (ascending). To begin
467 * processing L, if the first node is not the default namespace node (a node
468 * with no namespace URI and no local name), then generate a space followed
469 * by xmlns="" if and only if the following conditions are met:
470 * - the element E that owns the axis is in the node-set
471 * - The nearest ancestor element of E in the node-set has a default
472 * namespace node in the node-set (default namespace nodes always
473 * have non-empty values in XPath)
474 * The latter condition eliminates unnecessary occurrences of xmlns="" in
475 * the canonical form since an element only receives an xmlns="" if its
476 * default namespace is empty and if it has an immediate parent in the
477 * canonical form that has a non-empty default namespace. To finish
478 * processing L, simply process every namespace node in L, except omit
479 * namespace node with local name xml, which defines the xml prefix,
480 * if its string value is http://www.w3.org/XML/1998/namespace.
481 *
482 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
483 * Canonical XML applied to a document subset requires the search of the
484 * ancestor nodes of each orphan element node for attributes in the xml
485 * namespace, such as xml:lang and xml:space. These are copied into the
486 * element node except if a declaration of the same attribute is already
487 * in the attribute axis of the element (whether or not it is included in
488 * the document subset). This search and copying are omitted from the
489 * Exclusive XML Canonicalization method.
490 *
491 * Returns 0 on success or -1 on fail.
492 */
493static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000494xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000495{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000496 xmlNodePtr n;
497 xmlNsPtr ns, tmp;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000498 xmlListPtr list;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000499 int already_rendered;
500 int has_empty_ns = 0;
Daniel Veillard5c396542002-03-15 07:57:50 +0000501
Daniel Veillard9ff88172002-03-11 09:15:32 +0000502 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
503#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000504 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000505 "xmlC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
506#endif
507 return (-1);
508 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000509
510 /*
511 * Create a sorted list to store element namespaces
512 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000513 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000514 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000515#ifdef DEBUG_C14N
516 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000517 "xmlC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000518#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000519 return (-1);
520 }
521
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000522 /* check all namespaces */
523 for(n = cur; n != NULL; n = n->parent) {
524 for(ns = n->nsDef; ns != NULL; ns = ns->next) {
525 tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
526
527 if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
528 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
529 if(visible) {
530 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
531 }
532 if(!already_rendered) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000533 xmlListInsert(list, ns);
534 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000535 if(xmlStrlen(ns->prefix) == 0) {
536 has_empty_ns = 1;
537 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000538 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000539 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000540 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000541
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000542 /**
543 * if the first node is not the default namespace node (a node with no
544 * namespace URI and no local name), then generate a space followed by
545 * xmlns="" if and only if the following conditions are met:
546 * - the element E that owns the axis is in the node-set
547 * - the nearest ancestor element of E in the node-set has a default
548 * namespace node in the node-set (default namespace nodes always
549 * have non-empty values in XPath)
550 */
551 if(visible && !has_empty_ns) {
552 static xmlNs ns_default;
553
554 memset(&ns_default, 0, sizeof(ns_default));
555 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
556 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000557 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000558 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000559
560
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000561 /*
562 * print out all elements from list
563 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000564 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000565
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000566 /*
567 * Cleanup
568 */
569 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000570 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000571}
572
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000573
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000574/**
575 * xmlExcC14NProcessNamespacesAxis:
576 * @ctx: the C14N context
577 * @node: the current node
578 *
579 * Prints out exclusive canonical namespace axis of the current node to the
580 * buffer from C14N context as follows
581 *
582 * Exclusive XML Canonicalization
583 * http://www.w3.org/TR/xml-exc-c14n
584 *
585 * If the element node is in the XPath subset then output the node in
586 * accordance with Canonical XML except for namespace nodes which are
587 * rendered as follows:
588 *
589 * 1. Render each namespace node iff:
590 * * it is visibly utilized by the immediate parent element or one of
591 * its attributes, or is present in InclusiveNamespaces PrefixList, and
592 * * its prefix and value do not appear in ns_rendered. ns_rendered is
593 * obtained by popping the state stack in order to obtain a list of
594 * prefixes and their values which have already been rendered by
595 * an output ancestor of the namespace node's parent element.
596 * 2. Append the rendered namespace node to the list ns_rendered of namespace
597 * nodes rendered by output ancestors. Push ns_rendered on state stack and
598 * recurse.
599 * 3. After the recursion returns, pop thestate stack.
600 *
601 *
602 * Returns 0 on success or -1 on fail.
603 */
604static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000605xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000606{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000607 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000608 xmlListPtr list;
609 xmlAttrPtr attr;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000610 int already_rendered;
611 int has_empty_ns = 0;
612 int has_visibly_utilized_empty_ns = 0;
613 int has_empty_ns_in_inclusive_list = 0;
614
Daniel Veillard9ff88172002-03-11 09:15:32 +0000615 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
616#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000617 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000618 "xmlExcC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
619#endif
620 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000621 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000622
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000623 if(!ctx->exclusive) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000624#ifdef DEBUG_C14N
625 xmlGenericError(xmlGenericErrorContext,
626 "xmlExcC14NProcessNamespacesAxis: called for non-exclusive canonization or rendered stack is NULL.\n");
627#endif
628 return (-1);
629
630 }
631
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000632 /*
633 * Create a sorted list to store element namespaces
634 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000635 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000636 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000637#ifdef DEBUG_C14N
638 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000639 "xmlExcC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000640#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000641 return (-1);
642 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000643
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000644 /*
645 * process inclusive namespaces:
646 * All namespace nodes appearing on inclusive ns list are
647 * handled as provided in Canonical XML
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000648 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000649 if(ctx->inclusive_ns_prefixes != NULL) {
650 xmlChar *prefix;
651 int i;
652
653 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
654 prefix = ctx->inclusive_ns_prefixes[i];
655 /*
656 * Special values for namespace with empty prefix
657 */
658 if (xmlStrEqual(prefix, BAD_CAST "#default")
659 || xmlStrEqual(prefix, BAD_CAST "")) {
660 prefix = NULL;
661 has_empty_ns_in_inclusive_list = 1;
662 }
663
664 ns = xmlSearchNs(cur->doc, cur, prefix);
665 if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
666 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
667 if(visible) {
668 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
669 }
670 if(!already_rendered) {
671 xmlListInsert(list, ns);
672 }
673 if(xmlStrlen(ns->prefix) == 0) {
674 has_empty_ns = 1;
675 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000676 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000677 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000678 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000679
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000680 /* add node namespace */
681 if(cur->ns != NULL) {
682 ns = cur->ns;
683 } else {
684 ns = xmlSearchNs(cur->doc, cur, NULL);
685 has_visibly_utilized_empty_ns = 1;
686 }
687 if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
688 if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
689 if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
690 xmlListInsert(list, ns);
691 }
692 }
693 if(visible) {
694 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
695 }
696 if(xmlStrlen(ns->prefix) == 0) {
697 has_empty_ns = 1;
698 }
699 }
700
701
702 /* add attributes */
703 for(attr = cur->properties; attr != NULL; attr = attr->next) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000704 /*
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000705 * we need to check that attribute is visible and has non
706 * default namespace (XML Namespaces: "default namespaces
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000707 * do not apply directly to attributes")
Daniel Veillard9ff88172002-03-11 09:15:32 +0000708 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000709 if((attr->ns != NULL) && xmlC14NIsVisible(ctx, attr, cur)) {
710 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
711 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, (xmlNodePtr)attr);
712 if(!already_rendered && visible) {
713 xmlListInsert(list, attr->ns);
714 }
715 if(xmlStrlen(attr->ns->prefix) == 0) {
716 has_empty_ns = 1;
717 }
718 } else if(attr->ns == NULL) {
719 has_visibly_utilized_empty_ns = 1;
720 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000721 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000722
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000723 /*
724 * Process xmlns=""
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000725 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000726 if(visible && has_visibly_utilized_empty_ns &&
727 !has_empty_ns && !has_empty_ns_in_inclusive_list) {
728 static xmlNs ns_default;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000729
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000730 memset(&ns_default, 0, sizeof(ns_default));
731
732 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
733 if(!already_rendered) {
734 xmlC14NPrintNamespaces(&ns_default, ctx);
735 }
736 } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
737 static xmlNs ns_default;
738
739 memset(&ns_default, 0, sizeof(ns_default));
740 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
741 xmlC14NPrintNamespaces(&ns_default, ctx);
742 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000743 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000744
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000745
746
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000747 /*
748 * print out all elements from list
749 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000750 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000751
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000752 /*
753 * Cleanup
754 */
755 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000756 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000757}
758
759
760/**
761 * xmlC14NAttrsCompare:
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000762 * @attr1: the pointer tls o first attr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000763 * @attr2: the pointer to second attr
764 *
765 * Prints the given attribute to the output buffer from C14N context.
766 *
767 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
768 */
769static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000770xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
771{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000772 int ret = 0;
773
774 /*
775 * Simple cases
776 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000777 if (attr1 == attr2)
778 return (0);
779 if (attr1 == NULL)
780 return (-1);
781 if (attr2 == NULL)
782 return (1);
783 if (attr1->ns == attr2->ns) {
784 return (xmlStrcmp(attr1->name, attr2->name));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000785 }
786
787 /*
788 * Attributes in the default namespace are first
789 * because the default namespace is not applied to
790 * unqualified attributes
791 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000792 if (attr1->ns == NULL)
793 return (-1);
794 if (attr2->ns == NULL)
795 return (1);
796 if (attr1->ns->prefix == NULL)
797 return (-1);
798 if (attr2->ns->prefix == NULL)
799 return (1);
800
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000801 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000802 if (ret == 0) {
803 ret = xmlStrcmp(attr1->name, attr2->name);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000804 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000805 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000806}
807
808
809/**
810 * xmlC14NPrintAttrs:
811 * @attr: the pointer to attr
812 * @ctx: the C14N context
813 *
814 * Prints out canonical attribute urrent node to the
815 * buffer from C14N context as follows
816 *
817 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
818 *
819 * Returns 1 on success or 0 on fail.
820 */
821static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000822xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
823{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000824 xmlChar *value;
825 xmlChar *buffer;
826
Daniel Veillard9ff88172002-03-11 09:15:32 +0000827 if ((attr == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000828#ifdef DEBUG_C14N
829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000830 "xmlC14NPrintAttrs: attr == NULL or ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000831#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000832 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000833 }
834
835 xmlOutputBufferWriteString(ctx->buf, " ");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000836 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
837 xmlOutputBufferWriteString(ctx->buf,
838 (const char *) attr->ns->prefix);
839 xmlOutputBufferWriteString(ctx->buf, ":");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000840 }
841 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
842 xmlOutputBufferWriteString(ctx->buf, "=\"");
843
844 value = xmlNodeListGetString(attr->doc, attr->children, 1);
845 /* todo: should we log an error if value==NULL ? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000846 if (value != NULL) {
847 buffer = xmlC11NNormalizeAttr(value);
848 xmlFree(value);
849 if (buffer != NULL) {
850 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
851 xmlFree(buffer);
852 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000853#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +0000854 xmlGenericError(xmlGenericErrorContext,
855 "xmlC14NPrintAttrs: xmlC11NNormalizeAttr failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000856#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000857 return (0);
858 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000859 }
860 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000861 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000862}
863
864/**
865 * xmlC14NProcessAttrsAxis:
866 * @ctx: the C14N context
867 * @cur: the current node
868 *
869 * Prints out canonical attribute axis of the current node to the
870 * buffer from C14N context as follows
871 *
872 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
873 *
874 * Attribute Axis
875 * In lexicographic order (ascending), process each node that
876 * is in the element's attribute axis and in the node-set.
877 *
878 * The processing of an element node E MUST be modified slightly
879 * when an XPath node-set is given as input and the element's
880 * parent is omitted from the node-set.
881 *
882 *
883 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
884 *
885 * Canonical XML applied to a document subset requires the search of the
886 * ancestor nodes of each orphan element node for attributes in the xml
887 * namespace, such as xml:lang and xml:space. These are copied into the
888 * element node except if a declaration of the same attribute is already
889 * in the attribute axis of the element (whether or not it is included in
890 * the document subset). This search and copying are omitted from the
891 * Exclusive XML Canonicalization method.
892 *
893 * Returns 0 on success or -1 on fail.
894 */
895static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000896xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur)
897{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000898 xmlAttrPtr attr;
899 xmlListPtr list;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000900
901 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
902#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000903 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000904 "xmlC14NProcessAttrsAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
905#endif
906 return (-1);
907 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000908
909 /*
910 * Create a sorted list to store element attributes
911 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000912 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
913 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000914#ifdef DEBUG_C14N
915 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000916 "xmlC14NProcessAttrsAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000917#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000918 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000919 }
920
921 /*
922 * Add all visible attributes from current node.
923 */
924 attr = cur->properties;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000925 while (attr != NULL) {
926 /* check that attribute is visible */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000927 if (xmlC14NIsVisible(ctx, attr, cur)) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000928 xmlListInsert(list, attr);
929 }
930 attr = attr->next;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000931 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000932
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000933 /*
934 * include attributes in "xml" namespace defined in ancestors
935 * (only for non-exclusive XML Canonicalization)
936 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000937 if ((!ctx->exclusive) && (cur->parent != NULL)
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000938 && (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000939 /*
Daniel Veillard9ff88172002-03-11 09:15:32 +0000940 * If XPath node-set is not specified then the parent is always
941 * visible!
942 */
943 cur = cur->parent;
944 while (cur != NULL) {
945 attr = cur->properties;
946 while (attr != NULL) {
947 if ((attr->ns != NULL)
948 && (xmlStrEqual(attr->ns->prefix, BAD_CAST "xml"))) {
949 if (xmlListSearch(list, attr) == NULL) {
950 xmlListInsert(list, attr);
951 }
952 }
953 attr = attr->next;
954 }
955 cur = cur->parent;
956 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000957 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000958
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000959 /*
960 * print out all elements from list
961 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000962 xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000963
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000964 /*
965 * Cleanup
966 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000967 xmlListDelete(list);
968 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000969}
970
971/**
972 * xmlC14NCheckForRelativeNamespaces:
973 * @ctx: the C14N context
974 * @cur: the current element node
975 *
976 * Checks that current element node has no relative namespaces defined
977 *
978 * Returns 0 if the node has no relative namespaces or -1 otherwise.
979 */
980static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000981xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
982{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000983 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000984
Daniel Veillard9ff88172002-03-11 09:15:32 +0000985 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
986#ifdef DEBUG_C14N
987 xmlGenericError(xmlGenericErrorContext,
988 "xmlC14NCheckForRelativeNamespaces: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
989#endif
990 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000991 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000992
993 ns = cur->nsDef;
994 while (ns != NULL) {
995 if (xmlStrlen(ns->href) > 0) {
996 xmlURIPtr uri;
997
998 uri = xmlParseURI((const char *) ns->href);
999 if (uri == NULL) {
1000#ifdef DEBUG_C14N
1001 xmlGenericError(xmlGenericErrorContext,
1002 "xmlC14NCheckForRelativeNamespaces: unable to parse uri=\"%s\".\n",
1003 ns->href);
1004#endif
1005 return (-1);
1006 }
1007 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
1008 xmlFreeURI(uri);
1009 return (-1);
1010 }
1011 if ((!xmlStrEqual
1012 ((const xmlChar *) uri->scheme, BAD_CAST "urn"))
1013 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
1014 xmlFreeURI(uri);
1015 return (-1);
1016 }
1017 xmlFreeURI(uri);
1018 }
1019 ns = ns->next;
1020 }
1021 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001022}
1023
1024/**
1025 * xmlC14NProcessElementNode:
1026 * @ctx: the pointer to C14N context object
1027 * @cur: the node to process
1028 *
1029 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1030 *
1031 * Element Nodes
1032 * If the element is not in the node-set, then the result is obtained
1033 * by processing the namespace axis, then the attribute axis, then
1034 * processing the child nodes of the element that are in the node-set
1035 * (in document order). If the element is in the node-set, then the result
1036 * is an open angle bracket (<), the element QName, the result of
1037 * processing the namespace axis, the result of processing the attribute
1038 * axis, a close angle bracket (>), the result of processing the child
1039 * nodes of the element that are in the node-set (in document order), an
1040 * open angle bracket, a forward slash (/), the element QName, and a close
1041 * angle bracket.
1042 *
1043 * Returns non-negative value on success or negative value on fail
1044 */
1045static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001046xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1047{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001048 int ret;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001049 xmlC14NVisibleNsStack state;
Daniel Veillard6f293b12002-03-15 09:42:33 +00001050 int parent_is_doc = 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001051
Daniel Veillard9ff88172002-03-11 09:15:32 +00001052 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1053#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001054 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001055 "xmlC14NProcessElementNode: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
1056#endif
1057 return (-1);
1058 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001059
1060 /*
1061 * Check relative relative namespaces:
1062 * implementations of XML canonicalization MUST report an operation
1063 * failure on documents containing relative namespace URIs.
1064 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001065 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1066#ifdef DEBUG_C14N
1067 xmlGenericError(xmlGenericErrorContext,
1068 "xmlC14NProcessElementNode: xmlC14NCheckForRelativeNamespaces failed.\n");
1069#endif
1070 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001071 }
1072
1073
1074 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001075 * Save ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001076 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001077 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001078
Daniel Veillard6f293b12002-03-15 09:42:33 +00001079 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001080 if (ctx->parent_is_doc) {
Daniel Veillard6f293b12002-03-15 09:42:33 +00001081 /* save this flag into the stack */
1082 parent_is_doc = ctx->parent_is_doc;
1083 ctx->parent_is_doc = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001084 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1085 }
1086 xmlOutputBufferWriteString(ctx->buf, "<");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001087
Daniel Veillard9ff88172002-03-11 09:15:32 +00001088 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1089 xmlOutputBufferWriteString(ctx->buf,
1090 (const char *) cur->ns->prefix);
1091 xmlOutputBufferWriteString(ctx->buf, ":");
1092 }
1093 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001094 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001095
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001096 if (!ctx->exclusive) {
1097 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1098 } else {
1099 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1100 }
1101 if (ret < 0) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001102#ifdef DEBUG_C14N
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001103 xmlGenericError(xmlGenericErrorContext,
1104 "xmlC14NProcessElementNode: xmlC14NProcessNamespacesAxis failed.\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001105#endif
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001106 return (-1);
1107 }
1108 /* todo: shouldn't this go to "visible only"? */
1109 if(visible) {
1110 xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1111 }
1112
1113 if(visible) {
1114 ret = xmlC14NProcessAttrsAxis(ctx, cur);
1115 if (ret < 0) {
1116#ifdef DEBUG_C14N
1117 xmlGenericError(xmlGenericErrorContext,
1118 "xmlC14NProcessElementNode: xmlC14NProcessAttrsAxis failed.\n");
1119#endif
1120 return (-1);
Aleksey Saninc57f9c12002-05-31 19:14:57 +00001121 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001122 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001123
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001124 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001125 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001126 }
1127 if (cur->children != NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001128 ret = xmlC14NProcessNodeList(ctx, cur->children);
1129 if (ret < 0) {
1130#ifdef DEBUG_C14N
1131 xmlGenericError(xmlGenericErrorContext,
1132 "xmlC14NProcessElementNode: xmlC14NProcessNodeList failed.\n");
1133#endif
1134 return (-1);
1135 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001136 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001137 if (visible) {
1138 xmlOutputBufferWriteString(ctx->buf, "</");
1139 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1140 xmlOutputBufferWriteString(ctx->buf,
1141 (const char *) cur->ns->prefix);
1142 xmlOutputBufferWriteString(ctx->buf, ":");
1143 }
1144 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1145 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard6f293b12002-03-15 09:42:33 +00001146 if (parent_is_doc) {
1147 /* restore this flag from the stack for next node */
1148 ctx->parent_is_doc = parent_is_doc;
1149 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001150 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001151 }
1152
1153 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001154 * Restore ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001155 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001156 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001157 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001158}
1159
1160/**
1161 * xmlC14NProcessNode:
1162 * @ctx: the pointer to C14N context object
1163 * @cur: the node to process
1164 *
1165 * Processes the given node
1166 *
1167 * Returns non-negative value on success or negative value on fail
1168 */
1169static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001170xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1171{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001172 int ret = 0;
1173 int visible;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001174
1175 if ((ctx == NULL) || (cur == NULL)) {
1176#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001177 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001178 "xmlC14NProcessNode: Null context or node pointer.\n");
1179#endif
1180 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001181 }
1182
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001183 visible = xmlC14NIsVisible(ctx, cur, cur->parent);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001184 switch (cur->type) {
1185 case XML_ELEMENT_NODE:
1186 ret = xmlC14NProcessElementNode(ctx, cur, visible);
1187 break;
1188 case XML_CDATA_SECTION_NODE:
1189 case XML_TEXT_NODE:
1190 /*
1191 * Text Nodes
1192 * the string value, except all ampersands are replaced
1193 * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1194 * angle brackets (>) are replaced by &gt;, and all #xD characters are
1195 * replaced by &#xD;.
1196 */
1197 /* cdata sections are processed as text nodes */
1198 /* todo: verify that cdata sections are included in XPath nodes set */
1199 if ((visible) && (cur->content != NULL)) {
1200 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001201
Daniel Veillard9ff88172002-03-11 09:15:32 +00001202 buffer = xmlC11NNormalizeText(cur->content);
1203 if (buffer != NULL) {
1204 xmlOutputBufferWriteString(ctx->buf,
1205 (const char *) buffer);
1206 xmlFree(buffer);
1207 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001208#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001209 xmlGenericError(xmlGenericErrorContext,
1210 "xmlC14NProcessNode: xmlC11NNormalizeText() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001211#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001212 return (-1);
1213 }
1214 }
1215 break;
1216 case XML_PI_NODE:
1217 /*
1218 * Processing Instruction (PI) Nodes-
1219 * The opening PI symbol (<?), the PI target name of the node,
1220 * a leading space and the string value if it is not empty, and
1221 * the closing PI symbol (?>). If the string value is empty,
1222 * then the leading space is not added. Also, a trailing #xA is
1223 * rendered after the closing PI symbol for PI children of the
1224 * root node with a lesser document order than the document
1225 * element, and a leading #xA is rendered before the opening PI
1226 * symbol of PI children of the root node with a greater document
1227 * order than the document element.
1228 */
1229 if (visible) {
1230 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1231 xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1232 } else {
1233 xmlOutputBufferWriteString(ctx->buf, "<?");
1234 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001235
Daniel Veillard9ff88172002-03-11 09:15:32 +00001236 xmlOutputBufferWriteString(ctx->buf,
1237 (const char *) cur->name);
1238 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1239 xmlChar *buffer;
1240
1241 xmlOutputBufferWriteString(ctx->buf, " ");
1242
1243 /* todo: do we need to normalize pi? */
1244 buffer = xmlC11NNormalizePI(cur->content);
1245 if (buffer != NULL) {
1246 xmlOutputBufferWriteString(ctx->buf,
1247 (const char *) buffer);
1248 xmlFree(buffer);
1249 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001250#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001251 xmlGenericError(xmlGenericErrorContext,
1252 "xmlC14NProcessNode: xmlC11NNormalizePI() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001253#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001254 return (-1);
1255 }
1256 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001257
Daniel Veillard9ff88172002-03-11 09:15:32 +00001258 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1259 xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1260 } else {
1261 xmlOutputBufferWriteString(ctx->buf, "?>");
1262 }
1263 }
1264 break;
1265 case XML_COMMENT_NODE:
1266 /*
1267 * Comment Nodes
1268 * Nothing if generating canonical XML without comments. For
1269 * canonical XML with comments, generate the opening comment
1270 * symbol (<!--), the string value of the node, and the
1271 * closing comment symbol (-->). Also, a trailing #xA is rendered
1272 * after the closing comment symbol for comment children of the
1273 * root node with a lesser document order than the document
1274 * element, and a leading #xA is rendered before the opening
1275 * comment symbol of comment children of the root node with a
1276 * greater document order than the document element. (Comment
1277 * children of the root node represent comments outside of the
1278 * top-level document element and outside of the document type
1279 * declaration).
1280 */
1281 if (visible && ctx->with_comments) {
1282 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1283 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1284 } else {
1285 xmlOutputBufferWriteString(ctx->buf, "<!--");
1286 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001287
Daniel Veillard9ff88172002-03-11 09:15:32 +00001288 if (cur->content != NULL) {
1289 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001290
Daniel Veillard9ff88172002-03-11 09:15:32 +00001291 /* todo: do we need to normalize comment? */
1292 buffer = xmlC11NNormalizeComment(cur->content);
1293 if (buffer != NULL) {
1294 xmlOutputBufferWriteString(ctx->buf,
1295 (const char *) buffer);
1296 xmlFree(buffer);
1297 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001298#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001299 xmlGenericError(xmlGenericErrorContext,
1300 "xmlC14NProcessNode: xmlC11NNormalizeComment() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001301#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001302 return (-1);
1303 }
1304 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001305
Daniel Veillard9ff88172002-03-11 09:15:32 +00001306 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1307 xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1308 } else {
1309 xmlOutputBufferWriteString(ctx->buf, "-->");
1310 }
1311 }
1312 break;
1313 case XML_DOCUMENT_NODE:
1314 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001315#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001316 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001317#endif
1318#ifdef LIBXML_HTML_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001319 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001320#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001321 if (cur->children != NULL) {
1322 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1323 ctx->parent_is_doc = 1;
1324 ret = xmlC14NProcessNodeList(ctx, cur->children);
1325 }
1326 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001327
Daniel Veillard9ff88172002-03-11 09:15:32 +00001328 case XML_ATTRIBUTE_NODE:
1329 xmlGenericError(xmlGenericErrorContext,
1330 "xmlC14NProcessNode: XML_ATTRIBUTE_NODE is illegal here\n");
1331 return (-1);
1332 case XML_NAMESPACE_DECL:
1333 xmlGenericError(xmlGenericErrorContext,
1334 "xmlC14NProcessNode: XML_NAMESPACE_DECL is illegal here\n");
1335 return (-1);
1336 case XML_ENTITY_REF_NODE:
1337 xmlGenericError(xmlGenericErrorContext,
1338 "xmlC14NProcessNode: XML_ENTITY_REF_NODE is illegal here\n");
1339 return (-1);
1340 case XML_ENTITY_NODE:
1341 xmlGenericError(xmlGenericErrorContext,
1342 "xmlC14NProcessNode: XML_ENTITY_NODE is illegal here\n");
1343 return (-1);
1344
1345 case XML_DOCUMENT_TYPE_NODE:
1346 case XML_NOTATION_NODE:
1347 case XML_DTD_NODE:
1348 case XML_ELEMENT_DECL:
1349 case XML_ATTRIBUTE_DECL:
1350 case XML_ENTITY_DECL:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001351#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001352 case XML_XINCLUDE_START:
1353 case XML_XINCLUDE_END:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001354#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001355 /*
1356 * should be ignored according to "W3C Canonical XML"
1357 */
1358 break;
1359 default:
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001360#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001361 xmlGenericError(xmlGenericErrorContext,
1362 "xmlC14NProcessNode: unknown node type = %d\n",
1363 cur->type);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001364#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001365 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001366 }
1367
Daniel Veillard9ff88172002-03-11 09:15:32 +00001368 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001369}
1370
1371/**
1372 * xmlC14NProcessNodeList:
1373 * @ctx: the pointer to C14N context object
1374 * @cur: the node to start from
1375 *
1376 * Processes all nodes in the row starting from cur.
1377 *
1378 * Returns non-negative value on success or negative value on fail
1379 */
1380static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001381xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1382{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001383 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001384
1385 if (ctx == NULL) {
1386#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001387 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001388 "xmlC14NProcessNodeList: Null context pointer.\n");
1389#endif
1390 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001391 }
1392
Daniel Veillard9ff88172002-03-11 09:15:32 +00001393 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1394 ret = xmlC14NProcessNode(ctx, cur);
1395 }
1396 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001397}
1398
1399
1400/**
1401 * xmlC14NFreeCtx:
1402 * @ctx: the pointer to C14N context object
1403 *
1404 * Cleanups the C14N context object.
1405 */
1406
1407static void
Daniel Veillard9ff88172002-03-11 09:15:32 +00001408xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1409{
1410 if (ctx == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001411#ifdef DEBUG_C14N
1412 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001413 "xmlC14NFreeCtx: ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001414#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001415 return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001416 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001417
1418 if (ctx->ns_rendered != NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001419 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001420 }
1421 xmlFree(ctx);
1422}
1423
1424/**
1425 * xmlC14NNewCtx:
1426 * @doc: the XML document for canonization
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001427 * @is_visible_callback:the function to use to determine is node visible
1428 * or not
1429 * @user_data: the first parameter for @is_visible_callback function
1430 * (in most cases, it is nodes set)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001431 * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1432 * ended with a NULL or NULL if there is no
1433 * inclusive namespaces (only for exclusive
1434 * canonicalization)
1435 * @with_comments: include comments in the result (!=0) or not (==0)
1436 * @buf: the output buffer to store canonical XML; this
1437 * buffer MUST have encoder==NULL because C14N requires
1438 * UTF-8 output
1439 *
1440 * Creates new C14N context object to store C14N parameters.
1441 *
1442 * Returns pointer to newly created object (success) or NULL (fail)
1443 */
1444static xmlC14NCtxPtr
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001445xmlC14NNewCtx(xmlDocPtr doc,
1446 xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001447 int exclusive, xmlChar ** inclusive_ns_prefixes,
1448 int with_comments, xmlOutputBufferPtr buf)
1449{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001450 xmlC14NCtxPtr ctx;
1451
Daniel Veillard9ff88172002-03-11 09:15:32 +00001452 if ((doc == NULL) || (buf == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001453#ifdef DEBUG_C14N
1454 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001455 "xmlC14NNewCtx: pointer to document or output buffer is NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001456#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001457 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001458 }
1459
1460 /*
1461 * Validate the encoding output buffer encoding
1462 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001463 if (buf->encoder != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001465 "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
1466 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001467 }
1468
1469 /*
1470 * Validate the XML document encoding value, if provided.
1471 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001472 if (doc->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001473 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001474 "xmlC14NNewCtx: source document not in UTF8\n");
1475 return (NULL);
1476 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001477
1478 /*
1479 * Allocate a new xmlC14NCtxPtr and fill the fields.
1480 */
1481 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1482 if (ctx == NULL) {
1483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001484 "xmlC14NNewCtx: malloc failed\n");
1485 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001486 }
1487 memset(ctx, 0, sizeof(xmlC14NCtx));
1488
1489 /*
1490 * initialize C14N context
Daniel Veillard9ff88172002-03-11 09:15:32 +00001491 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001492 ctx->doc = doc;
1493 ctx->with_comments = with_comments;
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001494 ctx->is_visible_callback = is_visible_callback;
1495 ctx->user_data = user_data;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001496 ctx->buf = buf;
1497 ctx->parent_is_doc = 1;
1498 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001499 ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1500
1501 if(ctx->ns_rendered == NULL) {
1502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
1504 xmlC14NFreeCtx(ctx);
1505 return (NULL);
1506 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001507
1508 /*
1509 * Set "exclusive" flag, create a nodes set for namespaces
1510 * stack and remember list of incluseve prefixes
1511 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001512 if (exclusive) {
1513 ctx->exclusive = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001514 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1515 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001516 return (ctx);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001517}
1518
1519/**
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001520 * xmlC14NExecute:
1521 * @doc: the XML document for canonization
1522 * @is_visible_callback:the function to use to determine is node visible
1523 * or not
1524 * @user_data: the first parameter for @is_visible_callback function
1525 * (in most cases, it is nodes set)
1526 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1527 * otherwise - exclusive canonicalization)
1528 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1529 * ended with a NULL or NULL if there is no
1530 * inclusive namespaces (only for exclusive
1531 * canonicalization, ignored otherwise)
1532 * @with_comments: include comments in the result (!=0) or not (==0)
1533 * @buf: the output buffer to store canonical XML; this
1534 * buffer MUST have encoder==NULL because C14N requires
1535 * UTF-8 output
1536 *
1537 * Dumps the canonized image of given XML document into the provided buffer.
1538 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1539 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1540 *
1541 * Returns non-negative value on success or a negative value on fail
1542 */
1543int
1544xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
1545 void* user_data, int exclusive, xmlChar **inclusive_ns_prefixes,
1546 int with_comments, xmlOutputBufferPtr buf) {
1547
1548 xmlC14NCtxPtr ctx;
1549 int ret;
1550
1551 if ((buf == NULL) || (doc == NULL)) {
1552#ifdef DEBUG_C14N
1553 xmlGenericError(xmlGenericErrorContext,
1554 "xmlC14NExecute: null return buffer or doc pointer\n");
1555#endif
1556 return (-1);
1557 }
1558
1559 /*
1560 * Validate the encoding output buffer encoding
1561 */
1562 if (buf->encoder != NULL) {
1563 xmlGenericError(xmlGenericErrorContext,
1564 "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
1565 return (-1);
1566 }
1567
1568 ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
1569 exclusive, inclusive_ns_prefixes,
1570 with_comments, buf);
1571 if (ctx == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
1573 "xmlC14NExecute: unable to create C14N context\n");
1574 return (-1);
1575 }
1576
1577
1578
1579 /*
1580 * Root Node
1581 * The root node is the parent of the top-level document element. The
1582 * result of processing each of its child nodes that is in the node-set
1583 * in document order. The root node does not generate a byte order mark,
1584 * XML declaration, nor anything from within the document type
1585 * declaration.
1586 */
1587 if (doc->children != NULL) {
1588 ret = xmlC14NProcessNodeList(ctx, doc->children);
1589 if (ret < 0) {
1590#ifdef DEBUG_C14N
1591 xmlGenericError(xmlGenericErrorContext,
1592 "xmlC14NExecute: process childrens' list failed.\n");
1593#endif
1594 xmlC14NFreeCtx(ctx);
1595 return (-1);
1596 }
1597 }
1598
1599 /*
1600 * Flush buffer to get number of bytes written
1601 */
1602 ret = xmlOutputBufferFlush(buf);
1603 if (ret < 0) {
1604#ifdef DEBUG_C14N
1605 xmlGenericError(xmlGenericErrorContext,
1606 "xmlC14NExecute: buffer flush failed.\n");
1607#endif
1608 xmlC14NFreeCtx(ctx);
1609 return (-1);
1610 }
1611
1612 /*
1613 * Cleanup
1614 */
1615 xmlC14NFreeCtx(ctx);
1616 return (ret);
1617}
1618
1619/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001620 * xmlC14NDocSaveTo:
1621 * @doc: the XML document for canonization
1622 * @nodes: the nodes set to be included in the canonized image
1623 * or NULL if all document nodes should be included
1624 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1625 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001626 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001627 * ended with a NULL or NULL if there is no
1628 * inclusive namespaces (only for exclusive
1629 * canonicalization, ignored otherwise)
1630 * @with_comments: include comments in the result (!=0) or not (==0)
1631 * @buf: the output buffer to store canonical XML; this
1632 * buffer MUST have encoder==NULL because C14N requires
1633 * UTF-8 output
1634 *
1635 * Dumps the canonized image of given XML document into the provided buffer.
1636 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1637 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1638 *
1639 * Returns non-negative value on success or a negative value on fail
1640 */
1641int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001642xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1643 int exclusive, xmlChar ** inclusive_ns_prefixes,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001644 int with_comments, xmlOutputBufferPtr buf) {
1645 return(xmlC14NExecute(doc,
1646 (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1647 nodes,
1648 exclusive,
1649 inclusive_ns_prefixes,
1650 with_comments,
1651 buf));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001652}
1653
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001654
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001655/**
1656 * xmlC14NDocDumpMemory:
1657 * @doc: the XML document for canonization
1658 * @nodes: the nodes set to be included in the canonized image
1659 * or NULL if all document nodes should be included
1660 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1661 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001662 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001663 * ended with a NULL or NULL if there is no
1664 * inclusive namespaces (only for exclusive
1665 * canonicalization, ignored otherwise)
1666 * @with_comments: include comments in the result (!=0) or not (==0)
1667 * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
1668 * the caller of this functions is responsible for calling
1669 * xmlFree() to free allocated memory
1670 *
1671 * Dumps the canonized image of given XML document into memory.
1672 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1673 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1674 *
1675 * Returns the number of bytes written on success or a negative value on fail
1676 */
1677int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001678xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
1679 int exclusive, xmlChar ** inclusive_ns_prefixes,
1680 int with_comments, xmlChar ** doc_txt_ptr)
1681{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001682 int ret;
1683 xmlOutputBufferPtr buf;
1684
1685 if (doc_txt_ptr == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001686#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001687 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001688 "xmlC14NDocDumpMemory: null return buffer pointer\n");
1689#endif
1690 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001691 }
1692
1693 *doc_txt_ptr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001694
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001695 /*
1696 * create memory buffer with UTF8 (default) encoding
1697 */
1698 buf = xmlAllocOutputBuffer(NULL);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001699 if (buf == NULL) {
1700#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001701 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001702 "xmlC14NDocDumpMemory: failed to allocate output buffer.\n");
1703#endif
1704 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001705 }
1706
1707 /*
1708 * canonize document and write to buffer
1709 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001710 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1711 with_comments, buf);
1712 if (ret < 0) {
1713#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001714 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001715 "xmlC14NDocDumpMemory: xmlC14NDocSaveTo failed.\n");
1716#endif
1717 (void) xmlOutputBufferClose(buf);
1718 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001719 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001720
Daniel Veillard9ff88172002-03-11 09:15:32 +00001721 ret = buf->buffer->use;
1722 if (ret > 0) {
1723 *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
1724 }
1725 (void) xmlOutputBufferClose(buf);
1726
1727 if ((*doc_txt_ptr == NULL) && (ret > 0)) {
1728#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001729 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001730 "xmlC14NDocDumpMemory: failed to allocate memory for document text representation\n");
1731#endif
1732 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001733 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001734 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001735}
1736
1737/**
1738 * xmlC14NDocSave:
1739 * @doc: the XML document for canonization
1740 * @nodes: the nodes set to be included in the canonized image
1741 * or NULL if all document nodes should be included
1742 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1743 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001744 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745 * ended with a NULL or NULL if there is no
1746 * inclusive namespaces (only for exclusive
1747 * canonicalization, ignored otherwise)
1748 * @with_comments: include comments in the result (!=0) or not (==0)
1749 * @filename: the filename to store canonical XML image
1750 * @compression: the compression level (zlib requred):
1751 * -1 - libxml default,
1752 * 0 - uncompressed,
1753 * >0 - compression level
1754 *
1755 * Dumps the canonized image of given XML document into the file.
1756 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1757 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1758 *
1759 * Returns the number of bytes written success or a negative value on fail
1760 */
1761int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001762xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
1763 int exclusive, xmlChar ** inclusive_ns_prefixes,
1764 int with_comments, const char *filename, int compression)
1765{
1766 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001767 int ret;
1768
Daniel Veillard9ff88172002-03-11 09:15:32 +00001769 if (filename == NULL) {
1770#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001772 "xmlC14NDocSave: filename is NULL\n");
1773#endif
1774 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001776#ifdef HAVE_ZLIB_H
Daniel Veillard9ff88172002-03-11 09:15:32 +00001777 if (compression < 0)
1778 compression = xmlGetCompressMode();
1779#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001780
1781 /*
1782 * save the content to a temp buffer, use default UTF8 encoding.
1783 */
1784 buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
1785 if (buf == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001786#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001788 "xmlC14NDocSave: unable to create buffer for file=\"%s\" with compressin=%d\n",
1789 filename, compression);
1790#endif
1791 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001792 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001793
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001794 /*
1795 * canonize document and write to buffer
1796 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001797 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1798 with_comments, buf);
1799 if (ret < 0) {
1800#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001801 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001802 "xmlC14NDocSave: xmlC14NDocSaveTo failed.\n");
1803#endif
1804 (void) xmlOutputBufferClose(buf);
1805 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001806 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001807
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001808 /*
1809 * get the numbers of bytes written
1810 */
1811 ret = xmlOutputBufferClose(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001812 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001813}
1814
1815
1816
1817/*
1818 * Macro used to grow the current buffer.
1819 */
1820#define growBufferReentrant() { \
1821 buffer_size *= 2; \
1822 buffer = (xmlChar *) \
1823 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
1824 if (buffer == NULL) { \
Daniel Veillard3487c8d2002-09-05 11:33:25 +00001825 xmlGenericError(xmlGenericErrorContext, "realloc failed"); \
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001826 return(NULL); \
1827 } \
1828}
1829
1830/**
1831 * xmlC11NNormalizeString:
1832 * @input: the input string
1833 * @mode: the normalization mode (attribute, comment, PI or text)
1834 *
1835 * Converts a string to a canonical (normalized) format. The code is stolen
1836 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
1837 * and the @mode parameter
1838 *
1839 * Returns a normalized string (caller is responsible for calling xmlFree())
1840 * or NULL if an error occurs
1841 */
1842static xmlChar *
Daniel Veillard9ff88172002-03-11 09:15:32 +00001843xmlC11NNormalizeString(const xmlChar * input,
1844 xmlC14NNormalizationMode mode)
1845{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846 const xmlChar *cur = input;
1847 xmlChar *buffer = NULL;
1848 xmlChar *out = NULL;
1849 int buffer_size = 0;
1850
Daniel Veillard9ff88172002-03-11 09:15:32 +00001851 if (input == NULL)
1852 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001853
1854 /*
1855 * allocate an translation buffer.
1856 */
1857 buffer_size = 1000;
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001858 buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001859 if (buffer == NULL) {
Daniel Veillard3487c8d2002-09-05 11:33:25 +00001860 xmlGenericError(xmlGenericErrorContext, "malloc failed");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001861 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001862 }
1863 out = buffer;
1864
1865 while (*cur != '\0') {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001866 if ((out - buffer) > (buffer_size - 10)) {
1867 int indx = out - buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868
Daniel Veillard9ff88172002-03-11 09:15:32 +00001869 growBufferReentrant();
1870 out = &buffer[indx];
1871 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872
Daniel Veillard9ff88172002-03-11 09:15:32 +00001873 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1874 (mode == XMLC14N_NORMALIZE_TEXT))) {
1875 *out++ = '&';
1876 *out++ = 'l';
1877 *out++ = 't';
1878 *out++ = ';';
1879 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
1880 *out++ = '&';
1881 *out++ = 'g';
1882 *out++ = 't';
1883 *out++ = ';';
1884 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1885 (mode == XMLC14N_NORMALIZE_TEXT))) {
1886 *out++ = '&';
1887 *out++ = 'a';
1888 *out++ = 'm';
1889 *out++ = 'p';
1890 *out++ = ';';
1891 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1892 *out++ = '&';
1893 *out++ = 'q';
1894 *out++ = 'u';
1895 *out++ = 'o';
1896 *out++ = 't';
1897 *out++ = ';';
1898 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1899 *out++ = '&';
1900 *out++ = '#';
1901 *out++ = 'x';
1902 *out++ = '9';
1903 *out++ = ';';
1904 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1905 *out++ = '&';
1906 *out++ = '#';
1907 *out++ = 'x';
1908 *out++ = 'A';
1909 *out++ = ';';
1910 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1911 (mode == XMLC14N_NORMALIZE_TEXT) ||
1912 (mode == XMLC14N_NORMALIZE_COMMENT) ||
1913 (mode == XMLC14N_NORMALIZE_PI))) {
1914 *out++ = '&';
1915 *out++ = '#';
1916 *out++ = 'x';
1917 *out++ = 'D';
1918 *out++ = ';';
1919 } else {
1920 /*
1921 * Works because on UTF-8, all extended sequences cannot
1922 * result in bytes in the ASCII range.
1923 */
1924 *out++ = *cur;
1925 }
1926 cur++;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001927 }
1928 *out++ = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001929 return (buffer);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001930}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001931#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001932#endif /* LIBXML_C14N_ENABLED */