xml-tree.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                             X   X  M   M  L                                 %
00007 %                              X X   MM MM  L                                 %
00008 %                               X    M M M  L                                 %
00009 %                              X X   M   M  L                                 %
00010 %                             X   X  M   M  LLLLL                             %
00011 %                                                                             %
00012 %                         TTTTT  RRRR   EEEEE  EEEEE                          %
00013 %                           T    R   R  E      E                              %
00014 %                           T    RRRR   EEE    EEE                            %
00015 %                           T    R R    E      E                              %
00016 %                           T    R  R   EEEEE  EEEEE                          %
00017 %                                                                             %
00018 %                                                                             %
00019 %                              XML Tree Methods                               %
00020 %                                                                             %
00021 %                              Software Design                                %
00022 %                                John Cristy                                  %
00023 %                               December 2004                                 %
00024 %                                                                             %
00025 %                                                                             %
00026 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00027 %  dedicated to making software imaging solutions freely available.           %
00028 %                                                                             %
00029 %  You may not use this file except in compliance with the License.  You may  %
00030 %  obtain a copy of the License at                                            %
00031 %                                                                             %
00032 %    http://www.imagemagick.org/script/license.php                            %
00033 %                                                                             %
00034 %  Unless required by applicable law or agreed to in writing, software        %
00035 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00036 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00037 %  See the License for the specific language governing permissions and        %
00038 %  limitations under the License.                                             %
00039 %                                                                             %
00040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00041 %
00042 %  This module implements the standard handy xml-tree methods for storing and
00043 %  retrieving nodes and attributes from an XML string.
00044 %
00045 */
00046 
00047 /*
00048   Include declarations.
00049 */
00050 #include "magick/studio.h"
00051 #include "magick/blob.h"
00052 #include "magick/exception.h"
00053 #include "magick/exception-private.h"
00054 #include "magick/log.h"
00055 #include "magick/memory_.h"
00056 #include "magick/semaphore.h"
00057 #include "magick/string_.h"
00058 #include "magick/xml-tree.h"
00059 #include "magick/utility.h"
00060 
00061 /*
00062   Define declarations.
00063 */
00064 #define NumberPredefinedEntities  10
00065 #define XMLWhitespace "\t\r\n "
00066 
00067 /*
00068   Typedef declarations.
00069 */
00070 struct _XMLTreeInfo
00071 {
00072   char
00073     *tag,
00074     **attributes,
00075     *content;
00076 
00077   size_t
00078     offset;
00079 
00080   XMLTreeInfo
00081     *parent,
00082     *next,
00083     *sibling,
00084     *ordered,
00085     *child;
00086 
00087   MagickBooleanType
00088     debug;
00089 
00090   SemaphoreInfo
00091     *semaphore;
00092 
00093   unsigned long
00094     signature;
00095 };
00096 
00097 typedef struct _XMLTreeRoot
00098   XMLTreeRoot;
00099 
00100 struct _XMLTreeRoot
00101 {
00102   struct _XMLTreeInfo
00103     root;
00104 
00105   XMLTreeInfo
00106     *node;
00107 
00108   MagickBooleanType
00109     standalone;
00110 
00111   char
00112     ***processing_instructions,
00113     **entities,
00114     ***attributes;
00115 
00116   MagickBooleanType
00117     debug;
00118 
00119   SemaphoreInfo
00120     *semaphore;
00121 
00122   unsigned long
00123     signature;
00124 };
00125 
00126 /*
00127   Global declarations.
00128 */
00129 static char
00130   *sentinel[] = { (char *) NULL };
00131 
00132 /*
00133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00134 %                                                                             %
00135 %                                                                             %
00136 %                                                                             %
00137 %   A d d C h i l d T o X M L T r e e                                         %
00138 %                                                                             %
00139 %                                                                             %
00140 %                                                                             %
00141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00142 %
00143 %  AddChildToXMLTree() adds a child tag at an offset relative to the start of
00144 %  the parent tag's character content.  Return the child tag.
00145 %
00146 %  The format of the AddChildToXMLTree method is:
00147 %
00148 %      XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag,
00149 %        const size_t offset)
00150 %
00151 %  A description of each parameter follows:
00152 %
00153 %    o xml_info: the xml info.
00154 %
00155 %    o tag: the tag.
00156 %
00157 %    o offset: the tag offset.
00158 %
00159 */
00160 MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,
00161   const char *tag,const size_t offset)
00162 {
00163   XMLTreeInfo
00164     *child;
00165 
00166   if (xml_info == (XMLTreeInfo *) NULL)
00167     return((XMLTreeInfo *) NULL);
00168   child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child));
00169   if (child == (XMLTreeInfo *) NULL)
00170     return((XMLTreeInfo *) NULL);
00171   (void) ResetMagickMemory(child,0,sizeof(*child));
00172   child->tag=ConstantString(tag);
00173   child->attributes=sentinel;
00174   child->content=ConstantString("");
00175   child->debug=IsEventLogging();
00176   child->signature=MagickSignature;
00177   return(InsertTagIntoXMLTree(xml_info,child,offset));
00178 }
00179 
00180 /*
00181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00182 %                                                                             %
00183 %                                                                             %
00184 %                                                                             %
00185 %   A d d P a t h T o X M L T r e e                                           %
00186 %                                                                             %
00187 %                                                                             %
00188 %                                                                             %
00189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00190 %
00191 %  AddPathToXMLTree() adds a child tag at an offset relative to the start of
00192 %  the parent tag's character content.  This method returns the child tag.
00193 %
00194 %  The format of the AddPathToXMLTree method is:
00195 %
00196 %      XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path,
00197 %        const size_t offset)
00198 %
00199 %  A description of each parameter follows:
00200 %
00201 %    o xml_info: the xml info.
00202 %
00203 %    o path: the path.
00204 %
00205 %    o offset: the tag offset.
00206 %
00207 */
00208 MagickExport XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,
00209   const char *path,const size_t offset)
00210 {
00211   char
00212     **components,
00213     subnode[MaxTextExtent],
00214     tag[MaxTextExtent];
00215 
00216   long
00217     j;
00218 
00219   register long
00220     i;
00221 
00222   XMLTreeInfo
00223     *child,
00224     *node;
00225 
00226   unsigned long
00227     number_components;
00228 
00229   assert(xml_info != (XMLTreeInfo *) NULL);
00230   assert((xml_info->signature == MagickSignature) ||
00231          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00232   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00233   node=xml_info;
00234   components=GetPathComponents(path,&number_components);
00235   if (components == (char **) NULL)
00236     return((XMLTreeInfo *) NULL);
00237   for (i=0; i < (long) number_components; i++)
00238   {
00239     GetPathComponent(components[i],SubimagePath,subnode);
00240     GetPathComponent(components[i],CanonicalPath,tag);
00241     child=GetXMLTreeChild(node,tag);
00242     if (child == (XMLTreeInfo *) NULL)
00243       child=AddChildToXMLTree(node,tag,offset);
00244     node=child;
00245     if (node == (XMLTreeInfo *) NULL)
00246       break;
00247     for (j=atol(subnode)-1; j > 0; j--)
00248     {
00249       node=GetXMLTreeOrdered(node);
00250       if (node == (XMLTreeInfo *) NULL)
00251         break;
00252     }
00253     if (node == (XMLTreeInfo *) NULL)
00254       break;
00255     components[i]=DestroyString(components[i]);
00256   }
00257   for ( ; i < (long) number_components; i++)
00258     components[i]=DestroyString(components[i]);
00259   components=(char **) RelinquishMagickMemory(components);
00260   return(node);
00261 }
00262 
00263 /*
00264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00265 %                                                                             %
00266 %                                                                             %
00267 %                                                                             %
00268 %   C a n o n i c a l X M L C o n t e n t                                     %
00269 %                                                                             %
00270 %                                                                             %
00271 %                                                                             %
00272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00273 %
00274 %  CanonicalXMLContent() converts text to canonical XML content by converting
00275 %  to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding
00276 %  as base-64 as required.
00277 %
00278 %  The format of the CanonicalXMLContent method is:
00279 %
00280 %
00281 %      char *CanonicalXMLContent(const char *content,
00282 %        const MagickBooleanType pedantic)
00283 %
00284 %  A description of each parameter follows:
00285 %
00286 %    o content: the content.
00287 %
00288 %    o pedantic: if true, replace newlines and tabs with their respective
00289 %      entities.
00290 %
00291 */
00292 
00293 static unsigned char *ConvertLatin1ToUTF8(const unsigned char *content)
00294 {
00295   register const unsigned char
00296     *p;
00297 
00298   register unsigned char
00299     *q;
00300 
00301   size_t
00302     length;
00303 
00304   unsigned char
00305     *utf8;
00306 
00307   unsigned int
00308     c;
00309 
00310   length=0;
00311   for (p=content; *p != '\0'; p++)
00312     length+=(*p & 0x80) != 0 ? 2 : 1;
00313   utf8=(unsigned char *) NULL;
00314   if (~length >= 1)
00315     utf8=(unsigned char *) AcquireQuantumMemory(length+1UL,sizeof(*utf8));
00316   if (utf8 == (unsigned char *) NULL)
00317     return((unsigned char *) NULL);
00318   q=utf8;
00319   for (p=content; *p != '\0'; p++)
00320   {
00321     c=(*p);
00322     if ((c & 0x80) == 0)
00323       *q++=c;
00324     else
00325       {
00326         *q++=0xc0 | ((c >> 6) & 0x3f);
00327         *q++=0x80 | (c & 0x3f);
00328       }
00329   }
00330   *q='\0';
00331   return(utf8);
00332 }
00333 
00334 MagickExport char *CanonicalXMLContent(const char *content,
00335   const MagickBooleanType pedantic)
00336 {
00337   char
00338     *base64,
00339     *canonical_content;
00340 
00341   register const unsigned char
00342     *p;
00343 
00344   register long
00345     i;
00346 
00347   size_t
00348     extent,
00349     length;
00350 
00351   unsigned char
00352     *utf8;
00353 
00354   utf8=ConvertLatin1ToUTF8((const unsigned char *) content);
00355   if (utf8 == (unsigned char *) NULL)
00356     return((char *) NULL);
00357   for (p=utf8; *p != '\0'; p++)
00358     if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d))
00359       break;
00360   if (*p != '\0')
00361     {
00362       /*
00363         String is binary, base64-encode it.
00364       */
00365       base64=Base64Encode(utf8,strlen((char *) utf8),&length);
00366       utf8=(unsigned char *) RelinquishMagickMemory(utf8);
00367       if (base64 == (char *) NULL)
00368         return((char *) NULL);
00369       canonical_content=AcquireString("<base64>");
00370       (void) ConcatenateString(&canonical_content,base64);
00371       base64=DestroyString(base64);
00372       (void) ConcatenateString(&canonical_content,"</base64>");
00373       return(canonical_content);
00374     }
00375   /*
00376     Substitute predefined entities.
00377   */
00378   i=0;
00379   canonical_content=AcquireString((char *) NULL);
00380   extent=MaxTextExtent;
00381   for (p=utf8; *p != '\0'; p++)
00382   {
00383     if ((i+MaxTextExtent) > (long) extent)
00384       {
00385         extent+=MaxTextExtent;
00386         canonical_content=(char *) ResizeQuantumMemory(canonical_content,extent,
00387           sizeof(*canonical_content));
00388         if (canonical_content == (char *) NULL)
00389           return(canonical_content);
00390       }
00391     switch (*p)
00392     {
00393       case '&':
00394       {
00395         i+=FormatMagickString(canonical_content+i,extent,"&amp;");
00396         break;
00397       }
00398       case '<':
00399       {
00400         i+=FormatMagickString(canonical_content+i,extent,"&lt;");
00401         break;
00402       }
00403       case '>':
00404       {
00405         i+=FormatMagickString(canonical_content+i,extent,"&gt;");
00406         break;
00407       }
00408       case '"':
00409       {
00410         i+=FormatMagickString(canonical_content+i,extent,"&quot;");
00411         break;
00412       }
00413       case '\n':
00414       {
00415         if (pedantic == MagickFalse)
00416           {
00417             canonical_content[i++]=(char) (*p);
00418             break;
00419           }
00420         i+=FormatMagickString(canonical_content+i,extent,"&#xA;");
00421         break;
00422       }
00423       case '\t':
00424       {
00425         if (pedantic == MagickFalse)
00426           {
00427             canonical_content[i++]=(char) (*p);
00428             break;
00429           }
00430         i+=FormatMagickString(canonical_content+i,extent,"&#x9;");
00431         break;
00432       }
00433       case '\r':
00434       {
00435         i+=FormatMagickString(canonical_content+i,extent,"&#xD;");
00436         break;
00437       }
00438       default:
00439       {
00440         canonical_content[i++]=(char) (*p);
00441         break;
00442       }
00443     }
00444   }
00445   canonical_content[i]='\0';
00446   utf8=(unsigned char *) RelinquishMagickMemory(utf8);
00447   return(canonical_content);
00448 }
00449 
00450 /*
00451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00452 %                                                                             %
00453 %                                                                             %
00454 %                                                                             %
00455 %   D e s t r o y X M L T r e e                                               %
00456 %                                                                             %
00457 %                                                                             %
00458 %                                                                             %
00459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00460 %
00461 %  DestroyXMLTree() destroys the xml-tree.
00462 %
00463 %  The format of the DestroyXMLTree method is:
00464 %
00465 %      XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
00466 %
00467 %  A description of each parameter follows:
00468 %
00469 %    o xml_info: the xml info.
00470 %
00471 */
00472 
00473 static char **DestroyXMLTreeAttributes(char **attributes)
00474 {
00475   register long
00476     i;
00477 
00478   /*
00479     Destroy a tag attribute list.
00480   */
00481   if ((attributes == (char **) NULL) || (attributes == sentinel))
00482     return((char **) NULL);
00483   for (i=0; attributes[i] != (char *) NULL; i+=2)
00484   {
00485     /*
00486       Destroy attribute tag and value.
00487     */
00488     if (attributes[i] != (char *) NULL)
00489       attributes[i]=DestroyString(attributes[i]);
00490     if (attributes[i+1] != (char *) NULL)
00491       attributes[i+1]=DestroyString(attributes[i+1]);
00492   }
00493   attributes=(char **) RelinquishMagickMemory(attributes);
00494   return((char **) NULL);
00495 }
00496 
00497 MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
00498 {
00499   char
00500     **attributes;
00501 
00502   long
00503     j;
00504 
00505   register long
00506     i;
00507 
00508   XMLTreeRoot
00509     *root;
00510 
00511   assert(xml_info != (XMLTreeInfo *) NULL);
00512   assert((xml_info->signature == MagickSignature) ||
00513          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00514   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00515   if (xml_info->child != (XMLTreeInfo *) NULL)
00516     xml_info->child=DestroyXMLTree(xml_info->child);
00517   if (xml_info->ordered != (XMLTreeInfo *) NULL)
00518     xml_info->ordered=DestroyXMLTree(xml_info->ordered);
00519   if (xml_info->parent == (XMLTreeInfo *) NULL)
00520     {
00521       /*
00522         Free root tag allocations.
00523       */
00524       root=(XMLTreeRoot *) xml_info;
00525       for (i=NumberPredefinedEntities; root->entities[i]; i+=2)
00526         root->entities[i+1]=DestroyString(root->entities[i+1]);
00527       root->entities=(char **) RelinquishMagickMemory(root->entities);
00528       for (i=0; root->attributes[i] != (char **) NULL; i++)
00529       {
00530         attributes=root->attributes[i];
00531         if (attributes[0] != (char *) NULL)
00532           attributes[0]=DestroyString(attributes[0]);
00533         for (j=1; attributes[j] != (char *) NULL; j+=3)
00534         {
00535           if (attributes[j] != (char *) NULL)
00536             attributes[j]=DestroyString(attributes[j]);
00537           if (attributes[j+1] != (char *) NULL)
00538             attributes[j+1]=DestroyString(attributes[j+1]);
00539           if (attributes[j+2] != (char *) NULL)
00540             attributes[j+2]=DestroyString(attributes[j+2]);
00541         }
00542         attributes=(char **) RelinquishMagickMemory(attributes);
00543       }
00544       if (root->attributes[0] != (char **) NULL)
00545         root->attributes=(char ***) RelinquishMagickMemory(root->attributes);
00546       if (root->processing_instructions[0] != (char **) NULL)
00547         {
00548           for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
00549           {
00550             for (j=0; root->processing_instructions[i][j] != (char *) NULL; j++)
00551               root->processing_instructions[i][j]=DestroyString(
00552                 root->processing_instructions[i][j]);
00553             root->processing_instructions[i][j+1]=DestroyString(
00554               root->processing_instructions[i][j+1]);
00555             root->processing_instructions[i]=(char **) RelinquishMagickMemory(
00556               root->processing_instructions[i]);
00557           }
00558           root->processing_instructions=(char ***) RelinquishMagickMemory(
00559             root->processing_instructions);
00560         }
00561     }
00562   xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes);
00563   xml_info->content=DestroyString(xml_info->content);
00564   xml_info->tag=DestroyString(xml_info->tag);
00565   xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info);
00566   return((XMLTreeInfo *) NULL);
00567 }
00568 
00569 /*
00570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00571 %                                                                             %
00572 %                                                                             %
00573 %                                                                             %
00574 %   G e t N e x t X M L T r e e T a g                                         %
00575 %                                                                             %
00576 %                                                                             %
00577 %                                                                             %
00578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00579 %
00580 %  GetNextXMLTreeTag() returns the next tag or NULL if not found.
00581 %
00582 %  The format of the GetNextXMLTreeTag method is:
00583 %
00584 %      XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
00585 %
00586 %  A description of each parameter follows:
00587 %
00588 %    o xml_info: the xml info.
00589 %
00590 */
00591 MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
00592 {
00593   assert(xml_info != (XMLTreeInfo *) NULL);
00594   assert((xml_info->signature == MagickSignature) ||
00595          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00596   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00597   return(xml_info->next);
00598 }
00599 
00600 /*
00601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00602 %                                                                             %
00603 %                                                                             %
00604 %                                                                             %
00605 %   G e t X M L T r e e A t t r i b u t e                                     %
00606 %                                                                             %
00607 %                                                                             %
00608 %                                                                             %
00609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00610 %
00611 %  GetXMLTreeAttribute() returns the value of the attribute tag with the
00612 %  specified tag if found, otherwise NULL.
00613 %
00614 %  The format of the GetXMLTreeAttribute method is:
00615 %
00616 %      const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag)
00617 %
00618 %  A description of each parameter follows:
00619 %
00620 %    o xml_info: the xml info.
00621 %
00622 %    o tag: the attribute tag.
00623 %
00624 */
00625 MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,
00626   const char *tag)
00627 {
00628   long
00629     j;
00630 
00631   register long
00632     i;
00633 
00634   XMLTreeRoot
00635     *root;
00636 
00637   assert(xml_info != (XMLTreeInfo *) NULL);
00638   assert((xml_info->signature == MagickSignature) ||
00639          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00640   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00641   if (xml_info->attributes == (char **) NULL)
00642     return((const char *) NULL);
00643   i=0;
00644   while ((xml_info->attributes[i] != (char *) NULL) &&
00645          (strcmp(xml_info->attributes[i],tag) != 0))
00646     i+=2;
00647   if (xml_info->attributes[i] != (char *) NULL)
00648     return(xml_info->attributes[i+1]);
00649   root=(XMLTreeRoot*) xml_info;
00650   while (root->root.parent != (XMLTreeInfo *) NULL)
00651     root=(XMLTreeRoot *) root->root.parent;
00652   i=0;
00653   while ((root->attributes[i] != (char **) NULL) &&
00654          (strcmp(root->attributes[i][0],xml_info->tag) != 0))
00655     i++;
00656   if (root->attributes[i] == (char **) NULL)
00657     return((const char *) NULL);
00658   j=1;
00659   while ((root->attributes[i][j] != (char *) NULL) &&
00660          (strcmp(root->attributes[i][j],tag) != 0))
00661     j+=3;
00662   if (root->attributes[i][j] == (char *) NULL)
00663     return((const char *) NULL);
00664   return(root->attributes[i][j+1]);
00665 }
00666 
00667 /*
00668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00669 %                                                                             %
00670 %                                                                             %
00671 %                                                                             %
00672 %   G e t X M L T r e e A t t r i b u t e s                                   %
00673 %                                                                             %
00674 %                                                                             %
00675 %                                                                             %
00676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00677 %
00678 %  GetXMLTreeAttributes() injects all attributes associated with the current
00679 %  tag in the specified splay-tree.
00680 %
00681 %  The format of the GetXMLTreeAttributes method is:
00682 %
00683 %      MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
00684 %        SplayTreeInfo *attributes)
00685 %
00686 %  A description of each parameter follows:
00687 %
00688 %    o xml_info: the xml info.
00689 %
00690 %    o attributes: the attribute splay-tree.
00691 %
00692 */
00693 MagickExport MagickBooleanType GetXMLTreeAttributes(const XMLTreeInfo *xml_info,
00694   SplayTreeInfo *attributes)
00695 {
00696   register long
00697     i;
00698 
00699   assert(xml_info != (XMLTreeInfo *) NULL);
00700   assert((xml_info->signature == MagickSignature) ||
00701          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00702   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00703   assert(attributes != (SplayTreeInfo *) NULL);
00704   if (xml_info->attributes == (char **) NULL)
00705     return(MagickTrue);
00706   i=0;
00707   while (xml_info->attributes[i] != (char *) NULL)
00708   {
00709      (void) AddValueToSplayTree(attributes,
00710        ConstantString(xml_info->attributes[i]),
00711        ConstantString(xml_info->attributes[i+1]));
00712     i+=2;
00713   }
00714   return(MagickTrue);
00715 }
00716 
00717 /*
00718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00719 %                                                                             %
00720 %                                                                             %
00721 %                                                                             %
00722 %   G e t X M L T r e e C h i l d                                             %
00723 %                                                                             %
00724 %                                                                             %
00725 %                                                                             %
00726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00727 %
00728 %  GetXMLTreeChild() returns the first child tag with the specified tag if
00729 %  found, otherwise NULL.
00730 %
00731 %  The format of the GetXMLTreeChild method is:
00732 %
00733 %      XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
00734 %
00735 %  A description of each parameter follows:
00736 %
00737 %    o xml_info: the xml info.
00738 %
00739 */
00740 MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
00741 {
00742   XMLTreeInfo
00743     *child;
00744 
00745   assert(xml_info != (XMLTreeInfo *) NULL);
00746   assert((xml_info->signature == MagickSignature) ||
00747          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00748   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00749   child=xml_info->child;
00750   if (tag != (const char *) NULL)
00751     while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0))
00752       child=child->sibling;
00753   return(child);
00754 }
00755 
00756 /*
00757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00758 %                                                                             %
00759 %                                                                             %
00760 %                                                                             %
00761 %   G e t X M L T r e e C o n t e n t                                         %
00762 %                                                                             %
00763 %                                                                             %
00764 %                                                                             %
00765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00766 %
00767 %  GetXMLTreeContent() returns any content associated with specified
00768 %  xml-tree node.
00769 %
00770 %  The format of the GetXMLTreeContent method is:
00771 %
00772 %      const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
00773 %
00774 %  A description of each parameter follows:
00775 %
00776 %    o xml_info: the xml info.
00777 %
00778 */
00779 MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
00780 {
00781   assert(xml_info != (XMLTreeInfo *) NULL);
00782   assert((xml_info->signature == MagickSignature) ||
00783          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00784   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00785   return(xml_info->content);
00786 }
00787 
00788 /*
00789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00790 %                                                                             %
00791 %                                                                             %
00792 %                                                                             %
00793 %   G e t X M L T r e e O r d e r e d                                         %
00794 %                                                                             %
00795 %                                                                             %
00796 %                                                                             %
00797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00798 %
00799 %  GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL.
00800 %
00801 %  The format of the GetXMLTreeOrdered method is:
00802 %
00803 %      XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
00804 %
00805 %  A description of each parameter follows:
00806 %
00807 %    o xml_info: the xml info.
00808 %
00809 */
00810 MagickExport XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
00811 {
00812   assert(xml_info != (XMLTreeInfo *) NULL);
00813   assert((xml_info->signature == MagickSignature) ||
00814          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00815   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00816   return(xml_info->ordered);
00817 }
00818 
00819 /*
00820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00821 %                                                                             %
00822 %                                                                             %
00823 %                                                                             %
00824 %   G e t X M L T r e e P a t h                                               %
00825 %                                                                             %
00826 %                                                                             %
00827 %                                                                             %
00828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00829 %
00830 %  GetXMLTreePath() traverses the XML-tree as defined by the specified path
00831 %  and returns the node if found, otherwise NULL.
00832 %
00833 %  The format of the GetXMLTreePath method is:
00834 %
00835 %      XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
00836 %
00837 %  A description of each parameter follows:
00838 %
00839 %    o xml_info: the xml info.
00840 %
00841 %    o path: the path (e.g. property/elapsed-time).
00842 %
00843 */
00844 MagickExport XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
00845 {
00846   char
00847     **components,
00848     subnode[MaxTextExtent],
00849     tag[MaxTextExtent];
00850 
00851   long
00852     j;
00853 
00854   register long
00855     i;
00856 
00857   XMLTreeInfo
00858     *node;
00859 
00860   unsigned long
00861     number_components;
00862 
00863   assert(xml_info != (XMLTreeInfo *) NULL);
00864   assert((xml_info->signature == MagickSignature) ||
00865          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00866   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00867   node=xml_info;
00868   components=GetPathComponents(path,&number_components);
00869   if (components == (char **) NULL)
00870     return((XMLTreeInfo *) NULL);
00871   for (i=0; i < (long) number_components; i++)
00872   {
00873     GetPathComponent(components[i],SubimagePath,subnode);
00874     GetPathComponent(components[i],CanonicalPath,tag);
00875     node=GetXMLTreeChild(node,tag);
00876     if (node == (XMLTreeInfo *) NULL)
00877       break;
00878     for (j=atol(subnode)-1; j > 0; j--)
00879     {
00880       node=GetXMLTreeOrdered(node);
00881       if (node == (XMLTreeInfo *) NULL)
00882         break;
00883     }
00884     if (node == (XMLTreeInfo *) NULL)
00885       break;
00886     components[i]=DestroyString(components[i]);
00887   }
00888   for ( ; i < (long) number_components; i++)
00889     components[i]=DestroyString(components[i]);
00890   components=(char **) RelinquishMagickMemory(components);
00891   return(node);
00892 }
00893 
00894 /*
00895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00896 %                                                                             %
00897 %                                                                             %
00898 %                                                                             %
00899 %   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           %
00900 %                                                                             %
00901 %                                                                             %
00902 %                                                                             %
00903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00904 %
00905 %  GetXMLTreeProcessingInstructions() returns a null terminated array of
00906 %  processing instructions for the given target.
00907 %
00908 %  The format of the GetXMLTreeProcessingInstructions method is:
00909 %
00910 %      const char **GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info,
00911 %        const char *target)
00912 %
00913 %  A description of each parameter follows:
00914 %
00915 %    o xml_info: the xml info.
00916 %
00917 */
00918 MagickExport const char **GetXMLTreeProcessingInstructions(
00919   XMLTreeInfo *xml_info,const char *target)
00920 {
00921   register long
00922     i;
00923 
00924   XMLTreeRoot
00925     *root;
00926 
00927   assert(xml_info != (XMLTreeInfo *) NULL);
00928   assert((xml_info->signature == MagickSignature) ||
00929          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00930   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00931   root=(XMLTreeRoot *) xml_info;
00932   while (root->root.parent != (XMLTreeInfo *) NULL)
00933     root=(XMLTreeRoot *) root->root.parent;
00934   i=0;
00935   while ((root->processing_instructions[i] != (char **) NULL) &&
00936          (strcmp(root->processing_instructions[i][0],target) != 0))
00937     i++;
00938   if (root->processing_instructions[i] == (char **) NULL)
00939     return((const char **) sentinel);
00940   return((const char **) (root->processing_instructions[i]+1));
00941 }
00942 
00943 /*
00944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00945 %                                                                             %
00946 %                                                                             %
00947 %                                                                             %
00948 %   G e t X M L T r e e S i b l i n g                                         %
00949 %                                                                             %
00950 %                                                                             %
00951 %                                                                             %
00952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00953 %
00954 %  GetXMLTreeSibling() returns the node sibling if found, otherwise NULL.
00955 %
00956 %  The format of the GetXMLTreeSibling method is:
00957 %
00958 %      XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
00959 %
00960 %  A description of each parameter follows:
00961 %
00962 %    o xml_info: the xml info.
00963 %
00964 */
00965 MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
00966 {
00967   assert(xml_info != (XMLTreeInfo *) NULL);
00968   assert((xml_info->signature == MagickSignature) ||
00969          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
00970   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00971   return(xml_info->sibling);
00972 }
00973 
00974 /*
00975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00976 %                                                                             %
00977 %                                                                             %
00978 %                                                                             %
00979 %   G e t X M L T r e e T a g                                                 %
00980 %                                                                             %
00981 %                                                                             %
00982 %                                                                             %
00983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00984 %
00985 %  GetXMLTreeTag() returns the tag associated with specified xml-tree node.
00986 %
00987 %  The format of the GetXMLTreeTag method is:
00988 %
00989 %      const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
00990 %
00991 %  A description of each parameter follows:
00992 %
00993 %    o xml_info: the xml info.
00994 %
00995 */
00996 MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
00997 {
00998   assert(xml_info != (XMLTreeInfo *) NULL);
00999   assert((xml_info->signature == MagickSignature) ||
01000          (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
01001   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
01002   return(xml_info->tag);
01003 }
01004 
01005 /*
01006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01007 %                                                                             %
01008 %                                                                             %
01009 %                                                                             %
01010 %   I n s e r t I n t o T a g X M L T r e e                                   %
01011 %                                                                             %
01012 %                                                                             %
01013 %                                                                             %
01014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01015 %
01016 %  InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of
01017 %  the parent tag's character content.  This method returns the child tag.
01018 %
01019 %  The format of the InsertTagIntoXMLTree method is:
01020 %
01021 %      XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
01022 %        XMLTreeInfo *child,const size_t offset)
01023 %
01024 %  A description of each parameter follows:
01025 %
01026 %    o xml_info: the xml info.
01027 %
01028 %    o child: the child tag.
01029 %
01030 %    o offset: the tag offset.
01031 %
01032 */
01033 MagickExport XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
01034   XMLTreeInfo *child,const size_t offset)
01035 {
01036   XMLTreeInfo
01037     *head,
01038     *node,
01039     *previous;
01040 
01041   child->ordered=(XMLTreeInfo *) NULL;
01042   child->sibling=(XMLTreeInfo *) NULL;
01043   child->next=(XMLTreeInfo *) NULL;
01044   child->offset=offset;
01045   child->parent=xml_info;
01046   if (xml_info->child == (XMLTreeInfo *) NULL)
01047     {
01048       xml_info->child=child;
01049       return(child);
01050     }
01051   head=xml_info->child;
01052   if (head->offset > offset)
01053     {
01054       child->ordered=head;
01055       xml_info->child=child;
01056     }
01057   else
01058     {
01059       node=head;
01060       while ((node->ordered != (XMLTreeInfo *) NULL) &&
01061              (node->ordered->offset <= offset))
01062         node=node->ordered;
01063       child->ordered=node->ordered;
01064       node->ordered=child;
01065     }
01066   previous=(XMLTreeInfo *) NULL;
01067   node=head;
01068   while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0))
01069   {
01070     previous=node;
01071     node=node->sibling;
01072   }
01073   if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
01074     {
01075       while ((node->next != (XMLTreeInfo *) NULL) &&
01076              (node->next->offset <= offset))
01077         node=node->next;
01078       child->next=node->next;
01079       node->next=child;
01080     }
01081   else
01082     {
01083       if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL))
01084         previous->sibling=node->sibling;
01085       child->next=node;
01086       previous=(XMLTreeInfo *) NULL;
01087       node=head;
01088       while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
01089       {
01090         previous=node;
01091         node=node->sibling;
01092       }
01093       child->sibling=node;
01094       if (previous != (XMLTreeInfo *) NULL)
01095         previous->sibling=child;
01096     }
01097   return(child);
01098 }
01099 
01100 /*
01101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01102 %                                                                             %
01103 %                                                                             %
01104 %                                                                             %
01105 %   N e w X M L T r e e                                                       %
01106 %                                                                             %
01107 %                                                                             %
01108 %                                                                             %
01109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01110 %
01111 %  NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified