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