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"
64#define MimeFilename "mime.xml"
66#if defined(MAGICKCORE_WINDOWS_SUPPORT)
67# if !defined(strcasecmp)
68# define strcasecmp _stricmp
127static MagickBooleanType
130#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
131static MagickBooleanType
132 LoadMimeCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
162MagickExport
LinkedListInfo *AcquireMimeCache(
const char *filename,
168 cache=NewLinkedList(0);
169#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
177 options=GetConfigureOptions(filename,exception);
178 option=(
const StringInfo *) GetNextValueInLinkedList(options);
181 (void) LoadMimeCache(cache,(
const char *)
182 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
183 option=(
const StringInfo *) GetNextValueInLinkedList(options);
185 options=DestroyConfigureOptions(options);
188 magick_unreferenced(filename);
189 magick_unreferenced(exception);
227MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
228 const unsigned char *magic,
const size_t length,
ExceptionInfo *exception)
250 if (IsMimeCacheInstantiated(exception) == MagickFalse)
256 LockSemaphoreInfo(mime_semaphore);
257 p=GetHeadElementInLinkedList(mime_cache);
258 if ((magic == (
const unsigned char *) NULL) || (length == 0))
260 UnlockSemaphoreInfo(mime_semaphore);
262 return((
const MimeInfo *) p->value);
272 assert(q->offset >= 0);
274 if (q->priority > ((
const MimeInfo *) element_info->value)->priority)
279 if ((q->pattern != (
char *) NULL) && (filename != (
char *) NULL))
281 if (GlobExpression(filename,q->pattern,MagickFalse) != MagickFalse)
286 switch (q->data_type)
290 if ((
size_t) (q->offset+4) > length)
293 value=(ssize_t) (*r++);
296 if (q->value == value)
301 if ((q->value & q->mask) == value)
308 if ((
size_t) (q->offset+4) > length)
312 if (q->endian == UndefinedEndian)
313 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
314 if (endian == LSBEndian)
316 value=(ssize_t) (*r++);
321 value=(ssize_t) (*r++) << 8;
326 if (q->value == value)
331 if ((q->value & q->mask) == value)
338 if ((
size_t) (q->offset+4) > length)
342 if (q->endian == UndefinedEndian)
343 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
344 if (endian == LSBEndian)
346 value=(ssize_t) (*r++);
347 value|=((ssize_t) *r++) << 8;
348 value|=((ssize_t) *r++) << 16;
349 value|=((ssize_t) *r++) << 24;
353 value=(ssize_t) (*r++) << 24;
354 value|=((ssize_t) *r++) << 16;
355 value|=((ssize_t) *r++) << 8;
356 value|=((ssize_t) *r++);
360 if (q->value == value)
365 if ((q->value & q->mask) == value)
373 for (i=0; i <= (ssize_t) q->extent; i++)
375 if ((
size_t) (q->offset+i+(ssize_t) q->length) > length)
377 if (memcmp(magic+q->offset+i,q->magic,q->length) == 0)
389 SetHeadElementInLinkedList(mime_cache,element_info);
390 UnlockSemaphoreInfo(mime_semaphore);
393 return((
const MimeInfo *) element_info->value);
426#if defined(__cplusplus) || defined(c_plusplus)
430static int MimeInfoCompare(
const void *x,
const void *y)
438 if (strcasecmp((*p)->path,(*q)->path) == 0)
439 return(strcasecmp((*p)->type,(*q)->type));
440 return(strcasecmp((*p)->path,(*q)->path));
443#if defined(__cplusplus) || defined(c_plusplus)
447MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
459 assert(pattern != (
char *) NULL);
460 assert(number_aliases != (
size_t *) NULL);
461 if (IsEventLogging() != MagickFalse)
462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
464 if (IsMimeCacheInstantiated(exception) == MagickFalse)
466 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
467 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
468 if (aliases == (
const MimeInfo **) NULL)
470 LockSemaphoreInfo(mime_semaphore);
471 p=GetHeadElementInLinkedList(mime_cache);
478 if ((mime_info->stealth == MagickFalse) &&
479 (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
480 aliases[i++]=mime_info;
483 UnlockSemaphoreInfo(mime_semaphore);
485 aliases=(
const MimeInfo **) RelinquishMagickMemory((
void *) aliases);
488 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeInfoCompare);
491 *number_aliases=(size_t) i;
525#if defined(__cplusplus) || defined(c_plusplus)
529static int MimeCompare(
const void *x,
const void *y)
537 return(strcasecmp(p,q));
540#if defined(__cplusplus) || defined(c_plusplus)
544MagickExport
char **GetMimeList(
const char *pattern,
556 assert(pattern != (
char *) NULL);
557 assert(number_aliases != (
size_t *) NULL);
558 if (IsEventLogging() != MagickFalse)
559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
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);
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);
580 UnlockSemaphoreInfo(mime_semaphore);
582 aliases=(
char **) RelinquishMagickMemory(aliases);
585 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
586 aliases[i]=(
char *) NULL;
588 *number_aliases=(size_t) i;
614MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
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);
645MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
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);
677static MagickBooleanType IsMimeCacheInstantiated(
ExceptionInfo *exception)
682 ActivateSemaphoreInfo(&mime_semaphore);
683 LockSemaphoreInfo(mime_semaphore);
685 mime_cache=AcquireMimeCache(MimeFilename,exception);
686 UnlockSemaphoreInfo(mime_semaphore);
688 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
715MagickExport MagickBooleanType ListMimeInfo(FILE *file,
ExceptionInfo *exception)
732 if (file == (
const FILE *) NULL)
734 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
735 if (mime_info == (
const MimeInfo **) NULL)
738 path=(
const char *) NULL;
739 for (i=0; i < (ssize_t) number_aliases; i++)
741 if (mime_info[i]->stealth != MagickFalse)
743 if ((path == (
const char *) NULL) ||
744 (strcasecmp(path,mime_info[i]->path) != 0))
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");
753 path=mime_info[i]->path;
754 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
755 if (strlen(mime_info[i]->type) <= 25)
757 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
758 (
void) FormatLocaleFile(file,
" ");
762 (void) FormatLocaleFile(file,
"\n");
763 for (j=0; j <= 27; j++)
764 (
void) FormatLocaleFile(file,
" ");
766 if (mime_info[i]->description != (
char *) NULL)
767 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
768 (void) FormatLocaleFile(file,
"\n");
771 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
775#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
806static MagickBooleanType LoadMimeCache(
LinkedListInfo *cache,
const char *xml,
807 const char *filename,
const size_t depth,
ExceptionInfo *exception)
826 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
827 "Loading mime map \"%s\" ...",filename);
828 if (xml == (
const char *) NULL)
830 mime_map=NewXMLTree(xml,exception);
834 include=GetXMLTreeChild(mime_map,
"include");
840 attribute=GetXMLTreeAttribute(include,
"file");
841 if (attribute != (
const char *) NULL)
843 if (depth > MagickMaxRecursionDepth)
844 (void) ThrowMagickException(exception,GetMagickModule(),
845 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",filename);
849 path[MagickPathExtent],
852 GetPathComponent(filename,HeadPath,path);
854 (void) ConcatenateMagickString(path,DirectorySeparator,
856 if (*attribute == *DirectorySeparator)
857 (void) CopyMagickString(path,attribute,MagickPathExtent);
859 (
void) ConcatenateMagickString(path,attribute,MagickPathExtent);
860 file_xml=FileToXML(path,~0UL);
861 if (file_xml != (
char *) NULL)
863 status&=(MagickStatusType) LoadMimeCache(cache,file_xml,path,
865 file_xml=DestroyString(file_xml);
869 include=GetNextXMLTreeTag(include);
871 mime=GetXMLTreeChild(mime_map,
"mime");
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)
904 token=AcquireString(attribute);
905 (void) SubstituteString((
char **) &token,
"<",
"<");
906 (void) SubstituteString((
char **) &token,
"&",
"&");
907 (void) SubstituteString((
char **) &token,
""",
"\"");
908 mime_info->magic=(
unsigned char *) AcquireString(token);
910 for (p=token; *p !=
'\0'; )
915 if (isdigit((
int) ((
unsigned char) *p)) != 0)
920 *q++=(
unsigned char) strtol(p,&end,8);
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;
942 *q++=(
unsigned char) (*p++);
945 token=DestroyString(token);
946 if (mime_info->data_type != StringData)
947 mime_info->value=(ssize_t) strtoul((
char *) mime_info->magic,
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)
959 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
961 mime_info->extent=(size_t) strtol(c+1,(
char **) NULL,0);
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);
981 mime_map=DestroyXMLTree(mime_map);
982 return(status != 0 ? MagickTrue : MagickFalse);
1011MagickExport
char *MagickToMime(
const char *magick)
1014 filename[MagickPathExtent],
1015 media[MagickPathExtent];
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));
1053MagickPrivate MagickBooleanType MimeComponentGenesis(
void)
1056 mime_semaphore=AcquireSemaphoreInfo();
1079static 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);
1099MagickPrivate
void MimeComponentTerminus(
void)
1102 ActivateSemaphoreInfo(&mime_semaphore);
1103 LockSemaphoreInfo(mime_semaphore);
1105 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1106 UnlockSemaphoreInfo(mime_semaphore);
1107 RelinquishSemaphoreInfo(&mime_semaphore);