]> granicus.if.org Git - imagemagick/blob - magick/mime.c
(no commit message)
[imagemagick] / magick / mime.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                        M   M  IIIII  M   M  EEEEE                           %
6 %                        MM MM    I    MM MM  E                               %
7 %                        M M M    I    M M M  EEE                             %
8 %                        M   M    I    M   M  E                               %
9 %                        M   M  IIIII  M   M  EEEEE                           %
10 %                                                                             %
11 %                                                                             %
12 %                          MagickCore Mime Methods                            %
13 %                                                                             %
14 %                              Software Design                                %
15 %                                 July 2000                                   %
16 %                                                                             %
17 %                                                                             %
18 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
19 %  dedicated to making software imaging solutions freely available.           %
20 %                                                                             %
21 %  You may not use this file except in compliance with the License.  You may  %
22 %  obtain a copy of the License at                                            %
23 %                                                                             %
24 %    http://www.imagemagick.org/MagicksToolkit/script/license.php             %
25 %                                                                             %
26 %  Unless required by applicable law or agreed to in writing, software        %
27 %  distributed under the License is distributed on an "AS IS" BASIS,          %
28 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
29 %  See the License for the specific language governing permissions and        %
30 %  limitations under the License.                                             %
31 %                                                                             %
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 %
34 %
35 */
36 \f
37 /*
38   Include declarations.
39 */
40 #include "magick/studio.h"
41 #include "magick/blob.h"
42 #include "magick/client.h"
43 #include "magick/configure.h"
44 #include "magick/exception.h"
45 #include "magick/exception-private.h"
46 #include "magick/hashmap.h"
47 #include "magick/memory_.h"
48 #include "magick/mime.h"
49 #include "magick/mime-private.h"
50 #include "magick/option.h"
51 #include "magick/semaphore.h"
52 #include "magick/string_.h"
53 #include "magick/token.h"
54 #include "magick/utility.h"
55 #include "magick/xml-tree.h"
56 \f
57 /*
58   Define declarations.
59 */
60 #define MimeFilename  "mime.xml"
61 \f
62 /*
63   Typedef declaration.
64 */
65 struct _MimeInfo
66 {
67   char
68     *path,
69     *type,
70     *description,
71     *pattern;
72
73   long
74     priority;
75
76   MagickOffsetType
77     offset;
78
79   size_t
80     extent;
81
82   DataType
83     data_type;
84
85   long
86     mask,
87     value;
88
89   EndianType
90     endian;
91
92   size_t
93     length;
94
95   unsigned char
96     *magic;
97
98   MagickBooleanType
99     stealth;
100
101   unsigned long
102     signature;
103 };
104 \f
105 /*
106   Static declarations.
107 */
108 static const char
109   *MimeMap = (char *)
110     "<?xml version=\"1.0\"?>"
111     "<mimemap>"
112     "</mimemap>";
113
114 static LinkedListInfo
115   *mime_list = (LinkedListInfo *) NULL;
116
117 static SemaphoreInfo
118   *mime_semaphore = (SemaphoreInfo *) NULL;
119
120 static volatile MagickBooleanType
121   instantiate_mime = MagickFalse;
122 \f
123 /*
124   Forward declarations.
125 */
126 static MagickBooleanType
127   InitializeMimeList(ExceptionInfo *);
128 \f
129 /*
130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 %                                                                             %
132 %                                                                             %
133 %                                                                             %
134 +   D e s t r o y M i m e L i s t                                             %
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 %
140 %  DestroyMimeList() deallocates memory associated with the mime list.
141 %
142 %  The format of the DestroyMimeList method is:
143 %
144 %      DestroyMimeList(void)
145 %
146 */
147
148 static void *DestroyMimeElement(void *mime_info)
149 {
150   register MimeInfo
151     *p;
152
153   p=(MimeInfo *) mime_info;
154   if (p->magic != (unsigned char *) NULL)
155     p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
156   if (p->pattern != (char *) NULL)
157     p->pattern=DestroyString(p->pattern);
158   if (p->description != (char *) NULL)
159     p->description=DestroyString(p->description);
160   if (p->type != (char *) NULL)
161     p->type=DestroyString(p->type);
162   if (p->path != (char *) NULL)
163     p->path=DestroyString(p->path);
164   p=(MimeInfo *) RelinquishMagickMemory(p);
165   return((void *) NULL);
166 }
167
168 MagickExport void DestroyMimeList(void)
169 {
170   AcquireSemaphoreInfo(&mime_semaphore);
171   if (mime_list != (LinkedListInfo *) NULL)
172     mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
173   instantiate_mime=MagickFalse;
174   RelinquishSemaphoreInfo(mime_semaphore);
175   DestroySemaphoreInfo(&mime_semaphore);
176 }
177 \f
178 /*
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 %                                                                             %
181 %                                                                             %
182 %                                                                             %
183 +   G e t M i m e I n f o                                                     %
184 %                                                                             %
185 %                                                                             %
186 %                                                                             %
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 %
189 %  GetMimeInfo() attempts to classify the content to identify which mime type
190 %  is associated with the content, if any.
191 %
192 %  The format of the GetMimeInfo method is:
193 %
194 %      const MimeInfo *GetMimeInfo(const char *filename,
195 %        const unsigned char *magic,const size_t length,
196 %        ExceptionInfo *exception)
197 %
198 %  A description of each parameter follows:
199 %
200 %    o filename:  If we cannot not classify the string, we attempt to classify
201 %      based on the filename (e.g. *.pdf returns application/pdf).
202 %
203 %    o magic: A binary string generally representing the first few characters
204 %      of the image file or blob.
205 %
206 %    o length: the length of the binary signature.
207 %
208 %    o exception: return any errors or warnings in this structure.
209 %
210 */
211 MagickExport const MimeInfo *GetMimeInfo(const char *filename,
212   const unsigned char *magic,const size_t length,ExceptionInfo *exception)
213 {
214   const MimeInfo
215     *mime_info;
216
217   EndianType
218     endian;
219
220   long
221     value;
222
223   register const MimeInfo
224     *p;
225
226   register const unsigned char
227     *q;
228
229   register long
230     i;
231
232   unsigned long
233     lsb_first;
234
235   assert(exception != (ExceptionInfo *) NULL);
236   if ((mime_list == (LinkedListInfo *) NULL) ||
237       (instantiate_mime == MagickFalse))
238     if (InitializeMimeList(exception) == MagickFalse)
239       return((const MimeInfo *) NULL);
240   if ((mime_list == (LinkedListInfo *) NULL) ||
241       (IsLinkedListEmpty(mime_list) != MagickFalse))
242     return((const MimeInfo *) NULL);
243   if ((magic == (const unsigned char *) NULL) || (length == 0))
244     return((const MimeInfo *) GetValueFromLinkedList(mime_list,0));
245   if (length == 0)
246     return((const MimeInfo *) NULL);
247   /*
248     Search for mime tag.
249   */
250   mime_info=(const MimeInfo *) NULL;
251   lsb_first=1;
252   AcquireSemaphoreInfo(&mime_semaphore);
253   ResetLinkedListIterator(mime_list);
254   p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
255   while (p != (const MimeInfo *) NULL)
256   {
257     assert(p->offset >= 0);
258     if (mime_info != (const MimeInfo *) NULL)
259       if (p->priority > mime_info->priority)
260         {
261           p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
262           continue;
263         }
264     if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
265       {
266         if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
267           mime_info=p;
268         p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
269         continue;
270       }
271     switch (p->data_type)
272     {
273       case ByteData:
274       {
275         if ((size_t) (p->offset+4) > length)
276           break;
277         q=magic+p->offset;
278         value=(*q++);
279         if (p->mask == 0)
280           {
281             if (p->value == value)
282               mime_info=p;
283           }
284         else
285           {
286             if ((p->value & p->mask) == value)
287               mime_info=p;
288           }
289         break;
290       }
291       case ShortData:
292       {
293         if ((size_t) (p->offset+4) > length)
294           break;
295         q=magic+p->offset;
296         endian=p->endian;
297         if (p->endian == UndefinedEndian)
298           endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
299         if (endian == LSBEndian)
300           {
301             value=(*q++);
302             value|=(*q++) << 8;
303           }
304         else
305           {
306             value=(*q++) << 8;
307             value|=(*q++);
308           }
309         if (p->mask == 0)
310           {
311             if (p->value == value)
312               mime_info=p;
313           }
314         else
315           {
316             if ((p->value & p->mask) == value)
317               mime_info=p;
318           }
319         break;
320       }
321       case LongData:
322       {
323         if ((size_t) (p->offset+4) > length)
324           break;
325         q=magic+p->offset;
326         endian=p->endian;
327         if (p->endian == UndefinedEndian)
328           endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
329         if (endian == LSBEndian)
330           {
331             value=(*q++);
332             value|=(*q++) << 8;
333             value|=(*q++) << 16;
334             value|=(*q++) << 24;
335           }
336         else
337           {
338             value=(*q++) << 24;
339             value|=(*q++) << 16;
340             value|=(*q++) << 8;
341             value|=(*q++);
342           }
343         if (p->mask == 0)
344           {
345             if (p->value == value)
346               mime_info=p;
347           }
348         else
349           {
350             if ((p->value & p->mask) == value)
351               mime_info=p;
352           }
353         break;
354       }
355       case StringData:
356       default:
357       {
358         for (i=0; i <= (long) p->extent; i++)
359         {
360           if ((size_t) (p->offset+i+p->length) > length)
361             break;
362           if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
363             {
364               mime_info=p;
365               break;
366             }
367         }
368         break;
369       }
370     }
371     p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
372   }
373   if (p != (const MimeInfo *) NULL)
374     (void) InsertValueInLinkedList(mime_list,0,
375       RemoveElementByValueFromLinkedList(mime_list,p));
376   RelinquishSemaphoreInfo(mime_semaphore);
377   return(mime_info);
378 }
379 \f
380 /*
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 %                                                                             %
383 %                                                                             %
384 %                                                                             %
385 %   G e t M i m e I n f o L i s t                                             %
386 %                                                                             %
387 %                                                                             %
388 %                                                                             %
389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %
391 %  GetMimeInfoList() returns any image aliases that match the specified
392 %  pattern.
393 %
394 %  The magic of the GetMimeInfoList function is:
395 %
396 %      const MimeInfo **GetMimeInfoList(const char *pattern,
397 %        unsigned long *number_aliases,ExceptionInfo *exception)
398 %
399 %  A description of each parameter follows:
400 %
401 %    o pattern: Specifies a pointer to a text string containing a pattern.
402 %
403 %    o number_aliases:  This integer returns the number of magics in the
404 %      list.
405 %
406 %    o exception: return any errors or warnings in this structure.
407 %
408 */
409
410 #if defined(__cplusplus) || defined(c_plusplus)
411 extern "C" {
412 #endif
413
414 static int MimeInfoCompare(const void *x,const void *y)
415 {
416   const MimeInfo
417     **p,
418     **q;
419
420   p=(const MimeInfo **) x,
421   q=(const MimeInfo **) y;
422   if (strcasecmp((*p)->path,(*q)->path) == 0)
423     return(strcasecmp((*p)->type,(*q)->type));
424   return(strcasecmp((*p)->path,(*q)->path));
425 }
426
427 #if defined(__cplusplus) || defined(c_plusplus)
428 }
429 #endif
430
431 MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
432   unsigned long *number_aliases,ExceptionInfo *exception)
433 {
434   const MimeInfo
435     **aliases;
436
437   register const MimeInfo
438     *p;
439
440   register long
441     i;
442
443   /*
444     Allocate mime list.
445   */
446   assert(pattern != (char *) NULL);
447   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
448   assert(number_aliases != (unsigned long *) NULL);
449   *number_aliases=0;
450   p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
451   if (p == (const MimeInfo *) NULL)
452     return((const MimeInfo **) NULL);
453   aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
454     GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
455   if (aliases == (const MimeInfo **) NULL)
456     return((const MimeInfo **) NULL);
457   /*
458     Generate mime list.
459   */
460   AcquireSemaphoreInfo(&mime_semaphore);
461   ResetLinkedListIterator(mime_list);
462   p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
463   for (i=0; p != (const MimeInfo *) NULL; )
464   {
465     if ((p->stealth == MagickFalse) &&
466         (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
467       aliases[i++]=p;
468     p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
469   }
470   RelinquishSemaphoreInfo(mime_semaphore);
471   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
472   aliases[i]=(MimeInfo *) NULL;
473   *number_aliases=(unsigned long) i;
474   return(aliases);
475 }
476 \f
477 /*
478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 %                                                                             %
480 %                                                                             %
481 %                                                                             %
482 %   G e t M i m e L i s t                                                     %
483 %                                                                             %
484 %                                                                             %
485 %                                                                             %
486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487 %
488 %  GetMimeList() returns any image format alias that matches the specified
489 %  pattern.
490 %
491 %  The format of the GetMimeList function is:
492 %
493 %      char **GetMimeList(const char *pattern,unsigned long *number_aliases,
494 %        ExceptionInfo *exception)
495 %
496 %  A description of each parameter follows:
497 %
498 %    o pattern: Specifies a pointer to a text string containing a pattern.
499 %
500 %    o number_aliases:  This integer returns the number of image format aliases
501 %      in the list.
502 %
503 %    o exception: return any errors or warnings in this structure.
504 %
505 */
506
507 #if defined(__cplusplus) || defined(c_plusplus)
508 extern "C" {
509 #endif
510
511 static int MimeCompare(const void *x,const void *y)
512 {
513   register char
514     *p,
515     *q;
516
517   p=(char *) x;
518   q=(char *) y;
519   return(strcasecmp(p,q));
520 }
521
522 #if defined(__cplusplus) || defined(c_plusplus)
523 }
524 #endif
525
526 MagickExport char **GetMimeList(const char *pattern,
527   unsigned long *number_aliases,ExceptionInfo *exception)
528 {
529   char
530     **aliases;
531
532   register const MimeInfo
533     *p;
534
535   register long
536     i;
537
538   /*
539     Allocate configure list.
540   */
541   assert(pattern != (char *) NULL);
542   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
543   assert(number_aliases != (unsigned long *) NULL);
544   *number_aliases=0;
545   p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
546   if (p == (const MimeInfo *) NULL)
547     return((char **) NULL);
548   aliases=(char **) AcquireQuantumMemory((size_t)
549     GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
550   if (aliases == (char **) NULL)
551     return((char **) NULL);
552   AcquireSemaphoreInfo(&mime_semaphore);
553   ResetLinkedListIterator(mime_list);
554   p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
555   for (i=0; p != (const MimeInfo *) NULL; )
556   {
557     if ((p->stealth == MagickFalse) &&
558         (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
559       aliases[i++]=ConstantString(p->type);
560     p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
561   }
562   RelinquishSemaphoreInfo(mime_semaphore);
563   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
564   aliases[i]=(char *) NULL;
565   *number_aliases=(unsigned long) i;
566   return(aliases);
567 }
568 \f
569 /*
570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571 %                                                                             %
572 %                                                                             %
573 %                                                                             %
574 %   G e t M i m e D e s c r i p t i o n                                       %
575 %                                                                             %
576 %                                                                             %
577 %                                                                             %
578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
579 %
580 %  GetMimeDescription() returns the mime type description.
581 %
582 %  The format of the GetMimeDescription method is:
583 %
584 %      const char *GetMimeDescription(const MimeInfo *mime_info)
585 %
586 %  A description of each parameter follows:
587 %
588 %    o mime_info:  The magic info.
589 %
590 */
591 MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
592 {
593   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
594   assert(mime_info != (MimeInfo *) NULL);
595   assert(mime_info->signature == MagickSignature);
596   return(mime_info->description);
597 }
598 \f
599 /*
600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601 %                                                                             %
602 %                                                                             %
603 %                                                                             %
604 %   G e t M i m e T y p e                                                     %
605 %                                                                             %
606 %                                                                             %
607 %                                                                             %
608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
609 %
610 %  GetMimeType() returns the mime type.
611 %
612 %  The format of the GetMimeType method is:
613 %
614 %      const char *GetMimeType(const MimeInfo *mime_info)
615 %
616 %  A description of each parameter follows:
617 %
618 %    o mime_info:  The magic info.
619 %
620 */
621 MagickExport const char *GetMimeType(const MimeInfo *mime_info)
622 {
623   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
624   assert(mime_info != (MimeInfo *) NULL);
625   assert(mime_info->signature == MagickSignature);
626   return(mime_info->type);
627 }
628 \f
629 /*
630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631 %                                                                             %
632 %                                                                             %
633 %                                                                             %
634 +   I n i t i a l i z e M i m e L i s t                                       %
635 %                                                                             %
636 %                                                                             %
637 %                                                                             %
638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 %
640 %  InitializeMimeList() initializes the mime list.
641 %
642 %  The format of the InitializeMimeList method is:
643 %
644 %      MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
645 %
646 %  A description of each parameter follows.
647 %
648 %    o exception: return any errors or warnings in this structure.
649 %
650 */
651 static MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
652 {
653   if ((mime_list == (LinkedListInfo *) NULL) &&
654       (instantiate_mime == MagickFalse))
655     {
656       AcquireSemaphoreInfo(&mime_semaphore);
657       if ((mime_list == (LinkedListInfo *) NULL) &&
658           (instantiate_mime == MagickFalse))
659         {
660           (void) LoadMimeLists(MimeFilename,exception);
661           instantiate_mime=MagickTrue;
662         }
663       RelinquishSemaphoreInfo(mime_semaphore);
664     }
665   return(mime_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
666 }
667 \f
668 /*
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %                                                                             %
671 %                                                                             %
672 %                                                                             %
673 %  L i s t M i m e I n f o                                                    %
674 %                                                                             %
675 %                                                                             %
676 %                                                                             %
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %
679 %  ListMimeInfo() lists the magic info to a file.
680 %
681 %  The format of the ListMimeInfo method is:
682 %
683 %      MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
684 %
685 %  A description of each parameter follows.
686 %
687 %    o file:  An pointer to a FILE.
688 %
689 %    o exception: return any errors or warnings in this structure.
690 %
691 */
692 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
693 {
694   const char
695     *path;
696
697   const MimeInfo
698     **mime_info;
699
700   long
701     j;
702
703   register long
704     i;
705
706   unsigned long
707     number_aliases;
708
709   if (file == (const FILE *) NULL)
710     file=stdout;
711   mime_info=GetMimeInfoList("*",&number_aliases,exception);
712   if (mime_info == (const MimeInfo **) NULL)
713     return(MagickFalse);
714   j=0;
715   path=(const char *) NULL;
716   for (i=0; i < (long) number_aliases; i++)
717   {
718     if (mime_info[i]->stealth != MagickFalse)
719       continue;
720     if ((path == (const char *) NULL) ||
721         (strcasecmp(path,mime_info[i]->path) != 0))
722       {
723         if (mime_info[i]->path != (char *) NULL)
724           (void) fprintf(file,"\nPath: %s\n\n",mime_info[i]->path);
725         (void) fprintf(file,"Type                   Description\n");
726         (void) fprintf(file,"-------------------------------------------------"
727           "------------------------------\n");
728       }
729     path=mime_info[i]->path;
730     (void) fprintf(file,"%s",mime_info[i]->type);
731     if (strlen(mime_info[i]->type) <= 25)
732       {
733         for (j=(long) strlen(mime_info[i]->type); j <= 27; j++)
734           (void) fprintf(file," ");
735       }
736     else
737       {
738         (void) fprintf(file,"\n");
739         for (j=0; j <= 27; j++)
740           (void) fprintf(file," ");
741       }
742     if (mime_info[i]->description != (char *) NULL)
743       (void) fprintf(file,"%s",mime_info[i]->description);
744     (void) fprintf(file,"\n");
745   }
746   (void) fflush(file);
747   mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
748   return(MagickTrue);
749 }
750 \f
751 /*
752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753 %                                                                             %
754 %                                                                             %
755 %                                                                             %
756 +   L o a d M i m e L i s t                                                   %
757 %                                                                             %
758 %                                                                             %
759 %                                                                             %
760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761 %
762 %  LoadMimeList() loads the magic configuration file which provides a mapping
763 %  between magic attributes and a magic name.
764 %
765 %  The format of the LoadMimeList method is:
766 %
767 %      MagickBooleanType LoadMimeList(const char *xml,const char *filename,
768 %        const unsigned long depth,ExceptionInfo *exception)
769 %
770 %  A description of each parameter follows:
771 %
772 %    o xml:  The mime list in XML format.
773 %
774 %    o filename:  The mime list filename.
775 %
776 %    o depth: depth of <include /> statements.
777 %
778 %    o exception: return any errors or warnings in this structure.
779 %
780 */
781 static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
782   const unsigned long depth,ExceptionInfo *exception)
783 {
784   const char
785     *attribute;
786
787   MimeInfo
788     *mime_info = (MimeInfo *) NULL;
789
790   MagickBooleanType
791     status;
792
793   XMLTreeInfo
794     *mime,
795     *mime_map,
796     *include;
797
798   /*
799     Load the mime map file.
800   */
801   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
802     "Loading mime map \"%s\" ...",filename);
803   if (xml == (const char *) NULL)
804     return(MagickFalse);
805   if (mime_list == (LinkedListInfo *) NULL)
806     {
807       mime_list=NewLinkedList(0);
808       if (mime_list == (LinkedListInfo *) NULL)
809         {
810           ThrowFileException(exception,ResourceLimitError,
811             "MemoryAllocationFailed",filename);
812           return(MagickFalse);
813         }
814     }
815   mime_map=NewXMLTree(xml,exception);
816   if (mime_map == (XMLTreeInfo *) NULL)
817     return(MagickFalse);
818   status=MagickTrue;
819   include=GetXMLTreeChild(mime_map,"include");
820   while (include != (XMLTreeInfo *) NULL)
821   {
822     /*
823       Process include element.
824     */
825     attribute=GetXMLTreeAttribute(include,"file");
826     if (attribute != (const char *) NULL)
827       {
828         if (depth > 200)
829           (void) ThrowMagickException(exception,GetMagickModule(),
830             ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
831         else
832           {
833             char
834               path[MaxTextExtent],
835               *xml;
836
837             GetPathComponent(filename,HeadPath,path);
838             if (*path != '\0')
839               (void) ConcatenateMagickString(path,DirectorySeparator,
840                 MaxTextExtent);
841             if (*attribute == *DirectorySeparator)
842               (void) CopyMagickString(path,attribute,MaxTextExtent);
843             else
844               (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
845             xml=FileToString(path,~0,exception);
846             if (xml != (char *) NULL)
847               {
848                 status=LoadMimeList(xml,path,depth+1,exception);
849                 xml=DestroyString(xml);
850               }
851           }
852       }
853     include=GetNextXMLTreeTag(include);
854   }
855   mime=GetXMLTreeChild(mime_map,"mime");
856   while (mime != (XMLTreeInfo *) NULL)
857   {
858     const char
859       *attribute;
860
861     /*
862       Process mime element.
863     */
864     mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
865     if (mime_info == (MimeInfo *) NULL)
866       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
867     (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
868     mime_info->path=ConstantString(filename);
869     mime_info->signature=MagickSignature;
870     attribute=GetXMLTreeAttribute(mime,"data-type");
871     if (attribute != (const char *) NULL)
872       mime_info->data_type=(DataType) ParseMagickOption(MagickDataTypeOptions,
873         MagickTrue,attribute);
874     attribute=GetXMLTreeAttribute(mime,"description");
875     if (attribute != (const char *) NULL)
876       mime_info->description=ConstantString(attribute);
877     attribute=GetXMLTreeAttribute(mime,"endian");
878     if (attribute != (const char *) NULL)
879       mime_info->endian=(EndianType) ParseMagickOption(MagickEndianOptions,
880         MagickTrue,attribute);
881     attribute=GetXMLTreeAttribute(mime,"magic");
882     if (attribute != (const char *) NULL)
883       {
884         char
885           *token;
886
887         const char
888           *p;
889
890         register unsigned char
891           *q;
892
893         token=AcquireString(attribute);
894         (void) SubstituteString((char **) &token,"&lt;","<");
895         (void) SubstituteString((char **) &token,"&amp;","&");
896         (void) SubstituteString((char **) &token,"&quot;","\"");
897         mime_info->magic=(unsigned char *) AcquireString(token);
898         q=mime_info->magic;
899         for (p=token; *p != '\0'; )
900         {
901           if (*p == '\\')
902             {
903               p++;
904               if (isdigit((int) ((unsigned char) *p)) != 0)
905                 {
906                   char
907                     *end;
908
909                   *q++=(unsigned char) strtol(p,&end,8);
910                   p+=(end-p);
911                   mime_info->length++;
912                   continue;
913                 }
914               switch (*p)
915               {
916                 case 'b': *q='\b'; break;
917                 case 'f': *q='\f'; break;
918                 case 'n': *q='\n'; break;
919                 case 'r': *q='\r'; break;
920                 case 't': *q='\t'; break;
921                 case 'v': *q='\v'; break;
922                 case 'a': *q='a'; break;
923                 case '?': *q='\?'; break;
924                 default: *q=(unsigned char) (*p); break;
925               }
926               p++;
927               q++;
928               mime_info->length++;
929               continue;
930             }
931           *q++=(unsigned char) (*p++);
932           mime_info->length++;
933         }
934         token=DestroyString(token);
935         if (mime_info->data_type != StringData)
936           mime_info->value=strtol((char *) mime_info->magic,(char **) NULL,0);
937       }
938     attribute=GetXMLTreeAttribute(mime,"mask");
939     if (attribute != (const char *) NULL)
940       mime_info->mask=strtol(attribute,(char **) NULL,0);
941     attribute=GetXMLTreeAttribute(mime,"offset");
942     if (attribute != (const char *) NULL)
943       {
944         char
945           *c;
946
947         mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
948         if (*c == ':')
949           mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
950       }
951     attribute=GetXMLTreeAttribute(mime,"pattern");
952     if (attribute != (const char *) NULL)
953       mime_info->pattern=ConstantString(attribute);
954     attribute=GetXMLTreeAttribute(mime,"priority");
955     if (attribute != (const char *) NULL)
956       mime_info->priority=strtol(attribute,(char **) NULL,0);
957     attribute=GetXMLTreeAttribute(mime,"stealth");
958     if (attribute != (const char *) NULL)
959       mime_info->stealth=IsMagickTrue(attribute);
960     attribute=GetXMLTreeAttribute(mime,"type");
961     if (attribute != (const char *) NULL)
962       mime_info->type=ConstantString(attribute);
963     status=AppendValueToLinkedList(mime_list,mime_info);
964     if (status == MagickFalse)
965       (void) ThrowMagickException(exception,GetMagickModule(),
966         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
967     mime=GetNextXMLTreeTag(mime);
968   }
969   mime_map=DestroyXMLTree(mime_map);
970   return(status);
971 }
972 \f
973 /*
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 %                                                                             %
976 %                                                                             %
977 %                                                                             %
978 %  L o a d M i m e L i s t s                                                  %
979 %                                                                             %
980 %                                                                             %
981 %                                                                             %
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983 %
984 %  LoadMimeList() loads one or more magic configuration file which provides a
985 %  mapping between magic attributes and a magic name.
986 %
987 %  The format of the LoadMimeLists method is:
988 %
989 %      MagickBooleanType LoadMimeLists(const char *filename,
990 %        ExceptionInfo *exception)
991 %
992 %  A description of each parameter follows:
993 %
994 %    o filename: the font file name.
995 %
996 %    o exception: return any errors or warnings in this structure.
997 %
998 */
999 MagickExport MagickBooleanType LoadMimeLists(const char *filename,
1000   ExceptionInfo *exception)
1001 {
1002 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
1003   return(LoadMimeList(MimeMap,"built-in",0,exception));
1004 #else
1005   const StringInfo
1006     *option;
1007
1008   LinkedListInfo
1009     *options;
1010
1011   MagickStatusType
1012     status;
1013
1014   status=MagickFalse;
1015   options=GetConfigureOptions(filename,exception);
1016   option=(const StringInfo *) GetNextValueInLinkedList(options);
1017   while (option != (const StringInfo *) NULL)
1018   {
1019     status|=LoadMimeList((const char *) GetStringInfoDatum(option),
1020       GetStringInfoPath(option),0,exception);
1021     option=(const StringInfo *) GetNextValueInLinkedList(options);
1022   }
1023   options=DestroyConfigureOptions(options);
1024   if ((mime_list == (LinkedListInfo *) NULL) || 
1025       (IsLinkedListEmpty(mime_list) != MagickFalse))
1026     status|=LoadMimeList(MimeMap,"built-in",0,exception);
1027   else
1028     ClearMagickException(exception);
1029   return(status != 0 ? MagickTrue : MagickFalse);
1030 #endif
1031 }
1032 \f
1033 /*
1034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 %                                                                             %
1036 %                                                                             %
1037 %                                                                             %
1038 +  M a g i c k T o M i m e                                                    %
1039 %                                                                             %
1040 %                                                                             %
1041 %                                                                             %
1042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043 %
1044 %  MagickToMime() returns the officially registered (or de facto) MIME
1045 %  media-type corresponding to a magick string.  If there is no registered
1046 %  media-type, then the string "image/x-magick" (all lower case) is returned.
1047 %  The returned string must be deallocated by the user.
1048 %
1049 %  The format of the MagickToMime method is:
1050 %
1051 %      char *MagickToMime(const char *magick)
1052 %
1053 %  A description of each parameter follows.
1054 %
1055 %   o  magick:  ImageMagick format specification "magick" tag.
1056 %
1057 */
1058 MagickExport char *MagickToMime(const char *magick)
1059 {
1060   char
1061     filename[MaxTextExtent],
1062     media[MaxTextExtent];
1063
1064   const MimeInfo
1065     *mime_info;
1066
1067   ExceptionInfo
1068     *exception;
1069
1070   (void) FormatMagickString(filename,MaxTextExtent,"file.%s",magick);
1071   LocaleLower(filename);
1072   exception=AcquireExceptionInfo();
1073   mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1074   exception=DestroyExceptionInfo(exception);
1075   if (mime_info != (const MimeInfo *) NULL)
1076     return(ConstantString(GetMimeType(mime_info)));
1077   (void) FormatMagickString(media,MaxTextExtent,"image/x-%s",magick);
1078   LocaleLower(media+8);
1079   return(ConstantString(media));
1080 }