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