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