2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12 % TTTTT RRRR EEEEE EEEEE %
26 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
27 % dedicated to making software imaging solutions freely available. %
29 % You may not use this file except in compliance with the License. You may %
30 % obtain a copy of the License at %
32 % http://www.imagemagick.org/script/license.php %
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. %
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 % This module implements the standard handy xml-tree methods for storing and
43 % retrieving nodes and attributes from an XML string.
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/log.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/semaphore.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/token-private.h"
61 #include "MagickCore/xml-tree.h"
62 #include "MagickCore/xml-tree-private.h"
63 #include "MagickCore/utility.h"
64 #include "MagickCore/utility-private.h"
69 #define NumberPredefinedEntities 10
70 #define XMLWhitespace "\t\r\n "
102 typedef struct _XMLTreeRoot
117 ***processing_instructions,
135 *sentinel[] = { (char *) NULL };
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 % A d d C h i l d T o X M L T r e e %
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 % AddChildToXMLTree() adds a child tag at an offset relative to the start of
149 % the parent tag's character content. Return the child tag.
151 % The format of the AddChildToXMLTree method is:
153 % XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag,
154 % const size_t offset)
156 % A description of each parameter follows:
158 % o xml_info: the xml info.
162 % o offset: the tag offset.
165 MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,
166 const char *tag,const size_t offset)
171 if (xml_info == (XMLTreeInfo *) NULL)
172 return((XMLTreeInfo *) NULL);
173 child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child));
174 if (child == (XMLTreeInfo *) NULL)
175 return((XMLTreeInfo *) NULL);
176 (void) ResetMagickMemory(child,0,sizeof(*child));
177 child->tag=ConstantString(tag);
178 child->attributes=sentinel;
179 child->content=ConstantString("");
180 child->debug=IsEventLogging();
181 child->signature=MagickSignature;
182 return(InsertTagIntoXMLTree(xml_info,child,offset));
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 % A d d P a t h T o X M L T r e e %
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 % AddPathToXMLTree() adds a child tag at an offset relative to the start of
197 % the parent tag's character content. This method returns the child tag.
199 % The format of the AddPathToXMLTree method is:
201 % XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path,
202 % const size_t offset)
204 % A description of each parameter follows:
206 % o xml_info: the xml info.
210 % o offset: the tag offset.
213 MagickPrivate XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,
214 const char *path,const size_t offset)
218 subnode[MaxTextExtent],
234 assert(xml_info != (XMLTreeInfo *) NULL);
235 assert((xml_info->signature == MagickSignature) ||
236 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
239 components=GetPathComponents(path,&number_components);
240 if (components == (char **) NULL)
241 return((XMLTreeInfo *) NULL);
242 for (i=0; i < (ssize_t) number_components; i++)
244 GetPathComponent(components[i],SubimagePath,subnode);
245 GetPathComponent(components[i],CanonicalPath,tag);
246 child=GetXMLTreeChild(node,tag);
247 if (child == (XMLTreeInfo *) NULL)
248 child=AddChildToXMLTree(node,tag,offset);
250 if (node == (XMLTreeInfo *) NULL)
252 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
254 node=GetXMLTreeOrdered(node);
255 if (node == (XMLTreeInfo *) NULL)
258 if (node == (XMLTreeInfo *) NULL)
260 components[i]=DestroyString(components[i]);
262 for ( ; i < (ssize_t) number_components; i++)
263 components[i]=DestroyString(components[i]);
264 components=(char **) RelinquishMagickMemory(components);
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 % C a n o n i c a l X M L C o n t e n t %
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % CanonicalXMLContent() converts text to canonical XML content by converting
280 % to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding
281 % as base-64 as required.
283 % The format of the CanonicalXMLContent method is:
286 % char *CanonicalXMLContent(const char *content,
287 % const MagickBooleanType pedantic)
289 % A description of each parameter follows:
291 % o content: the content.
293 % o pedantic: if true, replace newlines and tabs with their respective
297 MagickPrivate char *CanonicalXMLContent(const char *content,
298 const MagickBooleanType pedantic)
304 register const unsigned char
317 utf8=ConvertLatin1ToUTF8((const unsigned char *) content);
318 if (utf8 == (unsigned char *) NULL)
319 return((char *) NULL);
320 for (p=utf8; *p != '\0'; p++)
321 if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d))
326 String is binary, base64-encode it.
328 base64=Base64Encode(utf8,strlen((char *) utf8),&length);
329 utf8=(unsigned char *) RelinquishMagickMemory(utf8);
330 if (base64 == (char *) NULL)
331 return((char *) NULL);
332 canonical_content=AcquireString("<base64>");
333 (void) ConcatenateString(&canonical_content,base64);
334 base64=DestroyString(base64);
335 (void) ConcatenateString(&canonical_content,"</base64>");
336 return(canonical_content);
339 Substitute predefined entities.
342 canonical_content=AcquireString((char *) NULL);
343 extent=MaxTextExtent;
344 for (p=utf8; *p != '\0'; p++)
346 if ((i+MaxTextExtent) > (ssize_t) extent)
348 extent+=MaxTextExtent;
349 canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent,
350 sizeof(*canonical_content));
351 if (canonical_content == (char *) NULL)
352 return(canonical_content);
358 i+=FormatLocaleString(canonical_content+i,extent,"&");
363 i+=FormatLocaleString(canonical_content+i,extent,"<");
368 i+=FormatLocaleString(canonical_content+i,extent,">");
373 i+=FormatLocaleString(canonical_content+i,extent,""");
378 if (pedantic == MagickFalse)
380 canonical_content[i++]=(char) (*p);
383 i+=FormatLocaleString(canonical_content+i,extent,"
");
388 if (pedantic == MagickFalse)
390 canonical_content[i++]=(char) (*p);
393 i+=FormatLocaleString(canonical_content+i,extent,"	");
398 i+=FormatLocaleString(canonical_content+i,extent,"
");
403 canonical_content[i++]=(char) (*p);
408 canonical_content[i]='\0';
409 utf8=(unsigned char *) RelinquishMagickMemory(utf8);
410 return(canonical_content);
414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 % D e s t r o y X M L T r e e %
422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424 % DestroyXMLTree() destroys the xml-tree.
426 % The format of the DestroyXMLTree method is:
428 % XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
430 % A description of each parameter follows:
432 % o xml_info: the xml info.
436 static char **DestroyXMLTreeAttributes(char **attributes)
442 Destroy a tag attribute list.
444 if ((attributes == (char **) NULL) || (attributes == sentinel))
445 return((char **) NULL);
446 for (i=0; attributes[i] != (char *) NULL; i+=2)
449 Destroy attribute tag and value.
451 if (attributes[i] != (char *) NULL)
452 attributes[i]=DestroyString(attributes[i]);
453 if (attributes[i+1] != (char *) NULL)
454 attributes[i+1]=DestroyString(attributes[i+1]);
456 attributes=(char **) RelinquishMagickMemory(attributes);
457 return((char **) NULL);
460 static void DestroyXMLTreeRoot(XMLTreeInfo *xml_info)
474 assert(xml_info != (XMLTreeInfo *) NULL);
475 assert((xml_info->signature == MagickSignature) ||
476 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
477 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
478 if (xml_info->parent != (XMLTreeInfo *) NULL)
481 Free root tag allocations.
483 root=(XMLTreeRoot *) xml_info;
484 for (i=NumberPredefinedEntities; root->entities[i] != (char *) NULL; i+=2)
485 root->entities[i+1]=DestroyString(root->entities[i+1]);
486 root->entities=(char **) RelinquishMagickMemory(root->entities);
487 for (i=0; root->attributes[i] != (char **) NULL; i++)
489 attributes=root->attributes[i];
490 if (attributes[0] != (char *) NULL)
491 attributes[0]=DestroyString(attributes[0]);
492 for (j=1; attributes[j] != (char *) NULL; j+=3)
494 if (attributes[j] != (char *) NULL)
495 attributes[j]=DestroyString(attributes[j]);
496 if (attributes[j+1] != (char *) NULL)
497 attributes[j+1]=DestroyString(attributes[j+1]);
498 if (attributes[j+2] != (char *) NULL)
499 attributes[j+2]=DestroyString(attributes[j+2]);
501 attributes=(char **) RelinquishMagickMemory(attributes);
503 if (root->attributes[0] != (char **) NULL)
504 root->attributes=(char ***) RelinquishMagickMemory(root->attributes);
505 if (root->processing_instructions[0] != (char **) NULL)
507 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
509 for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++)
510 root->processing_instructions[i][j]=DestroyString(
511 root->processing_instructions[i][j]);
512 root->processing_instructions[i][j+1]=DestroyString(
513 root->processing_instructions[i][j+1]);
514 root->processing_instructions[i]=(char **) RelinquishMagickMemory(
515 root->processing_instructions[i]);
517 root->processing_instructions=(char ***) RelinquishMagickMemory(
518 root->processing_instructions);
522 MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
524 assert(xml_info != (XMLTreeInfo *) NULL);
525 assert((xml_info->signature == MagickSignature) ||
526 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
528 if (xml_info->child != (XMLTreeInfo *) NULL)
529 xml_info->child=DestroyXMLTree(xml_info->child);
530 if (xml_info->ordered != (XMLTreeInfo *) NULL)
531 xml_info->ordered=DestroyXMLTree(xml_info->ordered);
532 DestroyXMLTreeRoot(xml_info);
533 xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes);
534 xml_info->content=DestroyString(xml_info->content);
535 xml_info->tag=DestroyString(xml_info->tag);
536 xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info);
537 return((XMLTreeInfo *) NULL);
541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
545 % F i l e T o X M L %
549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551 % FileToXML() returns the contents of a file as a XML string.
553 % The format of the FileToXML method is:
555 % char *FileToXML(const char *filename,const size_t extent)
557 % A description of each parameter follows:
559 % o filename: the filename.
561 % o extent: Maximum length of the string.
565 static inline size_t MagickMin(const size_t x,const size_t y)
572 MagickPrivate char *FileToXML(const char *filename,const size_t extent)
595 assert(filename != (const char *) NULL);
598 if (LocaleCompare(filename,"-") != 0)
599 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
601 return((char *) NULL);
602 offset=(MagickOffsetType) lseek(file,0,SEEK_END);
604 if ((file == fileno(stdin)) || (offset < 0) ||
605 (offset != (MagickOffsetType) ((ssize_t) offset)))
614 Stream is not seekable.
616 offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
617 quantum=(size_t) MagickMaxBufferExtent;
618 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0))
619 quantum=(size_t) MagickMin((MagickSizeType) file_stats.st_size,
620 MagickMaxBufferExtent);
621 xml=(char *) AcquireQuantumMemory(quantum,sizeof(*xml));
622 for (i=0; xml != (char *) NULL; i+=count)
624 count=read(file,xml+i,quantum);
631 if (~((size_t) i) < (quantum+1))
633 xml=(char *) RelinquishMagickMemory(xml);
636 xml=(char *) ResizeQuantumMemory(xml,i+quantum+1,sizeof(*xml));
637 if ((size_t) (i+count) >= extent)
640 if (LocaleCompare(filename,"-") != 0)
642 if (xml == (char *) NULL)
643 return((char *) NULL);
646 xml=(char *) RelinquishMagickMemory(xml);
647 return((char *) NULL);
649 length=(size_t) MagickMin(i+count,extent);
653 length=(size_t) MagickMin((MagickSizeType) offset,extent);
655 if (~length >= (MaxTextExtent-1))
656 xml=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*xml));
657 if (xml == (char *) NULL)
660 return((char *) NULL);
662 map=MapBlob(file,ReadMode,0,length);
663 if (map != (char *) NULL)
665 (void) memcpy(xml,map,length);
666 (void) UnmapBlob(map,length);
670 (void) lseek(file,0,SEEK_SET);
671 for (i=0; i < length; i+=count)
673 count=read(file,xml+i,(size_t) MagickMin(length-i,(MagickSizeType)
685 xml=(char *) RelinquishMagickMemory(xml);
686 return((char *) NULL);
690 if (LocaleCompare(filename,"-") != 0)
693 xml=(char *) RelinquishMagickMemory(xml);
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
702 % G e t N e x t X M L T r e e T a g %
706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 % GetNextXMLTreeTag() returns the next tag or NULL if not found.
710 % The format of the GetNextXMLTreeTag method is:
712 % XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
714 % A description of each parameter follows:
716 % o xml_info: the xml info.
719 MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
721 assert(xml_info != (XMLTreeInfo *) NULL);
722 assert((xml_info->signature == MagickSignature) ||
723 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
725 return(xml_info->next);
729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 % G e t X M L T r e e A t t r i b u t e %
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739 % GetXMLTreeAttribute() returns the value of the attribute tag with the
740 % specified tag if found, otherwise NULL.
742 % The format of the GetXMLTreeAttribute method is:
744 % const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag)
746 % A description of each parameter follows:
748 % o xml_info: the xml info.
750 % o tag: the attribute tag.
753 MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,
765 assert(xml_info != (XMLTreeInfo *) NULL);
766 assert((xml_info->signature == MagickSignature) ||
767 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
768 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
769 if (xml_info->attributes == (char **) NULL)
770 return((const char *) NULL);
772 while ((xml_info->attributes[i] != (char *) NULL) &&
773 (strcmp(xml_info->attributes[i],tag) != 0))
775 if (xml_info->attributes[i] != (char *) NULL)
776 return(xml_info->attributes[i+1]);
777 root=(XMLTreeRoot*) xml_info;
778 while (root->root.parent != (XMLTreeInfo *) NULL)
779 root=(XMLTreeRoot *) root->root.parent;
781 while ((root->attributes[i] != (char **) NULL) &&
782 (strcmp(root->attributes[i][0],xml_info->tag) != 0))
784 if (root->attributes[i] == (char **) NULL)
785 return((const char *) NULL);
787 while ((root->attributes[i][j] != (char *) NULL) &&
788 (strcmp(root->attributes[i][j],tag) != 0))
790 if (root->attributes[i][j] == (char *) NULL)
791 return((const char *) NULL);
792 return(root->attributes[i][j+1]);
796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800 % G e t X M L T r e e A t t r i b u t e s %
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
806 % GetXMLTreeAttributes() injects all attributes associated with the current
807 % tag in the specified splay-tree.
809 % The format of the GetXMLTreeAttributes method is:
811 % MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
812 % SplayTreeInfo *attributes)
814 % A description of each parameter follows:
816 % o xml_info: the xml info.
818 % o attributes: the attribute splay-tree.
821 MagickPrivate MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
822 SplayTreeInfo *attributes)
827 assert(xml_info != (XMLTreeInfo *) NULL);
828 assert((xml_info->signature == MagickSignature) ||
829 (((const XMLTreeRoot *) xml_info)->signature == MagickSignature));
830 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
831 assert(attributes != (SplayTreeInfo *) NULL);
832 if (xml_info->attributes == (char **) NULL)
835 while (xml_info->attributes[i] != (char *) NULL)
837 (void) AddValueToSplayTree(attributes,
838 ConstantString(xml_info->attributes[i]),
839 ConstantString(xml_info->attributes[i+1]));
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % G e t X M L T r e e C h i l d %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % GetXMLTreeChild() returns the first child tag with the specified tag if
857 % found, otherwise NULL.
859 % The format of the GetXMLTreeChild method is:
861 % XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
863 % A description of each parameter follows:
865 % o xml_info: the xml info.
868 MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
873 assert(xml_info != (XMLTreeInfo *) NULL);
874 assert((xml_info->signature == MagickSignature) ||
875 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
876 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
877 child=xml_info->child;
878 if (tag != (const char *) NULL)
879 while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0))
880 child=child->sibling;
885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 % G e t X M L T r e e C o n t e n t %
893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895 % GetXMLTreeContent() returns any content associated with specified
898 % The format of the GetXMLTreeContent method is:
900 % const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
902 % A description of each parameter follows:
904 % o xml_info: the xml info.
907 MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
909 assert(xml_info != (XMLTreeInfo *) NULL);
910 assert((xml_info->signature == MagickSignature) ||
911 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
912 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
913 return(xml_info->content);
917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 % G e t X M L T r e e O r d e r e d %
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927 % GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL.
929 % The format of the GetXMLTreeOrdered method is:
931 % XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
933 % A description of each parameter follows:
935 % o xml_info: the xml info.
938 MagickPrivate XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
940 assert(xml_info != (XMLTreeInfo *) NULL);
941 assert((xml_info->signature == MagickSignature) ||
942 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
944 return(xml_info->ordered);
948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
952 % G e t X M L T r e e P a t h %
956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 % GetXMLTreePath() traverses the XML-tree as defined by the specified path
959 % and returns the node if found, otherwise NULL.
961 % The format of the GetXMLTreePath method is:
963 % XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
965 % A description of each parameter follows:
967 % o xml_info: the xml info.
969 % o path: the path (e.g. property/elapsed-time).
972 MagickPrivate XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
976 subnode[MaxTextExtent],
991 assert(xml_info != (XMLTreeInfo *) NULL);
992 assert((xml_info->signature == MagickSignature) ||
993 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
994 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
996 components=GetPathComponents(path,&number_components);
997 if (components == (char **) NULL)
998 return((XMLTreeInfo *) NULL);
999 for (i=0; i < (ssize_t) number_components; i++)
1001 GetPathComponent(components[i],SubimagePath,subnode);
1002 GetPathComponent(components[i],CanonicalPath,tag);
1003 node=GetXMLTreeChild(node,tag);
1004 if (node == (XMLTreeInfo *) NULL)
1006 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
1008 node=GetXMLTreeOrdered(node);
1009 if (node == (XMLTreeInfo *) NULL)
1012 if (node == (XMLTreeInfo *) NULL)
1014 components[i]=DestroyString(components[i]);
1016 for ( ; i < (ssize_t) number_components; i++)
1017 components[i]=DestroyString(components[i]);
1018 components=(char **) RelinquishMagickMemory(components);
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1027 % 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 %
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % GetXMLTreeProcessingInstructions() returns a null terminated array of
1034 % processing instructions for the given target.
1036 % The format of the GetXMLTreeProcessingInstructions method is:
1038 % const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info,
1039 % const char *target)
1041 % A description of each parameter follows:
1043 % o xml_info: the xml info.
1046 MagickPrivate const char **GetXMLTreeProcessingInstructions(
1047 XMLTreeInfo *xml_info,const char *target)
1055 assert(xml_info != (XMLTreeInfo *) NULL);
1056 assert((xml_info->signature == MagickSignature) ||
1057 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1058 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1059 root=(XMLTreeRoot *) xml_info;
1060 while (root->root.parent != (XMLTreeInfo *) NULL)
1061 root=(XMLTreeRoot *) root->root.parent;
1063 while ((root->processing_instructions[i] != (char **) NULL) &&
1064 (strcmp(root->processing_instructions[i][0],target) != 0))
1066 if (root->processing_instructions[i] == (char **) NULL)
1067 return((const char **) sentinel);
1068 return((const char **) (root->processing_instructions[i]+1));
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 % G e t X M L T r e e S i b l i n g %
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082 % GetXMLTreeSibling() returns the node sibling if found, otherwise NULL.
1084 % The format of the GetXMLTreeSibling method is:
1086 % XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
1088 % A description of each parameter follows:
1090 % o xml_info: the xml info.
1093 MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
1095 assert(xml_info != (XMLTreeInfo *) NULL);
1096 assert((xml_info->signature == MagickSignature) ||
1097 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1099 return(xml_info->sibling);
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107 % G e t X M L T r e e T a g %
1111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113 % GetXMLTreeTag() returns the tag associated with specified xml-tree node.
1115 % The format of the GetXMLTreeTag method is:
1117 % const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
1119 % A description of each parameter follows:
1121 % o xml_info: the xml info.
1124 MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
1126 assert(xml_info != (XMLTreeInfo *) NULL);
1127 assert((xml_info->signature == MagickSignature) ||
1128 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1130 return(xml_info->tag);
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 % I n s e r t I n t o T a g X M L T r e e %
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 % InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of
1145 % the parent tag's character content. This method returns the child tag.
1147 % The format of the InsertTagIntoXMLTree method is:
1149 % XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
1150 % XMLTreeInfo *child,const size_t offset)
1152 % A description of each parameter follows:
1154 % o xml_info: the xml info.
1156 % o child: the child tag.
1158 % o offset: the tag offset.
1161 MagickPrivate XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
1162 XMLTreeInfo *child,const size_t offset)
1169 child->ordered=(XMLTreeInfo *) NULL;
1170 child->sibling=(XMLTreeInfo *) NULL;
1171 child->next=(XMLTreeInfo *) NULL;
1172 child->offset=offset;
1173 child->parent=xml_info;
1174 if (xml_info->child == (XMLTreeInfo *) NULL)
1176 xml_info->child=child;
1179 head=xml_info->child;
1180 if (head->offset > offset)
1182 child->ordered=head;
1183 xml_info->child=child;
1188 while ((node->ordered != (XMLTreeInfo *) NULL) &&
1189 (node->ordered->offset <= offset))
1191 child->ordered=node->ordered;
1192 node->ordered=child;
1194 previous=(XMLTreeInfo *) NULL;
1196 while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0))
1201 if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
1203 while ((node->next != (XMLTreeInfo *) NULL) &&
1204 (node->next->offset <= offset))
1206 child->next=node->next;
1211 if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL))
1212 previous->sibling=node->sibling;
1214 previous=(XMLTreeInfo *) NULL;
1216 while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
1221 child->sibling=node;
1222 if (previous != (XMLTreeInfo *) NULL)
1223 previous->sibling=child;
1229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233 % N e w X M L T r e e %
1237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239 % NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified
1242 % The format of the NewXMLTree method is:
1244 % XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
1246 % A description of each parameter follows:
1248 % o xml: The XML string.
1250 % o exception: return any errors or warnings in this structure.
1254 static char *ConvertUTF16ToUTF8(const char *content,size_t *length)
1274 utf8=(char *) AcquireQuantumMemory(*length,sizeof(*utf8));
1275 if (utf8 == (char *) NULL)
1276 return((char *) NULL);
1277 encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1;
1283 (void) CopyMagickMemory(utf8,content,*length*sizeof(*utf8));
1288 for (i=2; i < (ssize_t) (*length-1); i+=2)
1290 c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) :
1291 ((content[i+1] & 0xff) << 8) | (content[i] & 0xff);
1292 if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (ssize_t) (*length-1)))
1294 byte=(encoding != 0) ? ((content[i] & 0xff) << 8) |
1295 (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) |
1296 (content[i] & 0xff);
1297 c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000;
1299 if ((size_t) (j+MaxTextExtent) > extent)
1301 extent=(size_t) j+MaxTextExtent;
1302 utf8=(char *) ResizeQuantumMemory(utf8,extent,sizeof(*utf8));
1303 if (utf8 == (char *) NULL)
1313 Multi-byte UTF-8 sequence.
1316 for (bits=0; byte != 0; byte/=2)
1319 utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits));
1323 utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f);
1328 return((char *) ResizeQuantumMemory(utf8,*length,sizeof(*utf8)));
1331 static char *ParseEntities(char *xml,char **entities,int state)
1355 Normalize line endings.
1359 for ( ; *xml != '\0'; xml++)
1360 while (*xml == '\r')
1364 (void) CopyMagickMemory(xml,xml+1,strlen(xml));
1368 while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') ||
1369 (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0)))
1375 '&' for general entity decoding
1376 '%' for parameter entity decoding
1377 'c' for CDATA sections
1378 ' ' for attributes normalization
1379 '*' for non-CDATA attributes normalization
1381 if ((state != 'c') && (strncmp(xml,"&#",2) == 0))
1384 Character reference.
1387 c=strtol(xml+2,&entity,10); /* base 10 */
1389 c=strtol(xml+3,&entity,16); /* base 16 */
1390 if ((c == 0) || (*entity != ';'))
1393 Not a character reference.
1403 Multi-byte UTF-8 sequence.
1406 for (i=0; byte != 0; byte/=2)
1409 *xml=(char) ((0xFF << (7-i)) | (c >> (6*i)));
1414 *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F));
1418 (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';')));
1421 if (((*xml == '&') && ((state == '&') || (state == ' ') ||
1422 (state == '*'))) || ((state == '%') && (*xml == '%')))
1425 Find entity in the list.
1428 while ((entities[i] != (char *) NULL) &&
1429 (strncmp(xml+1,entities[i],strlen(entities[i])) != 0))
1431 if (entities[i++] == (char *) NULL)
1438 length=strlen(entities[i]);
1439 entity=strchr(xml,';');
1440 if ((length-1L) >= (size_t) (entity-xml))
1442 offset=(ssize_t) (xml-p);
1443 extent=(size_t) (offset+length+strlen(entity));
1445 p=(char *) ResizeQuantumMemory(p,extent,sizeof(*p));
1451 xml=(char *) AcquireQuantumMemory(extent,sizeof(*xml));
1452 if (xml != (char *) NULL)
1454 (void) CopyMagickString(xml,p,extent*sizeof(*xml));
1458 if (p == (char *) NULL)
1459 ThrowFatalException(ResourceLimitFatalError,
1460 "MemoryAllocationFailed");
1462 entity=strchr(xml,';');
1464 (void) CopyMagickMemory(xml+length,entity+1,strlen(entity));
1465 (void) strncpy(xml,entities[i],length);
1469 if (((state == ' ') || (state == '*')) &&
1470 (isspace((int) ((unsigned char) *xml) != 0)))
1478 Normalize spaces for non-CDATA attributes.
1480 for (xml=p; *xml != '\0'; xml++)
1482 i=(ssize_t) strspn(xml," ");
1484 (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1);
1485 while ((*xml != '\0') && (*xml != ' '))
1489 if ((xml >= p) && (*xml == ' '))
1492 return(p == q ? ConstantString(p) : p);
1495 static void ParseCharacterContent(XMLTreeRoot *root,char *xml,
1496 const size_t length,const char state)
1501 xml_info=root->node;
1502 if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) ||
1506 xml=ParseEntities(xml,root->entities,state);
1507 if (*xml_info->content != '\0')
1509 (void) ConcatenateString(&xml_info->content,xml);
1510 xml=DestroyString(xml);
1514 if (xml_info->content != (char *) NULL)
1515 xml_info->content=DestroyString(xml_info->content);
1516 xml_info->content=xml;
1520 static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag,
1521 char *magick_unused(xml),ExceptionInfo *exception)
1523 if ((root->node == (XMLTreeInfo *) NULL) ||
1524 (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0))
1526 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1527 "ParseError","unexpected closing tag </%s>",tag);
1528 return(&root->root);
1530 root->node=root->node->parent;
1531 return((XMLTreeInfo *) NULL);
1534 static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities)
1540 Check for circular entity references.
1544 while ((*xml != '\0') && (*xml != '&'))
1548 if (strncmp(xml+1,tag,strlen(tag)) == 0)
1549 return(MagickFalse);
1551 while ((entities[i] != (char *) NULL) &&
1552 (strncmp(entities[i],xml+1,strlen(entities[i])) == 0))
1554 if ((entities[i] != (char *) NULL) &&
1555 (ValidateEntities(tag,entities[i+1],entities) == 0))
1556 return(MagickFalse);
1560 static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml,
1574 xml+=strcspn(xml,XMLWhitespace);
1578 xml+=strspn(xml+1,XMLWhitespace)+1;
1580 if (strcmp(target,"xml") == 0)
1582 xml=strstr(xml,"standalone");
1583 if ((xml != (char *) NULL) &&
1584 (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0))
1585 root->standalone=MagickTrue;
1588 if (root->processing_instructions[0] == (char **) NULL)
1590 root->processing_instructions=(char ***) AcquireMagickMemory(sizeof(
1591 *root->processing_instructions));
1592 if (root->processing_instructions ==(char ***) NULL)
1593 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1594 *root->processing_instructions=(char **) NULL;
1597 while ((root->processing_instructions[i] != (char **) NULL) &&
1598 (strcmp(target,root->processing_instructions[i][0]) != 0))
1600 if (root->processing_instructions[i] == (char **) NULL)
1602 root->processing_instructions=(char ***) ResizeQuantumMemory(
1603 root->processing_instructions,(size_t) (i+2),
1604 sizeof(*root->processing_instructions));
1605 if (root->processing_instructions == (char ***) NULL)
1606 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1607 root->processing_instructions[i]=(char **) AcquireQuantumMemory(3,
1608 sizeof(**root->processing_instructions));
1609 if (root->processing_instructions[i] == (char **) NULL)
1610 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1611 root->processing_instructions[i+1]=(char **) NULL;
1612 root->processing_instructions[i][0]=ConstantString(target);
1613 root->processing_instructions[i][1]=(char *)
1614 root->processing_instructions[i+1];
1615 root->processing_instructions[i+1]=(char **) NULL;
1616 root->processing_instructions[i][2]=ConstantString("");
1619 while (root->processing_instructions[i][j] != (char *) NULL)
1621 root->processing_instructions[i]=(char **) ResizeQuantumMemory(
1622 root->processing_instructions[i],(size_t) (j+3),
1623 sizeof(**root->processing_instructions));
1624 if (root->processing_instructions[i] == (char **) NULL)
1625 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1626 root->processing_instructions[i][j+2]=(char *) ResizeQuantumMemory(
1627 root->processing_instructions[i][j+1],(size_t) (j+1),
1628 sizeof(**root->processing_instructions));
1629 if (root->processing_instructions[i][j+2] == (char *) NULL)
1630 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1631 (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1,
1632 root->root.tag != (char *) NULL ? ">" : "<",2);
1633 root->processing_instructions[i][j]=ConstantString(xml);
1634 root->processing_instructions[i][j+1]=(char *) NULL;
1637 static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml,
1638 size_t length,ExceptionInfo *exception)
1644 **predefined_entitites,
1656 predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel));
1657 if (predefined_entitites == (char **) NULL)
1658 ThrowFatalException(ResourceLimitError,"MemoryAllocationFailed");
1659 (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel));
1660 for (xml[length]='\0'; xml != (char *) NULL; )
1662 while ((*xml != '\0') && (*xml != '<') && (*xml != '%'))
1666 if (strncmp(xml,"<!ENTITY",8) == 0)
1669 Parse entity definitions.
1671 xml+=strspn(xml+8,XMLWhitespace)+8;
1673 n=xml+strspn(xml,XMLWhitespace "%");
1674 xml=n+strcspn(n,XMLWhitespace);
1676 v=xml+strspn(xml+1,XMLWhitespace)+1;
1679 if ((q != '"') && (q != '\''))
1684 xml=strchr(xml,'>');
1687 entities=(*c == '%') ? predefined_entitites : root->entities;
1688 for (i=0; entities[i] != (char *) NULL; i++) ;
1689 entities=(char **) ResizeQuantumMemory(entities,(size_t) (i+3),
1691 if (entities == (char **) NULL)
1692 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1694 predefined_entitites=entities;
1696 root->entities=entities;
1700 if (xml != (char *) NULL)
1705 entities[i+1]=ParseEntities(v,predefined_entitites,'%');
1706 entities[i+2]=(char *) NULL;
1707 if (ValidateEntities(n,entities[i+1],entities) != MagickFalse)
1711 if (entities[i+1] != v)
1712 entities[i+1]=DestroyString(entities[i+1]);
1713 (void) ThrowMagickException(exception,GetMagickModule(),
1714 OptionWarning,"ParseError","circular entity declaration &%s",n);
1715 predefined_entitites=(char **) RelinquishMagickMemory(
1716 predefined_entitites);
1717 return(MagickFalse);
1721 if (strncmp(xml,"<!ATTLIST",9) == 0)
1724 Parse default attributes.
1726 t=xml+strspn(xml+9,XMLWhitespace)+9;
1729 (void) ThrowMagickException(exception,GetMagickModule(),
1730 OptionWarning,"ParseError","unclosed <!ATTLIST");
1731 predefined_entitites=(char **) RelinquishMagickMemory(
1732 predefined_entitites);
1733 return(MagickFalse);
1735 xml=t+strcspn(t,XMLWhitespace ">");
1740 while ((root->attributes[i] != (char **) NULL) &&
1741 (strcmp(n,root->attributes[i][0]) != 0))
1743 while ((*(n=xml+strspn(xml+1,XMLWhitespace)+1) != '\0') &&
1746 xml=n+strcspn(n,XMLWhitespace);
1751 (void) ThrowMagickException(exception,GetMagickModule(),
1752 OptionWarning,"ParseError","malformed <!ATTLIST");
1753 predefined_entitites=(char **) RelinquishMagickMemory(
1754 predefined_entitites);
1755 return(MagickFalse);
1757 xml+=strspn(xml+1,XMLWhitespace)+1;
1758 c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " ");
1759 if (strncmp(xml,"NOTATION",8) == 0)
1760 xml+=strspn(xml+8,XMLWhitespace)+8;
1761 xml=(*xml == '(') ? strchr(xml,')') : xml+
1762 strcspn(xml,XMLWhitespace);
1763 if (xml == (char *) NULL)
1765 (void) ThrowMagickException(exception,GetMagickModule(),
1766 OptionWarning,"ParseError","malformed <!ATTLIST");
1767 predefined_entitites=(char **) RelinquishMagickMemory(
1768 predefined_entitites);
1769 return(MagickFalse);
1771 xml+=strspn(xml,XMLWhitespace ")");
1772 if (strncmp(xml,"#FIXED",6) == 0)
1773 xml+=strspn(xml+6,XMLWhitespace)+6;
1776 xml+=strcspn(xml,XMLWhitespace ">")-1;
1782 if (((*xml == '"') || (*xml == '\'')) &&
1783 ((xml=strchr(v=xml+1,*xml)) != (char *) NULL))
1787 (void) ThrowMagickException(exception,GetMagickModule(),
1788 OptionWarning,"ParseError","malformed <!ATTLIST");
1789 predefined_entitites=(char **) RelinquishMagickMemory(
1790 predefined_entitites);
1791 return(MagickFalse);
1793 if (root->attributes[i] == (char **) NULL)
1799 root->attributes=(char ***) AcquireQuantumMemory(2,
1800 sizeof(*root->attributes));
1802 root->attributes=(char ***) ResizeQuantumMemory(
1803 root->attributes,(size_t) (i+2),
1804 sizeof(*root->attributes));
1805 if (root->attributes == (char ***) NULL)
1806 ThrowFatalException(ResourceLimitFatalError,
1807 "MemoryAllocationFailed");
1808 root->attributes[i]=(char **) AcquireQuantumMemory(2,
1809 sizeof(*root->attributes));
1810 if (root->attributes[i] == (char **) NULL)
1811 ThrowFatalException(ResourceLimitFatalError,
1812 "MemoryAllocationFailed");
1813 root->attributes[i][0]=ConstantString(t);
1814 root->attributes[i][1]=(char *) NULL;
1815 root->attributes[i+1]=(char **) NULL;
1817 for (j=1; root->attributes[i][j] != (char *) NULL; j+=3) ;
1818 root->attributes[i]=(char **) ResizeQuantumMemory(
1819 root->attributes[i],(size_t) (j+4),sizeof(*root->attributes));
1820 if (root->attributes[i] == (char **) NULL)
1821 ThrowFatalException(ResourceLimitFatalError,
1822 "MemoryAllocationFailed");
1823 root->attributes[i][j+3]=(char *) NULL;
1824 root->attributes[i][j+2]=ConstantString(c);
1825 root->attributes[i][j+1]=(char *) NULL;
1826 if (v != (char *) NULL)
1827 root->attributes[i][j+1]=ParseEntities(v,root->entities,*c);
1828 root->attributes[i][j]=ConstantString(n);
1832 if (strncmp(xml, "<!--", 4) == 0)
1833 xml=strstr(xml+4,"-->");
1835 if (strncmp(xml,"<?", 2) == 0)
1839 if (xml != (char *) NULL)
1841 ParseProcessingInstructions(root,c,(size_t) (xml-c));
1847 xml=strchr(xml,'>');
1849 if ((*(xml++) == '%') && (root->standalone == MagickFalse))
1852 predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites);
1856 static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes)
1861 xml_info=root->node;
1862 if (xml_info->tag == (char *) NULL)
1863 xml_info->tag=ConstantString(tag);
1865 xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content));
1866 xml_info->attributes=attributes;
1867 root->node=xml_info;
1870 MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
1902 Convert xml-string to UTF8.
1904 if ((xml == (const char *) NULL) || (strlen(xml) == 0))
1906 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1907 "ParseError","root tag missing");
1908 return((XMLTreeInfo *) NULL);
1910 root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL);
1912 utf8=ConvertUTF16ToUTF8(xml,&length);
1913 if (utf8 == (char *) NULL)
1915 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1916 "ParseError","UTF16 to UTF8 failed");
1917 return((XMLTreeInfo *) NULL);
1919 terminal=utf8[length-1];
1920 utf8[length-1]='\0';
1922 while ((*p != '\0') && (*p != '<'))
1926 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1927 "ParseError","root tag missing");
1928 utf8=DestroyString(utf8);
1929 return((XMLTreeInfo *) NULL);
1931 attribute=(char **) NULL;
1934 attributes=(char **) sentinel;
1937 if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') ||
1938 (*p == ':') || (c < '\0'))
1943 if (root->node == (XMLTreeInfo *) NULL)
1945 (void) ThrowMagickException(exception,GetMagickModule(),
1946 OptionWarning,"ParseError","root tag missing");
1947 utf8=DestroyString(utf8);
1948 return(&root->root);
1950 p+=strcspn(p,XMLWhitespace "/>");
1951 while (isspace((int) ((unsigned char) *p)) != 0)
1953 if ((*p != '\0') && (*p != '/') && (*p != '>'))
1956 Find tag in default attributes list.
1959 while ((root->attributes[i] != (char **) NULL) &&
1960 (strcmp(root->attributes[i][0],tag) != 0))
1962 attribute=root->attributes[i];
1964 for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2)
1970 attributes=(char **) AcquireQuantumMemory(4,sizeof(*attributes));
1972 attributes=(char **) ResizeQuantumMemory(attributes,(size_t) (l+4),
1973 sizeof(*attributes));
1974 if (attributes == (char **) NULL)
1976 (void) ThrowMagickException(exception,GetMagickModule(),
1977 ResourceLimitError,"MemoryAllocationFailed","`%s'","");
1978 utf8=DestroyString(utf8);
1979 return(&root->root);
1981 attributes[l+2]=(char *) NULL;
1982 attributes[l+1]=(char *) NULL;
1984 p+=strcspn(p,XMLWhitespace "=/>");
1985 if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0))
1986 attributes[l]=ConstantString("");
1990 p+=strspn(p,XMLWhitespace "=");
1992 if ((c == '"') || (c == '\''))
1999 while ((*p != '\0') && (*p != c))
2005 attributes[l]=ConstantString("");
2006 attributes[l+1]=ConstantString("");
2007 (void) DestroyXMLTreeAttributes(attributes);
2008 (void) ThrowMagickException(exception,GetMagickModule(),
2009 OptionWarning,"ParseError","missing %c",c);
2010 utf8=DestroyString(utf8);
2011 return(&root->root);
2014 while ((attribute != (char **) NULL) &&
2015 (attribute[j] != (char *) NULL) &&
2016 (strcmp(attribute[j],attributes[l]) != 0))
2018 attributes[l+1]=ParseEntities(attributes[l+1],root->entities,
2019 (attribute != (char **) NULL) && (attribute[j] !=
2020 (char *) NULL) ? *attribute[j+2] : ' ');
2022 attributes[l]=ConstantString(attributes[l]);
2024 while (isspace((int) ((unsigned char) *p)) != 0)
2033 if (((*p != '\0') && (*p != '>')) ||
2034 ((*p == '\0') && (terminal != '>')))
2037 (void) DestroyXMLTreeAttributes(attributes);
2038 (void) ThrowMagickException(exception,GetMagickModule(),
2039 OptionWarning,"ParseError","missing >");
2040 utf8=DestroyString(utf8);
2041 return(&root->root);
2043 ParseOpenTag(root,tag,attributes);
2044 (void) ParseCloseTag(root,tag,p,exception);
2049 if ((*p == '>') || ((*p == '\0') && (terminal == '>')))
2052 ParseOpenTag(root,tag,attributes);
2058 (void) DestroyXMLTreeAttributes(attributes);
2059 (void) ThrowMagickException(exception,GetMagickModule(),
2060 OptionWarning,"ParseError","missing >");
2061 utf8=DestroyString(utf8);
2062 return(&root->root);
2073 p+=strcspn(tag,XMLWhitespace ">")+1;
2075 if ((c == '\0') && (terminal != '>'))
2077 (void) ThrowMagickException(exception,GetMagickModule(),
2078 OptionWarning,"ParseError","missing >");
2079 utf8=DestroyString(utf8);
2080 return(&root->root);
2083 if (ParseCloseTag(root,tag,p,exception) != (XMLTreeInfo *) NULL)
2085 utf8=DestroyString(utf8);
2086 return(&root->root);
2089 if (isspace((int) ((unsigned char) *p)) != 0)
2090 p+=strspn(p,XMLWhitespace);
2093 if (strncmp(p,"!--",3) == 0)
2099 if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) ||
2100 ((*p == '\0') && (terminal != '>')))
2102 (void) ThrowMagickException(exception,GetMagickModule(),
2103 OptionWarning,"ParseError","unclosed <!--");
2104 utf8=DestroyString(utf8);
2105 return(&root->root);
2109 if (strncmp(p,"![CDATA[",8) == 0)
2115 if (p != (char *) NULL)
2118 ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c');
2122 (void) ThrowMagickException(exception,GetMagickModule(),
2123 OptionWarning,"ParseError","unclosed <![CDATA[");
2124 utf8=DestroyString(utf8);
2125 return(&root->root);
2129 if (strncmp(p,"!DOCTYPE",8) == 0)
2134 for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) ||
2135 ((l != 0) && ((*p != ']') ||
2136 (*(p+strspn(p+1,XMLWhitespace)+1) != '>'))));
2137 l=(ssize_t) ((*p == '[') ? 1 : l))
2138 p+=strcspn(p+1,"[]>")+1;
2139 if ((*p == '\0') && (terminal != '>'))
2141 (void) ThrowMagickException(exception,GetMagickModule(),
2142 OptionWarning,"ParseError","unclosed <!DOCTYPE");
2143 utf8=DestroyString(utf8);
2144 return(&root->root);
2147 tag=strchr(tag,'[')+1;
2150 status=ParseInternalDoctype(root,tag,(size_t) (p-tag),
2152 if (status == MagickFalse)
2154 utf8=DestroyString(utf8);
2155 return(&root->root);
2164 Processing instructions.
2169 if (p == (char *) NULL)
2172 } while ((*p != '\0') && (*p != '>'));
2173 if ((p == (char *) NULL) || ((*p == '\0') &&
2176 (void) ThrowMagickException(exception,GetMagickModule(),
2177 OptionWarning,"ParseError","unclosed <?");
2178 utf8=DestroyString(utf8);
2179 return(&root->root);
2181 ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2));
2185 (void) ThrowMagickException(exception,GetMagickModule(),
2186 OptionWarning,"ParseError","unexpected <");
2187 utf8=DestroyString(utf8);
2188 return(&root->root);
2190 if ((p == (char *) NULL) || (*p == '\0'))
2194 if ((*p != '\0') && (*p != '<'))
2197 Tag character content.
2199 while ((*p != '\0') && (*p != '<'))
2203 ParseCharacterContent(root,tag,(size_t) (p-tag),'&');
2209 utf8=DestroyString(utf8);
2210 if (root->node == (XMLTreeInfo *) NULL)
2211 return(&root->root);
2212 if (root->node->tag == (char *) NULL)
2214 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2215 "ParseError","root tag missing");
2216 return(&root->root);
2218 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2219 "ParseError","unclosed tag: '%s'",root->node->tag);
2220 return(&root->root);
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2228 % N e w X M L T r e e T a g %
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 % NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag.
2236 % The format of the NewXMLTreeTag method is:
2238 % XMLTreeInfo *NewXMLTreeTag(const char *tag)
2240 % A description of each parameter follows:
2245 MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag)
2248 *predefined_entities[NumberPredefinedEntities+1] =
2250 "lt;", "<", "gt;", ">", "quot;", """,
2251 "apos;", "'", "amp;", "&", (char *) NULL
2257 root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root));
2258 if (root == (XMLTreeRoot *) NULL)
2259 return((XMLTreeInfo *) NULL);
2260 (void) ResetMagickMemory(root,0,sizeof(*root));
2261 root->root.tag=(char *) NULL;
2262 if (tag != (char *) NULL)
2263 root->root.tag=ConstantString(tag);
2264 root->node=(&root->root);
2265 root->root.content=ConstantString("");
2266 root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities));
2267 if (root->entities == (char **) NULL)
2268 return((XMLTreeInfo *) NULL);
2269 (void) CopyMagickMemory(root->entities,predefined_entities,
2270 sizeof(predefined_entities));
2271 root->root.attributes=sentinel;
2272 root->attributes=(char ***) root->root.attributes;
2273 root->processing_instructions=(char ***) root->root.attributes;
2274 root->debug=IsEventLogging();
2275 root->signature=MagickSignature;
2276 return(&root->root);
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2284 % P r u n e T a g F r o m X M L T r e e %
2288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2290 % PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its
2293 % The format of the PruneTagFromXMLTree method is:
2295 % XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
2297 % A description of each parameter follows:
2299 % o xml_info: the xml info.
2302 MagickPrivate XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
2307 assert(xml_info != (XMLTreeInfo *) NULL);
2308 assert((xml_info->signature == MagickSignature) ||
2309 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2311 if (xml_info->next != (XMLTreeInfo *) NULL)
2312 xml_info->next->sibling=xml_info->sibling;
2313 if (xml_info->parent != (XMLTreeInfo *) NULL)
2315 node=xml_info->parent->child;
2316 if (node == xml_info)
2317 xml_info->parent->child=xml_info->ordered;
2320 while (node->ordered != xml_info)
2322 node->ordered=node->ordered->ordered;
2323 node=xml_info->parent->child;
2324 if (strcmp(node->tag,xml_info->tag) != 0)
2326 while (strcmp(node->sibling->tag,xml_info->tag) != 0)
2328 if (node->sibling != xml_info)
2331 node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ?
2332 xml_info->next : node->sibling->sibling;
2334 while ((node->next != (XMLTreeInfo *) NULL) &&
2335 (node->next != xml_info))
2337 if (node->next != (XMLTreeInfo *) NULL)
2338 node->next=node->next->next;
2341 xml_info->ordered=(XMLTreeInfo *) NULL;
2342 xml_info->sibling=(XMLTreeInfo *) NULL;
2343 xml_info->next=(XMLTreeInfo *) NULL;
2348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 % S e t X M L T r e e A t t r i b u t e %
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not
2359 % found. A value of NULL removes the specified attribute.
2361 % The format of the SetXMLTreeAttribute method is:
2363 % XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag,
2364 % const char *value)
2366 % A description of each parameter follows:
2368 % o xml_info: the xml info.
2370 % o tag: The attribute tag.
2372 % o value: The attribute value.
2375 MagickPrivate XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,
2376 const char *tag,const char *value)
2384 assert(xml_info != (XMLTreeInfo *) NULL);
2385 assert((xml_info->signature == MagickSignature) ||
2386 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2387 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2389 while ((xml_info->attributes[i] != (char *) NULL) &&
2390 (strcmp(xml_info->attributes[i],tag) != 0))
2392 if (xml_info->attributes[i] == (char *) NULL)
2395 Add new attribute tag.
2397 if (value == (const char *) NULL)
2399 if (xml_info->attributes != sentinel)
2400 xml_info->attributes=(char **) ResizeQuantumMemory(
2401 xml_info->attributes,(size_t) (i+4),sizeof(*xml_info->attributes));
2404 xml_info->attributes=(char **) AcquireQuantumMemory(4,
2405 sizeof(*xml_info->attributes));
2406 if (xml_info->attributes != (char **) NULL)
2407 xml_info->attributes[1]=ConstantString("");
2409 if (xml_info->attributes == (char **) NULL)
2410 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
2411 xml_info->attributes[i]=ConstantString(tag);
2412 xml_info->attributes[i+2]=(char *) NULL;
2413 (void) strlen(xml_info->attributes[i+1]);
2416 Add new value to an existing attribute.
2418 for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2) ;
2419 if (xml_info->attributes[i+1] != (char *) NULL)
2420 xml_info->attributes[i+1]=DestroyString(xml_info->attributes[i+1]);
2421 if (value != (const char *) NULL)
2423 xml_info->attributes[i+1]=ConstantString(value);
2426 if (xml_info->attributes[i] != (char *) NULL)
2427 xml_info->attributes[i]=DestroyString(xml_info->attributes[i]);
2428 (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2,
2429 (size_t) (j-i)*sizeof(*xml_info->attributes));
2430 xml_info->attributes=(char **) ResizeQuantumMemory(xml_info->attributes,
2431 (size_t) (j+2),sizeof(*xml_info->attributes));
2432 if (xml_info->attributes == (char **) NULL)
2433 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
2435 (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2),
2436 xml_info->attributes[j+1]+(i/2)+1,(size_t) (((j+2)/2)-(i/2))*
2437 sizeof(*xml_info->attributes));
2442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446 % S e t X M L T r e e C o n t e n t %
2450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452 % SetXMLTreeContent() sets the character content for the given tag and
2455 % The format of the SetXMLTreeContent method is:
2457 % XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
2458 % const char *content)
2460 % A description of each parameter follows:
2462 % o xml_info: the xml info.
2464 % o content: The content.
2467 MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
2468 const char *content)
2470 assert(xml_info != (XMLTreeInfo *) NULL);
2471 assert((xml_info->signature == MagickSignature) ||
2472 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2473 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2474 if (xml_info->content != (char *) NULL)
2475 xml_info->content=DestroyString(xml_info->content);
2476 xml_info->content=(char *) ConstantString(content);
2481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485 % X M L T r e e I n f o T o X M L %
2489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2491 % XMLTreeInfoToXML() converts an xml-tree to an XML string.
2493 % The format of the XMLTreeInfoToXML method is:
2495 % char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
2497 % A description of each parameter follows:
2499 % o xml_info: the xml info.
2503 static char *EncodePredefinedEntities(const char *source,ssize_t offset,
2504 char **destination,size_t *length,size_t *extent,MagickBooleanType pedantic)
2510 canonical_content=CanonicalXMLContent(source,pedantic);
2516 content=AcquireString(source);
2517 content[offset]='\0';
2518 canonical_content=CanonicalXMLContent(content,pedantic);
2519 content=DestroyString(content);
2521 if (canonical_content == (char *) NULL)
2522 return(*destination);
2523 if ((*length+strlen(canonical_content)+MaxTextExtent) > *extent)
2525 *extent=(*length)+strlen(canonical_content)+MaxTextExtent;
2526 *destination=(char *) ResizeQuantumMemory(*destination,*extent,
2527 sizeof(**destination));
2528 if (*destination == (char *) NULL)
2529 return(*destination);
2531 *length+=FormatLocaleString(*destination+(*length),*extent,"%s",
2533 canonical_content=DestroyString(canonical_content);
2534 return(*destination);
2537 static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length,
2538 size_t *extent,size_t start,char ***attributes)
2555 content=(char *) "";
2556 if (xml_info->parent != (XMLTreeInfo *) NULL)
2557 content=xml_info->parent->content;
2559 *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset-
2560 start),source,length,extent,MagickFalse);
2561 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
2563 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
2564 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2565 if (*source == (char *) NULL)
2568 *length+=FormatLocaleString(*source+(*length),*extent,"<%s",xml_info->tag);
2569 for (i=0; xml_info->attributes[i]; i+=2)
2571 attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]);
2572 if (attribute != xml_info->attributes[i+1])
2574 if ((*length+strlen(xml_info->attributes[i])+MaxTextExtent) > *extent)
2576 *extent=(*length)+strlen(xml_info->attributes[i])+MaxTextExtent;
2577 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2578 if (*source == (char *) NULL)
2579 return((char *) NULL);
2581 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
2582 xml_info->attributes[i]);
2583 (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length,
2585 *length+=FormatLocaleString(*source+(*length),*extent,"\"");
2588 while ((attributes[i] != (char **) NULL) &&
2589 (strcmp(attributes[i][0],xml_info->tag) != 0))
2592 while ((attributes[i] != (char **) NULL) &&
2593 (attributes[i][j] != (char *) NULL))
2595 if ((attributes[i][j+1] == (char *) NULL) ||
2596 (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1]))
2601 if ((*length+strlen(attributes[i][j])+MaxTextExtent) > *extent)
2603 *extent=(*length)+strlen(attributes[i][j])+MaxTextExtent;
2604 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2605 if (*source == (char *) NULL)
2606 return((char *) NULL);
2608 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
2610 (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent,
2612 *length+=FormatLocaleString(*source+(*length),*extent,"\"");
2615 *length+=FormatLocaleString(*source+(*length),*extent,*xml_info->content ?
2617 if (xml_info->child != (XMLTreeInfo *) NULL)
2618 *source=XMLTreeTagToXML(xml_info->child,source,length,extent,0,attributes);
2620 *source=EncodePredefinedEntities(xml_info->content,-1,source,length,extent,
2622 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
2624 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
2625 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2626 if (*source == (char *) NULL)
2627 return((char *) NULL);
2629 if (*xml_info->content != '\0')
2630 *length+=FormatLocaleString(*source+(*length),*extent,"</%s>",
2632 while ((content[offset] != '\0') && (offset < xml_info->offset))
2634 if (xml_info->ordered != (XMLTreeInfo *) NULL)
2635 content=XMLTreeTagToXML(xml_info->ordered,source,length,extent,offset,
2638 content=EncodePredefinedEntities(content+offset,-1,source,length,extent,
2643 MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
2670 assert(xml_info != (XMLTreeInfo *) NULL);
2671 assert((xml_info->signature == MagickSignature) ||
2672 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2674 if (xml_info->tag == (char *) NULL)
2675 return((char *) NULL);
2676 xml=AcquireString((char *) NULL);
2678 extent=MaxTextExtent;
2679 root=(XMLTreeRoot *) xml_info;
2680 while (root->root.parent != (XMLTreeInfo *) NULL)
2681 root=(XMLTreeRoot *) root->root.parent;
2682 parent=(XMLTreeInfo *) NULL;
2683 if (xml_info != (XMLTreeInfo *) NULL)
2684 parent=xml_info->parent;
2685 if (parent == (XMLTreeInfo *) NULL)
2686 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
2689 Pre-root processing instructions.
2691 for (k=2; root->processing_instructions[i][k-1]; k++) ;
2692 p=root->processing_instructions[i][1];
2693 for (j=1; p != (char *) NULL; j++)
2695 if (root->processing_instructions[i][k][j-1] == '>')
2697 p=root->processing_instructions[i][j];
2700 q=root->processing_instructions[i][0];
2701 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
2703 extent=length+strlen(p)+strlen(q)+MaxTextExtent;
2704 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
2705 if (xml == (char *) NULL)
2708 length+=FormatLocaleString(xml+length,extent,"<?%s%s%s?>\n",q,
2709 *p != '\0' ? " " : "",p);
2710 p=root->processing_instructions[i][j];
2713 ordered=(XMLTreeInfo *) NULL;
2714 if (xml_info != (XMLTreeInfo *) NULL)
2715 ordered=xml_info->ordered;
2716 xml_info->parent=(XMLTreeInfo *) NULL;
2717 xml_info->ordered=(XMLTreeInfo *) NULL;
2718 xml=XMLTreeTagToXML(xml_info,&xml,&length,&extent,0,root->attributes);
2719 xml_info->parent=parent;
2720 xml_info->ordered=ordered;
2721 if (parent == (XMLTreeInfo *) NULL)
2722 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
2725 Post-root processing instructions.
2727 for (k=2; root->processing_instructions[i][k-1]; k++) ;
2728 p=root->processing_instructions[i][1];
2729 for (j=1; p != (char *) NULL; j++)
2731 if (root->processing_instructions[i][k][j-1] == '<')
2733 p=root->processing_instructions[i][j];
2736 q=root->processing_instructions[i][0];
2737 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
2739 extent=length+strlen(p)+strlen(q)+MaxTextExtent;
2740 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
2741 if (xml == (char *) NULL)
2744 length+=FormatLocaleString(xml+length,extent,"\n<?%s%s%s?>",q,
2745 *p != '\0' ? " " : "",p);
2746 p=root->processing_instructions[i][j];
2749 return((char *) ResizeQuantumMemory(xml,length+1,sizeof(*xml)));