Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenc14n.cGo 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 &, all open angle brackets (<) are replaced by <, all closing 01542 * angle brackets (>) are replaced by >, and all #xD characters are 01543 * replaced by 
. 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
1.6.3
|