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