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