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