MagickCore  6.9.12-53
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  assert(p->offset >= 0);
397  if (((size_t) (p->offset+p->length) <= length) &&
398  (memcmp(magic+p->offset,p->magic,p->length) == 0))
399  break;
400  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
401  }
402  if (p != (const MagicInfo *) NULL)
403  (void) InsertValueInLinkedList(magic_cache,0,
404  RemoveElementByValueFromLinkedList(magic_cache,p));
405  UnlockSemaphoreInfo(magic_semaphore);
406  return(p);
407 }
408 
409 /*
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 % %
412 % %
413 % %
414 % G e t M a g i c I n f o L i s t %
415 % %
416 % %
417 % %
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 %
420 % GetMagicInfoList() returns any image aliases that match the specified
421 % pattern.
422 %
423 % The magic of the GetMagicInfoList function is:
424 %
425 % const MagicInfo **GetMagicInfoList(const char *pattern,
426 % size_t *number_aliases,ExceptionInfo *exception)
427 %
428 % A description of each parameter follows:
429 %
430 % o pattern: Specifies a pointer to a text string containing a pattern.
431 %
432 % o number_aliases: This integer returns the number of aliases in the list.
433 %
434 % o exception: return any errors or warnings in this structure.
435 %
436 */
437 
438 #if defined(__cplusplus) || defined(c_plusplus)
439 extern "C" {
440 #endif
441 
442 static int MagicInfoCompare(const void *x,const void *y)
443 {
444  const MagicInfo
445  **p,
446  **q;
447 
448  p=(const MagicInfo **) x,
449  q=(const MagicInfo **) y;
450  if (LocaleCompare((*p)->path,(*q)->path) == 0)
451  return(LocaleCompare((*p)->name,(*q)->name));
452  return(LocaleCompare((*p)->path,(*q)->path));
453 }
454 
455 #if defined(__cplusplus) || defined(c_plusplus)
456 }
457 #endif
458 
459 MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
460  size_t *number_aliases,ExceptionInfo *exception)
461 {
462  const MagicInfo
463  **aliases;
464 
465  const MagicInfo
466  *p;
467 
468  ssize_t
469  i;
470 
471  /*
472  Allocate magic list.
473  */
474  assert(pattern != (char *) NULL);
475  assert(number_aliases != (size_t *) NULL);
476  if (IsEventLogging() != MagickFalse)
477  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
478  *number_aliases=0;
479  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
480  if (p == (const MagicInfo *) NULL)
481  return((const MagicInfo **) NULL);
482  aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
483  GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
484  if (aliases == (const MagicInfo **) NULL)
485  return((const MagicInfo **) NULL);
486  /*
487  Generate magic list.
488  */
489  LockSemaphoreInfo(magic_semaphore);
490  ResetLinkedListIterator(magic_cache);
491  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
492  for (i=0; p != (const MagicInfo *) NULL; )
493  {
494  if ((p->stealth == MagickFalse) &&
495  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
496  aliases[i++]=p;
497  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
498  }
499  UnlockSemaphoreInfo(magic_semaphore);
500  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
501  aliases[i]=(MagicInfo *) NULL;
502  *number_aliases=(size_t) i;
503  return(aliases);
504 }
505 
506 /*
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 % %
509 % %
510 % %
511 % G e t M a g i c L i s t %
512 % %
513 % %
514 % %
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 %
517 % GetMagicList() returns any image format aliases that match the specified
518 % pattern.
519 %
520 % The format of the GetMagicList function is:
521 %
522 % char **GetMagicList(const char *pattern,size_t *number_aliases,
523 % ExceptionInfo *exception)
524 %
525 % A description of each parameter follows:
526 %
527 % o pattern: Specifies a pointer to a text string containing a pattern.
528 %
529 % o number_aliases: This integer returns the number of image format aliases
530 % in the list.
531 %
532 % o exception: return any errors or warnings in this structure.
533 %
534 */
535 
536 #if defined(__cplusplus) || defined(c_plusplus)
537 extern "C" {
538 #endif
539 
540 static int MagicCompare(const void *x,const void *y)
541 {
542  const char
543  *p,
544  *q;
545 
546  p=(const char *) x;
547  q=(const char *) y;
548  return(LocaleCompare(p,q));
549 }
550 
551 #if defined(__cplusplus) || defined(c_plusplus)
552 }
553 #endif
554 
555 MagickExport char **GetMagicList(const char *pattern,size_t *number_aliases,
556  ExceptionInfo *exception)
557 {
558  char
559  **aliases;
560 
561  const MagicInfo
562  *p;
563 
564  ssize_t
565  i;
566 
567  /*
568  Allocate configure list.
569  */
570  assert(pattern != (char *) NULL);
571  assert(number_aliases != (size_t *) NULL);
572  if (IsEventLogging() != MagickFalse)
573  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
574  *number_aliases=0;
575  p=GetMagicInfo((const unsigned char *) NULL,0,exception);
576  if (p == (const MagicInfo *) NULL)
577  return((char **) NULL);
578  aliases=(char **) AcquireQuantumMemory((size_t)
579  GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
580  if (aliases == (char **) NULL)
581  return((char **) NULL);
582  LockSemaphoreInfo(magic_semaphore);
583  ResetLinkedListIterator(magic_cache);
584  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
585  for (i=0; p != (const MagicInfo *) NULL; )
586  {
587  if ((p->stealth == MagickFalse) &&
588  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
589  aliases[i++]=ConstantString(p->name);
590  p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
591  }
592  UnlockSemaphoreInfo(magic_semaphore);
593  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
594  aliases[i]=(char *) NULL;
595  *number_aliases=(size_t) i;
596  return(aliases);
597 }
598 
599 /*
600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601 % %
602 % %
603 % %
604 % G e t M a g i c N a m e %
605 % %
606 % %
607 % %
608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609 %
610 % GetMagicName() returns the name associated with the magic.
611 %
612 % The format of the GetMagicName method is:
613 %
614 % const char *GetMagicName(const MagicInfo *magic_info)
615 %
616 % A description of each parameter follows:
617 %
618 % o magic_info: The magic info.
619 %
620 */
621 MagickExport const char *GetMagicName(const MagicInfo *magic_info)
622 {
623  assert(magic_info != (MagicInfo *) NULL);
624  assert(magic_info->signature == MagickCoreSignature);
625  if (IsEventLogging() != MagickFalse)
626  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
627  return(magic_info->name);
628 }
629 
630 /*
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 % %
633 % %
634 % %
635 + I s M a g i c C a c h e I n s t a n t i a t e d %
636 % %
637 % %
638 % %
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
640 %
641 % IsMagicCacheInstantiated() determines if the magic list is instantiated.
642 % If not, it instantiates the list and returns it.
643 %
644 % The format of the IsMagicInstantiated method is:
645 %
646 % MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
647 %
648 % A description of each parameter follows.
649 %
650 % o exception: return any errors or warnings in this structure.
651 %
652 */
653 static MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
654 {
655  if (magic_cache == (LinkedListInfo *) NULL)
656  {
657  if (magic_semaphore == (SemaphoreInfo *) NULL)
658  ActivateSemaphoreInfo(&magic_semaphore);
659  LockSemaphoreInfo(magic_semaphore);
660  if (magic_cache == (LinkedListInfo *) NULL)
661  magic_cache=AcquireMagicCache(MagicFilename,exception);
662  UnlockSemaphoreInfo(magic_semaphore);
663  }
664  return(magic_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
665 }
666 
667 /*
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 % %
670 % %
671 % %
672 % L i s t M a g i c I n f o %
673 % %
674 % %
675 % %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 %
678 % ListMagicInfo() lists the magic info to a file.
679 %
680 % The format of the ListMagicInfo method is:
681 %
682 % MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
683 %
684 % A description of each parameter follows.
685 %
686 % o file: An pointer to a FILE.
687 %
688 % o exception: return any errors or warnings in this structure.
689 %
690 */
691 MagickExport MagickBooleanType ListMagicInfo(FILE *file,
692  ExceptionInfo *exception)
693 {
694  const char
695  *path;
696 
697  const MagicInfo
698  **magic_info;
699 
700  ssize_t
701  i;
702 
703  size_t
704  number_aliases;
705 
706  ssize_t
707  j;
708 
709  if (file == (const FILE *) NULL)
710  file=stdout;
711  magic_info=GetMagicInfoList("*",&number_aliases,exception);
712  if (magic_info == (const MagicInfo **) NULL)
713  return(MagickFalse);
714  j=0;
715  path=(const char *) NULL;
716  for (i=0; i < (ssize_t) number_aliases; i++)
717  {
718  if (magic_info[i]->stealth != MagickFalse)
719  continue;
720  if ((path == (const char *) NULL) ||
721  (LocaleCompare(path,magic_info[i]->path) != 0))
722  {
723  if (magic_info[i]->path != (char *) NULL)
724  (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
725  (void) FormatLocaleFile(file,"Name Offset Target\n");
726  (void) FormatLocaleFile(file,
727  "-------------------------------------------------"
728  "------------------------------\n");
729  }
730  path=magic_info[i]->path;
731  (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
732  for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
733  (void) FormatLocaleFile(file," ");
734  (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
735  if (magic_info[i]->target != (char *) NULL)
736  {
737  ssize_t
738  j;
739 
740  for (j=0; magic_info[i]->target[j] != '\0'; j++)
741  if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
742  (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
743  else
744  (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
745  ((unsigned char) magic_info[i]->target[j]));
746  }
747  (void) FormatLocaleFile(file,"\n");
748  }
749  (void) fflush(file);
750  magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
751  return(MagickTrue);
752 }
753 
754 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
755 /*
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 % %
758 % %
759 % %
760 + L o a d M a g i c C a c h e %
761 % %
762 % %
763 % %
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %
766 % LoadMagicCache() loads the magic configurations which provides a mapping
767 % between magic attributes and a magic name.
768 %
769 % The format of the LoadMagicCache method is:
770 %
771 % MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
772 % const char *filename,const size_t depth,ExceptionInfo *exception)
773 %
774 % A description of each parameter follows:
775 %
776 % o xml: The magic list in XML format.
777 %
778 % o filename: The magic list filename.
779 %
780 % o depth: depth of <include /> statements.
781 %
782 % o exception: return any errors or warnings in this structure.
783 %
784 */
785 static MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
786  const char *filename,const size_t depth,ExceptionInfo *exception)
787 {
788  char
789  keyword[MaxTextExtent],
790  *token;
791 
792  const char
793  *q;
794 
795  MagicInfo
796  *magic_info;
797 
798  MagickStatusType
799  status;
800 
801  size_t
802  extent;
803 
804  /*
805  Load the magic map file.
806  */
807  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
808  "Loading magic configure file \"%s\" ...",filename);
809  if (xml == (char *) NULL)
810  return(MagickFalse);
811  status=MagickTrue;
812  magic_info=(MagicInfo *) NULL;
813  token=AcquireString(xml);
814  extent=strlen(token)+MaxTextExtent;
815  for (q=(char *) xml; *q != '\0'; )
816  {
817  /*
818  Interpret XML.
819  */
820  (void) GetNextToken(q,&q,extent,token);
821  if (*token == '\0')
822  break;
823  (void) CopyMagickString(keyword,token,MaxTextExtent);
824  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
825  {
826  /*
827  Doctype element.
828  */
829  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
830  (void) GetNextToken(q,&q,extent,token);
831  continue;
832  }
833  if (LocaleNCompare(keyword,"<!--",4) == 0)
834  {
835  /*
836  Comment element.
837  */
838  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
839  (void) GetNextToken(q,&q,extent,token);
840  continue;
841  }
842  if (LocaleCompare(keyword,"<include") == 0)
843  {
844  /*
845  Include element.
846  */
847  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
848  {
849  (void) CopyMagickString(keyword,token,MaxTextExtent);
850  (void) GetNextToken(q,&q,extent,token);
851  if (*token != '=')
852  continue;
853  (void) GetNextToken(q,&q,extent,token);
854  if (LocaleCompare(keyword,"file") == 0)
855  {
856  if (depth > MagickMaxRecursionDepth)
857  (void) ThrowMagickException(exception,GetMagickModule(),
858  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
859  else
860  {
861  char
862  path[MaxTextExtent],
863  *xml;
864 
865  GetPathComponent(filename,HeadPath,path);
866  if (*path != '\0')
867  (void) ConcatenateMagickString(path,DirectorySeparator,
868  MaxTextExtent);
869  if (*token == *DirectorySeparator)
870  (void) CopyMagickString(path,token,MaxTextExtent);
871  else
872  (void) ConcatenateMagickString(path,token,MaxTextExtent);
873  xml=FileToXML(path,~0UL);
874  if (xml != (char *) NULL)
875  {
876  status&=LoadMagicCache(cache,xml,path,depth+1,
877  exception);
878  xml=(char *) RelinquishMagickMemory(xml);
879  }
880  }
881  }
882  }
883  continue;
884  }
885  if (LocaleCompare(keyword,"<magic") == 0)
886  {
887  /*
888  Magic element.
889  */
890  magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
891  if (magic_info == (MagicInfo *) NULL)
892  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
893  (void) memset(magic_info,0,sizeof(*magic_info));
894  magic_info->path=ConstantString(filename);
895  magic_info->exempt=MagickFalse;
896  magic_info->signature=MagickCoreSignature;
897  continue;
898  }
899  if (magic_info == (MagicInfo *) NULL)
900  continue;
901  if ((LocaleCompare(keyword,"/>") == 0) ||
902  (LocaleCompare(keyword,"</policy>") == 0))
903  {
904  status=AppendValueToLinkedList(cache,magic_info);
905  if (status == MagickFalse)
906  (void) ThrowMagickException(exception,GetMagickModule(),
907  ResourceLimitError,"MemoryAllocationFailed","`%s'",
908  magic_info->name);
909  magic_info=(MagicInfo *) NULL;
910  continue;
911  }
912  (void) GetNextToken(q,(const char **) NULL,extent,token);
913  if (*token != '=')
914  continue;
915  (void) GetNextToken(q,&q,extent,token);
916  (void) GetNextToken(q,&q,extent,token);
917  switch (*keyword)
918  {
919  case 'N':
920  case 'n':
921  {
922  if (LocaleCompare((char *) keyword,"name") == 0)
923  {
924  magic_info->name=ConstantString(token);
925  break;
926  }
927  break;
928  }
929  case 'O':
930  case 'o':
931  {
932  if (LocaleCompare((char *) keyword,"offset") == 0)
933  {
934  magic_info->offset=(MagickOffsetType) StringToLong(token);
935  break;
936  }
937  break;
938  }
939  case 'S':
940  case 's':
941  {
942  if (LocaleCompare((char *) keyword,"stealth") == 0)
943  {
944  magic_info->stealth=IsMagickTrue(token);
945  break;
946  }
947  break;
948  }
949  case 'T':
950  case 't':
951  {
952  if (LocaleCompare((char *) keyword,"target") == 0)
953  {
954  char
955  *p;
956 
957  unsigned char
958  *q;
959 
960  size_t
961  length;
962 
963  length=strlen(token);
964  magic_info->target=ConstantString(token);
965  magic_info->magic=(unsigned char *) ConstantString(token);
966  q=magic_info->magic;
967  for (p=magic_info->target; *p != '\0'; )
968  {
969  if (*p == '\\')
970  {
971  p++;
972  if (isdigit((int) ((unsigned char) *p)) != 0)
973  {
974  char
975  *end;
976 
977  *q++=(unsigned char) strtol(p,&end,8);
978  p+=(end-p);
979  magic_info->length++;
980  continue;
981  }
982  switch (*p)
983  {
984  case 'b': *q='\b'; break;
985  case 'f': *q='\f'; break;
986  case 'n': *q='\n'; break;
987  case 'r': *q='\r'; break;
988  case 't': *q='\t'; break;
989  case 'v': *q='\v'; break;
990  case 'a': *q='a'; break;
991  case '?': *q='\?'; break;
992  default: *q=(unsigned char) (*p); break;
993  }
994  p++;
995  q++;
996  magic_info->length++;
997  continue;
998  }
999  else
1000  if (LocaleNCompare(p,"&amp;",5) == 0)
1001  (void) CopyMagickString(p+1,p+5,length-magic_info->length);
1002  *q++=(unsigned char) (*p++);
1003  magic_info->length++;
1004  }
1005  break;
1006  }
1007  break;
1008  }
1009  default:
1010  break;
1011  }
1012  }
1013  token=(char *) RelinquishMagickMemory(token);
1014  return(status != 0 ? MagickTrue : MagickFalse);
1015 }
1016 #endif
1017 
1018 /*
1019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020 % %
1021 % %
1022 % %
1023 + M a g i c C o m p o n e n t G e n e s i s %
1024 % %
1025 % %
1026 % %
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028 %
1029 % MagicComponentGenesis() instantiates the magic component.
1030 %
1031 % The format of the MagicComponentGenesis method is:
1032 %
1033 % MagickBooleanType MagicComponentGenesis(void)
1034 %
1035 */
1036 MagickExport MagickBooleanType MagicComponentGenesis(void)
1037 {
1038  if (magic_semaphore == (SemaphoreInfo *) NULL)
1039  magic_semaphore=AllocateSemaphoreInfo();
1040  return(MagickTrue);
1041 }
1042 
1043 /*
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045 % %
1046 % %
1047 % %
1048 + M a g i c C o m p o n e n t T e r m i n u s %
1049 % %
1050 % %
1051 % %
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 %
1054 % MagicComponentTerminus() destroys the magic component.
1055 %
1056 % The format of the MagicComponentTerminus method is:
1057 %
1058 % MagicComponentTerminus(void)
1059 %
1060 */
1061 
1062 static void *DestroyMagicElement(void *magic_info)
1063 {
1064  MagicInfo
1065  *p;
1066 
1067  p=(MagicInfo *) magic_info;
1068  if (p->exempt == MagickFalse)
1069  {
1070  if (p->path != (char *) NULL)
1071  p->path=DestroyString(p->path);
1072  if (p->name != (char *) NULL)
1073  p->name=DestroyString(p->name);
1074  if (p->target != (char *) NULL)
1075  p->target=DestroyString(p->target);
1076  if (p->magic != (unsigned char *) NULL)
1077  p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1078  }
1079  p=(MagicInfo *) RelinquishMagickMemory(p);
1080  return((void *) NULL);
1081 }
1082 
1083 MagickExport void MagicComponentTerminus(void)
1084 {
1085  if (magic_semaphore == (SemaphoreInfo *) NULL)
1086  ActivateSemaphoreInfo(&magic_semaphore);
1087  LockSemaphoreInfo(magic_semaphore);
1088  if (magic_cache != (LinkedListInfo *) NULL)
1089  magic_cache=DestroyLinkedList(magic_cache,DestroyMagicElement);
1090  UnlockSemaphoreInfo(magic_semaphore);
1091  DestroySemaphoreInfo(&magic_semaphore);
1092 }