]> granicus.if.org Git - imagemagick/blob - MagickCore/delegate.c
Added checks for exceptions.
[imagemagick] / MagickCore / delegate.c
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-2014 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %  The Delegates methods associate a set of commands with a particular
36 %  image format.  ImageMagick uses delegates for formats it does not handle
37 %  directly.
38 %
39 %  Thanks to Bob Friesenhahn for the initial inspiration and design of the
40 %  delegates methods.
41 %
42 %
43 */
44 \f
45 /*
46   Include declarations.
47 */
48 #include "MagickCore/studio.h"
49 #include "MagickCore/property.h"
50 #include "MagickCore/blob.h"
51 #include "MagickCore/client.h"
52 #include "MagickCore/configure.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/delegate.h"
55 #include "MagickCore/delegate-private.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/hashmap.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/memory_.h"
61 #include "MagickCore/nt-base-private.h"
62 #include "MagickCore/policy.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/semaphore.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/token.h"
67 #include "MagickCore/utility.h"
68 #include "MagickCore/utility-private.h"
69 #include "MagickCore/xml-tree.h"
70 #include "MagickCore/xml-tree-private.h"
71 \f
72 /*
73   Define declarations.
74 */
75 #define DelegateFilename  "delegates.xml"
76 \f
77 /*
78   Declare delegate map.
79 */
80 static const char
81   *DelegateMap = (const char *)
82     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
83     "<delegatemap>"
84     "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
85     "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
86     "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;\"/>"
87     "  <delegate decode=\"cgm\" thread-support=\"False\" command=\"&quot;ralcgm&quot; -d ps -oC &lt; &quot;%i&quot; &gt; &quot;%o&quot; 2&gt; &quot;%u&quot;\"/>"
88     "  <delegate decode=\"dng:decode\" command=\"&quot;/usr/bin/ufraw-batch&quot; --silent --wb=camera --black-point=auto --exposure=auto --create-id=also --out-type=ppm16 &quot;--output=%u.pnm&quot; &quot;%i&quot;\"/>"
89     "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
90     "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
91     "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
92     "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
93     "  <delegate decode=\"gplt\" command=\"&quot;echo&quot; &quot;set size 1.25,0.62     set terminal postscript portrait color solid; set output &quot;%o&quot;; load &quot;%i&quot;&quot; &gt; &quot;%u&quot;;&quot;gnuplot&quot; &quot;%u&quot;\"/>"
94     "  <delegate decode=\"hpg\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
95     "  <delegate decode=\"hpgl\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
96     "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
97     "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
98     "  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
99     "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
100     "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
101     "  <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -v -1 -vframes %S -i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%Z&quot;\"/>"
102     "  <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%Z&quot;\"/>"
103     "  <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;\"/>"
104     "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
105     "  <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;\"/>"
106     "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
107     "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
108     "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
109     "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
110     "  <delegate decode=\"pov\" command=\"&quot;povray&quot; &quot;+i&quot;%i&quot;&quot; -D0 +o&quot;%o&quot; +fn%q +w%w +h%h +a -q9 -kfi&quot;%s&quot; -kff&quot;%n&quot;     &quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;\"/>"
111     "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
112     "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
113     "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
114     "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pngalpha&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
115     "  <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bbox&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
116     "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
117     "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
118     "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
119     "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
120     "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
121     "  <delegate encode=\"show\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
122     "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
123     "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
124     "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
125     "  <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
126     "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
127     "</delegatemap>";
128 \f
129 /*
130   Global declaractions.
131 */
132 static LinkedListInfo
133   *delegate_cache = (LinkedListInfo *) NULL;
134
135 static SemaphoreInfo
136   *delegate_semaphore = (SemaphoreInfo *) NULL;
137 \f
138 /*
139   Forward declaractions.
140 */
141 static MagickBooleanType
142   IsDelegateCacheInstantiated(ExceptionInfo *),
143   LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t,
144     ExceptionInfo *);
145 \f
146 /*
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %                                                                             %
149 %                                                                             %
150 %                                                                             %
151 %  A c q u i r e D e l e g a t e C a c h e                                    %
152 %                                                                             %
153 %                                                                             %
154 %                                                                             %
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 %
157 %  AcquireDelegateCache() caches one or more delegate configurations which
158 %  provides a mapping between delegate attributes and a delegate name.
159 %
160 %  The format of the AcquireDelegateCache method is:
161 %
162 %      LinkedListInfo *AcquireDelegateCache(const char *filename,
163 %        ExceptionInfo *exception)
164 %
165 %  A description of each parameter follows:
166 %
167 %    o filename: the font file name.
168 %
169 %    o exception: return any errors or warnings in this structure.
170 %
171 */
172 static LinkedListInfo *AcquireDelegateCache(const char *filename,
173   ExceptionInfo *exception)
174 {
175   LinkedListInfo
176     *delegate_cache;
177
178   MagickStatusType
179     status;
180
181   delegate_cache=NewLinkedList(0);
182   if (delegate_cache == (LinkedListInfo *) NULL)
183     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
184   status=MagickTrue;
185 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
186   {
187     const StringInfo
188       *option;
189
190     LinkedListInfo
191       *options;
192
193     options=GetConfigureOptions(filename,exception);
194     option=(const StringInfo *) GetNextValueInLinkedList(options);
195     while (option != (const StringInfo *) NULL)
196     {
197       status&=LoadDelegateCache(delegate_cache,(const char *)
198         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
199       option=(const StringInfo *) GetNextValueInLinkedList(options);
200     }
201     options=DestroyConfigureOptions(options);
202   }
203 #endif
204   if (IfMagickTrue(IsLinkedListEmpty(delegate_cache)))
205     status&=LoadDelegateCache(delegate_cache,DelegateMap,"built-in",0,
206       exception);
207   return(delegate_cache);
208 }
209 \f
210 /*
211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212 %                                                                             %
213 %                                                                             %
214 %                                                                             %
215 +   D e l e g a t e C o m p o n e n t G e n e s i s                           %
216 %                                                                             %
217 %                                                                             %
218 %                                                                             %
219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 %
221 %  DelegateComponentGenesis() instantiates the delegate component.
222 %
223 %  The format of the DelegateComponentGenesis method is:
224 %
225 %      MagickBooleanType DelegateComponentGenesis(void)
226 %
227 */
228 MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
229 {
230   if (delegate_semaphore == (SemaphoreInfo *) NULL)
231     delegate_semaphore=AcquireSemaphoreInfo();
232   return(MagickTrue);
233 }
234 \f
235 /*
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 %                                                                             %
238 %                                                                             %
239 %                                                                             %
240 %   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                         %
241 %                                                                             %
242 %                                                                             %
243 %                                                                             %
244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 %
246 %  DelegateComponentTerminus() destroys the delegate component.
247 %
248 %  The format of the DelegateComponentTerminus method is:
249 %
250 %      DelegateComponentTerminus(void)
251 %
252 */
253
254 static void *DestroyDelegate(void *delegate_info)
255 {
256   register DelegateInfo
257     *p;
258
259   p=(DelegateInfo *) delegate_info;
260   if (p->path != (char *) NULL)
261     p->path=DestroyString(p->path);
262   if (p->decode != (char *) NULL)
263     p->decode=DestroyString(p->decode);
264   if (p->encode != (char *) NULL)
265     p->encode=DestroyString(p->encode);
266   if (p->commands != (char *) NULL)
267     p->commands=DestroyString(p->commands);
268   if (p->semaphore != (SemaphoreInfo *) NULL)
269     RelinquishSemaphoreInfo(&p->semaphore);
270   p=(DelegateInfo *) RelinquishMagickMemory(p);
271   return((void *) NULL);
272 }
273
274 MagickPrivate void DelegateComponentTerminus(void)
275 {
276   if (delegate_semaphore == (SemaphoreInfo *) NULL)
277     ActivateSemaphoreInfo(&delegate_semaphore);
278   LockSemaphoreInfo(delegate_semaphore);
279   if (delegate_cache != (LinkedListInfo *) NULL)
280     delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
281   UnlockSemaphoreInfo(delegate_semaphore);
282   RelinquishSemaphoreInfo(&delegate_semaphore);
283 }
284 \f
285 /*
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 %                                                                             %
288 %                                                                             %
289 %                                                                             %
290 %   G e t D e l e g a t e C o m m a n d                                       %
291 %                                                                             %
292 %                                                                             %
293 %                                                                             %
294 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295 %
296 %  GetDelegateCommand() replaces any embedded formatting characters with the
297 %  appropriate image attribute and returns the resulting command.
298 %
299 %  The format of the GetDelegateCommand method is:
300 %
301 %      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
302 %        const char *decode,const char *encode,ExceptionInfo *exception)
303 %
304 %  A description of each parameter follows:
305 %
306 %    o command: Method GetDelegateCommand returns the command associated
307 %      with specified delegate tag.
308 %
309 %    o image_info: the image info.
310 %
311 %    o image: the image.
312 %
313 %    o decode: Specifies the decode delegate we are searching for as a
314 %      character string.
315 %
316 %    o encode: Specifies the encode delegate we are searching for as a
317 %      character string.
318 %
319 %    o exception: return any errors or warnings in this structure.
320 %
321 */
322 MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
323   const char *decode,const char *encode,ExceptionInfo *exception)
324 {
325   char
326     *command,
327     **commands;
328
329   const DelegateInfo
330     *delegate_info;
331
332   register ssize_t
333     i;
334
335   assert(image_info != (ImageInfo *) NULL);
336   assert(image_info->signature == MagickSignature);
337   assert(image != (Image *) NULL);
338   assert(image->signature == MagickSignature);
339   if( IfMagickTrue(image->debug) )
340     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
341
342   delegate_info=GetDelegateInfo(decode,encode,exception);
343   if (delegate_info == (const DelegateInfo *) NULL)
344     {
345       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
346         "NoTagFound","`%s'",decode ? decode : encode);
347       return((char *) NULL);
348     }
349   commands=StringToList(delegate_info->commands);
350   if (commands == (char **) NULL)
351     {
352       (void) ThrowMagickException(exception,GetMagickModule(),
353         ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
354         encode);
355       return((char *) NULL);
356     }
357   command=InterpretImageProperties((ImageInfo *) image_info,image,commands[0],
358     exception);
359   if (command == (char *) NULL)
360     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
361       "MemoryAllocationFailed","`%s'",commands[0]);
362   /*
363     Relinquish resources.
364   */
365   for (i=0; commands[i] != (char *) NULL; i++)
366     commands[i]=DestroyString(commands[i]);
367   commands=(char **) RelinquishMagickMemory(commands);
368   return(command);
369 }
370 \f
371 /*
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 %                                                                             %
374 %                                                                             %
375 %                                                                             %
376 %   G e t D e l e g a t e C o m m a n d s                                     %
377 %                                                                             %
378 %                                                                             %
379 %                                                                             %
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 %
382 %  GetDelegateCommands() returns the commands associated with a delegate.
383 %
384 %  The format of the GetDelegateCommands method is:
385 %
386 %      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
387 %
388 %  A description of each parameter follows:
389 %
390 %    o delegate_info:  The delegate info.
391 %
392 */
393 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
394 {
395   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
396
397   assert(delegate_info != (DelegateInfo *) NULL);
398   assert(delegate_info->signature == MagickSignature);
399   return(delegate_info->commands);
400 }
401 \f
402 /*
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 %                                                                             %
405 %                                                                             %
406 %                                                                             %
407 %   G e t D e l e g a t e I n f o                                             %
408 %                                                                             %
409 %                                                                             %
410 %                                                                             %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %
413 %  GetDelegateInfo() returns any delegates associated with the specified tag.
414 %
415 %  The format of the GetDelegateInfo method is:
416 %
417 %      const DelegateInfo *GetDelegateInfo(const char *decode,
418 %        const char *encode,ExceptionInfo *exception)
419 %
420 %  A description of each parameter follows:
421 %
422 %    o decode: Specifies the decode delegate we are searching for as a
423 %      character string.
424 %
425 %    o encode: Specifies the encode delegate we are searching for as a
426 %      character string.
427 %
428 %    o exception: return any errors or warnings in this structure.
429 %
430 */
431 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
432   const char *encode,ExceptionInfo *exception)
433 {
434   register const DelegateInfo
435     *p;
436
437   assert(exception != (ExceptionInfo *) NULL);
438   if (IfMagickFalse(IsDelegateCacheInstantiated(exception)))
439     return((const DelegateInfo *) NULL);
440   /*
441     Search for named delegate.
442   */
443   LockSemaphoreInfo(delegate_semaphore);
444   ResetLinkedListIterator(delegate_cache);
445   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
446   if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
447     {
448       UnlockSemaphoreInfo(delegate_semaphore);
449       return(p);
450     }
451   while (p != (const DelegateInfo *) NULL)
452   {
453     if (p->mode > 0)
454       {
455         if (LocaleCompare(p->decode,decode) == 0)
456           break;
457         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
458         continue;
459       }
460     if (p->mode < 0)
461       {
462         if (LocaleCompare(p->encode,encode) == 0)
463           break;
464         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
465         continue;
466       }
467     if (LocaleCompare(decode,p->decode) == 0)
468       if (LocaleCompare(encode,p->encode) == 0)
469         break;
470     if (LocaleCompare(decode,"*") == 0)
471       if (LocaleCompare(encode,p->encode) == 0)
472         break;
473     if (LocaleCompare(decode,p->decode) == 0)
474       if (LocaleCompare(encode,"*") == 0)
475         break;
476     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
477   }
478   if (p != (const DelegateInfo *) NULL)
479     (void) InsertValueInLinkedList(delegate_cache,0,
480       RemoveElementByValueFromLinkedList(delegate_cache,p));
481   UnlockSemaphoreInfo(delegate_semaphore);
482   return(p);
483 }
484 \f
485 /*
486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487 %                                                                             %
488 %                                                                             %
489 %                                                                             %
490 %   G e t D e l e g a t e I n f o L i s t                                     %
491 %                                                                             %
492 %                                                                             %
493 %                                                                             %
494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 %
496 %  GetDelegateInfoList() returns any delegates that match the specified pattern.
497 %
498 %  The delegate of the GetDelegateInfoList function is:
499 %
500 %      const DelegateInfo **GetDelegateInfoList(const char *pattern,
501 %        size_t *number_delegates,ExceptionInfo *exception)
502 %
503 %  A description of each parameter follows:
504 %
505 %    o pattern: Specifies a pointer to a text string containing a pattern.
506 %
507 %    o number_delegates:  This integer returns the number of delegates in the
508 %      list.
509 %
510 %    o exception: return any errors or warnings in this structure.
511 %
512 */
513
514 #if defined(__cplusplus) || defined(c_plusplus)
515 extern "C" {
516 #endif
517
518 static int DelegateInfoCompare(const void *x,const void *y)
519 {
520   const DelegateInfo
521     **p,
522     **q;
523
524   p=(const DelegateInfo **) x,
525   q=(const DelegateInfo **) y;
526   if (LocaleCompare((*p)->path,(*q)->path) == 0)
527     {
528       if ((*p)->decode == (char *) NULL)
529         if (((*p)->encode != (char *) NULL) &&
530             ((*q)->encode != (char *) NULL))
531           return(strcmp((*p)->encode,(*q)->encode));
532       if (((*p)->decode != (char *) NULL) &&
533           ((*q)->decode != (char *) NULL))
534         return(strcmp((*p)->decode,(*q)->decode));
535     }
536   return(LocaleCompare((*p)->path,(*q)->path));
537 }
538
539 #if defined(__cplusplus) || defined(c_plusplus)
540 }
541 #endif
542
543 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
544   size_t *number_delegates,ExceptionInfo *exception)
545 {
546   const DelegateInfo
547     **delegates;
548
549   register const DelegateInfo
550     *p;
551
552   register ssize_t
553     i;
554
555   /*
556     Allocate delegate list.
557   */
558   assert(number_delegates != (size_t *) NULL);
559   assert(pattern != (char *) NULL);
560   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
561
562   *number_delegates=0;
563   p=GetDelegateInfo("*","*",exception);
564   if (p == (const DelegateInfo *) NULL)
565     return((const DelegateInfo **) NULL);
566   delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
567     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
568   if (delegates == (const DelegateInfo **) NULL)
569     return((const DelegateInfo **) NULL);
570   /*
571     Generate delegate list.
572   */
573   LockSemaphoreInfo(delegate_semaphore);
574   ResetLinkedListIterator(delegate_cache);
575   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
576   for (i=0; p != (const DelegateInfo *) NULL; )
577   {
578     if( IfMagickFalse(p->stealth) &&
579         ( IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) ||
580           IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse))) )
581       delegates[i++]=p;
582     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
583   }
584   UnlockSemaphoreInfo(delegate_semaphore);
585   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
586   delegates[i]=(DelegateInfo *) NULL;
587   *number_delegates=(size_t) i;
588   return(delegates);
589 }
590 \f
591 /*
592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593 %                                                                             %
594 %                                                                             %
595 %                                                                             %
596 %   G e t D e l e g a t e L i s t                                             %
597 %                                                                             %
598 %                                                                             %
599 %                                                                             %
600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
601 %
602 %  GetDelegateList() returns any image format delegates that match the
603 %  specified  pattern.
604 %
605 %  The format of the GetDelegateList function is:
606 %
607 %      char **GetDelegateList(const char *pattern,
608 %        size_t *number_delegates,ExceptionInfo *exception)
609 %
610 %  A description of each parameter follows:
611 %
612 %    o pattern: Specifies a pointer to a text string containing a pattern.
613 %
614 %    o number_delegates:  This integer returns the number of delegates
615 %      in the list.
616 %
617 %    o exception: return any errors or warnings in this structure.
618 %
619 */
620
621 #if defined(__cplusplus) || defined(c_plusplus)
622 extern "C" {
623 #endif
624
625 static int DelegateCompare(const void *x,const void *y)
626 {
627   register const char
628     **p,
629     **q;
630
631   p=(const char **) x;
632   q=(const char **) y;
633   return(LocaleCompare(*p,*q));
634 }
635
636 #if defined(__cplusplus) || defined(c_plusplus)
637 }
638 #endif
639
640 MagickExport char **GetDelegateList(const char *pattern,
641   size_t *number_delegates,ExceptionInfo *exception)
642 {
643   char
644     **delegates;
645
646   register const DelegateInfo
647     *p;
648
649   register ssize_t
650     i;
651
652   /*
653     Allocate delegate list.
654   */
655   assert(pattern != (char *) NULL);
656   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
657
658   assert(number_delegates != (size_t *) NULL);
659   *number_delegates=0;
660   p=GetDelegateInfo("*","*",exception);
661   if (p == (const DelegateInfo *) NULL)
662     return((char **) NULL);
663   delegates=(char **) AcquireQuantumMemory((size_t)
664     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
665   if (delegates == (char **) NULL)
666     return((char **) NULL);
667   LockSemaphoreInfo(delegate_semaphore);
668   ResetLinkedListIterator(delegate_cache);
669   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
670   for (i=0; p != (const DelegateInfo *) NULL; )
671   {
672     if( IfMagickFalse(p->stealth) &&
673         IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) )
674       delegates[i++]=ConstantString(p->decode);
675     if( IfMagickFalse(p->stealth) &&
676         IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse)) )
677       delegates[i++]=ConstantString(p->encode);
678     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
679   }
680   UnlockSemaphoreInfo(delegate_semaphore);
681   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
682   delegates[i]=(char *) NULL;
683   *number_delegates=(size_t) i;
684   return(delegates);
685 }
686 \f
687 /*
688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689 %                                                                             %
690 %                                                                             %
691 %                                                                             %
692 %   G e t D e l e g a t e M o d e                                             %
693 %                                                                             %
694 %                                                                             %
695 %                                                                             %
696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697 %
698 %  GetDelegateMode() returns the mode of the delegate.
699 %
700 %  The format of the GetDelegateMode method is:
701 %
702 %      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
703 %
704 %  A description of each parameter follows:
705 %
706 %    o delegate_info:  The delegate info.
707 %
708 */
709 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
710 {
711   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
712
713   assert(delegate_info != (DelegateInfo *) NULL);
714   assert(delegate_info->signature == MagickSignature);
715   return(delegate_info->mode);
716 }
717 \f
718 /*
719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 %                                                                             %
721 %                                                                             %
722 %                                                                             %
723 +   G e t D e l e g a t e T h r e a d S u p p o r t                           %
724 %                                                                             %
725 %                                                                             %
726 %                                                                             %
727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728 %
729 %  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
730 %  threads.
731 %
732 %  The format of the GetDelegateThreadSupport method is:
733 %
734 %      MagickBooleanType GetDelegateThreadSupport(
735 %        const DelegateInfo *delegate_info)
736 %
737 %  A description of each parameter follows:
738 %
739 %    o delegate_info:  The delegate info.
740 %
741 */
742 MagickExport MagickBooleanType GetDelegateThreadSupport(
743   const DelegateInfo *delegate_info)
744 {
745   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
746
747   assert(delegate_info != (DelegateInfo *) NULL);
748   assert(delegate_info->signature == MagickSignature);
749   return(delegate_info->thread_support);
750 }
751 \f
752 /*
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 %                                                                             %
755 %                                                                             %
756 %                                                                             %
757 +   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                     %
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762 %
763 %  IsDelegateCacheInstantiated() determines if the delegate cache is
764 %  instantiated.  If not, it instantiates the cache and returns it.
765 %
766 %  The format of the IsDelegateInstantiated method is:
767 %
768 %      MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
769 %
770 %  A description of each parameter follows.
771 %
772 %    o exception: return any errors or warnings in this structure.
773 %
774 */
775 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
776 {
777   if (delegate_cache == (LinkedListInfo *) NULL)
778     {
779       if (delegate_semaphore == (SemaphoreInfo *) NULL)
780         ActivateSemaphoreInfo(&delegate_semaphore);
781       LockSemaphoreInfo(delegate_semaphore);
782       if (delegate_cache == (LinkedListInfo *) NULL)
783         delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
784       UnlockSemaphoreInfo(delegate_semaphore);
785     }
786   return(IsMagickNotNULL(delegate_cache));
787 }
788 \f
789 /*
790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
791 %                                                                             %
792 %                                                                             %
793 %                                                                             %
794 %   I n v o k e D e l e g a t e                                               %
795 %                                                                             %
796 %                                                                             %
797 %                                                                             %
798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
799 %
800 %  InvokeDelegate replaces any embedded formatting characters with the
801 %  appropriate image attribute and executes the resulting command.  MagickFalse
802 %  is returned if the commands execute with success otherwise MagickTrue.
803 %
804 %  The format of the InvokeDelegate method is:
805 %
806 %      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
807 %        const char *decode,const char *encode,ExceptionInfo *exception)
808 %
809 %  A description of each parameter follows:
810 %
811 %    o image_info: the imageInfo.
812 %
813 %    o image: the image.
814 %
815 %    o exception: return any errors or warnings in this structure.
816 %
817 */
818
819 static inline size_t MagickMin(const size_t x,const size_t y)
820 {
821   if (x < y)
822     return(x);
823   return(y);
824 }
825
826 static MagickBooleanType CopyDelegateFile(const char *source,
827   const char *destination)
828 {
829   int
830     destination_file,
831     source_file;
832
833   MagickBooleanType
834     status;
835
836   register size_t
837     i;
838
839   size_t
840     length,
841     quantum;
842
843   ssize_t
844     count;
845
846   struct stat
847     attributes;
848
849   unsigned char
850     *buffer;
851
852   /*
853     Copy source file to destination.
854   */
855   assert(source != (const char *) NULL);
856   assert(destination != (char *) NULL);
857   status=GetPathAttributes(destination,&attributes);
858   if( IfMagickTrue(status) && (attributes.st_size != 0))
859     return(MagickTrue);
860   destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
861   if (destination_file == -1)
862     return(MagickFalse);
863   source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
864   if (source_file == -1)
865     {
866       (void) close(destination_file);
867       return(MagickFalse);
868     }
869   quantum=(size_t) MagickMaxBufferExtent;
870   if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
871     quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
872   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
873   if (buffer == (unsigned char *) NULL)
874     {
875       (void) close(source_file);
876       (void) close(destination_file);
877       return(MagickFalse);
878     }
879   length=0;
880   for (i=0; ; i+=count)
881   {
882     count=(ssize_t) read(source_file,buffer,quantum);
883     if (count <= 0)
884       break;
885     length=(size_t) count;
886     count=(ssize_t) write(destination_file,buffer,length);
887     if ((size_t) count != length)
888       break;
889   }
890   (void) close(destination_file);
891   (void) close(source_file);
892   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
893   return(IsMagickTrue(i!=0));
894 }
895
896 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
897   Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
898 {
899   char
900     *command,
901     **commands,
902     input_filename[MaxTextExtent],
903     output_filename[MaxTextExtent];
904
905   const DelegateInfo
906     *delegate_info;
907
908   MagickBooleanType
909     status,
910     temporary;
911
912   register ssize_t
913     i;
914
915   PolicyRights
916     rights;
917
918   /*
919     Get delegate.
920   */
921   assert(image_info != (ImageInfo *) NULL);
922   assert(image_info->signature == MagickSignature);
923   assert(image != (Image *) NULL);
924   assert(image->signature == MagickSignature);
925   if( IfMagickTrue(image->debug) )
926     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
927
928   rights=ExecutePolicyRights;
929   if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,decode)) )
930     {
931       errno=EPERM;
932       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
933         "NotAuthorized","`%s'",decode);
934       return(MagickFalse);
935     }
936   if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,encode)) )
937     {
938       errno=EPERM;
939       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
940         "NotAuthorized","`%s'",encode);
941       return(MagickFalse);
942     }
943   temporary=IsMagickTrue(*image->filename == '\0');
944   if( IfMagickTrue(temporary) )
945     if( IfMagickFalse(AcquireUniqueFilename(image->filename)) )
946       {
947         ThrowFileException(exception,FileOpenError,
948           "UnableToCreateTemporaryFile",image->filename);
949         return(MagickFalse);
950       }
951   delegate_info=GetDelegateInfo(decode,encode,exception);
952   if (delegate_info == (DelegateInfo *) NULL)
953     {
954       if( IfMagickTrue(temporary) )
955         (void) RelinquishUniqueFileResource(image->filename);
956       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
957         "NoTagFound","`%s'",decode ? decode : encode);
958       return(MagickFalse);
959     }
960   if (*image_info->filename == '\0')
961     {
962       if( IfMagickFalse(AcquireUniqueFilename(image_info->filename)) )
963         {
964           if( IfMagickTrue(temporary) )
965             (void) RelinquishUniqueFileResource(image->filename);
966           ThrowFileException(exception,FileOpenError,
967             "UnableToCreateTemporaryFile",image_info->filename);
968           return(MagickFalse);
969         }
970       image_info->temporary=MagickTrue;
971     }
972   if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
973         (delegate_info->encode != (char *) NULL)) ||
974        ((encode != (const char *) NULL) &&
975         (delegate_info->decode != (char *) NULL))))
976     {
977       char
978         *magick;
979
980       ImageInfo
981         *clone_info;
982
983       register Image
984         *p;
985
986       /*
987         Delegate requires a particular image format.
988       */
989       if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
990         {
991           ThrowFileException(exception,FileOpenError,
992             "UnableToCreateTemporaryFile",image_info->unique);
993           return(MagickFalse);
994         }
995       if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
996         {
997           (void) RelinquishUniqueFileResource(image_info->unique);
998           ThrowFileException(exception,FileOpenError,
999             "UnableToCreateTemporaryFile",image_info->zero);
1000           return(MagickFalse);
1001         }
1002       magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
1003         delegate_info->encode : delegate_info->decode,exception);
1004       if (magick == (char *) NULL)
1005         {
1006           (void) RelinquishUniqueFileResource(image_info->unique);
1007           (void) RelinquishUniqueFileResource(image_info->zero);
1008           if( IfMagickTrue(temporary) )
1009             (void) RelinquishUniqueFileResource(image->filename);
1010           (void) ThrowMagickException(exception,GetMagickModule(),
1011             DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1012           return(MagickFalse);
1013         }
1014       LocaleUpper(magick);
1015       clone_info=CloneImageInfo(image_info);
1016       (void) CopyMagickString((char *) clone_info->magick,magick,
1017         MaxTextExtent);
1018       if (LocaleCompare(magick,"NULL") != 0)
1019         (void) CopyMagickString(image->magick,magick,MaxTextExtent);
1020       magick=DestroyString(magick);
1021       (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
1022         delegate_info->decode);
1023       (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
1024         exception);
1025       (void) CopyMagickString(clone_info->filename,image_info->filename,
1026         MaxTextExtent);
1027       (void) CopyMagickString(image_info->filename,image->filename,
1028         MaxTextExtent);
1029       for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1030       {
1031         (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
1032           delegate_info->decode,clone_info->filename);
1033         status=WriteImage(clone_info,p,exception);
1034         if( IfMagickFalse(status) )
1035           {
1036             (void) RelinquishUniqueFileResource(image_info->unique);
1037             (void) RelinquishUniqueFileResource(image_info->zero);
1038             if( IfMagickTrue(temporary) )
1039               (void) RelinquishUniqueFileResource(image->filename);
1040             clone_info=DestroyImageInfo(clone_info);
1041             (void) ThrowMagickException(exception,GetMagickModule(),
1042               DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1043             return(MagickFalse);
1044           }
1045         if( IfMagickTrue(clone_info->adjoin) )
1046           break;
1047       }
1048       (void) RelinquishUniqueFileResource(image_info->unique);
1049       (void) RelinquishUniqueFileResource(image_info->zero);
1050       clone_info=DestroyImageInfo(clone_info);
1051     }
1052   /*
1053     Invoke delegate.
1054   */
1055   commands=StringToList(delegate_info->commands);
1056   if (commands == (char **) NULL)
1057     {
1058       if( IfMagickTrue(temporary) )
1059         (void) RelinquishUniqueFileResource(image->filename);
1060       (void) ThrowMagickException(exception,GetMagickModule(),
1061         ResourceLimitError,"MemoryAllocationFailed","`%s'",
1062         decode ? decode : encode);
1063       return(MagickFalse);
1064     }
1065   command=(char *) NULL;
1066   status=MagickFalse;
1067   (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
1068   (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
1069   for (i=0; commands[i] != (char *) NULL; i++)
1070   {
1071     status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
1072     if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
1073       {
1074         ThrowFileException(exception,FileOpenError,
1075           "UnableToCreateTemporaryFile",image_info->unique);
1076         break;
1077       }
1078     if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
1079       {
1080         (void) RelinquishUniqueFileResource(image_info->unique);
1081         ThrowFileException(exception,FileOpenError,
1082           "UnableToCreateTemporaryFile",image_info->zero);
1083         break;
1084       }
1085     if (LocaleCompare(decode,"SCAN") != 0)
1086       {
1087         status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1088         if( IfMagickFalse(status) )
1089           {
1090             ThrowFileException(exception,FileOpenError,
1091               "UnableToCreateTemporaryFile",input_filename);
1092             break;
1093           }
1094       }
1095     status=MagickFalse;
1096     command=InterpretImageProperties(image_info,image,commands[i],exception);
1097     if (command != (char *) NULL)
1098       {
1099         /*
1100           Execute delegate.
1101         */
1102         status=IsMagickTrue(SystemCommand(delegate_info->spawn,
1103           image_info->verbose,command,exception) != 0);
1104         if (IfMagickTrue(delegate_info->spawn))
1105           {
1106             ssize_t
1107               count;
1108
1109             /*
1110               Wait for input file to 'disappear', or maximum 10 seconds.
1111             */
1112             count=100;
1113             while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
1114               (void) MagickDelay(100);  /* sleep 0.1 seconds */
1115           }
1116         command=DestroyString(command);
1117       }
1118     if (LocaleCompare(decode,"SCAN") != 0)
1119       {
1120         if( IfMagickFalse(CopyDelegateFile(image->filename,input_filename)) )
1121           (void) RelinquishUniqueFileResource(input_filename);
1122       }
1123     if( IfMagickFalse(CopyDelegateFile(image_info->filename,output_filename)) )
1124       (void) RelinquishUniqueFileResource(output_filename);
1125     if( IfMagickTrue(image_info->temporary) )
1126       (void) RelinquishUniqueFileResource(image_info->filename);
1127     (void) RelinquishUniqueFileResource(image_info->unique);
1128     (void) RelinquishUniqueFileResource(image_info->zero);
1129     (void) RelinquishUniqueFileResource(image_info->filename);
1130     (void) RelinquishUniqueFileResource(image->filename);
1131     if( IfMagickTrue(status) )
1132       {
1133         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1134           "DelegateFailed","`%s'",commands[i]);
1135         break;
1136       }
1137     commands[i]=DestroyString(commands[i]);
1138   }
1139   (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1140   (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1141   /*
1142     Relinquish resources.
1143   */
1144   for ( ; commands[i] != (char *) NULL; i++)
1145     commands[i]=DestroyString(commands[i]);
1146   commands=(char **) RelinquishMagickMemory(commands);
1147   if( IfMagickTrue(temporary) )
1148     (void) RelinquishUniqueFileResource(image->filename);
1149   return(IsMagickFalse(status));
1150 }
1151 \f
1152 /*
1153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1154 %                                                                             %
1155 %                                                                             %
1156 %                                                                             %
1157 %  L i s t D e l e g a t e I n f o                                            %
1158 %                                                                             %
1159 %                                                                             %
1160 %                                                                             %
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 %
1163 %  ListDelegateInfo() lists the image formats to a file.
1164 %
1165 %  The format of the ListDelegateInfo method is:
1166 %
1167 %      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1168 %
1169 %  A description of each parameter follows.
1170 %
1171 %    o file:  An pointer to a FILE.
1172 %
1173 %    o exception: return any errors or warnings in this structure.
1174 %
1175 */
1176 MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1177   ExceptionInfo *exception)
1178 {
1179   const DelegateInfo
1180     **delegate_info;
1181
1182   char
1183     **commands,
1184     delegate[MaxTextExtent];
1185
1186   const char
1187     *path;
1188
1189   register ssize_t
1190     i;
1191
1192   size_t
1193     number_delegates;
1194
1195   ssize_t
1196     j;
1197
1198   if (file == (const FILE *) NULL)
1199     file=stdout;
1200   delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1201   if (delegate_info == (const DelegateInfo **) NULL)
1202     return(MagickFalse);
1203   path=(const char *) NULL;
1204   for (i=0; i < (ssize_t) number_delegates; i++)
1205   {
1206     if( IfMagickTrue(delegate_info[i]->stealth) )
1207       continue;
1208     if ((path == (const char *) NULL) ||
1209         (LocaleCompare(path,delegate_info[i]->path) != 0))
1210       {
1211         if (delegate_info[i]->path != (char *) NULL)
1212           (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1213         (void) FormatLocaleFile(file,"Delegate                Command\n");
1214         (void) FormatLocaleFile(file,
1215           "-------------------------------------------------"
1216           "------------------------------\n");
1217       }
1218     path=delegate_info[i]->path;
1219     *delegate='\0';
1220     if (delegate_info[i]->encode != (char *) NULL)
1221       (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
1222     (void) ConcatenateMagickString(delegate,"        ",MaxTextExtent);
1223     delegate[8]='\0';
1224     commands=StringToList(delegate_info[i]->commands);
1225     if (commands == (char **) NULL)
1226       continue;
1227     (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
1228       delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1229       delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1230     StripString(commands[0]);
1231     (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
1232     for (j=1; commands[j] != (char *) NULL; j++)
1233     {
1234       StripString(commands[j]);
1235       (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
1236     }
1237     for (j=0; commands[j] != (char *) NULL; j++)
1238       commands[j]=DestroyString(commands[j]);
1239     commands=(char **) RelinquishMagickMemory(commands);
1240   }
1241   (void) fflush(file);
1242   delegate_info=(const DelegateInfo **)
1243     RelinquishMagickMemory((void *) delegate_info);
1244   return(MagickTrue);
1245 }
1246 \f
1247 /*
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1249 %                                                                             %
1250 %                                                                             %
1251 %                                                                             %
1252 +   L o a d D e l e g a t e L i s t                                           %
1253 %                                                                             %
1254 %                                                                             %
1255 %                                                                             %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257 %
1258 %  LoadDelegateCache() loads the delegate configurations which provides a
1259 %  mapping between delegate attributes and a delegate name.
1260 %
1261 %  The format of the LoadDelegateCache method is:
1262 %
1263 %      MagickBooleanType LoadDelegateCache(LinkedListInfo *delegate_cache,
1264 %        const char *xml,const char *filename,const size_t depth,
1265 %        ExceptionInfo *exception)
1266 %
1267 %  A description of each parameter follows:
1268 %
1269 %    o xml:  The delegate list in XML format.
1270 %
1271 %    o filename:  The delegate list filename.
1272 %
1273 %    o depth: depth of <include /> statements.
1274 %
1275 %    o exception: return any errors or warnings in this structure.
1276 %
1277 */
1278 static MagickBooleanType LoadDelegateCache(LinkedListInfo *delegate_cache,
1279   const char *xml,const char *filename,const size_t depth,
1280   ExceptionInfo *exception)
1281 {
1282   char
1283     keyword[MaxTextExtent],
1284     *token;
1285
1286   const char
1287     *q;
1288
1289   DelegateInfo
1290     *delegate_info;
1291
1292   MagickBooleanType
1293     status;
1294
1295   /*
1296     Load the delegate map file.
1297   */
1298   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1299     "Loading delegate configuration file \"%s\" ...",filename);
1300   if (xml == (const char *) NULL)
1301     return(MagickFalse);
1302   status=MagickTrue;
1303   delegate_info=(DelegateInfo *) NULL;
1304   token=AcquireString(xml);
1305   for (q=(const char *) xml; *q != '\0'; )
1306   {
1307     /*
1308       Interpret XML.
1309     */
1310     GetMagickToken(q,&q,token);
1311     if (*token == '\0')
1312       break;
1313     (void) CopyMagickString(keyword,token,MaxTextExtent);
1314     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1315       {
1316         /*
1317           Doctype element.
1318         */
1319         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1320           GetMagickToken(q,&q,token);
1321         continue;
1322       }
1323     if (LocaleNCompare(keyword,"<!--",4) == 0)
1324       {
1325         /*
1326           Comment element.
1327         */
1328         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1329           GetMagickToken(q,&q,token);
1330         continue;
1331       }
1332     if (LocaleCompare(keyword,"<include") == 0)
1333       {
1334         /*
1335           Include element.
1336         */
1337         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1338         {
1339           (void) CopyMagickString(keyword,token,MaxTextExtent);
1340           GetMagickToken(q,&q,token);
1341           if (*token != '=')
1342             continue;
1343           GetMagickToken(q,&q,token);
1344           if (LocaleCompare(keyword,"file") == 0)
1345             {
1346               if (depth > 200)
1347                 (void) ThrowMagickException(exception,GetMagickModule(),
1348                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1349               else
1350                 {
1351                   char
1352                     path[MaxTextExtent],
1353                     *xml;
1354
1355                   GetPathComponent(filename,HeadPath,path);
1356                   if (*path != '\0')
1357                     (void) ConcatenateMagickString(path,DirectorySeparator,
1358                       MaxTextExtent);
1359                   if (*token == *DirectorySeparator)
1360                     (void) CopyMagickString(path,token,MaxTextExtent);
1361                   else
1362                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1363                   xml=FileToXML(path,~0UL);
1364                   if (xml != (char *) NULL)
1365                     {
1366                       status&=LoadDelegateCache(delegate_cache,xml,path,
1367                         depth+1,exception);
1368                       xml=(char *) RelinquishMagickMemory(xml);
1369                     }
1370                 }
1371             }
1372         }
1373         continue;
1374       }
1375     if (LocaleCompare(keyword,"<delegate") == 0)
1376       {
1377         /*
1378           Delegate element.
1379         */
1380         delegate_info=(DelegateInfo *) AcquireMagickMemory(
1381           sizeof(*delegate_info));
1382         if (delegate_info == (DelegateInfo *) NULL)
1383           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1384         (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
1385         delegate_info->path=ConstantString(filename);
1386         delegate_info->thread_support=MagickTrue;
1387         delegate_info->signature=MagickSignature;
1388         continue;
1389       }
1390     if (delegate_info == (DelegateInfo *) NULL)
1391       continue;
1392     if (LocaleCompare(keyword,"/>") == 0)
1393       {
1394         status=AppendValueToLinkedList(delegate_cache,delegate_info);
1395         if( IfMagickFalse(status) )
1396           (void) ThrowMagickException(exception,GetMagickModule(),
1397             ResourceLimitError,"MemoryAllocationFailed","`%s'",
1398             delegate_info->commands);
1399         delegate_info=(DelegateInfo *) NULL;
1400         continue;
1401       }
1402     GetMagickToken(q,(const char **) NULL,token);
1403     if (*token != '=')
1404       continue;
1405     GetMagickToken(q,&q,token);
1406     GetMagickToken(q,&q,token);
1407     switch (*keyword)
1408     {
1409       case 'C':
1410       case 'c':
1411       {
1412         if (LocaleCompare((char *) keyword,"command") == 0)
1413           {
1414             char
1415               *commands;
1416
1417             commands=AcquireString(token);
1418 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1419             if (strchr(commands,'@') != (char *) NULL)
1420               {
1421                 char
1422                   path[MaxTextExtent];
1423
1424                 NTGhostscriptEXE(path,MaxTextExtent);
1425                 (void) SubstituteString((char **) &commands,"@PSDelegate@",
1426                   path);
1427                 (void) SubstituteString((char **) &commands,"\\","/");
1428               }
1429 #endif
1430             (void) SubstituteString((char **) &commands,"&amp;","&");
1431             (void) SubstituteString((char **) &commands,"&quot;","\"");
1432             (void) SubstituteString((char **) &commands,"&gt;",">");
1433             (void) SubstituteString((char **) &commands,"&lt;","<");
1434             delegate_info->commands=commands;
1435             break;
1436           }
1437         break;
1438       }
1439       case 'D':
1440       case 'd':
1441       {
1442         if (LocaleCompare((char *) keyword,"decode") == 0)
1443           {
1444             delegate_info->decode=ConstantString(token);
1445             delegate_info->mode=1;
1446             break;
1447           }
1448         break;
1449       }
1450       case 'E':
1451       case 'e':
1452       {
1453         if (LocaleCompare((char *) keyword,"encode") == 0)
1454           {
1455             delegate_info->encode=ConstantString(token);
1456             delegate_info->mode=(-1);
1457             break;
1458           }
1459         break;
1460       }
1461       case 'M':
1462       case 'm':
1463       {
1464         if (LocaleCompare((char *) keyword,"mode") == 0)
1465           {
1466             delegate_info->mode=1;
1467             if (LocaleCompare(token,"bi") == 0)
1468               delegate_info->mode=0;
1469             else
1470               if (LocaleCompare(token,"encode") == 0)
1471                 delegate_info->mode=(-1);
1472             break;
1473           }
1474         break;
1475       }
1476       case 'S':
1477       case 's':
1478       {
1479         if (LocaleCompare((char *) keyword,"spawn") == 0)
1480           {
1481             delegate_info->spawn=IsStringTrue(token);
1482             break;
1483           }
1484         if (LocaleCompare((char *) keyword,"stealth") == 0)
1485           {
1486             delegate_info->stealth=IsStringTrue(token);
1487             break;
1488           }
1489         break;
1490       }
1491       case 'T':
1492       case 't':
1493       {
1494         if (LocaleCompare((char *) keyword,"thread-support") == 0)
1495           {
1496             delegate_info->thread_support=IsStringTrue(token);
1497             if (delegate_info->thread_support == MagickFalse)
1498               delegate_info->semaphore=AcquireSemaphoreInfo();
1499             break;
1500           }
1501         break;
1502       }
1503       default:
1504         break;
1505     }
1506   }
1507   token=(char *) RelinquishMagickMemory(token);
1508   return(status);
1509 }