]> 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 F a c i l i t y                                     %
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 %
140 %  DestroyMimeFacility() destroys the mime facility.
141 %
142 %  The format of the DestroyMimeFacility method is:
143 %
144 %      DestroyMimeFacility(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 DestroyMimeFacility(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 +   I n s t a n t i a t e M i m e F a c i l i t y                             %
674 %                                                                             %
675 %                                                                             %
676 %                                                                             %
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %
679 %  InstantiateMimeFacility() instantiates the mime facility.
680 %
681 %  The format of the InstantiateMimeFacility method is:
682 %
683 %      MagickBooleanType InstantiateMimeFacility(void)
684 %
685 */
686 MagickExport MagickBooleanType InstantiateMimeFacility(void)
687 {
688   AcquireSemaphoreInfo(&mime_semaphore);
689   RelinquishSemaphoreInfo(mime_semaphore);
690   return(MagickTrue);
691 }
692 \f
693 /*
694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695 %                                                                             %
696 %                                                                             %
697 %                                                                             %
698 %  L i s t M i m e I n f o                                                    %
699 %                                                                             %
700 %                                                                             %
701 %                                                                             %
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 %
704 %  ListMimeInfo() lists the magic info to a file.
705 %
706 %  The format of the ListMimeInfo method is:
707 %
708 %      MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
709 %
710 %  A description of each parameter follows.
711 %
712 %    o file:  An pointer to a FILE.
713 %
714 %    o exception: return any errors or warnings in this structure.
715 %
716 */
717 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
718 {
719   const char
720     *path;
721
722   const MimeInfo
723     **mime_info;
724
725   long
726     j;
727
728   register long
729     i;
730
731   unsigned long
732     number_aliases;
733
734   if (file == (const FILE *) NULL)
735     file=stdout;
736   mime_info=GetMimeInfoList("*",&number_aliases,exception);
737   if (mime_info == (const MimeInfo **) NULL)
738     return(MagickFalse);
739   j=0;
740   path=(const char *) NULL;
741   for (i=0; i < (long) number_aliases; i++)
742   {
743     if (mime_info[i]->stealth != MagickFalse)
744       continue;
745     if ((path == (const char *) NULL) ||
746         (strcasecmp(path,mime_info[i]->path) != 0))
747       {
748         if (mime_info[i]->path != (char *) NULL)
749           (void) fprintf(file,"\nPath: %s\n\n",mime_info[i]->path);
750         (void) fprintf(file,"Type                   Description\n");
751         (void) fprintf(file,"-------------------------------------------------"
752           "------------------------------\n");
753       }
754     path=mime_info[i]->path;
755     (void) fprintf(file,"%s",mime_info[i]->type);
756     if (strlen(mime_info[i]->type) <= 25)
757       {
758         for (j=(long) strlen(mime_info[i]->type); j <= 27; j++)
759           (void) fprintf(file," ");
760       }
761     else
762       {
763         (void) fprintf(file,"\n");
764         for (j=0; j <= 27; j++)
765           (void) fprintf(file," ");
766       }
767     if (mime_info[i]->description != (char *) NULL)
768       (void) fprintf(file,"%s",mime_info[i]->description);
769     (void) fprintf(file,"\n");
770   }
771   (void) fflush(file);
772   mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
773   return(MagickTrue);
774 }
775 \f
776 /*
777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778 %                                                                             %
779 %                                                                             %
780 %                                                                             %
781 +   L o a d M i m e L i s t                                                   %
782 %                                                                             %
783 %                                                                             %
784 %                                                                             %
785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 %
787 %  LoadMimeList() loads the magic configuration file which provides a mapping
788 %  between magic attributes and a magic name.
789 %
790 %  The format of the LoadMimeList method is:
791 %
792 %      MagickBooleanType LoadMimeList(const char *xml,const char *filename,
793 %        const unsigned long depth,ExceptionInfo *exception)
794 %
795 %  A description of each parameter follows:
796 %
797 %    o xml:  The mime list in XML format.
798 %
799 %    o filename:  The mime list filename.
800 %
801 %    o depth: depth of <include /> statements.
802 %
803 %    o exception: return any errors or warnings in this structure.
804 %
805 */
806 static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
807   const unsigned long depth,ExceptionInfo *exception)
808 {
809   const char
810     *attribute;
811
812   MimeInfo
813     *mime_info = (MimeInfo *) NULL;
814
815   MagickBooleanType
816     status;
817
818   XMLTreeInfo
819     *mime,
820     *mime_map,
821     *include;
822
823   /*
824     Load the mime map file.
825   */
826   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
827     "Loading mime map \"%s\" ...",filename);
828   if (xml == (const char *) NULL)
829     return(MagickFalse);
830   if (mime_list == (LinkedListInfo *) NULL)
831     {
832       mime_list=NewLinkedList(0);
833       if (mime_list == (LinkedListInfo *) NULL)
834         {
835           ThrowFileException(exception,ResourceLimitError,
836             "MemoryAllocationFailed",filename);
837           return(MagickFalse);
838         }
839     }
840   mime_map=NewXMLTree(xml,exception);
841   if (mime_map == (XMLTreeInfo *) NULL)
842     return(MagickFalse);
843   status=MagickTrue;
844   include=GetXMLTreeChild(mime_map,"include");
845   while (include != (XMLTreeInfo *) NULL)
846   {
847     /*
848       Process include element.
849     */
850     attribute=GetXMLTreeAttribute(include,"file");
851     if (attribute != (const char *) NULL)
852       {
853         if (depth > 200)
854           (void) ThrowMagickException(exception,GetMagickModule(),
855             ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
856         else
857           {
858             char
859               path[MaxTextExtent],
860               *xml;
861
862             GetPathComponent(filename,HeadPath,path);
863             if (*path != '\0')
864               (void) ConcatenateMagickString(path,DirectorySeparator,
865                 MaxTextExtent);
866             if (*attribute == *DirectorySeparator)
867               (void) CopyMagickString(path,attribute,MaxTextExtent);
868             else
869               (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
870             xml=FileToString(path,~0,exception);
871             if (xml != (char *) NULL)
872               {
873                 status=LoadMimeList(xml,path,depth+1,exception);
874                 xml=DestroyString(xml);
875               }
876           }
877       }
878     include=GetNextXMLTreeTag(include);
879   }
880   mime=GetXMLTreeChild(mime_map,"mime");
881   while (mime != (XMLTreeInfo *) NULL)
882   {
883     const char
884       *attribute;
885
886     /*
887       Process mime element.
888     */
889     mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
890     if (mime_info == (MimeInfo *) NULL)
891       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
892     (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
893     mime_info->path=ConstantString(filename);
894     mime_info->signature=MagickSignature;
895     attribute=GetXMLTreeAttribute(mime,"data-type");
896     if (attribute != (const char *) NULL)
897       mime_info->data_type=(DataType) ParseMagickOption(MagickDataTypeOptions,
898         MagickTrue,attribute);
899     attribute=GetXMLTreeAttribute(mime,"description");
900     if (attribute != (const char *) NULL)
901       mime_info->description=ConstantString(attribute);
902     attribute=GetXMLTreeAttribute(mime,"endian");
903     if (attribute != (const char *) NULL)
904       mime_info->endian=(EndianType) ParseMagickOption(MagickEndianOptions,
905         MagickTrue,attribute);
906     attribute=GetXMLTreeAttribute(mime,"magic");
907     if (attribute != (const char *) NULL)
908       {
909         char
910           *token;
911
912         const char
913           *p;
914
915         register unsigned char
916           *q;
917
918         token=AcquireString(attribute);
919         (void) SubstituteString((char **) &token,"&lt;","<");
920         (void) SubstituteString((char **) &token,"&amp;","&");
921         (void) SubstituteString((char **) &token,"&quot;","\"");
922         mime_info->magic=(unsigned char *) AcquireString(token);
923         q=mime_info->magic;
924         for (p=token; *p != '\0'; )
925         {
926           if (*p == '\\')
927             {
928               p++;
929               if (isdigit((int) ((unsigned char) *p)) != 0)
930                 {
931                   char
932                     *end;
933
934                   *q++=(unsigned char) strtol(p,&end,8);
935                   p+=(end-p);
936                   mime_info->length++;
937                   continue;
938                 }
939               switch (*p)
940               {
941                 case 'b': *q='\b'; break;
942                 case 'f': *q='\f'; break;
943                 case 'n': *q='\n'; break;
944                 case 'r': *q='\r'; break;
945                 case 't': *q='\t'; break;
946                 case 'v': *q='\v'; break;
947                 case 'a': *q='a'; break;
948                 case '?': *q='\?'; break;
949                 default: *q=(unsigned char) (*p); break;
950               }
951               p++;
952               q++;
953               mime_info->length++;
954               continue;
955             }
956           *q++=(unsigned char) (*p++);
957           mime_info->length++;
958         }
959         token=DestroyString(token);
960         if (mime_info->data_type != StringData)
961           mime_info->value=strtol((char *) mime_info->magic,(char **) NULL,0);
962       }
963     attribute=GetXMLTreeAttribute(mime,"mask");
964     if (attribute != (const char *) NULL)
965       mime_info->mask=strtol(attribute,(char **) NULL,0);
966     attribute=GetXMLTreeAttribute(mime,"offset");
967     if (attribute != (const char *) NULL)
968       {
969         char
970           *c;
971
972         mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
973         if (*c == ':')
974           mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
975       }
976     attribute=GetXMLTreeAttribute(mime,"pattern");
977     if (attribute != (const char *) NULL)
978       mime_info->pattern=ConstantString(attribute);
979     attribute=GetXMLTreeAttribute(mime,"priority");
980     if (attribute != (const char *) NULL)
981       mime_info->priority=strtol(attribute,(char **) NULL,0);
982     attribute=GetXMLTreeAttribute(mime,"stealth");
983     if (attribute != (const char *) NULL)
984       mime_info->stealth=IsMagickTrue(attribute);
985     attribute=GetXMLTreeAttribute(mime,"type");
986     if (attribute != (const char *) NULL)
987       mime_info->type=ConstantString(attribute);
988     status=AppendValueToLinkedList(mime_list,mime_info);
989     if (status == MagickFalse)
990       (void) ThrowMagickException(exception,GetMagickModule(),
991         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
992     mime=GetNextXMLTreeTag(mime);
993   }
994   mime_map=DestroyXMLTree(mime_map);
995   return(status);
996 }
997 \f
998 /*
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000 %                                                                             %
1001 %                                                                             %
1002 %                                                                             %
1003 %  L o a d M i m e L i s t s                                                  %
1004 %                                                                             %
1005 %                                                                             %
1006 %                                                                             %
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 %
1009 %  LoadMimeList() loads one or more magic configuration file which provides a
1010 %  mapping between magic attributes and a magic name.
1011 %
1012 %  The format of the LoadMimeLists method is:
1013 %
1014 %      MagickBooleanType LoadMimeLists(const char *filename,
1015 %        ExceptionInfo *exception)
1016 %
1017 %  A description of each parameter follows:
1018 %
1019 %    o filename: the font file name.
1020 %
1021 %    o exception: return any errors or warnings in this structure.
1022 %
1023 */
1024 MagickExport MagickBooleanType LoadMimeLists(const char *filename,
1025   ExceptionInfo *exception)
1026 {
1027 #if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
1028   return(LoadMimeList(MimeMap,"built-in",0,exception));
1029 #else
1030   const StringInfo
1031     *option;
1032
1033   LinkedListInfo
1034     *options;
1035
1036   MagickStatusType
1037     status;
1038
1039   status=MagickFalse;
1040   options=GetConfigureOptions(filename,exception);
1041   option=(const StringInfo *) GetNextValueInLinkedList(options);
1042   while (option != (const StringInfo *) NULL)
1043   {
1044     status|=LoadMimeList((const char *) GetStringInfoDatum(option),
1045       GetStringInfoPath(option),0,exception);
1046     option=(const StringInfo *) GetNextValueInLinkedList(options);
1047   }
1048   options=DestroyConfigureOptions(options);
1049   if ((mime_list == (LinkedListInfo *) NULL) ||
1050       (IsLinkedListEmpty(mime_list) != MagickFalse))
1051     status|=LoadMimeList(MimeMap,"built-in",0,exception);
1052   else
1053     ClearMagickException(exception);
1054   return(status != 0 ? MagickTrue : MagickFalse);
1055 #endif
1056 }
1057 \f
1058 /*
1059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1060 %                                                                             %
1061 %                                                                             %
1062 %                                                                             %
1063 +  M a g i c k T o M i m e                                                    %
1064 %                                                                             %
1065 %                                                                             %
1066 %                                                                             %
1067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1068 %
1069 %  MagickToMime() returns the officially registered (or de facto) MIME
1070 %  media-type corresponding to a magick string.  If there is no registered
1071 %  media-type, then the string "image/x-magick" (all lower case) is returned.
1072 %  The returned string must be deallocated by the user.
1073 %
1074 %  The format of the MagickToMime method is:
1075 %
1076 %      char *MagickToMime(const char *magick)
1077 %
1078 %  A description of each parameter follows.
1079 %
1080 %   o  magick:  ImageMagick format specification "magick" tag.
1081 %
1082 */
1083 MagickExport char *MagickToMime(const char *magick)
1084 {
1085   char
1086     filename[MaxTextExtent],
1087     media[MaxTextExtent];
1088
1089   const MimeInfo
1090     *mime_info;
1091
1092   ExceptionInfo
1093     *exception;
1094
1095   (void) FormatMagickString(filename,MaxTextExtent,"file.%s",magick);
1096   LocaleLower(filename);
1097   exception=AcquireExceptionInfo();
1098   mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1099   exception=DestroyExceptionInfo(exception);
1100   if (mime_info != (const MimeInfo *) NULL)
1101     return(ConstantString(GetMimeType(mime_info)));
1102   (void) FormatMagickString(media,MaxTextExtent,"image/x-%s",magick);
1103   LocaleLower(media+8);
1104   return(ConstantString(media));
1105 }