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