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