blob: 9d42fa383a74f28503fa428dd777895017936868 [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 {
42 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 */
Aleksey Sanindffd5c82002-05-31 04:24:13 +000045 int nsMax; /* size of the array as allocated */
46 xmlNsPtr *nsTab; /* array of nodes in no particular order */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000047} xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
48static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
49static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
50static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
51 xmlNsPtr ns);
52static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
53 xmlC14NVisibleNsStackPtr state);
54static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
55 xmlC14NVisibleNsStackPtr state);
56static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
57static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
58 xmlNsPtr ns,
59 int exclusive);
Aleksey Sanindffd5c82002-05-31 04:24:13 +000060
Daniel Veillard044fc6b2002-03-04 17:09:44 +000061typedef struct _xmlC14NCtx {
62 /* input parameters */
Daniel Veillard9ff88172002-03-11 09:15:32 +000063 xmlDocPtr doc;
64 xmlNodeSetPtr visible_nodes;
65 int with_comments;
66 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000067
68 /* position in the XML document */
Daniel Veillard9ff88172002-03-11 09:15:32 +000069 xmlC14NPosition pos;
70 int parent_is_doc;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000071 xmlC14NVisibleNsStackPtr ns_rendered;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000072
73 /* exclusive canonicalization */
Daniel Veillard9ff88172002-03-11 09:15:32 +000074 int exclusive;
Daniel Veillard9ff88172002-03-11 09:15:32 +000075 xmlChar **inclusive_ns_prefixes;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000076} xmlC14NCtx, *xmlC14NCtxPtr;
77
78
Daniel Veillard9ff88172002-03-11 09:15:32 +000079static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
80static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000081typedef enum {
Daniel Veillard9ff88172002-03-11 09:15:32 +000082 XMLC14N_NORMALIZE_ATTR = 0,
83 XMLC14N_NORMALIZE_COMMENT = 1,
84 XMLC14N_NORMALIZE_PI = 2,
85 XMLC14N_NORMALIZE_TEXT = 3
86} xmlC14NNormalizationMode;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000087
Daniel Veillard9ff88172002-03-11 09:15:32 +000088static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
89 xmlC14NNormalizationMode mode);
Daniel Veillard044fc6b2002-03-04 17:09:44 +000090
91#define xmlC11NNormalizeAttr( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +000092 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000093#define xmlC11NNormalizeComment( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +000094 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000095#define xmlC11NNormalizePI( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +000096 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000097#define xmlC11NNormalizeText( a ) \
Daniel Veillard9ff88172002-03-11 09:15:32 +000098 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000099
100/************************************************************************
101 * *
102 * The implementation internals *
103 * *
104 ************************************************************************/
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000105#define XML_NAMESPACES_DEFAULT 16
106
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000107static xmlC14NVisibleNsStackPtr
108xmlC14NVisibleNsStackCreate(void) {
109 xmlC14NVisibleNsStackPtr ret;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000110
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000111 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000112 if (ret == NULL) {
113 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000114 "xmlC14NVisibleNsStackCreate: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000115 return(NULL);
116 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000117 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000118 return(ret);
119}
120
121static void
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000122xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000123 if(cur == NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000124#ifdef DEBUG_C14N
125 xmlGenericError(xmlGenericErrorContext,
126 "xmlC14NVisibleNsStackAdd: cur is null.\n");
127#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000128 return;
129 }
130 if(cur->nsTab != NULL) {
131 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
132 xmlFree(cur->nsTab);
133 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000134 memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000135 xmlFree(cur);
136
137}
138
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000139static void
140xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns) {
141 if(cur == NULL) {
142#ifdef DEBUG_C14N
143 xmlGenericError(xmlGenericErrorContext,
144 "xmlC14NVisibleNsStackAdd: cur is null.\n");
145#endif
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000146 return;
147 }
148
149 if (cur->nsTab == NULL) {
150 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
151 if (cur->nsTab == NULL) {
152 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000153 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000154 return;
155 }
156 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
157 cur->nsMax = XML_NAMESPACES_DEFAULT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000158 } else if(cur->nsMax == cur->nsCurEnd) {
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000159 xmlNsPtr *tmp;
160 int tmpSize;
161
162 tmpSize = 2 * cur->nsMax;
163 tmp = (xmlNsPtr*) xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
164 if (tmp == NULL) {
165 xmlGenericError(xmlGenericErrorContext,
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000166 "xmlC14NVisibleNsStackAdd: out of memory\n");
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000167 return;
168 }
169 cur->nsTab = tmp;
170 cur->nsMax = tmpSize;
171 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000172 cur->nsTab[cur->nsCurEnd++] = ns;
173}
174
175static void
176xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
177 if((cur == NULL) || (state == NULL)) {
178#ifdef DEBUG_C14N
179 xmlGenericError(xmlGenericErrorContext,
180 "xmlC14NVisibleNsStackSave: cur or state is null.\n");
181#endif
182 return;
183 }
184
185 state->nsCurEnd = cur->nsCurEnd;
186 state->nsPrevStart = cur->nsPrevStart;
187 state->nsPrevEnd = cur->nsPrevEnd;
188}
189
190static void
191xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
192 if((cur == NULL) || (state == NULL)) {
193#ifdef DEBUG_C14N
194 xmlGenericError(xmlGenericErrorContext,
195 "xmlC14NVisibleNsStackRestore: cur or state is null.\n");
196#endif
197 return;
198 }
199 cur->nsCurEnd = state->nsCurEnd;
200 cur->nsPrevStart = state->nsPrevStart;
201 cur->nsPrevEnd = state->nsPrevEnd;
202}
203
204static void
205xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
206 if(cur == NULL) {
207#ifdef DEBUG_C14N
208 xmlGenericError(xmlGenericErrorContext,
209 "xmlC14NVisibleNsStackRestore: cur is null.\n");
210#endif
211 return;
212 }
213 cur->nsPrevStart = cur->nsPrevEnd;
214 cur->nsPrevEnd = cur->nsCurEnd;
215}
216
217static int
218xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
219 if (str1 == str2) return(1);
220 if (str1 == NULL) return((*str2) == '\0');
221 if (str2 == NULL) return((*str1) == '\0');
222 do {
223 if (*str1++ != *str2) return(0);
224 } while (*str2++);
225 return(1);
226}
227
228/**
229 * xmlC14NVisibleNsStackFind:
230 * @ctx the C14N context
231 * @ns the namespace to check
232 *
233 * Checks whether the given namespace was already rendered or not
234 *
235 * Returns 1 if we already wrote this namespace or 0 otherwise
236 */
237static int
238xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, int exclusive)
239{
240 int i;
241 const xmlChar *prefix;
242 const xmlChar *href;
243 int emptyNs;
244
245 if(cur == NULL) {
246#ifdef DEBUG_C14N
247 xmlGenericError(xmlGenericErrorContext,
248 "xmlC14NVisibleNsStackFind: cur is null.\n");
249#endif
250 return (0);
251 }
252
253 /*
254 * if the default namespace xmlns="" is not defined yet then
255 * we do not want to print it out
256 */
257 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
258 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
259 emptyNs = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
260 if (cur->nsTab != NULL) {
261 int start = (exclusive || emptyNs) ? 0 : cur->nsPrevStart;
262 for (i = cur->nsCurEnd - 1; i >= start; --i) {
263 xmlNsPtr ns1 = cur->nsTab[i];
264
265 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
266 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
267 }
268 }
269 }
270 return(emptyNs);
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000271}
272
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000273
274/**
275 * xmlC14NIsVisible:
276 * @ctx: the C14N context
277 * @node: the node to check
278 *
279 * Checks whether the given node is visible. If the XML document normalization
280 * was called for the whole document then it is always "true".
281 *
282 * Returns 1 if the node is visible or 0 otherwise.
283 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000284
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000285/* todo: make it a define? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000286static int
287xmlC14NIsVisible(xmlC14NCtxPtr ctx, void *node)
288{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000289 /*
290 * If the input is an XPath node-set, then the node-set must explicitly
291 * contain every node to be rendered to the canonical form.
292 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000293 if ((ctx->visible_nodes != NULL) &&
294 (!xmlXPathNodeSetContains(ctx->visible_nodes, (xmlNodePtr) node)))
295 {
296 return (0);
297 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000298
Daniel Veillard9ff88172002-03-11 09:15:32 +0000299 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000300}
301
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000302static int
303xmlC14NIsNsVisible(xmlC14NCtxPtr ctx, xmlNsPtr ns, xmlNodePtr cur)
304{
305 xmlNs ns1;
306
307 if(ns == NULL) {
308 return(1);
309 }
310 memcpy(&ns1, ns, sizeof(ns1));
311 ns1.next = (xmlNsPtr)cur;
312
313 /*
314 * If the input is an XPath node-set, then the node-set must explicitly
315 * contain every node to be rendered to the canonical form.
316 */
317 if ((ctx->visible_nodes != NULL) &&
318 (!xmlXPathNodeSetContains(ctx->visible_nodes, (xmlNodePtr) &ns1)))
319 {
320 return (0);
321 }
322
323 return (1);
324}
325
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000326/**
327 * xmlC14NIsXmlNs:
328 * @ns: the namespace to check
329 *
330 * Checks whether the given namespace is a default "xml:" namespace
331 * with href="http://www.w3.org/XML/1998/namespace"
332 *
333 * Returns 1 if the node is default or 0 otherwise
334 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000335
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000336/* todo: make it a define? */
337static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000338xmlC14NIsXmlNs(xmlNsPtr ns)
339{
340 return ((ns != NULL) &&
341 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
342 (xmlStrEqual(ns->href,
343 BAD_CAST
344 "http://www.w3.org/XML/1998/namespace")));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000345}
346
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000347
348/**
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000349 * xmlC14NNsCompare:
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000350 * @ns1: the pointer to first namespace
351 * @ns2: the pointer to second namespace
352 *
353 * Compares the namespaces by names (prefixes).
354 *
355 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
356 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000357static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000358xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000359{
360 if (ns1 == ns2)
361 return (0);
362 if (ns1 == NULL)
363 return (-1);
364 if (ns2 == NULL)
365 return (1);
366
367 return (xmlStrcmp(ns1->prefix, ns2->prefix));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000368}
369
370
371/**
372 * xmlC14NPrintNamespaces:
373 * @ns: the pointer to namespace
374 * @ctx: the C14N context
375 *
376 * Prints the given namespace to the output buffer from C14N context.
377 *
378 * Returns 1 on success or 0 on fail.
379 */
380static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000381xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
382{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000383
Daniel Veillard9ff88172002-03-11 09:15:32 +0000384 if ((ns == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000385#ifdef DEBUG_C14N
386 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000387 "xmlC14NPrintNamespace: namespace or context pointer is null\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000388#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000389 return 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000390 }
391
Daniel Veillard9ff88172002-03-11 09:15:32 +0000392 if (ns->prefix != NULL) {
393 xmlOutputBufferWriteString(ctx->buf, " xmlns:");
394 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
395 xmlOutputBufferWriteString(ctx->buf, "=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000396 } else {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000397 xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000398 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000399 if(ns->href != NULL) {
400 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
401 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000402 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000403 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000404}
405
406/**
407 * xmlC14NProcessNamespacesAxis:
408 * @ctx: the C14N context
409 * @node: the current node
410 *
411 * Prints out canonical namespace axis of the current node to the
412 * buffer from C14N context as follows
413 *
414 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
415 *
416 * Namespace Axis
417 * Consider a list L containing only namespace nodes in the
418 * axis and in the node-set in lexicographic order (ascending). To begin
419 * processing L, if the first node is not the default namespace node (a node
420 * with no namespace URI and no local name), then generate a space followed
421 * by xmlns="" if and only if the following conditions are met:
422 * - the element E that owns the axis is in the node-set
423 * - The nearest ancestor element of E in the node-set has a default
424 * namespace node in the node-set (default namespace nodes always
425 * have non-empty values in XPath)
426 * The latter condition eliminates unnecessary occurrences of xmlns="" in
427 * the canonical form since an element only receives an xmlns="" if its
428 * default namespace is empty and if it has an immediate parent in the
429 * canonical form that has a non-empty default namespace. To finish
430 * processing L, simply process every namespace node in L, except omit
431 * namespace node with local name xml, which defines the xml prefix,
432 * if its string value is http://www.w3.org/XML/1998/namespace.
433 *
434 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
435 * Canonical XML applied to a document subset requires the search of the
436 * ancestor nodes of each orphan element node for attributes in the xml
437 * namespace, such as xml:lang and xml:space. These are copied into the
438 * element node except if a declaration of the same attribute is already
439 * in the attribute axis of the element (whether or not it is included in
440 * the document subset). This search and copying are omitted from the
441 * Exclusive XML Canonicalization method.
442 *
443 * Returns 0 on success or -1 on fail.
444 */
445static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000446xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000447{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000448 xmlNsPtr ns;
449 xmlListPtr list;
Daniel Veillard5c396542002-03-15 07:57:50 +0000450
Daniel Veillard9ff88172002-03-11 09:15:32 +0000451 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
452#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000453 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000454 "xmlC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
455#endif
456 return (-1);
457 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000458
459 /*
460 * Create a sorted list to store element namespaces
461 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000462 list =
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000463 xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000464 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000465#ifdef DEBUG_C14N
466 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000467 "xmlC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000468#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000469 return (-1);
470 }
471
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000472 if(ctx->visible_nodes == NULL) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000473 xmlNsPtr tmp;
474
475 for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
476 if(!xmlC14NIsXmlNs(ns)) {
477 tmp = (cur->parent != NULL) ?
478 xmlSearchNs(ctx->doc, cur->parent, ns->prefix) :
479 NULL;
480 if(((tmp == NULL) && (xmlStrlen(ns->href) > 0)) ||
481 ((tmp != NULL) && !xmlStrEqual(ns->href, tmp->href))) {
482 xmlListInsert(list, ns);
483 }
484 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000485 }
486 } else {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000487 xmlNodePtr node;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000488 int i;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000489 int emptyNs = 0;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000490
491 /*
492 * All visible namespace nodes are in the nodes set
493 */
494 for(i = 0; i < ctx->visible_nodes->nodeNr; i++) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000495 node = ctx->visible_nodes->nodeTab[i];
496 if((node != NULL) && (node->type == XML_NAMESPACE_DECL)) {
497 ns = (xmlNsPtr)node;
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000498
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000499 if(((xmlNodePtr)(ns->next) == cur) && !xmlC14NIsXmlNs(ns)) {
500 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns, 0)) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000501 xmlListInsert(list, ns);
502 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000503 if(visible) {
504 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns);
505 }
506 if(xmlStrlen(ns->prefix) == 0) {
507 emptyNs = 1;
508 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000509 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000510 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000511 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000512
513 /**
514 * if the first node is not the default namespace node (a node with no
515 * namespace URI and no local name), then generate a space followed by
516 * xmlns="" if and only if the following conditions are met:
517 * - the element E that owns the axis is in the node-set
518 * - the nearest ancestor element of E in the node-set has a default
519 * namespace node in the node-set (default namespace nodes always
520 * have non-empty values in XPath)
521 */
522 if(visible && !emptyNs) {
523 xmlNs ns1;
524
525 memset(&ns1, 0, sizeof(ns1));
526 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns1, 0)) {
527 xmlC14NPrintNamespaces(&ns1, ctx);
528 }
529 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000530 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000531
532
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000533 /*
534 * print out all elements from list
535 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000536 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000537
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000538 /*
539 * Cleanup
540 */
541 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000542 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000543}
544
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000545
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000546/**
547 * xmlExcC14NProcessNamespacesAxis:
548 * @ctx: the C14N context
549 * @node: the current node
550 *
551 * Prints out exclusive canonical namespace axis of the current node to the
552 * buffer from C14N context as follows
553 *
554 * Exclusive XML Canonicalization
555 * http://www.w3.org/TR/xml-exc-c14n
556 *
557 * If the element node is in the XPath subset then output the node in
558 * accordance with Canonical XML except for namespace nodes which are
559 * rendered as follows:
560 *
561 * 1. Render each namespace node iff:
562 * * it is visibly utilized by the immediate parent element or one of
563 * its attributes, or is present in InclusiveNamespaces PrefixList, and
564 * * its prefix and value do not appear in ns_rendered. ns_rendered is
565 * obtained by popping the state stack in order to obtain a list of
566 * prefixes and their values which have already been rendered by
567 * an output ancestor of the namespace node's parent element.
568 * 2. Append the rendered namespace node to the list ns_rendered of namespace
569 * nodes rendered by output ancestors. Push ns_rendered on state stack and
570 * recurse.
571 * 3. After the recursion returns, pop thestate stack.
572 *
573 *
574 * Returns 0 on success or -1 on fail.
575 */
576static int
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000577xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
Daniel Veillard9ff88172002-03-11 09:15:32 +0000578{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000579 xmlListPtr list;
580 xmlAttrPtr attr;
581 xmlNsPtr ns;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000582 xmlNs default_ns;
583
Daniel Veillard9ff88172002-03-11 09:15:32 +0000584
585 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
586#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000587 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000588 "xmlExcC14NProcessNamespacesAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
589#endif
590 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000591 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000592
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000593 if(!ctx->exclusive) {
Daniel Veillard9ff88172002-03-11 09:15:32 +0000594#ifdef DEBUG_C14N
595 xmlGenericError(xmlGenericErrorContext,
596 "xmlExcC14NProcessNamespacesAxis: called for non-exclusive canonization or rendered stack is NULL.\n");
597#endif
598 return (-1);
599
600 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000601 memset(&default_ns, 0, sizeof(default_ns));
Daniel Veillard9ff88172002-03-11 09:15:32 +0000602
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000603 /*
604 * Create a sorted list to store element namespaces
605 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000606 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000607 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000608#ifdef DEBUG_C14N
609 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000610 "xmlExcC14NProcessNamespacesAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000611#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000612 return (-1);
613 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000614
615 /*
616 * First of all, add all namespaces required by current node
617 * (i.e. node namespace and all attribute namespaces)
Daniel Veillard54761132002-04-18 21:00:44 +0000618 * we also need to check for default "xml:" namespace
Aleksey Sanindffd5c82002-05-31 04:24:13 +0000619 * todo: shouldn't we check for namespaces "visibility"?
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000620 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000621 if(visible) {
622 ns = (cur->ns != NULL) ? cur->ns : xmlSearchNs(ctx->doc, cur, NULL);
623 if ((ns != NULL) && (!xmlC14NIsXmlNs(ns)) && (xmlListSearch(list, ns) == NULL) &&
624 xmlC14NIsNsVisible(ctx, ns, cur)) {
625 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns, 1)) {
626 xmlListInsert(list, ns);
627 }
628 if(visible) {
629 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns);
630 }
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000631 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000632 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000633
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000634 attr = cur->properties;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000635 while (attr != NULL) {
636 /*
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000637 * we need to check that attribute is visible and has non
638 * default namespace (XML Namespaces: "default namespaces
639 * do not apply directly to attributes")
Daniel Veillard9ff88172002-03-11 09:15:32 +0000640 */
Daniel Veillard2d347fa2002-03-17 10:34:11 +0000641 if ((attr->ns != NULL) && xmlC14NIsVisible(ctx, attr) &&
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000642 xmlC14NIsNsVisible(ctx, attr->ns, cur) &&
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000643 (!xmlC14NIsXmlNs(attr->ns)) && (xmlListSearch(list, attr->ns) == NULL)) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000644 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, 1)) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000645 xmlListInsert(list, attr->ns);
646 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000647 if(visible) {
648 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns);
649 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000650 }
651 attr = attr->next;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000652 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000653
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000654 /*
655 * Next add all inclusive namespaces if needed.
656 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000657 if (ctx->inclusive_ns_prefixes != NULL) {
658 int i;
659 xmlChar *prefix;
660
661 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
662 prefix = ctx->inclusive_ns_prefixes[i];
663 /*
664 * Special values for namespace with empty prefix
665 */
666 if (xmlStrEqual(prefix, BAD_CAST "#default")
667 || xmlStrEqual(prefix, BAD_CAST "")) {
668 prefix = NULL;
669 }
670 ns = xmlSearchNs(ctx->doc, cur, prefix);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000671 if((ns != NULL) && (!xmlC14NIsXmlNs(ns))) {
672 int ns_visible = xmlC14NIsNsVisible(ctx, ns, cur);
673
674 if(!ns_visible && (prefix == NULL)) {
675 ns = &default_ns;
676 ns_visible = 1;
677 }
678 if (ns_visible) {
679 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns, 1)) {
Aleksey Saninc57f9c12002-05-31 19:14:57 +0000680 xmlListInsert(list, ns);
681 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000682 if(visible) {
683 xmlC14NVisibleNsStackAdd(ctx->ns_rendered,
684 (ns == &default_ns) ? NULL : ns);
685 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000686 }
687 }
688 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000689 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000690
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000691 /*
692 * print out all elements from list
693 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000694 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000695
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000696 /*
697 * Cleanup
698 */
699 xmlListDelete(list);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000700 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000701}
702
703
704/**
705 * xmlC14NAttrsCompare:
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000706 * @attr1: the pointer tls o first attr
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000707 * @attr2: the pointer to second attr
708 *
709 * Prints the given attribute to the output buffer from C14N context.
710 *
711 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
712 */
713static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000714xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
715{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000716 int ret = 0;
717
718 /*
719 * Simple cases
720 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000721 if (attr1 == attr2)
722 return (0);
723 if (attr1 == NULL)
724 return (-1);
725 if (attr2 == NULL)
726 return (1);
727 if (attr1->ns == attr2->ns) {
728 return (xmlStrcmp(attr1->name, attr2->name));
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000729 }
730
731 /*
732 * Attributes in the default namespace are first
733 * because the default namespace is not applied to
734 * unqualified attributes
735 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000736 if (attr1->ns == NULL)
737 return (-1);
738 if (attr2->ns == NULL)
739 return (1);
740 if (attr1->ns->prefix == NULL)
741 return (-1);
742 if (attr2->ns->prefix == NULL)
743 return (1);
744
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000745 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000746 if (ret == 0) {
747 ret = xmlStrcmp(attr1->name, attr2->name);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000748 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000749 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000750}
751
752
753/**
754 * xmlC14NPrintAttrs:
755 * @attr: the pointer to attr
756 * @ctx: the C14N context
757 *
758 * Prints out canonical attribute urrent node to the
759 * buffer from C14N context as follows
760 *
761 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
762 *
763 * Returns 1 on success or 0 on fail.
764 */
765static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000766xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
767{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000768 xmlChar *value;
769 xmlChar *buffer;
770
Daniel Veillard9ff88172002-03-11 09:15:32 +0000771 if ((attr == NULL) || (ctx == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000772#ifdef DEBUG_C14N
773 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000774 "xmlC14NPrintAttrs: attr == NULL or ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000775#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000776 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000777 }
778
779 xmlOutputBufferWriteString(ctx->buf, " ");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000780 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
781 xmlOutputBufferWriteString(ctx->buf,
782 (const char *) attr->ns->prefix);
783 xmlOutputBufferWriteString(ctx->buf, ":");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000784 }
785 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
786 xmlOutputBufferWriteString(ctx->buf, "=\"");
787
788 value = xmlNodeListGetString(attr->doc, attr->children, 1);
789 /* todo: should we log an error if value==NULL ? */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000790 if (value != NULL) {
791 buffer = xmlC11NNormalizeAttr(value);
792 xmlFree(value);
793 if (buffer != NULL) {
794 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
795 xmlFree(buffer);
796 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000797#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +0000798 xmlGenericError(xmlGenericErrorContext,
799 "xmlC14NPrintAttrs: xmlC11NNormalizeAttr failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000800#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000801 return (0);
802 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000803 }
804 xmlOutputBufferWriteString(ctx->buf, "\"");
Daniel Veillard9ff88172002-03-11 09:15:32 +0000805 return (1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000806}
807
808/**
809 * xmlC14NProcessAttrsAxis:
810 * @ctx: the C14N context
811 * @cur: the current node
812 *
813 * Prints out canonical attribute axis of the current node to the
814 * buffer from C14N context as follows
815 *
816 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
817 *
818 * Attribute Axis
819 * In lexicographic order (ascending), process each node that
820 * is in the element's attribute axis and in the node-set.
821 *
822 * The processing of an element node E MUST be modified slightly
823 * when an XPath node-set is given as input and the element's
824 * parent is omitted from the node-set.
825 *
826 *
827 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
828 *
829 * Canonical XML applied to a document subset requires the search of the
830 * ancestor nodes of each orphan element node for attributes in the xml
831 * namespace, such as xml:lang and xml:space. These are copied into the
832 * element node except if a declaration of the same attribute is already
833 * in the attribute axis of the element (whether or not it is included in
834 * the document subset). This search and copying are omitted from the
835 * Exclusive XML Canonicalization method.
836 *
837 * Returns 0 on success or -1 on fail.
838 */
839static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000840xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur)
841{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000842 xmlAttrPtr attr;
843 xmlListPtr list;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000844
845 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
846#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000847 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000848 "xmlC14NProcessAttrsAxis: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
849#endif
850 return (-1);
851 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000852
853 /*
854 * Create a sorted list to store element attributes
855 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000856 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
857 if (list == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000858#ifdef DEBUG_C14N
859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000860 "xmlC14NProcessAttrsAxis: list creation failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000861#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +0000862 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000863 }
864
865 /*
866 * Add all visible attributes from current node.
867 */
868 attr = cur->properties;
Daniel Veillard9ff88172002-03-11 09:15:32 +0000869 while (attr != NULL) {
870 /* check that attribute is visible */
871 if (xmlC14NIsVisible(ctx, attr)) {
872 xmlListInsert(list, attr);
873 }
874 attr = attr->next;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000875 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000876
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000877 /*
878 * include attributes in "xml" namespace defined in ancestors
879 * (only for non-exclusive XML Canonicalization)
880 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000881 if ((!ctx->exclusive) && (cur->parent != NULL)
882 && (!xmlC14NIsVisible(ctx, cur->parent))) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000883 /*
Daniel Veillard9ff88172002-03-11 09:15:32 +0000884 * If XPath node-set is not specified then the parent is always
885 * visible!
886 */
887 cur = cur->parent;
888 while (cur != NULL) {
889 attr = cur->properties;
890 while (attr != NULL) {
891 if ((attr->ns != NULL)
892 && (xmlStrEqual(attr->ns->prefix, BAD_CAST "xml"))) {
893 if (xmlListSearch(list, attr) == NULL) {
894 xmlListInsert(list, attr);
895 }
896 }
897 attr = attr->next;
898 }
899 cur = cur->parent;
900 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000901 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000902
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000903 /*
904 * print out all elements from list
905 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000906 xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
Daniel Veillard9ff88172002-03-11 09:15:32 +0000907
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000908 /*
909 * Cleanup
910 */
Daniel Veillard9ff88172002-03-11 09:15:32 +0000911 xmlListDelete(list);
912 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000913}
914
915/**
916 * xmlC14NCheckForRelativeNamespaces:
917 * @ctx: the C14N context
918 * @cur: the current element node
919 *
920 * Checks that current element node has no relative namespaces defined
921 *
922 * Returns 0 if the node has no relative namespaces or -1 otherwise.
923 */
924static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000925xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
926{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000927 xmlNsPtr ns;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000928
Daniel Veillard9ff88172002-03-11 09:15:32 +0000929 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
930#ifdef DEBUG_C14N
931 xmlGenericError(xmlGenericErrorContext,
932 "xmlC14NCheckForRelativeNamespaces: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
933#endif
934 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000935 }
Daniel Veillard9ff88172002-03-11 09:15:32 +0000936
937 ns = cur->nsDef;
938 while (ns != NULL) {
939 if (xmlStrlen(ns->href) > 0) {
940 xmlURIPtr uri;
941
942 uri = xmlParseURI((const char *) ns->href);
943 if (uri == NULL) {
944#ifdef DEBUG_C14N
945 xmlGenericError(xmlGenericErrorContext,
946 "xmlC14NCheckForRelativeNamespaces: unable to parse uri=\"%s\".\n",
947 ns->href);
948#endif
949 return (-1);
950 }
951 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
952 xmlFreeURI(uri);
953 return (-1);
954 }
955 if ((!xmlStrEqual
956 ((const xmlChar *) uri->scheme, BAD_CAST "urn"))
957 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
958 xmlFreeURI(uri);
959 return (-1);
960 }
961 xmlFreeURI(uri);
962 }
963 ns = ns->next;
964 }
965 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000966}
967
968/**
969 * xmlC14NProcessElementNode:
970 * @ctx: the pointer to C14N context object
971 * @cur: the node to process
972 *
973 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
974 *
975 * Element Nodes
976 * If the element is not in the node-set, then the result is obtained
977 * by processing the namespace axis, then the attribute axis, then
978 * processing the child nodes of the element that are in the node-set
979 * (in document order). If the element is in the node-set, then the result
980 * is an open angle bracket (<), the element QName, the result of
981 * processing the namespace axis, the result of processing the attribute
982 * axis, a close angle bracket (>), the result of processing the child
983 * nodes of the element that are in the node-set (in document order), an
984 * open angle bracket, a forward slash (/), the element QName, and a close
985 * angle bracket.
986 *
987 * Returns non-negative value on success or negative value on fail
988 */
989static int
Daniel Veillard9ff88172002-03-11 09:15:32 +0000990xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
991{
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000992 int ret;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +0000993 xmlC14NVisibleNsStack state;
Daniel Veillard6f293b12002-03-15 09:42:33 +0000994 int parent_is_doc = 0;
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000995
Daniel Veillard9ff88172002-03-11 09:15:32 +0000996 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
997#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +0000998 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +0000999 "xmlC14NProcessElementNode: Null context or node pointer or type != XML_ELEMENT_NODE.\n");
1000#endif
1001 return (-1);
1002 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001003
1004 /*
1005 * Check relative relative namespaces:
1006 * implementations of XML canonicalization MUST report an operation
1007 * failure on documents containing relative namespace URIs.
1008 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001009 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1010#ifdef DEBUG_C14N
1011 xmlGenericError(xmlGenericErrorContext,
1012 "xmlC14NProcessElementNode: xmlC14NCheckForRelativeNamespaces failed.\n");
1013#endif
1014 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001015 }
1016
1017
1018 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001019 * Save ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001020 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001021 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001022
Daniel Veillard6f293b12002-03-15 09:42:33 +00001023 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001024 if (ctx->parent_is_doc) {
Daniel Veillard6f293b12002-03-15 09:42:33 +00001025 /* save this flag into the stack */
1026 parent_is_doc = ctx->parent_is_doc;
1027 ctx->parent_is_doc = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001028 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1029 }
1030 xmlOutputBufferWriteString(ctx->buf, "<");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001031
Daniel Veillard9ff88172002-03-11 09:15:32 +00001032 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1033 xmlOutputBufferWriteString(ctx->buf,
1034 (const char *) cur->ns->prefix);
1035 xmlOutputBufferWriteString(ctx->buf, ":");
1036 }
1037 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001038 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001039
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001040 if (!ctx->exclusive) {
1041 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1042 } else {
1043 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1044 }
1045 if (ret < 0) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001046#ifdef DEBUG_C14N
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001047 xmlGenericError(xmlGenericErrorContext,
1048 "xmlC14NProcessElementNode: xmlC14NProcessNamespacesAxis failed.\n");
Daniel Veillard9ff88172002-03-11 09:15:32 +00001049#endif
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001050 return (-1);
1051 }
1052 /* todo: shouldn't this go to "visible only"? */
1053 if(visible) {
1054 xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1055 }
1056
1057 if(visible) {
1058 ret = xmlC14NProcessAttrsAxis(ctx, cur);
1059 if (ret < 0) {
1060#ifdef DEBUG_C14N
1061 xmlGenericError(xmlGenericErrorContext,
1062 "xmlC14NProcessElementNode: xmlC14NProcessAttrsAxis failed.\n");
1063#endif
1064 return (-1);
Aleksey Saninc57f9c12002-05-31 19:14:57 +00001065 }
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001066 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001067
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001068 if (visible) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001069 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001070 }
1071 if (cur->children != NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001072 ret = xmlC14NProcessNodeList(ctx, cur->children);
1073 if (ret < 0) {
1074#ifdef DEBUG_C14N
1075 xmlGenericError(xmlGenericErrorContext,
1076 "xmlC14NProcessElementNode: xmlC14NProcessNodeList failed.\n");
1077#endif
1078 return (-1);
1079 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001080 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001081 if (visible) {
1082 xmlOutputBufferWriteString(ctx->buf, "</");
1083 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);
1089 xmlOutputBufferWriteString(ctx->buf, ">");
Daniel Veillard6f293b12002-03-15 09:42:33 +00001090 if (parent_is_doc) {
1091 /* restore this flag from the stack for next node */
1092 ctx->parent_is_doc = parent_is_doc;
1093 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001094 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001095 }
1096
1097 /*
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001098 * Restore ns_rendered stack position
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001099 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001100 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001101 return (0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001102}
1103
1104/**
1105 * xmlC14NProcessNode:
1106 * @ctx: the pointer to C14N context object
1107 * @cur: the node to process
1108 *
1109 * Processes the given node
1110 *
1111 * Returns non-negative value on success or negative value on fail
1112 */
1113static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001114xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1115{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001116 int ret = 0;
1117 int visible;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001118
1119 if ((ctx == NULL) || (cur == NULL)) {
1120#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001121 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001122 "xmlC14NProcessNode: Null context or node pointer.\n");
1123#endif
1124 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001125 }
1126
1127 visible = xmlC14NIsVisible(ctx, cur);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001128 switch (cur->type) {
1129 case XML_ELEMENT_NODE:
1130 ret = xmlC14NProcessElementNode(ctx, cur, visible);
1131 break;
1132 case XML_CDATA_SECTION_NODE:
1133 case XML_TEXT_NODE:
1134 /*
1135 * Text Nodes
1136 * the string value, except all ampersands are replaced
1137 * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1138 * angle brackets (>) are replaced by &gt;, and all #xD characters are
1139 * replaced by &#xD;.
1140 */
1141 /* cdata sections are processed as text nodes */
1142 /* todo: verify that cdata sections are included in XPath nodes set */
1143 if ((visible) && (cur->content != NULL)) {
1144 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001145
Daniel Veillard9ff88172002-03-11 09:15:32 +00001146 buffer = xmlC11NNormalizeText(cur->content);
1147 if (buffer != NULL) {
1148 xmlOutputBufferWriteString(ctx->buf,
1149 (const char *) buffer);
1150 xmlFree(buffer);
1151 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001152#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001153 xmlGenericError(xmlGenericErrorContext,
1154 "xmlC14NProcessNode: xmlC11NNormalizeText() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001155#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001156 return (-1);
1157 }
1158 }
1159 break;
1160 case XML_PI_NODE:
1161 /*
1162 * Processing Instruction (PI) Nodes-
1163 * The opening PI symbol (<?), the PI target name of the node,
1164 * a leading space and the string value if it is not empty, and
1165 * the closing PI symbol (?>). If the string value is empty,
1166 * then the leading space is not added. Also, a trailing #xA is
1167 * rendered after the closing PI symbol for PI children of the
1168 * root node with a lesser document order than the document
1169 * element, and a leading #xA is rendered before the opening PI
1170 * symbol of PI children of the root node with a greater document
1171 * order than the document element.
1172 */
1173 if (visible) {
1174 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1175 xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1176 } else {
1177 xmlOutputBufferWriteString(ctx->buf, "<?");
1178 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001179
Daniel Veillard9ff88172002-03-11 09:15:32 +00001180 xmlOutputBufferWriteString(ctx->buf,
1181 (const char *) cur->name);
1182 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1183 xmlChar *buffer;
1184
1185 xmlOutputBufferWriteString(ctx->buf, " ");
1186
1187 /* todo: do we need to normalize pi? */
1188 buffer = xmlC11NNormalizePI(cur->content);
1189 if (buffer != NULL) {
1190 xmlOutputBufferWriteString(ctx->buf,
1191 (const char *) buffer);
1192 xmlFree(buffer);
1193 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001194#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001195 xmlGenericError(xmlGenericErrorContext,
1196 "xmlC14NProcessNode: xmlC11NNormalizePI() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001197#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001198 return (-1);
1199 }
1200 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001201
Daniel Veillard9ff88172002-03-11 09:15:32 +00001202 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1203 xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1204 } else {
1205 xmlOutputBufferWriteString(ctx->buf, "?>");
1206 }
1207 }
1208 break;
1209 case XML_COMMENT_NODE:
1210 /*
1211 * Comment Nodes
1212 * Nothing if generating canonical XML without comments. For
1213 * canonical XML with comments, generate the opening comment
1214 * symbol (<!--), the string value of the node, and the
1215 * closing comment symbol (-->). Also, a trailing #xA is rendered
1216 * after the closing comment symbol for comment children of the
1217 * root node with a lesser document order than the document
1218 * element, and a leading #xA is rendered before the opening
1219 * comment symbol of comment children of the root node with a
1220 * greater document order than the document element. (Comment
1221 * children of the root node represent comments outside of the
1222 * top-level document element and outside of the document type
1223 * declaration).
1224 */
1225 if (visible && ctx->with_comments) {
1226 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1227 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1228 } else {
1229 xmlOutputBufferWriteString(ctx->buf, "<!--");
1230 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001231
Daniel Veillard9ff88172002-03-11 09:15:32 +00001232 if (cur->content != NULL) {
1233 xmlChar *buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001234
Daniel Veillard9ff88172002-03-11 09:15:32 +00001235 /* todo: do we need to normalize comment? */
1236 buffer = xmlC11NNormalizeComment(cur->content);
1237 if (buffer != NULL) {
1238 xmlOutputBufferWriteString(ctx->buf,
1239 (const char *) buffer);
1240 xmlFree(buffer);
1241 } else {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001242#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001243 xmlGenericError(xmlGenericErrorContext,
1244 "xmlC14NProcessNode: xmlC11NNormalizeComment() failed\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001245#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001246 return (-1);
1247 }
1248 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001249
Daniel Veillard9ff88172002-03-11 09:15:32 +00001250 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1251 xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1252 } else {
1253 xmlOutputBufferWriteString(ctx->buf, "-->");
1254 }
1255 }
1256 break;
1257 case XML_DOCUMENT_NODE:
1258 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001259#ifdef LIBXML_DOCB_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001260 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001261#endif
1262#ifdef LIBXML_HTML_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001263 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
Daniel Veillard1840ef02002-03-21 08:05:23 +00001264#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001265 if (cur->children != NULL) {
1266 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1267 ctx->parent_is_doc = 1;
1268 ret = xmlC14NProcessNodeList(ctx, cur->children);
1269 }
1270 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001271
Daniel Veillard9ff88172002-03-11 09:15:32 +00001272 case XML_ATTRIBUTE_NODE:
1273 xmlGenericError(xmlGenericErrorContext,
1274 "xmlC14NProcessNode: XML_ATTRIBUTE_NODE is illegal here\n");
1275 return (-1);
1276 case XML_NAMESPACE_DECL:
1277 xmlGenericError(xmlGenericErrorContext,
1278 "xmlC14NProcessNode: XML_NAMESPACE_DECL is illegal here\n");
1279 return (-1);
1280 case XML_ENTITY_REF_NODE:
1281 xmlGenericError(xmlGenericErrorContext,
1282 "xmlC14NProcessNode: XML_ENTITY_REF_NODE is illegal here\n");
1283 return (-1);
1284 case XML_ENTITY_NODE:
1285 xmlGenericError(xmlGenericErrorContext,
1286 "xmlC14NProcessNode: XML_ENTITY_NODE is illegal here\n");
1287 return (-1);
1288
1289 case XML_DOCUMENT_TYPE_NODE:
1290 case XML_NOTATION_NODE:
1291 case XML_DTD_NODE:
1292 case XML_ELEMENT_DECL:
1293 case XML_ATTRIBUTE_DECL:
1294 case XML_ENTITY_DECL:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001295#ifdef LIBXML_XINCLUDE_ENABLED
Daniel Veillard9ff88172002-03-11 09:15:32 +00001296 case XML_XINCLUDE_START:
1297 case XML_XINCLUDE_END:
Daniel Veillard1840ef02002-03-21 08:05:23 +00001298#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001299 /*
1300 * should be ignored according to "W3C Canonical XML"
1301 */
1302 break;
1303 default:
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001304#ifdef DEBUG_C14N
Daniel Veillard9ff88172002-03-11 09:15:32 +00001305 xmlGenericError(xmlGenericErrorContext,
1306 "xmlC14NProcessNode: unknown node type = %d\n",
1307 cur->type);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001308#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001309 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001310 }
1311
Daniel Veillard9ff88172002-03-11 09:15:32 +00001312 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001313}
1314
1315/**
1316 * xmlC14NProcessNodeList:
1317 * @ctx: the pointer to C14N context object
1318 * @cur: the node to start from
1319 *
1320 * Processes all nodes in the row starting from cur.
1321 *
1322 * Returns non-negative value on success or negative value on fail
1323 */
1324static int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001325xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1326{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001327 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001328
1329 if (ctx == NULL) {
1330#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001331 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001332 "xmlC14NProcessNodeList: Null context pointer.\n");
1333#endif
1334 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001335 }
1336
Daniel Veillard9ff88172002-03-11 09:15:32 +00001337 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1338 ret = xmlC14NProcessNode(ctx, cur);
1339 }
1340 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001341}
1342
1343
1344/**
1345 * xmlC14NFreeCtx:
1346 * @ctx: the pointer to C14N context object
1347 *
1348 * Cleanups the C14N context object.
1349 */
1350
1351static void
Daniel Veillard9ff88172002-03-11 09:15:32 +00001352xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1353{
1354 if (ctx == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001355#ifdef DEBUG_C14N
1356 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001357 "xmlC14NFreeCtx: ctx == NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001358#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001359 return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001360 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001361
1362 if (ctx->ns_rendered != NULL) {
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001363 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001364 }
1365 xmlFree(ctx);
1366}
1367
1368/**
1369 * xmlC14NNewCtx:
1370 * @doc: the XML document for canonization
1371 * @nodes: the nodes set to be included in the canonized image
1372 * or NULL if all document nodes should be included
1373 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1374 * otherwise - exclusive canonicalization)
1375 * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1376 * ended with a NULL or NULL if there is no
1377 * inclusive namespaces (only for exclusive
1378 * canonicalization)
1379 * @with_comments: include comments in the result (!=0) or not (==0)
1380 * @buf: the output buffer to store canonical XML; this
1381 * buffer MUST have encoder==NULL because C14N requires
1382 * UTF-8 output
1383 *
1384 * Creates new C14N context object to store C14N parameters.
1385 *
1386 * Returns pointer to newly created object (success) or NULL (fail)
1387 */
1388static xmlC14NCtxPtr
Daniel Veillard9ff88172002-03-11 09:15:32 +00001389xmlC14NNewCtx(xmlDocPtr doc, xmlNodeSetPtr nodes,
1390 int exclusive, xmlChar ** inclusive_ns_prefixes,
1391 int with_comments, xmlOutputBufferPtr buf)
1392{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001393 xmlC14NCtxPtr ctx;
1394
Daniel Veillard9ff88172002-03-11 09:15:32 +00001395 if ((doc == NULL) || (buf == NULL)) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001396#ifdef DEBUG_C14N
1397 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001398 "xmlC14NNewCtx: pointer to document or output buffer is NULL\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001399#endif
Daniel Veillard9ff88172002-03-11 09:15:32 +00001400 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001401 }
1402
1403 /*
1404 * Validate the encoding output buffer encoding
1405 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001406 if (buf->encoder != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001408 "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
1409 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001410 }
1411
1412 /*
1413 * Validate the XML document encoding value, if provided.
1414 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001415 if (doc->charset != XML_CHAR_ENCODING_UTF8) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001416 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001417 "xmlC14NNewCtx: source document not in UTF8\n");
1418 return (NULL);
1419 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001420
1421 /*
1422 * Allocate a new xmlC14NCtxPtr and fill the fields.
1423 */
1424 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1425 if (ctx == NULL) {
1426 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001427 "xmlC14NNewCtx: malloc failed\n");
1428 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001429 }
1430 memset(ctx, 0, sizeof(xmlC14NCtx));
1431
1432 /*
1433 * initialize C14N context
Daniel Veillard9ff88172002-03-11 09:15:32 +00001434 */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001435 ctx->doc = doc;
1436 ctx->with_comments = with_comments;
1437 ctx->visible_nodes = nodes;
1438 ctx->buf = buf;
1439 ctx->parent_is_doc = 1;
1440 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001441 ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1442
1443 if(ctx->ns_rendered == NULL) {
1444 xmlGenericError(xmlGenericErrorContext,
1445 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
1446 xmlC14NFreeCtx(ctx);
1447 return (NULL);
1448 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001449
1450 /*
1451 * Set "exclusive" flag, create a nodes set for namespaces
1452 * stack and remember list of incluseve prefixes
1453 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001454 if (exclusive) {
1455 ctx->exclusive = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001456 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1457 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001458 return (ctx);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001459}
1460
1461/**
1462 * xmlC14NDocSaveTo:
1463 * @doc: the XML document for canonization
1464 * @nodes: the nodes set to be included in the canonized image
1465 * or NULL if all document nodes should be included
1466 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1467 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001468 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001469 * ended with a NULL or NULL if there is no
1470 * inclusive namespaces (only for exclusive
1471 * canonicalization, ignored otherwise)
1472 * @with_comments: include comments in the result (!=0) or not (==0)
1473 * @buf: the output buffer to store canonical XML; this
1474 * buffer MUST have encoder==NULL because C14N requires
1475 * UTF-8 output
1476 *
1477 * Dumps the canonized image of given XML document into the provided buffer.
1478 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1479 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1480 *
1481 * Returns non-negative value on success or a negative value on fail
1482 */
1483int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001484xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1485 int exclusive, xmlChar ** inclusive_ns_prefixes,
1486 int with_comments, xmlOutputBufferPtr buf)
1487{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001488 xmlC14NCtxPtr ctx;
1489 int ret;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001490
1491 if ((buf == NULL) || (doc == NULL)) {
1492#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001493 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001494 "xmlC14NDocSaveTo: null return buffer or doc pointer\n");
1495#endif
1496 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001497 }
1498
1499 /*
1500 * Validate the encoding output buffer encoding
1501 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001502 if (buf->encoder != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001503 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001504 "xmlC14NDocSaveTo: output buffer encoder != NULL but C14N requires UTF8 output\n");
1505 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001506 }
1507
1508 ctx = xmlC14NNewCtx(doc, nodes, exclusive, inclusive_ns_prefixes,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001509 with_comments, buf);
1510 if (ctx == NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001511 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001512 "xmlC14NDocSaveTo: unable to create C14N context\n");
1513 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001514 }
1515
1516
1517
1518 /*
1519 * Root Node
1520 * The root node is the parent of the top-level document element. The
1521 * result of processing each of its child nodes that is in the node-set
1522 * in document order. The root node does not generate a byte order mark,
1523 * XML declaration, nor anything from within the document type
1524 * declaration.
1525 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001526 if (doc->children != NULL) {
1527 ret = xmlC14NProcessNodeList(ctx, doc->children);
1528 if (ret < 0) {
1529#ifdef DEBUG_C14N
1530 xmlGenericError(xmlGenericErrorContext,
1531 "xmlC14NDocSaveTo: process childrens' list failed.\n");
1532#endif
1533 xmlC14NFreeCtx(ctx);
1534 return (-1);
1535 }
1536 }
1537
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001538 /*
1539 * Flush buffer to get number of bytes written
1540 */
1541 ret = xmlOutputBufferFlush(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001542 if (ret < 0) {
1543#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001544 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001545 "xmlC14NDocSaveTo: buffer flush failed.\n");
1546#endif
1547 xmlC14NFreeCtx(ctx);
1548 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001549 }
1550
1551 /*
1552 * Cleanup
1553 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001554 xmlC14NFreeCtx(ctx);
1555 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001556}
1557
1558/**
1559 * xmlC14NDocDumpMemory:
1560 * @doc: the XML document for canonization
1561 * @nodes: the nodes set to be included in the canonized image
1562 * or NULL if all document nodes should be included
1563 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1564 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001565 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001566 * ended with a NULL or NULL if there is no
1567 * inclusive namespaces (only for exclusive
1568 * canonicalization, ignored otherwise)
1569 * @with_comments: include comments in the result (!=0) or not (==0)
1570 * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
1571 * the caller of this functions is responsible for calling
1572 * xmlFree() to free allocated memory
1573 *
1574 * Dumps the canonized image of given XML document into memory.
1575 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1576 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1577 *
1578 * Returns the number of bytes written on success or a negative value on fail
1579 */
1580int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001581xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
1582 int exclusive, xmlChar ** inclusive_ns_prefixes,
1583 int with_comments, xmlChar ** doc_txt_ptr)
1584{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001585 int ret;
1586 xmlOutputBufferPtr buf;
1587
1588 if (doc_txt_ptr == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001589#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001590 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001591 "xmlC14NDocDumpMemory: null return buffer pointer\n");
1592#endif
1593 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001594 }
1595
1596 *doc_txt_ptr = NULL;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001597
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001598 /*
1599 * create memory buffer with UTF8 (default) encoding
1600 */
1601 buf = xmlAllocOutputBuffer(NULL);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001602 if (buf == NULL) {
1603#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001604 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001605 "xmlC14NDocDumpMemory: failed to allocate output buffer.\n");
1606#endif
1607 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001608 }
1609
1610 /*
1611 * canonize document and write to buffer
1612 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001613 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1614 with_comments, buf);
1615 if (ret < 0) {
1616#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001617 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001618 "xmlC14NDocDumpMemory: xmlC14NDocSaveTo failed.\n");
1619#endif
1620 (void) xmlOutputBufferClose(buf);
1621 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001622 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001623
Daniel Veillard9ff88172002-03-11 09:15:32 +00001624 ret = buf->buffer->use;
1625 if (ret > 0) {
1626 *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
1627 }
1628 (void) xmlOutputBufferClose(buf);
1629
1630 if ((*doc_txt_ptr == NULL) && (ret > 0)) {
1631#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001632 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001633 "xmlC14NDocDumpMemory: failed to allocate memory for document text representation\n");
1634#endif
1635 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001636 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001637 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001638}
1639
1640/**
1641 * xmlC14NDocSave:
1642 * @doc: the XML document for canonization
1643 * @nodes: the nodes set to be included in the canonized image
1644 * or NULL if all document nodes should be included
1645 * @exclusive: the exclusive flag (0 - non-exclusive canonicalization;
1646 * otherwise - exclusive canonicalization)
Daniel Veillarddb1bdba2002-03-09 14:13:11 +00001647 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001648 * ended with a NULL or NULL if there is no
1649 * inclusive namespaces (only for exclusive
1650 * canonicalization, ignored otherwise)
1651 * @with_comments: include comments in the result (!=0) or not (==0)
1652 * @filename: the filename to store canonical XML image
1653 * @compression: the compression level (zlib requred):
1654 * -1 - libxml default,
1655 * 0 - uncompressed,
1656 * >0 - compression level
1657 *
1658 * Dumps the canonized image of given XML document into the file.
1659 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1660 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1661 *
1662 * Returns the number of bytes written success or a negative value on fail
1663 */
1664int
Daniel Veillard9ff88172002-03-11 09:15:32 +00001665xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
1666 int exclusive, xmlChar ** inclusive_ns_prefixes,
1667 int with_comments, const char *filename, int compression)
1668{
1669 xmlOutputBufferPtr buf;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001670 int ret;
1671
Daniel Veillard9ff88172002-03-11 09:15:32 +00001672 if (filename == NULL) {
1673#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001674 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001675 "xmlC14NDocSave: filename is NULL\n");
1676#endif
1677 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001678 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001679#ifdef HAVE_ZLIB_H
Daniel Veillard9ff88172002-03-11 09:15:32 +00001680 if (compression < 0)
1681 compression = xmlGetCompressMode();
1682#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001683
1684 /*
1685 * save the content to a temp buffer, use default UTF8 encoding.
1686 */
1687 buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
1688 if (buf == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001689#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001690 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001691 "xmlC14NDocSave: unable to create buffer for file=\"%s\" with compressin=%d\n",
1692 filename, compression);
1693#endif
1694 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001695 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001696
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001697 /*
1698 * canonize document and write to buffer
1699 */
Daniel Veillard9ff88172002-03-11 09:15:32 +00001700 ret = xmlC14NDocSaveTo(doc, nodes, exclusive, inclusive_ns_prefixes,
1701 with_comments, buf);
1702 if (ret < 0) {
1703#ifdef DEBUG_C14N
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001704 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard9ff88172002-03-11 09:15:32 +00001705 "xmlC14NDocSave: xmlC14NDocSaveTo failed.\n");
1706#endif
1707 (void) xmlOutputBufferClose(buf);
1708 return (-1);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 }
Daniel Veillard9ff88172002-03-11 09:15:32 +00001710
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001711 /*
1712 * get the numbers of bytes written
1713 */
1714 ret = xmlOutputBufferClose(buf);
Daniel Veillard9ff88172002-03-11 09:15:32 +00001715 return (ret);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001716}
1717
1718
1719
1720/*
1721 * Macro used to grow the current buffer.
1722 */
1723#define growBufferReentrant() { \
1724 buffer_size *= 2; \
1725 buffer = (xmlChar *) \
1726 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
1727 if (buffer == NULL) { \
1728 perror("realloc failed"); \
1729 return(NULL); \
1730 } \
1731}
1732
1733/**
1734 * xmlC11NNormalizeString:
1735 * @input: the input string
1736 * @mode: the normalization mode (attribute, comment, PI or text)
1737 *
1738 * Converts a string to a canonical (normalized) format. The code is stolen
1739 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
1740 * and the @mode parameter
1741 *
1742 * Returns a normalized string (caller is responsible for calling xmlFree())
1743 * or NULL if an error occurs
1744 */
1745static xmlChar *
Daniel Veillard9ff88172002-03-11 09:15:32 +00001746xmlC11NNormalizeString(const xmlChar * input,
1747 xmlC14NNormalizationMode mode)
1748{
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001749 const xmlChar *cur = input;
1750 xmlChar *buffer = NULL;
1751 xmlChar *out = NULL;
1752 int buffer_size = 0;
1753
Daniel Veillard9ff88172002-03-11 09:15:32 +00001754 if (input == NULL)
1755 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001756
1757 /*
1758 * allocate an translation buffer.
1759 */
1760 buffer_size = 1000;
1761 buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
1762 if (buffer == NULL) {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001763 perror("malloc failed");
1764 return (NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001765 }
1766 out = buffer;
1767
1768 while (*cur != '\0') {
Daniel Veillard9ff88172002-03-11 09:15:32 +00001769 if ((out - buffer) > (buffer_size - 10)) {
1770 int indx = out - buffer;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771
Daniel Veillard9ff88172002-03-11 09:15:32 +00001772 growBufferReentrant();
1773 out = &buffer[indx];
1774 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775
Daniel Veillard9ff88172002-03-11 09:15:32 +00001776 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1777 (mode == XMLC14N_NORMALIZE_TEXT))) {
1778 *out++ = '&';
1779 *out++ = 'l';
1780 *out++ = 't';
1781 *out++ = ';';
1782 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
1783 *out++ = '&';
1784 *out++ = 'g';
1785 *out++ = 't';
1786 *out++ = ';';
1787 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1788 (mode == XMLC14N_NORMALIZE_TEXT))) {
1789 *out++ = '&';
1790 *out++ = 'a';
1791 *out++ = 'm';
1792 *out++ = 'p';
1793 *out++ = ';';
1794 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1795 *out++ = '&';
1796 *out++ = 'q';
1797 *out++ = 'u';
1798 *out++ = 'o';
1799 *out++ = 't';
1800 *out++ = ';';
1801 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1802 *out++ = '&';
1803 *out++ = '#';
1804 *out++ = 'x';
1805 *out++ = '9';
1806 *out++ = ';';
1807 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
1808 *out++ = '&';
1809 *out++ = '#';
1810 *out++ = 'x';
1811 *out++ = 'A';
1812 *out++ = ';';
1813 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
1814 (mode == XMLC14N_NORMALIZE_TEXT) ||
1815 (mode == XMLC14N_NORMALIZE_COMMENT) ||
1816 (mode == XMLC14N_NORMALIZE_PI))) {
1817 *out++ = '&';
1818 *out++ = '#';
1819 *out++ = 'x';
1820 *out++ = 'D';
1821 *out++ = ';';
1822 } else {
1823 /*
1824 * Works because on UTF-8, all extended sequences cannot
1825 * result in bytes in the ASCII range.
1826 */
1827 *out++ = *cur;
1828 }
1829 cur++;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001830 }
1831 *out++ = 0;
Daniel Veillard9ff88172002-03-11 09:15:32 +00001832 return (buffer);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001833}
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001834#endif /* LIBXML_C14N_ENABLED */