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