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