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