]> granicus.if.org Git - imagemagick/blob - MagickCore/magic.c
...
[imagemagick] / MagickCore / magic.c
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-2017 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 %    https://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 "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 \f
62 /*
63   Define declarations.
64 */
65 #define MagicFilename  "magic.xml"
66 #define MagicPattern(magic)  (const unsigned char *) (magic), sizeof(magic)-1
67 \f
68 /*
69   Typedef declarations.
70 */
71 typedef 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 \f
86 /*
87   Static declarations.
88 */
89 static 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     { "PGX", 0, MagicPattern("PG ML") },
172     { "PGX", 0, MagicPattern("PG LM") },
173     { "PS", 0, MagicPattern("%!") },
174     { "PS", 0, MagicPattern("\004%!") },
175     { "PS", 0, MagicPattern("\305\320\323\306") },
176     { "PSB", 0, MagicPattern("8BPB") },
177     { "PSD", 0, MagicPattern("8BPS") },
178     { "PWP", 0, MagicPattern("SFW95") },
179     { "RAF", 0, MagicPattern("FUJIFILMCCD-RAW ") },
180     { "RLE", 0, MagicPattern("\122\314") },
181     { "SCT", 0, MagicPattern("CT") },
182     { "SFW", 0, MagicPattern("SFW94") },
183     { "SGI", 0, MagicPattern("\001\332") },
184     { "SUN", 0, MagicPattern("\131\246\152\225") },
185     { "SVG", 1, MagicPattern("?XML") },
186     { "SVG", 1, MagicPattern("?xml") },
187     { "TIFF", 0, MagicPattern("\115\115\000\052") },
188     { "TIFF", 0, MagicPattern("\111\111\052\000") },
189     { "TIFF64", 0, MagicPattern("\115\115\000\053\000\010\000\000") },
190     { "TIFF64", 0, MagicPattern("\111\111\053\000\010\000\000\000") },
191     { "TTF", 0, MagicPattern("\000\001\000\000\000") },
192     { "TXT", 0, MagicPattern("# ImageMagick pixel enumeration:") },
193     { "VICAR", 0, MagicPattern("LBLSIZE") },
194     { "VICAR", 0, MagicPattern("NJPL1I") },
195     { "VIFF", 0, MagicPattern("\253\001") },
196     { "WEBP", 8, MagicPattern("WEBP") },
197     { "WMF", 0, MagicPattern("\327\315\306\232") },
198     { "WMF", 0, MagicPattern("\001\000\011\000") },
199     { "WPG", 0, MagicPattern("\377WPC") },
200     { "XBM", 0, MagicPattern("#define") },
201     { "XCF", 0, MagicPattern("gimp xcf") },
202     { "XEF", 0, MagicPattern("FOVb") },
203     { "XPM", 1, MagicPattern("* XPM *") }
204  };
205
206 static LinkedListInfo
207   *magic_cache = (LinkedListInfo *) NULL;
208
209 static SemaphoreInfo
210   *magic_semaphore = (SemaphoreInfo *) NULL;
211 \f
212 /*
213   Forward declarations.
214 */
215 static MagickBooleanType
216   IsMagicCacheInstantiated(ExceptionInfo *),
217   LoadMagicCache(LinkedListInfo *,const char *,const char *,const size_t,
218     ExceptionInfo *);
219 \f
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 */
246 static 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
261 static 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 \f
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 */
370 MagickExport 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 */
428 MagickExport 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 \f
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)
489 extern "C" {
490 #endif
491
492 static 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
509 MagickExport 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 \f
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)
586 extern "C" {
587 #endif
588
589 static 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
604 MagickExport 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 \f
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 */
669 MagickExport 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 \f
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 */
700 static 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 \f
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 */
738 MagickExport 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 \f
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 */
831 static 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         (LocaleCompare(keyword,"</policy>") == 0))
949       {
950         status=InsertValueInSortedLinkedList(cache,CompareMagickInfoSize,
951           NULL,magic_info);
952         if (status == MagickFalse)
953           (void) ThrowMagickException(exception,GetMagickModule(),
954             ResourceLimitError,"MemoryAllocationFailed","`%s'",
955             magic_info->name);
956         magic_info=(MagicInfo *) NULL;
957         continue;
958       }
959     GetNextToken(q,(const char **) NULL,extent,token);
960     if (*token != '=')
961       continue;
962     GetNextToken(q,&q,extent,token);
963     GetNextToken(q,&q,extent,token);
964     switch (*keyword)
965     {
966       case 'N':
967       case 'n':
968       {
969         if (LocaleCompare((char *) keyword,"name") == 0)
970           {
971             magic_info->name=ConstantString(token);
972             break;
973           }
974         break;
975       }
976       case 'O':
977       case 'o':
978       {
979         if (LocaleCompare((char *) keyword,"offset") == 0)
980           {
981             magic_info->offset=(MagickOffsetType) StringToLong(token);
982             break;
983           }
984         break;
985       }
986       case 'S':
987       case 's':
988       {
989         if (LocaleCompare((char *) keyword,"stealth") == 0)
990           {
991             magic_info->stealth=IsStringTrue(token);
992             break;
993           }
994         break;
995       }
996       case 'T':
997       case 't':
998       {
999         if (LocaleCompare((char *) keyword,"target") == 0)
1000           {
1001             char
1002               *p;
1003
1004             register unsigned char
1005               *q;
1006
1007             size_t
1008               length;
1009
1010             length=strlen(token);
1011             magic_info->target=ConstantString(token);
1012             magic_info->magic=(unsigned char *) ConstantString(token);
1013             q=magic_info->magic;
1014             for (p=magic_info->target; *p != '\0'; )
1015             {
1016               if (*p == '\\')
1017                 {
1018                   p++;
1019                   if (isdigit((int) ((unsigned char) *p)) != 0)
1020                     {
1021                       char
1022                         *end;
1023
1024                       *q++=(unsigned char) strtol(p,&end,8);
1025                       p+=(end-p);
1026                       magic_info->length++;
1027                       continue;
1028                     }
1029                   switch (*p)
1030                   {
1031                     case 'b': *q='\b'; break;
1032                     case 'f': *q='\f'; break;
1033                     case 'n': *q='\n'; break;
1034                     case 'r': *q='\r'; break;
1035                     case 't': *q='\t'; break;
1036                     case 'v': *q='\v'; break;
1037                     case 'a': *q='a'; break;
1038                     case '?': *q='\?'; break;
1039                     default: *q=(unsigned char) (*p); break;
1040                   }
1041                   p++;
1042                   q++;
1043                   magic_info->length++;
1044                   continue;
1045                 }
1046               else
1047                 if (LocaleNCompare(p,"&amp;",5) == 0)
1048                   (void) CopyMagickString(p+1,p+5,length-magic_info->length);
1049               *q++=(unsigned char) (*p++);
1050               magic_info->length++;
1051             }
1052             break;
1053           }
1054         break;
1055       }
1056       default:
1057         break;
1058     }
1059   }
1060   token=(char *) RelinquishMagickMemory(token);
1061   return(status != 0 ? MagickTrue : MagickFalse);
1062 }
1063 \f
1064 /*
1065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066 %                                                                             %
1067 %                                                                             %
1068 %                                                                             %
1069 +   M a g i c C o m p o n e n t G e n e s i s                                 %
1070 %                                                                             %
1071 %                                                                             %
1072 %                                                                             %
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 %
1075 %  MagicComponentGenesis() instantiates the magic component.
1076 %
1077 %  The format of the MagicComponentGenesis method is:
1078 %
1079 %      MagickBooleanType MagicComponentGenesis(void)
1080 %
1081 */
1082 MagickPrivate MagickBooleanType MagicComponentGenesis(void)
1083 {
1084   if (magic_semaphore == (SemaphoreInfo *) NULL)
1085     magic_semaphore=AcquireSemaphoreInfo();
1086   return(MagickTrue);
1087 }
1088 \f
1089 /*
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091 %                                                                             %
1092 %                                                                             %
1093 %                                                                             %
1094 +   M a g i c C o m p o n e n t T e r m i n u s                               %
1095 %                                                                             %
1096 %                                                                             %
1097 %                                                                             %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 %
1100 %  MagicComponentTerminus() destroys the magic component.
1101 %
1102 %  The format of the MagicComponentTerminus method is:
1103 %
1104 %      MagicComponentTerminus(void)
1105 %
1106 */
1107
1108 static void *DestroyMagicElement(void *magic_info)
1109 {
1110   register MagicInfo
1111     *p;
1112
1113   p=(MagicInfo *) magic_info;
1114   if (p->exempt == MagickFalse)
1115     {
1116       if (p->path != (char *) NULL)
1117         p->path=DestroyString(p->path);
1118       if (p->name != (char *) NULL)
1119         p->name=DestroyString(p->name);
1120       if (p->target != (char *) NULL)
1121         p->target=DestroyString(p->target);
1122       if (p->magic != (unsigned char *) NULL)
1123         p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1124     }
1125   p=(MagicInfo *) RelinquishMagickMemory(p);
1126   return((void *) NULL);
1127 }
1128
1129 MagickPrivate void MagicComponentTerminus(void)
1130 {
1131   if (magic_semaphore == (SemaphoreInfo *) NULL)
1132     ActivateSemaphoreInfo(&magic_semaphore);
1133   LockSemaphoreInfo(magic_semaphore);
1134   if (magic_cache != (LinkedListInfo *) NULL)
1135     magic_cache=DestroyLinkedList(magic_cache,DestroyMagicElement);
1136   UnlockSemaphoreInfo(magic_semaphore);
1137   RelinquishSemaphoreInfo(&magic_semaphore);
1138 }