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