/ libxml2 / c14n.c
c14n.c
   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  	xmlBufWriteQuotedString(ctx->buf->buffer, ns->href);
 556      } else {
 557      	xmlOutputBufferWriteString(ctx->buf, "\"\"");
 558      }
 559      return (1);
 560  }
 561  
 562  /**
 563   * xmlC14NProcessNamespacesAxis:
 564   * @ctx:		the C14N context
 565   * @node:		the current node
 566   *
 567   * Prints out canonical namespace axis of the current node to the
 568   * buffer from C14N context as follows
 569   *
 570   * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
 571   *
 572   * Namespace Axis
 573   * Consider a list L containing only namespace nodes in the
 574   * axis and in the node-set in lexicographic order (ascending). To begin
 575   * processing L, if the first node is not the default namespace node (a node
 576   * with no namespace URI and no local name), then generate a space followed
 577   * by xmlns="" if and only if the following conditions are met:
 578   *    - the element E that owns the axis is in the node-set
 579   *    - The nearest ancestor element of E in the node-set has a default
 580   *	    namespace node in the node-set (default namespace nodes always
 581   *      have non-empty values in XPath)
 582   * The latter condition eliminates unnecessary occurrences of xmlns="" in
 583   * the canonical form since an element only receives an xmlns="" if its
 584   * default namespace is empty and if it has an immediate parent in the
 585   * canonical form that has a non-empty default namespace. To finish
 586   * processing  L, simply process every namespace node in L, except omit
 587   * namespace node with local name xml, which defines the xml prefix,
 588   * if its string value is http://www.w3.org/XML/1998/namespace.
 589   *
 590   * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
 591   * Canonical XML applied to a document subset requires the search of the
 592   * ancestor nodes of each orphan element node for attributes in the xml
 593   * namespace, such as xml:lang and xml:space. These are copied into the
 594   * element node except if a declaration of the same attribute is already
 595   * in the attribute axis of the element (whether or not it is included in
 596   * the document subset). This search and copying are omitted from the
 597   * Exclusive XML Canonicalization method.
 598   *
 599   * Returns 0 on success or -1 on fail.
 600   */
 601  static int
 602  xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
 603  {
 604      xmlNodePtr n;
 605      xmlNsPtr ns, tmp;
 606      xmlListPtr list;
 607      int already_rendered;
 608      int has_empty_ns = 0;
 609  
 610      if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
 611          xmlC14NErrParam("processing namespaces axis (c14n)");
 612          return (-1);
 613      }
 614  
 615      /*
 616       * Create a sorted list to store element namespaces
 617       */
 618      list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
 619      if (list == NULL) {
 620          xmlC14NErrInternal("creating namespaces list (c14n)");
 621          return (-1);
 622      }
 623  
 624      /* check all namespaces */
 625      for(n = cur; n != NULL; n = n->parent) {
 626  	for(ns = n->nsDef; ns != NULL; ns = ns->next) {
 627  	    tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
 628  
 629  	    if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
 630  		already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
 631  		if(visible) {
 632  	    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
 633  		}
 634  		if(!already_rendered) {
 635  		    xmlListInsert(list, ns);
 636  		}
 637  		if(xmlStrlen(ns->prefix) == 0) {
 638  		    has_empty_ns = 1;
 639  		}
 640  	    }
 641  	}
 642      }
 643  
 644      /**
 645       * if the first node is not the default namespace node (a node with no
 646       * namespace URI and no local name), then generate a space followed by
 647       * xmlns="" if and only if the following conditions are met:
 648       *  - the element E that owns the axis is in the node-set
 649       *  - the nearest ancestor element of E in the node-set has a default
 650       *     namespace node in the node-set (default namespace nodes always
 651       *     have non-empty values in XPath)
 652       */
 653      if(visible && !has_empty_ns) {
 654          static xmlNs ns_default;
 655  
 656          memset(&ns_default, 0, sizeof(ns_default));
 657          if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
 658  	    xmlC14NPrintNamespaces(&ns_default, ctx);
 659  	}
 660      }
 661  
 662  
 663      /*
 664       * print out all elements from list
 665       */
 666      xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
 667  
 668      /*
 669       * Cleanup
 670       */
 671      xmlListDelete(list);
 672      return (0);
 673  }
 674  
 675  
 676  /**
 677   * xmlExcC14NProcessNamespacesAxis:
 678   * @ctx:		the C14N context
 679   * @node:		the current node
 680   *
 681   * Prints out exclusive canonical namespace axis of the current node to the
 682   * buffer from C14N context as follows
 683   *
 684   * Exclusive XML Canonicalization
 685   * http://www.w3.org/TR/xml-exc-c14n
 686   *
 687   * If the element node is in the XPath subset then output the node in
 688   * accordance with Canonical XML except for namespace nodes which are
 689   * rendered as follows:
 690   *
 691   * 1. Render each namespace node iff:
 692   *    * it is visibly utilized by the immediate parent element or one of
 693   *      its attributes, or is present in InclusiveNamespaces PrefixList, and
 694   *    * its prefix and value do not appear in ns_rendered. ns_rendered is
 695   *      obtained by popping the state stack in order to obtain a list of
 696   *      prefixes and their values which have already been rendered by
 697   *      an output ancestor of the namespace node's parent element.
 698   * 2. Append the rendered namespace node to the list ns_rendered of namespace
 699   * nodes rendered by output ancestors. Push ns_rendered on state stack and
 700   * recurse.
 701   * 3. After the recursion returns, pop thestate stack.
 702   *
 703   *
 704   * Returns 0 on success or -1 on fail.
 705   */
 706  static int
 707  xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
 708  {
 709      xmlNsPtr ns;
 710      xmlListPtr list;
 711      xmlAttrPtr attr;
 712      int already_rendered;
 713      int has_empty_ns = 0;
 714      int has_visibly_utilized_empty_ns = 0;
 715      int has_empty_ns_in_inclusive_list = 0;
 716  
 717      if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
 718          xmlC14NErrParam("processing namespaces axis (exc c14n)");
 719          return (-1);
 720      }
 721  
 722      if(!xmlC14NIsExclusive(ctx)) {
 723          xmlC14NErrParam("processing namespaces axis (exc c14n)");
 724          return (-1);
 725  
 726      }
 727  
 728      /*
 729       * Create a sorted list to store element namespaces
 730       */
 731      list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
 732      if (list == NULL) {
 733          xmlC14NErrInternal("creating namespaces list (exc c14n)");
 734          return (-1);
 735      }
 736  
 737      /*
 738       * process inclusive namespaces:
 739       * All namespace nodes appearing on inclusive ns list are
 740       * handled as provided in Canonical XML
 741       */
 742      if(ctx->inclusive_ns_prefixes != NULL) {
 743  	xmlChar *prefix;
 744  	int i;
 745  
 746  	for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
 747  	    prefix = ctx->inclusive_ns_prefixes[i];
 748  	    /*
 749  	     * Special values for namespace with empty prefix
 750  	     */
 751              if (xmlStrEqual(prefix, BAD_CAST "#default")
 752                  || xmlStrEqual(prefix, BAD_CAST "")) {
 753                  prefix = NULL;
 754  		has_empty_ns_in_inclusive_list = 1;
 755              }
 756  
 757  	    ns = xmlSearchNs(cur->doc, cur, prefix);
 758  	    if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
 759  		already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
 760  		if(visible) {
 761  		    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
 762  		}
 763  		if(!already_rendered) {
 764  		    xmlListInsert(list, ns);
 765  		}
 766  		if(xmlStrlen(ns->prefix) == 0) {
 767  		    has_empty_ns = 1;
 768  		}
 769  	    }
 770  	}
 771      }
 772  
 773      /* add node namespace */
 774      if(cur->ns != NULL) {
 775  	ns = cur->ns;
 776      } else {
 777          ns = xmlSearchNs(cur->doc, cur, NULL);
 778  	has_visibly_utilized_empty_ns = 1;
 779      }
 780      if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
 781  	if(visible && xmlC14NIsVisible(ctx, ns, cur)) {
 782  	    if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
 783  		xmlListInsert(list, ns);
 784  	    }
 785  	}
 786  	if(visible) {
 787  	    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
 788  	}
 789  	if(xmlStrlen(ns->prefix) == 0) {
 790  	    has_empty_ns = 1;
 791  	}
 792      }
 793  
 794  
 795      /* add attributes */
 796      for(attr = cur->properties; attr != NULL; attr = attr->next) {
 797          /*
 798           * we need to check that attribute is visible and has non
 799           * default namespace (XML Namespaces: "default namespaces
 800  	 * do not apply directly to attributes")
 801           */
 802  	if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) {
 803  	    already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
 804  	    xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur);
 805  	    if(!already_rendered && visible) {
 806  		xmlListInsert(list, attr->ns);
 807  	    }
 808  	    if(xmlStrlen(attr->ns->prefix) == 0) {
 809  		has_empty_ns = 1;
 810  	    }
 811  	} else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) {
 812  	    has_visibly_utilized_empty_ns = 1;
 813  	}
 814      }
 815  
 816      /*
 817       * Process xmlns=""
 818       */
 819      if(visible && has_visibly_utilized_empty_ns &&
 820  	    !has_empty_ns && !has_empty_ns_in_inclusive_list) {
 821          static xmlNs ns_default;
 822  
 823          memset(&ns_default, 0, sizeof(ns_default));
 824  
 825          already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
 826  	if(!already_rendered) {
 827  	    xmlC14NPrintNamespaces(&ns_default, ctx);
 828  	}
 829      } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
 830          static xmlNs ns_default;
 831  
 832          memset(&ns_default, 0, sizeof(ns_default));
 833          if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
 834  	    xmlC14NPrintNamespaces(&ns_default, ctx);
 835  	}
 836      }
 837  
 838  
 839  
 840      /*
 841       * print out all elements from list
 842       */
 843      xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
 844  
 845      /*
 846       * Cleanup
 847       */
 848      xmlListDelete(list);
 849      return (0);
 850  }
 851  
 852  
 853  /**
 854   * xmlC14NIsXmlAttr:
 855   * @attr:		the attr to check
 856   *
 857   * Checks whether the given attribute is a default "xml:" namespace
 858   * with href="http://www.w3.org/XML/1998/namespace"
 859   *
 860   * Returns 1 if the node is default or 0 otherwise
 861   */
 862  
 863  /* todo: make it a define? */
 864  static int
 865  xmlC14NIsXmlAttr(xmlAttrPtr attr)
 866  {
 867      return ((attr->ns != NULL) &&
 868             (xmlC14NIsXmlNs(attr->ns) != 0));
 869  }
 870  
 871  
 872  /**
 873   * xmlC14NAttrsCompare:
 874   * @attr1:		the pointer tls o first attr
 875   * @attr2:		the pointer to second attr
 876   *
 877   * Prints the given attribute to the output buffer from C14N context.
 878   *
 879   * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2.
 880   */
 881  static int
 882  xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
 883  {
 884      int ret = 0;
 885  
 886      /*
 887       * Simple cases
 888       */
 889      if (attr1 == attr2)
 890          return (0);
 891      if (attr1 == NULL)
 892          return (-1);
 893      if (attr2 == NULL)
 894          return (1);
 895      if (attr1->ns == attr2->ns) {
 896          return (xmlStrcmp(attr1->name, attr2->name));
 897      }
 898  
 899      /*
 900       * Attributes in the default namespace are first
 901       * because the default namespace is not applied to
 902       * unqualified attributes
 903       */
 904      if (attr1->ns == NULL)
 905          return (-1);
 906      if (attr2->ns == NULL)
 907          return (1);
 908      if (attr1->ns->prefix == NULL)
 909          return (-1);
 910      if (attr2->ns->prefix == NULL)
 911          return (1);
 912  
 913      ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
 914      if (ret == 0) {
 915          ret = xmlStrcmp(attr1->name, attr2->name);
 916      }
 917      return (ret);
 918  }
 919  
 920  
 921  /**
 922   * xmlC14NPrintAttrs:
 923   * @attr:		the pointer to attr
 924   * @ctx:		the C14N context
 925   *
 926   * Prints out canonical attribute urrent node to the
 927   * buffer from C14N context as follows
 928   *
 929   * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
 930   *
 931   * Returns 1 on success or 0 on fail.
 932   */
 933  static int
 934  xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
 935  {
 936      xmlChar *value;
 937      xmlChar *buffer;
 938  
 939      if ((attr == NULL) || (ctx == NULL)) {
 940          xmlC14NErrParam("writing attributes");
 941          return (0);
 942      }
 943  
 944      xmlOutputBufferWriteString(ctx->buf, " ");
 945      if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
 946          xmlOutputBufferWriteString(ctx->buf,
 947                                     (const char *) attr->ns->prefix);
 948          xmlOutputBufferWriteString(ctx->buf, ":");
 949      }
 950      xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
 951      xmlOutputBufferWriteString(ctx->buf, "=\"");
 952  
 953      value = xmlNodeListGetString(ctx->doc, attr->children, 1);
 954      /* todo: should we log an error if value==NULL ? */
 955      if (value != NULL) {
 956          buffer = xmlC11NNormalizeAttr(value);
 957          xmlFree(value);
 958          if (buffer != NULL) {
 959              xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
 960              xmlFree(buffer);
 961          } else {
 962              xmlC14NErrInternal("normalizing attributes axis");
 963              return (0);
 964          }
 965      }
 966      xmlOutputBufferWriteString(ctx->buf, "\"");
 967      return (1);
 968  }
 969  
 970  /**
 971   * xmlC14NFindHiddenParentAttr:
 972   *
 973   * Finds an attribute in a hidden parent node.
 974   *
 975   * Returns a pointer to the attribute node (if found) or NULL otherwise.
 976   */
 977  static xmlAttrPtr
 978  xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns)
 979  {
 980      xmlAttrPtr res;
 981      while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
 982          res = xmlHasNsProp(cur, name, ns);
 983          if(res != NULL) {
 984              return res;
 985          }
 986  
 987          cur = cur->parent;
 988      }
 989  
 990      return NULL;
 991  }
 992  
 993  /**
 994   * xmlC14NFixupBaseAttr:
 995   *
 996   * Fixes up the xml:base attribute
 997   *
 998   * Returns the newly created attribute or NULL
 999   */
1000  static xmlAttrPtr
1001  xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr)
1002  {
1003      xmlChar * res = NULL;
1004      xmlNodePtr cur;
1005      xmlAttrPtr attr;
1006      xmlChar * tmp_str;
1007      xmlChar * tmp_str2;
1008      int tmp_str_len;
1009  
1010      if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) {
1011          xmlC14NErrParam("processing xml:base attribute");
1012          return (NULL);
1013      }
1014  
1015      /* start from current value */
1016      res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1);
1017      if(res == NULL) {
1018          xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1019          return (NULL);
1020      }
1021  
1022      /* go up the stack until we find a node that we rendered already */
1023      cur = xml_base_attr->parent->parent;
1024      while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
1025          attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
1026          if(attr != NULL) {
1027              /* get attr value */
1028              tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1);
1029              if(tmp_str == NULL) {
1030                  xmlFree(res);
1031  
1032                  xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
1033                  return (NULL);
1034              }
1035  
1036              /* we need to add '/' if our current base uri ends with '..' or '.'
1037              to ensure that we are forced to go "up" all the time */
1038              tmp_str_len = xmlStrlen(tmp_str);
1039              if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') {
1040                  tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/");
1041                  if(tmp_str2 == NULL) {
1042                      xmlFree(tmp_str);
1043                      xmlFree(res);
1044  
1045                      xmlC14NErrInternal("processing xml:base attribute - can't modify uri");
1046                      return (NULL);
1047                  }
1048  
1049                  tmp_str = tmp_str2;
1050              }
1051  
1052              /* build uri */
1053              tmp_str2 = xmlBuildURI(res, tmp_str);
1054              if(tmp_str2 == NULL) {
1055                  xmlFree(tmp_str);
1056                  xmlFree(res);
1057  
1058                  xmlC14NErrInternal("processing xml:base attribute - can't construct uri");
1059                  return (NULL);
1060              }
1061  
1062              /* cleanup and set the new res */
1063              xmlFree(tmp_str);
1064              xmlFree(res);
1065              res = tmp_str2;
1066          }
1067  
1068          /* next */
1069          cur = cur->parent;
1070      }
1071  
1072      /* check if result uri is empty or not */
1073      if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) {
1074          xmlFree(res);
1075          return (NULL);
1076      }
1077  
1078      /* create and return the new attribute node */
1079      attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res);
1080      if(attr == NULL) {
1081          xmlFree(res);
1082  
1083          xmlC14NErrInternal("processing xml:base attribute - can't construct attribute");
1084          return (NULL);
1085      }
1086  
1087      /* done */
1088      xmlFree(res);
1089      return (attr);
1090  }
1091  
1092  /**
1093   * xmlC14NProcessAttrsAxis:
1094   * @ctx:		the C14N context
1095   * @cur:		the current node
1096   * @parent_visible:	the visibility of parent node
1097   * @all_parents_visible: the visibility of all parent nodes
1098   *
1099   * Prints out canonical attribute axis of the current node to the
1100   * buffer from C14N context as follows
1101   *
1102   * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1103   *
1104   * Attribute Axis
1105   * In lexicographic order (ascending), process each node that
1106   * is in the element's attribute axis and in the node-set.
1107   *
1108   * The processing of an element node E MUST be modified slightly
1109   * when an XPath node-set is given as input and the element's
1110   * parent is omitted from the node-set.
1111   *
1112   *
1113   * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n)
1114   *
1115   * Canonical XML applied to a document subset requires the search of the
1116   * ancestor nodes of each orphan element node for attributes in the xml
1117   * namespace, such as xml:lang and xml:space. These are copied into the
1118   * element node except if a declaration of the same attribute is already
1119   * in the attribute axis of the element (whether or not it is included in
1120   * the document subset). This search and copying are omitted from the
1121   * Exclusive XML Canonicalization method.
1122   *
1123   * Returns 0 on success or -1 on fail.
1124   */
1125  static int
1126  xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible)
1127  {
1128      xmlAttrPtr attr;
1129      xmlListPtr list;
1130      xmlAttrPtr attrs_to_delete = NULL;
1131  
1132      /* special processing for 1.1 spec */
1133      xmlAttrPtr xml_base_attr = NULL;
1134      xmlAttrPtr xml_lang_attr = NULL;
1135      xmlAttrPtr xml_space_attr = NULL;
1136  
1137      if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1138          xmlC14NErrParam("processing attributes axis");
1139          return (-1);
1140      }
1141  
1142      /*
1143       * Create a sorted list to store element attributes
1144       */
1145      list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
1146      if (list == NULL) {
1147          xmlC14NErrInternal("creating attributes list");
1148          return (-1);
1149      }
1150  
1151      switch(ctx->mode) {
1152      case XML_C14N_1_0:
1153          /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1154           * given as input and the element's parent is omitted from the node-set. The method for processing
1155           * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's
1156           * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such
1157           * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes,
1158           * remove any that are in E's attribute axis (whether or not they are in the node-set). Then,
1159           * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1160           * the node-set. The result of visiting the attribute axis is computed by processing the attribute
1161           * nodes in this merged attribute list.
1162           */
1163  
1164          /*
1165           * Add all visible attributes from current node.
1166           */
1167          attr = cur->properties;
1168          while (attr != NULL) {
1169              /* check that attribute is visible */
1170              if (xmlC14NIsVisible(ctx, attr, cur)) {
1171                  xmlListInsert(list, attr);
1172              }
1173              attr = attr->next;
1174          }
1175  
1176          /*
1177           * Handle xml attributes
1178           */
1179          if (parent_visible && (cur->parent != NULL) &&
1180              (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent)))
1181          {
1182              xmlNodePtr tmp;
1183  
1184              /*
1185               * If XPath node-set is not specified then the parent is always
1186               * visible!
1187               */
1188              tmp = cur->parent;
1189              while (tmp != NULL) {
1190                  attr = tmp->properties;
1191                  while (attr != NULL) {
1192                      if (xmlC14NIsXmlAttr(attr) != 0) {
1193                          if (xmlListSearch(list, attr) == NULL) {
1194                              xmlListInsert(list, attr);
1195                          }
1196                      }
1197                      attr = attr->next;
1198                  }
1199                  tmp = tmp->parent;
1200              }
1201          }
1202  
1203          /* done */
1204          break;
1205      case XML_C14N_EXCLUSIVE_1_0:
1206          /* attributes in the XML namespace, such as xml:lang and xml:space
1207           * are not imported into orphan nodes of the document subset
1208           */
1209  
1210          /*
1211           * Add all visible attributes from current node.
1212           */
1213          attr = cur->properties;
1214          while (attr != NULL) {
1215              /* check that attribute is visible */
1216              if (xmlC14NIsVisible(ctx, attr, cur)) {
1217                  xmlListInsert(list, attr);
1218              }
1219              attr = attr->next;
1220          }
1221  
1222          /* do nothing special for xml attributes */
1223          break;
1224      case XML_C14N_1_1:
1225          /* The processing of an element node E MUST be modified slightly when an XPath node-set is
1226           * given as input and some of the element's ancestors are omitted from the node-set.
1227           *
1228           * Simple inheritable attributes are attributes that have a value that requires at most a simple
1229           * redeclaration. This redeclaration is done by supplying a new value in the child axis. The
1230           * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done
1231           * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes
1232           * are xml:lang and xml:space.
1233           *
1234           * The method for processing the attribute axis of an element E in the node-set is hence enhanced.
1235           * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple
1236           * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they
1237           * are in the node-set). From this list of attributes, any simple inheritable attributes that are
1238           * already in E's attribute axis (whether or not they are in the node-set) are removed. Then,
1239           * lexicographically merge this attribute list with the nodes of E's attribute axis that are in
1240           * the node-set. The result of visiting the attribute axis is computed by processing the attribute
1241           * nodes in this merged attribute list.
1242           *
1243           * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is
1244           * performed.
1245           *
1246           * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond
1247           * a simple redeclaration.
1248           *
1249           * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed
1250           * as ordinary attributes.
1251           */
1252  
1253          /*
1254           * Add all visible attributes from current node.
1255           */
1256          attr = cur->properties;
1257          while (attr != NULL) {
1258              /* special processing for XML attribute kiks in only when we have invisible parents */
1259              if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) {
1260                  /* check that attribute is visible */
1261                  if (xmlC14NIsVisible(ctx, attr, cur)) {
1262                      xmlListInsert(list, attr);
1263                  }
1264              } else {
1265                  int matched = 0;
1266  
1267                  /* check for simple inheritance attributes */
1268                  if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) {
1269                      xml_lang_attr = attr;
1270                      matched = 1;
1271                  }
1272                  if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) {
1273                      xml_space_attr = attr;
1274                      matched = 1;
1275                  }
1276  
1277                  /* check for base attr */
1278                  if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) {
1279                      xml_base_attr = attr;
1280                      matched = 1;
1281                  }
1282  
1283                  /* otherwise, it is a normal attribute, so just check if it is visible */
1284                  if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) {
1285                      xmlListInsert(list, attr);
1286                  }
1287              }
1288  
1289              /* move to the next one */
1290              attr = attr->next;
1291          }
1292  
1293          /* special processing for XML attribute kiks in only when we have invisible parents */
1294          if ((parent_visible)) {
1295  
1296              /* simple inheritance attributes - copy */
1297              if(xml_lang_attr == NULL) {
1298                  xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE);
1299              }
1300              if(xml_lang_attr != NULL) {
1301                  xmlListInsert(list, xml_lang_attr);
1302              }
1303              if(xml_space_attr == NULL) {
1304                  xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE);
1305              }
1306              if(xml_space_attr != NULL) {
1307                  xmlListInsert(list, xml_space_attr);
1308              }
1309  
1310              /* base uri attribute - fix up */
1311              if(xml_base_attr == NULL) {
1312                  /* if we don't have base uri attribute, check if we have a "hidden" one above */
1313                  xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE);
1314              }
1315              if(xml_base_attr != NULL) {
1316                  xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr);
1317                  if(xml_base_attr != NULL) {
1318                      xmlListInsert(list, xml_base_attr);
1319  
1320                      /* note that we MUST delete returned attr node ourselves! */
1321                      xml_base_attr->next = attrs_to_delete;
1322                      attrs_to_delete = xml_base_attr;
1323                  }
1324              }
1325          }
1326  
1327          /* done */
1328          break;
1329      }
1330  
1331      /*
1332       * print out all elements from list
1333       */
1334      xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
1335  
1336      /*
1337       * Cleanup
1338       */
1339      xmlFreePropList(attrs_to_delete);
1340      xmlListDelete(list);
1341      return (0);
1342  }
1343  
1344  /**
1345   * xmlC14NCheckForRelativeNamespaces:
1346   * @ctx:		the C14N context
1347   * @cur:		the current element node
1348   *
1349   * Checks that current element node has no relative namespaces defined
1350   *
1351   * Returns 0 if the node has no relative namespaces or -1 otherwise.
1352   */
1353  static int
1354  xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1355  {
1356      xmlNsPtr ns;
1357  
1358      if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1359          xmlC14NErrParam("checking for relative namespaces");
1360          return (-1);
1361      }
1362  
1363      ns = cur->nsDef;
1364      while (ns != NULL) {
1365          if (xmlStrlen(ns->href) > 0) {
1366              xmlURIPtr uri;
1367  
1368              uri = xmlParseURI((const char *) ns->href);
1369              if (uri == NULL) {
1370                  xmlC14NErrInternal("parsing namespace uri");
1371                  return (-1);
1372              }
1373              if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
1374                  xmlC14NErrRelativeNamespace(uri->scheme);
1375                  xmlFreeURI(uri);
1376                  return (-1);
1377              }
1378              if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0)
1379                  && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0)
1380                  && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
1381                  xmlC14NErrRelativeNamespace(uri->scheme);
1382                  xmlFreeURI(uri);
1383                  return (-1);
1384              }
1385              xmlFreeURI(uri);
1386          }
1387          ns = ns->next;
1388      }
1389      return (0);
1390  }
1391  
1392  /**
1393   * xmlC14NProcessElementNode:
1394   * @ctx:		the pointer to C14N context object
1395   * @cur:		the node to process
1396   * @visible:    this node is visible
1397   * @all_parents_visible: whether all the parents of this node are visible
1398   *
1399   * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n)
1400   *
1401   * Element Nodes
1402   * If the element is not in the node-set, then the result is obtained
1403   * by processing the namespace axis, then the attribute axis, then
1404   * processing the child nodes of the element that are in the node-set
1405   * (in document order). If the element is in the node-set, then the result
1406   * is an open angle bracket (<), the element QName, the result of
1407   * processing the namespace axis, the result of processing the attribute
1408   * axis, a close angle bracket (>), the result of processing the child
1409   * nodes of the element that are in the node-set (in document order), an
1410   * open angle bracket, a forward slash (/), the element QName, and a close
1411   * angle bracket.
1412   *
1413   * Returns non-negative value on success or negative value on fail
1414   */
1415  static int
1416  xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
1417  {
1418      int ret;
1419      xmlC14NVisibleNsStack state;
1420      int parent_is_doc = 0;
1421  
1422      if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
1423          xmlC14NErrParam("processing element node");
1424          return (-1);
1425      }
1426  
1427      /*
1428       * Check relative relative namespaces:
1429       * implementations of XML canonicalization MUST report an operation
1430       * failure on documents containing relative namespace URIs.
1431       */
1432      if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
1433          xmlC14NErrInternal("checking for relative namespaces");
1434          return (-1);
1435      }
1436  
1437  
1438      /*
1439       * Save ns_rendered stack position
1440       */
1441      memset(&state, 0, sizeof(state));
1442      xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
1443  
1444      if (visible) {
1445          if (ctx->parent_is_doc) {
1446  	    /* save this flag into the stack */
1447  	    parent_is_doc = ctx->parent_is_doc;
1448  	    ctx->parent_is_doc = 0;
1449              ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
1450          }
1451          xmlOutputBufferWriteString(ctx->buf, "<");
1452  
1453          if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1454              xmlOutputBufferWriteString(ctx->buf,
1455                                         (const char *) cur->ns->prefix);
1456              xmlOutputBufferWriteString(ctx->buf, ":");
1457          }
1458          xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1459      }
1460  
1461      if (!xmlC14NIsExclusive(ctx)) {
1462          ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
1463      } else {
1464          ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
1465      }
1466      if (ret < 0) {
1467          xmlC14NErrInternal("processing namespaces axis");
1468          return (-1);
1469      }
1470      /* todo: shouldn't this go to "visible only"? */
1471      if(visible) {
1472  	xmlC14NVisibleNsStackShift(ctx->ns_rendered);
1473      }
1474  
1475      ret = xmlC14NProcessAttrsAxis(ctx, cur, visible);
1476      if (ret < 0) {
1477  	xmlC14NErrInternal("processing attributes axis");
1478  	return (-1);
1479      }
1480  
1481      if (visible) {
1482          xmlOutputBufferWriteString(ctx->buf, ">");
1483      }
1484      if (cur->children != NULL) {
1485          ret = xmlC14NProcessNodeList(ctx, cur->children);
1486          if (ret < 0) {
1487              xmlC14NErrInternal("processing childrens list");
1488              return (-1);
1489          }
1490      }
1491      if (visible) {
1492          xmlOutputBufferWriteString(ctx->buf, "</");
1493          if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
1494              xmlOutputBufferWriteString(ctx->buf,
1495                                         (const char *) cur->ns->prefix);
1496              xmlOutputBufferWriteString(ctx->buf, ":");
1497          }
1498          xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
1499          xmlOutputBufferWriteString(ctx->buf, ">");
1500          if (parent_is_doc) {
1501  	    /* restore this flag from the stack for next node */
1502              ctx->parent_is_doc = parent_is_doc;
1503  	    ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
1504          }
1505      }
1506  
1507      /*
1508       * Restore ns_rendered stack position
1509       */
1510      xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
1511      return (0);
1512  }
1513  
1514  /**
1515   * xmlC14NProcessNode:
1516   * @ctx:		the pointer to C14N context object
1517   * @cur:		the node to process
1518   *
1519   * Processes the given node
1520   *
1521   * Returns non-negative value on success or negative value on fail
1522   */
1523  static int
1524  xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1525  {
1526      int ret = 0;
1527      int visible;
1528  
1529      if ((ctx == NULL) || (cur == NULL)) {
1530          xmlC14NErrParam("processing node");
1531          return (-1);
1532      }
1533  
1534      visible = xmlC14NIsVisible(ctx, cur, cur->parent);
1535      switch (cur->type) {
1536          case XML_ELEMENT_NODE:
1537              ret = xmlC14NProcessElementNode(ctx, cur, visible);
1538              break;
1539          case XML_CDATA_SECTION_NODE:
1540          case XML_TEXT_NODE:
1541              /*
1542               * Text Nodes
1543               * the string value, except all ampersands are replaced
1544               * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing
1545               * angle brackets (>) are replaced by &gt;, and all #xD characters are
1546               * replaced by &#xD;.
1547               */
1548              /* cdata sections are processed as text nodes */
1549              /* todo: verify that cdata sections are included in XPath nodes set */
1550              if ((visible) && (cur->content != NULL)) {
1551                  xmlChar *buffer;
1552  
1553                  buffer = xmlC11NNormalizeText(cur->content);
1554                  if (buffer != NULL) {
1555                      xmlOutputBufferWriteString(ctx->buf,
1556                                                 (const char *) buffer);
1557                      xmlFree(buffer);
1558                  } else {
1559                      xmlC14NErrInternal("normalizing text node");
1560                      return (-1);
1561                  }
1562              }
1563              break;
1564          case XML_PI_NODE:
1565              /*
1566               * Processing Instruction (PI) Nodes-
1567               * The opening PI symbol (<?), the PI target name of the node,
1568               * a leading space and the string value if it is not empty, and
1569               * the closing PI symbol (?>). If the string value is empty,
1570               * then the leading space is not added. Also, a trailing #xA is
1571               * rendered after the closing PI symbol for PI children of the
1572               * root node with a lesser document order than the document
1573               * element, and a leading #xA is rendered before the opening PI
1574               * symbol of PI children of the root node with a greater document
1575               * order than the document element.
1576               */
1577              if (visible) {
1578                  if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1579                      xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
1580                  } else {
1581                      xmlOutputBufferWriteString(ctx->buf, "<?");
1582                  }
1583  
1584                  xmlOutputBufferWriteString(ctx->buf,
1585                                             (const char *) cur->name);
1586                  if ((cur->content != NULL) && (*(cur->content) != '\0')) {
1587                      xmlChar *buffer;
1588  
1589                      xmlOutputBufferWriteString(ctx->buf, " ");
1590  
1591                      /* todo: do we need to normalize pi? */
1592                      buffer = xmlC11NNormalizePI(cur->content);
1593                      if (buffer != NULL) {
1594                          xmlOutputBufferWriteString(ctx->buf,
1595                                                     (const char *) buffer);
1596                          xmlFree(buffer);
1597                      } else {
1598                          xmlC14NErrInternal("normalizing pi node");
1599                          return (-1);
1600                      }
1601                  }
1602  
1603                  if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1604                      xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
1605                  } else {
1606                      xmlOutputBufferWriteString(ctx->buf, "?>");
1607                  }
1608              }
1609              break;
1610          case XML_COMMENT_NODE:
1611              /*
1612               * Comment Nodes
1613               * Nothing if generating canonical XML without  comments. For
1614               * canonical XML with comments, generate the opening comment
1615               * symbol (<!--), the string value of the node, and the
1616               * closing comment symbol (-->). Also, a trailing #xA is rendered
1617               * after the closing comment symbol for comment children of the
1618               * root node with a lesser document order than the document
1619               * element, and a leading #xA is rendered before the opening
1620               * comment symbol of comment children of the root node with a
1621               * greater document order than the document element. (Comment
1622               * children of the root node represent comments outside of the
1623               * top-level document element and outside of the document type
1624               * declaration).
1625               */
1626              if (visible && ctx->with_comments) {
1627                  if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
1628                      xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
1629                  } else {
1630                      xmlOutputBufferWriteString(ctx->buf, "<!--");
1631                  }
1632  
1633                  if (cur->content != NULL) {
1634                      xmlChar *buffer;
1635  
1636                      /* todo: do we need to normalize comment? */
1637                      buffer = xmlC11NNormalizeComment(cur->content);
1638                      if (buffer != NULL) {
1639                          xmlOutputBufferWriteString(ctx->buf,
1640                                                     (const char *) buffer);
1641                          xmlFree(buffer);
1642                      } else {
1643                          xmlC14NErrInternal("normalizing comment node");
1644                          return (-1);
1645                      }
1646                  }
1647  
1648                  if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
1649                      xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
1650                  } else {
1651                      xmlOutputBufferWriteString(ctx->buf, "-->");
1652                  }
1653              }
1654              break;
1655          case XML_DOCUMENT_NODE:
1656          case XML_DOCUMENT_FRAG_NODE:   /* should be processed as document? */
1657  #ifdef LIBXML_DOCB_ENABLED
1658          case XML_DOCB_DOCUMENT_NODE:   /* should be processed as document? */
1659  #endif
1660  #ifdef LIBXML_HTML_ENABLED
1661          case XML_HTML_DOCUMENT_NODE:   /* should be processed as document? */
1662  #endif
1663              if (cur->children != NULL) {
1664                  ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1665                  ctx->parent_is_doc = 1;
1666                  ret = xmlC14NProcessNodeList(ctx, cur->children);
1667              }
1668              break;
1669  
1670          case XML_ATTRIBUTE_NODE:
1671              xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node");
1672              return (-1);
1673          case XML_NAMESPACE_DECL:
1674              xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node");
1675              return (-1);
1676          case XML_ENTITY_REF_NODE:
1677              xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node");
1678              return (-1);
1679          case XML_ENTITY_NODE:
1680              xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node");
1681              return (-1);
1682  
1683          case XML_DOCUMENT_TYPE_NODE:
1684          case XML_NOTATION_NODE:
1685          case XML_DTD_NODE:
1686          case XML_ELEMENT_DECL:
1687          case XML_ATTRIBUTE_DECL:
1688          case XML_ENTITY_DECL:
1689  #ifdef LIBXML_XINCLUDE_ENABLED
1690          case XML_XINCLUDE_START:
1691          case XML_XINCLUDE_END:
1692  #endif
1693              /*
1694               * should be ignored according to "W3C Canonical XML"
1695               */
1696              break;
1697          default:
1698              xmlC14NErrUnknownNode(cur->type, "processing node");
1699              return (-1);
1700      }
1701  
1702      return (ret);
1703  }
1704  
1705  /**
1706   * xmlC14NProcessNodeList:
1707   * @ctx:		the pointer to C14N context object
1708   * @cur:		the node to start from
1709   *
1710   * Processes all nodes in the row starting from cur.
1711   *
1712   * Returns non-negative value on success or negative value on fail
1713   */
1714  static int
1715  xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
1716  {
1717      int ret;
1718  
1719      if (ctx == NULL) {
1720          xmlC14NErrParam("processing node list");
1721          return (-1);
1722      }
1723  
1724      for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
1725          ret = xmlC14NProcessNode(ctx, cur);
1726      }
1727      return (ret);
1728  }
1729  
1730  
1731  /**
1732   * xmlC14NFreeCtx:
1733   * @ctx: the pointer to C14N context object
1734   *
1735   * Cleanups the C14N context object.
1736   */
1737  
1738  static void
1739  xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
1740  {
1741      if (ctx == NULL) {
1742          xmlC14NErrParam("freeing context");
1743          return;
1744      }
1745  
1746      if (ctx->ns_rendered != NULL) {
1747          xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
1748      }
1749      xmlFree(ctx);
1750  }
1751  
1752  /**
1753   * xmlC14NNewCtx:
1754   * @doc:		the XML document for canonization
1755   * @is_visible_callback:the function to use to determine is node visible
1756   *			or not
1757   * @user_data:		the first parameter for @is_visible_callback function
1758   *			(in most cases, it is nodes set)
1759   * @mode:   the c14n mode (see @xmlC14NMode)
1760   * @inclusive_ns_prefixe the list of inclusive namespace prefixes
1761   *			ended with a NULL or NULL if there is no
1762   *			inclusive namespaces (only for `
1763   *			canonicalization)
1764   * @with_comments:	include comments in the result (!=0) or not (==0)
1765   * @buf:		the output buffer to store canonical XML; this
1766   *			buffer MUST have encoder==NULL because C14N requires
1767   *			UTF-8 output
1768   *
1769   * Creates new C14N context object to store C14N parameters.
1770   *
1771   * Returns pointer to newly created object (success) or NULL (fail)
1772   */
1773  static xmlC14NCtxPtr
1774  xmlC14NNewCtx(xmlDocPtr doc,
1775  	      xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
1776                xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes,
1777                int with_comments, xmlOutputBufferPtr buf)
1778  {
1779      xmlC14NCtxPtr ctx = NULL;
1780  
1781      if ((doc == NULL) || (buf == NULL)) {
1782          xmlC14NErrParam("creating new context");
1783          return (NULL);
1784      }
1785  
1786      /*
1787       *  Validate the encoding output buffer encoding
1788       */
1789      if (buf->encoder != NULL) {
1790          xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1791  "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
1792          return (NULL);
1793      }
1794  
1795      /*
1796       *  Validate the XML document encoding value, if provided.
1797       */
1798      if (doc->charset != XML_CHAR_ENCODING_UTF8) {
1799          xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1800  		   "xmlC14NNewCtx: source document not in UTF8\n");
1801          return (NULL);
1802      }
1803  
1804      /*
1805       * Allocate a new xmlC14NCtxPtr and fill the fields.
1806       */
1807      ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
1808      if (ctx == NULL) {
1809  	xmlC14NErrMemory("creating context");
1810          return (NULL);
1811      }
1812      memset(ctx, 0, sizeof(xmlC14NCtx));
1813  
1814      /*
1815       * initialize C14N context
1816       */
1817      ctx->doc = doc;
1818      ctx->with_comments = with_comments;
1819      ctx->is_visible_callback = is_visible_callback;
1820      ctx->user_data = user_data;
1821      ctx->buf = buf;
1822      ctx->parent_is_doc = 1;
1823      ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
1824      ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
1825  
1826      if(ctx->ns_rendered == NULL) {
1827          xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
1828  		   "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
1829  	xmlC14NFreeCtx(ctx);
1830          return (NULL);
1831      }
1832  
1833      /*
1834       * Set "mode" flag and remember list of incluseve prefixes
1835       * for exclusive c14n
1836       */
1837      ctx->mode = mode;
1838      if(xmlC14NIsExclusive(ctx)) {
1839          ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
1840      }
1841      return (ctx);
1842  }
1843  
1844  /**
1845   * xmlC14NExecute:
1846   * @doc:		the XML document for canonization
1847   * @is_visible_callback:the function to use to determine is node visible
1848   *			or not
1849   * @user_data:		the first parameter for @is_visible_callback function
1850   *			(in most cases, it is nodes set)
1851   * @mode:	the c14n mode (see @xmlC14NMode)
1852   * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1853   *			ended with a NULL or NULL if there is no
1854   *			inclusive namespaces (only for exclusive
1855   *			canonicalization, ignored otherwise)
1856   * @with_comments:	include comments in the result (!=0) or not (==0)
1857   * @buf:		the output buffer to store canonical XML; this
1858   *			buffer MUST have encoder==NULL because C14N requires
1859   *			UTF-8 output
1860   *
1861   * Dumps the canonized image of given XML document into the provided buffer.
1862   * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1863   * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1864   *
1865   * Returns non-negative value on success or a negative value on fail
1866   */
1867  int
1868  xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
1869  	 void* user_data, int mode, xmlChar **inclusive_ns_prefixes,
1870  	 int with_comments, xmlOutputBufferPtr buf) {
1871  
1872      xmlC14NCtxPtr ctx;
1873      xmlC14NMode c14n_mode = XML_C14N_1_0;
1874      int ret;
1875  
1876      if ((buf == NULL) || (doc == NULL)) {
1877          xmlC14NErrParam("executing c14n");
1878          return (-1);
1879      }
1880  
1881      /* for backward compatibility, we have to have "mode" as "int"
1882         and here we check that user gives valid value */
1883      switch(mode) {
1884      case XML_C14N_1_0:
1885      case XML_C14N_EXCLUSIVE_1_0:
1886      case XML_C14N_1_1:
1887           c14n_mode = (xmlC14NMode)mode;
1888           break;
1889      default:
1890          xmlC14NErrParam("invalid mode for executing c14n");
1891          return (-1);
1892      }
1893  
1894      /*
1895       *  Validate the encoding output buffer encoding
1896       */
1897      if (buf->encoder != NULL) {
1898          xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
1899  "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
1900          return (-1);
1901      }
1902  
1903      ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data,
1904  	            c14n_mode, inclusive_ns_prefixes,
1905                      with_comments, buf);
1906      if (ctx == NULL) {
1907          xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
1908  		   "xmlC14NExecute: unable to create C14N context\n");
1909          return (-1);
1910      }
1911  
1912  
1913  
1914      /*
1915       * Root Node
1916       * The root node is the parent of the top-level document element. The
1917       * result of processing each of its child nodes that is in the node-set
1918       * in document order. The root node does not generate a byte order mark,
1919       * XML declaration, nor anything from within the document type
1920       * declaration.
1921       */
1922      if (doc->children != NULL) {
1923          ret = xmlC14NProcessNodeList(ctx, doc->children);
1924          if (ret < 0) {
1925              xmlC14NErrInternal("processing docs children list");
1926              xmlC14NFreeCtx(ctx);
1927              return (-1);
1928          }
1929      }
1930  
1931      /*
1932       * Flush buffer to get number of bytes written
1933       */
1934      ret = xmlOutputBufferFlush(buf);
1935      if (ret < 0) {
1936          xmlC14NErrInternal("flushing output buffer");
1937          xmlC14NFreeCtx(ctx);
1938          return (-1);
1939      }
1940  
1941      /*
1942       * Cleanup
1943       */
1944      xmlC14NFreeCtx(ctx);
1945      return (ret);
1946  }
1947  
1948  /**
1949   * xmlC14NDocSaveTo:
1950   * @doc:		the XML document for canonization
1951   * @nodes:		the nodes set to be included in the canonized image
1952   *		or NULL if all document nodes should be included
1953   * @mode:		the c14n mode (see @xmlC14NMode)
1954   * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1955   *			ended with a NULL or NULL if there is no
1956   *			inclusive namespaces (only for exclusive
1957   *			canonicalization, ignored otherwise)
1958   * @with_comments:	include comments in the result (!=0) or not (==0)
1959   * @buf:		the output buffer to store canonical XML; this
1960   *			buffer MUST have encoder==NULL because C14N requires
1961   *			UTF-8 output
1962   *
1963   * Dumps the canonized image of given XML document into the provided buffer.
1964   * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
1965   * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
1966   *
1967   * Returns non-negative value on success or a negative value on fail
1968   */
1969  int
1970  xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
1971                   int mode, xmlChar ** inclusive_ns_prefixes,
1972                   int with_comments, xmlOutputBufferPtr buf) {
1973      return(xmlC14NExecute(doc,
1974  			(xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
1975  			nodes,
1976  			mode,
1977  			inclusive_ns_prefixes,
1978  			with_comments,
1979  			buf));
1980  }
1981  
1982  
1983  /**
1984   * xmlC14NDocDumpMemory:
1985   * @doc:		the XML document for canonization
1986   * @nodes:		the nodes set to be included in the canonized image
1987   *		or NULL if all document nodes should be included
1988   * @mode:		the c14n mode (see @xmlC14NMode)
1989   * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
1990   *			ended with a NULL or NULL if there is no
1991   *			inclusive namespaces (only for exclusive
1992   *			canonicalization, ignored otherwise)
1993   * @with_comments:	include comments in the result (!=0) or not (==0)
1994   * @doc_txt_ptr:	the memory pointer for allocated canonical XML text;
1995   *			the caller of this functions is responsible for calling
1996   *			xmlFree() to free allocated memory
1997   *
1998   * Dumps the canonized image of given XML document into memory.
1999   * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
2000   * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
2001   *
2002   * Returns the number of bytes written on success or a negative value on fail
2003   */
2004  int
2005  xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
2006                       int mode, xmlChar ** inclusive_ns_prefixes,
2007                       int with_comments, xmlChar ** doc_txt_ptr)
2008  {
2009      int ret;
2010      xmlOutputBufferPtr buf;
2011  
2012      if (doc_txt_ptr == NULL) {
2013          xmlC14NErrParam("dumping doc to memory");
2014          return (-1);
2015      }
2016  
2017      *doc_txt_ptr = NULL;
2018  
2019      /*
2020       * create memory buffer with UTF8 (default) encoding
2021       */
2022      buf = xmlAllocOutputBuffer(NULL);
2023      if (buf == NULL) {
2024          xmlC14NErrMemory("creating output buffer");
2025          return (-1);
2026      }
2027  
2028      /*
2029       * canonize document and write to buffer
2030       */
2031      ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
2032                             with_comments, buf);
2033      if (ret < 0) {
2034          xmlC14NErrInternal("saving doc to output buffer");
2035          (void) xmlOutputBufferClose(buf);
2036          return (-1);
2037      }
2038  
2039      ret = xmlBufUse(buf->buffer);
2040      if (ret >= 0) {
2041          *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), ret);
2042      }
2043      (void) xmlOutputBufferClose(buf);
2044  
2045      if ((*doc_txt_ptr == NULL) && (ret >= 0)) {
2046          xmlC14NErrMemory("copying canonicalized document");
2047          return (-1);
2048      }
2049      return (ret);
2050  }
2051  
2052  /**
2053   * xmlC14NDocSave:
2054   * @doc:		the XML document for canonization
2055   * @nodes:		the nodes set to be included in the canonized image
2056   *		or NULL if all document nodes should be included
2057   * @mode:		the c14n mode (see @xmlC14NMode)
2058   * @inclusive_ns_prefixes: the list of inclusive namespace prefixes
2059   *			ended with a NULL or NULL if there is no
2060   *			inclusive namespaces (only for exclusive
2061   *			canonicalization, ignored otherwise)
2062   * @with_comments:	include comments in the result (!=0) or not (==0)
2063   * @filename:		the filename to store canonical XML image
2064   * @compression:	the compression level (zlib requred):
2065   *				-1 - libxml default,
2066   *				 0 - uncompressed,
2067   *				>0 - compression level
2068   *
2069   * Dumps the canonized image of given XML document into the file.
2070   * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or
2071   * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n)
2072   *
2073   * Returns the number of bytes written success or a negative value on fail
2074   */
2075  int
2076  xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
2077                 int mode, xmlChar ** inclusive_ns_prefixes,
2078                 int with_comments, const char *filename, int compression)
2079  {
2080      xmlOutputBufferPtr buf;
2081      int ret;
2082  
2083      if (filename == NULL) {
2084          xmlC14NErrParam("saving doc");
2085          return (-1);
2086      }
2087  #ifdef HAVE_ZLIB_H
2088      if (compression < 0)
2089          compression = xmlGetCompressMode();
2090  #endif
2091  
2092      /*
2093       * save the content to a temp buffer, use default UTF8 encoding.
2094       */
2095      buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
2096      if (buf == NULL) {
2097          xmlC14NErrInternal("creating temporary filename");
2098          return (-1);
2099      }
2100  
2101      /*
2102       * canonize document and write to buffer
2103       */
2104      ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
2105                             with_comments, buf);
2106      if (ret < 0) {
2107          xmlC14NErrInternal("cannicanize document to buffer");
2108          (void) xmlOutputBufferClose(buf);
2109          return (-1);
2110      }
2111  
2112      /*
2113       * get the numbers of bytes written
2114       */
2115      ret = xmlOutputBufferClose(buf);
2116      return (ret);
2117  }
2118  
2119  
2120  
2121  /*
2122   * Macro used to grow the current buffer.
2123   */
2124  #define growBufferReentrant() {						\
2125      buffer_size *= 2;							\
2126      buffer = (xmlChar *)						\
2127  		xmlRealloc(buffer, buffer_size * sizeof(xmlChar));	\
2128      if (buffer == NULL) {						\
2129  	xmlC14NErrMemory("growing buffer");				\
2130  	return(NULL);							\
2131      }									\
2132  }
2133  
2134  /**
2135   * xmlC11NNormalizeString:
2136   * @input:		the input string
2137   * @mode:		the normalization mode (attribute, comment, PI or text)
2138   *
2139   * Converts a string to a canonical (normalized) format. The code is stolen
2140   * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A
2141   * and the @mode parameter
2142   *
2143   * Returns a normalized string (caller is responsible for calling xmlFree())
2144   * or NULL if an error occurs
2145   */
2146  static xmlChar *
2147  xmlC11NNormalizeString(const xmlChar * input,
2148                         xmlC14NNormalizationMode mode)
2149  {
2150      const xmlChar *cur = input;
2151      xmlChar *buffer = NULL;
2152      xmlChar *out = NULL;
2153      int buffer_size = 0;
2154  
2155      if (input == NULL)
2156          return (NULL);
2157  
2158      /*
2159       * allocate an translation buffer.
2160       */
2161      buffer_size = 1000;
2162      buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
2163      if (buffer == NULL) {
2164  	xmlC14NErrMemory("allocating buffer");
2165          return (NULL);
2166      }
2167      out = buffer;
2168  
2169      while (*cur != '\0') {
2170          if ((out - buffer) > (buffer_size - 10)) {
2171              int indx = out - buffer;
2172  
2173              growBufferReentrant();
2174              out = &buffer[indx];
2175          }
2176  
2177          if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2178                                (mode == XMLC14N_NORMALIZE_TEXT))) {
2179              *out++ = '&';
2180              *out++ = 'l';
2181              *out++ = 't';
2182              *out++ = ';';
2183          } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
2184              *out++ = '&';
2185              *out++ = 'g';
2186              *out++ = 't';
2187              *out++ = ';';
2188          } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2189                                       (mode == XMLC14N_NORMALIZE_TEXT))) {
2190              *out++ = '&';
2191              *out++ = 'a';
2192              *out++ = 'm';
2193              *out++ = 'p';
2194              *out++ = ';';
2195          } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2196              *out++ = '&';
2197              *out++ = 'q';
2198              *out++ = 'u';
2199              *out++ = 'o';
2200              *out++ = 't';
2201              *out++ = ';';
2202          } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2203              *out++ = '&';
2204              *out++ = '#';
2205              *out++ = 'x';
2206              *out++ = '9';
2207              *out++ = ';';
2208          } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
2209              *out++ = '&';
2210              *out++ = '#';
2211              *out++ = 'x';
2212              *out++ = 'A';
2213              *out++ = ';';
2214          } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
2215                                          (mode == XMLC14N_NORMALIZE_TEXT) ||
2216                                          (mode == XMLC14N_NORMALIZE_COMMENT) ||
2217  					(mode == XMLC14N_NORMALIZE_PI))) {
2218              *out++ = '&';
2219              *out++ = '#';
2220              *out++ = 'x';
2221              *out++ = 'D';
2222              *out++ = ';';
2223          } else {
2224              /*
2225               * Works because on UTF-8, all extended sequences cannot
2226               * result in bytes in the ASCII range.
2227               */
2228              *out++ = *cur;
2229          }
2230          cur++;
2231      }
2232      *out = 0;
2233      return (buffer);
2234  }
2235  #endif /* LIBXML_OUTPUT_ENABLED */
2236  #define bottom_c14n
2237  #include "elfgcchack.h"
2238  #endif /* LIBXML_C14N_ENABLED */