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