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