|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % X X M M L % 00007 % X X MM MM L % 00008 % X M M M L % 00009 % X X M M L % 00010 % X X M M LLLLL % 00011 % % 00012 % TTTTT RRRR EEEEE EEEEE % 00013 % T R R E E % 00014 % T RRRR EEE EEE % 00015 % T R R E E % 00016 % T R R EEEEE EEEEE % 00017 % % 00018 % % 00019 % XML Tree Methods % 00020 % % 00021 % Software Design % 00022 % John Cristy % 00023 % December 2004 % 00024 % % 00025 % % 00026 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00027 % dedicated to making software imaging solutions freely available. % 00028 % % 00029 % You may not use this file except in compliance with the License. You may % 00030 % obtain a copy of the License at % 00031 % % 00032 % http://www.imagemagick.org/script/license.php % 00033 % % 00034 % Unless required by applicable law or agreed to in writing, software % 00035 % distributed under the License is distributed on an "AS IS" BASIS, % 00036 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00037 % See the License for the specific language governing permissions and % 00038 % limitations under the License. % 00039 % % 00040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00041 % 00042 % This module implements the standard handy xml-tree methods for storing and 00043 % retrieving nodes and attributes from an XML string. 00044 % 00045 */ 00046 00047 /* 00048 Include declarations. 00049 */ 00050 #include "MagickCore/studio.h" 00051 #include "MagickCore/blob.h" 00052 #include "MagickCore/exception.h" 00053 #include "MagickCore/exception-private.h" 00054 #include "MagickCore/log.h" 00055 #include "MagickCore/memory_.h" 00056 #include "MagickCore/semaphore.h" 00057 #include "MagickCore/string_.h" 00058 #include "MagickCore/string-private.h" 00059 #include "MagickCore/token-private.h" 00060 #include "MagickCore/xml-tree.h" 00061 #include "MagickCore/xml-tree-private.h" 00062 #include "MagickCore/utility.h" 00063 #include "MagickCore/utility-private.h" 00064 00065 /* 00066 Define declarations. 00067 */ 00068 #define NumberPredefinedEntities 10 00069 #define XMLWhitespace "\t\r\n " 00070 00071 /* 00072 Typedef declarations. 00073 */ 00074 struct _XMLTreeInfo 00075 { 00076 char 00077 *tag, 00078 **attributes, 00079 *content; 00080 00081 size_t 00082 offset; 00083 00084 XMLTreeInfo 00085 *parent, 00086 *next, 00087 *sibling, 00088 *ordered, 00089 *child; 00090 00091 MagickBooleanType 00092 debug; 00093 00094 SemaphoreInfo 00095 *semaphore; 00096 00097 size_t 00098 signature; 00099 }; 00100 00101 typedef struct _XMLTreeRoot 00102 XMLTreeRoot; 00103 00104 struct _XMLTreeRoot 00105 { 00106 struct _XMLTreeInfo 00107 root; 00108 00109 XMLTreeInfo 00110 *node; 00111 00112 MagickBooleanType 00113 standalone; 00114 00115 char 00116 ***processing_instructions, 00117 **entities, 00118 ***attributes; 00119 00120 MagickBooleanType 00121 debug; 00122 00123 SemaphoreInfo 00124 *semaphore; 00125 00126 size_t 00127 signature; 00128 }; 00129 00130 /* 00131 Global declarations. 00132 */ 00133 static char 00134 *sentinel[] = { (char *) NULL }; 00135 00136 /* 00137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00138 % % 00139 % % 00140 % % 00141 % A d d C h i l d T o X M L T r e e % 00142 % % 00143 % % 00144 % % 00145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00146 % 00147 % AddChildToXMLTree() adds a child tag at an offset relative to the start of 00148 % the parent tag's character content. Return the child tag. 00149 % 00150 % The format of the AddChildToXMLTree method is: 00151 % 00152 % XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag, 00153 % const size_t offset) 00154 % 00155 % A description of each parameter follows: 00156 % 00157 % o xml_info: the xml info. 00158 % 00159 % o tag: the tag. 00160 % 00161 % o offset: the tag offset. 00162 % 00163 */ 00164 MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info, 00165 const char *tag,const size_t offset) 00166 { 00167 XMLTreeInfo 00168 *child; 00169 00170 if (xml_info == (XMLTreeInfo *) NULL) 00171 return((XMLTreeInfo *) NULL); 00172 child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child)); 00173 if (child == (XMLTreeInfo *) NULL) 00174 return((XMLTreeInfo *) NULL); 00175 (void) ResetMagickMemory(child,0,sizeof(*child)); 00176 child->tag=ConstantString(tag); 00177 child->attributes=sentinel; 00178 child->content=ConstantString(""); 00179 child->debug=IsEventLogging(); 00180 child->signature=MagickSignature; 00181 return(InsertTagIntoXMLTree(xml_info,child,offset)); 00182 } 00183 00184 /* 00185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00186 % % 00187 % % 00188 % % 00189 % A d d P a t h T o X M L T r e e % 00190 % % 00191 % % 00192 % % 00193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00194 % 00195 % AddPathToXMLTree() adds a child tag at an offset relative to the start of 00196 % the parent tag's character content. This method returns the child tag. 00197 % 00198 % The format of the AddPathToXMLTree method is: 00199 % 00200 % XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path, 00201 % const size_t offset) 00202 % 00203 % A description of each parameter follows: 00204 % 00205 % o xml_info: the xml info. 00206 % 00207 % o path: the path. 00208 % 00209 % o offset: the tag offset. 00210 % 00211 */ 00212 MagickPrivate XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info, 00213 const char *path,const size_t offset) 00214 { 00215 char 00216 **components, 00217 subnode[MaxTextExtent], 00218 tag[MaxTextExtent]; 00219 00220 register ssize_t 00221 i; 00222 00223 size_t 00224 number_components; 00225 00226 ssize_t 00227 j; 00228 00229 XMLTreeInfo 00230 *child, 00231 *node; 00232 00233 assert(xml_info != (XMLTreeInfo *) NULL); 00234 assert((xml_info->signature == MagickSignature) || 00235 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00236 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00237 node=xml_info; 00238 components=GetPathComponents(path,&number_components); 00239 if (components == (char **) NULL) 00240 return((XMLTreeInfo *) NULL); 00241 for (i=0; i < (ssize_t) number_components; i++) 00242 { 00243 GetPathComponent(components[i],SubimagePath,subnode); 00244 GetPathComponent(components[i],CanonicalPath,tag); 00245 child=GetXMLTreeChild(node,tag); 00246 if (child == (XMLTreeInfo *) NULL) 00247 child=AddChildToXMLTree(node,tag,offset); 00248 node=child; 00249 if (node == (XMLTreeInfo *) NULL) 00250 break; 00251 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--) 00252 { 00253 node=GetXMLTreeOrdered(node); 00254 if (node == (XMLTreeInfo *) NULL) 00255 break; 00256 } 00257 if (node == (XMLTreeInfo *) NULL) 00258 break; 00259 components[i]=DestroyString(components[i]); 00260 } 00261 for ( ; i < (ssize_t) number_components; i++) 00262 components[i]=DestroyString(components[i]); 00263 components=(char **) RelinquishMagickMemory(components); 00264 return(node); 00265 } 00266 00267 /* 00268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00269 % % 00270 % % 00271 % % 00272 % C a n o n i c a l X M L C o n t e n t % 00273 % % 00274 % % 00275 % % 00276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00277 % 00278 % CanonicalXMLContent() converts text to canonical XML content by converting 00279 % to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding 00280 % as base-64 as required. 00281 % 00282 % The format of the CanonicalXMLContent method is: 00283 % 00284 % 00285 % char *CanonicalXMLContent(const char *content, 00286 % const MagickBooleanType pedantic) 00287 % 00288 % A description of each parameter follows: 00289 % 00290 % o content: the content. 00291 % 00292 % o pedantic: if true, replace newlines and tabs with their respective 00293 % entities. 00294 % 00295 */ 00296 MagickPrivate char *CanonicalXMLContent(const char *content, 00297 const MagickBooleanType pedantic) 00298 { 00299 char 00300 *base64, 00301 *canonical_content; 00302 00303 register const unsigned char 00304 *p; 00305 00306 register ssize_t 00307 i; 00308 00309 size_t 00310 extent, 00311 length; 00312 00313 unsigned char 00314 *utf8; 00315 00316 utf8=ConvertLatin1ToUTF8((const unsigned char *) content); 00317 if (utf8 == (unsigned char *) NULL) 00318 return((char *) NULL); 00319 for (p=utf8; *p != '\0'; p++) 00320 if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d)) 00321 break; 00322 if (*p != '\0') 00323 { 00324 /* 00325 String is binary, base64-encode it. 00326 */ 00327 base64=Base64Encode(utf8,strlen((char *) utf8),&length); 00328 utf8=(unsigned char *) RelinquishMagickMemory(utf8); 00329 if (base64 == (char *) NULL) 00330 return((char *) NULL); 00331 canonical_content=AcquireString("<base64>"); 00332 (void) ConcatenateString(&canonical_content,base64); 00333 base64=DestroyString(base64); 00334 (void) ConcatenateString(&canonical_content,"</base64>"); 00335 return(canonical_content); 00336 } 00337 /* 00338 Substitute predefined entities. 00339 */ 00340 i=0; 00341 canonical_content=AcquireString((char *) NULL); 00342 extent=MaxTextExtent; 00343 for (p=utf8; *p != '\0'; p++) 00344 { 00345 if ((i+MaxTextExtent) > (ssize_t) extent) 00346 { 00347 extent+=MaxTextExtent; 00348 canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent, 00349 sizeof(*canonical_content)); 00350 if (canonical_content == (char *) NULL) 00351 return(canonical_content); 00352 } 00353 switch (*p) 00354 { 00355 case '&': 00356 { 00357 i+=FormatLocaleString(canonical_content+i,extent,"&"); 00358 break; 00359 } 00360 case '<': 00361 { 00362 i+=FormatLocaleString(canonical_content+i,extent,"<"); 00363 break; 00364 } 00365 case '>': 00366 { 00367 i+=FormatLocaleString(canonical_content+i,extent,">"); 00368 break; 00369 } 00370 case '"': 00371 { 00372 i+=FormatLocaleString(canonical_content+i,extent,"""); 00373 break; 00374 } 00375 case '\n': 00376 { 00377 if (pedantic == MagickFalse) 00378 { 00379 canonical_content[i++]=(char) (*p); 00380 break; 00381 } 00382 i+=FormatLocaleString(canonical_content+i,extent,"
"); 00383 break; 00384 } 00385 case '\t': 00386 { 00387 if (pedantic == MagickFalse) 00388 { 00389 canonical_content[i++]=(char) (*p); 00390 break; 00391 } 00392 i+=FormatLocaleString(canonical_content+i,extent,"	"); 00393 break; 00394 } 00395 case '\r': 00396 { 00397 i+=FormatLocaleString(canonical_content+i,extent,"
"); 00398 break; 00399 } 00400 default: 00401 { 00402 canonical_content[i++]=(char) (*p); 00403 break; 00404 } 00405 } 00406 } 00407 canonical_content[i]='\0'; 00408 utf8=(unsigned char *) RelinquishMagickMemory(utf8); 00409 return(canonical_content); 00410 } 00411 00412 /* 00413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00414 % % 00415 % % 00416 % % 00417 % D e s t r o y X M L T r e e % 00418 % % 00419 % % 00420 % % 00421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00422 % 00423 % DestroyXMLTree() destroys the xml-tree. 00424 % 00425 % The format of the DestroyXMLTree method is: 00426 % 00427 % XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info) 00428 % 00429 % A description of each parameter follows: 00430 % 00431 % o xml_info: the xml info. 00432 % 00433 */ 00434 00435 static char **DestroyXMLTreeAttributes(char **attributes) 00436 { 00437 register ssize_t 00438 i; 00439 00440 /* 00441 Destroy a tag attribute list. 00442 */ 00443 if ((attributes == (char **) NULL) || (attributes == sentinel)) 00444 return((char **) NULL); 00445 for (i=0; attributes[i] != (char *) NULL; i+=2) 00446 { 00447 /* 00448 Destroy attribute tag and value. 00449 */ 00450 if (attributes[i] != (char *) NULL) 00451 attributes[i]=DestroyString(attributes[i]); 00452 if (attributes[i+1] != (char *) NULL) 00453 attributes[i+1]=DestroyString(attributes[i+1]); 00454 } 00455 attributes=(char **) RelinquishMagickMemory(attributes); 00456 return((char **) NULL); 00457 } 00458 00459 MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info) 00460 { 00461 char 00462 **attributes; 00463 00464 register ssize_t 00465 i; 00466 00467 ssize_t 00468 j; 00469 00470 XMLTreeRoot 00471 *root; 00472 00473 assert(xml_info != (XMLTreeInfo *) NULL); 00474 assert((xml_info->signature == MagickSignature) || 00475 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00476 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00477 if (xml_info->child != (XMLTreeInfo *) NULL) 00478 xml_info->child=DestroyXMLTree(xml_info->child); 00479 if (xml_info->ordered != (XMLTreeInfo *) NULL) 00480 xml_info->ordered=DestroyXMLTree(xml_info->ordered); 00481 if (xml_info->parent == (XMLTreeInfo *) NULL) 00482 { 00483 /* 00484 Free root tag allocations. 00485 */ 00486 root=(XMLTreeRoot *) xml_info; 00487 for (i=NumberPredefinedEntities; root->entities[i]; i+=2) 00488 root->entities[i+1]=DestroyString(root->entities[i+1]); 00489 root->entities=(char **) RelinquishMagickMemory(root->entities); 00490 for (i=0; root->attributes[i] != (char **) NULL; i++) 00491 { 00492 attributes=root->attributes[i]; 00493 if (attributes[0] != (char *) NULL) 00494 attributes[0]=DestroyString(attributes[0]); 00495 for (j=1; attributes[j] != (char *) NULL; j+=3) 00496 { 00497 if (attributes[j] != (char *) NULL) 00498 attributes[j]=DestroyString(attributes[j]); 00499 if (attributes[j+1] != (char *) NULL) 00500 attributes[j+1]=DestroyString(attributes[j+1]); 00501 if (attributes[j+2] != (char *) NULL) 00502 attributes[j+2]=DestroyString(attributes[j+2]); 00503 } 00504 attributes=(char **) RelinquishMagickMemory(attributes); 00505 } 00506 if (root->attributes[0] != (char **) NULL) 00507 root->attributes=(char ***) RelinquishMagickMemory(root->attributes); 00508 if (root->processing_instructions[0] != (char **) NULL) 00509 { 00510 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 00511 { 00512 for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++) 00513 root->processing_instructions[i][j]=DestroyString( 00514 root->processing_instructions[i][j]); 00515 root->processing_instructions[i][j+1]=DestroyString( 00516 root->processing_instructions[i][j+1]); 00517 root->processing_instructions[i]=(char **) RelinquishMagickMemory( 00518 root->processing_instructions[i]); 00519 } 00520 root->processing_instructions=(char ***) RelinquishMagickMemory( 00521 root->processing_instructions); 00522 } 00523 } 00524 xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes); 00525 xml_info->content=DestroyString(xml_info->content); 00526 xml_info->tag=DestroyString(xml_info->tag); 00527 xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info); 00528 return((XMLTreeInfo *) NULL); 00529 } 00530 00531 /* 00532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00533 % % 00534 % % 00535 % % 00536 % G e t N e x t X M L T r e e T a g % 00537 % % 00538 % % 00539 % % 00540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00541 % 00542 % GetNextXMLTreeTag() returns the next tag or NULL if not found. 00543 % 00544 % The format of the GetNextXMLTreeTag method is: 00545 % 00546 % XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info) 00547 % 00548 % A description of each parameter follows: 00549 % 00550 % o xml_info: the xml info. 00551 % 00552 */ 00553 MagickPrivate XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info) 00554 { 00555 assert(xml_info != (XMLTreeInfo *) NULL); 00556 assert((xml_info->signature == MagickSignature) || 00557 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00558 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00559 return(xml_info->next); 00560 } 00561 00562 /* 00563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00564 % % 00565 % % 00566 % % 00567 % G e t X M L T r e e A t t r i b u t e % 00568 % % 00569 % % 00570 % % 00571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00572 % 00573 % GetXMLTreeAttribute() returns the value of the attribute tag with the 00574 % specified tag if found, otherwise NULL. 00575 % 00576 % The format of the GetXMLTreeAttribute method is: 00577 % 00578 % const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag) 00579 % 00580 % A description of each parameter follows: 00581 % 00582 % o xml_info: the xml info. 00583 % 00584 % o tag: the attribute tag. 00585 % 00586 */ 00587 MagickPrivate const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info, 00588 const char *tag) 00589 { 00590 register ssize_t 00591 i; 00592 00593 ssize_t 00594 j; 00595 00596 XMLTreeRoot 00597 *root; 00598 00599 assert(xml_info != (XMLTreeInfo *) NULL); 00600 assert((xml_info->signature == MagickSignature) || 00601 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00603 if (xml_info->attributes == (char **) NULL) 00604 return((const char *) NULL); 00605 i=0; 00606 while ((xml_info->attributes[i] != (char *) NULL) && 00607 (strcmp(xml_info->attributes[i],tag) != 0)) 00608 i+=2; 00609 if (xml_info->attributes[i] != (char *) NULL) 00610 return(xml_info->attributes[i+1]); 00611 root=(XMLTreeRoot*) xml_info; 00612 while (root->root.parent != (XMLTreeInfo *) NULL) 00613 root=(XMLTreeRoot *) root->root.parent; 00614 i=0; 00615 while ((root->attributes[i] != (char **) NULL) && 00616 (strcmp(root->attributes[i][0],xml_info->tag) != 0)) 00617 i++; 00618 if (root->attributes[i] == (char **) NULL) 00619 return((const char *) NULL); 00620 j=1; 00621 while ((root->attributes[i][j] != (char *) NULL) && 00622 (strcmp(root->attributes[i][j],tag) != 0)) 00623 j+=3; 00624 if (root->attributes[i][j] == (char *) NULL) 00625 return((const char *) NULL); 00626 return(root->attributes[i][j+1]); 00627 } 00628 00629 /* 00630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00631 % % 00632 % % 00633 % % 00634 % G e t X M L T r e e A t t r i b u t e s % 00635 % % 00636 % % 00637 % % 00638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00639 % 00640 % GetXMLTreeAttributes() injects all attributes associated with the current 00641 % tag in the specified splay-tree. 00642 % 00643 % The format of the GetXMLTreeAttributes method is: 00644 % 00645 % MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info, 00646 % SplayTreeInfo *attributes) 00647 % 00648 % A description of each parameter follows: 00649 % 00650 % o xml_info: the xml info. 00651 % 00652 % o attributes: the attribute splay-tree. 00653 % 00654 */ 00655 MagickPrivate MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info, 00656 SplayTreeInfo *attributes) 00657 { 00658 register ssize_t 00659 i; 00660 00661 assert(xml_info != (XMLTreeInfo *) NULL); 00662 assert((xml_info->signature == MagickSignature) || 00663 (((const XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00664 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00665 assert(attributes != (SplayTreeInfo *) NULL); 00666 if (xml_info->attributes == (char **) NULL) 00667 return(MagickTrue); 00668 i=0; 00669 while (xml_info->attributes[i] != (char *) NULL) 00670 { 00671 (void) AddValueToSplayTree(attributes, 00672 ConstantString(xml_info->attributes[i]), 00673 ConstantString(xml_info->attributes[i+1])); 00674 i+=2; 00675 } 00676 return(MagickTrue); 00677 } 00678 00679 /* 00680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00681 % % 00682 % % 00683 % % 00684 % G e t X M L T r e e C h i l d % 00685 % % 00686 % % 00687 % % 00688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00689 % 00690 % GetXMLTreeChild() returns the first child tag with the specified tag if 00691 % found, otherwise NULL. 00692 % 00693 % The format of the GetXMLTreeChild method is: 00694 % 00695 % XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag) 00696 % 00697 % A description of each parameter follows: 00698 % 00699 % o xml_info: the xml info. 00700 % 00701 */ 00702 MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag) 00703 { 00704 XMLTreeInfo 00705 *child; 00706 00707 assert(xml_info != (XMLTreeInfo *) NULL); 00708 assert((xml_info->signature == MagickSignature) || 00709 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00711 child=xml_info->child; 00712 if (tag != (const char *) NULL) 00713 while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0)) 00714 child=child->sibling; 00715 return(child); 00716 } 00717 00718 /* 00719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00720 % % 00721 % % 00722 % % 00723 % G e t X M L T r e e C o n t e n t % 00724 % % 00725 % % 00726 % % 00727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00728 % 00729 % GetXMLTreeContent() returns any content associated with specified 00730 % xml-tree node. 00731 % 00732 % The format of the GetXMLTreeContent method is: 00733 % 00734 % const char *GetXMLTreeContent(XMLTreeInfo *xml_info) 00735 % 00736 % A description of each parameter follows: 00737 % 00738 % o xml_info: the xml info. 00739 % 00740 */ 00741 MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info) 00742 { 00743 assert(xml_info != (XMLTreeInfo *) NULL); 00744 assert((xml_info->signature == MagickSignature) || 00745 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00746 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00747 return(xml_info->content); 00748 } 00749 00750 /* 00751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00752 % % 00753 % % 00754 % % 00755 % G e t X M L T r e e O r d e r e d % 00756 % % 00757 % % 00758 % % 00759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00760 % 00761 % GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL. 00762 % 00763 % The format of the GetXMLTreeOrdered method is: 00764 % 00765 % XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info) 00766 % 00767 % A description of each parameter follows: 00768 % 00769 % o xml_info: the xml info. 00770 % 00771 */ 00772 MagickPrivate XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info) 00773 { 00774 assert(xml_info != (XMLTreeInfo *) NULL); 00775 assert((xml_info->signature == MagickSignature) || 00776 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00777 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00778 return(xml_info->ordered); 00779 } 00780 00781 /* 00782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00783 % % 00784 % % 00785 % % 00786 % G e t X M L T r e e P a t h % 00787 % % 00788 % % 00789 % % 00790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00791 % 00792 % GetXMLTreePath() traverses the XML-tree as defined by the specified path 00793 % and returns the node if found, otherwise NULL. 00794 % 00795 % The format of the GetXMLTreePath method is: 00796 % 00797 % XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path) 00798 % 00799 % A description of each parameter follows: 00800 % 00801 % o xml_info: the xml info. 00802 % 00803 % o path: the path (e.g. property/elapsed-time). 00804 % 00805 */ 00806 MagickPrivate XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path) 00807 { 00808 char 00809 **components, 00810 subnode[MaxTextExtent], 00811 tag[MaxTextExtent]; 00812 00813 register ssize_t 00814 i; 00815 00816 size_t 00817 number_components; 00818 00819 ssize_t 00820 j; 00821 00822 XMLTreeInfo 00823 *node; 00824 00825 assert(xml_info != (XMLTreeInfo *) NULL); 00826 assert((xml_info->signature == MagickSignature) || 00827 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00829 node=xml_info; 00830 components=GetPathComponents(path,&number_components); 00831 if (components == (char **) NULL) 00832 return((XMLTreeInfo *) NULL); 00833 for (i=0; i < (ssize_t) number_components; i++) 00834 { 00835 GetPathComponent(components[i],SubimagePath,subnode); 00836 GetPathComponent(components[i],CanonicalPath,tag); 00837 node=GetXMLTreeChild(node,tag); 00838 if (node == (XMLTreeInfo *) NULL) 00839 break; 00840 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--) 00841 { 00842 node=GetXMLTreeOrdered(node); 00843 if (node == (XMLTreeInfo *) NULL) 00844 break; 00845 } 00846 if (node == (XMLTreeInfo *) NULL) 00847 break; 00848 components[i]=DestroyString(components[i]); 00849 } 00850 for ( ; i < (ssize_t) number_components; i++) 00851 components[i]=DestroyString(components[i]); 00852 components=(char **) RelinquishMagickMemory(components); 00853 return(node); 00854 } 00855 00856 /* 00857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00858 % % 00859 % % 00860 % % 00861 % 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 % 00862 % % 00863 % % 00864 % % 00865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00866 % 00867 % GetXMLTreeProcessingInstructions() returns a null terminated array of 00868 % processing instructions for the given target. 00869 % 00870 % The format of the GetXMLTreeProcessingInstructions method is: 00871 % 00872 % const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info, 00873 % const char *target) 00874 % 00875 % A description of each parameter follows: 00876 % 00877 % o xml_info: the xml info. 00878 % 00879 */ 00880 MagickPrivate const char **GetXMLTreeProcessingInstructions( 00881 XMLTreeInfo *xml_info,const char *target) 00882 { 00883 register ssize_t 00884 i; 00885 00886 XMLTreeRoot 00887 *root; 00888 00889 assert(xml_info != (XMLTreeInfo *) NULL); 00890 assert((xml_info->signature == MagickSignature) || 00891 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00892 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00893 root=(XMLTreeRoot *) xml_info; 00894 while (root->root.parent != (XMLTreeInfo *) NULL) 00895 root=(XMLTreeRoot *) root->root.parent; 00896 i=0; 00897 while ((root->processing_instructions[i] != (char **) NULL) && 00898 (strcmp(root->processing_instructions[i][0],target) != 0)) 00899 i++; 00900 if (root->processing_instructions[i] == (char **) NULL) 00901 return((const char **) sentinel); 00902 return((const char **) (root->processing_instructions[i]+1)); 00903 } 00904 00905 /* 00906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00907 % % 00908 % % 00909 % % 00910 % G e t X M L T r e e S i b l i n g % 00911 % % 00912 % % 00913 % % 00914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00915 % 00916 % GetXMLTreeSibling() returns the node sibling if found, otherwise NULL. 00917 % 00918 % The format of the GetXMLTreeSibling method is: 00919 % 00920 % XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info) 00921 % 00922 % A description of each parameter follows: 00923 % 00924 % o xml_info: the xml info. 00925 % 00926 */ 00927 MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info) 00928 { 00929 assert(xml_info != (XMLTreeInfo *) NULL); 00930 assert((xml_info->signature == MagickSignature) || 00931 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00932 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00933 return(xml_info->sibling); 00934 } 00935 00936 /* 00937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00938 % % 00939 % % 00940 % % 00941 % G e t X M L T r e e T a g % 00942 % % 00943 % % 00944 % % 00945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00946 % 00947 % GetXMLTreeTag() returns the tag associated with specified xml-tree node. 00948 % 00949 % The format of the GetXMLTreeTag method is: 00950 % 00951 % const char *GetXMLTreeTag(XMLTreeInfo *xml_info) 00952 % 00953 % A description of each parameter follows: 00954 % 00955 % o xml_info: the xml info. 00956 % 00957 */ 00958 MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info) 00959 { 00960 assert(xml_info != (XMLTreeInfo *) NULL); 00961 assert((xml_info->signature == MagickSignature) || 00962 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 00963 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 00964 return(xml_info->tag); 00965 } 00966 00967 /* 00968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00969 % % 00970 % % 00971 % % 00972 % I n s e r t I n t o T a g X M L T r e e % 00973 % % 00974 % % 00975 % % 00976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00977 % 00978 % InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of 00979 % the parent tag's character content. This method returns the child tag. 00980 % 00981 % The format of the InsertTagIntoXMLTree method is: 00982 % 00983 % XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info, 00984 % XMLTreeInfo *child,const size_t offset) 00985 % 00986 % A description of each parameter follows: 00987 % 00988 % o xml_info: the xml info. 00989 % 00990 % o child: the child tag. 00991 % 00992 % o offset: the tag offset. 00993 % 00994 */ 00995 MagickPrivate XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info, 00996 XMLTreeInfo *child,const size_t offset) 00997 { 00998 XMLTreeInfo 00999 *head, 01000 *node, 01001 *previous; 01002 01003 child->ordered=(XMLTreeInfo *) NULL; 01004 child->sibling=(XMLTreeInfo *) NULL; 01005 child->next=(XMLTreeInfo *) NULL; 01006 child->offset=offset; 01007 child->parent=xml_info; 01008 if (xml_info->child == (XMLTreeInfo *) NULL) 01009 { 01010 xml_info->child=child; 01011 return(child); 01012 } 01013 head=xml_info->child; 01014 if (head->offset > offset) 01015 { 01016 child->ordered=head; 01017 xml_info->child=child; 01018 } 01019 else 01020 { 01021 node=head; 01022 while ((node->ordered != (XMLTreeInfo *) NULL) && 01023 (node->ordered->offset <= offset)) 01024 node=node->ordered; 01025 child->ordered=node->ordered; 01026 node->ordered=child; 01027 } 01028 previous=(XMLTreeInfo *) NULL; 01029 node=head; 01030 while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0)) 01031 { 01032 previous=node; 01033 node=node->sibling; 01034 } 01035 if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset)) 01036 { 01037 while ((node->next != (XMLTreeInfo *) NULL) && 01038 (node->next->offset <= offset)) 01039 node=node->next; 01040 child->next=node->next; 01041 node->next=child; 01042 } 01043 else 01044 { 01045 if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL)) 01046 previous->sibling=node->sibling; 01047 child->next=node; 01048 previous=(XMLTreeInfo *) NULL; 01049 node=head; 01050 while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset)) 01051 { 01052 previous=node; 01053 node=node->sibling; 01054 } 01055 child->sibling=node; 01056 if (previous != (XMLTreeInfo *) NULL) 01057 previous->sibling=child; 01058 } 01059 return(child); 01060 } 01061 01062 /* 01063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01064 % % 01065 % % 01066 % % 01067 % N e w X M L T r e e % 01068 % % 01069 % % 01070 % % 01071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01072 % 01073 % NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified 01074 % XML string. 01075 % 01076 % The format of the NewXMLTree method is: 01077 % 01078 % XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception) 01079 % 01080 % A description of each parameter follows: 01081 % 01082 % o xml: The XML string. 01083 % 01084 % o exception: return any errors or warnings in this structure. 01085 % 01086 */ 01087 01088 static char *ConvertUTF16ToUTF8(const char *content,size_t *length) 01089 { 01090 char 01091 *utf8; 01092 01093 int 01094 bits, 01095 byte, 01096 c, 01097 encoding; 01098 01099 register ssize_t 01100 i; 01101 01102 size_t 01103 extent; 01104 01105 ssize_t 01106 j; 01107 01108 utf8=(char *) AcquireQuantumMemory(*length,sizeof(*utf8)); 01109 if (utf8 == (char *) NULL) 01110 return((char *) NULL); 01111 encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1; 01112 if (encoding == -1) 01113 { 01114 /* 01115 Already UTF-8. 01116 */ 01117 (void) CopyMagickMemory(utf8,content,*length*sizeof(*utf8)); 01118 return(utf8); 01119 } 01120 j=0; 01121 extent=(*length); 01122 for (i=2; i < (ssize_t) (*length-1); i+=2) 01123 { 01124 c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) : 01125 ((content[i+1] & 0xff) << 8) | (content[i] & 0xff); 01126 if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (ssize_t) (*length-1))) 01127 { 01128 byte=(encoding != 0) ? ((content[i] & 0xff) << 8) | 01129 (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) | 01130 (content[i] & 0xff); 01131 c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000; 01132 } 01133 if ((size_t) (j+MaxTextExtent) > extent) 01134 { 01135 extent=(size_t) j+MaxTextExtent; 01136 utf8=(char *) ResizeQuantumMemory(utf8,extent,sizeof(*utf8)); 01137 if (utf8 == (char *) NULL) 01138 return(utf8); 01139 } 01140 if (c < 0x80) 01141 { 01142 utf8[j]=c; 01143 j++; 01144 continue; 01145 } 01146 /* 01147 Multi-byte UTF-8 sequence. 01148 */ 01149 byte=c; 01150 for (bits=0; byte != 0; byte/=2) 01151 bits++; 01152 bits=(bits-2)/5; 01153 utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits)); 01154 while (bits != 0) 01155 { 01156 bits--; 01157 utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f); 01158 j++; 01159 } 01160 } 01161 *length=(size_t) j; 01162 return((char *) ResizeQuantumMemory(utf8,*length,sizeof(*utf8))); 01163 } 01164 01165 static char *ParseEntities(char *xml,char **entities,int state) 01166 { 01167 char 01168 *entity; 01169 01170 int 01171 byte, 01172 c; 01173 01174 register char 01175 *p, 01176 *q; 01177 01178 register ssize_t 01179 i; 01180 01181 size_t 01182 extent, 01183 length; 01184 01185 ssize_t 01186 offset; 01187 01188 /* 01189 Normalize line endings. 01190 */ 01191 p=xml; 01192 q=xml; 01193 for ( ; *xml != '\0'; xml++) 01194 while (*xml == '\r') 01195 { 01196 *(xml++)='\n'; 01197 if (*xml == '\n') 01198 (void) CopyMagickMemory(xml,xml+1,strlen(xml)); 01199 } 01200 for (xml=p; ; ) 01201 { 01202 while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') || 01203 (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0))) 01204 xml++; 01205 if (*xml == '\0') 01206 break; 01207 /* 01208 States include: 01209 '&' for general entity decoding 01210 '%' for parameter entity decoding 01211 'c' for CDATA sections 01212 ' ' for attributes normalization 01213 '*' for non-CDATA attributes normalization 01214 */ 01215 if ((state != 'c') && (strncmp(xml,"&#",2) == 0)) 01216 { 01217 /* 01218 Character reference. 01219 */ 01220 if (xml[2] != 'x') 01221 c=strtol(xml+2,&entity,10); /* base 10 */ 01222 else 01223 c=strtol(xml+3,&entity,16); /* base 16 */ 01224 if ((c == 0) || (*entity != ';')) 01225 { 01226 /* 01227 Not a character reference. 01228 */ 01229 xml++; 01230 continue; 01231 } 01232 if (c < 0x80) 01233 *(xml++)=c; 01234 else 01235 { 01236 /* 01237 Multi-byte UTF-8 sequence. 01238 */ 01239 byte=c; 01240 for (i=0; byte != 0; byte/=2) 01241 i++; 01242 i=(i-2)/5; 01243 *xml=(char) ((0xFF << (7-i)) | (c >> (6*i))); 01244 xml++; 01245 while (i != 0) 01246 { 01247 i--; 01248 *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F)); 01249 xml++; 01250 } 01251 } 01252 (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';'))); 01253 } 01254 else 01255 if (((*xml == '&') && ((state == '&') || (state == ' ') || 01256 (state == '*'))) || ((state == '%') && (*xml == '%'))) 01257 { 01258 /* 01259 Find entity in the list. 01260 */ 01261 i=0; 01262 while ((entities[i] != (char *) NULL) && 01263 (strncmp(xml+1,entities[i],strlen(entities[i])) != 0)) 01264 i+=2; 01265 if (entities[i++] == (char *) NULL) 01266 xml++; 01267 else 01268 { 01269 /* 01270 Found a match. 01271 */ 01272 length=strlen(entities[i]); 01273 entity=strchr(xml,';'); 01274 if ((length-1L) >= (size_t) (entity-xml)) 01275 { 01276 offset=(ssize_t) (xml-p); 01277 extent=(size_t) (offset+length+strlen(entity)); 01278 if (p != q) 01279 p=(char *) ResizeQuantumMemory(p,extent,sizeof(*p)); 01280 else 01281 { 01282 char 01283 *xml; 01284 01285 xml=(char *) AcquireQuantumMemory(extent,sizeof(*xml)); 01286 if (xml != (char *) NULL) 01287 { 01288 (void) CopyMagickString(xml,p,extent*sizeof(*xml)); 01289 p=xml; 01290 } 01291 } 01292 if (p == (char *) NULL) 01293 ThrowFatalException(ResourceLimitFatalError, 01294 "MemoryAllocationFailed"); 01295 xml=p+offset; 01296 entity=strchr(xml,';'); 01297 } 01298 (void) CopyMagickMemory(xml+length,entity+1,strlen(entity)); 01299 (void) strncpy(xml,entities[i],length); 01300 } 01301 } 01302 else 01303 if (((state == ' ') || (state == '*')) && 01304 (isspace((int) ((unsigned char) *xml) != 0))) 01305 *(xml++)=' '; 01306 else 01307 xml++; 01308 } 01309 if (state == '*') 01310 { 01311 /* 01312 Normalize spaces for non-CDATA attributes. 01313 */ 01314 for (xml=p; *xml != '\0'; xml++) 01315 { 01316 i=(ssize_t) strspn(xml," "); 01317 if (i != 0) 01318 (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1); 01319 while ((*xml != '\0') && (*xml != ' ')) 01320 xml++; 01321 } 01322 xml--; 01323 if ((xml >= p) && (*xml == ' ')) 01324 *xml='\0'; 01325 } 01326 return(p == q ? ConstantString(p) : p); 01327 } 01328 01329 static void ParseCharacterContent(XMLTreeRoot *root,char *xml, 01330 const size_t length,const char state) 01331 { 01332 XMLTreeInfo 01333 *xml_info; 01334 01335 xml_info=root->node; 01336 if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) || 01337 (length == 0)) 01338 return; 01339 xml[length]='\0'; 01340 xml=ParseEntities(xml,root->entities,state); 01341 if (*xml_info->content != '\0') 01342 { 01343 (void) ConcatenateString(&xml_info->content,xml); 01344 xml=DestroyString(xml); 01345 } 01346 else 01347 { 01348 if (xml_info->content != (char *) NULL) 01349 xml_info->content=DestroyString(xml_info->content); 01350 xml_info->content=xml; 01351 } 01352 } 01353 01354 static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag, 01355 char *magick_unused(xml),ExceptionInfo *exception) 01356 { 01357 if ((root->node == (XMLTreeInfo *) NULL) || 01358 (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0)) 01359 { 01360 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 01361 "ParseError","unexpected closing tag </%s>",tag); 01362 return(&root->root); 01363 } 01364 root->node=root->node->parent; 01365 return((XMLTreeInfo *) NULL); 01366 } 01367 01368 static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities) 01369 { 01370 register ssize_t 01371 i; 01372 01373 /* 01374 Check for circular entity references. 01375 */ 01376 for ( ; ; xml++) 01377 { 01378 while ((*xml != '\0') && (*xml != '&')) 01379 xml++; 01380 if (*xml == '\0') 01381 return(MagickTrue); 01382 if (strncmp(xml+1,tag,strlen(tag)) == 0) 01383 return(MagickFalse); 01384 i=0; 01385 while ((entities[i] != (char *) NULL) && 01386 (strncmp(entities[i],xml+1,strlen(entities[i]) == 0))) 01387 i+=2; 01388 if ((entities[i] != (char *) NULL) && 01389 (ValidateEntities(tag,entities[i+1],entities) == 0)) 01390 return(MagickFalse); 01391 } 01392 return(MagickTrue); 01393 } 01394 01395 static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml, 01396 size_t length) 01397 { 01398 char 01399 *target; 01400 01401 register ssize_t 01402 i; 01403 01404 ssize_t 01405 j; 01406 01407 target=xml; 01408 xml[length]='\0'; 01409 xml+=strcspn(xml,XMLWhitespace); 01410 if (*xml != '\0') 01411 { 01412 *xml='\0'; 01413 xml+=strspn(xml+1,XMLWhitespace)+1; 01414 } 01415 if (strcmp(target,"xml") == 0) 01416 { 01417 xml=strstr(xml,"standalone"); 01418 if ((xml != (char *) NULL) && 01419 (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0)) 01420 root->standalone=MagickTrue; 01421 return; 01422 } 01423 if (root->processing_instructions[0] == (char **) NULL) 01424 { 01425 root->processing_instructions=(char ***) AcquireMagickMemory(sizeof( 01426 *root->processing_instructions)); 01427 if (root->processing_instructions ==(char ***) NULL) 01428 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01429 *root->processing_instructions=(char **) NULL; 01430 } 01431 i=0; 01432 while ((root->processing_instructions[i] != (char **) NULL) && 01433 (strcmp(target,root->processing_instructions[i][0]) != 0)) 01434 i++; 01435 if (root->processing_instructions[i] == (char **) NULL) 01436 { 01437 root->processing_instructions=(char ***) ResizeQuantumMemory( 01438 root->processing_instructions,(size_t) (i+2), 01439 sizeof(*root->processing_instructions)); 01440 if (root->processing_instructions == (char ***) NULL) 01441 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01442 root->processing_instructions[i]=(char **) AcquireQuantumMemory(3, 01443 sizeof(**root->processing_instructions)); 01444 if (root->processing_instructions[i] == (char **) NULL) 01445 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01446 root->processing_instructions[i+1]=(char **) NULL; 01447 root->processing_instructions[i][0]=ConstantString(target); 01448 root->processing_instructions[i][1]=(char *) 01449 root->processing_instructions[i+1]; 01450 root->processing_instructions[i+1]=(char **) NULL; 01451 root->processing_instructions[i][2]=ConstantString(""); 01452 } 01453 j=1; 01454 while (root->processing_instructions[i][j] != (char *) NULL) 01455 j++; 01456 root->processing_instructions[i]=(char **) ResizeQuantumMemory( 01457 root->processing_instructions[i],(size_t) (j+3), 01458 sizeof(**root->processing_instructions)); 01459 if (root->processing_instructions[i] == (char **) NULL) 01460 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01461 root->processing_instructions[i][j+2]=(char *) ResizeQuantumMemory( 01462 root->processing_instructions[i][j+1],(size_t) (j+1), 01463 sizeof(**root->processing_instructions)); 01464 if (root->processing_instructions[i][j+2] == (char *) NULL) 01465 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01466 (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1, 01467 root->root.tag != (char *) NULL ? ">" : "<",2); 01468 root->processing_instructions[i][j]=ConstantString(xml); 01469 root->processing_instructions[i][j+1]=(char *) NULL; 01470 } 01471 01472 static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml, 01473 size_t length,ExceptionInfo *exception) 01474 { 01475 char 01476 *c, 01477 **entities, 01478 *n, 01479 **predefined_entitites, 01480 q, 01481 *t, 01482 *v; 01483 01484 register ssize_t 01485 i; 01486 01487 ssize_t 01488 j; 01489 01490 n=(char *) NULL; 01491 predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel)); 01492 if (predefined_entitites == (char **) NULL) 01493 ThrowFatalException(ResourceLimitError,"MemoryAllocationFailed"); 01494 (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel)); 01495 for (xml[length]='\0'; xml != (char *) NULL; ) 01496 { 01497 while ((*xml != '\0') && (*xml != '<') && (*xml != '%')) 01498 xml++; 01499 if (*xml == '\0') 01500 break; 01501 if (strncmp(xml,"<!ENTITY",8) == 0) 01502 { 01503 /* 01504 Parse entity definitions. 01505 */ 01506 xml+=strspn(xml+8,XMLWhitespace)+8; 01507 c=xml; 01508 n=xml+strspn(xml,XMLWhitespace "%"); 01509 xml=n+strcspn(n,XMLWhitespace); 01510 *xml=';'; 01511 v=xml+strspn(xml+1,XMLWhitespace)+1; 01512 q=(*v); 01513 v++; 01514 if ((q != '"') && (q != '\'')) 01515 { 01516 /* 01517 Skip externals. 01518 */ 01519 xml=strchr(xml,'>'); 01520 continue; 01521 } 01522 entities=(*c == '%') ? predefined_entitites : root->entities; 01523 for (i=0; entities[i] != (char *) NULL; i++) ; 01524 entities=(char **) ResizeQuantumMemory(entities,(size_t) (i+3), 01525 sizeof(*entities)); 01526 if (entities == (char **) NULL) 01527 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 01528 if (*c == '%') 01529 predefined_entitites=entities; 01530 else 01531 root->entities=entities; 01532 xml++; 01533 *xml='\0'; 01534 xml=strchr(v,q); 01535 if (xml != (char *) NULL) 01536 { 01537 *xml='\0'; 01538 xml++; 01539 } 01540 entities[i+1]=ParseEntities(v,predefined_entitites,'%'); 01541 entities[i+2]=(char *) NULL; 01542 if (ValidateEntities(n,entities[i+1],entities) != MagickFalse) 01543 entities[i]=n; 01544 else 01545 { 01546 if (entities[i+1] != v) 01547 entities[i+1]=DestroyString(entities[i+1]); 01548 (void) ThrowMagickException(exception,GetMagickModule(), 01549 OptionWarning,"ParseError","circular entity declaration &%s",n); 01550 predefined_entitites=(char **) RelinquishMagickMemory( 01551 predefined_entitites); 01552 return(MagickFalse); 01553 } 01554 } 01555 else 01556 if (strncmp(xml,"<!ATTLIST",9) == 0) 01557 { 01558 /* 01559 Parse default attributes. 01560 */ 01561 t=xml+strspn(xml+9,XMLWhitespace)+9; 01562 if (*t == '\0') 01563 { 01564 (void) ThrowMagickException(exception,GetMagickModule(), 01565 OptionWarning,"ParseError","unclosed <!ATTLIST"); 01566 predefined_entitites=(char **) RelinquishMagickMemory( 01567 predefined_entitites); 01568 return(MagickFalse); 01569 } 01570 xml=t+strcspn(t,XMLWhitespace ">"); 01571 if (*xml == '>') 01572 continue; 01573 *xml='\0'; 01574 i=0; 01575 while ((root->attributes[i] != (char **) NULL) && 01576 (strcmp(n,root->attributes[i][0]) != 0)) 01577 i++; 01578 while ((*(n=xml+strspn(xml+1,XMLWhitespace)+1) != '\0') && 01579 (*n != '>')) 01580 { 01581 xml=n+strcspn(n,XMLWhitespace); 01582 if (*xml != '\0') 01583 *xml='\0'; 01584 else 01585 { 01586 (void) ThrowMagickException(exception,GetMagickModule(), 01587 OptionWarning,"ParseError","malformed <!ATTLIST"); 01588 predefined_entitites=(char **) RelinquishMagickMemory( 01589 predefined_entitites); 01590 return(MagickFalse); 01591 } 01592 xml+=strspn(xml+1,XMLWhitespace)+1; 01593 c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " "); 01594 if (strncmp(xml,"NOTATION",8) == 0) 01595 xml+=strspn(xml+8,XMLWhitespace)+8; 01596 xml=(*xml == '(') ? strchr(xml,')') : xml+ 01597 strcspn(xml,XMLWhitespace); 01598 if (xml == (char *) NULL) 01599 { 01600 (void) ThrowMagickException(exception,GetMagickModule(), 01601 OptionWarning,"ParseError","malformed <!ATTLIST"); 01602 predefined_entitites=(char **) RelinquishMagickMemory( 01603 predefined_entitites); 01604 return(MagickFalse); 01605 } 01606 xml+=strspn(xml,XMLWhitespace ")"); 01607 if (strncmp(xml,"#FIXED",6) == 0) 01608 xml+=strspn(xml+6,XMLWhitespace)+6; 01609 if (*xml == '#') 01610 { 01611 xml+=strcspn(xml,XMLWhitespace ">")-1; 01612 if (*c == ' ') 01613 continue; 01614 v=(char *) NULL; 01615 } 01616 else 01617 if (((*xml == '"') || (*xml == '\'')) && 01618 ((xml=strchr(v=xml+1,*xml)) != (char *) NULL)) 01619 *xml='\0'; 01620 else 01621 { 01622 (void) ThrowMagickException(exception,GetMagickModule(), 01623 OptionWarning,"ParseError","malformed <!ATTLIST"); 01624 predefined_entitites=(char **) RelinquishMagickMemory( 01625 predefined_entitites); 01626 return(MagickFalse); 01627 } 01628 if (root->attributes[i] == (char **) NULL) 01629 { 01630 /* 01631 New attribute tag. 01632 */ 01633 if (i == 0) 01634 root->attributes=(char ***) AcquireQuantumMemory(2, 01635 sizeof(*root->attributes)); 01636 else 01637 root->attributes=(char ***) ResizeQuantumMemory( 01638 root->attributes,(size_t) (i+2), 01639 sizeof(*root->attributes)); 01640 if (root->attributes == (char ***) NULL) 01641 ThrowFatalException(ResourceLimitFatalError, 01642 "MemoryAllocationFailed"); 01643 root->attributes[i]=(char **) AcquireQuantumMemory(2, 01644 sizeof(*root->attributes)); 01645 if (root->attributes[i] == (char **) NULL) 01646 ThrowFatalException(ResourceLimitFatalError, 01647 "MemoryAllocationFailed"); 01648 root->attributes[i][0]=ConstantString(t); 01649 root->attributes[i][1]=(char *) NULL; 01650 root->attributes[i+1]=(char **) NULL; 01651 } 01652 for (j=1; root->attributes[i][j] != (char *) NULL; j+=3) ; 01653 root->attributes[i]=(char **) ResizeQuantumMemory( 01654 root->attributes[i],(size_t) (j+4),sizeof(*root->attributes)); 01655 if (root->attributes[i] == (char **) NULL) 01656 ThrowFatalException(ResourceLimitFatalError, 01657 "MemoryAllocationFailed"); 01658 root->attributes[i][j+3]=(char *) NULL; 01659 root->attributes[i][j+2]=ConstantString(c); 01660 root->attributes[i][j+1]=(char *) NULL; 01661 if (v != (char *) NULL) 01662 root->attributes[i][j+1]=ParseEntities(v,root->entities,*c); 01663 root->attributes[i][j]=ConstantString(n); 01664 } 01665 } 01666 else 01667 if (strncmp(xml, "<!--", 4) == 0) 01668 xml=strstr(xml+4,"-->"); 01669 else 01670 if (strncmp(xml,"<?", 2) == 0) 01671 { 01672 c=xml+2; 01673 xml=strstr(c,"?>"); 01674 if (xml != (char *) NULL) 01675 { 01676 ParseProcessingInstructions(root,c,(size_t) (xml-c)); 01677 xml++; 01678 } 01679 } 01680 else 01681 if (*xml == '<') 01682 xml=strchr(xml,'>'); 01683 else 01684 if ((*(xml++) == '%') && (root->standalone == MagickFalse)) 01685 break; 01686 } 01687 predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites); 01688 return(MagickTrue); 01689 } 01690 01691 static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes) 01692 { 01693 XMLTreeInfo 01694 *xml_info; 01695 01696 xml_info=root->node; 01697 if (xml_info->tag == (char *) NULL) 01698 xml_info->tag=ConstantString(tag); 01699 else 01700 xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content)); 01701 xml_info->attributes=attributes; 01702 root->node=xml_info; 01703 } 01704 01705 MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception) 01706 { 01707 char 01708 **attribute, 01709 **attributes, 01710 *tag, 01711 *utf8; 01712 01713 int 01714 c, 01715 terminal; 01716 01717 MagickBooleanType 01718 status; 01719 01720 register char 01721 *p; 01722 01723 register ssize_t 01724 i; 01725 01726 size_t 01727 length; 01728 01729 ssize_t 01730 j, 01731 l; 01732 01733 XMLTreeRoot 01734 *root; 01735 01736 /* 01737 Convert xml-string to UTF8. 01738 */ 01739 if ((xml == (const char *) NULL) || (strlen(xml) == 0)) 01740 { 01741 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 01742 "ParseError","root tag missing"); 01743 return((XMLTreeInfo *) NULL); 01744 } 01745 root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL); 01746 length=strlen(xml); 01747 utf8=ConvertUTF16ToUTF8(xml,&length); 01748 if (utf8 == (char *) NULL) 01749 { 01750 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 01751 "ParseError","UTF16 to UTF8 failed"); 01752 return((XMLTreeInfo *) NULL); 01753 } 01754 terminal=utf8[length-1]; 01755 utf8[length-1]='\0'; 01756 p=utf8; 01757 while ((*p != '\0') && (*p != '<')) 01758 p++; 01759 if (*p == '\0') 01760 { 01761 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 01762 "ParseError","root tag missing"); 01763 utf8=DestroyString(utf8); 01764 return((XMLTreeInfo *) NULL); 01765 } 01766 attribute=(char **) NULL; 01767 for (p++; ; p++) 01768 { 01769 attributes=(char **) sentinel; 01770 tag=p; 01771 c=(*p); 01772 if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') || 01773 (*p == ':') || (c < '\0')) 01774 { 01775 /* 01776 Tag. 01777 */ 01778 if (root->node == (XMLTreeInfo *) NULL) 01779 { 01780 (void) ThrowMagickException(exception,GetMagickModule(), 01781 OptionWarning,"ParseError","root tag missing"); 01782 utf8=DestroyString(utf8); 01783 return(&root->root); 01784 } 01785 p+=strcspn(p,XMLWhitespace "/>"); 01786 while (isspace((int) ((unsigned char) *p)) != 0) 01787 *p++='\0'; 01788 if ((*p != '\0') && (*p != '/') && (*p != '>')) 01789 { 01790 /* 01791 Find tag in default attributes list. 01792 */ 01793 i=0; 01794 while ((root->attributes[i] != (char **) NULL) && 01795 (strcmp(root->attributes[i][0],tag) != 0)) 01796 i++; 01797 attribute=root->attributes[i]; 01798 } 01799 for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2) 01800 { 01801 /* 01802 Attribute. 01803 */ 01804 if (l == 0) 01805 attributes=(char **) AcquireQuantumMemory(4,sizeof(*attributes)); 01806 else 01807 attributes=(char **) ResizeQuantumMemory(attributes,(size_t) (l+4), 01808 sizeof(*attributes)); 01809 if (attributes == (char **) NULL) 01810 { 01811 (void) ThrowMagickException(exception,GetMagickModule(), 01812 ResourceLimitError,"MemoryAllocationFailed","`%s'",""); 01813 utf8=DestroyString(utf8); 01814 return(&root->root); 01815 } 01816 attributes[l+2]=(char *) NULL; 01817 attributes[l+1]=(char *) NULL; 01818 attributes[l]=p; 01819 p+=strcspn(p,XMLWhitespace "=/>"); 01820 if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0)) 01821 attributes[l]=ConstantString(""); 01822 else 01823 { 01824 *p++='\0'; 01825 p+=strspn(p,XMLWhitespace "="); 01826 c=(*p); 01827 if ((c == '"') || (c == '\'')) 01828 { 01829 /* 01830 Attributes value. 01831 */ 01832 p++; 01833 attributes[l+1]=p; 01834 while ((*p != '\0') && (*p != c)) 01835 p++; 01836 if (*p != '\0') 01837 *p++='\0'; 01838 else 01839 { 01840 attributes[l]=ConstantString(""); 01841 attributes[l+1]=ConstantString(""); 01842 (void) DestroyXMLTreeAttributes(attributes); 01843 (void) ThrowMagickException(exception,GetMagickModule(), 01844 OptionWarning,"ParseError","missing %c",c); 01845 utf8=DestroyString(utf8); 01846 return(&root->root); 01847 } 01848 j=1; 01849 while ((attribute != (char **) NULL) && 01850 (attribute[j] != (char *) NULL) && 01851 (strcmp(attribute[j],attributes[l]) != 0)) 01852 j+=3; 01853 attributes[l+1]=ParseEntities(attributes[l+1],root->entities, 01854 (attribute != (char **) NULL) && (attribute[j] != 01855 (char *) NULL) ? *attribute[j+2] : ' '); 01856 } 01857 attributes[l]=ConstantString(attributes[l]); 01858 } 01859 while (isspace((int) ((unsigned char) *p)) != 0) 01860 p++; 01861 } 01862 if (*p == '/') 01863 { 01864 /* 01865 Self closing tag. 01866 */ 01867 *p++='\0'; 01868 if (((*p != '\0') && (*p != '>')) || 01869 ((*p == '\0') && (terminal != '>'))) 01870 { 01871 if (l != 0) 01872 (void) DestroyXMLTreeAttributes(attributes); 01873 (void) ThrowMagickException(exception,GetMagickModule(), 01874 OptionWarning,"ParseError","missing >"); 01875 utf8=DestroyString(utf8); 01876 return(&root->root); 01877 } 01878 ParseOpenTag(root,tag,attributes); 01879 (void) ParseCloseTag(root,tag,p,exception); 01880 } 01881 else 01882 { 01883 c=(*p); 01884 if ((*p == '>') || ((*p == '\0') && (terminal == '>'))) 01885 { 01886 *p='\0'; 01887 ParseOpenTag(root,tag,attributes); 01888 *p=c; 01889 } 01890 else 01891 { 01892 if (l != 0) 01893 (void) DestroyXMLTreeAttributes(attributes); 01894 (void) ThrowMagickException(exception,GetMagickModule(), 01895 OptionWarning,"ParseError","missing >"); 01896 utf8=DestroyString(utf8); 01897 return(&root->root); 01898 } 01899 } 01900 } 01901 else 01902 if (*p == '/') 01903 { 01904 /* 01905 Close tag. 01906 */ 01907 tag=p+1; 01908 p+=strcspn(tag,XMLWhitespace ">")+1; 01909 c=(*p); 01910 if ((c == '\0') && (terminal != '>')) 01911 { 01912 (void) ThrowMagickException(exception,GetMagickModule(), 01913 OptionWarning,"ParseError","missing >"); 01914 utf8=DestroyString(utf8); 01915 return(&root->root); 01916 } 01917 *p='\0'; 01918 if (ParseCloseTag(root,tag,p,exception) != (XMLTreeInfo *) NULL) 01919 { 01920 utf8=DestroyString(utf8); 01921 return(&root->root); 01922 } 01923 *p=c; 01924 if (isspace((int) ((unsigned char) *p)) != 0) 01925 p+=strspn(p,XMLWhitespace); 01926 } 01927 else 01928 if (strncmp(p,"!--",3) == 0) 01929 { 01930 /* 01931 Comment. 01932 */ 01933 p=strstr(p+3,"--"); 01934 if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) || 01935 ((*p == '\0') && (terminal != '>'))) 01936 { 01937 (void) ThrowMagickException(exception,GetMagickModule(), 01938 OptionWarning,"ParseError","unclosed <!--"); 01939 utf8=DestroyString(utf8); 01940 return(&root->root); 01941 } 01942 } 01943 else 01944 if (strncmp(p,"![CDATA[",8) == 0) 01945 { 01946 /* 01947 Cdata. 01948 */ 01949 p=strstr(p,"]]>"); 01950 if (p != (char *) NULL) 01951 { 01952 p+=2; 01953 ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c'); 01954 } 01955 else 01956 { 01957 (void) ThrowMagickException(exception,GetMagickModule(), 01958 OptionWarning,"ParseError","unclosed <![CDATA["); 01959 utf8=DestroyString(utf8); 01960 return(&root->root); 01961 } 01962 } 01963 else 01964 if (strncmp(p,"!DOCTYPE",8) == 0) 01965 { 01966 /* 01967 DTD. 01968 */ 01969 for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) || 01970 ((l != 0) && ((*p != ']') || 01971 (*(p+strspn(p+1,XMLWhitespace)+1) != '>')))); 01972 l=(ssize_t) ((*p == '[') ? 1 : l)) 01973 p+=strcspn(p+1,"[]>")+1; 01974 if ((*p == '\0') && (terminal != '>')) 01975 { 01976 (void) ThrowMagickException(exception,GetMagickModule(), 01977 OptionWarning,"ParseError","unclosed <!DOCTYPE"); 01978 utf8=DestroyString(utf8); 01979 return(&root->root); 01980 } 01981 if (l != 0) 01982 tag=strchr(tag,'[')+1; 01983 if (l != 0) 01984 { 01985 status=ParseInternalDoctype(root,tag,(size_t) (p-tag), 01986 exception); 01987 if (status == MagickFalse) 01988 { 01989 utf8=DestroyString(utf8); 01990 return(&root->root); 01991 } 01992 p++; 01993 } 01994 } 01995 else 01996 if (*p == '?') 01997 { 01998 /* 01999 Processing instructions. 02000 */ 02001 do 02002 { 02003 p=strchr(p,'?'); 02004 if (p == (char *) NULL) 02005 break; 02006 p++; 02007 } while ((*p != '\0') && (*p != '>')); 02008 if ((p == (char *) NULL) || ((*p == '\0') && 02009 (terminal != '>'))) 02010 { 02011 (void) ThrowMagickException(exception,GetMagickModule(), 02012 OptionWarning,"ParseError","unclosed <?"); 02013 utf8=DestroyString(utf8); 02014 return(&root->root); 02015 } 02016 ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2)); 02017 } 02018 else 02019 { 02020 (void) ThrowMagickException(exception,GetMagickModule(), 02021 OptionWarning,"ParseError","unexpected <"); 02022 utf8=DestroyString(utf8); 02023 return(&root->root); 02024 } 02025 if ((p == (char *) NULL) || (*p == '\0')) 02026 break; 02027 *p++='\0'; 02028 tag=p; 02029 if ((*p != '\0') && (*p != '<')) 02030 { 02031 /* 02032 Tag character content. 02033 */ 02034 while ((*p != '\0') && (*p != '<')) 02035 p++; 02036 if (*p == '\0') 02037 break; 02038 ParseCharacterContent(root,tag,(size_t) (p-tag),'&'); 02039 } 02040 else 02041 if (*p == '\0') 02042 break; 02043 } 02044 utf8=DestroyString(utf8); 02045 if (root->node == (XMLTreeInfo *) NULL) 02046 return(&root->root); 02047 if (root->node->tag == (char *) NULL) 02048 { 02049 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 02050 "ParseError","root tag missing"); 02051 return(&root->root); 02052 } 02053 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 02054 "ParseError","unclosed tag: `%s'",root->node->tag); 02055 return(&root->root); 02056 } 02057 02058 /* 02059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02060 % % 02061 % % 02062 % % 02063 % N e w X M L T r e e T a g % 02064 % % 02065 % % 02066 % % 02067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02068 % 02069 % NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag. 02070 % 02071 % The format of the NewXMLTreeTag method is: 02072 % 02073 % XMLTreeInfo *NewXMLTreeTag(const char *tag) 02074 % 02075 % A description of each parameter follows: 02076 % 02077 % o tag: the tag. 02078 % 02079 */ 02080 MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag) 02081 { 02082 static const char 02083 *predefined_entities[NumberPredefinedEntities+1] = 02084 { 02085 "lt;", "<", "gt;", ">", "quot;", """, 02086 "apos;", "'", "amp;", "&", (char *) NULL 02087 }; 02088 02089 XMLTreeRoot 02090 *root; 02091 02092 root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root)); 02093 if (root == (XMLTreeRoot *) NULL) 02094 return((XMLTreeInfo *) NULL); 02095 (void) ResetMagickMemory(root,0,sizeof(*root)); 02096 root->root.tag=(char *) NULL; 02097 if (tag != (char *) NULL) 02098 root->root.tag=ConstantString(tag); 02099 root->node=(&root->root); 02100 root->root.content=ConstantString(""); 02101 root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities)); 02102 if (root->entities == (char **) NULL) 02103 return((XMLTreeInfo *) NULL); 02104 (void) CopyMagickMemory(root->entities,predefined_entities, 02105 sizeof(predefined_entities)); 02106 root->root.attributes=sentinel; 02107 root->attributes=(char ***) root->root.attributes; 02108 root->processing_instructions=(char ***) root->root.attributes; 02109 root->debug=IsEventLogging(); 02110 root->signature=MagickSignature; 02111 return(&root->root); 02112 } 02113 02114 /* 02115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02116 % % 02117 % % 02118 % % 02119 % P r u n e T a g F r o m X M L T r e e % 02120 % % 02121 % % 02122 % % 02123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02124 % 02125 % PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its 02126 % subtags. 02127 % 02128 % The format of the PruneTagFromXMLTree method is: 02129 % 02130 % XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info) 02131 % 02132 % A description of each parameter follows: 02133 % 02134 % o xml_info: the xml info. 02135 % 02136 */ 02137 MagickPrivate XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info) 02138 { 02139 XMLTreeInfo 02140 *node; 02141 02142 assert(xml_info != (XMLTreeInfo *) NULL); 02143 assert((xml_info->signature == MagickSignature) || 02144 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 02145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 02146 if (xml_info->next != (XMLTreeInfo *) NULL) 02147 xml_info->next->sibling=xml_info->sibling; 02148 if (xml_info->parent != (XMLTreeInfo *) NULL) 02149 { 02150 node=xml_info->parent->child; 02151 if (node == xml_info) 02152 xml_info->parent->child=xml_info->ordered; 02153 else 02154 { 02155 while (node->ordered != xml_info) 02156 node=node->ordered; 02157 node->ordered=node->ordered->ordered; 02158 node=xml_info->parent->child; 02159 if (strcmp(node->tag,xml_info->tag) != 0) 02160 { 02161 while (strcmp(node->sibling->tag,xml_info->tag) != 0) 02162 node=node->sibling; 02163 if (node->sibling != xml_info) 02164 node=node->sibling; 02165 else 02166 node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ? 02167 xml_info->next : node->sibling->sibling; 02168 } 02169 while ((node->next != (XMLTreeInfo *) NULL) && 02170 (node->next != xml_info)) 02171 node=node->next; 02172 if (node->next != (XMLTreeInfo *) NULL) 02173 node->next=node->next->next; 02174 } 02175 } 02176 xml_info->ordered=(XMLTreeInfo *) NULL; 02177 xml_info->sibling=(XMLTreeInfo *) NULL; 02178 xml_info->next=(XMLTreeInfo *) NULL; 02179 return(xml_info); 02180 } 02181 02182 /* 02183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02184 % % 02185 % % 02186 % % 02187 % S e t X M L T r e e A t t r i b u t e % 02188 % % 02189 % % 02190 % % 02191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02192 % 02193 % SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not 02194 % found. A value of NULL removes the specified attribute. 02195 % 02196 % The format of the SetXMLTreeAttribute method is: 02197 % 02198 % XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag, 02199 % const char *value) 02200 % 02201 % A description of each parameter follows: 02202 % 02203 % o xml_info: the xml info. 02204 % 02205 % o tag: The attribute tag. 02206 % 02207 % o value: The attribute value. 02208 % 02209 */ 02210 MagickPrivate XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info, 02211 const char *tag,const char *value) 02212 { 02213 register ssize_t 02214 i; 02215 02216 ssize_t 02217 j; 02218 02219 assert(xml_info != (XMLTreeInfo *) NULL); 02220 assert((xml_info->signature == MagickSignature) || 02221 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 02222 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 02223 i=0; 02224 while ((xml_info->attributes[i] != (char *) NULL) && 02225 (strcmp(xml_info->attributes[i],tag) != 0)) 02226 i+=2; 02227 if (xml_info->attributes[i] == (char *) NULL) 02228 { 02229 /* 02230 Add new attribute tag. 02231 */ 02232 if (value == (const char *) NULL) 02233 return(xml_info); 02234 if (xml_info->attributes != sentinel) 02235 xml_info->attributes=(char **) ResizeQuantumMemory( 02236 xml_info->attributes,(size_t) (i+4),sizeof(*xml_info->attributes)); 02237 else 02238 { 02239 xml_info->attributes=(char **) AcquireQuantumMemory(4, 02240 sizeof(*xml_info->attributes)); 02241 if (xml_info->attributes != (char **) NULL) 02242 xml_info->attributes[1]=ConstantString(""); 02243 } 02244 if (xml_info->attributes == (char **) NULL) 02245 ThrowFatalException(ResourceLimitFatalError, 02246 "UnableToAcquireString"); 02247 xml_info->attributes[i]=ConstantString(tag); 02248 xml_info->attributes[i+2]=(char *) NULL; 02249 (void) strlen(xml_info->attributes[i+1]); 02250 } 02251 /* 02252 Add new value to an existing attribute. 02253 */ 02254 for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2) ; 02255 if (xml_info->attributes[i+1] != (char *) NULL) 02256 xml_info->attributes[i+1]=DestroyString(xml_info->attributes[i+1]); 02257 if (value != (const char *) NULL) 02258 { 02259 xml_info->attributes[i+1]=ConstantString(value); 02260 return(xml_info); 02261 } 02262 if (xml_info->attributes[i] != (char *) NULL) 02263 xml_info->attributes[i]=DestroyString(xml_info->attributes[i]); 02264 (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2, 02265 (size_t) (j-i)*sizeof(*xml_info->attributes)); 02266 j-=2; 02267 xml_info->attributes=(char **) ResizeQuantumMemory(xml_info->attributes, 02268 (size_t) (j+2),sizeof(*xml_info->attributes)); 02269 if (xml_info->attributes == (char **) NULL) 02270 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString"); 02271 (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2), 02272 xml_info->attributes[j+1]+(i/2)+1,(size_t) ((j/2)-(i/2))* 02273 sizeof(*xml_info->attributes)); 02274 return(xml_info); 02275 } 02276 02277 /* 02278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02279 % % 02280 % % 02281 % % 02282 % S e t X M L T r e e C o n t e n t % 02283 % % 02284 % % 02285 % % 02286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02287 % 02288 % SetXMLTreeContent() sets the character content for the given tag and 02289 % returns the tag. 02290 % 02291 % The format of the SetXMLTreeContent method is: 02292 % 02293 % XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info, 02294 % const char *content) 02295 % 02296 % A description of each parameter follows: 02297 % 02298 % o xml_info: the xml info. 02299 % 02300 % o content: The content. 02301 % 02302 */ 02303 MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info, 02304 const char *content) 02305 { 02306 assert(xml_info != (XMLTreeInfo *) NULL); 02307 assert((xml_info->signature == MagickSignature) || 02308 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 02309 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 02310 if (xml_info->content != (char *) NULL) 02311 xml_info->content=DestroyString(xml_info->content); 02312 xml_info->content=(char *) ConstantString(content); 02313 return(xml_info); 02314 } 02315 02316 /* 02317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02318 % % 02319 % % 02320 % % 02321 % X M L T r e e I n f o T o X M L % 02322 % % 02323 % % 02324 % % 02325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02326 % 02327 % XMLTreeInfoToXML() converts an xml-tree to an XML string. 02328 % 02329 % The format of the XMLTreeInfoToXML method is: 02330 % 02331 % char *XMLTreeInfoToXML(XMLTreeInfo *xml_info) 02332 % 02333 % A description of each parameter follows: 02334 % 02335 % o xml_info: the xml info. 02336 % 02337 */ 02338 02339 static char *EncodePredefinedEntities(const char *source,ssize_t offset, 02340 char **destination,size_t *length,size_t *extent,MagickBooleanType pedantic) 02341 { 02342 char 02343 *canonical_content; 02344 02345 if (offset < 0) 02346 canonical_content=CanonicalXMLContent(source,pedantic); 02347 else 02348 { 02349 char 02350 *content; 02351 02352 content=AcquireString(source); 02353 content[offset]='\0'; 02354 canonical_content=CanonicalXMLContent(content,pedantic); 02355 content=DestroyString(content); 02356 } 02357 if (canonical_content == (char *) NULL) 02358 return(*destination); 02359 if ((*length+strlen(canonical_content)+MaxTextExtent) > *extent) 02360 { 02361 *extent=(*length)+strlen(canonical_content)+MaxTextExtent; 02362 *destination=(char *) ResizeQuantumMemory(*destination,*extent, 02363 sizeof(**destination)); 02364 if (*destination == (char *) NULL) 02365 return(*destination); 02366 } 02367 *length+=FormatLocaleString(*destination+(*length),*extent,"%s", 02368 canonical_content); 02369 canonical_content=DestroyString(canonical_content); 02370 return(*destination); 02371 } 02372 02373 static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length, 02374 size_t *extent,size_t start,char ***attributes) 02375 { 02376 char 02377 *content; 02378 02379 const char 02380 *attribute; 02381 02382 register ssize_t 02383 i; 02384 02385 size_t 02386 offset; 02387 02388 ssize_t 02389 j; 02390 02391 content=(char *) ""; 02392 if (xml_info->parent != (XMLTreeInfo *) NULL) 02393 content=xml_info->parent->content; 02394 offset=0; 02395 *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset- 02396 start),source,length,extent,MagickFalse); 02397 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent) 02398 { 02399 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent; 02400 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(*source)); 02401 if (*source == (char *) NULL) 02402 return(*source); 02403 } 02404 *length+=FormatLocaleString(*source+(*length),*extent,"<%s",xml_info->tag); 02405 for (i=0; xml_info->attributes[i]; i+=2) 02406 { 02407 attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]); 02408 if (attribute != xml_info->attributes[i+1]) 02409 continue; 02410 if ((*length+strlen(xml_info->attributes[i])+MaxTextExtent) > *extent) 02411 { 02412 *extent=(*length)+strlen(xml_info->attributes[i])+MaxTextExtent; 02413 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 02414 if (*source == (char *) NULL) 02415 return((char *) NULL); 02416 } 02417 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"", 02418 xml_info->attributes[i]); 02419 (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length, 02420 extent,MagickTrue); 02421 *length+=FormatLocaleString(*source+(*length),*extent,"\""); 02422 } 02423 i=0; 02424 while ((attributes[i] != (char **) NULL) && 02425 (strcmp(attributes[i][0],xml_info->tag) != 0)) 02426 i++; 02427 j=1; 02428 while ((attributes[i] != (char **) NULL) && 02429 (attributes[i][j] != (char *) NULL)) 02430 { 02431 if ((attributes[i][j+1] == (char *) NULL) || 02432 (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1])) 02433 { 02434 j+=3; 02435 continue; 02436 } 02437 if ((*length+strlen(attributes[i][j])+MaxTextExtent) > *extent) 02438 { 02439 *extent=(*length)+strlen(attributes[i][j])+MaxTextExtent; 02440 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 02441 if (*source == (char *) NULL) 02442 return((char *) NULL); 02443 } 02444 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"", 02445 attributes[i][j]); 02446 (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent, 02447 MagickTrue); 02448 *length+=FormatLocaleString(*source+(*length),*extent,"\""); 02449 j+=3; 02450 } 02451 *length+=FormatLocaleString(*source+(*length),*extent,*xml_info->content ? 02452 ">" : "/>"); 02453 if (xml_info->child != (XMLTreeInfo *) NULL) 02454 *source=XMLTreeTagToXML(xml_info->child,source,length,extent,0,attributes); 02455 else 02456 *source=EncodePredefinedEntities(xml_info->content,-1,source,length,extent, 02457 MagickFalse); 02458 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent) 02459 { 02460 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent; 02461 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source)); 02462 if (*source == (char *) NULL) 02463 return((char *) NULL); 02464 } 02465 if (*xml_info->content != '\0') 02466 *length+=FormatLocaleString(*source+(*length),*extent,"</%s>", 02467 xml_info->tag); 02468 while ((content[offset] != '\0') && (offset < xml_info->offset)) 02469 offset++; 02470 if (xml_info->ordered != (XMLTreeInfo *) NULL) 02471 content=XMLTreeTagToXML(xml_info->ordered,source,length,extent,offset, 02472 attributes); 02473 else 02474 content=EncodePredefinedEntities(content+offset,-1,source,length,extent, 02475 MagickFalse); 02476 return(content); 02477 } 02478 02479 MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info) 02480 { 02481 char 02482 *xml; 02483 02484 register char 02485 *p, 02486 *q; 02487 02488 register ssize_t 02489 i; 02490 02491 size_t 02492 extent, 02493 length; 02494 02495 ssize_t 02496 j, 02497 k; 02498 02499 XMLTreeInfo 02500 *ordered, 02501 *parent; 02502 02503 XMLTreeRoot 02504 *root; 02505 02506 assert(xml_info != (XMLTreeInfo *) NULL); 02507 assert((xml_info->signature == MagickSignature) || 02508 (((XMLTreeRoot *) xml_info)->signature == MagickSignature)); 02509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 02510 if (xml_info->tag == (char *) NULL) 02511 return((char *) NULL); 02512 xml=AcquireString((char *) NULL); 02513 length=0; 02514 extent=MaxTextExtent; 02515 root=(XMLTreeRoot *) xml_info; 02516 while (root->root.parent != (XMLTreeInfo *) NULL) 02517 root=(XMLTreeRoot *) root->root.parent; 02518 parent=(XMLTreeInfo *) NULL; 02519 if (xml_info != (XMLTreeInfo *) NULL) 02520 parent=xml_info->parent; 02521 if (parent == (XMLTreeInfo *) NULL) 02522 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 02523 { 02524 /* 02525 Pre-root processing instructions. 02526 */ 02527 for (k=2; root->processing_instructions[i][k-1]; k++) ; 02528 p=root->processing_instructions[i][1]; 02529 for (j=1; p != (char *) NULL; j++) 02530 { 02531 if (root->processing_instructions[i][k][j-1] == '>') 02532 { 02533 p=root->processing_instructions[i][j]; 02534 continue; 02535 } 02536 q=root->processing_instructions[i][0]; 02537 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent) 02538 { 02539 extent=length+strlen(p)+strlen(q)+MaxTextExtent; 02540 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml)); 02541 if (xml == (char *) NULL) 02542 return(xml); 02543 } 02544 length+=FormatLocaleString(xml+length,extent,"<?%s%s%s?>\n",q, 02545 *p != '\0' ? " " : "",p); 02546 p=root->processing_instructions[i][j]; 02547 } 02548 } 02549 ordered=(XMLTreeInfo *) NULL; 02550 if (xml_info != (XMLTreeInfo *) NULL) 02551 ordered=xml_info->ordered; 02552 xml_info->parent=(XMLTreeInfo *) NULL; 02553 xml_info->ordered=(XMLTreeInfo *) NULL; 02554 xml=XMLTreeTagToXML(xml_info,&xml,&length,&extent,0,root->attributes); 02555 xml_info->parent=parent; 02556 xml_info->ordered=ordered; 02557 if (parent == (XMLTreeInfo *) NULL) 02558 for (i=0; root->processing_instructions[i] != (char **) NULL; i++) 02559 { 02560 /* 02561 Post-root processing instructions. 02562 */ 02563 for (k=2; root->processing_instructions[i][k-1]; k++) ; 02564 p=root->processing_instructions[i][1]; 02565 for (j=1; p != (char *) NULL; j++) 02566 { 02567 if (root->processing_instructions[i][k][j-1] == '<') 02568 { 02569 p=root->processing_instructions[i][j]; 02570 continue; 02571 } 02572 q=root->processing_instructions[i][0]; 02573 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent) 02574 { 02575 extent=length+strlen(p)+strlen(q)+MaxTextExtent; 02576 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml)); 02577 if (xml == (char *) NULL) 02578 return(xml); 02579 } 02580 length+=FormatLocaleString(xml+length,extent,"\n<?%s%s%s?>",q, 02581 *p != '\0' ? " " : "",p); 02582 p=root->processing_instructions[i][j]; 02583 } 02584 } 02585 return((char *) ResizeQuantumMemory(xml,length+1,sizeof(*xml))); 02586 }