File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / c14n.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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 &amp;, all open angle brackets (<) are replaced by &lt;, all closing 
 1542:              * angle brackets (>) are replaced by &gt;, and all #xD characters are 
 1543:              * replaced by &#xD;.
 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>