text: /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %           DDDD   EEEEE  L      EEEEE   GGGG   AAA   TTTTT  EEEEE            %
  %           D   D  E      L      E      G      A   A    T    E                %
  %           D   D  EEE    L      EEE    G  GG  AAAAA    T    EEE              %
  %           D   D  E      L      E      G   G  A   A    T    E                %
  %           DDDD   EEEEE  LLLLL  EEEEE   GGG   A   A    T    EEEEE            %
  %                                                                             %
  %                                                                             %
  %             MagickCore Methods to Read/Write/Invoke Delegates               %
  %                                                                             %
  %                             Software Design                                 %
  %                                  Cristy                                     %
  %                               October 1998                                  %
  %                                                                             %
  %                                                                             %
  %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
  %  dedicated to making software imaging solutions freely available.           %
  %                                                                             %
  %  You may not use this file except in compliance with the License.  You may  %
  %  obtain a copy of the License at                                            %
  %                                                                             %
  %    https://imagemagick.org/script/license.php                               %
  %                                                                             %
  %  Unless required by applicable law or agreed to in writing, software        %
  %  distributed under the License is distributed on an "AS IS" BASIS,          %
  %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
  %  See the License for the specific language governing permissions and        %
  %  limitations under the License.                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  The Delegates methods associate a set of commands with a particular
  %  image format.  ImageMagick uses delegates for formats it does not handle
  %  directly.
  %
  %  Thanks to Bob Friesenhahn for the initial inspiration and design of the
  %  delegates methods.
  %
  %
  */
  
  /*
    Include declarations.
  */
  #include "MagickCore/studio.h"
  #include "MagickCore/artifact.h"
  #include "MagickCore/attribute.h"
  #include "MagickCore/blob.h"
  #include "MagickCore/client.h"
  #include "MagickCore/configure.h"
  #include "MagickCore/constitute.h"
  #include "MagickCore/delegate.h"
  #include "MagickCore/delegate-private.h"
  #include "MagickCore/exception.h"
  #include "MagickCore/exception-private.h"
  #include "MagickCore/fx-private.h"
  #include "MagickCore/image-private.h"
  #include "MagickCore/linked-list.h"
  #include "MagickCore/list.h"
  #include "MagickCore/memory_.h"
  #include "MagickCore/memory-private.h"
  #include "MagickCore/nt-base-private.h"
  #include "MagickCore/option.h"
  #include "MagickCore/policy.h"
  #include "MagickCore/property.h"
  #include "MagickCore/resource_.h"
  #include "MagickCore/semaphore.h"
  #include "MagickCore/signature.h"
  #include "MagickCore/string_.h"
  #include "MagickCore/token.h"
  #include "MagickCore/token-private.h"
  #include "MagickCore/utility.h"
  #include "MagickCore/utility-private.h"
  #include "MagickCore/xml-tree.h"
  #include "MagickCore/xml-tree-private.h"
  
  /*
    Define declarations.
  */
  #define DelegateFilename  "delegates.xml"
  
  /*
    Declare delegate map.
  */
  static const char
    *DelegateMap = (const char *)
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
      "<delegatemap>"
      "  <delegate decode=\"bpg\" command=\"&quot;bpgdec&quot; -b 16 -o &quot;%o.png&quot; &quot;%i&quot;; mv &quot;%o.png&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"png\" encode=\"bpg\" command=\"&quot;bpgenc&quot; -b 12 -q %~ -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; https://imagemagick.org/; rm &quot;%i&quot;\"/>"
      "  <delegate decode=\"cdr\" command=\"&quot;uniconvertor&quot; &quot;%i&quot; &quot;%o.svg&quot;; mv &quot;%o.svg&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"cgm\" command=\"&quot;uniconvertor&quot; &quot;%i&quot; &quot;%o.svg&quot;; mv &quot;%o.svg&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"https\" command=\"&quot;curl&quot; -s -k -L -o &quot;%o&quot; &quot;https:%M&quot;\"/>"
      "  <delegate decode=\"doc\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"docx\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <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;\"/>"
      "  <delegate decode=\"dot\" command=\"&quot;dot&quot; -Tsvg &quot;%i&quot; -o &quot;%o&quot;\"/>"
      "  <delegate decode=\"dvi\" command=\"&quot;dvips&quot; -sstdout=%%stderr -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"dxf\" command=\"&quot;uniconvertor&quot; &quot;%i&quot; &quot;%o.svg&quot;; mv &quot;%o.svg&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
      "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"fig\" command=\"&quot;uniconvertor&quot; &quot;%i&quot; &quot;%o.svg&quot;; mv &quot;%o.svg&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"hpg\" command=\"&quot;hp2xx&quot; -sstdout=%%stderr -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
      "  <delegate decode=\"hpgl\" command=\"&quot;hp2xx&quot; -sstdout=%%stderr -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
      "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
      "  <delegate decode=\"jpg\" encode=\"lep\" mode=\"encode\" command=\"&quot;lepton&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"jxr\" command=\"mv &quot;%i&quot; &quot;%i.jxr&quot;; &quot;JxrDecApp&quot; -i &quot;%i.jxr&quot; -o &quot;%o.pnm&quot;; mv &quot;%i.jxr&quot; &quot;%i&quot;; mv &quot;%o.pnm&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"lep\" mode=\"decode\" command=\"&quot;lepton&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"mpeg:decode\" command=\"&quot;avconv&quot; -v -1 -i &quot;%i&quot; -vframes %S -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%u&quot;\"/>"
      "  <delegate decode=\"odt\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pamcmyk32&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
      "  <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;\"/>"
      "  <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;\"/>"
      "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 -sPDFPassword=&quot;%a&quot; &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; -sPDFPassword=&quot;%a&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"png\" encode=\"webp\" command=\"&quot;cwebp&quot; -quiet -q %Q &quot;%i&quot; -o &quot;%o&quot;\"/>"
      "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
      "  <delegate decode=\"bmp\" encode=\"jxr\" command=\"mv &quot;%i&quot; &quot;%i.bmp&quot;; &quot;JxrEncApp&quot; -i &quot;%i.bmp&quot; -o &quot;%o.jxr&quot;; mv &quot;%i.bmp&quot; &quot;%i&quot;; mv &quot;%o.jxr&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"bmp\" encode=\"wdp\" command=\"mv &quot;%i&quot; &quot;%i.bmp&quot;; &quot;JxrEncApp&quot; -i &quot;%i.bmp&quot; -o &quot;%o.jxr&quot;; mv &quot;%i.bmp&quot; &quot;%i&quot;; mv &quot;%o.jxr&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"ppt\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"pptx\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"ps\" encode=\"prt\" command=\"&quot;lpr&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -sstdout=%%stderr -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;\"/>"
      "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pamcmyk32&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
      "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -sstdout=%%stderr -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;\"/>"
      "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
      "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
      "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -sstdout=%%stderr -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;-f%s&quot; &quot;-f%s&quot;\"/>"
      "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"sid\" command=\"&quot;mrsidgeodecode&quot; -if sid -i &quot;%i&quot; -of tif -o &quot;%o&quot; &gt; &quot;%u&quot;\"/>"
      "  <delegate decode=\"svg\" command=\"&quot;rsvg-convert&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"svg:decode\" stealth=\"True\" command=\"&quot;inkscape&quot; &quot;%s&quot; --export-png=&quot;%s&quot; --export-dpi=&quot;%s&quot; --export-background=&quot;%s&quot; --export-background-opacity=&quot;%s&quot; &gt; &quot;%s&quot; 2&gt;&amp;1\"/>"
      "  <delegate decode=\"tiff\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
      "  <delegate decode=\"wdp\" command=\"mv &quot;%i&quot; &quot;%i.jxr&quot;; &quot;JxrDecApp&quot; -i &quot;%i.jxr&quot; -o &quot;%o.bmp&quot;; mv &quot;%i.jxr&quot; &quot;%i&quot;; mv &quot;%o.bmp&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"webp\" command=\"&quot;dwebp&quot; -pam &quot;%i&quot; -o &quot;%o&quot;\"/>"
      "  <delegate decode=\"xls\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"xlsx\" command=\"&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; mv &quot;%i.pdf&quot; &quot;%o&quot;\"/>"
      "  <delegate decode=\"xps:cmyk\" stealth=\"True\" command=\"&quot;gxps&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;\"/>"
      "  <delegate decode=\"xps:color\" stealth=\"True\" command=\"&quot;gxps&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;\"/>"
      "  <delegate decode=\"xps:mono\" stealth=\"True\" command=\"&quot;gxps&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;\"/>"
      "  <delegate encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;avconv&quot; -v -1 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%u&quot;\"/>"
      "</delegatemap>";
  
  /*
    Global declaractions.
  */
  static LinkedListInfo
    *delegate_cache = (LinkedListInfo *) NULL;
  
  static SemaphoreInfo
    *delegate_semaphore = (SemaphoreInfo *) NULL;
  
  /*
    Forward declaractions.
  */
  static MagickBooleanType
    IsDelegateCacheInstantiated(ExceptionInfo *),
    LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t,
      ExceptionInfo *);
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %  A c q u i r e D e l e g a t e C a c h e                                    %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  AcquireDelegateCache() caches one or more delegate configurations which
  %  provides a mapping between delegate attributes and a delegate name.
  %
  %  The format of the AcquireDelegateCache method is:
  %
  %      LinkedListInfo *AcquireDelegateCache(const char *filename,
  %        ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o filename: the font file name.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  static LinkedListInfo *AcquireDelegateCache(const char *filename,
    ExceptionInfo *exception)
  {
    LinkedListInfo
      *cache;
  
    MagickStatusType
      status;
  
    cache=NewLinkedList(0);
    status=MagickTrue;
  #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    {
      const StringInfo
        *option;
  
      LinkedListInfo
        *options;
  
      options=GetConfigureOptions(filename,exception);
      option=(const StringInfo *) GetNextValueInLinkedList(options);
      while (option != (const StringInfo *) NULL)
      {
        status&=LoadDelegateCache(cache,(const char *)
          GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
        option=(const StringInfo *) GetNextValueInLinkedList(options);
      }
      options=DestroyConfigureOptions(options);
    }
  #endif
    if (IsLinkedListEmpty(cache) != MagickFalse)
      status&=LoadDelegateCache(cache,DelegateMap,"built-in",0,exception);
    return(cache);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  +   D e l e g a t e C o m p o n e n t G e n e s i s                           %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  DelegateComponentGenesis() instantiates the delegate component.
  %
  %  The format of the DelegateComponentGenesis method is:
  %
  %      MagickBooleanType DelegateComponentGenesis(void)
  %
  */
  MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
  {
    if (delegate_semaphore == (SemaphoreInfo *) NULL)
      delegate_semaphore=AcquireSemaphoreInfo();
    return(MagickTrue);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   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                         %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  DelegateComponentTerminus() destroys the delegate component.
  %
  %  The format of the DelegateComponentTerminus method is:
  %
  %      DelegateComponentTerminus(void)
  %
  */
  
  static void *DestroyDelegate(void *delegate_info)
  {
    register DelegateInfo
      *p;
  
    p=(DelegateInfo *) delegate_info;
    if (p->path != (char *) NULL)
      p->path=DestroyString(p->path);
    if (p->decode != (char *) NULL)
      p->decode=DestroyString(p->decode);
    if (p->encode != (char *) NULL)
      p->encode=DestroyString(p->encode);
    if (p->commands != (char *) NULL)
      p->commands=DestroyString(p->commands);
    if (p->semaphore != (SemaphoreInfo *) NULL)
      RelinquishSemaphoreInfo(&p->semaphore);
    p=(DelegateInfo *) RelinquishMagickMemory(p);
    return((void *) NULL);
  }
  
  MagickPrivate void DelegateComponentTerminus(void)
  {
    if (delegate_semaphore == (SemaphoreInfo *) NULL)
      ActivateSemaphoreInfo(&delegate_semaphore);
    LockSemaphoreInfo(delegate_semaphore);
    if (delegate_cache != (LinkedListInfo *) NULL)
      delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
    UnlockSemaphoreInfo(delegate_semaphore);
    RelinquishSemaphoreInfo(&delegate_semaphore);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  +   E x t e r n a l D e l e g a t e C o m m a n d                             %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  ExternalDelegateCommand() executes the specified command and waits until it
  %  terminates.  The returned value is the exit status of the command.
  %
  %  The format of the ExternalDelegateCommand method is:
  %
  %      int ExternalDelegateCommand(const MagickBooleanType asynchronous,
  %        const MagickBooleanType verbose,const char *command,
  %        char *message,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o asynchronous: a value other than 0 executes the parent program
  %      concurrently with the new child process.
  %
  %    o verbose: a value other than 0 prints the executed command before it is
  %      invoked.
  %
  %    o command: this string is the command to execute.
  %
  %    o message: an option buffer to receive any message posted to stdout or
  %      stderr.
  %
  %    o exception: return any errors here.
  %
  */
  MagickExport int ExternalDelegateCommand(const MagickBooleanType asynchronous,
    const MagickBooleanType verbose,const char *command,char *message,
    ExceptionInfo *exception)
  {
    char
      **arguments,
      *sanitize_command;
  
    int
      number_arguments,
      status;
  
    PolicyDomain
      domain;
  
    PolicyRights
      rights;
  
    register ssize_t
      i;
  
    status=(-1);
    arguments=StringToArgv(command,&number_arguments);
    if (arguments == (char **) NULL)
      return(status);
    if (*arguments[1] == '\0')
      {
        for (i=0; i < (ssize_t) number_arguments; i++)
          arguments[i]=DestroyString(arguments[i]);
        arguments=(char **) RelinquishMagickMemory(arguments);
        return(-1);
      }
    rights=ExecutePolicyRights;
    domain=DelegatePolicyDomain;
    if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
      {
        errno=EPERM;
        (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
          "NotAuthorized","`%s'",arguments[1]);
        for (i=0; i < (ssize_t) number_arguments; i++)
          arguments[i]=DestroyString(arguments[i]);
        arguments=(char **) RelinquishMagickMemory(arguments);
        return(-1);
      }
    if (verbose != MagickFalse)
      {
        (void) FormatLocaleFile(stderr,"%s\n",command);
        (void) fflush(stderr);
      }
    sanitize_command=SanitizeString(command);
    if (asynchronous != MagickFalse)
      (void) ConcatenateMagickString(sanitize_command,"&",MagickPathExtent);
    if (message != (char *) NULL)
      *message='\0';
  #if defined(MAGICKCORE_POSIX_SUPPORT)
  #if !defined(MAGICKCORE_HAVE_EXECVP)
    status=system(sanitize_command);
  #else
    if ((asynchronous != MagickFalse) ||
        (strpbrk(sanitize_command,"&;<>|") != (char *) NULL))
      status=system(sanitize_command);
    else
      {
        pid_t
          child_pid;
  
        /*
          Call application directly rather than from a shell.
        */
        child_pid=(pid_t) fork();
        if (child_pid == (pid_t) -1)
          status=system(sanitize_command);
        else
          if (child_pid == 0)
            {
              status=execvp(arguments[1],arguments+1);
              _exit(1);
            }
          else
            {
              int
                child_status;
  
              pid_t
                pid;
  
              child_status=0;
              pid=(pid_t) waitpid(child_pid,&child_status,0);
              if (pid == -1)
                status=(-1);
              else
                {
                  if (WIFEXITED(child_status) != 0)
                    status=WEXITSTATUS(child_status);
                  else
                    if (WIFSIGNALED(child_status))
                      status=(-1);
                }
            }
      }
  #endif
  #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    {
      register char
        *p;
  
      /*
        If a command shell is executed we need to change the forward slashes in
        files to a backslash. We need to do this to keep Windows happy when we
        want to 'move' a file.
  
        TODO: This won't work if one of the delegate parameters has a forward
              slash as aparameter.
      */
      p=strstr(sanitize_command,"cmd.exe /c");
      if (p != (char*) NULL)
        {
          p+=10;
          for ( ; *p != '\0'; p++)
            if (*p == '/')
              *p=(*DirectorySeparator);
        }
    }
    status=NTSystemCommand(sanitize_command,message);
  #elif defined(macintosh)
    status=MACSystemCommand(sanitize_command);
  #elif defined(vms)
    status=system(sanitize_command);
  #else
  #  error No suitable system() method.
  #endif
    if (status < 0)
      {
        if ((message != (char *) NULL) && (*message != '\0'))
          (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
            "FailedToExecuteCommand","`%s' (%s)",sanitize_command,message);
        else
          (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
            "FailedToExecuteCommand","`%s' (%d)",sanitize_command,status);
      }
    sanitize_command=DestroyString(sanitize_command);
    for (i=0; i < (ssize_t) number_arguments; i++)
      arguments[i]=DestroyString(arguments[i]);
    arguments=(char **) RelinquishMagickMemory(arguments);
    return(status);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e C o m m a n d                                       %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateCommand() replaces any embedded formatting characters with the
  %  appropriate image attribute and returns the resulting command.
  %
  %  The format of the GetDelegateCommand method is:
  %
  %      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
  %        const char *decode,const char *encode,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o command: Method GetDelegateCommand returns the command associated
  %      with specified delegate tag.
  %
  %    o image_info: the image info.
  %
  %    o image: the image.
  %
  %    o decode: Specifies the decode delegate we are searching for as a
  %      character string.
  %
  %    o encode: Specifies the encode delegate we are searching for as a
  %      character string.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  
  static char *GetMagickPropertyLetter(ImageInfo *image_info,Image *image,
    const char letter,ExceptionInfo *exception)
  {
  #define WarnNoImageReturn(format,letter) \
    if (image == (Image *) NULL) \
      { \
        (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
          "NoImageForProperty",format,letter); \
        break; \
      }
  #define WarnNoImageInfoReturn(format,letter) \
    if (image_info == (ImageInfo *) NULL) \
      { \
        (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
          "NoImageInfoForProperty",format,letter); \
        break; \
      }
  
    char
      value[MagickPathExtent];
  
    const char
      *string;
  
    if ((image != (Image *) NULL) && (image->debug != MagickFalse))
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    else
      if ((image_info != (ImageInfo *) NULL) &&
          (image_info->debug != MagickFalse))
        (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
    /*
      Get properties that are directly defined by images.
    */
    *value='\0';           /* formatted string */
    string=(const char *) value;
    switch (letter)
    {
      case 'a': /* authentication passphase */
      {
        WarnNoImageInfoReturn("\"%%%c\"",letter);
        string=GetImageOption(image_info,"authenticate");
        break;
      }
      case 'b':  /* image size read in - in bytes */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatMagickSize(image->extent,MagickFalse,"B",MagickPathExtent,
          value);
        if (image->extent == 0)
          (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
            MagickPathExtent,value);
        break;
      }
      case 'd':  /* Directory component of filename */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        GetPathComponent(image->magick_filename,HeadPath,value);
        break;
      }
      case 'e': /* Filename extension (suffix) of image file */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        GetPathComponent(image->magick_filename,ExtensionPath,value);
        break;
      }
      case 'f': /* Filename without directory component */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        GetPathComponent(image->magick_filename,TailPath,value);
        break;
      }
      case 'g': /* Image geometry, canvas and offset  %Wx%H+%X+%Y */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,
          "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
          image->page.height,(double) image->page.x,(double) image->page.y);
        break;
      }
      case 'h': /* Image height (current) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          (image->rows != 0 ? image->rows : image->magick_rows));
        break;
      }
      case 'i': /* Filename last used for an image (read or write) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=image->filename;
        break;
      }
      case 'm': /* Image format (file magick) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=image->magick;
        break;
      }
      case 'n': /* Number of images in the list.  */
      {
        if (image != (Image *) NULL)
          (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
            GetImageListLength(image));
        break;
      }
      case 'o': /* Output Filename */
      {
        WarnNoImageInfoReturn("\"%%%c\"",letter);
        string=image_info->filename;
        break;
      }
      case 'p': /* Image index in current image list */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          GetImageIndexInList(image));
        break;
      }
      case 'q': /* Quantum depth of image in memory */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          MAGICKCORE_QUANTUM_DEPTH);
        break;
      }
      case 'r': /* Image storage class, colorspace, and alpha enabled.  */
      {
        ColorspaceType
          colorspace;
  
        WarnNoImageReturn("\"%%%c\"",letter);
        colorspace=image->colorspace;
        if (SetImageGray(image,exception) != MagickFalse)
          colorspace=GRAYColorspace;   /* FUTURE: this is IMv6 not IMv7 */
        (void) FormatLocaleString(value,MagickPathExtent,"%s %s %s",
          CommandOptionToMnemonic(MagickClassOptions,(ssize_t)
          image->storage_class),CommandOptionToMnemonic(MagickColorspaceOptions,
          (ssize_t) colorspace),image->alpha_trait != UndefinedPixelTrait ?
          "Alpha" : "");
        break;
      }
      case 's': /* Image scene number */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          image->scene);
        break;
      }
      case 't': /* Base filename without directory or extention */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        GetPathComponent(image->magick_filename,BasePath,value);
        break;
      }
      case 'u': /* Unique filename */
      {
        WarnNoImageInfoReturn("\"%%%c\"",letter);
        string=image_info->unique;
        break;
      }
      case 'w': /* Image width (current) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          (image->columns != 0 ? image->columns : image->magick_columns));
        break;
      }
      case 'x': /* Image horizontal resolution (with units) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
          fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0);
        break;
      }
      case 'y': /* Image vertical resolution (with units) */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
          fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0);
        break;
      }
      case 'z': /* Image depth as read in */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
          (double) image->depth);
        break;
      }
      case 'A': /* Image alpha channel  */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
          image->alpha_trait);
        break;
      }
      case 'C': /* Image compression method.  */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=CommandOptionToMnemonic(MagickCompressOptions,
          (ssize_t) image->compression);
        break;
      }
      case 'D': /* Image dispose method.  */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=CommandOptionToMnemonic(MagickDisposeOptions,
          (ssize_t) image->dispose);
        break;
      }
      case 'F':
      {
        /*
          Magick filename - filename given incl. coder & read mods.
        */
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
        break;
      }
      case 'G': /* Image size as geometry = "%wx%h" */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
          (double) image->magick_columns,(double) image->magick_rows);
        break;
      }
      case 'H': /* layer canvas height */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
          (double) image->page.height);
        break;
      }
      case 'M': /* Magick filename - filename given incl. coder & read mods */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=image->magick_filename;
        break;
      }
      case 'O': /* layer canvas offset with sign = "+%X+%Y" */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%+ld%+ld",(long)
          image->page.x,(long) image->page.y);
        break;
      }
      case 'P': /* layer canvas page size = "%Wx%H" */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
          (double) image->page.width,(double) image->page.height);
        break;
      }
      case '~': /* BPG image compression quality */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          (100-(image->quality == 0 ? 42 : image->quality))/2);
        break;
      }
      case 'Q': /* image compression quality */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          (image->quality == 0 ? 92 : image->quality));
        break;
      }
      case 'S': /* Number of scenes in image list.  */
      {
        WarnNoImageInfoReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          (image_info->number_scenes == 0 ? 2147483647 :
           image_info->number_scenes));
        break;
      }
      case 'T': /* image time delay for animations */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          image->delay);
        break;
      }
      case 'U': /* Image resolution units. */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        string=CommandOptionToMnemonic(MagickResolutionOptions,
          (ssize_t) image->units);
        break;
      }
      case 'W': /* layer canvas width */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
          image->page.width);
        break;
      }
      case 'X': /* layer canvas X offset */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
          image->page.x);
        break;
      }
      case 'Y': /* layer canvas Y offset */
      {
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
          image->page.y);
        break;
      }
      case '%': /* percent escaped */
      {
        string="%";
        break;
      }
      case '@': /* Trim bounding box, without actually trimming! */
      {
        RectangleInfo
          page;
  
        WarnNoImageReturn("\"%%%c\"",letter);
        page=GetImageBoundingBox(image,exception);
        (void) FormatLocaleString(value,MagickPathExtent,
          "%.20gx%.20g%+.20g%+.20g",(double) page.width,(double) page.height,
          (double) page.x,(double) page.y);
        break;
      }
      case '#':
      {
        /*
          Image signature.
        */
        WarnNoImageReturn("\"%%%c\"",letter);
        (void) SignatureImage(image,exception);
        string=GetImageProperty(image,"signature",exception);
        break;
      }
    }
    return(SanitizeString(string));
  }
  
  static char *InterpretDelegateProperties(ImageInfo *image_info,
    Image *image,const char *embed_text,ExceptionInfo *exception)
  {
  #define ExtendInterpretText(string_length) \
  DisableMSCWarning(4127) \
  { \
    size_t length=(string_length); \
    if ((size_t) (q-interpret_text+length+1) >= extent) \
      { \
        extent+=length; \
        interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
          MaxTextExtent,sizeof(*interpret_text)); \
        if (interpret_text == (char *) NULL) \
          return((char *) NULL); \
        q=interpret_text+strlen(interpret_text); \
     } \
  } \
  RestoreMSCWarning
  
  #define AppendKeyValue2Text(key,value)\
  DisableMSCWarning(4127) \
  { \
    size_t length=strlen(key)+strlen(value)+2; \
    if ((size_t) (q-interpret_text+length+1) >= extent) \
      { \
        extent+=length; \
        interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
          MaxTextExtent,sizeof(*interpret_text)); \
        if (interpret_text == (char *) NULL) \
          return((char *) NULL); \
        q=interpret_text+strlen(interpret_text); \
       } \
     q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(value)); \
  } \
  RestoreMSCWarning
  
  #define AppendString2Text(string) \
  DisableMSCWarning(4127) \
  { \
    size_t length=strlen((string)); \
    if ((size_t) (q-interpret_text+length+1) >= extent) \
      { \
        extent+=length; \
        interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
          MaxTextExtent,sizeof(*interpret_text)); \
        if (interpret_text == (char *) NULL) \
          return((char *) NULL); \
        q=interpret_text+strlen(interpret_text); \
      } \
    (void) CopyMagickString(q,(string),extent); \
    q+=length; \
  } \
  RestoreMSCWarning
  
    char
      *interpret_text,
      *string;
  
    register char
      *q;  /* current position in interpret_text */
  
    register const char
      *p;  /* position in embed_text string being expanded */
  
    size_t
      extent;  /* allocated length of interpret_text */
  
    MagickBooleanType
      number;
  
    assert(image == NULL || image->signature == MagickCoreSignature);
    assert(image_info == NULL || image_info->signature == MagickCoreSignature);
    if ((image != (Image *) NULL) && (image->debug != MagickFalse))
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    else
     if ((image_info != (ImageInfo *) NULL) && (image_info->debug != MagickFalse))
       (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-image");
    if (embed_text == (const char *) NULL)
      return(ConstantString(""));
    p=embed_text;
    while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0'))
      p++;
    if (*p == '\0')
      return(ConstantString(""));
    /*
      Translate any embedded format characters.
    */
    interpret_text=AcquireString(embed_text);  /* new string with extra space */
    extent=MagickPathExtent;  /* allocated space in string */
    number=MagickFalse;  /* is last char a number? */
    for (q=interpret_text; *p!='\0';
      number=isdigit((int) ((unsigned char) *p)) ? MagickTrue : MagickFalse,p++)
    {
      /*
        Interpret escape characters (e.g. Filename: %M).
      */
      *q='\0';
      ExtendInterpretText(MagickPathExtent);
      switch (*p)
      {
        case '\\':
        {
          switch (*(p+1))
          {
            case '\0':
              continue;
            case 'r':  /* convert to RETURN */
            {
              *q++='\r';
              p++;
              continue;
            }
            case 'n':  /* convert to NEWLINE */
            {
              *q++='\n';
              p++;
              continue;
            }
            case '\n':  /* EOL removal UNIX,MacOSX */
            {
              p++;
              continue;
            }
            case '\r':  /* EOL removal DOS,Windows */
            {
              p++;
              if (*p == '\n') /* return-newline EOL */
                p++;
              continue;
            }
            default:
            {
              p++;
              *q++=(*p);
            }
          }
          continue;
        }
        case '&':
        {
          if (LocaleNCompare("&lt;",p,4) == 0)
            {
              *q++='<';
              p+=3;
            }
          else
            if (LocaleNCompare("&gt;",p,4) == 0)
              {
                *q++='>';
                p+=3;
              }
            else
              if (LocaleNCompare("&amp;",p,5) == 0)
                {
                  *q++='&';
                  p+=4;
                }
              else
                *q++=(*p);
          continue;
        }
        case '%':
          break;  /* continue to next set of handlers */
        default:
        {
          *q++=(*p);  /* any thing else is 'as normal' */
          continue;
        }
      }
      p++; /* advance beyond the percent */
      /*
        Doubled Percent - or percent at end of string.
      */
      if ((*p == '\0') || (*p == '\'') || (*p == '"'))
        p--;
      if (*p == '%')
        {
          *q++='%';
          continue;
        }
      /*
        Single letter escapes %c.
      */
      if (number != MagickFalse)
        {
          /*
            But only if not preceeded by a number!
          */
          *q++='%'; /* do NOT substitute the percent */
          p--;      /* back up one */
          continue;
        }
      string=GetMagickPropertyLetter(image_info,image,*p,exception);
      if (string != (char *) NULL)
        {
          AppendString2Text(string);
          string=DestroyString(string);
          continue;
        }
      (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
        "UnknownImageProperty","\"%%%c\"",*p);
    }
    *q='\0';
    return(interpret_text);
  }
  
  MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
    const char *decode,const char *encode,ExceptionInfo *exception)
  {
    char
      *command,
      **commands;
  
    const DelegateInfo
      *delegate_info;
  
    register ssize_t
      i;
  
    assert(image_info != (ImageInfo *) NULL);
    assert(image_info->signature == MagickCoreSignature);
    assert(image != (Image *) NULL);
    assert(image->signature == MagickCoreSignature);
    if (image->debug != MagickFalse)
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  
    delegate_info=GetDelegateInfo(decode,encode,exception);
    if (delegate_info == (const DelegateInfo *) NULL)
      {
        (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
          "NoTagFound","`%s'",decode ? decode : encode);
        return((char *) NULL);
      }
    commands=StringToList(delegate_info->commands);
    if (commands == (char **) NULL)
      {
        (void) ThrowMagickException(exception,GetMagickModule(),
          ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
          encode);
        return((char *) NULL);
      }
    command=InterpretDelegateProperties((ImageInfo *) image_info,image,
      commands[0],exception);
    if (command == (char *) NULL)
      (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
        "MemoryAllocationFailed","`%s'",commands[0]);
    /*
      Relinquish resources.
    */
    for (i=0; commands[i] != (char *) NULL; i++)
      commands[i]=DestroyString(commands[i]);
    commands=(char **) RelinquishMagickMemory(commands);
    return(command);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e C o m m a n d s                                     %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateCommands() returns the commands associated with a delegate.
  %
  %  The format of the GetDelegateCommands method is:
  %
  %      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
  %
  %  A description of each parameter follows:
  %
  %    o delegate_info:  The delegate info.
  %
  */
  MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
  {
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  
    assert(delegate_info != (DelegateInfo *) NULL);
    assert(delegate_info->signature == MagickCoreSignature);
    return(delegate_info->commands);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e I n f o                                             %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateInfo() returns any delegates associated with the specified tag.
  %
  %  The format of the GetDelegateInfo method is:
  %
  %      const DelegateInfo *GetDelegateInfo(const char *decode,
  %        const char *encode,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o decode: Specifies the decode delegate we are searching for as a
  %      character string.
  %
  %    o encode: Specifies the encode delegate we are searching for as a
  %      character string.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
    const char *encode,ExceptionInfo *exception)
  {
    register const DelegateInfo
      *p;
  
    assert(exception != (ExceptionInfo *) NULL);
    if (IsDelegateCacheInstantiated(exception) == MagickFalse)
      return((const DelegateInfo *) NULL);
    /*
      Search for named delegate.
    */
    LockSemaphoreInfo(delegate_semaphore);
    ResetLinkedListIterator(delegate_cache);
    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
      {
        UnlockSemaphoreInfo(delegate_semaphore);
        return(p);
      }
    while (p != (const DelegateInfo *) NULL)
    {
      if (p->mode > 0)
        {
          if (LocaleCompare(p->decode,decode) == 0)
            break;
          p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
          continue;
        }
      if (p->mode < 0)
        {
          if (LocaleCompare(p->encode,encode) == 0)
            break;
          p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
          continue;
        }
      if (LocaleCompare(decode,p->decode) == 0)
        if (LocaleCompare(encode,p->encode) == 0)
          break;
      if (LocaleCompare(decode,"*") == 0)
        if (LocaleCompare(encode,p->encode) == 0)
          break;
      if (LocaleCompare(decode,p->decode) == 0)
        if (LocaleCompare(encode,"*") == 0)
          break;
      p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    }
    if (p != (const DelegateInfo *) NULL)
      (void) InsertValueInLinkedList(delegate_cache,0,
        RemoveElementByValueFromLinkedList(delegate_cache,p));
    UnlockSemaphoreInfo(delegate_semaphore);
    return(p);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e I n f o L i s t                                     %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateInfoList() returns any delegates that match the specified pattern.
  %
  %  The delegate of the GetDelegateInfoList function is:
  %
  %      const DelegateInfo **GetDelegateInfoList(const char *pattern,
  %        size_t *number_delegates,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o pattern: Specifies a pointer to a text string containing a pattern.
  %
  %    o number_delegates:  This integer returns the number of delegates in the
  %      list.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  
  #if defined(__cplusplus) || defined(c_plusplus)
  extern "C" {
  #endif
  
  static int DelegateInfoCompare(const void *x,const void *y)
  {
    const DelegateInfo
      **p,
      **q;
  
    int
      cmp;
  
    p=(const DelegateInfo **) x,
    q=(const DelegateInfo **) y;
    cmp=LocaleCompare((*p)->path,(*q)->path);
    if (cmp == 0)
      {
        if ((*p)->decode == (char *) NULL)
          if (((*p)->encode != (char *) NULL) &&
              ((*q)->encode != (char *) NULL))
            return(strcmp((*p)->encode,(*q)->encode));
        if (((*p)->decode != (char *) NULL) &&
            ((*q)->decode != (char *) NULL))
          return(strcmp((*p)->decode,(*q)->decode));
      }
    return(cmp);
  }
  
  #if defined(__cplusplus) || defined(c_plusplus)
  }
  #endif
  
  MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
    size_t *number_delegates,ExceptionInfo *exception)
  {
    const DelegateInfo
      **delegates;
  
    register const DelegateInfo
      *p;
  
    register ssize_t
      i;
  
    /*
      Allocate delegate list.
    */
    assert(number_delegates != (size_t *) NULL);
    assert(pattern != (char *) NULL);
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
  
    *number_delegates=0;
    p=GetDelegateInfo("*","*",exception);
    if (p == (const DelegateInfo *) NULL)
      return((const DelegateInfo **) NULL);
    delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
      GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
    if (delegates == (const DelegateInfo **) NULL)
      return((const DelegateInfo **) NULL);
    /*
      Generate delegate list.
    */
    LockSemaphoreInfo(delegate_semaphore);
    ResetLinkedListIterator(delegate_cache);
    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    for (i=0; p != (const DelegateInfo *) NULL; )
    {
      if( (p->stealth == MagickFalse) &&
          ( GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse ||
            GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse) )
        delegates[i++]=p;
      p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    }
    UnlockSemaphoreInfo(delegate_semaphore);
    qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
    delegates[i]=(DelegateInfo *) NULL;
    *number_delegates=(size_t) i;
    return(delegates);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e L i s t                                             %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateList() returns any image format delegates that match the
  %  specified  pattern.
  %
  %  The format of the GetDelegateList function is:
  %
  %      char **GetDelegateList(const char *pattern,
  %        size_t *number_delegates,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o pattern: Specifies a pointer to a text string containing a pattern.
  %
  %    o number_delegates:  This integer returns the number of delegates
  %      in the list.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  
  #if defined(__cplusplus) || defined(c_plusplus)
  extern "C" {
  #endif
  
  static int DelegateCompare(const void *x,const void *y)
  {
    register const char
      **p,
      **q;
  
    p=(const char **) x;
    q=(const char **) y;
    return(LocaleCompare(*p,*q));
  }
  
  #if defined(__cplusplus) || defined(c_plusplus)
  }
  #endif
  
  MagickExport char **GetDelegateList(const char *pattern,
    size_t *number_delegates,ExceptionInfo *exception)
  {
    char
      **delegates;
  
    register const DelegateInfo
      *p;
  
    register ssize_t
      i;
  
    /*
      Allocate delegate list.
    */
    assert(pattern != (char *) NULL);
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
  
    assert(number_delegates != (size_t *) NULL);
    *number_delegates=0;
    p=GetDelegateInfo("*","*",exception);
    if (p == (const DelegateInfo *) NULL)
      return((char **) NULL);
    delegates=(char **) AcquireQuantumMemory((size_t)
      GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
    if (delegates == (char **) NULL)
      return((char **) NULL);
    LockSemaphoreInfo(delegate_semaphore);
    ResetLinkedListIterator(delegate_cache);
    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    for (i=0; p != (const DelegateInfo *) NULL; )
    {
      if( (p->stealth == MagickFalse) &&
          GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse )
        delegates[i++]=ConstantString(p->decode);
      if( (p->stealth == MagickFalse) &&
          GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse )
        delegates[i++]=ConstantString(p->encode);
      p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
    }
    UnlockSemaphoreInfo(delegate_semaphore);
    qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
    delegates[i]=(char *) NULL;
    *number_delegates=(size_t) i;
    return(delegates);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   G e t D e l e g a t e M o d e                                             %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateMode() returns the mode of the delegate.
  %
  %  The format of the GetDelegateMode method is:
  %
  %      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
  %
  %  A description of each parameter follows:
  %
  %    o delegate_info:  The delegate info.
  %
  */
  MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
  {
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  
    assert(delegate_info != (DelegateInfo *) NULL);
    assert(delegate_info->signature == MagickCoreSignature);
    return(delegate_info->mode);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  +   G e t D e l e g a t e T h r e a d S u p p o r t                           %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
  %  threads.
  %
  %  The format of the GetDelegateThreadSupport method is:
  %
  %      MagickBooleanType GetDelegateThreadSupport(
  %        const DelegateInfo *delegate_info)
  %
  %  A description of each parameter follows:
  %
  %    o delegate_info:  The delegate info.
  %
  */
  MagickExport MagickBooleanType GetDelegateThreadSupport(
    const DelegateInfo *delegate_info)
  {
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  
    assert(delegate_info != (DelegateInfo *) NULL);
    assert(delegate_info->signature == MagickCoreSignature);
    return(delegate_info->thread_support);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  +   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                     %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  IsDelegateCacheInstantiated() determines if the delegate cache is
  %  instantiated.  If not, it instantiates the cache and returns it.
  %
  %  The format of the IsDelegateInstantiated method is:
  %
  %      MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
  %
  %  A description of each parameter follows.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
  {
    if (delegate_cache == (LinkedListInfo *) NULL)
      {
        if (delegate_semaphore == (SemaphoreInfo *) NULL)
          ActivateSemaphoreInfo(&delegate_semaphore);
        LockSemaphoreInfo(delegate_semaphore);
        if (delegate_cache == (LinkedListInfo *) NULL)
          delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
        UnlockSemaphoreInfo(delegate_semaphore);
      }
    return(delegate_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %   I n v o k e D e l e g a t e                                               %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  InvokeDelegate replaces any embedded formatting characters with the
  %  appropriate image attribute and executes the resulting command.  MagickFalse
  %  is returned if the commands execute with success otherwise MagickTrue.
  %
  %  The format of the InvokeDelegate method is:
  %
  %      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
  %        const char *decode,const char *encode,ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o image_info: the imageInfo.
  %
  %    o image: the image.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  
  static MagickBooleanType CopyDelegateFile(const char *source,
    const char *destination,const MagickBooleanType overwrite)
  {
    int
      destination_file,
      source_file;
  
    MagickBooleanType
      status;
  
    register size_t
      i;
  
    size_t
      length,
      quantum;
  
    ssize_t
      count;
  
    struct stat
      attributes;
  
    unsigned char
      *buffer;
  
    /*
      Copy source file to destination.
    */
    assert(source != (const char *) NULL);
    assert(destination != (char *) NULL);
    if (overwrite == MagickFalse)
      {
        status=GetPathAttributes(destination,&attributes);
        if (status != MagickFalse)
          return(MagickTrue);
      }
    destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
    if (destination_file == -1)
      return(MagickFalse);
    source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
    if (source_file == -1)
      {
        (void) close(destination_file);
        return(MagickFalse);
      }
    quantum=(size_t) MagickMaxBufferExtent;
    if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
      quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
    buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
    if (buffer == (unsigned char *) NULL)
      {
        (void) close(source_file);
        (void) close(destination_file);
        return(MagickFalse);
      }
    length=0;
    for (i=0; ; i+=count)
    {
      count=(ssize_t) read(source_file,buffer,quantum);
      if (count <= 0)
        break;
      length=(size_t) count;
      count=(ssize_t) write(destination_file,buffer,length);
      if ((size_t) count != length)
        break;
    }
    (void) close(destination_file);
    (void) close(source_file);
    buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    return(i != 0 ? MagickTrue : MagickFalse);
  }
  
  MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
    Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
  {
    char
      *command,
      **commands,
      input_filename[MagickPathExtent],
      output_filename[MagickPathExtent];
  
    const DelegateInfo
      *delegate_info;
  
    MagickBooleanType
      status,
      temporary;
  
    PolicyRights
      rights;
  
    register ssize_t
      i;
  
    /*
      Get delegate.
    */
    assert(image_info != (ImageInfo *) NULL);
    assert(image_info->signature == MagickCoreSignature);
    assert(image != (Image *) NULL);
    assert(image->signature == MagickCoreSignature);
    if (image->debug != MagickFalse)
      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    rights=ExecutePolicyRights;
    if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
      {
        errno=EPERM;
        (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
          "NotAuthorized","`%s'",decode);
        return(MagickFalse);
      }
    if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
      {
        errno=EPERM;
        (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
          "NotAuthorized","`%s'",encode);
        return(MagickFalse);
      }
    temporary=*image->filename == '\0' ? MagickTrue : MagickFalse;
    if ((temporary != MagickFalse) && (AcquireUniqueFilename(image->filename) ==
        MagickFalse))
      {
        ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
          image->filename);
        return(MagickFalse);
      }
    delegate_info=GetDelegateInfo(decode,encode,exception);
    if (delegate_info == (DelegateInfo *) NULL)
      {
        if (temporary != MagickFalse)
          (void) RelinquishUniqueFileResource(image->filename);
        (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
          "NoTagFound","`%s'",decode ? decode : encode);
        return(MagickFalse);
      }
    if (*image_info->filename == '\0')
      {
        if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
          {
            if (temporary != MagickFalse)
              (void) RelinquishUniqueFileResource(image->filename);
            ThrowFileException(exception,FileOpenError,
              "UnableToCreateTemporaryFile",image_info->filename);
            return(MagickFalse);
          }
        image_info->temporary=MagickTrue;
      }
    if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
          (delegate_info->encode != (char *) NULL)) ||
         ((encode != (const char *) NULL) &&
          (delegate_info->decode != (char *) NULL))))
      {
        char
          *magick;
  
        ImageInfo
          *clone_info;
  
        register Image
          *p;
  
        /*
          Delegate requires a particular image format.
        */
        if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
          {
            ThrowFileException(exception,FileOpenError,
              "UnableToCreateTemporaryFile",image_info->unique);
            return(MagickFalse);
          }
        magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
          delegate_info->encode : delegate_info->decode,exception);
        if (magick == (char *) NULL)
          {
            (void) RelinquishUniqueFileResource(image_info->unique);
            if (temporary != MagickFalse)
              (void) RelinquishUniqueFileResource(image->filename);
            (void) ThrowMagickException(exception,GetMagickModule(),
              DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
            return(MagickFalse);
          }
        LocaleUpper(magick);
        clone_info=CloneImageInfo(image_info);
        (void) CopyMagickString((char *) clone_info->magick,magick,
          MagickPathExtent);
        if (LocaleCompare(magick,"NULL") != 0)
          (void) CopyMagickString(image->magick,magick,MagickPathExtent);
        magick=DestroyString(magick);
        (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:",
          delegate_info->decode);
        (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
          exception);
        (void) CopyMagickString(clone_info->filename,image_info->filename,
          MagickPathExtent);
        (void) CopyMagickString(image_info->filename,image->filename,
          MagickPathExtent);
        for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
        {
          (void) FormatLocaleString(p->filename,MagickPathExtent,"%s:%s",
            delegate_info->decode,clone_info->filename);
          status=WriteImage(clone_info,p,exception);
          if (status == MagickFalse)
            {
              (void) RelinquishUniqueFileResource(image_info->unique);
              if (temporary != MagickFalse)
                (void) RelinquishUniqueFileResource(image->filename);
              clone_info=DestroyImageInfo(clone_info);
              (void) ThrowMagickException(exception,GetMagickModule(),
                DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
              return(MagickFalse);
            }
          if (clone_info->adjoin != MagickFalse)
            break;
        }
        (void) RelinquishUniqueFileResource(image_info->unique);
        clone_info=DestroyImageInfo(clone_info);
      }
    /*
      Invoke delegate.
    */
    commands=StringToList(delegate_info->commands);
    if (commands == (char **) NULL)
      {
        if (temporary != MagickFalse)
          (void) RelinquishUniqueFileResource(image->filename);
        (void) ThrowMagickException(exception,GetMagickModule(),
          ResourceLimitError,"MemoryAllocationFailed","`%s'",
          decode ? decode : encode);
        return(MagickFalse);
      }
    command=(char *) NULL;
    status=MagickTrue;
    (void) CopyMagickString(output_filename,image_info->filename,
      MagickPathExtent);
    (void) CopyMagickString(input_filename,image->filename,MagickPathExtent);
    for (i=0; commands[i] != (char *) NULL; i++)
    {
      (void) AcquireUniqueSymbolicLink(output_filename,image_info->filename);
      if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
        {
          ThrowFileException(exception,FileOpenError,
            "UnableToCreateTemporaryFile",image_info->unique);
          break;
        }
      if (LocaleCompare(decode,"SCAN") != 0)
        {
          status=AcquireUniqueSymbolicLink(input_filename,image->filename);
          if (status == MagickFalse)
            {
              ThrowFileException(exception,FileOpenError,
                "UnableToCreateTemporaryFile",input_filename);
              break;
            }
        }
      status=MagickTrue;
      command=InterpretDelegateProperties(image_info,image,commands[i],exception);
      if (command != (char *) NULL)
        {
          /*
            Execute delegate.
          */
          if (ExternalDelegateCommand(delegate_info->spawn,image_info->verbose,
            command,(char *) NULL,exception) != 0)
            status=MagickFalse;
          if (delegate_info->spawn != MagickFalse)
            {
              ssize_t
                count;
  
              /*
                Wait for input file to 'disappear', or maximum 2 seconds.
              */
              count=20;
              while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
                (void) MagickDelay(100);  /* sleep 0.1 seconds */
            }
          command=DestroyString(command);
        }
      if (LocaleCompare(decode,"SCAN") != 0)
        {
          if (CopyDelegateFile(image->filename,input_filename,MagickFalse) == MagickFalse)
            (void) RelinquishUniqueFileResource(input_filename);
        }
      if ((strcmp(input_filename,output_filename) != 0) &&
          (CopyDelegateFile(image_info->filename,output_filename,MagickTrue) == MagickFalse))
        (void) RelinquishUniqueFileResource(output_filename);
      if (image_info->temporary != MagickFalse)
        (void) RelinquishUniqueFileResource(image_info->filename);
      (void) RelinquishUniqueFileResource(image_info->unique);
      (void) RelinquishUniqueFileResource(image_info->filename);
      (void) RelinquishUniqueFileResource(image->filename);
      if (status == MagickFalse)
        {
          (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
            "DelegateFailed","`%s'",commands[i]);
          break;
        }
      commands[i]=DestroyString(commands[i]);
    }
    (void) CopyMagickString(image_info->filename,output_filename,
      MagickPathExtent);
    (void) CopyMagickString(image->filename,input_filename,MagickPathExtent);
    /*
      Relinquish resources.
    */
    for ( ; commands[i] != (char *) NULL; i++)
      commands[i]=DestroyString(commands[i]);
    commands=(char **) RelinquishMagickMemory(commands);
    if (temporary != MagickFalse)
      (void) RelinquishUniqueFileResource(image->filename);
    return(status);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %  L i s t D e l e g a t e I n f o                                            %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  ListDelegateInfo() lists the image formats to a file.
  %
  %  The format of the ListDelegateInfo method is:
  %
  %      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
  %
  %  A description of each parameter follows.
  %
  %    o file:  An pointer to a FILE.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
    ExceptionInfo *exception)
  {
    const DelegateInfo
      **delegate_info;
  
    char
      **commands,
      delegate[MagickPathExtent];
  
    const char
      *path;
  
    register ssize_t
      i;
  
    size_t
      number_delegates;
  
    ssize_t
      j;
  
    if (file == (const FILE *) NULL)
      file=stdout;
    delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
    if (delegate_info == (const DelegateInfo **) NULL)
      return(MagickFalse);
    path=(const char *) NULL;
    for (i=0; i < (ssize_t) number_delegates; i++)
    {
      if (delegate_info[i]->stealth != MagickFalse)
        continue;
      if ((path == (const char *) NULL) ||
          (LocaleCompare(path,delegate_info[i]->path) != 0))
        {
          if (delegate_info[i]->path != (char *) NULL)
            (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
          (void) FormatLocaleFile(file,"Delegate                Command\n");
          (void) FormatLocaleFile(file,
            "-------------------------------------------------"
            "------------------------------\n");
        }
      path=delegate_info[i]->path;
      *delegate='\0';
      if (delegate_info[i]->encode != (char *) NULL)
        (void) CopyMagickString(delegate,delegate_info[i]->encode,
          MagickPathExtent);
      (void) ConcatenateMagickString(delegate,"        ",MagickPathExtent);
      delegate[8]='\0';
      commands=StringToList(delegate_info[i]->commands);
      if (commands == (char **) NULL)
        continue;
      (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
        delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
        delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
      StripString(commands[0]);
      (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
      for (j=1; commands[j] != (char *) NULL; j++)
      {
        StripString(commands[j]);
        (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
      }
      for (j=0; commands[j] != (char *) NULL; j++)
        commands[j]=DestroyString(commands[j]);
      commands=(char **) RelinquishMagickMemory(commands);
    }
    (void) fflush(file);
    delegate_info=(const DelegateInfo **)
      RelinquishMagickMemory((void *) delegate_info);
    return(MagickTrue);
  }
  
  /*
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                                                             %
  %                                                                             %
  %                                                                             %
  +   L o a d D e l e g a t e C a c h e                                         %
  %                                                                             %
  %                                                                             %
  %                                                                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  %  LoadDelegateCache() loads the delegate configurations which provides a
  %  mapping between delegate attributes and a delegate name.
  %
  %  The format of the LoadDelegateCache method is:
  %
  %      MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
  %        const char *xml,const char *filename,const size_t depth,
  %        ExceptionInfo *exception)
  %
  %  A description of each parameter follows:
  %
  %    o xml:  The delegate list in XML format.
  %
  %    o filename:  The delegate list filename.
  %
  %    o depth: depth of <include /> statements.
  %
  %    o exception: return any errors or warnings in this structure.
  %
  */
  static MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
    const char *xml,const char *filename,const size_t depth,
    ExceptionInfo *exception)
  {
    char
      keyword[MagickPathExtent],
      *token;
  
    const char
      *q;
  
    DelegateInfo
      *delegate_info;
  
    MagickStatusType
      status;
  
    size_t
      extent;
  
    /*
      Load the delegate map file.
    */
    (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
      "Loading delegate configuration file \"%s\" ...",filename);
    if (xml == (const char *) NULL)
      return(MagickFalse);
    status=MagickTrue;
    delegate_info=(DelegateInfo *) NULL;
    token=AcquireString(xml);
    extent=strlen(token)+MagickPathExtent;
    for (q=(const char *) xml; *q != '\0'; )
    {
      /*
        Interpret XML.
      */
      (void) GetNextToken(q,&q,extent,token);
      if (*token == '\0')
        break;
      (void) CopyMagickString(keyword,token,MagickPathExtent);
      if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
        {
          /*
            Doctype element.
          */
          while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
            (void) GetNextToken(q,&q,extent,token);
          continue;
        }
      if (LocaleNCompare(keyword,"<!--",4) == 0)
        {
          /*
            Comment element.
          */
          while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
            (void) GetNextToken(q,&q,extent,token);
          continue;
        }
      if (LocaleCompare(keyword,"<include") == 0)
        {
          /*
            Include element.
          */
          while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
          {
            (void) CopyMagickString(keyword,token,MagickPathExtent);
            (void) GetNextToken(q,&q,extent,token);
            if (*token != '=')
              continue;
            (void) GetNextToken(q,&q,extent,token);
            if (LocaleCompare(keyword,"file") == 0)
              {
                if (depth > MagickMaxRecursionDepth)
                  (void) ThrowMagickException(exception,GetMagickModule(),
                    ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
                else
                  {
                    char
                      path[MagickPathExtent],
                      *file_xml;
  
                    GetPathComponent(filename,HeadPath,path);
                    if (*path != '\0')
                      (void) ConcatenateMagickString(path,DirectorySeparator,
                        MagickPathExtent);
                    if (*token == *DirectorySeparator)
                      (void) CopyMagickString(path,token,MagickPathExtent);
                    else
                      (void) ConcatenateMagickString(path,token,MagickPathExtent);
                    file_xml=FileToXML(path,~0UL);
                    if (file_xml != (char *) NULL)
                      {
                        status&=LoadDelegateCache(cache,file_xml,path,
                          depth+1,exception);
                        file_xml=DestroyString(file_xml);
                      }
                  }
              }
          }
          continue;
        }
      if (LocaleCompare(keyword,"<delegate") == 0)
        {
          /*
            Delegate element.
          */
          delegate_info=(DelegateInfo *) AcquireCriticalMemory(
            sizeof(*delegate_info));
          (void) memset(delegate_info,0,sizeof(*delegate_info));
          delegate_info->path=ConstantString(filename);
          delegate_info->thread_support=MagickTrue;
          delegate_info->signature=MagickCoreSignature;
          continue;
        }
      if (delegate_info == (DelegateInfo *) NULL)
        continue;
      if ((LocaleCompare(keyword,"/>") == 0) ||
          (LocaleCompare(keyword,"</policy>") == 0))
        {
          status=AppendValueToLinkedList(cache,delegate_info);
          if (status == MagickFalse)
            (void) ThrowMagickException(exception,GetMagickModule(),
              ResourceLimitError,"MemoryAllocationFailed","`%s'",
              delegate_info->commands);
          delegate_info=(DelegateInfo *) NULL;
          continue;
        }
      (void) GetNextToken(q,(const char **) NULL,extent,token);
      if (*token != '=')
        continue;
      (void) GetNextToken(q,&q,extent,token);
      (void) GetNextToken(q,&q,extent,token);
      switch (*keyword)
      {
        case 'C':
        case 'c':
        {
          if (LocaleCompare((char *) keyword,"command") == 0)
            {
              char
                *commands;
  
              commands=AcquireString(token);
  #if defined(MAGICKCORE_WINDOWS_SUPPORT)
              if (strchr(commands,'@') != (char *) NULL)
                {
                  char
                    path[MagickPathExtent];
  
                  NTGhostscriptEXE(path,MagickPathExtent);
                  (void) SubstituteString((char **) &commands,"@PSDelegate@",
                    path);
                  (void) SubstituteString((char **) &commands,"\\","/");
                }
              (void) SubstituteString((char **) &commands,"&quot;","\"");
  #else
              (void) SubstituteString((char **) &commands,"&quot;","'");
  #endif
              (void) SubstituteString((char **) &commands,"&amp;","&");
              (void) SubstituteString((char **) &commands,"&gt;",">");
              (void) SubstituteString((char **) &commands,"&lt;","<");
              delegate_info->commands=commands;
              break;
            }
          break;
        }
        case 'D':
        case 'd':
        {
          if (LocaleCompare((char *) keyword,"decode") == 0)
            {
              delegate_info->decode=ConstantString(token);
              delegate_info->mode=1;
              break;
            }
          break;
        }
        case 'E':
        case 'e':
        {
          if (LocaleCompare((char *) keyword,"encode") == 0)
            {
              delegate_info->encode=ConstantString(token);
              delegate_info->mode=(-1);
              break;
            }
          break;
        }
        case 'M':
        case 'm':
        {
          if (LocaleCompare((char *) keyword,"mode") == 0)
            {
              delegate_info->mode=1;
              if (LocaleCompare(token,"bi") == 0)
                delegate_info->mode=0;
              else
                if (LocaleCompare(token,"encode") == 0)
                  delegate_info->mode=(-1);
              break;
            }
          break;
        }
        case 'S':
        case 's':
        {
          if (LocaleCompare((char *) keyword,"spawn") == 0)
            {
              delegate_info->spawn=IsStringTrue(token);
              break;
            }
          if (LocaleCompare((char *) keyword,"stealth") == 0)
            {
              delegate_info->stealth=IsStringTrue(token);
              break;
            }
          break;
        }
        case 'T':
        case 't':
        {
          if (LocaleCompare((char *) keyword,"thread-support") == 0)
            {
              delegate_info->thread_support=IsStringTrue(token);
              if (delegate_info->thread_support == MagickFalse)
                delegate_info->semaphore=AcquireSemaphoreInfo();
              break;
            }
          break;
        }
        default:
          break;
      }
    }
    token=(char *) RelinquishMagickMemory(token);
    return(status != 0 ? MagickTrue : MagickFalse);
  }
  