]> granicus.if.org Git - imagemagick/blob - MagickCore/magic.c
https://github.com/ImageMagick/ImageMagick/issues/1681
[imagemagick] / MagickCore / magic.c
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-2019 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 %    https://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 \f
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/memory-private.h"
54 #include "MagickCore/semaphore.h"
55 #include "MagickCore/string_.h"
56 #include "MagickCore/string-private.h"
57 #include "MagickCore/token.h"
58 #include "MagickCore/utility.h"
59 #include "MagickCore/utility-private.h"
60 #include "coders/coders.h"
61 \f
62 /*
63   Define declarations.
64 */
65 #define AddMagickCoder(coder) Magick ## coder ## Headers
66 \f
67 /*
68   Typedef declarations.
69 */
70 typedef struct _MagicMapInfo
71 {
72   const char
73     name[10];
74
75   const MagickOffsetType
76     offset;
77
78   const unsigned char
79     *const magic;
80
81   const size_t
82     length;
83 } MagicMapInfo;
84
85 struct _MagicInfo
86 {
87   char
88     *path,
89     *name,
90     *target;
91
92   unsigned char
93     *magic;
94
95   size_t
96     length;
97
98   MagickOffsetType
99     offset;
100
101   MagickBooleanType
102     exempt,
103     stealth;
104
105   size_t
106     signature;
107 };
108 \f
109 /*
110   Static declarations.
111 */
112 static const MagicMapInfo
113   MagicMap[] =
114   {
115     #include "coders/coders-list.h"
116     MagickCoderHeader("CGM", 0, "BEGMF")
117     MagickCoderHeader("FIG", 0, "#FIG")
118     MagickCoderHeader("HPGL", 0, "IN;")
119     MagickCoderHeader("ILBM", 8, "ILBM")
120   };
121
122 static LinkedListInfo
123   *magic_cache = (LinkedListInfo *) NULL,
124   *magic_list = (LinkedListInfo *) NULL;
125
126 static SemaphoreInfo
127   *magic_cache_semaphore = (SemaphoreInfo *) NULL,
128   *magic_list_semaphore = (SemaphoreInfo *) NULL;
129 \f
130 /*
131   Forward declarations.
132 */
133 static MagickBooleanType
134   IsMagicListInstantiated(ExceptionInfo *);
135 \f
136 /*
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 %                                                                             %
139 %                                                                             %
140 %                                                                             %
141 %  A c q u i r e M a g i c L i s t                                            %
142 %                                                                             %
143 %                                                                             %
144 %                                                                             %
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 %
147 %  AcquireMagicList() caches one or more magic configurations which provides a
148 %  mapping between magic attributes and a magic name.
149 %
150 %  The format of the AcquireMagicList method is:
151 %
152 %      LinkedListInfo *AcquireMagicList(ExceptionInfo *exception)
153 %
154 %  A description of each parameter follows:
155 %
156 %    o filename: the font file name.
157 %
158 %    o exception: return any errors or warnings in this structure.
159 %
160 */
161 static int CompareMagickInfoSize(const void *a,const void *b)
162 {
163   MagicInfo
164     *ma,
165     *mb;
166
167   ma=(MagicInfo *) a;
168   mb=(MagicInfo *) b;
169   if (ma->offset != mb->offset)
170     {
171       MagickOffsetType
172         max_offset;
173
174       /*
175         When the offset is near the start we first search a bit further
176         in the stream.
177       */
178       max_offset=ma->offset > mb->offset ? ma->offset : mb->offset;
179       if (max_offset <= 10)
180         return((int) (mb->offset-ma->offset));
181       else
182         return((int) (ma->offset-mb->offset));
183     }
184   return((int) (mb->length-ma->length));
185 }
186
187 static LinkedListInfo *AcquireMagicList(ExceptionInfo *exception)
188 {
189   LinkedListInfo
190     *list;
191
192   MagickStatusType
193     status;
194
195   register ssize_t
196     i;
197
198   list=NewLinkedList(0);
199   status=MagickTrue;
200   /*
201     Load built-in magic map.
202   */
203   for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
204   {
205     MagicInfo
206       *magic_info;
207
208     register const MagicMapInfo
209       *p;
210
211     p=MagicMap+i;
212     magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
213     if (magic_info == (MagicInfo *) NULL)
214       {
215         (void) ThrowMagickException(exception,GetMagickModule(),
216           ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
217         continue;
218       }
219     (void) memset(magic_info,0,sizeof(*magic_info));
220     magic_info->path=(char *) "[built-in]";
221     magic_info->name=(char *) p->name;
222     magic_info->offset=p->offset;
223     magic_info->target=(char *) p->magic;
224     magic_info->magic=(unsigned char *) p->magic;
225     magic_info->length=p->length;
226     magic_info->exempt=MagickTrue;
227     magic_info->signature=MagickCoreSignature;
228     status&=InsertValueInSortedLinkedList(list,CompareMagickInfoSize,
229       NULL,magic_info);
230     if (status == MagickFalse)
231       (void) ThrowMagickException(exception,GetMagickModule(),
232         ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
233   }
234   return(list);
235 }
236 \f
237 /*
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 %                                                                             %
240 %                                                                             %
241 %                                                                             %
242 %   G e t M a g i c I n f o                                                   %
243 %                                                                             %
244 %                                                                             %
245 %                                                                             %
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 %
248 %  GetMagicInfo() searches the magic list for the specified name and if found
249 %  returns attributes for that magic.
250 %
251 %  The format of the GetMagicInfo method is:
252 %
253 %      const MagicInfo *GetMagicInfo(const unsigned char *magic,
254 %        const size_t length,ExceptionInfo *exception)
255 %
256 %  A description of each parameter follows:
257 %
258 %    o magic: A binary string generally representing the first few characters
259 %      of the image file or blob.
260 %
261 %    o length: the length of the binary signature.
262 %
263 %    o exception: return any errors or warnings in this structure.
264 %
265 */
266 static MagickBooleanType IsMagicCacheInstantiated()
267 {
268   if (magic_cache == (LinkedListInfo *) NULL)
269     {
270       if (magic_cache_semaphore == (SemaphoreInfo *) NULL)
271         ActivateSemaphoreInfo(&magic_cache_semaphore);
272       LockSemaphoreInfo(magic_cache_semaphore);
273       if (magic_cache == (LinkedListInfo *) NULL)
274         magic_cache=NewLinkedList(0);
275       UnlockSemaphoreInfo(magic_cache_semaphore);
276     }
277   return(magic_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
278 }
279
280 MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
281   const size_t length,ExceptionInfo *exception)
282 {
283   register const MagicInfo
284     *p;
285
286   assert(exception != (ExceptionInfo *) NULL);
287   if (IsMagicListInstantiated(exception) == MagickFalse)
288     return((const MagicInfo *) NULL);
289   if (IsMagicCacheInstantiated() == MagickFalse)
290     return((const MagicInfo *) NULL);
291   /*
292     Search for cached entries.
293   */
294   if (magic != (const unsigned char *) NULL)
295     {
296       LockSemaphoreInfo(magic_cache_semaphore);
297       ResetLinkedListIterator(magic_cache);
298       p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
299       while (p != (const MagicInfo *) NULL)
300       {
301         if (((size_t) (p->offset+p->length) <= length) &&
302             (memcmp(magic+p->offset,p->magic,p->length) == 0))
303           break;
304         p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
305       }
306       UnlockSemaphoreInfo(magic_cache_semaphore);
307       if (p != (const MagicInfo *) NULL)
308         return(p);
309     }
310   /*
311     Search for magic tag.
312   */
313   LockSemaphoreInfo(magic_list_semaphore);
314   ResetLinkedListIterator(magic_list);
315   p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
316   if (magic == (const unsigned char *) NULL)
317     {
318       UnlockSemaphoreInfo(magic_list_semaphore);
319       return(p);
320     }
321   while (p != (const MagicInfo *) NULL)
322   {
323     assert(p->offset >= 0);
324     if (((size_t) (p->offset+p->length) <= length) &&
325         (memcmp(magic+p->offset,p->magic,p->length) == 0))
326       break;
327     p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
328   }
329   UnlockSemaphoreInfo(magic_list_semaphore);
330   if (p != (const MagicInfo *) NULL)
331     {
332       LockSemaphoreInfo(magic_cache_semaphore);
333       InsertValueInSortedLinkedList(magic_cache,CompareMagickInfoSize,
334         NULL,p);
335       UnlockSemaphoreInfo(magic_cache_semaphore);
336     }
337   return(p);
338 }
339
340 /*
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 %                                                                             %
343 %                                                                             %
344 %                                                                             %
345 %   G e t M a g i c P a t t e r n E x t e n t                                 %
346 %                                                                             %
347 %                                                                             %
348 %                                                                             %
349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 %
351 %  GetMagicPatternExtent() returns the the extent of the buffer that is
352 %  required to check all the MagickInfos. It returns zero if the list is empty.
353 %
354 %  The format of the GetMagicPatternExtent method is:
355 %
356 %      size_t GetMagicPatternExtent(ExceptionInfo *exception)
357 %
358 %  A description of each parameter follows:
359 %
360 %    o exception: return any errors or warnings in this structure.
361 %
362 */
363 MagickExport size_t GetMagicPatternExtent(ExceptionInfo *exception)
364 {
365   register const MagicInfo
366     *p;
367
368   size_t
369     magickSize,
370     max;
371
372   static size_t
373     size=0;
374
375   assert(exception != (ExceptionInfo *) NULL);
376   if ((size != 0) || (IsMagicListInstantiated(exception) == MagickFalse))
377     return(size);
378   LockSemaphoreInfo(magic_list_semaphore);
379   ResetLinkedListIterator(magic_list);
380   max=0;
381   p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
382   while (p != (const MagicInfo *) NULL)
383   {
384     magickSize=(size_t) (p->offset+p->length);
385     if (magickSize > max)
386       max=magickSize;
387     p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
388   }
389   size=max;
390   UnlockSemaphoreInfo(magic_list_semaphore);
391   return(size);
392 }
393 \f
394 /*
395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 %                                                                             %
397 %                                                                             %
398 %                                                                             %
399 %   G e t M a g i c I n f o L i s t                                           %
400 %                                                                             %
401 %                                                                             %
402 %                                                                             %
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 %
405 %  GetMagicInfoList() returns any image aliases that match the specified
406 %  pattern.
407 %
408 %  The magic of the GetMagicInfoList function is:
409 %
410 %      const MagicInfo **GetMagicInfoList(const char *pattern,
411 %        size_t *number_aliases,ExceptionInfo *exception)
412 %
413 %  A description of each parameter follows:
414 %
415 %    o pattern: Specifies a pointer to a text string containing a pattern.
416 %
417 %    o number_aliases:  This integer returns the number of aliases in the list.
418 %
419 %    o exception: return any errors or warnings in this structure.
420 %
421 */
422
423 #if defined(__cplusplus) || defined(c_plusplus)
424 extern "C" {
425 #endif
426
427 static int MagicInfoCompare(const void *x,const void *y)
428 {
429   const MagicInfo
430     **p,
431     **q;
432
433   p=(const MagicInfo **) x,
434   q=(const MagicInfo **) y;
435   if (LocaleCompare((*p)->path,(*q)->path) == 0)
436     return(LocaleCompare((*p)->name,(*q)->name));
437   return(LocaleCompare((*p)->path,(*q)->path));
438 }
439
440 #if defined(__cplusplus) || defined(c_plusplus)
441 }
442 #endif
443
444 MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
445   size_t *number_aliases,ExceptionInfo *exception)
446 {
447   const MagicInfo
448     **aliases;
449
450   register const MagicInfo
451     *p;
452
453   register ssize_t
454     i;
455
456   /*
457     Allocate magic list.
458   */
459   assert(pattern != (char *) NULL);
460   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
461   assert(number_aliases != (size_t *) NULL);
462   *number_aliases=0;
463   p=GetMagicInfo((const unsigned char *) NULL,0,exception);
464   if (p == (const MagicInfo *) NULL)
465     return((const MagicInfo **) NULL);
466   aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
467     GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
468   if (aliases == (const MagicInfo **) NULL)
469     return((const MagicInfo **) NULL);
470   /*
471     Generate magic list.
472   */
473   LockSemaphoreInfo(magic_list_semaphore);
474   ResetLinkedListIterator(magic_list);
475   p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
476   for (i=0; p != (const MagicInfo *) NULL; )
477   {
478     if ((p->stealth == MagickFalse) &&
479         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
480       aliases[i++]=p;
481     p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
482   }
483   UnlockSemaphoreInfo(magic_list_semaphore);
484   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
485   aliases[i]=(MagicInfo *) NULL;
486   *number_aliases=(size_t) i;
487   return(aliases);
488 }
489 \f
490 /*
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 %                                                                             %
493 %                                                                             %
494 %                                                                             %
495 %   G e t M a g i c L i s t                                                   %
496 %                                                                             %
497 %                                                                             %
498 %                                                                             %
499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 %
501 %  GetMagicList() returns any image format aliases that match the specified
502 %  pattern.
503 %
504 %  The format of the GetMagicList function is:
505 %
506 %      char **GetMagicList(const char *pattern,size_t *number_aliases,
507 %        ExceptionInfo *exception)
508 %
509 %  A description of each parameter follows:
510 %
511 %    o pattern: Specifies a pointer to a text string containing a pattern.
512 %
513 %    o number_aliases:  This integer returns the number of image format aliases
514 %      in the list.
515 %
516 %    o exception: return any errors or warnings in this structure.
517 %
518 */
519
520 #if defined(__cplusplus) || defined(c_plusplus)
521 extern "C" {
522 #endif
523
524 static int MagicCompare(const void *x,const void *y)
525 {
526   register const char
527     *p,
528     *q;
529
530   p=(const char *) x;
531   q=(const char *) y;
532   return(LocaleCompare(p,q));
533 }
534
535 #if defined(__cplusplus) || defined(c_plusplus)
536 }
537 #endif
538
539 MagickExport char **GetMagicList(const char *pattern,size_t *number_aliases,
540   ExceptionInfo *exception)
541 {
542   char
543     **aliases;
544
545   register const MagicInfo
546     *p;
547
548   register ssize_t
549     i;
550
551   /*
552     Allocate configure list.
553   */
554   assert(pattern != (char *) NULL);
555   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
556   assert(number_aliases != (size_t *) NULL);
557   *number_aliases=0;
558   p=GetMagicInfo((const unsigned char *) NULL,0,exception);
559   if (p == (const MagicInfo *) NULL)
560     return((char **) NULL);
561   aliases=(char **) AcquireQuantumMemory((size_t)
562     GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases));
563   if (aliases == (char **) NULL)
564     return((char **) NULL);
565   LockSemaphoreInfo(magic_list_semaphore);
566   ResetLinkedListIterator(magic_list);
567   p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
568   for (i=0; p != (const MagicInfo *) NULL; )
569   {
570     if ((p->stealth == MagickFalse) &&
571         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
572       aliases[i++]=ConstantString(p->name);
573     p=(const MagicInfo *) GetNextValueInLinkedList(magic_list);
574   }
575   UnlockSemaphoreInfo(magic_list_semaphore);
576   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
577   aliases[i]=(char *) NULL;
578   *number_aliases=(size_t) i;
579   return(aliases);
580 }
581 \f
582 /*
583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 %                                                                             %
585 %                                                                             %
586 %                                                                             %
587 %   G e t M a g i c N a m e                                                   %
588 %                                                                             %
589 %                                                                             %
590 %                                                                             %
591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 %
593 %  GetMagicName() returns the name associated with the magic.
594 %
595 %  The format of the GetMagicName method is:
596 %
597 %      const char *GetMagicName(const MagicInfo *magic_info)
598 %
599 %  A description of each parameter follows:
600 %
601 %    o magic_info:  The magic info.
602 %
603 */
604 MagickExport const char *GetMagicName(const MagicInfo *magic_info)
605 {
606   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
607   assert(magic_info != (MagicInfo *) NULL);
608   assert(magic_info->signature == MagickCoreSignature);
609   return(magic_info->name);
610 }
611 \f
612 /*
613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 %                                                                             %
615 %                                                                             %
616 %                                                                             %
617 +   I s M a g i c L i s t I n s t a n t i a t e d                             %
618 %                                                                             %
619 %                                                                             %
620 %                                                                             %
621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 %
623 %  IsMagicListInstantiated() determines if the magic list is instantiated.
624 %  If not, it instantiates the list and returns it.
625 %
626 %  The format of the IsMagicListInstantiated method is:
627 %
628 %      MagickBooleanType IsMagicListInstantiated(ExceptionInfo *exception)
629 %
630 %  A description of each parameter follows.
631 %
632 %    o exception: return any errors or warnings in this structure.
633 %
634 */
635 static MagickBooleanType IsMagicListInstantiated(ExceptionInfo *exception)
636 {
637   if (magic_list == (LinkedListInfo *) NULL)
638     {
639       if (magic_list_semaphore == (SemaphoreInfo *) NULL)
640         ActivateSemaphoreInfo(&magic_list_semaphore);
641       LockSemaphoreInfo(magic_list_semaphore);
642       if (magic_list == (LinkedListInfo *) NULL)
643         magic_list=AcquireMagicList(exception);
644       UnlockSemaphoreInfo(magic_list_semaphore);
645     }
646   return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
647 }
648 \f
649 /*
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651 %                                                                             %
652 %                                                                             %
653 %                                                                             %
654 %  L i s t M a g i c I n f o                                                  %
655 %                                                                             %
656 %                                                                             %
657 %                                                                             %
658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 %
660 %  ListMagicInfo() lists the magic info to a file.
661 %
662 %  The format of the ListMagicInfo method is:
663 %
664 %      MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
665 %
666 %  A description of each parameter follows.
667 %
668 %    o file:  An pointer to a FILE.
669 %
670 %    o exception: return any errors or warnings in this structure.
671 %
672 */
673 MagickExport MagickBooleanType ListMagicInfo(FILE *file,
674   ExceptionInfo *exception)
675 {
676   const char
677     *path;
678
679   const MagicInfo
680     **magic_info;
681
682   register ssize_t
683     i;
684
685   size_t
686     number_aliases;
687
688   ssize_t
689     j;
690
691   if (file == (const FILE *) NULL)
692     file=stdout;
693   magic_info=GetMagicInfoList("*",&number_aliases,exception);
694   if (magic_info == (const MagicInfo **) NULL)
695     return(MagickFalse);
696   path=(const char *) NULL;
697   for (i=0; i < (ssize_t) number_aliases; i++)
698   {
699     if (magic_info[i]->stealth != MagickFalse)
700       continue;
701     if ((path == (const char *) NULL) ||
702         (LocaleCompare(path,magic_info[i]->path) != 0))
703       {
704         if (magic_info[i]->path != (char *) NULL)
705           (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
706         (void) FormatLocaleFile(file,"Name      Offset Target\n");
707         (void) FormatLocaleFile(file,
708           "-------------------------------------------------"
709           "------------------------------\n");
710       }
711     path=magic_info[i]->path;
712     (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
713     for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
714       (void) FormatLocaleFile(file," ");
715     (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
716     if (magic_info[i]->target != (char *) NULL)
717       {
718         for (j=0; magic_info[i]->target[j] != '\0'; j++)
719           if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
720             (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
721           else
722             (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
723               ((unsigned char) magic_info[i]->target[j]));
724       }
725     (void) FormatLocaleFile(file,"\n");
726   }
727   (void) fflush(file);
728   magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
729   return(MagickTrue);
730 }
731 \f
732 /*
733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734 %                                                                             %
735 %                                                                             %
736 %                                                                             %
737 +   M a g i c C o m p o n e n t G e n e s i s                                 %
738 %                                                                             %
739 %                                                                             %
740 %                                                                             %
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 %
743 %  MagicComponentGenesis() instantiates the magic component.
744 %
745 %  The format of the MagicComponentGenesis method is:
746 %
747 %      MagickBooleanType MagicComponentGenesis(void)
748 %
749 */
750 MagickPrivate MagickBooleanType MagicComponentGenesis(void)
751 {
752   if (magic_list_semaphore == (SemaphoreInfo *) NULL)
753     magic_list_semaphore=AcquireSemaphoreInfo();
754   return(MagickTrue);
755 }
756 \f
757 /*
758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759 %                                                                             %
760 %                                                                             %
761 %                                                                             %
762 +   M a g i c C o m p o n e n t T e r m i n u s                               %
763 %                                                                             %
764 %                                                                             %
765 %                                                                             %
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767 %
768 %  MagicComponentTerminus() destroys the magic component.
769 %
770 %  The format of the MagicComponentTerminus method is:
771 %
772 %      MagicComponentTerminus(void)
773 %
774 */
775
776 static void *DestroyMagicElement(void *magic_info)
777 {
778   register MagicInfo
779     *p;
780
781   p=(MagicInfo *) magic_info;
782   if (p->exempt == MagickFalse)
783     {
784       if (p->path != (char *) NULL)
785         p->path=DestroyString(p->path);
786       if (p->name != (char *) NULL)
787         p->name=DestroyString(p->name);
788       if (p->target != (char *) NULL)
789         p->target=DestroyString(p->target);
790       if (p->magic != (unsigned char *) NULL)
791         p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
792     }
793   p=(MagicInfo *) RelinquishMagickMemory(p);
794   return((void *) NULL);
795 }
796
797 MagickPrivate void MagicComponentTerminus(void)
798 {
799   if (magic_list_semaphore == (SemaphoreInfo *) NULL)
800     ActivateSemaphoreInfo(&magic_list_semaphore);
801   LockSemaphoreInfo(magic_list_semaphore);
802   if (magic_list != (LinkedListInfo *) NULL)
803     magic_list=DestroyLinkedList(magic_list,DestroyMagicElement);
804   UnlockSemaphoreInfo(magic_list_semaphore);
805   RelinquishSemaphoreInfo(&magic_list_semaphore);
806   if (magic_cache_semaphore == (SemaphoreInfo *) NULL)
807     ActivateSemaphoreInfo(&magic_cache_semaphore);
808   LockSemaphoreInfo(magic_cache_semaphore);
809   if (magic_cache != (LinkedListInfo *) NULL)
810     magic_cache=DestroyLinkedList(magic_cache,(void *(*)(void *)) NULL);
811   UnlockSemaphoreInfo(magic_cache_semaphore);
812   RelinquishSemaphoreInfo(&magic_cache_semaphore);
813 }