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