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