blob: 2b61fd765270799042acba60f23ca6e8639b7ae5 [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
15
16#ifdef HAVE_STDLIB_H
17#include <stdlib.h>
18#endif
19#include <string.h>
20
21#include <libxml/tree.h>
22#include <libxml/parser.h>
Daniel Veillard9ff88172002-03-11 09:15:32 +000023#include <libxml/uri.h>
Daniel Veillard044fc6b2002-03-04 17:09:44 +000024#include <libxml/xmlerror.h>
25#include <libxml/globals.h>
26#include <libxml/xpathInternals.h>
27#include <libxml/c14n.h>
28
29/************************************************************************
30 * *
31 * Some declaration better left private ATM *
32 * *
33 ************************************************************************/
34
Daniel Veillard9ff88172002-03-11 09:15:32 +000035typedef enum {
36 XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
37 XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
38 XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
Daniel Veillard044fc6b2002-03-04 17:09:44 +000039} xmlC14NPosition;
40
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000041typedef struct _xmlC14NVisibleNsStack {
Aleksey Sanin2c135a12002-08-01 06:31:50 +000042 int nsCurEnd; /* number of nodes in the set */
43 int nsPrevStart; /* the begginning of the stack for previous visible node */
44 int nsPrevEnd; /* the end of the stack for previous visible node */
45 int nsMax; /* size of the array as allocated */
46 xmlNsPtr *nsTab; /* array of ns in no particular order */
47 xmlNodePtr *nodeTab;/* array of nodes in no particular order */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000048} xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
Aleksey Sanindffd5c82002-05-31 04:24:13 +000049
Daniel Veillard044fc6b2002-03-04 17:09:44 +000050typedef struct _xmlC14NCtx {
51 /* input parameters */
Daniel Veillard9ff88172002-03-11 09:15:32 +000052 xmlDocPtr doc;
Aleksey Sanin2c135a12002-08-01 06:31:50 +000053 xmlC14NIsVisibleCallback is_visible_callback;
54 void* user_data;
Daniel Veillard9ff88172002-03-11 09:15:32 +000055 int with_comments;
56 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000057
58 /* position in the XML document */
Daniel Veillard9ff88172002-03-11 09:15:32 +000059 xmlC14NPosition pos;
60 int parent_is_doc;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000061 xmlC14NVisibleNsStackPtr ns_rendered;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000062
63 /* exclusive canonicalization */
Daniel Veillard9ff88172002-03-11 09:15:32 +000064 int exclusive;
Daniel Veillard9ff88172002-03-11 09:15:32 +000065 xmlChar **inclusive_ns_prefixes;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000066} xmlC14NCtx, *xmlC14NCtxPtr;
67
Aleksey Sanin2c135a12002-08-01 06:31:50 +000068static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
69static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
70static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
71 xmlNsPtr ns,
72 xmlNodePtr node);
73static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
74 xmlC14NVisibleNsStackPtr state);
75static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
76 xmlC14NVisibleNsStackPtr state);
77static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
78static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
79 xmlNsPtr ns);
80static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
81 xmlNsPtr ns,
82 xmlC14NCtxPtr ctx);
83
84static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes,
85 xmlNodePtr node,
86 xmlNodePtr parent);
87
88
Daniel Veillard044fc6b2002-03-04 17:09:44 +000089
Daniel Veillard9ff88172002-03-11 09:15:32 +000090static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
91static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000092typedef enum {
Daniel Veillard9ff88172002-03-11 09:15:32 +000093 XMLC14N_NORMALIZE_ATTR = 0,
94 XMLC14N_NORMALIZE_COMMENT = 1,
95 XMLC14N_NORMALIZE_PI = 2,
96 XMLC14N_NORMALIZE_TEXT = 3
97} xmlC14NNormalizationMode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000098
Daniel Veillard9ff88172002-03-11 09:15:32 +000099static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
100 xmlC14NNormalizationMode mode);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000101
102#define xmlC11NNormalizeAttr( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000103 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000104#define xmlC11NNormalizeComment( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000105 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000106#define xmlC11NNormalizePI( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000107 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000108#define xmlC11NNormalizeText( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +0000109 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000110
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000111#define xmlC14NIsVisible( ctx, node, parent ) \
112 (((ctx)->is_visible_callback != NULL) ? \
113 (ctx)->is_visible_callback((ctx)->user_data, \
114 (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000115/************************************************************************
116 * *
117 * The implementation internals *
118 * *
119 ************************************************************************/
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000120#define XML_NAMESPACES_DEFAULT 16
121
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000122static int
123xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
124 if((nodes != NULL) && (node != NULL)) {
125 if(node->type != XML_NAMESPACE_DECL) {
126 return(xmlXPathNodeSetContains(nodes, node));
127 } else {
128 xmlNs ns;
129
130 memcpy(&ns, node, sizeof(ns));
131 ns.next = (xmlNsPtr)parent; /* this is a libxml hack! check xpath.c for details */
132
133 /*
134 * If the input is an XPath node-set, then the node-set must explicitly
135 * contain every node to be rendered to the canonical form.
136 */
137 return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
138 }
139 }
140 return(1);
141}
142
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000143static xmlC14NVisibleNsStackPtr
144xmlC14NVisibleNsStackCreate(void) {
145 xmlC14NVisibleNsStackPtr ret;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000146
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000147 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000148 if (ret == NULL) {
149 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000150 "xmlC14NVisibleNsStackCreate: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000151 return(NULL);
152 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000153 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000154 return(ret);
155}
156
157static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000158xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000159 if(cur == NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000160#ifdef DEBUG_C14N
161 xmlGenericError(xmlGenericErrorContext,
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000162 "xmlC14NVisibleNsStackDestroy: cur is null.\n");
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000163#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000164 return;
165 }
166 if(cur->nsTab != NULL) {
167 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
168 xmlFree(cur->nsTab);
169 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000170 memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000171 xmlFree(cur);
172
173}
174
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000175static void
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000176xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
177 if((cur == NULL) ||
178 ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
179 ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000180#ifdef DEBUG_C14N
181 xmlGenericError(xmlGenericErrorContext,
182 "xmlC14NVisibleNsStackAdd: cur is null.\n");
183#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000184 return;
185 }
186
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000187 if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000188 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000189 cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
190 if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000191 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000192 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000193 return;
194 }
195 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000196 memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000197 cur->nsMax = XML_NAMESPACES_DEFAULT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000198 } else if(cur->nsMax == cur->nsCurEnd) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000199 void *tmp;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000200 int tmpSize;
201
202 tmpSize = 2 * cur->nsMax;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000203 tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000204 if (tmp == NULL) {
205 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000206 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000207 return;
208 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000209 cur->nsTab = (xmlNsPtr*)tmp;
210
211 tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
212 if (tmp == NULL) {
213 xmlGenericError(xmlGenericErrorContext,
214 "xmlC14NVisibleNsStackAdd: out of memory\n");
215 return;
216 }
217 cur->nodeTab = (xmlNodePtr*)tmp;
218
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000219 cur->nsMax = tmpSize;
220 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000221 cur->nsTab[cur->nsCurEnd] = ns;
222 cur->nodeTab[cur->nsCurEnd] = node;
223
224 ++cur->nsCurEnd;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000225}
226
227static void
228xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
229 if((cur == NULL) || (state == NULL)) {
230#ifdef DEBUG_C14N
231 xmlGenericError(xmlGenericErrorContext,
232 "xmlC14NVisibleNsStackSave: cur or state is null.\n");
233#endif
234 return;
235 }
236
237 state->nsCurEnd = cur->nsCurEnd;
238 state->nsPrevStart = cur->nsPrevStart;
239 state->nsPrevEnd = cur->nsPrevEnd;
240}
241
242static void
243xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
244 if((cur == NULL) || (state == NULL)) {
245#ifdef DEBUG_C14N
246 xmlGenericError(xmlGenericErrorContext,
247 "xmlC14NVisibleNsStackRestore: cur or state is null.\n");
248#endif
249 return;
250 }
251 cur->nsCurEnd = state->nsCurEnd;
252 cur->nsPrevStart = state->nsPrevStart;
253 cur->nsPrevEnd = state->nsPrevEnd;
254}
255
256static void
257xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
258 if(cur == NULL) {
259#ifdef DEBUG_C14N
260 xmlGenericError(xmlGenericErrorContext,
261 "xmlC14NVisibleNsStackRestore: cur is null.\n");
262#endif
263 return;
264 }
265 cur->nsPrevStart = cur->nsPrevEnd;
266 cur->nsPrevEnd = cur->nsCurEnd;
267}
268
269static int
270xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
271 if (str1 == str2) return(1);
272 if (str1 == NULL) return((*str2) == '\0');
273 if (str2 == NULL) return((*str1) == '\0');
274 do {
275 if (*str1++ != *str2) return(0);
276 } while (*str2++);
277 return(1);
278}
279
280/**
281 * xmlC14NVisibleNsStackFind:
282 * @ctx the C14N context
283 * @ns the namespace to check
284 *
285 * Checks whether the given namespace was already rendered or not
286 *
287 * Returns 1 if we already wrote this namespace or 0 otherwise
288 */
289static int
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000290xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000291{
292 int i;
293 const xmlChar *prefix;
294 const xmlChar *href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000295 int has_empty_ns;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000296
297 if(cur == NULL) {
298#ifdef DEBUG_C14N
299 xmlGenericError(xmlGenericErrorContext,
300 "xmlC14NVisibleNsStackFind: cur is null.\n");
301#endif
302 return (0);
303 }
304
305 /*
306 * if the default namespace xmlns="" is not defined yet then
307 * we do not want to print it out
308 */
309 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
310 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000311 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
312
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000313 if (cur->nsTab != NULL) {
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000314 int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000315 for (i = cur->nsCurEnd - 1; i >= start; --i) {
316 xmlNsPtr ns1 = cur->nsTab[i];
317
318 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
319 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
320 }
321 }
322 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000323 return(has_empty_ns);
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000324}
325
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000326static int
327xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
328 int i;
329 const xmlChar *prefix;
330 const xmlChar *href;
331 int has_empty_ns;
332
333 if(cur == NULL) {
334#ifdef DEBUG_C14N
335 xmlGenericError(xmlGenericErrorContext,
336 "xmlExcC14NVisibleNsStackFind: cur is null.\n");
337#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000338 return (0);
339 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000340
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000341 /*
342 * if the default namespace xmlns="" is not defined yet then
343 * we do not want to print it out
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000344 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000345 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
346 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
347 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000348
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000349 if (cur->nsTab != NULL) {
350 int start = 0;
351 for (i = cur->nsCurEnd - 1; i >= start; --i) {
352 xmlNsPtr ns1 = cur->nsTab[i];
353
354 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
355 if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
356 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
357 } else {
358 return(0);
359 }
360 }
361 }
362 }
363 return(has_empty_ns);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000364}
365
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000366
367
368
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000369/**
370 * xmlC14NIsXmlNs:
371 * @ns: the namespace to check
372 *
373 * Checks whether the given namespace is a default "xml:" namespace
374 * with href="http://www.w3.org/XML/1998/namespace"
375 *
376 * Returns 1 if the node is default or 0 otherwise
377 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000378
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000379/* todo: make it a define? */
380static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000381xmlC14NIsXmlNs(xmlNsPtr ns)
382{
383 return ((ns != NULL) &&
384 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
385 (xmlStrEqual(ns->href,
386 BAD_CAST
387 "http://www.w3.org/XML/1998/namespace")));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000388}
389
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000390
391/**
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000392 * xmlC14NNsCompare:
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000393 * @ns1: the pointer to first namespace
394 * @ns2: the pointer to second namespace
395 *
396 * Compares the namespaces by names (prefixes).
397 *
398 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
399 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000400static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000401xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000402{
403 if (ns1 == ns2)
404 return (0);
405 if (ns1 == NULL)
406 return (-1);
407 if (ns2 == NULL)
408 return (1);
409
410 return (xmlStrcmp(ns1->prefix, ns2->prefix));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000411}
412
413
414/**
415 * xmlC14NPrintNamespaces:
416 * @ns: the pointer to namespace
417 * @ctx: the C14N context
418 *
419 * Prints the given namespace to the output buffer from C14N context.
420 *
421 * Returns 1 on success or 0 on fail.
422 */
423static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000424xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
425{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000426
Daniel Veillard9ff88172002-03-11 09:15:32 +0000427 if ((ns == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000428#ifdef DEBUG_C14N
429 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000430 "xmlC14NPrintNamespace: namespace or context pointer is null\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000431#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000432 return 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000433 }
434
Daniel Veillard9ff88172002-03-11 09:15:32 +0000435 if (ns->prefix != NULL) {
436 xmlOutputBufferWriteString(ctx->buf, " xmlns:");
437 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
438 xmlOutputBufferWriteString(ctx->buf, "=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000439 } else {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000440 xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000441 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000442 if(ns->href != NULL) {
443 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
444 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000445 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000446 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000447}
448
449/**
450 * xmlC14NProcessNamespacesAxis:
451 * @ctx: the C14N context
452 * @node: the current node
453 *
454 * Prints out canonical namespace axis of the current node to the
455 * buffer from C14N context as follows
456 *
457 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
458 *
459 * Namespace Axis
460 * Consider a list L containing only namespace nodes in the
461 * axis and in the node-set in lexicographic order (ascending). To begin
462 * processing L, if the first node is not the default namespace node (a node
463 * with no namespace URI and no local name), then generate a space followed
464 * by xmlns="" if and only if the following conditions are met:
465 * - the element E that owns the axis is in the node-set
466 * - The nearest ancestor element of E in the node-set has a default
467 * namespace node in the node-set (default namespace nodes always
468 * have non-empty values in XPath)
469 * The latter condition eliminates unnecessary occurrences of xmlns="" in
470 * the canonical form since an element only receives an xmlns="" if its
471 * default namespace is empty and if it has an immediate parent in the
472 * canonical form that has a non-empty default namespace. To finish
473 * processing L, simply process every namespace node in L, except omit
474 * namespace node with local name xml, which defines the xml prefix,
475 * if its string value is http://www.w3.org/XML/1998/namespace.
476 *
477 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
478 * Canonical XML applied to a document subset requires the search of the
479 * ancestor nodes of each orphan element node for attributes in the xml
480 * namespace, such as xml:lang and xml:space. These are copied into the
481 * element node except if a declaration of the same attribute is already
482 * in the attribute axis of the element (whether or not it is included in
483 * the document subset). This search and copying are omitted from the
484 * Exclusive XML Canonicalization method.
485 *
486 * Returns 0 on success or -1 on fail.
487 */
488static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000489xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000490{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000491 xmlNodePtr n;
492 xmlNsPtr ns, tmp;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000493 xmlListPtr list;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000494 int already_rendered;
495 int has_empty_ns = 0;
Daniel Veillard5c396542002-03-15 07:57:50 +0000496
Daniel Veillard9ff88172002-03-11 09:15:32 +0000497 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
498#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000499 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000500 "xmlC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
501#endif
502 return (-1);
503 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000504
505 /*
506 * Create a sorted list to store element namespaces
507 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000508 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000509 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000510#ifdef DEBUG_C14N
511 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000512 "xmlC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000513#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000514 return (-1);
515 }
516
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000517 /* check all namespaces */
518 for(n = cur; n != NULL; n = n->parent) {
519 for(ns = n->nsDef; ns != NULL; ns = ns->next) {
520 tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
521
522 if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
523 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
524 if(visible) {
525 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
526 }
527 if(!already_rendered) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000528 xmlListInsert(list, ns);
529 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000530 if(xmlStrlen(ns->prefix) == 0) {
531 has_empty_ns = 1;
532 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000533 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000534 }
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000535 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000536
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000537 /**
538 * if the first node is not the default namespace node (a node with no
539 * namespace URI and no local name), then generate a space followed by
540 * xmlns="" if and only if the following conditions are met:
541 * - the element E that owns the axis is in the node-set
542 * - the nearest ancestor element of E in the node-set has a default
543 * namespace node in the node-set (default namespace nodes always
544 * have non-empty values in XPath)
545 */
546 if(visible && !has_empty_ns) {
547 static xmlNs ns_default;
548
549 memset(&ns_default, 0, sizeof(ns_default));
550 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
551 xmlC14NPrintNamespaces(&ns_default, ctx);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000552 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000553 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000554
555
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000556 /*
557 * print out all elements from list
558 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000559 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000560
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000561 /*
562 * Cleanup
563 */
564 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000565 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000566}
567
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000568
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000569/**
570 * xmlExcC14NProcessNamespacesAxis:
571 * @ctx: the C14N context
572 * @node: the current node
573 *
574 * Prints out exclusive canonical namespace axis of the current node to the
575 * buffer from C14N context as follows
576 *
577 * Exclusive XML Canonicalization
578 * http://www.w3.org/TR/xml-exc-c14n
579 *
580 * If the element node is in the XPath subset then output the node in
581 * accordance with Canonical XML except for namespace nodes which are
582 * rendered as follows:
583 *
584 * 1. Render each namespace node iff:
585 * * it is visibly utilized by the immediate parent element or one of
586 * its attributes, or is present in InclusiveNamespaces PrefixList, and
587 * * its prefix and value do not appear in ns_rendered. ns_rendered is
588 * obtained by popping the state stack in order to obtain a list of
589 * prefixes and their values which have already been rendered by
590 * an output ancestor of the namespace node's parent element.
591 * 2. Append the rendered namespace node to the list ns_rendered of namespace
592 * nodes rendered by output ancestors. Push ns_rendered on state stack and
593 * recurse.
594 * 3. After the recursion returns, pop thestate stack.
595 *
596 *
597 * Returns 0 on success or -1 on fail.
598 */
599static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000600xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000601{
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000602 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000603 xmlListPtr list;
604 xmlAttrPtr attr;
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000605 int already_rendered;
606 int has_empty_ns = 0;
607 int has_visibly_utilized_empty_ns = 0;
608 int has_empty_ns_in_inclusive_list = 0;
609
Daniel Veillard9ff88172002-03-11 09:15:32 +0000610 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
611#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000612 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000613 "xmlExcC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
614#endif
615 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000616 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000617
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000618 if(!ctx->exclusive) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000619#ifdef DEBUG_C14N
620 xmlGenericError(xmlGenericErrorContext,
621 "xmlExcC14NProcessNamespacesAxis: called for non-exclusive canonization or rendered stack is NULL.\n");
622#endif
623 return (-1);
624
625 }
626
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000627 /*
628 * Create a sorted list to store element namespaces
629 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000630 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000631 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000632#ifdef DEBUG_C14N
633 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000634 "xmlExcC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000635#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000636 return (-1);
637 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000638
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000639 /*
640 * process inclusive namespaces:
641 * All namespace nodes appearing on inclusive ns list are
642 * handled as provided in Canonical XML
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000643 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000644 if(ctx->inclusive_ns_prefixes != NULL) {
645 xmlChar *prefix;
646 int i;
647
648 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
649 prefix = ctx->inclusive_ns_prefixes[i];
650 /*
651 * Special values for namespace with empty prefix
652 */
653 if (xmlStrEqual(prefix, BAD_CAST "#default")
654 || xmlStrEqual(prefix, BAD_CAST "")) {
655 prefix = NULL;
656 has_empty_ns_in_inclusive_list = 1;
657 }
658
659 ns = xmlSearchNs(cur->doc, cur, prefix);
660 if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
661 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
662 if(visible) {
663 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
664 }
665 if(!already_rendered) {
666 xmlListInsert(list, ns);
667 }
668 if(xmlStrlen(ns->prefix) == 0) {
669 has_empty_ns = 1;
670 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000671 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000672 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000673 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000674
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000675 /* add node namespace */
676 if(cur->ns != NULL) {
677 ns = cur->ns;
678 } else {
679 ns = xmlSearchNs(cur->doc, cur, NULL);
680 has_visibly_utilized_empty_ns = 1;
681 }
682 if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
683 if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
684 if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
685 xmlListInsert(list, ns);
686 }
687 }
688 if(visible) {
689 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
690 }
691 if(xmlStrlen(ns->prefix) == 0) {
692 has_empty_ns = 1;
693 }
694 }
695
696
697 /* add attributes */
698 for(attr = cur->properties; attr != NULL; attr = attr->next) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000699 /*
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000700 * we need to check that attribute is visible and has non
701 * default namespace (XML Namespaces: "default namespaces
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000702 * do not apply directly to attributes")
Daniel Veillard9ff88172002-03-11 09:15:32 +0000703 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000704 if((attr->ns != NULL) && xmlC14NIsVisible(ctx, attr, cur)) {
705 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
706 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, (xmlNodePtr)attr);
707 if(!already_rendered && visible) {
708 xmlListInsert(list, attr->ns);
709 }
710 if(xmlStrlen(attr->ns->prefix) == 0) {
711 has_empty_ns = 1;
712 }
713 } else if(attr->ns == NULL) {
714 has_visibly_utilized_empty_ns = 1;
715 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000716 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000717
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000718 /*
719 * Process xmlns=""
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000720 */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000721 if(visible && has_visibly_utilized_empty_ns &&
722 !has_empty_ns && !has_empty_ns_in_inclusive_list) {
723 static xmlNs ns_default;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000724
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000725 memset(&ns_default, 0, sizeof(ns_default));
726
727 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
728 if(!already_rendered) {
729 xmlC14NPrintNamespaces(&ns_default, ctx);
730 }
731 } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
732 static xmlNs ns_default;
733
734 memset(&ns_default, 0, sizeof(ns_default));
735 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
736 xmlC14NPrintNamespaces(&ns_default, ctx);
737 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000738 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000739
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000740
741
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000742 /*
743 * print out all elements from list
744 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000745 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000746
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000747 /*
748 * Cleanup
749 */
750 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000751 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000752}
753
754
755/**
756 * xmlC14NAttrsCompare:
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000757 * @attr1: the pointer tls o first attr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000758 * @attr2: the pointer to second attr
759 *
760 * Prints the given attribute to the output buffer from C14N context.
761 *
762 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
763 */
764static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000765xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
766{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000767 int ret = 0;
768
769 /*
770 * Simple cases
771 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000772 if (attr1 == attr2)
773 return (0);
774 if (attr1 == NULL)
775 return (-1);
776 if (attr2 == NULL)
777 return (1);
778 if (attr1->ns == attr2->ns) {
779 return (xmlStrcmp(attr1->name, attr2->name));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000780 }
781
782 /*
783 * Attributes in the default namespace are first
784 * because the default namespace is not applied to
785 * unqualified attributes
786 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000787 if (attr1->ns == NULL)
788 return (-1);
789 if (attr2->ns == NULL)
790 return (1);
791 if (attr1->ns->prefix == NULL)
792 return (-1);
793 if (attr2->ns->prefix == NULL)
794 return (1);
795
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000796 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000797 if (ret == 0) {
798 ret = xmlStrcmp(attr1->name, attr2->name);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000799 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000800 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000801}
802
803
804/**
805 * xmlC14NPrintAttrs:
806 * @attr: the pointer to attr
807 * @ctx: the C14N context
808 *
809 * Prints out canonical attribute urrent node to the
810 * buffer from C14N context as follows
811 *
812 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
813 *
814 * Returns 1 on success or 0 on fail.
815 */
816static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000817xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
818{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000819 xmlChar *value;
820 xmlChar *buffer;
821
Daniel Veillard9ff88172002-03-11 09:15:32 +0000822 if ((attr == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000823#ifdef DEBUG_C14N
824 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000825 "xmlC14NPrintAttrs: attr == NULL or ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000826#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000827 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000828 }
829
830 xmlOutputBufferWriteString(ctx->buf, " ");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000831 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
832 xmlOutputBufferWriteString(ctx->buf,
833 (const char *) attr->ns->prefix);
834 xmlOutputBufferWriteString(ctx->buf, ":");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000835 }
836 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
837 xmlOutputBufferWriteString(ctx->buf, "=\"");
838
839 value = xmlNodeListGetString(attr->doc, attr->children, 1);
840 /* todo: should we log an error if value==NULL ? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000841 if (value != NULL) {
842 buffer = xmlC11NNormalizeAttr(value);
843 xmlFree(value);
844 if (buffer != NULL) {
845 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
846 xmlFree(buffer);
847 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000848#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +0000849 xmlGenericError(xmlGenericErrorContext,
850 "xmlC14NPrintAttrs: xmlC11NNormalizeAttr failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000851#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000852 return (0);
853 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000854 }
855 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000856 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000857}
858
859/**
860 * xmlC14NProcessAttrsAxis:
861 * @ctx: the C14N context
862 * @cur: the current node
863 *
864 * Prints out canonical attribute axis of the current node to the
865 * buffer from C14N context as follows
866 *
867 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
868 *
869 * Attribute Axis
870 * In lexicographic order (ascending), process each node that
871 * is in the element's attribute axis and in the node-set.
872 *
873 * The processing of an element node E MUST be modified slightly
874 * when an XPath node-set is given as input and the element's
875 * parent is omitted from the node-set.
876 *
877 *
878 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
879 *
880 * Canonical XML applied to a document subset requires the search of the
881 * ancestor nodes of each orphan element node for attributes in the xml
882 * namespace, such as xml:lang and xml:space. These are copied into the
883 * element node except if a declaration of the same attribute is already
884 * in the attribute axis of the element (whether or not it is included in
885 * the document subset). This search and copying are omitted from the
886 * Exclusive XML Canonicalization method.
887 *
888 * Returns 0 on success or -1 on fail.
889 */
890static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000891xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur)
892{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000893 xmlAttrPtr attr;
894 xmlListPtr list;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000895
896 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
897#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000898 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000899 "xmlC14NProcessAttrsAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
900#endif
901 return (-1);
902 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000903
904 /*
905 * Create a sorted list to store element attributes
906 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000907 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
908 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000909#ifdef DEBUG_C14N
910 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000911 "xmlC14NProcessAttrsAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000912#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000913 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000914 }
915
916 /*
917 * Add all visible attributes from current node.
918 */
919 attr = cur->properties;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000920 while (attr != NULL) {
921 /* check that attribute is visible */
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000922 if (xmlC14NIsVisible(ctx, attr, cur)) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000923 xmlListInsert(list, attr);
924 }
925 attr = attr->next;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000926 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000927
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000928 /*
929 * include attributes in "xml" namespace defined in ancestors
930 * (only for non-exclusive XML Canonicalization)
931 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000932 if ((!ctx->exclusive) && (cur->parent != NULL)
Aleksey Sanin2c135a12002-08-01 06:31:50 +0000933 && (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000934 /*
Daniel Veillard9ff88172002-03-11 09:15:32 +0000935 * If XPath node-set is not specified then the parent is always
936 * visible!
937 */
938 cur = cur->parent;
939 while (cur != NULL) {
940 attr = cur->properties;
941 while (attr != NULL) {
942 if ((attr->ns != NULL)
943 && (xmlStrEqual(attr->ns->prefix, BAD_CAST "xml"))) {
944 if (xmlListSearch(list, attr) == NULL) {
945 xmlListInsert(list, attr);
946 }
947 }
948 attr = attr->next;
949 }
950 cur = cur->parent;
951 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000952 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000953
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000954 /*
955 * print out all elements from list
956 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000957 xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000958
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000959 /*
960 * Cleanup
961 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000962 xmlListDelete(list);
963 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000964}
965
966/**
967 * xmlC14NCheckForRelativeNamespaces:
968 * @ctx: the C14N context
969 * @cur: the current element node
970 *
971 * Checks that current element node has no relative namespaces defined
972 *
973 * Returns 0 if the node has no relative namespaces or -1 otherwise.
974 */
975static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000976xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
977{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000978 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000979
Daniel Veillard9ff88172002-03-11 09:15:32 +0000980 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
981#ifdef DEBUG_C14N
982 xmlGenericError(xmlGenericErrorContext,
983 "xmlC14NCheckForRelativeNamespaces: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
984#endif
985 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000986 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000987
988 ns = cur->nsDef;
989 while (ns != NULL) {
990 if (xmlStrlen(ns->href) > 0) {
991 xmlURIPtr uri;
992
993 uri = xmlParseURI((const char *) ns->href);
994 if (uri == NULL) {
995#ifdef DEBUG_C14N
996 xmlGenericError(xmlGenericErrorContext,
997 "xmlC14NCheckForRelativeNamespaces: unable to parse uri=\"%s\".\n",
998 ns->href);
999#endif
1000 return (-1);
1001 }
1002 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
1003 xmlFreeURI(uri);
1004 return (-1);
1005 }
1006 if ((!xmlStrEqual
1007 ((const xmlChar *) uri->scheme, BAD_CAST "urn"))
1008 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
1009 xmlFreeURI(uri);
1010 return (-1);
1011 }
1012 xmlFreeURI(uri);
1013 }
1014 ns = ns->next;
1015 }
1016 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001017}
1018
1019/**
1020 * xmlC14NProcessElementNode:
1021 * @ctx: the pointer to C14N context object
1022 * @cur: the node to process
1023 *
1024 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1025 *
1026 * Element Nodes
1027 * If the element is not in the node-set, then the result is obtained
1028 * by processing the namespace axis, then the attribute axis, then
1029 * processing the child nodes of the element that are in the node-set
1030 * (in document order). If the element is in the node-set, then the result
1031 * is an open angle bracket (<), the element QName, the result of
1032 * processing the namespace axis, the result of processing the attribute
1033 * axis, a close angle bracket (>), the result of processing the child
1034 * nodes of the element that are in the node-set (in document order), an
1035 * open angle bracket, a forward slash (/), the element QName, and a close
1036 * angle bracket.
1037 *
1038 * Returns non-negative value on success or negative value on fail
1039 */
1040static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001041xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1042{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001043 int ret;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001044 xmlC14NVisibleNsStack state;
Daniel Veillard6f293b12002-03-15 09:42:33 +00001045 int parent_is_doc = 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001046
Daniel Veillard9ff88172002-03-11 09:15:32 +00001047 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1048#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001050 "xmlC14NProcessElementNode: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
1051#endif
1052 return (-1);
1053 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001054
1055 /*
1056 * Check relative relative namespaces:
1057 * implementations of XML canonicalization MUST report an operation
1058 * failure on documents containing relative namespace URIs.
1059 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001060 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1061#ifdef DEBUG_C14N
1062 xmlGenericError(xmlGenericErrorContext,
1063 "xmlC14NProcessElementNode: xmlC14NCheckForRelativeNamespaces failed.\n");
1064#endif
1065 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001066 }
1067
1068
1069 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001070 * Save ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001071 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001072 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001073
Daniel Veillard6f293b12002-03-15 09:42:33 +00001074 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001075 if (ctx->parent_is_doc) {
Daniel Veillard6f293b12002-03-15 09:42:33 +00001076 /* save this flag into the stack */
1077 parent_is_doc = ctx->parent_is_doc;
1078 ctx->parent_is_doc = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001079 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1080 }
1081 xmlOutputBufferWriteString(ctx->buf, "<");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001082
Daniel Veillard9ff88172002-03-11 09:15:32 +00001083 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1084 xmlOutputBufferWriteString(ctx->buf,
1085 (const char *) cur->ns->prefix);
1086 xmlOutputBufferWriteString(ctx->buf, ":");
1087 }
1088 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001089 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001090
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001091 if (!ctx->exclusive) {
1092 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1093 } else {
1094 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1095 }
1096 if (ret < 0) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001097#ifdef DEBUG_C14N
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001098 xmlGenericError(xmlGenericErrorContext,
1099 "xmlC14NProcessElementNode: xmlC14NProcessNamespacesAxis failed.\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001100#endif
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001101 return (-1);
1102 }
1103 /* todo: shouldn't this go to "visible only"? */
1104 if(visible) {
1105 xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1106 }
1107
1108 if(visible) {
1109 ret = xmlC14NProcessAttrsAxis(ctx, cur);
1110 if (ret < 0) {
1111#ifdef DEBUG_C14N
1112 xmlGenericError(xmlGenericErrorContext,
1113 "xmlC14NProcessElementNode: xmlC14NProcessAttrsAxis failed.\n");
1114#endif
1115 return (-1);
Aleksey Saninc57f9c12002-05-31 19:14:57 +00001116 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001117 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001118
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001119 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001120 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001121 }
1122 if (cur->children != NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001123 ret = xmlC14NProcessNodeList(ctx, cur->children);
1124 if (ret < 0) {
1125#ifdef DEBUG_C14N
1126 xmlGenericError(xmlGenericErrorContext,
1127 "xmlC14NProcessElementNode: xmlC14NProcessNodeList failed.\n");
1128#endif
1129 return (-1);
1130 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001131 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001132 if (visible) {
1133 xmlOutputBufferWriteString(ctx->buf, "</");
1134 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1135 xmlOutputBufferWriteString(ctx->buf,
1136 (const char *) cur->ns->prefix);
1137 xmlOutputBufferWriteString(ctx->buf, ":");
1138 }
1139 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1140 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard6f293b12002-03-15 09:42:33 +00001141 if (parent_is_doc) {
1142 /* restore this flag from the stack for next node */
1143 ctx->parent_is_doc = parent_is_doc;
1144 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001145 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001146 }
1147
1148 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001149 * Restore ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001150 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001151 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001152 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001153}
1154
1155/**
1156 * xmlC14NProcessNode:
1157 * @ctx: the pointer to C14N context object
1158 * @cur: the node to process
1159 *
1160 * Processes the given node
1161 *
1162 * Returns non-negative value on success or negative value on fail
1163 */
1164static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001165xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1166{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001167 int ret = 0;
1168 int visible;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001169
1170 if ((ctx == NULL) || (cur == NULL)) {
1171#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001173 "xmlC14NProcessNode: Null context or node pointer.\n");
1174#endif
1175 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001176 }
1177
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001178 visible = xmlC14NIsVisible(ctx, cur, cur->parent);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001179 switch (cur->type) {
1180 case XML_ELEMENT_NODE:
1181 ret = xmlC14NProcessElementNode(ctx, cur, visible);
1182 break;
1183 case XML_CDATA_SECTION_NODE:
1184 case XML_TEXT_NODE:
1185 /*
1186 * Text Nodes
1187 * the string value, except all ampersands are replaced
1188 * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1189 * angle brackets (>) are replaced by &gt;, and all #xD characters are
1190 * replaced by &#xD;.
1191 */
1192 /* cdata sections are processed as text nodes */
1193 /* todo: verify that cdata sections are included in XPath nodes set */
1194 if ((visible) && (cur->content != NULL)) {
1195 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001196
Daniel Veillard9ff88172002-03-11 09:15:32 +00001197 buffer = xmlC11NNormalizeText(cur->content);
1198 if (buffer != NULL) {
1199 xmlOutputBufferWriteString(ctx->buf,
1200 (const char *) buffer);
1201 xmlFree(buffer);
1202 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001203#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001204 xmlGenericError(xmlGenericErrorContext,
1205 "xmlC14NProcessNode: xmlC11NNormalizeText() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001206#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001207 return (-1);
1208 }
1209 }
1210 break;
1211 case XML_PI_NODE:
1212 /*
1213 * Processing Instruction (PI) Nodes-
1214 * The opening PI symbol (<?), the PI target name of the node,
1215 * a leading space and the string value if it is not empty, and
1216 * the closing PI symbol (?>). If the string value is empty,
1217 * then the leading space is not added. Also, a trailing #xA is
1218 * rendered after the closing PI symbol for PI children of the
1219 * root node with a lesser document order than the document
1220 * element, and a leading #xA is rendered before the opening PI
1221 * symbol of PI children of the root node with a greater document
1222 * order than the document element.
1223 */
1224 if (visible) {
1225 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1226 xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1227 } else {
1228 xmlOutputBufferWriteString(ctx->buf, "<?");
1229 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001230
Daniel Veillard9ff88172002-03-11 09:15:32 +00001231 xmlOutputBufferWriteString(ctx->buf,
1232 (const char *) cur->name);
1233 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1234 xmlChar *buffer;
1235
1236 xmlOutputBufferWriteString(ctx->buf, " ");
1237
1238 /* todo: do we need to normalize pi? */
1239 buffer = xmlC11NNormalizePI(cur->content);
1240 if (buffer != NULL) {
1241 xmlOutputBufferWriteString(ctx->buf,
1242 (const char *) buffer);
1243 xmlFree(buffer);
1244 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001245#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001246 xmlGenericError(xmlGenericErrorContext,
1247 "xmlC14NProcessNode: xmlC11NNormalizePI() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001248#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001249 return (-1);
1250 }
1251 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001252
Daniel Veillard9ff88172002-03-11 09:15:32 +00001253 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1254 xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1255 } else {
1256 xmlOutputBufferWriteString(ctx->buf, "?>");
1257 }
1258 }
1259 break;
1260 case XML_COMMENT_NODE:
1261 /*
1262 * Comment Nodes
1263 * Nothing if generating canonical XML without comments. For
1264 * canonical XML with comments, generate the opening comment
1265 * symbol (<!--), the string value of the node, and the
1266 * closing comment symbol (-->). Also, a trailing #xA is rendered
1267 * after the closing comment symbol for comment children of the
1268 * root node with a lesser document order than the document
1269 * element, and a leading #xA is rendered before the opening
1270 * comment symbol of comment children of the root node with a
1271 * greater document order than the document element. (Comment
1272 * children of the root node represent comments outside of the
1273 * top-level document element and outside of the document type
1274 * declaration).
1275 */
1276 if (visible && ctx->with_comments) {
1277 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1278 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1279 } else {
1280 xmlOutputBufferWriteString(ctx->buf, "<!--");
1281 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001282
Daniel Veillard9ff88172002-03-11 09:15:32 +00001283 if (cur->content != NULL) {
1284 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001285
Daniel Veillard9ff88172002-03-11 09:15:32 +00001286 /* todo: do we need to normalize comment? */
1287 buffer = xmlC11NNormalizeComment(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: xmlC11NNormalizeComment() 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_DOCUMENT_NODE:
1309 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001310#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001311 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001312#endif
1313#ifdef LIBXML_HTML_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001314 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001315#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001316 if (cur->children != NULL) {
1317 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1318 ctx->parent_is_doc = 1;
1319 ret = xmlC14NProcessNodeList(ctx, cur->children);
1320 }
1321 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001322
Daniel Veillard9ff88172002-03-11 09:15:32 +00001323 case XML_ATTRIBUTE_NODE:
1324 xmlGenericError(xmlGenericErrorContext,
1325 "xmlC14NProcessNode: XML_ATTRIBUTE_NODE is illegal here\n");
1326 return (-1);
1327 case XML_NAMESPACE_DECL:
1328 xmlGenericError(xmlGenericErrorContext,
1329 "xmlC14NProcessNode: XML_NAMESPACE_DECL is illegal here\n");
1330 return (-1);
1331 case XML_ENTITY_REF_NODE:
1332 xmlGenericError(xmlGenericErrorContext,
1333 "xmlC14NProcessNode: XML_ENTITY_REF_NODE is illegal here\n");
1334 return (-1);
1335 case XML_ENTITY_NODE:
1336 xmlGenericError(xmlGenericErrorContext,
1337 "xmlC14NProcessNode: XML_ENTITY_NODE is illegal here\n");
1338 return (-1);
1339
1340 case XML_DOCUMENT_TYPE_NODE:
1341 case XML_NOTATION_NODE:
1342 case XML_DTD_NODE:
1343 case XML_ELEMENT_DECL:
1344 case XML_ATTRIBUTE_DECL:
1345 case XML_ENTITY_DECL:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001346#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001347 case XML_XINCLUDE_START:
1348 case XML_XINCLUDE_END:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001349#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001350 /*
1351 * should be ignored according to "W3C Canonical XML"
1352 */
1353 break;
1354 default:
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001355#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001356 xmlGenericError(xmlGenericErrorContext,
1357 "xmlC14NProcessNode: unknown node type = %d\n",
1358 cur->type);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001359#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001360 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001361 }
1362
Daniel Veillard9ff88172002-03-11 09:15:32 +00001363 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001364}
1365
1366/**
1367 * xmlC14NProcessNodeList:
1368 * @ctx: the pointer to C14N context object
1369 * @cur: the node to start from
1370 *
1371 * Processes all nodes in the row starting from cur.
1372 *
1373 * Returns non-negative value on success or negative value on fail
1374 */
1375static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001376xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1377{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001378 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001379
1380 if (ctx == NULL) {
1381#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001383 "xmlC14NProcessNodeList: Null context pointer.\n");
1384#endif
1385 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001386 }
1387
Daniel Veillard9ff88172002-03-11 09:15:32 +00001388 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1389 ret = xmlC14NProcessNode(ctx, cur);
1390 }
1391 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001392}
1393
1394
1395/**
1396 * xmlC14NFreeCtx:
1397 * @ctx: the pointer to C14N context object
1398 *
1399 * Cleanups the C14N context object.
1400 */
1401
1402static void
Daniel Veillard9ff88172002-03-11 09:15:32 +00001403xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1404{
1405 if (ctx == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001406#ifdef DEBUG_C14N
1407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001408 "xmlC14NFreeCtx: ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001409#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001410 return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001411 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001412
1413 if (ctx->ns_rendered != NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001414 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001415 }
1416 xmlFree(ctx);
1417}
1418
1419/**
1420 * xmlC14NNewCtx:
1421 * @doc: the XML document for canonization
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001422 * @is_visible_callback:the function to use to determine is node visible
1423 * or not
1424 * @user_data: the first parameter for @is_visible_callback function
1425 * (in most cases, it is nodes set)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001426 * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1427 * ended with a NULL or NULL if there is no
1428 * inclusive namespaces (only for exclusive
1429 * canonicalization)
1430 * @with_comments: include comments in the result (!=0) or not (==0)
1431 * @buf: the output buffer to store canonical XML; this
1432 * buffer MUST have encoder==NULL because C14N requires
1433 * UTF-8 output
1434 *
1435 * Creates new C14N context object to store C14N parameters.
1436 *
1437 * Returns pointer to newly created object (success) or NULL (fail)
1438 */
1439static xmlC14NCtxPtr
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001440xmlC14NNewCtx(xmlDocPtr doc,
1441 xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001442 int exclusive, xmlChar ** inclusive_ns_prefixes,
1443 int with_comments, xmlOutputBufferPtr buf)
1444{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001445 xmlC14NCtxPtr ctx;
1446
Daniel Veillard9ff88172002-03-11 09:15:32 +00001447 if ((doc == NULL) || (buf == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001448#ifdef DEBUG_C14N
1449 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001450 "xmlC14NNewCtx: pointer to document or output buffer is NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001451#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001452 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001453 }
1454
1455 /*
1456 * Validate the encoding output buffer encoding
1457 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001458 if (buf->encoder != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001459 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001460 "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
1461 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001462 }
1463
1464 /*
1465 * Validate the XML document encoding value, if provided.
1466 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001467 if (doc->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001469 "xmlC14NNewCtx: source document not in UTF8\n");
1470 return (NULL);
1471 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001472
1473 /*
1474 * Allocate a new xmlC14NCtxPtr and fill the fields.
1475 */
1476 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1477 if (ctx == NULL) {
1478 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001479 "xmlC14NNewCtx: malloc failed\n");
1480 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001481 }
1482 memset(ctx, 0, sizeof(xmlC14NCtx));
1483
1484 /*
1485 * initialize C14N context
Daniel Veillard9ff88172002-03-11 09:15:32 +00001486 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001487 ctx->doc = doc;
1488 ctx->with_comments = with_comments;
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001489 ctx->is_visible_callback = is_visible_callback;
1490 ctx->user_data = user_data;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001491 ctx->buf = buf;
1492 ctx->parent_is_doc = 1;
1493 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001494 ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1495
1496 if(ctx->ns_rendered == NULL) {
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
1499 xmlC14NFreeCtx(ctx);
1500 return (NULL);
1501 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001502
1503 /*
1504 * Set "exclusive" flag, create a nodes set for namespaces
1505 * stack and remember list of incluseve prefixes
1506 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001507 if (exclusive) {
1508 ctx->exclusive = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001509 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1510 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001511 return (ctx);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001512}
1513
1514/**
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001515 * xmlC14NExecute:
1516 * @doc: the XML document for canonization
1517 * @is_visible_callback:the function to use to determine is node visible
1518 * or not
1519 * @user_data: the first parameter for @is_visible_callback function
1520 * (in most cases, it is nodes set)
1521 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1522 * otherwise - exclusive canonicalization)
1523 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1524 * ended with a NULL or NULL if there is no
1525 * inclusive namespaces (only for exclusive
1526 * canonicalization, ignored otherwise)
1527 * @with_comments: include comments in the result (!=0) or not (==0)
1528 * @buf: the output buffer to store canonical XML; this
1529 * buffer MUST have encoder==NULL because C14N requires
1530 * UTF-8 output
1531 *
1532 * Dumps the canonized image of given XML document into the provided buffer.
1533 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1534 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1535 *
1536 * Returns non-negative value on success or a negative value on fail
1537 */
1538int
1539xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
1540 void* user_data, int exclusive, xmlChar **inclusive_ns_prefixes,
1541 int with_comments, xmlOutputBufferPtr buf) {
1542
1543 xmlC14NCtxPtr ctx;
1544 int ret;
1545
1546 if ((buf == NULL) || (doc == NULL)) {
1547#ifdef DEBUG_C14N
1548 xmlGenericError(xmlGenericErrorContext,
1549 "xmlC14NExecute: null return buffer or doc pointer\n");
1550#endif
1551 return (-1);
1552 }
1553
1554 /*
1555 * Validate the encoding output buffer encoding
1556 */
1557 if (buf->encoder != NULL) {
1558 xmlGenericError(xmlGenericErrorContext,
1559 "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
1560 return (-1);
1561 }
1562
1563 ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
1564 exclusive, inclusive_ns_prefixes,
1565 with_comments, buf);
1566 if (ctx == NULL) {
1567 xmlGenericError(xmlGenericErrorContext,
1568 "xmlC14NExecute: unable to create C14N context\n");
1569 return (-1);
1570 }
1571
1572
1573
1574 /*
1575 * Root Node
1576 * The root node is the parent of the top-level document element. The
1577 * result of processing each of its child nodes that is in the node-set
1578 * in document order. The root node does not generate a byte order mark,
1579 * XML declaration, nor anything from within the document type
1580 * declaration.
1581 */
1582 if (doc->children != NULL) {
1583 ret = xmlC14NProcessNodeList(ctx, doc->children);
1584 if (ret < 0) {
1585#ifdef DEBUG_C14N
1586 xmlGenericError(xmlGenericErrorContext,
1587 "xmlC14NExecute: process childrens' list failed.\n");
1588#endif
1589 xmlC14NFreeCtx(ctx);
1590 return (-1);
1591 }
1592 }
1593
1594 /*
1595 * Flush buffer to get number of bytes written
1596 */
1597 ret = xmlOutputBufferFlush(buf);
1598 if (ret < 0) {
1599#ifdef DEBUG_C14N
1600 xmlGenericError(xmlGenericErrorContext,
1601 "xmlC14NExecute: buffer flush failed.\n");
1602#endif
1603 xmlC14NFreeCtx(ctx);
1604 return (-1);
1605 }
1606
1607 /*
1608 * Cleanup
1609 */
1610 xmlC14NFreeCtx(ctx);
1611 return (ret);
1612}
1613
1614/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001615 * xmlC14NDocSaveTo:
1616 * @doc: the XML document for canonization
1617 * @nodes: the nodes set to be included in the canonized image
1618 * or NULL if all document nodes should be included
1619 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1620 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001621 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001622 * ended with a NULL or NULL if there is no
1623 * inclusive namespaces (only for exclusive
1624 * canonicalization, ignored otherwise)
1625 * @with_comments: include comments in the result (!=0) or not (==0)
1626 * @buf: the output buffer to store canonical XML; this
1627 * buffer MUST have encoder==NULL because C14N requires
1628 * UTF-8 output
1629 *
1630 * Dumps the canonized image of given XML document into the provided buffer.
1631 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1632 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1633 *
1634 * Returns non-negative value on success or a negative value on fail
1635 */
1636int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001637xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1638 int exclusive, xmlChar ** inclusive_ns_prefixes,
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001639 int with_comments, xmlOutputBufferPtr buf) {
1640 return(xmlC14NExecute(doc,
1641 (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1642 nodes,
1643 exclusive,
1644 inclusive_ns_prefixes,
1645 with_comments,
1646 buf));
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001647}
1648
Aleksey Sanin2c135a12002-08-01 06:31:50 +00001649
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001650/**
1651 * xmlC14NDocDumpMemory:
1652 * @doc: the XML document for canonization
1653 * @nodes: the nodes set to be included in the canonized image
1654 * or NULL if all document nodes should be included
1655 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1656 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001657 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001658 * ended with a NULL or NULL if there is no
1659 * inclusive namespaces (only for exclusive
1660 * canonicalization, ignored otherwise)
1661 * @with_comments: include comments in the result (!=0) or not (==0)
1662 * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
1663 * the caller of this functions is responsible for calling
1664 * xmlFree() to free allocated memory
1665 *
1666 * Dumps the canonized image of given XML document into memory.
1667 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1668 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1669 *
1670 * Returns the number of bytes written on success or a negative value on fail
1671 */
1672int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001673xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
1674 int exclusive, xmlChar ** inclusive_ns_prefixes,
1675 int with_comments, xmlChar ** doc_txt_ptr)
1676{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001677 int ret;
1678 xmlOutputBufferPtr buf;
1679
1680 if (doc_txt_ptr == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001681#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001682 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001683 "xmlC14NDocDumpMemory: null return buffer pointer\n");
1684#endif
1685 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001686 }
1687
1688 *doc_txt_ptr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001689
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001690 /*
1691 * create memory buffer with UTF8 (default) encoding
1692 */
1693 buf = xmlAllocOutputBuffer(NULL);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001694 if (buf == NULL) {
1695#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001696 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001697 "xmlC14NDocDumpMemory: failed to allocate output buffer.\n");
1698#endif
1699 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001700 }
1701
1702 /*
1703 * canonize document and write to buffer
1704 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001705 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1706 with_comments, buf);
1707 if (ret < 0) {
1708#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001710 "xmlC14NDocDumpMemory: xmlC14NDocSaveTo failed.\n");
1711#endif
1712 (void) xmlOutputBufferClose(buf);
1713 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001714 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001715
Daniel Veillard9ff88172002-03-11 09:15:32 +00001716 ret = buf->buffer->use;
1717 if (ret > 0) {
1718 *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
1719 }
1720 (void) xmlOutputBufferClose(buf);
1721
1722 if ((*doc_txt_ptr == NULL) && (ret > 0)) {
1723#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001724 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001725 "xmlC14NDocDumpMemory: failed to allocate memory for document text representation\n");
1726#endif
1727 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001728 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001729 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001730}
1731
1732/**
1733 * xmlC14NDocSave:
1734 * @doc: the XML document for canonization
1735 * @nodes: the nodes set to be included in the canonized image
1736 * or NULL if all document nodes should be included
1737 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1738 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001739 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001740 * ended with a NULL or NULL if there is no
1741 * inclusive namespaces (only for exclusive
1742 * canonicalization, ignored otherwise)
1743 * @with_comments: include comments in the result (!=0) or not (==0)
1744 * @filename: the filename to store canonical XML image
1745 * @compression: the compression level (zlib requred):
1746 * -1 - libxml default,
1747 * 0 - uncompressed,
1748 * >0 - compression level
1749 *
1750 * Dumps the canonized image of given XML document into the file.
1751 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1752 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1753 *
1754 * Returns the number of bytes written success or a negative value on fail
1755 */
1756int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001757xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
1758 int exclusive, xmlChar ** inclusive_ns_prefixes,
1759 int with_comments, const char *filename, int compression)
1760{
1761 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762 int ret;
1763
Daniel Veillard9ff88172002-03-11 09:15:32 +00001764 if (filename == NULL) {
1765#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001767 "xmlC14NDocSave: filename is NULL\n");
1768#endif
1769 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001770 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771#ifdef HAVE_ZLIB_H
Daniel Veillard9ff88172002-03-11 09:15:32 +00001772 if (compression < 0)
1773 compression = xmlGetCompressMode();
1774#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775
1776 /*
1777 * save the content to a temp buffer, use default UTF8 encoding.
1778 */
1779 buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
1780 if (buf == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001781#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001783 "xmlC14NDocSave: unable to create buffer for file=\"%s\" with compressin=%d\n",
1784 filename, compression);
1785#endif
1786 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001788
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001789 /*
1790 * canonize document and write to buffer
1791 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001792 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1793 with_comments, buf);
1794 if (ret < 0) {
1795#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001796 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001797 "xmlC14NDocSave: xmlC14NDocSaveTo failed.\n");
1798#endif
1799 (void) xmlOutputBufferClose(buf);
1800 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001801 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001802
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001803 /*
1804 * get the numbers of bytes written
1805 */
1806 ret = xmlOutputBufferClose(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001807 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001808}
1809
1810
1811
1812/*
1813 * Macro used to grow the current buffer.
1814 */
1815#define growBufferReentrant() { \
1816 buffer_size *= 2; \
1817 buffer = (xmlChar *) \
1818 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
1819 if (buffer == NULL) { \
1820 perror("realloc failed"); \
1821 return(NULL); \
1822 } \
1823}
1824
1825/**
1826 * xmlC11NNormalizeString:
1827 * @input: the input string
1828 * @mode: the normalization mode (attribute, comment, PI or text)
1829 *
1830 * Converts a string to a canonical (normalized) format. The code is stolen
1831 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
1832 * and the @mode parameter
1833 *
1834 * Returns a normalized string (caller is responsible for calling xmlFree())
1835 * or NULL if an error occurs
1836 */
1837static xmlChar *
Daniel Veillard9ff88172002-03-11 09:15:32 +00001838xmlC11NNormalizeString(const xmlChar * input,
1839 xmlC14NNormalizationMode mode)
1840{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001841 const xmlChar *cur = input;
1842 xmlChar *buffer = NULL;
1843 xmlChar *out = NULL;
1844 int buffer_size = 0;
1845
Daniel Veillard9ff88172002-03-11 09:15:32 +00001846 if (input == NULL)
1847 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001848
1849 /*
1850 * allocate an translation buffer.
1851 */
1852 buffer_size = 1000;
1853 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1854 if (buffer == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001855 perror("malloc failed");
1856 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001857 }
1858 out = buffer;
1859
1860 while (*cur != '\0') {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001861 if ((out - buffer) > (buffer_size - 10)) {
1862 int indx = out - buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001863
Daniel Veillard9ff88172002-03-11 09:15:32 +00001864 growBufferReentrant();
1865 out = &buffer[indx];
1866 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001867
Daniel Veillard9ff88172002-03-11 09:15:32 +00001868 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1869 (mode == XMLC14N_NORMALIZE_TEXT))) {
1870 *out++ = '&';
1871 *out++ = 'l';
1872 *out++ = 't';
1873 *out++ = ';';
1874 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
1875 *out++ = '&';
1876 *out++ = 'g';
1877 *out++ = 't';
1878 *out++ = ';';
1879 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1880 (mode == XMLC14N_NORMALIZE_TEXT))) {
1881 *out++ = '&';
1882 *out++ = 'a';
1883 *out++ = 'm';
1884 *out++ = 'p';
1885 *out++ = ';';
1886 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1887 *out++ = '&';
1888 *out++ = 'q';
1889 *out++ = 'u';
1890 *out++ = 'o';
1891 *out++ = 't';
1892 *out++ = ';';
1893 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1894 *out++ = '&';
1895 *out++ = '#';
1896 *out++ = 'x';
1897 *out++ = '9';
1898 *out++ = ';';
1899 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1900 *out++ = '&';
1901 *out++ = '#';
1902 *out++ = 'x';
1903 *out++ = 'A';
1904 *out++ = ';';
1905 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1906 (mode == XMLC14N_NORMALIZE_TEXT) ||
1907 (mode == XMLC14N_NORMALIZE_COMMENT) ||
1908 (mode == XMLC14N_NORMALIZE_PI))) {
1909 *out++ = '&';
1910 *out++ = '#';
1911 *out++ = 'x';
1912 *out++ = 'D';
1913 *out++ = ';';
1914 } else {
1915 /*
1916 * Works because on UTF-8, all extended sequences cannot
1917 * result in bytes in the ASCII range.
1918 */
1919 *out++ = *cur;
1920 }
1921 cur++;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001922 }
1923 *out++ = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001924 return (buffer);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001925}
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001926#endif /* LIBXML_C14N_ENABLED */