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