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"
65#if defined(MAGICKCORE_WINDOWS_SUPPORT)
66# if !defined(strcasecmp)
67# define strcasecmp _stricmp
119 "<?xml version=\"1.0\"?>"
124 *mime_cache = (LinkedListInfo *) NULL;
132static MagickBooleanType
133 IsMimeCacheInstantiated(ExceptionInfo *),
134 LoadMimeCache(LinkedListInfo *,
const char *,
const char *,
const size_t,
163static LinkedListInfo *AcquireMimeCache(
const char *filename,
164 ExceptionInfo *exception)
169 cache=NewLinkedList(0);
170 if (cache == (LinkedListInfo *) NULL)
171 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
172#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
180 options=GetConfigureOptions(filename,exception);
181 option=(
const StringInfo *) GetNextValueInLinkedList(options);
182 while (option != (
const StringInfo *) NULL)
184 (void) LoadMimeCache(cache, (
const char *)
185 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
186 option=(
const StringInfo *) GetNextValueInLinkedList(options);
188 options=DestroyConfigureOptions(options);
191 magick_unreferenced(filename);
193 if (IsLinkedListEmpty(cache) != MagickFalse)
194 (void) LoadMimeCache(cache,MimeMap,
"built-in",0,exception);
198MagickExport MagickBooleanType LoadMimeLists(
const char *name,
199 ExceptionInfo *exception)
201 mime_cache=AcquireMimeCache(name,exception);
202 return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
238MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
239 const unsigned char *magic,
const size_t length,ExceptionInfo *exception)
262 assert(exception != (ExceptionInfo *) NULL);
263 if (IsMimeCacheInstantiated(exception) == MagickFalse)
264 return((
const MimeInfo *) NULL);
268 mime_info=(
const MimeInfo *) NULL;
270 LockSemaphoreInfo(mime_semaphore);
271 ResetLinkedListIterator(mime_cache);
272 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
273 if ((magic == (
const unsigned char *) NULL) || (length == 0))
275 UnlockSemaphoreInfo(mime_semaphore);
278 while (p != (
const MimeInfo *) NULL)
280 assert(p->offset >= 0);
281 if (mime_info != (
const MimeInfo *) NULL)
282 if (p->priority > mime_info->priority)
284 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
287 if ((p->pattern != (
char *) NULL) && (filename != (
char *) NULL))
289 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
291 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
294 switch (p->data_type)
298 if ((
size_t) (p->offset+4) > length)
301 value=(ssize_t) (*q++);
304 if (p->value == value)
309 if ((p->value & p->mask) == value)
316 if ((
size_t) (p->offset+4) > length)
320 if (p->endian == UndefinedEndian)
321 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
322 if (endian == LSBEndian)
324 value=(ssize_t) (*q++);
329 value=(ssize_t) (*q++) << 8;
334 if (p->value == value)
339 if ((p->value & p->mask) == value)
346 if ((
size_t) (p->offset+4) > length)
350 if (p->endian == UndefinedEndian)
351 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
352 if (endian == LSBEndian)
354 value=(ssize_t) (*q++);
355 value|=((ssize_t) *q++) << 8;
356 value|=((ssize_t) *q++) << 16;
357 value|=((ssize_t) *q++) << 24;
361 value=(ssize_t) (*q++) << 24;
362 value|=((ssize_t) *q++) << 16;
363 value|=((ssize_t) *q++) << 8;
364 value|=((ssize_t) *q++);
368 if (p->value == value)
373 if ((p->value & p->mask) == value)
381 for (i=0; i <= (ssize_t) p->extent; i++)
383 if ((
size_t) (p->offset+i+p->length) > length)
385 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
394 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
396 if (mime_info != (
const MimeInfo *) NULL)
397 (void) InsertValueInLinkedList(mime_cache,0,
398 RemoveElementByValueFromLinkedList(mime_cache,p));
399 UnlockSemaphoreInfo(mime_semaphore);
433#if defined(__cplusplus) || defined(c_plusplus)
437static int MimeInfoCompare(
const void *x,
const void *y)
443 p=(
const MimeInfo **) x,
444 q=(
const MimeInfo **) y;
445 if (strcasecmp((*p)->path,(*q)->path) == 0)
446 return(strcasecmp((*p)->type,(*q)->type));
447 return(strcasecmp((*p)->path,(*q)->path));
450#if defined(__cplusplus) || defined(c_plusplus)
454MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
455 size_t *number_aliases,ExceptionInfo *exception)
469 assert(pattern != (
char *) NULL);
470 assert(number_aliases != (
size_t *) NULL);
471 if (IsEventLogging() != MagickFalse)
472 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
474 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
475 if (p == (
const MimeInfo *) NULL)
476 return((
const MimeInfo **) NULL);
477 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
478 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
479 if (aliases == (
const MimeInfo **) NULL)
480 return((
const MimeInfo **) NULL);
484 LockSemaphoreInfo(mime_semaphore);
485 ResetLinkedListIterator(mime_cache);
486 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
487 for (i=0; p != (
const MimeInfo *) NULL; )
489 if ((p->stealth == MagickFalse) &&
490 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
492 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
494 UnlockSemaphoreInfo(mime_semaphore);
495 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeInfoCompare);
496 aliases[i]=(MimeInfo *) NULL;
497 *number_aliases=(size_t) i;
531#if defined(__cplusplus) || defined(c_plusplus)
535static int MimeCompare(
const void *x,
const void *y)
543 return(strcasecmp(p,q));
546#if defined(__cplusplus) || defined(c_plusplus)
550MagickExport
char **GetMimeList(
const char *pattern,
551 size_t *number_aliases,ExceptionInfo *exception)
565 assert(pattern != (
char *) NULL);
566 assert(number_aliases != (
size_t *) NULL);
567 if (IsEventLogging() != MagickFalse)
568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
570 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
571 if (p == (
const MimeInfo *) NULL)
572 return((
char **) NULL);
573 aliases=(
char **) AcquireQuantumMemory((
size_t)
574 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
575 if (aliases == (
char **) NULL)
576 return((
char **) NULL);
577 LockSemaphoreInfo(mime_semaphore);
578 ResetLinkedListIterator(mime_cache);
579 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
580 for (i=0; p != (
const MimeInfo *) NULL; )
582 if ((p->stealth == MagickFalse) &&
583 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
584 aliases[i++]=ConstantString(p->type);
585 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
587 UnlockSemaphoreInfo(mime_semaphore);
588 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
589 aliases[i]=(
char *) NULL;
590 *number_aliases=(size_t) i;
616MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
618 assert(mime_info != (MimeInfo *) NULL);
619 assert(mime_info->signature == MagickCoreSignature);
620 if (IsEventLogging() != MagickFalse)
621 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
622 return(mime_info->description);
647MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
649 assert(mime_info != (MimeInfo *) NULL);
650 assert(mime_info->signature == MagickCoreSignature);
651 if (IsEventLogging() != MagickFalse)
652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
653 return(mime_info->type);
679static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
681 if (mime_cache == (LinkedListInfo *) NULL)
684 ActivateSemaphoreInfo(&mime_semaphore);
685 LockSemaphoreInfo(mime_semaphore);
686 if (mime_cache == (LinkedListInfo *) NULL)
687 mime_cache=AcquireMimeCache(MimeFilename,exception);
688 UnlockSemaphoreInfo(mime_semaphore);
690 return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
717MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
734 if (file == (
const FILE *) NULL)
736 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
737 if (mime_info == (
const MimeInfo **) NULL)
740 path=(
const char *) NULL;
741 for (i=0; i < (ssize_t) number_aliases; i++)
743 if (mime_info[i]->stealth != MagickFalse)
745 if ((path == (
const char *) NULL) ||
746 (strcasecmp(path,mime_info[i]->path) != 0))
748 if (mime_info[i]->path != (
char *) NULL)
749 (void) FormatLocaleFile(file,
"\nPath: %s\n\n",mime_info[i]->path);
750 (void) FormatLocaleFile(file,
"Type Description\n");
751 (void) FormatLocaleFile(file,
752 "-------------------------------------------------"
753 "------------------------------\n");
755 path=mime_info[i]->path;
756 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
757 if (strlen(mime_info[i]->type) <= 25)
759 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
760 (
void) FormatLocaleFile(file,
" ");
764 (void) FormatLocaleFile(file,
"\n");
765 for (j=0; j <= 27; j++)
766 (
void) FormatLocaleFile(file,
" ");
768 if (mime_info[i]->description != (
char *) NULL)
769 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
770 (void) FormatLocaleFile(file,
"\n");
773 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
807static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,
const char *xml,
808 const char *filename,
const size_t depth,ExceptionInfo *exception)
814 *mime_info = (MimeInfo *) NULL;
827 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
828 "Loading mime map \"%s\" ...",filename);
829 if (xml == (
const char *) NULL)
831 mime_map=NewXMLTree(xml,exception);
832 if (mime_map == (XMLTreeInfo *) NULL)
835 include=GetXMLTreeChild(mime_map,
"include");
836 while (include != (XMLTreeInfo *) NULL)
841 attribute=GetXMLTreeAttribute(include,
"file");
842 if (attribute != (
const char *) NULL)
844 if (depth > MagickMaxRecursionDepth)
845 (void) ThrowMagickException(exception,GetMagickModule(),
846 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",filename);
853 GetPathComponent(filename,HeadPath,path);
855 (void) ConcatenateMagickString(path,DirectorySeparator,
857 if (*attribute == *DirectorySeparator)
858 (void) CopyMagickString(path,attribute,MaxTextExtent);
860 (
void) ConcatenateMagickString(path,attribute,MaxTextExtent);
861 xml=FileToXML(path,~0UL);
862 if (xml != (
char *) NULL)
864 status&=LoadMimeCache(cache,xml,path,depth+1,exception);
865 xml=DestroyString(xml);
869 include=GetNextXMLTreeTag(include);
871 mime=GetXMLTreeChild(mime_map,
"mime");
872 while (mime != (XMLTreeInfo *) NULL)
880 mime_info=(MimeInfo *) AcquireMagickMemory(
sizeof(*mime_info));
881 if (mime_info == (MimeInfo *) NULL)
882 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
883 (void) memset(mime_info,0,
sizeof(*mime_info));
884 mime_info->path=ConstantString(filename);
885 mime_info->signature=MagickCoreSignature;
886 attribute=GetXMLTreeAttribute(mime,
"data-type");
887 if (attribute != (
const char *) NULL)
888 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
889 MagickTrue,attribute);
890 attribute=GetXMLTreeAttribute(mime,
"description");
891 if (attribute != (
const char *) NULL)
892 mime_info->description=ConstantString(attribute);
893 attribute=GetXMLTreeAttribute(mime,
"endian");
894 if (attribute != (
const char *) NULL)
895 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
896 MagickTrue,attribute);
897 attribute=GetXMLTreeAttribute(mime,
"magic");
898 if (attribute != (
const char *) NULL)
909 token=AcquireString(attribute);
910 (void) SubstituteString(&token,
"<",
"<");
911 (void) SubstituteString(&token,
">",
">");
912 (void) SubstituteString(&token,
"&",
"&");
913 (void) SubstituteString(&token,
""",
"\"");
914 (void) SubstituteString(&token,
"'",
"'");
915 mime_info->magic=(
unsigned char *) AcquireString(token);
917 for (p=token; *p !=
'\0'; )
922 if (isdigit((
int) ((
unsigned char) *p)) != 0)
927 *q++=(
unsigned char) strtol(p,&end,8);
928 p+=(ptrdiff_t) (end-p);
934 case 'b': *q=
'\b';
break;
935 case 'f': *q=
'\f';
break;
936 case 'n': *q=
'\n';
break;
937 case 'r': *q=
'\r';
break;
938 case 't': *q=
'\t';
break;
939 case 'v': *q=
'\v';
break;
940 case 'a': *q=
'a';
break;
941 case '?': *q=
'\?';
break;
942 default: *q=(
unsigned char) (*p);
break;
949 *q++=(
unsigned char) (*p++);
952 token=DestroyString(token);
953 if (mime_info->data_type != StringData)
954 mime_info->value=(ssize_t) strtoul((
char *) mime_info->magic,
957 attribute=GetXMLTreeAttribute(mime,
"mask");
958 if (attribute != (
const char *) NULL)
959 mime_info->mask=(ssize_t) strtoul(attribute,(
char **) NULL,0);
960 attribute=GetXMLTreeAttribute(mime,
"offset");
961 if (attribute != (
const char *) NULL)
966 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
968 mime_info->extent=(size_t) strtol(c+1,(
char **) NULL,0);
970 attribute=GetXMLTreeAttribute(mime,
"pattern");
971 if (attribute != (
const char *) NULL)
972 mime_info->pattern=ConstantString(attribute);
973 attribute=GetXMLTreeAttribute(mime,
"priority");
974 if (attribute != (
const char *) NULL)
975 mime_info->priority=(ssize_t) strtol(attribute,(
char **) NULL,0);
976 attribute=GetXMLTreeAttribute(mime,
"stealth");
977 if (attribute != (
const char *) NULL)
978 mime_info->stealth=IsMagickTrue(attribute);
979 attribute=GetXMLTreeAttribute(mime,
"type");
980 if (attribute != (
const char *) NULL)
981 mime_info->type=ConstantString(attribute);
982 status=AppendValueToLinkedList(cache,mime_info);
983 if (status == MagickFalse)
984 (void) ThrowMagickException(exception,GetMagickModule(),
985 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
986 mime=GetNextXMLTreeTag(mime);
988 mime_map=DestroyXMLTree(mime_map);
989 return(status != 0 ? MagickTrue : MagickFalse);
1017MagickExport
char *MagickToMime(
const char *magick)
1020 filename[MaxTextExtent],
1021 media[MaxTextExtent];
1029 (void) FormatLocaleString(filename,MaxTextExtent,
"file.%s",magick);
1030 LocaleLower(filename);
1031 exception=AcquireExceptionInfo();
1032 mime_info=GetMimeInfo(filename,(
unsigned char *)
" ",1,exception);
1033 exception=DestroyExceptionInfo(exception);
1034 if (mime_info != (
const MimeInfo *) NULL)
1035 return(ConstantString(GetMimeType(mime_info)));
1036 (void) FormatLocaleString(media,MaxTextExtent,
"image/x-%s",magick);
1037 LocaleLower(media+8);
1038 return(ConstantString(media));
1059MagickExport MagickBooleanType MimeComponentGenesis(
void)
1062 mime_semaphore=AllocateSemaphoreInfo();
1085static void *DestroyMimeElement(
void *mime_info)
1090 p=(MimeInfo *) mime_info;
1091 if (p->magic != (
unsigned char *) NULL)
1092 p->magic=(
unsigned char *) RelinquishMagickMemory(p->magic);
1093 if (p->pattern != (
char *) NULL)
1094 p->pattern=DestroyString(p->pattern);
1095 if (p->description != (
char *) NULL)
1096 p->description=DestroyString(p->description);
1097 if (p->type != (
char *) NULL)
1098 p->type=DestroyString(p->type);
1099 if (p->path != (
char *) NULL)
1100 p->path=DestroyString(p->path);
1101 p=(MimeInfo *) RelinquishMagickMemory(p);
1102 return((
void *) NULL);
1105MagickExport
void MimeComponentTerminus(
void)
1108 ActivateSemaphoreInfo(&mime_semaphore);
1109 LockSemaphoreInfo(mime_semaphore);
1110 if (mime_cache != (LinkedListInfo *) NULL)
1111 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1112 UnlockSemaphoreInfo(mime_semaphore);
1113 DestroySemaphoreInfo(&mime_semaphore);