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