MagickCore 6.9.13-20
Convert, Edit, Or Compose Bitmap Images
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 { "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
214static LinkedListInfo
215 *magic_cache = (LinkedListInfo *) NULL;
216
217static SemaphoreInfo
218 *magic_semaphore = (SemaphoreInfo *) NULL;
219
220/*
221 Forward declarations.
222*/
223static MagickBooleanType
224 IsMagicCacheInstantiated(ExceptionInfo *);
225
226#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
227static 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*/
258static int CompareMagickInfoSize(const void *a,const void *b)
259{
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
271static 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 {
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*/
380MagickExport 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)
459extern "C" {
460#endif
461
462static 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
479MagickExport 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)
557extern "C" {
558#endif
559
560static 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
575MagickExport 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*/
641MagickExport 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*/
673static 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*/
711MagickExport 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*/
805static 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
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+=(ptrdiff_t) (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*/
1056MagickExport 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
1082static 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
1103MagickExport 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}