blob: 20c91db7da2baac423e30f28fa1f8c06df0e9feb [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
cristyb1860752011-03-14 00:27:46 +00005% %
cristy3ed852e2009-09-05 21:47:34 +00006% 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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/client.h"
45#include "MagickCore/configure.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
48#include "MagickCore/hashmap.h"
49#include "MagickCore/magic.h"
cristy5ff4eaf2011-09-03 01:38:02 +000050#include "MagickCore/magic-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#include "MagickCore/memory_.h"
52#include "MagickCore/semaphore.h"
53#include "MagickCore/string_.h"
54#include "MagickCore/string-private.h"
55#include "MagickCore/token.h"
56#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000057#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000058#include "MagickCore/xml-tree.h"
cristy3ed852e2009-09-05 21:47:34 +000059
60/*
61 Define declarations.
62*/
63#define MagicFilename "magic.xml"
cristy54a531d2009-10-21 17:58:01 +000064#define MagickString(magic) (const unsigned char *) (magic), sizeof(magic)-1
cristy3ed852e2009-09-05 21:47:34 +000065
66/*
cristy54a531d2009-10-21 17:58:01 +000067 Typedef declarations.
cristy3ed852e2009-09-05 21:47:34 +000068*/
cristy1ca3eb32009-10-15 18:41:54 +000069typedef struct _MagicMapInfo
70{
71 const char
72 *name;
73
cristye3e77a12009-10-16 00:47:21 +000074 const MagickOffsetType
75 offset;
76
cristybcdce3d2009-10-15 20:04:49 +000077 const unsigned char
cristy1ca3eb32009-10-15 18:41:54 +000078 *magic;
79
cristye3e77a12009-10-16 00:47:21 +000080 const size_t
cristy1ca3eb32009-10-15 18:41:54 +000081 length;
cristy1ca3eb32009-10-15 18:41:54 +000082} MagicMapInfo;
cristy54a531d2009-10-21 17:58:01 +000083
84/*
85 Static declarations.
86*/
cristy1ca3eb32009-10-15 18:41:54 +000087static const MagicMapInfo
88 MagicMap[] =
89 {
cristye3e77a12009-10-16 00:47:21 +000090 { "8BIMWTEXT", 0, MagickString("8\000B\000I\000M\000#") },
91 { "8BIMTEXT", 0, MagickString("8BIM#") },
92 { "8BIM", 0, MagickString("8BIM") },
93 { "BMP", 0, MagickString("BA") },
94 { "BMP", 0, MagickString("BM") },
95 { "BMP", 0, MagickString("CI") },
96 { "BMP", 0, MagickString("CP") },
97 { "BMP", 0, MagickString("IC") },
98 { "BMP", 0, MagickString("PI") },
99 { "CALS", 21, MagickString("version: MIL-STD-1840") },
100 { "CALS", 0, MagickString("srcdocid:") },
101 { "CALS", 9, MagickString("srcdocid:") },
102 { "CALS", 8, MagickString("rorient:") },
103 { "CGM", 0, MagickString("BEGMF") },
104 { "CIN", 0, MagickString("\200\052\137\327") },
105 { "CRW", 0, MagickString("II\x1a\x00\x00\x00HEAPCCDR") },
106 { "DCM", 128, MagickString("DICM") },
107 { "DCX", 0, MagickString("\261\150\336\72") },
108 { "DIB", 0, MagickString("\050\000") },
109 { "DDS", 0, MagickString("DDS ") },
110 { "DJVU", 0, MagickString("AT&TFORM") },
111 { "DOT", 0, MagickString("digraph") },
112 { "DPX", 0, MagickString("SDPX") },
113 { "DPX", 0, MagickString("XPDS") },
114 { "EMF", 40, MagickString("\040\105\115\106\000\000\001\000") },
115 { "EPT", 0, MagickString("\305\320\323\306") },
116 { "EXR", 0, MagickString("\166\057\061\001") },
117 { "FAX", 0, MagickString("DFAX") },
118 { "FIG", 0, MagickString("#FIG") },
119 { "FITS", 0, MagickString("IT0") },
120 { "FITS", 0, MagickString("SIMPLE") },
121 { "FPX", 0, MagickString("\320\317\021\340") },
122 { "GIF", 0, MagickString("GIF8") },
123 { "GPLT", 0, MagickString("#!/usr/local/bin/gnuplot") },
124 { "HDF", 1, MagickString("HDF") },
cristy03533f22011-03-06 23:30:17 +0000125 { "HDR", 0, MagickString("#?RADIANCE") },
cristy84c3d052011-03-07 19:22:02 +0000126 { "HDR", 0, MagickString("#?RGBE") },
cristye3e77a12009-10-16 00:47:21 +0000127 { "HPGL", 0, MagickString("IN;") },
cristye3e77a12009-10-16 00:47:21 +0000128 { "HTML", 1, MagickString("HTML") },
129 { "HTML", 1, MagickString("html") },
130 { "ILBM", 8, MagickString("ILBM") },
131 { "IPTCWTEXT", 0, MagickString("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
132 { "IPTCTEXT", 0, MagickString("2#0=\042�\042") },
133 { "IPTC", 0, MagickString("\034\002") },
134 { "JNG", 0, MagickString("\213JNG\r\n\032\n") },
135 { "JPEG", 0, MagickString("\377\330\377") },
136 { "JPC", 0, MagickString("\377\117") },
137 { "JP2", 4, MagickString("\152\120\040\040\015") },
cristya7cb4312010-06-26 00:47:03 +0000138 { "MAT", 0, MagickString("MATLAB 5.0 MAT-file,") },
cristye3e77a12009-10-16 00:47:21 +0000139 { "MIFF", 0, MagickString("Id=ImageMagick") },
140 { "MIFF", 0, MagickString("id=ImageMagick") },
141 { "MNG", 0, MagickString("\212MNG\r\n\032\n") },
142 { "MPC", 0, MagickString("id=MagickCache") },
143 { "MPEG", 0, MagickString("\000\000\001\263") },
144 { "MRW", 0, MagickString("\x00MRM") },
145 { "MVG", 0, MagickString("push graphic-context") },
146 { "ORF", 0, MagickString("IIRO\x08\x00\x00\x00") },
147 { "PCD", 2048, MagickString("PCD_") },
148 { "PCL", 0, MagickString("\033E\033") },
149 { "PCX", 0, MagickString("\012\002") },
150 { "PCX", 0, MagickString("\012\005") },
151 { "PDB", 60, MagickString("vIMGView") },
152 { "PDF", 0, MagickString("%PDF-") },
cristy7adb4db2010-01-24 17:14:03 +0000153 { "PES", 0, MagickString("#PES") },
cristye3e77a12009-10-16 00:47:21 +0000154 { "PFA", 0, MagickString("%!PS-AdobeFont-1.0") },
155 { "PFB", 6, MagickString("%!PS-AdobeFont-1.0") },
156 { "PGX", 0, MagickString("\050\107\020\115\046") },
157 { "PICT", 522, MagickString("\000\021\002\377\014\000") },
158 { "PNG", 0, MagickString("\211PNG\r\n\032\n") },
cristy34575212010-11-06 12:39:23 +0000159 { "PBM", 0, MagickString("P1") },
160 { "PGM", 0, MagickString("P2") },
161 { "PPM", 0, MagickString("P3") },
162 { "PBM", 0, MagickString("P4") },
163 { "PGM", 0, MagickString("P5") },
164 { "PPM", 0, MagickString("P6") },
165 { "PAM", 0, MagickString("P7") },
166 { "PFM", 0, MagickString("PF") },
167 { "PFM", 0, MagickString("Pf") },
cristye3e77a12009-10-16 00:47:21 +0000168 { "PS", 0, MagickString("%!") },
169 { "PS", 0, MagickString("\004%!") },
170 { "PS", 0, MagickString("\305\320\323\306") },
cristyb4233012010-02-28 20:09:14 +0000171 { "PSB", 0, MagickString("8BPB") },
cristye3e77a12009-10-16 00:47:21 +0000172 { "PSD", 0, MagickString("8BPS") },
173 { "PWP", 0, MagickString("SFW95") },
174 { "RAF", 0, MagickString("FUJIFILMCCD-RAW ") },
cristye3e77a12009-10-16 00:47:21 +0000175 { "RLE", 0, MagickString("\122\314") },
176 { "SCT", 0, MagickString("CT") },
177 { "SFW", 0, MagickString("SFW94") },
178 { "SGI", 0, MagickString("\001\332") },
179 { "SUN", 0, MagickString("\131\246\152\225") },
180 { "SVG", 1, MagickString("?XML") },
181 { "SVG", 1, MagickString("?xml") },
182 { "TIFF", 0, MagickString("\115\115\000\052") },
183 { "TIFF", 0, MagickString("\111\111\052\000") },
184 { "TIFF64", 0, MagickString("\115\115\000\053\000\010\000\000") },
185 { "TIFF64", 0, MagickString("\111\111\053\000\010\000\000\000") },
186 { "TXT", 0, MagickString("# ImageMagick pixel enumeration:") },
187 { "VICAR", 0, MagickString("LBLSIZE") },
188 { "VICAR", 0, MagickString("NJPL1I") },
189 { "VIFF", 0, MagickString("\253\001") },
cristy56dd2cd2010-10-11 00:45:14 +0000190 { "WEBP", 8, MagickString("WEBP") },
cristye3e77a12009-10-16 00:47:21 +0000191 { "WMF", 0, MagickString("\327\315\306\232") },
192 { "WMF", 0, MagickString("\001\000\011\000") },
193 { "WPG", 0, MagickString("\377WPC") },
194 { "XBM", 0, MagickString("#define") },
195 { "XCF", 0, MagickString("gimp xcf") },
196 { "XEF", 0, MagickString("FOVb") },
197 { "XPM", 1, MagickString("* XPM *") },
198 { "XWD", 4, MagickString("\007\000\000") },
cristy54a531d2009-10-21 17:58:01 +0000199 { "XWD", 5, MagickString("\000\000\007") }
cristy1ca3eb32009-10-15 18:41:54 +0000200 };
cristy3ed852e2009-09-05 21:47:34 +0000201
202static LinkedListInfo
203 *magic_list = (LinkedListInfo *) NULL;
204
205static SemaphoreInfo
206 *magic_semaphore = (SemaphoreInfo *) NULL;
207
208static volatile MagickBooleanType
209 instantiate_magic = MagickFalse;
210
211/*
212 Forward declarations.
213*/
214static MagickBooleanType
215 InitializeMagicList(ExceptionInfo *),
216 LoadMagicLists(const char *,ExceptionInfo *);
217
218/*
219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220% %
221% %
222% %
cristy3ed852e2009-09-05 21:47:34 +0000223+ G e t M a g i c I n f o %
224% %
225% %
226% %
227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228%
229% GetMagicInfo() searches the magic list for the specified name and if found
230% returns attributes for that magic.
231%
232% The format of the GetMagicInfo method is:
233%
234% const MagicInfo *GetMagicInfo(const unsigned char *magic,
235% const size_t length,ExceptionInfo *exception)
236%
237% A description of each parameter follows:
238%
239% o magic: A binary string generally representing the first few characters
240% of the image file or blob.
241%
242% o length: the length of the binary signature.
243%
244% o exception: return any errors or warnings in this structure.
245%
246*/
247MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
248 const size_t length,ExceptionInfo *exception)
249{
250 register const MagicInfo
251 *p;
252
253 assert(exception != (ExceptionInfo *) NULL);
254 if ((magic_list == (LinkedListInfo *) NULL) ||
255 (instantiate_magic == MagickFalse))
256 if (InitializeMagicList(exception) == MagickFalse)
257 return((const MagicInfo *) NULL);
258 if ((magic_list == (LinkedListInfo *) NULL) ||
259 (IsLinkedListEmpty(magic_list) != MagickFalse))
260 return((const MagicInfo *) NULL);
261 if (magic == (const unsigned char *) NULL)
262 return((const MagicInfo *) GetValueFromLinkedList(magic_list,0));
263 if (length == 0)
264 return((const MagicInfo *) NULL);
265 /*
266 Search for magic tag.
267 */
cristyf84a1932010-01-03 18:00:18 +0000268 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000269 ResetLinkedListIterator(magic_list);
270 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
271 while (p != (const MagicInfo *) NULL)
272 {
273 assert(p->offset >= 0);
274 if (((size_t) (p->offset+p->length) <= length) &&
275 (memcmp(magic+p->offset,p->magic,p->length) == 0))
276 break;
277 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
278 }
279 if (p != (const MagicInfo *) NULL)
280 (void) InsertValueInLinkedList(magic_list,0,
281 RemoveElementByValueFromLinkedList(magic_list,p));
cristyf84a1932010-01-03 18:00:18 +0000282 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000283 return(p);
284}
285
286/*
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288% %
289% %
290% %
291% G e t M a g i c I n f o L i s t %
292% %
293% %
294% %
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296%
297% GetMagicInfoList() returns any image aliases that match the specified
298% pattern.
299%
300% The magic of the GetMagicInfoList function is:
301%
302% const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000303% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000304%
305% A description of each parameter follows:
306%
307% o pattern: Specifies a pointer to a text string containing a pattern.
308%
cristyfc0d1122009-10-17 20:22:37 +0000309% o number_aliases: This integer returns the number of aliases in the list.
cristy3ed852e2009-09-05 21:47:34 +0000310%
311% o exception: return any errors or warnings in this structure.
312%
313*/
314
315#if defined(__cplusplus) || defined(c_plusplus)
316extern "C" {
317#endif
318
319static int MagicInfoCompare(const void *x,const void *y)
320{
321 const MagicInfo
322 **p,
323 **q;
324
325 p=(const MagicInfo **) x,
326 q=(const MagicInfo **) y;
327 if (LocaleCompare((*p)->path,(*q)->path) == 0)
328 return(LocaleCompare((*p)->name,(*q)->name));
329 return(LocaleCompare((*p)->path,(*q)->path));
330}
331
332#if defined(__cplusplus) || defined(c_plusplus)
333}
334#endif
335
336MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000337 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000338{
339 const MagicInfo
340 **aliases;
341
342 register const MagicInfo
343 *p;
344
cristybb503372010-05-27 20:51:26 +0000345 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000346 i;
347
348 /*
349 Allocate magic list.
350 */
351 assert(pattern != (char *) NULL);
352 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000353 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000354 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000355 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000356 if (p == (const MagicInfo *) NULL)
357 return((const MagicInfo **) NULL);
358 aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
359 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
360 if (aliases == (const MagicInfo **) NULL)
361 return((const MagicInfo **) NULL);
362 /*
363 Generate magic list.
364 */
cristyf84a1932010-01-03 18:00:18 +0000365 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000366 ResetLinkedListIterator(magic_list);
367 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
368 for (i=0; p != (const MagicInfo *) NULL; )
369 {
370 if ((p->stealth == MagickFalse) &&
371 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
372 aliases[i++]=p;
373 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
374 }
cristyf84a1932010-01-03 18:00:18 +0000375 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000376 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
377 aliases[i]=(MagicInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000378 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000379 return(aliases);
380}
381
382/*
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384% %
385% %
386% %
387% G e t M a g i c L i s t %
388% %
389% %
390% %
391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392%
393% GetMagicList() returns any image format aliases that match the specified
394% pattern.
395%
396% The format of the GetMagicList function is:
397%
cristybb503372010-05-27 20:51:26 +0000398% char **GetMagicList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000399% ExceptionInfo *exception)
400%
401% A description of each parameter follows:
402%
403% o pattern: Specifies a pointer to a text string containing a pattern.
404%
405% o number_aliases: This integer returns the number of image format aliases
406% in the list.
407%
408% o exception: return any errors or warnings in this structure.
409%
410*/
411
412#if defined(__cplusplus) || defined(c_plusplus)
413extern "C" {
414#endif
415
416static int MagicCompare(const void *x,const void *y)
417{
418 register const char
419 *p,
420 *q;
421
422 p=(const char *) x;
423 q=(const char *) y;
424 return(LocaleCompare(p,q));
425}
426
427#if defined(__cplusplus) || defined(c_plusplus)
428}
429#endif
430
431MagickExport char **GetMagicList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000432 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000433{
434 char
435 **aliases;
436
437 register const MagicInfo
438 *p;
439
cristybb503372010-05-27 20:51:26 +0000440 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000441 i;
442
443 /*
444 Allocate configure list.
445 */
446 assert(pattern != (char *) NULL);
447 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000448 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000449 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000450 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000451 if (p == (const MagicInfo *) NULL)
452 return((char **) NULL);
453 aliases=(char **) AcquireQuantumMemory((size_t)
454 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
455 if (aliases == (char **) NULL)
456 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000457 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000458 ResetLinkedListIterator(magic_list);
459 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
460 for (i=0; p != (const MagicInfo *) NULL; )
461 {
462 if ((p->stealth == MagickFalse) &&
463 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
464 aliases[i++]=ConstantString(p->name);
465 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
466 }
cristyf84a1932010-01-03 18:00:18 +0000467 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000468 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
469 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000470 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000471 return(aliases);
472}
473
474/*
475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476% %
477% %
478% %
479% G e t M a g i c N a m e %
480% %
481% %
482% %
483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484%
485% GetMagicName() returns the name associated with the magic.
486%
487% The format of the GetMagicName method is:
488%
489% const char *GetMagicName(const MagicInfo *magic_info)
490%
491% A description of each parameter follows:
492%
493% o magic_info: The magic info.
494%
495*/
496MagickExport const char *GetMagicName(const MagicInfo *magic_info)
497{
498 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
499 assert(magic_info != (MagicInfo *) NULL);
500 assert(magic_info->signature == MagickSignature);
501 return(magic_info->name);
502}
503
504/*
505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506% %
507% %
508% %
509+ I n i t i a l i z e M a g i c L i s t %
510% %
511% %
512% %
513%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514%
515% InitializeMagicList() initializes the magic list.
516%
517% The format of the InitializeMagicList method is:
518%
519% MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
520%
521% A description of each parameter follows.
522%
523% o exception: return any errors or warnings in this structure.
524%
525*/
526static MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
527{
528 if ((magic_list == (LinkedListInfo *) NULL) &&
529 (instantiate_magic == MagickFalse))
530 {
cristy4e1dff62009-10-25 20:36:03 +0000531 if (magic_semaphore == (SemaphoreInfo *) NULL)
532 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000533 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000534 if ((magic_list == (LinkedListInfo *) NULL) &&
535 (instantiate_magic == MagickFalse))
536 {
537 (void) LoadMagicLists(MagicFilename,exception);
538 instantiate_magic=MagickTrue;
539 }
cristyf84a1932010-01-03 18:00:18 +0000540 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000541 }
542 return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
543}
544
545/*
546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547% %
548% %
549% %
550% L i s t M a g i c I n f o %
551% %
552% %
553% %
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555%
556% ListMagicInfo() lists the magic info to a file.
557%
558% The format of the ListMagicInfo method is:
559%
560% MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
561%
562% A description of each parameter follows.
563%
564% o file: An pointer to a FILE.
565%
566% o exception: return any errors or warnings in this structure.
567%
568*/
569MagickExport MagickBooleanType ListMagicInfo(FILE *file,
570 ExceptionInfo *exception)
571{
572 const char
573 *path;
574
575 const MagicInfo
576 **magic_info;
577
cristybb503372010-05-27 20:51:26 +0000578 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000579 i;
580
cristybb503372010-05-27 20:51:26 +0000581 size_t
cristy3ed852e2009-09-05 21:47:34 +0000582 number_aliases;
583
cristy9d314ff2011-03-09 01:30:28 +0000584 ssize_t
585 j;
586
cristy3ed852e2009-09-05 21:47:34 +0000587 if (file == (const FILE *) NULL)
588 file=stdout;
589 magic_info=GetMagicInfoList("*",&number_aliases,exception);
590 if (magic_info == (const MagicInfo **) NULL)
591 return(MagickFalse);
592 j=0;
593 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000594 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000595 {
596 if (magic_info[i]->stealth != MagickFalse)
597 continue;
598 if ((path == (const char *) NULL) ||
599 (LocaleCompare(path,magic_info[i]->path) != 0))
600 {
601 if (magic_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000602 (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
603 (void) FormatLocaleFile(file,"Name Offset Target\n");
cristy1e604812011-05-19 18:07:50 +0000604 (void) FormatLocaleFile(file,
605 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000606 "------------------------------\n");
607 }
608 path=magic_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000609 (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
cristybb503372010-05-27 20:51:26 +0000610 for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
cristyb51dff52011-05-19 16:55:47 +0000611 (void) FormatLocaleFile(file," ");
612 (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
cristy3ed852e2009-09-05 21:47:34 +0000613 if (magic_info[i]->target != (char *) NULL)
cristy1ca3eb32009-10-15 18:41:54 +0000614 {
cristybb503372010-05-27 20:51:26 +0000615 register ssize_t
cristy1ca3eb32009-10-15 18:41:54 +0000616 j;
617
618 for (j=0; magic_info[i]->target[j] != '\0'; j++)
619 if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
cristyb51dff52011-05-19 16:55:47 +0000620 (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
cristy1ca3eb32009-10-15 18:41:54 +0000621 else
cristyb51dff52011-05-19 16:55:47 +0000622 (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
cristy50931922009-10-15 18:59:59 +0000623 ((unsigned char) magic_info[i]->target[j]));
cristy1ca3eb32009-10-15 18:41:54 +0000624 }
cristyb51dff52011-05-19 16:55:47 +0000625 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000626 }
627 (void) fflush(file);
628 magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
629 return(MagickTrue);
630}
631
632/*
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634% %
635% %
636% %
637+ L o a d M a g i c L i s t %
638% %
639% %
640% %
641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642%
643% LoadMagicList() loads the magic configuration file which provides a mapping
644% between magic attributes and a magic name.
645%
646% The format of the LoadMagicList method is:
647%
648% MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000649% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000650%
651% A description of each parameter follows:
652%
cristy1ca3eb32009-10-15 18:41:54 +0000653% o xml: The magic list in XML format.
cristy3ed852e2009-09-05 21:47:34 +0000654%
cristy1ca3eb32009-10-15 18:41:54 +0000655% o filename: The magic list filename.
cristy3ed852e2009-09-05 21:47:34 +0000656%
657% o depth: depth of <include /> statements.
658%
659% o exception: return any errors or warnings in this structure.
660%
661*/
662static MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000663 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000664{
665 char
666 keyword[MaxTextExtent],
667 *token;
668
669 const char
670 *q;
671
672 MagickBooleanType
673 status;
674
675 MagicInfo
676 *magic_info;
677
678 /*
679 Load the magic map file.
680 */
681 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
682 "Loading magic configure file \"%s\" ...",filename);
683 if (xml == (char *) NULL)
684 return(MagickFalse);
685 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000686 {
687 magic_list=NewLinkedList(0);
688 if (magic_list == (LinkedListInfo *) NULL)
689 {
690 ThrowFileException(exception,ResourceLimitError,
691 "MemoryAllocationFailed",filename);
692 return(MagickFalse);
693 }
694 }
cristy3ed852e2009-09-05 21:47:34 +0000695 status=MagickTrue;
696 magic_info=(MagicInfo *) NULL;
697 token=AcquireString(xml);
698 for (q=(char *) xml; *q != '\0'; )
699 {
700 /*
701 Interpret XML.
702 */
703 GetMagickToken(q,&q,token);
704 if (*token == '\0')
705 break;
706 (void) CopyMagickString(keyword,token,MaxTextExtent);
707 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
708 {
709 /*
710 Doctype element.
711 */
712 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
713 GetMagickToken(q,&q,token);
714 continue;
715 }
716 if (LocaleNCompare(keyword,"<!--",4) == 0)
717 {
718 /*
719 Comment element.
720 */
721 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
722 GetMagickToken(q,&q,token);
723 continue;
724 }
725 if (LocaleCompare(keyword,"<include") == 0)
726 {
727 /*
728 Include element.
729 */
730 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
731 {
732 (void) CopyMagickString(keyword,token,MaxTextExtent);
733 GetMagickToken(q,&q,token);
734 if (*token != '=')
735 continue;
736 GetMagickToken(q,&q,token);
737 if (LocaleCompare(keyword,"file") == 0)
738 {
739 if (depth > 200)
740 (void) ThrowMagickException(exception,GetMagickModule(),
741 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
742 else
743 {
744 char
745 path[MaxTextExtent],
746 *xml;
747
748 GetPathComponent(filename,HeadPath,path);
749 if (*path != '\0')
750 (void) ConcatenateMagickString(path,DirectorySeparator,
751 MaxTextExtent);
752 if (*token == *DirectorySeparator)
753 (void) CopyMagickString(path,token,MaxTextExtent);
754 else
755 (void) ConcatenateMagickString(path,token,MaxTextExtent);
756 xml=FileToString(path,~0,exception);
757 if (xml != (char *) NULL)
758 {
759 status=LoadMagicList(xml,path,depth+1,exception);
760 xml=(char *) RelinquishMagickMemory(xml);
761 }
762 }
763 }
764 }
765 continue;
766 }
767 if (LocaleCompare(keyword,"<magic") == 0)
768 {
769 /*
770 Magic element.
771 */
cristy73bd4a52010-10-05 11:24:23 +0000772 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy3ed852e2009-09-05 21:47:34 +0000773 if (magic_info == (MagicInfo *) NULL)
774 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
775 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
776 magic_info->path=ConstantString(filename);
cristye3e77a12009-10-16 00:47:21 +0000777 magic_info->exempt=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000778 magic_info->signature=MagickSignature;
779 continue;
780 }
781 if (magic_info == (MagicInfo *) NULL)
782 continue;
783 if (LocaleCompare(keyword,"/>") == 0)
784 {
785 status=AppendValueToLinkedList(magic_list,magic_info);
786 if (status == MagickFalse)
787 (void) ThrowMagickException(exception,GetMagickModule(),
788 ResourceLimitError,"MemoryAllocationFailed","`%s'",
789 magic_info->name);
790 magic_info=(MagicInfo *) NULL;
791 }
792 GetMagickToken(q,(const char **) NULL,token);
793 if (*token != '=')
794 continue;
795 GetMagickToken(q,&q,token);
796 GetMagickToken(q,&q,token);
797 switch (*keyword)
798 {
799 case 'N':
800 case 'n':
801 {
802 if (LocaleCompare((char *) keyword,"name") == 0)
803 {
804 magic_info->name=ConstantString(token);
805 break;
806 }
807 break;
808 }
809 case 'O':
810 case 'o':
811 {
812 if (LocaleCompare((char *) keyword,"offset") == 0)
813 {
cristyf2f27272009-12-17 14:48:46 +0000814 magic_info->offset=(MagickOffsetType) StringToLong(token);
cristy3ed852e2009-09-05 21:47:34 +0000815 break;
816 }
817 break;
818 }
819 case 'S':
820 case 's':
821 {
822 if (LocaleCompare((char *) keyword,"stealth") == 0)
823 {
824 magic_info->stealth=IsMagickTrue(token);
825 break;
826 }
827 break;
828 }
829 case 'T':
830 case 't':
831 {
832 if (LocaleCompare((char *) keyword,"target") == 0)
833 {
834 char
835 *p;
836
837 register unsigned char
838 *q;
839
840 size_t
841 length;
842
843 length=strlen(token);
844 magic_info->target=ConstantString(token);
845 magic_info->magic=(unsigned char *) ConstantString(token);
846 q=magic_info->magic;
847 for (p=magic_info->target; *p != '\0'; )
848 {
849 if (*p == '\\')
850 {
851 p++;
852 if (isdigit((int) ((unsigned char) *p)) != 0)
853 {
854 char
855 *end;
856
857 *q++=(unsigned char) strtol(p,&end,8);
858 p+=(end-p);
859 magic_info->length++;
860 continue;
861 }
862 switch (*p)
863 {
864 case 'b': *q='\b'; break;
865 case 'f': *q='\f'; break;
866 case 'n': *q='\n'; break;
867 case 'r': *q='\r'; break;
868 case 't': *q='\t'; break;
869 case 'v': *q='\v'; break;
870 case 'a': *q='a'; break;
871 case '?': *q='\?'; break;
872 default: *q=(unsigned char) (*p); break;
873 }
874 p++;
875 q++;
876 magic_info->length++;
877 continue;
878 }
879 else
880 if (LocaleNCompare(p,"&amp;",5) == 0)
881 (void) CopyMagickString(p+1,p+5,length-magic_info->length);
882 *q++=(unsigned char) (*p++);
883 magic_info->length++;
884 }
885 break;
886 }
887 break;
888 }
889 default:
890 break;
891 }
892 }
893 token=(char *) RelinquishMagickMemory(token);
894 return(status);
895}
896
897/*
898%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899% %
900% %
901% %
902% L o a d M a g i c L i s t s %
903% %
904% %
905% %
906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907%
908% LoadMagicLists() loads one or more magic configuration file which provides a
909% mapping between magic attributes and a magic name.
910%
911% The format of the LoadMagicLists method is:
912%
913% MagickBooleanType LoadMagicLists(const char *filename,
914% ExceptionInfo *exception)
915%
916% A description of each parameter follows:
917%
918% o filename: the font file name.
919%
920% o exception: return any errors or warnings in this structure.
921%
922*/
923static MagickBooleanType LoadMagicLists(const char *filename,
924 ExceptionInfo *exception)
925{
cristy3ed852e2009-09-05 21:47:34 +0000926 char
927 path[MaxTextExtent];
928
929 const StringInfo
930 *option;
931
932 LinkedListInfo
933 *options;
934
935 MagickStatusType
936 status;
937
cristybb503372010-05-27 20:51:26 +0000938 register ssize_t
cristy54a531d2009-10-21 17:58:01 +0000939 i;
cristy1ca3eb32009-10-15 18:41:54 +0000940
941 /*
942 Load built-in magic map.
943 */
cristy3ed852e2009-09-05 21:47:34 +0000944 status=MagickFalse;
cristy1ca3eb32009-10-15 18:41:54 +0000945 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000946 {
947 magic_list=NewLinkedList(0);
948 if (magic_list == (LinkedListInfo *) NULL)
949 {
950 ThrowFileException(exception,ResourceLimitError,
951 "MemoryAllocationFailed",filename);
952 return(MagickFalse);
953 }
954 }
cristybb503372010-05-27 20:51:26 +0000955 for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
cristy1ca3eb32009-10-15 18:41:54 +0000956 {
957 MagicInfo
958 *magic_info;
959
cristy54a531d2009-10-21 17:58:01 +0000960 register const MagicMapInfo
961 *p;
962
963 p=MagicMap+i;
cristy73bd4a52010-10-05 11:24:23 +0000964 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy1ca3eb32009-10-15 18:41:54 +0000965 if (magic_info == (MagicInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000966 {
967 (void) ThrowMagickException(exception,GetMagickModule(),
968 ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
969 continue;
970 }
cristy1ca3eb32009-10-15 18:41:54 +0000971 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
cristy38b8ed92009-10-16 01:20:21 +0000972 magic_info->path=(char *) "[built-in]";
cristy1ca3eb32009-10-15 18:41:54 +0000973 magic_info->name=(char *) p->name;
974 magic_info->offset=p->offset;
975 magic_info->target=(char *) p->magic;
cristye3e77a12009-10-16 00:47:21 +0000976 magic_info->magic=(unsigned char *) p->magic;
cristy1ca3eb32009-10-15 18:41:54 +0000977 magic_info->length=p->length;
978 magic_info->exempt=MagickTrue;
979 magic_info->signature=MagickSignature;
980 status=AppendValueToLinkedList(magic_list,magic_info);
981 if (status == MagickFalse)
982 (void) ThrowMagickException(exception,GetMagickModule(),
983 ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
984 }
985 /*
986 Load external magic map.
987 */
cristy3ed852e2009-09-05 21:47:34 +0000988 *path='\0';
989 options=GetConfigureOptions(filename,exception);
990 option=(const StringInfo *) GetNextValueInLinkedList(options);
991 while (option != (const StringInfo *) NULL)
992 {
993 (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
994 status|=LoadMagicList((const char *) GetStringInfoDatum(option),
995 GetStringInfoPath(option),0,exception);
996 option=(const StringInfo *) GetNextValueInLinkedList(options);
997 }
998 options=DestroyConfigureOptions(options);
cristy3ed852e2009-09-05 21:47:34 +0000999 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001000}
cristyf34a1452009-10-24 22:29:27 +00001001
1002/*
1003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004% %
1005% %
1006% %
1007+ M a g i c C o m p o n e n t G e n e s i s %
1008% %
1009% %
1010% %
1011%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012%
1013% MagicComponentGenesis() instantiates the magic component.
1014%
1015% The format of the MagicComponentGenesis method is:
1016%
1017% MagickBooleanType MagicComponentGenesis(void)
1018%
1019*/
cristy5ff4eaf2011-09-03 01:38:02 +00001020MagickPrivate MagickBooleanType MagicComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +00001021{
cristy165b6092009-10-26 13:52:10 +00001022 AcquireSemaphoreInfo(&magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001023 return(MagickTrue);
1024}
1025
1026/*
1027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028% %
1029% %
1030% %
1031+ M a g i c C o m p o n e n t T e r m i n u s %
1032% %
1033% %
1034% %
1035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036%
1037% MagicComponentTerminus() destroys the magic component.
1038%
1039% The format of the MagicComponentTerminus method is:
1040%
1041% MagicComponentTerminus(void)
1042%
1043*/
1044
1045static void *DestroyMagicElement(void *magic_info)
1046{
1047 register MagicInfo
1048 *p;
1049
1050 p=(MagicInfo *) magic_info;
1051 if (p->exempt == MagickFalse)
1052 {
1053 if (p->path != (char *) NULL)
1054 p->path=DestroyString(p->path);
1055 if (p->name != (char *) NULL)
1056 p->name=DestroyString(p->name);
1057 if (p->target != (char *) NULL)
1058 p->target=DestroyString(p->target);
1059 if (p->magic != (unsigned char *) NULL)
1060 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1061 }
1062 p=(MagicInfo *) RelinquishMagickMemory(p);
1063 return((void *) NULL);
1064}
1065
cristy5ff4eaf2011-09-03 01:38:02 +00001066MagickPrivate void MagicComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +00001067{
cristy18b17442009-10-25 18:36:48 +00001068 if (magic_semaphore == (SemaphoreInfo *) NULL)
1069 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001070 LockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001071 if (magic_list != (LinkedListInfo *) NULL)
1072 magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
1073 instantiate_magic=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001074 UnlockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001075 DestroySemaphoreInfo(&magic_semaphore);
1076}