Annotation of embedaddon/libxml2/c14n.c, revision 1.1.1.1
1.1 misho 1: /*
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: */
12: #define IN_LIBXML
13: #include "libxml.h"
14: #ifdef LIBXML_C14N_ENABLED
15: #ifdef LIBXML_OUTPUT_ENABLED
16:
17: #ifdef HAVE_STDLIB_H
18: #include <stdlib.h>
19: #endif
20: #include <string.h>
21:
22: #include <libxml/tree.h>
23: #include <libxml/parser.h>
24: #include <libxml/uri.h>
25: #include <libxml/xmlerror.h>
26: #include <libxml/globals.h>
27: #include <libxml/xpathInternals.h>
28: #include <libxml/c14n.h>
29:
30: /************************************************************************
31: * *
32: * Some declaration better left private ATM *
33: * *
34: ************************************************************************/
35:
36: typedef enum {
37: XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
38: XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
39: XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
40: } xmlC14NPosition;
41:
42: typedef struct _xmlC14NVisibleNsStack {
43: int nsCurEnd; /* number of nodes in the set */
44: int nsPrevStart; /* the begginning of the stack for previous visible node */
45: int nsPrevEnd; /* the end of the stack for previous visible node */
46: int nsMax; /* size of the array as allocated */
47: xmlNsPtr *nsTab; /* array of ns in no particular order */
48: xmlNodePtr *nodeTab; /* array of nodes in no particular order */
49: } xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
50:
51: typedef struct _xmlC14NCtx {
52: /* input parameters */
53: xmlDocPtr doc;
54: xmlC14NIsVisibleCallback is_visible_callback;
55: void* user_data;
56: int with_comments;
57: xmlOutputBufferPtr buf;
58:
59: /* position in the XML document */
60: xmlC14NPosition pos;
61: int parent_is_doc;
62: xmlC14NVisibleNsStackPtr ns_rendered;
63:
64: /* C14N mode */
65: xmlC14NMode mode;
66:
67: /* exclusive canonicalization */
68: xmlChar **inclusive_ns_prefixes;
69:
70: /* error number */
71: int error;
72: } xmlC14NCtx, *xmlC14NCtxPtr;
73:
74: static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
75: static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur);
76: static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur,
77: xmlNsPtr ns,
78: xmlNodePtr node);
79: static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur,
80: xmlC14NVisibleNsStackPtr state);
81: static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur,
82: xmlC14NVisibleNsStackPtr state);
83: static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur);
84: static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
85: xmlNsPtr ns);
86: static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur,
87: xmlNsPtr ns,
88: xmlC14NCtxPtr ctx);
89:
90: static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes,
91: xmlNodePtr node,
92: xmlNodePtr parent);
93:
94:
95:
96: static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
97: static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
98: typedef enum {
99: XMLC14N_NORMALIZE_ATTR = 0,
100: XMLC14N_NORMALIZE_COMMENT = 1,
101: XMLC14N_NORMALIZE_PI = 2,
102: XMLC14N_NORMALIZE_TEXT = 3
103: } xmlC14NNormalizationMode;
104:
105: static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
106: xmlC14NNormalizationMode mode);
107:
108: #define xmlC11NNormalizeAttr( a ) \
109: xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
110: #define xmlC11NNormalizeComment( a ) \
111: xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
112: #define xmlC11NNormalizePI( a ) \
113: xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
114: #define xmlC11NNormalizeText( a ) \
115: xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
116:
117: #define xmlC14NIsVisible( ctx, node, parent ) \
118: (((ctx)->is_visible_callback != NULL) ? \
119: (ctx)->is_visible_callback((ctx)->user_data, \
120: (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
121:
122: #define xmlC14NIsExclusive( ctx ) \
123: ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 )
124:
125: /************************************************************************
126: * *
127: * Some factorized error routines *
128: * *
129: ************************************************************************/
130:
131: /**
132: * xmlC14NErrMemory:
133: * @extra: extra informations
134: *
135: * Handle a redefinition of memory error
136: */
137: static void
138: xmlC14NErrMemory(const char *extra)
139: {
140: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
141: XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
142: NULL, NULL, 0, 0,
143: "Memory allocation failed : %s\n", extra);
144: }
145:
146: /**
147: * xmlC14NErrParam:
148: * @extra: extra informations
149: *
150: * Handle a redefinition of param error
151: */
152: static void
153: xmlC14NErrParam(const char *extra)
154: {
155: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
156: XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
157: NULL, NULL, 0, 0,
158: "Invalid parameter : %s\n", extra);
159: }
160:
161: /**
162: * xmlC14NErrInternal:
163: * @extra: extra informations
164: *
165: * Handle a redefinition of internal error
166: */
167: static void
168: xmlC14NErrInternal(const char *extra)
169: {
170: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
171: XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
172: NULL, NULL, 0, 0,
173: "Internal error : %s\n", extra);
174: }
175:
176: /**
177: * xmlC14NErrInvalidNode:
178: * @extra: extra informations
179: *
180: * Handle a redefinition of invalid node error
181: */
182: static void
183: xmlC14NErrInvalidNode(const char *node_type, const char *extra)
184: {
185: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
186: XML_C14N_INVALID_NODE, XML_ERR_ERROR, NULL, 0, extra,
187: NULL, NULL, 0, 0,
188: "Node %s is invalid here : %s\n", node_type, extra);
189: }
190:
191: /**
192: * xmlC14NErrUnknownNode:
193: * @extra: extra informations
194: *
195: * Handle a redefinition of unknown node error
196: */
197: static void
198: xmlC14NErrUnknownNode(int node_type, const char *extra)
199: {
200: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
201: XML_C14N_UNKNOW_NODE, XML_ERR_ERROR, NULL, 0, extra,
202: NULL, NULL, 0, 0,
203: "Unknown node type %d found : %s\n", node_type, extra);
204: }
205:
206: /**
207: * xmlC14NErrRelativeNamespace:
208: * @extra: extra informations
209: *
210: * Handle a redefinition of relative namespace error
211: */
212: static void
213: xmlC14NErrRelativeNamespace(const char *ns_uri)
214: {
215: __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
216: XML_C14N_RELATIVE_NAMESPACE, XML_ERR_ERROR, NULL, 0, NULL,
217: NULL, NULL, 0, 0,
218: "Relative namespace UR is invalid here : %s\n", ns_uri);
219: }
220:
221:
222:
223: /**
224: * xmlC14NErr:
225: * @ctxt: a C14N evaluation context
226: * @node: the context node
227: * @error: the erorr code
228: * @msg: the message
229: * @extra: extra informations
230: *
231: * Handle a redefinition of attribute error
232: */
233: static void
234: xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error,
235: const char * msg)
236: {
237: if (ctxt != NULL)
238: ctxt->error = error;
239: __xmlRaiseError(NULL, NULL, NULL,
240: ctxt, node, XML_FROM_C14N, error,
241: XML_ERR_ERROR, NULL, 0,
242: NULL, NULL, NULL, 0, 0, "%s", msg);
243: }
244:
245: /************************************************************************
246: * *
247: * The implementation internals *
248: * *
249: ************************************************************************/
250: #define XML_NAMESPACES_DEFAULT 16
251:
252: static int
253: xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
254: if((nodes != NULL) && (node != NULL)) {
255: if(node->type != XML_NAMESPACE_DECL) {
256: return(xmlXPathNodeSetContains(nodes, node));
257: } else {
258: xmlNs ns;
259:
260: memcpy(&ns, node, sizeof(ns));
261:
262: /* this is a libxml hack! check xpath.c for details */
263: if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) {
264: ns.next = (xmlNsPtr)parent->parent;
265: } else {
266: ns.next = (xmlNsPtr)parent;
267: }
268:
269: /*
270: * If the input is an XPath node-set, then the node-set must explicitly
271: * contain every node to be rendered to the canonical form.
272: */
273: return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
274: }
275: }
276: return(1);
277: }
278:
279: static xmlC14NVisibleNsStackPtr
280: xmlC14NVisibleNsStackCreate(void) {
281: xmlC14NVisibleNsStackPtr ret;
282:
283: ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
284: if (ret == NULL) {
285: xmlC14NErrMemory("creating namespaces stack");
286: return(NULL);
287: }
288: memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
289: return(ret);
290: }
291:
292: static void
293: xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
294: if(cur == NULL) {
295: xmlC14NErrParam("destroying namespaces stack");
296: return;
297: }
298: if(cur->nsTab != NULL) {
299: memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
300: xmlFree(cur->nsTab);
301: }
302: if(cur->nodeTab != NULL) {
303: memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
304: xmlFree(cur->nodeTab);
305: }
306: memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
307: xmlFree(cur);
308:
309: }
310:
311: static void
312: xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
313: if((cur == NULL) ||
314: ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
315: ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
316: xmlC14NErrParam("adding namespace to stack");
317: return;
318: }
319:
320: if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
321: cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
322: cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
323: if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
324: xmlC14NErrMemory("adding node to stack");
325: return;
326: }
327: memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
328: memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
329: cur->nsMax = XML_NAMESPACES_DEFAULT;
330: } else if(cur->nsMax == cur->nsCurEnd) {
331: void *tmp;
332: int tmpSize;
333:
334: tmpSize = 2 * cur->nsMax;
335: tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
336: if (tmp == NULL) {
337: xmlC14NErrMemory("adding node to stack");
338: return;
339: }
340: cur->nsTab = (xmlNsPtr*)tmp;
341:
342: tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
343: if (tmp == NULL) {
344: xmlC14NErrMemory("adding node to stack");
345: return;
346: }
347: cur->nodeTab = (xmlNodePtr*)tmp;
348:
349: cur->nsMax = tmpSize;
350: }
351: cur->nsTab[cur->nsCurEnd] = ns;
352: cur->nodeTab[cur->nsCurEnd] = node;
353:
354: ++cur->nsCurEnd;
355: }
356:
357: static void
358: xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
359: if((cur == NULL) || (state == NULL)) {
360: xmlC14NErrParam("saving namespaces stack");
361: return;
362: }
363:
364: state->nsCurEnd = cur->nsCurEnd;
365: state->nsPrevStart = cur->nsPrevStart;
366: state->nsPrevEnd = cur->nsPrevEnd;
367: }
368:
369: static void
370: xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
371: if((cur == NULL) || (state == NULL)) {
372: xmlC14NErrParam("restoring namespaces stack");
373: return;
374: }
375: cur->nsCurEnd = state->nsCurEnd;
376: cur->nsPrevStart = state->nsPrevStart;
377: cur->nsPrevEnd = state->nsPrevEnd;
378: }
379:
380: static void
381: xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
382: if(cur == NULL) {
383: xmlC14NErrParam("shifting namespaces stack");
384: return;
385: }
386: cur->nsPrevStart = cur->nsPrevEnd;
387: cur->nsPrevEnd = cur->nsCurEnd;
388: }
389:
390: static int
391: xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
392: if (str1 == str2) return(1);
393: if (str1 == NULL) return((*str2) == '\0');
394: if (str2 == NULL) return((*str1) == '\0');
395: do {
396: if (*str1++ != *str2) return(0);
397: } while (*str2++);
398: return(1);
399: }
400:
401: /**
402: * xmlC14NVisibleNsStackFind:
403: * @ctx: the C14N context
404: * @ns: the namespace to check
405: *
406: * Checks whether the given namespace was already rendered or not
407: *
408: * Returns 1 if we already wrote this namespace or 0 otherwise
409: */
410: static int
411: xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
412: {
413: int i;
414: const xmlChar *prefix;
415: const xmlChar *href;
416: int has_empty_ns;
417:
418: if(cur == NULL) {
419: xmlC14NErrParam("searching namespaces stack (c14n)");
420: return (0);
421: }
422:
423: /*
424: * if the default namespace xmlns="" is not defined yet then
425: * we do not want to print it out
426: */
427: prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
428: href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
429: has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
430:
431: if (cur->nsTab != NULL) {
432: int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
433: for (i = cur->nsCurEnd - 1; i >= start; --i) {
434: xmlNsPtr ns1 = cur->nsTab[i];
435:
436: if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
437: return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
438: }
439: }
440: }
441: return(has_empty_ns);
442: }
443:
444: static int
445: xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
446: int i;
447: const xmlChar *prefix;
448: const xmlChar *href;
449: int has_empty_ns;
450:
451: if(cur == NULL) {
452: xmlC14NErrParam("searching namespaces stack (exc c14n)");
453: return (0);
454: }
455:
456: /*
457: * if the default namespace xmlns="" is not defined yet then
458: * we do not want to print it out
459: */
460: prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
461: href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
462: has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
463:
464: if (cur->nsTab != NULL) {
465: int start = 0;
466: for (i = cur->nsCurEnd - 1; i >= start; --i) {
467: xmlNsPtr ns1 = cur->nsTab[i];
468:
469: if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
470: if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
471: return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
472: } else {
473: return(0);
474: }
475: }
476: }
477: }
478: return(has_empty_ns);
479: }
480:
481:
482:
483:
484: /**
485: * xmlC14NIsXmlNs:
486: * @ns: the namespace to check
487: *
488: * Checks whether the given namespace is a default "xml:" namespace
489: * with href="http://www.w3.org/XML/1998/namespace"
490: *
491: * Returns 1 if the node is default or 0 otherwise
492: */
493:
494: /* todo: make it a define? */
495: static int
496: xmlC14NIsXmlNs(xmlNsPtr ns)
497: {
498: return ((ns != NULL) &&
499: (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
500: (xmlStrEqual(ns->href, XML_XML_NAMESPACE)));
501: }
502:
503:
504: /**
505: * xmlC14NNsCompare:
506: * @ns1: the pointer to first namespace
507: * @ns2: the pointer to second namespace
508: *
509: * Compares the namespaces by names (prefixes).
510: *
511: * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2.
512: */
513: static int
514: xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
515: {
516: if (ns1 == ns2)
517: return (0);
518: if (ns1 == NULL)
519: return (-1);
520: if (ns2 == NULL)
521: return (1);
522:
523: return (xmlStrcmp(ns1->prefix, ns2->prefix));
524: }
525:
526:
527: /**
528: * xmlC14NPrintNamespaces:
529: * @ns: the pointer to namespace
530: * @ctx: the C14N context
531: *
532: * Prints the given namespace to the output buffer from C14N context.
533: *
534: * Returns 1 on success or 0 on fail.
535: */
536: static int
537: xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
538: {
539:
540: if ((ns == NULL) || (ctx == NULL)) {
541: xmlC14NErrParam("writing namespaces");
542: return 0;
543: }
544:
545: if (ns->prefix != NULL) {
546: xmlOutputBufferWriteString(ctx->buf, " xmlns:");
547: xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
548: xmlOutputBufferWriteString(ctx->buf, "=\"");
549: } else {
550: xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
551: }
552: if(ns->href != NULL) {
553: xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
554: }
555: xmlOutputBufferWriteString(ctx->buf, "\"");
556: return (1);
557: }
558:
559: /**
560: * xmlC14NProcessNamespacesAxis:
561: * @ctx: the C14N context
562: * @node: the current node
563: *
564: * Prints out canonical namespace axis of the current node to the
565: * buffer from C14N context as follows
566: *
567: * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
568: *
569: * Namespace Axis
570: * Consider a list L containing only namespace nodes in the
571: * axis and in the node-set in lexicographic order (ascending). To begin
572: * processing L, if the first node is not the default namespace node (a node
573: * with no namespace URI and no local name), then generate a space followed
574: * by xmlns="" if and only if the following conditions are met:
575: * - the element E that owns the axis is in the node-set
576: * - The nearest ancestor element of E in the node-set has a default
577: * namespace node in the node-set (default namespace nodes always
578: * have non-empty values in XPath)
579: * The latter condition eliminates unnecessary occurrences of xmlns="" in
580: * the canonical form since an element only receives an xmlns="" if its
581: * default namespace is empty and if it has an immediate parent in the
582: * canonical form that has a non-empty default namespace. To finish
583: * processing L, simply process every namespace node in L, except omit
584: * namespace node with local name xml, which defines the xml prefix,
585: * if its string value is http://www.w3.org/XML/1998/namespace.
586: *
587: * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
588: * Canonical XML applied to a document subset requires the search of the
589: * ancestor nodes of each orphan element node for attributes in the xml
590: * namespace, such as xml:lang and xml:space. These are copied into the
591: * element node except if a declaration of the same attribute is already
592: * in the attribute axis of the element (whether or not it is included in
593: * the document subset). This search and copying are omitted from the
594: * Exclusive XML Canonicalization method.
595: *
596: * Returns 0 on success or -1 on fail.
597: */
598: static int
599: xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
600: {
601: xmlNodePtr n;
602: xmlNsPtr ns, tmp;
603: xmlListPtr list;
604: int already_rendered;
605: int has_empty_ns = 0;
606:
607: if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
608: xmlC14NErrParam("processing namespaces axis (c14n)");
609: return (-1);
610: }
611:
612: /*
613: * Create a sorted list to store element namespaces
614: */
615: list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
616: if (list == NULL) {
617: xmlC14NErrInternal("creating namespaces list (c14n)");
618: return (-1);
619: }
620:
621: /* check all namespaces */
622: for(n = cur; n != NULL; n = n->parent) {
623: for(ns = n->nsDef; ns != NULL; ns = ns->next) {
624: tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
625:
626: if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
627: already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
628: if(visible) {
629: xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
630: }
631: if(!already_rendered) {
632: xmlListInsert(list, ns);
633: }
634: if(xmlStrlen(ns->prefix) == 0) {
635: has_empty_ns = 1;
636: }
637: }
638: }
639: }
640:
641: /**
642: * if the first node is not the default namespace node (a node with no
643: * namespace URI and no local name), then generate a space followed by
644: * xmlns="" if and only if the following conditions are met:
645: * - the element E that owns the axis is in the node-set
646: * - the nearest ancestor element of E in the node-set has a default
647: * namespace node in the node-set (default namespace nodes always
648: * have non-empty values in XPath)
649: */
650: if(visible && !has_empty_ns) {
651: static xmlNs ns_default;
652:
653: memset(&ns_default, 0, sizeof(ns_default));
654: if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
655: xmlC14NPrintNamespaces(&ns_default, ctx);
656: }
657: }
658:
659:
660: /*
661: * print out all elements from list
662: */
663: xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
664:
665: /*
666: * Cleanup
667: */
668: xmlListDelete(list);
669: return (0);
670: }
671:
672:
673: /**
674: * xmlExcC14NProcessNamespacesAxis:
675: * @ctx: the C14N context
676: * @node: the current node
677: *
678: * Prints out exclusive canonical namespace axis of the current node to the
679: * buffer from C14N context as follows
680: *
681: * Exclusive XML Canonicalization
682: * http://www.w3.org/TR/xml-exc-c14n
683: *
684: * If the element node is in the XPath subset then output the node in
685: * accordance with Canonical XML except for namespace nodes which are
686: * rendered as follows:
687: *
688: * 1. Render each namespace node iff:
689: * * it is visibly utilized by the immediate parent element or one of
690: * its attributes, or is present in InclusiveNamespaces PrefixList, and
691: * * its prefix and value do not appear in ns_rendered. ns_rendered is
692: * obtained by popping the state stack in order to obtain a list of
693: * prefixes and their values which have already been rendered by
694: * an output ancestor of the namespace node's parent element.
695: * 2. Append the rendered namespace node to the list ns_rendered of namespace
696: * nodes rendered by output ancestors. Push ns_rendered on state stack and
697: * recurse.
698: * 3. After the recursion returns, pop thestate stack.
699: *
700: *
701: * Returns 0 on success or -1 on fail.
702: */
703: static int
704: xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
705: {
706: xmlNsPtr ns;
707: xmlListPtr list;
708: xmlAttrPtr attr;
709: int already_rendered;
710: int has_empty_ns = 0;
711: int has_visibly_utilized_empty_ns = 0;
712: int has_empty_ns_in_inclusive_list = 0;
713:
714: if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
715: xmlC14NErrParam("processing namespaces axis (exc c14n)");
716: return (-1);
717: }
718:
719: if(!xmlC14NIsExclusive(ctx)) {
720: xmlC14NErrParam("processing namespaces axis (exc c14n)");
721: return (-1);
722:
723: }
724:
725: /*
726: * Create a sorted list to store element namespaces
727: */
728: list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
729: if (list == NULL) {
730: xmlC14NErrInternal("creating namespaces list (exc c14n)");
731: return (-1);
732: }
733:
734: /*
735: * process inclusive namespaces:
736: * All namespace nodes appearing on inclusive ns list are
737: * handled as provided in Canonical XML
738: */
739: if(ctx->inclusive_ns_prefixes != NULL) {
740: xmlChar *prefix;
741: int i;
742:
743: for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
744: prefix = ctx->inclusive_ns_prefixes[i];
745: /*
746: * Special values for namespace with empty prefix
747: */
748: if (xmlStrEqual(prefix, BAD_CAST "#default")
749: || xmlStrEqual(prefix, BAD_CAST "")) {
750: prefix = NULL;
751: has_empty_ns_in_inclusive_list = 1;
752: }
753:
754: ns = xmlSearchNs(cur->doc, cur, prefix);
755: if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
756: already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
757: if(visible) {
758: xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
759: }
760: if(!already_rendered) {
761: xmlListInsert(list, ns);
762: }
763: if(xmlStrlen(ns->prefix) == 0) {
764: has_empty_ns = 1;
765: }
766: }
767: }
768: }
769:
770: /* add node namespace */
771: if(cur->ns != NULL) {
772: ns = cur->ns;
773: } else {
774: ns = xmlSearchNs(cur->doc, cur, NULL);
775: has_visibly_utilized_empty_ns = 1;
776: }
777: if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
778: if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
779: if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
780: xmlListInsert(list, ns);
781: }
782: }
783: if(visible) {
784: xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
785: }
786: if(xmlStrlen(ns->prefix) == 0) {
787: has_empty_ns = 1;
788: }
789: }
790:
791:
792: /* add attributes */
793: for(attr = cur->properties; attr != NULL; attr = attr->next) {
794: /*
795: * we need to check that attribute is visible and has non
796: * default namespace (XML Namespaces: "default namespaces
797: * do not apply directly to attributes")
798: */
799: if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) {
800: already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
801: xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur);
802: if(!already_rendered && visible) {
803: xmlListInsert(list, attr->ns);
804: }
805: if(xmlStrlen(attr->ns->prefix) == 0) {
806: has_empty_ns = 1;
807: }
808: } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) {
809: has_visibly_utilized_empty_ns = 1;
810: }
811: }
812:
813: /*
814: * Process xmlns=""
815: */
816: if(visible && has_visibly_utilized_empty_ns &&
817: !has_empty_ns && !has_empty_ns_in_inclusive_list) {
818: static xmlNs ns_default;
819:
820: memset(&ns_default, 0, sizeof(ns_default));
821:
822: already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
823: if(!already_rendered) {
824: xmlC14NPrintNamespaces(&ns_default, ctx);
825: }
826: } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
827: static xmlNs ns_default;
828:
829: memset(&ns_default, 0, sizeof(ns_default));
830: if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
831: xmlC14NPrintNamespaces(&ns_default, ctx);
832: }
833: }
834:
835:
836:
837: /*
838: * print out all elements from list
839: */
840: xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
841:
842: /*
843: * Cleanup
844: */
845: xmlListDelete(list);
846: return (0);
847: }
848:
849:
850: /**
851: * xmlC14NIsXmlAttr:
852: * @attr: the attr to check
853: *
854: * Checks whether the given attribute is a default "xml:" namespace
855: * with href="http://www.w3.org/XML/1998/namespace"
856: *
857: * Returns 1 if the node is default or 0 otherwise
858: */
859:
860: /* todo: make it a define? */
861: static int
862: xmlC14NIsXmlAttr(xmlAttrPtr attr)
863: {
864: return ((attr->ns != NULL) &&
865: (xmlC14NIsXmlNs(attr->ns) != 0));
866: }
867:
868:
869: /**
870: * xmlC14NAttrsCompare:
871: * @attr1: the pointer tls o first attr
872: * @attr2: the pointer to second attr
873: *
874: * Prints the given attribute to the output buffer from C14N context.
875: *
876: * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
877: */
878: static int
879: xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
880: {
881: int ret = 0;
882:
883: /*
884: * Simple cases
885: */
886: if (attr1 == attr2)
887: return (0);
888: if (attr1 == NULL)
889: return (-1);
890: if (attr2 == NULL)
891: return (1);
892: if (attr1->ns == attr2->ns) {
893: return (xmlStrcmp(attr1->name, attr2->name));
894: }
895:
896: /*
897: * Attributes in the default namespace are first
898: * because the default namespace is not applied to
899: * unqualified attributes
900: */
901: if (attr1->ns == NULL)
902: return (-1);
903: if (attr2->ns == NULL)
904: return (1);
905: if (attr1->ns->prefix == NULL)
906: return (-1);
907: if (attr2->ns->prefix == NULL)
908: return (1);
909:
910: ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
911: if (ret == 0) {
912: ret = xmlStrcmp(attr1->name, attr2->name);
913: }
914: return (ret);
915: }
916:
917:
918: /**
919: * xmlC14NPrintAttrs:
920: * @attr: the pointer to attr
921: * @ctx: the C14N context
922: *
923: * Prints out canonical attribute urrent node to the
924: * buffer from C14N context as follows
925: *
926: * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
927: *
928: * Returns 1 on success or 0 on fail.
929: */
930: static int
931: xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
932: {
933: xmlChar *value;
934: xmlChar *buffer;
935:
936: if ((attr == NULL) || (ctx == NULL)) {
937: xmlC14NErrParam("writing attributes");
938: return (0);
939: }
940:
941: xmlOutputBufferWriteString(ctx->buf, " ");
942: if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
943: xmlOutputBufferWriteString(ctx->buf,
944: (const char *) attr->ns->prefix);
945: xmlOutputBufferWriteString(ctx->buf, ":");
946: }
947: xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
948: xmlOutputBufferWriteString(ctx->buf, "=\"");
949:
950: value = xmlNodeListGetString(ctx->doc, attr->children, 1);
951: /* todo: should we log an error if value==NULL ? */
952: if (value != NULL) {
953: buffer = xmlC11NNormalizeAttr(value);
954: xmlFree(value);
955: if (buffer != NULL) {
956: xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
957: xmlFree(buffer);
958: } else {
959: xmlC14NErrInternal("normalizing attributes axis");
960: return (0);
961: }
962: }
963: xmlOutputBufferWriteString(ctx->buf, "\"");
964: return (1);
965: }
966:
967: /**
968: * xmlC14NFindHiddenParentAttr:
969: *
970: * Finds an attribute in a hidden parent node.
971: *
972: * Returns a pointer to the attribute node (if found) or NULL otherwise.
973: */
974: static xmlAttrPtr
975: xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns)
976: {
977: xmlAttrPtr res;
978: while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
979: res = xmlHasNsProp(cur, name, ns);
980: if(res != NULL) {
981: return res;
982: }
983:
984: cur = cur->parent;
985: }
986:
987: return NULL;
988: }
989:
990: /**
991: * xmlC14NFixupBaseAttr:
992: *
993: * Fixes up the xml:base attribute
994: *
995: * Returns the newly created attribute or NULL
996: */
997: static xmlAttrPtr
998: xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr)
999: {
1000: xmlChar * res = NULL;
1001: xmlNodePtr cur;
1002: xmlAttrPtr attr;
1003: xmlChar * tmp_str;
1004: xmlChar * tmp_str2;
1005: int tmp_str_len;
1006:
1007: if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) {
1008: xmlC14NErrParam("processing xml:base attribute");
1009: return (NULL);
1010: }
1011:
1012: /* start from current value */
1013: res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1);
1014: if(res == NULL) {
1015: xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1016: return (NULL);
1017: }
1018:
1019: /* go up the stack until we find a node that we rendered already */
1020: cur = xml_base_attr->parent->parent;
1021: while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
1022: attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1023: if(attr != NULL) {
1024: /* get attr value */
1025: tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1);
1026: if(tmp_str == NULL) {
1027: xmlFree(res);
1028:
1029: xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1030: return (NULL);
1031: }
1032:
1033: /* we need to add '/' if our current base uri ends with '..' or '.'
1034: to ensure that we are forced to go "up" all the time */
1035: tmp_str_len = xmlStrlen(tmp_str);
1036: if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') {
1037: tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/");
1038: if(tmp_str2 == NULL) {
1039: xmlFree(tmp_str);
1040: xmlFree(res);
1041:
1042: xmlC14NErrInternal("processing xml:base attribute - can't modify uri");
1043: return (NULL);
1044: }
1045:
1046: tmp_str = tmp_str2;
1047: }
1048:
1049: /* build uri */
1050: tmp_str2 = xmlBuildURI(res, tmp_str);
1051: if(tmp_str2 == NULL) {
1052: xmlFree(tmp_str);
1053: xmlFree(res);
1054:
1055: xmlC14NErrInternal("processing xml:base attribute - can't construct uri");
1056: return (NULL);
1057: }
1058:
1059: /* cleanup and set the new res */
1060: xmlFree(tmp_str);
1061: xmlFree(res);
1062: res = tmp_str2;
1063: }
1064:
1065: /* next */
1066: cur = cur->parent;
1067: }
1068:
1069: /* check if result uri is empty or not */
1070: if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) {
1071: xmlFree(res);
1072: return (NULL);
1073: }
1074:
1075: /* create and return the new attribute node */
1076: attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res);
1077: if(attr == NULL) {
1078: xmlFree(res);
1079:
1080: xmlC14NErrInternal("processing xml:base attribute - can't construct attribute");
1081: return (NULL);
1082: }
1083:
1084: /* done */
1085: xmlFree(res);
1086: return (attr);
1087: }
1088:
1089: /**
1090: * xmlC14NProcessAttrsAxis:
1091: * @ctx: the C14N context
1092: * @cur: the current node
1093: * @parent_visible: the visibility of parent node
1094: * @all_parents_visible: the visibility of all parent nodes
1095: *
1096: * Prints out canonical attribute axis of the current node to the
1097: * buffer from C14N context as follows
1098: *
1099: * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1100: *
1101: * Attribute Axis
1102: * In lexicographic order (ascending), process each node that
1103: * is in the element's attribute axis and in the node-set.
1104: *
1105: * The processing of an element node E MUST be modified slightly
1106: * when an XPath node-set is given as input and the element's
1107: * parent is omitted from the node-set.
1108: *
1109: *
1110: * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
1111: *
1112: * Canonical XML applied to a document subset requires the search of the
1113: * ancestor nodes of each orphan element node for attributes in the xml
1114: * namespace, such as xml:lang and xml:space. These are copied into the
1115: * element node except if a declaration of the same attribute is already
1116: * in the attribute axis of the element (whether or not it is included in
1117: * the document subset). This search and copying are omitted from the
1118: * Exclusive XML Canonicalization method.
1119: *
1120: * Returns 0 on success or -1 on fail.
1121: */
1122: static int
1123: xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible)
1124: {
1125: xmlAttrPtr attr;
1126: xmlListPtr list;
1127: xmlAttrPtr attrs_to_delete = NULL;
1128:
1129: /* special processing for 1.1 spec */
1130: xmlAttrPtr xml_base_attr = NULL;
1131: xmlAttrPtr xml_lang_attr = NULL;
1132: xmlAttrPtr xml_space_attr = NULL;
1133:
1134: if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1135: xmlC14NErrParam("processing attributes axis");
1136: return (-1);
1137: }
1138:
1139: /*
1140: * Create a sorted list to store element attributes
1141: */
1142: list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
1143: if (list == NULL) {
1144: xmlC14NErrInternal("creating attributes list");
1145: return (-1);
1146: }
1147:
1148: switch(ctx->mode) {
1149: case XML_C14N_1_0:
1150: /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1151: * given as input and the element's parent is omitted from the node-set. The method for processing
1152: * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's
1153: * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such
1154: * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes,
1155: * remove any that are in E's attribute axis (whether or not they are in the node-set). Then,
1156: * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1157: * the node-set. The result of visiting the attribute axis is computed by processing the attribute
1158: * nodes in this merged attribute list.
1159: */
1160:
1161: /*
1162: * Add all visible attributes from current node.
1163: */
1164: attr = cur->properties;
1165: while (attr != NULL) {
1166: /* check that attribute is visible */
1167: if (xmlC14NIsVisible(ctx, attr, cur)) {
1168: xmlListInsert(list, attr);
1169: }
1170: attr = attr->next;
1171: }
1172:
1173: /*
1174: * Handle xml attributes
1175: */
1176: if (parent_visible && (cur->parent != NULL) &&
1177: (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent)))
1178: {
1179: xmlNodePtr tmp;
1180:
1181: /*
1182: * If XPath node-set is not specified then the parent is always
1183: * visible!
1184: */
1185: tmp = cur->parent;
1186: while (tmp != NULL) {
1187: attr = tmp->properties;
1188: while (attr != NULL) {
1189: if (xmlC14NIsXmlAttr(attr) != 0) {
1190: if (xmlListSearch(list, attr) == NULL) {
1191: xmlListInsert(list, attr);
1192: }
1193: }
1194: attr = attr->next;
1195: }
1196: tmp = tmp->parent;
1197: }
1198: }
1199:
1200: /* done */
1201: break;
1202: case XML_C14N_EXCLUSIVE_1_0:
1203: /* attributes in the XML namespace, such as xml:lang and xml:space
1204: * are not imported into orphan nodes of the document subset
1205: */
1206:
1207: /*
1208: * Add all visible attributes from current node.
1209: */
1210: attr = cur->properties;
1211: while (attr != NULL) {
1212: /* check that attribute is visible */
1213: if (xmlC14NIsVisible(ctx, attr, cur)) {
1214: xmlListInsert(list, attr);
1215: }
1216: attr = attr->next;
1217: }
1218:
1219: /* do nothing special for xml attributes */
1220: break;
1221: case XML_C14N_1_1:
1222: /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1223: * given as input and some of the element's ancestors are omitted from the node-set.
1224: *
1225: * Simple inheritable attributes are attributes that have a value that requires at most a simple
1226: * redeclaration. This redeclaration is done by supplying a new value in the child axis. The
1227: * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done
1228: * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes
1229: * are xml:lang and xml:space.
1230: *
1231: * The method for processing the attribute axis of an element E in the node-set is hence enhanced.
1232: * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple
1233: * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they
1234: * are in the node-set). From this list of attributes, any simple inheritable attributes that are
1235: * already in E's attribute axis (whether or not they are in the node-set) are removed. Then,
1236: * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1237: * the node-set. The result of visiting the attribute axis is computed by processing the attribute
1238: * nodes in this merged attribute list.
1239: *
1240: * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is
1241: * performed.
1242: *
1243: * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond
1244: * a simple redeclaration.
1245: *
1246: * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed
1247: * as ordinary attributes.
1248: */
1249:
1250: /*
1251: * Add all visible attributes from current node.
1252: */
1253: attr = cur->properties;
1254: while (attr != NULL) {
1255: /* special processing for XML attribute kiks in only when we have invisible parents */
1256: if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) {
1257: /* check that attribute is visible */
1258: if (xmlC14NIsVisible(ctx, attr, cur)) {
1259: xmlListInsert(list, attr);
1260: }
1261: } else {
1262: int matched = 0;
1263:
1264: /* check for simple inheritance attributes */
1265: if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) {
1266: xml_lang_attr = attr;
1267: matched = 1;
1268: }
1269: if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) {
1270: xml_space_attr = attr;
1271: matched = 1;
1272: }
1273:
1274: /* check for base attr */
1275: if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) {
1276: xml_base_attr = attr;
1277: matched = 1;
1278: }
1279:
1280: /* otherwise, it is a normal attribute, so just check if it is visible */
1281: if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) {
1282: xmlListInsert(list, attr);
1283: }
1284: }
1285:
1286: /* move to the next one */
1287: attr = attr->next;
1288: }
1289:
1290: /* special processing for XML attribute kiks in only when we have invisible parents */
1291: if ((parent_visible)) {
1292:
1293: /* simple inheritance attributes - copy */
1294: if(xml_lang_attr == NULL) {
1295: xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE);
1296: }
1297: if(xml_lang_attr != NULL) {
1298: xmlListInsert(list, xml_lang_attr);
1299: }
1300: if(xml_space_attr == NULL) {
1301: xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE);
1302: }
1303: if(xml_space_attr != NULL) {
1304: xmlListInsert(list, xml_space_attr);
1305: }
1306:
1307: /* base uri attribute - fix up */
1308: if(xml_base_attr == NULL) {
1309: /* if we don't have base uri attribute, check if we have a "hidden" one above */
1310: xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE);
1311: }
1312: if(xml_base_attr != NULL) {
1313: xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr);
1314: if(xml_base_attr != NULL) {
1315: xmlListInsert(list, xml_base_attr);
1316:
1317: /* note that we MUST delete returned attr node ourselves! */
1318: xml_base_attr->next = attrs_to_delete;
1319: attrs_to_delete = xml_base_attr;
1320: }
1321: }
1322: }
1323:
1324: /* done */
1325: break;
1326: }
1327:
1328: /*
1329: * print out all elements from list
1330: */
1331: xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
1332:
1333: /*
1334: * Cleanup
1335: */
1336: xmlFreePropList(attrs_to_delete);
1337: xmlListDelete(list);
1338: return (0);
1339: }
1340:
1341: /**
1342: * xmlC14NCheckForRelativeNamespaces:
1343: * @ctx: the C14N context
1344: * @cur: the current element node
1345: *
1346: * Checks that current element node has no relative namespaces defined
1347: *
1348: * Returns 0 if the node has no relative namespaces or -1 otherwise.
1349: */
1350: static int
1351: xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1352: {
1353: xmlNsPtr ns;
1354:
1355: if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1356: xmlC14NErrParam("checking for relative namespaces");
1357: return (-1);
1358: }
1359:
1360: ns = cur->nsDef;
1361: while (ns != NULL) {
1362: if (xmlStrlen(ns->href) > 0) {
1363: xmlURIPtr uri;
1364:
1365: uri = xmlParseURI((const char *) ns->href);
1366: if (uri == NULL) {
1367: xmlC14NErrInternal("parsing namespace uri");
1368: return (-1);
1369: }
1370: if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
1371: xmlC14NErrRelativeNamespace(uri->scheme);
1372: xmlFreeURI(uri);
1373: return (-1);
1374: }
1375: if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0)
1376: && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0)
1377: && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
1378: xmlC14NErrRelativeNamespace(uri->scheme);
1379: xmlFreeURI(uri);
1380: return (-1);
1381: }
1382: xmlFreeURI(uri);
1383: }
1384: ns = ns->next;
1385: }
1386: return (0);
1387: }
1388:
1389: /**
1390: * xmlC14NProcessElementNode:
1391: * @ctx: the pointer to C14N context object
1392: * @cur: the node to process
1393: * @visible: this node is visible
1394: * @all_parents_visible: whether all the parents of this node are visible
1395: *
1396: * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1397: *
1398: * Element Nodes
1399: * If the element is not in the node-set, then the result is obtained
1400: * by processing the namespace axis, then the attribute axis, then
1401: * processing the child nodes of the element that are in the node-set
1402: * (in document order). If the element is in the node-set, then the result
1403: * is an open angle bracket (<), the element QName, the result of
1404: * processing the namespace axis, the result of processing the attribute
1405: * axis, a close angle bracket (>), the result of processing the child
1406: * nodes of the element that are in the node-set (in document order), an
1407: * open angle bracket, a forward slash (/), the element QName, and a close
1408: * angle bracket.
1409: *
1410: * Returns non-negative value on success or negative value on fail
1411: */
1412: static int
1413: xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1414: {
1415: int ret;
1416: xmlC14NVisibleNsStack state;
1417: int parent_is_doc = 0;
1418:
1419: if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1420: xmlC14NErrParam("processing element node");
1421: return (-1);
1422: }
1423:
1424: /*
1425: * Check relative relative namespaces:
1426: * implementations of XML canonicalization MUST report an operation
1427: * failure on documents containing relative namespace URIs.
1428: */
1429: if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1430: xmlC14NErrInternal("checking for relative namespaces");
1431: return (-1);
1432: }
1433:
1434:
1435: /*
1436: * Save ns_rendered stack position
1437: */
1438: memset(&state, 0, sizeof(state));
1439: xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
1440:
1441: if (visible) {
1442: if (ctx->parent_is_doc) {
1443: /* save this flag into the stack */
1444: parent_is_doc = ctx->parent_is_doc;
1445: ctx->parent_is_doc = 0;
1446: ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1447: }
1448: xmlOutputBufferWriteString(ctx->buf, "<");
1449:
1450: if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1451: xmlOutputBufferWriteString(ctx->buf,
1452: (const char *) cur->ns->prefix);
1453: xmlOutputBufferWriteString(ctx->buf, ":");
1454: }
1455: xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1456: }
1457:
1458: if (!xmlC14NIsExclusive(ctx)) {
1459: ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1460: } else {
1461: ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1462: }
1463: if (ret < 0) {
1464: xmlC14NErrInternal("processing namespaces axis");
1465: return (-1);
1466: }
1467: /* todo: shouldn't this go to "visible only"? */
1468: if(visible) {
1469: xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1470: }
1471:
1472: ret = xmlC14NProcessAttrsAxis(ctx, cur, visible);
1473: if (ret < 0) {
1474: xmlC14NErrInternal("processing attributes axis");
1475: return (-1);
1476: }
1477:
1478: if (visible) {
1479: xmlOutputBufferWriteString(ctx->buf, ">");
1480: }
1481: if (cur->children != NULL) {
1482: ret = xmlC14NProcessNodeList(ctx, cur->children);
1483: if (ret < 0) {
1484: xmlC14NErrInternal("processing childrens list");
1485: return (-1);
1486: }
1487: }
1488: if (visible) {
1489: xmlOutputBufferWriteString(ctx->buf, "</");
1490: if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1491: xmlOutputBufferWriteString(ctx->buf,
1492: (const char *) cur->ns->prefix);
1493: xmlOutputBufferWriteString(ctx->buf, ":");
1494: }
1495: xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1496: xmlOutputBufferWriteString(ctx->buf, ">");
1497: if (parent_is_doc) {
1498: /* restore this flag from the stack for next node */
1499: ctx->parent_is_doc = parent_is_doc;
1500: ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
1501: }
1502: }
1503:
1504: /*
1505: * Restore ns_rendered stack position
1506: */
1507: xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
1508: return (0);
1509: }
1510:
1511: /**
1512: * xmlC14NProcessNode:
1513: * @ctx: the pointer to C14N context object
1514: * @cur: the node to process
1515: *
1516: * Processes the given node
1517: *
1518: * Returns non-negative value on success or negative value on fail
1519: */
1520: static int
1521: xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1522: {
1523: int ret = 0;
1524: int visible;
1525:
1526: if ((ctx == NULL) || (cur == NULL)) {
1527: xmlC14NErrParam("processing node");
1528: return (-1);
1529: }
1530:
1531: visible = xmlC14NIsVisible(ctx, cur, cur->parent);
1532: switch (cur->type) {
1533: case XML_ELEMENT_NODE:
1534: ret = xmlC14NProcessElementNode(ctx, cur, visible);
1535: break;
1536: case XML_CDATA_SECTION_NODE:
1537: case XML_TEXT_NODE:
1538: /*
1539: * Text Nodes
1540: * the string value, except all ampersands are replaced
1541: * by &, all open angle brackets (<) are replaced by <, all closing
1542: * angle brackets (>) are replaced by >, and all #xD characters are
1543: * replaced by 
.
1544: */
1545: /* cdata sections are processed as text nodes */
1546: /* todo: verify that cdata sections are included in XPath nodes set */
1547: if ((visible) && (cur->content != NULL)) {
1548: xmlChar *buffer;
1549:
1550: buffer = xmlC11NNormalizeText(cur->content);
1551: if (buffer != NULL) {
1552: xmlOutputBufferWriteString(ctx->buf,
1553: (const char *) buffer);
1554: xmlFree(buffer);
1555: } else {
1556: xmlC14NErrInternal("normalizing text node");
1557: return (-1);
1558: }
1559: }
1560: break;
1561: case XML_PI_NODE:
1562: /*
1563: * Processing Instruction (PI) Nodes-
1564: * The opening PI symbol (<?), the PI target name of the node,
1565: * a leading space and the string value if it is not empty, and
1566: * the closing PI symbol (?>). If the string value is empty,
1567: * then the leading space is not added. Also, a trailing #xA is
1568: * rendered after the closing PI symbol for PI children of the
1569: * root node with a lesser document order than the document
1570: * element, and a leading #xA is rendered before the opening PI
1571: * symbol of PI children of the root node with a greater document
1572: * order than the document element.
1573: */
1574: if (visible) {
1575: if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1576: xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1577: } else {
1578: xmlOutputBufferWriteString(ctx->buf, "<?");
1579: }
1580:
1581: xmlOutputBufferWriteString(ctx->buf,
1582: (const char *) cur->name);
1583: if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1584: xmlChar *buffer;
1585:
1586: xmlOutputBufferWriteString(ctx->buf, " ");
1587:
1588: /* todo: do we need to normalize pi? */
1589: buffer = xmlC11NNormalizePI(cur->content);
1590: if (buffer != NULL) {
1591: xmlOutputBufferWriteString(ctx->buf,
1592: (const char *) buffer);
1593: xmlFree(buffer);
1594: } else {
1595: xmlC14NErrInternal("normalizing pi node");
1596: return (-1);
1597: }
1598: }
1599:
1600: if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1601: xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1602: } else {
1603: xmlOutputBufferWriteString(ctx->buf, "?>");
1604: }
1605: }
1606: break;
1607: case XML_COMMENT_NODE:
1608: /*
1609: * Comment Nodes
1610: * Nothing if generating canonical XML without comments. For
1611: * canonical XML with comments, generate the opening comment
1612: * symbol (<!--), the string value of the node, and the
1613: * closing comment symbol (-->). Also, a trailing #xA is rendered
1614: * after the closing comment symbol for comment children of the
1615: * root node with a lesser document order than the document
1616: * element, and a leading #xA is rendered before the opening
1617: * comment symbol of comment children of the root node with a
1618: * greater document order than the document element. (Comment
1619: * children of the root node represent comments outside of the
1620: * top-level document element and outside of the document type
1621: * declaration).
1622: */
1623: if (visible && ctx->with_comments) {
1624: if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1625: xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1626: } else {
1627: xmlOutputBufferWriteString(ctx->buf, "<!--");
1628: }
1629:
1630: if (cur->content != NULL) {
1631: xmlChar *buffer;
1632:
1633: /* todo: do we need to normalize comment? */
1634: buffer = xmlC11NNormalizeComment(cur->content);
1635: if (buffer != NULL) {
1636: xmlOutputBufferWriteString(ctx->buf,
1637: (const char *) buffer);
1638: xmlFree(buffer);
1639: } else {
1640: xmlC14NErrInternal("normalizing comment node");
1641: return (-1);
1642: }
1643: }
1644:
1645: if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1646: xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1647: } else {
1648: xmlOutputBufferWriteString(ctx->buf, "-->");
1649: }
1650: }
1651: break;
1652: case XML_DOCUMENT_NODE:
1653: case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */
1654: #ifdef LIBXML_DOCB_ENABLED
1655: case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */
1656: #endif
1657: #ifdef LIBXML_HTML_ENABLED
1658: case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */
1659: #endif
1660: if (cur->children != NULL) {
1661: ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1662: ctx->parent_is_doc = 1;
1663: ret = xmlC14NProcessNodeList(ctx, cur->children);
1664: }
1665: break;
1666:
1667: case XML_ATTRIBUTE_NODE:
1668: xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node");
1669: return (-1);
1670: case XML_NAMESPACE_DECL:
1671: xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node");
1672: return (-1);
1673: case XML_ENTITY_REF_NODE:
1674: xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node");
1675: return (-1);
1676: case XML_ENTITY_NODE:
1677: xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node");
1678: return (-1);
1679:
1680: case XML_DOCUMENT_TYPE_NODE:
1681: case XML_NOTATION_NODE:
1682: case XML_DTD_NODE:
1683: case XML_ELEMENT_DECL:
1684: case XML_ATTRIBUTE_DECL:
1685: case XML_ENTITY_DECL:
1686: #ifdef LIBXML_XINCLUDE_ENABLED
1687: case XML_XINCLUDE_START:
1688: case XML_XINCLUDE_END:
1689: #endif
1690: /*
1691: * should be ignored according to "W3C Canonical XML"
1692: */
1693: break;
1694: default:
1695: xmlC14NErrUnknownNode(cur->type, "processing node");
1696: return (-1);
1697: }
1698:
1699: return (ret);
1700: }
1701:
1702: /**
1703: * xmlC14NProcessNodeList:
1704: * @ctx: the pointer to C14N context object
1705: * @cur: the node to start from
1706: *
1707: * Processes all nodes in the row starting from cur.
1708: *
1709: * Returns non-negative value on success or negative value on fail
1710: */
1711: static int
1712: xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1713: {
1714: int ret;
1715:
1716: if (ctx == NULL) {
1717: xmlC14NErrParam("processing node list");
1718: return (-1);
1719: }
1720:
1721: for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1722: ret = xmlC14NProcessNode(ctx, cur);
1723: }
1724: return (ret);
1725: }
1726:
1727:
1728: /**
1729: * xmlC14NFreeCtx:
1730: * @ctx: the pointer to C14N context object
1731: *
1732: * Cleanups the C14N context object.
1733: */
1734:
1735: static void
1736: xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1737: {
1738: if (ctx == NULL) {
1739: xmlC14NErrParam("freeing context");
1740: return;
1741: }
1742:
1743: if (ctx->ns_rendered != NULL) {
1744: xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
1745: }
1746: xmlFree(ctx);
1747: }
1748:
1749: /**
1750: * xmlC14NNewCtx:
1751: * @doc: the XML document for canonization
1752: * @is_visible_callback:the function to use to determine is node visible
1753: * or not
1754: * @user_data: the first parameter for @is_visible_callback function
1755: * (in most cases, it is nodes set)
1756: * @mode: the c14n mode (see @xmlC14NMode)
1757: * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1758: * ended with a NULL or NULL if there is no
1759: * inclusive namespaces (only for `
1760: * canonicalization)
1761: * @with_comments: include comments in the result (!=0) or not (==0)
1762: * @buf: the output buffer to store canonical XML; this
1763: * buffer MUST have encoder==NULL because C14N requires
1764: * UTF-8 output
1765: *
1766: * Creates new C14N context object to store C14N parameters.
1767: *
1768: * Returns pointer to newly created object (success) or NULL (fail)
1769: */
1770: static xmlC14NCtxPtr
1771: xmlC14NNewCtx(xmlDocPtr doc,
1772: xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
1773: xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes,
1774: int with_comments, xmlOutputBufferPtr buf)
1775: {
1776: xmlC14NCtxPtr ctx = NULL;
1777:
1778: if ((doc == NULL) || (buf == NULL)) {
1779: xmlC14NErrParam("creating new context");
1780: return (NULL);
1781: }
1782:
1783: /*
1784: * Validate the encoding output buffer encoding
1785: */
1786: if (buf->encoder != NULL) {
1787: xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1788: "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
1789: return (NULL);
1790: }
1791:
1792: /*
1793: * Validate the XML document encoding value, if provided.
1794: */
1795: if (doc->charset != XML_CHAR_ENCODING_UTF8) {
1796: xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1797: "xmlC14NNewCtx: source document not in UTF8\n");
1798: return (NULL);
1799: }
1800:
1801: /*
1802: * Allocate a new xmlC14NCtxPtr and fill the fields.
1803: */
1804: ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1805: if (ctx == NULL) {
1806: xmlC14NErrMemory("creating context");
1807: return (NULL);
1808: }
1809: memset(ctx, 0, sizeof(xmlC14NCtx));
1810:
1811: /*
1812: * initialize C14N context
1813: */
1814: ctx->doc = doc;
1815: ctx->with_comments = with_comments;
1816: ctx->is_visible_callback = is_visible_callback;
1817: ctx->user_data = user_data;
1818: ctx->buf = buf;
1819: ctx->parent_is_doc = 1;
1820: ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1821: ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1822:
1823: if(ctx->ns_rendered == NULL) {
1824: xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
1825: "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
1826: xmlC14NFreeCtx(ctx);
1827: return (NULL);
1828: }
1829:
1830: /*
1831: * Set "mode" flag and remember list of incluseve prefixes
1832: * for exclusive c14n
1833: */
1834: ctx->mode = mode;
1835: if(xmlC14NIsExclusive(ctx)) {
1836: ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1837: }
1838: return (ctx);
1839: }
1840:
1841: /**
1842: * xmlC14NExecute:
1843: * @doc: the XML document for canonization
1844: * @is_visible_callback:the function to use to determine is node visible
1845: * or not
1846: * @user_data: the first parameter for @is_visible_callback function
1847: * (in most cases, it is nodes set)
1848: * @mode: the c14n mode (see @xmlC14NMode)
1849: * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1850: * ended with a NULL or NULL if there is no
1851: * inclusive namespaces (only for exclusive
1852: * canonicalization, ignored otherwise)
1853: * @with_comments: include comments in the result (!=0) or not (==0)
1854: * @buf: the output buffer to store canonical XML; this
1855: * buffer MUST have encoder==NULL because C14N requires
1856: * UTF-8 output
1857: *
1858: * Dumps the canonized image of given XML document into the provided buffer.
1859: * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1860: * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1861: *
1862: * Returns non-negative value on success or a negative value on fail
1863: */
1864: int
1865: xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
1866: void* user_data, int mode, xmlChar **inclusive_ns_prefixes,
1867: int with_comments, xmlOutputBufferPtr buf) {
1868:
1869: xmlC14NCtxPtr ctx;
1870: xmlC14NMode c14n_mode = XML_C14N_1_0;
1871: int ret;
1872:
1873: if ((buf == NULL) || (doc == NULL)) {
1874: xmlC14NErrParam("executing c14n");
1875: return (-1);
1876: }
1877:
1878: /* for backward compatibility, we have to have "mode" as "int"
1879: and here we check that user gives valid value */
1880: switch(mode) {
1881: case XML_C14N_1_0:
1882: case XML_C14N_EXCLUSIVE_1_0:
1883: case XML_C14N_1_1:
1884: c14n_mode = (xmlC14NMode)mode;
1885: break;
1886: default:
1887: xmlC14NErrParam("invalid mode for executing c14n");
1888: return (-1);
1889: }
1890:
1891: /*
1892: * Validate the encoding output buffer encoding
1893: */
1894: if (buf->encoder != NULL) {
1895: xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1896: "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
1897: return (-1);
1898: }
1899:
1900: ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
1901: c14n_mode, inclusive_ns_prefixes,
1902: with_comments, buf);
1903: if (ctx == NULL) {
1904: xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
1905: "xmlC14NExecute: unable to create C14N context\n");
1906: return (-1);
1907: }
1908:
1909:
1910:
1911: /*
1912: * Root Node
1913: * The root node is the parent of the top-level document element. The
1914: * result of processing each of its child nodes that is in the node-set
1915: * in document order. The root node does not generate a byte order mark,
1916: * XML declaration, nor anything from within the document type
1917: * declaration.
1918: */
1919: if (doc->children != NULL) {
1920: ret = xmlC14NProcessNodeList(ctx, doc->children);
1921: if (ret < 0) {
1922: xmlC14NErrInternal("processing docs children list");
1923: xmlC14NFreeCtx(ctx);
1924: return (-1);
1925: }
1926: }
1927:
1928: /*
1929: * Flush buffer to get number of bytes written
1930: */
1931: ret = xmlOutputBufferFlush(buf);
1932: if (ret < 0) {
1933: xmlC14NErrInternal("flushing output buffer");
1934: xmlC14NFreeCtx(ctx);
1935: return (-1);
1936: }
1937:
1938: /*
1939: * Cleanup
1940: */
1941: xmlC14NFreeCtx(ctx);
1942: return (ret);
1943: }
1944:
1945: /**
1946: * xmlC14NDocSaveTo:
1947: * @doc: the XML document for canonization
1948: * @nodes: the nodes set to be included in the canonized image
1949: * or NULL if all document nodes should be included
1950: * @mode: the c14n mode (see @xmlC14NMode)
1951: * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1952: * ended with a NULL or NULL if there is no
1953: * inclusive namespaces (only for exclusive
1954: * canonicalization, ignored otherwise)
1955: * @with_comments: include comments in the result (!=0) or not (==0)
1956: * @buf: the output buffer to store canonical XML; this
1957: * buffer MUST have encoder==NULL because C14N requires
1958: * UTF-8 output
1959: *
1960: * Dumps the canonized image of given XML document into the provided buffer.
1961: * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1962: * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1963: *
1964: * Returns non-negative value on success or a negative value on fail
1965: */
1966: int
1967: xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1968: int mode, xmlChar ** inclusive_ns_prefixes,
1969: int with_comments, xmlOutputBufferPtr buf) {
1970: return(xmlC14NExecute(doc,
1971: (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1972: nodes,
1973: mode,
1974: inclusive_ns_prefixes,
1975: with_comments,
1976: buf));
1977: }
1978:
1979:
1980: /**
1981: * xmlC14NDocDumpMemory:
1982: * @doc: the XML document for canonization
1983: * @nodes: the nodes set to be included in the canonized image
1984: * or NULL if all document nodes should be included
1985: * @mode: the c14n mode (see @xmlC14NMode)
1986: * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1987: * ended with a NULL or NULL if there is no
1988: * inclusive namespaces (only for exclusive
1989: * canonicalization, ignored otherwise)
1990: * @with_comments: include comments in the result (!=0) or not (==0)
1991: * @doc_txt_ptr: the memory pointer for allocated canonical XML text;
1992: * the caller of this functions is responsible for calling
1993: * xmlFree() to free allocated memory
1994: *
1995: * Dumps the canonized image of given XML document into memory.
1996: * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1997: * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1998: *
1999: * Returns the number of bytes written on success or a negative value on fail
2000: */
2001: int
2002: xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
2003: int mode, xmlChar ** inclusive_ns_prefixes,
2004: int with_comments, xmlChar ** doc_txt_ptr)
2005: {
2006: int ret;
2007: xmlOutputBufferPtr buf;
2008:
2009: if (doc_txt_ptr == NULL) {
2010: xmlC14NErrParam("dumping doc to memory");
2011: return (-1);
2012: }
2013:
2014: *doc_txt_ptr = NULL;
2015:
2016: /*
2017: * create memory buffer with UTF8 (default) encoding
2018: */
2019: buf = xmlAllocOutputBuffer(NULL);
2020: if (buf == NULL) {
2021: xmlC14NErrMemory("creating output buffer");
2022: return (-1);
2023: }
2024:
2025: /*
2026: * canonize document and write to buffer
2027: */
2028: ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
2029: with_comments, buf);
2030: if (ret < 0) {
2031: xmlC14NErrInternal("saving doc to output buffer");
2032: (void) xmlOutputBufferClose(buf);
2033: return (-1);
2034: }
2035:
2036: ret = buf->buffer->use;
2037: if (ret > 0) {
2038: *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
2039: }
2040: (void) xmlOutputBufferClose(buf);
2041:
2042: if ((*doc_txt_ptr == NULL) && (ret > 0)) {
2043: xmlC14NErrMemory("coping canonicanized document");
2044: return (-1);
2045: }
2046: return (ret);
2047: }
2048:
2049: /**
2050: * xmlC14NDocSave:
2051: * @doc: the XML document for canonization
2052: * @nodes: the nodes set to be included in the canonized image
2053: * or NULL if all document nodes should be included
2054: * @mode: the c14n mode (see @xmlC14NMode)
2055: * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
2056: * ended with a NULL or NULL if there is no
2057: * inclusive namespaces (only for exclusive
2058: * canonicalization, ignored otherwise)
2059: * @with_comments: include comments in the result (!=0) or not (==0)
2060: * @filename: the filename to store canonical XML image
2061: * @compression: the compression level (zlib requred):
2062: * -1 - libxml default,
2063: * 0 - uncompressed,
2064: * >0 - compression level
2065: *
2066: * Dumps the canonized image of given XML document into the file.
2067: * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
2068: * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
2069: *
2070: * Returns the number of bytes written success or a negative value on fail
2071: */
2072: int
2073: xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
2074: int mode, xmlChar ** inclusive_ns_prefixes,
2075: int with_comments, const char *filename, int compression)
2076: {
2077: xmlOutputBufferPtr buf;
2078: int ret;
2079:
2080: if (filename == NULL) {
2081: xmlC14NErrParam("saving doc");
2082: return (-1);
2083: }
2084: #ifdef HAVE_ZLIB_H
2085: if (compression < 0)
2086: compression = xmlGetCompressMode();
2087: #endif
2088:
2089: /*
2090: * save the content to a temp buffer, use default UTF8 encoding.
2091: */
2092: buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
2093: if (buf == NULL) {
2094: xmlC14NErrInternal("creating temporary filename");
2095: return (-1);
2096: }
2097:
2098: /*
2099: * canonize document and write to buffer
2100: */
2101: ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
2102: with_comments, buf);
2103: if (ret < 0) {
2104: xmlC14NErrInternal("cannicanize document to buffer");
2105: (void) xmlOutputBufferClose(buf);
2106: return (-1);
2107: }
2108:
2109: /*
2110: * get the numbers of bytes written
2111: */
2112: ret = xmlOutputBufferClose(buf);
2113: return (ret);
2114: }
2115:
2116:
2117:
2118: /*
2119: * Macro used to grow the current buffer.
2120: */
2121: #define growBufferReentrant() { \
2122: buffer_size *= 2; \
2123: buffer = (xmlChar *) \
2124: xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
2125: if (buffer == NULL) { \
2126: xmlC14NErrMemory("growing buffer"); \
2127: return(NULL); \
2128: } \
2129: }
2130:
2131: /**
2132: * xmlC11NNormalizeString:
2133: * @input: the input string
2134: * @mode: the normalization mode (attribute, comment, PI or text)
2135: *
2136: * Converts a string to a canonical (normalized) format. The code is stolen
2137: * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
2138: * and the @mode parameter
2139: *
2140: * Returns a normalized string (caller is responsible for calling xmlFree())
2141: * or NULL if an error occurs
2142: */
2143: static xmlChar *
2144: xmlC11NNormalizeString(const xmlChar * input,
2145: xmlC14NNormalizationMode mode)
2146: {
2147: const xmlChar *cur = input;
2148: xmlChar *buffer = NULL;
2149: xmlChar *out = NULL;
2150: int buffer_size = 0;
2151:
2152: if (input == NULL)
2153: return (NULL);
2154:
2155: /*
2156: * allocate an translation buffer.
2157: */
2158: buffer_size = 1000;
2159: buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
2160: if (buffer == NULL) {
2161: xmlC14NErrMemory("allocating buffer");
2162: return (NULL);
2163: }
2164: out = buffer;
2165:
2166: while (*cur != '\0') {
2167: if ((out - buffer) > (buffer_size - 10)) {
2168: int indx = out - buffer;
2169:
2170: growBufferReentrant();
2171: out = &buffer[indx];
2172: }
2173:
2174: if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2175: (mode == XMLC14N_NORMALIZE_TEXT))) {
2176: *out++ = '&';
2177: *out++ = 'l';
2178: *out++ = 't';
2179: *out++ = ';';
2180: } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
2181: *out++ = '&';
2182: *out++ = 'g';
2183: *out++ = 't';
2184: *out++ = ';';
2185: } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2186: (mode == XMLC14N_NORMALIZE_TEXT))) {
2187: *out++ = '&';
2188: *out++ = 'a';
2189: *out++ = 'm';
2190: *out++ = 'p';
2191: *out++ = ';';
2192: } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2193: *out++ = '&';
2194: *out++ = 'q';
2195: *out++ = 'u';
2196: *out++ = 'o';
2197: *out++ = 't';
2198: *out++ = ';';
2199: } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2200: *out++ = '&';
2201: *out++ = '#';
2202: *out++ = 'x';
2203: *out++ = '9';
2204: *out++ = ';';
2205: } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2206: *out++ = '&';
2207: *out++ = '#';
2208: *out++ = 'x';
2209: *out++ = 'A';
2210: *out++ = ';';
2211: } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2212: (mode == XMLC14N_NORMALIZE_TEXT) ||
2213: (mode == XMLC14N_NORMALIZE_COMMENT) ||
2214: (mode == XMLC14N_NORMALIZE_PI))) {
2215: *out++ = '&';
2216: *out++ = '#';
2217: *out++ = 'x';
2218: *out++ = 'D';
2219: *out++ = ';';
2220: } else {
2221: /*
2222: * Works because on UTF-8, all extended sequences cannot
2223: * result in bytes in the ASCII range.
2224: */
2225: *out++ = *cur;
2226: }
2227: cur++;
2228: }
2229: *out = 0;
2230: return (buffer);
2231: }
2232: #endif /* LIBXML_OUTPUT_ENABLED */
2233: #define bottom_c14n
2234: #include "elfgcchack.h"
2235: #endif /* LIBXML_C14N_ENABLED */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>