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