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