blob: f2d7b7abf1f8d51ad51df6678811ed71be07af16 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% M M AAA GGGG IIIII CCCC %
6% MM MM A A G I C %
7% M M M AAAAA G GGG I C %
8% M M A A G G I C %
9% M M A A GGGG IIIII CCCC %
10% %
11% %
12% MagickCore Image Magic Methods %
13% %
14% Software Design %
15% Bob Friesenhahn %
16% July 2000 %
17% %
18% %
cristy7e41fe82010-12-04 23:12:08 +000019% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000020% dedicated to making software imaging solutions freely available. %
21% %
22% You may not use this file except in compliance with the License. You may %
23% obtain a copy of the License at %
24% %
25% http://www.imagemagick.org/script/license.php %
26% %
27% Unless required by applicable law or agreed to in writing, software %
28% distributed under the License is distributed on an "AS IS" BASIS, %
29% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
30% See the License for the specific language governing permissions and %
31% limitations under the License. %
32% %
33%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34%
35%
36*/
37
38/*
39 Include declarations.
40*/
41#include "magick/studio.h"
42#include "magick/blob.h"
43#include "magick/client.h"
44#include "magick/configure.h"
45#include "magick/exception.h"
46#include "magick/exception-private.h"
47#include "magick/hashmap.h"
48#include "magick/magic.h"
49#include "magick/memory_.h"
50#include "magick/semaphore.h"
51#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000052#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/token.h"
54#include "magick/utility.h"
55#include "magick/xml-tree.h"
56
57/*
58 Define declarations.
59*/
60#define MagicFilename "magic.xml"
cristy54a531d2009-10-21 17:58:01 +000061#define MagickString(magic) (const unsigned char *) (magic), sizeof(magic)-1
cristy3ed852e2009-09-05 21:47:34 +000062
63/*
cristy54a531d2009-10-21 17:58:01 +000064 Typedef declarations.
cristy3ed852e2009-09-05 21:47:34 +000065*/
cristy1ca3eb32009-10-15 18:41:54 +000066typedef struct _MagicMapInfo
67{
68 const char
69 *name;
70
cristye3e77a12009-10-16 00:47:21 +000071 const MagickOffsetType
72 offset;
73
cristybcdce3d2009-10-15 20:04:49 +000074 const unsigned char
cristy1ca3eb32009-10-15 18:41:54 +000075 *magic;
76
cristye3e77a12009-10-16 00:47:21 +000077 const size_t
cristy1ca3eb32009-10-15 18:41:54 +000078 length;
cristy1ca3eb32009-10-15 18:41:54 +000079} MagicMapInfo;
cristy54a531d2009-10-21 17:58:01 +000080
81/*
82 Static declarations.
83*/
cristy1ca3eb32009-10-15 18:41:54 +000084static const MagicMapInfo
85 MagicMap[] =
86 {
cristye3e77a12009-10-16 00:47:21 +000087 { "AVI", 0, MagickString("RIFF") },
88 { "8BIMWTEXT", 0, MagickString("8\000B\000I\000M\000#") },
89 { "8BIMTEXT", 0, MagickString("8BIM#") },
90 { "8BIM", 0, MagickString("8BIM") },
91 { "BMP", 0, MagickString("BA") },
92 { "BMP", 0, MagickString("BM") },
93 { "BMP", 0, MagickString("CI") },
94 { "BMP", 0, MagickString("CP") },
95 { "BMP", 0, MagickString("IC") },
96 { "BMP", 0, MagickString("PI") },
97 { "CALS", 21, MagickString("version: MIL-STD-1840") },
98 { "CALS", 0, MagickString("srcdocid:") },
99 { "CALS", 9, MagickString("srcdocid:") },
100 { "CALS", 8, MagickString("rorient:") },
101 { "CGM", 0, MagickString("BEGMF") },
102 { "CIN", 0, MagickString("\200\052\137\327") },
103 { "CRW", 0, MagickString("II\x1a\x00\x00\x00HEAPCCDR") },
104 { "DCM", 128, MagickString("DICM") },
105 { "DCX", 0, MagickString("\261\150\336\72") },
106 { "DIB", 0, MagickString("\050\000") },
107 { "DDS", 0, MagickString("DDS ") },
108 { "DJVU", 0, MagickString("AT&TFORM") },
109 { "DOT", 0, MagickString("digraph") },
110 { "DPX", 0, MagickString("SDPX") },
111 { "DPX", 0, MagickString("XPDS") },
112 { "EMF", 40, MagickString("\040\105\115\106\000\000\001\000") },
113 { "EPT", 0, MagickString("\305\320\323\306") },
114 { "EXR", 0, MagickString("\166\057\061\001") },
115 { "FAX", 0, MagickString("DFAX") },
116 { "FIG", 0, MagickString("#FIG") },
117 { "FITS", 0, MagickString("IT0") },
118 { "FITS", 0, MagickString("SIMPLE") },
119 { "FPX", 0, MagickString("\320\317\021\340") },
120 { "GIF", 0, MagickString("GIF8") },
121 { "GPLT", 0, MagickString("#!/usr/local/bin/gnuplot") },
122 { "HDF", 1, MagickString("HDF") },
123 { "HPGL", 0, MagickString("IN;") },
cristye3e77a12009-10-16 00:47:21 +0000124 { "HTML", 1, MagickString("HTML") },
125 { "HTML", 1, MagickString("html") },
126 { "ILBM", 8, MagickString("ILBM") },
127 { "IPTCWTEXT", 0, MagickString("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
128 { "IPTCTEXT", 0, MagickString("2#0=\042�\042") },
129 { "IPTC", 0, MagickString("\034\002") },
130 { "JNG", 0, MagickString("\213JNG\r\n\032\n") },
131 { "JPEG", 0, MagickString("\377\330\377") },
132 { "JPC", 0, MagickString("\377\117") },
133 { "JP2", 4, MagickString("\152\120\040\040\015") },
cristya7cb4312010-06-26 00:47:03 +0000134 { "MAT", 0, MagickString("MATLAB 5.0 MAT-file,") },
cristye3e77a12009-10-16 00:47:21 +0000135 { "MIFF", 0, MagickString("Id=ImageMagick") },
136 { "MIFF", 0, MagickString("id=ImageMagick") },
137 { "MNG", 0, MagickString("\212MNG\r\n\032\n") },
138 { "MPC", 0, MagickString("id=MagickCache") },
139 { "MPEG", 0, MagickString("\000\000\001\263") },
140 { "MRW", 0, MagickString("\x00MRM") },
141 { "MVG", 0, MagickString("push graphic-context") },
142 { "ORF", 0, MagickString("IIRO\x08\x00\x00\x00") },
143 { "PCD", 2048, MagickString("PCD_") },
144 { "PCL", 0, MagickString("\033E\033") },
145 { "PCX", 0, MagickString("\012\002") },
146 { "PCX", 0, MagickString("\012\005") },
147 { "PDB", 60, MagickString("vIMGView") },
148 { "PDF", 0, MagickString("%PDF-") },
cristy7adb4db2010-01-24 17:14:03 +0000149 { "PES", 0, MagickString("#PES") },
cristye3e77a12009-10-16 00:47:21 +0000150 { "PFA", 0, MagickString("%!PS-AdobeFont-1.0") },
151 { "PFB", 6, MagickString("%!PS-AdobeFont-1.0") },
152 { "PGX", 0, MagickString("\050\107\020\115\046") },
153 { "PICT", 522, MagickString("\000\021\002\377\014\000") },
154 { "PNG", 0, MagickString("\211PNG\r\n\032\n") },
cristy34575212010-11-06 12:39:23 +0000155 { "PBM", 0, MagickString("P1") },
156 { "PGM", 0, MagickString("P2") },
157 { "PPM", 0, MagickString("P3") },
158 { "PBM", 0, MagickString("P4") },
159 { "PGM", 0, MagickString("P5") },
160 { "PPM", 0, MagickString("P6") },
161 { "PAM", 0, MagickString("P7") },
162 { "PFM", 0, MagickString("PF") },
163 { "PFM", 0, MagickString("Pf") },
cristye3e77a12009-10-16 00:47:21 +0000164 { "PS", 0, MagickString("%!") },
165 { "PS", 0, MagickString("\004%!") },
166 { "PS", 0, MagickString("\305\320\323\306") },
cristyb4233012010-02-28 20:09:14 +0000167 { "PSB", 0, MagickString("8BPB") },
cristye3e77a12009-10-16 00:47:21 +0000168 { "PSD", 0, MagickString("8BPS") },
169 { "PWP", 0, MagickString("SFW95") },
170 { "RAF", 0, MagickString("FUJIFILMCCD-RAW ") },
171 { "RAD", 0, MagickString("#?RADIANCE") },
172 { "RAD", 0, MagickString("VIEW= ") },
173 { "RLE", 0, MagickString("\122\314") },
174 { "SCT", 0, MagickString("CT") },
175 { "SFW", 0, MagickString("SFW94") },
176 { "SGI", 0, MagickString("\001\332") },
177 { "SUN", 0, MagickString("\131\246\152\225") },
178 { "SVG", 1, MagickString("?XML") },
179 { "SVG", 1, MagickString("?xml") },
180 { "TIFF", 0, MagickString("\115\115\000\052") },
181 { "TIFF", 0, MagickString("\111\111\052\000") },
182 { "TIFF64", 0, MagickString("\115\115\000\053\000\010\000\000") },
183 { "TIFF64", 0, MagickString("\111\111\053\000\010\000\000\000") },
184 { "TXT", 0, MagickString("# ImageMagick pixel enumeration:") },
185 { "VICAR", 0, MagickString("LBLSIZE") },
186 { "VICAR", 0, MagickString("NJPL1I") },
187 { "VIFF", 0, MagickString("\253\001") },
cristy56dd2cd2010-10-11 00:45:14 +0000188 { "WEBP", 8, MagickString("WEBP") },
cristye3e77a12009-10-16 00:47:21 +0000189 { "WMF", 0, MagickString("\327\315\306\232") },
190 { "WMF", 0, MagickString("\001\000\011\000") },
191 { "WPG", 0, MagickString("\377WPC") },
192 { "XBM", 0, MagickString("#define") },
193 { "XCF", 0, MagickString("gimp xcf") },
194 { "XEF", 0, MagickString("FOVb") },
195 { "XPM", 1, MagickString("* XPM *") },
196 { "XWD", 4, MagickString("\007\000\000") },
cristy54a531d2009-10-21 17:58:01 +0000197 { "XWD", 5, MagickString("\000\000\007") }
cristy1ca3eb32009-10-15 18:41:54 +0000198 };
cristy3ed852e2009-09-05 21:47:34 +0000199
200static LinkedListInfo
201 *magic_list = (LinkedListInfo *) NULL;
202
203static SemaphoreInfo
204 *magic_semaphore = (SemaphoreInfo *) NULL;
205
206static volatile MagickBooleanType
207 instantiate_magic = MagickFalse;
208
209/*
210 Forward declarations.
211*/
212static MagickBooleanType
213 InitializeMagicList(ExceptionInfo *),
214 LoadMagicLists(const char *,ExceptionInfo *);
215
216/*
217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
218% %
219% %
220% %
cristy3ed852e2009-09-05 21:47:34 +0000221+ G e t M a g i c I n f o %
222% %
223% %
224% %
225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226%
227% GetMagicInfo() searches the magic list for the specified name and if found
228% returns attributes for that magic.
229%
230% The format of the GetMagicInfo method is:
231%
232% const MagicInfo *GetMagicInfo(const unsigned char *magic,
233% const size_t length,ExceptionInfo *exception)
234%
235% A description of each parameter follows:
236%
237% o magic: A binary string generally representing the first few characters
238% of the image file or blob.
239%
240% o length: the length of the binary signature.
241%
242% o exception: return any errors or warnings in this structure.
243%
244*/
245MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
246 const size_t length,ExceptionInfo *exception)
247{
248 register const MagicInfo
249 *p;
250
251 assert(exception != (ExceptionInfo *) NULL);
252 if ((magic_list == (LinkedListInfo *) NULL) ||
253 (instantiate_magic == MagickFalse))
254 if (InitializeMagicList(exception) == MagickFalse)
255 return((const MagicInfo *) NULL);
256 if ((magic_list == (LinkedListInfo *) NULL) ||
257 (IsLinkedListEmpty(magic_list) != MagickFalse))
258 return((const MagicInfo *) NULL);
259 if (magic == (const unsigned char *) NULL)
260 return((const MagicInfo *) GetValueFromLinkedList(magic_list,0));
261 if (length == 0)
262 return((const MagicInfo *) NULL);
263 /*
264 Search for magic tag.
265 */
cristyf84a1932010-01-03 18:00:18 +0000266 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000267 ResetLinkedListIterator(magic_list);
268 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
269 while (p != (const MagicInfo *) NULL)
270 {
271 assert(p->offset >= 0);
272 if (((size_t) (p->offset+p->length) <= length) &&
273 (memcmp(magic+p->offset,p->magic,p->length) == 0))
274 break;
275 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
276 }
277 if (p != (const MagicInfo *) NULL)
278 (void) InsertValueInLinkedList(magic_list,0,
279 RemoveElementByValueFromLinkedList(magic_list,p));
cristyf84a1932010-01-03 18:00:18 +0000280 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000281 return(p);
282}
283
284/*
285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286% %
287% %
288% %
289% G e t M a g i c I n f o L i s t %
290% %
291% %
292% %
293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294%
295% GetMagicInfoList() returns any image aliases that match the specified
296% pattern.
297%
298% The magic of the GetMagicInfoList function is:
299%
300% const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000301% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000302%
303% A description of each parameter follows:
304%
305% o pattern: Specifies a pointer to a text string containing a pattern.
306%
cristyfc0d1122009-10-17 20:22:37 +0000307% o number_aliases: This integer returns the number of aliases in the list.
cristy3ed852e2009-09-05 21:47:34 +0000308%
309% o exception: return any errors or warnings in this structure.
310%
311*/
312
313#if defined(__cplusplus) || defined(c_plusplus)
314extern "C" {
315#endif
316
317static int MagicInfoCompare(const void *x,const void *y)
318{
319 const MagicInfo
320 **p,
321 **q;
322
323 p=(const MagicInfo **) x,
324 q=(const MagicInfo **) y;
325 if (LocaleCompare((*p)->path,(*q)->path) == 0)
326 return(LocaleCompare((*p)->name,(*q)->name));
327 return(LocaleCompare((*p)->path,(*q)->path));
328}
329
330#if defined(__cplusplus) || defined(c_plusplus)
331}
332#endif
333
334MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000335 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000336{
337 const MagicInfo
338 **aliases;
339
340 register const MagicInfo
341 *p;
342
cristybb503372010-05-27 20:51:26 +0000343 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000344 i;
345
346 /*
347 Allocate magic list.
348 */
349 assert(pattern != (char *) NULL);
350 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000351 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000352 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000353 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000354 if (p == (const MagicInfo *) NULL)
355 return((const MagicInfo **) NULL);
356 aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
357 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
358 if (aliases == (const MagicInfo **) NULL)
359 return((const MagicInfo **) NULL);
360 /*
361 Generate magic list.
362 */
cristyf84a1932010-01-03 18:00:18 +0000363 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000364 ResetLinkedListIterator(magic_list);
365 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
366 for (i=0; p != (const MagicInfo *) NULL; )
367 {
368 if ((p->stealth == MagickFalse) &&
369 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
370 aliases[i++]=p;
371 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
372 }
cristyf84a1932010-01-03 18:00:18 +0000373 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000374 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
375 aliases[i]=(MagicInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000376 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000377 return(aliases);
378}
379
380/*
381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382% %
383% %
384% %
385% G e t M a g i c L i s t %
386% %
387% %
388% %
389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390%
391% GetMagicList() returns any image format aliases that match the specified
392% pattern.
393%
394% The format of the GetMagicList function is:
395%
cristybb503372010-05-27 20:51:26 +0000396% char **GetMagicList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000397% ExceptionInfo *exception)
398%
399% A description of each parameter follows:
400%
401% o pattern: Specifies a pointer to a text string containing a pattern.
402%
403% o number_aliases: This integer returns the number of image format aliases
404% in the list.
405%
406% o exception: return any errors or warnings in this structure.
407%
408*/
409
410#if defined(__cplusplus) || defined(c_plusplus)
411extern "C" {
412#endif
413
414static int MagicCompare(const void *x,const void *y)
415{
416 register const char
417 *p,
418 *q;
419
420 p=(const char *) x;
421 q=(const char *) y;
422 return(LocaleCompare(p,q));
423}
424
425#if defined(__cplusplus) || defined(c_plusplus)
426}
427#endif
428
429MagickExport char **GetMagicList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000430 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000431{
432 char
433 **aliases;
434
435 register const MagicInfo
436 *p;
437
cristybb503372010-05-27 20:51:26 +0000438 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000439 i;
440
441 /*
442 Allocate configure list.
443 */
444 assert(pattern != (char *) NULL);
445 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000446 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000447 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000448 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000449 if (p == (const MagicInfo *) NULL)
450 return((char **) NULL);
451 aliases=(char **) AcquireQuantumMemory((size_t)
452 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
453 if (aliases == (char **) NULL)
454 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000455 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000456 ResetLinkedListIterator(magic_list);
457 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
458 for (i=0; p != (const MagicInfo *) NULL; )
459 {
460 if ((p->stealth == MagickFalse) &&
461 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
462 aliases[i++]=ConstantString(p->name);
463 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
464 }
cristyf84a1932010-01-03 18:00:18 +0000465 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000466 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
467 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000468 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000469 return(aliases);
470}
471
472/*
473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474% %
475% %
476% %
477% G e t M a g i c N a m e %
478% %
479% %
480% %
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482%
483% GetMagicName() returns the name associated with the magic.
484%
485% The format of the GetMagicName method is:
486%
487% const char *GetMagicName(const MagicInfo *magic_info)
488%
489% A description of each parameter follows:
490%
491% o magic_info: The magic info.
492%
493*/
494MagickExport const char *GetMagicName(const MagicInfo *magic_info)
495{
496 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
497 assert(magic_info != (MagicInfo *) NULL);
498 assert(magic_info->signature == MagickSignature);
499 return(magic_info->name);
500}
501
502/*
503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504% %
505% %
506% %
507+ I n i t i a l i z e M a g i c L i s t %
508% %
509% %
510% %
511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512%
513% InitializeMagicList() initializes the magic list.
514%
515% The format of the InitializeMagicList method is:
516%
517% MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
518%
519% A description of each parameter follows.
520%
521% o exception: return any errors or warnings in this structure.
522%
523*/
524static MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
525{
526 if ((magic_list == (LinkedListInfo *) NULL) &&
527 (instantiate_magic == MagickFalse))
528 {
cristy4e1dff62009-10-25 20:36:03 +0000529 if (magic_semaphore == (SemaphoreInfo *) NULL)
530 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000531 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000532 if ((magic_list == (LinkedListInfo *) NULL) &&
533 (instantiate_magic == MagickFalse))
534 {
535 (void) LoadMagicLists(MagicFilename,exception);
536 instantiate_magic=MagickTrue;
537 }
cristyf84a1932010-01-03 18:00:18 +0000538 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000539 }
540 return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
541}
542
543/*
544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
545% %
546% %
547% %
548% L i s t M a g i c I n f o %
549% %
550% %
551% %
552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553%
554% ListMagicInfo() lists the magic info to a file.
555%
556% The format of the ListMagicInfo method is:
557%
558% MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
559%
560% A description of each parameter follows.
561%
562% o file: An pointer to a FILE.
563%
564% o exception: return any errors or warnings in this structure.
565%
566*/
567MagickExport MagickBooleanType ListMagicInfo(FILE *file,
568 ExceptionInfo *exception)
569{
570 const char
571 *path;
572
573 const MagicInfo
574 **magic_info;
575
cristybb503372010-05-27 20:51:26 +0000576 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000577 j;
578
cristybb503372010-05-27 20:51:26 +0000579 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000580 i;
581
cristybb503372010-05-27 20:51:26 +0000582 size_t
cristy3ed852e2009-09-05 21:47:34 +0000583 number_aliases;
584
585 if (file == (const FILE *) NULL)
586 file=stdout;
587 magic_info=GetMagicInfoList("*",&number_aliases,exception);
588 if (magic_info == (const MagicInfo **) NULL)
589 return(MagickFalse);
590 j=0;
591 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000592 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000593 {
594 if (magic_info[i]->stealth != MagickFalse)
595 continue;
596 if ((path == (const char *) NULL) ||
597 (LocaleCompare(path,magic_info[i]->path) != 0))
598 {
599 if (magic_info[i]->path != (char *) NULL)
600 (void) fprintf(file,"\nPath: %s\n\n",magic_info[i]->path);
601 (void) fprintf(file,"Name Offset Target\n");
602 (void) fprintf(file,"-------------------------------------------------"
603 "------------------------------\n");
604 }
605 path=magic_info[i]->path;
606 (void) fprintf(file,"%s",magic_info[i]->name);
cristybb503372010-05-27 20:51:26 +0000607 for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
cristy3ed852e2009-09-05 21:47:34 +0000608 (void) fprintf(file," ");
cristycee97112010-05-28 00:44:52 +0000609 (void) fprintf(file,"%6ld ",(long) magic_info[i]->offset);
cristy3ed852e2009-09-05 21:47:34 +0000610 if (magic_info[i]->target != (char *) NULL)
cristy1ca3eb32009-10-15 18:41:54 +0000611 {
cristybb503372010-05-27 20:51:26 +0000612 register ssize_t
cristy1ca3eb32009-10-15 18:41:54 +0000613 j;
614
615 for (j=0; magic_info[i]->target[j] != '\0'; j++)
616 if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
617 (void) fprintf(file,"%c",magic_info[i]->target[j]);
618 else
cristy50931922009-10-15 18:59:59 +0000619 (void) fprintf(file,"\\%03o",(unsigned int)
620 ((unsigned char) magic_info[i]->target[j]));
cristy1ca3eb32009-10-15 18:41:54 +0000621 }
cristy3ed852e2009-09-05 21:47:34 +0000622 (void) fprintf(file,"\n");
623 }
624 (void) fflush(file);
625 magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
626 return(MagickTrue);
627}
628
629/*
630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631% %
632% %
633% %
634+ L o a d M a g i c L i s t %
635% %
636% %
637% %
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639%
640% LoadMagicList() loads the magic configuration file which provides a mapping
641% between magic attributes and a magic name.
642%
643% The format of the LoadMagicList method is:
644%
645% MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000646% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000647%
648% A description of each parameter follows:
649%
cristy1ca3eb32009-10-15 18:41:54 +0000650% o xml: The magic list in XML format.
cristy3ed852e2009-09-05 21:47:34 +0000651%
cristy1ca3eb32009-10-15 18:41:54 +0000652% o filename: The magic list filename.
cristy3ed852e2009-09-05 21:47:34 +0000653%
654% o depth: depth of <include /> statements.
655%
656% o exception: return any errors or warnings in this structure.
657%
658*/
659static MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000660 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000661{
662 char
663 keyword[MaxTextExtent],
664 *token;
665
666 const char
667 *q;
668
669 MagickBooleanType
670 status;
671
672 MagicInfo
673 *magic_info;
674
675 /*
676 Load the magic map file.
677 */
678 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
679 "Loading magic configure file \"%s\" ...",filename);
680 if (xml == (char *) NULL)
681 return(MagickFalse);
682 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000683 {
684 magic_list=NewLinkedList(0);
685 if (magic_list == (LinkedListInfo *) NULL)
686 {
687 ThrowFileException(exception,ResourceLimitError,
688 "MemoryAllocationFailed",filename);
689 return(MagickFalse);
690 }
691 }
cristy3ed852e2009-09-05 21:47:34 +0000692 status=MagickTrue;
693 magic_info=(MagicInfo *) NULL;
694 token=AcquireString(xml);
695 for (q=(char *) xml; *q != '\0'; )
696 {
697 /*
698 Interpret XML.
699 */
700 GetMagickToken(q,&q,token);
701 if (*token == '\0')
702 break;
703 (void) CopyMagickString(keyword,token,MaxTextExtent);
704 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
705 {
706 /*
707 Doctype element.
708 */
709 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
710 GetMagickToken(q,&q,token);
711 continue;
712 }
713 if (LocaleNCompare(keyword,"<!--",4) == 0)
714 {
715 /*
716 Comment element.
717 */
718 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
719 GetMagickToken(q,&q,token);
720 continue;
721 }
722 if (LocaleCompare(keyword,"<include") == 0)
723 {
724 /*
725 Include element.
726 */
727 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
728 {
729 (void) CopyMagickString(keyword,token,MaxTextExtent);
730 GetMagickToken(q,&q,token);
731 if (*token != '=')
732 continue;
733 GetMagickToken(q,&q,token);
734 if (LocaleCompare(keyword,"file") == 0)
735 {
736 if (depth > 200)
737 (void) ThrowMagickException(exception,GetMagickModule(),
738 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
739 else
740 {
741 char
742 path[MaxTextExtent],
743 *xml;
744
745 GetPathComponent(filename,HeadPath,path);
746 if (*path != '\0')
747 (void) ConcatenateMagickString(path,DirectorySeparator,
748 MaxTextExtent);
749 if (*token == *DirectorySeparator)
750 (void) CopyMagickString(path,token,MaxTextExtent);
751 else
752 (void) ConcatenateMagickString(path,token,MaxTextExtent);
753 xml=FileToString(path,~0,exception);
754 if (xml != (char *) NULL)
755 {
756 status=LoadMagicList(xml,path,depth+1,exception);
757 xml=(char *) RelinquishMagickMemory(xml);
758 }
759 }
760 }
761 }
762 continue;
763 }
764 if (LocaleCompare(keyword,"<magic") == 0)
765 {
766 /*
767 Magic element.
768 */
cristy73bd4a52010-10-05 11:24:23 +0000769 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy3ed852e2009-09-05 21:47:34 +0000770 if (magic_info == (MagicInfo *) NULL)
771 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
772 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
773 magic_info->path=ConstantString(filename);
cristye3e77a12009-10-16 00:47:21 +0000774 magic_info->exempt=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000775 magic_info->signature=MagickSignature;
776 continue;
777 }
778 if (magic_info == (MagicInfo *) NULL)
779 continue;
780 if (LocaleCompare(keyword,"/>") == 0)
781 {
782 status=AppendValueToLinkedList(magic_list,magic_info);
783 if (status == MagickFalse)
784 (void) ThrowMagickException(exception,GetMagickModule(),
785 ResourceLimitError,"MemoryAllocationFailed","`%s'",
786 magic_info->name);
787 magic_info=(MagicInfo *) NULL;
788 }
789 GetMagickToken(q,(const char **) NULL,token);
790 if (*token != '=')
791 continue;
792 GetMagickToken(q,&q,token);
793 GetMagickToken(q,&q,token);
794 switch (*keyword)
795 {
796 case 'N':
797 case 'n':
798 {
799 if (LocaleCompare((char *) keyword,"name") == 0)
800 {
801 magic_info->name=ConstantString(token);
802 break;
803 }
804 break;
805 }
806 case 'O':
807 case 'o':
808 {
809 if (LocaleCompare((char *) keyword,"offset") == 0)
810 {
cristyf2f27272009-12-17 14:48:46 +0000811 magic_info->offset=(MagickOffsetType) StringToLong(token);
cristy3ed852e2009-09-05 21:47:34 +0000812 break;
813 }
814 break;
815 }
816 case 'S':
817 case 's':
818 {
819 if (LocaleCompare((char *) keyword,"stealth") == 0)
820 {
821 magic_info->stealth=IsMagickTrue(token);
822 break;
823 }
824 break;
825 }
826 case 'T':
827 case 't':
828 {
829 if (LocaleCompare((char *) keyword,"target") == 0)
830 {
831 char
832 *p;
833
834 register unsigned char
835 *q;
836
837 size_t
838 length;
839
840 length=strlen(token);
841 magic_info->target=ConstantString(token);
842 magic_info->magic=(unsigned char *) ConstantString(token);
843 q=magic_info->magic;
844 for (p=magic_info->target; *p != '\0'; )
845 {
846 if (*p == '\\')
847 {
848 p++;
849 if (isdigit((int) ((unsigned char) *p)) != 0)
850 {
851 char
852 *end;
853
854 *q++=(unsigned char) strtol(p,&end,8);
855 p+=(end-p);
856 magic_info->length++;
857 continue;
858 }
859 switch (*p)
860 {
861 case 'b': *q='\b'; break;
862 case 'f': *q='\f'; break;
863 case 'n': *q='\n'; break;
864 case 'r': *q='\r'; break;
865 case 't': *q='\t'; break;
866 case 'v': *q='\v'; break;
867 case 'a': *q='a'; break;
868 case '?': *q='\?'; break;
869 default: *q=(unsigned char) (*p); break;
870 }
871 p++;
872 q++;
873 magic_info->length++;
874 continue;
875 }
876 else
877 if (LocaleNCompare(p,"&amp;",5) == 0)
878 (void) CopyMagickString(p+1,p+5,length-magic_info->length);
879 *q++=(unsigned char) (*p++);
880 magic_info->length++;
881 }
882 break;
883 }
884 break;
885 }
886 default:
887 break;
888 }
889 }
890 token=(char *) RelinquishMagickMemory(token);
891 return(status);
892}
893
894/*
895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
896% %
897% %
898% %
899% L o a d M a g i c L i s t s %
900% %
901% %
902% %
903%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
904%
905% LoadMagicLists() loads one or more magic configuration file which provides a
906% mapping between magic attributes and a magic name.
907%
908% The format of the LoadMagicLists method is:
909%
910% MagickBooleanType LoadMagicLists(const char *filename,
911% ExceptionInfo *exception)
912%
913% A description of each parameter follows:
914%
915% o filename: the font file name.
916%
917% o exception: return any errors or warnings in this structure.
918%
919*/
920static MagickBooleanType LoadMagicLists(const char *filename,
921 ExceptionInfo *exception)
922{
cristy3ed852e2009-09-05 21:47:34 +0000923 char
924 path[MaxTextExtent];
925
926 const StringInfo
927 *option;
928
929 LinkedListInfo
930 *options;
931
932 MagickStatusType
933 status;
934
cristybb503372010-05-27 20:51:26 +0000935 register ssize_t
cristy54a531d2009-10-21 17:58:01 +0000936 i;
cristy1ca3eb32009-10-15 18:41:54 +0000937
938 /*
939 Load built-in magic map.
940 */
cristy3ed852e2009-09-05 21:47:34 +0000941 status=MagickFalse;
cristy1ca3eb32009-10-15 18:41:54 +0000942 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000943 {
944 magic_list=NewLinkedList(0);
945 if (magic_list == (LinkedListInfo *) NULL)
946 {
947 ThrowFileException(exception,ResourceLimitError,
948 "MemoryAllocationFailed",filename);
949 return(MagickFalse);
950 }
951 }
cristybb503372010-05-27 20:51:26 +0000952 for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
cristy1ca3eb32009-10-15 18:41:54 +0000953 {
954 MagicInfo
955 *magic_info;
956
cristy54a531d2009-10-21 17:58:01 +0000957 register const MagicMapInfo
958 *p;
959
960 p=MagicMap+i;
cristy73bd4a52010-10-05 11:24:23 +0000961 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy1ca3eb32009-10-15 18:41:54 +0000962 if (magic_info == (MagicInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000963 {
964 (void) ThrowMagickException(exception,GetMagickModule(),
965 ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
966 continue;
967 }
cristy1ca3eb32009-10-15 18:41:54 +0000968 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
cristy38b8ed92009-10-16 01:20:21 +0000969 magic_info->path=(char *) "[built-in]";
cristy1ca3eb32009-10-15 18:41:54 +0000970 magic_info->name=(char *) p->name;
971 magic_info->offset=p->offset;
972 magic_info->target=(char *) p->magic;
cristye3e77a12009-10-16 00:47:21 +0000973 magic_info->magic=(unsigned char *) p->magic;
cristy1ca3eb32009-10-15 18:41:54 +0000974 magic_info->length=p->length;
975 magic_info->exempt=MagickTrue;
976 magic_info->signature=MagickSignature;
977 status=AppendValueToLinkedList(magic_list,magic_info);
978 if (status == MagickFalse)
979 (void) ThrowMagickException(exception,GetMagickModule(),
980 ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
981 }
982 /*
983 Load external magic map.
984 */
cristy3ed852e2009-09-05 21:47:34 +0000985 *path='\0';
986 options=GetConfigureOptions(filename,exception);
987 option=(const StringInfo *) GetNextValueInLinkedList(options);
988 while (option != (const StringInfo *) NULL)
989 {
990 (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
991 status|=LoadMagicList((const char *) GetStringInfoDatum(option),
992 GetStringInfoPath(option),0,exception);
993 option=(const StringInfo *) GetNextValueInLinkedList(options);
994 }
995 options=DestroyConfigureOptions(options);
cristy3ed852e2009-09-05 21:47:34 +0000996 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000997}
cristyf34a1452009-10-24 22:29:27 +0000998
999/*
1000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1001% %
1002% %
1003% %
1004+ M a g i c C o m p o n e n t G e n e s i s %
1005% %
1006% %
1007% %
1008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009%
1010% MagicComponentGenesis() instantiates the magic component.
1011%
1012% The format of the MagicComponentGenesis method is:
1013%
1014% MagickBooleanType MagicComponentGenesis(void)
1015%
1016*/
1017MagickExport MagickBooleanType MagicComponentGenesis(void)
1018{
cristy165b6092009-10-26 13:52:10 +00001019 AcquireSemaphoreInfo(&magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001020 return(MagickTrue);
1021}
1022
1023/*
1024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1025% %
1026% %
1027% %
1028+ M a g i c C o m p o n e n t T e r m i n u s %
1029% %
1030% %
1031% %
1032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033%
1034% MagicComponentTerminus() destroys the magic component.
1035%
1036% The format of the MagicComponentTerminus method is:
1037%
1038% MagicComponentTerminus(void)
1039%
1040*/
1041
1042static void *DestroyMagicElement(void *magic_info)
1043{
1044 register MagicInfo
1045 *p;
1046
1047 p=(MagicInfo *) magic_info;
1048 if (p->exempt == MagickFalse)
1049 {
1050 if (p->path != (char *) NULL)
1051 p->path=DestroyString(p->path);
1052 if (p->name != (char *) NULL)
1053 p->name=DestroyString(p->name);
1054 if (p->target != (char *) NULL)
1055 p->target=DestroyString(p->target);
1056 if (p->magic != (unsigned char *) NULL)
1057 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1058 }
1059 p=(MagicInfo *) RelinquishMagickMemory(p);
1060 return((void *) NULL);
1061}
1062
1063MagickExport void MagicComponentTerminus(void)
1064{
cristy18b17442009-10-25 18:36:48 +00001065 if (magic_semaphore == (SemaphoreInfo *) NULL)
1066 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001067 LockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001068 if (magic_list != (LinkedListInfo *) NULL)
1069 magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
1070 instantiate_magic=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001071 UnlockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001072 DestroySemaphoreInfo(&magic_semaphore);
1073}