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