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