File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / c14n.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>