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