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