Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                    M   M   AAA    GGGG  IIIII   CCCC                        %
      7 %                    MM MM  A   A  G        I    C                            %
      8 %                    M M M  AAAAA  G GGG    I    C                            %
      9 %                    M   M  A   A  G   G    I    C                            %
     10 %                    M   M  A   A   GGGG  IIIII   CCCC                        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                      MagickCore Image Magic Methods                         %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                              Bob Friesenhahn                                %
     17 %                                 July 2000                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 
     39 /*
     41   Include declarations.
     42 */
     43 #include "MagickCore/studio.h"
     44 #include "MagickCore/blob.h"
     45 #include "MagickCore/client.h"
     46 #include "MagickCore/configure.h"
     47 #include "MagickCore/configure-private.h"
     48 #include "MagickCore/exception.h"
     49 #include "MagickCore/exception-private.h"
     50 #include "MagickCore/linked-list.h"
     51 #include "MagickCore/magic.h"
     52 #include "MagickCore/magic-private.h"
     53 #include "MagickCore/memory_.h"
     54 #include "MagickCore/semaphore.h"
     55 #include "MagickCore/string_.h"
     56 #include "MagickCore/string-private.h"
     57 #include "MagickCore/token.h"
     58 #include "MagickCore/utility.h"
     59 #include "MagickCore/utility-private.h"
     60 #include "MagickCore/xml-tree.h"
     61 #include "MagickCore/xml-tree-private.h"
     62 
     63 /*
     65   Define declarations.
     66 */
     67 #define MagicFilename  "magic.xml"
     68 #define MagicPattern(magic)  (const unsigned char *) (magic), sizeof(magic)-1
     69 
     70 /*
     72   Typedef declarations.
     73 */
     74 typedef struct _MagicMapInfo
     75 {
     76   const char
     77     *name;
     78 
     79   const MagickOffsetType
     80     offset;
     81 
     82   const unsigned char
     83     *magic;
     84 
     85   const size_t
     86     length;
     87 } MagicMapInfo;
     88 
     89 /*
     91   Static declarations.
     92 */
     93 static const MagicMapInfo
     94   MagicMap[] =
     95   {
     96     { "8BIMWTEXT", 0, MagicPattern("8\000B\000I\000M\000#") },
     97     { "8BIMTEXT", 0, MagicPattern("8BIM#") },
     98     { "8BIM", 0, MagicPattern("8BIM") },
     99     { "BMP", 0, MagicPattern("BA") },
    100     { "BMP", 0, MagicPattern("BM") },
    101     { "BMP", 0, MagicPattern("CI") },
    102     { "BMP", 0, MagicPattern("CP") },
    103     { "BMP", 0, MagicPattern("IC") },
    104     { "PICT", 0, MagicPattern("PICT") },
    105     { "BMP", 0, MagicPattern("PI") },
    106     { "CALS", 21, MagicPattern("version: MIL-STD-1840") },
    107     { "CALS", 0, MagicPattern("srcdocid:") },
    108     { "CALS", 9, MagicPattern("srcdocid:") },
    109     { "CALS", 8, MagicPattern("rorient:") },
    110     { "CGM", 0, MagicPattern("BEGMF") },
    111     { "CIN", 0, MagicPattern("\200\052\137\327") },
    112     { "CRW", 0, MagicPattern("II\x1a\x00\x00\x00HEAPCCDR") },
    113     { "DCM", 128, MagicPattern("DICM") },
    114     { "DCX", 0, MagicPattern("\261\150\336\72") },
    115     { "DIB", 0, MagicPattern("\050\000") },
    116     { "DDS", 0, MagicPattern("DDS ") },
    117     { "DJVU", 0, MagicPattern("AT&TFORM") },
    118     { "DOT", 0, MagicPattern("digraph") },
    119     { "DPX", 0, MagicPattern("SDPX") },
    120     { "DPX", 0, MagicPattern("XPDS") },
    121     { "EMF", 40, MagicPattern("\040\105\115\106\000\000\001\000") },
    122     { "EPT", 0, MagicPattern("\305\320\323\306") },
    123     { "EXR", 0, MagicPattern("\166\057\061\001") },
    124     { "FAX", 0, MagicPattern("DFAX") },
    125     { "FIG", 0, MagicPattern("#FIG") },
    126     { "FITS", 0, MagicPattern("IT0") },
    127     { "FITS", 0, MagicPattern("SIMPLE") },
    128     { "FLIF", 0, MagicPattern("FLIF") },
    129     { "GIF", 0, MagicPattern("GIF8") },
    130     { "GPLT", 0, MagicPattern("#!/usr/local/bin/gnuplot") },
    131     { "HDF", 1, MagicPattern("HDF") },
    132     { "HDR", 0, MagicPattern("#?RADIANCE") },
    133     { "HDR", 0, MagicPattern("#?RGBE") },
    134     { "HPGL", 0, MagicPattern("IN;") },
    135     { "HTML", 1, MagicPattern("HTML") },
    136     { "HTML", 1, MagicPattern("html") },
    137     { "ILBM", 8, MagicPattern("ILBM") },
    138     { "IPTCWTEXT", 0, MagicPattern("\062\000#\000\060\000=\000\042\000&\000#\000\060\000;\000&\000#\000\062\000;\000\042\000") },
    139     { "IPTCTEXT", 0, MagicPattern("2#0=\042�\042") },
    140     { "IPTC", 0, MagicPattern("\034\002") },
    141     { "JNG", 0, MagicPattern("\213JNG\r\n\032\n") },
    142     { "JPEG", 0, MagicPattern("\377\330\377") },
    143     { "J2K", 0, MagicPattern("\xff\x4f\xff\x51") },
    144     { "JPC", 0, MagicPattern("\x0d\x0a\x87\x0a") },
    145     { "JP2", 0, MagicPattern("\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a") },
    146     { "MAT", 0, MagicPattern("MATLAB 5.0 MAT-file,") },
    147     { "MIFF", 0, MagicPattern("Id=ImageMagick") },
    148     { "MIFF", 0, MagicPattern("id=ImageMagick") },
    149     { "MNG", 0, MagicPattern("\212MNG\r\n\032\n") },
    150     { "MPC", 0, MagicPattern("id=MagickCache") },
    151     { "MPEG", 0, MagicPattern("\000\000\001\263") },
    152     { "MRW", 0, MagicPattern("\x00MRM") },
    153     { "ORF", 0, MagicPattern("IIRO\x08\x00\x00\x00") },
    154     { "PCD", 2048, MagicPattern("PCD_") },
    155     { "PCL", 0, MagicPattern("\033E\033") },
    156     { "PCX", 0, MagicPattern("\012\002") },
    157     { "PCX", 0, MagicPattern("\012\005") },
    158     { "PDB", 60, MagicPattern("vIMGView") },
    159     { "PDF", 0, MagicPattern("%PDF-") },
    160     { "PES", 0, MagicPattern("#PES") },
    161     { "PFA", 0, MagicPattern("%!PS-AdobeFont-1.0") },
    162     { "PFB", 6, MagicPattern("%!PS-AdobeFont-1.0") },
    163     { "PGX", 0, MagicPattern("\050\107\020\115\046") },
    164     { "PICT", 522, MagicPattern("\000\021\002\377\014\000") },
    165     { "PNG", 0, MagicPattern("\211PNG\r\n\032\n") },
    166     { "PBM", 0, MagicPattern("P1") },
    167     { "PGM", 0, MagicPattern("P2") },
    168     { "PPM", 0, MagicPattern("P3") },
    169     { "PBM", 0, MagicPattern("P4") },
    170     { "PGM", 0, MagicPattern("P5") },
    171     { "PPM", 0, MagicPattern("P6") },
    172     { "PAM", 0, MagicPattern("P7") },
    173     { "PFM", 0, MagicPattern("PF") },
    174     { "PFM", 0, MagicPattern("Pf") },
    175     { "PS", 0, MagicPattern("%!") },
    176     { "PS", 0, MagicPattern("\004%!") },
    177     { "PS", 0, MagicPattern("\305\320\323\306") },
    178     { "PSB", 0, MagicPattern("8BPB") },
    179     { "PSD", 0, MagicPattern("8BPS") },
    180     { "PWP", 0, MagicPattern("SFW95") },
    181     { "RAF", 0, MagicPattern("FUJIFILMCCD-RAW ") },
    182     { "RLE", 0, MagicPattern("\122\314") },
    183     { "SCT", 0, MagicPattern("CT") },
    184     { "SFW", 0, MagicPattern("SFW94") },
    185     { "SGI", 0, MagicPattern("\001\332") },
    186     { "SUN", 0, MagicPattern("\131\246\152\225") },
    187     { "SVG", 1, MagicPattern("?XML") },
    188     { "SVG", 1, MagicPattern("?xml") },
    189     { "TIFF", 0, MagicPattern("\115\115\000\052") },
    190     { "TIFF", 0, MagicPattern("\111\111\052\000") },
    191     { "TIFF64", 0, MagicPattern("\115\115\000\053\000\010\000\000") },
    192     { "TIFF64", 0, MagicPattern("\111\111\053\000\010\000\000\000") },
    193     { "TTF", 0, MagicPattern("\000\001\000\000\000") },
    194     { "TXT", 0, MagicPattern("# ImageMagick pixel enumeration:") },
    195     { "VICAR", 0, MagicPattern("LBLSIZE") },
    196     { "VICAR", 0, MagicPattern("NJPL1I") },
    197     { "VIFF", 0, MagicPattern("\253\001") },
    198     { "WEBP", 8, MagicPattern("WEBP") },
    199     { "WMF", 0, MagicPattern("\327\315\306\232") },
    200     { "WMF", 0, MagicPattern("\001\000\011\000") },
    201     { "WPG", 0, MagicPattern("\377WPC") },
    202     { "XBM", 0, MagicPattern("#define") },
    203     { "XCF", 0, MagicPattern("gimp xcf") },
    204     { "XEF", 0, MagicPattern("FOVb") },
    205     { "XPM", 1, MagicPattern("* XPM *") },
    206     { "XWD", 4, MagicPattern("\007\000\000") },
    207     { "XWD", 5, MagicPattern("\000\000\007") }
    208  };
    209 
    210 static LinkedListInfo
    211   *magic_cache = (LinkedListInfo *) NULL;
    212 
    213 static SemaphoreInfo
    214   *magic_semaphore = (SemaphoreInfo *) NULL;
    215 
    216 /*
    218   Forward declarations.
    219 */
    220 static MagickBooleanType
    221   IsMagicCacheInstantiated(ExceptionInfo *),
    222   LoadMagicCache(LinkedListInfo *,const char *,const char *,const size_t,
    223     ExceptionInfo *);
    224 
    225 /*
    227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    228 %                                                                             %
    229 %                                                                             %
    230 %                                                                             %
    231 %  A c q u i r e M a g i c L i s t s                                          %
    232 %                                                                             %
    233 %                                                                             %
    234 %                                                                             %
    235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    236 %
    237 %  AcquireMagicCache() caches one or more magic configurations which provides a
    238 %  mapping between magic attributes and a magic name.
    239 %
    240 %  The format of the AcquireMagicCache method is:
    241 %
    242 %      LinkedListInfo *AcquireMagicCache(const char *filename,
    243 %        ExceptionInfo *exception)
    244 %
    245 %  A description of each parameter follows:
    246 %
    247 %    o filename: the font file name.
    248 %
    249 %    o exception: return any errors or warnings in this structure.
    250 %
    251 */
    252 static int CompareMagickInfoSize(const void *a,const void *b)
    253 {
    254   MagicInfo
    255     *ma,
    256     *mb;
    257 
    258   ma=(MagicInfo *) a;
    259   mb=(MagicInfo *) b;
    260 
    261   if (ma->offset != mb->offset)
    262     return((int) (ma->offset-mb->offset));
    263 
    264   return((int) (mb->length-ma->length));
    265 }
    266 
    267 static LinkedListInfo *AcquireMagicCache(const char *filename,
    268   ExceptionInfo *exception)
    269 {
    270   LinkedListInfo
    271     *cache;
    272 
    273   MagickStatusType
    274     status;
    275 
    276   register ssize_t
    277     i;
    278 
    279   /*
    280     Load external magic map.
    281   */
    282   cache=NewLinkedList(0);
    283   if (cache == (LinkedListInfo *) NULL)
    284     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    285   status=MagickTrue;
    286 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    287   {
    288     char
    289       path[MagickPathExtent];
    290 
    291     const StringInfo
    292       *option;
    293 
    294     LinkedListInfo
    295       *options;
    296 
    297     *path='\0';
    298     options=GetConfigureOptions(filename,exception);
    299     option=(const StringInfo *) GetNextValueInLinkedList(options);
    300     while (option != (const StringInfo *) NULL)
    301     {
    302       (void) CopyMagickString(path,GetStringInfoPath(option),MagickPathExtent);
    303       status&=LoadMagicCache(cache,(const char *)
    304         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
    305       option=(const StringInfo *) GetNextValueInLinkedList(options);
    306     }
    307     options=DestroyConfigureOptions(options);
    308   }
    309 #endif
    310   /*
    311     Load built-in magic map.
    312   */
    313   for (i=0; i < (ssize_t) (sizeof(MagicMap)/sizeof(*MagicMap)); i++)
    314   {
    315     MagicInfo
    316       *magic_info;
    317 
    318     register const MagicMapInfo
    319       *p;
    320 
    321     p=MagicMap+i;
    322     magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
    323     if (magic_info == (MagicInfo *) NULL)
    324       {
    325         (void) ThrowMagickException(exception,GetMagickModule(),
    326           ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
    327         continue;
    328       }
    329     (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
    330     magic_info->path=(char *) "[built-in]";
    331     magic_info->name=(char *) p->name;
    332     magic_info->offset=p->offset;
    333     magic_info->target=(char *) p->magic;
    334     magic_info->magic=(unsigned char *) p->magic;
    335     magic_info->length=p->length;
    336     magic_info->exempt=MagickTrue;
    337     magic_info->signature=MagickCoreSignature;
    338     status&=InsertValueInSortedLinkedList(cache,CompareMagickInfoSize,
    339       NULL,magic_info);
    340     if (status == MagickFalse)
    341       (void) ThrowMagickException(exception,GetMagickModule(),
    342         ResourceLimitError,"MemoryAllocationFailed","`%s'",magic_info->name);
    343   }
    344   return(cache);
    345 }
    346 
    347 /*
    349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    350 %                                                                             %
    351 %                                                                             %
    352 %                                                                             %
    353 %   G e t M a g i c I n f o                                                   %
    354 %                                                                             %
    355 %                                                                             %
    356 %                                                                             %
    357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    358 %
    359 %  GetMagicInfo() searches the magic list for the specified name and if found
    360 %  returns attributes for that magic.
    361 %
    362 %  The format of the GetMagicInfo method is:
    363 %
    364 %      const MagicInfo *GetMagicInfo(const unsigned char *magic,
    365 %        const size_t length,ExceptionInfo *exception)
    366 %
    367 %  A description of each parameter follows:
    368 %
    369 %    o magic: A binary string generally representing the first few characters
    370 %      of the image file or blob.
    371 %
    372 %    o length: the length of the binary signature.
    373 %
    374 %    o exception: return any errors or warnings in this structure.
    375 %
    376 */
    377 MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic,
    378   const size_t length,ExceptionInfo *exception)
    379 {
    380   register const MagicInfo
    381     *p;
    382 
    383   assert(exception != (ExceptionInfo *) NULL);
    384   if (IsMagicCacheInstantiated(exception) == MagickFalse)
    385     return((const MagicInfo *) NULL);
    386   /*
    387     Search for magic tag.
    388   */
    389   LockSemaphoreInfo(magic_semaphore);
    390   ResetLinkedListIterator(magic_cache);
    391   p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    392   if (magic == (const unsigned char *) NULL)
    393     {
    394       UnlockSemaphoreInfo(magic_semaphore);
    395       return(p);
    396     }
    397   while (p != (const MagicInfo *) NULL)
    398   {
    399     assert(p->offset >= 0);
    400     if (((size_t) (p->offset+p->length) <= length) &&
    401         (memcmp(magic+p->offset,p->magic,p->length) == 0))
    402       break;
    403     p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    404   }
    405   if (p != (const MagicInfo *) NULL)
    406     (void) InsertValueInLinkedList(magic_cache,0,
    407       RemoveElementByValueFromLinkedList(magic_cache,p));
    408   UnlockSemaphoreInfo(magic_semaphore);
    409   return(p);
    410 }
    411 
    412 /*
    413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    414 %                                                                             %
    415 %                                                                             %
    416 %                                                                             %
    417 %   G e t M a g i c P a t t e r n E x t e n t                                 %
    418 %                                                                             %
    419 %                                                                             %
    420 %                                                                             %
    421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    422 %
    423 %  GetMagicPatternExtent() returns the the extent of the buffer that is
    424 %  required to check all the MagickInfos. It returns zero if the list is empty.
    425 %
    426 %  The format of the GetMagicPatternExtent method is:
    427 %
    428 %      size_t GetMagicPatternExtent(ExceptionInfo *exception)
    429 %
    430 %  A description of each parameter follows:
    431 %
    432 %    o exception: return any errors or warnings in this structure.
    433 %
    434 */
    435 MagickExport size_t GetMagicPatternExtent(ExceptionInfo *exception)
    436 {
    437   register const MagicInfo
    438     *p;
    439 
    440   size_t
    441     magickSize,
    442     max;
    443 
    444   static size_t
    445     size=0;
    446 
    447   assert(exception != (ExceptionInfo *) NULL);
    448   if ((size != 0) || (IsMagicCacheInstantiated(exception) == MagickFalse))
    449     return(size);
    450   LockSemaphoreInfo(magic_semaphore);
    451   ResetLinkedListIterator(magic_cache);
    452   max=0;
    453   p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    454   while (p != (const MagicInfo *) NULL)
    455   {
    456     magickSize=(size_t) (p->offset+p->length);
    457     if (magickSize > max)
    458       max=magickSize;
    459     p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    460   }
    461   size=max;
    462   UnlockSemaphoreInfo(magic_semaphore);
    463   return(size);
    464 }
    465 
    466 /*
    468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    469 %                                                                             %
    470 %                                                                             %
    471 %                                                                             %
    472 %   G e t M a g i c I n f o L i s t                                           %
    473 %                                                                             %
    474 %                                                                             %
    475 %                                                                             %
    476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    477 %
    478 %  GetMagicInfoList() returns any image aliases that match the specified
    479 %  pattern.
    480 %
    481 %  The magic of the GetMagicInfoList function is:
    482 %
    483 %      const MagicInfo **GetMagicInfoList(const char *pattern,
    484 %        size_t *number_aliases,ExceptionInfo *exception)
    485 %
    486 %  A description of each parameter follows:
    487 %
    488 %    o pattern: Specifies a pointer to a text string containing a pattern.
    489 %
    490 %    o number_aliases:  This integer returns the number of aliases in the list.
    491 %
    492 %    o exception: return any errors or warnings in this structure.
    493 %
    494 */
    495 
    496 #if defined(__cplusplus) || defined(c_plusplus)
    497 extern "C" {
    498 #endif
    499 
    500 static int MagicInfoCompare(const void *x,const void *y)
    501 {
    502   const MagicInfo
    503     **p,
    504     **q;
    505 
    506   p=(const MagicInfo **) x,
    507   q=(const MagicInfo **) y;
    508   if (LocaleCompare((*p)->path,(*q)->path) == 0)
    509     return(LocaleCompare((*p)->name,(*q)->name));
    510   return(LocaleCompare((*p)->path,(*q)->path));
    511 }
    512 
    513 #if defined(__cplusplus) || defined(c_plusplus)
    514 }
    515 #endif
    516 
    517 MagickExport const MagicInfo **GetMagicInfoList(const char *pattern,
    518   size_t *number_aliases,ExceptionInfo *exception)
    519 {
    520   const MagicInfo
    521     **aliases;
    522 
    523   register const MagicInfo
    524     *p;
    525 
    526   register ssize_t
    527     i;
    528 
    529   /*
    530     Allocate magic list.
    531   */
    532   assert(pattern != (char *) NULL);
    533   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    534   assert(number_aliases != (size_t *) NULL);
    535   *number_aliases=0;
    536   p=GetMagicInfo((const unsigned char *) NULL,0,exception);
    537   if (p == (const MagicInfo *) NULL)
    538     return((const MagicInfo **) NULL);
    539   aliases=(const MagicInfo **) AcquireQuantumMemory((size_t)
    540     GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
    541   if (aliases == (const MagicInfo **) NULL)
    542     return((const MagicInfo **) NULL);
    543   /*
    544     Generate magic list.
    545   */
    546   LockSemaphoreInfo(magic_semaphore);
    547   ResetLinkedListIterator(magic_cache);
    548   p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    549   for (i=0; p != (const MagicInfo *) NULL; )
    550   {
    551     if ((p->stealth == MagickFalse) &&
    552         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    553       aliases[i++]=p;
    554     p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    555   }
    556   UnlockSemaphoreInfo(magic_semaphore);
    557   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare);
    558   aliases[i]=(MagicInfo *) NULL;
    559   *number_aliases=(size_t) i;
    560   return(aliases);
    561 }
    562 
    563 /*
    565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    566 %                                                                             %
    567 %                                                                             %
    568 %                                                                             %
    569 %   G e t M a g i c L i s t                                                   %
    570 %                                                                             %
    571 %                                                                             %
    572 %                                                                             %
    573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    574 %
    575 %  GetMagicList() returns any image format aliases that match the specified
    576 %  pattern.
    577 %
    578 %  The format of the GetMagicList function is:
    579 %
    580 %      char **GetMagicList(const char *pattern,size_t *number_aliases,
    581 %        ExceptionInfo *exception)
    582 %
    583 %  A description of each parameter follows:
    584 %
    585 %    o pattern: Specifies a pointer to a text string containing a pattern.
    586 %
    587 %    o number_aliases:  This integer returns the number of image format aliases
    588 %      in the list.
    589 %
    590 %    o exception: return any errors or warnings in this structure.
    591 %
    592 */
    593 
    594 #if defined(__cplusplus) || defined(c_plusplus)
    595 extern "C" {
    596 #endif
    597 
    598 static int MagicCompare(const void *x,const void *y)
    599 {
    600   register const char
    601     *p,
    602     *q;
    603 
    604   p=(const char *) x;
    605   q=(const char *) y;
    606   return(LocaleCompare(p,q));
    607 }
    608 
    609 #if defined(__cplusplus) || defined(c_plusplus)
    610 }
    611 #endif
    612 
    613 MagickExport char **GetMagicList(const char *pattern,size_t *number_aliases,
    614   ExceptionInfo *exception)
    615 {
    616   char
    617     **aliases;
    618 
    619   register const MagicInfo
    620     *p;
    621 
    622   register ssize_t
    623     i;
    624 
    625   /*
    626     Allocate configure list.
    627   */
    628   assert(pattern != (char *) NULL);
    629   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    630   assert(number_aliases != (size_t *) NULL);
    631   *number_aliases=0;
    632   p=GetMagicInfo((const unsigned char *) NULL,0,exception);
    633   if (p == (const MagicInfo *) NULL)
    634     return((char **) NULL);
    635   aliases=(char **) AcquireQuantumMemory((size_t)
    636     GetNumberOfElementsInLinkedList(magic_cache)+1UL,sizeof(*aliases));
    637   if (aliases == (char **) NULL)
    638     return((char **) NULL);
    639   LockSemaphoreInfo(magic_semaphore);
    640   ResetLinkedListIterator(magic_cache);
    641   p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    642   for (i=0; p != (const MagicInfo *) NULL; )
    643   {
    644     if ((p->stealth == MagickFalse) &&
    645         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    646       aliases[i++]=ConstantString(p->name);
    647     p=(const MagicInfo *) GetNextValueInLinkedList(magic_cache);
    648   }
    649   UnlockSemaphoreInfo(magic_semaphore);
    650   qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare);
    651   aliases[i]=(char *) NULL;
    652   *number_aliases=(size_t) i;
    653   return(aliases);
    654 }
    655 
    656 /*
    658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    659 %                                                                             %
    660 %                                                                             %
    661 %                                                                             %
    662 %   G e t M a g i c N a m e                                                   %
    663 %                                                                             %
    664 %                                                                             %
    665 %                                                                             %
    666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    667 %
    668 %  GetMagicName() returns the name associated with the magic.
    669 %
    670 %  The format of the GetMagicName method is:
    671 %
    672 %      const char *GetMagicName(const MagicInfo *magic_info)
    673 %
    674 %  A description of each parameter follows:
    675 %
    676 %    o magic_info:  The magic info.
    677 %
    678 */
    679 MagickExport const char *GetMagicName(const MagicInfo *magic_info)
    680 {
    681   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
    682   assert(magic_info != (MagicInfo *) NULL);
    683   assert(magic_info->signature == MagickCoreSignature);
    684   return(magic_info->name);
    685 }
    686 
    687 /*
    689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    690 %                                                                             %
    691 %                                                                             %
    692 %                                                                             %
    693 +   I s M a g i c C a c h e I n s t a n t i a t e d                           %
    694 %                                                                             %
    695 %                                                                             %
    696 %                                                                             %
    697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    698 %
    699 %  IsMagicCacheInstantiated() determines if the magic list is instantiated.
    700 %  If not, it instantiates the list and returns it.
    701 %
    702 %  The format of the IsMagicInstantiated method is:
    703 %
    704 %      MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
    705 %
    706 %  A description of each parameter follows.
    707 %
    708 %    o exception: return any errors or warnings in this structure.
    709 %
    710 */
    711 static MagickBooleanType IsMagicCacheInstantiated(ExceptionInfo *exception)
    712 {
    713   if (magic_cache == (LinkedListInfo *) NULL)
    714     {
    715       if (magic_semaphore == (SemaphoreInfo *) NULL)
    716         ActivateSemaphoreInfo(&magic_semaphore);
    717       LockSemaphoreInfo(magic_semaphore);
    718       if (magic_cache == (LinkedListInfo *) NULL)
    719         magic_cache=AcquireMagicCache(MagicFilename,exception);
    720       UnlockSemaphoreInfo(magic_semaphore);
    721     }
    722   return(magic_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
    723 }
    724 
    725 /*
    727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    728 %                                                                             %
    729 %                                                                             %
    730 %                                                                             %
    731 %  L i s t M a g i c I n f o                                                  %
    732 %                                                                             %
    733 %                                                                             %
    734 %                                                                             %
    735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    736 %
    737 %  ListMagicInfo() lists the magic info to a file.
    738 %
    739 %  The format of the ListMagicInfo method is:
    740 %
    741 %      MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception)
    742 %
    743 %  A description of each parameter follows.
    744 %
    745 %    o file:  An pointer to a FILE.
    746 %
    747 %    o exception: return any errors or warnings in this structure.
    748 %
    749 */
    750 MagickExport MagickBooleanType ListMagicInfo(FILE *file,
    751   ExceptionInfo *exception)
    752 {
    753   const char
    754     *path;
    755 
    756   const MagicInfo
    757     **magic_info;
    758 
    759   register ssize_t
    760     i;
    761 
    762   size_t
    763     number_aliases;
    764 
    765   ssize_t
    766     j;
    767 
    768   if (file == (const FILE *) NULL)
    769     file=stdout;
    770   magic_info=GetMagicInfoList("*",&number_aliases,exception);
    771   if (magic_info == (const MagicInfo **) NULL)
    772     return(MagickFalse);
    773   j=0;
    774   path=(const char *) NULL;
    775   for (i=0; i < (ssize_t) number_aliases; i++)
    776   {
    777     if (magic_info[i]->stealth != MagickFalse)
    778       continue;
    779     if ((path == (const char *) NULL) ||
    780         (LocaleCompare(path,magic_info[i]->path) != 0))
    781       {
    782         if (magic_info[i]->path != (char *) NULL)
    783           (void) FormatLocaleFile(file,"\nPath: %s\n\n",magic_info[i]->path);
    784         (void) FormatLocaleFile(file,"Name      Offset Target\n");
    785         (void) FormatLocaleFile(file,
    786           "-------------------------------------------------"
    787           "------------------------------\n");
    788       }
    789     path=magic_info[i]->path;
    790     (void) FormatLocaleFile(file,"%s",magic_info[i]->name);
    791     for (j=(ssize_t) strlen(magic_info[i]->name); j <= 9; j++)
    792       (void) FormatLocaleFile(file," ");
    793     (void) FormatLocaleFile(file,"%6ld ",(long) magic_info[i]->offset);
    794     if (magic_info[i]->target != (char *) NULL)
    795       {
    796         register ssize_t
    797           j;
    798 
    799         for (j=0; magic_info[i]->target[j] != '\0'; j++)
    800           if (isprint((int) ((unsigned char) magic_info[i]->target[j])) != 0)
    801             (void) FormatLocaleFile(file,"%c",magic_info[i]->target[j]);
    802           else
    803             (void) FormatLocaleFile(file,"\\%03o",(unsigned int)
    804               ((unsigned char) magic_info[i]->target[j]));
    805       }
    806     (void) FormatLocaleFile(file,"\n");
    807   }
    808   (void) fflush(file);
    809   magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info);
    810   return(MagickTrue);
    811 }
    812 
    813 /*
    815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    816 %                                                                             %
    817 %                                                                             %
    818 %                                                                             %
    819 +   L o a d M a g i c C a c h e                                               %
    820 %                                                                             %
    821 %                                                                             %
    822 %                                                                             %
    823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    824 %
    825 %  LoadMagicCache() loads the magic configurations which provides a mapping
    826 %  between magic attributes and a magic name.
    827 %
    828 %  The format of the LoadMagicCache method is:
    829 %
    830 %      MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
    831 %        const char *filename,const size_t depth,ExceptionInfo *exception)
    832 %
    833 %  A description of each parameter follows:
    834 %
    835 %    o xml: The magic list in XML format.
    836 %
    837 %    o filename: The magic list filename.
    838 %
    839 %    o depth: depth of <include /> statements.
    840 %
    841 %    o exception: return any errors or warnings in this structure.
    842 %
    843 */
    844 static MagickBooleanType LoadMagicCache(LinkedListInfo *cache,const char *xml,
    845   const char *filename,const size_t depth,ExceptionInfo *exception)
    846 {
    847   char
    848     keyword[MagickPathExtent],
    849     *token;
    850 
    851   const char
    852     *q;
    853 
    854   MagicInfo
    855     *magic_info;
    856 
    857   MagickStatusType
    858     status;
    859 
    860   size_t
    861     extent;
    862 
    863   /*
    864     Load the magic map file.
    865   */
    866   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
    867     "Loading magic configure file \"%s\" ...",filename);
    868   if (xml == (char *) NULL)
    869     return(MagickFalse);
    870   status=MagickTrue;
    871   magic_info=(MagicInfo *) NULL;
    872   token=AcquireString(xml);
    873   extent=strlen(token)+MagickPathExtent;
    874   for (q=(char *) xml; *q != '\0'; )
    875   {
    876     /*
    877       Interpret XML.
    878     */
    879     GetNextToken(q,&q,extent,token);
    880     if (*token == '\0')
    881       break;
    882     (void) CopyMagickString(keyword,token,MagickPathExtent);
    883     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
    884       {
    885         /*
    886           Doctype element.
    887         */
    888         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
    889           GetNextToken(q,&q,extent,token);
    890         continue;
    891       }
    892     if (LocaleNCompare(keyword,"<!--",4) == 0)
    893       {
    894         /*
    895           Comment element.
    896         */
    897         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
    898           GetNextToken(q,&q,extent,token);
    899         continue;
    900       }
    901     if (LocaleCompare(keyword,"<include") == 0)
    902       {
    903         /*
    904           Include element.
    905         */
    906         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
    907         {
    908           (void) CopyMagickString(keyword,token,MagickPathExtent);
    909           GetNextToken(q,&q,extent,token);
    910           if (*token != '=')
    911             continue;
    912           GetNextToken(q,&q,extent,token);
    913           if (LocaleCompare(keyword,"file") == 0)
    914             {
    915               if (depth > 200)
    916                 (void) ThrowMagickException(exception,GetMagickModule(),
    917                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
    918               else
    919                 {
    920                   char
    921                     path[MagickPathExtent],
    922                     *file_xml;
    923 
    924                   GetPathComponent(filename,HeadPath,path);
    925                   if (*path != '\0')
    926                     (void) ConcatenateMagickString(path,DirectorySeparator,
    927                       MagickPathExtent);
    928                   if (*token == *DirectorySeparator)
    929                     (void) CopyMagickString(path,token,MagickPathExtent);
    930                   else
    931                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
    932                   file_xml=FileToXML(path,~0UL);
    933                   if (xml != (char *) NULL)
    934                     {
    935                       status&=LoadMagicCache(cache,file_xml,path,depth+1,
    936                         exception);
    937                       file_xml=DestroyString(file_xml);
    938                     }
    939                 }
    940             }
    941         }
    942         continue;
    943       }
    944     if (LocaleCompare(keyword,"<magic") == 0)
    945       {
    946         /*
    947           Magic element.
    948         */
    949         magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info));
    950         if (magic_info == (MagicInfo *) NULL)
    951           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    952         (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info));
    953         magic_info->path=ConstantString(filename);
    954         magic_info->exempt=MagickFalse;
    955         magic_info->signature=MagickCoreSignature;
    956         continue;
    957       }
    958     if (magic_info == (MagicInfo *) NULL)
    959       continue;
    960     if (LocaleCompare(keyword,"/>") == 0)
    961       {
    962         status=InsertValueInSortedLinkedList(cache,CompareMagickInfoSize,
    963           NULL,magic_info);
    964         if (status == MagickFalse)
    965           (void) ThrowMagickException(exception,GetMagickModule(),
    966             ResourceLimitError,"MemoryAllocationFailed","`%s'",
    967             magic_info->name);
    968         magic_info=(MagicInfo *) NULL;
    969         continue;
    970       }
    971     GetNextToken(q,(const char **) NULL,extent,token);
    972     if (*token != '=')
    973       continue;
    974     GetNextToken(q,&q,extent,token);
    975     GetNextToken(q,&q,extent,token);
    976     switch (*keyword)
    977     {
    978       case 'N':
    979       case 'n':
    980       {
    981         if (LocaleCompare((char *) keyword,"name") == 0)
    982           {
    983             magic_info->name=ConstantString(token);
    984             break;
    985           }
    986         break;
    987       }
    988       case 'O':
    989       case 'o':
    990       {
    991         if (LocaleCompare((char *) keyword,"offset") == 0)
    992           {
    993             magic_info->offset=(MagickOffsetType) StringToLong(token);
    994             break;
    995           }
    996         break;
    997       }
    998       case 'S':
    999       case 's':
   1000       {
   1001         if (LocaleCompare((char *) keyword,"stealth") == 0)
   1002           {
   1003             magic_info->stealth=IsStringTrue(token);
   1004             break;
   1005           }
   1006         break;
   1007       }
   1008       case 'T':
   1009       case 't':
   1010       {
   1011         if (LocaleCompare((char *) keyword,"target") == 0)
   1012           {
   1013             char
   1014               *p;
   1015 
   1016             register unsigned char
   1017               *q;
   1018 
   1019             size_t
   1020               length;
   1021 
   1022             length=strlen(token);
   1023             magic_info->target=ConstantString(token);
   1024             magic_info->magic=(unsigned char *) ConstantString(token);
   1025             q=magic_info->magic;
   1026             for (p=magic_info->target; *p != '\0'; )
   1027             {
   1028               if (*p == '\\')
   1029                 {
   1030                   p++;
   1031                   if (isdigit((int) ((unsigned char) *p)) != 0)
   1032                     {
   1033                       char
   1034                         *end;
   1035 
   1036                       *q++=(unsigned char) strtol(p,&end,8);
   1037                       p+=(end-p);
   1038                       magic_info->length++;
   1039                       continue;
   1040                     }
   1041                   switch (*p)
   1042                   {
   1043                     case 'b': *q='\b'; break;
   1044                     case 'f': *q='\f'; break;
   1045                     case 'n': *q='\n'; break;
   1046                     case 'r': *q='\r'; break;
   1047                     case 't': *q='\t'; break;
   1048                     case 'v': *q='\v'; break;
   1049                     case 'a': *q='a'; break;
   1050                     case '?': *q='\?'; break;
   1051                     default: *q=(unsigned char) (*p); break;
   1052                   }
   1053                   p++;
   1054                   q++;
   1055                   magic_info->length++;
   1056                   continue;
   1057                 }
   1058               else
   1059                 if (LocaleNCompare(p,"&amp;",5) == 0)
   1060                   (void) CopyMagickString(p+1,p+5,length-magic_info->length);
   1061               *q++=(unsigned char) (*p++);
   1062               magic_info->length++;
   1063             }
   1064             break;
   1065           }
   1066         break;
   1067       }
   1068       default:
   1069         break;
   1070     }
   1071   }
   1072   token=(char *) RelinquishMagickMemory(token);
   1073   return(status != 0 ? MagickTrue : MagickFalse);
   1074 }
   1075 
   1076 /*
   1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1079 %                                                                             %
   1080 %                                                                             %
   1081 %                                                                             %
   1082 +   M a g i c C o m p o n e n t G e n e s i s                                 %
   1083 %                                                                             %
   1084 %                                                                             %
   1085 %                                                                             %
   1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1087 %
   1088 %  MagicComponentGenesis() instantiates the magic component.
   1089 %
   1090 %  The format of the MagicComponentGenesis method is:
   1091 %
   1092 %      MagickBooleanType MagicComponentGenesis(void)
   1093 %
   1094 */
   1095 MagickPrivate MagickBooleanType MagicComponentGenesis(void)
   1096 {
   1097   if (magic_semaphore == (SemaphoreInfo *) NULL)
   1098     magic_semaphore=AcquireSemaphoreInfo();
   1099   return(MagickTrue);
   1100 }
   1101 
   1102 /*
   1104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1105 %                                                                             %
   1106 %                                                                             %
   1107 %                                                                             %
   1108 +   M a g i c C o m p o n e n t T e r m i n u s                               %
   1109 %                                                                             %
   1110 %                                                                             %
   1111 %                                                                             %
   1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1113 %
   1114 %  MagicComponentTerminus() destroys the magic component.
   1115 %
   1116 %  The format of the MagicComponentTerminus method is:
   1117 %
   1118 %      MagicComponentTerminus(void)
   1119 %
   1120 */
   1121 
   1122 static void *DestroyMagicElement(void *magic_info)
   1123 {
   1124   register MagicInfo
   1125     *p;
   1126 
   1127   p=(MagicInfo *) magic_info;
   1128   if (p->exempt == MagickFalse)
   1129     {
   1130       if (p->path != (char *) NULL)
   1131         p->path=DestroyString(p->path);
   1132       if (p->name != (char *) NULL)
   1133         p->name=DestroyString(p->name);
   1134       if (p->target != (char *) NULL)
   1135         p->target=DestroyString(p->target);
   1136       if (p->magic != (unsigned char *) NULL)
   1137         p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
   1138     }
   1139   p=(MagicInfo *) RelinquishMagickMemory(p);
   1140   return((void *) NULL);
   1141 }
   1142 
   1143 MagickPrivate void MagicComponentTerminus(void)
   1144 {
   1145   if (magic_semaphore == (SemaphoreInfo *) NULL)
   1146     ActivateSemaphoreInfo(&magic_semaphore);
   1147   LockSemaphoreInfo(magic_semaphore);
   1148   if (magic_cache != (LinkedListInfo *) NULL)
   1149     magic_cache=DestroyLinkedList(magic_cache,DestroyMagicElement);
   1150   UnlockSemaphoreInfo(magic_semaphore);
   1151   RelinquishSemaphoreInfo(&magic_semaphore);
   1152 }
   1153