Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %           DDDD   EEEEE  L      EEEEE   GGGG   AAA   TTTTT  EEEEE            %
      6 %           D   D  E      L      E      G      A   A    T    E                %
      7 %           D   D  EEE    L      EEE    G  GG  AAAAA    T    EEE              %
      8 %           D   D  E      L      E      G   G  A   A    T    E                %
      9 %           DDDD   EEEEE  LLLLL  EEEEE   GGG   A   A    T    EEEEE            %
     10 %                                                                             %
     11 %                                                                             %
     12 %             MagickCore Methods to Read/Write/Invoke Delegates               %
     13 %                                                                             %
     14 %                             Software Design                                 %
     15 %                                  Cristy                                     %
     16 %                               October 1998                                  %
     17 %                                                                             %
     18 %                                                                             %
     19 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     20 %  dedicated to making software imaging solutions freely available.           %
     21 %                                                                             %
     22 %  You may not use this file except in compliance with the License.  You may  %
     23 %  obtain a copy of the License at                                            %
     24 %                                                                             %
     25 %    http://www.imagemagick.org/script/license.php                            %
     26 %                                                                             %
     27 %  Unless required by applicable law or agreed to in writing, software        %
     28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     30 %  See the License for the specific language governing permissions and        %
     31 %  limitations under the License.                                             %
     32 %                                                                             %
     33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     34 %
     35 %  The Delegates methods associate a set of commands with a particular
     36 %  image format.  ImageMagick uses delegates for formats it does not handle
     37 %  directly.
     38 %
     39 %  Thanks to Bob Friesenhahn for the initial inspiration and design of the
     40 %  delegates methods.
     41 %
     42 %
     43 */
     44 
     45 /*
     47   Include declarations.
     48 */
     49 #include "MagickCore/studio.h"
     50 #include "MagickCore/artifact.h"
     51 #include "MagickCore/attribute.h"
     52 #include "MagickCore/blob.h"
     53 #include "MagickCore/client.h"
     54 #include "MagickCore/configure.h"
     55 #include "MagickCore/constitute.h"
     56 #include "MagickCore/delegate.h"
     57 #include "MagickCore/delegate-private.h"
     58 #include "MagickCore/exception.h"
     59 #include "MagickCore/exception-private.h"
     60 #include "MagickCore/fx-private.h"
     61 #include "MagickCore/image-private.h"
     62 #include "MagickCore/linked-list.h"
     63 #include "MagickCore/list.h"
     64 #include "MagickCore/memory_.h"
     65 #include "MagickCore/nt-base-private.h"
     66 #include "MagickCore/option.h"
     67 #include "MagickCore/policy.h"
     68 #include "MagickCore/property.h"
     69 #include "MagickCore/resource_.h"
     70 #include "MagickCore/semaphore.h"
     71 #include "MagickCore/signature.h"
     72 #include "MagickCore/string_.h"
     73 #include "MagickCore/token.h"
     74 #include "MagickCore/token-private.h"
     75 #include "MagickCore/utility.h"
     76 #include "MagickCore/utility-private.h"
     77 #include "MagickCore/xml-tree.h"
     78 #include "MagickCore/xml-tree-private.h"
     79 
     80 /*
     82   Define declarations.
     83 */
     84 #define DelegateFilename  "delegates.xml"
     85 
     86 /*
     88   Declare delegate map.
     89 */
     90 static const char
     91   *DelegateMap = (const char *)
     92     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
     93     "<delegatemap>"
     94     "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
     95     "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
     96     "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;\"/>"
     97     "  <delegate decode=\"cgm\" thread-support=\"False\" command=\"&quot;ralcgm&quot; -d ps -oC &lt; &quot;%i&quot; &gt; &quot;%o&quot; 2&gt; &quot;%u&quot;\"/>"
     98     "  <delegate decode=\"dng:decode\" command=\"&quot;ufraw-batch&quot; --silent --create-id=also --out-type=png --out-depth=16 &quot;--output=%u.png&quot; &quot;%i&quot;\"/>"
     99     "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
    100     "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    101     "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    102     "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
    103     "  <delegate decode=\"hpg\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
    104     "  <delegate decode=\"hpgl\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
    105     "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
    106     "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
    107     "  <delegate decode=\"https\" command=\"&quot;curl&quot; -s -k -L -o &quot;%o&quot; &quot;https:%M&quot;\"/>"
    108     "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
    109     "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
    110     "  <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -nostdin -v -1 -vframes %S -i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%Z&quot;\"/>"
    111     "  <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -nostdin -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%Z&quot;\"/>"
    112     "  <delegate decode=\"pcl:color\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
    113     "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
    114     "  <delegate decode=\"pcl:mono\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
    115     "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    116     "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    117     "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
    118     "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
    119     "  <delegate decode=\"pov\" command=\"&quot;povray&quot; &quot;+i&quot;%i&quot;&quot; -D0 +o&quot;%o&quot; +fn%q +w%w +h%h +a -q9 -kfi&quot;%s&quot; -kff&quot;%n&quot;     &quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;\"/>"
    120     "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    121     "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
    122     "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
    123     "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pngalpha&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
    124     "  <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bbox&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
    125     "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
    126     "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
    127     "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
    128     "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
    129     "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
    130     "  <delegate encode=\"show\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -title &quot;%M&quot; &quot;%i&quot;\"/>"
    131     "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
    132     "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
    133     "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
    134     "  <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -title  &quot;%M&quot; &quot;%i&quot;\"/>"
    135     "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
    136     "</delegatemap>";
    137 
    138 /*
    140   Global declaractions.
    141 */
    142 static LinkedListInfo
    143   *delegate_cache = (LinkedListInfo *) NULL;
    144 
    145 static SemaphoreInfo
    146   *delegate_semaphore = (SemaphoreInfo *) NULL;
    147 
    148 /*
    150   Forward declaractions.
    151 */
    152 static MagickBooleanType
    153   IsDelegateCacheInstantiated(ExceptionInfo *),
    154   LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t,
    155     ExceptionInfo *);
    156 
    157 /*
    159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    160 %                                                                             %
    161 %                                                                             %
    162 %                                                                             %
    163 %  A c q u i r e D e l e g a t e C a c h e                                    %
    164 %                                                                             %
    165 %                                                                             %
    166 %                                                                             %
    167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    168 %
    169 %  AcquireDelegateCache() caches one or more delegate configurations which
    170 %  provides a mapping between delegate attributes and a delegate name.
    171 %
    172 %  The format of the AcquireDelegateCache method is:
    173 %
    174 %      LinkedListInfo *AcquireDelegateCache(const char *filename,
    175 %        ExceptionInfo *exception)
    176 %
    177 %  A description of each parameter follows:
    178 %
    179 %    o filename: the font file name.
    180 %
    181 %    o exception: return any errors or warnings in this structure.
    182 %
    183 */
    184 static LinkedListInfo *AcquireDelegateCache(const char *filename,
    185   ExceptionInfo *exception)
    186 {
    187   LinkedListInfo
    188     *cache;
    189 
    190   MagickStatusType
    191     status;
    192 
    193   cache=NewLinkedList(0);
    194   if (cache == (LinkedListInfo *) NULL)
    195     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    196   status=MagickTrue;
    197 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    198   {
    199     const StringInfo
    200       *option;
    201 
    202     LinkedListInfo
    203       *options;
    204 
    205     options=GetConfigureOptions(filename,exception);
    206     option=(const StringInfo *) GetNextValueInLinkedList(options);
    207     while (option != (const StringInfo *) NULL)
    208     {
    209       status&=LoadDelegateCache(cache,(const char *)
    210         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
    211       option=(const StringInfo *) GetNextValueInLinkedList(options);
    212     }
    213     options=DestroyConfigureOptions(options);
    214   }
    215 #endif
    216   if (IsLinkedListEmpty(cache) != MagickFalse)
    217     status&=LoadDelegateCache(cache,DelegateMap,"built-in",0,exception);
    218   return(cache);
    219 }
    220 
    221 /*
    223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    224 %                                                                             %
    225 %                                                                             %
    226 %                                                                             %
    227 +   D e l e g a t e C o m p o n e n t G e n e s i s                           %
    228 %                                                                             %
    229 %                                                                             %
    230 %                                                                             %
    231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    232 %
    233 %  DelegateComponentGenesis() instantiates the delegate component.
    234 %
    235 %  The format of the DelegateComponentGenesis method is:
    236 %
    237 %      MagickBooleanType DelegateComponentGenesis(void)
    238 %
    239 */
    240 MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
    241 {
    242   if (delegate_semaphore == (SemaphoreInfo *) NULL)
    243     delegate_semaphore=AcquireSemaphoreInfo();
    244   return(MagickTrue);
    245 }
    246 
    247 /*
    249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    250 %                                                                             %
    251 %                                                                             %
    252 %                                                                             %
    253 %   D e l e g a t e C o m p o n e n t T e r m i n u s                         %
    254 %                                                                             %
    255 %                                                                             %
    256 %                                                                             %
    257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    258 %
    259 %  DelegateComponentTerminus() destroys the delegate component.
    260 %
    261 %  The format of the DelegateComponentTerminus method is:
    262 %
    263 %      DelegateComponentTerminus(void)
    264 %
    265 */
    266 
    267 static void *DestroyDelegate(void *delegate_info)
    268 {
    269   register DelegateInfo
    270     *p;
    271 
    272   p=(DelegateInfo *) delegate_info;
    273   if (p->path != (char *) NULL)
    274     p->path=DestroyString(p->path);
    275   if (p->decode != (char *) NULL)
    276     p->decode=DestroyString(p->decode);
    277   if (p->encode != (char *) NULL)
    278     p->encode=DestroyString(p->encode);
    279   if (p->commands != (char *) NULL)
    280     p->commands=DestroyString(p->commands);
    281   if (p->semaphore != (SemaphoreInfo *) NULL)
    282     RelinquishSemaphoreInfo(&p->semaphore);
    283   p=(DelegateInfo *) RelinquishMagickMemory(p);
    284   return((void *) NULL);
    285 }
    286 
    287 MagickPrivate void DelegateComponentTerminus(void)
    288 {
    289   if (delegate_semaphore == (SemaphoreInfo *) NULL)
    290     ActivateSemaphoreInfo(&delegate_semaphore);
    291   LockSemaphoreInfo(delegate_semaphore);
    292   if (delegate_cache != (LinkedListInfo *) NULL)
    293     delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
    294   UnlockSemaphoreInfo(delegate_semaphore);
    295   RelinquishSemaphoreInfo(&delegate_semaphore);
    296 }
    297 
    298 /*
    300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    301 %                                                                             %
    302 %                                                                             %
    303 %                                                                             %
    304 +   E x t e r n a l D e l e g a t e C o m m a n d                             %
    305 %                                                                             %
    306 %                                                                             %
    307 %                                                                             %
    308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    309 %
    310 %  ExternalDelegateCommand() executes the specified command and waits until it
    311 %  terminates.  The returned value is the exit status of the command.
    312 %
    313 %  The format of the ExternalDelegateCommand method is:
    314 %
    315 %      int ExternalDelegateCommand(const MagickBooleanType asynchronous,
    316 %        const MagickBooleanType verbose,const char *command,
    317 %        char *message,ExceptionInfo *exception)
    318 %
    319 %  A description of each parameter follows:
    320 %
    321 %    o asynchronous: a value other than 0 executes the parent program
    322 %      concurrently with the new child process.
    323 %
    324 %    o verbose: a value other than 0 prints the executed command before it is
    325 %      invoked.
    326 %
    327 %    o command: this string is the command to execute.
    328 %
    329 %    o message: an option buffer to receive any message posted to stdout or
    330 %      stderr.
    331 %
    332 %    o exception: return any errors here.
    333 %
    334 */
    335 MagickExport int ExternalDelegateCommand(const MagickBooleanType asynchronous,
    336   const MagickBooleanType verbose,const char *command,char *message,
    337   ExceptionInfo *exception)
    338 {
    339   char
    340     **arguments,
    341     *sanitize_command;
    342 
    343   int
    344     number_arguments,
    345     status;
    346 
    347   PolicyDomain
    348     domain;
    349 
    350   PolicyRights
    351     rights;
    352 
    353   register ssize_t
    354     i;
    355 
    356   status=(-1);
    357   arguments=StringToArgv(command,&number_arguments);
    358   if (arguments == (char **) NULL)
    359     return(status);
    360   if (*arguments[1] == '\0')
    361     {
    362       for (i=0; i < (ssize_t) number_arguments; i++)
    363         arguments[i]=DestroyString(arguments[i]);
    364       arguments=(char **) RelinquishMagickMemory(arguments);
    365       return(-1);
    366     }
    367   rights=ExecutePolicyRights;
    368   domain=DelegatePolicyDomain;
    369   if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
    370     {
    371       errno=EPERM;
    372       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
    373         "NotAuthorized","`%s'",arguments[1]);
    374       for (i=0; i < (ssize_t) number_arguments; i++)
    375         arguments[i]=DestroyString(arguments[i]);
    376       arguments=(char **) RelinquishMagickMemory(arguments);
    377       return(-1);
    378     }
    379   if (verbose != MagickFalse)
    380     {
    381       (void) FormatLocaleFile(stderr,"%s\n",command);
    382       (void) fflush(stderr);
    383     }
    384   sanitize_command=SanitizeString(command);
    385   if (asynchronous != MagickFalse)
    386     (void) ConcatenateMagickString(sanitize_command,"&",MagickPathExtent);
    387   if (message != (char *) NULL)
    388     *message='\0';
    389 #if defined(MAGICKCORE_POSIX_SUPPORT)
    390 #if !defined(MAGICKCORE_HAVE_EXECVP)
    391   status=system(sanitize_command);
    392 #else
    393   if ((asynchronous != MagickFalse) ||
    394       (strpbrk(sanitize_command,"&;<>|") != (char *) NULL))
    395     status=system(sanitize_command);
    396   else
    397     {
    398       pid_t
    399         child_pid;
    400 
    401       /*
    402         Call application directly rather than from a shell.
    403       */
    404       child_pid=(pid_t) fork();
    405       if (child_pid == (pid_t) -1)
    406         status=system(sanitize_command);
    407       else
    408         if (child_pid == 0)
    409           {
    410             status=execvp(arguments[1],arguments+1);
    411             _exit(1);
    412           }
    413         else
    414           {
    415             int
    416               child_status;
    417 
    418             pid_t
    419               pid;
    420 
    421             child_status=0;
    422             pid=(pid_t) waitpid(child_pid,&child_status,0);
    423             if (pid == -1)
    424               status=(-1);
    425             else
    426               {
    427                 if (WIFEXITED(child_status) != 0)
    428                   status=WEXITSTATUS(child_status);
    429                 else
    430                   if (WIFSIGNALED(child_status))
    431                     status=(-1);
    432               }
    433           }
    434     }
    435 #endif
    436 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    437   {
    438     register char
    439       *p;
    440 
    441     /*
    442       If a command shell is executed we need to change the forward slashes in
    443       files to a backslash. We need to do this to keep Windows happy when we
    444       want to 'move' a file.
    445 
    446       TODO: This won't work if one of the delegate parameters has a forward
    447             slash as aparameter.
    448     */
    449     p=strstr(sanitize_command, "cmd.exe /c");
    450     if (p != (char*) NULL)
    451       {
    452         p+=10;
    453         for (; *p != '\0'; p++)
    454           if (*p == '/')
    455             *p=*DirectorySeparator;
    456       }
    457   }
    458   status=NTSystemCommand(sanitize_command,message);
    459 #elif defined(macintosh)
    460   status=MACSystemCommand(sanitize_command);
    461 #elif defined(vms)
    462   status=system(sanitize_command);
    463 #else
    464 #  error No suitable system() method.
    465 #endif
    466   if (status < 0)
    467     {
    468       if ((message != (char *) NULL) && (*message != '\0'))
    469         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
    470           "FailedToExecuteCommand","`%s' (%s)",sanitize_command,message);
    471       else
    472         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
    473           "FailedToExecuteCommand","`%s' (%d)",sanitize_command,status);
    474     }
    475   sanitize_command=DestroyString(sanitize_command);
    476   for (i=0; i < (ssize_t) number_arguments; i++)
    477     arguments[i]=DestroyString(arguments[i]);
    478   arguments=(char **) RelinquishMagickMemory(arguments);
    479   return(status);
    480 }
    481 
    482 /*
    484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    485 %                                                                             %
    486 %                                                                             %
    487 %                                                                             %
    488 %   G e t D e l e g a t e C o m m a n d                                       %
    489 %                                                                             %
    490 %                                                                             %
    491 %                                                                             %
    492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    493 %
    494 %  GetDelegateCommand() replaces any embedded formatting characters with the
    495 %  appropriate image attribute and returns the resulting command.
    496 %
    497 %  The format of the GetDelegateCommand method is:
    498 %
    499 %      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
    500 %        const char *decode,const char *encode,ExceptionInfo *exception)
    501 %
    502 %  A description of each parameter follows:
    503 %
    504 %    o command: Method GetDelegateCommand returns the command associated
    505 %      with specified delegate tag.
    506 %
    507 %    o image_info: the image info.
    508 %
    509 %    o image: the image.
    510 %
    511 %    o decode: Specifies the decode delegate we are searching for as a
    512 %      character string.
    513 %
    514 %    o encode: Specifies the encode delegate we are searching for as a
    515 %      character string.
    516 %
    517 %    o exception: return any errors or warnings in this structure.
    518 %
    519 */
    520 
    521 static char *GetMagickPropertyLetter(ImageInfo *image_info,Image *image,
    522   const char letter,ExceptionInfo *exception)
    523 {
    524 #define WarnNoImageReturn(format,letter) \
    525   if (image == (Image *) NULL) \
    526     { \
    527       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
    528         "NoImageForProperty",format,letter); \
    529       break; \
    530     }
    531 #define WarnNoImageInfoReturn(format,letter) \
    532   if (image_info == (ImageInfo *) NULL) \
    533     { \
    534       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
    535         "NoImageInfoForProperty",format,letter); \
    536       break; \
    537     }
    538 
    539   char
    540     value[MagickPathExtent];
    541 
    542   const char
    543     *string;
    544 
    545   if ((image != (Image *) NULL) && (image->debug != MagickFalse))
    546     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    547   else
    548     if ((image_info != (ImageInfo *) NULL) &&
    549         (image_info->debug != MagickFalse))
    550       (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
    551   /*
    552     Get properties that are directly defined by images.
    553   */
    554   *value='\0';           /* formatted string */
    555   string=(const char *) value;
    556   switch (letter)
    557   {
    558     case 'a': /* authentication passphase */
    559     {
    560       WarnNoImageInfoReturn("\"%%%c\"",letter);
    561       string=GetImageOption(image_info,"authenticate");
    562       break;
    563     }
    564     case 'b':  /* image size read in - in bytes */
    565     {
    566       WarnNoImageReturn("\"%%%c\"",letter);
    567       (void) FormatMagickSize(image->extent,MagickFalse,"B",MagickPathExtent,
    568         value);
    569       if (image->extent == 0)
    570         (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
    571           MagickPathExtent,value);
    572       break;
    573     }
    574     case 'd':  /* Directory component of filename */
    575     {
    576       WarnNoImageReturn("\"%%%c\"",letter);
    577       GetPathComponent(image->magick_filename,HeadPath,value);
    578       break;
    579     }
    580     case 'e': /* Filename extension (suffix) of image file */
    581     {
    582       WarnNoImageReturn("\"%%%c\"",letter);
    583       GetPathComponent(image->magick_filename,ExtensionPath,value);
    584       break;
    585     }
    586     case 'f': /* Filename without directory component */
    587     {
    588       WarnNoImageReturn("\"%%%c\"",letter);
    589       GetPathComponent(image->magick_filename,TailPath,value);
    590       break;
    591     }
    592     case 'g': /* Image geometry, canvas and offset  %Wx%H+%X+%Y */
    593     {
    594       WarnNoImageReturn("\"%%%c\"",letter);
    595       (void) FormatLocaleString(value,MagickPathExtent,
    596         "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
    597         image->page.height,(double) image->page.x,(double) image->page.y);
    598       break;
    599     }
    600     case 'h': /* Image height (current) */
    601     {
    602       WarnNoImageReturn("\"%%%c\"",letter);
    603       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    604         (image->rows != 0 ? image->rows : image->magick_rows));
    605       break;
    606     }
    607     case 'i': /* Filename last used for an image (read or write) */
    608     {
    609       WarnNoImageReturn("\"%%%c\"",letter);
    610       string=image->filename;
    611       break;
    612     }
    613     case 'm': /* Image format (file magick) */
    614     {
    615       WarnNoImageReturn("\"%%%c\"",letter);
    616       string=image->magick;
    617       break;
    618     }
    619     case 'n': /* Number of images in the list.  */
    620     {
    621       if (image != (Image *) NULL)
    622         (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    623           GetImageListLength(image));
    624       break;
    625     }
    626     case 'o': /* Output Filename */
    627     {
    628       WarnNoImageInfoReturn("\"%%%c\"",letter);
    629       string=image_info->filename;
    630       break;
    631     }
    632     case 'p': /* Image index in current image list */
    633     {
    634       WarnNoImageReturn("\"%%%c\"",letter);
    635       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    636         GetImageIndexInList(image));
    637       break;
    638     }
    639     case 'q': /* Quantum depth of image in memory */
    640     {
    641       WarnNoImageReturn("\"%%%c\"",letter);
    642       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    643         MAGICKCORE_QUANTUM_DEPTH);
    644       break;
    645     }
    646     case 'r': /* Image storage class, colorspace, and alpha enabled.  */
    647     {
    648       ColorspaceType
    649         colorspace;
    650 
    651       WarnNoImageReturn("\"%%%c\"",letter);
    652       colorspace=image->colorspace;
    653       if (SetImageGray(image,exception) != MagickFalse)
    654         colorspace=GRAYColorspace;   /* FUTURE: this is IMv6 not IMv7 */
    655       (void) FormatLocaleString(value,MagickPathExtent,"%s %s %s",
    656         CommandOptionToMnemonic(MagickClassOptions,(ssize_t)
    657         image->storage_class),CommandOptionToMnemonic(MagickColorspaceOptions,
    658         (ssize_t) colorspace),image->alpha_trait != UndefinedPixelTrait ?
    659         "Alpha" : "");
    660       break;
    661     }
    662     case 's': /* Image scene number */
    663     {
    664       WarnNoImageReturn("\"%%%c\"",letter);
    665       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    666         image->scene);
    667       break;
    668     }
    669     case 't': /* Base filename without directory or extention */
    670     {
    671       WarnNoImageReturn("\"%%%c\"",letter);
    672       GetPathComponent(image->magick_filename,BasePath,value);
    673       break;
    674     }
    675     case 'u': /* Unique filename */
    676     {
    677       WarnNoImageInfoReturn("\"%%%c\"",letter);
    678       string=image_info->unique;
    679       break;
    680     }
    681     case 'w': /* Image width (current) */
    682     {
    683       WarnNoImageReturn("\"%%%c\"",letter);
    684       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    685         (image->columns != 0 ? image->columns : image->magick_columns));
    686       break;
    687     }
    688     case 'x': /* Image horizontal resolution (with units) */
    689     {
    690       WarnNoImageReturn("\"%%%c\"",letter);
    691       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
    692         fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0);
    693       break;
    694     }
    695     case 'y': /* Image vertical resolution (with units) */
    696     {
    697       WarnNoImageReturn("\"%%%c\"",letter);
    698       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
    699         fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0);
    700       break;
    701     }
    702     case 'z': /* Image depth as read in */
    703     {
    704       WarnNoImageReturn("\"%%%c\"",letter);
    705       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
    706         (double) image->depth);
    707       break;
    708     }
    709     case 'A': /* Image alpha channel  */
    710     {
    711       WarnNoImageReturn("\"%%%c\"",letter);
    712       string=CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
    713         image->alpha_trait);
    714       break;
    715     }
    716     case 'C': /* Image compression method.  */
    717     {
    718       WarnNoImageReturn("\"%%%c\"",letter);
    719       string=CommandOptionToMnemonic(MagickCompressOptions,
    720         (ssize_t) image->compression);
    721       break;
    722     }
    723     case 'D': /* Image dispose method.  */
    724     {
    725       WarnNoImageReturn("\"%%%c\"",letter);
    726       string=CommandOptionToMnemonic(MagickDisposeOptions,
    727         (ssize_t) image->dispose);
    728       break;
    729     }
    730     case 'F':
    731     {
    732       /*
    733         Magick filename - filename given incl. coder & read mods.
    734       */
    735       WarnNoImageReturn("\"%%%c\"",letter);
    736       (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
    737       break;
    738     }
    739     case 'G': /* Image size as geometry = "%wx%h" */
    740     {
    741       WarnNoImageReturn("\"%%%c\"",letter);
    742       (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
    743         (double) image->magick_columns,(double) image->magick_rows);
    744       break;
    745     }
    746     case 'H': /* layer canvas height */
    747     {
    748       WarnNoImageReturn("\"%%%c\"",letter);
    749       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
    750         (double) image->page.height);
    751       break;
    752     }
    753     case 'M': /* Magick filename - filename given incl. coder & read mods */
    754     {
    755       WarnNoImageReturn("\"%%%c\"",letter);
    756       string=image->magick_filename;
    757       break;
    758     }
    759     case 'O': /* layer canvas offset with sign = "+%X+%Y" */
    760     {
    761       WarnNoImageReturn("\"%%%c\"",letter);
    762       (void) FormatLocaleString(value,MagickPathExtent,"%+ld%+ld",(long)
    763         image->page.x,(long) image->page.y);
    764       break;
    765     }
    766     case 'P': /* layer canvas page size = "%Wx%H" */
    767     {
    768       WarnNoImageReturn("\"%%%c\"",letter);
    769       (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
    770         (double) image->page.width,(double) image->page.height);
    771       break;
    772     }
    773     case 'Q': /* image compression quality */
    774     {
    775       WarnNoImageReturn("\"%%%c\"",letter);
    776       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    777         (image->quality == 0 ? 92 : image->quality));
    778       break;
    779     }
    780     case 'S': /* Number of scenes in image list.  */
    781     {
    782       WarnNoImageInfoReturn("\"%%%c\"",letter);
    783       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    784         (image_info->number_scenes == 0 ? 2147483647 :
    785          image_info->number_scenes));
    786       break;
    787     }
    788     case 'T': /* image time delay for animations */
    789     {
    790       WarnNoImageReturn("\"%%%c\"",letter);
    791       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    792         image->delay);
    793       break;
    794     }
    795     case 'U': /* Image resolution units. */
    796     {
    797       WarnNoImageReturn("\"%%%c\"",letter);
    798       string=CommandOptionToMnemonic(MagickResolutionOptions,
    799         (ssize_t) image->units);
    800       break;
    801     }
    802     case 'W': /* layer canvas width */
    803     {
    804       WarnNoImageReturn("\"%%%c\"",letter);
    805       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
    806         image->page.width);
    807       break;
    808     }
    809     case 'X': /* layer canvas X offset */
    810     {
    811       WarnNoImageReturn("\"%%%c\"",letter);
    812       (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
    813         image->page.x);
    814       break;
    815     }
    816     case 'Y': /* layer canvas Y offset */
    817     {
    818       WarnNoImageReturn("\"%%%c\"",letter);
    819       (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
    820         image->page.y);
    821       break;
    822     }
    823     case '%': /* percent escaped */
    824     {
    825       string="%";
    826       break;
    827     }
    828     case '@': /* Trim bounding box, without actually trimming! */
    829     {
    830       RectangleInfo
    831         page;
    832 
    833       WarnNoImageReturn("\"%%%c\"",letter);
    834       page=GetImageBoundingBox(image,exception);
    835       (void) FormatLocaleString(value,MagickPathExtent,
    836         "%.20gx%.20g%+.20g%+.20g",(double) page.width,(double) page.height,
    837         (double) page.x,(double) page.y);
    838       break;
    839     }
    840     case '#':
    841     {
    842       /*
    843         Image signature.
    844       */
    845       WarnNoImageReturn("\"%%%c\"",letter);
    846       (void) SignatureImage(image,exception);
    847       string=GetImageProperty(image,"signature",exception);
    848       break;
    849     }
    850   }
    851   return(SanitizeString(string));
    852 }
    853 
    854 static char *InterpretDelegateProperties(ImageInfo *image_info,
    855   Image *image,const char *embed_text,ExceptionInfo *exception)
    856 {
    857 #define ExtendInterpretText(string_length) \
    858 DisableMSCWarning(4127) \
    859 { \
    860   size_t length=(string_length); \
    861   if ((size_t) (q-interpret_text+length+1) >= extent) \
    862     { \
    863       extent+=length; \
    864       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
    865         MaxTextExtent,sizeof(*interpret_text)); \
    866       if (interpret_text == (char *) NULL) \
    867         return((char *) NULL); \
    868       q=interpret_text+strlen(interpret_text); \
    869    } \
    870 } \
    871 RestoreMSCWarning
    872 
    873 #define AppendKeyValue2Text(key,value)\
    874 DisableMSCWarning(4127) \
    875 { \
    876   size_t length=strlen(key)+strlen(value)+2; \
    877   if ((size_t) (q-interpret_text+length+1) >= extent) \
    878     { \
    879       extent+=length; \
    880       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
    881         MaxTextExtent,sizeof(*interpret_text)); \
    882       if (interpret_text == (char *) NULL) \
    883         return((char *) NULL); \
    884       q=interpret_text+strlen(interpret_text); \
    885      } \
    886    q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(value)); \
    887 } \
    888 RestoreMSCWarning
    889 
    890 #define AppendString2Text(string) \
    891 DisableMSCWarning(4127) \
    892 { \
    893   size_t length=strlen((string)); \
    894   if ((size_t) (q-interpret_text+length+1) >= extent) \
    895     { \
    896       extent+=length; \
    897       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
    898         MaxTextExtent,sizeof(*interpret_text)); \
    899       if (interpret_text == (char *) NULL) \
    900         return((char *) NULL); \
    901       q=interpret_text+strlen(interpret_text); \
    902     } \
    903   (void) CopyMagickString(q,(string),extent); \
    904   q+=length; \
    905 } \
    906 RestoreMSCWarning
    907 
    908   char
    909     *interpret_text,
    910     *string;
    911 
    912   register char
    913     *q;  /* current position in interpret_text */
    914 
    915   register const char
    916     *p;  /* position in embed_text string being expanded */
    917 
    918   size_t
    919     extent;  /* allocated length of interpret_text */
    920 
    921   MagickBooleanType
    922     number;
    923 
    924   assert(image == NULL || image->signature == MagickCoreSignature);
    925   assert(image_info == NULL || image_info->signature == MagickCoreSignature);
    926   if ((image != (Image *) NULL) && (image->debug != MagickFalse))
    927     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    928   else
    929    if ((image_info != (ImageInfo *) NULL) && (image_info->debug != MagickFalse))
    930      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-image");
    931   if (embed_text == (const char *) NULL)
    932     return(ConstantString(""));
    933   p=embed_text;
    934   while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0'))
    935     p++;
    936   if (*p == '\0')
    937     return(ConstantString(""));
    938   /*
    939     Translate any embedded format characters.
    940   */
    941   interpret_text=AcquireString(embed_text);  /* new string with extra space */
    942   extent=MagickPathExtent;  /* allocated space in string */
    943   number=MagickFalse;  /* is last char a number? */
    944   for (q=interpret_text; *p!='\0';
    945     number=isdigit(*p) ? MagickTrue : MagickFalse,p++)
    946   {
    947     /*
    948       Interpret escape characters (e.g. Filename: %M).
    949     */
    950     *q='\0';
    951     ExtendInterpretText(MagickPathExtent);
    952     switch (*p)
    953     {
    954       case '\\':
    955       {
    956         switch (*(p+1))
    957         {
    958           case '\0':
    959             continue;
    960           case 'r':  /* convert to RETURN */
    961           {
    962             *q++='\r';
    963             p++;
    964             continue;
    965           }
    966           case 'n':  /* convert to NEWLINE */
    967           {
    968             *q++='\n';
    969             p++;
    970             continue;
    971           }
    972           case '\n':  /* EOL removal UNIX,MacOSX */
    973           {
    974             p++;
    975             continue;
    976           }
    977           case '\r':  /* EOL removal DOS,Windows */
    978           {
    979             p++;
    980             if (*p == '\n') /* return-newline EOL */
    981               p++;
    982             continue;
    983           }
    984           default:
    985           {
    986             p++;
    987             *q++=(*p);
    988           }
    989         }
    990         continue;
    991       }
    992       case '&':
    993       {
    994         if (LocaleNCompare("&lt;",p,4) == 0)
    995           {
    996             *q++='<';
    997             p+=3;
    998           }
    999         else
   1000           if (LocaleNCompare("&gt;",p,4) == 0)
   1001             {
   1002               *q++='>';
   1003               p+=3;
   1004             }
   1005           else
   1006             if (LocaleNCompare("&amp;",p,5) == 0)
   1007               {
   1008                 *q++='&';
   1009                 p+=4;
   1010               }
   1011             else
   1012               *q++=(*p);
   1013         continue;
   1014       }
   1015       case '%':
   1016         break;  /* continue to next set of handlers */
   1017       default:
   1018       {
   1019         *q++=(*p);  /* any thing else is 'as normal' */
   1020         continue;
   1021       }
   1022     }
   1023     p++; /* advance beyond the percent */
   1024     /*
   1025       Doubled Percent - or percent at end of string.
   1026     */
   1027     if ((*p == '\0') || (*p == '\'') || (*p == '"'))
   1028       p--;
   1029     if (*p == '%')
   1030       {
   1031         *q++='%';
   1032         continue;
   1033       }
   1034     /*
   1035       Single letter escapes %c.
   1036     */
   1037     if (number != MagickFalse)
   1038       {
   1039         /*
   1040           But only if not preceeded by a number!
   1041         */
   1042         *q++='%'; /* do NOT substitute the percent */
   1043         p--;      /* back up one */
   1044         continue;
   1045       }
   1046     string=GetMagickPropertyLetter(image_info,image,*p, exception);
   1047     if (string != (char *) NULL)
   1048       {
   1049         AppendString2Text(string);
   1050         string=DestroyString(string);
   1051         continue;
   1052       }
   1053     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
   1054       "UnknownImageProperty","\"%%%c\"",*p);
   1055   }
   1056   *q='\0';
   1057   return(interpret_text);
   1058 }
   1059 
   1060 MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
   1061   const char *decode,const char *encode,ExceptionInfo *exception)
   1062 {
   1063   char
   1064     *command,
   1065     **commands;
   1066 
   1067   const DelegateInfo
   1068     *delegate_info;
   1069 
   1070   register ssize_t
   1071     i;
   1072 
   1073   assert(image_info != (ImageInfo *) NULL);
   1074   assert(image_info->signature == MagickCoreSignature);
   1075   assert(image != (Image *) NULL);
   1076   assert(image->signature == MagickCoreSignature);
   1077   if (image->debug != MagickFalse)
   1078     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1079 
   1080   delegate_info=GetDelegateInfo(decode,encode,exception);
   1081   if (delegate_info == (const DelegateInfo *) NULL)
   1082     {
   1083       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
   1084         "NoTagFound","`%s'",decode ? decode : encode);
   1085       return((char *) NULL);
   1086     }
   1087   commands=StringToList(delegate_info->commands);
   1088   if (commands == (char **) NULL)
   1089     {
   1090       (void) ThrowMagickException(exception,GetMagickModule(),
   1091         ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
   1092         encode);
   1093       return((char *) NULL);
   1094     }
   1095   command=InterpretDelegateProperties((ImageInfo *) image_info,image,
   1096     commands[0],exception);
   1097   if (command == (char *) NULL)
   1098     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
   1099       "MemoryAllocationFailed","`%s'",commands[0]);
   1100   /*
   1101     Relinquish resources.
   1102   */
   1103   for (i=0; commands[i] != (char *) NULL; i++)
   1104     commands[i]=DestroyString(commands[i]);
   1105   commands=(char **) RelinquishMagickMemory(commands);
   1106   return(command);
   1107 }
   1108 
   1109 /*
   1111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1112 %                                                                             %
   1113 %                                                                             %
   1114 %                                                                             %
   1115 %   G e t D e l e g a t e C o m m a n d s                                     %
   1116 %                                                                             %
   1117 %                                                                             %
   1118 %                                                                             %
   1119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1120 %
   1121 %  GetDelegateCommands() returns the commands associated with a delegate.
   1122 %
   1123 %  The format of the GetDelegateCommands method is:
   1124 %
   1125 %      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
   1126 %
   1127 %  A description of each parameter follows:
   1128 %
   1129 %    o delegate_info:  The delegate info.
   1130 %
   1131 */
   1132 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
   1133 {
   1134   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   1135 
   1136   assert(delegate_info != (DelegateInfo *) NULL);
   1137   assert(delegate_info->signature == MagickCoreSignature);
   1138   return(delegate_info->commands);
   1139 }
   1140 
   1141 /*
   1143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1144 %                                                                             %
   1145 %                                                                             %
   1146 %                                                                             %
   1147 %   G e t D e l e g a t e I n f o                                             %
   1148 %                                                                             %
   1149 %                                                                             %
   1150 %                                                                             %
   1151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1152 %
   1153 %  GetDelegateInfo() returns any delegates associated with the specified tag.
   1154 %
   1155 %  The format of the GetDelegateInfo method is:
   1156 %
   1157 %      const DelegateInfo *GetDelegateInfo(const char *decode,
   1158 %        const char *encode,ExceptionInfo *exception)
   1159 %
   1160 %  A description of each parameter follows:
   1161 %
   1162 %    o decode: Specifies the decode delegate we are searching for as a
   1163 %      character string.
   1164 %
   1165 %    o encode: Specifies the encode delegate we are searching for as a
   1166 %      character string.
   1167 %
   1168 %    o exception: return any errors or warnings in this structure.
   1169 %
   1170 */
   1171 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
   1172   const char *encode,ExceptionInfo *exception)
   1173 {
   1174   register const DelegateInfo
   1175     *p;
   1176 
   1177   assert(exception != (ExceptionInfo *) NULL);
   1178   if (IsDelegateCacheInstantiated(exception) == MagickFalse)
   1179     return((const DelegateInfo *) NULL);
   1180   /*
   1181     Search for named delegate.
   1182   */
   1183   LockSemaphoreInfo(delegate_semaphore);
   1184   ResetLinkedListIterator(delegate_cache);
   1185   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1186   if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
   1187     {
   1188       UnlockSemaphoreInfo(delegate_semaphore);
   1189       return(p);
   1190     }
   1191   while (p != (const DelegateInfo *) NULL)
   1192   {
   1193     if (p->mode > 0)
   1194       {
   1195         if (LocaleCompare(p->decode,decode) == 0)
   1196           break;
   1197         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1198         continue;
   1199       }
   1200     if (p->mode < 0)
   1201       {
   1202         if (LocaleCompare(p->encode,encode) == 0)
   1203           break;
   1204         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1205         continue;
   1206       }
   1207     if (LocaleCompare(decode,p->decode) == 0)
   1208       if (LocaleCompare(encode,p->encode) == 0)
   1209         break;
   1210     if (LocaleCompare(decode,"*") == 0)
   1211       if (LocaleCompare(encode,p->encode) == 0)
   1212         break;
   1213     if (LocaleCompare(decode,p->decode) == 0)
   1214       if (LocaleCompare(encode,"*") == 0)
   1215         break;
   1216     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1217   }
   1218   if (p != (const DelegateInfo *) NULL)
   1219     (void) InsertValueInLinkedList(delegate_cache,0,
   1220       RemoveElementByValueFromLinkedList(delegate_cache,p));
   1221   UnlockSemaphoreInfo(delegate_semaphore);
   1222   return(p);
   1223 }
   1224 
   1225 /*
   1227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1228 %                                                                             %
   1229 %                                                                             %
   1230 %                                                                             %
   1231 %   G e t D e l e g a t e I n f o L i s t                                     %
   1232 %                                                                             %
   1233 %                                                                             %
   1234 %                                                                             %
   1235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1236 %
   1237 %  GetDelegateInfoList() returns any delegates that match the specified pattern.
   1238 %
   1239 %  The delegate of the GetDelegateInfoList function is:
   1240 %
   1241 %      const DelegateInfo **GetDelegateInfoList(const char *pattern,
   1242 %        size_t *number_delegates,ExceptionInfo *exception)
   1243 %
   1244 %  A description of each parameter follows:
   1245 %
   1246 %    o pattern: Specifies a pointer to a text string containing a pattern.
   1247 %
   1248 %    o number_delegates:  This integer returns the number of delegates in the
   1249 %      list.
   1250 %
   1251 %    o exception: return any errors or warnings in this structure.
   1252 %
   1253 */
   1254 
   1255 #if defined(__cplusplus) || defined(c_plusplus)
   1256 extern "C" {
   1257 #endif
   1258 
   1259 static int DelegateInfoCompare(const void *x,const void *y)
   1260 {
   1261   const DelegateInfo
   1262     **p,
   1263     **q;
   1264 
   1265   int
   1266     cmp;
   1267 
   1268   p=(const DelegateInfo **) x,
   1269   q=(const DelegateInfo **) y;
   1270   cmp=LocaleCompare((*p)->path,(*q)->path);
   1271   if (cmp == 0)
   1272     {
   1273       if ((*p)->decode == (char *) NULL)
   1274         if (((*p)->encode != (char *) NULL) &&
   1275             ((*q)->encode != (char *) NULL))
   1276           return(strcmp((*p)->encode,(*q)->encode));
   1277       if (((*p)->decode != (char *) NULL) &&
   1278           ((*q)->decode != (char *) NULL))
   1279         return(strcmp((*p)->decode,(*q)->decode));
   1280     }
   1281   return(cmp);
   1282 }
   1283 
   1284 #if defined(__cplusplus) || defined(c_plusplus)
   1285 }
   1286 #endif
   1287 
   1288 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
   1289   size_t *number_delegates,ExceptionInfo *exception)
   1290 {
   1291   const DelegateInfo
   1292     **delegates;
   1293 
   1294   register const DelegateInfo
   1295     *p;
   1296 
   1297   register ssize_t
   1298     i;
   1299 
   1300   /*
   1301     Allocate delegate list.
   1302   */
   1303   assert(number_delegates != (size_t *) NULL);
   1304   assert(pattern != (char *) NULL);
   1305   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
   1306 
   1307   *number_delegates=0;
   1308   p=GetDelegateInfo("*","*",exception);
   1309   if (p == (const DelegateInfo *) NULL)
   1310     return((const DelegateInfo **) NULL);
   1311   delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
   1312     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
   1313   if (delegates == (const DelegateInfo **) NULL)
   1314     return((const DelegateInfo **) NULL);
   1315   /*
   1316     Generate delegate list.
   1317   */
   1318   LockSemaphoreInfo(delegate_semaphore);
   1319   ResetLinkedListIterator(delegate_cache);
   1320   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1321   for (i=0; p != (const DelegateInfo *) NULL; )
   1322   {
   1323     if( (p->stealth == MagickFalse) &&
   1324         ( GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse ||
   1325           GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse) )
   1326       delegates[i++]=p;
   1327     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1328   }
   1329   UnlockSemaphoreInfo(delegate_semaphore);
   1330   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
   1331   delegates[i]=(DelegateInfo *) NULL;
   1332   *number_delegates=(size_t) i;
   1333   return(delegates);
   1334 }
   1335 
   1336 /*
   1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1339 %                                                                             %
   1340 %                                                                             %
   1341 %                                                                             %
   1342 %   G e t D e l e g a t e L i s t                                             %
   1343 %                                                                             %
   1344 %                                                                             %
   1345 %                                                                             %
   1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1347 %
   1348 %  GetDelegateList() returns any image format delegates that match the
   1349 %  specified  pattern.
   1350 %
   1351 %  The format of the GetDelegateList function is:
   1352 %
   1353 %      char **GetDelegateList(const char *pattern,
   1354 %        size_t *number_delegates,ExceptionInfo *exception)
   1355 %
   1356 %  A description of each parameter follows:
   1357 %
   1358 %    o pattern: Specifies a pointer to a text string containing a pattern.
   1359 %
   1360 %    o number_delegates:  This integer returns the number of delegates
   1361 %      in the list.
   1362 %
   1363 %    o exception: return any errors or warnings in this structure.
   1364 %
   1365 */
   1366 
   1367 #if defined(__cplusplus) || defined(c_plusplus)
   1368 extern "C" {
   1369 #endif
   1370 
   1371 static int DelegateCompare(const void *x,const void *y)
   1372 {
   1373   register const char
   1374     **p,
   1375     **q;
   1376 
   1377   p=(const char **) x;
   1378   q=(const char **) y;
   1379   return(LocaleCompare(*p,*q));
   1380 }
   1381 
   1382 #if defined(__cplusplus) || defined(c_plusplus)
   1383 }
   1384 #endif
   1385 
   1386 MagickExport char **GetDelegateList(const char *pattern,
   1387   size_t *number_delegates,ExceptionInfo *exception)
   1388 {
   1389   char
   1390     **delegates;
   1391 
   1392   register const DelegateInfo
   1393     *p;
   1394 
   1395   register ssize_t
   1396     i;
   1397 
   1398   /*
   1399     Allocate delegate list.
   1400   */
   1401   assert(pattern != (char *) NULL);
   1402   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
   1403 
   1404   assert(number_delegates != (size_t *) NULL);
   1405   *number_delegates=0;
   1406   p=GetDelegateInfo("*","*",exception);
   1407   if (p == (const DelegateInfo *) NULL)
   1408     return((char **) NULL);
   1409   delegates=(char **) AcquireQuantumMemory((size_t)
   1410     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
   1411   if (delegates == (char **) NULL)
   1412     return((char **) NULL);
   1413   LockSemaphoreInfo(delegate_semaphore);
   1414   ResetLinkedListIterator(delegate_cache);
   1415   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1416   for (i=0; p != (const DelegateInfo *) NULL; )
   1417   {
   1418     if( (p->stealth == MagickFalse) &&
   1419         GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse )
   1420       delegates[i++]=ConstantString(p->decode);
   1421     if( (p->stealth == MagickFalse) &&
   1422         GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse )
   1423       delegates[i++]=ConstantString(p->encode);
   1424     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
   1425   }
   1426   UnlockSemaphoreInfo(delegate_semaphore);
   1427   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
   1428   delegates[i]=(char *) NULL;
   1429   *number_delegates=(size_t) i;
   1430   return(delegates);
   1431 }
   1432 
   1433 /*
   1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1436 %                                                                             %
   1437 %                                                                             %
   1438 %                                                                             %
   1439 %   G e t D e l e g a t e M o d e                                             %
   1440 %                                                                             %
   1441 %                                                                             %
   1442 %                                                                             %
   1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1444 %
   1445 %  GetDelegateMode() returns the mode of the delegate.
   1446 %
   1447 %  The format of the GetDelegateMode method is:
   1448 %
   1449 %      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
   1450 %
   1451 %  A description of each parameter follows:
   1452 %
   1453 %    o delegate_info:  The delegate info.
   1454 %
   1455 */
   1456 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
   1457 {
   1458   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   1459 
   1460   assert(delegate_info != (DelegateInfo *) NULL);
   1461   assert(delegate_info->signature == MagickCoreSignature);
   1462   return(delegate_info->mode);
   1463 }
   1464 
   1465 /*
   1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1468 %                                                                             %
   1469 %                                                                             %
   1470 %                                                                             %
   1471 +   G e t D e l e g a t e T h r e a d S u p p o r t                           %
   1472 %                                                                             %
   1473 %                                                                             %
   1474 %                                                                             %
   1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1476 %
   1477 %  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
   1478 %  threads.
   1479 %
   1480 %  The format of the GetDelegateThreadSupport method is:
   1481 %
   1482 %      MagickBooleanType GetDelegateThreadSupport(
   1483 %        const DelegateInfo *delegate_info)
   1484 %
   1485 %  A description of each parameter follows:
   1486 %
   1487 %    o delegate_info:  The delegate info.
   1488 %
   1489 */
   1490 MagickExport MagickBooleanType GetDelegateThreadSupport(
   1491   const DelegateInfo *delegate_info)
   1492 {
   1493   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   1494 
   1495   assert(delegate_info != (DelegateInfo *) NULL);
   1496   assert(delegate_info->signature == MagickCoreSignature);
   1497   return(delegate_info->thread_support);
   1498 }
   1499 
   1500 /*
   1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1503 %                                                                             %
   1504 %                                                                             %
   1505 %                                                                             %
   1506 +   I s D e l e g a t e C a c h e I n s t a n t i a t e d                     %
   1507 %                                                                             %
   1508 %                                                                             %
   1509 %                                                                             %
   1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1511 %
   1512 %  IsDelegateCacheInstantiated() determines if the delegate cache is
   1513 %  instantiated.  If not, it instantiates the cache and returns it.
   1514 %
   1515 %  The format of the IsDelegateInstantiated method is:
   1516 %
   1517 %      MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
   1518 %
   1519 %  A description of each parameter follows.
   1520 %
   1521 %    o exception: return any errors or warnings in this structure.
   1522 %
   1523 */
   1524 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
   1525 {
   1526   if (delegate_cache == (LinkedListInfo *) NULL)
   1527     {
   1528       if (delegate_semaphore == (SemaphoreInfo *) NULL)
   1529         ActivateSemaphoreInfo(&delegate_semaphore);
   1530       LockSemaphoreInfo(delegate_semaphore);
   1531       if (delegate_cache == (LinkedListInfo *) NULL)
   1532         delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
   1533       UnlockSemaphoreInfo(delegate_semaphore);
   1534     }
   1535   return(delegate_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
   1536 }
   1537 
   1538 /*
   1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1541 %                                                                             %
   1542 %                                                                             %
   1543 %                                                                             %
   1544 %   I n v o k e D e l e g a t e                                               %
   1545 %                                                                             %
   1546 %                                                                             %
   1547 %                                                                             %
   1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1549 %
   1550 %  InvokeDelegate replaces any embedded formatting characters with the
   1551 %  appropriate image attribute and executes the resulting command.  MagickFalse
   1552 %  is returned if the commands execute with success otherwise MagickTrue.
   1553 %
   1554 %  The format of the InvokeDelegate method is:
   1555 %
   1556 %      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
   1557 %        const char *decode,const char *encode,ExceptionInfo *exception)
   1558 %
   1559 %  A description of each parameter follows:
   1560 %
   1561 %    o image_info: the imageInfo.
   1562 %
   1563 %    o image: the image.
   1564 %
   1565 %    o exception: return any errors or warnings in this structure.
   1566 %
   1567 */
   1568 
   1569 static MagickBooleanType CopyDelegateFile(const char *source,
   1570   const char *destination,const MagickBooleanType overwrite)
   1571 {
   1572   int
   1573     destination_file,
   1574     source_file;
   1575 
   1576   MagickBooleanType
   1577     status;
   1578 
   1579   register size_t
   1580     i;
   1581 
   1582   size_t
   1583     length,
   1584     quantum;
   1585 
   1586   ssize_t
   1587     count;
   1588 
   1589   struct stat
   1590     attributes;
   1591 
   1592   unsigned char
   1593     *buffer;
   1594 
   1595   /*
   1596     Copy source file to destination.
   1597   */
   1598   assert(source != (const char *) NULL);
   1599   assert(destination != (char *) NULL);
   1600   if (overwrite == MagickFalse)
   1601     {
   1602       status=GetPathAttributes(destination,&attributes);
   1603       if (status != MagickFalse)
   1604         return(MagickTrue);
   1605     }
   1606   destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
   1607   if (destination_file == -1)
   1608     return(MagickFalse);
   1609   source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
   1610   if (source_file == -1)
   1611     {
   1612       (void) close(destination_file);
   1613       return(MagickFalse);
   1614     }
   1615   quantum=(size_t) MagickMaxBufferExtent;
   1616   if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
   1617     quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
   1618   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
   1619   if (buffer == (unsigned char *) NULL)
   1620     {
   1621       (void) close(source_file);
   1622       (void) close(destination_file);
   1623       return(MagickFalse);
   1624     }
   1625   length=0;
   1626   for (i=0; ; i+=count)
   1627   {
   1628     count=(ssize_t) read(source_file,buffer,quantum);
   1629     if (count <= 0)
   1630       break;
   1631     length=(size_t) count;
   1632     count=(ssize_t) write(destination_file,buffer,length);
   1633     if ((size_t) count != length)
   1634       break;
   1635   }
   1636   (void) close(destination_file);
   1637   (void) close(source_file);
   1638   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
   1639   return(i != 0 ? MagickTrue : MagickFalse);
   1640 }
   1641 
   1642 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
   1643   Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
   1644 {
   1645   char
   1646     *command,
   1647     **commands,
   1648     input_filename[MagickPathExtent],
   1649     output_filename[MagickPathExtent];
   1650 
   1651   const DelegateInfo
   1652     *delegate_info;
   1653 
   1654   MagickBooleanType
   1655     status,
   1656     temporary;
   1657 
   1658   PolicyRights
   1659     rights;
   1660 
   1661   register ssize_t
   1662     i;
   1663 
   1664   /*
   1665     Get delegate.
   1666   */
   1667   assert(image_info != (ImageInfo *) NULL);
   1668   assert(image_info->signature == MagickCoreSignature);
   1669   assert(image != (Image *) NULL);
   1670   assert(image->signature == MagickCoreSignature);
   1671   if (image->debug != MagickFalse)
   1672     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   1673   rights=ExecutePolicyRights;
   1674   if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
   1675     {
   1676       errno=EPERM;
   1677       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
   1678         "NotAuthorized","`%s'",decode);
   1679       return(MagickFalse);
   1680     }
   1681   if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
   1682     {
   1683       errno=EPERM;
   1684       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
   1685         "NotAuthorized","`%s'",encode);
   1686       return(MagickFalse);
   1687     }
   1688   temporary=*image->filename == '\0' ? MagickTrue : MagickFalse;
   1689   if ((temporary != MagickFalse) && (AcquireUniqueFilename(image->filename) ==
   1690       MagickFalse))
   1691     {
   1692       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
   1693         image->filename);
   1694       return(MagickFalse);
   1695     }
   1696   delegate_info=GetDelegateInfo(decode,encode,exception);
   1697   if (delegate_info == (DelegateInfo *) NULL)
   1698     {
   1699       if (temporary != MagickFalse)
   1700         (void) RelinquishUniqueFileResource(image->filename);
   1701       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
   1702         "NoTagFound","`%s'",decode ? decode : encode);
   1703       return(MagickFalse);
   1704     }
   1705   if (*image_info->filename == '\0')
   1706     {
   1707       if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
   1708         {
   1709           if (temporary != MagickFalse)
   1710             (void) RelinquishUniqueFileResource(image->filename);
   1711           ThrowFileException(exception,FileOpenError,
   1712             "UnableToCreateTemporaryFile",image_info->filename);
   1713           return(MagickFalse);
   1714         }
   1715       image_info->temporary=MagickTrue;
   1716     }
   1717   if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
   1718         (delegate_info->encode != (char *) NULL)) ||
   1719        ((encode != (const char *) NULL) &&
   1720         (delegate_info->decode != (char *) NULL))))
   1721     {
   1722       char
   1723         *magick;
   1724 
   1725       ImageInfo
   1726         *clone_info;
   1727 
   1728       register Image
   1729         *p;
   1730 
   1731       /*
   1732         Delegate requires a particular image format.
   1733       */
   1734       if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
   1735         {
   1736           ThrowFileException(exception,FileOpenError,
   1737             "UnableToCreateTemporaryFile",image_info->unique);
   1738           return(MagickFalse);
   1739         }
   1740       magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
   1741         delegate_info->encode : delegate_info->decode,exception);
   1742       if (magick == (char *) NULL)
   1743         {
   1744           (void) RelinquishUniqueFileResource(image_info->unique);
   1745           if (temporary != MagickFalse)
   1746             (void) RelinquishUniqueFileResource(image->filename);
   1747           (void) ThrowMagickException(exception,GetMagickModule(),
   1748             DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
   1749           return(MagickFalse);
   1750         }
   1751       LocaleUpper(magick);
   1752       clone_info=CloneImageInfo(image_info);
   1753       (void) CopyMagickString((char *) clone_info->magick,magick,
   1754         MagickPathExtent);
   1755       if (LocaleCompare(magick,"NULL") != 0)
   1756         (void) CopyMagickString(image->magick,magick,MagickPathExtent);
   1757       magick=DestroyString(magick);
   1758       (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:",
   1759         delegate_info->decode);
   1760       (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
   1761         exception);
   1762       (void) CopyMagickString(clone_info->filename,image_info->filename,
   1763         MagickPathExtent);
   1764       (void) CopyMagickString(image_info->filename,image->filename,
   1765         MagickPathExtent);
   1766       for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
   1767       {
   1768         (void) FormatLocaleString(p->filename,MagickPathExtent,"%s:%s",
   1769           delegate_info->decode,clone_info->filename);
   1770         status=WriteImage(clone_info,p,exception);
   1771         if (status == MagickFalse)
   1772           {
   1773             (void) RelinquishUniqueFileResource(image_info->unique);
   1774             if (temporary != MagickFalse)
   1775               (void) RelinquishUniqueFileResource(image->filename);
   1776             clone_info=DestroyImageInfo(clone_info);
   1777             (void) ThrowMagickException(exception,GetMagickModule(),
   1778               DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
   1779             return(MagickFalse);
   1780           }
   1781         if (clone_info->adjoin != MagickFalse)
   1782           break;
   1783       }
   1784       (void) RelinquishUniqueFileResource(image_info->unique);
   1785       clone_info=DestroyImageInfo(clone_info);
   1786     }
   1787   /*
   1788     Invoke delegate.
   1789   */
   1790   commands=StringToList(delegate_info->commands);
   1791   if (commands == (char **) NULL)
   1792     {
   1793       if (temporary != MagickFalse)
   1794         (void) RelinquishUniqueFileResource(image->filename);
   1795       (void) ThrowMagickException(exception,GetMagickModule(),
   1796         ResourceLimitError,"MemoryAllocationFailed","`%s'",
   1797         decode ? decode : encode);
   1798       return(MagickFalse);
   1799     }
   1800   command=(char *) NULL;
   1801   status=MagickTrue;
   1802   (void) CopyMagickString(output_filename,image_info->filename,
   1803     MagickPathExtent);
   1804   (void) CopyMagickString(input_filename,image->filename,MagickPathExtent);
   1805   for (i=0; commands[i] != (char *) NULL; i++)
   1806   {
   1807     (void) AcquireUniqueSymbolicLink(output_filename,image_info->filename);
   1808     if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
   1809       {
   1810         ThrowFileException(exception,FileOpenError,
   1811           "UnableToCreateTemporaryFile",image_info->unique);
   1812         break;
   1813       }
   1814     if (LocaleCompare(decode,"SCAN") != 0)
   1815       {
   1816         status=AcquireUniqueSymbolicLink(input_filename,image->filename);
   1817         if (status == MagickFalse)
   1818           {
   1819             ThrowFileException(exception,FileOpenError,
   1820               "UnableToCreateTemporaryFile",input_filename);
   1821             break;
   1822           }
   1823       }
   1824     status=MagickTrue;
   1825     command=InterpretDelegateProperties(image_info,image,commands[i],exception);
   1826     if (command != (char *) NULL)
   1827       {
   1828         /*
   1829           Execute delegate.
   1830         */
   1831         if (ExternalDelegateCommand(delegate_info->spawn,image_info->verbose,
   1832           command,(char *) NULL,exception) != 0)
   1833           status=MagickFalse;
   1834         if (delegate_info->spawn != MagickFalse)
   1835           {
   1836             ssize_t
   1837               count;
   1838 
   1839             /*
   1840               Wait for input file to 'disappear', or maximum 10 seconds.
   1841             */
   1842             count=100;
   1843             while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
   1844               (void) MagickDelay(100);  /* sleep 0.1 seconds */
   1845           }
   1846         command=DestroyString(command);
   1847       }
   1848     if (LocaleCompare(decode,"SCAN") != 0)
   1849       {
   1850         if (CopyDelegateFile(image->filename,input_filename,MagickFalse) == MagickFalse)
   1851           (void) RelinquishUniqueFileResource(input_filename);
   1852       }
   1853     if ((strcmp(input_filename,output_filename) != 0) &&
   1854         (CopyDelegateFile(image_info->filename,output_filename,MagickTrue) == MagickFalse))
   1855       (void) RelinquishUniqueFileResource(output_filename);
   1856     if (image_info->temporary != MagickFalse)
   1857       (void) RelinquishUniqueFileResource(image_info->filename);
   1858     (void) RelinquishUniqueFileResource(image_info->unique);
   1859     (void) RelinquishUniqueFileResource(image_info->filename);
   1860     (void) RelinquishUniqueFileResource(image->filename);
   1861     if (status == MagickFalse)
   1862       {
   1863         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
   1864           "DelegateFailed","`%s'",commands[i]);
   1865         break;
   1866       }
   1867     commands[i]=DestroyString(commands[i]);
   1868   }
   1869   (void) CopyMagickString(image_info->filename,output_filename,
   1870     MagickPathExtent);
   1871   (void) CopyMagickString(image->filename,input_filename,MagickPathExtent);
   1872   /*
   1873     Relinquish resources.
   1874   */
   1875   for ( ; commands[i] != (char *) NULL; i++)
   1876     commands[i]=DestroyString(commands[i]);
   1877   commands=(char **) RelinquishMagickMemory(commands);
   1878   if (temporary != MagickFalse)
   1879     (void) RelinquishUniqueFileResource(image->filename);
   1880   return(status);
   1881 }
   1882 
   1883 /*
   1885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1886 %                                                                             %
   1887 %                                                                             %
   1888 %                                                                             %
   1889 %  L i s t D e l e g a t e I n f o                                            %
   1890 %                                                                             %
   1891 %                                                                             %
   1892 %                                                                             %
   1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1894 %
   1895 %  ListDelegateInfo() lists the image formats to a file.
   1896 %
   1897 %  The format of the ListDelegateInfo method is:
   1898 %
   1899 %      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
   1900 %
   1901 %  A description of each parameter follows.
   1902 %
   1903 %    o file:  An pointer to a FILE.
   1904 %
   1905 %    o exception: return any errors or warnings in this structure.
   1906 %
   1907 */
   1908 MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
   1909   ExceptionInfo *exception)
   1910 {
   1911   const DelegateInfo
   1912     **delegate_info;
   1913 
   1914   char
   1915     **commands,
   1916     delegate[MagickPathExtent];
   1917 
   1918   const char
   1919     *path;
   1920 
   1921   register ssize_t
   1922     i;
   1923 
   1924   size_t
   1925     number_delegates;
   1926 
   1927   ssize_t
   1928     j;
   1929 
   1930   if (file == (const FILE *) NULL)
   1931     file=stdout;
   1932   delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
   1933   if (delegate_info == (const DelegateInfo **) NULL)
   1934     return(MagickFalse);
   1935   path=(const char *) NULL;
   1936   for (i=0; i < (ssize_t) number_delegates; i++)
   1937   {
   1938     if (delegate_info[i]->stealth != MagickFalse)
   1939       continue;
   1940     if ((path == (const char *) NULL) ||
   1941         (LocaleCompare(path,delegate_info[i]->path) != 0))
   1942       {
   1943         if (delegate_info[i]->path != (char *) NULL)
   1944           (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
   1945         (void) FormatLocaleFile(file,"Delegate                Command\n");
   1946         (void) FormatLocaleFile(file,
   1947           "-------------------------------------------------"
   1948           "------------------------------\n");
   1949       }
   1950     path=delegate_info[i]->path;
   1951     *delegate='\0';
   1952     if (delegate_info[i]->encode != (char *) NULL)
   1953       (void) CopyMagickString(delegate,delegate_info[i]->encode,
   1954         MagickPathExtent);
   1955     (void) ConcatenateMagickString(delegate,"        ",MagickPathExtent);
   1956     delegate[8]='\0';
   1957     commands=StringToList(delegate_info[i]->commands);
   1958     if (commands == (char **) NULL)
   1959       continue;
   1960     (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
   1961       delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
   1962       delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
   1963     StripString(commands[0]);
   1964     (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
   1965     for (j=1; commands[j] != (char *) NULL; j++)
   1966     {
   1967       StripString(commands[j]);
   1968       (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
   1969     }
   1970     for (j=0; commands[j] != (char *) NULL; j++)
   1971       commands[j]=DestroyString(commands[j]);
   1972     commands=(char **) RelinquishMagickMemory(commands);
   1973   }
   1974   (void) fflush(file);
   1975   delegate_info=(const DelegateInfo **)
   1976     RelinquishMagickMemory((void *) delegate_info);
   1977   return(MagickTrue);
   1978 }
   1979 
   1980 /*
   1982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1983 %                                                                             %
   1984 %                                                                             %
   1985 %                                                                             %
   1986 +   L o a d D e l e g a t e C a c h e                                         %
   1987 %                                                                             %
   1988 %                                                                             %
   1989 %                                                                             %
   1990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1991 %
   1992 %  LoadDelegateCache() loads the delegate configurations which provides a
   1993 %  mapping between delegate attributes and a delegate name.
   1994 %
   1995 %  The format of the LoadDelegateCache method is:
   1996 %
   1997 %      MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
   1998 %        const char *xml,const char *filename,const size_t depth,
   1999 %        ExceptionInfo *exception)
   2000 %
   2001 %  A description of each parameter follows:
   2002 %
   2003 %    o xml:  The delegate list in XML format.
   2004 %
   2005 %    o filename:  The delegate list filename.
   2006 %
   2007 %    o depth: depth of <include /> statements.
   2008 %
   2009 %    o exception: return any errors or warnings in this structure.
   2010 %
   2011 */
   2012 static MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
   2013   const char *xml,const char *filename,const size_t depth,
   2014   ExceptionInfo *exception)
   2015 {
   2016   char
   2017     keyword[MagickPathExtent],
   2018     *token;
   2019 
   2020   const char
   2021     *q;
   2022 
   2023   DelegateInfo
   2024     *delegate_info;
   2025 
   2026   MagickStatusType
   2027     status;
   2028 
   2029   size_t
   2030     extent;
   2031 
   2032   /*
   2033     Load the delegate map file.
   2034   */
   2035   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
   2036     "Loading delegate configuration file \"%s\" ...",filename);
   2037   if (xml == (const char *) NULL)
   2038     return(MagickFalse);
   2039   status=MagickTrue;
   2040   delegate_info=(DelegateInfo *) NULL;
   2041   token=AcquireString(xml);
   2042   extent=strlen(token)+MagickPathExtent;
   2043   for (q=(const char *) xml; *q != '\0'; )
   2044   {
   2045     /*
   2046       Interpret XML.
   2047     */
   2048     GetNextToken(q,&q,extent,token);
   2049     if (*token == '\0')
   2050       break;
   2051     (void) CopyMagickString(keyword,token,MagickPathExtent);
   2052     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
   2053       {
   2054         /*
   2055           Doctype element.
   2056         */
   2057         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
   2058           GetNextToken(q,&q,extent,token);
   2059         continue;
   2060       }
   2061     if (LocaleNCompare(keyword,"<!--",4) == 0)
   2062       {
   2063         /*
   2064           Comment element.
   2065         */
   2066         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
   2067           GetNextToken(q,&q,extent,token);
   2068         continue;
   2069       }
   2070     if (LocaleCompare(keyword,"<include") == 0)
   2071       {
   2072         /*
   2073           Include element.
   2074         */
   2075         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
   2076         {
   2077           (void) CopyMagickString(keyword,token,MagickPathExtent);
   2078           GetNextToken(q,&q,extent,token);
   2079           if (*token != '=')
   2080             continue;
   2081           GetNextToken(q,&q,extent,token);
   2082           if (LocaleCompare(keyword,"file") == 0)
   2083             {
   2084               if (depth > 200)
   2085                 (void) ThrowMagickException(exception,GetMagickModule(),
   2086                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
   2087               else
   2088                 {
   2089                   char
   2090                     path[MagickPathExtent],
   2091                     *file_xml;
   2092 
   2093                   GetPathComponent(filename,HeadPath,path);
   2094                   if (*path != '\0')
   2095                     (void) ConcatenateMagickString(path,DirectorySeparator,
   2096                       MagickPathExtent);
   2097                   if (*token == *DirectorySeparator)
   2098                     (void) CopyMagickString(path,token,MagickPathExtent);
   2099                   else
   2100                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
   2101                   file_xml=FileToXML(path,~0UL);
   2102                   if (file_xml != (char *) NULL)
   2103                     {
   2104                       status&=LoadDelegateCache(cache,file_xml,path,
   2105                         depth+1,exception);
   2106                       file_xml=DestroyString(file_xml);
   2107                     }
   2108                 }
   2109             }
   2110         }
   2111         continue;
   2112       }
   2113     if (LocaleCompare(keyword,"<delegate") == 0)
   2114       {
   2115         /*
   2116           Delegate element.
   2117         */
   2118         delegate_info=(DelegateInfo *) AcquireMagickMemory(
   2119           sizeof(*delegate_info));
   2120         if (delegate_info == (DelegateInfo *) NULL)
   2121           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   2122         (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
   2123         delegate_info->path=ConstantString(filename);
   2124         delegate_info->thread_support=MagickTrue;
   2125         delegate_info->signature=MagickCoreSignature;
   2126         continue;
   2127       }
   2128     if (delegate_info == (DelegateInfo *) NULL)
   2129       continue;
   2130     if (LocaleCompare(keyword,"/>") == 0)
   2131       {
   2132         status=AppendValueToLinkedList(cache,delegate_info);
   2133         if (status == MagickFalse)
   2134           (void) ThrowMagickException(exception,GetMagickModule(),
   2135             ResourceLimitError,"MemoryAllocationFailed","`%s'",
   2136             delegate_info->commands);
   2137         delegate_info=(DelegateInfo *) NULL;
   2138         continue;
   2139       }
   2140     GetNextToken(q,(const char **) NULL,extent,token);
   2141     if (*token != '=')
   2142       continue;
   2143     GetNextToken(q,&q,extent,token);
   2144     GetNextToken(q,&q,extent,token);
   2145     switch (*keyword)
   2146     {
   2147       case 'C':
   2148       case 'c':
   2149       {
   2150         if (LocaleCompare((char *) keyword,"command") == 0)
   2151           {
   2152             char
   2153               *commands;
   2154 
   2155             commands=AcquireString(token);
   2156 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
   2157             if (strchr(commands,'@') != (char *) NULL)
   2158               {
   2159                 char
   2160                   path[MagickPathExtent];
   2161 
   2162                 NTGhostscriptEXE(path,MagickPathExtent);
   2163                 (void) SubstituteString((char **) &commands,"@PSDelegate@",
   2164                   path);
   2165                 (void) SubstituteString((char **) &commands,"\\","/");
   2166               }
   2167             (void) SubstituteString((char **) &commands,"&quot;","\"");
   2168 #else
   2169             (void) SubstituteString((char **) &commands,"&quot;","'");
   2170 #endif
   2171             (void) SubstituteString((char **) &commands,"&amp;","&");
   2172             (void) SubstituteString((char **) &commands,"&gt;",">");
   2173             (void) SubstituteString((char **) &commands,"&lt;","<");
   2174             delegate_info->commands=commands;
   2175             break;
   2176           }
   2177         break;
   2178       }
   2179       case 'D':
   2180       case 'd':
   2181       {
   2182         if (LocaleCompare((char *) keyword,"decode") == 0)
   2183           {
   2184             delegate_info->decode=ConstantString(token);
   2185             delegate_info->mode=1;
   2186             break;
   2187           }
   2188         break;
   2189       }
   2190       case 'E':
   2191       case 'e':
   2192       {
   2193         if (LocaleCompare((char *) keyword,"encode") == 0)
   2194           {
   2195             delegate_info->encode=ConstantString(token);
   2196             delegate_info->mode=(-1);
   2197             break;
   2198           }
   2199         break;
   2200       }
   2201       case 'M':
   2202       case 'm':
   2203       {
   2204         if (LocaleCompare((char *) keyword,"mode") == 0)
   2205           {
   2206             delegate_info->mode=1;
   2207             if (LocaleCompare(token,"bi") == 0)
   2208               delegate_info->mode=0;
   2209             else
   2210               if (LocaleCompare(token,"encode") == 0)
   2211                 delegate_info->mode=(-1);
   2212             break;
   2213           }
   2214         break;
   2215       }
   2216       case 'S':
   2217       case 's':
   2218       {
   2219         if (LocaleCompare((char *) keyword,"spawn") == 0)
   2220           {
   2221             delegate_info->spawn=IsStringTrue(token);
   2222             break;
   2223           }
   2224         if (LocaleCompare((char *) keyword,"stealth") == 0)
   2225           {
   2226             delegate_info->stealth=IsStringTrue(token);
   2227             break;
   2228           }
   2229         break;
   2230       }
   2231       case 'T':
   2232       case 't':
   2233       {
   2234         if (LocaleCompare((char *) keyword,"thread-support") == 0)
   2235           {
   2236             delegate_info->thread_support=IsStringTrue(token);
   2237             if (delegate_info->thread_support == MagickFalse)
   2238               delegate_info->semaphore=AcquireSemaphoreInfo();
   2239             break;
   2240           }
   2241         break;
   2242       }
   2243       default:
   2244         break;
   2245     }
   2246   }
   2247   token=(char *) RelinquishMagickMemory(token);
   2248   return(status != 0 ? MagickTrue : MagickFalse);
   2249 }
   2250