/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % M M AAA GGGG IIIII CCCC % % MM MM A A G I C % % M M M AAAAA G GGG I C % % M M A A G G I C % % M M A A GGGG IIIII CCCC % % % % % % ImageMagick Image Magic Methods % % % % Software Design % % Bob Friesenhahn % % July 2000 % % % % % % Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % http://www.imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "magick/studio.h" #include "magick/blob.h" #include "magick/client.h" #include "magick/configure.h" #include "magick/exception.h" #include "magick/exception-private.h" #include "magick/hashmap.h" #include "magick/magic.h" #include "magick/memory_.h" #include "magick/semaphore.h" #include "magick/string_.h" #include "magick/token.h" #include "magick/utility.h" #include "magick/xml-tree.h" /* Define declarations. */ #define MagicFilename "magic.xml" /* Static declarations. */ static const char *MagicMap = (const char *) "" "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static LinkedListInfo *magic_list = (LinkedListInfo *) NULL; static SemaphoreInfo *magic_semaphore = (SemaphoreInfo *) NULL; static volatile MagickBooleanType instantiate_magic = MagickFalse; /* Forward declarations. */ static MagickBooleanType InitializeMagicList(ExceptionInfo *), LoadMagicLists(const char *,ExceptionInfo *); /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + D e s t r o y M a g i c L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % DestroyMagicList() deallocates memory associated with the magic list. % % The format of the DestroyMagicList method is: % % DestroyMagicList(void) % */ static void *DestroyMagicElement(void *magic_info) { register MagicInfo *p; p=(MagicInfo *) magic_info; if (p->path != (char *) NULL) p->path=DestroyString(p->path); if (p->name != (char *) NULL) p->name=DestroyString(p->name); if (p->target != (char *) NULL) p->target=DestroyString(p->target); if (p->magic != (unsigned char *) NULL) p->magic=(unsigned char *) RelinquishMagickMemory(p->magic); p=(MagicInfo *) RelinquishMagickMemory(p); return((void *) NULL); } MagickExport void DestroyMagicList(void) { AcquireSemaphoreInfo(&magic_semaphore); if (magic_list != (LinkedListInfo *) NULL) magic_list=DestroyLinkedList(magic_list,DestroyMagicElement); instantiate_magic=MagickFalse; RelinquishSemaphoreInfo(magic_semaphore); magic_semaphore=DestroySemaphoreInfo(magic_semaphore); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + G e t M a g i c I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagicInfo() searches the magic list for the specified name and if found % returns attributes for that magic. % % The format of the GetMagicInfo method is: % % const MagicInfo *GetMagicInfo(const unsigned char *magic, % const size_t length,ExceptionInfo *exception) % % A description of each parameter follows: % % o magic: A binary string generally representing the first few characters % of the image file or blob. % % o length: The length of the binary signature. % % o exception: Return any errors or warnings in this structure. % */ MagickExport const MagicInfo *GetMagicInfo(const unsigned char *magic, const size_t length,ExceptionInfo *exception) { register const MagicInfo *p; assert(exception != (ExceptionInfo *) NULL); if ((magic_list == (LinkedListInfo *) NULL) || (instantiate_magic == MagickFalse)) if (InitializeMagicList(exception) == MagickFalse) return((const MagicInfo *) NULL); if ((magic_list == (LinkedListInfo *) NULL) || (IsLinkedListEmpty(magic_list) != MagickFalse)) return((const MagicInfo *) NULL); if ((magic == (const unsigned char *) NULL) || (length == 0)) return((const MagicInfo *) GetValueFromLinkedList(magic_list,0)); if (length == 0) return((const MagicInfo *) NULL); /* Search for requested magic. */ AcquireSemaphoreInfo(&magic_semaphore); ResetLinkedListIterator(magic_list); p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); while (p != (const MagicInfo *) NULL) { assert(p->offset >= 0); if (((size_t) (p->offset+p->length) <= length) && (memcmp(magic+p->offset,p->magic,p->length) == 0)) break; p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); } RelinquishSemaphoreInfo(magic_semaphore); return((const MagicInfo *) p); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t M a g i c I n f o L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagicInfoList() returns any image aliases that match the specified % pattern. % % The magic of the GetMagicInfoList function is: % % const MagicInfo **GetMagicInfoList(const char *pattern, % unsigned long *number_aliases,ExceptionInfo *exception) % % A description of each parameter follows: % % o pattern: Specifies a pointer to a text string containing a pattern. % % o number_aliases: This integer returns the number of aliases in the % list. % % o exception: Return any errors or warnings in this structure. % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int MagicInfoCompare(const void *x,const void *y) { const MagicInfo **p, **q; p=(const MagicInfo **) x, q=(const MagicInfo **) y; if (LocaleCompare((*p)->path,(*q)->path) == 0) return(LocaleCompare((*p)->name,(*q)->name)); return(LocaleCompare((*p)->path,(*q)->path)); } #if defined(__cplusplus) || defined(c_plusplus) } #endif MagickExport const MagicInfo **GetMagicInfoList(const char *pattern, unsigned long *number_aliases,ExceptionInfo *exception) { const MagicInfo **aliases; register const MagicInfo *p; register long i; /* Allocate magic list. */ assert(pattern != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); assert(number_aliases != (unsigned long *) NULL); *number_aliases=0; p=GetMagicInfo((const unsigned char *) "*",0,exception); if (p == (const MagicInfo *) NULL) return((const MagicInfo **) NULL); aliases=(const MagicInfo **) AcquireQuantumMemory((size_t) GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases)); if (aliases == (const MagicInfo **) NULL) return((const MagicInfo **) NULL); /* Generate magic list. */ AcquireSemaphoreInfo(&magic_semaphore); ResetLinkedListIterator(magic_list); p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); for (i=0; p != (const MagicInfo *) NULL; ) { if ((p->stealth == MagickFalse) && (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) aliases[i++]=p; p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); } RelinquishSemaphoreInfo(magic_semaphore); qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicInfoCompare); aliases[i]=(MagicInfo *) NULL; *number_aliases=(unsigned long) i; return(aliases); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t M a g i c L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagicList() returns any image format aliases that match the specified % pattern. % % The format of the GetMagicList function is: % % char **GetMagicList(const char *pattern,unsigned long *number_aliases, % ExceptionInfo *exception) % % A description of each parameter follows: % % o pattern: Specifies a pointer to a text string containing a pattern. % % o number_aliases: This integer returns the number of image format aliases % in the list. % % o exception: Return any errors or warnings in this structure. % */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static int MagicCompare(const void *x,const void *y) { register const char *p, *q; p=(const char *) x; q=(const char *) y; return(LocaleCompare(p,q)); } #if defined(__cplusplus) || defined(c_plusplus) } #endif MagickExport char **GetMagicList(const char *pattern, unsigned long *number_aliases,ExceptionInfo *exception) { char **aliases; register const MagicInfo *p; register long i; /* Allocate configure list. */ assert(pattern != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); assert(number_aliases != (unsigned long *) NULL); *number_aliases=0; p=GetMagicInfo((const unsigned char *) "*",0,exception); if (p == (const MagicInfo *) NULL) return((char **) NULL); aliases=(char **) AcquireQuantumMemory((size_t) GetNumberOfElementsInLinkedList(magic_list)+1UL,sizeof(*aliases)); if (aliases == (char **) NULL) return((char **) NULL); AcquireSemaphoreInfo(&magic_semaphore); ResetLinkedListIterator(magic_list); p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); for (i=0; p != (const MagicInfo *) NULL; ) { if ((p->stealth == MagickFalse) && (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) aliases[i++]=ConstantString(p->name); p=(const MagicInfo *) GetNextValueInLinkedList(magic_list); } RelinquishSemaphoreInfo(magic_semaphore); qsort((void *) aliases,(size_t) i,sizeof(*aliases),MagicCompare); aliases[i]=(char *) NULL; *number_aliases=(unsigned long) i; return(aliases); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t M a g i c N a m e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagicName() returns the name associated with the magic. % % The format of the GetMagicName method is: % % const char *GetMagicName(const MagicInfo *magic_info) % % A description of each parameter follows: % % o magic_info: The magic info. % */ MagickExport const char *GetMagicName(const MagicInfo *magic_info) { (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); assert(magic_info != (MagicInfo *) NULL); assert(magic_info->signature == MagickSignature); return(magic_info->name); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + I n i t i a l i z e M a g i c L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % InitializeMagicList() initializes the magic list. % % The format of the InitializeMagicList method is: % % MagickBooleanType InitializeMagicList(ExceptionInfo *exception) % % A description of each parameter follows. % % o exception: Return any errors or warnings in this structure. % */ static MagickBooleanType InitializeMagicList(ExceptionInfo *exception) { if ((magic_list == (LinkedListInfo *) NULL) && (instantiate_magic == MagickFalse)) { AcquireSemaphoreInfo(&magic_semaphore); if ((magic_list == (LinkedListInfo *) NULL) && (instantiate_magic == MagickFalse)) { (void) LoadMagicLists(MagicFilename,exception); instantiate_magic=MagickTrue; } RelinquishSemaphoreInfo(magic_semaphore); } return(magic_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % L i s t M a g i c I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ListMagicInfo() lists the magic info to a file. % % The format of the ListMagicInfo method is: % % MagickBooleanType ListMagicInfo(FILE *file,ExceptionInfo *exception) % % A description of each parameter follows. % % o file: An pointer to a FILE. % % o exception: Return any errors or warnings in this structure. % */ MagickExport MagickBooleanType ListMagicInfo(FILE *file, ExceptionInfo *exception) { const char *path; const MagicInfo **magic_info; long j; register long i; unsigned long number_aliases; if (file == (const FILE *) NULL) file=stdout; magic_info=GetMagicInfoList("*",&number_aliases,exception); if (magic_info == (const MagicInfo **) NULL) return(MagickFalse); j=0; path=(const char *) NULL; for (i=0; i < (long) number_aliases; i++) { if (magic_info[i]->stealth != MagickFalse) continue; if ((path == (const char *) NULL) || (LocaleCompare(path,magic_info[i]->path) != 0)) { if (magic_info[i]->path != (char *) NULL) (void) fprintf(file,"\nPath: %s\n\n",magic_info[i]->path); (void) fprintf(file,"Name Offset Target\n"); (void) fprintf(file,"-------------------------------------------------" "------------------------------\n"); } path=magic_info[i]->path; (void) fprintf(file,"%s",magic_info[i]->name); for (j=(long) strlen(magic_info[i]->name); j <= 9; j++) (void) fprintf(file," "); (void) fprintf(file,"%6ld ",(long) magic_info[i]->offset); if (magic_info[i]->target != (char *) NULL) (void) fprintf(file,"%s",magic_info[i]->target); (void) fprintf(file,"\n"); } (void) fflush(file); magic_info=(const MagicInfo **) RelinquishMagickMemory((void *) magic_info); return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + L o a d M a g i c L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % LoadMagicList() loads the magic configuration file which provides a mapping % between magic attributes and a magic name. % % The format of the LoadMagicList method is: % % MagickBooleanType LoadMagicList(const char *xml,const char *filename, % const unsigned long depth,ExceptionInfo *exception) % % A description of each parameter follows: % % o xml: The magic list in XML format. % % o filename: The magic list filename. % % o depth: depth of statements. % % o exception: Return any errors or warnings in this structure. % */ static MagickBooleanType LoadMagicList(const char *xml,const char *filename, const unsigned long depth,ExceptionInfo *exception) { const char *attribute; MagicInfo *magic_info = (MagicInfo *) NULL; MagickBooleanType status; XMLTreeInfo *magic, *magic_map, *include; /* Load the magic map file. */ (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), "Loading magic map \"%s\" ...",filename); if (xml == (const char *) NULL) return(MagickFalse); if (magic_list == (LinkedListInfo *) NULL) { magic_list=NewLinkedList(0); if (magic_list == (LinkedListInfo *) NULL) { ThrowFileException(exception,ResourceLimitError, "MemoryAllocationFailed",filename); return(MagickFalse); } } magic_map=NewXMLTree(xml,exception); if (magic_map == (XMLTreeInfo *) NULL) return(MagickFalse); status=MagickTrue; include=GetXMLTreeChild(magic_map,"include"); while (include != (XMLTreeInfo *) NULL) { /* Process include element. */ attribute=GetXMLTreeAttribute(include,"file"); if (attribute != (const char *) NULL) { if (depth > 200) (void) ThrowMagickException(exception,GetMagickModule(), ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename); else { char path[MaxTextExtent], *xml; GetPathComponent(filename,HeadPath,path); if (*path != '\0') (void) ConcatenateMagickString(path,DirectorySeparator, MaxTextExtent); (void) ConcatenateMagickString(path,attribute,MaxTextExtent); xml=FileToString(path,~0,exception); if (xml != (char *) NULL) { status=LoadMagicList(xml,path,depth+1,exception); xml=DestroyString(xml); } } } include=GetNextXMLTreeTag(include); } magic=GetXMLTreeChild(magic_map,"magic"); while (magic != (XMLTreeInfo *) NULL) { const char *attribute; /* Process magic element. */ magic_info=(MagicInfo *) AcquireMagickMemory(sizeof(*magic_info)); if (magic_info == (MagicInfo *) NULL) ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); (void) ResetMagickMemory(magic_info,0,sizeof(*magic_info)); magic_info->path=ConstantString(filename); magic_info->signature=MagickSignature; attribute=GetXMLTreeAttribute(magic,"name"); if (attribute != (const char *) NULL) magic_info->name=ConstantString(attribute); attribute=GetXMLTreeAttribute(magic,"offset"); if (attribute != (const char *) NULL) magic_info->offset=(MagickOffsetType) atol(attribute); attribute=GetXMLTreeAttribute(magic,"stealth"); if (attribute != (const char *) NULL) magic_info->stealth=IsMagickTrue(attribute); attribute=GetXMLTreeAttribute(magic,"target"); if (attribute != (const char *) NULL) { const char *p; register unsigned char *q; magic_info->target=ConstantString(attribute); magic_info->magic=(unsigned char *) ConstantString(attribute); q=magic_info->magic; for (p=magic_info->target; *p != '\0'; ) { if (*p == '\\') { p++; if (isdigit((int) ((unsigned char) *p)) != 0) { char *end; *q++=(unsigned char) strtol(p,&end,8); p+=(end-p); magic_info->length++; continue; } switch (*p) { case 'b': *q='\b'; break; case 'f': *q='\f'; break; case 'n': *q='\n'; break; case 'r': *q='\r'; break; case 't': *q='\t'; break; case 'v': *q='\v'; break; case 'a': *q='a'; break; case '?': *q='\?'; break; default: *q=(unsigned char) (*p); break; } p++; q++; magic_info->length++; continue; } *q++=(unsigned char) (*p++); magic_info->length++; } } status=AppendValueToLinkedList(magic_list,magic_info); if (status == MagickFalse) (void) ThrowMagickException(exception,GetMagickModule(), ResourceLimitError,"MemoryAllocationFailed","`%s'",filename); magic=GetNextXMLTreeTag(magic); } magic_map=DestroyXMLTree(magic_map); return(status); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % L o a d M a g i c L i s t s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % LoadMagicList() loads one or more magic configuration file which provides a % mapping between magic attributes and a magic name. % % The format of the LoadMagicLists method is: % % MagickBooleanType LoadMagicLists(const char *filename, % ExceptionInfo *exception) % % A description of each parameter follows: % % o filename: The font file name. % % o exception: Return any errors or warnings in this structure. % */ static MagickBooleanType LoadMagicLists(const char *filename, ExceptionInfo *exception) { #if defined(UseEmbeddableMagick) return(LoadMagicList(MagicMap,"built-in",0,exception)); #else char path[MaxTextExtent]; const StringInfo *option; LinkedListInfo *options; MagickStatusType status; status=MagickFalse; *path='\0'; options=GetConfigureOptions(filename,exception); option=(const StringInfo *) GetNextValueInLinkedList(options); while (option != (const StringInfo *) NULL) { (void) CopyMagickString(path,GetStringInfoPath(option),MaxTextExtent); status|=LoadMagicList((const char *) GetStringInfoDatum(option), GetStringInfoPath(option),0,exception); option=(const StringInfo *) GetNextValueInLinkedList(options); } options=DestroyConfigureOptions(options); if ((magic_list == (LinkedListInfo *) NULL) || (IsLinkedListEmpty(magic_list) != MagickFalse)) { (void) ThrowMagickException(exception,GetMagickModule(),ConfigureWarning, "UnableToOpenConfigureFile","`%s'",path); status|=LoadMagicList(MagicMap,"built-in",0,exception); } return(status != 0 ? MagickTrue : MagickFalse); #endif }