blob: f21db0f01c6a5903acd8ab6a5faa05a34fc4de8e [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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"
cristy9639ba32011-09-05 15:09:42 +000046#include "MagickCore/configure-private.h"
cristy4c08aed2011-07-01 19:47:50 +000047#include "MagickCore/exception.h"
48#include "MagickCore/exception-private.h"
49#include "MagickCore/hashmap.h"
50#include "MagickCore/magic.h"
cristy5ff4eaf2011-09-03 01:38:02 +000051#include "MagickCore/magic-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/memory_.h"
53#include "MagickCore/semaphore.h"
54#include "MagickCore/string_.h"
55#include "MagickCore/string-private.h"
56#include "MagickCore/token.h"
57#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000058#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/xml-tree.h"
cristy3ed852e2009-09-05 21:47:34 +000060
61/*
62 Define declarations.
63*/
64#define MagicFilename "magic.xml"
cristy54a531d2009-10-21 17:58:01 +000065#define MagickString(magic) (const unsigned char *) (magic), sizeof(magic)-1
cristy3ed852e2009-09-05 21:47:34 +000066
67/*
cristy54a531d2009-10-21 17:58:01 +000068 Typedef declarations.
cristy3ed852e2009-09-05 21:47:34 +000069*/
cristy1ca3eb32009-10-15 18:41:54 +000070typedef struct _MagicMapInfo
71{
72 const char
73 *name;
74
cristye3e77a12009-10-16 00:47:21 +000075 const MagickOffsetType
76 offset;
77
cristybcdce3d2009-10-15 20:04:49 +000078 const unsigned char
cristy1ca3eb32009-10-15 18:41:54 +000079 *magic;
80
cristye3e77a12009-10-16 00:47:21 +000081 const size_t
cristy1ca3eb32009-10-15 18:41:54 +000082 length;
cristy1ca3eb32009-10-15 18:41:54 +000083} MagicMapInfo;
cristy54a531d2009-10-21 17:58:01 +000084
85/*
86 Static declarations.
87*/
cristy1ca3eb32009-10-15 18:41:54 +000088static const MagicMapInfo
89 MagicMap[] =
90 {
cristye3e77a12009-10-16 00:47:21 +000091 { "8BIMWTEXT", 0, MagickString("8\000B\000I\000M\000#") },
92 { "8BIMTEXT", 0, MagickString("8BIM#") },
93 { "8BIM", 0, MagickString("8BIM") },
94 { "BMP", 0, MagickString("BA") },
95 { "BMP", 0, MagickString("BM") },
96 { "BMP", 0, MagickString("CI") },
97 { "BMP", 0, MagickString("CP") },
98 { "BMP", 0, MagickString("IC") },
99 { "BMP", 0, MagickString("PI") },
100 { "CALS", 21, MagickString("version: MIL-STD-1840") },
101 { "CALS", 0, MagickString("srcdocid:") },
102 { "CALS", 9, MagickString("srcdocid:") },
103 { "CALS", 8, MagickString("rorient:") },
104 { "CGM", 0, MagickString("BEGMF") },
105 { "CIN", 0, MagickString("\200\052\137\327") },
106 { "CRW", 0, MagickString("II\x1a\x00\x00\x00HEAPCCDR") },
107 { "DCM", 128, MagickString("DICM") },
108 { "DCX", 0, MagickString("\261\150\336\72") },
109 { "DIB", 0, MagickString("\050\000") },
110 { "DDS", 0, MagickString("DDS ") },
111 { "DJVU", 0, MagickString("AT&TFORM") },
112 { "DOT", 0, MagickString("digraph") },
113 { "DPX", 0, MagickString("SDPX") },
114 { "DPX", 0, MagickString("XPDS") },
115 { "EMF", 40, MagickString("\040\105\115\106\000\000\001\000") },
116 { "EPT", 0, MagickString("\305\320\323\306") },
117 { "EXR", 0, MagickString("\166\057\061\001") },
118 { "FAX", 0, MagickString("DFAX") },
119 { "FIG", 0, MagickString("#FIG") },
120 { "FITS", 0, MagickString("IT0") },
121 { "FITS", 0, MagickString("SIMPLE") },
122 { "FPX", 0, MagickString("\320\317\021\340") },
123 { "GIF", 0, MagickString("GIF8") },
124 { "GPLT", 0, MagickString("#!/usr/local/bin/gnuplot") },
125 { "HDF", 1, MagickString("HDF") },
cristy03533f22011-03-06 23:30:17 +0000126 { "HDR", 0, MagickString("#?RADIANCE") },
cristy84c3d052011-03-07 19:22:02 +0000127 { "HDR", 0, MagickString("#?RGBE") },
cristye3e77a12009-10-16 00:47:21 +0000128 { "HPGL", 0, MagickString("IN;") },
cristye3e77a12009-10-16 00:47:21 +0000129 { "HTML", 1, MagickString("HTML") },
130 { "HTML", 1, MagickString("html") },
131 { "ILBM", 8, MagickString("ILBM") },
132 { "IPTCWTEXT", 0, MagickString("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
133 { "IPTCTEXT", 0, MagickString("2#0=\042�\042") },
134 { "IPTC", 0, MagickString("\034\002") },
135 { "JNG", 0, MagickString("\213JNG\r\n\032\n") },
136 { "JPEG", 0, MagickString("\377\330\377") },
137 { "JPC", 0, MagickString("\377\117") },
138 { "JP2", 4, MagickString("\152\120\040\040\015") },
cristya7cb4312010-06-26 00:47:03 +0000139 { "MAT", 0, MagickString("MATLAB 5.0 MAT-file,") },
cristye3e77a12009-10-16 00:47:21 +0000140 { "MIFF", 0, MagickString("Id=ImageMagick") },
141 { "MIFF", 0, MagickString("id=ImageMagick") },
142 { "MNG", 0, MagickString("\212MNG\r\n\032\n") },
143 { "MPC", 0, MagickString("id=MagickCache") },
144 { "MPEG", 0, MagickString("\000\000\001\263") },
145 { "MRW", 0, MagickString("\x00MRM") },
146 { "MVG", 0, MagickString("push graphic-context") },
147 { "ORF", 0, MagickString("IIRO\x08\x00\x00\x00") },
148 { "PCD", 2048, MagickString("PCD_") },
149 { "PCL", 0, MagickString("\033E\033") },
150 { "PCX", 0, MagickString("\012\002") },
151 { "PCX", 0, MagickString("\012\005") },
152 { "PDB", 60, MagickString("vIMGView") },
153 { "PDF", 0, MagickString("%PDF-") },
cristy7adb4db2010-01-24 17:14:03 +0000154 { "PES", 0, MagickString("#PES") },
cristye3e77a12009-10-16 00:47:21 +0000155 { "PFA", 0, MagickString("%!PS-AdobeFont-1.0") },
156 { "PFB", 6, MagickString("%!PS-AdobeFont-1.0") },
157 { "PGX", 0, MagickString("\050\107\020\115\046") },
158 { "PICT", 522, MagickString("\000\021\002\377\014\000") },
159 { "PNG", 0, MagickString("\211PNG\r\n\032\n") },
cristy34575212010-11-06 12:39:23 +0000160 { "PBM", 0, MagickString("P1") },
161 { "PGM", 0, MagickString("P2") },
162 { "PPM", 0, MagickString("P3") },
163 { "PBM", 0, MagickString("P4") },
164 { "PGM", 0, MagickString("P5") },
165 { "PPM", 0, MagickString("P6") },
166 { "PAM", 0, MagickString("P7") },
167 { "PFM", 0, MagickString("PF") },
168 { "PFM", 0, MagickString("Pf") },
cristye3e77a12009-10-16 00:47:21 +0000169 { "PS", 0, MagickString("%!") },
170 { "PS", 0, MagickString("\004%!") },
171 { "PS", 0, MagickString("\305\320\323\306") },
cristyb4233012010-02-28 20:09:14 +0000172 { "PSB", 0, MagickString("8BPB") },
cristye3e77a12009-10-16 00:47:21 +0000173 { "PSD", 0, MagickString("8BPS") },
174 { "PWP", 0, MagickString("SFW95") },
175 { "RAF", 0, MagickString("FUJIFILMCCD-RAW ") },
cristye3e77a12009-10-16 00:47:21 +0000176 { "RLE", 0, MagickString("\122\314") },
177 { "SCT", 0, MagickString("CT") },
178 { "SFW", 0, MagickString("SFW94") },
179 { "SGI", 0, MagickString("\001\332") },
180 { "SUN", 0, MagickString("\131\246\152\225") },
181 { "SVG", 1, MagickString("?XML") },
182 { "SVG", 1, MagickString("?xml") },
183 { "TIFF", 0, MagickString("\115\115\000\052") },
184 { "TIFF", 0, MagickString("\111\111\052\000") },
185 { "TIFF64", 0, MagickString("\115\115\000\053\000\010\000\000") },
186 { "TIFF64", 0, MagickString("\111\111\053\000\010\000\000\000") },
cristy7c13f592012-09-14 23:19:22 +0000187 { "TTF", 0, MagickString("\000\001\000\000\000") },
cristye3e77a12009-10-16 00:47:21 +0000188 { "TXT", 0, MagickString("# ImageMagick pixel enumeration:") },
189 { "VICAR", 0, MagickString("LBLSIZE") },
190 { "VICAR", 0, MagickString("NJPL1I") },
191 { "VIFF", 0, MagickString("\253\001") },
cristy56dd2cd2010-10-11 00:45:14 +0000192 { "WEBP", 8, MagickString("WEBP") },
cristye3e77a12009-10-16 00:47:21 +0000193 { "WMF", 0, MagickString("\327\315\306\232") },
194 { "WMF", 0, MagickString("\001\000\011\000") },
195 { "WPG", 0, MagickString("\377WPC") },
196 { "XBM", 0, MagickString("#define") },
197 { "XCF", 0, MagickString("gimp xcf") },
198 { "XEF", 0, MagickString("FOVb") },
199 { "XPM", 1, MagickString("* XPM *") },
200 { "XWD", 4, MagickString("\007\000\000") },
cristy54a531d2009-10-21 17:58:01 +0000201 { "XWD", 5, MagickString("\000\000\007") }
cristy1ca3eb32009-10-15 18:41:54 +0000202 };
cristy3ed852e2009-09-05 21:47:34 +0000203
204static LinkedListInfo
205 *magic_list = (LinkedListInfo *) NULL;
206
207static SemaphoreInfo
208 *magic_semaphore = (SemaphoreInfo *) NULL;
209
210static volatile MagickBooleanType
211 instantiate_magic = MagickFalse;
212
213/*
214 Forward declarations.
215*/
216static MagickBooleanType
217 InitializeMagicList(ExceptionInfo *),
218 LoadMagicLists(const char *,ExceptionInfo *);
219
220/*
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222% %
223% %
224% %
cristy3ed852e2009-09-05 21:47:34 +0000225+ G e t M a g i c I n f o %
226% %
227% %
228% %
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%
231% GetMagicInfo() searches the magic list for the specified name and if found
232% returns attributes for that magic.
233%
234% The format of the GetMagicInfo method is:
235%
236% const MagicInfo *GetMagicInfo(const unsigned char *magic,
237% const size_t length,ExceptionInfo *exception)
238%
239% A description of each parameter follows:
240%
241% o magic: A binary string generally representing the first few characters
242% of the image file or blob.
243%
244% o length: the length of the binary signature.
245%
246% o exception: return any errors or warnings in this structure.
247%
248*/
249MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
250 const size_t length,ExceptionInfo *exception)
251{
252 register const MagicInfo
253 *p;
254
255 assert(exception != (ExceptionInfo *) NULL);
256 if ((magic_list == (LinkedListInfo *) NULL) ||
257 (instantiate_magic == MagickFalse))
258 if (InitializeMagicList(exception) == MagickFalse)
259 return((const MagicInfo *) NULL);
260 if ((magic_list == (LinkedListInfo *) NULL) ||
261 (IsLinkedListEmpty(magic_list) != MagickFalse))
262 return((const MagicInfo *) NULL);
263 if (magic == (const unsigned char *) NULL)
264 return((const MagicInfo *) GetValueFromLinkedList(magic_list,0));
265 if (length == 0)
266 return((const MagicInfo *) NULL);
267 /*
268 Search for magic tag.
269 */
cristyf84a1932010-01-03 18:00:18 +0000270 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000271 ResetLinkedListIterator(magic_list);
272 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
273 while (p != (const MagicInfo *) NULL)
274 {
275 assert(p->offset >= 0);
276 if (((size_t) (p->offset+p->length) <= length) &&
277 (memcmp(magic+p->offset,p->magic,p->length) == 0))
278 break;
279 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
280 }
281 if (p != (const MagicInfo *) NULL)
282 (void) InsertValueInLinkedList(magic_list,0,
283 RemoveElementByValueFromLinkedList(magic_list,p));
cristyf84a1932010-01-03 18:00:18 +0000284 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000285 return(p);
286}
287
288/*
289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290% %
291% %
292% %
293% G e t M a g i c I n f o L i s t %
294% %
295% %
296% %
297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298%
299% GetMagicInfoList() returns any image aliases that match the specified
300% pattern.
301%
302% The magic of the GetMagicInfoList function is:
303%
304% const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000305% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000306%
307% A description of each parameter follows:
308%
309% o pattern: Specifies a pointer to a text string containing a pattern.
310%
cristyfc0d1122009-10-17 20:22:37 +0000311% o number_aliases: This integer returns the number of aliases in the list.
cristy3ed852e2009-09-05 21:47:34 +0000312%
313% o exception: return any errors or warnings in this structure.
314%
315*/
316
317#if defined(__cplusplus) || defined(c_plusplus)
318extern "C" {
319#endif
320
321static int MagicInfoCompare(const void *x,const void *y)
322{
323 const MagicInfo
324 **p,
325 **q;
326
327 p=(const MagicInfo **) x,
328 q=(const MagicInfo **) y;
329 if (LocaleCompare((*p)->path,(*q)->path) == 0)
330 return(LocaleCompare((*p)->name,(*q)->name));
331 return(LocaleCompare((*p)->path,(*q)->path));
332}
333
334#if defined(__cplusplus) || defined(c_plusplus)
335}
336#endif
337
338MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000339 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000340{
341 const MagicInfo
342 **aliases;
343
344 register const MagicInfo
345 *p;
346
cristybb503372010-05-27 20:51:26 +0000347 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000348 i;
349
350 /*
351 Allocate magic list.
352 */
353 assert(pattern != (char *) NULL);
354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000355 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000356 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000357 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000358 if (p == (const MagicInfo *) NULL)
359 return((const MagicInfo **) NULL);
360 aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
361 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
362 if (aliases == (const MagicInfo **) NULL)
363 return((const MagicInfo **) NULL);
364 /*
365 Generate magic list.
366 */
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000368 ResetLinkedListIterator(magic_list);
369 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
370 for (i=0; p != (const MagicInfo *) NULL; )
371 {
372 if ((p->stealth == MagickFalse) &&
373 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
374 aliases[i++]=p;
375 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
376 }
cristyf84a1932010-01-03 18:00:18 +0000377 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000378 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
379 aliases[i]=(MagicInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000380 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000381 return(aliases);
382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
389% G e t M a g i c L i s t %
390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395% GetMagicList() returns any image format aliases that match the specified
396% pattern.
397%
398% The format of the GetMagicList function is:
399%
cristybb503372010-05-27 20:51:26 +0000400% char **GetMagicList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000401% ExceptionInfo *exception)
402%
403% A description of each parameter follows:
404%
405% o pattern: Specifies a pointer to a text string containing a pattern.
406%
407% o number_aliases: This integer returns the number of image format aliases
408% in the list.
409%
410% o exception: return any errors or warnings in this structure.
411%
412*/
413
414#if defined(__cplusplus) || defined(c_plusplus)
415extern "C" {
416#endif
417
418static int MagicCompare(const void *x,const void *y)
419{
420 register const char
421 *p,
422 *q;
423
424 p=(const char *) x;
425 q=(const char *) y;
426 return(LocaleCompare(p,q));
427}
428
429#if defined(__cplusplus) || defined(c_plusplus)
430}
431#endif
432
433MagickExport char **GetMagicList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000434 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000435{
436 char
437 **aliases;
438
439 register const MagicInfo
440 *p;
441
cristybb503372010-05-27 20:51:26 +0000442 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000443 i;
444
445 /*
446 Allocate configure list.
447 */
448 assert(pattern != (char *) NULL);
449 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000450 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000451 *number_aliases=0;
cristy1ca3eb32009-10-15 18:41:54 +0000452 p=GetMagicInfo((const unsigned char *) NULL,0,exception);
cristy3ed852e2009-09-05 21:47:34 +0000453 if (p == (const MagicInfo *) NULL)
454 return((char **) NULL);
455 aliases=(char **) AcquireQuantumMemory((size_t)
456 GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
457 if (aliases == (char **) NULL)
458 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000459 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000460 ResetLinkedListIterator(magic_list);
461 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
462 for (i=0; p != (const MagicInfo *) NULL; )
463 {
464 if ((p->stealth == MagickFalse) &&
465 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
466 aliases[i++]=ConstantString(p->name);
467 p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
468 }
cristyf84a1932010-01-03 18:00:18 +0000469 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000470 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
471 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000472 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000473 return(aliases);
474}
475
476/*
477%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478% %
479% %
480% %
481% G e t M a g i c N a m e %
482% %
483% %
484% %
485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486%
487% GetMagicName() returns the name associated with the magic.
488%
489% The format of the GetMagicName method is:
490%
491% const char *GetMagicName(const MagicInfo *magic_info)
492%
493% A description of each parameter follows:
494%
495% o magic_info: The magic info.
496%
497*/
498MagickExport const char *GetMagicName(const MagicInfo *magic_info)
499{
500 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
501 assert(magic_info != (MagicInfo *) NULL);
502 assert(magic_info->signature == MagickSignature);
503 return(magic_info->name);
504}
505
506/*
507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508% %
509% %
510% %
511+ I n i t i a l i z e M a g i c L i s t %
512% %
513% %
514% %
515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516%
517% InitializeMagicList() initializes the magic list.
518%
519% The format of the InitializeMagicList method is:
520%
521% MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
522%
523% A description of each parameter follows.
524%
525% o exception: return any errors or warnings in this structure.
526%
527*/
528static MagickBooleanType InitializeMagicList(ExceptionInfo *exception)
529{
530 if ((magic_list == (LinkedListInfo *) NULL) &&
531 (instantiate_magic == MagickFalse))
532 {
cristy4e1dff62009-10-25 20:36:03 +0000533 if (magic_semaphore == (SemaphoreInfo *) NULL)
534 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000535 LockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000536 if ((magic_list == (LinkedListInfo *) NULL) &&
537 (instantiate_magic == MagickFalse))
538 {
539 (void) LoadMagicLists(MagicFilename,exception);
540 instantiate_magic=MagickTrue;
541 }
cristyf84a1932010-01-03 18:00:18 +0000542 UnlockSemaphoreInfo(magic_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000543 }
544 return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
545}
546
547/*
548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549% %
550% %
551% %
552% L i s t M a g i c I n f o %
553% %
554% %
555% %
556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557%
558% ListMagicInfo() lists the magic info to a file.
559%
560% The format of the ListMagicInfo method is:
561%
562% MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
563%
564% A description of each parameter follows.
565%
566% o file: An pointer to a FILE.
567%
568% o exception: return any errors or warnings in this structure.
569%
570*/
571MagickExport MagickBooleanType ListMagicInfo(FILE *file,
572 ExceptionInfo *exception)
573{
574 const char
575 *path;
576
577 const MagicInfo
578 **magic_info;
579
cristybb503372010-05-27 20:51:26 +0000580 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000581 i;
582
cristybb503372010-05-27 20:51:26 +0000583 size_t
cristy3ed852e2009-09-05 21:47:34 +0000584 number_aliases;
585
cristy9d314ff2011-03-09 01:30:28 +0000586 ssize_t
587 j;
588
cristy3ed852e2009-09-05 21:47:34 +0000589 if (file == (const FILE *) NULL)
590 file=stdout;
591 magic_info=GetMagicInfoList("*",&number_aliases,exception);
592 if (magic_info == (const MagicInfo **) NULL)
593 return(MagickFalse);
594 j=0;
595 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000596 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000597 {
598 if (magic_info[i]->stealth != MagickFalse)
599 continue;
600 if ((path == (const char *) NULL) ||
601 (LocaleCompare(path,magic_info[i]->path) != 0))
602 {
603 if (magic_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000604 (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
605 (void) FormatLocaleFile(file,"Name Offset Target\n");
cristy1e604812011-05-19 18:07:50 +0000606 (void) FormatLocaleFile(file,
607 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000608 "------------------------------\n");
609 }
610 path=magic_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000611 (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
cristybb503372010-05-27 20:51:26 +0000612 for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
cristyb51dff52011-05-19 16:55:47 +0000613 (void) FormatLocaleFile(file," ");
614 (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
cristy3ed852e2009-09-05 21:47:34 +0000615 if (magic_info[i]->target != (char *) NULL)
cristy1ca3eb32009-10-15 18:41:54 +0000616 {
cristybb503372010-05-27 20:51:26 +0000617 register ssize_t
cristy1ca3eb32009-10-15 18:41:54 +0000618 j;
619
620 for (j=0; magic_info[i]->target[j] != '\0'; j++)
621 if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
cristyb51dff52011-05-19 16:55:47 +0000622 (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
cristy1ca3eb32009-10-15 18:41:54 +0000623 else
cristyb51dff52011-05-19 16:55:47 +0000624 (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
cristy50931922009-10-15 18:59:59 +0000625 ((unsigned char) magic_info[i]->target[j]));
cristy1ca3eb32009-10-15 18:41:54 +0000626 }
cristyb51dff52011-05-19 16:55:47 +0000627 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000628 }
629 (void) fflush(file);
630 magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
631 return(MagickTrue);
632}
633
634/*
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636% %
637% %
638% %
639+ L o a d M a g i c L i s t %
640% %
641% %
642% %
643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644%
645% LoadMagicList() loads the magic configuration file which provides a mapping
646% between magic attributes and a magic name.
647%
648% The format of the LoadMagicList method is:
649%
650% MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000651% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000652%
653% A description of each parameter follows:
654%
cristy1ca3eb32009-10-15 18:41:54 +0000655% o xml: The magic list in XML format.
cristy3ed852e2009-09-05 21:47:34 +0000656%
cristy1ca3eb32009-10-15 18:41:54 +0000657% o filename: The magic list filename.
cristy3ed852e2009-09-05 21:47:34 +0000658%
659% o depth: depth of <include /> statements.
660%
661% o exception: return any errors or warnings in this structure.
662%
663*/
664static MagickBooleanType LoadMagicList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000665 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000666{
667 char
668 keyword[MaxTextExtent],
669 *token;
670
671 const char
672 *q;
673
674 MagickBooleanType
675 status;
676
677 MagicInfo
678 *magic_info;
679
680 /*
681 Load the magic map file.
682 */
683 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
684 "Loading magic configure file \"%s\" ...",filename);
685 if (xml == (char *) NULL)
686 return(MagickFalse);
687 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000688 {
689 magic_list=NewLinkedList(0);
690 if (magic_list == (LinkedListInfo *) NULL)
691 {
692 ThrowFileException(exception,ResourceLimitError,
693 "MemoryAllocationFailed",filename);
694 return(MagickFalse);
695 }
696 }
cristy3ed852e2009-09-05 21:47:34 +0000697 status=MagickTrue;
698 magic_info=(MagicInfo *) NULL;
699 token=AcquireString(xml);
700 for (q=(char *) xml; *q != '\0'; )
701 {
702 /*
703 Interpret XML.
704 */
705 GetMagickToken(q,&q,token);
706 if (*token == '\0')
707 break;
708 (void) CopyMagickString(keyword,token,MaxTextExtent);
709 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
710 {
711 /*
712 Doctype element.
713 */
714 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
715 GetMagickToken(q,&q,token);
716 continue;
717 }
718 if (LocaleNCompare(keyword,"<!--",4) == 0)
719 {
720 /*
721 Comment element.
722 */
723 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
724 GetMagickToken(q,&q,token);
725 continue;
726 }
727 if (LocaleCompare(keyword,"<include") == 0)
728 {
729 /*
730 Include element.
731 */
732 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
733 {
734 (void) CopyMagickString(keyword,token,MaxTextExtent);
735 GetMagickToken(q,&q,token);
736 if (*token != '=')
737 continue;
738 GetMagickToken(q,&q,token);
739 if (LocaleCompare(keyword,"file") == 0)
740 {
741 if (depth > 200)
742 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000743 ConfigureError,"IncludeElementNestedTooDeeply","'%s'",token);
cristy3ed852e2009-09-05 21:47:34 +0000744 else
745 {
746 char
747 path[MaxTextExtent],
748 *xml;
749
750 GetPathComponent(filename,HeadPath,path);
751 if (*path != '\0')
752 (void) ConcatenateMagickString(path,DirectorySeparator,
753 MaxTextExtent);
754 if (*token == *DirectorySeparator)
755 (void) CopyMagickString(path,token,MaxTextExtent);
756 else
757 (void) ConcatenateMagickString(path,token,MaxTextExtent);
758 xml=FileToString(path,~0,exception);
759 if (xml != (char *) NULL)
760 {
761 status=LoadMagicList(xml,path,depth+1,exception);
762 xml=(char *) RelinquishMagickMemory(xml);
763 }
764 }
765 }
766 }
767 continue;
768 }
769 if (LocaleCompare(keyword,"<magic") == 0)
770 {
771 /*
772 Magic element.
773 */
cristy73bd4a52010-10-05 11:24:23 +0000774 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy3ed852e2009-09-05 21:47:34 +0000775 if (magic_info == (MagicInfo *) NULL)
776 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
777 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
778 magic_info->path=ConstantString(filename);
cristye3e77a12009-10-16 00:47:21 +0000779 magic_info->exempt=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000780 magic_info->signature=MagickSignature;
781 continue;
782 }
783 if (magic_info == (MagicInfo *) NULL)
784 continue;
785 if (LocaleCompare(keyword,"/>") == 0)
786 {
787 status=AppendValueToLinkedList(magic_list,magic_info);
788 if (status == MagickFalse)
789 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000790 ResourceLimitError,"MemoryAllocationFailed","'%s'",
cristy3ed852e2009-09-05 21:47:34 +0000791 magic_info->name);
792 magic_info=(MagicInfo *) NULL;
793 }
794 GetMagickToken(q,(const char **) NULL,token);
795 if (*token != '=')
796 continue;
797 GetMagickToken(q,&q,token);
798 GetMagickToken(q,&q,token);
799 switch (*keyword)
800 {
801 case 'N':
802 case 'n':
803 {
804 if (LocaleCompare((char *) keyword,"name") == 0)
805 {
806 magic_info->name=ConstantString(token);
807 break;
808 }
809 break;
810 }
811 case 'O':
812 case 'o':
813 {
814 if (LocaleCompare((char *) keyword,"offset") == 0)
815 {
cristyf2f27272009-12-17 14:48:46 +0000816 magic_info->offset=(MagickOffsetType) StringToLong(token);
cristy3ed852e2009-09-05 21:47:34 +0000817 break;
818 }
819 break;
820 }
821 case 'S':
822 case 's':
823 {
824 if (LocaleCompare((char *) keyword,"stealth") == 0)
825 {
anthony6f201312012-03-30 04:08:15 +0000826 magic_info->stealth=IsStringTrue(token);
cristy3ed852e2009-09-05 21:47:34 +0000827 break;
828 }
829 break;
830 }
831 case 'T':
832 case 't':
833 {
834 if (LocaleCompare((char *) keyword,"target") == 0)
835 {
836 char
837 *p;
838
839 register unsigned char
840 *q;
841
842 size_t
843 length;
844
845 length=strlen(token);
846 magic_info->target=ConstantString(token);
847 magic_info->magic=(unsigned char *) ConstantString(token);
848 q=magic_info->magic;
849 for (p=magic_info->target; *p != '\0'; )
850 {
851 if (*p == '\\')
852 {
853 p++;
854 if (isdigit((int) ((unsigned char) *p)) != 0)
855 {
856 char
857 *end;
858
859 *q++=(unsigned char) strtol(p,&end,8);
860 p+=(end-p);
861 magic_info->length++;
862 continue;
863 }
864 switch (*p)
865 {
866 case 'b': *q='\b'; break;
867 case 'f': *q='\f'; break;
868 case 'n': *q='\n'; break;
869 case 'r': *q='\r'; break;
870 case 't': *q='\t'; break;
871 case 'v': *q='\v'; break;
872 case 'a': *q='a'; break;
873 case '?': *q='\?'; break;
874 default: *q=(unsigned char) (*p); break;
875 }
876 p++;
877 q++;
878 magic_info->length++;
879 continue;
880 }
881 else
882 if (LocaleNCompare(p,"&amp;",5) == 0)
883 (void) CopyMagickString(p+1,p+5,length-magic_info->length);
884 *q++=(unsigned char) (*p++);
885 magic_info->length++;
886 }
887 break;
888 }
889 break;
890 }
891 default:
892 break;
893 }
894 }
895 token=(char *) RelinquishMagickMemory(token);
896 return(status);
897}
898
899/*
900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901% %
902% %
903% %
904% L o a d M a g i c L i s t s %
905% %
906% %
907% %
908%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909%
910% LoadMagicLists() loads one or more magic configuration file which provides a
911% mapping between magic attributes and a magic name.
912%
913% The format of the LoadMagicLists method is:
914%
915% MagickBooleanType LoadMagicLists(const char *filename,
916% ExceptionInfo *exception)
917%
918% A description of each parameter follows:
919%
920% o filename: the font file name.
921%
922% o exception: return any errors or warnings in this structure.
923%
924*/
925static MagickBooleanType LoadMagicLists(const char *filename,
926 ExceptionInfo *exception)
927{
cristy3ed852e2009-09-05 21:47:34 +0000928 char
929 path[MaxTextExtent];
930
931 const StringInfo
932 *option;
933
934 LinkedListInfo
935 *options;
936
937 MagickStatusType
938 status;
939
cristybb503372010-05-27 20:51:26 +0000940 register ssize_t
cristy54a531d2009-10-21 17:58:01 +0000941 i;
cristy1ca3eb32009-10-15 18:41:54 +0000942
943 /*
944 Load built-in magic map.
945 */
cristy3ed852e2009-09-05 21:47:34 +0000946 status=MagickFalse;
cristy1ca3eb32009-10-15 18:41:54 +0000947 if (magic_list == (LinkedListInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000948 {
949 magic_list=NewLinkedList(0);
950 if (magic_list == (LinkedListInfo *) NULL)
951 {
952 ThrowFileException(exception,ResourceLimitError,
953 "MemoryAllocationFailed",filename);
954 return(MagickFalse);
955 }
956 }
cristybb503372010-05-27 20:51:26 +0000957 for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
cristy1ca3eb32009-10-15 18:41:54 +0000958 {
959 MagicInfo
960 *magic_info;
961
cristy54a531d2009-10-21 17:58:01 +0000962 register const MagicMapInfo
963 *p;
964
965 p=MagicMap+i;
cristy73bd4a52010-10-05 11:24:23 +0000966 magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
cristy1ca3eb32009-10-15 18:41:54 +0000967 if (magic_info == (MagicInfo *) NULL)
cristye3e77a12009-10-16 00:47:21 +0000968 {
969 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000970 ResourceLimitError,"MemoryAllocationFailed","'%s'",magic_info->name);
cristye3e77a12009-10-16 00:47:21 +0000971 continue;
972 }
cristy1ca3eb32009-10-15 18:41:54 +0000973 (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
cristy38b8ed92009-10-16 01:20:21 +0000974 magic_info->path=(char *) "[built-in]";
cristy1ca3eb32009-10-15 18:41:54 +0000975 magic_info->name=(char *) p->name;
976 magic_info->offset=p->offset;
977 magic_info->target=(char *) p->magic;
cristye3e77a12009-10-16 00:47:21 +0000978 magic_info->magic=(unsigned char *) p->magic;
cristy1ca3eb32009-10-15 18:41:54 +0000979 magic_info->length=p->length;
980 magic_info->exempt=MagickTrue;
981 magic_info->signature=MagickSignature;
982 status=AppendValueToLinkedList(magic_list,magic_info);
983 if (status == MagickFalse)
984 (void) ThrowMagickException(exception,GetMagickModule(),
anthonye5b39652012-04-21 05:37:29 +0000985 ResourceLimitError,"MemoryAllocationFailed","'%s'",magic_info->name);
cristy1ca3eb32009-10-15 18:41:54 +0000986 }
987 /*
988 Load external magic map.
989 */
cristy3ed852e2009-09-05 21:47:34 +0000990 *path='\0';
991 options=GetConfigureOptions(filename,exception);
992 option=(const StringInfo *) GetNextValueInLinkedList(options);
993 while (option != (const StringInfo *) NULL)
994 {
995 (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent);
996 status|=LoadMagicList((const char *) GetStringInfoDatum(option),
997 GetStringInfoPath(option),0,exception);
998 option=(const StringInfo *) GetNextValueInLinkedList(options);
999 }
1000 options=DestroyConfigureOptions(options);
cristy3ed852e2009-09-05 21:47:34 +00001001 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001002}
cristyf34a1452009-10-24 22:29:27 +00001003
1004/*
1005%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1006% %
1007% %
1008% %
1009+ M a g i c C o m p o n e n t G e n e s i s %
1010% %
1011% %
1012% %
1013%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014%
1015% MagicComponentGenesis() instantiates the magic component.
1016%
1017% The format of the MagicComponentGenesis method is:
1018%
1019% MagickBooleanType MagicComponentGenesis(void)
1020%
1021*/
cristy5ff4eaf2011-09-03 01:38:02 +00001022MagickPrivate MagickBooleanType MagicComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +00001023{
cristy165b6092009-10-26 13:52:10 +00001024 AcquireSemaphoreInfo(&magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001025 return(MagickTrue);
1026}
1027
1028/*
1029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030% %
1031% %
1032% %
1033+ M a g i c C o m p o n e n t T e r m i n u s %
1034% %
1035% %
1036% %
1037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038%
1039% MagicComponentTerminus() destroys the magic component.
1040%
1041% The format of the MagicComponentTerminus method is:
1042%
1043% MagicComponentTerminus(void)
1044%
1045*/
1046
1047static void *DestroyMagicElement(void *magic_info)
1048{
1049 register MagicInfo
1050 *p;
1051
1052 p=(MagicInfo *) magic_info;
1053 if (p->exempt == MagickFalse)
1054 {
1055 if (p->path != (char *) NULL)
1056 p->path=DestroyString(p->path);
1057 if (p->name != (char *) NULL)
1058 p->name=DestroyString(p->name);
1059 if (p->target != (char *) NULL)
1060 p->target=DestroyString(p->target);
1061 if (p->magic != (unsigned char *) NULL)
1062 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1063 }
1064 p=(MagicInfo *) RelinquishMagickMemory(p);
1065 return((void *) NULL);
1066}
1067
cristy5ff4eaf2011-09-03 01:38:02 +00001068MagickPrivate void MagicComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +00001069{
cristy18b17442009-10-25 18:36:48 +00001070 if (magic_semaphore == (SemaphoreInfo *) NULL)
1071 AcquireSemaphoreInfo(&magic_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001072 LockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001073 if (magic_list != (LinkedListInfo *) NULL)
1074 magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
1075 instantiate_magic=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001076 UnlockSemaphoreInfo(magic_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001077 DestroySemaphoreInfo(&magic_semaphore);
1078}