You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1085 lines
36 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% M M IIIII M M EEEEE %
% MM MM I MM MM E %
% M M M I M M M EEE %
% M M I M M E %
% M M IIIII M M EEEEE %
% %
% %
% MagickCore Mime Methods %
% %
% Software Design %
% July 2000 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/client.h"
#include "MagickCore/configure.h"
#include "MagickCore/configure-private.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/linked-list.h"
#include "MagickCore/memory_.h"
#include "MagickCore/mime.h"
#include "MagickCore/mime-private.h"
#include "MagickCore/option.h"
#include "MagickCore/semaphore.h"
#include "MagickCore/string_.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
#include "MagickCore/xml-tree.h"
#include "MagickCore/xml-tree-private.h"
/*
Define declarations.
*/
#define MimeFilename "mime.xml"
/*
Typedef declaration.
*/
struct _MimeInfo
{
char
*path,
*type,
*description,
*pattern;
ssize_t
priority;
MagickOffsetType
offset;
size_t
extent;
DataType
data_type;
ssize_t
mask,
value;
EndianType
endian;
size_t
length;
unsigned char
*magic;
MagickBooleanType
stealth;
size_t
signature;
};
/*
Static declarations.
*/
static LinkedListInfo
*mime_cache = (LinkedListInfo *) NULL;
static SemaphoreInfo
*mime_semaphore = (SemaphoreInfo *) NULL;
/*
Forward declarations.
*/
static MagickBooleanType
IsMimeCacheInstantiated(ExceptionInfo *);
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
static MagickBooleanType
LoadMimeCache(LinkedListInfo *,const char *,const char *,const size_t,
ExceptionInfo *);
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% A c q u i r e M i m e C a c h e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireMimeCache() caches one or more magic configurations which provides
% a mapping between magic attributes and a magic name.
%
% The format of the AcquireMimeCache method is:
%
% LinkedListInfo *AcquireMimeCache(const char *filename,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o filename: the font file name.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport LinkedListInfo *AcquireMimeCache(const char *filename,
ExceptionInfo *exception)
{
LinkedListInfo
*cache;
cache=NewLinkedList(0);
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
{
const StringInfo
*option;
LinkedListInfo
*options;
options=GetConfigureOptions(filename,exception);
option=(const StringInfo *) GetNextValueInLinkedList(options);
while (option != (const StringInfo *) NULL)
{
(void) LoadMimeCache(cache,(const char *)
GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
option=(const StringInfo *) GetNextValueInLinkedList(options);
}
options=DestroyConfigureOptions(options);
}
#endif
return(cache);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t M i m e I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMimeInfo() attempts to classify the content to identify which mime type
% is associated with the content, if any.
%
% The format of the GetMimeInfo method is:
%
% const MimeInfo *GetMimeInfo(const char *filename,
% const unsigned char *magic,const size_t length,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o filename: If we cannot not classify the string, we attempt to classify
% based on the filename (e.g. *.pdf returns application/pdf).
%
% o magic: A binary string generally representing the first few characters
% of the image file or blob.
%
% o length: the length of the binary signature.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport const MimeInfo *GetMimeInfo(const char *filename,
const unsigned char *magic,const size_t length,ExceptionInfo *exception)
{
const MimeInfo
*mime_info;
EndianType
endian;
const MimeInfo
*p;
const unsigned char
*q;
ssize_t
i;
ssize_t
value;
unsigned long
lsb_first;
assert(exception != (ExceptionInfo *) NULL);
if (IsMimeCacheInstantiated(exception) == MagickFalse)
return((const MimeInfo *) NULL);
/*
Search for mime tag.
*/
mime_info=(const MimeInfo *) NULL;
lsb_first=1;
LockSemaphoreInfo(mime_semaphore);
ResetLinkedListIterator(mime_cache);
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
if ((magic == (const unsigned char *) NULL) || (length == 0))
{
UnlockSemaphoreInfo(mime_semaphore);
return(p);
}
while (p != (const MimeInfo *) NULL)
{
assert(p->offset >= 0);
if (mime_info != (const MimeInfo *) NULL)
if (p->priority > mime_info->priority)
{
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
continue;
}
if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
{
if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
mime_info=p;
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
continue;
}
switch (p->data_type)
{
case ByteData:
{
if ((size_t) (p->offset+4) > length)
break;
q=magic+p->offset;
value=(ssize_t) (*q++);
if (p->mask == 0)
{
if (p->value == value)
mime_info=p;
}
else
{
if ((p->value & p->mask) == value)
mime_info=p;
}
break;
}
case ShortData:
{
if ((size_t) (p->offset+4) > length)
break;
q=magic+p->offset;
endian=p->endian;
if (p->endian == UndefinedEndian)
endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
if (endian == LSBEndian)
{
value=(ssize_t) (*q++);
value|=(*q++) << 8;
}
else
{
value=(ssize_t) (*q++) << 8;
value|=(*q++);
}
if (p->mask == 0)
{
if (p->value == value)
mime_info=p;
}
else
{
if ((p->value & p->mask) == value)
mime_info=p;
}
break;
}
case LongData:
{
if ((size_t) (p->offset+4) > length)
break;
q=magic+p->offset;
endian=p->endian;
if (p->endian == UndefinedEndian)
endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
if (endian == LSBEndian)
{
value=(ssize_t) (*q++);
value|=((ssize_t) *q++) << 8;
value|=((ssize_t) *q++) << 16;
value|=((ssize_t) *q++) << 24;
}
else
{
value=(ssize_t) (*q++) << 24;
value|=((ssize_t) *q++) << 16;
value|=((ssize_t) *q++) << 8;
value|=((ssize_t) *q++);
}
if (p->mask == 0)
{
if (p->value == value)
mime_info=p;
}
else
{
if ((p->value & p->mask) == value)
mime_info=p;
}
break;
}
case StringData:
default:
{
for (i=0; i <= (ssize_t) p->extent; i++)
{
if ((size_t) (p->offset+i+p->length) > length)
break;
if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
{
mime_info=p;
break;
}
}
break;
}
}
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
}
if (mime_info != (const MimeInfo *) NULL)
(void) InsertValueInLinkedList(mime_cache,0,
RemoveElementByValueFromLinkedList(mime_cache,p));
UnlockSemaphoreInfo(mime_semaphore);
return(mime_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t M i m e I n f o L i s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMimeInfoList() returns any image aliases that match the specified
% pattern.
%
% The magic of the GetMimeInfoList function is:
%
% const MimeInfo **GetMimeInfoList(const char *pattern,
% size_t *number_aliases,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o pattern: Specifies a pointer to a text string containing a pattern.
%
% o number_aliases: This integer returns the number of magics in the
% list.
%
% o exception: return any errors or warnings in this structure.
%
*/
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static int MimeInfoCompare(const void *x,const void *y)
{
const MimeInfo
**p,
**q;
p=(const MimeInfo **) x,
q=(const MimeInfo **) y;
if (strcasecmp((*p)->path,(*q)->path) == 0)
return(strcasecmp((*p)->type,(*q)->type));
return(strcasecmp((*p)->path,(*q)->path));
}
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
size_t *number_aliases,ExceptionInfo *exception)
{
const MimeInfo
**aliases;
const MimeInfo
*p;
ssize_t
i;
/*
Allocate mime list.
*/
assert(pattern != (char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
assert(number_aliases != (size_t *) NULL);
*number_aliases=0;
p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
if (p == (const MimeInfo *) NULL)
return((const MimeInfo **) NULL);
aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
if (aliases == (const MimeInfo **) NULL)
return((const MimeInfo **) NULL);
/*
Generate mime list.
*/
LockSemaphoreInfo(mime_semaphore);
ResetLinkedListIterator(mime_cache);
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
for (i=0; p != (const MimeInfo *) NULL; )
{
if ((p->stealth == MagickFalse) &&
(GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
aliases[i++]=p;
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
}
UnlockSemaphoreInfo(mime_semaphore);
qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
aliases[i]=(MimeInfo *) NULL;
*number_aliases=(size_t) i;
return(aliases);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t M i m e L i s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMimeList() returns any image format alias that matches the specified
% pattern.
%
% The format of the GetMimeList function is:
%
% char **GetMimeList(const char *pattern,size_t *number_aliases,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o pattern: Specifies a pointer to a text string containing a pattern.
%
% o number_aliases: This integer returns the number of image format aliases
% in the list.
%
% o exception: return any errors or warnings in this structure.
%
*/
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static int MimeCompare(const void *x,const void *y)
{
char
*p,
*q;
p=(char *) x;
q=(char *) y;
return(strcasecmp(p,q));
}
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
MagickExport char **GetMimeList(const char *pattern,
size_t *number_aliases,ExceptionInfo *exception)
{
char
**aliases;
const MimeInfo
*p;
ssize_t
i;
/*
Allocate configure list.
*/
assert(pattern != (char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
assert(number_aliases != (size_t *) NULL);
*number_aliases=0;
p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
if (p == (const MimeInfo *) NULL)
return((char **) NULL);
aliases=(char **) AcquireQuantumMemory((size_t)
GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
if (aliases == (char **) NULL)
return((char **) NULL);
LockSemaphoreInfo(mime_semaphore);
ResetLinkedListIterator(mime_cache);
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
for (i=0; p != (const MimeInfo *) NULL; )
{
if ((p->stealth == MagickFalse) &&
(GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
aliases[i++]=ConstantString(p->type);
p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
}
UnlockSemaphoreInfo(mime_semaphore);
qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
aliases[i]=(char *) NULL;
*number_aliases=(size_t) i;
return(aliases);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t M i m e D e s c r i p t i o n %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMimeDescription() returns the mime type description.
%
% The format of the GetMimeDescription method is:
%
% const char *GetMimeDescription(const MimeInfo *mime_info)
%
% A description of each parameter follows:
%
% o mime_info: The magic info.
%
*/
MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
{
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(mime_info != (MimeInfo *) NULL);
assert(mime_info->signature == MagickCoreSignature);
return(mime_info->description);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t M i m e T y p e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMimeType() returns the mime type.
%
% The format of the GetMimeType method is:
%
% const char *GetMimeType(const MimeInfo *mime_info)
%
% A description of each parameter follows:
%
% o mime_info: The magic info.
%
*/
MagickExport const char *GetMimeType(const MimeInfo *mime_info)
{
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(mime_info != (MimeInfo *) NULL);
assert(mime_info->signature == MagickCoreSignature);
return(mime_info->type);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I s M i m e C a c h e I n s t a n t i a t e d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsMimeCacheInstantiated() determines if the mime list is instantiated. If
% not, it instantiates the list and returns it.
%
% The format of the IsMimeInstantiated method is:
%
% MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
%
% A description of each parameter follows.
%
% o exception: return any errors or warnings in this structure.
%
*/
static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
{
if (mime_cache == (LinkedListInfo *) NULL)
{
if (mime_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&mime_semaphore);
LockSemaphoreInfo(mime_semaphore);
if (mime_cache == (LinkedListInfo *) NULL)
mime_cache=AcquireMimeCache(MimeFilename,exception);
UnlockSemaphoreInfo(mime_semaphore);
}
return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% L i s t M i m e I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ListMimeInfo() lists the magic info to a file.
%
% The format of the ListMimeInfo method is:
%
% MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
%
% A description of each parameter follows.
%
% o file: An pointer to a FILE.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
{
const char
*path;
const MimeInfo
**mime_info;
ssize_t
i;
size_t
number_aliases;
ssize_t
j;
if (file == (const FILE *) NULL)
file=stdout;
mime_info=GetMimeInfoList("*",&number_aliases,exception);
if (mime_info == (const MimeInfo **) NULL)
return(MagickFalse);
j=0;
path=(const char *) NULL;
for (i=0; i < (ssize_t) number_aliases; i++)
{
if (mime_info[i]->stealth != MagickFalse)
continue;
if ((path == (const char *) NULL) ||
(strcasecmp(path,mime_info[i]->path) != 0))
{
if (mime_info[i]->path != (char *) NULL)
(void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
(void) FormatLocaleFile(file,"Type Description\n");
(void) FormatLocaleFile(file,
"-------------------------------------------------"
"------------------------------\n");
}
path=mime_info[i]->path;
(void) FormatLocaleFile(file,"%s",mime_info[i]->type);
if (strlen(mime_info[i]->type) <= 25)
{
for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
(void) FormatLocaleFile(file," ");
}
else
{
(void) FormatLocaleFile(file,"\n");
for (j=0; j <= 27; j++)
(void) FormatLocaleFile(file," ");
}
if (mime_info[i]->description != (char *) NULL)
(void) FormatLocaleFile(file,"%s",mime_info[i]->description);
(void) FormatLocaleFile(file,"\n");
}
(void) fflush(file);
mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
return(MagickTrue);
}
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ L o a d M i m e C a c h e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% LoadMimeCache() loads the mime configurations which provides a mapping
% between mime attributes and a mime name.
%
% The format of the LoadMimeCache method is:
%
% MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
% const char *filename,const size_t depth,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o xml: The mime list in XML format.
%
% o filename: The mime list filename.
%
% o depth: depth of <include /> statements.
%
% o exception: return any errors or warnings in this structure.
%
*/
static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
const char *filename,const size_t depth,ExceptionInfo *exception)
{
const char
*attribute;
MimeInfo
*mime_info = (MimeInfo *) NULL;
MagickStatusType
status;
XMLTreeInfo
*mime,
*mime_map,
*include;
/*
Load the mime map file.
*/
(void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
"Loading mime map \"%s\" ...",filename);
if (xml == (const char *) NULL)
return(MagickFalse);
mime_map=NewXMLTree(xml,exception);
if (mime_map == (XMLTreeInfo *) NULL)
return(MagickFalse);
status=MagickTrue;
include=GetXMLTreeChild(mime_map,"include");
while (include != (XMLTreeInfo *) NULL)
{
/*
Process include element.
*/
attribute=GetXMLTreeAttribute(include,"file");
if (attribute != (const char *) NULL)
{
if (depth > MagickMaxRecursionDepth)
(void) ThrowMagickException(exception,GetMagickModule(),
ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
else
{
char
path[MagickPathExtent],
*file_xml;
GetPathComponent(filename,HeadPath,path);
if (*path != '\0')
(void) ConcatenateMagickString(path,DirectorySeparator,
MagickPathExtent);
if (*attribute == *DirectorySeparator)
(void) CopyMagickString(path,attribute,MagickPathExtent);
else
(void) ConcatenateMagickString(path,attribute,MagickPathExtent);
file_xml=FileToXML(path,~0UL);
if (file_xml != (char *) NULL)
{
status&=LoadMimeCache(cache,file_xml,path,depth+1,exception);
file_xml=DestroyString(file_xml);
}
}
}
include=GetNextXMLTreeTag(include);
}
mime=GetXMLTreeChild(mime_map,"mime");
while (mime != (XMLTreeInfo *) NULL)
{
/*
Process mime element.
*/
mime_info=(MimeInfo *) AcquireCriticalMemory(sizeof(*mime_info));
(void) memset(mime_info,0,sizeof(*mime_info));
mime_info->path=ConstantString(filename);
mime_info->signature=MagickCoreSignature;
attribute=GetXMLTreeAttribute(mime,"data-type");
if (attribute != (const char *) NULL)
mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
MagickTrue,attribute);
attribute=GetXMLTreeAttribute(mime,"description");
if (attribute != (const char *) NULL)
mime_info->description=ConstantString(attribute);
attribute=GetXMLTreeAttribute(mime,"endian");
if (attribute != (const char *) NULL)
mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
MagickTrue,attribute);
attribute=GetXMLTreeAttribute(mime,"magic");
if (attribute != (const char *) NULL)
{
char
*token;
const char
*p;
unsigned char
*q;
token=AcquireString(attribute);
(void) SubstituteString((char **) &token,"&lt;","<");
(void) SubstituteString((char **) &token,"&amp;","&");
(void) SubstituteString((char **) &token,"&quot;","\"");
mime_info->magic=(unsigned char *) AcquireString(token);
q=mime_info->magic;
for (p=token; *p != '\0'; )
{
if (*p == '\\')
{
p++;
if (isdigit((int) ((unsigned char) *p)) != 0)
{
char
*end;
*q++=(unsigned char) strtol(p,&end,8);
p+=(end-p);
mime_info->length++;
continue;
}
switch (*p)
{
case 'b': *q='\b'; break;
case 'f': *q='\f'; break;
case 'n': *q='\n'; break;
case 'r': *q='\r'; break;
case 't': *q='\t'; break;
case 'v': *q='\v'; break;
case 'a': *q='a'; break;
case '?': *q='\?'; break;
default: *q=(unsigned char) (*p); break;
}
p++;
q++;
mime_info->length++;
continue;
}
*q++=(unsigned char) (*p++);
mime_info->length++;
}
token=DestroyString(token);
if (mime_info->data_type != StringData)
mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
(char **) NULL,0);
}
attribute=GetXMLTreeAttribute(mime,"mask");
if (attribute != (const char *) NULL)
mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
attribute=GetXMLTreeAttribute(mime,"offset");
if (attribute != (const char *) NULL)
{
char
*c;
mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
if (*c == ':')
mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
}
attribute=GetXMLTreeAttribute(mime,"pattern");
if (attribute != (const char *) NULL)
mime_info->pattern=ConstantString(attribute);
attribute=GetXMLTreeAttribute(mime,"priority");
if (attribute != (const char *) NULL)
mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
attribute=GetXMLTreeAttribute(mime,"stealth");
if (attribute != (const char *) NULL)
mime_info->stealth=IsStringTrue(attribute);
attribute=GetXMLTreeAttribute(mime,"type");
if (attribute != (const char *) NULL)
mime_info->type=ConstantString(attribute);
status=AppendValueToLinkedList(cache,mime_info);
if (status == MagickFalse)
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
mime=GetNextXMLTreeTag(mime);
}
mime_map=DestroyXMLTree(mime_map);
return(status != 0 ? MagickTrue : MagickFalse);
}
#endif
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ M a g i c k T o M i m e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MagickToMime() returns the officially registered (or de facto) MIME
% media-type corresponding to a magick string. If there is no registered
% media-type, then the string "image/x-magick" (all lower case) is returned.
% The returned string must be deallocated by the user.
%
% The format of the MagickToMime method is:
%
% char *MagickToMime(const char *magick)
%
% A description of each parameter follows.
%
% o magick: ImageMagick format specification "magick" tag.
%
*/
MagickExport char *MagickToMime(const char *magick)
{
char
filename[MagickPathExtent],
media[MagickPathExtent];
const MimeInfo
*mime_info;
ExceptionInfo
*exception;
(void) FormatLocaleString(filename,MagickPathExtent,"file.%s",magick);
LocaleLower(filename);
exception=AcquireExceptionInfo();
mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
exception=DestroyExceptionInfo(exception);
if (mime_info != (const MimeInfo *) NULL)
return(ConstantString(GetMimeType(mime_info)));
(void) FormatLocaleString(media,MagickPathExtent,"image/x-%s",magick);
LocaleLower(media+8);
return(ConstantString(media));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ M i m e C o m p o n e n t G e n e s i s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MimeComponentGenesis() instantiates the mime component.
%
% The format of the MimeComponentGenesis method is:
%
% MagickBooleanType MimeComponentGenesis(void)
%
*/
MagickPrivate MagickBooleanType MimeComponentGenesis(void)
{
if (mime_semaphore == (SemaphoreInfo *) NULL)
mime_semaphore=AcquireSemaphoreInfo();
return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ M i m e C o m p o n e n t T e r m i n u s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% MimeComponentTerminus() destroys the mime component.
%
% The format of the MimeComponentTerminus method is:
%
% MimeComponentTerminus(void)
%
*/
static void *DestroyMimeElement(void *mime_info)
{
MimeInfo
*p;
p=(MimeInfo *) mime_info;
if (p->magic != (unsigned char *) NULL)
p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
if (p->pattern != (char *) NULL)
p->pattern=DestroyString(p->pattern);
if (p->description != (char *) NULL)
p->description=DestroyString(p->description);
if (p->type != (char *) NULL)
p->type=DestroyString(p->type);
if (p->path != (char *) NULL)
p->path=DestroyString(p->path);
p=(MimeInfo *) RelinquishMagickMemory(p);
return((void *) NULL);
}
MagickPrivate void MimeComponentTerminus(void)
{
if (mime_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&mime_semaphore);
LockSemaphoreInfo(mime_semaphore);
if (mime_cache != (LinkedListInfo *) NULL)
mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
UnlockSemaphoreInfo(mime_semaphore);
RelinquishSemaphoreInfo(&mime_semaphore);
}