]> granicus.if.org Git - imagemagick/blob - MagickCore/mime.c
...
[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-2017 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/linked-list.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     *cache;
162
163   MagickStatusType
164     status;
165
166   cache=NewLinkedList(0);
167   if (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(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(cache) != MagickFalse)
190     status&=LoadMimeCache(cache,MimeMap,"built-in",0,exception);
191   return(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   ssize_t
246     value;
247
248   unsigned long
249     lsb_first;
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 == MagickCoreSignature);
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 == MagickCoreSignature);
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 *cache,const char *xml,
779 %        const char *filename,const size_t depth,ExceptionInfo *exception)
780 %
781 %  A description of each parameter follows:
782 %
783 %    o xml:  The mime list in XML format.
784 %
785 %    o filename:  The mime list filename.
786 %
787 %    o depth: depth of <include /> statements.
788 %
789 %    o exception: return any errors or warnings in this structure.
790 %
791 */
792 static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
793   const char *filename,const size_t depth,ExceptionInfo *exception)
794 {
795   const char
796     *attribute;
797
798   MimeInfo
799     *mime_info = (MimeInfo *) NULL;
800
801   MagickStatusType
802     status;
803
804   XMLTreeInfo
805     *mime,
806     *mime_map,
807     *include;
808
809   /*
810     Load the mime map file.
811   */
812   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
813     "Loading mime map \"%s\" ...",filename);
814   if (xml == (const char *) NULL)
815     return(MagickFalse);
816   mime_map=NewXMLTree(xml,exception);
817   if (mime_map == (XMLTreeInfo *) NULL)
818     return(MagickFalse);
819   status=MagickTrue;
820   include=GetXMLTreeChild(mime_map,"include");
821   while (include != (XMLTreeInfo *) NULL)
822   {
823     /*
824       Process include element.
825     */
826     attribute=GetXMLTreeAttribute(include,"file");
827     if (attribute != (const char *) NULL)
828       {
829         if (depth > 200)
830           (void) ThrowMagickException(exception,GetMagickModule(),
831             ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
832         else
833           {
834             char
835               path[MagickPathExtent],
836               *file_xml;
837
838             GetPathComponent(filename,HeadPath,path);
839             if (*path != '\0')
840               (void) ConcatenateMagickString(path,DirectorySeparator,
841                 MagickPathExtent);
842             if (*attribute == *DirectorySeparator)
843               (void) CopyMagickString(path,attribute,MagickPathExtent);
844             else
845               (void) ConcatenateMagickString(path,attribute,MagickPathExtent);
846             file_xml=FileToXML(path,~0UL);
847             if (file_xml != (char *) NULL)
848               {
849                 status&=LoadMimeCache(cache,file_xml,path,depth+1,exception);
850                 file_xml=DestroyString(file_xml);
851               }
852           }
853       }
854     include=GetNextXMLTreeTag(include);
855   }
856   mime=GetXMLTreeChild(mime_map,"mime");
857   while (mime != (XMLTreeInfo *) NULL)
858   {
859     /*
860       Process mime element.
861     */
862     mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
863     if (mime_info == (MimeInfo *) NULL)
864       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
865     (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
866     mime_info->path=ConstantString(filename);
867     mime_info->signature=MagickCoreSignature;
868     attribute=GetXMLTreeAttribute(mime,"data-type");
869     if (attribute != (const char *) NULL)
870       mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
871         MagickTrue,attribute);
872     attribute=GetXMLTreeAttribute(mime,"description");
873     if (attribute != (const char *) NULL)
874       mime_info->description=ConstantString(attribute);
875     attribute=GetXMLTreeAttribute(mime,"endian");
876     if (attribute != (const char *) NULL)
877       mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
878         MagickTrue,attribute);
879     attribute=GetXMLTreeAttribute(mime,"magic");
880     if (attribute != (const char *) NULL)
881       {
882         char
883           *token;
884
885         const char
886           *p;
887
888         register unsigned char
889           *q;
890
891         token=AcquireString(attribute);
892         (void) SubstituteString((char **) &token,"&lt;","<");
893         (void) SubstituteString((char **) &token,"&amp;","&");
894         (void) SubstituteString((char **) &token,"&quot;","\"");
895         mime_info->magic=(unsigned char *) AcquireString(token);
896         q=mime_info->magic;
897         for (p=token; *p != '\0'; )
898         {
899           if (*p == '\\')
900             {
901               p++;
902               if (isdigit((int) ((unsigned char) *p)) != 0)
903                 {
904                   char
905                     *end;
906
907                   *q++=(unsigned char) strtol(p,&end,8);
908                   p+=(end-p);
909                   mime_info->length++;
910                   continue;
911                 }
912               switch (*p)
913               {
914                 case 'b': *q='\b'; break;
915                 case 'f': *q='\f'; break;
916                 case 'n': *q='\n'; break;
917                 case 'r': *q='\r'; break;
918                 case 't': *q='\t'; break;
919                 case 'v': *q='\v'; break;
920                 case 'a': *q='a'; break;
921                 case '?': *q='\?'; break;
922                 default: *q=(unsigned char) (*p); break;
923               }
924               p++;
925               q++;
926               mime_info->length++;
927               continue;
928             }
929           *q++=(unsigned char) (*p++);
930           mime_info->length++;
931         }
932         token=DestroyString(token);
933         if (mime_info->data_type != StringData)
934           mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
935             (char **) NULL,0);
936       }
937     attribute=GetXMLTreeAttribute(mime,"mask");
938     if (attribute != (const char *) NULL)
939       mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
940     attribute=GetXMLTreeAttribute(mime,"offset");
941     if (attribute != (const char *) NULL)
942       {
943         char
944           *c;
945
946         mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
947         if (*c == ':')
948           mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
949       }
950     attribute=GetXMLTreeAttribute(mime,"pattern");
951     if (attribute != (const char *) NULL)
952       mime_info->pattern=ConstantString(attribute);
953     attribute=GetXMLTreeAttribute(mime,"priority");
954     if (attribute != (const char *) NULL)
955       mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
956     attribute=GetXMLTreeAttribute(mime,"stealth");
957     if (attribute != (const char *) NULL)
958       mime_info->stealth=IsStringTrue(attribute);
959     attribute=GetXMLTreeAttribute(mime,"type");
960     if (attribute != (const char *) NULL)
961       mime_info->type=ConstantString(attribute);
962     status=AppendValueToLinkedList(cache,mime_info);
963     if (status == MagickFalse)
964       (void) ThrowMagickException(exception,GetMagickModule(),
965         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
966     mime=GetNextXMLTreeTag(mime);
967   }
968   mime_map=DestroyXMLTree(mime_map);
969   return(status != 0 ? MagickTrue : MagickFalse);
970 }
971 \f
972 /*
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 %                                                                             %
975 %                                                                             %
976 %                                                                             %
977 +  M a g i c k T o M i m e                                                    %
978 %                                                                             %
979 %                                                                             %
980 %                                                                             %
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 %
983 %  MagickToMime() returns the officially registered (or de facto) MIME
984 %  media-type corresponding to a magick string.  If there is no registered
985 %  media-type, then the string "image/x-magick" (all lower case) is returned.
986 %  The returned string must be deallocated by the user.
987 %
988 %  The format of the MagickToMime method is:
989 %
990 %      char *MagickToMime(const char *magick)
991 %
992 %  A description of each parameter follows.
993 %
994 %   o  magick:  ImageMagick format specification "magick" tag.
995 %
996 */
997 MagickExport char *MagickToMime(const char *magick)
998 {
999   char
1000     filename[MagickPathExtent],
1001     media[MagickPathExtent];
1002
1003   const MimeInfo
1004     *mime_info;
1005
1006   ExceptionInfo
1007     *exception;
1008
1009   (void) FormatLocaleString(filename,MagickPathExtent,"file.%s",magick);
1010   LocaleLower(filename);
1011   exception=AcquireExceptionInfo();
1012   mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1013   exception=DestroyExceptionInfo(exception);
1014   if (mime_info != (const MimeInfo *) NULL)
1015     return(ConstantString(GetMimeType(mime_info)));
1016   (void) FormatLocaleString(media,MagickPathExtent,"image/x-%s",magick);
1017   LocaleLower(media+8);
1018   return(ConstantString(media));
1019 }
1020 \f
1021 /*
1022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023 %                                                                             %
1024 %                                                                             %
1025 %                                                                             %
1026 +   M i m e C o m p o n e n t G e n e s i s                                   %
1027 %                                                                             %
1028 %                                                                             %
1029 %                                                                             %
1030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1031 %
1032 %  MimeComponentGenesis() instantiates the mime component.
1033 %
1034 %  The format of the MimeComponentGenesis method is:
1035 %
1036 %      MagickBooleanType MimeComponentGenesis(void)
1037 %
1038 */
1039 MagickPrivate MagickBooleanType MimeComponentGenesis(void)
1040 {
1041   if (mime_semaphore == (SemaphoreInfo *) NULL)
1042     mime_semaphore=AcquireSemaphoreInfo();
1043   return(MagickTrue);
1044 }
1045 \f
1046 /*
1047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1048 %                                                                             %
1049 %                                                                             %
1050 %                                                                             %
1051 +   M i m e C o m p o n e n t T e r m i n u s                                 %
1052 %                                                                             %
1053 %                                                                             %
1054 %                                                                             %
1055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1056 %
1057 %  MimeComponentTerminus() destroys the mime component.
1058 %
1059 %  The format of the MimeComponentTerminus method is:
1060 %
1061 %      MimeComponentTerminus(void)
1062 %
1063 */
1064
1065 static void *DestroyMimeElement(void *mime_info)
1066 {
1067   register MimeInfo
1068     *p;
1069
1070   p=(MimeInfo *) mime_info;
1071   if (p->magic != (unsigned char *) NULL)
1072     p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1073   if (p->pattern != (char *) NULL)
1074     p->pattern=DestroyString(p->pattern);
1075   if (p->description != (char *) NULL)
1076     p->description=DestroyString(p->description);
1077   if (p->type != (char *) NULL)
1078     p->type=DestroyString(p->type);
1079   if (p->path != (char *) NULL)
1080     p->path=DestroyString(p->path);
1081   p=(MimeInfo *) RelinquishMagickMemory(p);
1082   return((void *) NULL);
1083 }
1084
1085 MagickPrivate void MimeComponentTerminus(void)
1086 {
1087   if (mime_semaphore == (SemaphoreInfo *) NULL)
1088     ActivateSemaphoreInfo(&mime_semaphore);
1089   LockSemaphoreInfo(mime_semaphore);
1090   if (mime_cache != (LinkedListInfo *) NULL)
1091     mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1092   UnlockSemaphoreInfo(mime_semaphore);
1093   RelinquishSemaphoreInfo(&mime_semaphore);
1094 }