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