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