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