1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % X X M M L % 7 % X X MM MM L % 8 % X M M M L % 9 % X X M M L % 10 % X X M M LLLLL % 11 % % 12 % TTTTT RRRR EEEEE EEEEE % 13 % T R R E E % 14 % T RRRR EEE EEE % 15 % T R R E E % 16 % T R R EEEEE EEEEE % 17 % % 18 % % 19 % XML Tree Methods % 20 % % 21 % Software Design % 22 % Cristy % 23 % December 2004 % 24 % % 25 % % 26 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 27 % dedicated to making software imaging solutions freely available. % 28 % % 29 % You may not use this file except in compliance with the License. You may % 30 % obtain a copy of the License at % 31 % % 32 % http://www.imagemagick.org/script/license.php % 33 % % 34 % Unless required by applicable law or agreed to in writing, software % 35 % distributed under the License is distributed on an "AS IS" BASIS, % 36 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 37 % See the License for the specific language governing permissions and % 38 % limitations under the License. % 39 % % 40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41 % 42 % This module implements the standard handy xml-tree methods for storing and 43 % retrieving nodes and attributes from an XML string. 44 % 45 */ 46 47 /* 49 Include declarations. 50 */ 51 #include "MagickCore/studio.h" 52 #include "MagickCore/blob.h" 53 #include "MagickCore/blob-private.h" 54 #include "MagickCore/exception.h" 55 #include "MagickCore/exception-private.h" 56 #include "MagickCore/image-private.h" 57 #include "MagickCore/log.h" 58 #include "MagickCore/memory_.h" 59 #include "MagickCore/semaphore.h" 60 #include "MagickCore/string_.h" 61 #include "MagickCore/string-private.h" 62 #include "MagickCore/token-private.h" 63 #include "MagickCore/xml-tree.h" 64 #include "MagickCore/xml-tree-private.h" 65 #include "MagickCore/utility.h" 66 #include "MagickCore/utility-private.h" 67 68 /* 70 Define declarations. 71 */ 72 #define NumberPredefinedEntities 10 73 #define XMLWhitespace "\t\r\n " 74 75 /* 77 Typedef declarations. 78 */ 79 struct _XMLTreeInfo 80 { 81 char 82 *tag, 83 **attributes, 84 *content; 85 86 size_t 87 offset; 88 89 XMLTreeInfo 90 *parent, 91 *next, 92 *sibling, 93 *ordered, 94 *child; 95 96 MagickBooleanType 97 debug; 98 99 SemaphoreInfo 100 *semaphore; 101 102 size_t 103 signature; 104 }; 105 106 typedef struct _XMLTreeRoot 107 XMLTreeRoot; 108 109 struct _XMLTreeRoot 110 { 111 struct _XMLTreeInfo 112 root; 113 114 XMLTreeInfo 115 *node; 116 117 MagickBooleanType 118 standalone; 119 120 char 121 ***processing_instructions, 122 **entities, 123 ***attributes; 124 125 MagickBooleanType 126 debug; 127 128 SemaphoreInfo 129 *semaphore; 130 131 size_t 132 signature; 133 }; 134 135 /* 137 Global declarations. 138 */ 139 static char 140 *sentinel[] = { (char *) NULL }; 141 142 /* 144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 145 % % 146 % % 147 % % 148 % A d d C h i l d T o X M L T r e e % 149 % % 150 % % 151 % % 152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153 % 154 % AddChildToXMLTree() adds a child tag at an offset relative to the start of 155 % the parent tag's character content. Return the child tag. 156 % 157 % The format of the AddChildToXMLTree method is: 158 % 159 % XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag, 160 % const size_t offset) 161 % 162 % A description of each parameter follows: 163 % 164 % o xml_info: the xml info. 165 % 166 % o tag: the tag. 167 % 168 % o offset: the tag offset. 169 % 170 */ 171 MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info, 172 const char *tag,const size_t offset) 173 { 174 XMLTreeInfo 175 *child; 176 177 if (xml_info == (XMLTreeInfo *) NULL) 178 return((XMLTreeInfo *) NULL); 179 child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child)); 180 if (child == (XMLTreeInfo *) NULL) 181 return((XMLTreeInfo *) NULL); 182 (void) ResetMagickMemory(child,0,sizeof(*child)); 183 child->tag=ConstantString(tag); 184 child->attributes=sentinel; 185 child->content=ConstantString(""); 186 child->debug=IsEventLogging(); 187 child->signature=MagickCoreSignature; 188 return(InsertTagIntoXMLTree(xml_info,child,offset)); 189 } 190 191 /* 193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 194 % % 195 % % 196 % % 197 % A d d P a t h T o X M L T r e e % 198 % % 199 % % 200 % % 201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 202 % 203 % AddPathToXMLTree() adds a child tag at an offset relative to the start of 204 % the parent tag's character content. This method returns the child tag. 205 % 206 % The format of the AddPathToXMLTree method is: 207 % 208 % XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path, 209 % const size_t offset) 210 % 211 % A description of each parameter follows: 212 % 213 % o xml_info: the xml info. 214 % 215 % o path: the path. 216 % 217 % o offset: the tag offset. 218 % 219 */ 220 MagickPrivate XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info, 221 const char *path,const size_t offset) 222 { 223 char 224 **components, 225 subnode[MagickPathExtent], 226 tag[MagickPathExtent]; 227 228 register ssize_t 229 i; 230 231 size_t 232 number_components; 233 234 ssize_t 235 j; 236 237 XMLTreeInfo 238 *child, 239 *node; 240 241 assert(xml_info != (XMLTreeInfo *) NULL); 242 assert((xml_info->signature == MagickCoreSignature) || 243 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 244 if (xml_info->debug != MagickFalse) 245 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 246 node=xml_info; 247 components=GetPathComponents(path,&number_components); 248 if (components == (char **) NULL) 249 return((XMLTreeInfo *) NULL); 250 for (i=0; i < (ssize_t) number_components; i++) 251 { 252 GetPathComponent(components[i],SubimagePath,subnode); 253 GetPathComponent(components[i],CanonicalPath,tag); 254 child=GetXMLTreeChild(node,tag); 255 if (child == (XMLTreeInfo *) NULL) 256 child=AddChildToXMLTree(node,tag,offset); 257 node=child; 258 if (node == (XMLTreeInfo *) NULL) 259 break; 260 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--) 261 { 262 node=GetXMLTreeOrdered(node); 263 if (node == (XMLTreeInfo *) NULL) 264 break; 265 } 266 if (node == (XMLTreeInfo *) NULL) 267 break; 268 components[i]=DestroyString(components[i]); 269 } 270 for ( ; i < (ssize_t) number_components; i++) 271 components[i]=DestroyString(components[i]); 272 components=(char **) RelinquishMagickMemory(components); 273 return(node); 274 } 275 276 /* 278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 279 % % 280 % % 281 % % 282 % C a n o n i c a l X M L C o n t e n t % 283 % % 284 % % 285 % % 286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 287 % 288 % CanonicalXMLContent() converts text to canonical XML content by converting 289 % to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding 290 % as base-64 as required. 291 % 292 % The format of the CanonicalXMLContent method is: 293 % 294 % 295 % char *CanonicalXMLContent(const char *content, 296 % const MagickBooleanType pedantic) 297 % 298 % A description of each parameter follows: 299 % 300 % o content: the content. 301 % 302 % o pedantic: if true, replace newlines and tabs with their respective 303 % entities. 304 % 305 */ 306 MagickPrivate char *CanonicalXMLContent(const char *content, 307 const MagickBooleanType pedantic) 308 { 309 char 310 *base64, 311 *canonical_content; 312 313 register const unsigned char 314 *p; 315 316 register ssize_t 317 i; 318 319 size_t 320 extent, 321 length; 322 323 unsigned char 324 *utf8; 325 326 utf8=ConvertLatin1ToUTF8((const unsigned char *) content); 327 if (utf8 == (unsigned char *) NULL) 328 return((char *) NULL); 329 for (p=utf8; *p != '\0'; p++) 330 if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d)) 331 break; 332 if (*p != '\0') 333 { 334 /* 335 String is binary, base64-encode it. 336 */ 337 base64=Base64Encode(utf8,strlen((char *) utf8),&length); 338 utf8=(unsigned char *) RelinquishMagickMemory(utf8); 339 if (base64 == (char *) NULL) 340 return((char *) NULL); 341 canonical_content=AcquireString("<base64>"); 342 (void) ConcatenateString(&canonical_content,base64); 343 base64=DestroyString(base64); 344 (void) ConcatenateString(&canonical_content,"</base64>"); 345 return(canonical_content); 346 } 347 /* 348 Substitute predefined entities. 349 */ 350 i=0; 351 canonical_content=AcquireString((char *) NULL); 352 extent=MagickPathExtent; 353 for (p=utf8; *p != '\0'; p++) 354 { 355 if ((i+MagickPathExtent) > (ssize_t) extent) 356 { 357 extent+=MagickPathExtent; 358 canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent, 359 sizeof(*canonical_content)); 360 if (canonical_content == (char *) NULL) 361 return(canonical_content); 362 } 363 switch (*p) 364 { 365 case '&': 366 { 367 i+=FormatLocaleString(canonical_content+i,extent,"&"); 368 break; 369 } 370 case '<': 371 { 372 i+=FormatLocaleString(canonical_content+i,extent,"<"); 373 break; 374 } 375 case '>': 376 { 377 i+=FormatLocaleString(canonical_content+i,extent,">"); 378 break; 379 } 380 case '"': 381 { 382 i+=FormatLocaleString(canonical_content+i,extent,"""); 383 break; 384 } 385 case '\n': 386 { 387 if (pedantic == MagickFalse) 388 { 389 canonical_content[i++]=(char) (*p); 390 break; 391 } 392 i+=FormatLocaleString(canonical_content+i,extent,"
"); 393 break; 394 } 395 case '\t': 396 { 397 if (pedantic == MagickFalse) 398 { 399 canonical_content[i++]=(char) (*p); 400 break; 401 } 402 i+=FormatLocaleString(canonical_content+i,extent,"	"); 403 break; 404 } 405 case '\r': 406 { 407 i+=FormatLocaleString(canonical_content+i,extent,"
"); 408 break; 409 } 410 default: 411 { 412 canonical_content[i++]=(char) (*p); 413 break; 414 } 415 } 416 } 417 canonical_content[i]='\0'; 418 utf8=(unsigned char *) RelinquishMagickMemory(utf8); 419 return(canonical_content); 420 } 421 422 /* 424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 425 % % 426 % % 427 % % 428 % D e s t r o y X M L T r e e % 429 % % 430 % % 431 % % 432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 433 % 434 % DestroyXMLTree() destroys the xml-tree. 435 % 436 % The format of the DestroyXMLTree method is: 437 % 438 % XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info) 439 % 440 % A description of each parameter follows: 441 % 442 % o xml_info: the xml info. 443 % 444 */ 445 446 static char **DestroyXMLTreeAttributes(char **attributes) 447 { 448 register ssize_t 449 i; 450 451 /* 452 Destroy a tag attribute list. 453 */ 454 if ((attributes == (char **) NULL) || (attributes == sentinel)) 455 return((char **) NULL); 456 for (i=0; attributes[i] != (char *) NULL; i+=2) 457 { 458 /* 459 Destroy attribute tag and value. 460 */ 461 if (attributes[i] != (char *) NULL) 462 attributes[i]=DestroyString(attributes[i]); 463 if (attributes[i+1] != (char *) NULL) 464 attributes[i+1]=DestroyString(attributes[i+1]); 465 } 466 attributes=(char **) RelinquishMagickMemory(attributes); 467 return((char **) NULL); 468 } 469 470 static void DestroyXMLTreeChild(XMLTreeInfo *xml_info) 471 { 472 XMLTreeInfo 473 *child, 474 *node; 475 476 child=xml_info->child; 477 while(child != (XMLTreeInfo *) NULL) 478 { 479 node=child; 480 child=node->child; 481 node->child=(XMLTreeInfo *) NULL; 482 (void) DestroyXMLTree(node); 483 } 484 } 485 486 static void DestroyXMLTreeOrdered(XMLTreeInfo *xml_info) 487 { 488 XMLTreeInfo 489 *node, 490 *ordered; 491 492 ordered=xml_info->ordered; 493 while(ordered != (XMLTreeInfo *) NULL) 494 { 495 node=ordered; 496 ordered=node->ordered; 497 node->ordered=(XMLTreeInfo *) NULL; 498 (void) DestroyXMLTree(node); 499 } 500 } 501 502 static void DestroyXMLTreeRoot(XMLTreeInfo *xml_info) 503 { 504 char 505 **attributes; 506 507 register ssize_t 508 i; 509 510 ssize_t 511 j; 512 513 XMLTreeRoot 514 *root; 515 516 assert(xml_info != (XMLTreeInfo *) NULL); 517 assert((xml_info->signature == MagickCoreSignature) || 518 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 519 if (xml_info->debug != MagickFalse) 520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 521 if (xml_info->parent != (XMLTreeInfo *) NULL) 522 return; 523 /* 524 Free root tag allocations. 525 */ 526 root=(XMLTreeRoot *) xml_info; 527 for (i=NumberPredefinedEntities; root->entities[i] != (char *) NULL; i+=2) 528 root->entities[i+1]=DestroyString(root->entities[i+1]); 529 root->entities=(char **) RelinquishMagickMemory(root->entities); 530 for (i=0; root->attributes[i] != (char **) NULL; i++) 531 { 532 attributes=root->attributes[i]; 533 if (attributes[0] != (char *) NULL) 534 attributes[0]=DestroyString(attributes[0]); 535 for (j=1; attributes[j] != (char *) NULL; j+=3) 536 { 537 if (attributes[j] != (char *) NULL) 538 attributes[j]=DestroyString(attributes[j]); 539 if (attributes[j+1] != (char *) NULL) 540 attributes[j+1]=DestroyString(attributes[j+1]); 541 if (attributes[j+2] != (char *) NULL) 542 attributes[j+2]=DestroyString(attributes[j+2]); 543 } 544 attributes=(char **) RelinquishMagickMemory(attributes); 545 } 546 if (root->attributes[0] != (char **) NULL) 547 root->attributes=(char ***) RelinquishMagickMemory(root->attributes); 548 if (root->processing_instructions[0] != (char **) NULL) 549 { 550 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 551 { 552 for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++) 553 root->processing_instructions[i][j]=DestroyString( 554 root->processing_instructions[i][j]); 555 root->processing_instructions[i][j+1]=DestroyString( 556 root->processing_instructions[i][j+1]); 557 root->processing_instructions[i]=(char **) RelinquishMagickMemory( 558 root->processing_instructions[i]); 559 } 560 root->processing_instructions=(char ***) RelinquishMagickMemory( 561 root->processing_instructions); 562 } 563 } 564 565 MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info) 566 { 567 assert(xml_info != (XMLTreeInfo *) NULL); 568 assert((xml_info->signature == MagickCoreSignature) || 569 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 570 if (xml_info->debug != MagickFalse) 571 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 572 DestroyXMLTreeChild(xml_info); 573 DestroyXMLTreeOrdered(xml_info); 574 DestroyXMLTreeRoot(xml_info); 575 xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes); 576 xml_info->content=DestroyString(xml_info->content); 577 xml_info->tag=DestroyString(xml_info->tag); 578 xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info); 579 return((XMLTreeInfo *) NULL); 580 } 581 582 /* 584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 585 % % 586 % % 587 % % 588 % F i l e T o X M L % 589 % % 590 % % 591 % % 592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 593 % 594 % FileToXML() returns the contents of a file as a XML string. 595 % 596 % The format of the FileToXML method is: 597 % 598 % char *FileToXML(const char *filename,const size_t extent) 599 % 600 % A description of each parameter follows: 601 % 602 % o filename: the filename. 603 % 604 % o extent: Maximum length of the string. 605 % 606 */ 607 608 MagickPrivate char *FileToXML(const char *filename,const size_t extent) 609 { 610 char 611 *xml; 612 613 int 614 file; 615 616 MagickOffsetType 617 offset; 618 619 register size_t 620 i; 621 622 size_t 623 length; 624 625 ssize_t 626 count; 627 628 void 629 *map; 630 631 assert(filename != (const char *) NULL); 632 length=0; 633 file=fileno(stdin); 634 if (LocaleCompare(filename,"-") != 0) 635 file=open_utf8(filename,O_RDONLY | O_BINARY,0); 636 if (file == -1) 637 return((char *) NULL); 638 offset=(MagickOffsetType) lseek(file,0,SEEK_END); 639 count=0; 640 if ((file == fileno(stdin)) || (offset < 0) || 641 (offset != (MagickOffsetType) ((ssize_t) offset))) 642 { 643 size_t 644 quantum; 645 646 struct stat 647 file_stats; 648 649 /* 650 Stream is not seekable. 651 */ 652 offset=(MagickOffsetType) lseek(file,0,SEEK_SET); 653 quantum=(size_t) MagickMaxBufferExtent; 654 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0)) 655 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent); 656 xml=(char *) AcquireQuantumMemory(quantum,sizeof(*xml)); 657 for (i=0; xml != (char *) NULL; i+=count) 658 { 659 count=read(file,xml+i,quantum); 660 if (count <= 0) 661 { 662 count=0; 663 if (errno != EINTR) 664 break; 665 } 666 if (~((size_t) i) < (quantum+1)) 667 { 668 xml=(char *) RelinquishMagickMemory(xml); 669 break; 670 } 671 xml=(char *) ResizeQuantumMemory(xml,i+quantum+1,sizeof(*xml)); 672 if ((size_t) (i+count) >= extent) 673 break; 674 } 675 if (LocaleCompare(filename,"-") != 0) 676 file=close(file); 677 if (xml == (char *) NULL) 678 return((char *) NULL); 679 if (file == -1) 680 { 681 xml=(char *) RelinquishMagickMemory(xml); 682 return((char *) NULL); 683 } 684 length=(size_t) MagickMin(i+count,extent); 685 xml[length]='\0'; 686 return(xml); 687 } 688 length=(size_t) MagickMin(offset,(MagickOffsetType) extent); 689 xml=(char *) NULL; 690 if (~length >= (MagickPathExtent-1)) 691 xml=(char *) AcquireQuantumMemory(length+MagickPathExtent,sizeof(*xml)); 692 if (xml == (char *) NULL) 693 { 694 file=close(file); 695 return((char *) NULL); 696 } 697 map=MapBlob(file,ReadMode,0,length); 698 if (map != (char *) NULL) 699 { 700 (void) memcpy(xml,map,length); 701 (void) UnmapBlob(map,length); 702 } 703 else 704 { 705 (void) lseek(file,0,SEEK_SET); 706 for (i=0; i < length; i+=count) 707 { 708 count=read(file,xml+i,(size_t) MagickMin(length-i,SSIZE_MAX)); 709 if (count <= 0) 710 { 711 count=0; 712 if (errno != EINTR) 713 break; 714 } 715 } 716 if (i < length) 717 { 718 file=close(file)-1; 719 xml=(char *) RelinquishMagickMemory(xml); 720 return((char *) NULL); 721 } 722 } 723 xml[length]='\0'; 724 if (LocaleCompare(filename,"-") != 0) 725 file=close(file); 726 if (file == -1) 727 xml=(char *) RelinquishMagickMemory(xml); 728 return(xml); 729 } 730 731 /* 733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 734 % % 735 % % 736 % % 737 % G e t N e x t X M L T r e e T a g % 738 % % 739 % % 740 % % 741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 742 % 743 % GetNextXMLTreeTag() returns the next tag or NULL if not found. 744 % 745 % The format of the GetNextXMLTreeTag method is: 746 % 747 % XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info) 748 % 749 % A description of each parameter follows: 750 % 751 % o xml_info: the xml info. 752 % 753 */ 754 MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info) 755 { 756 assert(xml_info != (XMLTreeInfo *) NULL); 757 assert((xml_info->signature == MagickCoreSignature) || 758 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 759 if (xml_info->debug != MagickFalse) 760 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 761 return(xml_info->next); 762 } 763 764 /* 766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 767 % % 768 % % 769 % % 770 % G e t X M L T r e e A t t r i b u t e % 771 % % 772 % % 773 % % 774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 775 % 776 % GetXMLTreeAttribute() returns the value of the attribute tag with the 777 % specified tag if found, otherwise NULL. 778 % 779 % The format of the GetXMLTreeAttribute method is: 780 % 781 % const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag) 782 % 783 % A description of each parameter follows: 784 % 785 % o xml_info: the xml info. 786 % 787 % o tag: the attribute tag. 788 % 789 */ 790 MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info, 791 const char *tag) 792 { 793 register ssize_t 794 i; 795 796 ssize_t 797 j; 798 799 XMLTreeRoot 800 *root; 801 802 assert(xml_info != (XMLTreeInfo *) NULL); 803 assert((xml_info->signature == MagickCoreSignature) || 804 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 805 if (xml_info->debug != MagickFalse) 806 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 807 if (xml_info->attributes == (char **) NULL) 808 return((const char *) NULL); 809 i=0; 810 while ((xml_info->attributes[i] != (char *) NULL) && 811 (strcmp(xml_info->attributes[i],tag) != 0)) 812 i+=2; 813 if (xml_info->attributes[i] != (char *) NULL) 814 return(xml_info->attributes[i+1]); 815 root=(XMLTreeRoot*) xml_info; 816 while (root->root.parent != (XMLTreeInfo *) NULL) 817 root=(XMLTreeRoot *) root->root.parent; 818 i=0; 819 while ((root->attributes[i] != (char **) NULL) && 820 (strcmp(root->attributes[i][0],xml_info->tag) != 0)) 821 i++; 822 if (root->attributes[i] == (char **) NULL) 823 return((const char *) NULL); 824 j=1; 825 while ((root->attributes[i][j] != (char *) NULL) && 826 (strcmp(root->attributes[i][j],tag) != 0)) 827 j+=3; 828 if (root->attributes[i][j] == (char *) NULL) 829 return((const char *) NULL); 830 return(root->attributes[i][j+1]); 831 } 832 833 /* 835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 836 % % 837 % % 838 % % 839 % G e t X M L T r e e A t t r i b u t e s % 840 % % 841 % % 842 % % 843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 844 % 845 % GetXMLTreeAttributes() injects all attributes associated with the current 846 % tag in the specified splay-tree. 847 % 848 % The format of the GetXMLTreeAttributes method is: 849 % 850 % MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info, 851 % SplayTreeInfo *attributes) 852 % 853 % A description of each parameter follows: 854 % 855 % o xml_info: the xml info. 856 % 857 % o attributes: the attribute splay-tree. 858 % 859 */ 860 MagickPrivate MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info, 861 SplayTreeInfo *attributes) 862 { 863 register ssize_t 864 i; 865 866 assert(xml_info != (XMLTreeInfo *) NULL); 867 assert((xml_info->signature == MagickCoreSignature) || 868 (((const XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 869 if (xml_info->debug != MagickFalse) 870 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 871 assert(attributes != (SplayTreeInfo *) NULL); 872 if (xml_info->attributes == (char **) NULL) 873 return(MagickTrue); 874 i=0; 875 while (xml_info->attributes[i] != (char *) NULL) 876 { 877 (void) AddValueToSplayTree(attributes, 878 ConstantString(xml_info->attributes[i]), 879 ConstantString(xml_info->attributes[i+1])); 880 i+=2; 881 } 882 return(MagickTrue); 883 } 884 885 /* 887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 888 % % 889 % % 890 % % 891 % G e t X M L T r e e C h i l d % 892 % % 893 % % 894 % % 895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 896 % 897 % GetXMLTreeChild() returns the first child tag with the specified tag if 898 % found, otherwise NULL. 899 % 900 % The format of the GetXMLTreeChild method is: 901 % 902 % XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag) 903 % 904 % A description of each parameter follows: 905 % 906 % o xml_info: the xml info. 907 % 908 */ 909 MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag) 910 { 911 XMLTreeInfo 912 *child; 913 914 assert(xml_info != (XMLTreeInfo *) NULL); 915 assert((xml_info->signature == MagickCoreSignature) || 916 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 917 if (xml_info->debug != MagickFalse) 918 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 919 child=xml_info->child; 920 if (tag != (const char *) NULL) 921 while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0)) 922 child=child->sibling; 923 return(child); 924 } 925 926 /* 928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 929 % % 930 % % 931 % % 932 % G e t X M L T r e e C o n t e n t % 933 % % 934 % % 935 % % 936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 937 % 938 % GetXMLTreeContent() returns any content associated with specified 939 % xml-tree node. 940 % 941 % The format of the GetXMLTreeContent method is: 942 % 943 % const char *GetXMLTreeContent(XMLTreeInfo *xml_info) 944 % 945 % A description of each parameter follows: 946 % 947 % o xml_info: the xml info. 948 % 949 */ 950 MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info) 951 { 952 assert(xml_info != (XMLTreeInfo *) NULL); 953 assert((xml_info->signature == MagickCoreSignature) || 954 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 955 if (xml_info->debug != MagickFalse) 956 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 957 return(xml_info->content); 958 } 959 960 /* 962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 963 % % 964 % % 965 % % 966 % G e t X M L T r e e O r d e r e d % 967 % % 968 % % 969 % % 970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 971 % 972 % GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL. 973 % 974 % The format of the GetXMLTreeOrdered method is: 975 % 976 % XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info) 977 % 978 % A description of each parameter follows: 979 % 980 % o xml_info: the xml info. 981 % 982 */ 983 MagickPrivate XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info) 984 { 985 assert(xml_info != (XMLTreeInfo *) NULL); 986 assert((xml_info->signature == MagickCoreSignature) || 987 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 988 if (xml_info->debug != MagickFalse) 989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 990 return(xml_info->ordered); 991 } 992 993 /* 995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 996 % % 997 % % 998 % % 999 % G e t X M L T r e e P a t h % 1000 % % 1001 % % 1002 % % 1003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1004 % 1005 % GetXMLTreePath() traverses the XML-tree as defined by the specified path 1006 % and returns the node if found, otherwise NULL. 1007 % 1008 % The format of the GetXMLTreePath method is: 1009 % 1010 % XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path) 1011 % 1012 % A description of each parameter follows: 1013 % 1014 % o xml_info: the xml info. 1015 % 1016 % o path: the path (e.g. property/elapsed-time). 1017 % 1018 */ 1019 MagickPrivate XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path) 1020 { 1021 char 1022 **components, 1023 subnode[MagickPathExtent], 1024 tag[MagickPathExtent]; 1025 1026 register ssize_t 1027 i; 1028 1029 size_t 1030 number_components; 1031 1032 ssize_t 1033 j; 1034 1035 XMLTreeInfo 1036 *node; 1037 1038 assert(xml_info != (XMLTreeInfo *) NULL); 1039 assert((xml_info->signature == MagickCoreSignature) || 1040 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 1041 if (xml_info->debug != MagickFalse) 1042 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1043 node=xml_info; 1044 components=GetPathComponents(path,&number_components); 1045 if (components == (char **) NULL) 1046 return((XMLTreeInfo *) NULL); 1047 for (i=0; i < (ssize_t) number_components; i++) 1048 { 1049 GetPathComponent(components[i],SubimagePath,subnode); 1050 GetPathComponent(components[i],CanonicalPath,tag); 1051 node=GetXMLTreeChild(node,tag); 1052 if (node == (XMLTreeInfo *) NULL) 1053 break; 1054 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--) 1055 { 1056 node=GetXMLTreeOrdered(node); 1057 if (node == (XMLTreeInfo *) NULL) 1058 break; 1059 } 1060 if (node == (XMLTreeInfo *) NULL) 1061 break; 1062 components[i]=DestroyString(components[i]); 1063 } 1064 for ( ; i < (ssize_t) number_components; i++) 1065 components[i]=DestroyString(components[i]); 1066 components=(char **) RelinquishMagickMemory(components); 1067 return(node); 1068 } 1069 1070 /* 1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1073 % % 1074 % % 1075 % % 1076 % G e t X M L T r e e P r o c e s s i n g I n s t r u c t i o n s % 1077 % % 1078 % % 1079 % % 1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1081 % 1082 % GetXMLTreeProcessingInstructions() returns a null terminated array of 1083 % processing instructions for the given target. 1084 % 1085 % The format of the GetXMLTreeProcessingInstructions method is: 1086 % 1087 % const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info, 1088 % const char *target) 1089 % 1090 % A description of each parameter follows: 1091 % 1092 % o xml_info: the xml info. 1093 % 1094 */ 1095 MagickPrivate const char **GetXMLTreeProcessingInstructions( 1096 XMLTreeInfo *xml_info,const char *target) 1097 { 1098 register ssize_t 1099 i; 1100 1101 XMLTreeRoot 1102 *root; 1103 1104 assert(xml_info != (XMLTreeInfo *) NULL); 1105 assert((xml_info->signature == MagickCoreSignature) || 1106 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 1107 if (xml_info->debug != MagickFalse) 1108 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1109 root=(XMLTreeRoot *) xml_info; 1110 while (root->root.parent != (XMLTreeInfo *) NULL) 1111 root=(XMLTreeRoot *) root->root.parent; 1112 i=0; 1113 while ((root->processing_instructions[i] != (char **) NULL) && 1114 (strcmp(root->processing_instructions[i][0],target) != 0)) 1115 i++; 1116 if (root->processing_instructions[i] == (char **) NULL) 1117 return((const char **) sentinel); 1118 return((const char **) (root->processing_instructions[i]+1)); 1119 } 1120 1121 /* 1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1124 % % 1125 % % 1126 % % 1127 % G e t X M L T r e e S i b l i n g % 1128 % % 1129 % % 1130 % % 1131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1132 % 1133 % GetXMLTreeSibling() returns the node sibling if found, otherwise NULL. 1134 % 1135 % The format of the GetXMLTreeSibling method is: 1136 % 1137 % XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info) 1138 % 1139 % A description of each parameter follows: 1140 % 1141 % o xml_info: the xml info. 1142 % 1143 */ 1144 MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info) 1145 { 1146 assert(xml_info != (XMLTreeInfo *) NULL); 1147 assert((xml_info->signature == MagickCoreSignature) || 1148 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 1149 if (xml_info->debug != MagickFalse) 1150 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1151 return(xml_info->sibling); 1152 } 1153 1154 /* 1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1157 % % 1158 % % 1159 % % 1160 % G e t X M L T r e e T a g % 1161 % % 1162 % % 1163 % % 1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1165 % 1166 % GetXMLTreeTag() returns the tag associated with specified xml-tree node. 1167 % 1168 % The format of the GetXMLTreeTag method is: 1169 % 1170 % const char *GetXMLTreeTag(XMLTreeInfo *xml_info) 1171 % 1172 % A description of each parameter follows: 1173 % 1174 % o xml_info: the xml info. 1175 % 1176 */ 1177 MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info) 1178 { 1179 assert(xml_info != (XMLTreeInfo *) NULL); 1180 assert((xml_info->signature == MagickCoreSignature) || 1181 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 1182 if (xml_info->debug != MagickFalse) 1183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1184 return(xml_info->tag); 1185 } 1186 1187 /* 1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1190 % % 1191 % % 1192 % % 1193 % I n s e r t I n t o T a g X M L T r e e % 1194 % % 1195 % % 1196 % % 1197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1198 % 1199 % InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of 1200 % the parent tag's character content. This method returns the child tag. 1201 % 1202 % The format of the InsertTagIntoXMLTree method is: 1203 % 1204 % XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info, 1205 % XMLTreeInfo *child,const size_t offset) 1206 % 1207 % A description of each parameter follows: 1208 % 1209 % o xml_info: the xml info. 1210 % 1211 % o child: the child tag. 1212 % 1213 % o offset: the tag offset. 1214 % 1215 */ 1216 MagickPrivate XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info, 1217 XMLTreeInfo *child,const size_t offset) 1218 { 1219 XMLTreeInfo 1220 *head, 1221 *node, 1222 *previous; 1223 1224 child->ordered=(XMLTreeInfo *) NULL; 1225 child->sibling=(XMLTreeInfo *) NULL; 1226 child->next=(XMLTreeInfo *) NULL; 1227 child->offset=offset; 1228 child->parent=xml_info; 1229 if (xml_info->child == (XMLTreeInfo *) NULL) 1230 { 1231 xml_info->child=child; 1232 return(child); 1233 } 1234 head=xml_info->child; 1235 if (head->offset > offset) 1236 { 1237 child->ordered=head; 1238 xml_info->child=child; 1239 } 1240 else 1241 { 1242 node=head; 1243 while ((node->ordered != (XMLTreeInfo *) NULL) && 1244 (node->ordered->offset <= offset)) 1245 node=node->ordered; 1246 child->ordered=node->ordered; 1247 node->ordered=child; 1248 } 1249 previous=(XMLTreeInfo *) NULL; 1250 node=head; 1251 while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0)) 1252 { 1253 previous=node; 1254 node=node->sibling; 1255 } 1256 if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset)) 1257 { 1258 while ((node->next != (XMLTreeInfo *) NULL) && 1259 (node->next->offset <= offset)) 1260 node=node->next; 1261 child->next=node->next; 1262 node->next=child; 1263 } 1264 else 1265 { 1266 if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL)) 1267 previous->sibling=node->sibling; 1268 child->next=node; 1269 previous=(XMLTreeInfo *) NULL; 1270 node=head; 1271 while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset)) 1272 { 1273 previous=node; 1274 node=node->sibling; 1275 } 1276 child->sibling=node; 1277 if (previous != (XMLTreeInfo *) NULL) 1278 previous->sibling=child; 1279 } 1280 return(child); 1281 } 1282 1283 /* 1285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1286 % % 1287 % % 1288 % % 1289 % N e w X M L T r e e % 1290 % % 1291 % % 1292 % % 1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1294 % 1295 % NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified 1296 % XML string. 1297 % 1298 % The format of the NewXMLTree method is: 1299 % 1300 % XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception) 1301 % 1302 % A description of each parameter follows: 1303 % 1304 % o xml: The XML string. 1305 % 1306 % o exception: return any errors or warnings in this structure. 1307 % 1308 */ 1309 1310 static char *ConvertUTF16ToUTF8(const char *content,size_t *length) 1311 { 1312 char 1313 *utf8; 1314 1315 int 1316 bits, 1317 byte, 1318 c, 1319 encoding; 1320 1321 register ssize_t 1322 i; 1323 1324 size_t 1325 extent; 1326 1327 ssize_t 1328 j; 1329 1330 utf8=(char *) AcquireQuantumMemory(*length+1,sizeof(*utf8)); 1331 if (utf8 == (char *) NULL) 1332 return((char *) NULL); 1333 encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1; 1334 if (encoding == -1) 1335 { 1336 /* 1337 Already UTF-8. 1338 */ 1339 (void) CopyMagickMemory(utf8,content,*length*sizeof(*utf8)); 1340 utf8[*length]='\0'; 1341 return(utf8); 1342 } 1343 j=0; 1344 extent=(*length); 1345 for (i=2; i < (ssize_t) (*length-1); i+=2) 1346 { 1347 c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) : 1348 ((content[i+1] & 0xff) << 8) | (content[i] & 0xff); 1349 if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (ssize_t) (*length-1))) 1350 { 1351 byte=(encoding != 0) ? ((content[i] & 0xff) << 8) | 1352 (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) | 1353 (content[i] & 0xff); 1354 c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000; 1355 } 1356 if ((size_t) (j+MagickPathExtent) > extent) 1357 { 1358 extent=(size_t) j+MagickPathExtent; 1359 utf8=(char *) ResizeQuantumMemory(utf8,extent,sizeof(*utf8)); 1360 if (utf8 == (char *) NULL) 1361 return(utf8); 1362 } 1363 if (c < 0x80) 1364 { 1365 utf8[j]=c; 1366 j++; 1367 continue; 1368 } 1369 /* 1370 Multi-byte UTF-8 sequence. 1371 */ 1372 byte=c; 1373 for (bits=0; byte != 0; byte/=2) 1374 bits++; 1375 bits=(bits-2)/5; 1376 utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits)); 1377 while (bits != 0) 1378 { 1379 bits--; 1380 utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f); 1381 j++; 1382 } 1383 } 1384 *length=(size_t) j; 1385 utf8=(char *) ResizeQuantumMemory(utf8,*length,sizeof(*utf8)); 1386 if (utf8 != (char *) NULL) 1387 utf8[*length]='\0'; 1388 return(utf8); 1389 } 1390 1391 static char *ParseEntities(char *xml,char **entities,int state) 1392 { 1393 char 1394 *entity; 1395 1396 int 1397 byte, 1398 c; 1399 1400 register char 1401 *p, 1402 *q; 1403 1404 register ssize_t 1405 i; 1406 1407 size_t 1408 extent, 1409 length; 1410 1411 ssize_t 1412 offset; 1413 1414 /* 1415 Normalize line endings. 1416 */ 1417 p=xml; 1418 q=xml; 1419 for ( ; *xml != '\0'; xml++) 1420 while (*xml == '\r') 1421 { 1422 *(xml++)='\n'; 1423 if (*xml == '\n') 1424 (void) CopyMagickMemory(xml,xml+1,strlen(xml)); 1425 } 1426 for (xml=p; ; ) 1427 { 1428 while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') || 1429 (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0))) 1430 xml++; 1431 if (*xml == '\0') 1432 break; 1433 /* 1434 States include: 1435 '&' for general entity decoding 1436 '%' for parameter entity decoding 1437 'c' for CDATA sections 1438 ' ' for attributes normalization 1439 '*' for non-CDATA attributes normalization 1440 */ 1441 if ((state != 'c') && (strncmp(xml,"&#",2) == 0)) 1442 { 1443 /* 1444 Character reference. 1445 */ 1446 if (xml[2] != 'x') 1447 c=strtol(xml+2,&entity,10); /* base 10 */ 1448 else 1449 c=strtol(xml+3,&entity,16); /* base 16 */ 1450 if ((c == 0) || (*entity != ';')) 1451 { 1452 /* 1453 Not a character reference. 1454 */ 1455 xml++; 1456 continue; 1457 } 1458 if (c < 0x80) 1459 *(xml++)=c; 1460 else 1461 { 1462 /* 1463 Multi-byte UTF-8 sequence. 1464 */ 1465 byte=c; 1466 for (i=0; byte != 0; byte/=2) 1467 i++; 1468 i=(i-2)/5; 1469 *xml=(char) ((0xFF << (7-i)) | (c >> (6*i))); 1470 xml++; 1471 while (i != 0) 1472 { 1473 i--; 1474 *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F)); 1475 xml++; 1476 } 1477 } 1478 (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';'))); 1479 } 1480 else 1481 if (((*xml == '&') && ((state == '&') || (state == ' ') || 1482 (state == '*'))) || ((state == '%') && (*xml == '%'))) 1483 { 1484 /* 1485 Find entity in the list. 1486 */ 1487 i=0; 1488 while ((entities[i] != (char *) NULL) && 1489 (strncmp(xml+1,entities[i],strlen(entities[i])) != 0)) 1490 i+=2; 1491 if (entities[i++] == (char *) NULL) 1492 xml++; 1493 else 1494 if (entities[i] != (char *) NULL) 1495 { 1496 /* 1497 Found a match. 1498 */ 1499 length=strlen(entities[i]); 1500 entity=strchr(xml,';'); 1501 if ((entity != (char *) NULL) && 1502 ((length-1L) >= (size_t) (entity-xml))) 1503 { 1504 offset=(ssize_t) (xml-p); 1505 extent=(size_t) (offset+length+strlen(entity)); 1506 if (p != q) 1507 p=(char *) ResizeQuantumMemory(p,extent,sizeof(*p)); 1508 else 1509 { 1510 char 1511 *extent_xml; 1512 1513 extent_xml=(char *) AcquireQuantumMemory(extent, 1514 sizeof(*extent_xml)); 1515 if (extent_xml != (char *) NULL) 1516 { 1517 (void) CopyMagickString(extent_xml,p,extent* 1518 sizeof(*extent_xml)); 1519 p= extent_xml; 1520 } 1521 } 1522 if (p == (char *) NULL) 1523 ThrowFatalException(ResourceLimitFatalError, 1524 "MemoryAllocationFailed"); 1525 xml=p+offset; 1526 entity=strchr(xml,';'); 1527 } 1528 if (entity != (char *) NULL) 1529 (void) CopyMagickMemory(xml+length,entity+1,strlen(entity)); 1530 (void) strncpy(xml,entities[i],length); 1531 } 1532 } 1533 else 1534 if (((state == ' ') || (state == '*')) && 1535 (isspace((int) ((unsigned char) *xml) != 0))) 1536 *(xml++)=' '; 1537 else 1538 xml++; 1539 } 1540 if (state == '*') 1541 { 1542 /* 1543 Normalize spaces for non-CDATA attributes. 1544 */ 1545 for (xml=p; *xml != '\0'; xml++) 1546 { 1547 char 1548 accept[] = " "; 1549 1550 i=(ssize_t) strspn(xml,accept); 1551 if (i != 0) 1552 (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1); 1553 while ((*xml != '\0') && (*xml != ' ')) 1554 xml++; 1555 } 1556 xml--; 1557 if ((xml >= p) && (*xml == ' ')) 1558 *xml='\0'; 1559 } 1560 return(p == q ? ConstantString(p) : p); 1561 } 1562 1563 static void ParseCharacterContent(XMLTreeRoot *root,char *xml, 1564 const size_t length,const char state) 1565 { 1566 XMLTreeInfo 1567 *xml_info; 1568 1569 xml_info=root->node; 1570 if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) || 1571 (length == 0)) 1572 return; 1573 xml[length]='\0'; 1574 xml=ParseEntities(xml,root->entities,state); 1575 if ((xml_info->content != (char *) NULL) && (*xml_info->content != '\0')) 1576 { 1577 (void) ConcatenateString(&xml_info->content,xml); 1578 xml=DestroyString(xml); 1579 } 1580 else 1581 { 1582 if (xml_info->content != (char *) NULL) 1583 xml_info->content=DestroyString(xml_info->content); 1584 xml_info->content=xml; 1585 } 1586 } 1587 1588 static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag, 1589 ExceptionInfo *exception) 1590 { 1591 if ((root->node == (XMLTreeInfo *) NULL) || 1592 (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0)) 1593 { 1594 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 1595 "ParseError","unexpected closing tag </%s>",tag); 1596 return(&root->root); 1597 } 1598 root->node=root->node->parent; 1599 return((XMLTreeInfo *) NULL); 1600 } 1601 1602 static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities) 1603 { 1604 register ssize_t 1605 i; 1606 1607 /* 1608 Check for circular entity references. 1609 */ 1610 for ( ; ; xml++) 1611 { 1612 while ((*xml != '\0') && (*xml != '&')) 1613 xml++; 1614 if (*xml == '\0') 1615 return(MagickTrue); 1616 if (strncmp(xml+1,tag,strlen(tag)) == 0) 1617 return(MagickFalse); 1618 i=0; 1619 while ((entities[i] != (char *) NULL) && 1620 (strncmp(entities[i],xml+1,strlen(entities[i])) == 0)) 1621 i+=2; 1622 if ((entities[i] != (char *) NULL) && 1623 (ValidateEntities(tag,entities[i+1],entities) == 0)) 1624 return(MagickFalse); 1625 } 1626 } 1627 1628 static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml, 1629 size_t length) 1630 { 1631 char 1632 *target; 1633 1634 register ssize_t 1635 i; 1636 1637 ssize_t 1638 j; 1639 1640 target=xml; 1641 xml[length]='\0'; 1642 xml+=strcspn(xml,XMLWhitespace); 1643 if (*xml != '\0') 1644 { 1645 *xml='\0'; 1646 xml+=strspn(xml+1,XMLWhitespace)+1; 1647 } 1648 if (strcmp(target,"xml") == 0) 1649 { 1650 xml=strstr(xml,"standalone"); 1651 if ((xml != (char *) NULL) && 1652 (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0)) 1653 root->standalone=MagickTrue; 1654 return; 1655 } 1656 if (root->processing_instructions[0] == (char **) NULL) 1657 { 1658 root->processing_instructions=(char ***) AcquireMagickMemory(sizeof( 1659 *root->processing_instructions)); 1660 if (root->processing_instructions ==(char ***) NULL) 1661 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1662 *root->processing_instructions=(char **) NULL; 1663 } 1664 i=0; 1665 while ((root->processing_instructions[i] != (char **) NULL) && 1666 (strcmp(target,root->processing_instructions[i][0]) != 0)) 1667 i++; 1668 if (root->processing_instructions[i] == (char **) NULL) 1669 { 1670 root->processing_instructions=(char ***) ResizeQuantumMemory( 1671 root->processing_instructions,(size_t) (i+2), 1672 sizeof(*root->processing_instructions)); 1673 if (root->processing_instructions == (char ***) NULL) 1674 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1675 root->processing_instructions[i]=(char **) AcquireQuantumMemory(3, 1676 sizeof(**root->processing_instructions)); 1677 if (root->processing_instructions[i] == (char **) NULL) 1678 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1679 root->processing_instructions[i+1]=(char **) NULL; 1680 root->processing_instructions[i][0]=ConstantString(target); 1681 root->processing_instructions[i][1]=(char *) 1682 root->processing_instructions[i+1]; 1683 root->processing_instructions[i+1]=(char **) NULL; 1684 root->processing_instructions[i][2]=ConstantString(""); 1685 } 1686 j=1; 1687 while (root->processing_instructions[i][j] != (char *) NULL) 1688 j++; 1689 root->processing_instructions[i]=(char **) ResizeQuantumMemory( 1690 root->processing_instructions[i],(size_t) (j+3), 1691 sizeof(**root->processing_instructions)); 1692 if (root->processing_instructions[i] == (char **) NULL) 1693 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1694 root->processing_instructions[i][j+2]=(char *) ResizeQuantumMemory( 1695 root->processing_instructions[i][j+1],(size_t) (j+1), 1696 sizeof(***root->processing_instructions)); 1697 if (root->processing_instructions[i][j+2] == (char *) NULL) 1698 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1699 (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1, 1700 root->root.tag != (char *) NULL ? ">" : "<",2); 1701 root->processing_instructions[i][j]=ConstantString(xml); 1702 root->processing_instructions[i][j+1]=(char *) NULL; 1703 } 1704 1705 static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml, 1706 size_t length,ExceptionInfo *exception) 1707 { 1708 char 1709 *c, 1710 **entities, 1711 *n, 1712 **predefined_entitites, 1713 q, 1714 *t, 1715 *v; 1716 1717 register ssize_t 1718 i; 1719 1720 ssize_t 1721 j; 1722 1723 n=(char *) NULL; 1724 predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel)); 1725 if (predefined_entitites == (char **) NULL) 1726 ThrowFatalException(ResourceLimitError,"MemoryAllocationFailed"); 1727 (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel)); 1728 for (xml[length]='\0'; xml != (char *) NULL; ) 1729 { 1730 while ((*xml != '\0') && (*xml != '<') && (*xml != '%')) 1731 xml++; 1732 if (*xml == '\0') 1733 break; 1734 if (strncmp(xml,"<!ENTITY",8) == 0) 1735 { 1736 /* 1737 Parse entity definitions. 1738 */ 1739 xml+=strspn(xml+8,XMLWhitespace)+8; 1740 c=xml; 1741 n=xml+strspn(xml,XMLWhitespace "%"); 1742 xml=n+strcspn(n,XMLWhitespace); 1743 *xml=';'; 1744 v=xml+strspn(xml+1,XMLWhitespace)+1; 1745 q=(*v); 1746 v++; 1747 if ((q != '"') && (q != '\'')) 1748 { 1749 /* 1750 Skip externals. 1751 */ 1752 xml=strchr(xml,'>'); 1753 continue; 1754 } 1755 entities=(*c == '%') ? predefined_entitites : root->entities; 1756 for (i=0; entities[i] != (char *) NULL; i++) ; 1757 entities=(char **) ResizeQuantumMemory(entities,(size_t) (i+3), 1758 sizeof(*entities)); 1759 if (entities == (char **) NULL) 1760 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 1761 if (*c == '%') 1762 predefined_entitites=entities; 1763 else 1764 root->entities=entities; 1765 xml++; 1766 *xml='\0'; 1767 xml=strchr(v,q); 1768 if (xml != (char *) NULL) 1769 { 1770 *xml='\0'; 1771 xml++; 1772 } 1773 entities[i+1]=ParseEntities(v,predefined_entitites,'%'); 1774 entities[i+2]=(char *) NULL; 1775 if (ValidateEntities(n,entities[i+1],entities) != MagickFalse) 1776 entities[i]=n; 1777 else 1778 { 1779 if (entities[i+1] != v) 1780 entities[i+1]=DestroyString(entities[i+1]); 1781 (void) ThrowMagickException(exception,GetMagickModule(), 1782 OptionWarning,"ParseError","circular entity declaration &%s",n); 1783 predefined_entitites=(char **) RelinquishMagickMemory( 1784 predefined_entitites); 1785 return(MagickFalse); 1786 } 1787 } 1788 else 1789 if (strncmp(xml,"<!ATTLIST",9) == 0) 1790 { 1791 /* 1792 Parse default attributes. 1793 */ 1794 t=xml+strspn(xml+9,XMLWhitespace)+9; 1795 if (*t == '\0') 1796 { 1797 (void) ThrowMagickException(exception,GetMagickModule(), 1798 OptionWarning,"ParseError","unclosed <!ATTLIST"); 1799 predefined_entitites=(char **) RelinquishMagickMemory( 1800 predefined_entitites); 1801 return(MagickFalse); 1802 } 1803 xml=t+strcspn(t,XMLWhitespace ">"); 1804 if (*xml == '>') 1805 continue; 1806 *xml='\0'; 1807 i=0; 1808 while ((root->attributes[i] != (char **) NULL) && 1809 (n != (char *) NULL) && 1810 (strcmp(n,root->attributes[i][0]) != 0)) 1811 i++; 1812 while ((*(n=xml+strspn(xml+1,XMLWhitespace)+1) != '\0') && 1813 (*n != '>')) 1814 { 1815 xml=n+strcspn(n,XMLWhitespace); 1816 if (*xml != '\0') 1817 *xml='\0'; 1818 else 1819 { 1820 (void) ThrowMagickException(exception,GetMagickModule(), 1821 OptionWarning,"ParseError","malformed <!ATTLIST"); 1822 predefined_entitites=(char **) RelinquishMagickMemory( 1823 predefined_entitites); 1824 return(MagickFalse); 1825 } 1826 xml+=strspn(xml+1,XMLWhitespace)+1; 1827 c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " "); 1828 if (strncmp(xml,"NOTATION",8) == 0) 1829 xml+=strspn(xml+8,XMLWhitespace)+8; 1830 xml=(*xml == '(') ? strchr(xml,')') : xml+ 1831 strcspn(xml,XMLWhitespace); 1832 if (xml == (char *) NULL) 1833 { 1834 (void) ThrowMagickException(exception,GetMagickModule(), 1835 OptionWarning,"ParseError","malformed <!ATTLIST"); 1836 predefined_entitites=(char **) RelinquishMagickMemory( 1837 predefined_entitites); 1838 return(MagickFalse); 1839 } 1840 xml+=strspn(xml,XMLWhitespace ")"); 1841 if (strncmp(xml,"#FIXED",6) == 0) 1842 xml+=strspn(xml+6,XMLWhitespace)+6; 1843 if (*xml == '#') 1844 { 1845 xml+=strcspn(xml,XMLWhitespace ">")-1; 1846 if (*c == ' ') 1847 continue; 1848 v=(char *) NULL; 1849 } 1850 else 1851 if (((*xml == '"') || (*xml == '\'')) && 1852 ((xml=strchr(v=xml+1,*xml)) != (char *) NULL)) 1853 *xml='\0'; 1854 else 1855 { 1856 (void) ThrowMagickException(exception,GetMagickModule(), 1857 OptionWarning,"ParseError","malformed <!ATTLIST"); 1858 predefined_entitites=(char **) RelinquishMagickMemory( 1859 predefined_entitites); 1860 return(MagickFalse); 1861 } 1862 if (root->attributes[i] == (char **) NULL) 1863 { 1864 /* 1865 New attribute tag. 1866 */ 1867 if (i == 0) 1868 root->attributes=(char ***) AcquireQuantumMemory(2, 1869 sizeof(*root->attributes)); 1870 else 1871 root->attributes=(char ***) ResizeQuantumMemory( 1872 root->attributes,(size_t) (i+2), 1873 sizeof(*root->attributes)); 1874 if (root->attributes == (char ***) NULL) 1875 ThrowFatalException(ResourceLimitFatalError, 1876 "MemoryAllocationFailed"); 1877 root->attributes[i]=(char **) AcquireQuantumMemory(2, 1878 sizeof(**root->attributes)); 1879 if (root->attributes[i] == (char **) NULL) 1880 ThrowFatalException(ResourceLimitFatalError, 1881 "MemoryAllocationFailed"); 1882 root->attributes[i][0]=ConstantString(t); 1883 root->attributes[i][1]=(char *) NULL; 1884 root->attributes[i+1]=(char **) NULL; 1885 } 1886 for (j=1; root->attributes[i][j] != (char *) NULL; j+=3) ; 1887 root->attributes[i]=(char **) ResizeQuantumMemory( 1888 root->attributes[i],(size_t) (j+4),sizeof(**root->attributes)); 1889 if (root->attributes[i] == (char **) NULL) 1890 ThrowFatalException(ResourceLimitFatalError, 1891 "MemoryAllocationFailed"); 1892 root->attributes[i][j+3]=(char *) NULL; 1893 root->attributes[i][j+2]=ConstantString(c); 1894 root->attributes[i][j+1]=(char *) NULL; 1895 if (v != (char *) NULL) 1896 root->attributes[i][j+1]=ParseEntities(v,root->entities,*c); 1897 root->attributes[i][j]=ConstantString(n); 1898 } 1899 } 1900 else 1901 if (strncmp(xml, "<!--", 4) == 0) 1902 xml=strstr(xml+4,"-->"); 1903 else 1904 if (strncmp(xml,"<?", 2) == 0) 1905 { 1906 c=xml+2; 1907 xml=strstr(c,"?>"); 1908 if (xml != (char *) NULL) 1909 { 1910 ParseProcessingInstructions(root,c,(size_t) (xml-c)); 1911 xml++; 1912 } 1913 } 1914 else 1915 if (*xml == '<') 1916 xml=strchr(xml,'>'); 1917 else 1918 if ((*(xml++) == '%') && (root->standalone == MagickFalse)) 1919 break; 1920 } 1921 predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites); 1922 return(MagickTrue); 1923 } 1924 1925 static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes) 1926 { 1927 XMLTreeInfo 1928 *xml_info; 1929 1930 xml_info=root->node; 1931 if (xml_info->tag == (char *) NULL) 1932 xml_info->tag=ConstantString(tag); 1933 else 1934 xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content)); 1935 if (xml_info != (XMLTreeInfo *) NULL) 1936 xml_info->attributes=attributes; 1937 root->node=xml_info; 1938 } 1939 1940 static const char 1941 *ignore_tags[3] = 1942 { 1943 "rdf:Bag", 1944 "rdf:Seq", 1945 (const char *) NULL 1946 }; 1947 1948 static inline MagickBooleanType IsSkipTag(const char *tag) 1949 { 1950 register ssize_t 1951 i; 1952 1953 i=0; 1954 while (ignore_tags[i] != (const char *) NULL) 1955 { 1956 if (LocaleCompare(tag,ignore_tags[i]) == 0) 1957 return(MagickTrue); 1958 i++; 1959 } 1960 return(MagickFalse); 1961 } 1962 1963 MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception) 1964 { 1965 char 1966 **attribute, 1967 **attributes, 1968 *tag, 1969 *utf8; 1970 1971 int 1972 c, 1973 terminal; 1974 1975 MagickBooleanType 1976 status; 1977 1978 register char 1979 *p; 1980 1981 register ssize_t 1982 i; 1983 1984 size_t 1985 ignore_depth, 1986 length; 1987 1988 ssize_t 1989 j, 1990 l; 1991 1992 XMLTreeRoot 1993 *root; 1994 1995 /* 1996 Convert xml-string to UTF8. 1997 */ 1998 if ((xml == (const char *) NULL) || (strlen(xml) == 0)) 1999 { 2000 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 2001 "ParseError","root tag missing"); 2002 return((XMLTreeInfo *) NULL); 2003 } 2004 root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL); 2005 length=strlen(xml); 2006 utf8=ConvertUTF16ToUTF8(xml,&length); 2007 if (utf8 == (char *) NULL) 2008 { 2009 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 2010 "ParseError","UTF16 to UTF8 failed"); 2011 return((XMLTreeInfo *) NULL); 2012 } 2013 terminal=utf8[length-1]; 2014 utf8[length-1]='\0'; 2015 p=utf8; 2016 while ((*p != '\0') && (*p != '<')) 2017 p++; 2018 if (*p == '\0') 2019 { 2020 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 2021 "ParseError","root tag missing"); 2022 utf8=DestroyString(utf8); 2023 return((XMLTreeInfo *) NULL); 2024 } 2025 attribute=(char **) NULL; 2026 l=0; 2027 ignore_depth=0; 2028 for (p++; ; p++) 2029 { 2030 attributes=(char **) sentinel; 2031 tag=p; 2032 c=(*p); 2033 if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') || 2034 (*p == ':') || (c < '\0')) 2035 { 2036 /* 2037 Tag. 2038 */ 2039 if (root->node == (XMLTreeInfo *) NULL) 2040 { 2041 (void) ThrowMagickException(exception,GetMagickModule(), 2042 OptionWarning,"ParseError","root tag missing"); 2043 utf8=DestroyString(utf8); 2044 return(&root->root); 2045 } 2046 p+=strcspn(p,XMLWhitespace "/>"); 2047 while (isspace((int) ((unsigned char) *p)) != 0) 2048 *p++='\0'; 2049 if (ignore_depth == 0) 2050 { 2051 if ((*p != '\0') && (*p != '/') && (*p != '>')) 2052 { 2053 /* 2054 Find tag in default attributes list. 2055 */ 2056 i=0; 2057 while ((root->attributes[i] != (char **) NULL) && 2058 (strcmp(root->attributes[i][0],tag) != 0)) 2059 i++; 2060 attribute=root->attributes[i]; 2061 } 2062 for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2) 2063 { 2064 /* 2065 Attribute. 2066 */ 2067 if (l == 0) 2068 attributes=(char **) AcquireQuantumMemory(4, 2069 sizeof(*attributes)); 2070 else 2071 attributes=(char **) ResizeQuantumMemory(attributes, 2072 (size_t) (l+4),sizeof(*attributes)); 2073 if (attributes == (char **) NULL) 2074 { 2075 (void) ThrowMagickException(exception,GetMagickModule(), 2076 ResourceLimitError,"MemoryAllocationFailed","`%s'",""); 2077 utf8=DestroyString(utf8); 2078 return(&root->root); 2079 } 2080 attributes[l+2]=(char *) NULL; 2081 attributes[l+1]=(char *) NULL; 2082 attributes[l]=p; 2083 p+=strcspn(p,XMLWhitespace "=/>"); 2084 if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0)) 2085 attributes[l]=ConstantString(""); 2086 else 2087 { 2088 *p++='\0'; 2089 p+=strspn(p,XMLWhitespace "="); 2090 c=(*p); 2091 if ((c == '"') || (c == '\'')) 2092 { 2093 /* 2094 Attributes value. 2095 */ 2096 p++; 2097 attributes[l+1]=p; 2098 while ((*p != '\0') && (*p != c)) 2099 p++; 2100 if (*p != '\0') 2101 *p++='\0'; 2102 else 2103 { 2104 attributes[l]=ConstantString(""); 2105 attributes[l+1]=ConstantString(""); 2106 (void) DestroyXMLTreeAttributes(attributes); 2107 (void) ThrowMagickException(exception, 2108 GetMagickModule(),OptionWarning,"ParseError", 2109 "missing %c",c); 2110 utf8=DestroyString(utf8); 2111 return(&root->root); 2112 } 2113 j=1; 2114 while ((attribute != (char **) NULL) && 2115 (attribute[j] != (char *) NULL) && 2116 (strcmp(attribute[j],attributes[l]) != 0)) 2117 j+=3; 2118 attributes[l+1]=ParseEntities(attributes[l+1], 2119 root->entities,(attribute != (char **) NULL) && 2120 (attribute[j] != (char *) NULL) ? *attribute[j+2] : 2121 ' '); 2122 } 2123 attributes[l]=ConstantString(attributes[l]); 2124 } 2125 while (isspace((int) ((unsigned char) *p)) != 0) 2126 p++; 2127 } 2128 } 2129 else 2130 { 2131 while((*p != '\0') && (*p != '/') && (*p != '>')) 2132 p++; 2133 } 2134 if (*p == '/') 2135 { 2136 /* 2137 Self closing tag. 2138 */ 2139 *p++='\0'; 2140 if (((*p != '\0') && (*p != '>')) || 2141 ((*p == '\0') && (terminal != '>'))) 2142 { 2143 if (l != 0) 2144 (void) DestroyXMLTreeAttributes(attributes); 2145 (void) ThrowMagickException(exception,GetMagickModule(), 2146 OptionWarning,"ParseError","missing >"); 2147 utf8=DestroyString(utf8); 2148 return(&root->root); 2149 } 2150 if ((ignore_depth == 0) && (IsSkipTag(tag) == MagickFalse)) 2151 { 2152 ParseOpenTag(root,tag,attributes); 2153 (void) ParseCloseTag(root,tag,exception); 2154 } 2155 } 2156 else 2157 { 2158 c=(*p); 2159 if ((*p == '>') || ((*p == '\0') && (terminal == '>'))) 2160 { 2161 *p='\0'; 2162 if ((ignore_depth == 0) && (IsSkipTag(tag) == MagickFalse)) 2163 ParseOpenTag(root,tag,attributes); 2164 else 2165 { 2166 ignore_depth++; 2167 (void) DestroyXMLTreeAttributes(attributes); 2168 } 2169 *p=c; 2170 } 2171 else 2172 { 2173 if (l != 0) 2174 (void) DestroyXMLTreeAttributes(attributes); 2175 (void) ThrowMagickException(exception,GetMagickModule(), 2176 OptionWarning,"ParseError","missing >"); 2177 utf8=DestroyString(utf8); 2178 return(&root->root); 2179 } 2180 } 2181 } 2182 else 2183 if (*p == '/') 2184 { 2185 /* 2186 Close tag. 2187 */ 2188 tag=p+1; 2189 p+=strcspn(tag,XMLWhitespace ">")+1; 2190 c=(*p); 2191 if ((c == '\0') && (terminal != '>')) 2192 { 2193 (void) ThrowMagickException(exception,GetMagickModule(), 2194 OptionWarning,"ParseError","missing >"); 2195 utf8=DestroyString(utf8); 2196 return(&root->root); 2197 } 2198 *p='\0'; 2199 if (ignore_depth == 0 && ParseCloseTag(root,tag,exception) != 2200 (XMLTreeInfo *) NULL) 2201 { 2202 utf8=DestroyString(utf8); 2203 return(&root->root); 2204 } 2205 if (ignore_depth > 0) 2206 ignore_depth--; 2207 *p=c; 2208 if (isspace((int) ((unsigned char) *p)) != 0) 2209 p+=strspn(p,XMLWhitespace); 2210 } 2211 else 2212 if (strncmp(p,"!--",3) == 0) 2213 { 2214 /* 2215 Comment. 2216 */ 2217 p=strstr(p+3,"--"); 2218 if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) || 2219 ((*p == '\0') && (terminal != '>'))) 2220 { 2221 (void) ThrowMagickException(exception,GetMagickModule(), 2222 OptionWarning,"ParseError","unclosed <!--"); 2223 utf8=DestroyString(utf8); 2224 return(&root->root); 2225 } 2226 } 2227 else 2228 if (strncmp(p,"![CDATA[",8) == 0) 2229 { 2230 /* 2231 Cdata. 2232 */ 2233 p=strstr(p,"]]>"); 2234 if (p != (char *) NULL) 2235 { 2236 p+=2; 2237 if (ignore_depth == 0) 2238 ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c'); 2239 } 2240 else 2241 { 2242 (void) ThrowMagickException(exception,GetMagickModule(), 2243 OptionWarning,"ParseError","unclosed <![CDATA["); 2244 utf8=DestroyString(utf8); 2245 return(&root->root); 2246 } 2247 } 2248 else 2249 if (strncmp(p,"!DOCTYPE",8) == 0) 2250 { 2251 /* 2252 DTD. 2253 */ 2254 for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) || 2255 ((l != 0) && ((*p != ']') || 2256 (*(p+strspn(p+1,XMLWhitespace)+1) != '>')))); 2257 l=(ssize_t) ((*p == '[') ? 1 : l)) 2258 p+=strcspn(p+1,"[]>")+1; 2259 if ((*p == '\0') && (terminal != '>')) 2260 { 2261 (void) ThrowMagickException(exception,GetMagickModule(), 2262 OptionWarning,"ParseError","unclosed <!DOCTYPE"); 2263 utf8=DestroyString(utf8); 2264 return(&root->root); 2265 } 2266 if (l != 0) 2267 tag=strchr(tag,'[')+1; 2268 if (l != 0) 2269 { 2270 status=ParseInternalDoctype(root,tag,(size_t) (p-tag), 2271 exception); 2272 if (status == MagickFalse) 2273 { 2274 utf8=DestroyString(utf8); 2275 return(&root->root); 2276 } 2277 p++; 2278 } 2279 } 2280 else 2281 if (*p == '?') 2282 { 2283 /* 2284 Processing instructions. 2285 */ 2286 do 2287 { 2288 p=strchr(p,'?'); 2289 if (p == (char *) NULL) 2290 break; 2291 p++; 2292 } while ((*p != '\0') && (*p != '>')); 2293 if ((p == (char *) NULL) || ((*p == '\0') && 2294 (terminal != '>'))) 2295 { 2296 (void) ThrowMagickException(exception,GetMagickModule(), 2297 OptionWarning,"ParseError","unclosed <?"); 2298 utf8=DestroyString(utf8); 2299 return(&root->root); 2300 } 2301 ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2)); 2302 } 2303 else 2304 { 2305 (void) ThrowMagickException(exception,GetMagickModule(), 2306 OptionWarning,"ParseError","unexpected <"); 2307 utf8=DestroyString(utf8); 2308 return(&root->root); 2309 } 2310 if ((p == (char *) NULL) || (*p == '\0')) 2311 break; 2312 *p++='\0'; 2313 tag=p; 2314 if ((*p != '\0') && (*p != '<')) 2315 { 2316 /* 2317 Tag character content. 2318 */ 2319 while ((*p != '\0') && (*p != '<')) 2320 p++; 2321 if (*p == '\0') 2322 break; 2323 if (ignore_depth == 0) 2324 ParseCharacterContent(root,tag,(size_t) (p-tag),'&'); 2325 } 2326 else 2327 if (*p == '\0') 2328 break; 2329 } 2330 utf8=DestroyString(utf8); 2331 if (root->node == (XMLTreeInfo *) NULL) 2332 return(&root->root); 2333 if (root->node->tag == (char *) NULL) 2334 { 2335 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 2336 "ParseError","root tag missing"); 2337 return(&root->root); 2338 } 2339 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 2340 "ParseError","unclosed tag: '%s'",root->node->tag); 2341 return(&root->root); 2342 } 2343 2344 /* 2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2347 % % 2348 % % 2349 % % 2350 % N e w X M L T r e e T a g % 2351 % % 2352 % % 2353 % % 2354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2355 % 2356 % NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag. 2357 % 2358 % The format of the NewXMLTreeTag method is: 2359 % 2360 % XMLTreeInfo *NewXMLTreeTag(const char *tag) 2361 % 2362 % A description of each parameter follows: 2363 % 2364 % o tag: the tag. 2365 % 2366 */ 2367 MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag) 2368 { 2369 static const char 2370 *predefined_entities[NumberPredefinedEntities+1] = 2371 { 2372 "lt;", "<", "gt;", ">", "quot;", """, 2373 "apos;", "'", "amp;", "&", (char *) NULL 2374 }; 2375 2376 XMLTreeRoot 2377 *root; 2378 2379 root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root)); 2380 if (root == (XMLTreeRoot *) NULL) 2381 return((XMLTreeInfo *) NULL); 2382 (void) ResetMagickMemory(root,0,sizeof(*root)); 2383 root->root.tag=(char *) NULL; 2384 if (tag != (char *) NULL) 2385 root->root.tag=ConstantString(tag); 2386 root->node=(&root->root); 2387 root->root.content=ConstantString(""); 2388 root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities)); 2389 if (root->entities == (char **) NULL) 2390 return((XMLTreeInfo *) NULL); 2391 (void) CopyMagickMemory(root->entities,predefined_entities, 2392 sizeof(predefined_entities)); 2393 root->root.attributes=sentinel; 2394 root->attributes=(char ***) root->root.attributes; 2395 root->processing_instructions=(char ***) root->root.attributes; 2396 root->debug=IsEventLogging(); 2397 root->signature=MagickCoreSignature; 2398 return(&root->root); 2399 } 2400 2401 /* 2403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2404 % % 2405 % % 2406 % % 2407 % P r u n e T a g F r o m X M L T r e e % 2408 % % 2409 % % 2410 % % 2411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2412 % 2413 % PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its 2414 % subtags. 2415 % 2416 % The format of the PruneTagFromXMLTree method is: 2417 % 2418 % XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info) 2419 % 2420 % A description of each parameter follows: 2421 % 2422 % o xml_info: the xml info. 2423 % 2424 */ 2425 MagickPrivate XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info) 2426 { 2427 XMLTreeInfo 2428 *node; 2429 2430 assert(xml_info != (XMLTreeInfo *) NULL); 2431 assert((xml_info->signature == MagickCoreSignature) || 2432 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 2433 if (xml_info->debug != MagickFalse) 2434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 2435 if (xml_info->next != (XMLTreeInfo *) NULL) 2436 xml_info->next->sibling=xml_info->sibling; 2437 if (xml_info->parent != (XMLTreeInfo *) NULL) 2438 { 2439 node=xml_info->parent->child; 2440 if (node == xml_info) 2441 xml_info->parent->child=xml_info->ordered; 2442 else 2443 { 2444 while (node->ordered != xml_info) 2445 node=node->ordered; 2446 node->ordered=node->ordered->ordered; 2447 node=xml_info->parent->child; 2448 if (strcmp(node->tag,xml_info->tag) != 0) 2449 { 2450 while (strcmp(node->sibling->tag,xml_info->tag) != 0) 2451 node=node->sibling; 2452 if (node->sibling != xml_info) 2453 node=node->sibling; 2454 else 2455 node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ? 2456 xml_info->next : node->sibling->sibling; 2457 } 2458 while ((node->next != (XMLTreeInfo *) NULL) && 2459 (node->next != xml_info)) 2460 node=node->next; 2461 if (node->next != (XMLTreeInfo *) NULL) 2462 node->next=node->next->next; 2463 } 2464 } 2465 xml_info->ordered=(XMLTreeInfo *) NULL; 2466 xml_info->sibling=(XMLTreeInfo *) NULL; 2467 xml_info->next=(XMLTreeInfo *) NULL; 2468 return(xml_info); 2469 } 2470 2471 /* 2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2474 % % 2475 % % 2476 % % 2477 % S e t X M L T r e e A t t r i b u t e % 2478 % % 2479 % % 2480 % % 2481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2482 % 2483 % SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not 2484 % found. A value of NULL removes the specified attribute. 2485 % 2486 % The format of the SetXMLTreeAttribute method is: 2487 % 2488 % XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag, 2489 % const char *value) 2490 % 2491 % A description of each parameter follows: 2492 % 2493 % o xml_info: the xml info. 2494 % 2495 % o tag: The attribute tag. 2496 % 2497 % o value: The attribute value. 2498 % 2499 */ 2500 MagickPrivate XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info, 2501 const char *tag,const char *value) 2502 { 2503 register ssize_t 2504 i; 2505 2506 ssize_t 2507 j; 2508 2509 assert(xml_info != (XMLTreeInfo *) NULL); 2510 assert((xml_info->signature == MagickCoreSignature) || 2511 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 2512 if (xml_info->debug != MagickFalse) 2513 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 2514 i=0; 2515 while ((xml_info->attributes[i] != (char *) NULL) && 2516 (strcmp(xml_info->attributes[i],tag) != 0)) 2517 i+=2; 2518 if (xml_info->attributes[i] == (char *) NULL) 2519 { 2520 /* 2521 Add new attribute tag. 2522 */ 2523 if (value == (const char *) NULL) 2524 return(xml_info); 2525 if (xml_info->attributes != sentinel) 2526 xml_info->attributes=(char **) ResizeQuantumMemory( 2527 xml_info->attributes,(size_t) (i+4),sizeof(*xml_info->attributes)); 2528 else 2529 { 2530 xml_info->attributes=(char **) AcquireQuantumMemory(4, 2531 sizeof(*xml_info->attributes)); 2532 if (xml_info->attributes != (char **) NULL) 2533 xml_info->attributes[1]=ConstantString(""); 2534 } 2535 if (xml_info->attributes == (char **) NULL) 2536 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString"); 2537 xml_info->attributes[i]=ConstantString(tag); 2538 xml_info->attributes[i+2]=(char *) NULL; 2539 (void) strlen(xml_info->attributes[i+1]); 2540 } 2541 /* 2542 Add new value to an existing attribute. 2543 */ 2544 for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2) ; 2545 if (xml_info->attributes[i+1] != (char *) NULL) 2546 xml_info->attributes[i+1]=DestroyString(xml_info->attributes[i+1]); 2547 if (value != (const char *) NULL) 2548 { 2549 xml_info->attributes[i+1]=ConstantString(value); 2550 return(xml_info); 2551 } 2552 if (xml_info->attributes[i] != (char *) NULL) 2553 xml_info->attributes[i]=DestroyString(xml_info->attributes[i]); 2554 (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2, 2555 (size_t) (j-i)*sizeof(*xml_info->attributes)); 2556 xml_info->attributes=(char **) ResizeQuantumMemory(xml_info->attributes, 2557 (size_t) (j+2),sizeof(*xml_info->attributes)); 2558 if (xml_info->attributes == (char **) NULL) 2559 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString"); 2560 j-=2; 2561 (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2), 2562 xml_info->attributes[j+1]+(i/2)+1,(size_t) (((j+2)/2)-(i/2))* 2563 sizeof(**xml_info->attributes)); 2564 return(xml_info); 2565 } 2566 2567 /* 2569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2570 % % 2571 % % 2572 % % 2573 % S e t X M L T r e e C o n t e n t % 2574 % % 2575 % % 2576 % % 2577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2578 % 2579 % SetXMLTreeContent() sets the character content for the given tag and 2580 % returns the tag. 2581 % 2582 % The format of the SetXMLTreeContent method is: 2583 % 2584 % XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info, 2585 % const char *content) 2586 % 2587 % A description of each parameter follows: 2588 % 2589 % o xml_info: the xml info. 2590 % 2591 % o content: The content. 2592 % 2593 */ 2594 MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info, 2595 const char *content) 2596 { 2597 assert(xml_info != (XMLTreeInfo *) NULL); 2598 assert((xml_info->signature == MagickCoreSignature) || 2599 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 2600 if (xml_info->debug != MagickFalse) 2601 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 2602 if (xml_info->content != (char *) NULL) 2603 xml_info->content=DestroyString(xml_info->content); 2604 xml_info->content=(char *) ConstantString(content); 2605 return(xml_info); 2606 } 2607 2608 /* 2610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2611 % % 2612 % % 2613 % % 2614 % X M L T r e e I n f o T o X M L % 2615 % % 2616 % % 2617 % % 2618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2619 % 2620 % XMLTreeInfoToXML() converts an xml-tree to an XML string. 2621 % 2622 % The format of the XMLTreeInfoToXML method is: 2623 % 2624 % char *XMLTreeInfoToXML(XMLTreeInfo *xml_info) 2625 % 2626 % A description of each parameter follows: 2627 % 2628 % o xml_info: the xml info. 2629 % 2630 */ 2631 2632 static char *EncodePredefinedEntities(const char *source,ssize_t offset, 2633 char **destination,size_t *length,size_t *extent,MagickBooleanType pedantic) 2634 { 2635 char 2636 *canonical_content; 2637 2638 if (offset < 0) 2639 canonical_content=CanonicalXMLContent(source,pedantic); 2640 else 2641 { 2642 char 2643 *content; 2644 2645 content=AcquireString(source); 2646 content[offset]='\0'; 2647 canonical_content=CanonicalXMLContent(content,pedantic); 2648 content=DestroyString(content); 2649 } 2650 if (canonical_content == (char *) NULL) 2651 return(*destination); 2652 if ((*length+strlen(canonical_content)+MagickPathExtent) > *extent) 2653 { 2654 *extent=(*length)+strlen(canonical_content)+MagickPathExtent; 2655 *destination=(char *) ResizeQuantumMemory(*destination,*extent, 2656 sizeof(**destination)); 2657 if (*destination == (char *) NULL) 2658 return(*destination); 2659 } 2660 *length+=FormatLocaleString(*destination+(*length),*extent,"%s", 2661 canonical_content); 2662 canonical_content=DestroyString(canonical_content); 2663 return(*destination); 2664 } 2665 2666 static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length, 2667 size_t *extent,size_t start,char ***attributes) 2668 { 2669 char 2670 *content; 2671 2672 const char 2673 *attribute; 2674 2675 register ssize_t 2676 i; 2677 2678 size_t 2679 offset; 2680 2681 ssize_t 2682 j; 2683 2684 content=(char *) ""; 2685 if (xml_info->parent != (XMLTreeInfo *) NULL) 2686 content=xml_info->parent->content; 2687 offset=0; 2688 *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset- 2689 start),source,length,extent,MagickFalse); 2690 if ((*length+strlen(xml_info->tag)+MagickPathExtent) > *extent) 2691 { 2692 *extent=(*length)+strlen(xml_info->tag)+MagickPathExtent; 2693 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 2694 if (*source == (char *) NULL) 2695 return(*source); 2696 } 2697 *length+=FormatLocaleString(*source+(*length),*extent,"<%s",xml_info->tag); 2698 for (i=0; xml_info->attributes[i]; i+=2) 2699 { 2700 attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]); 2701 if (attribute != xml_info->attributes[i+1]) 2702 continue; 2703 if ((*length+strlen(xml_info->attributes[i])+MagickPathExtent) > *extent) 2704 { 2705 *extent=(*length)+strlen(xml_info->attributes[i])+MagickPathExtent; 2706 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 2707 if (*source == (char *) NULL) 2708 return((char *) NULL); 2709 } 2710 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"", 2711 xml_info->attributes[i]); 2712 (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length, 2713 extent,MagickTrue); 2714 *length+=FormatLocaleString(*source+(*length),*extent,"\""); 2715 } 2716 i=0; 2717 while ((attributes[i] != (char **) NULL) && 2718 (strcmp(attributes[i][0],xml_info->tag) != 0)) 2719 i++; 2720 j=1; 2721 while ((attributes[i] != (char **) NULL) && 2722 (attributes[i][j] != (char *) NULL)) 2723 { 2724 if ((attributes[i][j+1] == (char *) NULL) || 2725 (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1])) 2726 { 2727 j+=3; 2728 continue; 2729 } 2730 if ((*length+strlen(attributes[i][j])+MagickPathExtent) > *extent) 2731 { 2732 *extent=(*length)+strlen(attributes[i][j])+MagickPathExtent; 2733 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 2734 if (*source == (char *) NULL) 2735 return((char *) NULL); 2736 } 2737 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"", 2738 attributes[i][j]); 2739 (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent, 2740 MagickTrue); 2741 *length+=FormatLocaleString(*source+(*length),*extent,"\""); 2742 j+=3; 2743 } 2744 *length+=FormatLocaleString(*source+(*length),*extent,*xml_info->content ? 2745 ">" : "/>"); 2746 if (xml_info->child != (XMLTreeInfo *) NULL) 2747 *source=XMLTreeTagToXML(xml_info->child,source,length,extent,0,attributes); 2748 else 2749 *source=EncodePredefinedEntities(xml_info->content,-1,source,length,extent, 2750 MagickFalse); 2751 if ((*length+strlen(xml_info->tag)+MagickPathExtent) > *extent) 2752 { 2753 *extent=(*length)+strlen(xml_info->tag)+MagickPathExtent; 2754 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 2755 if (*source == (char *) NULL) 2756 return((char *) NULL); 2757 } 2758 if (*xml_info->content != '\0') 2759 *length+=FormatLocaleString(*source+(*length),*extent,"</%s>", 2760 xml_info->tag); 2761 while ((content[offset] != '\0') && (offset < xml_info->offset)) 2762 offset++; 2763 if (xml_info->ordered != (XMLTreeInfo *) NULL) 2764 content=XMLTreeTagToXML(xml_info->ordered,source,length,extent,offset, 2765 attributes); 2766 else 2767 content=EncodePredefinedEntities(content+offset,-1,source,length,extent, 2768 MagickFalse); 2769 return(content); 2770 } 2771 2772 MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info) 2773 { 2774 char 2775 *xml; 2776 2777 register char 2778 *p, 2779 *q; 2780 2781 register ssize_t 2782 i; 2783 2784 size_t 2785 extent, 2786 length; 2787 2788 ssize_t 2789 j, 2790 k; 2791 2792 XMLTreeInfo 2793 *ordered, 2794 *parent; 2795 2796 XMLTreeRoot 2797 *root; 2798 2799 assert(xml_info != (XMLTreeInfo *) NULL); 2800 assert((xml_info->signature == MagickCoreSignature) || 2801 (((XMLTreeRoot *) xml_info)->signature == MagickCoreSignature)); 2802 if (xml_info->debug != MagickFalse) 2803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 2804 if (xml_info->tag == (char *) NULL) 2805 return((char *) NULL); 2806 xml=AcquireString((char *) NULL); 2807 length=0; 2808 extent=MagickPathExtent; 2809 root=(XMLTreeRoot *) xml_info; 2810 while (root->root.parent != (XMLTreeInfo *) NULL) 2811 root=(XMLTreeRoot *) root->root.parent; 2812 parent=xml_info->parent; 2813 if (parent == (XMLTreeInfo *) NULL) 2814 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 2815 { 2816 /* 2817 Pre-root processing instructions. 2818 */ 2819 for (k=2; root->processing_instructions[i][k-1]; k++) ; 2820 p=root->processing_instructions[i][1]; 2821 for (j=1; p != (char *) NULL; j++) 2822 { 2823 if (root->processing_instructions[i][k][j-1] == '>') 2824 { 2825 p=root->processing_instructions[i][j]; 2826 continue; 2827 } 2828 q=root->processing_instructions[i][0]; 2829 if ((length+strlen(p)+strlen(q)+MagickPathExtent) > extent) 2830 { 2831 extent=length+strlen(p)+strlen(q)+MagickPathExtent; 2832 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml)); 2833 if (xml == (char *) NULL) 2834 return(xml); 2835 } 2836 length+=FormatLocaleString(xml+length,extent,"<?%s%s%s?>\n",q, 2837 *p != '\0' ? " " : "",p); 2838 p=root->processing_instructions[i][j]; 2839 } 2840 } 2841 ordered=xml_info->ordered; 2842 xml_info->parent=(XMLTreeInfo *) NULL; 2843 xml_info->ordered=(XMLTreeInfo *) NULL; 2844 xml=XMLTreeTagToXML(xml_info,&xml,&length,&extent,0,root->attributes); 2845 xml_info->parent=parent; 2846 xml_info->ordered=ordered; 2847 if (parent == (XMLTreeInfo *) NULL) 2848 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 2849 { 2850 /* 2851 Post-root processing instructions. 2852 */ 2853 for (k=2; root->processing_instructions[i][k-1]; k++) ; 2854 p=root->processing_instructions[i][1]; 2855 for (j=1; p != (char *) NULL; j++) 2856 { 2857 if (root->processing_instructions[i][k][j-1] == '<') 2858 { 2859 p=root->processing_instructions[i][j]; 2860 continue; 2861 } 2862 q=root->processing_instructions[i][0]; 2863 if ((length+strlen(p)+strlen(q)+MagickPathExtent) > extent) 2864 { 2865 extent=length+strlen(p)+strlen(q)+MagickPathExtent; 2866 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml)); 2867 if (xml == (char *) NULL) 2868 return(xml); 2869 } 2870 length+=FormatLocaleString(xml+length,extent,"\n<?%s%s%s?>",q, 2871 *p != '\0' ? " " : "",p); 2872 p=root->processing_instructions[i][j]; 2873 } 2874 } 2875 return((char *) ResizeQuantumMemory(xml,length+1,sizeof(*xml))); 2876 } 2877