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