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