Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                        M   M  IIIII  M   M  EEEEE                           %
      6 %                        MM MM    I    MM MM  E                               %
      7 %                        M M M    I    M M M  EEE                             %
      8 %                        M   M    I    M   M  E                               %
      9 %                        M   M  IIIII  M   M  EEEEE                           %
     10 %                                                                             %
     11 %                                                                             %
     12 %                          MagickCore Mime Methods                            %
     13 %                                                                             %
     14 %                              Software Design                                %
     15 %                                 July 2000                                   %
     16 %                                                                             %
     17 %                                                                             %
     18 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     19 %  dedicated to making software imaging solutions freely available.           %
     20 %                                                                             %
     21 %  You may not use this file except in compliance with the License.  You may  %
     22 %  obtain a copy of the License at                                            %
     23 %                                                                             %
     24 %    http://www.imagemagick.org/MagicksToolkit/script/license.php             %
     25 %                                                                             %
     26 %  Unless required by applicable law or agreed to in writing, software        %
     27 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     28 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     29 %  See the License for the specific language governing permissions and        %
     30 %  limitations under the License.                                             %
     31 %                                                                             %
     32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     33 %
     34 %
     35 */
     36 
     37 /*
     39   Include declarations.
     40 */
     41 #include "MagickCore/studio.h"
     42 #include "MagickCore/blob.h"
     43 #include "MagickCore/client.h"
     44 #include "MagickCore/configure.h"
     45 #include "MagickCore/configure-private.h"
     46 #include "MagickCore/exception.h"
     47 #include "MagickCore/exception-private.h"
     48 #include "MagickCore/linked-list.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"
     60 
     61 /*
     63   Define declarations.
     64 */
     65 #define MimeFilename  "mime.xml"
     66 
     67 /*
     69   Typedef declaration.
     70 */
     71 struct _MimeInfo
     72 {
     73   char
     74     *path,
     75     *type,
     76     *description,
     77     *pattern;
     78 
     79   ssize_t
     80     priority;
     81 
     82   MagickOffsetType
     83     offset;
     84 
     85   size_t
     86     extent;
     87 
     88   DataType
     89     data_type;
     90 
     91   ssize_t
     92     mask,
     93     value;
     94 
     95   EndianType
     96     endian;
     97 
     98   size_t
     99     length;
    100 
    101   unsigned char
    102     *magic;
    103 
    104   MagickBooleanType
    105     stealth;
    106 
    107   size_t
    108     signature;
    109 };
    110 
    111 /*
    113   Static declarations.
    114 */
    115 static const char
    116   *MimeMap = (char *)
    117     "<?xml version=\"1.0\"?>"
    118     "<mimemap>"
    119     "</mimemap>";
    120 
    121 static LinkedListInfo
    122   *mime_cache = (LinkedListInfo *) NULL;
    123 
    124 static SemaphoreInfo
    125   *mime_semaphore = (SemaphoreInfo *) NULL;
    126 
    127 /*
    129   Forward declarations.
    130 */
    131 static MagickBooleanType
    132   IsMimeCacheInstantiated(ExceptionInfo *),
    133   LoadMimeCache(LinkedListInfo *,const char *,const char *,const size_t,
    134     ExceptionInfo *);
    135 
    136 /*
    138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    139 %                                                                             %
    140 %                                                                             %
    141 %                                                                             %
    142 %  A c q u i r e M i m e C a c h e                                            %
    143 %                                                                             %
    144 %                                                                             %
    145 %                                                                             %
    146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    147 %
    148 %  AcquireMimeCache() caches one or more magic configurations which provides
    149 %  a mapping between magic attributes and a magic name.
    150 %
    151 %  The format of the AcquireMimeCache method is:
    152 %
    153 %      LinkedListInfo *AcquireMimeCache(const char *filename,
    154 %        ExceptionInfo *exception)
    155 %
    156 %  A description of each parameter follows:
    157 %
    158 %    o filename: the font file name.
    159 %
    160 %    o exception: return any errors or warnings in this structure.
    161 %
    162 */
    163 MagickExport LinkedListInfo *AcquireMimeCache(const char *filename,
    164   ExceptionInfo *exception)
    165 {
    166   LinkedListInfo
    167     *cache;
    168 
    169   MagickStatusType
    170     status;
    171 
    172   cache=NewLinkedList(0);
    173   if (cache == (LinkedListInfo *) NULL)
    174     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    175   status=MagickTrue;
    176 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    177   {
    178     const StringInfo
    179       *option;
    180 
    181     LinkedListInfo
    182       *options;
    183 
    184     options=GetConfigureOptions(filename,exception);
    185     option=(const StringInfo *) GetNextValueInLinkedList(options);
    186     while (option != (const StringInfo *) NULL)
    187     {
    188       status&=LoadMimeCache(cache,(const char *)
    189         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
    190       option=(const StringInfo *) GetNextValueInLinkedList(options);
    191     }
    192     options=DestroyConfigureOptions(options);
    193   }
    194 #endif
    195   if (IsLinkedListEmpty(cache) != MagickFalse)
    196     status&=LoadMimeCache(cache,MimeMap,"built-in",0,exception);
    197   return(cache);
    198 }
    199 
    200 /*
    202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    203 %                                                                             %
    204 %                                                                             %
    205 %                                                                             %
    206 +   G e t M i m e I n f o                                                     %
    207 %                                                                             %
    208 %                                                                             %
    209 %                                                                             %
    210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    211 %
    212 %  GetMimeInfo() attempts to classify the content to identify which mime type
    213 %  is associated with the content, if any.
    214 %
    215 %  The format of the GetMimeInfo method is:
    216 %
    217 %      const MimeInfo *GetMimeInfo(const char *filename,
    218 %        const unsigned char *magic,const size_t length,
    219 %        ExceptionInfo *exception)
    220 %
    221 %  A description of each parameter follows:
    222 %
    223 %    o filename:  If we cannot not classify the string, we attempt to classify
    224 %      based on the filename (e.g. *.pdf returns application/pdf).
    225 %
    226 %    o magic: A binary string generally representing the first few characters
    227 %      of the image file or blob.
    228 %
    229 %    o length: the length of the binary signature.
    230 %
    231 %    o exception: return any errors or warnings in this structure.
    232 %
    233 */
    234 MagickExport const MimeInfo *GetMimeInfo(const char *filename,
    235   const unsigned char *magic,const size_t length,ExceptionInfo *exception)
    236 {
    237   const MimeInfo
    238     *mime_info;
    239 
    240   EndianType
    241     endian;
    242 
    243   register const MimeInfo
    244     *p;
    245 
    246   register const unsigned char
    247     *q;
    248 
    249   register ssize_t
    250     i;
    251 
    252   ssize_t
    253     value;
    254 
    255   unsigned long
    256     lsb_first;
    257 
    258   assert(exception != (ExceptionInfo *) NULL);
    259   if (IsMimeCacheInstantiated(exception) == MagickFalse)
    260     return((const MimeInfo *) NULL);
    261   /*
    262     Search for mime tag.
    263   */
    264   mime_info=(const MimeInfo *) NULL;
    265   lsb_first=1;
    266   LockSemaphoreInfo(mime_semaphore);
    267   ResetLinkedListIterator(mime_cache);
    268   p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    269   if ((magic == (const unsigned char *) NULL) || (length == 0))
    270     {
    271       UnlockSemaphoreInfo(mime_semaphore);
    272       return(p);
    273     }
    274   while (p != (const MimeInfo *) NULL)
    275   {
    276     assert(p->offset >= 0);
    277     if (mime_info != (const MimeInfo *) NULL)
    278       if (p->priority > mime_info->priority)
    279         {
    280           p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    281           continue;
    282         }
    283     if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
    284       {
    285         if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
    286           mime_info=p;
    287         p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    288         continue;
    289       }
    290     switch (p->data_type)
    291     {
    292       case ByteData:
    293       {
    294         if ((size_t) (p->offset+4) > length)
    295           break;
    296         q=magic+p->offset;
    297         value=(ssize_t) (*q++);
    298         if (p->mask == 0)
    299           {
    300             if (p->value == value)
    301               mime_info=p;
    302           }
    303         else
    304           {
    305             if ((p->value & p->mask) == value)
    306               mime_info=p;
    307           }
    308         break;
    309       }
    310       case ShortData:
    311       {
    312         if ((size_t) (p->offset+4) > length)
    313           break;
    314         q=magic+p->offset;
    315         endian=p->endian;
    316         if (p->endian == UndefinedEndian)
    317           endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
    318         if (endian == LSBEndian)
    319           {
    320             value=(ssize_t) (*q++);
    321             value|=(*q++) << 8;
    322           }
    323         else
    324           {
    325             value=(ssize_t) (*q++) << 8;
    326             value|=(*q++);
    327           }
    328         if (p->mask == 0)
    329           {
    330             if (p->value == value)
    331               mime_info=p;
    332           }
    333         else
    334           {
    335             if ((p->value & p->mask) == value)
    336               mime_info=p;
    337           }
    338         break;
    339       }
    340       case LongData:
    341       {
    342         if ((size_t) (p->offset+4) > length)
    343           break;
    344         q=magic+p->offset;
    345         endian=p->endian;
    346         if (p->endian == UndefinedEndian)
    347           endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
    348         if (endian == LSBEndian)
    349           {
    350             value=(ssize_t) (*q++);
    351             value|=((ssize_t) *q++) << 8;
    352             value|=((ssize_t) *q++) << 16;
    353             value|=((ssize_t) *q++) << 24;
    354           }
    355         else
    356           {
    357             value=(ssize_t) (*q++) << 24;
    358             value|=((ssize_t) *q++) << 16;
    359             value|=((ssize_t) *q++) << 8;
    360             value|=((ssize_t) *q++);
    361           }
    362         if (p->mask == 0)
    363           {
    364             if (p->value == value)
    365               mime_info=p;
    366           }
    367         else
    368           {
    369             if ((p->value & p->mask) == value)
    370               mime_info=p;
    371           }
    372         break;
    373       }
    374       case StringData:
    375       default:
    376       {
    377         for (i=0; i <= (ssize_t) p->extent; i++)
    378         {
    379           if ((size_t) (p->offset+i+p->length) > length)
    380             break;
    381           if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
    382             {
    383               mime_info=p;
    384               break;
    385             }
    386         }
    387         break;
    388       }
    389     }
    390     p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    391   }
    392   if (mime_info != (const MimeInfo *) NULL)
    393     (void) InsertValueInLinkedList(mime_cache,0,
    394       RemoveElementByValueFromLinkedList(mime_cache,p));
    395   UnlockSemaphoreInfo(mime_semaphore);
    396   return(mime_info);
    397 }
    398 
    399 /*
    401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    402 %                                                                             %
    403 %                                                                             %
    404 %                                                                             %
    405 %   G e t M i m e I n f o L i s t                                             %
    406 %                                                                             %
    407 %                                                                             %
    408 %                                                                             %
    409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    410 %
    411 %  GetMimeInfoList() returns any image aliases that match the specified
    412 %  pattern.
    413 %
    414 %  The magic of the GetMimeInfoList function is:
    415 %
    416 %      const MimeInfo **GetMimeInfoList(const char *pattern,
    417 %        size_t *number_aliases,ExceptionInfo *exception)
    418 %
    419 %  A description of each parameter follows:
    420 %
    421 %    o pattern: Specifies a pointer to a text string containing a pattern.
    422 %
    423 %    o number_aliases:  This integer returns the number of magics in the
    424 %      list.
    425 %
    426 %    o exception: return any errors or warnings in this structure.
    427 %
    428 */
    429 
    430 #if defined(__cplusplus) || defined(c_plusplus)
    431 extern "C" {
    432 #endif
    433 
    434 static int MimeInfoCompare(const void *x,const void *y)
    435 {
    436   const MimeInfo
    437     **p,
    438     **q;
    439 
    440   p=(const MimeInfo **) x,
    441   q=(const MimeInfo **) y;
    442   if (strcasecmp((*p)->path,(*q)->path) == 0)
    443     return(strcasecmp((*p)->type,(*q)->type));
    444   return(strcasecmp((*p)->path,(*q)->path));
    445 }
    446 
    447 #if defined(__cplusplus) || defined(c_plusplus)
    448 }
    449 #endif
    450 
    451 MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
    452   size_t *number_aliases,ExceptionInfo *exception)
    453 {
    454   const MimeInfo
    455     **aliases;
    456 
    457   register const MimeInfo
    458     *p;
    459 
    460   register ssize_t
    461     i;
    462 
    463   /*
    464     Allocate mime list.
    465   */
    466   assert(pattern != (char *) NULL);
    467   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    468   assert(number_aliases != (size_t *) NULL);
    469   *number_aliases=0;
    470   p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
    471   if (p == (const MimeInfo *) NULL)
    472     return((const MimeInfo **) NULL);
    473   aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
    474     GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
    475   if (aliases == (const MimeInfo **) NULL)
    476     return((const MimeInfo **) NULL);
    477   /*
    478     Generate mime list.
    479   */
    480   LockSemaphoreInfo(mime_semaphore);
    481   ResetLinkedListIterator(mime_cache);
    482   p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    483   for (i=0; p != (const MimeInfo *) NULL; )
    484   {
    485     if ((p->stealth == MagickFalse) &&
    486         (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
    487       aliases[i++]=p;
    488     p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    489   }
    490   UnlockSemaphoreInfo(mime_semaphore);
    491   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
    492   aliases[i]=(MimeInfo *) NULL;
    493   *number_aliases=(size_t) i;
    494   return(aliases);
    495 }
    496 
    497 /*
    499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    500 %                                                                             %
    501 %                                                                             %
    502 %                                                                             %
    503 %   G e t M i m e L i s t                                                     %
    504 %                                                                             %
    505 %                                                                             %
    506 %                                                                             %
    507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    508 %
    509 %  GetMimeList() returns any image format alias that matches the specified
    510 %  pattern.
    511 %
    512 %  The format of the GetMimeList function is:
    513 %
    514 %      char **GetMimeList(const char *pattern,size_t *number_aliases,
    515 %        ExceptionInfo *exception)
    516 %
    517 %  A description of each parameter follows:
    518 %
    519 %    o pattern: Specifies a pointer to a text string containing a pattern.
    520 %
    521 %    o number_aliases:  This integer returns the number of image format aliases
    522 %      in the list.
    523 %
    524 %    o exception: return any errors or warnings in this structure.
    525 %
    526 */
    527 
    528 #if defined(__cplusplus) || defined(c_plusplus)
    529 extern "C" {
    530 #endif
    531 
    532 static int MimeCompare(const void *x,const void *y)
    533 {
    534   register char
    535     *p,
    536     *q;
    537 
    538   p=(char *) x;
    539   q=(char *) y;
    540   return(strcasecmp(p,q));
    541 }
    542 
    543 #if defined(__cplusplus) || defined(c_plusplus)
    544 }
    545 #endif
    546 
    547 MagickExport char **GetMimeList(const char *pattern,
    548   size_t *number_aliases,ExceptionInfo *exception)
    549 {
    550   char
    551     **aliases;
    552 
    553   register const MimeInfo
    554     *p;
    555 
    556   register ssize_t
    557     i;
    558 
    559   /*
    560     Allocate configure list.
    561   */
    562   assert(pattern != (char *) NULL);
    563   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    564   assert(number_aliases != (size_t *) NULL);
    565   *number_aliases=0;
    566   p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
    567   if (p == (const MimeInfo *) NULL)
    568     return((char **) NULL);
    569   aliases=(char **) AcquireQuantumMemory((size_t)
    570     GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
    571   if (aliases == (char **) NULL)
    572     return((char **) NULL);
    573   LockSemaphoreInfo(mime_semaphore);
    574   ResetLinkedListIterator(mime_cache);
    575   p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    576   for (i=0; p != (const MimeInfo *) NULL; )
    577   {
    578     if ((p->stealth == MagickFalse) &&
    579         (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
    580       aliases[i++]=ConstantString(p->type);
    581     p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
    582   }
    583   UnlockSemaphoreInfo(mime_semaphore);
    584   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
    585   aliases[i]=(char *) NULL;
    586   *number_aliases=(size_t) i;
    587   return(aliases);
    588 }
    589 
    590 /*
    592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    593 %                                                                             %
    594 %                                                                             %
    595 %                                                                             %
    596 %   G e t M i m e D e s c r i p t i o n                                       %
    597 %                                                                             %
    598 %                                                                             %
    599 %                                                                             %
    600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    601 %
    602 %  GetMimeDescription() returns the mime type description.
    603 %
    604 %  The format of the GetMimeDescription method is:
    605 %
    606 %      const char *GetMimeDescription(const MimeInfo *mime_info)
    607 %
    608 %  A description of each parameter follows:
    609 %
    610 %    o mime_info:  The magic info.
    611 %
    612 */
    613 MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
    614 {
    615   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
    616   assert(mime_info != (MimeInfo *) NULL);
    617   assert(mime_info->signature == MagickCoreSignature);
    618   return(mime_info->description);
    619 }
    620 
    621 /*
    623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    624 %                                                                             %
    625 %                                                                             %
    626 %                                                                             %
    627 %   G e t M i m e T y p e                                                     %
    628 %                                                                             %
    629 %                                                                             %
    630 %                                                                             %
    631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    632 %
    633 %  GetMimeType() returns the mime type.
    634 %
    635 %  The format of the GetMimeType method is:
    636 %
    637 %      const char *GetMimeType(const MimeInfo *mime_info)
    638 %
    639 %  A description of each parameter follows:
    640 %
    641 %    o mime_info:  The magic info.
    642 %
    643 */
    644 MagickExport const char *GetMimeType(const MimeInfo *mime_info)
    645 {
    646   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
    647   assert(mime_info != (MimeInfo *) NULL);
    648   assert(mime_info->signature == MagickCoreSignature);
    649   return(mime_info->type);
    650 }
    651 
    652 /*
    654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    655 %                                                                             %
    656 %                                                                             %
    657 %                                                                             %
    658 +   I s M i m e C a c h e I n s t a n t i a t e d                             %
    659 %                                                                             %
    660 %                                                                             %
    661 %                                                                             %
    662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    663 %
    664 %  IsMimeCacheInstantiated() determines if the mime list is instantiated.  If
    665 %  not, it instantiates the list and returns it.
    666 %
    667 %  The format of the IsMimeInstantiated method is:
    668 %
    669 %      MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
    670 %
    671 %  A description of each parameter follows.
    672 %
    673 %    o exception: return any errors or warnings in this structure.
    674 %
    675 */
    676 static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
    677 {
    678   if (mime_cache == (LinkedListInfo *) NULL)
    679     {
    680       if (mime_semaphore == (SemaphoreInfo *) NULL)
    681         ActivateSemaphoreInfo(&mime_semaphore);
    682       LockSemaphoreInfo(mime_semaphore);
    683       if (mime_cache == (LinkedListInfo *) NULL)
    684         mime_cache=AcquireMimeCache(MimeFilename,exception);
    685       UnlockSemaphoreInfo(mime_semaphore);
    686     }
    687   return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
    688 }
    689 
    690 /*
    692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    693 %                                                                             %
    694 %                                                                             %
    695 %                                                                             %
    696 %  L i s t M i m e I n f o                                                    %
    697 %                                                                             %
    698 %                                                                             %
    699 %                                                                             %
    700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    701 %
    702 %  ListMimeInfo() lists the magic info to a file.
    703 %
    704 %  The format of the ListMimeInfo method is:
    705 %
    706 %      MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
    707 %
    708 %  A description of each parameter follows.
    709 %
    710 %    o file:  An pointer to a FILE.
    711 %
    712 %    o exception: return any errors or warnings in this structure.
    713 %
    714 */
    715 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
    716 {
    717   const char
    718     *path;
    719 
    720   const MimeInfo
    721     **mime_info;
    722 
    723   register ssize_t
    724     i;
    725 
    726   size_t
    727     number_aliases;
    728 
    729   ssize_t
    730     j;
    731 
    732   if (file == (const FILE *) NULL)
    733     file=stdout;
    734   mime_info=GetMimeInfoList("*",&number_aliases,exception);
    735   if (mime_info == (const MimeInfo **) NULL)
    736     return(MagickFalse);
    737   j=0;
    738   path=(const char *) NULL;
    739   for (i=0; i < (ssize_t) number_aliases; i++)
    740   {
    741     if (mime_info[i]->stealth != MagickFalse)
    742       continue;
    743     if ((path == (const char *) NULL) ||
    744         (strcasecmp(path,mime_info[i]->path) != 0))
    745       {
    746         if (mime_info[i]->path != (char *) NULL)
    747           (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
    748         (void) FormatLocaleFile(file,"Type                   Description\n");
    749         (void) FormatLocaleFile(file,
    750           "-------------------------------------------------"
    751           "------------------------------\n");
    752       }
    753     path=mime_info[i]->path;
    754     (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
    755     if (strlen(mime_info[i]->type) <= 25)
    756       {
    757         for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
    758           (void) FormatLocaleFile(file," ");
    759       }
    760     else
    761       {
    762         (void) FormatLocaleFile(file,"\n");
    763         for (j=0; j <= 27; j++)
    764           (void) FormatLocaleFile(file," ");
    765       }
    766     if (mime_info[i]->description != (char *) NULL)
    767       (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
    768     (void) FormatLocaleFile(file,"\n");
    769   }
    770   (void) fflush(file);
    771   mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
    772   return(MagickTrue);
    773 }
    774 
    775 /*
    777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    778 %                                                                             %
    779 %                                                                             %
    780 %                                                                             %
    781 +   L o a d M i m e C a c h e                                                 %
    782 %                                                                             %
    783 %                                                                             %
    784 %                                                                             %
    785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    786 %
    787 %  LoadMimeCache() loads the mime configurations which provides a mapping
    788 %  between mime attributes and a mime name.
    789 %
    790 %  The format of the LoadMimeCache method is:
    791 %
    792 %      MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
    793 %        const char *filename,const size_t depth,ExceptionInfo *exception)
    794 %
    795 %  A description of each parameter follows:
    796 %
    797 %    o xml:  The mime list in XML format.
    798 %
    799 %    o filename:  The mime list filename.
    800 %
    801 %    o depth: depth of <include /> statements.
    802 %
    803 %    o exception: return any errors or warnings in this structure.
    804 %
    805 */
    806 static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
    807   const char *filename,const size_t depth,ExceptionInfo *exception)
    808 {
    809   const char
    810     *attribute;
    811 
    812   MimeInfo
    813     *mime_info = (MimeInfo *) NULL;
    814 
    815   MagickStatusType
    816     status;
    817 
    818   XMLTreeInfo
    819     *mime,
    820     *mime_map,
    821     *include;
    822 
    823   /*
    824     Load the mime map file.
    825   */
    826   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
    827     "Loading mime map \"%s\" ...",filename);
    828   if (xml == (const char *) NULL)
    829     return(MagickFalse);
    830   mime_map=NewXMLTree(xml,exception);
    831   if (mime_map == (XMLTreeInfo *) NULL)
    832     return(MagickFalse);
    833   status=MagickTrue;
    834   include=GetXMLTreeChild(mime_map,"include");
    835   while (include != (XMLTreeInfo *) NULL)
    836   {
    837     /*
    838       Process include element.
    839     */
    840     attribute=GetXMLTreeAttribute(include,"file");
    841     if (attribute != (const char *) NULL)
    842       {
    843         if (depth > 200)
    844           (void) ThrowMagickException(exception,GetMagickModule(),
    845             ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
    846         else
    847           {
    848             char
    849               path[MagickPathExtent],
    850               *file_xml;
    851 
    852             GetPathComponent(filename,HeadPath,path);
    853             if (*path != '\0')
    854               (void) ConcatenateMagickString(path,DirectorySeparator,
    855                 MagickPathExtent);
    856             if (*attribute == *DirectorySeparator)
    857               (void) CopyMagickString(path,attribute,MagickPathExtent);
    858             else
    859               (void) ConcatenateMagickString(path,attribute,MagickPathExtent);
    860             file_xml=FileToXML(path,~0UL);
    861             if (file_xml != (char *) NULL)
    862               {
    863                 status&=LoadMimeCache(cache,file_xml,path,depth+1,exception);
    864                 file_xml=DestroyString(file_xml);
    865               }
    866           }
    867       }
    868     include=GetNextXMLTreeTag(include);
    869   }
    870   mime=GetXMLTreeChild(mime_map,"mime");
    871   while (mime != (XMLTreeInfo *) NULL)
    872   {
    873     /*
    874       Process mime element.
    875     */
    876     mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
    877     if (mime_info == (MimeInfo *) NULL)
    878       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    879     (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
    880     mime_info->path=ConstantString(filename);
    881     mime_info->signature=MagickCoreSignature;
    882     attribute=GetXMLTreeAttribute(mime,"data-type");
    883     if (attribute != (const char *) NULL)
    884       mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
    885         MagickTrue,attribute);
    886     attribute=GetXMLTreeAttribute(mime,"description");
    887     if (attribute != (const char *) NULL)
    888       mime_info->description=ConstantString(attribute);
    889     attribute=GetXMLTreeAttribute(mime,"endian");
    890     if (attribute != (const char *) NULL)
    891       mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
    892         MagickTrue,attribute);
    893     attribute=GetXMLTreeAttribute(mime,"magic");
    894     if (attribute != (const char *) NULL)
    895       {
    896         char
    897           *token;
    898 
    899         const char
    900           *p;
    901 
    902         register unsigned char
    903           *q;
    904 
    905         token=AcquireString(attribute);
    906         (void) SubstituteString((char **) &token,"&lt;","<");
    907         (void) SubstituteString((char **) &token,"&amp;","&");
    908         (void) SubstituteString((char **) &token,"&quot;","\"");
    909         mime_info->magic=(unsigned char *) AcquireString(token);
    910         q=mime_info->magic;
    911         for (p=token; *p != '\0'; )
    912         {
    913           if (*p == '\\')
    914             {
    915               p++;
    916               if (isdigit((int) ((unsigned char) *p)) != 0)
    917                 {
    918                   char
    919                     *end;
    920 
    921                   *q++=(unsigned char) strtol(p,&end,8);
    922                   p+=(end-p);
    923                   mime_info->length++;
    924                   continue;
    925                 }
    926               switch (*p)
    927               {
    928                 case 'b': *q='\b'; break;
    929                 case 'f': *q='\f'; break;
    930                 case 'n': *q='\n'; break;
    931                 case 'r': *q='\r'; break;
    932                 case 't': *q='\t'; break;
    933                 case 'v': *q='\v'; break;
    934                 case 'a': *q='a'; break;
    935                 case '?': *q='\?'; break;
    936                 default: *q=(unsigned char) (*p); break;
    937               }
    938               p++;
    939               q++;
    940               mime_info->length++;
    941               continue;
    942             }
    943           *q++=(unsigned char) (*p++);
    944           mime_info->length++;
    945         }
    946         token=DestroyString(token);
    947         if (mime_info->data_type != StringData)
    948           mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
    949             (char **) NULL,0);
    950       }
    951     attribute=GetXMLTreeAttribute(mime,"mask");
    952     if (attribute != (const char *) NULL)
    953       mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
    954     attribute=GetXMLTreeAttribute(mime,"offset");
    955     if (attribute != (const char *) NULL)
    956       {
    957         char
    958           *c;
    959 
    960         mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
    961         if (*c == ':')
    962           mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
    963       }
    964     attribute=GetXMLTreeAttribute(mime,"pattern");
    965     if (attribute != (const char *) NULL)
    966       mime_info->pattern=ConstantString(attribute);
    967     attribute=GetXMLTreeAttribute(mime,"priority");
    968     if (attribute != (const char *) NULL)
    969       mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
    970     attribute=GetXMLTreeAttribute(mime,"stealth");
    971     if (attribute != (const char *) NULL)
    972       mime_info->stealth=IsStringTrue(attribute);
    973     attribute=GetXMLTreeAttribute(mime,"type");
    974     if (attribute != (const char *) NULL)
    975       mime_info->type=ConstantString(attribute);
    976     status=AppendValueToLinkedList(cache,mime_info);
    977     if (status == MagickFalse)
    978       (void) ThrowMagickException(exception,GetMagickModule(),
    979         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
    980     mime=GetNextXMLTreeTag(mime);
    981   }
    982   mime_map=DestroyXMLTree(mime_map);
    983   return(status != 0 ? MagickTrue : MagickFalse);
    984 }
    985 
    986 /*
    988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    989 %                                                                             %
    990 %                                                                             %
    991 %                                                                             %
    992 +  M a g i c k T o M i m e                                                    %
    993 %                                                                             %
    994 %                                                                             %
    995 %                                                                             %
    996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    997 %
    998 %  MagickToMime() returns the officially registered (or de facto) MIME
    999 %  media-type corresponding to a magick string.  If there is no registered
   1000 %  media-type, then the string "image/x-magick" (all lower case) is returned.
   1001 %  The returned string must be deallocated by the user.
   1002 %
   1003 %  The format of the MagickToMime method is:
   1004 %
   1005 %      char *MagickToMime(const char *magick)
   1006 %
   1007 %  A description of each parameter follows.
   1008 %
   1009 %   o  magick:  ImageMagick format specification "magick" tag.
   1010 %
   1011 */
   1012 MagickExport char *MagickToMime(const char *magick)
   1013 {
   1014   char
   1015     filename[MagickPathExtent],
   1016     media[MagickPathExtent];
   1017 
   1018   const MimeInfo
   1019     *mime_info;
   1020 
   1021   ExceptionInfo
   1022     *exception;
   1023 
   1024   (void) FormatLocaleString(filename,MagickPathExtent,"file.%s",magick);
   1025   LocaleLower(filename);
   1026   exception=AcquireExceptionInfo();
   1027   mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
   1028   exception=DestroyExceptionInfo(exception);
   1029   if (mime_info != (const MimeInfo *) NULL)
   1030     return(ConstantString(GetMimeType(mime_info)));
   1031   (void) FormatLocaleString(media,MagickPathExtent,"image/x-%s",magick);
   1032   LocaleLower(media+8);
   1033   return(ConstantString(media));
   1034 }
   1035 
   1036 /*
   1038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1039 %                                                                             %
   1040 %                                                                             %
   1041 %                                                                             %
   1042 +   M i m e C o m p o n e n t G e n e s i s                                   %
   1043 %                                                                             %
   1044 %                                                                             %
   1045 %                                                                             %
   1046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1047 %
   1048 %  MimeComponentGenesis() instantiates the mime component.
   1049 %
   1050 %  The format of the MimeComponentGenesis method is:
   1051 %
   1052 %      MagickBooleanType MimeComponentGenesis(void)
   1053 %
   1054 */
   1055 MagickPrivate MagickBooleanType MimeComponentGenesis(void)
   1056 {
   1057   if (mime_semaphore == (SemaphoreInfo *) NULL)
   1058     mime_semaphore=AcquireSemaphoreInfo();
   1059   return(MagickTrue);
   1060 }
   1061 
   1062 /*
   1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1065 %                                                                             %
   1066 %                                                                             %
   1067 %                                                                             %
   1068 +   M i m e C o m p o n e n t T e r m i n u s                                 %
   1069 %                                                                             %
   1070 %                                                                             %
   1071 %                                                                             %
   1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1073 %
   1074 %  MimeComponentTerminus() destroys the mime component.
   1075 %
   1076 %  The format of the MimeComponentTerminus method is:
   1077 %
   1078 %      MimeComponentTerminus(void)
   1079 %
   1080 */
   1081 
   1082 static void *DestroyMimeElement(void *mime_info)
   1083 {
   1084   register MimeInfo
   1085     *p;
   1086 
   1087   p=(MimeInfo *) mime_info;
   1088   if (p->magic != (unsigned char *) NULL)
   1089     p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
   1090   if (p->pattern != (char *) NULL)
   1091     p->pattern=DestroyString(p->pattern);
   1092   if (p->description != (char *) NULL)
   1093     p->description=DestroyString(p->description);
   1094   if (p->type != (char *) NULL)
   1095     p->type=DestroyString(p->type);
   1096   if (p->path != (char *) NULL)
   1097     p->path=DestroyString(p->path);
   1098   p=(MimeInfo *) RelinquishMagickMemory(p);
   1099   return((void *) NULL);
   1100 }
   1101 
   1102 MagickPrivate void MimeComponentTerminus(void)
   1103 {
   1104   if (mime_semaphore == (SemaphoreInfo *) NULL)
   1105     ActivateSemaphoreInfo(&mime_semaphore);
   1106   LockSemaphoreInfo(mime_semaphore);
   1107   if (mime_cache != (LinkedListInfo *) NULL)
   1108     mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
   1109   UnlockSemaphoreInfo(mime_semaphore);
   1110   RelinquishSemaphoreInfo(&mime_semaphore);
   1111 }
   1112