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