2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 % M M IIIII M M EEEEE %
9 % M M IIIII M M EEEEE %
12 % MagickCore Mime Methods %
18 % Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
19 % dedicated to making software imaging solutions freely available. %
21 % You may not use this file except in compliance with the License. You may %
22 % obtain a copy of the License at %
24 % http://www.imagemagick.org/MagicksToolkit/script/license.php %
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. %
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/hashmap.h"
48 #include "MagickCore/memory_.h"
49 #include "MagickCore/mime.h"
50 #include "MagickCore/mime-private.h"
51 #include "MagickCore/option.h"
52 #include "MagickCore/semaphore.h"
53 #include "MagickCore/string_.h"
54 #include "MagickCore/token.h"
55 #include "MagickCore/utility.h"
56 #include "MagickCore/utility-private.h"
57 #include "MagickCore/xml-tree.h"
58 #include "MagickCore/xml-tree-private.h"
63 #define MimeFilename "mime.xml"
113 "<?xml version=\"1.0\"?>"
117 static LinkedListInfo
118 *mime_cache = (LinkedListInfo *) NULL;
121 *mime_semaphore = (SemaphoreInfo *) NULL;
124 Forward declarations.
126 static MagickBooleanType
127 IsMimeCacheInstantiated(ExceptionInfo *),
128 LoadMimeCache(LinkedListInfo *,const char *,const char *,const size_t,
132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 % A c q u i r e M i m e C a c h e %
140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 % AcquireMimeCache() caches one or more magic configurations which provides
143 % a mapping between magic attributes and a magic name.
145 % The format of the AcquireMimeCache method is:
147 % LinkedListInfo *AcquireMimeCache(const char *filename,
148 % ExceptionInfo *exception)
150 % A description of each parameter follows:
152 % o filename: the font file name.
154 % o exception: return any errors or warnings in this structure.
157 MagickExport LinkedListInfo *AcquireMimeCache(const char *filename,
158 ExceptionInfo *exception)
166 mime_cache=NewLinkedList(0);
167 if (mime_cache == (LinkedListInfo *) NULL)
168 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
170 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
178 options=GetConfigureOptions(filename,exception);
179 option=(const StringInfo *) GetNextValueInLinkedList(options);
180 while (option != (const StringInfo *) NULL)
182 status&=LoadMimeCache(mime_cache,(const char *)
183 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
184 option=(const StringInfo *) GetNextValueInLinkedList(options);
186 options=DestroyConfigureOptions(options);
189 if (IsLinkedListEmpty(mime_cache) != MagickFalse)
190 status&=LoadMimeCache(mime_cache,MimeMap,"built-in",0,exception);
195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 + G e t M i m e I n f o %
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 % GetMimeInfo() attempts to classify the content to identify which mime type
206 % is associated with the content, if any.
208 % The format of the GetMimeInfo method is:
210 % const MimeInfo *GetMimeInfo(const char *filename,
211 % const unsigned char *magic,const size_t length,
212 % ExceptionInfo *exception)
214 % A description of each parameter follows:
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).
219 % o magic: A binary string generally representing the first few characters
220 % of the image file or blob.
222 % o length: the length of the binary signature.
224 % o exception: return any errors or warnings in this structure.
227 MagickExport const MimeInfo *GetMimeInfo(const char *filename,
228 const unsigned char *magic,const size_t length,ExceptionInfo *exception)
236 register const MimeInfo
239 register const unsigned char
251 assert(exception != (ExceptionInfo *) NULL);
252 if (IsMimeCacheInstantiated(exception) == MagickFalse)
253 return((const MimeInfo *) NULL);
257 mime_info=(const MimeInfo *) NULL;
259 LockSemaphoreInfo(mime_semaphore);
260 ResetLinkedListIterator(mime_cache);
261 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
262 if ((magic == (const unsigned char *) NULL) || (length == 0))
264 UnlockSemaphoreInfo(mime_semaphore);
267 while (p != (const MimeInfo *) NULL)
269 assert(p->offset >= 0);
270 if (mime_info != (const MimeInfo *) NULL)
271 if (p->priority > mime_info->priority)
273 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
276 if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
278 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
280 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
283 switch (p->data_type)
287 if ((size_t) (p->offset+4) > length)
290 value=(ssize_t) (*q++);
293 if (p->value == value)
298 if ((p->value & p->mask) == value)
305 if ((size_t) (p->offset+4) > length)
309 if (p->endian == UndefinedEndian)
310 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
311 if (endian == LSBEndian)
313 value=(ssize_t) (*q++);
318 value=(ssize_t) (*q++) << 8;
323 if (p->value == value)
328 if ((p->value & p->mask) == value)
335 if ((size_t) (p->offset+4) > length)
339 if (p->endian == UndefinedEndian)
340 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
341 if (endian == LSBEndian)
343 value=(ssize_t) (*q++);
344 value|=((ssize_t) *q++) << 8;
345 value|=((ssize_t) *q++) << 16;
346 value|=((ssize_t) *q++) << 24;
350 value=(ssize_t) (*q++) << 24;
351 value|=((ssize_t) *q++) << 16;
352 value|=((ssize_t) *q++) << 8;
353 value|=((ssize_t) *q++);
357 if (p->value == value)
362 if ((p->value & p->mask) == value)
370 for (i=0; i <= (ssize_t) p->extent; i++)
372 if ((size_t) (p->offset+i+p->length) > length)
374 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
383 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
385 if (mime_info != (const MimeInfo *) NULL)
386 (void) InsertValueInLinkedList(mime_cache,0,
387 RemoveElementByValueFromLinkedList(mime_cache,p));
388 UnlockSemaphoreInfo(mime_semaphore);
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 % G e t M i m e I n f o L i s t %
401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 % GetMimeInfoList() returns any image aliases that match the specified
406 % The magic of the GetMimeInfoList function is:
408 % const MimeInfo **GetMimeInfoList(const char *pattern,
409 % size_t *number_aliases,ExceptionInfo *exception)
411 % A description of each parameter follows:
413 % o pattern: Specifies a pointer to a text string containing a pattern.
415 % o number_aliases: This integer returns the number of magics in the
418 % o exception: return any errors or warnings in this structure.
422 #if defined(__cplusplus) || defined(c_plusplus)
426 static int MimeInfoCompare(const void *x,const void *y)
432 p=(const MimeInfo **) x,
433 q=(const MimeInfo **) y;
434 if (strcasecmp((*p)->path,(*q)->path) == 0)
435 return(strcasecmp((*p)->type,(*q)->type));
436 return(strcasecmp((*p)->path,(*q)->path));
439 #if defined(__cplusplus) || defined(c_plusplus)
443 MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
444 size_t *number_aliases,ExceptionInfo *exception)
449 register const MimeInfo
458 assert(pattern != (char *) NULL);
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
460 assert(number_aliases != (size_t *) NULL);
462 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
463 if (p == (const MimeInfo *) NULL)
464 return((const MimeInfo **) NULL);
465 aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
466 GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
467 if (aliases == (const MimeInfo **) NULL)
468 return((const MimeInfo **) NULL);
472 LockSemaphoreInfo(mime_semaphore);
473 ResetLinkedListIterator(mime_cache);
474 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
475 for (i=0; p != (const MimeInfo *) NULL; )
477 if ((p->stealth == MagickFalse) &&
478 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
480 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
482 UnlockSemaphoreInfo(mime_semaphore);
483 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
484 aliases[i]=(MimeInfo *) NULL;
485 *number_aliases=(size_t) i;
490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494 % G e t M i m e L i s t %
498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 % GetMimeList() returns any image format alias that matches the specified
503 % The format of the GetMimeList function is:
505 % char **GetMimeList(const char *pattern,size_t *number_aliases,
506 % ExceptionInfo *exception)
508 % A description of each parameter follows:
510 % o pattern: Specifies a pointer to a text string containing a pattern.
512 % o number_aliases: This integer returns the number of image format aliases
515 % o exception: return any errors or warnings in this structure.
519 #if defined(__cplusplus) || defined(c_plusplus)
523 static int MimeCompare(const void *x,const void *y)
531 return(strcasecmp(p,q));
534 #if defined(__cplusplus) || defined(c_plusplus)
538 MagickExport char **GetMimeList(const char *pattern,
539 size_t *number_aliases,ExceptionInfo *exception)
544 register const MimeInfo
551 Allocate configure list.
553 assert(pattern != (char *) NULL);
554 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
555 assert(number_aliases != (size_t *) NULL);
557 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
558 if (p == (const MimeInfo *) NULL)
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 ResetLinkedListIterator(mime_cache);
566 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
567 for (i=0; p != (const MimeInfo *) NULL; )
569 if ((p->stealth == MagickFalse) &&
570 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
571 aliases[i++]=ConstantString(p->type);
572 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
574 UnlockSemaphoreInfo(mime_semaphore);
575 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
576 aliases[i]=(char *) NULL;
577 *number_aliases=(size_t) i;
582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586 % G e t M i m e D e s c r i p t i o n %
590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 % GetMimeDescription() returns the mime type description.
594 % The format of the GetMimeDescription method is:
596 % const char *GetMimeDescription(const MimeInfo *mime_info)
598 % A description of each parameter follows:
600 % o mime_info: The magic info.
603 MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
605 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
606 assert(mime_info != (MimeInfo *) NULL);
607 assert(mime_info->signature == MagickSignature);
608 return(mime_info->description);
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616 % G e t M i m e T y p e %
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 % GetMimeType() returns the mime type.
624 % The format of the GetMimeType method is:
626 % const char *GetMimeType(const MimeInfo *mime_info)
628 % A description of each parameter follows:
630 % o mime_info: The magic info.
633 MagickExport const char *GetMimeType(const MimeInfo *mime_info)
635 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
636 assert(mime_info != (MimeInfo *) NULL);
637 assert(mime_info->signature == MagickSignature);
638 return(mime_info->type);
642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646 + I s M i m e C a c h e I n s t a n t i a t e d %
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652 % IsMimeCacheInstantiated() determines if the mime list is instantiated. If
653 % not, it instantiates the list and returns it.
655 % The format of the IsMimeInstantiated method is:
657 % MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
659 % A description of each parameter follows.
661 % o exception: return any errors or warnings in this structure.
664 static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
666 if (mime_cache == (LinkedListInfo *) NULL)
668 if (mime_semaphore == (SemaphoreInfo *) NULL)
669 ActivateSemaphoreInfo(&mime_semaphore);
670 LockSemaphoreInfo(mime_semaphore);
671 if (mime_cache == (LinkedListInfo *) NULL)
672 mime_cache=AcquireMimeCache(MimeFilename,exception);
673 UnlockSemaphoreInfo(mime_semaphore);
675 return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 % L i s t M i m e I n f o %
687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 % ListMimeInfo() lists the magic info to a file.
691 % The format of the ListMimeInfo method is:
693 % MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
695 % A description of each parameter follows.
697 % o file: An pointer to a FILE.
699 % o exception: return any errors or warnings in this structure.
702 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
719 if (file == (const FILE *) NULL)
721 mime_info=GetMimeInfoList("*",&number_aliases,exception);
722 if (mime_info == (const MimeInfo **) NULL)
725 path=(const char *) NULL;
726 for (i=0; i < (ssize_t) number_aliases; i++)
728 if (mime_info[i]->stealth != MagickFalse)
730 if ((path == (const char *) NULL) ||
731 (strcasecmp(path,mime_info[i]->path) != 0))
733 if (mime_info[i]->path != (char *) NULL)
734 (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
735 (void) FormatLocaleFile(file,"Type Description\n");
736 (void) FormatLocaleFile(file,
737 "-------------------------------------------------"
738 "------------------------------\n");
740 path=mime_info[i]->path;
741 (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
742 if (strlen(mime_info[i]->type) <= 25)
744 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
745 (void) FormatLocaleFile(file," ");
749 (void) FormatLocaleFile(file,"\n");
750 for (j=0; j <= 27; j++)
751 (void) FormatLocaleFile(file," ");
753 if (mime_info[i]->description != (char *) NULL)
754 (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
755 (void) FormatLocaleFile(file,"\n");
758 mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767 + L o a d M i m e C a c h e %
771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773 % LoadMimeCache() loads the mime configurations which provides a mapping
774 % between mime attributes and a mime name.
776 % The format of the LoadMimeCache method is:
778 % MagickBooleanType LoadMimeCache(LinkedListInfo *mime_cache,
779 % const char *xml,const char *filename,const size_t depth,
780 % ExceptionInfo *exception)
782 % A description of each parameter follows:
784 % o xml: The mime list in XML format.
786 % o filename: The mime list filename.
788 % o depth: depth of <include /> statements.
790 % o exception: return any errors or warnings in this structure.
793 static MagickBooleanType LoadMimeCache(LinkedListInfo *mime_cache,
794 const char *xml,const char *filename,const size_t depth,
795 ExceptionInfo *exception)
801 *mime_info = (MimeInfo *) NULL;
812 Load the mime map file.
814 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
815 "Loading mime map \"%s\" ...",filename);
816 if (xml == (const char *) NULL)
818 mime_map=NewXMLTree(xml,exception);
819 if (mime_map == (XMLTreeInfo *) NULL)
822 include=GetXMLTreeChild(mime_map,"include");
823 while (include != (XMLTreeInfo *) NULL)
826 Process include element.
828 attribute=GetXMLTreeAttribute(include,"file");
829 if (attribute != (const char *) NULL)
832 (void) ThrowMagickException(exception,GetMagickModule(),
833 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
840 GetPathComponent(filename,HeadPath,path);
842 (void) ConcatenateMagickString(path,DirectorySeparator,
844 if (*attribute == *DirectorySeparator)
845 (void) CopyMagickString(path,attribute,MaxTextExtent);
847 (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
848 xml=FileToXML(path,~0UL);
849 if (xml != (char *) NULL)
851 status&=LoadMimeCache(mime_cache,xml,path,depth+1,exception);
852 xml=DestroyString(xml);
856 include=GetNextXMLTreeTag(include);
858 mime=GetXMLTreeChild(mime_map,"mime");
859 while (mime != (XMLTreeInfo *) NULL)
865 Process mime element.
867 mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
868 if (mime_info == (MimeInfo *) NULL)
869 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
870 (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
871 mime_info->path=ConstantString(filename);
872 mime_info->signature=MagickSignature;
873 attribute=GetXMLTreeAttribute(mime,"data-type");
874 if (attribute != (const char *) NULL)
875 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
876 MagickTrue,attribute);
877 attribute=GetXMLTreeAttribute(mime,"description");
878 if (attribute != (const char *) NULL)
879 mime_info->description=ConstantString(attribute);
880 attribute=GetXMLTreeAttribute(mime,"endian");
881 if (attribute != (const char *) NULL)
882 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
883 MagickTrue,attribute);
884 attribute=GetXMLTreeAttribute(mime,"magic");
885 if (attribute != (const char *) NULL)
893 register unsigned char
896 token=AcquireString(attribute);
897 (void) SubstituteString((char **) &token,"<","<");
898 (void) SubstituteString((char **) &token,"&","&");
899 (void) SubstituteString((char **) &token,""","\"");
900 mime_info->magic=(unsigned char *) AcquireString(token);
902 for (p=token; *p != '\0'; )
907 if (isdigit((int) ((unsigned char) *p)) != 0)
912 *q++=(unsigned char) strtol(p,&end,8);
919 case 'b': *q='\b'; break;
920 case 'f': *q='\f'; break;
921 case 'n': *q='\n'; break;
922 case 'r': *q='\r'; break;
923 case 't': *q='\t'; break;
924 case 'v': *q='\v'; break;
925 case 'a': *q='a'; break;
926 case '?': *q='\?'; break;
927 default: *q=(unsigned char) (*p); break;
934 *q++=(unsigned char) (*p++);
937 token=DestroyString(token);
938 if (mime_info->data_type != StringData)
939 mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
942 attribute=GetXMLTreeAttribute(mime,"mask");
943 if (attribute != (const char *) NULL)
944 mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
945 attribute=GetXMLTreeAttribute(mime,"offset");
946 if (attribute != (const char *) NULL)
951 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
953 mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
955 attribute=GetXMLTreeAttribute(mime,"pattern");
956 if (attribute != (const char *) NULL)
957 mime_info->pattern=ConstantString(attribute);
958 attribute=GetXMLTreeAttribute(mime,"priority");
959 if (attribute != (const char *) NULL)
960 mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
961 attribute=GetXMLTreeAttribute(mime,"stealth");
962 if (attribute != (const char *) NULL)
963 mime_info->stealth=IsStringTrue(attribute);
964 attribute=GetXMLTreeAttribute(mime,"type");
965 if (attribute != (const char *) NULL)
966 mime_info->type=ConstantString(attribute);
967 status=AppendValueToLinkedList(mime_cache,mime_info);
968 if (status == MagickFalse)
969 (void) ThrowMagickException(exception,GetMagickModule(),
970 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
971 mime=GetNextXMLTreeTag(mime);
973 mime_map=DestroyXMLTree(mime_map);
974 return(status != 0 ? MagickTrue : MagickFalse);
978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 + M a g i c k T o M i m e %
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % MagickToMime() returns the officially registered (or de facto) MIME
989 % media-type corresponding to a magick string. If there is no registered
990 % media-type, then the string "image/x-magick" (all lower case) is returned.
991 % The returned string must be deallocated by the user.
993 % The format of the MagickToMime method is:
995 % char *MagickToMime(const char *magick)
997 % A description of each parameter follows.
999 % o magick: ImageMagick format specification "magick" tag.
1002 MagickExport char *MagickToMime(const char *magick)
1005 filename[MaxTextExtent],
1006 media[MaxTextExtent];
1014 (void) FormatLocaleString(filename,MaxTextExtent,"file.%s",magick);
1015 LocaleLower(filename);
1016 exception=AcquireExceptionInfo();
1017 mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1018 exception=DestroyExceptionInfo(exception);
1019 if (mime_info != (const MimeInfo *) NULL)
1020 return(ConstantString(GetMimeType(mime_info)));
1021 (void) FormatLocaleString(media,MaxTextExtent,"image/x-%s",magick);
1022 LocaleLower(media+8);
1023 return(ConstantString(media));
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1031 + M i m e C o m p o n e n t G e n e s i s %
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 % MimeComponentGenesis() instantiates the mime component.
1039 % The format of the MimeComponentGenesis method is:
1041 % MagickBooleanType MimeComponentGenesis(void)
1044 MagickPrivate MagickBooleanType MimeComponentGenesis(void)
1046 if (mime_semaphore == (SemaphoreInfo *) NULL)
1047 mime_semaphore=AcquireSemaphoreInfo();
1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1056 + M i m e C o m p o n e n t T e r m i n u s %
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1062 % MimeComponentTerminus() destroys the mime component.
1064 % The format of the MimeComponentTerminus method is:
1066 % MimeComponentTerminus(void)
1070 static void *DestroyMimeElement(void *mime_info)
1075 p=(MimeInfo *) mime_info;
1076 if (p->magic != (unsigned char *) NULL)
1077 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1078 if (p->pattern != (char *) NULL)
1079 p->pattern=DestroyString(p->pattern);
1080 if (p->description != (char *) NULL)
1081 p->description=DestroyString(p->description);
1082 if (p->type != (char *) NULL)
1083 p->type=DestroyString(p->type);
1084 if (p->path != (char *) NULL)
1085 p->path=DestroyString(p->path);
1086 p=(MimeInfo *) RelinquishMagickMemory(p);
1087 return((void *) NULL);
1090 MagickPrivate void MimeComponentTerminus(void)
1092 if (mime_semaphore == (SemaphoreInfo *) NULL)
1093 ActivateSemaphoreInfo(&mime_semaphore);
1094 LockSemaphoreInfo(mime_semaphore);
1095 if (mime_cache != (LinkedListInfo *) NULL)
1096 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1097 UnlockSemaphoreInfo(mime_semaphore);
1098 RelinquishSemaphoreInfo(&mime_semaphore);