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