]> granicus.if.org Git - imagemagick/blob - magick/coder.c
(no commit message)
[imagemagick] / magick / coder.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                   CCCC   OOO   DDDD    EEEEE  RRRR                          %
7 %                  C      O   O  D   D   E      R   R                         %
8 %                  C      O   O  D   D   EEE    RRRR                          %
9 %                  C      O   O  D   D   E      R R                           %
10 %                   CCCC   OOO   DDDD    EEEEE  R  R                          %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Coder Methods                          %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 May 2001                                    %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/client.h"
45 #include "magick/coder.h"
46 #include "magick/configure.h"
47 #include "magick/draw.h"
48 #include "magick/exception.h"
49 #include "magick/exception-private.h"
50 #include "magick/hashmap.h"
51 #include "magick/log.h"
52 #include "magick/memory_.h"
53 #include "magick/option.h"
54 #include "magick/semaphore.h"
55 #include "magick/string_.h"
56 #include "magick/splay-tree.h"
57 #include "magick/token.h"
58 #include "magick/utility.h"
59 #include "magick/xml-tree.h"
60 \f
61 /*
62   Define declarations.
63 */
64 #define MagickCoderFilename  "coder.xml"
65 \f
66 /*
67   Static declarations.
68 */
69 typedef struct _CoderMapInfo
70 {
71   const char
72     *magick,
73     *name;
74 } CoderMapInfo;
75
76 static const CoderMapInfo
77   CoderMap[] =
78   {
79     { "3FR", "DNG" },
80     { "8BIM", "META" },
81     { "8BIMTEXT", "META" },
82     { "8BIMWTEXT", "META" },
83     { "AFM", "TTF" },
84     { "A", "RAW" },
85     { "AI", "PDF" },
86     { "APP1JPEG", "META" },
87     { "APP1", "META" },
88     { "ARW", "DNG" },
89     { "BIE", "JBIG" },
90     { "BMP2", "BMP" },
91     { "BMP3", "BMP" },
92     { "B", "RAW" },
93     { "BRF", "BRAILLE" },
94     { "BGR", "RGB" },
95     { "BRG", "RGB" },
96     { "CMYKA", "CMYK" },
97     { "C", "RAW" },
98     { "CAL", "CALS" },
99     { "CR2", "DNG" },
100     { "CRW", "DNG" },
101     { "CUR", "ICON" },
102     { "DCR", "DNG" },
103     { "DCX", "PCX" },
104     { "DFONT", "TTF" },
105     { "EPDF", "PDF" },
106     { "EPI", "PS" },
107     { "EPS2", "PS2" },
108     { "EPS3", "PS3" },
109     { "EPSF", "PS" },
110     { "EPSI", "PS" },
111     { "EPS", "PS" },
112     { "EPT2", "EPT" },
113     { "EPT3", "EPT" },
114     { "ERF", "DNG" },
115     { "EXIF", "META" },
116     { "FILE", "URL" },
117     { "FRACTAL", "PLASMA" },
118     { "FTP", "URL" },
119     { "FTS", "FITS" },
120     { "G3", "FAX" },
121     { "GIF87", "GIF" },
122     { "G", "RAW" },
123     { "GBR", "RGB" },
124     { "GRB", "RGB" },
125     { "GRANITE", "MAGICK" },
126     { "GROUP4", "TIFF" },
127     { "K25", "DNG" },
128     { "KDC", "DNG" },
129     { "H", "MAGICK" },
130     { "HTM", "HTML" },
131     { "HTTP", "URL" },
132     { "ICB", "TGA" },
133     { "ICC", "META" },
134     { "ICM", "META" },
135     { "ICO", "ICON" },
136     { "IMPLICIT", "***" },
137     { "IPTC", "META" },
138     { "IPTCTEXT", "META" },
139     { "IPTCWTEXT", "META" },
140     { "ISOBRL", "BRAILLE" },
141     { "JBG", "JBIG" },
142     { "JNG", "PNG" },
143     { "JPC", "JP2" },
144     { "JPG", "JPEG" },
145     { "JPX", "JP2" },
146     { "K", "RAW" },
147     { "LOGO", "MAGICK" },
148     { "M2V", "MPEG" },
149     { "M4V", "MPEG" },
150     { "M", "RAW" },
151     { "MNG", "PNG" },
152     { "MOV", "PNG" },
153     { "MP4", "MPEG" },
154     { "MPG", "MPEG" },
155     { "MPRI", "MPR" },
156     { "MRW", "DNG" },
157     { "MSVG", "SVG" },
158     { "NEF", "DNG" },
159     { "NETSCAPE", "MAGICK" },
160     { "O", "RAW" },
161     { "ORF", "DNG" },
162     { "OTF", "TTF" },
163     { "P7", "PNM" },
164     { "PAL", "UYVY" },
165     { "PAM", "PNM" },
166     { "PBM", "PNM" },
167     { "PCDS", "PCD" },
168     { "PDFA", "PDF" },
169     { "PEF", "DNG" },
170     { "PEF", "DNG" },
171     { "PFA", "TTF" },
172     { "PFB", "TTF" },
173     { "PFM", "PNM" },
174     { "PGM", "PNM" },
175     { "PGX", "JP2" },
176     { "PICON", "XPM" },
177     { "PJPEG", "JPEG" },
178     { "PM", "XPM" },
179     { "PNG24", "PNG" },
180     { "PNG32", "PNG" },
181     { "PNG8", "PNG" },
182     { "PPM", "PNM" },
183     { "PTIF", "TIFF" },
184     { "RADIAL-GRADIENT", "GRADIENT" },
185     { "RAF", "DNG" },
186     { "RAS", "SUN" },
187     { "RBG", "RGB" },
188     { "RGBA", "RGB" },
189     { "RGBO", "RGB" },
190     { "R", "RAW" },
191     { "ROSE", "MAGICK" },
192     { "SHTML", "HTML" },
193     { "SR2", "DNG" },
194     { "SRF", "DNG" },
195     { "SVGZ", "SVG" },
196     { "TEXT", "TXT" },
197     { "TIFF64", "TIFF" },
198     { "TIF", "TIFF" },
199     { "TTC", "TTF" },
200     { "UBRL", "BRAILLE" },
201     { "VDA", "TGA" },
202     { "VST", "TGA" },
203     { "WMV", "MPEG" },
204     { "WMFWIN32", "EMF" },
205     { "WMZ", "WMF" },
206     { "X3f", "DNG" },
207     { "XMP", "META" },
208     { "XTRNARRAY", "XTRN" },
209     { "XTRNBLOB", "XTRN" },
210     { "XTRNBSTR", "XTRN" },
211     { "XTRNFILE", "XTRN" },
212     { "XTRNIMAGE", "XTRN" },
213     { "XTRNSTREAM", "XTRN" },
214     { "XV", "VIFF" },
215     { "Y", "RAW" },
216     { "YCbCrA", "YCbCr" },
217     { (const char *) NULL, (const char *) NULL }
218  };
219
220 static SemaphoreInfo
221   *coder_semaphore = (SemaphoreInfo *) NULL;
222
223 static SplayTreeInfo
224   *coder_list = (SplayTreeInfo *) NULL;
225
226 static volatile MagickBooleanType
227   instantiate_coder = MagickFalse;
228 \f
229 /*
230   Forward declarations.
231 */
232 static MagickBooleanType
233   InitializeCoderList(ExceptionInfo *),
234   LoadCoderLists(const char *,ExceptionInfo *);
235 \f
236 /*
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 %                                                                             %
239 %                                                                             %
240 %                                                                             %
241 +   D e s t r o y C o d e r L i s t                                           %
242 %                                                                             %
243 %                                                                             %
244 %                                                                             %
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 %
247 %  DestroyCoderList() deallocates memory associated with the font list.
248 %
249 %  The format of the DestroyCoderList method is:
250 %
251 %      DestroyCoderList(void)
252 %
253 */
254 MagickExport void DestroyCoderList(void)
255 {
256   AcquireSemaphoreInfo(&coder_semaphore);
257   if (coder_list != (SplayTreeInfo *) NULL)
258     coder_list=DestroySplayTree(coder_list);
259   instantiate_coder=MagickFalse;
260   RelinquishSemaphoreInfo(coder_semaphore);
261   DestroySemaphoreInfo(&coder_semaphore);
262 }
263 \f
264 /*
265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266 %                                                                             %
267 %                                                                             %
268 %                                                                             %
269 +   G e t C o d e r I n f o                                                   %
270 %                                                                             %
271 %                                                                             %
272 %                                                                             %
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 %
275 %  GetCoderInfo searches the coder list for the specified name and if found
276 %  returns attributes for that coder.
277 %
278 %  The format of the GetCoderInfo method is:
279 %
280 %      const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
281 %
282 %  A description of each parameter follows:
283 %
284 %    o name: the coder name.
285 %
286 %    o exception: return any errors or warnings in this structure.
287 %
288 */
289 MagickExport const CoderInfo *GetCoderInfo(const char *name,
290   ExceptionInfo *exception)
291 {
292   assert(exception != (ExceptionInfo *) NULL);
293   if ((coder_list == (SplayTreeInfo *) NULL) ||
294       (instantiate_coder == MagickFalse))
295     if (InitializeCoderList(exception) == MagickFalse)
296       return((const CoderInfo *) NULL);
297   if ((coder_list == (SplayTreeInfo *) NULL) ||
298       (GetNumberOfNodesInSplayTree(coder_list) == 0))
299     return((const CoderInfo *) NULL);
300   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
301     {
302       ResetSplayTreeIterator(coder_list);
303       return((const CoderInfo *) GetNextValueInSplayTree(coder_list));
304     }
305   return((const CoderInfo *) GetValueFromSplayTree(coder_list,name));
306 }
307 \f
308 /*
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310 %                                                                             %
311 %                                                                             %
312 %                                                                             %
313 %   G e t C o d e r I n f o L i s t                                           %
314 %                                                                             %
315 %                                                                             %
316 %                                                                             %
317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 %
319 %  GetCoderInfoList() returns any coder_map that match the specified pattern.
320 %  The format of the GetCoderInfoList function is:
321 %
322 %      const CoderInfo **GetCoderInfoList(const char *pattern,
323 %        unsigned long *number_coders,ExceptionInfo *exception)
324 %
325 %  A description of each parameter follows:
326 %
327 %    o pattern: Specifies a pointer to a text string containing a pattern.
328 %
329 %    o number_coders:  This integer returns the number of coders in the list.
330 %
331 %    o exception: return any errors or warnings in this structure.
332 %
333 */
334
335 static int CoderInfoCompare(const void *x,const void *y)
336 {
337   const CoderInfo
338     **p,
339     **q;
340
341   p=(const CoderInfo **) x,
342   q=(const CoderInfo **) y;
343   if (LocaleCompare((*p)->path,(*q)->path) == 0)
344     return(LocaleCompare((*p)->name,(*q)->name));
345   return(LocaleCompare((*p)->path,(*q)->path));
346 }
347
348 MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
349   unsigned long *number_coders,ExceptionInfo *exception)
350 {
351   const CoderInfo
352     **coder_map;
353
354   register const CoderInfo
355     *p;
356
357   register long
358     i;
359
360   /*
361     Allocate coder list.
362   */
363   assert(pattern != (char *) NULL);
364   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
365   assert(number_coders != (unsigned long *) NULL);
366   *number_coders=0;
367   p=GetCoderInfo("*",exception);
368   if (p == (const CoderInfo *) NULL)
369     return((const CoderInfo **) NULL);
370   coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
371     GetNumberOfNodesInSplayTree(coder_list)+1UL,sizeof(*coder_map));
372   if (coder_map == (const CoderInfo **) NULL)
373     return((const CoderInfo **) NULL);
374   /*
375     Generate coder list.
376   */
377   AcquireSemaphoreInfo(&coder_semaphore);
378   ResetSplayTreeIterator(coder_list);
379   p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
380   for (i=0; p != (const CoderInfo *) NULL; )
381   {
382     if ((p->stealth == MagickFalse) &&
383         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
384       coder_map[i++]=p;
385     p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
386   }
387   RelinquishSemaphoreInfo(coder_semaphore);
388   qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
389   coder_map[i]=(CoderInfo *) NULL;
390   *number_coders=(unsigned long) i;
391   return(coder_map);
392 }
393 \f
394 /*
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 %                                                                             %
397 %                                                                             %
398 %                                                                             %
399 %   G e t C o d e r L i s t                                                   %
400 %                                                                             %
401 %                                                                             %
402 %                                                                             %
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 %
405 %  GetCoderList() returns any coder_map that match the specified pattern.
406 %
407 %  The format of the GetCoderList function is:
408 %
409 %      char **GetCoderList(const char *pattern,unsigned long *number_coders,
410 %        ExceptionInfo *exception)
411 %
412 %  A description of each parameter follows:
413 %
414 %    o pattern: Specifies a pointer to a text string containing a pattern.
415 %
416 %    o number_coders:  This integer returns the number of coders in the list.
417 %
418 %    o exception: return any errors or warnings in this structure.
419 %
420 */
421
422 static int CoderCompare(const void *x,const void *y)
423 {
424   register const char
425     **p,
426     **q;
427
428   p=(const char **) x;
429   q=(const char **) y;
430   return(LocaleCompare(*p,*q));
431 }
432
433 MagickExport char **GetCoderList(const char *pattern,
434   unsigned long *number_coders,ExceptionInfo *exception)
435 {
436   char
437     **coder_map;
438
439   register const CoderInfo
440     *p;
441
442   register long
443     i;
444
445   /*
446     Allocate coder list.
447   */
448   assert(pattern != (char *) NULL);
449   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
450   assert(number_coders != (unsigned long *) NULL);
451   *number_coders=0;
452   p=GetCoderInfo("*",exception);
453   if (p == (const CoderInfo *) NULL)
454     return((char **) NULL);
455   coder_map=(char **) AcquireQuantumMemory((size_t)
456     GetNumberOfNodesInSplayTree(coder_list)+1UL,sizeof(*coder_map));
457   if (coder_map == (char **) NULL)
458     return((char **) NULL);
459   /*
460     Generate coder list.
461   */
462   AcquireSemaphoreInfo(&coder_semaphore);
463   ResetSplayTreeIterator(coder_list);
464   p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
465   for (i=0; p != (const CoderInfo *) NULL; )
466   {
467     if ((p->stealth == MagickFalse) &&
468         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
469       coder_map[i++]=ConstantString(p->name);
470     p=(const CoderInfo *) GetNextValueInSplayTree(coder_list);
471   }
472   RelinquishSemaphoreInfo(coder_semaphore);
473   qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
474   coder_map[i]=(char *) NULL;
475   *number_coders=(unsigned long) i;
476   return(coder_map);
477 }
478 \f
479 /*
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 +   I n i t i a l i z e C o d e r L i s t                                     %
485 %                                                                             %
486 %                                                                             %
487 %                                                                             %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 %
490 %  InitializeCoderList() initializes the coder list.
491 %
492 %  The format of the InitializeCoderList method is:
493 %
494 %      MagickBooleanType InitializeCoderList(ExceptionInfo *exception)
495 %
496 %  A description of each parameter follows.
497 %
498 %    o exception: return any errors or warnings in this structure.
499 %
500 */
501 static MagickBooleanType InitializeCoderList(ExceptionInfo *exception)
502 {
503   if ((coder_list == (SplayTreeInfo *) NULL) &&
504       (instantiate_coder == MagickFalse))
505     {
506       AcquireSemaphoreInfo(&coder_semaphore);
507       if ((coder_list == (SplayTreeInfo *) NULL) &&
508           (instantiate_coder == MagickFalse))
509         {
510           (void) LoadCoderLists(MagickCoderFilename,exception);
511           instantiate_coder=MagickTrue;
512         }
513       RelinquishSemaphoreInfo(coder_semaphore);
514     }
515   return(coder_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
516 }
517 \f
518 /*
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520 %                                                                             %
521 %                                                                             %
522 %                                                                             %
523 %  L i s t C o d e r I n f o                                                  %
524 %                                                                             %
525 %                                                                             %
526 %                                                                             %
527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528 %
529 %  ListCoderInfo() lists the coder info to a file.
530 %
531 %  The format of the ListCoderInfo coder is:
532 %
533 %      MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
534 %
535 %  A description of each parameter follows.
536 %
537 %    o file:  An pointer to a FILE.
538 %
539 %    o exception: return any errors or warnings in this structure.
540 %
541 */
542 MagickExport MagickBooleanType ListCoderInfo(FILE *file,
543   ExceptionInfo *exception)
544 {
545   const char
546     *path;
547
548   const CoderInfo
549     **coder_info;
550
551   long
552     j;
553
554   register long
555     i;
556
557   unsigned long
558     number_coders;
559
560   if (file == (const FILE *) NULL)
561     file=stdout;
562   coder_info=GetCoderInfoList("*",&number_coders,exception);
563   if (coder_info == (const CoderInfo **) NULL)
564     return(MagickFalse);
565   path=(const char *) NULL;
566   for (i=0; i < (long) number_coders; i++)
567   {
568     if (coder_info[i]->stealth != MagickFalse)
569       continue;
570     if ((path == (const char *) NULL) ||
571         (LocaleCompare(path,coder_info[i]->path) != 0))
572       {
573         if (coder_info[i]->path != (char *) NULL)
574           (void) fprintf(file,"\nPath: %s\n\n",coder_info[i]->path);
575         (void) fprintf(file,"Magick      Coder\n");
576         (void) fprintf(file,"-------------------------------------------------"
577           "------------------------------\n");
578       }
579     path=coder_info[i]->path;
580     (void) fprintf(file,"%s",coder_info[i]->magick);
581     for (j=(long) strlen(coder_info[i]->magick); j <= 11; j++)
582       (void) fprintf(file," ");
583     if (coder_info[i]->name != (char *) NULL)
584       (void) fprintf(file,"%s",coder_info[i]->name);
585     (void) fprintf(file,"\n");
586   }
587   coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
588   (void) fflush(file);
589   return(MagickTrue);
590 }
591 \f
592 /*
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594 %                                                                             %
595 %                                                                             %
596 %                                                                             %
597 +   L o a d C o d e r L i s t                                                 %
598 %                                                                             %
599 %                                                                             %
600 %                                                                             %
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 %
603 %  LoadCoderList() loads the coder configuration file which provides a
604 %  mapping between coder attributes and a coder name.
605 %
606 %  The format of the LoadCoderList coder is:
607 %
608 %      MagickBooleanType LoadCoderList(const char *xml,const char *filename,
609 %        const unsigned long depth,ExceptionInfo *exception)
610 %
611 %  A description of each parameter follows:
612 %
613 %    o xml:  The coder list in XML format.
614 %
615 %    o filename:  The coder list filename.
616 %
617 %    o depth: depth of <include /> statements.
618 %
619 %    o exception: return any errors or warnings in this structure.
620 %
621 */
622
623 static void *DestroyCoderNode(void *coder_info)
624 {
625   register CoderInfo
626     *p;
627
628   p=(CoderInfo *) coder_info;
629   if (p->exempt == MagickFalse)
630     {
631       if (p->path != (char *) NULL)
632         p->path=DestroyString(p->path);
633       if (p->name != (char *) NULL)
634         p->name=DestroyString(p->name);
635       if (p->magick != (char *) NULL)
636         p->magick=DestroyString(p->magick);
637     }
638   return(RelinquishMagickMemory(p));
639 }
640
641 static MagickBooleanType LoadCoderList(const char *xml,const char *filename,
642   const unsigned long depth,ExceptionInfo *exception)
643 {
644   char
645     keyword[MaxTextExtent],
646     *token;
647
648   const char
649     *q;
650
651   CoderInfo
652     *coder_info;
653
654   MagickBooleanType
655     status;
656
657   /*
658     Load the coder map file.
659   */
660   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
661     "Loading coder configuration file \"%s\" ...",filename);
662   if (xml == (const char *) NULL)
663     return(MagickFalse);
664   if (coder_list == (SplayTreeInfo *) NULL)
665     {
666       coder_list=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
667         DestroyCoderNode);
668       if (coder_list == (SplayTreeInfo *) NULL)
669         {
670           ThrowFileException(exception,ResourceLimitError,
671             "MemoryAllocationFailed",filename);
672           return(MagickFalse);
673         }
674     }
675   status=MagickTrue;
676   coder_info=(CoderInfo *) NULL;
677   token=AcquireString(xml);
678   for (q=(char *) xml; *q != '\0'; )
679   {
680     /*
681       Interpret XML.
682     */
683     GetMagickToken(q,&q,token);
684     if (*token == '\0')
685       break;
686     (void) CopyMagickString(keyword,token,MaxTextExtent);
687     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
688       {
689         /*
690           Doctype element.
691         */
692         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
693           GetMagickToken(q,&q,token);
694         continue;
695       }
696     if (LocaleNCompare(keyword,"<!--",4) == 0)
697       {
698         /*
699           Comment element.
700         */
701         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
702           GetMagickToken(q,&q,token);
703         continue;
704       }
705     if (LocaleCompare(keyword,"<include") == 0)
706       {
707         /*
708           Include element.
709         */
710         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
711         {
712           (void) CopyMagickString(keyword,token,MaxTextExtent);
713           GetMagickToken(q,&q,token);
714           if (*token != '=')
715             continue;
716           GetMagickToken(q,&q,token);
717           if (LocaleCompare(keyword,"file") == 0)
718             {
719               if (depth > 200)
720                 (void) ThrowMagickException(exception,GetMagickModule(),
721                   ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
722               else
723                 {
724                   char
725                     path[MaxTextExtent],
726                     *xml;
727
728                   GetPathComponent(filename,HeadPath,path);
729                   if (*path != '\0')
730                     (void) ConcatenateMagickString(path,DirectorySeparator,
731                       MaxTextExtent);
732                   if (*token == *DirectorySeparator)
733                     (void) CopyMagickString(path,token,MaxTextExtent);
734                   else
735                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
736                   xml=FileToString(path,~0,exception);
737                   if (xml != (char *) NULL)
738                     {
739                       status=LoadCoderList(xml,path,depth+1,exception);
740                       xml=(char *) RelinquishMagickMemory(xml);
741                     }
742                 }
743             }
744         }
745         continue;
746       }
747     if (LocaleCompare(keyword,"<coder") == 0)
748       {
749         /*
750           Coder element.
751         */
752         coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
753         if (coder_info == (CoderInfo *) NULL)
754           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
755         (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
756         coder_info->path=ConstantString(filename);
757         coder_info->exempt=MagickFalse;
758         coder_info->signature=MagickSignature;
759         continue;
760       }
761     if (coder_info == (CoderInfo *) NULL)
762       continue;
763     if (LocaleCompare(keyword,"/>") == 0)
764       {
765         status=AddValueToSplayTree(coder_list,ConstantString(
766           coder_info->magick),coder_info);
767         if (status == MagickFalse)
768           (void) ThrowMagickException(exception,GetMagickModule(),
769             ResourceLimitError,"MemoryAllocationFailed","`%s'",
770             coder_info->magick);
771         coder_info=(CoderInfo *) NULL;
772       }
773     GetMagickToken(q,(const char **) NULL,token);
774     if (*token != '=')
775       continue;
776     GetMagickToken(q,&q,token);
777     GetMagickToken(q,&q,token);
778     switch (*keyword)
779     {
780       case 'M':
781       case 'm':
782       {
783         if (LocaleCompare((char *) keyword,"magick") == 0)
784           {
785             coder_info->magick=ConstantString(token);
786             break;
787           }
788         break;
789       }
790       case 'N':
791       case 'n':
792       {
793         if (LocaleCompare((char *) keyword,"name") == 0)
794           {
795             coder_info->name=ConstantString(token);
796             break;
797           }
798         break;
799       }
800       case 'S':
801       case 's':
802       {
803         if (LocaleCompare((char *) keyword,"stealth") == 0)
804           {
805             coder_info->stealth=IsMagickTrue(token);
806             break;
807           }
808         break;
809       }
810       default:
811         break;
812     }
813   }
814   token=(char *) RelinquishMagickMemory(token);
815   return(status);
816 }
817 \f
818 /*
819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
820 %                                                                             %
821 %                                                                             %
822 %                                                                             %
823 %  L o a d C o d e r L i s t s                                                %
824 %                                                                             %
825 %                                                                             %
826 %                                                                             %
827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828 %
829 %  LoadCoderLists() loads one or more coder configuration file which
830 %  provides a mapping between coder attributes and a coder name.
831 %
832 %  The format of the LoadCoderLists coder is:
833 %
834 %      MagickBooleanType LoadCoderLists(const char *filename,
835 %        ExceptionInfo *exception)
836 %
837 %  A description of each parameter follows:
838 %
839 %    o filename: the font file name.
840 %
841 %    o exception: return any errors or warnings in this structure.
842 %
843 */
844 static MagickBooleanType LoadCoderLists(const char *filename,
845   ExceptionInfo *exception)
846 {
847   const StringInfo
848     *option;
849
850   LinkedListInfo
851     *options;
852
853   MagickStatusType
854     status;
855
856   register const CoderMapInfo
857     *p;
858
859   /*
860     Load built-in coder map.
861   */
862   status=MagickFalse;
863   if (coder_list == (SplayTreeInfo *) NULL)
864     {
865       coder_list=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
866         DestroyCoderNode);
867       if (coder_list == (SplayTreeInfo *) NULL)
868         {
869           ThrowFileException(exception,ResourceLimitError,
870             "MemoryAllocationFailed",filename);
871           return(MagickFalse);
872         }
873     }
874   for (p=CoderMap; p->magick != (const char *) NULL; p++)
875   {
876     CoderInfo
877       *coder_info;
878
879     coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
880     if (coder_info == (CoderInfo *) NULL)
881       {
882         (void) ThrowMagickException(exception,GetMagickModule(),
883           ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
884         continue;
885       }
886     (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
887     coder_info->path=(char *) "[built-in]";
888     coder_info->magick=(char *) p->magick;
889     coder_info->name=(char *) p->name;
890     coder_info->exempt=MagickTrue;
891     coder_info->signature=MagickSignature;
892     status=AddValueToSplayTree(coder_list,ConstantString(coder_info->magick),
893       coder_info);
894     if (status == MagickFalse)
895       (void) ThrowMagickException(exception,GetMagickModule(),
896         ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
897   }
898   /*
899     Load external coder map.
900   */
901   options=GetConfigureOptions(filename,exception);
902   option=(const StringInfo *) GetNextValueInLinkedList(options);
903   while (option != (const StringInfo *) NULL)
904   {
905     status|=LoadCoderList((const char *) GetStringInfoDatum(option),
906       GetStringInfoPath(option),0,exception);
907     option=(const StringInfo *) GetNextValueInLinkedList(options);
908   }
909   options=DestroyConfigureOptions(options);
910   return(status != 0 ? MagickTrue : MagickFalse);
911 }