1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                    M   M   AAA    GGGG  IIIII   CCCC                        %
7%                    MM MM  A   A  G        I    C                            %
8%                    M M M  AAAAA  G GGG    I    C                            %
9%                    M   M  A   A  G   G    I    C                            %
10%                    M   M  A   A   GGGG  IIIII   CCCC                        %
11%                                                                             %
12%                                                                             %
13%                      MagickCore Image Magic Methods                         %
14%                                                                             %
15%                              Software Design                                %
16%                              Bob Friesenhahn                                %
17%                                 July 2000                                   %
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/configure.h"
46#include "MagickCore/configure-private.h"
47#include "MagickCore/exception.h"
48#include "MagickCore/exception-private.h"
49#include "MagickCore/linked-list.h"
50#include "MagickCore/magic.h"
51#include "MagickCore/magic-private.h"
52#include "MagickCore/memory_.h"
53#include "MagickCore/semaphore.h"
54#include "MagickCore/string_.h"
55#include "MagickCore/string-private.h"
56#include "MagickCore/token.h"
57#include "MagickCore/utility.h"
58#include "MagickCore/utility-private.h"
59#include "MagickCore/xml-tree.h"
60#include "MagickCore/xml-tree-private.h"
61
62/*
63  Define declarations.
64*/
65#define MagicFilename  "magic.xml"
66#define MagicPattern(magic)  (const unsigned char *) (magic), sizeof(magic)-1
67
68/*
69  Typedef declarations.
70*/
71typedef struct _MagicMapInfo
72{
73  const char
74    *name;
75
76  const MagickOffsetType
77    offset;
78
79  const unsigned char
80    *magic;
81
82  const size_t
83    length;
84} MagicMapInfo;
85
86/*
87  Static declarations.
88*/
89static const MagicMapInfo
90  MagicMap[] =
91  {
92    { "8BIMWTEXT", 0, MagicPattern("8\000B\000I\000M\000#") },
93    { "8BIMTEXT", 0, MagicPattern("8BIM#") },
94    { "8BIM", 0, MagicPattern("8BIM") },
95    { "BMP", 0, MagicPattern("BA") },
96    { "BMP", 0, MagicPattern("BM") },
97    { "BMP", 0, MagicPattern("CI") },
98    { "BMP", 0, MagicPattern("CP") },
99    { "BMP", 0, MagicPattern("IC") },
100    { "PICT", 0, MagicPattern("PICT") },
101    { "BMP", 0, MagicPattern("PI") },
102    { "CALS", 21, MagicPattern("version: MIL-STD-1840") },
103    { "CALS", 0, MagicPattern("srcdocid:") },
104    { "CALS", 9, MagicPattern("srcdocid:") },
105    { "CALS", 8, MagicPattern("rorient:") },
106    { "CGM", 0, MagicPattern("BEGMF") },
107    { "CIN", 0, MagicPattern("\200\052\137\327") },
108    { "CRW", 0, MagicPattern("II\x1a\x00\x00\x00HEAPCCDR") },
109    { "DCM", 128, MagicPattern("DICM") },
110    { "DCX", 0, MagicPattern("\261\150\336\72") },
111    { "DIB", 0, MagicPattern("\050\000") },
112    { "DDS", 0, MagicPattern("DDS ") },
113    { "DJVU", 0, MagicPattern("AT&TFORM") },
114    { "DOT", 0, MagicPattern("digraph") },
115    { "DPX", 0, MagicPattern("SDPX") },
116    { "DPX", 0, MagicPattern("XPDS") },
117    { "EMF", 40, MagicPattern("\040\105\115\106\000\000\001\000") },
118    { "EPT", 0, MagicPattern("\305\320\323\306") },
119    { "EXR", 0, MagicPattern("\166\057\061\001") },
120    { "FAX", 0, MagicPattern("DFAX") },
121    { "FIG", 0, MagicPattern("#FIG") },
122    { "FITS", 0, MagicPattern("IT0") },
123    { "FITS", 0, MagicPattern("SIMPLE") },
124    { "FLIF", 0, MagicPattern("FLIF") },
125    { "GIF", 0, MagicPattern("GIF8") },
126    { "GPLT", 0, MagicPattern("#!/usr/local/bin/gnuplot") },
127    { "HDF", 1, MagicPattern("HDF") },
128    { "HDR", 0, MagicPattern("#?RADIANCE") },
129    { "HDR", 0, MagicPattern("#?RGBE") },
130    { "HPGL", 0, MagicPattern("IN;") },
131    { "HTML", 1, MagicPattern("HTML") },
132    { "HTML", 1, MagicPattern("html") },
133    { "ILBM", 8, MagicPattern("ILBM") },
134    { "IPTCWTEXT", 0, MagicPattern("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
135    { "IPTCTEXT", 0, MagicPattern("2#0=\042�\042") },
136    { "IPTC", 0, MagicPattern("\034\002") },
137    { "JNG", 0, MagicPattern("\213JNG\r\n\032\n") },
138    { "JPEG", 0, MagicPattern("\377\330\377") },
139    { "J2K", 0, MagicPattern("\xff\x4f\xff\x51") },
140    { "JPC", 0, MagicPattern("\x0d\x0a\x87\x0a") },
141    { "JP2", 0, MagicPattern("\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a") },
142    { "MAT", 0, MagicPattern("MATLAB 5.0 MAT-file,") },
143    { "MIFF", 0, MagicPattern("Id=ImageMagick") },
144    { "MIFF", 0, MagicPattern("id=ImageMagick") },
145    { "MNG", 0, MagicPattern("\212MNG\r\n\032\n") },
146    { "MPC", 0, MagicPattern("id=MagickCache") },
147    { "MPEG", 0, MagicPattern("\000\000\001\263") },
148    { "MRW", 0, MagicPattern("\x00MRM") },
149    { "ORF", 0, MagicPattern("IIRO\x08\x00\x00\x00") },
150    { "PCD", 2048, MagicPattern("PCD_") },
151    { "PCL", 0, MagicPattern("\033E\033") },
152    { "PCX", 0, MagicPattern("\012\002") },
153    { "PCX", 0, MagicPattern("\012\005") },
154    { "PDB", 60, MagicPattern("vIMGView") },
155    { "PDF", 0, MagicPattern("%PDF-") },
156    { "PES", 0, MagicPattern("#PES") },
157    { "PFA", 0, MagicPattern("%!PS-AdobeFont-1.0") },
158    { "PFB", 6, MagicPattern("%!PS-AdobeFont-1.0") },
159    { "PGX", 0, MagicPattern("\050\107\020\115\046") },
160    { "PICT", 522, MagicPattern("\000\021\002\377\014\000") },
161    { "PNG", 0, MagicPattern("\211PNG\r\n\032\n") },
162    { "PBM", 0, MagicPattern("P1") },
163    { "PGM", 0, MagicPattern("P2") },
164    { "PPM", 0, MagicPattern("P3") },
165    { "PBM", 0, MagicPattern("P4") },
166    { "PGM", 0, MagicPattern("P5") },
167    { "PPM", 0, MagicPattern("P6") },
168    { "PAM", 0, MagicPattern("P7") },
169    { "PFM", 0, MagicPattern("PF") },
170    { "PFM", 0, MagicPattern("Pf") },
171    { "PS", 0, MagicPattern("%!") },
172    { "PS", 0, MagicPattern("\004%!") },
173    { "PS", 0, MagicPattern("\305\320\323\306") },
174    { "PSB", 0, MagicPattern("8BPB") },
175    { "PSD", 0, MagicPattern("8BPS") },
176    { "PWP", 0, MagicPattern("SFW95") },
177    { "RAF", 0, MagicPattern("FUJIFILMCCD-RAW ") },
178    { "RLE", 0, MagicPattern("\122\314") },
179    { "SCT", 0, MagicPattern("CT") },
180    { "SFW", 0, MagicPattern("SFW94") },
181    { "SGI", 0, MagicPattern("\001\332") },
182    { "SUN", 0, MagicPattern("\131\246\152\225") },
183    { "SVG", 1, MagicPattern("?XML") },
184    { "SVG", 1, MagicPattern("?xml") },
185    { "TIFF", 0, MagicPattern("\115\115\000\052") },
186    { "TIFF", 0, MagicPattern("\111\111\052\000") },
187    { "TIFF64", 0, MagicPattern("\115\115\000\053\000\010\000\000") },
188    { "TIFF64", 0, MagicPattern("\111\111\053\000\010\000\000\000") },
189    { "TTF", 0, MagicPattern("\000\001\000\000\000") },
190    { "TXT", 0, MagicPattern("# ImageMagick pixel enumeration:") },
191    { "VICAR", 0, MagicPattern("LBLSIZE") },
192    { "VICAR", 0, MagicPattern("NJPL1I") },
193    { "VIFF", 0, MagicPattern("\253\001") },
194    { "WEBP", 8, MagicPattern("WEBP") },
195    { "WMF", 0, MagicPattern("\327\315\306\232") },
196    { "WMF", 0, MagicPattern("\001\000\011\000") },
197    { "WPG", 0, MagicPattern("\377WPC") },
198    { "XBM", 0, MagicPattern("#define") },
199    { "XCF", 0, MagicPattern("gimp xcf") },
200    { "XEF", 0, MagicPattern("FOVb") },
201    { "XPM", 1, MagicPattern("* XPM *") },
202    { "XWD", 4, MagicPattern("\007\000\000") },
203    { "XWD", 5, MagicPattern("\000\000\007") }
204 };
205
206static LinkedListInfo
207  *magic_cache = (LinkedListInfo *) NULL;
208
209static SemaphoreInfo
210  *magic_semaphore = (SemaphoreInfo *) NULL;
211
212/*
213  Forward declarations.
214*/
215static MagickBooleanType
216  IsMagicCacheInstantiated(ExceptionInfo *),
217  LoadMagicCache(LinkedListInfo *,const char *,const char *,const size_t,
218    ExceptionInfo *);
219
220/*
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222%                                                                             %
223%                                                                             %
224%                                                                             %
225%  A c q u i r e M a g i c L i s t s                                          %
226%                                                                             %
227%                                                                             %
228%                                                                             %
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%
231%  AcquireMagicCache() caches one or more magic configurations which provides a
232%  mapping between magic attributes and a magic name.
233%
234%  The format of the AcquireMagicCache method is:
235%
236%      LinkedListInfo *AcquireMagicCache(const char *filename,
237%        ExceptionInfo *exception)
238%
239%  A description of each parameter follows:
240%
241%    o filename: the font file name.
242%
243%    o exception: return any errors or warnings in this structure.
244%
245*/
246static int CompareMagickInfoSize(const void *a,const void *b)
247{
248  MagicInfo
249    *ma,
250    *mb;
251
252  ma=(MagicInfo *) a;
253  mb=(MagicInfo *) b;
254
255  if (ma->offset != mb->offset)
256    return((int) (ma->offset-mb->offset));
257
258  return((int) (mb->length-ma->length));
259}
260
261static LinkedListInfo *AcquireMagicCache(const char *filename,
262  ExceptionInfo *exception)
263{
264  LinkedListInfo
265    *cache;
266
267  MagickStatusType
268    status;
269
270  register ssize_t
271    i;
272
273  /*
274    Load external magic map.
275  */
276  cache=NewLinkedList(0);
277  if (cache == (LinkedListInfo *) NULL)
278    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
279  status=MagickTrue;
280#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
281  {
282    char
283      path[MagickPathExtent];
284
285    const StringInfo
286      *option;
287
288    LinkedListInfo
289      *options;
290
291    *path='\0';
292    options=GetConfigureOptions(filename,exception);
293    option=(const StringInfo *) GetNextValueInLinkedList(options);
294    while (option != (const StringInfo *) NULL)
295    {
296      (void) CopyMagickString(path,GetStringInfoPath(option),MagickPathExtent);
297      status&=LoadMagicCache(cache,(const char *)
298        GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
299      option=(const StringInfo *) GetNextValueInLinkedList(options);
300    }
301    options=DestroyConfigureOptions(options);
302  }
303#endif
304  /*
305    Load built-in magic map.
306  */
307  for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
308  {
309    MagicInfo
310      *magic_info;
311
312    register const MagicMapInfo
313      *p;
314
315    p=MagicMap+i;
316    magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
317    if (magic_info == (MagicInfo *) NULL)
318      {
319        (void) ThrowMagickException(exception,GetMagickModule(),
320          ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
321        continue;
322      }
323    (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
324    magic_info->path=(char *) "[built-in]";
325    magic_info->name=(char *) p->name;
326    magic_info->offset=p->offset;
327    magic_info->target=(char *) p->magic;
328    magic_info->magic=(unsigned char *) p->magic;
329    magic_info->length=p->length;
330    magic_info->exempt=MagickTrue;
331    magic_info->signature=MagickCoreSignature;
332    status&=InsertValueInSortedLinkedList(cache,CompareMagickInfoSize,
333      NULL,magic_info);
334    if (status == MagickFalse)
335      (void) ThrowMagickException(exception,GetMagickModule(),
336        ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
337  }
338  return(cache);
339}
340
341/*
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343%                                                                             %
344%                                                                             %
345%                                                                             %
346%   G e t M a g i c I n f o                                                   %
347%                                                                             %
348%                                                                             %
349%                                                                             %
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%
352%  GetMagicInfo() searches the magic list for the specified name and if found
353%  returns attributes for that magic.
354%
355%  The format of the GetMagicInfo method is:
356%
357%      const MagicInfo *GetMagicInfo(const unsigned char *magic,
358%        const size_t length,ExceptionInfo *exception)
359%
360%  A description of each parameter follows:
361%
362%    o magic: A binary string generally representing the first few characters
363%      of the image file or blob.
364%
365%    o length: the length of the binary signature.
366%
367%    o exception: return any errors or warnings in this structure.
368%
369*/
370MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
371  const size_t length,ExceptionInfo *exception)
372{
373  register const MagicInfo
374    *p;
375
376  assert(exception != (ExceptionInfo *) NULL);
377  if (IsMagicCacheInstantiated(exception) == MagickFalse)
378    return((const MagicInfo *) NULL);
379  /*
380    Search for magic tag.
381  */
382  LockSemaphoreInfo(magic_semaphore);
383  ResetLinkedListIterator(magic_cache);
384  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
385  if (magic == (const unsigned char *) NULL)
386    {
387      UnlockSemaphoreInfo(magic_semaphore);
388      return(p);
389    }
390  while (p != (const MagicInfo *) NULL)
391  {
392    assert(p->offset >= 0);
393    if (((size_t) (p->offset+p->length) <= length) &&
394        (memcmp(magic+p->offset,p->magic,p->length) == 0))
395      break;
396    p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
397  }
398  if (p != (const MagicInfo *) NULL)
399    (void) InsertValueInLinkedList(magic_cache,0,
400      RemoveElementByValueFromLinkedList(magic_cache,p));
401  UnlockSemaphoreInfo(magic_semaphore);
402  return(p);
403}
404
405/*
406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407%                                                                             %
408%                                                                             %
409%                                                                             %
410%   G e t M a g i c P a t t e r n E x t e n t                                 %
411%                                                                             %
412%                                                                             %
413%                                                                             %
414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415%
416%  GetMagicPatternExtent() returns the the extent of the buffer that is
417%  required to check all the MagickInfos. It returns zero if the list is empty.
418%
419%  The format of the GetMagicPatternExtent method is:
420%
421%      size_t GetMagicPatternExtent(ExceptionInfo *exception)
422%
423%  A description of each parameter follows:
424%
425%    o exception: return any errors or warnings in this structure.
426%
427*/
428MagickExport size_t GetMagicPatternExtent(ExceptionInfo *exception)
429{
430  register const MagicInfo
431    *p;
432
433  size_t
434    magickSize,
435    max;
436
437  static size_t
438    size=0;
439
440  assert(exception != (ExceptionInfo *) NULL);
441  if ((size != 0) || (IsMagicCacheInstantiated(exception) == MagickFalse))
442    return(size);
443  LockSemaphoreInfo(magic_semaphore);
444  ResetLinkedListIterator(magic_cache);
445  max=0;
446  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
447  while (p != (const MagicInfo *) NULL)
448  {
449    magickSize=(size_t) (p->offset+p->length);
450    if (magickSize > max)
451      max=magickSize;
452    p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
453  }
454  size=max;
455  UnlockSemaphoreInfo(magic_semaphore);
456  return(size);
457}
458
459/*
460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461%                                                                             %
462%                                                                             %
463%                                                                             %
464%   G e t M a g i c I n f o L i s t                                           %
465%                                                                             %
466%                                                                             %
467%                                                                             %
468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469%
470%  GetMagicInfoList() returns any image aliases that match the specified
471%  pattern.
472%
473%  The magic of the GetMagicInfoList function is:
474%
475%      const MagicInfo **GetMagicInfoList(const char *pattern,
476%        size_t *number_aliases,ExceptionInfo *exception)
477%
478%  A description of each parameter follows:
479%
480%    o pattern: Specifies a pointer to a text string containing a pattern.
481%
482%    o number_aliases:  This integer returns the number of aliases in the list.
483%
484%    o exception: return any errors or warnings in this structure.
485%
486*/
487
488#if defined(__cplusplus) || defined(c_plusplus)
489extern "C" {
490#endif
491
492static int MagicInfoCompare(const void *x,const void *y)
493{
494  const MagicInfo
495    **p,
496    **q;
497
498  p=(const MagicInfo **) x,
499  q=(const MagicInfo **) y;
500  if (LocaleCompare((*p)->path,(*q)->path) == 0)
501    return(LocaleCompare((*p)->name,(*q)->name));
502  return(LocaleCompare((*p)->path,(*q)->path));
503}
504
505#if defined(__cplusplus) || defined(c_plusplus)
506}
507#endif
508
509MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
510  size_t *number_aliases,ExceptionInfo *exception)
511{
512  const MagicInfo
513    **aliases;
514
515  register const MagicInfo
516    *p;
517
518  register ssize_t
519    i;
520
521  /*
522    Allocate magic list.
523  */
524  assert(pattern != (char *) NULL);
525  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
526  assert(number_aliases != (size_t *) NULL);
527  *number_aliases=0;
528  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
529  if (p == (const MagicInfo *) NULL)
530    return((const MagicInfo **) NULL);
531  aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
532    GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
533  if (aliases == (const MagicInfo **) NULL)
534    return((const MagicInfo **) NULL);
535  /*
536    Generate magic list.
537  */
538  LockSemaphoreInfo(magic_semaphore);
539  ResetLinkedListIterator(magic_cache);
540  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
541  for (i=0; p != (const MagicInfo *) NULL; )
542  {
543    if ((p->stealth == MagickFalse) &&
544        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
545      aliases[i++]=p;
546    p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
547  }
548  UnlockSemaphoreInfo(magic_semaphore);
549  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
550  aliases[i]=(MagicInfo *) NULL;
551  *number_aliases=(size_t) i;
552  return(aliases);
553}
554
555/*
556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557%                                                                             %
558%                                                                             %
559%                                                                             %
560%   G e t M a g i c L i s t                                                   %
561%                                                                             %
562%                                                                             %
563%                                                                             %
564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565%
566%  GetMagicList() returns any image format aliases that match the specified
567%  pattern.
568%
569%  The format of the GetMagicList function is:
570%
571%      char **GetMagicList(const char *pattern,size_t *number_aliases,
572%        ExceptionInfo *exception)
573%
574%  A description of each parameter follows:
575%
576%    o pattern: Specifies a pointer to a text string containing a pattern.
577%
578%    o number_aliases:  This integer returns the number of image format aliases
579%      in the list.
580%
581%    o exception: return any errors or warnings in this structure.
582%
583*/
584
585#if defined(__cplusplus) || defined(c_plusplus)
586extern "C" {
587#endif
588
589static int MagicCompare(const void *x,const void *y)
590{
591  register const char
592    *p,
593    *q;
594
595  p=(const char *) x;
596  q=(const char *) y;
597  return(LocaleCompare(p,q));
598}
599
600#if defined(__cplusplus) || defined(c_plusplus)
601}
602#endif
603
604MagickExport char **GetMagicList(const char *pattern,size_t *number_aliases,
605  ExceptionInfo *exception)
606{
607  char
608    **aliases;
609
610  register const MagicInfo
611    *p;
612
613  register ssize_t
614    i;
615
616  /*
617    Allocate configure list.
618  */
619  assert(pattern != (char *) NULL);
620  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
621  assert(number_aliases != (size_t *) NULL);
622  *number_aliases=0;
623  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
624  if (p == (const MagicInfo *) NULL)
625    return((char **) NULL);
626  aliases=(char **) AcquireQuantumMemory((size_t)
627    GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
628  if (aliases == (char **) NULL)
629    return((char **) NULL);
630  LockSemaphoreInfo(magic_semaphore);
631  ResetLinkedListIterator(magic_cache);
632  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
633  for (i=0; p != (const MagicInfo *) NULL; )
634  {
635    if ((p->stealth == MagickFalse) &&
636        (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
637      aliases[i++]=ConstantString(p->name);
638    p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
639  }
640  UnlockSemaphoreInfo(magic_semaphore);
641  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
642  aliases[i]=(char *) NULL;
643  *number_aliases=(size_t) i;
644  return(aliases);
645}
646
647/*
648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649%                                                                             %
650%                                                                             %
651%                                                                             %
652%   G e t M a g i c N a m e                                                   %
653%                                                                             %
654%                                                                             %
655%                                                                             %
656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657%
658%  GetMagicName() returns the name associated with the magic.
659%
660%  The format of the GetMagicName method is:
661%
662%      const char *GetMagicName(const MagicInfo *magic_info)
663%
664%  A description of each parameter follows:
665%
666%    o magic_info:  The magic info.
667%
668*/
669MagickExport const char *GetMagicName(const MagicInfo *magic_info)
670{
671  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
672  assert(magic_info != (MagicInfo *) NULL);
673  assert(magic_info->signature == MagickCoreSignature);
674  return(magic_info->name);
675}
676
677/*
678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
679%                                                                             %
680%                                                                             %
681%                                                                             %
682+   I s M a g i c C a c h e I n s t a n t i a t e d                           %
683%                                                                             %
684%                                                                             %
685%                                                                             %
686%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
687%
688%  IsMagicCacheInstantiated() determines if the magic list is instantiated.
689%  If not, it instantiates the list and returns it.
690%
691%  The format of the IsMagicInstantiated method is:
692%
693%      MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
694%
695%  A description of each parameter follows.
696%
697%    o exception: return any errors or warnings in this structure.
698%
699*/
700static MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
701{
702  if (magic_cache == (LinkedListInfo *) NULL)
703    {
704      if (magic_semaphore == (SemaphoreInfo *) NULL)
705        ActivateSemaphoreInfo(&magic_semaphore);
706      LockSemaphoreInfo(magic_semaphore);
707      if (magic_cache == (LinkedListInfo *) NULL)
708        magic_cache=AcquireMagicCache(MagicFilename,exception);
709      UnlockSemaphoreInfo(magic_semaphore);
710    }
711  return(magic_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
712}
713
714/*
715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716%                                                                             %
717%                                                                             %
718%                                                                             %
719%  L i s t M a g i c I n f o                                                  %
720%                                                                             %
721%                                                                             %
722%                                                                             %
723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724%
725%  ListMagicInfo() lists the magic info to a file.
726%
727%  The format of the ListMagicInfo method is:
728%
729%      MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
730%
731%  A description of each parameter follows.
732%
733%    o file:  An pointer to a FILE.
734%
735%    o exception: return any errors or warnings in this structure.
736%
737*/
738MagickExport MagickBooleanType ListMagicInfo(FILE *file,
739  ExceptionInfo *exception)
740{
741  const char
742    *path;
743
744  const MagicInfo
745    **magic_info;
746
747  register ssize_t
748    i;
749
750  size_t
751    number_aliases;
752
753  ssize_t
754    j;
755
756  if (file == (const FILE *) NULL)
757    file=stdout;
758  magic_info=GetMagicInfoList("*",&number_aliases,exception);
759  if (magic_info == (const MagicInfo **) NULL)
760    return(MagickFalse);
761  j=0;
762  path=(const char *) NULL;
763  for (i=0; i < (ssize_t) number_aliases; i++)
764  {
765    if (magic_info[i]->stealth != MagickFalse)
766      continue;
767    if ((path == (const char *) NULL) ||
768        (LocaleCompare(path,magic_info[i]->path) != 0))
769      {
770        if (magic_info[i]->path != (char *) NULL)
771          (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
772        (void) FormatLocaleFile(file,"Name      Offset Target\n");
773        (void) FormatLocaleFile(file,
774          "-------------------------------------------------"
775          "------------------------------\n");
776      }
777    path=magic_info[i]->path;
778    (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
779    for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
780      (void) FormatLocaleFile(file," ");
781    (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
782    if (magic_info[i]->target != (char *) NULL)
783      {
784        register ssize_t
785          j;
786
787        for (j=0; magic_info[i]->target[j] != '\0'; j++)
788          if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
789            (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
790          else
791            (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
792              ((unsigned char) magic_info[i]->target[j]));
793      }
794    (void) FormatLocaleFile(file,"\n");
795  }
796  (void) fflush(file);
797  magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
798  return(MagickTrue);
799}
800
801/*
802%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803%                                                                             %
804%                                                                             %
805%                                                                             %
806+   L o a d M a g i c C a c h e                                               %
807%                                                                             %
808%                                                                             %
809%                                                                             %
810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811%
812%  LoadMagicCache() loads the magic configurations which provides a mapping
813%  between magic attributes and a magic name.
814%
815%  The format of the LoadMagicCache method is:
816%
817%      MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
818%        const char *filename,const size_t depth,ExceptionInfo *exception)
819%
820%  A description of each parameter follows:
821%
822%    o xml: The magic list in XML format.
823%
824%    o filename: The magic list filename.
825%
826%    o depth: depth of <include /> statements.
827%
828%    o exception: return any errors or warnings in this structure.
829%
830*/
831static MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
832  const char *filename,const size_t depth,ExceptionInfo *exception)
833{
834  char
835    keyword[MagickPathExtent],
836    *token;
837
838  const char
839    *q;
840
841  MagicInfo
842    *magic_info;
843
844  MagickStatusType
845    status;
846
847  size_t
848    extent;
849
850  /*
851    Load the magic map file.
852  */
853  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
854    "Loading magic configure file \"%s\" ...",filename);
855  if (xml == (char *) NULL)
856    return(MagickFalse);
857  status=MagickTrue;
858  magic_info=(MagicInfo *) NULL;
859  token=AcquireString(xml);
860  extent=strlen(token)+MagickPathExtent;
861  for (q=(char *) xml; *q != '\0'; )
862  {
863    /*
864      Interpret XML.
865    */
866    GetNextToken(q,&q,extent,token);
867    if (*token == '\0')
868      break;
869    (void) CopyMagickString(keyword,token,MagickPathExtent);
870    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
871      {
872        /*
873          Doctype element.
874        */
875        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
876          GetNextToken(q,&q,extent,token);
877        continue;
878      }
879    if (LocaleNCompare(keyword,"<!--",4) == 0)
880      {
881        /*
882          Comment element.
883        */
884        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
885          GetNextToken(q,&q,extent,token);
886        continue;
887      }
888    if (LocaleCompare(keyword,"<include") == 0)
889      {
890        /*
891          Include element.
892        */
893        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
894        {
895          (void) CopyMagickString(keyword,token,MagickPathExtent);
896          GetNextToken(q,&q,extent,token);
897          if (*token != '=')
898            continue;
899          GetNextToken(q,&q,extent,token);
900          if (LocaleCompare(keyword,"file") == 0)
901            {
902              if (depth > 200)
903                (void) ThrowMagickException(exception,GetMagickModule(),
904                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
905              else
906                {
907                  char
908                    path[MagickPathExtent],
909                    *file_xml;
910
911                  GetPathComponent(filename,HeadPath,path);
912                  if (*path != '\0')
913                    (void) ConcatenateMagickString(path,DirectorySeparator,
914                      MagickPathExtent);
915                  if (*token == *DirectorySeparator)
916                    (void) CopyMagickString(path,token,MagickPathExtent);
917                  else
918                    (void) ConcatenateMagickString(path,token,MagickPathExtent);
919                  file_xml=FileToXML(path,~0UL);
920                  if (xml != (char *) NULL)
921                    {
922                      status&=LoadMagicCache(cache,file_xml,path,depth+1,
923                        exception);
924                      file_xml=DestroyString(file_xml);
925                    }
926                }
927            }
928        }
929        continue;
930      }
931    if (LocaleCompare(keyword,"<magic") == 0)
932      {
933        /*
934          Magic element.
935        */
936        magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
937        if (magic_info == (MagicInfo *) NULL)
938          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
939        (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
940        magic_info->path=ConstantString(filename);
941        magic_info->exempt=MagickFalse;
942        magic_info->signature=MagickCoreSignature;
943        continue;
944      }
945    if (magic_info == (MagicInfo *) NULL)
946      continue;
947    if (LocaleCompare(keyword,"/>") == 0)
948      {
949        status=InsertValueInSortedLinkedList(cache,CompareMagickInfoSize,
950          NULL,magic_info);
951        if (status == MagickFalse)
952          (void) ThrowMagickException(exception,GetMagickModule(),
953            ResourceLimitError,"MemoryAllocationFailed","`%s'",
954            magic_info->name);
955        magic_info=(MagicInfo *) NULL;
956        continue;
957      }
958    GetNextToken(q,(const char **) NULL,extent,token);
959    if (*token != '=')
960      continue;
961    GetNextToken(q,&q,extent,token);
962    GetNextToken(q,&q,extent,token);
963    switch (*keyword)
964    {
965      case 'N':
966      case 'n':
967      {
968        if (LocaleCompare((char *) keyword,"name") == 0)
969          {
970            magic_info->name=ConstantString(token);
971            break;
972          }
973        break;
974      }
975      case 'O':
976      case 'o':
977      {
978        if (LocaleCompare((char *) keyword,"offset") == 0)
979          {
980            magic_info->offset=(MagickOffsetType) StringToLong(token);
981            break;
982          }
983        break;
984      }
985      case 'S':
986      case 's':
987      {
988        if (LocaleCompare((char *) keyword,"stealth") == 0)
989          {
990            magic_info->stealth=IsStringTrue(token);
991            break;
992          }
993        break;
994      }
995      case 'T':
996      case 't':
997      {
998        if (LocaleCompare((char *) keyword,"target") == 0)
999          {
1000            char
1001              *p;
1002
1003            register unsigned char
1004              *q;
1005
1006            size_t
1007              length;
1008
1009            length=strlen(token);
1010            magic_info->target=ConstantString(token);
1011            magic_info->magic=(unsigned char *) ConstantString(token);
1012            q=magic_info->magic;
1013            for (p=magic_info->target; *p != '\0'; )
1014            {
1015              if (*p == '\\')
1016                {
1017                  p++;
1018                  if (isdigit((int) ((unsigned char) *p)) != 0)
1019                    {
1020                      char
1021                        *end;
1022
1023                      *q++=(unsigned char) strtol(p,&end,8);
1024                      p+=(end-p);
1025                      magic_info->length++;
1026                      continue;
1027                    }
1028                  switch (*p)
1029                  {
1030                    case 'b': *q='\b'; break;
1031                    case 'f': *q='\f'; break;
1032                    case 'n': *q='\n'; break;
1033                    case 'r': *q='\r'; break;
1034                    case 't': *q='\t'; break;
1035                    case 'v': *q='\v'; break;
1036                    case 'a': *q='a'; break;
1037                    case '?': *q='\?'; break;
1038                    default: *q=(unsigned char) (*p); break;
1039                  }
1040                  p++;
1041                  q++;
1042                  magic_info->length++;
1043                  continue;
1044                }
1045              else
1046                if (LocaleNCompare(p,"&amp;",5) == 0)
1047                  (void) CopyMagickString(p+1,p+5,length-magic_info->length);
1048              *q++=(unsigned char) (*p++);
1049              magic_info->length++;
1050            }
1051            break;
1052          }
1053        break;
1054      }
1055      default:
1056        break;
1057    }
1058  }
1059  token=(char *) RelinquishMagickMemory(token);
1060  return(status != 0 ? MagickTrue : MagickFalse);
1061}
1062
1063/*
1064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065%                                                                             %
1066%                                                                             %
1067%                                                                             %
1068+   M a g i c C o m p o n e n t G e n e s i s                                 %
1069%                                                                             %
1070%                                                                             %
1071%                                                                             %
1072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073%
1074%  MagicComponentGenesis() instantiates the magic component.
1075%
1076%  The format of the MagicComponentGenesis method is:
1077%
1078%      MagickBooleanType MagicComponentGenesis(void)
1079%
1080*/
1081MagickPrivate MagickBooleanType MagicComponentGenesis(void)
1082{
1083  if (magic_semaphore == (SemaphoreInfo *) NULL)
1084    magic_semaphore=AcquireSemaphoreInfo();
1085  return(MagickTrue);
1086}
1087
1088/*
1089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1090%                                                                             %
1091%                                                                             %
1092%                                                                             %
1093+   M a g i c C o m p o n e n t T e r m i n u s                               %
1094%                                                                             %
1095%                                                                             %
1096%                                                                             %
1097%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1098%
1099%  MagicComponentTerminus() destroys the magic component.
1100%
1101%  The format of the MagicComponentTerminus method is:
1102%
1103%      MagicComponentTerminus(void)
1104%
1105*/
1106
1107static void *DestroyMagicElement(void *magic_info)
1108{
1109  register MagicInfo
1110    *p;
1111
1112  p=(MagicInfo *) magic_info;
1113  if (p->exempt == MagickFalse)
1114    {
1115      if (p->path != (char *) NULL)
1116        p->path=DestroyString(p->path);
1117      if (p->name != (char *) NULL)
1118        p->name=DestroyString(p->name);
1119      if (p->target != (char *) NULL)
1120        p->target=DestroyString(p->target);
1121      if (p->magic != (unsigned char *) NULL)
1122        p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1123    }
1124  p=(MagicInfo *) RelinquishMagickMemory(p);
1125  return((void *) NULL);
1126}
1127
1128MagickPrivate void MagicComponentTerminus(void)
1129{
1130  if (magic_semaphore == (SemaphoreInfo *) NULL)
1131    ActivateSemaphoreInfo(&magic_semaphore);
1132  LockSemaphoreInfo(magic_semaphore);
1133  if (magic_cache != (LinkedListInfo *) NULL)
1134    magic_cache=DestroyLinkedList(magic_cache,DestroyMagicElement);
1135  UnlockSemaphoreInfo(magic_semaphore);
1136  RelinquishSemaphoreInfo(&magic_semaphore);
1137}
1138