Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
c14n.c
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 #include "buf.h" 00031 00032 /************************************************************************ 00033 * * 00034 * Some declaration better left private ATM * 00035 * * 00036 ************************************************************************/ 00037 00038 typedef enum { 00039 XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0, 00040 XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1, 00041 XMLC14N_AFTER_DOCUMENT_ELEMENT = 2 00042 } xmlC14NPosition; 00043 00044 typedef struct _xmlC14NVisibleNsStack { 00045 int nsCurEnd; /* number of nodes in the set */ 00046 int nsPrevStart; /* the begginning of the stack for previous visible node */ 00047 int nsPrevEnd; /* the end of the stack for previous visible node */ 00048 int nsMax; /* size of the array as allocated */ 00049 xmlNsPtr *nsTab; /* array of ns in no particular order */ 00050 xmlNodePtr *nodeTab; /* array of nodes in no particular order */ 00051 } xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr; 00052 00053 typedef struct _xmlC14NCtx { 00054 /* input parameters */ 00055 xmlDocPtr doc; 00056 xmlC14NIsVisibleCallback is_visible_callback; 00057 void* user_data; 00058 int with_comments; 00059 xmlOutputBufferPtr buf; 00060 00061 /* position in the XML document */ 00062 xmlC14NPosition pos; 00063 int parent_is_doc; 00064 xmlC14NVisibleNsStackPtr ns_rendered; 00065 00066 /* C14N mode */ 00067 xmlC14NMode mode; 00068 00069 /* exclusive canonicalization */ 00070 xmlChar **inclusive_ns_prefixes; 00071 00072 /* error number */ 00073 int error; 00074 } xmlC14NCtx, *xmlC14NCtxPtr; 00075 00076 static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void); 00077 static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur); 00078 static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur, 00079 xmlNsPtr ns, 00080 xmlNodePtr node); 00081 static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur, 00082 xmlC14NVisibleNsStackPtr state); 00083 static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur, 00084 xmlC14NVisibleNsStackPtr state); 00085 static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur); 00086 static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur, 00087 xmlNsPtr ns); 00088 static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur, 00089 xmlNsPtr ns, 00090 xmlC14NCtxPtr ctx); 00091 00092 static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes, 00093 xmlNodePtr node, 00094 xmlNodePtr parent); 00095 00096 00097 00098 static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur); 00099 static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur); 00100 typedef enum { 00101 XMLC14N_NORMALIZE_ATTR = 0, 00102 XMLC14N_NORMALIZE_COMMENT = 1, 00103 XMLC14N_NORMALIZE_PI = 2, 00104 XMLC14N_NORMALIZE_TEXT = 3 00105 } xmlC14NNormalizationMode; 00106 00107 static xmlChar *xmlC11NNormalizeString(const xmlChar * input, 00108 xmlC14NNormalizationMode mode); 00109 00110 #define xmlC11NNormalizeAttr( a ) \ 00111 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR) 00112 #define xmlC11NNormalizeComment( a ) \ 00113 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT) 00114 #define xmlC11NNormalizePI( a ) \ 00115 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI) 00116 #define xmlC11NNormalizeText( a ) \ 00117 xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT) 00118 00119 #define xmlC14NIsVisible( ctx, node, parent ) \ 00120 (((ctx)->is_visible_callback != NULL) ? \ 00121 (ctx)->is_visible_callback((ctx)->user_data, \ 00122 (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1) 00123 00124 #define xmlC14NIsExclusive( ctx ) \ 00125 ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 ) 00126 00127 /************************************************************************ 00128 * * 00129 * Some factorized error routines * 00130 * * 00131 ************************************************************************/ 00132 00133 /** 00134 * xmlC14NErrMemory: 00135 * @extra: extra informations 00136 * 00137 * Handle a redefinition of memory error 00138 */ 00139 static void 00140 xmlC14NErrMemory(const char *extra) 00141 { 00142 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00143 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, 00144 NULL, NULL, 0, 0, 00145 "Memory allocation failed : %s\n", extra); 00146 } 00147 00148 /** 00149 * xmlC14NErrParam: 00150 * @extra: extra informations 00151 * 00152 * Handle a redefinition of param error 00153 */ 00154 static void 00155 xmlC14NErrParam(const char *extra) 00156 { 00157 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00158 XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra, 00159 NULL, NULL, 0, 0, 00160 "Invalid parameter : %s\n", extra); 00161 } 00162 00163 /** 00164 * xmlC14NErrInternal: 00165 * @extra: extra informations 00166 * 00167 * Handle a redefinition of internal error 00168 */ 00169 static void 00170 xmlC14NErrInternal(const char *extra) 00171 { 00172 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00173 XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra, 00174 NULL, NULL, 0, 0, 00175 "Internal error : %s\n", extra); 00176 } 00177 00178 /** 00179 * xmlC14NErrInvalidNode: 00180 * @extra: extra informations 00181 * 00182 * Handle a redefinition of invalid node error 00183 */ 00184 static void 00185 xmlC14NErrInvalidNode(const char *node_type, const char *extra) 00186 { 00187 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00188 XML_C14N_INVALID_NODE, XML_ERR_ERROR, NULL, 0, extra, 00189 NULL, NULL, 0, 0, 00190 "Node %s is invalid here : %s\n", node_type, extra); 00191 } 00192 00193 /** 00194 * xmlC14NErrUnknownNode: 00195 * @extra: extra informations 00196 * 00197 * Handle a redefinition of unknown node error 00198 */ 00199 static void 00200 xmlC14NErrUnknownNode(int node_type, const char *extra) 00201 { 00202 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00203 XML_C14N_UNKNOW_NODE, XML_ERR_ERROR, NULL, 0, extra, 00204 NULL, NULL, 0, 0, 00205 "Unknown node type %d found : %s\n", node_type, extra); 00206 } 00207 00208 /** 00209 * xmlC14NErrRelativeNamespace: 00210 * @extra: extra informations 00211 * 00212 * Handle a redefinition of relative namespace error 00213 */ 00214 static void 00215 xmlC14NErrRelativeNamespace(const char *ns_uri) 00216 { 00217 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, 00218 XML_C14N_RELATIVE_NAMESPACE, XML_ERR_ERROR, NULL, 0, NULL, 00219 NULL, NULL, 0, 0, 00220 "Relative namespace UR is invalid here : %s\n", ns_uri); 00221 } 00222 00223 00224 00225 /** 00226 * xmlC14NErr: 00227 * @ctxt: a C14N evaluation context 00228 * @node: the context node 00229 * @error: the erorr code 00230 * @msg: the message 00231 * @extra: extra informations 00232 * 00233 * Handle a redefinition of attribute error 00234 */ 00235 static void 00236 xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error, 00237 const char * msg) 00238 { 00239 if (ctxt != NULL) 00240 ctxt->error = error; 00241 __xmlRaiseError(NULL, NULL, NULL, 00242 ctxt, node, XML_FROM_C14N, error, 00243 XML_ERR_ERROR, NULL, 0, 00244 NULL, NULL, NULL, 0, 0, "%s", msg); 00245 } 00246 00247 /************************************************************************ 00248 * * 00249 * The implementation internals * 00250 * * 00251 ************************************************************************/ 00252 #define XML_NAMESPACES_DEFAULT 16 00253 00254 static int 00255 xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) { 00256 if((nodes != NULL) && (node != NULL)) { 00257 if(node->type != XML_NAMESPACE_DECL) { 00258 return(xmlXPathNodeSetContains(nodes, node)); 00259 } else { 00260 xmlNs ns; 00261 00262 memcpy(&ns, node, sizeof(ns)); 00263 00264 /* this is a libxml hack! check xpath.c for details */ 00265 if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) { 00266 ns.next = (xmlNsPtr)parent->parent; 00267 } else { 00268 ns.next = (xmlNsPtr)parent; 00269 } 00270 00271 /* 00272 * If the input is an XPath node-set, then the node-set must explicitly 00273 * contain every node to be rendered to the canonical form. 00274 */ 00275 return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns)); 00276 } 00277 } 00278 return(1); 00279 } 00280 00281 static xmlC14NVisibleNsStackPtr 00282 xmlC14NVisibleNsStackCreate(void) { 00283 xmlC14NVisibleNsStackPtr ret; 00284 00285 ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack)); 00286 if (ret == NULL) { 00287 xmlC14NErrMemory("creating namespaces stack"); 00288 return(NULL); 00289 } 00290 memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack)); 00291 return(ret); 00292 } 00293 00294 static void 00295 xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) { 00296 if(cur == NULL) { 00297 xmlC14NErrParam("destroying namespaces stack"); 00298 return; 00299 } 00300 if(cur->nsTab != NULL) { 00301 memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr)); 00302 xmlFree(cur->nsTab); 00303 } 00304 if(cur->nodeTab != NULL) { 00305 memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr)); 00306 xmlFree(cur->nodeTab); 00307 } 00308 memset(cur, 0, sizeof(xmlC14NVisibleNsStack)); 00309 xmlFree(cur); 00310 00311 } 00312 00313 static void 00314 xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) { 00315 if((cur == NULL) || 00316 ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) || 00317 ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) { 00318 xmlC14NErrParam("adding namespace to stack"); 00319 return; 00320 } 00321 00322 if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) { 00323 cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr)); 00324 cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr)); 00325 if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) { 00326 xmlC14NErrMemory("adding node to stack"); 00327 return; 00328 } 00329 memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr)); 00330 memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr)); 00331 cur->nsMax = XML_NAMESPACES_DEFAULT; 00332 } else if(cur->nsMax == cur->nsCurEnd) { 00333 void *tmp; 00334 int tmpSize; 00335 00336 tmpSize = 2 * cur->nsMax; 00337 tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr)); 00338 if (tmp == NULL) { 00339 xmlC14NErrMemory("adding node to stack"); 00340 return; 00341 } 00342 cur->nsTab = (xmlNsPtr*)tmp; 00343 00344 tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr)); 00345 if (tmp == NULL) { 00346 xmlC14NErrMemory("adding node to stack"); 00347 return; 00348 } 00349 cur->nodeTab = (xmlNodePtr*)tmp; 00350 00351 cur->nsMax = tmpSize; 00352 } 00353 cur->nsTab[cur->nsCurEnd] = ns; 00354 cur->nodeTab[cur->nsCurEnd] = node; 00355 00356 ++cur->nsCurEnd; 00357 } 00358 00359 static void 00360 xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { 00361 if((cur == NULL) || (state == NULL)) { 00362 xmlC14NErrParam("saving namespaces stack"); 00363 return; 00364 } 00365 00366 state->nsCurEnd = cur->nsCurEnd; 00367 state->nsPrevStart = cur->nsPrevStart; 00368 state->nsPrevEnd = cur->nsPrevEnd; 00369 } 00370 00371 static void 00372 xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { 00373 if((cur == NULL) || (state == NULL)) { 00374 xmlC14NErrParam("restoring namespaces stack"); 00375 return; 00376 } 00377 cur->nsCurEnd = state->nsCurEnd; 00378 cur->nsPrevStart = state->nsPrevStart; 00379 cur->nsPrevEnd = state->nsPrevEnd; 00380 } 00381 00382 static void 00383 xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) { 00384 if(cur == NULL) { 00385 xmlC14NErrParam("shifting namespaces stack"); 00386 return; 00387 } 00388 cur->nsPrevStart = cur->nsPrevEnd; 00389 cur->nsPrevEnd = cur->nsCurEnd; 00390 } 00391 00392 static int 00393 xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) { 00394 if (str1 == str2) return(1); 00395 if (str1 == NULL) return((*str2) == '\0'); 00396 if (str2 == NULL) return((*str1) == '\0'); 00397 do { 00398 if (*str1++ != *str2) return(0); 00399 } while (*str2++); 00400 return(1); 00401 } 00402 00403 /** 00404 * xmlC14NVisibleNsStackFind: 00405 * @ctx: the C14N context 00406 * @ns: the namespace to check 00407 * 00408 * Checks whether the given namespace was already rendered or not 00409 * 00410 * Returns 1 if we already wrote this namespace or 0 otherwise 00411 */ 00412 static int 00413 xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns) 00414 { 00415 int i; 00416 const xmlChar *prefix; 00417 const xmlChar *href; 00418 int has_empty_ns; 00419 00420 if(cur == NULL) { 00421 xmlC14NErrParam("searching namespaces stack (c14n)"); 00422 return (0); 00423 } 00424 00425 /* 00426 * if the default namespace xmlns="" is not defined yet then 00427 * we do not want to print it out 00428 */ 00429 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix; 00430 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href; 00431 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL)); 00432 00433 if (cur->nsTab != NULL) { 00434 int start = (has_empty_ns) ? 0 : cur->nsPrevStart; 00435 for (i = cur->nsCurEnd - 1; i >= start; --i) { 00436 xmlNsPtr ns1 = cur->nsTab[i]; 00437 00438 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) { 00439 return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)); 00440 } 00441 } 00442 } 00443 return(has_empty_ns); 00444 } 00445 00446 static int 00447 xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) { 00448 int i; 00449 const xmlChar *prefix; 00450 const xmlChar *href; 00451 int has_empty_ns; 00452 00453 if(cur == NULL) { 00454 xmlC14NErrParam("searching namespaces stack (exc c14n)"); 00455 return (0); 00456 } 00457 00458 /* 00459 * if the default namespace xmlns="" is not defined yet then 00460 * we do not want to print it out 00461 */ 00462 prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix; 00463 href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href; 00464 has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL)); 00465 00466 if (cur->nsTab != NULL) { 00467 int start = 0; 00468 for (i = cur->nsCurEnd - 1; i >= start; --i) { 00469 xmlNsPtr ns1 = cur->nsTab[i]; 00470 00471 if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) { 00472 if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) { 00473 return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i])); 00474 } else { 00475 return(0); 00476 } 00477 } 00478 } 00479 } 00480 return(has_empty_ns); 00481 } 00482 00483 00484 00485 00486 /** 00487 * xmlC14NIsXmlNs: 00488 * @ns: the namespace to check 00489 * 00490 * Checks whether the given namespace is a default "xml:" namespace 00491 * with href="http://www.w3.org/XML/1998/namespace" 00492 * 00493 * Returns 1 if the node is default or 0 otherwise 00494 */ 00495 00496 /* todo: make it a define? */ 00497 static int 00498 xmlC14NIsXmlNs(xmlNsPtr ns) 00499 { 00500 return ((ns != NULL) && 00501 (xmlStrEqual(ns->prefix, BAD_CAST "xml")) && 00502 (xmlStrEqual(ns->href, XML_XML_NAMESPACE))); 00503 } 00504 00505 00506 /** 00507 * xmlC14NNsCompare: 00508 * @ns1: the pointer to first namespace 00509 * @ns2: the pointer to second namespace 00510 * 00511 * Compares the namespaces by names (prefixes). 00512 * 00513 * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2. 00514 */ 00515 static int 00516 xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2) 00517 { 00518 if (ns1 == ns2) 00519 return (0); 00520 if (ns1 == NULL) 00521 return (-1); 00522 if (ns2 == NULL) 00523 return (1); 00524 00525 return (xmlStrcmp(ns1->prefix, ns2->prefix)); 00526 } 00527 00528 00529 /** 00530 * xmlC14NPrintNamespaces: 00531 * @ns: the pointer to namespace 00532 * @ctx: the C14N context 00533 * 00534 * Prints the given namespace to the output buffer from C14N context. 00535 * 00536 * Returns 1 on success or 0 on fail. 00537 */ 00538 static int 00539 xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx) 00540 { 00541 00542 if ((ns == NULL) || (ctx == NULL)) { 00543 xmlC14NErrParam("writing namespaces"); 00544 return 0; 00545 } 00546 00547 if (ns->prefix != NULL) { 00548 xmlOutputBufferWriteString(ctx->buf, " xmlns:"); 00549 xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix); 00550 xmlOutputBufferWriteString(ctx->buf, "="); 00551 } else { 00552 xmlOutputBufferWriteString(ctx->buf, " xmlns="); 00553 } 00554 if(ns->href != NULL) { 00555 xmlBufWriteQuotedString(ctx->buf->buffer, ns->href); 00556 } else { 00557 xmlOutputBufferWriteString(ctx->buf, "\"\""); 00558 } 00559 return (1); 00560 } 00561 00562 /** 00563 * xmlC14NProcessNamespacesAxis: 00564 * @ctx: the C14N context 00565 * @node: the current node 00566 * 00567 * Prints out canonical namespace axis of the current node to the 00568 * buffer from C14N context as follows 00569 * 00570 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) 00571 * 00572 * Namespace Axis 00573 * Consider a list L containing only namespace nodes in the 00574 * axis and in the node-set in lexicographic order (ascending). To begin 00575 * processing L, if the first node is not the default namespace node (a node 00576 * with no namespace URI and no local name), then generate a space followed 00577 * by xmlns="" if and only if the following conditions are met: 00578 * - the element E that owns the axis is in the node-set 00579 * - The nearest ancestor element of E in the node-set has a default 00580 * namespace node in the node-set (default namespace nodes always 00581 * have non-empty values in XPath) 00582 * The latter condition eliminates unnecessary occurrences of xmlns="" in 00583 * the canonical form since an element only receives an xmlns="" if its 00584 * default namespace is empty and if it has an immediate parent in the 00585 * canonical form that has a non-empty default namespace. To finish 00586 * processing L, simply process every namespace node in L, except omit 00587 * namespace node with local name xml, which defines the xml prefix, 00588 * if its string value is http://www.w3.org/XML/1998/namespace. 00589 * 00590 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n) 00591 * Canonical XML applied to a document subset requires the search of the 00592 * ancestor nodes of each orphan element node for attributes in the xml 00593 * namespace, such as xml:lang and xml:space. These are copied into the 00594 * element node except if a declaration of the same attribute is already 00595 * in the attribute axis of the element (whether or not it is included in 00596 * the document subset). This search and copying are omitted from the 00597 * Exclusive XML Canonicalization method. 00598 * 00599 * Returns 0 on success or -1 on fail. 00600 */ 00601 static int 00602 xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) 00603 { 00604 xmlNodePtr n; 00605 xmlNsPtr ns, tmp; 00606 xmlListPtr list; 00607 int already_rendered; 00608 int has_empty_ns = 0; 00609 00610 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { 00611 xmlC14NErrParam("processing namespaces axis (c14n)"); 00612 return (-1); 00613 } 00614 00615 /* 00616 * Create a sorted list to store element namespaces 00617 */ 00618 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare); 00619 if (list == NULL) { 00620 xmlC14NErrInternal("creating namespaces list (c14n)"); 00621 return (-1); 00622 } 00623 00624 /* check all namespaces */ 00625 for(n = cur; n != NULL; n = n->parent) { 00626 for(ns = n->nsDef; ns != NULL; ns = ns->next) { 00627 tmp = xmlSearchNs(cur->doc, cur, ns->prefix); 00628 00629 if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) { 00630 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns); 00631 if(visible) { 00632 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); 00633 } 00634 if(!already_rendered) { 00635 xmlListInsert(list, ns); 00636 } 00637 if(xmlStrlen(ns->prefix) == 0) { 00638 has_empty_ns = 1; 00639 } 00640 } 00641 } 00642 } 00643 00644 /** 00645 * if the first node is not the default namespace node (a node with no 00646 * namespace URI and no local name), then generate a space followed by 00647 * xmlns="" if and only if the following conditions are met: 00648 * - the element E that owns the axis is in the node-set 00649 * - the nearest ancestor element of E in the node-set has a default 00650 * namespace node in the node-set (default namespace nodes always 00651 * have non-empty values in XPath) 00652 */ 00653 if(visible && !has_empty_ns) { 00654 static xmlNs ns_default; 00655 00656 memset(&ns_default, 0, sizeof(ns_default)); 00657 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) { 00658 xmlC14NPrintNamespaces(&ns_default, ctx); 00659 } 00660 } 00661 00662 00663 /* 00664 * print out all elements from list 00665 */ 00666 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx); 00667 00668 /* 00669 * Cleanup 00670 */ 00671 xmlListDelete(list); 00672 return (0); 00673 } 00674 00675 00676 /** 00677 * xmlExcC14NProcessNamespacesAxis: 00678 * @ctx: the C14N context 00679 * @node: the current node 00680 * 00681 * Prints out exclusive canonical namespace axis of the current node to the 00682 * buffer from C14N context as follows 00683 * 00684 * Exclusive XML Canonicalization 00685 * http://www.w3.org/TR/xml-exc-c14n 00686 * 00687 * If the element node is in the XPath subset then output the node in 00688 * accordance with Canonical XML except for namespace nodes which are 00689 * rendered as follows: 00690 * 00691 * 1. Render each namespace node iff: 00692 * * it is visibly utilized by the immediate parent element or one of 00693 * its attributes, or is present in InclusiveNamespaces PrefixList, and 00694 * * its prefix and value do not appear in ns_rendered. ns_rendered is 00695 * obtained by popping the state stack in order to obtain a list of 00696 * prefixes and their values which have already been rendered by 00697 * an output ancestor of the namespace node's parent element. 00698 * 2. Append the rendered namespace node to the list ns_rendered of namespace 00699 * nodes rendered by output ancestors. Push ns_rendered on state stack and 00700 * recurse. 00701 * 3. After the recursion returns, pop thestate stack. 00702 * 00703 * 00704 * Returns 0 on success or -1 on fail. 00705 */ 00706 static int 00707 xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) 00708 { 00709 xmlNsPtr ns; 00710 xmlListPtr list; 00711 xmlAttrPtr attr; 00712 int already_rendered; 00713 int has_empty_ns = 0; 00714 int has_visibly_utilized_empty_ns = 0; 00715 int has_empty_ns_in_inclusive_list = 0; 00716 00717 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { 00718 xmlC14NErrParam("processing namespaces axis (exc c14n)"); 00719 return (-1); 00720 } 00721 00722 if(!xmlC14NIsExclusive(ctx)) { 00723 xmlC14NErrParam("processing namespaces axis (exc c14n)"); 00724 return (-1); 00725 00726 } 00727 00728 /* 00729 * Create a sorted list to store element namespaces 00730 */ 00731 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare); 00732 if (list == NULL) { 00733 xmlC14NErrInternal("creating namespaces list (exc c14n)"); 00734 return (-1); 00735 } 00736 00737 /* 00738 * process inclusive namespaces: 00739 * All namespace nodes appearing on inclusive ns list are 00740 * handled as provided in Canonical XML 00741 */ 00742 if(ctx->inclusive_ns_prefixes != NULL) { 00743 xmlChar *prefix; 00744 int i; 00745 00746 for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) { 00747 prefix = ctx->inclusive_ns_prefixes[i]; 00748 /* 00749 * Special values for namespace with empty prefix 00750 */ 00751 if (xmlStrEqual(prefix, BAD_CAST "#default") 00752 || xmlStrEqual(prefix, BAD_CAST "")) { 00753 prefix = NULL; 00754 has_empty_ns_in_inclusive_list = 1; 00755 } 00756 00757 ns = xmlSearchNs(cur->doc, cur, prefix); 00758 if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) { 00759 already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns); 00760 if(visible) { 00761 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); 00762 } 00763 if(!already_rendered) { 00764 xmlListInsert(list, ns); 00765 } 00766 if(xmlStrlen(ns->prefix) == 0) { 00767 has_empty_ns = 1; 00768 } 00769 } 00770 } 00771 } 00772 00773 /* add node namespace */ 00774 if(cur->ns != NULL) { 00775 ns = cur->ns; 00776 } else { 00777 ns = xmlSearchNs(cur->doc, cur, NULL); 00778 has_visibly_utilized_empty_ns = 1; 00779 } 00780 if((ns != NULL) && !xmlC14NIsXmlNs(ns)) { 00781 if(visible && xmlC14NIsVisible(ctx, ns, cur)) { 00782 if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) { 00783 xmlListInsert(list, ns); 00784 } 00785 } 00786 if(visible) { 00787 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); 00788 } 00789 if(xmlStrlen(ns->prefix) == 0) { 00790 has_empty_ns = 1; 00791 } 00792 } 00793 00794 00795 /* add attributes */ 00796 for(attr = cur->properties; attr != NULL; attr = attr->next) { 00797 /* 00798 * we need to check that attribute is visible and has non 00799 * default namespace (XML Namespaces: "default namespaces 00800 * do not apply directly to attributes") 00801 */ 00802 if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) { 00803 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx); 00804 xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur); 00805 if(!already_rendered && visible) { 00806 xmlListInsert(list, attr->ns); 00807 } 00808 if(xmlStrlen(attr->ns->prefix) == 0) { 00809 has_empty_ns = 1; 00810 } 00811 } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) { 00812 has_visibly_utilized_empty_ns = 1; 00813 } 00814 } 00815 00816 /* 00817 * Process xmlns="" 00818 */ 00819 if(visible && has_visibly_utilized_empty_ns && 00820 !has_empty_ns && !has_empty_ns_in_inclusive_list) { 00821 static xmlNs ns_default; 00822 00823 memset(&ns_default, 0, sizeof(ns_default)); 00824 00825 already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx); 00826 if(!already_rendered) { 00827 xmlC14NPrintNamespaces(&ns_default, ctx); 00828 } 00829 } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) { 00830 static xmlNs ns_default; 00831 00832 memset(&ns_default, 0, sizeof(ns_default)); 00833 if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) { 00834 xmlC14NPrintNamespaces(&ns_default, ctx); 00835 } 00836 } 00837 00838 00839 00840 /* 00841 * print out all elements from list 00842 */ 00843 xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx); 00844 00845 /* 00846 * Cleanup 00847 */ 00848 xmlListDelete(list); 00849 return (0); 00850 } 00851 00852 00853 /** 00854 * xmlC14NIsXmlAttr: 00855 * @attr: the attr to check 00856 * 00857 * Checks whether the given attribute is a default "xml:" namespace 00858 * with href="http://www.w3.org/XML/1998/namespace" 00859 * 00860 * Returns 1 if the node is default or 0 otherwise 00861 */ 00862 00863 /* todo: make it a define? */ 00864 static int 00865 xmlC14NIsXmlAttr(xmlAttrPtr attr) 00866 { 00867 return ((attr->ns != NULL) && 00868 (xmlC14NIsXmlNs(attr->ns) != 0)); 00869 } 00870 00871 00872 /** 00873 * xmlC14NAttrsCompare: 00874 * @attr1: the pointer tls o first attr 00875 * @attr2: the pointer to second attr 00876 * 00877 * Prints the given attribute to the output buffer from C14N context. 00878 * 00879 * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2. 00880 */ 00881 static int 00882 xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2) 00883 { 00884 int ret = 0; 00885 00886 /* 00887 * Simple cases 00888 */ 00889 if (attr1 == attr2) 00890 return (0); 00891 if (attr1 == NULL) 00892 return (-1); 00893 if (attr2 == NULL) 00894 return (1); 00895 if (attr1->ns == attr2->ns) { 00896 return (xmlStrcmp(attr1->name, attr2->name)); 00897 } 00898 00899 /* 00900 * Attributes in the default namespace are first 00901 * because the default namespace is not applied to 00902 * unqualified attributes 00903 */ 00904 if (attr1->ns == NULL) 00905 return (-1); 00906 if (attr2->ns == NULL) 00907 return (1); 00908 if (attr1->ns->prefix == NULL) 00909 return (-1); 00910 if (attr2->ns->prefix == NULL) 00911 return (1); 00912 00913 ret = xmlStrcmp(attr1->ns->href, attr2->ns->href); 00914 if (ret == 0) { 00915 ret = xmlStrcmp(attr1->name, attr2->name); 00916 } 00917 return (ret); 00918 } 00919 00920 00921 /** 00922 * xmlC14NPrintAttrs: 00923 * @attr: the pointer to attr 00924 * @ctx: the C14N context 00925 * 00926 * Prints out canonical attribute urrent node to the 00927 * buffer from C14N context as follows 00928 * 00929 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) 00930 * 00931 * Returns 1 on success or 0 on fail. 00932 */ 00933 static int 00934 xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx) 00935 { 00936 xmlChar *value; 00937 xmlChar *buffer; 00938 00939 if ((attr == NULL) || (ctx == NULL)) { 00940 xmlC14NErrParam("writing attributes"); 00941 return (0); 00942 } 00943 00944 xmlOutputBufferWriteString(ctx->buf, " "); 00945 if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) { 00946 xmlOutputBufferWriteString(ctx->buf, 00947 (const char *) attr->ns->prefix); 00948 xmlOutputBufferWriteString(ctx->buf, ":"); 00949 } 00950 xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name); 00951 xmlOutputBufferWriteString(ctx->buf, "=\""); 00952 00953 value = xmlNodeListGetString(ctx->doc, attr->children, 1); 00954 /* todo: should we log an error if value==NULL ? */ 00955 if (value != NULL) { 00956 buffer = xmlC11NNormalizeAttr(value); 00957 xmlFree(value); 00958 if (buffer != NULL) { 00959 xmlOutputBufferWriteString(ctx->buf, (const char *) buffer); 00960 xmlFree(buffer); 00961 } else { 00962 xmlC14NErrInternal("normalizing attributes axis"); 00963 return (0); 00964 } 00965 } 00966 xmlOutputBufferWriteString(ctx->buf, "\""); 00967 return (1); 00968 } 00969 00970 /** 00971 * xmlC14NFindHiddenParentAttr: 00972 * 00973 * Finds an attribute in a hidden parent node. 00974 * 00975 * Returns a pointer to the attribute node (if found) or NULL otherwise. 00976 */ 00977 static xmlAttrPtr 00978 xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns) 00979 { 00980 xmlAttrPtr res; 00981 while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) { 00982 res = xmlHasNsProp(cur, name, ns); 00983 if(res != NULL) { 00984 return res; 00985 } 00986 00987 cur = cur->parent; 00988 } 00989 00990 return NULL; 00991 } 00992 00993 /** 00994 * xmlC14NFixupBaseAttr: 00995 * 00996 * Fixes up the xml:base attribute 00997 * 00998 * Returns the newly created attribute or NULL 00999 */ 01000 static xmlAttrPtr 01001 xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) 01002 { 01003 xmlChar * res = NULL; 01004 xmlNodePtr cur; 01005 xmlAttrPtr attr; 01006 xmlChar * tmp_str; 01007 xmlChar * tmp_str2; 01008 int tmp_str_len; 01009 01010 if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) { 01011 xmlC14NErrParam("processing xml:base attribute"); 01012 return (NULL); 01013 } 01014 01015 /* start from current value */ 01016 res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1); 01017 if(res == NULL) { 01018 xmlC14NErrInternal("processing xml:base attribute - can't get attr value"); 01019 return (NULL); 01020 } 01021 01022 /* go up the stack until we find a node that we rendered already */ 01023 cur = xml_base_attr->parent->parent; 01024 while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) { 01025 attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); 01026 if(attr != NULL) { 01027 /* get attr value */ 01028 tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1); 01029 if(tmp_str == NULL) { 01030 xmlFree(res); 01031 01032 xmlC14NErrInternal("processing xml:base attribute - can't get attr value"); 01033 return (NULL); 01034 } 01035 01036 /* we need to add '/' if our current base uri ends with '..' or '.' 01037 to ensure that we are forced to go "up" all the time */ 01038 tmp_str_len = xmlStrlen(tmp_str); 01039 if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') { 01040 tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/"); 01041 if(tmp_str2 == NULL) { 01042 xmlFree(tmp_str); 01043 xmlFree(res); 01044 01045 xmlC14NErrInternal("processing xml:base attribute - can't modify uri"); 01046 return (NULL); 01047 } 01048 01049 tmp_str = tmp_str2; 01050 } 01051 01052 /* build uri */ 01053 tmp_str2 = xmlBuildURI(res, tmp_str); 01054 if(tmp_str2 == NULL) { 01055 xmlFree(tmp_str); 01056 xmlFree(res); 01057 01058 xmlC14NErrInternal("processing xml:base attribute - can't construct uri"); 01059 return (NULL); 01060 } 01061 01062 /* cleanup and set the new res */ 01063 xmlFree(tmp_str); 01064 xmlFree(res); 01065 res = tmp_str2; 01066 } 01067 01068 /* next */ 01069 cur = cur->parent; 01070 } 01071 01072 /* check if result uri is empty or not */ 01073 if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) { 01074 xmlFree(res); 01075 return (NULL); 01076 } 01077 01078 /* create and return the new attribute node */ 01079 attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res); 01080 if(attr == NULL) { 01081 xmlFree(res); 01082 01083 xmlC14NErrInternal("processing xml:base attribute - can't construct attribute"); 01084 return (NULL); 01085 } 01086 01087 /* done */ 01088 xmlFree(res); 01089 return (attr); 01090 } 01091 01092 /** 01093 * xmlC14NProcessAttrsAxis: 01094 * @ctx: the C14N context 01095 * @cur: the current node 01096 * @parent_visible: the visibility of parent node 01097 * @all_parents_visible: the visibility of all parent nodes 01098 * 01099 * Prints out canonical attribute axis of the current node to the 01100 * buffer from C14N context as follows 01101 * 01102 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) 01103 * 01104 * Attribute Axis 01105 * In lexicographic order (ascending), process each node that 01106 * is in the element's attribute axis and in the node-set. 01107 * 01108 * The processing of an element node E MUST be modified slightly 01109 * when an XPath node-set is given as input and the element's 01110 * parent is omitted from the node-set. 01111 * 01112 * 01113 * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n) 01114 * 01115 * Canonical XML applied to a document subset requires the search of the 01116 * ancestor nodes of each orphan element node for attributes in the xml 01117 * namespace, such as xml:lang and xml:space. These are copied into the 01118 * element node except if a declaration of the same attribute is already 01119 * in the attribute axis of the element (whether or not it is included in 01120 * the document subset). This search and copying are omitted from the 01121 * Exclusive XML Canonicalization method. 01122 * 01123 * Returns 0 on success or -1 on fail. 01124 */ 01125 static int 01126 xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible) 01127 { 01128 xmlAttrPtr attr; 01129 xmlListPtr list; 01130 xmlAttrPtr attrs_to_delete = NULL; 01131 01132 /* special processing for 1.1 spec */ 01133 xmlAttrPtr xml_base_attr = NULL; 01134 xmlAttrPtr xml_lang_attr = NULL; 01135 xmlAttrPtr xml_space_attr = NULL; 01136 01137 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { 01138 xmlC14NErrParam("processing attributes axis"); 01139 return (-1); 01140 } 01141 01142 /* 01143 * Create a sorted list to store element attributes 01144 */ 01145 list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare); 01146 if (list == NULL) { 01147 xmlC14NErrInternal("creating attributes list"); 01148 return (-1); 01149 } 01150 01151 switch(ctx->mode) { 01152 case XML_C14N_1_0: 01153 /* The processing of an element node E MUST be modified slightly when an XPath node-set is 01154 * given as input and the element's parent is omitted from the node-set. The method for processing 01155 * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's 01156 * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such 01157 * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes, 01158 * remove any that are in E's attribute axis (whether or not they are in the node-set). Then, 01159 * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 01160 * the node-set. The result of visiting the attribute axis is computed by processing the attribute 01161 * nodes in this merged attribute list. 01162 */ 01163 01164 /* 01165 * Add all visible attributes from current node. 01166 */ 01167 attr = cur->properties; 01168 while (attr != NULL) { 01169 /* check that attribute is visible */ 01170 if (xmlC14NIsVisible(ctx, attr, cur)) { 01171 xmlListInsert(list, attr); 01172 } 01173 attr = attr->next; 01174 } 01175 01176 /* 01177 * Handle xml attributes 01178 */ 01179 if (parent_visible && (cur->parent != NULL) && 01180 (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) 01181 { 01182 xmlNodePtr tmp; 01183 01184 /* 01185 * If XPath node-set is not specified then the parent is always 01186 * visible! 01187 */ 01188 tmp = cur->parent; 01189 while (tmp != NULL) { 01190 attr = tmp->properties; 01191 while (attr != NULL) { 01192 if (xmlC14NIsXmlAttr(attr) != 0) { 01193 if (xmlListSearch(list, attr) == NULL) { 01194 xmlListInsert(list, attr); 01195 } 01196 } 01197 attr = attr->next; 01198 } 01199 tmp = tmp->parent; 01200 } 01201 } 01202 01203 /* done */ 01204 break; 01205 case XML_C14N_EXCLUSIVE_1_0: 01206 /* attributes in the XML namespace, such as xml:lang and xml:space 01207 * are not imported into orphan nodes of the document subset 01208 */ 01209 01210 /* 01211 * Add all visible attributes from current node. 01212 */ 01213 attr = cur->properties; 01214 while (attr != NULL) { 01215 /* check that attribute is visible */ 01216 if (xmlC14NIsVisible(ctx, attr, cur)) { 01217 xmlListInsert(list, attr); 01218 } 01219 attr = attr->next; 01220 } 01221 01222 /* do nothing special for xml attributes */ 01223 break; 01224 case XML_C14N_1_1: 01225 /* The processing of an element node E MUST be modified slightly when an XPath node-set is 01226 * given as input and some of the element's ancestors are omitted from the node-set. 01227 * 01228 * Simple inheritable attributes are attributes that have a value that requires at most a simple 01229 * redeclaration. This redeclaration is done by supplying a new value in the child axis. The 01230 * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done 01231 * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes 01232 * are xml:lang and xml:space. 01233 * 01234 * The method for processing the attribute axis of an element E in the node-set is hence enhanced. 01235 * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple 01236 * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they 01237 * are in the node-set). From this list of attributes, any simple inheritable attributes that are 01238 * already in E's attribute axis (whether or not they are in the node-set) are removed. Then, 01239 * lexicographically merge this attribute list with the nodes of E's attribute axis that are in 01240 * the node-set. The result of visiting the attribute axis is computed by processing the attribute 01241 * nodes in this merged attribute list. 01242 * 01243 * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is 01244 * performed. 01245 * 01246 * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond 01247 * a simple redeclaration. 01248 * 01249 * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed 01250 * as ordinary attributes. 01251 */ 01252 01253 /* 01254 * Add all visible attributes from current node. 01255 */ 01256 attr = cur->properties; 01257 while (attr != NULL) { 01258 /* special processing for XML attribute kiks in only when we have invisible parents */ 01259 if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) { 01260 /* check that attribute is visible */ 01261 if (xmlC14NIsVisible(ctx, attr, cur)) { 01262 xmlListInsert(list, attr); 01263 } 01264 } else { 01265 int matched = 0; 01266 01267 /* check for simple inheritance attributes */ 01268 if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) { 01269 xml_lang_attr = attr; 01270 matched = 1; 01271 } 01272 if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) { 01273 xml_space_attr = attr; 01274 matched = 1; 01275 } 01276 01277 /* check for base attr */ 01278 if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) { 01279 xml_base_attr = attr; 01280 matched = 1; 01281 } 01282 01283 /* otherwise, it is a normal attribute, so just check if it is visible */ 01284 if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) { 01285 xmlListInsert(list, attr); 01286 } 01287 } 01288 01289 /* move to the next one */ 01290 attr = attr->next; 01291 } 01292 01293 /* special processing for XML attribute kiks in only when we have invisible parents */ 01294 if ((parent_visible)) { 01295 01296 /* simple inheritance attributes - copy */ 01297 if(xml_lang_attr == NULL) { 01298 xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE); 01299 } 01300 if(xml_lang_attr != NULL) { 01301 xmlListInsert(list, xml_lang_attr); 01302 } 01303 if(xml_space_attr == NULL) { 01304 xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE); 01305 } 01306 if(xml_space_attr != NULL) { 01307 xmlListInsert(list, xml_space_attr); 01308 } 01309 01310 /* base uri attribute - fix up */ 01311 if(xml_base_attr == NULL) { 01312 /* if we don't have base uri attribute, check if we have a "hidden" one above */ 01313 xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE); 01314 } 01315 if(xml_base_attr != NULL) { 01316 xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr); 01317 if(xml_base_attr != NULL) { 01318 xmlListInsert(list, xml_base_attr); 01319 01320 /* note that we MUST delete returned attr node ourselves! */ 01321 xml_base_attr->next = attrs_to_delete; 01322 attrs_to_delete = xml_base_attr; 01323 } 01324 } 01325 } 01326 01327 /* done */ 01328 break; 01329 } 01330 01331 /* 01332 * print out all elements from list 01333 */ 01334 xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx); 01335 01336 /* 01337 * Cleanup 01338 */ 01339 xmlFreePropList(attrs_to_delete); 01340 xmlListDelete(list); 01341 return (0); 01342 } 01343 01344 /** 01345 * xmlC14NCheckForRelativeNamespaces: 01346 * @ctx: the C14N context 01347 * @cur: the current element node 01348 * 01349 * Checks that current element node has no relative namespaces defined 01350 * 01351 * Returns 0 if the node has no relative namespaces or -1 otherwise. 01352 */ 01353 static int 01354 xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur) 01355 { 01356 xmlNsPtr ns; 01357 01358 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { 01359 xmlC14NErrParam("checking for relative namespaces"); 01360 return (-1); 01361 } 01362 01363 ns = cur->nsDef; 01364 while (ns != NULL) { 01365 if (xmlStrlen(ns->href) > 0) { 01366 xmlURIPtr uri; 01367 01368 uri = xmlParseURI((const char *) ns->href); 01369 if (uri == NULL) { 01370 xmlC14NErrInternal("parsing namespace uri"); 01371 return (-1); 01372 } 01373 if (xmlStrlen((const xmlChar *) uri->scheme) == 0) { 01374 xmlC14NErrRelativeNamespace(uri->scheme); 01375 xmlFreeURI(uri); 01376 return (-1); 01377 } 01378 if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0) 01379 && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0) 01380 && (xmlStrlen((const xmlChar *) uri->server) == 0)) { 01381 xmlC14NErrRelativeNamespace(uri->scheme); 01382 xmlFreeURI(uri); 01383 return (-1); 01384 } 01385 xmlFreeURI(uri); 01386 } 01387 ns = ns->next; 01388 } 01389 return (0); 01390 } 01391 01392 /** 01393 * xmlC14NProcessElementNode: 01394 * @ctx: the pointer to C14N context object 01395 * @cur: the node to process 01396 * @visible: this node is visible 01397 * @all_parents_visible: whether all the parents of this node are visible 01398 * 01399 * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) 01400 * 01401 * Element Nodes 01402 * If the element is not in the node-set, then the result is obtained 01403 * by processing the namespace axis, then the attribute axis, then 01404 * processing the child nodes of the element that are in the node-set 01405 * (in document order). If the element is in the node-set, then the result 01406 * is an open angle bracket (<), the element QName, the result of 01407 * processing the namespace axis, the result of processing the attribute 01408 * axis, a close angle bracket (>), the result of processing the child 01409 * nodes of the element that are in the node-set (in document order), an 01410 * open angle bracket, a forward slash (/), the element QName, and a close 01411 * angle bracket. 01412 * 01413 * Returns non-negative value on success or negative value on fail 01414 */ 01415 static int 01416 xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) 01417 { 01418 int ret; 01419 xmlC14NVisibleNsStack state; 01420 int parent_is_doc = 0; 01421 01422 if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { 01423 xmlC14NErrParam("processing element node"); 01424 return (-1); 01425 } 01426 01427 /* 01428 * Check relative relative namespaces: 01429 * implementations of XML canonicalization MUST report an operation 01430 * failure on documents containing relative namespace URIs. 01431 */ 01432 if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) { 01433 xmlC14NErrInternal("checking for relative namespaces"); 01434 return (-1); 01435 } 01436 01437 01438 /* 01439 * Save ns_rendered stack position 01440 */ 01441 memset(&state, 0, sizeof(state)); 01442 xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state); 01443 01444 if (visible) { 01445 if (ctx->parent_is_doc) { 01446 /* save this flag into the stack */ 01447 parent_is_doc = ctx->parent_is_doc; 01448 ctx->parent_is_doc = 0; 01449 ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT; 01450 } 01451 xmlOutputBufferWriteString(ctx->buf, "<"); 01452 01453 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) { 01454 xmlOutputBufferWriteString(ctx->buf, 01455 (const char *) cur->ns->prefix); 01456 xmlOutputBufferWriteString(ctx->buf, ":"); 01457 } 01458 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name); 01459 } 01460 01461 if (!xmlC14NIsExclusive(ctx)) { 01462 ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible); 01463 } else { 01464 ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible); 01465 } 01466 if (ret < 0) { 01467 xmlC14NErrInternal("processing namespaces axis"); 01468 return (-1); 01469 } 01470 /* todo: shouldn't this go to "visible only"? */ 01471 if(visible) { 01472 xmlC14NVisibleNsStackShift(ctx->ns_rendered); 01473 } 01474 01475 ret = xmlC14NProcessAttrsAxis(ctx, cur, visible); 01476 if (ret < 0) { 01477 xmlC14NErrInternal("processing attributes axis"); 01478 return (-1); 01479 } 01480 01481 if (visible) { 01482 xmlOutputBufferWriteString(ctx->buf, ">"); 01483 } 01484 if (cur->children != NULL) { 01485 ret = xmlC14NProcessNodeList(ctx, cur->children); 01486 if (ret < 0) { 01487 xmlC14NErrInternal("processing childrens list"); 01488 return (-1); 01489 } 01490 } 01491 if (visible) { 01492 xmlOutputBufferWriteString(ctx->buf, "</"); 01493 if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) { 01494 xmlOutputBufferWriteString(ctx->buf, 01495 (const char *) cur->ns->prefix); 01496 xmlOutputBufferWriteString(ctx->buf, ":"); 01497 } 01498 xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name); 01499 xmlOutputBufferWriteString(ctx->buf, ">"); 01500 if (parent_is_doc) { 01501 /* restore this flag from the stack for next node */ 01502 ctx->parent_is_doc = parent_is_doc; 01503 ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT; 01504 } 01505 } 01506 01507 /* 01508 * Restore ns_rendered stack position 01509 */ 01510 xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state); 01511 return (0); 01512 } 01513 01514 /** 01515 * xmlC14NProcessNode: 01516 * @ctx: the pointer to C14N context object 01517 * @cur: the node to process 01518 * 01519 * Processes the given node 01520 * 01521 * Returns non-negative value on success or negative value on fail 01522 */ 01523 static int 01524 xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) 01525 { 01526 int ret = 0; 01527 int visible; 01528 01529 if ((ctx == NULL) || (cur == NULL)) { 01530 xmlC14NErrParam("processing node"); 01531 return (-1); 01532 } 01533 01534 visible = xmlC14NIsVisible(ctx, cur, cur->parent); 01535 switch (cur->type) { 01536 case XML_ELEMENT_NODE: 01537 ret = xmlC14NProcessElementNode(ctx, cur, visible); 01538 break; 01539 case XML_CDATA_SECTION_NODE: 01540 case XML_TEXT_NODE: 01541 /* 01542 * Text Nodes 01543 * the string value, except all ampersands are replaced 01544 * by &, all open angle brackets (<) are replaced by <, all closing 01545 * angle brackets (>) are replaced by >, and all #xD characters are 01546 * replaced by 
. 01547 */ 01548 /* cdata sections are processed as text nodes */ 01549 /* todo: verify that cdata sections are included in XPath nodes set */ 01550 if ((visible) && (cur->content != NULL)) { 01551 xmlChar *buffer; 01552 01553 buffer = xmlC11NNormalizeText(cur->content); 01554 if (buffer != NULL) { 01555 xmlOutputBufferWriteString(ctx->buf, 01556 (const char *) buffer); 01557 xmlFree(buffer); 01558 } else { 01559 xmlC14NErrInternal("normalizing text node"); 01560 return (-1); 01561 } 01562 } 01563 break; 01564 case XML_PI_NODE: 01565 /* 01566 * Processing Instruction (PI) Nodes- 01567 * The opening PI symbol (<?), the PI target name of the node, 01568 * a leading space and the string value if it is not empty, and 01569 * the closing PI symbol (?>). If the string value is empty, 01570 * then the leading space is not added. Also, a trailing #xA is 01571 * rendered after the closing PI symbol for PI children of the 01572 * root node with a lesser document order than the document 01573 * element, and a leading #xA is rendered before the opening PI 01574 * symbol of PI children of the root node with a greater document 01575 * order than the document element. 01576 */ 01577 if (visible) { 01578 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) { 01579 xmlOutputBufferWriteString(ctx->buf, "\x0A<?"); 01580 } else { 01581 xmlOutputBufferWriteString(ctx->buf, "<?"); 01582 } 01583 01584 xmlOutputBufferWriteString(ctx->buf, 01585 (const char *) cur->name); 01586 if ((cur->content != NULL) && (*(cur->content) != '\0')) { 01587 xmlChar *buffer; 01588 01589 xmlOutputBufferWriteString(ctx->buf, " "); 01590 01591 /* todo: do we need to normalize pi? */ 01592 buffer = xmlC11NNormalizePI(cur->content); 01593 if (buffer != NULL) { 01594 xmlOutputBufferWriteString(ctx->buf, 01595 (const char *) buffer); 01596 xmlFree(buffer); 01597 } else { 01598 xmlC14NErrInternal("normalizing pi node"); 01599 return (-1); 01600 } 01601 } 01602 01603 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) { 01604 xmlOutputBufferWriteString(ctx->buf, "?>\x0A"); 01605 } else { 01606 xmlOutputBufferWriteString(ctx->buf, "?>"); 01607 } 01608 } 01609 break; 01610 case XML_COMMENT_NODE: 01611 /* 01612 * Comment Nodes 01613 * Nothing if generating canonical XML without comments. For 01614 * canonical XML with comments, generate the opening comment 01615 * symbol (<!--), the string value of the node, and the 01616 * closing comment symbol (-->). Also, a trailing #xA is rendered 01617 * after the closing comment symbol for comment children of the 01618 * root node with a lesser document order than the document 01619 * element, and a leading #xA is rendered before the opening 01620 * comment symbol of comment children of the root node with a 01621 * greater document order than the document element. (Comment 01622 * children of the root node represent comments outside of the 01623 * top-level document element and outside of the document type 01624 * declaration). 01625 */ 01626 if (visible && ctx->with_comments) { 01627 if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) { 01628 xmlOutputBufferWriteString(ctx->buf, "\x0A<!--"); 01629 } else { 01630 xmlOutputBufferWriteString(ctx->buf, "<!--"); 01631 } 01632 01633 if (cur->content != NULL) { 01634 xmlChar *buffer; 01635 01636 /* todo: do we need to normalize comment? */ 01637 buffer = xmlC11NNormalizeComment(cur->content); 01638 if (buffer != NULL) { 01639 xmlOutputBufferWriteString(ctx->buf, 01640 (const char *) buffer); 01641 xmlFree(buffer); 01642 } else { 01643 xmlC14NErrInternal("normalizing comment node"); 01644 return (-1); 01645 } 01646 } 01647 01648 if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) { 01649 xmlOutputBufferWriteString(ctx->buf, "-->\x0A"); 01650 } else { 01651 xmlOutputBufferWriteString(ctx->buf, "-->"); 01652 } 01653 } 01654 break; 01655 case XML_DOCUMENT_NODE: 01656 case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */ 01657 #ifdef LIBXML_DOCB_ENABLED 01658 case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */ 01659 #endif 01660 #ifdef LIBXML_HTML_ENABLED 01661 case XML_HTML_DOCUMENT_NODE: /* should be processed as document? */ 01662 #endif 01663 if (cur->children != NULL) { 01664 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT; 01665 ctx->parent_is_doc = 1; 01666 ret = xmlC14NProcessNodeList(ctx, cur->children); 01667 } 01668 break; 01669 01670 case XML_ATTRIBUTE_NODE: 01671 xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node"); 01672 return (-1); 01673 case XML_NAMESPACE_DECL: 01674 xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node"); 01675 return (-1); 01676 case XML_ENTITY_REF_NODE: 01677 xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node"); 01678 return (-1); 01679 case XML_ENTITY_NODE: 01680 xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node"); 01681 return (-1); 01682 01683 case XML_DOCUMENT_TYPE_NODE: 01684 case XML_NOTATION_NODE: 01685 case XML_DTD_NODE: 01686 case XML_ELEMENT_DECL: 01687 case XML_ATTRIBUTE_DECL: 01688 case XML_ENTITY_DECL: 01689 #ifdef LIBXML_XINCLUDE_ENABLED 01690 case XML_XINCLUDE_START: 01691 case XML_XINCLUDE_END: 01692 #endif 01693 /* 01694 * should be ignored according to "W3C Canonical XML" 01695 */ 01696 break; 01697 default: 01698 xmlC14NErrUnknownNode(cur->type, "processing node"); 01699 return (-1); 01700 } 01701 01702 return (ret); 01703 } 01704 01705 /** 01706 * xmlC14NProcessNodeList: 01707 * @ctx: the pointer to C14N context object 01708 * @cur: the node to start from 01709 * 01710 * Processes all nodes in the row starting from cur. 01711 * 01712 * Returns non-negative value on success or negative value on fail 01713 */ 01714 static int 01715 xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur) 01716 { 01717 int ret; 01718 01719 if (ctx == NULL) { 01720 xmlC14NErrParam("processing node list"); 01721 return (-1); 01722 } 01723 01724 for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) { 01725 ret = xmlC14NProcessNode(ctx, cur); 01726 } 01727 return (ret); 01728 } 01729 01730 01731 /** 01732 * xmlC14NFreeCtx: 01733 * @ctx: the pointer to C14N context object 01734 * 01735 * Cleanups the C14N context object. 01736 */ 01737 01738 static void 01739 xmlC14NFreeCtx(xmlC14NCtxPtr ctx) 01740 { 01741 if (ctx == NULL) { 01742 xmlC14NErrParam("freeing context"); 01743 return; 01744 } 01745 01746 if (ctx->ns_rendered != NULL) { 01747 xmlC14NVisibleNsStackDestroy(ctx->ns_rendered); 01748 } 01749 xmlFree(ctx); 01750 } 01751 01752 /** 01753 * xmlC14NNewCtx: 01754 * @doc: the XML document for canonization 01755 * @is_visible_callback:the function to use to determine is node visible 01756 * or not 01757 * @user_data: the first parameter for @is_visible_callback function 01758 * (in most cases, it is nodes set) 01759 * @mode: the c14n mode (see @xmlC14NMode) 01760 * @inclusive_ns_prefixe the list of inclusive namespace prefixes 01761 * ended with a NULL or NULL if there is no 01762 * inclusive namespaces (only for ` 01763 * canonicalization) 01764 * @with_comments: include comments in the result (!=0) or not (==0) 01765 * @buf: the output buffer to store canonical XML; this 01766 * buffer MUST have encoder==NULL because C14N requires 01767 * UTF-8 output 01768 * 01769 * Creates new C14N context object to store C14N parameters. 01770 * 01771 * Returns pointer to newly created object (success) or NULL (fail) 01772 */ 01773 static xmlC14NCtxPtr 01774 xmlC14NNewCtx(xmlDocPtr doc, 01775 xmlC14NIsVisibleCallback is_visible_callback, void* user_data, 01776 xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes, 01777 int with_comments, xmlOutputBufferPtr buf) 01778 { 01779 xmlC14NCtxPtr ctx = NULL; 01780 01781 if ((doc == NULL) || (buf == NULL)) { 01782 xmlC14NErrParam("creating new context"); 01783 return (NULL); 01784 } 01785 01786 /* 01787 * Validate the encoding output buffer encoding 01788 */ 01789 if (buf->encoder != NULL) { 01790 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, 01791 "xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n"); 01792 return (NULL); 01793 } 01794 01795 /* 01796 * Validate the XML document encoding value, if provided. 01797 */ 01798 if (doc->charset != XML_CHAR_ENCODING_UTF8) { 01799 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, 01800 "xmlC14NNewCtx: source document not in UTF8\n"); 01801 return (NULL); 01802 } 01803 01804 /* 01805 * Allocate a new xmlC14NCtxPtr and fill the fields. 01806 */ 01807 ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx)); 01808 if (ctx == NULL) { 01809 xmlC14NErrMemory("creating context"); 01810 return (NULL); 01811 } 01812 memset(ctx, 0, sizeof(xmlC14NCtx)); 01813 01814 /* 01815 * initialize C14N context 01816 */ 01817 ctx->doc = doc; 01818 ctx->with_comments = with_comments; 01819 ctx->is_visible_callback = is_visible_callback; 01820 ctx->user_data = user_data; 01821 ctx->buf = buf; 01822 ctx->parent_is_doc = 1; 01823 ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT; 01824 ctx->ns_rendered = xmlC14NVisibleNsStackCreate(); 01825 01826 if(ctx->ns_rendered == NULL) { 01827 xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK, 01828 "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n"); 01829 xmlC14NFreeCtx(ctx); 01830 return (NULL); 01831 } 01832 01833 /* 01834 * Set "mode" flag and remember list of incluseve prefixes 01835 * for exclusive c14n 01836 */ 01837 ctx->mode = mode; 01838 if(xmlC14NIsExclusive(ctx)) { 01839 ctx->inclusive_ns_prefixes = inclusive_ns_prefixes; 01840 } 01841 return (ctx); 01842 } 01843 01844 /** 01845 * xmlC14NExecute: 01846 * @doc: the XML document for canonization 01847 * @is_visible_callback:the function to use to determine is node visible 01848 * or not 01849 * @user_data: the first parameter for @is_visible_callback function 01850 * (in most cases, it is nodes set) 01851 * @mode: the c14n mode (see @xmlC14NMode) 01852 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 01853 * ended with a NULL or NULL if there is no 01854 * inclusive namespaces (only for exclusive 01855 * canonicalization, ignored otherwise) 01856 * @with_comments: include comments in the result (!=0) or not (==0) 01857 * @buf: the output buffer to store canonical XML; this 01858 * buffer MUST have encoder==NULL because C14N requires 01859 * UTF-8 output 01860 * 01861 * Dumps the canonized image of given XML document into the provided buffer. 01862 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or 01863 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) 01864 * 01865 * Returns non-negative value on success or a negative value on fail 01866 */ 01867 int 01868 xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, 01869 void* user_data, int mode, xmlChar **inclusive_ns_prefixes, 01870 int with_comments, xmlOutputBufferPtr buf) { 01871 01872 xmlC14NCtxPtr ctx; 01873 xmlC14NMode c14n_mode = XML_C14N_1_0; 01874 int ret; 01875 01876 if ((buf == NULL) || (doc == NULL)) { 01877 xmlC14NErrParam("executing c14n"); 01878 return (-1); 01879 } 01880 01881 /* for backward compatibility, we have to have "mode" as "int" 01882 and here we check that user gives valid value */ 01883 switch(mode) { 01884 case XML_C14N_1_0: 01885 case XML_C14N_EXCLUSIVE_1_0: 01886 case XML_C14N_1_1: 01887 c14n_mode = (xmlC14NMode)mode; 01888 break; 01889 default: 01890 xmlC14NErrParam("invalid mode for executing c14n"); 01891 return (-1); 01892 } 01893 01894 /* 01895 * Validate the encoding output buffer encoding 01896 */ 01897 if (buf->encoder != NULL) { 01898 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, 01899 "xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n"); 01900 return (-1); 01901 } 01902 01903 ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data, 01904 c14n_mode, inclusive_ns_prefixes, 01905 with_comments, buf); 01906 if (ctx == NULL) { 01907 xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT, 01908 "xmlC14NExecute: unable to create C14N context\n"); 01909 return (-1); 01910 } 01911 01912 01913 01914 /* 01915 * Root Node 01916 * The root node is the parent of the top-level document element. The 01917 * result of processing each of its child nodes that is in the node-set 01918 * in document order. The root node does not generate a byte order mark, 01919 * XML declaration, nor anything from within the document type 01920 * declaration. 01921 */ 01922 if (doc->children != NULL) { 01923 ret = xmlC14NProcessNodeList(ctx, doc->children); 01924 if (ret < 0) { 01925 xmlC14NErrInternal("processing docs children list"); 01926 xmlC14NFreeCtx(ctx); 01927 return (-1); 01928 } 01929 } 01930 01931 /* 01932 * Flush buffer to get number of bytes written 01933 */ 01934 ret = xmlOutputBufferFlush(buf); 01935 if (ret < 0) { 01936 xmlC14NErrInternal("flushing output buffer"); 01937 xmlC14NFreeCtx(ctx); 01938 return (-1); 01939 } 01940 01941 /* 01942 * Cleanup 01943 */ 01944 xmlC14NFreeCtx(ctx); 01945 return (ret); 01946 } 01947 01948 /** 01949 * xmlC14NDocSaveTo: 01950 * @doc: the XML document for canonization 01951 * @nodes: the nodes set to be included in the canonized image 01952 * or NULL if all document nodes should be included 01953 * @mode: the c14n mode (see @xmlC14NMode) 01954 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 01955 * ended with a NULL or NULL if there is no 01956 * inclusive namespaces (only for exclusive 01957 * canonicalization, ignored otherwise) 01958 * @with_comments: include comments in the result (!=0) or not (==0) 01959 * @buf: the output buffer to store canonical XML; this 01960 * buffer MUST have encoder==NULL because C14N requires 01961 * UTF-8 output 01962 * 01963 * Dumps the canonized image of given XML document into the provided buffer. 01964 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or 01965 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) 01966 * 01967 * Returns non-negative value on success or a negative value on fail 01968 */ 01969 int 01970 xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes, 01971 int mode, xmlChar ** inclusive_ns_prefixes, 01972 int with_comments, xmlOutputBufferPtr buf) { 01973 return(xmlC14NExecute(doc, 01974 (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset, 01975 nodes, 01976 mode, 01977 inclusive_ns_prefixes, 01978 with_comments, 01979 buf)); 01980 } 01981 01982 01983 /** 01984 * xmlC14NDocDumpMemory: 01985 * @doc: the XML document for canonization 01986 * @nodes: the nodes set to be included in the canonized image 01987 * or NULL if all document nodes should be included 01988 * @mode: the c14n mode (see @xmlC14NMode) 01989 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 01990 * ended with a NULL or NULL if there is no 01991 * inclusive namespaces (only for exclusive 01992 * canonicalization, ignored otherwise) 01993 * @with_comments: include comments in the result (!=0) or not (==0) 01994 * @doc_txt_ptr: the memory pointer for allocated canonical XML text; 01995 * the caller of this functions is responsible for calling 01996 * xmlFree() to free allocated memory 01997 * 01998 * Dumps the canonized image of given XML document into memory. 01999 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or 02000 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) 02001 * 02002 * Returns the number of bytes written on success or a negative value on fail 02003 */ 02004 int 02005 xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, 02006 int mode, xmlChar ** inclusive_ns_prefixes, 02007 int with_comments, xmlChar ** doc_txt_ptr) 02008 { 02009 int ret; 02010 xmlOutputBufferPtr buf; 02011 02012 if (doc_txt_ptr == NULL) { 02013 xmlC14NErrParam("dumping doc to memory"); 02014 return (-1); 02015 } 02016 02017 *doc_txt_ptr = NULL; 02018 02019 /* 02020 * create memory buffer with UTF8 (default) encoding 02021 */ 02022 buf = xmlAllocOutputBuffer(NULL); 02023 if (buf == NULL) { 02024 xmlC14NErrMemory("creating output buffer"); 02025 return (-1); 02026 } 02027 02028 /* 02029 * canonize document and write to buffer 02030 */ 02031 ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes, 02032 with_comments, buf); 02033 if (ret < 0) { 02034 xmlC14NErrInternal("saving doc to output buffer"); 02035 (void) xmlOutputBufferClose(buf); 02036 return (-1); 02037 } 02038 02039 ret = xmlBufUse(buf->buffer); 02040 if (ret > 0) { 02041 *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), ret); 02042 } 02043 (void) xmlOutputBufferClose(buf); 02044 02045 if ((*doc_txt_ptr == NULL) && (ret > 0)) { 02046 xmlC14NErrMemory("coping canonicanized document"); 02047 return (-1); 02048 } 02049 return (ret); 02050 } 02051 02052 /** 02053 * xmlC14NDocSave: 02054 * @doc: the XML document for canonization 02055 * @nodes: the nodes set to be included in the canonized image 02056 * or NULL if all document nodes should be included 02057 * @mode: the c14n mode (see @xmlC14NMode) 02058 * @inclusive_ns_prefixes: the list of inclusive namespace prefixes 02059 * ended with a NULL or NULL if there is no 02060 * inclusive namespaces (only for exclusive 02061 * canonicalization, ignored otherwise) 02062 * @with_comments: include comments in the result (!=0) or not (==0) 02063 * @filename: the filename to store canonical XML image 02064 * @compression: the compression level (zlib requred): 02065 * -1 - libxml default, 02066 * 0 - uncompressed, 02067 * >0 - compression level 02068 * 02069 * Dumps the canonized image of given XML document into the file. 02070 * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or 02071 * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) 02072 * 02073 * Returns the number of bytes written success or a negative value on fail 02074 */ 02075 int 02076 xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, 02077 int mode, xmlChar ** inclusive_ns_prefixes, 02078 int with_comments, const char *filename, int compression) 02079 { 02080 xmlOutputBufferPtr buf; 02081 int ret; 02082 02083 if (filename == NULL) { 02084 xmlC14NErrParam("saving doc"); 02085 return (-1); 02086 } 02087 #ifdef HAVE_ZLIB_H 02088 if (compression < 0) 02089 compression = xmlGetCompressMode(); 02090 #endif 02091 02092 /* 02093 * save the content to a temp buffer, use default UTF8 encoding. 02094 */ 02095 buf = xmlOutputBufferCreateFilename(filename, NULL, compression); 02096 if (buf == NULL) { 02097 xmlC14NErrInternal("creating temporary filename"); 02098 return (-1); 02099 } 02100 02101 /* 02102 * canonize document and write to buffer 02103 */ 02104 ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes, 02105 with_comments, buf); 02106 if (ret < 0) { 02107 xmlC14NErrInternal("cannicanize document to buffer"); 02108 (void) xmlOutputBufferClose(buf); 02109 return (-1); 02110 } 02111 02112 /* 02113 * get the numbers of bytes written 02114 */ 02115 ret = xmlOutputBufferClose(buf); 02116 return (ret); 02117 } 02118 02119 02120 02121 /* 02122 * Macro used to grow the current buffer. 02123 */ 02124 #define growBufferReentrant() { \ 02125 buffer_size *= 2; \ 02126 buffer = (xmlChar *) \ 02127 xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \ 02128 if (buffer == NULL) { \ 02129 xmlC14NErrMemory("growing buffer"); \ 02130 return(NULL); \ 02131 } \ 02132 } 02133 02134 /** 02135 * xmlC11NNormalizeString: 02136 * @input: the input string 02137 * @mode: the normalization mode (attribute, comment, PI or text) 02138 * 02139 * Converts a string to a canonical (normalized) format. The code is stolen 02140 * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A 02141 * and the @mode parameter 02142 * 02143 * Returns a normalized string (caller is responsible for calling xmlFree()) 02144 * or NULL if an error occurs 02145 */ 02146 static xmlChar * 02147 xmlC11NNormalizeString(const xmlChar * input, 02148 xmlC14NNormalizationMode mode) 02149 { 02150 const xmlChar *cur = input; 02151 xmlChar *buffer = NULL; 02152 xmlChar *out = NULL; 02153 int buffer_size = 0; 02154 02155 if (input == NULL) 02156 return (NULL); 02157 02158 /* 02159 * allocate an translation buffer. 02160 */ 02161 buffer_size = 1000; 02162 buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); 02163 if (buffer == NULL) { 02164 xmlC14NErrMemory("allocating buffer"); 02165 return (NULL); 02166 } 02167 out = buffer; 02168 02169 while (*cur != '\0') { 02170 if ((out - buffer) > (buffer_size - 10)) { 02171 int indx = out - buffer; 02172 02173 growBufferReentrant(); 02174 out = &buffer[indx]; 02175 } 02176 02177 if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) || 02178 (mode == XMLC14N_NORMALIZE_TEXT))) { 02179 *out++ = '&'; 02180 *out++ = 'l'; 02181 *out++ = 't'; 02182 *out++ = ';'; 02183 } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) { 02184 *out++ = '&'; 02185 *out++ = 'g'; 02186 *out++ = 't'; 02187 *out++ = ';'; 02188 } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) || 02189 (mode == XMLC14N_NORMALIZE_TEXT))) { 02190 *out++ = '&'; 02191 *out++ = 'a'; 02192 *out++ = 'm'; 02193 *out++ = 'p'; 02194 *out++ = ';'; 02195 } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) { 02196 *out++ = '&'; 02197 *out++ = 'q'; 02198 *out++ = 'u'; 02199 *out++ = 'o'; 02200 *out++ = 't'; 02201 *out++ = ';'; 02202 } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) { 02203 *out++ = '&'; 02204 *out++ = '#'; 02205 *out++ = 'x'; 02206 *out++ = '9'; 02207 *out++ = ';'; 02208 } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) { 02209 *out++ = '&'; 02210 *out++ = '#'; 02211 *out++ = 'x'; 02212 *out++ = 'A'; 02213 *out++ = ';'; 02214 } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) || 02215 (mode == XMLC14N_NORMALIZE_TEXT) || 02216 (mode == XMLC14N_NORMALIZE_COMMENT) || 02217 (mode == XMLC14N_NORMALIZE_PI))) { 02218 *out++ = '&'; 02219 *out++ = '#'; 02220 *out++ = 'x'; 02221 *out++ = 'D'; 02222 *out++ = ';'; 02223 } else { 02224 /* 02225 * Works because on UTF-8, all extended sequences cannot 02226 * result in bytes in the ASCII range. 02227 */ 02228 *out++ = *cur; 02229 } 02230 cur++; 02231 } 02232 *out = 0; 02233 return (buffer); 02234 } 02235 #endif /* LIBXML_OUTPUT_ENABLED */ 02236 #define bottom_c14n 02237 #include "elfgcchack.h" 02238 #endif /* LIBXML_C14N_ENABLED */ 02239
Generated on Thu Jul 14 2022 13:59:07 by
