ReactOS Fundraising Campaign 2012
 
€ 3,303 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

c14n.c

Go to the documentation of this file.
00001 /*
00002  * "Canonical XML" implementation 
00003  * http://www.w3.org/TR/xml-c14n
00004  * 
00005  * "Exclusive XML Canonicalization" implementation
00006  * http://www.w3.org/TR/xml-exc-c14n
00007  *
00008  * See Copyright for the status of this software.
00009  * 
00010  * Author: Aleksey Sanin <aleksey@aleksey.com>
00011  */
00012 #define IN_LIBXML
00013 #include "libxml.h"
00014 #ifdef LIBXML_C14N_ENABLED
00015 #ifdef LIBXML_OUTPUT_ENABLED
00016 
00017 #ifdef HAVE_STDLIB_H
00018 #include <stdlib.h>
00019 #endif
00020 #include <string.h>
00021 
00022 #include <libxml/tree.h>
00023 #include <libxml/parser.h>
00024 #include <libxml/uri.h>
00025 #include <libxml/xmlerror.h>
00026 #include <libxml/globals.h>
00027 #include <libxml/xpathInternals.h>
00028 #include <libxml/c14n.h>
00029 
00030 /************************************************************************
00031  *                                  *
00032  *      Some declaration better left private ATM        *
00033  *                                  *
00034  ************************************************************************/
00035 
00036 typedef enum {
00037     XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0,
00038     XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1,
00039     XMLC14N_AFTER_DOCUMENT_ELEMENT = 2
00040 } xmlC14NPosition;
00041 
00042 typedef struct _xmlC14NVisibleNsStack {
00043     int nsCurEnd;           /* number of nodes in the set */
00044     int nsPrevStart;        /* the begginning of the stack for previous visible node */
00045     int nsPrevEnd;          /* the end of the stack for previous visible node */
00046     int nsMax;              /* size of the array as allocated */
00047     xmlNsPtr    *nsTab;     /* array of ns in no particular order */          
00048     xmlNodePtr  *nodeTab;   /* array of nodes in no particular order */
00049 } xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr;
00050 
00051 typedef struct _xmlC14NCtx {
00052     /* input parameters */
00053     xmlDocPtr doc;
00054     xmlC14NIsVisibleCallback is_visible_callback;
00055     void* user_data;    
00056     int with_comments;
00057     xmlOutputBufferPtr buf;
00058 
00059     /* position in the XML document */
00060     xmlC14NPosition pos;
00061     int parent_is_doc;
00062     xmlC14NVisibleNsStackPtr ns_rendered;
00063     
00064     /* C14N mode */
00065     xmlC14NMode mode;
00066 
00067     /* exclusive canonicalization */
00068     xmlChar **inclusive_ns_prefixes;
00069 
00070     /* error number */
00071     int error;
00072 } xmlC14NCtx, *xmlC14NCtxPtr;
00073 
00074 static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void);
00075 static void     xmlC14NVisibleNsStackDestroy    (xmlC14NVisibleNsStackPtr cur);
00076 static void     xmlC14NVisibleNsStackAdd        (xmlC14NVisibleNsStackPtr cur, 
00077                                                  xmlNsPtr ns,
00078                                                  xmlNodePtr node);
00079 static void             xmlC14NVisibleNsStackSave   (xmlC14NVisibleNsStackPtr cur,
00080                                  xmlC14NVisibleNsStackPtr state);
00081 static void             xmlC14NVisibleNsStackRestore    (xmlC14NVisibleNsStackPtr cur,
00082                                  xmlC14NVisibleNsStackPtr state);
00083 static void             xmlC14NVisibleNsStackShift  (xmlC14NVisibleNsStackPtr cur);
00084 static int          xmlC14NVisibleNsStackFind   (xmlC14NVisibleNsStackPtr cur, 
00085                                  xmlNsPtr ns);
00086 static int          xmlExcC14NVisibleNsStackFind    (xmlC14NVisibleNsStackPtr cur, 
00087                                  xmlNsPtr ns,
00088                                  xmlC14NCtxPtr ctx);
00089 
00090 static int          xmlC14NIsNodeInNodeset      (xmlNodeSetPtr nodes,
00091                                  xmlNodePtr node,
00092                                  xmlNodePtr parent);
00093 
00094 
00095 
00096 static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur);
00097 static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur);
00098 typedef enum {
00099     XMLC14N_NORMALIZE_ATTR = 0,
00100     XMLC14N_NORMALIZE_COMMENT = 1,
00101     XMLC14N_NORMALIZE_PI = 2,
00102     XMLC14N_NORMALIZE_TEXT = 3
00103 } xmlC14NNormalizationMode;
00104 
00105 static xmlChar *xmlC11NNormalizeString(const xmlChar * input,
00106                                        xmlC14NNormalizationMode mode);
00107 
00108 #define     xmlC11NNormalizeAttr( a ) \
00109     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR)
00110 #define     xmlC11NNormalizeComment( a ) \
00111     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT)
00112 #define     xmlC11NNormalizePI( a ) \
00113     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI)
00114 #define     xmlC11NNormalizeText( a ) \
00115     xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT)
00116 
00117 #define     xmlC14NIsVisible( ctx, node, parent ) \
00118      (((ctx)->is_visible_callback != NULL) ? \
00119     (ctx)->is_visible_callback((ctx)->user_data, \
00120         (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1)
00121 
00122 #define     xmlC14NIsExclusive( ctx ) \
00123     ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 )
00124 
00125 /************************************************************************
00126  *                                  *
00127  *      Some factorized error routines              *
00128  *                                  *
00129  ************************************************************************/
00130 
00137 static void
00138 xmlC14NErrMemory(const char *extra)
00139 {
00140     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00141             XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
00142             NULL, NULL, 0, 0,
00143             "Memory allocation failed : %s\n", extra);
00144 }
00145 
00152 static void
00153 xmlC14NErrParam(const char *extra)
00154 {
00155     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00156             XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
00157             NULL, NULL, 0, 0,
00158             "Invalid parameter : %s\n", extra);
00159 }
00160 
00167 static void
00168 xmlC14NErrInternal(const char *extra)
00169 {
00170     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00171             XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra,
00172             NULL, NULL, 0, 0,
00173             "Internal error : %s\n", extra);
00174 }
00175 
00182 static void
00183 xmlC14NErrInvalidNode(const char *node_type, const char *extra)
00184 {
00185     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00186             XML_C14N_INVALID_NODE, XML_ERR_ERROR, NULL, 0, extra,
00187             NULL, NULL, 0, 0,
00188             "Node %s is invalid here : %s\n", node_type, extra);
00189 }
00190 
00197 static void
00198 xmlC14NErrUnknownNode(int node_type, const char *extra)
00199 {
00200     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00201             XML_C14N_UNKNOW_NODE, XML_ERR_ERROR, NULL, 0, extra,
00202             NULL, NULL, 0, 0,
00203             "Unknown node type %d found : %s\n", node_type, extra);
00204 }
00205 
00212 static void
00213 xmlC14NErrRelativeNamespace(const char *ns_uri)
00214 {
00215     __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N,
00216             XML_C14N_RELATIVE_NAMESPACE, XML_ERR_ERROR, NULL, 0, NULL,
00217             NULL, NULL, 0, 0,
00218             "Relative namespace UR is invalid here : %s\n", ns_uri);
00219 }
00220 
00221 
00222 
00233 static void
00234 xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error,
00235            const char * msg)
00236 {
00237     if (ctxt != NULL)
00238         ctxt->error = error;
00239     __xmlRaiseError(NULL, NULL, NULL,
00240             ctxt, node, XML_FROM_C14N, error,
00241             XML_ERR_ERROR, NULL, 0,
00242             NULL, NULL, NULL, 0, 0, "%s", msg);
00243 }
00244 
00245 /************************************************************************
00246  *                                  *
00247  *      The implementation internals                *
00248  *                                  *
00249  ************************************************************************/
00250 #define XML_NAMESPACES_DEFAULT      16
00251 
00252 static int          
00253 xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) {
00254     if((nodes != NULL) && (node != NULL)) {
00255     if(node->type != XML_NAMESPACE_DECL) {
00256         return(xmlXPathNodeSetContains(nodes, node));
00257     } else {
00258         xmlNs ns;
00259         
00260         memcpy(&ns, node, sizeof(ns)); 
00261         
00262         /* this is a libxml hack! check xpath.c for details */
00263         if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) {
00264         ns.next = (xmlNsPtr)parent->parent;
00265         } else {
00266         ns.next = (xmlNsPtr)parent; 
00267         }
00268 
00269         /* 
00270          * If the input is an XPath node-set, then the node-set must explicitly 
00271          * contain every node to be rendered to the canonical form.
00272          */
00273         return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns));
00274     }
00275     }
00276     return(1);
00277 }
00278 
00279 static xmlC14NVisibleNsStackPtr
00280 xmlC14NVisibleNsStackCreate(void) {
00281     xmlC14NVisibleNsStackPtr ret;
00282 
00283     ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack));
00284     if (ret == NULL) {
00285         xmlC14NErrMemory("creating namespaces stack");
00286     return(NULL);
00287     }
00288     memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack));
00289     return(ret);
00290 }
00291 
00292 static void
00293 xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) {
00294     if(cur == NULL) {
00295         xmlC14NErrParam("destroying namespaces stack");
00296         return;
00297     }
00298     if(cur->nsTab != NULL) {
00299     memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr));
00300     xmlFree(cur->nsTab);
00301     }
00302     if(cur->nodeTab != NULL) {
00303     memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr));
00304     xmlFree(cur->nodeTab);
00305     }
00306     memset(cur, 0, sizeof(xmlC14NVisibleNsStack));
00307     xmlFree(cur);
00308     
00309 }
00310 
00311 static void 
00312 xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) {
00313     if((cur == NULL) || 
00314        ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) ||
00315        ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) {
00316         xmlC14NErrParam("adding namespace to stack");
00317     return;
00318     }
00319 
00320     if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) {
00321         cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
00322         cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
00323     if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) {
00324         xmlC14NErrMemory("adding node to stack");
00325         return;
00326     }
00327     memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr));
00328     memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr));
00329         cur->nsMax = XML_NAMESPACES_DEFAULT;
00330     } else if(cur->nsMax == cur->nsCurEnd) {
00331     void *tmp;  
00332     int tmpSize;
00333     
00334     tmpSize = 2 * cur->nsMax;
00335     tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr));
00336     if (tmp == NULL) {
00337         xmlC14NErrMemory("adding node to stack");
00338         return;
00339     }
00340     cur->nsTab = (xmlNsPtr*)tmp;
00341 
00342     tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr));
00343     if (tmp == NULL) {
00344         xmlC14NErrMemory("adding node to stack");
00345         return;
00346     }
00347     cur->nodeTab = (xmlNodePtr*)tmp;
00348 
00349     cur->nsMax = tmpSize;
00350     }
00351     cur->nsTab[cur->nsCurEnd] = ns;
00352     cur->nodeTab[cur->nsCurEnd] = node;
00353 
00354     ++cur->nsCurEnd;
00355 }
00356 
00357 static void
00358 xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
00359     if((cur == NULL) || (state == NULL)) {
00360         xmlC14NErrParam("saving namespaces stack");
00361     return;
00362     }
00363     
00364     state->nsCurEnd = cur->nsCurEnd;
00365     state->nsPrevStart = cur->nsPrevStart;
00366     state->nsPrevEnd = cur->nsPrevEnd;
00367 }
00368 
00369 static void
00370 xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) {
00371     if((cur == NULL) || (state == NULL)) {
00372         xmlC14NErrParam("restoring namespaces stack");
00373     return;
00374     }
00375     cur->nsCurEnd = state->nsCurEnd;
00376     cur->nsPrevStart = state->nsPrevStart;
00377     cur->nsPrevEnd = state->nsPrevEnd;
00378 }
00379 
00380 static void 
00381 xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) {
00382     if(cur == NULL) {
00383         xmlC14NErrParam("shifting namespaces stack");
00384     return;
00385     }
00386     cur->nsPrevStart = cur->nsPrevEnd;
00387     cur->nsPrevEnd = cur->nsCurEnd;
00388 }
00389 
00390 static int
00391 xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) {
00392     if (str1 == str2) return(1);
00393     if (str1 == NULL) return((*str2) == '\0');
00394     if (str2 == NULL) return((*str1) == '\0');
00395     do {
00396     if (*str1++ != *str2) return(0);
00397     } while (*str2++);
00398     return(1);
00399 }
00400 
00410 static int
00411 xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns)
00412 {
00413     int i;
00414     const xmlChar *prefix;
00415     const xmlChar *href;
00416     int has_empty_ns;
00417         
00418     if(cur == NULL) {
00419         xmlC14NErrParam("searching namespaces stack (c14n)");
00420         return (0);
00421     }
00422 
00423     /*
00424      * if the default namespace xmlns="" is not defined yet then 
00425      * we do not want to print it out
00426      */
00427     prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
00428     href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
00429     has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
00430 
00431     if (cur->nsTab != NULL) {
00432     int start = (has_empty_ns) ? 0 : cur->nsPrevStart;
00433         for (i = cur->nsCurEnd - 1; i >= start; --i) {
00434             xmlNsPtr ns1 = cur->nsTab[i];
00435         
00436         if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
00437         return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL));
00438         }
00439         }
00440     }
00441     return(has_empty_ns);
00442 }
00443 
00444 static int          
00445 xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) {
00446     int i;
00447     const xmlChar *prefix;
00448     const xmlChar *href;
00449     int has_empty_ns;
00450         
00451     if(cur == NULL) {
00452         xmlC14NErrParam("searching namespaces stack (exc c14n)");
00453         return (0);
00454     }
00455 
00456     /*
00457      * if the default namespace xmlns="" is not defined yet then 
00458      * we do not want to print it out
00459      */
00460     prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix;
00461     href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href;
00462     has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL));
00463 
00464     if (cur->nsTab != NULL) {
00465     int start = 0;
00466         for (i = cur->nsCurEnd - 1; i >= start; --i) {
00467             xmlNsPtr ns1 = cur->nsTab[i];
00468         
00469         if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) {
00470         if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) {
00471                 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i]));
00472         } else {
00473             return(0);
00474         }
00475         }
00476         }
00477     }
00478     return(has_empty_ns);
00479 }
00480 
00481 
00482 
00483 
00494 /* todo: make it a define? */
00495 static int
00496 xmlC14NIsXmlNs(xmlNsPtr ns)
00497 {
00498     return ((ns != NULL) &&
00499             (xmlStrEqual(ns->prefix, BAD_CAST "xml")) &&
00500             (xmlStrEqual(ns->href, XML_XML_NAMESPACE)));
00501 }
00502 
00503 
00513 static int
00514 xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2)
00515 {
00516     if (ns1 == ns2)
00517         return (0);
00518     if (ns1 == NULL)
00519         return (-1);
00520     if (ns2 == NULL)
00521         return (1);
00522 
00523     return (xmlStrcmp(ns1->prefix, ns2->prefix));
00524 }
00525 
00526 
00536 static int
00537 xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx)
00538 {
00539 
00540     if ((ns == NULL) || (ctx == NULL)) {
00541         xmlC14NErrParam("writing namespaces");
00542         return 0;
00543     }
00544 
00545     if (ns->prefix != NULL) {
00546         xmlOutputBufferWriteString(ctx->buf, " xmlns:");
00547         xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix);
00548         xmlOutputBufferWriteString(ctx->buf, "=\"");
00549     } else {
00550         xmlOutputBufferWriteString(ctx->buf, " xmlns=\"");
00551     }
00552     if(ns->href != NULL) {
00553     xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href);
00554     }
00555     xmlOutputBufferWriteString(ctx->buf, "\"");
00556     return (1);
00557 }
00558 
00598 static int
00599 xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
00600 {
00601     xmlNodePtr n;
00602     xmlNsPtr ns, tmp;
00603     xmlListPtr list;
00604     int already_rendered;
00605     int has_empty_ns = 0;
00606     
00607     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
00608         xmlC14NErrParam("processing namespaces axis (c14n)");
00609         return (-1);
00610     }
00611 
00612     /*
00613      * Create a sorted list to store element namespaces
00614      */
00615     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
00616     if (list == NULL) {
00617         xmlC14NErrInternal("creating namespaces list (c14n)");
00618         return (-1);
00619     }
00620 
00621     /* check all namespaces */
00622     for(n = cur; n != NULL; n = n->parent) {
00623     for(ns = n->nsDef; ns != NULL; ns = ns->next) {
00624         tmp = xmlSearchNs(cur->doc, cur, ns->prefix);
00625         
00626         if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
00627         already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
00628         if(visible) {
00629                 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
00630         }
00631         if(!already_rendered) {
00632             xmlListInsert(list, ns); 
00633         }
00634             if(xmlStrlen(ns->prefix) == 0) {
00635             has_empty_ns = 1;
00636         }
00637         }
00638     }
00639     }
00640     
00650     if(visible && !has_empty_ns) {
00651         static xmlNs ns_default;
00652 
00653         memset(&ns_default, 0, sizeof(ns_default));
00654         if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
00655             xmlC14NPrintNamespaces(&ns_default, ctx);
00656     }
00657     }
00658     
00659     
00660     /* 
00661      * print out all elements from list 
00662      */
00663     xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
00664 
00665     /* 
00666      * Cleanup
00667      */
00668     xmlListDelete(list);
00669     return (0);
00670 }
00671 
00672 
00703 static int
00704 xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
00705 {
00706     xmlNsPtr ns;
00707     xmlListPtr list;
00708     xmlAttrPtr attr;
00709     int already_rendered;
00710     int has_empty_ns = 0;
00711     int has_visibly_utilized_empty_ns = 0;
00712     int has_empty_ns_in_inclusive_list = 0;
00713         
00714     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
00715         xmlC14NErrParam("processing namespaces axis (exc c14n)");
00716         return (-1);
00717     }
00718 
00719     if(!xmlC14NIsExclusive(ctx)) {
00720         xmlC14NErrParam("processing namespaces axis (exc c14n)");
00721         return (-1);
00722 
00723     }
00724 
00725     /*
00726      * Create a sorted list to store element namespaces
00727      */
00728     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare);
00729     if (list == NULL) {
00730         xmlC14NErrInternal("creating namespaces list (exc c14n)");
00731         return (-1);
00732     }
00733 
00734     /* 
00735      * process inclusive namespaces:
00736      * All namespace nodes appearing on inclusive ns list are 
00737      * handled as provided in Canonical XML
00738      */
00739     if(ctx->inclusive_ns_prefixes != NULL) {
00740     xmlChar *prefix; 
00741     int i;
00742     
00743     for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) {
00744         prefix = ctx->inclusive_ns_prefixes[i];
00745         /*
00746          * Special values for namespace with empty prefix
00747          */
00748             if (xmlStrEqual(prefix, BAD_CAST "#default")
00749                 || xmlStrEqual(prefix, BAD_CAST "")) {
00750                 prefix = NULL;
00751         has_empty_ns_in_inclusive_list = 1;
00752             }
00753     
00754         ns = xmlSearchNs(cur->doc, cur, prefix);        
00755         if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) {
00756         already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns);
00757         if(visible) {
00758                     xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur);
00759         }
00760         if(!already_rendered) {
00761                 xmlListInsert(list, ns); 
00762         }
00763             if(xmlStrlen(ns->prefix) == 0) {
00764             has_empty_ns = 1;
00765         }
00766         }
00767     }
00768     }
00769     
00770     /* add node namespace */
00771     if(cur->ns != NULL) {
00772     ns = cur->ns;
00773     } else {
00774         ns = xmlSearchNs(cur->doc, cur, NULL);
00775     has_visibly_utilized_empty_ns = 1;
00776     }
00777     if((ns != NULL) && !xmlC14NIsXmlNs(ns)) {
00778     if(visible && xmlC14NIsVisible(ctx, ns, cur)) { 
00779         if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) {
00780         xmlListInsert(list, ns);
00781         }
00782     }
00783     if(visible) {
00784             xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); 
00785     }
00786     if(xmlStrlen(ns->prefix) == 0) {
00787         has_empty_ns = 1;
00788     }
00789     }
00790     
00791         
00792     /* add attributes */
00793     for(attr = cur->properties; attr != NULL; attr = attr->next) {
00794         /* 
00795          * we need to check that attribute is visible and has non
00796          * default namespace (XML Namespaces: "default namespaces 
00797          * do not apply directly to attributes")     
00798          */
00799     if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) {
00800         already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx);
00801         xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur); 
00802         if(!already_rendered && visible) {
00803         xmlListInsert(list, attr->ns); 
00804         }
00805         if(xmlStrlen(attr->ns->prefix) == 0) {
00806         has_empty_ns = 1;
00807         }
00808     } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) {
00809         has_visibly_utilized_empty_ns = 1;
00810     }
00811     }
00812 
00813     /*
00814      * Process xmlns=""
00815      */
00816     if(visible && has_visibly_utilized_empty_ns && 
00817         !has_empty_ns && !has_empty_ns_in_inclusive_list) {
00818         static xmlNs ns_default;
00819 
00820         memset(&ns_default, 0, sizeof(ns_default));
00821     
00822         already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx);
00823     if(!already_rendered) {
00824             xmlC14NPrintNamespaces(&ns_default, ctx);
00825     }
00826     } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) {
00827         static xmlNs ns_default;
00828 
00829         memset(&ns_default, 0, sizeof(ns_default));
00830         if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) {
00831             xmlC14NPrintNamespaces(&ns_default, ctx);
00832     }
00833     }
00834 
00835     
00836 
00837     /* 
00838      * print out all elements from list 
00839      */
00840     xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx);
00841 
00842     /* 
00843      * Cleanup
00844      */
00845     xmlListDelete(list);
00846     return (0);
00847 }
00848 
00849 
00860 /* todo: make it a define? */
00861 static int
00862 xmlC14NIsXmlAttr(xmlAttrPtr attr)
00863 {
00864     return ((attr->ns != NULL) && 
00865            (xmlC14NIsXmlNs(attr->ns) != 0));
00866 }
00867 
00868 
00878 static int
00879 xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2)
00880 {
00881     int ret = 0;
00882 
00883     /*
00884      * Simple cases
00885      */
00886     if (attr1 == attr2)
00887         return (0);
00888     if (attr1 == NULL)
00889         return (-1);
00890     if (attr2 == NULL)
00891         return (1);
00892     if (attr1->ns == attr2->ns) {
00893         return (xmlStrcmp(attr1->name, attr2->name));
00894     }
00895 
00896     /* 
00897      * Attributes in the default namespace are first
00898      * because the default namespace is not applied to
00899      * unqualified attributes
00900      */
00901     if (attr1->ns == NULL)
00902         return (-1);
00903     if (attr2->ns == NULL)
00904         return (1);
00905     if (attr1->ns->prefix == NULL)
00906         return (-1);
00907     if (attr2->ns->prefix == NULL)
00908         return (1);
00909 
00910     ret = xmlStrcmp(attr1->ns->href, attr2->ns->href);
00911     if (ret == 0) {
00912         ret = xmlStrcmp(attr1->name, attr2->name);
00913     }
00914     return (ret);
00915 }
00916 
00917 
00930 static int
00931 xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx)
00932 {
00933     xmlChar *value;
00934     xmlChar *buffer;
00935 
00936     if ((attr == NULL) || (ctx == NULL)) {
00937         xmlC14NErrParam("writing attributes");
00938         return (0);
00939     }
00940 
00941     xmlOutputBufferWriteString(ctx->buf, " ");
00942     if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) {
00943         xmlOutputBufferWriteString(ctx->buf,
00944                                    (const char *) attr->ns->prefix);
00945         xmlOutputBufferWriteString(ctx->buf, ":");
00946     }
00947     xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name);
00948     xmlOutputBufferWriteString(ctx->buf, "=\"");
00949 
00950     value = xmlNodeListGetString(ctx->doc, attr->children, 1);
00951     /* todo: should we log an error if value==NULL ? */
00952     if (value != NULL) {
00953         buffer = xmlC11NNormalizeAttr(value);
00954         xmlFree(value);
00955         if (buffer != NULL) {
00956             xmlOutputBufferWriteString(ctx->buf, (const char *) buffer);
00957             xmlFree(buffer);
00958         } else {
00959             xmlC14NErrInternal("normalizing attributes axis");
00960             return (0);
00961         }
00962     }
00963     xmlOutputBufferWriteString(ctx->buf, "\"");
00964     return (1);
00965 }
00966 
00974 static xmlAttrPtr
00975 xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns)
00976 {
00977     xmlAttrPtr res;
00978     while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
00979         res = xmlHasNsProp(cur, name, ns);
00980         if(res != NULL) {
00981             return res;
00982         }
00983 
00984         cur = cur->parent;
00985     }
00986 
00987     return NULL;
00988 }
00989 
00997 static xmlAttrPtr
00998 xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr)
00999 {    
01000     xmlChar * res = NULL;
01001     xmlNodePtr cur;
01002     xmlAttrPtr attr;
01003     xmlChar * tmp_str;
01004     xmlChar * tmp_str2;
01005     int tmp_str_len;
01006 
01007     if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) {
01008         xmlC14NErrParam("processing xml:base attribute");
01009         return (NULL);
01010     }
01011 
01012     /* start from current value */
01013     res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1);
01014     if(res == NULL) {
01015         xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
01016         return (NULL);
01017     }
01018 
01019     /* go up the stack until we find a node that we rendered already */
01020     cur = xml_base_attr->parent->parent;
01021     while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) {
01022         attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE);
01023         if(attr != NULL) {
01024             /* get attr value */
01025             tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1);
01026             if(tmp_str == NULL) {
01027                 xmlFree(res);
01028 
01029                 xmlC14NErrInternal("processing xml:base attribute - can't get attr value");
01030                 return (NULL);
01031             } 
01032 
01033             /* we need to add '/' if our current base uri ends with '..' or '.' 
01034             to ensure that we are forced to go "up" all the time */
01035             tmp_str_len = xmlStrlen(tmp_str);
01036             if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') {
01037                 tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/");
01038                 if(tmp_str2 == NULL) {
01039                     xmlFree(tmp_str);
01040                     xmlFree(res);
01041 
01042                     xmlC14NErrInternal("processing xml:base attribute - can't modify uri");
01043                     return (NULL);
01044                 }
01045 
01046                 tmp_str = tmp_str2;
01047             }
01048 
01049             /* build uri */
01050             tmp_str2 = xmlBuildURI(res, tmp_str); 
01051             if(tmp_str2 == NULL) {
01052                 xmlFree(tmp_str);
01053                 xmlFree(res);
01054 
01055                 xmlC14NErrInternal("processing xml:base attribute - can't construct uri");
01056                 return (NULL);
01057             }
01058 
01059             /* cleanup and set the new res */
01060             xmlFree(tmp_str);
01061             xmlFree(res);
01062             res = tmp_str2;
01063         }
01064 
01065         /* next */
01066         cur = cur->parent;
01067     }
01068 
01069     /* check if result uri is empty or not */
01070     if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) {
01071         xmlFree(res);
01072         return (NULL);
01073     }
01074 
01075     /* create and return the new attribute node */
01076     attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res);
01077     if(attr == NULL) {
01078         xmlFree(res);
01079 
01080         xmlC14NErrInternal("processing xml:base attribute - can't construct attribute");
01081         return (NULL);
01082     }
01083  
01084     /* done */
01085     xmlFree(res);
01086     return (attr);
01087 }
01088 
01122 static int
01123 xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible)
01124 {
01125     xmlAttrPtr attr;
01126     xmlListPtr list;    
01127     xmlAttrPtr attrs_to_delete = NULL;
01128     
01129     /* special processing for 1.1 spec */
01130     xmlAttrPtr xml_base_attr = NULL;
01131     xmlAttrPtr xml_lang_attr = NULL;
01132     xmlAttrPtr xml_space_attr = NULL;
01133 
01134     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
01135         xmlC14NErrParam("processing attributes axis");
01136         return (-1);
01137     }
01138 
01139     /*
01140      * Create a sorted list to store element attributes
01141      */
01142     list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare);
01143     if (list == NULL) {
01144         xmlC14NErrInternal("creating attributes list");
01145         return (-1);
01146     }
01147 
01148     switch(ctx->mode) {
01149     case XML_C14N_1_0:
01150         /* The processing of an element node E MUST be modified slightly when an XPath node-set is 
01151          * given as input and the element's parent is omitted from the node-set. The method for processing 
01152          * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's 
01153          * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such 
01154          * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes, 
01155          * remove any that are in E's attribute axis (whether or not they are in the node-set). Then, 
01156          * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 
01157          * the node-set. The result of visiting the attribute axis is computed by processing the attribute 
01158          * nodes in this merged attribute list. 
01159          */
01160     
01161         /* 
01162          * Add all visible attributes from current node. 
01163          */
01164         attr = cur->properties;
01165         while (attr != NULL) {
01166             /* check that attribute is visible */
01167             if (xmlC14NIsVisible(ctx, attr, cur)) {
01168                 xmlListInsert(list, attr);
01169             }
01170             attr = attr->next;
01171         }
01172 
01173         /* 
01174          * Handle xml attributes
01175          */
01176         if (parent_visible && (cur->parent != NULL) && 
01177             (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) 
01178         {
01179             xmlNodePtr tmp;
01180 
01181             /*
01182              * If XPath node-set is not specified then the parent is always 
01183              * visible!
01184              */
01185             tmp = cur->parent;
01186             while (tmp != NULL) {
01187                 attr = tmp->properties;
01188                 while (attr != NULL) {
01189                     if (xmlC14NIsXmlAttr(attr) != 0) {
01190                         if (xmlListSearch(list, attr) == NULL) {
01191                             xmlListInsert(list, attr);
01192                         }
01193                     }
01194                     attr = attr->next;
01195                 }
01196                 tmp = tmp->parent;
01197             }
01198         }
01199 
01200         /* done */
01201         break;
01202     case XML_C14N_EXCLUSIVE_1_0:
01203         /* attributes in the XML namespace, such as xml:lang and xml:space 
01204          * are not imported into orphan nodes of the document subset 
01205          */
01206 
01207         /* 
01208          * Add all visible attributes from current node. 
01209          */
01210         attr = cur->properties;
01211         while (attr != NULL) {
01212             /* check that attribute is visible */
01213             if (xmlC14NIsVisible(ctx, attr, cur)) {
01214                 xmlListInsert(list, attr);
01215             }
01216             attr = attr->next;
01217         }
01218 
01219         /* do nothing special for xml attributes */
01220         break;
01221     case XML_C14N_1_1:
01222         /* The processing of an element node E MUST be modified slightly when an XPath node-set is 
01223          * given as input and some of the element's ancestors are omitted from the node-set. 
01224          *
01225          * Simple inheritable attributes are attributes that have a value that requires at most a simple 
01226          * redeclaration. This redeclaration is done by supplying a new value in the child axis. The 
01227          * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done 
01228          * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes 
01229          * are xml:lang and xml:space.
01230          * 
01231          * The method for processing the attribute axis of an element E in the node-set is hence enhanced. 
01232          * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple 
01233          * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they 
01234          * are in the node-set). From this list of attributes, any simple inheritable attributes that are 
01235          * already in E's attribute axis (whether or not they are in the node-set) are removed. Then, 
01236          * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 
01237          * the node-set. The result of visiting the attribute axis is computed by processing the attribute 
01238          * nodes in this merged attribute list.
01239          * 
01240          * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is 
01241          * performed.
01242          * 
01243          * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond 
01244          * a simple redeclaration.
01245          * 
01246          * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed 
01247          * as ordinary attributes.
01248          */
01249 
01250         /* 
01251          * Add all visible attributes from current node. 
01252          */
01253         attr = cur->properties;
01254         while (attr != NULL) {
01255             /* special processing for XML attribute kiks in only when we have invisible parents */
01256             if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) {
01257                 /* check that attribute is visible */
01258                 if (xmlC14NIsVisible(ctx, attr, cur)) {
01259                     xmlListInsert(list, attr);
01260                 }
01261             } else {
01262                 int matched = 0;
01263 
01264                 /* check for simple inheritance attributes */
01265                 if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) {
01266                     xml_lang_attr = attr;
01267                     matched = 1;
01268                 } 
01269                 if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) {
01270                     xml_space_attr = attr;
01271                     matched = 1;
01272                 }
01273 
01274                 /* check for base attr */
01275                 if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) {
01276                     xml_base_attr = attr;
01277                     matched = 1;
01278                 }
01279 
01280                 /* otherwise, it is a normal attribute, so just check if it is visible */
01281                 if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) {
01282                     xmlListInsert(list, attr);
01283                 }
01284             }
01285          
01286             /* move to the next one */
01287             attr = attr->next;
01288         }
01289             
01290         /* special processing for XML attribute kiks in only when we have invisible parents */
01291         if ((parent_visible)) {
01292 
01293             /* simple inheritance attributes - copy */
01294             if(xml_lang_attr == NULL) {
01295                 xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE);
01296             }
01297             if(xml_lang_attr != NULL) {
01298                 xmlListInsert(list, xml_lang_attr);
01299             }
01300             if(xml_space_attr == NULL) {
01301                 xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE);
01302             }
01303             if(xml_space_attr != NULL) {
01304                 xmlListInsert(list, xml_space_attr);
01305             }
01306 
01307             /* base uri attribute - fix up */
01308             if(xml_base_attr == NULL) {
01309                 /* if we don't have base uri attribute, check if we have a "hidden" one above */
01310                 xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE);
01311             }
01312             if(xml_base_attr != NULL) {
01313                 xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr);
01314                 if(xml_base_attr != NULL) {                    
01315                     xmlListInsert(list, xml_base_attr);
01316 
01317                     /* note that we MUST delete returned attr node ourselves! */
01318                     xml_base_attr->next = attrs_to_delete;
01319                     attrs_to_delete = xml_base_attr;
01320                 }
01321             }
01322         }
01323 
01324         /* done */
01325         break;
01326     }
01327 
01328     /* 
01329      * print out all elements from list 
01330      */
01331     xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx);
01332 
01333     /* 
01334      * Cleanup
01335      */
01336     xmlFreePropList(attrs_to_delete);
01337     xmlListDelete(list);
01338     return (0);
01339 }
01340 
01350 static int
01351 xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur)
01352 {
01353     xmlNsPtr ns;
01354 
01355     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
01356         xmlC14NErrParam("checking for relative namespaces");
01357         return (-1);
01358     }
01359 
01360     ns = cur->nsDef;
01361     while (ns != NULL) {
01362         if (xmlStrlen(ns->href) > 0) {
01363             xmlURIPtr uri;
01364 
01365             uri = xmlParseURI((const char *) ns->href);
01366             if (uri == NULL) {
01367                 xmlC14NErrInternal("parsing namespace uri");
01368                 return (-1);
01369             }
01370             if (xmlStrlen((const xmlChar *) uri->scheme) == 0) {
01371                 xmlC14NErrRelativeNamespace(uri->scheme);
01372                 xmlFreeURI(uri);
01373                 return (-1);
01374             }
01375             if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0)
01376                 && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0)
01377                 && (xmlStrlen((const xmlChar *) uri->server) == 0)) {
01378                 xmlC14NErrRelativeNamespace(uri->scheme);
01379                 xmlFreeURI(uri);
01380                 return (-1);
01381             }
01382             xmlFreeURI(uri);
01383         }
01384         ns = ns->next;
01385     }
01386     return (0);
01387 }
01388 
01412 static int
01413 xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible)
01414 {
01415     int ret;
01416     xmlC14NVisibleNsStack state;
01417     int parent_is_doc = 0;
01418 
01419     if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) {
01420         xmlC14NErrParam("processing element node");
01421         return (-1);
01422     }
01423 
01424     /* 
01425      * Check relative relative namespaces:
01426      * implementations of XML canonicalization MUST report an operation
01427      * failure on documents containing relative namespace URIs.
01428      */
01429     if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) {
01430         xmlC14NErrInternal("checking for relative namespaces");
01431         return (-1);
01432     }
01433 
01434 
01435     /* 
01436      * Save ns_rendered stack position
01437      */
01438     memset(&state, 0, sizeof(state));
01439     xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state);
01440 
01441     if (visible) {  
01442         if (ctx->parent_is_doc) {
01443         /* save this flag into the stack */
01444         parent_is_doc = ctx->parent_is_doc;
01445         ctx->parent_is_doc = 0;
01446             ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT;
01447         }
01448         xmlOutputBufferWriteString(ctx->buf, "<");
01449 
01450         if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
01451             xmlOutputBufferWriteString(ctx->buf,
01452                                        (const char *) cur->ns->prefix);
01453             xmlOutputBufferWriteString(ctx->buf, ":");
01454         }
01455         xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
01456     }
01457 
01458     if (!xmlC14NIsExclusive(ctx)) {
01459         ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible);
01460     } else {
01461         ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible);
01462     }
01463     if (ret < 0) {
01464         xmlC14NErrInternal("processing namespaces axis");
01465         return (-1);
01466     }
01467     /* todo: shouldn't this go to "visible only"? */
01468     if(visible) {
01469     xmlC14NVisibleNsStackShift(ctx->ns_rendered);
01470     }
01471     
01472     ret = xmlC14NProcessAttrsAxis(ctx, cur, visible);
01473     if (ret < 0) {
01474     xmlC14NErrInternal("processing attributes axis");
01475         return (-1);
01476     }
01477 
01478     if (visible) { 
01479         xmlOutputBufferWriteString(ctx->buf, ">");
01480     }
01481     if (cur->children != NULL) {
01482         ret = xmlC14NProcessNodeList(ctx, cur->children);
01483         if (ret < 0) {
01484             xmlC14NErrInternal("processing childrens list");
01485             return (-1);
01486         }
01487     }
01488     if (visible) {
01489         xmlOutputBufferWriteString(ctx->buf, "</");
01490         if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) {
01491             xmlOutputBufferWriteString(ctx->buf,
01492                                        (const char *) cur->ns->prefix);
01493             xmlOutputBufferWriteString(ctx->buf, ":");
01494         }
01495         xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name);
01496         xmlOutputBufferWriteString(ctx->buf, ">");
01497         if (parent_is_doc) {
01498         /* restore this flag from the stack for next node */
01499             ctx->parent_is_doc = parent_is_doc;
01500         ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT;
01501         }
01502     }
01503 
01504     /* 
01505      * Restore ns_rendered stack position
01506      */
01507     xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state);
01508     return (0);
01509 }
01510 
01520 static int
01521 xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur)
01522 {
01523     int ret = 0;
01524     int visible;
01525 
01526     if ((ctx == NULL) || (cur == NULL)) {
01527         xmlC14NErrParam("processing node");
01528         return (-1);
01529     }
01530 
01531     visible = xmlC14NIsVisible(ctx, cur, cur->parent);
01532     switch (cur->type) {
01533         case XML_ELEMENT_NODE:
01534             ret = xmlC14NProcessElementNode(ctx, cur, visible);
01535             break;
01536         case XML_CDATA_SECTION_NODE:
01537         case XML_TEXT_NODE:
01538             /*
01539              * Text Nodes
01540              * the string value, except all ampersands are replaced 
01541              * by &amp;, all open angle brackets (<) are replaced by &lt;, all closing 
01542              * angle brackets (>) are replaced by &gt;, and all #xD characters are 
01543              * replaced by &#xD;.
01544              */
01545             /* cdata sections are processed as text nodes */
01546             /* todo: verify that cdata sections are included in XPath nodes set */
01547             if ((visible) && (cur->content != NULL)) {
01548                 xmlChar *buffer;
01549 
01550                 buffer = xmlC11NNormalizeText(cur->content);
01551                 if (buffer != NULL) {
01552                     xmlOutputBufferWriteString(ctx->buf,
01553                                                (const char *) buffer);
01554                     xmlFree(buffer);
01555                 } else {
01556                     xmlC14NErrInternal("normalizing text node");
01557                     return (-1);
01558                 }
01559             }
01560             break;
01561         case XML_PI_NODE:
01562             /* 
01563              * Processing Instruction (PI) Nodes- 
01564              * The opening PI symbol (<?), the PI target name of the node, 
01565              * a leading space and the string value if it is not empty, and 
01566              * the closing PI symbol (?>). If the string value is empty, 
01567              * then the leading space is not added. Also, a trailing #xA is 
01568              * rendered after the closing PI symbol for PI children of the 
01569              * root node with a lesser document order than the document 
01570              * element, and a leading #xA is rendered before the opening PI 
01571              * symbol of PI children of the root node with a greater document 
01572              * order than the document element.
01573              */
01574             if (visible) {
01575                 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
01576                     xmlOutputBufferWriteString(ctx->buf, "\x0A<?");
01577                 } else {
01578                     xmlOutputBufferWriteString(ctx->buf, "<?");
01579                 }
01580 
01581                 xmlOutputBufferWriteString(ctx->buf,
01582                                            (const char *) cur->name);
01583                 if ((cur->content != NULL) && (*(cur->content) != '\0')) {
01584                     xmlChar *buffer;
01585 
01586                     xmlOutputBufferWriteString(ctx->buf, " ");
01587 
01588                     /* todo: do we need to normalize pi? */
01589                     buffer = xmlC11NNormalizePI(cur->content);
01590                     if (buffer != NULL) {
01591                         xmlOutputBufferWriteString(ctx->buf,
01592                                                    (const char *) buffer);
01593                         xmlFree(buffer);
01594                     } else {
01595                         xmlC14NErrInternal("normalizing pi node");
01596                         return (-1);
01597                     }
01598                 }
01599 
01600                 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
01601                     xmlOutputBufferWriteString(ctx->buf, "?>\x0A");
01602                 } else {
01603                     xmlOutputBufferWriteString(ctx->buf, "?>");
01604                 }
01605             }
01606             break;
01607         case XML_COMMENT_NODE:
01608             /*
01609              * Comment Nodes
01610              * Nothing if generating canonical XML without  comments. For 
01611              * canonical XML with comments, generate the opening comment 
01612              * symbol (<!--), the string value of the node, and the 
01613              * closing comment symbol (-->). Also, a trailing #xA is rendered 
01614              * after the closing comment symbol for comment children of the 
01615              * root node with a lesser document order than the document 
01616              * element, and a leading #xA is rendered before the opening 
01617              * comment symbol of comment children of the root node with a 
01618              * greater document order than the document element. (Comment 
01619              * children of the root node represent comments outside of the 
01620              * top-level document element and outside of the document type 
01621              * declaration).
01622              */
01623             if (visible && ctx->with_comments) {
01624                 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) {
01625                     xmlOutputBufferWriteString(ctx->buf, "\x0A<!--");
01626                 } else {
01627                     xmlOutputBufferWriteString(ctx->buf, "<!--");
01628                 }
01629 
01630                 if (cur->content != NULL) {
01631                     xmlChar *buffer;
01632 
01633                     /* todo: do we need to normalize comment? */
01634                     buffer = xmlC11NNormalizeComment(cur->content);
01635                     if (buffer != NULL) {
01636                         xmlOutputBufferWriteString(ctx->buf,
01637                                                    (const char *) buffer);
01638                         xmlFree(buffer);
01639                     } else {
01640                         xmlC14NErrInternal("normalizing comment node");
01641                         return (-1);
01642                     }
01643                 }
01644 
01645                 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) {
01646                     xmlOutputBufferWriteString(ctx->buf, "-->\x0A");
01647                 } else {
01648                     xmlOutputBufferWriteString(ctx->buf, "-->");
01649                 }
01650             }
01651             break;
01652         case XML_DOCUMENT_NODE:
01653         case XML_DOCUMENT_FRAG_NODE:   /* should be processed as document? */
01654 #ifdef LIBXML_DOCB_ENABLED
01655         case XML_DOCB_DOCUMENT_NODE:   /* should be processed as document? */
01656 #endif
01657 #ifdef LIBXML_HTML_ENABLED
01658         case XML_HTML_DOCUMENT_NODE:   /* should be processed as document? */
01659 #endif
01660             if (cur->children != NULL) {
01661                 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
01662                 ctx->parent_is_doc = 1;
01663                 ret = xmlC14NProcessNodeList(ctx, cur->children);
01664             }
01665             break;
01666 
01667         case XML_ATTRIBUTE_NODE:
01668             xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node");
01669             return (-1);
01670         case XML_NAMESPACE_DECL:
01671             xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node");
01672             return (-1);
01673         case XML_ENTITY_REF_NODE:
01674             xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node");
01675             return (-1);
01676         case XML_ENTITY_NODE:
01677             xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node");
01678             return (-1);
01679 
01680         case XML_DOCUMENT_TYPE_NODE:
01681         case XML_NOTATION_NODE:
01682         case XML_DTD_NODE:
01683         case XML_ELEMENT_DECL:
01684         case XML_ATTRIBUTE_DECL:
01685         case XML_ENTITY_DECL:
01686 #ifdef LIBXML_XINCLUDE_ENABLED
01687         case XML_XINCLUDE_START:
01688         case XML_XINCLUDE_END:
01689 #endif
01690             /* 
01691              * should be ignored according to "W3C Canonical XML" 
01692              */
01693             break;
01694         default:
01695             xmlC14NErrUnknownNode(cur->type, "processing node");
01696             return (-1);
01697     }
01698 
01699     return (ret);
01700 }
01701 
01711 static int
01712 xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur)
01713 {
01714     int ret;
01715 
01716     if (ctx == NULL) {
01717         xmlC14NErrParam("processing node list");
01718         return (-1);
01719     }
01720 
01721     for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) {
01722         ret = xmlC14NProcessNode(ctx, cur);
01723     }
01724     return (ret);
01725 }
01726 
01727 
01735 static void
01736 xmlC14NFreeCtx(xmlC14NCtxPtr ctx)
01737 {
01738     if (ctx == NULL) {
01739         xmlC14NErrParam("freeing context");
01740         return;
01741     }
01742 
01743     if (ctx->ns_rendered != NULL) {
01744         xmlC14NVisibleNsStackDestroy(ctx->ns_rendered);
01745     }
01746     xmlFree(ctx);
01747 }
01748 
01770 static xmlC14NCtxPtr
01771 xmlC14NNewCtx(xmlDocPtr doc,  
01772           xmlC14NIsVisibleCallback is_visible_callback, void* user_data,
01773               xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes,
01774               int with_comments, xmlOutputBufferPtr buf)
01775 {
01776     xmlC14NCtxPtr ctx = NULL;
01777 
01778     if ((doc == NULL) || (buf == NULL)) {
01779         xmlC14NErrParam("creating new context");
01780         return (NULL);
01781     }
01782 
01783     /*
01784      *  Validate the encoding output buffer encoding
01785      */
01786     if (buf->encoder != NULL) {
01787         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
01788 "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n");
01789         return (NULL);
01790     }
01791 
01792     /*
01793      *  Validate the XML document encoding value, if provided.
01794      */
01795     if (doc->charset != XML_CHAR_ENCODING_UTF8) {
01796         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
01797            "xmlC14NNewCtx: source document not in UTF8\n");
01798         return (NULL);
01799     }
01800 
01801     /*
01802      * Allocate a new xmlC14NCtxPtr and fill the fields.
01803      */
01804     ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx));
01805     if (ctx == NULL) {
01806     xmlC14NErrMemory("creating context");
01807         return (NULL);
01808     }
01809     memset(ctx, 0, sizeof(xmlC14NCtx));
01810 
01811     /*
01812      * initialize C14N context
01813      */
01814     ctx->doc = doc;
01815     ctx->with_comments = with_comments;
01816     ctx->is_visible_callback = is_visible_callback;
01817     ctx->user_data = user_data;
01818     ctx->buf = buf;
01819     ctx->parent_is_doc = 1;
01820     ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT;
01821     ctx->ns_rendered = xmlC14NVisibleNsStackCreate();
01822 
01823     if(ctx->ns_rendered == NULL) {
01824         xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK,
01825            "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n");
01826     xmlC14NFreeCtx(ctx);
01827         return (NULL);
01828     }
01829 
01830     /*
01831      * Set "mode" flag and remember list of incluseve prefixes
01832      * for exclusive c14n
01833      */
01834     ctx->mode = mode;
01835     if(xmlC14NIsExclusive(ctx)) {
01836         ctx->inclusive_ns_prefixes = inclusive_ns_prefixes;
01837     }
01838     return (ctx);
01839 }
01840 
01864 int         
01865 xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback,
01866      void* user_data, int mode, xmlChar **inclusive_ns_prefixes,
01867      int with_comments, xmlOutputBufferPtr buf) {
01868 
01869     xmlC14NCtxPtr ctx;
01870     xmlC14NMode c14n_mode = XML_C14N_1_0;
01871     int ret;
01872 
01873     if ((buf == NULL) || (doc == NULL)) {
01874         xmlC14NErrParam("executing c14n");
01875         return (-1);
01876     }
01877 
01878     /* for backward compatibility, we have to have "mode" as "int" 
01879        and here we check that user gives valid value */
01880     switch(mode) {
01881     case XML_C14N_1_0:
01882     case XML_C14N_EXCLUSIVE_1_0:
01883     case XML_C14N_1_1: 
01884          c14n_mode = (xmlC14NMode)mode;
01885          break;
01886     default:       
01887         xmlC14NErrParam("invalid mode for executing c14n");
01888         return (-1);
01889     }
01890 
01891     /*
01892      *  Validate the encoding output buffer encoding
01893      */
01894     if (buf->encoder != NULL) {
01895         xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8,
01896 "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n");
01897         return (-1);
01898     }
01899 
01900     ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data, 
01901                 c14n_mode, inclusive_ns_prefixes,
01902                     with_comments, buf);
01903     if (ctx == NULL) {
01904         xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT,
01905            "xmlC14NExecute: unable to create C14N context\n");
01906         return (-1);
01907     }
01908 
01909 
01910 
01911     /*  
01912      * Root Node
01913      * The root node is the parent of the top-level document element. The 
01914      * result of processing each of its child nodes that is in the node-set 
01915      * in document order. The root node does not generate a byte order mark, 
01916      * XML declaration, nor anything from within the document type 
01917      * declaration.
01918      */
01919     if (doc->children != NULL) {
01920         ret = xmlC14NProcessNodeList(ctx, doc->children);
01921         if (ret < 0) {
01922             xmlC14NErrInternal("processing docs children list");
01923             xmlC14NFreeCtx(ctx);
01924             return (-1);
01925         }
01926     }
01927 
01928     /*
01929      * Flush buffer to get number of bytes written
01930      */
01931     ret = xmlOutputBufferFlush(buf);
01932     if (ret < 0) {
01933         xmlC14NErrInternal("flushing output buffer");
01934         xmlC14NFreeCtx(ctx);
01935         return (-1);
01936     }
01937 
01938     /* 
01939      * Cleanup
01940      */
01941     xmlC14NFreeCtx(ctx);
01942     return (ret);
01943 }
01944 
01966 int
01967 xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes,
01968                  int mode, xmlChar ** inclusive_ns_prefixes,
01969                  int with_comments, xmlOutputBufferPtr buf) {
01970     return(xmlC14NExecute(doc, 
01971             (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset,
01972             nodes,
01973             mode,
01974             inclusive_ns_prefixes,
01975             with_comments,
01976             buf));
01977 }
01978 
01979 
02001 int
02002 xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes,
02003                      int mode, xmlChar ** inclusive_ns_prefixes,
02004                      int with_comments, xmlChar ** doc_txt_ptr)
02005 {
02006     int ret;
02007     xmlOutputBufferPtr buf;
02008 
02009     if (doc_txt_ptr == NULL) {
02010         xmlC14NErrParam("dumping doc to memory");
02011         return (-1);
02012     }
02013 
02014     *doc_txt_ptr = NULL;
02015 
02016     /*
02017      * create memory buffer with UTF8 (default) encoding 
02018      */
02019     buf = xmlAllocOutputBuffer(NULL);
02020     if (buf == NULL) {
02021         xmlC14NErrMemory("creating output buffer");
02022         return (-1);
02023     }
02024 
02025     /*
02026      * canonize document and write to buffer
02027      */
02028     ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
02029                            with_comments, buf);
02030     if (ret < 0) {
02031         xmlC14NErrInternal("saving doc to output buffer");
02032         (void) xmlOutputBufferClose(buf);
02033         return (-1);
02034     }
02035 
02036     ret = buf->buffer->use;
02037     if (ret > 0) {
02038         *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret);
02039     }
02040     (void) xmlOutputBufferClose(buf);
02041 
02042     if ((*doc_txt_ptr == NULL) && (ret > 0)) {
02043         xmlC14NErrMemory("coping canonicanized document");
02044         return (-1);
02045     }
02046     return (ret);
02047 }
02048 
02072 int
02073 xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes,
02074                int mode, xmlChar ** inclusive_ns_prefixes,
02075                int with_comments, const char *filename, int compression)
02076 {
02077     xmlOutputBufferPtr buf;
02078     int ret;
02079 
02080     if (filename == NULL) {
02081         xmlC14NErrParam("saving doc");
02082         return (-1);
02083     }
02084 #ifdef HAVE_ZLIB_H
02085     if (compression < 0)
02086         compression = xmlGetCompressMode();
02087 #endif
02088 
02089     /* 
02090      * save the content to a temp buffer, use default UTF8 encoding.
02091      */
02092     buf = xmlOutputBufferCreateFilename(filename, NULL, compression);
02093     if (buf == NULL) {
02094         xmlC14NErrInternal("creating temporary filename");
02095         return (-1);
02096     }
02097 
02098     /*
02099      * canonize document and write to buffer
02100      */
02101     ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes,
02102                            with_comments, buf);
02103     if (ret < 0) {
02104         xmlC14NErrInternal("cannicanize document to buffer");
02105         (void) xmlOutputBufferClose(buf);
02106         return (-1);
02107     }
02108 
02109     /* 
02110      * get the numbers of bytes written 
02111      */
02112     ret = xmlOutputBufferClose(buf);
02113     return (ret);
02114 }
02115 
02116 
02117 
02118 /*
02119  * Macro used to grow the current buffer.
02120  */
02121 #define growBufferReentrant() {                     \
02122     buffer_size *= 2;                           \
02123     buffer = (xmlChar *)                        \
02124             xmlRealloc(buffer, buffer_size * sizeof(xmlChar));  \
02125     if (buffer == NULL) {                       \
02126     xmlC14NErrMemory("growing buffer");             \
02127     return(NULL);                           \
02128     }                                   \
02129 }
02130 
02143 static xmlChar *
02144 xmlC11NNormalizeString(const xmlChar * input,
02145                        xmlC14NNormalizationMode mode)
02146 {
02147     const xmlChar *cur = input;
02148     xmlChar *buffer = NULL;
02149     xmlChar *out = NULL;
02150     int buffer_size = 0;
02151 
02152     if (input == NULL)
02153         return (NULL);
02154 
02155     /*
02156      * allocate an translation buffer.
02157      */
02158     buffer_size = 1000;
02159     buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
02160     if (buffer == NULL) {
02161     xmlC14NErrMemory("allocating buffer");
02162         return (NULL);
02163     }
02164     out = buffer;
02165 
02166     while (*cur != '\0') {
02167         if ((out - buffer) > (buffer_size - 10)) {
02168             int indx = out - buffer;
02169 
02170             growBufferReentrant();
02171             out = &buffer[indx];
02172         }
02173 
02174         if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
02175                               (mode == XMLC14N_NORMALIZE_TEXT))) {
02176             *out++ = '&';
02177             *out++ = 'l';
02178             *out++ = 't';
02179             *out++ = ';';
02180         } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) {
02181             *out++ = '&';
02182             *out++ = 'g';
02183             *out++ = 't';
02184             *out++ = ';';
02185         } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
02186                                      (mode == XMLC14N_NORMALIZE_TEXT))) {
02187             *out++ = '&';
02188             *out++ = 'a';
02189             *out++ = 'm';
02190             *out++ = 'p';
02191             *out++ = ';';
02192         } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) {
02193             *out++ = '&';
02194             *out++ = 'q';
02195             *out++ = 'u';
02196             *out++ = 'o';
02197             *out++ = 't';
02198             *out++ = ';';
02199         } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) {
02200             *out++ = '&';
02201             *out++ = '#';
02202             *out++ = 'x';
02203             *out++ = '9';
02204             *out++ = ';';
02205         } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) {
02206             *out++ = '&';
02207             *out++ = '#';
02208             *out++ = 'x';
02209             *out++ = 'A';
02210             *out++ = ';';
02211         } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) ||
02212                                         (mode == XMLC14N_NORMALIZE_TEXT) ||
02213                                         (mode == XMLC14N_NORMALIZE_COMMENT) ||
02214                     (mode == XMLC14N_NORMALIZE_PI))) {
02215             *out++ = '&';
02216             *out++ = '#';
02217             *out++ = 'x';
02218             *out++ = 'D';
02219             *out++ = ';';
02220         } else {
02221             /*
02222              * Works because on UTF-8, all extended sequences cannot
02223              * result in bytes in the ASCII range.
02224              */
02225             *out++ = *cur;
02226         }
02227         cur++;
02228     }
02229     *out = 0;
02230     return (buffer);
02231 }
02232 #endif /* LIBXML_OUTPUT_ENABLED */
02233 #define bottom_c14n
02234 #include "elfgcchack.h"
02235 #endif /* LIBXML_C14N_ENABLED */

Generated on Tue May 15 04:58:38 2012 for ReactOS by doxygen 1.6.3

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.