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\"?>"
126static MagickBooleanType
128 LoadMimeCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
163 cache=NewLinkedList(0);
165 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
166#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
174 options=GetConfigureOptions(filename,exception);
175 option=(
const StringInfo *) GetNextValueInLinkedList(options);
178 (void) LoadMimeCache(cache, (
const char *)
179 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
180 option=(
const StringInfo *) GetNextValueInLinkedList(options);
182 options=DestroyConfigureOptions(options);
185 magick_unreferenced(filename);
187 if (IsLinkedListEmpty(cache) != MagickFalse)
188 (void) LoadMimeCache(cache,MimeMap,
"built-in",0,exception);
192MagickExport MagickBooleanType LoadMimeLists(
const char *name,
195 mime_cache=AcquireMimeCache(name,exception);
196 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
232MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
233 const unsigned char *magic,
const size_t length,
ExceptionInfo *exception)
257 if (IsMimeCacheInstantiated(exception) == MagickFalse)
264 LockSemaphoreInfo(mime_semaphore);
265 ResetLinkedListIterator(mime_cache);
266 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
267 if ((magic == (
const unsigned char *) NULL) || (length == 0))
269 UnlockSemaphoreInfo(mime_semaphore);
272 while (p != (
const MimeInfo *) NULL)
274 assert(p->offset >= 0);
275 if (mime_info != (
const MimeInfo *) NULL)
276 if (p->priority > mime_info->priority)
278 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
281 if ((p->pattern != (
char *) NULL) && (filename != (
char *) NULL))
283 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
285 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
288 switch (p->data_type)
292 if ((
size_t) (p->offset+4) > length)
295 value=(ssize_t) (*q++);
298 if (p->value == value)
303 if ((p->value & p->mask) == value)
310 if ((
size_t) (p->offset+4) > length)
314 if (p->endian == UndefinedEndian)
315 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
316 if (endian == LSBEndian)
318 value=(ssize_t) (*q++);
323 value=(ssize_t) (*q++) << 8;
328 if (p->value == value)
333 if ((p->value & p->mask) == value)
340 if ((
size_t) (p->offset+4) > length)
344 if (p->endian == UndefinedEndian)
345 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
346 if (endian == LSBEndian)
348 value=(ssize_t) (*q++);
349 value|=((ssize_t) *q++) << 8;
350 value|=((ssize_t) *q++) << 16;
351 value|=((ssize_t) *q++) << 24;
355 value=(ssize_t) (*q++) << 24;
356 value|=((ssize_t) *q++) << 16;
357 value|=((ssize_t) *q++) << 8;
358 value|=((ssize_t) *q++);
362 if (p->value == value)
367 if ((p->value & p->mask) == value)
375 for (i=0; i <= (ssize_t) p->extent; i++)
377 if ((
size_t) (p->offset+i+p->length) > length)
379 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
388 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
390 if (mime_info != (
const MimeInfo *) NULL)
391 (void) InsertValueInLinkedList(mime_cache,0,
392 RemoveElementByValueFromLinkedList(mime_cache,p));
393 UnlockSemaphoreInfo(mime_semaphore);
427#if defined(__cplusplus) || defined(c_plusplus)
431static int MimeInfoCompare(
const void *x,
const void *y)
439 if (strcasecmp((*p)->path,(*q)->path) == 0)
440 return(strcasecmp((*p)->type,(*q)->type));
441 return(strcasecmp((*p)->path,(*q)->path));
444#if defined(__cplusplus) || defined(c_plusplus)
448MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
463 assert(pattern != (
char *) NULL);
464 assert(number_aliases != (
size_t *) NULL);
465 if (IsEventLogging() != MagickFalse)
466 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
468 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
471 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
472 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
473 if (aliases == (
const MimeInfo **) NULL)
478 LockSemaphoreInfo(mime_semaphore);
479 ResetLinkedListIterator(mime_cache);
480 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
481 for (i=0; p != (
const MimeInfo *) NULL; )
483 if ((p->stealth == MagickFalse) &&
484 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
486 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
488 UnlockSemaphoreInfo(mime_semaphore);
489 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,
559 assert(pattern != (
char *) NULL);
560 assert(number_aliases != (
size_t *) NULL);
561 if (IsEventLogging() != MagickFalse)
562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
564 p=GetMimeInfo((
char *) NULL,(
unsigned char *)
"*",0,exception);
566 return((
char **) NULL);
567 aliases=(
char **) AcquireQuantumMemory((
size_t)
568 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
569 if (aliases == (
char **) NULL)
570 return((
char **) NULL);
571 LockSemaphoreInfo(mime_semaphore);
572 ResetLinkedListIterator(mime_cache);
573 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
574 for (i=0; p != (
const MimeInfo *) NULL; )
576 if ((p->stealth == MagickFalse) &&
577 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
578 aliases[i++]=ConstantString(p->type);
579 p=(
const MimeInfo *) GetNextValueInLinkedList(mime_cache);
581 UnlockSemaphoreInfo(mime_semaphore);
582 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
583 aliases[i]=(
char *) NULL;
584 *number_aliases=(size_t) i;
610MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
612 assert(mime_info != (
MimeInfo *) NULL);
613 assert(mime_info->signature == MagickCoreSignature);
614 if (IsEventLogging() != MagickFalse)
615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
616 return(mime_info->description);
641MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
643 assert(mime_info != (
MimeInfo *) NULL);
644 assert(mime_info->signature == MagickCoreSignature);
645 if (IsEventLogging() != MagickFalse)
646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
647 return(mime_info->type);
673static MagickBooleanType IsMimeCacheInstantiated(
ExceptionInfo *exception)
678 ActivateSemaphoreInfo(&mime_semaphore);
679 LockSemaphoreInfo(mime_semaphore);
681 mime_cache=AcquireMimeCache(MimeFilename,exception);
682 UnlockSemaphoreInfo(mime_semaphore);
684 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
711MagickExport MagickBooleanType ListMimeInfo(FILE *file,
ExceptionInfo *exception)
728 if (file == (
const FILE *) NULL)
730 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
731 if (mime_info == (
const MimeInfo **) NULL)
734 path=(
const char *) NULL;
735 for (i=0; i < (ssize_t) number_aliases; i++)
737 if (mime_info[i]->stealth != MagickFalse)
739 if ((path == (
const char *) NULL) ||
740 (strcasecmp(path,mime_info[i]->path) != 0))
742 if (mime_info[i]->path != (
char *) NULL)
743 (void) FormatLocaleFile(file,
"\nPath: %s\n\n",mime_info[i]->path);
744 (void) FormatLocaleFile(file,
"Type Description\n");
745 (void) FormatLocaleFile(file,
746 "-------------------------------------------------"
747 "------------------------------\n");
749 path=mime_info[i]->path;
750 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
751 if (strlen(mime_info[i]->type) <= 25)
753 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
754 (
void) FormatLocaleFile(file,
" ");
758 (void) FormatLocaleFile(file,
"\n");
759 for (j=0; j <= 27; j++)
760 (
void) FormatLocaleFile(file,
" ");
762 if (mime_info[i]->description != (
char *) NULL)
763 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
764 (void) FormatLocaleFile(file,
"\n");
767 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
801static MagickBooleanType LoadMimeCache(
LinkedListInfo *cache,
const char *xml,
802 const char *filename,
const size_t depth,
ExceptionInfo *exception)
821 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
822 "Loading mime map \"%s\" ...",filename);
823 if (xml == (
const char *) NULL)
825 mime_map=NewXMLTree(xml,exception);
829 include=GetXMLTreeChild(mime_map,
"include");
835 attribute=GetXMLTreeAttribute(include,
"file");
836 if (attribute != (
const char *) NULL)
838 if (depth > MagickMaxRecursionDepth)
839 (void) ThrowMagickException(exception,GetMagickModule(),
840 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",filename);
847 GetPathComponent(filename,HeadPath,path);
849 (void) ConcatenateMagickString(path,DirectorySeparator,
851 if (*attribute == *DirectorySeparator)
852 (void) CopyMagickString(path,attribute,MaxTextExtent);
854 (
void) ConcatenateMagickString(path,attribute,MaxTextExtent);
855 xml=FileToXML(path,~0UL);
856 if (xml != (
char *) NULL)
858 status&=LoadMimeCache(cache,xml,path,depth+1,exception);
859 xml=DestroyString(xml);
863 include=GetNextXMLTreeTag(include);
865 mime=GetXMLTreeChild(mime_map,
"mime");
874 mime_info=(
MimeInfo *) AcquireMagickMemory(
sizeof(*mime_info));
876 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
877 (void) memset(mime_info,0,
sizeof(*mime_info));
878 mime_info->path=ConstantString(filename);
879 mime_info->signature=MagickCoreSignature;
880 attribute=GetXMLTreeAttribute(mime,
"data-type");
881 if (attribute != (
const char *) NULL)
882 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
883 MagickTrue,attribute);
884 attribute=GetXMLTreeAttribute(mime,
"description");
885 if (attribute != (
const char *) NULL)
886 mime_info->description=ConstantString(attribute);
887 attribute=GetXMLTreeAttribute(mime,
"endian");
888 if (attribute != (
const char *) NULL)
889 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
890 MagickTrue,attribute);
891 attribute=GetXMLTreeAttribute(mime,
"magic");
892 if (attribute != (
const char *) NULL)
903 token=AcquireString(attribute);
904 (void) SubstituteString((
char **) &token,
"<",
"<");
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);
921 p+=(ptrdiff_t) (end-p);
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=IsMagickTrue(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);
1010MagickExport
char *MagickToMime(
const char *magick)
1013 filename[MaxTextExtent],
1014 media[MaxTextExtent];
1022 (void) FormatLocaleString(filename,MaxTextExtent,
"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,MaxTextExtent,
"image/x-%s",magick);
1030 LocaleLower(media+8);
1031 return(ConstantString(media));
1052MagickExport MagickBooleanType MimeComponentGenesis(
void)
1055 mime_semaphore=AllocateSemaphoreInfo();
1078static void *DestroyMimeElement(
void *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);
1098MagickExport
void MimeComponentTerminus(
void)
1101 ActivateSemaphoreInfo(&mime_semaphore);
1102 LockSemaphoreInfo(mime_semaphore);
1104 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1105 UnlockSemaphoreInfo(mime_semaphore);
1106 DestroySemaphoreInfo(&mime_semaphore);