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"
121static MagickBooleanType
124#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
125static MagickBooleanType
126 LoadMimeCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
156MagickExport
LinkedListInfo *AcquireMimeCache(
const char *filename,
162 cache=NewLinkedList(0);
163#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
171 options=GetConfigureOptions(filename,exception);
172 option=(
const StringInfo *) GetNextValueInLinkedList(options);
175 (void) LoadMimeCache(cache,(
const char *)
176 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
177 option=(
const StringInfo *) GetNextValueInLinkedList(options);
179 options=DestroyConfigureOptions(options);
182 magick_unreferenced(filename);
183 magick_unreferenced(exception);
221MagickExport
const MimeInfo *GetMimeInfo(
const char *filename,
222 const unsigned char *magic,
const size_t length,
ExceptionInfo *exception)
244 if (IsMimeCacheInstantiated(exception) == MagickFalse)
250 LockSemaphoreInfo(mime_semaphore);
251 p=GetHeadElementInLinkedList(mime_cache);
252 if ((magic == (
const unsigned char *) NULL) || (length == 0))
254 UnlockSemaphoreInfo(mime_semaphore);
256 return((
const MimeInfo *) p->value);
266 assert(q->offset >= 0);
268 if (q->priority > ((
const MimeInfo *) element_info->value)->priority)
273 if ((q->pattern != (
char *) NULL) && (filename != (
char *) NULL))
275 if (GlobExpression(filename,q->pattern,MagickFalse) != MagickFalse)
280 switch (q->data_type)
284 if ((
size_t) (q->offset+4) > length)
287 value=(ssize_t) (*r++);
290 if (q->value == value)
295 if ((q->value & q->mask) == value)
302 if ((
size_t) (q->offset+4) > length)
306 if (q->endian == UndefinedEndian)
307 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
308 if (endian == LSBEndian)
310 value=(ssize_t) (*r++);
315 value=(ssize_t) (*r++) << 8;
320 if (q->value == value)
325 if ((q->value & q->mask) == value)
332 if ((
size_t) (q->offset+4) > length)
336 if (q->endian == UndefinedEndian)
337 endian=(*(
char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
338 if (endian == LSBEndian)
340 value=(ssize_t) (*r++);
341 value|=((ssize_t) *r++) << 8;
342 value|=((ssize_t) *r++) << 16;
343 value|=((ssize_t) *r++) << 24;
347 value=(ssize_t) (*r++) << 24;
348 value|=((ssize_t) *r++) << 16;
349 value|=((ssize_t) *r++) << 8;
350 value|=((ssize_t) *r++);
354 if (q->value == value)
359 if ((q->value & q->mask) == value)
367 for (i=0; i <= (ssize_t) q->extent; i++)
369 if ((
size_t) (q->offset+i+(ssize_t) q->length) > length)
371 if (memcmp(magic+q->offset+i,q->magic,q->length) == 0)
383 SetHeadElementInLinkedList(mime_cache,element_info);
384 UnlockSemaphoreInfo(mime_semaphore);
387 return((
const MimeInfo *) element_info->value);
420#if defined(__cplusplus) || defined(c_plusplus)
424static int MimeInfoCompare(
const void *x,
const void *y)
432 if (strcasecmp((*p)->path,(*q)->path) == 0)
433 return(strcasecmp((*p)->type,(*q)->type));
434 return(strcasecmp((*p)->path,(*q)->path));
437#if defined(__cplusplus) || defined(c_plusplus)
441MagickExport
const MimeInfo **GetMimeInfoList(
const char *pattern,
453 assert(pattern != (
char *) NULL);
454 assert(number_aliases != (
size_t *) NULL);
455 if (IsEventLogging() != MagickFalse)
456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
458 if (IsMimeCacheInstantiated(exception) == MagickFalse)
460 aliases=(
const MimeInfo **) AcquireQuantumMemory((
size_t)
461 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
462 if (aliases == (
const MimeInfo **) NULL)
464 LockSemaphoreInfo(mime_semaphore);
465 p=GetHeadElementInLinkedList(mime_cache);
472 if ((mime_info->stealth == MagickFalse) &&
473 (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
474 aliases[i++]=mime_info;
477 UnlockSemaphoreInfo(mime_semaphore);
479 aliases=(
const MimeInfo **) RelinquishMagickMemory((
void *) aliases);
482 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeInfoCompare);
485 *number_aliases=(size_t) i;
519#if defined(__cplusplus) || defined(c_plusplus)
523static int MimeCompare(
const void *x,
const void *y)
531 return(strcasecmp(p,q));
534#if defined(__cplusplus) || defined(c_plusplus)
538MagickExport
char **GetMimeList(
const char *pattern,
550 assert(pattern != (
char *) NULL);
551 assert(number_aliases != (
size_t *) NULL);
552 if (IsEventLogging() != MagickFalse)
553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
555 if (IsMimeCacheInstantiated(exception) == MagickFalse)
556 return((
char **) NULL);
557 aliases=(
char **) AcquireQuantumMemory((
size_t)
558 GetNumberOfElementsInLinkedList(mime_cache)+1UL,
sizeof(*aliases));
559 if (aliases == (
char **) NULL)
560 return((
char **) NULL);
561 LockSemaphoreInfo(mime_semaphore);
562 p=GetHeadElementInLinkedList(mime_cache);
568 mime_info=(
const MimeInfo *) p->value;
569 if ((mime_info->stealth == MagickFalse) &&
570 (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
571 aliases[i++]=ConstantString(mime_info->type);
574 UnlockSemaphoreInfo(mime_semaphore);
576 aliases=(
char **) RelinquishMagickMemory(aliases);
579 qsort((
void *) aliases,(
size_t) i,
sizeof(*aliases),MimeCompare);
580 aliases[i]=(
char *) NULL;
582 *number_aliases=(size_t) i;
608MagickExport
const char *GetMimeDescription(
const MimeInfo *mime_info)
610 assert(mime_info != (
MimeInfo *) NULL);
611 assert(mime_info->signature == MagickCoreSignature);
612 if (IsEventLogging() != MagickFalse)
613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
614 return(mime_info->description);
639MagickExport
const char *GetMimeType(
const MimeInfo *mime_info)
641 assert(mime_info != (
MimeInfo *) NULL);
642 assert(mime_info->signature == MagickCoreSignature);
643 if (IsEventLogging() != MagickFalse)
644 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"...");
645 return(mime_info->type);
671static MagickBooleanType IsMimeCacheInstantiated(
ExceptionInfo *exception)
676 ActivateSemaphoreInfo(&mime_semaphore);
677 LockSemaphoreInfo(mime_semaphore);
679 mime_cache=AcquireMimeCache(MimeFilename,exception);
680 UnlockSemaphoreInfo(mime_semaphore);
682 return(mime_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
709MagickExport MagickBooleanType ListMimeInfo(FILE *file,
ExceptionInfo *exception)
726 if (file == (
const FILE *) NULL)
728 mime_info=GetMimeInfoList(
"*",&number_aliases,exception);
729 if (mime_info == (
const MimeInfo **) NULL)
732 path=(
const char *) NULL;
733 for (i=0; i < (ssize_t) number_aliases; i++)
735 if (mime_info[i]->stealth != MagickFalse)
737 if ((path == (
const char *) NULL) ||
738 (strcasecmp(path,mime_info[i]->path) != 0))
740 if (mime_info[i]->path != (
char *) NULL)
741 (
void) FormatLocaleFile(file,
"\nPath: %s\n\n",mime_info[i]->path);
742 (void) FormatLocaleFile(file,
"Type Description\n");
743 (void) FormatLocaleFile(file,
744 "-------------------------------------------------"
745 "------------------------------\n");
747 path=mime_info[i]->path;
748 (void) FormatLocaleFile(file,
"%s",mime_info[i]->type);
749 if (strlen(mime_info[i]->type) <= 25)
751 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
752 (
void) FormatLocaleFile(file,
" ");
756 (void) FormatLocaleFile(file,
"\n");
757 for (j=0; j <= 27; j++)
758 (
void) FormatLocaleFile(file,
" ");
760 if (mime_info[i]->description != (
char *) NULL)
761 (void) FormatLocaleFile(file,
"%s",mime_info[i]->description);
762 (void) FormatLocaleFile(file,
"\n");
765 mime_info=(
const MimeInfo **) RelinquishMagickMemory((
void *) mime_info);
769#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
800static MagickBooleanType LoadMimeCache(
LinkedListInfo *cache,
const char *xml,
801 const char *filename,
const size_t depth,
ExceptionInfo *exception)
820 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
821 "Loading mime map \"%s\" ...",filename);
822 if (xml == (
const char *) NULL)
824 mime_map=NewXMLTree(xml,exception);
828 include=GetXMLTreeChild(mime_map,
"include");
834 attribute=GetXMLTreeAttribute(include,
"file");
835 if (attribute != (
const char *) NULL)
837 if (depth > MagickMaxRecursionDepth)
838 (void) ThrowMagickException(exception,GetMagickModule(),
839 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",filename);
843 path[MagickPathExtent],
846 GetPathComponent(filename,HeadPath,path);
848 (void) ConcatenateMagickString(path,DirectorySeparator,
850 if (*attribute == *DirectorySeparator)
851 (void) CopyMagickString(path,attribute,MagickPathExtent);
853 (
void) ConcatenateMagickString(path,attribute,MagickPathExtent);
854 file_xml=FileToXML(path,~0UL);
855 if (file_xml != (
char *) NULL)
857 status&=(MagickStatusType) LoadMimeCache(cache,file_xml,path,
859 file_xml=DestroyString(file_xml);
863 include=GetNextXMLTreeTag(include);
865 mime=GetXMLTreeChild(mime_map,
"mime");
871 mime_info=(
MimeInfo *) AcquireCriticalMemory(
sizeof(*mime_info));
872 (void) memset(mime_info,0,
sizeof(*mime_info));
873 mime_info->path=ConstantString(filename);
874 mime_info->signature=MagickCoreSignature;
875 attribute=GetXMLTreeAttribute(mime,
"data-type");
876 if (attribute != (
const char *) NULL)
877 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
878 MagickTrue,attribute);
879 attribute=GetXMLTreeAttribute(mime,
"description");
880 if (attribute != (
const char *) NULL)
881 mime_info->description=ConstantString(attribute);
882 attribute=GetXMLTreeAttribute(mime,
"endian");
883 if (attribute != (
const char *) NULL)
884 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
885 MagickTrue,attribute);
886 attribute=GetXMLTreeAttribute(mime,
"magic");
887 if (attribute != (
const char *) NULL)
898 token=AcquireString(attribute);
899 (void) SubstituteString((
char **) &token,
"<",
"<");
900 (void) SubstituteString((
char **) &token,
"&",
"&");
901 (void) SubstituteString((
char **) &token,
""",
"\"");
902 mime_info->magic=(
unsigned char *) AcquireString(token);
904 for (p=token; *p !=
'\0'; )
909 if (isdigit((
int) ((
unsigned char) *p)) != 0)
914 *q++=(
unsigned char) strtol(p,&end,8);
921 case 'b': *q=
'\b';
break;
922 case 'f': *q=
'\f';
break;
923 case 'n': *q=
'\n';
break;
924 case 'r': *q=
'\r';
break;
925 case 't': *q=
'\t';
break;
926 case 'v': *q=
'\v';
break;
927 case 'a': *q=
'a';
break;
928 case '?': *q=
'\?';
break;
929 default: *q=(
unsigned char) (*p);
break;
936 *q++=(
unsigned char) (*p++);
939 token=DestroyString(token);
940 if (mime_info->data_type != StringData)
941 mime_info->value=(ssize_t) strtoul((
char *) mime_info->magic,
944 attribute=GetXMLTreeAttribute(mime,
"mask");
945 if (attribute != (
const char *) NULL)
946 mime_info->mask=(ssize_t) strtoul(attribute,(
char **) NULL,0);
947 attribute=GetXMLTreeAttribute(mime,
"offset");
948 if (attribute != (
const char *) NULL)
953 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
955 mime_info->extent=(size_t) strtol(c+1,(
char **) NULL,0);
957 attribute=GetXMLTreeAttribute(mime,
"pattern");
958 if (attribute != (
const char *) NULL)
959 mime_info->pattern=ConstantString(attribute);
960 attribute=GetXMLTreeAttribute(mime,
"priority");
961 if (attribute != (
const char *) NULL)
962 mime_info->priority=(ssize_t) strtol(attribute,(
char **) NULL,0);
963 attribute=GetXMLTreeAttribute(mime,
"stealth");
964 if (attribute != (
const char *) NULL)
965 mime_info->stealth=IsStringTrue(attribute);
966 attribute=GetXMLTreeAttribute(mime,
"type");
967 if (attribute != (
const char *) NULL)
968 mime_info->type=ConstantString(attribute);
969 status=AppendValueToLinkedList(cache,mime_info);
970 if (status == MagickFalse)
971 (void) ThrowMagickException(exception,GetMagickModule(),
972 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
973 mime=GetNextXMLTreeTag(mime);
975 mime_map=DestroyXMLTree(mime_map);
976 return(status != 0 ? MagickTrue : MagickFalse);
1005MagickExport
char *MagickToMime(
const char *magick)
1008 filename[MagickPathExtent],
1009 media[MagickPathExtent];
1017 (void) FormatLocaleString(filename,MagickPathExtent,
"file.%s",magick);
1018 LocaleLower(filename);
1019 exception=AcquireExceptionInfo();
1020 mime_info=GetMimeInfo(filename,(
unsigned char *)
" ",1,exception);
1021 exception=DestroyExceptionInfo(exception);
1022 if (mime_info != (
const MimeInfo *) NULL)
1023 return(ConstantString(GetMimeType(mime_info)));
1024 (void) FormatLocaleString(media,MagickPathExtent,
"image/x-%s",magick);
1025 LocaleLower(media+8);
1026 return(ConstantString(media));
1047MagickPrivate MagickBooleanType MimeComponentGenesis(
void)
1050 mime_semaphore=AcquireSemaphoreInfo();
1073static void *DestroyMimeElement(
void *mime_info)
1079 if (p->magic != (
unsigned char *) NULL)
1080 p->magic=(
unsigned char *) RelinquishMagickMemory(p->magic);
1081 if (p->pattern != (
char *) NULL)
1082 p->pattern=DestroyString(p->pattern);
1083 if (p->description != (
char *) NULL)
1084 p->description=DestroyString(p->description);
1085 if (p->type != (
char *) NULL)
1086 p->type=DestroyString(p->type);
1087 if (p->path != (
char *) NULL)
1088 p->path=DestroyString(p->path);
1089 p=(
MimeInfo *) RelinquishMagickMemory(p);
1090 return((
void *) NULL);
1093MagickPrivate
void MimeComponentTerminus(
void)
1096 ActivateSemaphoreInfo(&mime_semaphore);
1097 LockSemaphoreInfo(mime_semaphore);
1099 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1100 UnlockSemaphoreInfo(mime_semaphore);
1101 RelinquishSemaphoreInfo(&mime_semaphore);