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