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