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