/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % CCCC OOO DDDD EEEEE RRRR % % C O O D D E R R % % C O O D D EEE RRRR % % C O O D D E R R % % CCCC OOO DDDD EEEEE R R % % % % % % MagickCore Image Coder Methods % % % % Software Design % % Cristy % % May 2001 % % % % % % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % https://imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "magick/studio.h" #include "magick/blob.h" #include "magick/client.h" #include "magick/coder.h" #include "magick/configure.h" #include "magick/draw.h" #include "magick/exception.h" #include "magick/exception-private.h" #include "magick/hashmap.h" #include "magick/log.h" #include "magick/memory_.h" #include "magick/option.h" #include "magick/semaphore.h" #include "magick/string_.h" #include "magick/splay-tree.h" #include "magick/token.h" #include "magick/utility.h" #include "magick/xml-tree.h" #include "magick/xml-tree-private.h" /* Define declarations. */ #define MagickCoderFilename "coder.xml" /* Typedef declarations. */ typedef struct _CoderMapInfo { const char *magick, *name; } CoderMapInfo; /* Static declarations. */ static const CoderMapInfo CoderMap[] = { { "3FR", "DNG" }, { "3GP", "VIDEO" }, { "3G2", "VIDEO" }, { "8BIM", "META" }, { "8BIMTEXT", "META" }, { "8BIMWTEXT", "META" }, { "AFM", "TTF" }, { "A", "RAW" }, { "AI", "PDF" }, { "APNG", "VIDEO" }, { "APP1JPEG", "META" }, { "APP1", "META" }, { "ARW", "DNG" }, { "AVI", "VIDEO" }, { "AVIF", "HEIC" }, { "BIE", "JBIG" }, { "BMP2", "BMP" }, { "BMP3", "BMP" }, { "B", "RAW" }, { "BRF", "BRAILLE" }, { "BGRA", "BGR" }, { "BGRO", "BGR" }, { "CMYKA", "CMYK" }, { "C", "RAW" }, { "CAL", "CALS" }, { "CANVAS", "XC" }, { "CMYKA", "CMYK" }, { "CR2", "DNG" }, { "CR3", "DNG" }, { "CRW", "DNG" }, { "CUR", "ICON" }, { "DATA", "INLINE" }, { "DCR", "DNG" }, { "DCX", "PCX" }, { "DFONT", "TTF" }, { "DXT1", "DDS" }, { "DXT5", "DDS" }, { "EPDF", "PDF" }, { "EPI", "PS" }, { "EPS2", "PS2" }, { "EPS3", "PS3" }, { "EPSF", "PS" }, { "EPSI", "PS" }, { "EPS", "PS" }, { "EPT2", "EPT" }, { "EPT3", "EPT" }, { "ERF", "DNG" }, { "EXIF", "META" }, { "FILE", "URL" }, { "FRACTAL", "PLASMA" }, { "FTP", "URL" }, { "FTS", "FITS" }, { "G3", "FAX" }, { "G4", "FAX" }, { "GIF87", "GIF" }, { "G", "RAW" }, { "GRANITE", "MAGICK" }, { "GRAYA", "GRAY" }, { "GROUP4", "TIFF" }, { "GV", "DOT" }, { "HTM", "HTML" }, { "ICB", "TGA" }, { "ICO", "ICON" }, { "ICODIB", "DIB" }, { "IIQ", "DNG" }, { "K25", "DNG" }, { "KDC", "DNG" }, { "H", "MAGICK" }, { "HTM", "HTML" }, { "HTTP", "URL" }, { "HTTPS", "URL" }, { "ICB", "TGA" }, { "ICC", "META" }, { "ICM", "META" }, { "ICO", "ICON" }, { "IMPLICIT", "***" }, { "IPTC", "META" }, { "IPTCTEXT", "META" }, { "IPTCWTEXT", "META" }, { "ISOBRL", "BRAILLE" }, { "ISOBRL6", "BRAILLE" }, { "JBG", "JBIG" }, { "JNG", "PNG" }, { "JPC", "JP2" }, { "JPT", "JP2" }, { "JPM", "JP2" }, { "J2C", "JP2" }, { "J2K", "JP2" }, { "JNG", "PNG" }, { "JPE", "JPEG" }, { "JPG", "JPEG" }, { "JPM", "JP2" }, { "JPS", "JPEG" }, { "JPT", "JP2" }, { "JPX", "JP2" }, { "K", "RAW" }, { "K25", "DNG" }, { "KDC", "DNG" }, { "LOGO", "MAGICK" }, { "M", "RAW" }, { "M2V", "VIDEO" }, { "M4V", "VIDEO" }, { "MEF", "DNG" }, { "MKV", "VIDEO" }, { "MNG", "PNG" }, { "MOV", "VIDEO" }, { "MP4", "VIDEO" }, { "MPEG", "VIDEO" }, { "MPG", "VIDEO" }, { "MPRI", "MPR" }, { "MEF", "DNG" }, { "MRW", "DNG" }, { "MSVG", "SVG" }, { "NEF", "DNG" }, { "NETSCAPE", "MAGICK" }, { "NRW", "DNG" }, { "O", "RAW" }, { "ORF", "DNG" }, { "OTF", "TTF" }, { "P7", "PNM" }, { "PAL", "UYVY" }, { "PAM", "PNM" }, { "PBM", "PNM" }, { "PCDS", "PCD" }, { "PCT", "PICT" }, { "PDFA", "PDF" }, { "PEF", "DNG" }, { "PEF", "DNG" }, { "PFA", "TTF" }, { "PFB", "TTF" }, { "PFM", "PNM" }, { "PGM", "PNM" }, { "PICON", "XPM" }, { "PJPEG", "JPEG" }, { "PM", "XPM" }, { "PNG00", "PNG" }, { "PNG24", "PNG" }, { "PNG32", "PNG" }, { "PNG48", "PNG" }, { "PNG64", "PNG" }, { "PNG8", "PNG" }, { "PPM", "PNM" }, { "PSB", "PSD" }, { "PTIF", "TIFF" }, { "R", "RAW" }, { "RADIAL-GRADIENT", "GRADIENT" }, { "RAF", "DNG" }, { "RAS", "SUN" }, { "RAW", "DNG" }, { "RGBA", "RGB" }, { "RGBO", "RGB" }, { "RMF", "DNG" }, { "ROSE", "MAGICK" }, { "RW2", "DNG" }, { "SHTML", "HTML" }, { "SIX", "SIXEL" }, { "SPARSE-COLOR", "TXT" }, { "SR2", "DNG" }, { "SRF", "DNG" }, { "SVGZ", "SVG" }, { "TEXT", "TXT" }, { "TIFF64", "TIFF" }, { "TIF", "TIFF" }, { "TTC", "TTF" }, { "UBRL", "BRAILLE" }, { "UBRL6", "BRAILLE" }, { "VDA", "TGA" }, { "VST", "TGA" }, { "WEBM", "VIDEO" }, { "WIZARD", "MAGICK" }, #if defined(MAGICKCORE_WINGDI32_DELEGATE) { "WMF", "EMF" }, #endif { "WMV", "VIDEO" }, { "WMZ", "WMF" }, { "X3f", "DNG" }, { "XMP", "META" }, { "XTRNARRAY", "XTRN" }, { "XV", "VIFF" }, { "Y", "RAW" }, { "YCbCrA", "YCbCr" } }; static SemaphoreInfo *coder_semaphore = (SemaphoreInfo *) NULL; static SplayTreeInfo *coder_cache = (SplayTreeInfo *) NULL; /* Forward declarations. */ static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *); #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT static MagickBooleanType LoadCoderCache(SplayTreeInfo *,const char *,const char *,const size_t, ExceptionInfo *); #endif /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + A c q u i r e C o d e r C a c h e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AcquireCoderCache() caches one or more coder configurations which % provides a mapping between coder attributes and a coder name. % % The format of the AcquireCoderCache coder is: % % SplayTreeInfo *AcquireCoderCache(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 void *DestroyCoderNode(void *coder_info) { CoderInfo *p; p=(CoderInfo *) coder_info; if (p->exempt == MagickFalse) { if (p->path != (char *) NULL) p->path=DestroyString(p->path); if (p->name != (char *) NULL) p->name=DestroyString(p->name); if (p->magick != (char *) NULL) p->magick=DestroyString(p->magick); } return(RelinquishMagickMemory(p)); } static SplayTreeInfo *AcquireCoderCache(const char *filename, ExceptionInfo *exception) { MagickStatusType status; ssize_t i; SplayTreeInfo *cache; /* Load external coder map. */ cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory, DestroyCoderNode); if (cache == (SplayTreeInfo *) NULL) ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); status=MagickTrue; #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT { const StringInfo *option; LinkedListInfo *options; options=GetConfigureOptions(filename,exception); option=(const StringInfo *) GetNextValueInLinkedList(options); while (option != (const StringInfo *) NULL) { status&=LoadCoderCache(cache,(const char *) GetStringInfoDatum(option),GetStringInfoPath(option),0,exception); option=(const StringInfo *) GetNextValueInLinkedList(options); } options=DestroyConfigureOptions(options); } #endif /* Load built-in coder map. */ for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++) { CoderInfo *coder_info; const CoderMapInfo *p; p=CoderMap+i; coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info)); if (coder_info == (CoderInfo *) NULL) { (void) ThrowMagickException(exception,GetMagickModule(), ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name); continue; } (void) memset(coder_info,0,sizeof(*coder_info)); coder_info->path=(char *) "[built-in]"; coder_info->magick=(char *) p->magick; coder_info->name=(char *) p->name; coder_info->exempt=MagickTrue; coder_info->signature=MagickCoreSignature; status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick), coder_info); if (status == MagickFalse) (void) ThrowMagickException(exception,GetMagickModule(), ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name); } return(cache); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + C o d e r C o m p o n e n t G e n e s i s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CoderComponentGenesis() instantiates the coder component. % % The format of the CoderComponentGenesis method is: % % MagickBooleanType CoderComponentGenesis(void) % */ MagickExport MagickBooleanType CoderComponentGenesis(void) { if (coder_semaphore == (SemaphoreInfo *) NULL) coder_semaphore=AllocateSemaphoreInfo(); return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + C o d e r C o m p o n e n t T e r m i n u s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % CoderComponentTerminus() destroys the coder component. % % The format of the CoderComponentTerminus method is: % % CoderComponentTerminus(void) % */ MagickExport void CoderComponentTerminus(void) { if (coder_semaphore == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&coder_semaphore); LockSemaphoreInfo(coder_semaphore); if (coder_cache != (SplayTreeInfo *) NULL) coder_cache=DestroySplayTree(coder_cache); UnlockSemaphoreInfo(coder_semaphore); DestroySemaphoreInfo(&coder_semaphore); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + G e t C o d e r I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetCoderInfo searches the coder list for the specified name and if found % returns attributes for that coder. % % The format of the GetCoderInfo method is: % % const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception) % % A description of each parameter follows: % % o name: the coder name. % % o exception: return any errors or warnings in this structure. % */ MagickExport const CoderInfo *GetCoderInfo(const char *name, ExceptionInfo *exception) { assert(exception != (ExceptionInfo *) NULL); if (IsCoderTreeInstantiated(exception) == MagickFalse) return((const CoderInfo *) NULL); if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0)) return((const CoderInfo *) GetRootValueFromSplayTree(coder_cache)); return((const CoderInfo *) GetValueFromSplayTree(coder_cache,name)); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t C o d e r I n f o L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetCoderInfoList() returns any coder_map that match the specified pattern. % The format of the GetCoderInfoList function is: % % const CoderInfo **GetCoderInfoList(const char *pattern, % size_t *number_coders,ExceptionInfo *exception) % % A description of each parameter follows: % % o pattern: Specifies a pointer to a text string containing a pattern. % % o number_coders: This integer returns the number of coders in the list. % % o exception: return any errors or warnings in this structure. % */ static int CoderInfoCompare(const void *x,const void *y) { const CoderInfo **p, **q; p=(const CoderInfo **) x, q=(const CoderInfo **) y; if (LocaleCompare((*p)->path,(*q)->path) == 0) return(LocaleCompare((*p)->name,(*q)->name)); return(LocaleCompare((*p)->path,(*q)->path)); } MagickExport const CoderInfo **GetCoderInfoList(const char *pattern, size_t *number_coders,ExceptionInfo *exception) { const CoderInfo **coder_map; const CoderInfo *p; ssize_t i; /* Allocate coder list. */ assert(pattern != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); assert(number_coders != (size_t *) NULL); *number_coders=0; p=GetCoderInfo("*",exception); if (p == (const CoderInfo *) NULL) return((const CoderInfo **) NULL); coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t) GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map)); if (coder_map == (const CoderInfo **) NULL) return((const CoderInfo **) NULL); /* Generate coder list. */ LockSemaphoreInfo(coder_semaphore); ResetSplayTreeIterator(coder_cache); p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache); for (i=0; p != (const CoderInfo *) NULL; ) { if ((p->stealth == MagickFalse) && (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) coder_map[i++]=p; p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache); } UnlockSemaphoreInfo(coder_semaphore); qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare); coder_map[i]=(CoderInfo *) NULL; *number_coders=(size_t) i; return(coder_map); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t C o d e r L i s t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetCoderList() returns any coder_map that match the specified pattern. % % The format of the GetCoderList function is: % % char **GetCoderList(const char *pattern,size_t *number_coders, % ExceptionInfo *exception) % % A description of each parameter follows: % % o pattern: Specifies a pointer to a text string containing a pattern. % % o number_coders: This integer returns the number of coders in the list. % % o exception: return any errors or warnings in this structure. % */ static int CoderCompare(const void *x,const void *y) { const char **p, **q; p=(const char **) x; q=(const char **) y; return(LocaleCompare(*p,*q)); } MagickExport char **GetCoderList(const char *pattern, size_t *number_coders,ExceptionInfo *exception) { char **coder_map; const CoderInfo *p; ssize_t i; /* Allocate coder list. */ assert(pattern != (char *) NULL); (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); assert(number_coders != (size_t *) NULL); *number_coders=0; p=GetCoderInfo("*",exception); if (p == (const CoderInfo *) NULL) return((char **) NULL); coder_map=(char **) AcquireQuantumMemory((size_t) GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map)); if (coder_map == (char **) NULL) return((char **) NULL); /* Generate coder list. */ LockSemaphoreInfo(coder_semaphore); ResetSplayTreeIterator(coder_cache); p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache); for (i=0; p != (const CoderInfo *) NULL; ) { if ((p->stealth == MagickFalse) && (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) coder_map[i++]=ConstantString(p->name); p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache); } UnlockSemaphoreInfo(coder_semaphore); qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare); coder_map[i]=(char *) NULL; *number_coders=(size_t) i; return(coder_map); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + I s C o d e r T r e e I n s t a n t i a t e d % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % IsCoderTreeInstantiated() determines if the coder tree is instantiated. If % not, it instantiates the tree and returns it. % % The format of the IsCoderInstantiated method is: % % MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception) % % A description of each parameter follows. % % o exception: return any errors or warnings in this structure. % */ static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception) { if (coder_cache == (SplayTreeInfo *) NULL) { if (coder_semaphore == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&coder_semaphore); LockSemaphoreInfo(coder_semaphore); if (coder_cache == (SplayTreeInfo *) NULL) coder_cache=AcquireCoderCache(MagickCoderFilename,exception); UnlockSemaphoreInfo(coder_semaphore); } return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % L i s t C o d e r I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ListCoderInfo() lists the coder info to a file. % % The format of the ListCoderInfo coder is: % % MagickBooleanType ListCoderInfo(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 ListCoderInfo(FILE *file, ExceptionInfo *exception) { const char *path; const CoderInfo **coder_info; ssize_t i; size_t number_coders; ssize_t j; if (file == (const FILE *) NULL) file=stdout; coder_info=GetCoderInfoList("*",&number_coders,exception); if (coder_info == (const CoderInfo **) NULL) return(MagickFalse); path=(const char *) NULL; for (i=0; i < (ssize_t) number_coders; i++) { if (coder_info[i]->stealth != MagickFalse) continue; if ((path == (const char *) NULL) || (LocaleCompare(path,coder_info[i]->path) != 0)) { if (coder_info[i]->path != (char *) NULL) (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path); (void) FormatLocaleFile(file,"Magick Coder\n"); (void) FormatLocaleFile(file, "-------------------------------------------------" "------------------------------\n"); } path=coder_info[i]->path; (void) FormatLocaleFile(file,"%s",coder_info[i]->magick); for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 11; j++) (void) FormatLocaleFile(file," "); if (coder_info[i]->name != (char *) NULL) (void) FormatLocaleFile(file,"%s",coder_info[i]->name); (void) FormatLocaleFile(file,"\n"); } coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info); (void) fflush(file); return(MagickTrue); } #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + L o a d C o d e r C a c h e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % LoadCoderCache() loads the coder configurations which provides a % mapping between coder attributes and a coder name. % % The format of the LoadCoderCache coder is: % % MagickBooleanType LoadCoderCache(SplayTreeInfo *cache,const char *xml, % const char *filename,const size_t depth,ExceptionInfo *exception) % % A description of each parameter follows: % % o xml: The coder list in XML format. % % o filename: The coder list filename. % % o depth: depth of statements. % % o exception: return any errors or warnings in this structure. % */ static MagickBooleanType LoadCoderCache(SplayTreeInfo *cache,const char *xml, const char *filename,const size_t depth,ExceptionInfo *exception) { char keyword[MaxTextExtent], *token; const char *q; CoderInfo *coder_info; MagickStatusType status; size_t extent; /* Load the coder map file. */ (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), "Loading coder configuration file \"%s\" ...",filename); if (xml == (const char *) NULL) return(MagickFalse); status=MagickTrue; coder_info=(CoderInfo *) NULL; token=AcquireString(xml); extent=strlen(token)+MaxTextExtent; for (q=(char *) xml; *q != '\0'; ) { /* Interpret XML. */ (void) GetNextToken(q,&q,extent,token); if (*token == '\0') break; (void) CopyMagickString(keyword,token,MaxTextExtent); if (LocaleNCompare(keyword,"",2) != 0) && (*q != '\0')) (void) GetNextToken(q,&q,extent,token); continue; } if (LocaleNCompare(keyword,"