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/quantum-private.h"
59#include "MagickCore/xml-tree.h"
60#include "MagickCore/xml-tree-private.h"
65#define MimeFilename "mime.xml"
67#if defined(MAGICKCORE_WINDOWS_SUPPORT)
68# if !defined(strcasecmp)
69# define strcasecmp _stricmp
120 *mime_cache = (LinkedListInfo *) NULL;
128static MagickBooleanType
129 IsMimeCacheInstantiated(ExceptionInfo *);
131#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
132static MagickBooleanType
133 LoadMimeCache(LinkedListInfo *,
const char *,
const char *,
const size_t,
163MagickExport LinkedListInfo *AcquireMimeCache(
const char *filename,
164 ExceptionInfo *exception)
169 cache=NewLinkedList(0);
170#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
178 options=GetConfigureOptions(filename,exception);
179 option=(
const StringInfo *) GetNextValueInLinkedList(options);
180 while (option != (
const StringInfo *) NULL)
182 (void) LoadMimeCache(cache,(
const char *)
183 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
184 option=(
const StringInfo *) GetNextValueInLinkedList(options);
186 options=DestroyConfigureOptions(options);
189 magick_unreferenced(filename);
190 magick_unreferenced(exception);
228MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
229 const unsigned char *magic,
const size_t length,ExceptionInfo *exception)
247 assert(exception != (ExceptionInfo *) NULL);
248 if (IsMimeCacheInstantiated(exception) == MagickFalse)
249 return((
const MimeInfo *) NULL);
253 LockSemaphoreInfo(mime_semaphore);
254 p=GetHeadElementInLinkedList(mime_cache);
255 if ((magic == (
const unsigned char *) NULL) || (length == 0))
257 UnlockSemaphoreInfo(mime_semaphore);
258 if (p != (ElementInfo *) NULL)
259 return((
const MimeInfo *) p->value);
260 return((
const MimeInfo *) NULL);
262 element_info=(ElementInfo *) NULL;
263 while (p != (ElementInfo *) NULL)
268 q=(
const MimeInfo *) p->value;
269 assert(q->offset >= 0);
270 if (element_info != (
const ElementInfo *) NULL)
271 if (q->priority > ((
const MimeInfo *) element_info->value)->priority)
276 if ((q->pattern != (
char *) NULL) && (filename != (
char *) NULL))
278 if (GlobExpression(filename,q->pattern,MagickFalse) != MagickFalse)
283 switch (q->data_type)
287 if ((
size_t) (q->offset+4) > length)
290 value=(ssize_t) (*r++);
293 if (q->value == value)
298 if ((q->value & q->mask) == value)
305 if ((
size_t) (q->offset+4) > length)
309 if (q->endian == UndefinedEndian)
310 endian=GetHostEndian();
311 if (endian == LSBEndian)
313 value=(ssize_t) (*r++);
318 value=(ssize_t) (*r++) << 8;
323 if (q->value == value)
328 if ((q->value & q->mask) == value)
335 if ((
size_t) (q->offset+4) > length)
339 if (q->endian == UndefinedEndian)
340 endian=GetHostEndian();
341 if (endian == LSBEndian)
343 value=(ssize_t) (*r++);
344 value|=((ssize_t) *r++) << 8;
345 value|=((ssize_t) *r++) << 16;
346 value|=((ssize_t) *r++) << 24;
350 value=(ssize_t) (*r++) << 24;
351 value|=((ssize_t) *r++) << 16;
352 value|=((ssize_t) *r++) << 8;
353 value|=((ssize_t) *r++);
357 if (q->value == value)
362 if ((q->value & q->mask) == value)
370 for (i=0; i <= (ssize_t) q->extent; i++)
372 if ((
size_t) (q->offset+i+(ssize_t) q->length) > length)
374 if (memcmp(magic+q->offset+i,q->magic,q->length) == 0)
385 if (element_info != (ElementInfo *) NULL)
386 SetHeadElementInLinkedList(mime_cache,element_info);
387 UnlockSemaphoreInfo(mime_semaphore);
388 if (element_info == (ElementInfo *) NULL)
389 return((
const MimeInfo *) NULL);
390 return((
const MimeInfo *) element_info->value);
423#if defined(__cplusplus) || defined(c_plusplus)
427static int MimeInfoCompare(
const void *x,
const void *y)
433 p=(
const MimeInfo **) x,
434 q=(
const MimeInfo **) y;
435 if (strcasecmp((*p)->path,(*q)->path) == 0)
436 return(strcasecmp((*p)->type,(*q)->type));
437 return(strcasecmp((*p)->path,(*q)->path));
440#if defined(__cplusplus) || defined(c_plusplus)
444MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
445 size_t *number_aliases,ExceptionInfo *exception)
456 assert(pattern != (
char *) NULL);
457 assert(number_aliases != (
size_t *) NULL);
458 if (IsEventLogging() != MagickFalse)
459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
461 if (IsMimeCacheInstantiated(exception) == MagickFalse)
462 return((
const MimeInfo **) NULL);
463 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
464 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
465 if (aliases == (
const MimeInfo **) NULL)
466 return((
const MimeInfo **) NULL);
467 LockSemaphoreInfo(mime_semaphore);
468 p=GetHeadElementInLinkedList(mime_cache);
469 for (i=0; p != (ElementInfo *) NULL; )
474 mime_info=(MimeInfo *) p->value;
475 if ((mime_info->stealth == MagickFalse) &&
476 (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
477 aliases[i++]=mime_info;
480 UnlockSemaphoreInfo(mime_semaphore);
482 aliases=(
const MimeInfo **) RelinquishMagickMemory((
void *) aliases);
485 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeInfoCompare);
486 aliases[i]=(MimeInfo *) NULL;
488 *number_aliases=(size_t) i;
522#if defined(__cplusplus) || defined(c_plusplus)
526static int MimeCompare(
const void *x,
const void *y)
534 return(strcasecmp(p,q));
537#if defined(__cplusplus) || defined(c_plusplus)
541MagickExport
char **GetMimeList(
const char *pattern,
542 size_t *number_aliases,ExceptionInfo *exception)
553 assert(pattern != (
char *) NULL);
554 assert(number_aliases != (
size_t *) NULL);
555 if (IsEventLogging() != MagickFalse)
556 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
558 if (IsMimeCacheInstantiated(exception) == MagickFalse)
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 p=GetHeadElementInLinkedList(mime_cache);
566 for (i=0; p != (ElementInfo *) NULL; )
571 mime_info=(
const MimeInfo *) p->value;
572 if ((mime_info->stealth == MagickFalse) &&
573 (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
574 aliases[i++]=ConstantString(mime_info->type);
577 UnlockSemaphoreInfo(mime_semaphore);
579 aliases=(
char **) RelinquishMagickMemory(aliases);
582 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
583 aliases[i]=(
char *) NULL;
585 *number_aliases=(size_t) i;
611MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
613 assert(mime_info != (MimeInfo *) NULL);
614 assert(mime_info->signature == MagickCoreSignature);
615 if (IsEventLogging() != MagickFalse)
616 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
617 return(mime_info->description);
642MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
644 assert(mime_info != (MimeInfo *) NULL);
645 assert(mime_info->signature == MagickCoreSignature);
646 if (IsEventLogging() != MagickFalse)
647 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
648 return(mime_info->type);
674static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
676 if (mime_cache == (LinkedListInfo *) NULL)
679 ActivateSemaphoreInfo(&mime_semaphore);
680 LockSemaphoreInfo(mime_semaphore);
681 if (mime_cache == (LinkedListInfo *) NULL)
682 mime_cache=AcquireMimeCache(MimeFilename,exception);
683 UnlockSemaphoreInfo(mime_semaphore);
685 return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
712MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
729 if (file == (
const FILE *) NULL)
731 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
732 if (mime_info == (
const MimeInfo **) NULL)
735 path=(
const char *) NULL;
736 for (i=0; i < (ssize_t) number_aliases; i++)
738 if (mime_info[i]->stealth != MagickFalse)
740 if ((path == (
const char *) NULL) ||
741 (strcasecmp(path,mime_info[i]->path) != 0))
743 if (mime_info[i]->path != (
char *) NULL)
744 (void) FormatLocaleFile(file,
"\nPath: %s\n\n",mime_info[i]->path);
745 (void) FormatLocaleFile(file,
"Type Description\n");
746 (void) FormatLocaleFile(file,
747 "-------------------------------------------------"
748 "------------------------------\n");
750 path=mime_info[i]->path;
751 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
752 if (strlen(mime_info[i]->type) <= 25)
754 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
755 (
void) FormatLocaleFile(file,
" ");
759 (void) FormatLocaleFile(file,
"\n");
760 for (j=0; j <= 27; j++)
761 (
void) FormatLocaleFile(file,
" ");
763 if (mime_info[i]->description != (
char *) NULL)
764 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
765 (void) FormatLocaleFile(file,
"\n");
768 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
772#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
803static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,
const char *xml,
804 const char *filename,
const size_t depth,ExceptionInfo *exception)
810 *mime_info = (MimeInfo *) NULL;
823 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
824 "Loading mime map \"%s\" ...",filename);
825 if (xml == (
const char *) NULL)
827 mime_map=NewXMLTree(xml,exception);
828 if (mime_map == (XMLTreeInfo *) NULL)
831 include=GetXMLTreeChild(mime_map,
"include");
832 while (include != (XMLTreeInfo *) NULL)
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);
846 path[MagickPathExtent],
849 GetPathComponent(filename,HeadPath,path);
851 (void) ConcatenateMagickString(path,DirectorySeparator,
853 if (*attribute == *DirectorySeparator)
854 (void) CopyMagickString(path,attribute,MagickPathExtent);
856 (
void) ConcatenateMagickString(path,attribute,MagickPathExtent);
857 file_xml=FileToXML(path,~0UL);
858 if (file_xml != (
char *) NULL)
860 status&=(MagickStatusType) LoadMimeCache(cache,file_xml,path,
862 file_xml=DestroyString(file_xml);
866 include=GetNextXMLTreeTag(include);
868 mime=GetXMLTreeChild(mime_map,
"mime");
869 while (mime != (XMLTreeInfo *) NULL)
874 mime_info=(MimeInfo *) AcquireCriticalMemory(
sizeof(*mime_info));
875 (void) memset(mime_info,0,
sizeof(*mime_info));
876 mime_info->path=ConstantString(filename);
877 mime_info->signature=MagickCoreSignature;
878 attribute=GetXMLTreeAttribute(mime,
"data-type");
879 if (attribute != (
const char *) NULL)
880 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
881 MagickTrue,attribute);
882 attribute=GetXMLTreeAttribute(mime,
"description");
883 if (attribute != (
const char *) NULL)
884 mime_info->description=ConstantString(attribute);
885 attribute=GetXMLTreeAttribute(mime,
"endian");
886 if (attribute != (
const char *) NULL)
887 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
888 MagickTrue,attribute);
889 attribute=GetXMLTreeAttribute(mime,
"magic");
890 if (attribute != (
const char *) NULL)
901 token=AcquireString(attribute);
902 (void) SubstituteString(&token,
"<",
"<");
903 (void) SubstituteString(&token,
">",
">");
904 (void) SubstituteString(&token,
"&",
"&");
905 (void) SubstituteString(&token,
""",
"\"");
906 (void) SubstituteString(&token,
"'",
"'");
907 mime_info->magic=(
unsigned char *) AcquireString(token);
909 for (p=token; *p !=
'\0'; )
914 if (isdigit((
int) ((
unsigned char) *p)) != 0)
919 *q++=(
unsigned char) strtol(p,&end,8);
920 p+=(ptrdiff_t) (end-p);
926 case 'b': *q=
'\b';
break;
927 case 'f': *q=
'\f';
break;
928 case 'n': *q=
'\n';
break;
929 case 'r': *q=
'\r';
break;
930 case 't': *q=
'\t';
break;
931 case 'v': *q=
'\v';
break;
932 case 'a': *q=
'a';
break;
933 case '?': *q=
'\?';
break;
934 default: *q=(
unsigned char) (*p);
break;
941 *q++=(
unsigned char) (*p++);
944 token=DestroyString(token);
945 if (mime_info->data_type != StringData)
946 mime_info->value=(ssize_t) strtoul((
char *) mime_info->magic,
949 attribute=GetXMLTreeAttribute(mime,
"mask");
950 if (attribute != (
const char *) NULL)
951 mime_info->mask=(ssize_t) strtoul(attribute,(
char **) NULL,0);
952 attribute=GetXMLTreeAttribute(mime,
"offset");
953 if (attribute != (
const char *) NULL)
958 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
960 mime_info->extent=(size_t) strtol(c+1,(
char **) NULL,0);
962 attribute=GetXMLTreeAttribute(mime,
"pattern");
963 if (attribute != (
const char *) NULL)
964 mime_info->pattern=ConstantString(attribute);
965 attribute=GetXMLTreeAttribute(mime,
"priority");
966 if (attribute != (
const char *) NULL)
967 mime_info->priority=(ssize_t) strtol(attribute,(
char **) NULL,0);
968 attribute=GetXMLTreeAttribute(mime,
"stealth");
969 if (attribute != (
const char *) NULL)
970 mime_info->stealth=IsStringTrue(attribute);
971 attribute=GetXMLTreeAttribute(mime,
"type");
972 if (attribute != (
const char *) NULL)
973 mime_info->type=ConstantString(attribute);
974 status=AppendValueToLinkedList(cache,mime_info);
975 if (status == MagickFalse)
976 (void) ThrowMagickException(exception,GetMagickModule(),
977 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
978 mime=GetNextXMLTreeTag(mime);
980 mime_map=DestroyXMLTree(mime_map);
981 return(status != 0 ? MagickTrue : MagickFalse);
1010MagickExport
char *MagickToMime(
const char *magick)
1013 filename[MagickPathExtent],
1014 media[MagickPathExtent];
1022 (void) FormatLocaleString(filename,MagickPathExtent,
"file.%s",magick);
1023 LocaleLower(filename);
1024 exception=AcquireExceptionInfo();
1025 mime_info=GetMimeInfo(filename,(
unsigned char *)
" ",1,exception);
1026 exception=DestroyExceptionInfo(exception);
1027 if (mime_info != (
const MimeInfo *) NULL)
1028 return(ConstantString(GetMimeType(mime_info)));
1029 (void) FormatLocaleString(media,MagickPathExtent,
"image/x-%s",magick);
1030 LocaleLower(media+8);
1031 return(ConstantString(media));
1052MagickPrivate MagickBooleanType MimeComponentGenesis(
void)
1055 mime_semaphore=AcquireSemaphoreInfo();
1078static void *DestroyMimeElement(
void *mime_info)
1083 p=(MimeInfo *) mime_info;
1084 if (p->magic != (
unsigned char *) NULL)
1085 p->magic=(
unsigned char *) RelinquishMagickMemory(p->magic);
1086 if (p->pattern != (
char *) NULL)
1087 p->pattern=DestroyString(p->pattern);
1088 if (p->description != (
char *) NULL)
1089 p->description=DestroyString(p->description);
1090 if (p->type != (
char *) NULL)
1091 p->type=DestroyString(p->type);
1092 if (p->path != (
char *) NULL)
1093 p->path=DestroyString(p->path);
1094 p=(MimeInfo *) RelinquishMagickMemory(p);
1095 return((
void *) NULL);
1098MagickPrivate
void MimeComponentTerminus(
void)
1101 ActivateSemaphoreInfo(&mime_semaphore);
1102 LockSemaphoreInfo(mime_semaphore);
1103 if (mime_cache != (LinkedListInfo *) NULL)
1104 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1105 UnlockSemaphoreInfo(mime_semaphore);
1106 RelinquishSemaphoreInfo(&mime_semaphore);