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 if (xml_info->debug != MagickFalse)
238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
240 components=GetPathComponents(path,&number_components);
241 if (components == (char **) NULL)
242 return((XMLTreeInfo *) NULL);
243 for (i=0; i < (ssize_t) number_components; i++)
245 GetPathComponent(components[i],SubimagePath,subnode);
246 GetPathComponent(components[i],CanonicalPath,tag);
247 child=GetXMLTreeChild(node,tag);
248 if (child == (XMLTreeInfo *) NULL)
249 child=AddChildToXMLTree(node,tag,offset);
251 if (node == (XMLTreeInfo *) NULL)
253 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
255 node=GetXMLTreeOrdered(node);
256 if (node == (XMLTreeInfo *) NULL)
259 if (node == (XMLTreeInfo *) NULL)
261 components[i]=DestroyString(components[i]);
263 for ( ; i < (ssize_t) number_components; i++)
264 components[i]=DestroyString(components[i]);
265 components=(char **) RelinquishMagickMemory(components);
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 % C a n o n i c a l X M L C o n t e n t %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % CanonicalXMLContent() converts text to canonical XML content by converting
281 % to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding
282 % as base-64 as required.
284 % The format of the CanonicalXMLContent method is:
287 % char *CanonicalXMLContent(const char *content,
288 % const MagickBooleanType pedantic)
290 % A description of each parameter follows:
292 % o content: the content.
294 % o pedantic: if true, replace newlines and tabs with their respective
298 MagickPrivate char *CanonicalXMLContent(const char *content,
299 const MagickBooleanType pedantic)
305 register const unsigned char
318 utf8=ConvertLatin1ToUTF8((const unsigned char *) content);
319 if (utf8 == (unsigned char *) NULL)
320 return((char *) NULL);
321 for (p=utf8; *p != '\0'; p++)
322 if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d))
327 String is binary, base64-encode it.
329 base64=Base64Encode(utf8,strlen((char *) utf8),&length);
330 utf8=(unsigned char *) RelinquishMagickMemory(utf8);
331 if (base64 == (char *) NULL)
332 return((char *) NULL);
333 canonical_content=AcquireString("<base64>");
334 (void) ConcatenateString(&canonical_content,base64);
335 base64=DestroyString(base64);
336 (void) ConcatenateString(&canonical_content,"</base64>");
337 return(canonical_content);
340 Substitute predefined entities.
343 canonical_content=AcquireString((char *) NULL);
344 extent=MaxTextExtent;
345 for (p=utf8; *p != '\0'; p++)
347 if ((i+MaxTextExtent) > (ssize_t) extent)
349 extent+=MaxTextExtent;
350 canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent,
351 sizeof(*canonical_content));
352 if (canonical_content == (char *) NULL)
353 return(canonical_content);
359 i+=FormatLocaleString(canonical_content+i,extent,"&");
364 i+=FormatLocaleString(canonical_content+i,extent,"<");
369 i+=FormatLocaleString(canonical_content+i,extent,">");
374 i+=FormatLocaleString(canonical_content+i,extent,""");
379 if (pedantic == MagickFalse)
381 canonical_content[i++]=(char) (*p);
384 i+=FormatLocaleString(canonical_content+i,extent,"
");
389 if (pedantic == MagickFalse)
391 canonical_content[i++]=(char) (*p);
394 i+=FormatLocaleString(canonical_content+i,extent,"	");
399 i+=FormatLocaleString(canonical_content+i,extent,"
");
404 canonical_content[i++]=(char) (*p);
409 canonical_content[i]='\0';
410 utf8=(unsigned char *) RelinquishMagickMemory(utf8);
411 return(canonical_content);
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 % D e s t r o y X M L T r e e %
423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 % DestroyXMLTree() destroys the xml-tree.
427 % The format of the DestroyXMLTree method is:
429 % XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
431 % A description of each parameter follows:
433 % o xml_info: the xml info.
437 static char **DestroyXMLTreeAttributes(char **attributes)
443 Destroy a tag attribute list.
445 if ((attributes == (char **) NULL) || (attributes == sentinel))
446 return((char **) NULL);
447 for (i=0; attributes[i] != (char *) NULL; i+=2)
450 Destroy attribute tag and value.
452 if (attributes[i] != (char *) NULL)
453 attributes[i]=DestroyString(attributes[i]);
454 if (attributes[i+1] != (char *) NULL)
455 attributes[i+1]=DestroyString(attributes[i+1]);
457 attributes=(char **) RelinquishMagickMemory(attributes);
458 return((char **) NULL);
461 static void DestroyXMLTreeChild(XMLTreeInfo *xml_info)
467 node=xml_info->child;
468 while(node != (XMLTreeInfo *) NULL)
470 prev=(XMLTreeInfo *) NULL;
471 while(node->child != (XMLTreeInfo *) NULL)
476 (void) DestroyXMLTree(node);
477 if (prev != (XMLTreeInfo* ) NULL)
478 prev->child=(XMLTreeInfo *) NULL;
481 xml_info->child=(XMLTreeInfo *) NULL;
484 static void DestroyXMLTreeOrdered(XMLTreeInfo *xml_info)
490 node=xml_info->ordered;
491 while(node != (XMLTreeInfo *) NULL)
493 prev=(XMLTreeInfo *) NULL;
494 while(node->ordered != (XMLTreeInfo *) NULL)
499 (void) DestroyXMLTree(node);
500 if (prev != (XMLTreeInfo* ) NULL)
501 prev->ordered=(XMLTreeInfo *) NULL;
504 xml_info->ordered=(XMLTreeInfo *) NULL;
507 static void DestroyXMLTreeRoot(XMLTreeInfo *xml_info)
521 assert(xml_info != (XMLTreeInfo *) NULL);
522 assert((xml_info->signature == MagickSignature) ||
523 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
524 if (xml_info->debug != MagickFalse)
525 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
526 if (xml_info->parent != (XMLTreeInfo *) NULL)
529 Free root tag allocations.
531 root=(XMLTreeRoot *) xml_info;
532 for (i=NumberPredefinedEntities; root->entities[i] != (char *) NULL; i+=2)
533 root->entities[i+1]=DestroyString(root->entities[i+1]);
534 root->entities=(char **) RelinquishMagickMemory(root->entities);
535 for (i=0; root->attributes[i] != (char **) NULL; i++)
537 attributes=root->attributes[i];
538 if (attributes[0] != (char *) NULL)
539 attributes[0]=DestroyString(attributes[0]);
540 for (j=1; attributes[j] != (char *) NULL; j+=3)
542 if (attributes[j] != (char *) NULL)
543 attributes[j]=DestroyString(attributes[j]);
544 if (attributes[j+1] != (char *) NULL)
545 attributes[j+1]=DestroyString(attributes[j+1]);
546 if (attributes[j+2] != (char *) NULL)
547 attributes[j+2]=DestroyString(attributes[j+2]);
549 attributes=(char **) RelinquishMagickMemory(attributes);
551 if (root->attributes[0] != (char **) NULL)
552 root->attributes=(char ***) RelinquishMagickMemory(root->attributes);
553 if (root->processing_instructions[0] != (char **) NULL)
555 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
557 for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++)
558 root->processing_instructions[i][j]=DestroyString(
559 root->processing_instructions[i][j]);
560 root->processing_instructions[i][j+1]=DestroyString(
561 root->processing_instructions[i][j+1]);
562 root->processing_instructions[i]=(char **) RelinquishMagickMemory(
563 root->processing_instructions[i]);
565 root->processing_instructions=(char ***) RelinquishMagickMemory(
566 root->processing_instructions);
570 MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
572 assert(xml_info != (XMLTreeInfo *) NULL);
573 assert((xml_info->signature == MagickSignature) ||
574 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
575 if (xml_info->debug != MagickFalse)
576 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
577 DestroyXMLTreeChild(xml_info);
578 DestroyXMLTreeOrdered(xml_info);
579 DestroyXMLTreeRoot(xml_info);
580 xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes);
581 xml_info->content=DestroyString(xml_info->content);
582 xml_info->tag=DestroyString(xml_info->tag);
583 xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info);
584 return((XMLTreeInfo *) NULL);
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 % F i l e T o X M L %
596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 % FileToXML() returns the contents of a file as a XML string.
600 % The format of the FileToXML method is:
602 % char *FileToXML(const char *filename,const size_t extent)
604 % A description of each parameter follows:
606 % o filename: the filename.
608 % o extent: Maximum length of the string.
612 static inline MagickSizeType MagickMin(const MagickSizeType x,
613 const MagickSizeType y)
620 MagickPrivate char *FileToXML(const char *filename,const size_t extent)
643 assert(filename != (const char *) NULL);
646 if (LocaleCompare(filename,"-") != 0)
647 file=open_utf8(filename,O_RDONLY | O_BINARY,0);
649 return((char *) NULL);
650 offset=(MagickOffsetType) lseek(file,0,SEEK_END);
652 if ((file == fileno(stdin)) || (offset < 0) ||
653 (offset != (MagickOffsetType) ((ssize_t) offset)))
662 Stream is not seekable.
664 offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
665 quantum=(size_t) MagickMaxBufferExtent;
666 if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0))
667 quantum=(size_t) MagickMin((MagickSizeType) file_stats.st_size,
668 MagickMaxBufferExtent);
669 xml=(char *) AcquireQuantumMemory(quantum,sizeof(*xml));
670 for (i=0; xml != (char *) NULL; i+=count)
672 count=read(file,xml+i,quantum);
679 if (~((size_t) i) < (quantum+1))
681 xml=(char *) RelinquishMagickMemory(xml);
684 xml=(char *) ResizeQuantumMemory(xml,i+quantum+1,sizeof(*xml));
685 if ((size_t) (i+count) >= extent)
688 if (LocaleCompare(filename,"-") != 0)
690 if (xml == (char *) NULL)
691 return((char *) NULL);
694 xml=(char *) RelinquishMagickMemory(xml);
695 return((char *) NULL);
697 length=(size_t) MagickMin(i+count,extent);
701 length=(size_t) MagickMin((MagickSizeType) offset,extent);
703 if (~length >= (MaxTextExtent-1))
704 xml=(char *) AcquireQuantumMemory(length+MaxTextExtent,sizeof(*xml));
705 if (xml == (char *) NULL)
708 return((char *) NULL);
710 map=MapBlob(file,ReadMode,0,length);
711 if (map != (char *) NULL)
713 (void) memcpy(xml,map,length);
714 (void) UnmapBlob(map,length);
718 (void) lseek(file,0,SEEK_SET);
719 for (i=0; i < length; i+=count)
721 count=read(file,xml+i,(size_t) MagickMin(length-i,(MagickSizeType)
733 xml=(char *) RelinquishMagickMemory(xml);
734 return((char *) NULL);
738 if (LocaleCompare(filename,"-") != 0)
741 xml=(char *) RelinquishMagickMemory(xml);
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 % G e t N e x t X M L T r e e T a g %
754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 % GetNextXMLTreeTag() returns the next tag or NULL if not found.
758 % The format of the GetNextXMLTreeTag method is:
760 % XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
762 % A description of each parameter follows:
764 % o xml_info: the xml info.
767 MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
769 assert(xml_info != (XMLTreeInfo *) NULL);
770 assert((xml_info->signature == MagickSignature) ||
771 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
772 if (xml_info->debug != MagickFalse)
773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
774 return(xml_info->next);
778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782 % G e t X M L T r e e A t t r i b u t e %
786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788 % GetXMLTreeAttribute() returns the value of the attribute tag with the
789 % specified tag if found, otherwise NULL.
791 % The format of the GetXMLTreeAttribute method is:
793 % const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag)
795 % A description of each parameter follows:
797 % o xml_info: the xml info.
799 % o tag: the attribute tag.
802 MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,
814 assert(xml_info != (XMLTreeInfo *) NULL);
815 assert((xml_info->signature == MagickSignature) ||
816 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
817 if (xml_info->debug != MagickFalse)
818 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
819 if (xml_info->attributes == (char **) NULL)
820 return((const char *) NULL);
822 while ((xml_info->attributes[i] != (char *) NULL) &&
823 (strcmp(xml_info->attributes[i],tag) != 0))
825 if (xml_info->attributes[i] != (char *) NULL)
826 return(xml_info->attributes[i+1]);
827 root=(XMLTreeRoot*) xml_info;
828 while (root->root.parent != (XMLTreeInfo *) NULL)
829 root=(XMLTreeRoot *) root->root.parent;
831 while ((root->attributes[i] != (char **) NULL) &&
832 (strcmp(root->attributes[i][0],xml_info->tag) != 0))
834 if (root->attributes[i] == (char **) NULL)
835 return((const char *) NULL);
837 while ((root->attributes[i][j] != (char *) NULL) &&
838 (strcmp(root->attributes[i][j],tag) != 0))
840 if (root->attributes[i][j] == (char *) NULL)
841 return((const char *) NULL);
842 return(root->attributes[i][j+1]);
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 % G e t X M L T r e e A t t r i b u t e s %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % GetXMLTreeAttributes() injects all attributes associated with the current
857 % tag in the specified splay-tree.
859 % The format of the GetXMLTreeAttributes method is:
861 % MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
862 % SplayTreeInfo *attributes)
864 % A description of each parameter follows:
866 % o xml_info: the xml info.
868 % o attributes: the attribute splay-tree.
871 MagickPrivate MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
872 SplayTreeInfo *attributes)
877 assert(xml_info != (XMLTreeInfo *) NULL);
878 assert((xml_info->signature == MagickSignature) ||
879 (((const XMLTreeRoot *) xml_info)->signature == MagickSignature));
880 if (xml_info->debug != MagickFalse)
881 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
882 assert(attributes != (SplayTreeInfo *) NULL);
883 if (xml_info->attributes == (char **) NULL)
886 while (xml_info->attributes[i] != (char *) NULL)
888 (void) AddValueToSplayTree(attributes,
889 ConstantString(xml_info->attributes[i]),
890 ConstantString(xml_info->attributes[i+1]));
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 % G e t X M L T r e e C h i l d %
905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907 % GetXMLTreeChild() returns the first child tag with the specified tag if
908 % found, otherwise NULL.
910 % The format of the GetXMLTreeChild method is:
912 % XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
914 % A description of each parameter follows:
916 % o xml_info: the xml info.
919 MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
924 assert(xml_info != (XMLTreeInfo *) NULL);
925 assert((xml_info->signature == MagickSignature) ||
926 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
927 if (xml_info->debug != MagickFalse)
928 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
929 child=xml_info->child;
930 if (tag != (const char *) NULL)
931 while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0))
932 child=child->sibling;
937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 % G e t X M L T r e e C o n t e n t %
945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947 % GetXMLTreeContent() returns any content associated with specified
950 % The format of the GetXMLTreeContent method is:
952 % const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
954 % A description of each parameter follows:
956 % o xml_info: the xml info.
959 MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
961 assert(xml_info != (XMLTreeInfo *) NULL);
962 assert((xml_info->signature == MagickSignature) ||
963 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
964 if (xml_info->debug != MagickFalse)
965 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
966 return(xml_info->content);
970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 % G e t X M L T r e e O r d e r e d %
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 % GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL.
982 % The format of the GetXMLTreeOrdered method is:
984 % XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
986 % A description of each parameter follows:
988 % o xml_info: the xml info.
991 MagickPrivate XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
993 assert(xml_info != (XMLTreeInfo *) NULL);
994 assert((xml_info->signature == MagickSignature) ||
995 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
996 if (xml_info->debug != MagickFalse)
997 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
998 return(xml_info->ordered);
1002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1006 % G e t X M L T r e e P a t h %
1010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 % GetXMLTreePath() traverses the XML-tree as defined by the specified path
1013 % and returns the node if found, otherwise NULL.
1015 % The format of the GetXMLTreePath method is:
1017 % XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
1019 % A description of each parameter follows:
1021 % o xml_info: the xml info.
1023 % o path: the path (e.g. property/elapsed-time).
1026 MagickPrivate XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
1030 subnode[MaxTextExtent],
1045 assert(xml_info != (XMLTreeInfo *) NULL);
1046 assert((xml_info->signature == MagickSignature) ||
1047 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1048 if (xml_info->debug != MagickFalse)
1049 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1051 components=GetPathComponents(path,&number_components);
1052 if (components == (char **) NULL)
1053 return((XMLTreeInfo *) NULL);
1054 for (i=0; i < (ssize_t) number_components; i++)
1056 GetPathComponent(components[i],SubimagePath,subnode);
1057 GetPathComponent(components[i],CanonicalPath,tag);
1058 node=GetXMLTreeChild(node,tag);
1059 if (node == (XMLTreeInfo *) NULL)
1061 for (j=(ssize_t) StringToLong(subnode)-1; j > 0; j--)
1063 node=GetXMLTreeOrdered(node);
1064 if (node == (XMLTreeInfo *) NULL)
1067 if (node == (XMLTreeInfo *) NULL)
1069 components[i]=DestroyString(components[i]);
1071 for ( ; i < (ssize_t) number_components; i++)
1072 components[i]=DestroyString(components[i]);
1073 components=(char **) RelinquishMagickMemory(components);
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082 % 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 %
1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088 % GetXMLTreeProcessingInstructions() returns a null terminated array of
1089 % processing instructions for the given target.
1091 % The format of the GetXMLTreeProcessingInstructions method is:
1093 % const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info,
1094 % const char *target)
1096 % A description of each parameter follows:
1098 % o xml_info: the xml info.
1101 MagickPrivate const char **GetXMLTreeProcessingInstructions(
1102 XMLTreeInfo *xml_info,const char *target)
1110 assert(xml_info != (XMLTreeInfo *) NULL);
1111 assert((xml_info->signature == MagickSignature) ||
1112 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1113 if (xml_info->debug != MagickFalse)
1114 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1115 root=(XMLTreeRoot *) xml_info;
1116 while (root->root.parent != (XMLTreeInfo *) NULL)
1117 root=(XMLTreeRoot *) root->root.parent;
1119 while ((root->processing_instructions[i] != (char **) NULL) &&
1120 (strcmp(root->processing_instructions[i][0],target) != 0))
1122 if (root->processing_instructions[i] == (char **) NULL)
1123 return((const char **) sentinel);
1124 return((const char **) (root->processing_instructions[i]+1));
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 % G e t X M L T r e e S i b l i n g %
1136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 % GetXMLTreeSibling() returns the node sibling if found, otherwise NULL.
1140 % The format of the GetXMLTreeSibling method is:
1142 % XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
1144 % A description of each parameter follows:
1146 % o xml_info: the xml info.
1149 MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
1151 assert(xml_info != (XMLTreeInfo *) NULL);
1152 assert((xml_info->signature == MagickSignature) ||
1153 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1154 if (xml_info->debug != MagickFalse)
1155 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1156 return(xml_info->sibling);
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 % G e t X M L T r e e T a g %
1168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170 % GetXMLTreeTag() returns the tag associated with specified xml-tree node.
1172 % The format of the GetXMLTreeTag method is:
1174 % const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
1176 % A description of each parameter follows:
1178 % o xml_info: the xml info.
1181 MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
1183 assert(xml_info != (XMLTreeInfo *) NULL);
1184 assert((xml_info->signature == MagickSignature) ||
1185 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
1186 if (xml_info->debug != MagickFalse)
1187 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1188 return(xml_info->tag);
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196 % I n s e r t I n t o T a g X M L T r e e %
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 % InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of
1203 % the parent tag's character content. This method returns the child tag.
1205 % The format of the InsertTagIntoXMLTree method is:
1207 % XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
1208 % XMLTreeInfo *child,const size_t offset)
1210 % A description of each parameter follows:
1212 % o xml_info: the xml info.
1214 % o child: the child tag.
1216 % o offset: the tag offset.
1219 MagickPrivate XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
1220 XMLTreeInfo *child,const size_t offset)
1227 child->ordered=(XMLTreeInfo *) NULL;
1228 child->sibling=(XMLTreeInfo *) NULL;
1229 child->next=(XMLTreeInfo *) NULL;
1230 child->offset=offset;
1231 child->parent=xml_info;
1232 if (xml_info->child == (XMLTreeInfo *) NULL)
1234 xml_info->child=child;
1237 head=xml_info->child;
1238 if (head->offset > offset)
1240 child->ordered=head;
1241 xml_info->child=child;
1246 while ((node->ordered != (XMLTreeInfo *) NULL) &&
1247 (node->ordered->offset <= offset))
1249 child->ordered=node->ordered;
1250 node->ordered=child;
1252 previous=(XMLTreeInfo *) NULL;
1254 while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0))
1259 if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
1261 while ((node->next != (XMLTreeInfo *) NULL) &&
1262 (node->next->offset <= offset))
1264 child->next=node->next;
1269 if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL))
1270 previous->sibling=node->sibling;
1272 previous=(XMLTreeInfo *) NULL;
1274 while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
1279 child->sibling=node;
1280 if (previous != (XMLTreeInfo *) NULL)
1281 previous->sibling=child;
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291 % N e w X M L T r e e %
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified
1300 % The format of the NewXMLTree method is:
1302 % XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
1304 % A description of each parameter follows:
1306 % o xml: The XML string.
1308 % o exception: return any errors or warnings in this structure.
1312 static char *ConvertUTF16ToUTF8(const char *content,size_t *length)
1332 utf8=(char *) AcquireQuantumMemory(*length,sizeof(*utf8));
1333 if (utf8 == (char *) NULL)
1334 return((char *) NULL);
1335 encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1;
1341 (void) CopyMagickMemory(utf8,content,*length*sizeof(*utf8));
1346 for (i=2; i < (ssize_t) (*length-1); i+=2)
1348 c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) :
1349 ((content[i+1] & 0xff) << 8) | (content[i] & 0xff);
1350 if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (ssize_t) (*length-1)))
1352 byte=(encoding != 0) ? ((content[i] & 0xff) << 8) |
1353 (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) |
1354 (content[i] & 0xff);
1355 c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000;
1357 if ((size_t) (j+MaxTextExtent) > extent)
1359 extent=(size_t) j+MaxTextExtent;
1360 utf8=(char *) ResizeQuantumMemory(utf8,extent,sizeof(*utf8));
1361 if (utf8 == (char *) NULL)
1371 Multi-byte UTF-8 sequence.
1374 for (bits=0; byte != 0; byte/=2)
1377 utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits));
1381 utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f);
1386 return((char *) ResizeQuantumMemory(utf8,*length,sizeof(*utf8)));
1389 static char *ParseEntities(char *xml,char **entities,int state)
1413 Normalize line endings.
1417 for ( ; *xml != '\0'; xml++)
1418 while (*xml == '\r')
1422 (void) CopyMagickMemory(xml,xml+1,strlen(xml));
1426 while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') ||
1427 (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0)))
1433 '&' for general entity decoding
1434 '%' for parameter entity decoding
1435 'c' for CDATA sections
1436 ' ' for attributes normalization
1437 '*' for non-CDATA attributes normalization
1439 if ((state != 'c') && (strncmp(xml,"&#",2) == 0))
1442 Character reference.
1445 c=strtol(xml+2,&entity,10); /* base 10 */
1447 c=strtol(xml+3,&entity,16); /* base 16 */
1448 if ((c == 0) || (*entity != ';'))
1451 Not a character reference.
1461 Multi-byte UTF-8 sequence.
1464 for (i=0; byte != 0; byte/=2)
1467 *xml=(char) ((0xFF << (7-i)) | (c >> (6*i)));
1472 *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F));
1476 (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';')));
1479 if (((*xml == '&') && ((state == '&') || (state == ' ') ||
1480 (state == '*'))) || ((state == '%') && (*xml == '%')))
1483 Find entity in the list.
1486 while ((entities[i] != (char *) NULL) &&
1487 (strncmp(xml+1,entities[i],strlen(entities[i])) != 0))
1489 if (entities[i++] == (char *) NULL)
1496 length=strlen(entities[i]);
1497 entity=strchr(xml,';');
1498 if ((length-1L) >= (size_t) (entity-xml))
1500 offset=(ssize_t) (xml-p);
1501 extent=(size_t) (offset+length+strlen(entity));
1503 p=(char *) ResizeQuantumMemory(p,extent,sizeof(*p));
1509 xml=(char *) AcquireQuantumMemory(extent,sizeof(*xml));
1510 if (xml != (char *) NULL)
1512 (void) CopyMagickString(xml,p,extent*sizeof(*xml));
1516 if (p == (char *) NULL)
1517 ThrowFatalException(ResourceLimitFatalError,
1518 "MemoryAllocationFailed");
1520 entity=strchr(xml,';');
1522 if (entity != (char *) NULL)
1523 (void) CopyMagickMemory(xml+length,entity+1,strlen(entity));
1524 (void) strncpy(xml,entities[i],length);
1528 if (((state == ' ') || (state == '*')) &&
1529 (isspace((int) ((unsigned char) *xml) != 0)))
1537 Normalize spaces for non-CDATA attributes.
1539 for (xml=p; *xml != '\0'; xml++)
1541 i=(ssize_t) strspn(xml," ");
1543 (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1);
1544 while ((*xml != '\0') && (*xml != ' '))
1548 if ((xml >= p) && (*xml == ' '))
1551 return(p == q ? ConstantString(p) : p);
1554 static void ParseCharacterContent(XMLTreeRoot *root,char *xml,
1555 const size_t length,const char state)
1560 xml_info=root->node;
1561 if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) ||
1565 xml=ParseEntities(xml,root->entities,state);
1566 if ((xml_info->content != (char *) NULL) && (*xml_info->content != '\0'))
1568 (void) ConcatenateString(&xml_info->content,xml);
1569 xml=DestroyString(xml);
1573 if (xml_info->content != (char *) NULL)
1574 xml_info->content=DestroyString(xml_info->content);
1575 xml_info->content=xml;
1579 static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag,
1580 ExceptionInfo *exception)
1582 if ((root->node == (XMLTreeInfo *) NULL) ||
1583 (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0))
1585 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1586 "ParseError","unexpected closing tag </%s>",tag);
1587 return(&root->root);
1589 root->node=root->node->parent;
1590 return((XMLTreeInfo *) NULL);
1593 static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities)
1599 Check for circular entity references.
1603 while ((*xml != '\0') && (*xml != '&'))
1607 if (strncmp(xml+1,tag,strlen(tag)) == 0)
1608 return(MagickFalse);
1610 while ((entities[i] != (char *) NULL) &&
1611 (strncmp(entities[i],xml+1,strlen(entities[i])) == 0))
1613 if ((entities[i] != (char *) NULL) &&
1614 (ValidateEntities(tag,entities[i+1],entities) == 0))
1615 return(MagickFalse);
1619 static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml,
1633 xml+=strcspn(xml,XMLWhitespace);
1637 xml+=strspn(xml+1,XMLWhitespace)+1;
1639 if (strcmp(target,"xml") == 0)
1641 xml=strstr(xml,"standalone");
1642 if ((xml != (char *) NULL) &&
1643 (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0))
1644 root->standalone=MagickTrue;
1647 if (root->processing_instructions[0] == (char **) NULL)
1649 root->processing_instructions=(char ***) AcquireMagickMemory(sizeof(
1650 *root->processing_instructions));
1651 if (root->processing_instructions ==(char ***) NULL)
1652 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1653 *root->processing_instructions=(char **) NULL;
1656 while ((root->processing_instructions[i] != (char **) NULL) &&
1657 (strcmp(target,root->processing_instructions[i][0]) != 0))
1659 if (root->processing_instructions[i] == (char **) NULL)
1661 root->processing_instructions=(char ***) ResizeQuantumMemory(
1662 root->processing_instructions,(size_t) (i+2),
1663 sizeof(*root->processing_instructions));
1664 if (root->processing_instructions == (char ***) NULL)
1665 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1666 root->processing_instructions[i]=(char **) AcquireQuantumMemory(3,
1667 sizeof(**root->processing_instructions));
1668 if (root->processing_instructions[i] == (char **) NULL)
1669 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1670 root->processing_instructions[i+1]=(char **) NULL;
1671 root->processing_instructions[i][0]=ConstantString(target);
1672 root->processing_instructions[i][1]=(char *)
1673 root->processing_instructions[i+1];
1674 root->processing_instructions[i+1]=(char **) NULL;
1675 root->processing_instructions[i][2]=ConstantString("");
1678 while (root->processing_instructions[i][j] != (char *) NULL)
1680 root->processing_instructions[i]=(char **) ResizeQuantumMemory(
1681 root->processing_instructions[i],(size_t) (j+3),
1682 sizeof(**root->processing_instructions));
1683 if (root->processing_instructions[i] == (char **) NULL)
1684 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1685 root->processing_instructions[i][j+2]=(char *) ResizeQuantumMemory(
1686 root->processing_instructions[i][j+1],(size_t) (j+1),
1687 sizeof(*root->processing_instructions));
1688 if (root->processing_instructions[i][j+2] == (char *) NULL)
1689 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1690 (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1,
1691 root->root.tag != (char *) NULL ? ">" : "<",2);
1692 root->processing_instructions[i][j]=ConstantString(xml);
1693 root->processing_instructions[i][j+1]=(char *) NULL;
1696 static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml,
1697 size_t length,ExceptionInfo *exception)
1703 **predefined_entitites,
1715 predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel));
1716 if (predefined_entitites == (char **) NULL)
1717 ThrowFatalException(ResourceLimitError,"MemoryAllocationFailed");
1718 (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel));
1719 for (xml[length]='\0'; xml != (char *) NULL; )
1721 while ((*xml != '\0') && (*xml != '<') && (*xml != '%'))
1725 if (strncmp(xml,"<!ENTITY",8) == 0)
1728 Parse entity definitions.
1730 xml+=strspn(xml+8,XMLWhitespace)+8;
1732 n=xml+strspn(xml,XMLWhitespace "%");
1733 xml=n+strcspn(n,XMLWhitespace);
1735 v=xml+strspn(xml+1,XMLWhitespace)+1;
1738 if ((q != '"') && (q != '\''))
1743 xml=strchr(xml,'>');
1746 entities=(*c == '%') ? predefined_entitites : root->entities;
1747 for (i=0; entities[i] != (char *) NULL; i++) ;
1748 entities=(char **) ResizeQuantumMemory(entities,(size_t) (i+3),
1750 if (entities == (char **) NULL)
1751 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1753 predefined_entitites=entities;
1755 root->entities=entities;
1759 if (xml != (char *) NULL)
1764 entities[i+1]=ParseEntities(v,predefined_entitites,'%');
1765 entities[i+2]=(char *) NULL;
1766 if (ValidateEntities(n,entities[i+1],entities) != MagickFalse)
1770 if (entities[i+1] != v)
1771 entities[i+1]=DestroyString(entities[i+1]);
1772 (void) ThrowMagickException(exception,GetMagickModule(),
1773 OptionWarning,"ParseError","circular entity declaration &%s",n);
1774 predefined_entitites=(char **) RelinquishMagickMemory(
1775 predefined_entitites);
1776 return(MagickFalse);
1780 if (strncmp(xml,"<!ATTLIST",9) == 0)
1783 Parse default attributes.
1785 t=xml+strspn(xml+9,XMLWhitespace)+9;
1788 (void) ThrowMagickException(exception,GetMagickModule(),
1789 OptionWarning,"ParseError","unclosed <!ATTLIST");
1790 predefined_entitites=(char **) RelinquishMagickMemory(
1791 predefined_entitites);
1792 return(MagickFalse);
1794 xml=t+strcspn(t,XMLWhitespace ">");
1799 while ((root->attributes[i] != (char **) NULL) &&
1800 (n != (char *) NULL) &&
1801 (strcmp(n,root->attributes[i][0]) != 0))
1803 while ((*(n=xml+strspn(xml+1,XMLWhitespace)+1) != '\0') &&
1806 xml=n+strcspn(n,XMLWhitespace);
1811 (void) ThrowMagickException(exception,GetMagickModule(),
1812 OptionWarning,"ParseError","malformed <!ATTLIST");
1813 predefined_entitites=(char **) RelinquishMagickMemory(
1814 predefined_entitites);
1815 return(MagickFalse);
1817 xml+=strspn(xml+1,XMLWhitespace)+1;
1818 c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " ");
1819 if (strncmp(xml,"NOTATION",8) == 0)
1820 xml+=strspn(xml+8,XMLWhitespace)+8;
1821 xml=(*xml == '(') ? strchr(xml,')') : xml+
1822 strcspn(xml,XMLWhitespace);
1823 if (xml == (char *) NULL)
1825 (void) ThrowMagickException(exception,GetMagickModule(),
1826 OptionWarning,"ParseError","malformed <!ATTLIST");
1827 predefined_entitites=(char **) RelinquishMagickMemory(
1828 predefined_entitites);
1829 return(MagickFalse);
1831 xml+=strspn(xml,XMLWhitespace ")");
1832 if (strncmp(xml,"#FIXED",6) == 0)
1833 xml+=strspn(xml+6,XMLWhitespace)+6;
1836 xml+=strcspn(xml,XMLWhitespace ">")-1;
1842 if (((*xml == '"') || (*xml == '\'')) &&
1843 ((xml=strchr(v=xml+1,*xml)) != (char *) NULL))
1847 (void) ThrowMagickException(exception,GetMagickModule(),
1848 OptionWarning,"ParseError","malformed <!ATTLIST");
1849 predefined_entitites=(char **) RelinquishMagickMemory(
1850 predefined_entitites);
1851 return(MagickFalse);
1853 if (root->attributes[i] == (char **) NULL)
1859 root->attributes=(char ***) AcquireQuantumMemory(2,
1860 sizeof(*root->attributes));
1862 root->attributes=(char ***) ResizeQuantumMemory(
1863 root->attributes,(size_t) (i+2),
1864 sizeof(*root->attributes));
1865 if (root->attributes == (char ***) NULL)
1866 ThrowFatalException(ResourceLimitFatalError,
1867 "MemoryAllocationFailed");
1868 root->attributes[i]=(char **) AcquireQuantumMemory(2,
1869 sizeof(*root->attributes));
1870 if (root->attributes[i] == (char **) NULL)
1871 ThrowFatalException(ResourceLimitFatalError,
1872 "MemoryAllocationFailed");
1873 root->attributes[i][0]=ConstantString(t);
1874 root->attributes[i][1]=(char *) NULL;
1875 root->attributes[i+1]=(char **) NULL;
1877 for (j=1; root->attributes[i][j] != (char *) NULL; j+=3) ;
1878 root->attributes[i]=(char **) ResizeQuantumMemory(
1879 root->attributes[i],(size_t) (j+4),sizeof(*root->attributes));
1880 if (root->attributes[i] == (char **) NULL)
1881 ThrowFatalException(ResourceLimitFatalError,
1882 "MemoryAllocationFailed");
1883 root->attributes[i][j+3]=(char *) NULL;
1884 root->attributes[i][j+2]=ConstantString(c);
1885 root->attributes[i][j+1]=(char *) NULL;
1886 if (v != (char *) NULL)
1887 root->attributes[i][j+1]=ParseEntities(v,root->entities,*c);
1888 root->attributes[i][j]=ConstantString(n);
1892 if (strncmp(xml, "<!--", 4) == 0)
1893 xml=strstr(xml+4,"-->");
1895 if (strncmp(xml,"<?", 2) == 0)
1899 if (xml != (char *) NULL)
1901 ParseProcessingInstructions(root,c,(size_t) (xml-c));
1907 xml=strchr(xml,'>');
1909 if ((*(xml++) == '%') && (root->standalone == MagickFalse))
1912 predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites);
1916 static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes)
1921 xml_info=root->node;
1922 if (xml_info->tag == (char *) NULL)
1923 xml_info->tag=ConstantString(tag);
1925 xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content));
1926 if (xml_info != (XMLTreeInfo *) NULL)
1927 xml_info->attributes=attributes;
1928 root->node=xml_info;
1939 static inline MagickBooleanType IsSkipTag(const char *tag)
1945 while (ignore_tags[i] != (const char *) NULL)
1947 if (LocaleCompare(tag,ignore_tags[i]) == 0)
1951 return(MagickFalse);
1954 MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
1987 Convert xml-string to UTF8.
1989 if ((xml == (const char *) NULL) || (strlen(xml) == 0))
1991 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1992 "ParseError","root tag missing");
1993 return((XMLTreeInfo *) NULL);
1995 root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL);
1997 utf8=ConvertUTF16ToUTF8(xml,&length);
1998 if (utf8 == (char *) NULL)
2000 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2001 "ParseError","UTF16 to UTF8 failed");
2002 return((XMLTreeInfo *) NULL);
2004 terminal=utf8[length-1];
2005 utf8[length-1]='\0';
2007 while ((*p != '\0') && (*p != '<'))
2011 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2012 "ParseError","root tag missing");
2013 utf8=DestroyString(utf8);
2014 return((XMLTreeInfo *) NULL);
2016 attribute=(char **) NULL;
2021 attributes=(char **) sentinel;
2024 if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') ||
2025 (*p == ':') || (c < '\0'))
2030 if (root->node == (XMLTreeInfo *) NULL)
2032 (void) ThrowMagickException(exception,GetMagickModule(),
2033 OptionWarning,"ParseError","root tag missing");
2034 utf8=DestroyString(utf8);
2035 return(&root->root);
2037 p+=strcspn(p,XMLWhitespace "/>");
2038 while (isspace((int) ((unsigned char) *p)) != 0)
2040 if (ignore_depth == 0)
2042 if ((*p != '\0') && (*p != '/') && (*p != '>'))
2045 Find tag in default attributes list.
2048 while ((root->attributes[i] != (char **) NULL) &&
2049 (strcmp(root->attributes[i][0],tag) != 0))
2051 attribute=root->attributes[i];
2053 for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2)
2059 attributes=(char **) AcquireQuantumMemory(4,
2060 sizeof(*attributes));
2062 attributes=(char **) ResizeQuantumMemory(attributes,
2063 (size_t) (l+4),sizeof(*attributes));
2064 if (attributes == (char **) NULL)
2066 (void) ThrowMagickException(exception,GetMagickModule(),
2067 ResourceLimitError,"MemoryAllocationFailed","`%s'","");
2068 utf8=DestroyString(utf8);
2069 return(&root->root);
2071 attributes[l+2]=(char *) NULL;
2072 attributes[l+1]=(char *) NULL;
2074 p+=strcspn(p,XMLWhitespace "=/>");
2075 if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0))
2076 attributes[l]=ConstantString("");
2080 p+=strspn(p,XMLWhitespace "=");
2082 if ((c == '"') || (c == '\''))
2089 while ((*p != '\0') && (*p != c))
2095 attributes[l]=ConstantString("");
2096 attributes[l+1]=ConstantString("");
2097 (void) DestroyXMLTreeAttributes(attributes);
2098 (void) ThrowMagickException(exception,
2099 GetMagickModule(),OptionWarning,"ParseError",
2101 utf8=DestroyString(utf8);
2102 return(&root->root);
2105 while ((attribute != (char **) NULL) &&
2106 (attribute[j] != (char *) NULL) &&
2107 (strcmp(attribute[j],attributes[l]) != 0))
2109 attributes[l+1]=ParseEntities(attributes[l+1],
2110 root->entities,(attribute != (char **) NULL) &&
2111 (attribute[j] != (char *) NULL) ? *attribute[j+2] :
2114 attributes[l]=ConstantString(attributes[l]);
2116 while (isspace((int) ((unsigned char) *p)) != 0)
2122 while((*p != '\0') && (*p != '/') && (*p != '>'))
2131 if (((*p != '\0') && (*p != '>')) ||
2132 ((*p == '\0') && (terminal != '>')))
2135 (void) DestroyXMLTreeAttributes(attributes);
2136 (void) ThrowMagickException(exception,GetMagickModule(),
2137 OptionWarning,"ParseError","missing >");
2138 utf8=DestroyString(utf8);
2139 return(&root->root);
2141 if ((ignore_depth == 0) && (IsSkipTag(tag) == MagickFalse))
2143 ParseOpenTag(root,tag,attributes);
2144 (void) ParseCloseTag(root,tag,exception);
2150 if ((*p == '>') || ((*p == '\0') && (terminal == '>')))
2153 if ((ignore_depth == 0) && (IsSkipTag(tag) == MagickFalse))
2154 ParseOpenTag(root,tag,attributes);
2162 (void) DestroyXMLTreeAttributes(attributes);
2163 (void) ThrowMagickException(exception,GetMagickModule(),
2164 OptionWarning,"ParseError","missing >");
2165 utf8=DestroyString(utf8);
2166 return(&root->root);
2177 p+=strcspn(tag,XMLWhitespace ">")+1;
2179 if ((c == '\0') && (terminal != '>'))
2181 (void) ThrowMagickException(exception,GetMagickModule(),
2182 OptionWarning,"ParseError","missing >");
2183 utf8=DestroyString(utf8);
2184 return(&root->root);
2187 if (ignore_depth == 0 && ParseCloseTag(root,tag,exception) !=
2188 (XMLTreeInfo *) NULL)
2190 utf8=DestroyString(utf8);
2191 return(&root->root);
2193 if (ignore_depth > 0)
2196 if (isspace((int) ((unsigned char) *p)) != 0)
2197 p+=strspn(p,XMLWhitespace);
2200 if (strncmp(p,"!--",3) == 0)
2206 if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) ||
2207 ((*p == '\0') && (terminal != '>')))
2209 (void) ThrowMagickException(exception,GetMagickModule(),
2210 OptionWarning,"ParseError","unclosed <!--");
2211 utf8=DestroyString(utf8);
2212 return(&root->root);
2216 if (strncmp(p,"![CDATA[",8) == 0)
2222 if (p != (char *) NULL)
2225 if (ignore_depth == 0)
2226 ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c');
2230 (void) ThrowMagickException(exception,GetMagickModule(),
2231 OptionWarning,"ParseError","unclosed <![CDATA[");
2232 utf8=DestroyString(utf8);
2233 return(&root->root);
2237 if (strncmp(p,"!DOCTYPE",8) == 0)
2242 for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) ||
2243 ((l != 0) && ((*p != ']') ||
2244 (*(p+strspn(p+1,XMLWhitespace)+1) != '>'))));
2245 l=(ssize_t) ((*p == '[') ? 1 : l))
2246 p+=strcspn(p+1,"[]>")+1;
2247 if ((*p == '\0') && (terminal != '>'))
2249 (void) ThrowMagickException(exception,GetMagickModule(),
2250 OptionWarning,"ParseError","unclosed <!DOCTYPE");
2251 utf8=DestroyString(utf8);
2252 return(&root->root);
2255 tag=strchr(tag,'[')+1;
2258 status=ParseInternalDoctype(root,tag,(size_t) (p-tag),
2260 if (status == MagickFalse)
2262 utf8=DestroyString(utf8);
2263 return(&root->root);
2272 Processing instructions.
2277 if (p == (char *) NULL)
2280 } while ((*p != '\0') && (*p != '>'));
2281 if ((p == (char *) NULL) || ((*p == '\0') &&
2284 (void) ThrowMagickException(exception,GetMagickModule(),
2285 OptionWarning,"ParseError","unclosed <?");
2286 utf8=DestroyString(utf8);
2287 return(&root->root);
2289 ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2));
2293 (void) ThrowMagickException(exception,GetMagickModule(),
2294 OptionWarning,"ParseError","unexpected <");
2295 utf8=DestroyString(utf8);
2296 return(&root->root);
2298 if ((p == (char *) NULL) || (*p == '\0'))
2302 if ((*p != '\0') && (*p != '<'))
2305 Tag character content.
2307 while ((*p != '\0') && (*p != '<'))
2311 if (ignore_depth == 0)
2312 ParseCharacterContent(root,tag,(size_t) (p-tag),'&');
2318 utf8=DestroyString(utf8);
2319 if (root->node == (XMLTreeInfo *) NULL)
2320 return(&root->root);
2321 if (root->node->tag == (char *) NULL)
2323 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2324 "ParseError","root tag missing");
2325 return(&root->root);
2327 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
2328 "ParseError","unclosed tag: '%s'",root->node->tag);
2329 return(&root->root);
2333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 % N e w X M L T r e e T a g %
2341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 % NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag.
2345 % The format of the NewXMLTreeTag method is:
2347 % XMLTreeInfo *NewXMLTreeTag(const char *tag)
2349 % A description of each parameter follows:
2354 MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag)
2357 *predefined_entities[NumberPredefinedEntities+1] =
2359 "lt;", "<", "gt;", ">", "quot;", """,
2360 "apos;", "'", "amp;", "&", (char *) NULL
2366 root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root));
2367 if (root == (XMLTreeRoot *) NULL)
2368 return((XMLTreeInfo *) NULL);
2369 (void) ResetMagickMemory(root,0,sizeof(*root));
2370 root->root.tag=(char *) NULL;
2371 if (tag != (char *) NULL)
2372 root->root.tag=ConstantString(tag);
2373 root->node=(&root->root);
2374 root->root.content=ConstantString("");
2375 root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities));
2376 if (root->entities == (char **) NULL)
2377 return((XMLTreeInfo *) NULL);
2378 (void) CopyMagickMemory(root->entities,predefined_entities,
2379 sizeof(predefined_entities));
2380 root->root.attributes=sentinel;
2381 root->attributes=(char ***) root->root.attributes;
2382 root->processing_instructions=(char ***) root->root.attributes;
2383 root->debug=IsEventLogging();
2384 root->signature=MagickSignature;
2385 return(&root->root);
2389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393 % P r u n e T a g F r o m X M L T r e e %
2397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399 % PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its
2402 % The format of the PruneTagFromXMLTree method is:
2404 % XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
2406 % A description of each parameter follows:
2408 % o xml_info: the xml info.
2411 MagickPrivate XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
2416 assert(xml_info != (XMLTreeInfo *) NULL);
2417 assert((xml_info->signature == MagickSignature) ||
2418 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2419 if (xml_info->debug != MagickFalse)
2420 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2421 if (xml_info->next != (XMLTreeInfo *) NULL)
2422 xml_info->next->sibling=xml_info->sibling;
2423 if (xml_info->parent != (XMLTreeInfo *) NULL)
2425 node=xml_info->parent->child;
2426 if (node == xml_info)
2427 xml_info->parent->child=xml_info->ordered;
2430 while (node->ordered != xml_info)
2432 node->ordered=node->ordered->ordered;
2433 node=xml_info->parent->child;
2434 if (strcmp(node->tag,xml_info->tag) != 0)
2436 while (strcmp(node->sibling->tag,xml_info->tag) != 0)
2438 if (node->sibling != xml_info)
2441 node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ?
2442 xml_info->next : node->sibling->sibling;
2444 while ((node->next != (XMLTreeInfo *) NULL) &&
2445 (node->next != xml_info))
2447 if (node->next != (XMLTreeInfo *) NULL)
2448 node->next=node->next->next;
2451 xml_info->ordered=(XMLTreeInfo *) NULL;
2452 xml_info->sibling=(XMLTreeInfo *) NULL;
2453 xml_info->next=(XMLTreeInfo *) NULL;
2458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462 % S e t X M L T r e e A t t r i b u t e %
2466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468 % SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not
2469 % found. A value of NULL removes the specified attribute.
2471 % The format of the SetXMLTreeAttribute method is:
2473 % XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag,
2474 % const char *value)
2476 % A description of each parameter follows:
2478 % o xml_info: the xml info.
2480 % o tag: The attribute tag.
2482 % o value: The attribute value.
2485 MagickPrivate XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,
2486 const char *tag,const char *value)
2494 assert(xml_info != (XMLTreeInfo *) NULL);
2495 assert((xml_info->signature == MagickSignature) ||
2496 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2497 if (xml_info->debug != MagickFalse)
2498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2500 while ((xml_info->attributes[i] != (char *) NULL) &&
2501 (strcmp(xml_info->attributes[i],tag) != 0))
2503 if (xml_info->attributes[i] == (char *) NULL)
2506 Add new attribute tag.
2508 if (value == (const char *) NULL)
2510 if (xml_info->attributes != sentinel)
2511 xml_info->attributes=(char **) ResizeQuantumMemory(
2512 xml_info->attributes,(size_t) (i+4),sizeof(*xml_info->attributes));
2515 xml_info->attributes=(char **) AcquireQuantumMemory(4,
2516 sizeof(*xml_info->attributes));
2517 if (xml_info->attributes != (char **) NULL)
2518 xml_info->attributes[1]=ConstantString("");
2520 if (xml_info->attributes == (char **) NULL)
2521 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
2522 xml_info->attributes[i]=ConstantString(tag);
2523 xml_info->attributes[i+2]=(char *) NULL;
2524 (void) strlen(xml_info->attributes[i+1]);
2527 Add new value to an existing attribute.
2529 for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2) ;
2530 if (xml_info->attributes[i+1] != (char *) NULL)
2531 xml_info->attributes[i+1]=DestroyString(xml_info->attributes[i+1]);
2532 if (value != (const char *) NULL)
2534 xml_info->attributes[i+1]=ConstantString(value);
2537 if (xml_info->attributes[i] != (char *) NULL)
2538 xml_info->attributes[i]=DestroyString(xml_info->attributes[i]);
2539 (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2,
2540 (size_t) (j-i)*sizeof(*xml_info->attributes));
2541 xml_info->attributes=(char **) ResizeQuantumMemory(xml_info->attributes,
2542 (size_t) (j+2),sizeof(*xml_info->attributes));
2543 if (xml_info->attributes == (char **) NULL)
2544 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
2546 (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2),
2547 xml_info->attributes[j+1]+(i/2)+1,(size_t) (((j+2)/2)-(i/2))*
2548 sizeof(**xml_info->attributes));
2553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557 % S e t X M L T r e e C o n t e n t %
2561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563 % SetXMLTreeContent() sets the character content for the given tag and
2566 % The format of the SetXMLTreeContent method is:
2568 % XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
2569 % const char *content)
2571 % A description of each parameter follows:
2573 % o xml_info: the xml info.
2575 % o content: The content.
2578 MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
2579 const char *content)
2581 assert(xml_info != (XMLTreeInfo *) NULL);
2582 assert((xml_info->signature == MagickSignature) ||
2583 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2584 if (xml_info->debug != MagickFalse)
2585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2586 if (xml_info->content != (char *) NULL)
2587 xml_info->content=DestroyString(xml_info->content);
2588 xml_info->content=(char *) ConstantString(content);
2593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597 % X M L T r e e I n f o T o X M L %
2601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2603 % XMLTreeInfoToXML() converts an xml-tree to an XML string.
2605 % The format of the XMLTreeInfoToXML method is:
2607 % char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
2609 % A description of each parameter follows:
2611 % o xml_info: the xml info.
2615 static char *EncodePredefinedEntities(const char *source,ssize_t offset,
2616 char **destination,size_t *length,size_t *extent,MagickBooleanType pedantic)
2622 canonical_content=CanonicalXMLContent(source,pedantic);
2628 content=AcquireString(source);
2629 content[offset]='\0';
2630 canonical_content=CanonicalXMLContent(content,pedantic);
2631 content=DestroyString(content);
2633 if (canonical_content == (char *) NULL)
2634 return(*destination);
2635 if ((*length+strlen(canonical_content)+MaxTextExtent) > *extent)
2637 *extent=(*length)+strlen(canonical_content)+MaxTextExtent;
2638 *destination=(char *) ResizeQuantumMemory(*destination,*extent,
2639 sizeof(**destination));
2640 if (*destination == (char *) NULL)
2641 return(*destination);
2643 *length+=FormatLocaleString(*destination+(*length),*extent,"%s",
2645 canonical_content=DestroyString(canonical_content);
2646 return(*destination);
2649 static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length,
2650 size_t *extent,size_t start,char ***attributes)
2667 content=(char *) "";
2668 if (xml_info->parent != (XMLTreeInfo *) NULL)
2669 content=xml_info->parent->content;
2671 *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset-
2672 start),source,length,extent,MagickFalse);
2673 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
2675 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
2676 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2677 if (*source == (char *) NULL)
2680 *length+=FormatLocaleString(*source+(*length),*extent,"<%s",xml_info->tag);
2681 for (i=0; xml_info->attributes[i]; i+=2)
2683 attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]);
2684 if (attribute != xml_info->attributes[i+1])
2686 if ((*length+strlen(xml_info->attributes[i])+MaxTextExtent) > *extent)
2688 *extent=(*length)+strlen(xml_info->attributes[i])+MaxTextExtent;
2689 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2690 if (*source == (char *) NULL)
2691 return((char *) NULL);
2693 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
2694 xml_info->attributes[i]);
2695 (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length,
2697 *length+=FormatLocaleString(*source+(*length),*extent,"\"");
2700 while ((attributes[i] != (char **) NULL) &&
2701 (strcmp(attributes[i][0],xml_info->tag) != 0))
2704 while ((attributes[i] != (char **) NULL) &&
2705 (attributes[i][j] != (char *) NULL))
2707 if ((attributes[i][j+1] == (char *) NULL) ||
2708 (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1]))
2713 if ((*length+strlen(attributes[i][j])+MaxTextExtent) > *extent)
2715 *extent=(*length)+strlen(attributes[i][j])+MaxTextExtent;
2716 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2717 if (*source == (char *) NULL)
2718 return((char *) NULL);
2720 *length+=FormatLocaleString(*source+(*length),*extent," %s=\"",
2722 (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,extent,
2724 *length+=FormatLocaleString(*source+(*length),*extent,"\"");
2727 *length+=FormatLocaleString(*source+(*length),*extent,*xml_info->content ?
2729 if (xml_info->child != (XMLTreeInfo *) NULL)
2730 *source=XMLTreeTagToXML(xml_info->child,source,length,extent,0,attributes);
2732 *source=EncodePredefinedEntities(xml_info->content,-1,source,length,extent,
2734 if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *extent)
2736 *extent=(*length)+strlen(xml_info->tag)+MaxTextExtent;
2737 *source=(char *) ResizeQuantumMemory(*source,*extent,sizeof(**source));
2738 if (*source == (char *) NULL)
2739 return((char *) NULL);
2741 if (*xml_info->content != '\0')
2742 *length+=FormatLocaleString(*source+(*length),*extent,"</%s>",
2744 while ((content[offset] != '\0') && (offset < xml_info->offset))
2746 if (xml_info->ordered != (XMLTreeInfo *) NULL)
2747 content=XMLTreeTagToXML(xml_info->ordered,source,length,extent,offset,
2750 content=EncodePredefinedEntities(content+offset,-1,source,length,extent,
2755 MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
2782 assert(xml_info != (XMLTreeInfo *) NULL);
2783 assert((xml_info->signature == MagickSignature) ||
2784 (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
2785 if (xml_info->debug != MagickFalse)
2786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2787 if (xml_info->tag == (char *) NULL)
2788 return((char *) NULL);
2789 xml=AcquireString((char *) NULL);
2791 extent=MaxTextExtent;
2792 root=(XMLTreeRoot *) xml_info;
2793 while (root->root.parent != (XMLTreeInfo *) NULL)
2794 root=(XMLTreeRoot *) root->root.parent;
2795 parent=(XMLTreeInfo *) NULL;
2796 if (xml_info != (XMLTreeInfo *) NULL)
2797 parent=xml_info->parent;
2798 if (parent == (XMLTreeInfo *) NULL)
2799 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
2802 Pre-root processing instructions.
2804 for (k=2; root->processing_instructions[i][k-1]; k++) ;
2805 p=root->processing_instructions[i][1];
2806 for (j=1; p != (char *) NULL; j++)
2808 if (root->processing_instructions[i][k][j-1] == '>')
2810 p=root->processing_instructions[i][j];
2813 q=root->processing_instructions[i][0];
2814 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
2816 extent=length+strlen(p)+strlen(q)+MaxTextExtent;
2817 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
2818 if (xml == (char *) NULL)
2821 length+=FormatLocaleString(xml+length,extent,"<?%s%s%s?>\n",q,
2822 *p != '\0' ? " " : "",p);
2823 p=root->processing_instructions[i][j];
2826 ordered=(XMLTreeInfo *) NULL;
2827 if (xml_info != (XMLTreeInfo *) NULL)
2828 ordered=xml_info->ordered;
2829 xml_info->parent=(XMLTreeInfo *) NULL;
2830 xml_info->ordered=(XMLTreeInfo *) NULL;
2831 xml=XMLTreeTagToXML(xml_info,&xml,&length,&extent,0,root->attributes);
2832 xml_info->parent=parent;
2833 xml_info->ordered=ordered;
2834 if (parent == (XMLTreeInfo *) NULL)
2835 for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
2838 Post-root processing instructions.
2840 for (k=2; root->processing_instructions[i][k-1]; k++) ;
2841 p=root->processing_instructions[i][1];
2842 for (j=1; p != (char *) NULL; j++)
2844 if (root->processing_instructions[i][k][j-1] == '<')
2846 p=root->processing_instructions[i][j];
2849 q=root->processing_instructions[i][0];
2850 if ((length+strlen(p)+strlen(q)+MaxTextExtent) > extent)
2852 extent=length+strlen(p)+strlen(q)+MaxTextExtent;
2853 xml=(char *) ResizeQuantumMemory(xml,extent,sizeof(*xml));
2854 if (xml == (char *) NULL)
2857 length+=FormatLocaleString(xml+length,extent,"\n<?%s%s%s?>",q,
2858 *p != '\0' ? " " : "",p);
2859 p=root->processing_instructions[i][j];
2862 return((char *) ResizeQuantumMemory(xml,length+1,sizeof(*xml)));