]> granicus.if.org Git - imagemagick/blob - MagickCore/delegate.c
(no commit message)
[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(const char *,const char *,const size_t,ExceptionInfo *);
144 \f
145 /*
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 %                                                                             %
148 %                                                                             %
149 %                                                                             %
150 %  A c q u i r e D e l e g a t e C a c h e                                    %
151 %                                                                             %
152 %                                                                             %
153 %                                                                             %
154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155 %
156 %  AcquireDelegateCache() caches one or more delegate configurations which
157 %  provides a mapping between delegate attributes and a delegate name.
158 %
159 %  The format of the AcquireDelegateCache method is:
160 %
161 %      LinkedListInfo *AcquireDelegateCache(const char *filename,
162 %        ExceptionInfo *exception)
163 %
164 %  A description of each parameter follows:
165 %
166 %    o filename: the font file name.
167 %
168 %    o exception: return any errors or warnings in this structure.
169 %
170 */
171 static LinkedListInfo *AcquireDelegateCache(const char *filename,
172   ExceptionInfo *exception)
173 {
174   const StringInfo
175     *option;
176
177   LinkedListInfo
178     *delegate_cache,
179     *options;
180
181   MagickStatusType
182     status;
183
184   delegate_cache=NewLinkedList(0);
185   if (delegate_cache == (LinkedListInfo *) NULL)
186     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
187   status=MagickTrue;
188   options=GetConfigureOptions(filename,exception);
189   option=(const StringInfo *) GetNextValueInLinkedList(options);
190 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
191   while (option != (const StringInfo *) NULL)
192   {
193     status&=LoadDelegateCache((const char *) GetStringInfoDatum(option),
194       GetStringInfoPath(option),0,exception);
195     option=(const StringInfo *) GetNextValueInLinkedList(options);
196   }
197 #endif
198   options=DestroyConfigureOptions(options);
199   if (IfMagickTrue(IsLinkedListEmpty(delegate_cache)))
200     status&=LoadDelegateCache(DelegateMap,"built-in",0,exception);
201   return(delegate_cache);
202 }
203 \f
204 /*
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 %                                                                             %
207 %                                                                             %
208 %                                                                             %
209 +   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                         %
210 %                                                                             %
211 %                                                                             %
212 %                                                                             %
213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214 %
215 %  DelegateComponentGenesis() instantiates the delegate component.
216 %
217 %  The format of the DelegateComponentGenesis method is:
218 %
219 %      MagickBooleanType DelegateComponentGenesis(void)
220 %
221 */
222 MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
223 {
224   delegate_semaphore=AcquireSemaphoreInfo();
225   return(MagickTrue);
226 }
227 \f
228 /*
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230 %                                                                             %
231 %                                                                             %
232 %                                                                             %
233 %   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                         %
234 %                                                                             %
235 %                                                                             %
236 %                                                                             %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 %
239 %  DelegateComponentTerminus() destroys the delegate component.
240 %
241 %  The format of the DelegateComponentTerminus method is:
242 %
243 %      DelegateComponentTerminus(void)
244 %
245 */
246
247 static void *DestroyDelegate(void *delegate_info)
248 {
249   register DelegateInfo
250     *p;
251
252   p=(DelegateInfo *) delegate_info;
253   if (p->path != (char *) NULL)
254     p->path=DestroyString(p->path);
255   if (p->decode != (char *) NULL)
256     p->decode=DestroyString(p->decode);
257   if (p->encode != (char *) NULL)
258     p->encode=DestroyString(p->encode);
259   if (p->commands != (char *) NULL)
260     p->commands=DestroyString(p->commands);
261   if (p->semaphore != (SemaphoreInfo *) NULL)
262     p->semaphore=RelinquishSemaphoreInfo(&p->semaphore);
263   p=(DelegateInfo *) RelinquishMagickMemory(p);
264   return((void *) NULL);
265 }
266
267 MagickPrivate void DelegateComponentTerminus(void)
268 {
269   if (delegate_semaphore == (SemaphoreInfo *) NULL)
270     ActivateSemaphoreInfo(&delegate_semaphore);
271   LockSemaphoreInfo(delegate_semaphore);
272   if (delegate_cache != (LinkedListInfo *) NULL)
273     delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
274   UnlockSemaphoreInfo(delegate_semaphore);
275   RelinquishSemaphoreInfo(&delegate_semaphore);
276 }
277 \f
278 /*
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 %                                                                             %
281 %                                                                             %
282 %                                                                             %
283 %   G e t D e l e g a t e C o m m a n d                                       %
284 %                                                                             %
285 %                                                                             %
286 %                                                                             %
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 %
289 %  GetDelegateCommand() replaces any embedded formatting characters with the
290 %  appropriate image attribute and returns the resulting command.
291 %
292 %  The format of the GetDelegateCommand method is:
293 %
294 %      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
295 %        const char *decode,const char *encode,ExceptionInfo *exception)
296 %
297 %  A description of each parameter follows:
298 %
299 %    o command: Method GetDelegateCommand returns the command associated
300 %      with specified delegate tag.
301 %
302 %    o image_info: the image info.
303 %
304 %    o image: the image.
305 %
306 %    o decode: Specifies the decode delegate we are searching for as a
307 %      character string.
308 %
309 %    o encode: Specifies the encode delegate we are searching for as a
310 %      character string.
311 %
312 %    o exception: return any errors or warnings in this structure.
313 %
314 */
315 MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
316   const char *decode,const char *encode,ExceptionInfo *exception)
317 {
318   char
319     *command,
320     **commands;
321
322   const DelegateInfo
323     *delegate_info;
324
325   register ssize_t
326     i;
327
328   assert(image_info != (ImageInfo *) NULL);
329   assert(image_info->signature == MagickSignature);
330   assert(image != (Image *) NULL);
331   assert(image->signature == MagickSignature);
332   if( IfMagickTrue(image->debug) )
333     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
334
335   delegate_info=GetDelegateInfo(decode,encode,exception);
336   if (delegate_info == (const DelegateInfo *) NULL)
337     {
338       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
339         "NoTagFound","`%s'",decode ? decode : encode);
340       return((char *) NULL);
341     }
342   commands=StringToList(delegate_info->commands);
343   if (commands == (char **) NULL)
344     {
345       (void) ThrowMagickException(exception,GetMagickModule(),
346         ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
347         encode);
348       return((char *) NULL);
349     }
350   command=InterpretImageProperties((ImageInfo *) image_info,image,commands[0],
351     exception);
352   if (command == (char *) NULL)
353     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
354       "MemoryAllocationFailed","`%s'",commands[0]);
355   /*
356     Relinquish resources.
357   */
358   for (i=0; commands[i] != (char *) NULL; i++)
359     commands[i]=DestroyString(commands[i]);
360   commands=(char **) RelinquishMagickMemory(commands);
361   return(command);
362 }
363 \f
364 /*
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366 %                                                                             %
367 %                                                                             %
368 %                                                                             %
369 %   G e t D e l e g a t e C o m m a n d s                                     %
370 %                                                                             %
371 %                                                                             %
372 %                                                                             %
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 %
375 %  GetDelegateCommands() returns the commands associated with a delegate.
376 %
377 %  The format of the GetDelegateCommands method is:
378 %
379 %      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
380 %
381 %  A description of each parameter follows:
382 %
383 %    o delegate_info:  The delegate info.
384 %
385 */
386 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
387 {
388   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
389
390   assert(delegate_info != (DelegateInfo *) NULL);
391   assert(delegate_info->signature == MagickSignature);
392   return(delegate_info->commands);
393 }
394 \f
395 /*
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 %                                                                             %
398 %                                                                             %
399 %                                                                             %
400 %   G e t D e l e g a t e I n f o                                             %
401 %                                                                             %
402 %                                                                             %
403 %                                                                             %
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
405 %
406 %  GetDelegateInfo() returns any delegates associated with the specified tag.
407 %
408 %  The format of the GetDelegateInfo method is:
409 %
410 %      const DelegateInfo *GetDelegateInfo(const char *decode,
411 %        const char *encode,ExceptionInfo *exception)
412 %
413 %  A description of each parameter follows:
414 %
415 %    o decode: Specifies the decode delegate we are searching for as a
416 %      character string.
417 %
418 %    o encode: Specifies the encode delegate we are searching for as a
419 %      character string.
420 %
421 %    o exception: return any errors or warnings in this structure.
422 %
423 */
424 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
425   const char *encode,ExceptionInfo *exception)
426 {
427   register const DelegateInfo
428     *p;
429
430   assert(exception != (ExceptionInfo *) NULL);
431   if (delegate_cache == (LinkedListInfo *) NULL)
432     if( IfMagickFalse(IsDelegateCacheInstantiated(exception)) )
433       return((const DelegateInfo *) NULL);
434   /*
435     Search for named delegate.
436   */
437   LockSemaphoreInfo(delegate_semaphore);
438   ResetLinkedListIterator(delegate_cache);
439   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
440   if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
441     {
442       UnlockSemaphoreInfo(delegate_semaphore);
443       return(p);
444     }
445   while (p != (const DelegateInfo *) NULL)
446   {
447     if (p->mode > 0)
448       {
449         if (LocaleCompare(p->decode,decode) == 0)
450           break;
451         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
452         continue;
453       }
454     if (p->mode < 0)
455       {
456         if (LocaleCompare(p->encode,encode) == 0)
457           break;
458         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
459         continue;
460       }
461     if (LocaleCompare(decode,p->decode) == 0)
462       if (LocaleCompare(encode,p->encode) == 0)
463         break;
464     if (LocaleCompare(decode,"*") == 0)
465       if (LocaleCompare(encode,p->encode) == 0)
466         break;
467     if (LocaleCompare(decode,p->decode) == 0)
468       if (LocaleCompare(encode,"*") == 0)
469         break;
470     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
471   }
472   if (p != (const DelegateInfo *) NULL)
473     (void) InsertValueInLinkedList(delegate_cache,0,
474       RemoveElementByValueFromLinkedList(delegate_cache,p));
475   UnlockSemaphoreInfo(delegate_semaphore);
476   return(p);
477 }
478 \f
479 /*
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 %   G e t D e l e g a t e I n f o L i s t                                     %
485 %                                                                             %
486 %                                                                             %
487 %                                                                             %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 %
490 %  GetDelegateInfoList() returns any delegates that match the specified pattern.
491 %
492 %  The delegate of the GetDelegateInfoList function is:
493 %
494 %      const DelegateInfo **GetDelegateInfoList(const char *pattern,
495 %        size_t *number_delegates,ExceptionInfo *exception)
496 %
497 %  A description of each parameter follows:
498 %
499 %    o pattern: Specifies a pointer to a text string containing a pattern.
500 %
501 %    o number_delegates:  This integer returns the number of delegates in the
502 %      list.
503 %
504 %    o exception: return any errors or warnings in this structure.
505 %
506 */
507
508 #if defined(__cplusplus) || defined(c_plusplus)
509 extern "C" {
510 #endif
511
512 static int DelegateInfoCompare(const void *x,const void *y)
513 {
514   const DelegateInfo
515     **p,
516     **q;
517
518   p=(const DelegateInfo **) x,
519   q=(const DelegateInfo **) y;
520   if (LocaleCompare((*p)->path,(*q)->path) == 0)
521     {
522       if ((*p)->decode == (char *) NULL)
523         if (((*p)->encode != (char *) NULL) &&
524             ((*q)->encode != (char *) NULL))
525           return(strcmp((*p)->encode,(*q)->encode));
526       if (((*p)->decode != (char *) NULL) &&
527           ((*q)->decode != (char *) NULL))
528         return(strcmp((*p)->decode,(*q)->decode));
529     }
530   return(LocaleCompare((*p)->path,(*q)->path));
531 }
532
533 #if defined(__cplusplus) || defined(c_plusplus)
534 }
535 #endif
536
537 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
538   size_t *number_delegates,ExceptionInfo *exception)
539 {
540   const DelegateInfo
541     **delegates;
542
543   register const DelegateInfo
544     *p;
545
546   register ssize_t
547     i;
548
549   /*
550     Allocate delegate list.
551   */
552   assert(number_delegates != (size_t *) NULL);
553   assert(pattern != (char *) NULL);
554   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
555
556   *number_delegates=0;
557   p=GetDelegateInfo("*","*",exception);
558   if (p == (const DelegateInfo *) NULL)
559     return((const DelegateInfo **) NULL);
560   delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
561     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
562   if (delegates == (const DelegateInfo **) NULL)
563     return((const DelegateInfo **) NULL);
564   /*
565     Generate delegate list.
566   */
567   LockSemaphoreInfo(delegate_semaphore);
568   ResetLinkedListIterator(delegate_cache);
569   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
570   for (i=0; p != (const DelegateInfo *) NULL; )
571   {
572     if( IfMagickFalse(p->stealth) &&
573         ( IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) ||
574           IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse))) )
575       delegates[i++]=p;
576     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
577   }
578   UnlockSemaphoreInfo(delegate_semaphore);
579   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
580   delegates[i]=(DelegateInfo *) NULL;
581   *number_delegates=(size_t) i;
582   return(delegates);
583 }
584 \f
585 /*
586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
587 %                                                                             %
588 %                                                                             %
589 %                                                                             %
590 %   G e t D e l e g a t e L i s t                                             %
591 %                                                                             %
592 %                                                                             %
593 %                                                                             %
594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
595 %
596 %  GetDelegateList() returns any image format delegates that match the
597 %  specified  pattern.
598 %
599 %  The format of the GetDelegateList function is:
600 %
601 %      char **GetDelegateList(const char *pattern,
602 %        size_t *number_delegates,ExceptionInfo *exception)
603 %
604 %  A description of each parameter follows:
605 %
606 %    o pattern: Specifies a pointer to a text string containing a pattern.
607 %
608 %    o number_delegates:  This integer returns the number of delegates
609 %      in the list.
610 %
611 %    o exception: return any errors or warnings in this structure.
612 %
613 */
614
615 #if defined(__cplusplus) || defined(c_plusplus)
616 extern "C" {
617 #endif
618
619 static int DelegateCompare(const void *x,const void *y)
620 {
621   register const char
622     **p,
623     **q;
624
625   p=(const char **) x;
626   q=(const char **) y;
627   return(LocaleCompare(*p,*q));
628 }
629
630 #if defined(__cplusplus) || defined(c_plusplus)
631 }
632 #endif
633
634 MagickExport char **GetDelegateList(const char *pattern,
635   size_t *number_delegates,ExceptionInfo *exception)
636 {
637   char
638     **delegates;
639
640   register const DelegateInfo
641     *p;
642
643   register ssize_t
644     i;
645
646   /*
647     Allocate delegate list.
648   */
649   assert(pattern != (char *) NULL);
650   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
651
652   assert(number_delegates != (size_t *) NULL);
653   *number_delegates=0;
654   p=GetDelegateInfo("*","*",exception);
655   if (p == (const DelegateInfo *) NULL)
656     return((char **) NULL);
657   delegates=(char **) AcquireQuantumMemory((size_t)
658     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
659   if (delegates == (char **) NULL)
660     return((char **) NULL);
661   LockSemaphoreInfo(delegate_semaphore);
662   ResetLinkedListIterator(delegate_cache);
663   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
664   for (i=0; p != (const DelegateInfo *) NULL; )
665   {
666     if( IfMagickFalse(p->stealth) &&
667         IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) )
668       delegates[i++]=ConstantString(p->decode);
669     if( IfMagickFalse(p->stealth) &&
670         IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse)) )
671       delegates[i++]=ConstantString(p->encode);
672     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
673   }
674   UnlockSemaphoreInfo(delegate_semaphore);
675   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
676   delegates[i]=(char *) NULL;
677   *number_delegates=(size_t) i;
678   return(delegates);
679 }
680 \f
681 /*
682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 %                                                                             %
684 %                                                                             %
685 %                                                                             %
686 %   G e t D e l e g a t e M o d e                                             %
687 %                                                                             %
688 %                                                                             %
689 %                                                                             %
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 %
692 %  GetDelegateMode() returns the mode of the delegate.
693 %
694 %  The format of the GetDelegateMode method is:
695 %
696 %      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
697 %
698 %  A description of each parameter follows:
699 %
700 %    o delegate_info:  The delegate info.
701 %
702 */
703 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
704 {
705   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
706
707   assert(delegate_info != (DelegateInfo *) NULL);
708   assert(delegate_info->signature == MagickSignature);
709   return(delegate_info->mode);
710 }
711 \f
712 /*
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 %                                                                             %
715 %                                                                             %
716 %                                                                             %
717 +   G e t D e l e g a t e T h r e a d S u p p o r t                           %
718 %                                                                             %
719 %                                                                             %
720 %                                                                             %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 %
723 %  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
724 %  threads.
725 %
726 %  The format of the GetDelegateThreadSupport method is:
727 %
728 %      MagickBooleanType GetDelegateThreadSupport(
729 %        const DelegateInfo *delegate_info)
730 %
731 %  A description of each parameter follows:
732 %
733 %    o delegate_info:  The delegate info.
734 %
735 */
736 MagickExport MagickBooleanType GetDelegateThreadSupport(
737   const DelegateInfo *delegate_info)
738 {
739   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
740
741   assert(delegate_info != (DelegateInfo *) NULL);
742   assert(delegate_info->signature == MagickSignature);
743   return(delegate_info->thread_support);
744 }
745 \f
746 /*
747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
748 %                                                                             %
749 %                                                                             %
750 %                                                                             %
751 +   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                     %
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756 %
757 %  IsDelegateCacheInstantiated() determines if the delegate list is instantiated.
758 %  If not, it instantiates the list and returns it.
759 %
760 %  The format of the IsDelegateInstantiated method is:
761 %
762 %      MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
763 %
764 %  A description of each parameter follows.
765 %
766 %    o exception: return any errors or warnings in this structure.
767 %
768 */
769 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
770 {
771   if (delegate_cache == (LinkedListInfo *) NULL)
772     {
773       if (delegate_semaphore == (SemaphoreInfo *) NULL)
774         ActivateSemaphoreInfo(&delegate_semaphore);
775       LockSemaphoreInfo(delegate_semaphore);
776       if (delegate_cache == (LinkedListInfo *) NULL)
777         delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
778       UnlockSemaphoreInfo(delegate_semaphore);
779     }
780   return(IsMagickNotNULL(delegate_cache));
781 }
782 \f
783 /*
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 %                                                                             %
786 %                                                                             %
787 %                                                                             %
788 %   I n v o k e D e l e g a t e                                               %
789 %                                                                             %
790 %                                                                             %
791 %                                                                             %
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 %
794 %  InvokeDelegate replaces any embedded formatting characters with the
795 %  appropriate image attribute and executes the resulting command.  MagickFalse
796 %  is returned if the commands execute with success otherwise MagickTrue.
797 %
798 %  The format of the InvokeDelegate method is:
799 %
800 %      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
801 %        const char *decode,const char *encode,ExceptionInfo *exception)
802 %
803 %  A description of each parameter follows:
804 %
805 %    o image_info: the imageInfo.
806 %
807 %    o image: the image.
808 %
809 %    o exception: return any errors or warnings in this structure.
810 %
811 */
812
813 static inline size_t MagickMin(const size_t x,const size_t y)
814 {
815   if (x < y)
816     return(x);
817   return(y);
818 }
819
820 static MagickBooleanType CopyDelegateFile(const char *source,
821   const char *destination)
822 {
823   int
824     destination_file,
825     source_file;
826
827   MagickBooleanType
828     status;
829
830   register size_t
831     i;
832
833   size_t
834     length,
835     quantum;
836
837   ssize_t
838     count;
839
840   struct stat
841     attributes;
842
843   unsigned char
844     *buffer;
845
846   /*
847     Copy source file to destination.
848   */
849   assert(source != (const char *) NULL);
850   assert(destination != (char *) NULL);
851   status=GetPathAttributes(destination,&attributes);
852   if( IfMagickTrue(status) && (attributes.st_size != 0))
853     return(MagickTrue);
854   destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
855   if (destination_file == -1)
856     return(MagickFalse);
857   source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
858   if (source_file == -1)
859     {
860       (void) close(destination_file);
861       return(MagickFalse);
862     }
863   quantum=(size_t) MagickMaxBufferExtent;
864   if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
865     quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
866   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
867   if (buffer == (unsigned char *) NULL)
868     {
869       (void) close(source_file);
870       (void) close(destination_file);
871       return(MagickFalse);
872     }
873   length=0;
874   for (i=0; ; i+=count)
875   {
876     count=(ssize_t) read(source_file,buffer,quantum);
877     if (count <= 0)
878       break;
879     length=(size_t) count;
880     count=(ssize_t) write(destination_file,buffer,length);
881     if ((size_t) count != length)
882       break;
883   }
884   (void) close(destination_file);
885   (void) close(source_file);
886   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
887   return(IsMagickTrue(i!=0));
888 }
889
890 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
891   Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
892 {
893   char
894     *command,
895     **commands,
896     input_filename[MaxTextExtent],
897     output_filename[MaxTextExtent];
898
899   const DelegateInfo
900     *delegate_info;
901
902   MagickBooleanType
903     status,
904     temporary;
905
906   register ssize_t
907     i;
908
909   PolicyRights
910     rights;
911
912   /*
913     Get delegate.
914   */
915   assert(image_info != (ImageInfo *) NULL);
916   assert(image_info->signature == MagickSignature);
917   assert(image != (Image *) NULL);
918   assert(image->signature == MagickSignature);
919   if( IfMagickTrue(image->debug) )
920     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
921
922   rights=ExecutePolicyRights;
923   if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,decode)) )
924     {
925       errno=EPERM;
926       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
927         "NotAuthorized","`%s'",decode);
928       return(MagickFalse);
929     }
930   if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,encode)) )
931     {
932       errno=EPERM;
933       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
934         "NotAuthorized","`%s'",encode);
935       return(MagickFalse);
936     }
937   temporary=IsMagickTrue(*image->filename == '\0');
938   if( IfMagickTrue(temporary) )
939     if( IfMagickFalse(AcquireUniqueFilename(image->filename)) )
940       {
941         ThrowFileException(exception,FileOpenError,
942           "UnableToCreateTemporaryFile",image->filename);
943         return(MagickFalse);
944       }
945   delegate_info=GetDelegateInfo(decode,encode,exception);
946   if (delegate_info == (DelegateInfo *) NULL)
947     {
948       if( IfMagickTrue(temporary) )
949         (void) RelinquishUniqueFileResource(image->filename);
950       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
951         "NoTagFound","`%s'",decode ? decode : encode);
952       return(MagickFalse);
953     }
954   if (*image_info->filename == '\0')
955     {
956       if( IfMagickFalse(AcquireUniqueFilename(image_info->filename)) )
957         {
958           if( IfMagickTrue(temporary) )
959             (void) RelinquishUniqueFileResource(image->filename);
960           ThrowFileException(exception,FileOpenError,
961             "UnableToCreateTemporaryFile",image_info->filename);
962           return(MagickFalse);
963         }
964       image_info->temporary=MagickTrue;
965     }
966   if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
967         (delegate_info->encode != (char *) NULL)) ||
968        ((encode != (const char *) NULL) &&
969         (delegate_info->decode != (char *) NULL))))
970     {
971       char
972         *magick;
973
974       ImageInfo
975         *clone_info;
976
977       register Image
978         *p;
979
980       /*
981         Delegate requires a particular image format.
982       */
983       if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
984         {
985           ThrowFileException(exception,FileOpenError,
986             "UnableToCreateTemporaryFile",image_info->unique);
987           return(MagickFalse);
988         }
989       if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
990         {
991           (void) RelinquishUniqueFileResource(image_info->unique);
992           ThrowFileException(exception,FileOpenError,
993             "UnableToCreateTemporaryFile",image_info->zero);
994           return(MagickFalse);
995         }
996       magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
997         delegate_info->encode : delegate_info->decode,exception);
998       if (magick == (char *) NULL)
999         {
1000           (void) RelinquishUniqueFileResource(image_info->unique);
1001           (void) RelinquishUniqueFileResource(image_info->zero);
1002           if( IfMagickTrue(temporary) )
1003             (void) RelinquishUniqueFileResource(image->filename);
1004           (void) ThrowMagickException(exception,GetMagickModule(),
1005             DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1006           return(MagickFalse);
1007         }
1008       LocaleUpper(magick);
1009       clone_info=CloneImageInfo(image_info);
1010       (void) CopyMagickString((char *) clone_info->magick,magick,
1011         MaxTextExtent);
1012       if (LocaleCompare(magick,"NULL") != 0)
1013         (void) CopyMagickString(image->magick,magick,MaxTextExtent);
1014       magick=DestroyString(magick);
1015       (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
1016         delegate_info->decode);
1017       (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
1018         exception);
1019       (void) CopyMagickString(clone_info->filename,image_info->filename,
1020         MaxTextExtent);
1021       (void) CopyMagickString(image_info->filename,image->filename,
1022         MaxTextExtent);
1023       for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1024       {
1025         (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
1026           delegate_info->decode,clone_info->filename);
1027         status=WriteImage(clone_info,p,exception);
1028         if( IfMagickFalse(status) )
1029           {
1030             (void) RelinquishUniqueFileResource(image_info->unique);
1031             (void) RelinquishUniqueFileResource(image_info->zero);
1032             if( IfMagickTrue(temporary) )
1033               (void) RelinquishUniqueFileResource(image->filename);
1034             clone_info=DestroyImageInfo(clone_info);
1035             (void) ThrowMagickException(exception,GetMagickModule(),
1036               DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1037             return(MagickFalse);
1038           }
1039         if( IfMagickTrue(clone_info->adjoin) )
1040           break;
1041       }
1042       (void) RelinquishUniqueFileResource(image_info->unique);
1043       (void) RelinquishUniqueFileResource(image_info->zero);
1044       clone_info=DestroyImageInfo(clone_info);
1045     }
1046   /*
1047     Invoke delegate.
1048   */
1049   commands=StringToList(delegate_info->commands);
1050   if (commands == (char **) NULL)
1051     {
1052       if( IfMagickTrue(temporary) )
1053         (void) RelinquishUniqueFileResource(image->filename);
1054       (void) ThrowMagickException(exception,GetMagickModule(),
1055         ResourceLimitError,"MemoryAllocationFailed","`%s'",
1056         decode ? decode : encode);
1057       return(MagickFalse);
1058     }
1059   command=(char *) NULL;
1060   status=MagickFalse;
1061   (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
1062   (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
1063   for (i=0; commands[i] != (char *) NULL; i++)
1064   {
1065     status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
1066     if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
1067       {
1068         ThrowFileException(exception,FileOpenError,
1069           "UnableToCreateTemporaryFile",image_info->unique);
1070         break;
1071       }
1072     if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
1073       {
1074         (void) RelinquishUniqueFileResource(image_info->unique);
1075         ThrowFileException(exception,FileOpenError,
1076           "UnableToCreateTemporaryFile",image_info->zero);
1077         break;
1078       }
1079     if (LocaleCompare(decode,"SCAN") != 0)
1080       {
1081         status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1082         if( IfMagickFalse(status) )
1083           {
1084             ThrowFileException(exception,FileOpenError,
1085               "UnableToCreateTemporaryFile",input_filename);
1086             break;
1087           }
1088       }
1089     status=MagickFalse;
1090     command=InterpretImageProperties(image_info,image,commands[i],exception);
1091     if (command != (char *) NULL)
1092       {
1093         /*
1094           Execute delegate.
1095         */
1096         status=IsMagickTrue(SystemCommand(delegate_info->spawn,
1097           image_info->verbose,command,exception) != 0);
1098         if (IfMagickTrue(delegate_info->spawn))
1099           {
1100             ssize_t
1101               count;
1102
1103             /*
1104               Wait for input file to 'disappear', or maximum 10 seconds.
1105             */
1106             count=100;
1107             while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
1108               (void) MagickDelay(100);  /* sleep 0.1 seconds */
1109           }
1110         command=DestroyString(command);
1111       }
1112     if (LocaleCompare(decode,"SCAN") != 0)
1113       {
1114         if( IfMagickFalse(CopyDelegateFile(image->filename,input_filename)) )
1115           (void) RelinquishUniqueFileResource(input_filename);
1116       }
1117     if( IfMagickFalse(CopyDelegateFile(image_info->filename,output_filename)) )
1118       (void) RelinquishUniqueFileResource(output_filename);
1119     if( IfMagickTrue(image_info->temporary) )
1120       (void) RelinquishUniqueFileResource(image_info->filename);
1121     (void) RelinquishUniqueFileResource(image_info->unique);
1122     (void) RelinquishUniqueFileResource(image_info->zero);
1123     (void) RelinquishUniqueFileResource(image_info->filename);
1124     (void) RelinquishUniqueFileResource(image->filename);
1125     if( IfMagickTrue(status) )
1126       {
1127         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1128           "DelegateFailed","`%s'",commands[i]);
1129         break;
1130       }
1131     commands[i]=DestroyString(commands[i]);
1132   }
1133   (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1134   (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1135   /*
1136     Relinquish resources.
1137   */
1138   for ( ; commands[i] != (char *) NULL; i++)
1139     commands[i]=DestroyString(commands[i]);
1140   commands=(char **) RelinquishMagickMemory(commands);
1141   if( IfMagickTrue(temporary) )
1142     (void) RelinquishUniqueFileResource(image->filename);
1143   return(IsMagickFalse(status));
1144 }
1145 \f
1146 /*
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 %                                                                             %
1149 %                                                                             %
1150 %                                                                             %
1151 %  L i s t D e l e g a t e I n f o                                            %
1152 %                                                                             %
1153 %                                                                             %
1154 %                                                                             %
1155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156 %
1157 %  ListDelegateInfo() lists the image formats to a file.
1158 %
1159 %  The format of the ListDelegateInfo method is:
1160 %
1161 %      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1162 %
1163 %  A description of each parameter follows.
1164 %
1165 %    o file:  An pointer to a FILE.
1166 %
1167 %    o exception: return any errors or warnings in this structure.
1168 %
1169 */
1170 MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1171   ExceptionInfo *exception)
1172 {
1173   const DelegateInfo
1174     **delegate_info;
1175
1176   char
1177     **commands,
1178     delegate[MaxTextExtent];
1179
1180   const char
1181     *path;
1182
1183   register ssize_t
1184     i;
1185
1186   size_t
1187     number_delegates;
1188
1189   ssize_t
1190     j;
1191
1192   if (file == (const FILE *) NULL)
1193     file=stdout;
1194   delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1195   if (delegate_info == (const DelegateInfo **) NULL)
1196     return(MagickFalse);
1197   path=(const char *) NULL;
1198   for (i=0; i < (ssize_t) number_delegates; i++)
1199   {
1200     if( IfMagickTrue(delegate_info[i]->stealth) )
1201       continue;
1202     if ((path == (const char *) NULL) ||
1203         (LocaleCompare(path,delegate_info[i]->path) != 0))
1204       {
1205         if (delegate_info[i]->path != (char *) NULL)
1206           (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1207         (void) FormatLocaleFile(file,"Delegate                Command\n");
1208         (void) FormatLocaleFile(file,
1209           "-------------------------------------------------"
1210           "------------------------------\n");
1211       }
1212     path=delegate_info[i]->path;
1213     *delegate='\0';
1214     if (delegate_info[i]->encode != (char *) NULL)
1215       (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
1216     (void) ConcatenateMagickString(delegate,"        ",MaxTextExtent);
1217     delegate[8]='\0';
1218     commands=StringToList(delegate_info[i]->commands);
1219     if (commands == (char **) NULL)
1220       continue;
1221     (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
1222       delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1223       delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1224     StripString(commands[0]);
1225     (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
1226     for (j=1; commands[j] != (char *) NULL; j++)
1227     {
1228       StripString(commands[j]);
1229       (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
1230     }
1231     for (j=0; commands[j] != (char *) NULL; j++)
1232       commands[j]=DestroyString(commands[j]);
1233     commands=(char **) RelinquishMagickMemory(commands);
1234   }
1235   (void) fflush(file);
1236   delegate_info=(const DelegateInfo **)
1237     RelinquishMagickMemory((void *) delegate_info);
1238   return(MagickTrue);
1239 }
1240 \f
1241 /*
1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1243 %                                                                             %
1244 %                                                                             %
1245 %                                                                             %
1246 +   L o a d D e l e g a t e L i s t                                           %
1247 %                                                                             %
1248 %                                                                             %
1249 %                                                                             %
1250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1251 %
1252 %  LoadDelegateCache() loads the delegate configurations which provides a
1253 %  mapping between delegate attributes and a delegate name.
1254 %
1255 %  The format of the LoadDelegateCache method is:
1256 %
1257 %      MagickBooleanType LoadDelegateCache(const char *xml,const char *filename,
1258 %        const size_t depth,ExceptionInfo *exception)
1259 %
1260 %  A description of each parameter follows:
1261 %
1262 %    o xml:  The delegate list in XML format.
1263 %
1264 %    o filename:  The delegate list filename.
1265 %
1266 %    o depth: depth of <include /> statements.
1267 %
1268 %    o exception: return any errors or warnings in this structure.
1269 %
1270 */
1271 static MagickBooleanType LoadDelegateCache(const char *xml,const char *filename,
1272   const size_t depth,ExceptionInfo *exception)
1273 {
1274   char
1275     keyword[MaxTextExtent],
1276     *token;
1277
1278   const char
1279     *q;
1280
1281   DelegateInfo
1282     *delegate_info;
1283
1284   MagickBooleanType
1285     status;
1286
1287   /*
1288     Load the delegate map file.
1289   */
1290   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1291     "Loading delegate configuration file \"%s\" ...",filename);
1292   if (xml == (const char *) NULL)
1293     return(MagickFalse);
1294   if (delegate_cache == (LinkedListInfo *) NULL)
1295     {
1296       delegate_cache=NewLinkedList(0);
1297       if (delegate_cache == (LinkedListInfo *) NULL)
1298         {
1299           ThrowFileException(exception,ResourceLimitError,
1300             "MemoryAllocationFailed",filename);
1301           return(MagickFalse);
1302         }
1303     }
1304   status=MagickTrue;
1305   delegate_info=(DelegateInfo *) NULL;
1306   token=AcquireString(xml);
1307   for (q=(const char *) xml; *q != '\0'; )
1308   {
1309     /*
1310       Interpret XML.
1311     */
1312     GetMagickToken(q,&q,token);
1313     if (*token == '\0')
1314       break;
1315     (void) CopyMagickString(keyword,token,MaxTextExtent);
1316     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1317       {
1318         /*
1319           Doctype element.
1320         */
1321         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1322           GetMagickToken(q,&q,token);
1323         continue;
1324       }
1325     if (LocaleNCompare(keyword,"<!--",4) == 0)
1326       {
1327         /*
1328           Comment element.
1329         */
1330         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1331           GetMagickToken(q,&q,token);
1332         continue;
1333       }
1334     if (LocaleCompare(keyword,"<include") == 0)
1335       {
1336         /*
1337           Include element.
1338         */
1339         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1340         {
1341           (void) CopyMagickString(keyword,token,MaxTextExtent);
1342           GetMagickToken(q,&q,token);
1343           if (*token != '=')
1344             continue;
1345           GetMagickToken(q,&q,token);
1346           if (LocaleCompare(keyword,"file") == 0)
1347             {
1348               if (depth > 200)
1349                 (void) ThrowMagickException(exception,GetMagickModule(),
1350                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1351               else
1352                 {
1353                   char
1354                     path[MaxTextExtent],
1355                     *xml;
1356
1357                   GetPathComponent(filename,HeadPath,path);
1358                   if (*path != '\0')
1359                     (void) ConcatenateMagickString(path,DirectorySeparator,
1360                       MaxTextExtent);
1361                   if (*token == *DirectorySeparator)
1362                     (void) CopyMagickString(path,token,MaxTextExtent);
1363                   else
1364                     (void) ConcatenateMagickString(path,token,MaxTextExtent);
1365                   xml=FileToXML(path,~0UL);
1366                   if (xml != (char *) NULL)
1367                     {
1368                       status=LoadDelegateCache(xml,path,depth+1,exception);
1369                       xml=(char *) RelinquishMagickMemory(xml);
1370                     }
1371                 }
1372             }
1373         }
1374         continue;
1375       }
1376     if (LocaleCompare(keyword,"<delegate") == 0)
1377       {
1378         /*
1379           Delegate element.
1380         */
1381         delegate_info=(DelegateInfo *) AcquireMagickMemory(
1382           sizeof(*delegate_info));
1383         if (delegate_info == (DelegateInfo *) NULL)
1384           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1385         (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
1386         delegate_info->path=ConstantString(filename);
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 }