40 #include "magick/studio.h"
41 #include "magick/blob.h"
42 #include "magick/client.h"
43 #include "magick/configure.h"
44 #include "magick/deprecate.h"
45 #include "magick/exception.h"
46 #include "magick/exception-private.h"
47 #include "magick/hashmap.h"
48 #include "magick/memory_.h"
49 #include "magick/mime.h"
50 #include "magick/mime-private.h"
51 #include "magick/nt-base-private.h"
52 #include "magick/option.h"
53 #include "magick/semaphore.h"
54 #include "magick/string_.h"
55 #include "magick/token.h"
56 #include "magick/utility.h"
57 #include "magick/xml-tree.h"
58 #include "magick/xml-tree-private.h"
63 #define MimeFilename "mime.xml"
113 "<?xml version=\"1.0\"?>"
126 static MagickBooleanType
128 LoadMimeCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
166 cache=NewLinkedList(0);
168 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
170 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
178 options=GetConfigureOptions(filename,exception);
179 option=(
const StringInfo *) GetNextValueInLinkedList(options);
182 status&=LoadMimeCache(cache,(
const char *)
183 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
184 option=(
const StringInfo *) GetNextValueInLinkedList(options);
186 options=DestroyConfigureOptions(options);
189 if (IsLinkedListEmpty(cache) != MagickFalse)
190 status&=LoadMimeCache(cache,MimeMap,
"built-in",0,exception);
194 MagickExport MagickBooleanType LoadMimeLists(
const char *name,
197 mime_cache=AcquireMimeCache(name,exception);
198 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
234 MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
235 const unsigned char *magic,
const size_t length,
ExceptionInfo *exception)
259 if (IsMimeCacheInstantiated(exception) == MagickFalse)
266 LockSemaphoreInfo(mime_semaphore);
267 ResetLinkedListIterator(mime_cache);
268 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
269 if ((magic == (
const unsigned char *) NULL) || (length == 0))
271 UnlockSemaphoreInfo(mime_semaphore);
274 while (p != (
const MimeInfo *) NULL)
276 assert(p->offset >= 0);
277 if (mime_info != (
const MimeInfo *) NULL)
278 if (p->priority > mime_info->priority)
280 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
283 if ((p->pattern != (
char *) NULL) && (filename != (
char *) NULL))
285 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
287 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
290 switch (p->data_type)
294 if ((
size_t) (p->offset+4) > length)
297 value=(ssize_t) (*q++);
300 if (p->value == value)
305 if ((p->value & p->mask) == value)
312 if ((
size_t) (p->offset+4) > length)
316 if (p->endian == UndefinedEndian)
317 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
318 if (endian == LSBEndian)
320 value=(ssize_t) (*q++);
325 value=(ssize_t) (*q++) << 8;
330 if (p->value == value)
335 if ((p->value & p->mask) == value)
342 if ((
size_t) (p->offset+4) > length)
346 if (p->endian == UndefinedEndian)
347 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
348 if (endian == LSBEndian)
350 value=(ssize_t) (*q++);
351 value|=((ssize_t) *q++) << 8;
352 value|=((ssize_t) *q++) << 16;
353 value|=((ssize_t) *q++) << 24;
357 value=(ssize_t) (*q++) << 24;
358 value|=((ssize_t) *q++) << 16;
359 value|=((ssize_t) *q++) << 8;
360 value|=((ssize_t) *q++);
364 if (p->value == value)
369 if ((p->value & p->mask) == value)
377 for (i=0; i <= (ssize_t) p->extent; i++)
379 if ((
size_t) (p->offset+i+p->length) > length)
381 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
390 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
392 if (mime_info != (
const MimeInfo *) NULL)
393 (
void) InsertValueInLinkedList(mime_cache,0,
394 RemoveElementByValueFromLinkedList(mime_cache,p));
395 UnlockSemaphoreInfo(mime_semaphore);
429 #if defined(__cplusplus) || defined(c_plusplus)
433 static int MimeInfoCompare(
const void *x,
const void *y)
441 if (strcasecmp((*p)->path,(*q)->path) == 0)
442 return(strcasecmp((*p)->type,(*q)->type));
443 return(strcasecmp((*p)->path,(*q)->path));
446 #if defined(__cplusplus) || defined(c_plusplus)
450 MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
465 assert(pattern != (
char *) NULL);
466 assert(number_aliases != (
size_t *) NULL);
467 if (IsEventLogging() != MagickFalse)
468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
470 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
473 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
474 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
475 if (aliases == (
const MimeInfo **) NULL)
480 LockSemaphoreInfo(mime_semaphore);
481 ResetLinkedListIterator(mime_cache);
482 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
483 for (i=0; p != (
const MimeInfo *) NULL; )
485 if ((p->stealth == MagickFalse) &&
486 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
488 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
490 UnlockSemaphoreInfo(mime_semaphore);
491 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeInfoCompare);
493 *number_aliases=(size_t) i;
527 #if defined(__cplusplus) || defined(c_plusplus)
531 static int MimeCompare(
const void *x,
const void *y)
539 return(strcasecmp(p,q));
542 #if defined(__cplusplus) || defined(c_plusplus)
546 MagickExport
char **GetMimeList(
const char *pattern,
561 assert(pattern != (
char *) NULL);
562 assert(number_aliases != (
size_t *) NULL);
563 if (IsEventLogging() != MagickFalse)
564 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
566 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
568 return((
char **) NULL);
569 aliases=(
char **) AcquireQuantumMemory((
size_t)
570 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
571 if (aliases == (
char **) NULL)
572 return((
char **) NULL);
573 LockSemaphoreInfo(mime_semaphore);
574 ResetLinkedListIterator(mime_cache);
575 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
576 for (i=0; p != (
const MimeInfo *) NULL; )
578 if ((p->stealth == MagickFalse) &&
579 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
580 aliases[i++]=ConstantString(p->type);
581 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
583 UnlockSemaphoreInfo(mime_semaphore);
584 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
585 aliases[i]=(
char *) NULL;
586 *number_aliases=(size_t) i;
612 MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
614 assert(mime_info != (
MimeInfo *) NULL);
615 assert(mime_info->signature == MagickCoreSignature);
616 if (IsEventLogging() != MagickFalse)
617 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
618 return(mime_info->description);
643 MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
645 assert(mime_info != (
MimeInfo *) NULL);
646 assert(mime_info->signature == MagickCoreSignature);
647 if (IsEventLogging() != MagickFalse)
648 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
649 return(mime_info->type);
675 static MagickBooleanType IsMimeCacheInstantiated(
ExceptionInfo *exception)
680 ActivateSemaphoreInfo(&mime_semaphore);
681 LockSemaphoreInfo(mime_semaphore);
683 mime_cache=AcquireMimeCache(MimeFilename,exception);
684 UnlockSemaphoreInfo(mime_semaphore);
686 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
713 MagickExport MagickBooleanType ListMimeInfo(FILE *file,
ExceptionInfo *exception)
730 if (file == (
const FILE *) NULL)
732 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
733 if (mime_info == (
const MimeInfo **) NULL)
736 path=(
const char *) NULL;
737 for (i=0; i < (ssize_t) number_aliases; i++)
739 if (mime_info[i]->stealth != MagickFalse)
741 if ((path == (
const char *) NULL) ||
742 (strcasecmp(path,mime_info[i]->path) != 0))
744 if (mime_info[i]->path != (
char *) NULL)
745 (
void) FormatLocaleFile(file,
"\nPath: %s\n\n",mime_info[i]->path);
746 (void) FormatLocaleFile(file,
"Type Description\n");
747 (void) FormatLocaleFile(file,
748 "-------------------------------------------------"
749 "------------------------------\n");
751 path=mime_info[i]->path;
752 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
753 if (strlen(mime_info[i]->type) <= 25)
755 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
756 (
void) FormatLocaleFile(file,
" ");
760 (void) FormatLocaleFile(file,
"\n");
761 for (j=0; j <= 27; j++)
762 (
void) FormatLocaleFile(file,
" ");
764 if (mime_info[i]->description != (
char *) NULL)
765 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
766 (void) FormatLocaleFile(file,
"\n");
769 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
803 static MagickBooleanType LoadMimeCache(
LinkedListInfo *cache,
const char *xml,
804 const char *filename,
const size_t depth,
ExceptionInfo *exception)
823 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
824 "Loading mime map \"%s\" ...",filename);
825 if (xml == (
const char *) NULL)
827 mime_map=NewXMLTree(xml,exception);
831 include=GetXMLTreeChild(mime_map,
"include");
837 attribute=GetXMLTreeAttribute(include,
"file");
838 if (attribute != (
const char *) NULL)
840 if (depth > MagickMaxRecursionDepth)
841 (void) ThrowMagickException(exception,GetMagickModule(),
842 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",filename);
849 GetPathComponent(filename,HeadPath,path);
851 (void) ConcatenateMagickString(path,DirectorySeparator,
853 if (*attribute == *DirectorySeparator)
854 (void) CopyMagickString(path,attribute,MaxTextExtent);
856 (
void) ConcatenateMagickString(path,attribute,MaxTextExtent);
857 xml=FileToXML(path,~0UL);
858 if (xml != (
char *) NULL)
860 status&=LoadMimeCache(cache,xml,path,depth+1,exception);
861 xml=DestroyString(xml);
865 include=GetNextXMLTreeTag(include);
867 mime=GetXMLTreeChild(mime_map,
"mime");
876 mime_info=(
MimeInfo *) AcquireMagickMemory(
sizeof(*mime_info));
878 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
879 (void) memset(mime_info,0,
sizeof(*mime_info));
880 mime_info->path=ConstantString(filename);
881 mime_info->signature=MagickCoreSignature;
882 attribute=GetXMLTreeAttribute(mime,
"data-type");
883 if (attribute != (
const char *) NULL)
884 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
885 MagickTrue,attribute);
886 attribute=GetXMLTreeAttribute(mime,
"description");
887 if (attribute != (
const char *) NULL)
888 mime_info->description=ConstantString(attribute);
889 attribute=GetXMLTreeAttribute(mime,
"endian");
890 if (attribute != (
const char *) NULL)
891 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
892 MagickTrue,attribute);
893 attribute=GetXMLTreeAttribute(mime,
"magic");
894 if (attribute != (
const char *) NULL)
905 token=AcquireString(attribute);
906 (void) SubstituteString((
char **) &token,
"<",
"<");
907 (void) SubstituteString((
char **) &token,
"&",
"&");
908 (void) SubstituteString((
char **) &token,
""",
"\"");
909 mime_info->magic=(
unsigned char *) AcquireString(token);
911 for (p=token; *p !=
'\0'; )
916 if (isdigit((
int) ((
unsigned char) *p)) != 0)
921 *q++=(
unsigned char) strtol(p,&end,8);
928 case 'b': *q=
'\b';
break;
929 case 'f': *q=
'\f';
break;
930 case 'n': *q=
'\n';
break;
931 case 'r': *q=
'\r';
break;
932 case 't': *q=
'\t';
break;
933 case 'v': *q=
'\v';
break;
934 case 'a': *q=
'a';
break;
935 case '?': *q=
'\?';
break;
936 default: *q=(
unsigned char) (*p);
break;
943 *q++=(
unsigned char) (*p++);
946 token=DestroyString(token);
947 if (mime_info->data_type != StringData)
948 mime_info->value=(ssize_t) strtoul((
char *) mime_info->magic,
951 attribute=GetXMLTreeAttribute(mime,
"mask");
952 if (attribute != (
const char *) NULL)
953 mime_info->mask=(ssize_t) strtoul(attribute,(
char **) NULL,0);
954 attribute=GetXMLTreeAttribute(mime,
"offset");
955 if (attribute != (
const char *) NULL)
960 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
962 mime_info->extent=(size_t) strtol(c+1,(
char **) NULL,0);
964 attribute=GetXMLTreeAttribute(mime,
"pattern");
965 if (attribute != (
const char *) NULL)
966 mime_info->pattern=ConstantString(attribute);
967 attribute=GetXMLTreeAttribute(mime,
"priority");
968 if (attribute != (
const char *) NULL)
969 mime_info->priority=(ssize_t) strtol(attribute,(
char **) NULL,0);
970 attribute=GetXMLTreeAttribute(mime,
"stealth");
971 if (attribute != (
const char *) NULL)
972 mime_info->stealth=IsMagickTrue(attribute);
973 attribute=GetXMLTreeAttribute(mime,
"type");
974 if (attribute != (
const char *) NULL)
975 mime_info->type=ConstantString(attribute);
976 status=AppendValueToLinkedList(cache,mime_info);
977 if (status == MagickFalse)
978 (void) ThrowMagickException(exception,GetMagickModule(),
979 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
980 mime=GetNextXMLTreeTag(mime);
982 mime_map=DestroyXMLTree(mime_map);
983 return(status != 0 ? MagickTrue : MagickFalse);
1011 MagickExport
char *MagickToMime(
const char *magick)
1014 filename[MaxTextExtent],
1015 media[MaxTextExtent];
1023 (void) FormatLocaleString(filename,MaxTextExtent,
"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,MaxTextExtent,
"image/x-%s",magick);
1031 LocaleLower(media+8);
1032 return(ConstantString(media));
1053 MagickExport MagickBooleanType MimeComponentGenesis(
void)
1056 mime_semaphore=AllocateSemaphoreInfo();
1079 static void *DestroyMimeElement(
void *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);
1099 MagickExport
void MimeComponentTerminus(
void)
1102 ActivateSemaphoreInfo(&mime_semaphore);
1103 LockSemaphoreInfo(mime_semaphore);
1105 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1106 UnlockSemaphoreInfo(mime_semaphore);
1107 DestroySemaphoreInfo(&mime_semaphore);