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