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