]> granicus.if.org Git - imagemagick/blob - MagickCore/delegate.c
...
[imagemagick] / MagickCore / delegate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %           DDDD   EEEEE  L      EEEEE   GGGG   AAA   TTTTT  EEEEE            %
6 %           D   D  E      L      E      G      A   A    T    E                %
7 %           D   D  EEE    L      EEE    G  GG  AAAAA    T    EEE              %
8 %           D   D  E      L      E      G   G  A   A    T    E                %
9 %           DDDD   EEEEE  LLLLL  EEEEE   GGG   A   A    T    EEEEE            %
10 %                                                                             %
11 %                                                                             %
12 %             MagickCore Methods to Read/Write/Invoke Delegates               %
13 %                                                                             %
14 %                             Software Design                                 %
15 %                                  Cristy                                     %
16 %                               October 1998                                  %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %  The Delegates methods associate a set of commands with a particular
36 %  image format.  ImageMagick uses delegates for formats it does not handle
37 %  directly.
38 %
39 %  Thanks to Bob Friesenhahn for the initial inspiration and design of the
40 %  delegates methods.
41 %
42 %
43 */
44 \f
45 /*
46   Include declarations.
47 */
48 #include "MagickCore/studio.h"
49 #include "MagickCore/artifact.h"
50 #include "MagickCore/attribute.h"
51 #include "MagickCore/blob.h"
52 #include "MagickCore/client.h"
53 #include "MagickCore/configure.h"
54 #include "MagickCore/constitute.h"
55 #include "MagickCore/delegate.h"
56 #include "MagickCore/delegate-private.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/fx-private.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/linked-list.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/nt-base-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/policy.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/signature.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/token.h"
73 #include "MagickCore/token-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #include "MagickCore/xml-tree.h"
77 #include "MagickCore/xml-tree-private.h"
78 \f
79 /*
80   Define declarations.
81 */
82 #define DelegateFilename  "delegates.xml"
83 \f
84 /*
85   Declare delegate map.
86 */
87 static const char
88   *DelegateMap = (const char *)
89     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
90     "<delegatemap>"
91     "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
92     "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
93     "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;\"/>"
94     "  <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;\"/>"
95     "  <delegate decode=\"dng:decode\" command=\"&quot;ufraw-batch&quot; --silent --create-id=also --out-type=png --out-depth=16 &quot;--output=%u.png&quot; &quot;%i&quot;\"/>"
96     "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
97     "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
98     "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
99     "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
100     "  <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;\"/>"
101     "  <delegate decode=\"hpgl\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
102     "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
103     "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
104     "  <delegate decode=\"https\" command=\"&quot;curl&quot; -s -k -L -o &quot;%o&quot; &quot;https:%M&quot;\"/>"
105     "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
106     "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
107     "  <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -nostdin -v -1 -vframes %S -i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%Z&quot;\"/>"
108     "  <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -nostdin -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%Z&quot;\"/>"
109     "  <delegate decode=\"pcl:color\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
110     "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
111     "  <delegate decode=\"pcl:mono\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
112     "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
113     "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=ps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
114     "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
115     "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
116     "  <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;\"/>"
117     "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=eps2write&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
118     "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
119     "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
120     "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pngalpha&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
121     "  <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bbox&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
122     "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
123     "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
124     "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pnmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
125     "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
126     "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
127     "  <delegate encode=\"show\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -title &quot;%M&quot; &quot;%i&quot;\"/>"
128     "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
129     "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
130     "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
131     "  <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -title  &quot;%M&quot; &quot;%i&quot;\"/>"
132     "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
133     "</delegatemap>";
134 \f
135 /*
136   Global declaractions.
137 */
138 static LinkedListInfo
139   *delegate_cache = (LinkedListInfo *) NULL;
140
141 static SemaphoreInfo
142   *delegate_semaphore = (SemaphoreInfo *) NULL;
143 \f
144 /*
145   Forward declaractions.
146 */
147 static MagickBooleanType
148   IsDelegateCacheInstantiated(ExceptionInfo *),
149   LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t,
150     ExceptionInfo *);
151 \f
152 /*
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 %                                                                             %
155 %                                                                             %
156 %                                                                             %
157 %  A c q u i r e D e l e g a t e C a c h e                                    %
158 %                                                                             %
159 %                                                                             %
160 %                                                                             %
161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162 %
163 %  AcquireDelegateCache() caches one or more delegate configurations which
164 %  provides a mapping between delegate attributes and a delegate name.
165 %
166 %  The format of the AcquireDelegateCache method is:
167 %
168 %      LinkedListInfo *AcquireDelegateCache(const char *filename,
169 %        ExceptionInfo *exception)
170 %
171 %  A description of each parameter follows:
172 %
173 %    o filename: the font file name.
174 %
175 %    o exception: return any errors or warnings in this structure.
176 %
177 */
178 static LinkedListInfo *AcquireDelegateCache(const char *filename,
179   ExceptionInfo *exception)
180 {
181   LinkedListInfo
182     *cache;
183
184   MagickStatusType
185     status;
186
187   cache=NewLinkedList(0);
188   if (cache == (LinkedListInfo *) NULL)
189     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
190   status=MagickTrue;
191 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
192   {
193     const StringInfo
194       *option;
195
196     LinkedListInfo
197       *options;
198
199     options=GetConfigureOptions(filename,exception);
200     option=(const StringInfo *) GetNextValueInLinkedList(options);
201     while (option != (const StringInfo *) NULL)
202     {
203       status&=LoadDelegateCache(cache,(const char *)
204         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
205       option=(const StringInfo *) GetNextValueInLinkedList(options);
206     }
207     options=DestroyConfigureOptions(options);
208   }
209 #endif
210   if (IsLinkedListEmpty(cache) != MagickFalse)
211     status&=LoadDelegateCache(cache,DelegateMap,"built-in",0,exception);
212   return(cache);
213 }
214 \f
215 /*
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217 %                                                                             %
218 %                                                                             %
219 %                                                                             %
220 +   D e l e g a t e C o m p o n e n t G e n e s i s                           %
221 %                                                                             %
222 %                                                                             %
223 %                                                                             %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 %
226 %  DelegateComponentGenesis() instantiates the delegate component.
227 %
228 %  The format of the DelegateComponentGenesis method is:
229 %
230 %      MagickBooleanType DelegateComponentGenesis(void)
231 %
232 */
233 MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
234 {
235   if (delegate_semaphore == (SemaphoreInfo *) NULL)
236     delegate_semaphore=AcquireSemaphoreInfo();
237   return(MagickTrue);
238 }
239 \f
240 /*
241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 %                                                                             %
243 %                                                                             %
244 %                                                                             %
245 %   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                         %
246 %                                                                             %
247 %                                                                             %
248 %                                                                             %
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 %
251 %  DelegateComponentTerminus() destroys the delegate component.
252 %
253 %  The format of the DelegateComponentTerminus method is:
254 %
255 %      DelegateComponentTerminus(void)
256 %
257 */
258
259 static void *DestroyDelegate(void *delegate_info)
260 {
261   register DelegateInfo
262     *p;
263
264   p=(DelegateInfo *) delegate_info;
265   if (p->path != (char *) NULL)
266     p->path=DestroyString(p->path);
267   if (p->decode != (char *) NULL)
268     p->decode=DestroyString(p->decode);
269   if (p->encode != (char *) NULL)
270     p->encode=DestroyString(p->encode);
271   if (p->commands != (char *) NULL)
272     p->commands=DestroyString(p->commands);
273   if (p->semaphore != (SemaphoreInfo *) NULL)
274     RelinquishSemaphoreInfo(&p->semaphore);
275   p=(DelegateInfo *) RelinquishMagickMemory(p);
276   return((void *) NULL);
277 }
278
279 MagickPrivate void DelegateComponentTerminus(void)
280 {
281   if (delegate_semaphore == (SemaphoreInfo *) NULL)
282     ActivateSemaphoreInfo(&delegate_semaphore);
283   LockSemaphoreInfo(delegate_semaphore);
284   if (delegate_cache != (LinkedListInfo *) NULL)
285     delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
286   UnlockSemaphoreInfo(delegate_semaphore);
287   RelinquishSemaphoreInfo(&delegate_semaphore);
288 }
289 \f
290 /*
291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 %                                                                             %
293 %                                                                             %
294 %                                                                             %
295 +   E x t e r n a l D e l e g a t e C o m m a n d                             %
296 %                                                                             %
297 %                                                                             %
298 %                                                                             %
299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 %
301 %  ExternalDelegateCommand() executes the specified command and waits until it
302 %  terminates.  The returned value is the exit status of the command.
303 %
304 %  The format of the ExternalDelegateCommand method is:
305 %
306 %      int ExternalDelegateCommand(const MagickBooleanType asynchronous,
307 %        const MagickBooleanType verbose,const char *command,
308 %        char *message,ExceptionInfo *exception)
309 %
310 %  A description of each parameter follows:
311 %
312 %    o asynchronous: a value other than 0 executes the parent program
313 %      concurrently with the new child process.
314 %
315 %    o verbose: a value other than 0 prints the executed command before it is
316 %      invoked.
317 %
318 %    o command: this string is the command to execute.
319 %
320 %    o message: an option buffer to receive any message posted to stdout or
321 %      stderr.
322 %
323 %    o exception: return any errors here.
324 %
325 */
326 MagickExport int ExternalDelegateCommand(const MagickBooleanType asynchronous,
327   const MagickBooleanType verbose,const char *command,char *message,
328   ExceptionInfo *exception)
329 {
330   char
331     **arguments,
332     *sanitize_command;
333
334   int
335     number_arguments,
336     status;
337
338   PolicyDomain
339     domain;
340
341   PolicyRights
342     rights;
343
344   register ssize_t
345     i;
346
347   status=(-1);
348   arguments=StringToArgv(command,&number_arguments);
349   if (arguments == (char **) NULL)
350     return(status);
351   if (*arguments[1] == '\0')
352     {
353       for (i=0; i < (ssize_t) number_arguments; i++)
354         arguments[i]=DestroyString(arguments[i]);
355       arguments=(char **) RelinquishMagickMemory(arguments);
356       return(-1);
357     }
358   rights=ExecutePolicyRights;
359   domain=DelegatePolicyDomain;
360   if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
361     {
362       errno=EPERM;
363       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
364         "NotAuthorized","`%s'",arguments[1]);
365       for (i=0; i < (ssize_t) number_arguments; i++)
366         arguments[i]=DestroyString(arguments[i]);
367       arguments=(char **) RelinquishMagickMemory(arguments);
368       return(-1);
369     }
370   if (verbose != MagickFalse)
371     {
372       (void) FormatLocaleFile(stderr,"%s\n",command);
373       (void) fflush(stderr);
374     }
375   sanitize_command=SanitizeString(command);
376   if (asynchronous != MagickFalse)
377     (void) ConcatenateMagickString(sanitize_command,"&",MagickPathExtent);
378   if (message != (char *) NULL)
379     *message='\0';
380 #if defined(MAGICKCORE_POSIX_SUPPORT)
381 #if !defined(MAGICKCORE_HAVE_EXECVP)
382   status=system(sanitize_command);
383 #else
384   if ((asynchronous != MagickFalse) ||
385       (strpbrk(sanitize_command,"&;<>|") != (char *) NULL))
386     status=system(sanitize_command);
387   else
388     {
389       pid_t
390         child_pid;
391
392       /*
393         Call application directly rather than from a shell.
394       */
395       child_pid=(pid_t) fork();
396       if (child_pid == (pid_t) -1)
397         status=system(sanitize_command);
398       else
399         if (child_pid == 0)
400           {
401             status=execvp(arguments[1],arguments+1);
402             _exit(1);
403           }
404         else
405           {
406             int
407               child_status;
408
409             pid_t
410               pid;
411
412             child_status=0;
413             pid=(pid_t) waitpid(child_pid,&child_status,0);
414             if (pid == -1)
415               status=(-1);
416             else
417               {
418                 if (WIFEXITED(child_status) != 0)
419                   status=WEXITSTATUS(child_status);
420                 else
421                   if (WIFSIGNALED(child_status))
422                     status=(-1);
423               }
424           }
425     }
426 #endif
427 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
428   {
429     register char
430       *p;
431
432     /*
433       If a command shell is executed we need to change the forward slashes in
434       files to a backslash. We need to do this to keep Windows happy when we
435       want to 'move' a file.
436
437       TODO: This won't work if one of the delegate parameters has a forward
438             slash as aparameter.
439     */
440     p=strstr(sanitize_command, "cmd.exe /c");
441     if (p != (char*) NULL)
442       {
443         p+=10;
444         for (; *p != '\0'; p++)
445           if (*p == '/')
446             *p=*DirectorySeparator;
447       }
448   }
449   status=NTSystemCommand(sanitize_command,message);
450 #elif defined(macintosh)
451   status=MACSystemCommand(sanitize_command);
452 #elif defined(vms)
453   status=system(sanitize_command);
454 #else
455 #  error No suitable system() method.
456 #endif
457   if (status < 0)
458     {
459       if ((message != (char *) NULL) && (*message != '\0'))
460         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
461           "FailedToExecuteCommand","`%s' (%s)",sanitize_command,message);
462       else
463         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
464           "FailedToExecuteCommand","`%s' (%d)",sanitize_command,status);
465     }
466   sanitize_command=DestroyString(sanitize_command);
467   for (i=0; i < (ssize_t) number_arguments; i++)
468     arguments[i]=DestroyString(arguments[i]);
469   arguments=(char **) RelinquishMagickMemory(arguments);
470   return(status);
471 }
472 \f
473 /*
474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475 %                                                                             %
476 %                                                                             %
477 %                                                                             %
478 %   G e t D e l e g a t e C o m m a n d                                       %
479 %                                                                             %
480 %                                                                             %
481 %                                                                             %
482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 %
484 %  GetDelegateCommand() replaces any embedded formatting characters with the
485 %  appropriate image attribute and returns the resulting command.
486 %
487 %  The format of the GetDelegateCommand method is:
488 %
489 %      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
490 %        const char *decode,const char *encode,ExceptionInfo *exception)
491 %
492 %  A description of each parameter follows:
493 %
494 %    o command: Method GetDelegateCommand returns the command associated
495 %      with specified delegate tag.
496 %
497 %    o image_info: the image info.
498 %
499 %    o image: the image.
500 %
501 %    o decode: Specifies the decode delegate we are searching for as a
502 %      character string.
503 %
504 %    o encode: Specifies the encode delegate we are searching for as a
505 %      character string.
506 %
507 %    o exception: return any errors or warnings in this structure.
508 %
509 */
510
511 static char *GetMagickPropertyLetter(ImageInfo *image_info,Image *image,
512   const char letter,ExceptionInfo *exception)
513 {
514 #define WarnNoImageReturn(format,letter) \
515   if (image == (Image *) NULL) \
516     { \
517       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
518         "NoImageForProperty",format,letter); \
519       break; \
520     }
521 #define WarnNoImageInfoReturn(format,letter) \
522   if (image_info == (ImageInfo *) NULL) \
523     { \
524       (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \
525         "NoImageInfoForProperty",format,letter); \
526       break; \
527     }
528
529   char
530     value[MagickPathExtent];
531
532   const char
533     *string;
534
535   if ((image != (Image *) NULL) && (image->debug != MagickFalse))
536     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
537   else
538     if ((image_info != (ImageInfo *) NULL) &&
539         (image_info->debug != MagickFalse))
540       (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images");
541   /*
542     Get properties that are directly defined by images.
543   */
544   *value='\0';           /* formatted string */
545   string=(const char *) value;
546   switch (letter)
547   {
548     case 'a': /* authentication passphase */
549     {
550       WarnNoImageInfoReturn("\"%%%c\"",letter);
551       string=GetImageOption(image_info,"authenticate");
552       break;
553     }
554     case 'b':  /* image size read in - in bytes */
555     {
556       WarnNoImageReturn("\"%%%c\"",letter);
557       (void) FormatMagickSize(image->extent,MagickFalse,"B",MagickPathExtent,
558         value);
559       if (image->extent == 0)
560         (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",
561           MagickPathExtent,value);
562       break;
563     }
564     case 'd':  /* Directory component of filename */
565     {
566       WarnNoImageReturn("\"%%%c\"",letter);
567       GetPathComponent(image->magick_filename,HeadPath,value);
568       break;
569     }
570     case 'e': /* Filename extension (suffix) of image file */
571     {
572       WarnNoImageReturn("\"%%%c\"",letter);
573       GetPathComponent(image->magick_filename,ExtensionPath,value);
574       break;
575     }
576     case 'f': /* Filename without directory component */
577     {
578       WarnNoImageReturn("\"%%%c\"",letter);
579       GetPathComponent(image->magick_filename,TailPath,value);
580       break;
581     }
582     case 'g': /* Image geometry, canvas and offset  %Wx%H+%X+%Y */
583     {
584       WarnNoImageReturn("\"%%%c\"",letter);
585       (void) FormatLocaleString(value,MagickPathExtent,
586         "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double)
587         image->page.height,(double) image->page.x,(double) image->page.y);
588       break;
589     }
590     case 'h': /* Image height (current) */
591     {
592       WarnNoImageReturn("\"%%%c\"",letter);
593       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
594         (image->rows != 0 ? image->rows : image->magick_rows));
595       break;
596     }
597     case 'i': /* Filename last used for an image (read or write) */
598     {
599       WarnNoImageReturn("\"%%%c\"",letter);
600       string=image->filename;
601       break;
602     }
603     case 'm': /* Image format (file magick) */
604     {
605       WarnNoImageReturn("\"%%%c\"",letter);
606       string=image->magick;
607       break;
608     }
609     case 'n': /* Number of images in the list.  */
610     {
611       if (image != (Image *) NULL)
612         (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
613           GetImageListLength(image));
614       break;
615     }
616     case 'o': /* Output Filename */
617     {
618       WarnNoImageInfoReturn("\"%%%c\"",letter);
619       string=image_info->filename;
620       break;
621     }
622     case 'p': /* Image index in current image list */
623     {
624       WarnNoImageReturn("\"%%%c\"",letter);
625       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
626         GetImageIndexInList(image));
627       break;
628     }
629     case 'q': /* Quantum depth of image in memory */
630     {
631       WarnNoImageReturn("\"%%%c\"",letter);
632       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
633         MAGICKCORE_QUANTUM_DEPTH);
634       break;
635     }
636     case 'r': /* Image storage class, colorspace, and alpha enabled.  */
637     {
638       ColorspaceType
639         colorspace;
640
641       WarnNoImageReturn("\"%%%c\"",letter);
642       colorspace=image->colorspace;
643       if (SetImageGray(image,exception) != MagickFalse)
644         colorspace=GRAYColorspace;   /* FUTURE: this is IMv6 not IMv7 */
645       (void) FormatLocaleString(value,MagickPathExtent,"%s %s %s",
646         CommandOptionToMnemonic(MagickClassOptions,(ssize_t)
647         image->storage_class),CommandOptionToMnemonic(MagickColorspaceOptions,
648         (ssize_t) colorspace),image->alpha_trait != UndefinedPixelTrait ?
649         "Alpha" : "");
650       break;
651     }
652     case 's': /* Image scene number */
653     {
654       WarnNoImageReturn("\"%%%c\"",letter);
655       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
656         image->scene);
657       break;
658     }
659     case 't': /* Base filename without directory or extention */
660     {
661       WarnNoImageReturn("\"%%%c\"",letter);
662       GetPathComponent(image->magick_filename,BasePath,value);
663       break;
664     }
665     case 'u': /* Unique filename */
666     {
667       WarnNoImageInfoReturn("\"%%%c\"",letter);
668       string=image_info->unique;
669       break;
670     }
671     case 'w': /* Image width (current) */
672     {
673       WarnNoImageReturn("\"%%%c\"",letter);
674       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
675         (image->columns != 0 ? image->columns : image->magick_columns));
676       break;
677     }
678     case 'x': /* Image horizontal resolution (with units) */
679     {
680       WarnNoImageReturn("\"%%%c\"",letter);
681       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
682         fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0);
683       break;
684     }
685     case 'y': /* Image vertical resolution (with units) */
686     {
687       WarnNoImageReturn("\"%%%c\"",letter);
688       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
689         fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0);
690       break;
691     }
692     case 'z': /* Image depth as read in */
693     {
694       WarnNoImageReturn("\"%%%c\"",letter);
695       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
696         (double) image->depth);
697       break;
698     }
699     case 'A': /* Image alpha channel  */
700     {
701       WarnNoImageReturn("\"%%%c\"",letter);
702       string=CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
703         image->alpha_trait);
704       break;
705     }
706     case 'C': /* Image compression method.  */
707     {
708       WarnNoImageReturn("\"%%%c\"",letter);
709       string=CommandOptionToMnemonic(MagickCompressOptions,
710         (ssize_t) image->compression);
711       break;
712     }
713     case 'D': /* Image dispose method.  */
714     {
715       WarnNoImageReturn("\"%%%c\"",letter);
716       string=CommandOptionToMnemonic(MagickDisposeOptions,
717         (ssize_t) image->dispose);
718       break;
719     }
720     case 'F':
721     {
722       /*
723         Magick filename - filename given incl. coder & read mods.
724       */
725       WarnNoImageReturn("\"%%%c\"",letter);
726       (void) CopyMagickString(value,image->magick_filename,MagickPathExtent);
727       break;
728     }
729     case 'G': /* Image size as geometry = "%wx%h" */
730     {
731       WarnNoImageReturn("\"%%%c\"",letter);
732       (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
733         (double) image->magick_columns,(double) image->magick_rows);
734       break;
735     }
736     case 'H': /* layer canvas height */
737     {
738       WarnNoImageReturn("\"%%%c\"",letter);
739       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",
740         (double) image->page.height);
741       break;
742     }
743     case 'M': /* Magick filename - filename given incl. coder & read mods */
744     {
745       WarnNoImageReturn("\"%%%c\"",letter);
746       string=image->magick_filename;
747       break;
748     }
749     case 'O': /* layer canvas offset with sign = "+%X+%Y" */
750     {
751       WarnNoImageReturn("\"%%%c\"",letter);
752       (void) FormatLocaleString(value,MagickPathExtent,"%+ld%+ld",(long)
753         image->page.x,(long) image->page.y);
754       break;
755     }
756     case 'P': /* layer canvas page size = "%Wx%H" */
757     {
758       WarnNoImageReturn("\"%%%c\"",letter);
759       (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g",
760         (double) image->page.width,(double) image->page.height);
761       break;
762     }
763     case 'Q': /* image compression quality */
764     {
765       WarnNoImageReturn("\"%%%c\"",letter);
766       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
767         (image->quality == 0 ? 92 : image->quality));
768       break;
769     }
770     case 'S': /* Number of scenes in image list.  */
771     {
772       WarnNoImageInfoReturn("\"%%%c\"",letter);
773       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
774         (image_info->number_scenes == 0 ? 2147483647 :
775          image_info->number_scenes));
776       break;
777     }
778     case 'T': /* image time delay for animations */
779     {
780       WarnNoImageReturn("\"%%%c\"",letter);
781       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
782         image->delay);
783       break;
784     }
785     case 'U': /* Image resolution units. */
786     {
787       WarnNoImageReturn("\"%%%c\"",letter);
788       string=CommandOptionToMnemonic(MagickResolutionOptions,
789         (ssize_t) image->units);
790       break;
791     }
792     case 'W': /* layer canvas width */
793     {
794       WarnNoImageReturn("\"%%%c\"",letter);
795       (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
796         image->page.width);
797       break;
798     }
799     case 'X': /* layer canvas X offset */
800     {
801       WarnNoImageReturn("\"%%%c\"",letter);
802       (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
803         image->page.x);
804       break;
805     }
806     case 'Y': /* layer canvas Y offset */
807     {
808       WarnNoImageReturn("\"%%%c\"",letter);
809       (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double)
810         image->page.y);
811       break;
812     }
813     case '%': /* percent escaped */
814     {
815       string="%";
816       break;
817     }
818     case '@': /* Trim bounding box, without actually trimming! */
819     {
820       RectangleInfo
821         page;
822
823       WarnNoImageReturn("\"%%%c\"",letter);
824       page=GetImageBoundingBox(image,exception);
825       (void) FormatLocaleString(value,MagickPathExtent,
826         "%.20gx%.20g%+.20g%+.20g",(double) page.width,(double) page.height,
827         (double) page.x,(double) page.y);
828       break;
829     }
830     case '#':
831     {
832       /*
833         Image signature.
834       */
835       WarnNoImageReturn("\"%%%c\"",letter);
836       (void) SignatureImage(image,exception);
837       string=GetImageProperty(image,"signature",exception);
838       break;
839     }
840   }
841   return(SanitizeString(string));
842 }
843
844 static char *InterpretDelegateProperties(ImageInfo *image_info,
845   Image *image,const char *embed_text,ExceptionInfo *exception)
846 {
847 #define ExtendInterpretText(string_length) \
848 DisableMSCWarning(4127) \
849 { \
850   size_t length=(string_length); \
851   if ((size_t) (q-interpret_text+length+1) >= extent) \
852     { \
853       extent+=length; \
854       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
855         MaxTextExtent,sizeof(*interpret_text)); \
856       if (interpret_text == (char *) NULL) \
857         return((char *) NULL); \
858       q=interpret_text+strlen(interpret_text); \
859    } \
860 } \
861 RestoreMSCWarning
862
863 #define AppendKeyValue2Text(key,value)\
864 DisableMSCWarning(4127) \
865 { \
866   size_t length=strlen(key)+strlen(value)+2; \
867   if ((size_t) (q-interpret_text+length+1) >= extent) \
868     { \
869       extent+=length; \
870       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
871         MaxTextExtent,sizeof(*interpret_text)); \
872       if (interpret_text == (char *) NULL) \
873         return((char *) NULL); \
874       q=interpret_text+strlen(interpret_text); \
875      } \
876    q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(value)); \
877 } \
878 RestoreMSCWarning
879
880 #define AppendString2Text(string) \
881 DisableMSCWarning(4127) \
882 { \
883   size_t length=strlen((string)); \
884   if ((size_t) (q-interpret_text+length+1) >= extent) \
885     { \
886       extent+=length; \
887       interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \
888         MaxTextExtent,sizeof(*interpret_text)); \
889       if (interpret_text == (char *) NULL) \
890         return((char *) NULL); \
891       q=interpret_text+strlen(interpret_text); \
892     } \
893   (void) CopyMagickString(q,(string),extent); \
894   q+=length; \
895 } \
896 RestoreMSCWarning
897
898   char
899     *interpret_text,
900     *string;
901
902   register char
903     *q;  /* current position in interpret_text */
904
905   register const char
906     *p;  /* position in embed_text string being expanded */
907
908   size_t
909     extent;  /* allocated length of interpret_text */
910
911   MagickBooleanType
912     number;
913
914   assert(image == NULL || image->signature == MagickCoreSignature);
915   assert(image_info == NULL || image_info->signature == MagickCoreSignature);
916   if ((image != (Image *) NULL) && (image->debug != MagickFalse))
917     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
918   else
919    if ((image_info != (ImageInfo *) NULL) && (image_info->debug != MagickFalse))
920      (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-image");
921   if (embed_text == (const char *) NULL)
922     return(ConstantString(""));
923   p=embed_text;
924   while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0'))
925     p++;
926   if (*p == '\0')
927     return(ConstantString(""));
928   /*
929     Translate any embedded format characters.
930   */
931   interpret_text=AcquireString(embed_text);  /* new string with extra space */
932   extent=MagickPathExtent;  /* allocated space in string */
933   number=MagickFalse;  /* is last char a number? */
934   for (q=interpret_text; *p!='\0';
935     number=isdigit(*p) ? MagickTrue : MagickFalse,p++)
936   {
937     /*
938       Interpret escape characters (e.g. Filename: %M).
939     */
940     *q='\0';
941     ExtendInterpretText(MagickPathExtent);
942     switch (*p)
943     {
944       case '\\':
945       {
946         switch (*(p+1))
947         {
948           case '\0':
949             continue;
950           case 'r':  /* convert to RETURN */
951           {
952             *q++='\r';
953             p++;
954             continue;
955           }
956           case 'n':  /* convert to NEWLINE */
957           {
958             *q++='\n';
959             p++;
960             continue;
961           }
962           case '\n':  /* EOL removal UNIX,MacOSX */
963           {
964             p++;
965             continue;
966           }
967           case '\r':  /* EOL removal DOS,Windows */
968           {
969             p++;
970             if (*p == '\n') /* return-newline EOL */
971               p++;
972             continue;
973           }
974           default:
975           {
976             p++;
977             *q++=(*p);
978           }
979         }
980         continue;
981       }
982       case '&':
983       {
984         if (LocaleNCompare("&lt;",p,4) == 0)
985           {
986             *q++='<';
987             p+=3;
988           }
989         else
990           if (LocaleNCompare("&gt;",p,4) == 0)
991             {
992               *q++='>';
993               p+=3;
994             }
995           else
996             if (LocaleNCompare("&amp;",p,5) == 0)
997               {
998                 *q++='&';
999                 p+=4;
1000               }
1001             else
1002               *q++=(*p);
1003         continue;
1004       }
1005       case '%':
1006         break;  /* continue to next set of handlers */
1007       default:
1008       {
1009         *q++=(*p);  /* any thing else is 'as normal' */
1010         continue;
1011       }
1012     }
1013     p++; /* advance beyond the percent */
1014     /*
1015       Doubled Percent - or percent at end of string.
1016     */
1017     if ((*p == '\0') || (*p == '\'') || (*p == '"'))
1018       p--;
1019     if (*p == '%')
1020       {
1021         *q++='%';
1022         continue;
1023       }
1024     /*
1025       Single letter escapes %c.
1026     */
1027     if (number != MagickFalse)
1028       {
1029         /*
1030           But only if not preceeded by a number!
1031         */
1032         *q++='%'; /* do NOT substitute the percent */
1033         p--;      /* back up one */
1034         continue;
1035       }
1036     string=GetMagickPropertyLetter(image_info,image,*p, exception);
1037     if (string != (char *) NULL)
1038       {
1039         AppendString2Text(string);
1040         string=DestroyString(string);
1041         continue;
1042       }
1043     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1044       "UnknownImageProperty","\"%%%c\"",*p);
1045   }
1046   *q='\0';
1047   return(interpret_text);
1048 }
1049
1050 MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
1051   const char *decode,const char *encode,ExceptionInfo *exception)
1052 {
1053   char
1054     *command,
1055     **commands;
1056
1057   const DelegateInfo
1058     *delegate_info;
1059
1060   register ssize_t
1061     i;
1062
1063   assert(image_info != (ImageInfo *) NULL);
1064   assert(image_info->signature == MagickCoreSignature);
1065   assert(image != (Image *) NULL);
1066   assert(image->signature == MagickCoreSignature);
1067   if (image->debug != MagickFalse)
1068     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1069
1070   delegate_info=GetDelegateInfo(decode,encode,exception);
1071   if (delegate_info == (const DelegateInfo *) NULL)
1072     {
1073       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1074         "NoTagFound","`%s'",decode ? decode : encode);
1075       return((char *) NULL);
1076     }
1077   commands=StringToList(delegate_info->commands);
1078   if (commands == (char **) NULL)
1079     {
1080       (void) ThrowMagickException(exception,GetMagickModule(),
1081         ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
1082         encode);
1083       return((char *) NULL);
1084     }
1085   command=InterpretDelegateProperties((ImageInfo *) image_info,image,
1086     commands[0],exception);
1087   if (command == (char *) NULL)
1088     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
1089       "MemoryAllocationFailed","`%s'",commands[0]);
1090   /*
1091     Relinquish resources.
1092   */
1093   for (i=0; commands[i] != (char *) NULL; i++)
1094     commands[i]=DestroyString(commands[i]);
1095   commands=(char **) RelinquishMagickMemory(commands);
1096   return(command);
1097 }
1098 \f
1099 /*
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 %                                                                             %
1102 %                                                                             %
1103 %                                                                             %
1104 %   G e t D e l e g a t e C o m m a n d s                                     %
1105 %                                                                             %
1106 %                                                                             %
1107 %                                                                             %
1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 %
1110 %  GetDelegateCommands() returns the commands associated with a delegate.
1111 %
1112 %  The format of the GetDelegateCommands method is:
1113 %
1114 %      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
1115 %
1116 %  A description of each parameter follows:
1117 %
1118 %    o delegate_info:  The delegate info.
1119 %
1120 */
1121 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
1122 {
1123   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1124
1125   assert(delegate_info != (DelegateInfo *) NULL);
1126   assert(delegate_info->signature == MagickCoreSignature);
1127   return(delegate_info->commands);
1128 }
1129 \f
1130 /*
1131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 %                                                                             %
1133 %                                                                             %
1134 %                                                                             %
1135 %   G e t D e l e g a t e I n f o                                             %
1136 %                                                                             %
1137 %                                                                             %
1138 %                                                                             %
1139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1140 %
1141 %  GetDelegateInfo() returns any delegates associated with the specified tag.
1142 %
1143 %  The format of the GetDelegateInfo method is:
1144 %
1145 %      const DelegateInfo *GetDelegateInfo(const char *decode,
1146 %        const char *encode,ExceptionInfo *exception)
1147 %
1148 %  A description of each parameter follows:
1149 %
1150 %    o decode: Specifies the decode delegate we are searching for as a
1151 %      character string.
1152 %
1153 %    o encode: Specifies the encode delegate we are searching for as a
1154 %      character string.
1155 %
1156 %    o exception: return any errors or warnings in this structure.
1157 %
1158 */
1159 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
1160   const char *encode,ExceptionInfo *exception)
1161 {
1162   register const DelegateInfo
1163     *p;
1164
1165   assert(exception != (ExceptionInfo *) NULL);
1166   if (IsDelegateCacheInstantiated(exception) == MagickFalse)
1167     return((const DelegateInfo *) NULL);
1168   /*
1169     Search for named delegate.
1170   */
1171   LockSemaphoreInfo(delegate_semaphore);
1172   ResetLinkedListIterator(delegate_cache);
1173   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1174   if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
1175     {
1176       UnlockSemaphoreInfo(delegate_semaphore);
1177       return(p);
1178     }
1179   while (p != (const DelegateInfo *) NULL)
1180   {
1181     if (p->mode > 0)
1182       {
1183         if (LocaleCompare(p->decode,decode) == 0)
1184           break;
1185         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1186         continue;
1187       }
1188     if (p->mode < 0)
1189       {
1190         if (LocaleCompare(p->encode,encode) == 0)
1191           break;
1192         p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1193         continue;
1194       }
1195     if (LocaleCompare(decode,p->decode) == 0)
1196       if (LocaleCompare(encode,p->encode) == 0)
1197         break;
1198     if (LocaleCompare(decode,"*") == 0)
1199       if (LocaleCompare(encode,p->encode) == 0)
1200         break;
1201     if (LocaleCompare(decode,p->decode) == 0)
1202       if (LocaleCompare(encode,"*") == 0)
1203         break;
1204     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1205   }
1206   if (p != (const DelegateInfo *) NULL)
1207     (void) InsertValueInLinkedList(delegate_cache,0,
1208       RemoveElementByValueFromLinkedList(delegate_cache,p));
1209   UnlockSemaphoreInfo(delegate_semaphore);
1210   return(p);
1211 }
1212 \f
1213 /*
1214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 %                                                                             %
1216 %                                                                             %
1217 %                                                                             %
1218 %   G e t D e l e g a t e I n f o L i s t                                     %
1219 %                                                                             %
1220 %                                                                             %
1221 %                                                                             %
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 %
1224 %  GetDelegateInfoList() returns any delegates that match the specified pattern.
1225 %
1226 %  The delegate of the GetDelegateInfoList function is:
1227 %
1228 %      const DelegateInfo **GetDelegateInfoList(const char *pattern,
1229 %        size_t *number_delegates,ExceptionInfo *exception)
1230 %
1231 %  A description of each parameter follows:
1232 %
1233 %    o pattern: Specifies a pointer to a text string containing a pattern.
1234 %
1235 %    o number_delegates:  This integer returns the number of delegates in the
1236 %      list.
1237 %
1238 %    o exception: return any errors or warnings in this structure.
1239 %
1240 */
1241
1242 #if defined(__cplusplus) || defined(c_plusplus)
1243 extern "C" {
1244 #endif
1245
1246 static int DelegateInfoCompare(const void *x,const void *y)
1247 {
1248   const DelegateInfo
1249     **p,
1250     **q;
1251
1252   int
1253     cmp;
1254
1255   p=(const DelegateInfo **) x,
1256   q=(const DelegateInfo **) y;
1257   cmp=LocaleCompare((*p)->path,(*q)->path);
1258   if (cmp == 0)
1259     {
1260       if ((*p)->decode == (char *) NULL)
1261         if (((*p)->encode != (char *) NULL) &&
1262             ((*q)->encode != (char *) NULL))
1263           return(strcmp((*p)->encode,(*q)->encode));
1264       if (((*p)->decode != (char *) NULL) &&
1265           ((*q)->decode != (char *) NULL))
1266         return(strcmp((*p)->decode,(*q)->decode));
1267     }
1268   return(cmp);
1269 }
1270
1271 #if defined(__cplusplus) || defined(c_plusplus)
1272 }
1273 #endif
1274
1275 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
1276   size_t *number_delegates,ExceptionInfo *exception)
1277 {
1278   const DelegateInfo
1279     **delegates;
1280
1281   register const DelegateInfo
1282     *p;
1283
1284   register ssize_t
1285     i;
1286
1287   /*
1288     Allocate delegate list.
1289   */
1290   assert(number_delegates != (size_t *) NULL);
1291   assert(pattern != (char *) NULL);
1292   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1293
1294   *number_delegates=0;
1295   p=GetDelegateInfo("*","*",exception);
1296   if (p == (const DelegateInfo *) NULL)
1297     return((const DelegateInfo **) NULL);
1298   delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
1299     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
1300   if (delegates == (const DelegateInfo **) NULL)
1301     return((const DelegateInfo **) NULL);
1302   /*
1303     Generate delegate list.
1304   */
1305   LockSemaphoreInfo(delegate_semaphore);
1306   ResetLinkedListIterator(delegate_cache);
1307   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1308   for (i=0; p != (const DelegateInfo *) NULL; )
1309   {
1310     if( (p->stealth == MagickFalse) &&
1311         ( GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse ||
1312           GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse) )
1313       delegates[i++]=p;
1314     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1315   }
1316   UnlockSemaphoreInfo(delegate_semaphore);
1317   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
1318   delegates[i]=(DelegateInfo *) NULL;
1319   *number_delegates=(size_t) i;
1320   return(delegates);
1321 }
1322 \f
1323 /*
1324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325 %                                                                             %
1326 %                                                                             %
1327 %                                                                             %
1328 %   G e t D e l e g a t e L i s t                                             %
1329 %                                                                             %
1330 %                                                                             %
1331 %                                                                             %
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 %
1334 %  GetDelegateList() returns any image format delegates that match the
1335 %  specified  pattern.
1336 %
1337 %  The format of the GetDelegateList function is:
1338 %
1339 %      char **GetDelegateList(const char *pattern,
1340 %        size_t *number_delegates,ExceptionInfo *exception)
1341 %
1342 %  A description of each parameter follows:
1343 %
1344 %    o pattern: Specifies a pointer to a text string containing a pattern.
1345 %
1346 %    o number_delegates:  This integer returns the number of delegates
1347 %      in the list.
1348 %
1349 %    o exception: return any errors or warnings in this structure.
1350 %
1351 */
1352
1353 #if defined(__cplusplus) || defined(c_plusplus)
1354 extern "C" {
1355 #endif
1356
1357 static int DelegateCompare(const void *x,const void *y)
1358 {
1359   register const char
1360     **p,
1361     **q;
1362
1363   p=(const char **) x;
1364   q=(const char **) y;
1365   return(LocaleCompare(*p,*q));
1366 }
1367
1368 #if defined(__cplusplus) || defined(c_plusplus)
1369 }
1370 #endif
1371
1372 MagickExport char **GetDelegateList(const char *pattern,
1373   size_t *number_delegates,ExceptionInfo *exception)
1374 {
1375   char
1376     **delegates;
1377
1378   register const DelegateInfo
1379     *p;
1380
1381   register ssize_t
1382     i;
1383
1384   /*
1385     Allocate delegate list.
1386   */
1387   assert(pattern != (char *) NULL);
1388   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1389
1390   assert(number_delegates != (size_t *) NULL);
1391   *number_delegates=0;
1392   p=GetDelegateInfo("*","*",exception);
1393   if (p == (const DelegateInfo *) NULL)
1394     return((char **) NULL);
1395   delegates=(char **) AcquireQuantumMemory((size_t)
1396     GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
1397   if (delegates == (char **) NULL)
1398     return((char **) NULL);
1399   LockSemaphoreInfo(delegate_semaphore);
1400   ResetLinkedListIterator(delegate_cache);
1401   p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1402   for (i=0; p != (const DelegateInfo *) NULL; )
1403   {
1404     if( (p->stealth == MagickFalse) &&
1405         GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse )
1406       delegates[i++]=ConstantString(p->decode);
1407     if( (p->stealth == MagickFalse) &&
1408         GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse )
1409       delegates[i++]=ConstantString(p->encode);
1410     p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1411   }
1412   UnlockSemaphoreInfo(delegate_semaphore);
1413   qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
1414   delegates[i]=(char *) NULL;
1415   *number_delegates=(size_t) i;
1416   return(delegates);
1417 }
1418 \f
1419 /*
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 %                                                                             %
1422 %                                                                             %
1423 %                                                                             %
1424 %   G e t D e l e g a t e M o d e                                             %
1425 %                                                                             %
1426 %                                                                             %
1427 %                                                                             %
1428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 %
1430 %  GetDelegateMode() returns the mode of the delegate.
1431 %
1432 %  The format of the GetDelegateMode method is:
1433 %
1434 %      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
1435 %
1436 %  A description of each parameter follows:
1437 %
1438 %    o delegate_info:  The delegate info.
1439 %
1440 */
1441 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
1442 {
1443   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1444
1445   assert(delegate_info != (DelegateInfo *) NULL);
1446   assert(delegate_info->signature == MagickCoreSignature);
1447   return(delegate_info->mode);
1448 }
1449 \f
1450 /*
1451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1452 %                                                                             %
1453 %                                                                             %
1454 %                                                                             %
1455 +   G e t D e l e g a t e T h r e a d S u p p o r t                           %
1456 %                                                                             %
1457 %                                                                             %
1458 %                                                                             %
1459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460 %
1461 %  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
1462 %  threads.
1463 %
1464 %  The format of the GetDelegateThreadSupport method is:
1465 %
1466 %      MagickBooleanType GetDelegateThreadSupport(
1467 %        const DelegateInfo *delegate_info)
1468 %
1469 %  A description of each parameter follows:
1470 %
1471 %    o delegate_info:  The delegate info.
1472 %
1473 */
1474 MagickExport MagickBooleanType GetDelegateThreadSupport(
1475   const DelegateInfo *delegate_info)
1476 {
1477   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1478
1479   assert(delegate_info != (DelegateInfo *) NULL);
1480   assert(delegate_info->signature == MagickCoreSignature);
1481   return(delegate_info->thread_support);
1482 }
1483 \f
1484 /*
1485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486 %                                                                             %
1487 %                                                                             %
1488 %                                                                             %
1489 +   I s D e l e g a t e C a c h e I n s t a n t i a t e d                     %
1490 %                                                                             %
1491 %                                                                             %
1492 %                                                                             %
1493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1494 %
1495 %  IsDelegateCacheInstantiated() determines if the delegate cache is
1496 %  instantiated.  If not, it instantiates the cache and returns it.
1497 %
1498 %  The format of the IsDelegateInstantiated method is:
1499 %
1500 %      MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
1501 %
1502 %  A description of each parameter follows.
1503 %
1504 %    o exception: return any errors or warnings in this structure.
1505 %
1506 */
1507 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
1508 {
1509   if (delegate_cache == (LinkedListInfo *) NULL)
1510     {
1511       if (delegate_semaphore == (SemaphoreInfo *) NULL)
1512         ActivateSemaphoreInfo(&delegate_semaphore);
1513       LockSemaphoreInfo(delegate_semaphore);
1514       if (delegate_cache == (LinkedListInfo *) NULL)
1515         delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
1516       UnlockSemaphoreInfo(delegate_semaphore);
1517     }
1518   return(delegate_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1519 }
1520 \f
1521 /*
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523 %                                                                             %
1524 %                                                                             %
1525 %                                                                             %
1526 %   I n v o k e D e l e g a t e                                               %
1527 %                                                                             %
1528 %                                                                             %
1529 %                                                                             %
1530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531 %
1532 %  InvokeDelegate replaces any embedded formatting characters with the
1533 %  appropriate image attribute and executes the resulting command.  MagickFalse
1534 %  is returned if the commands execute with success otherwise MagickTrue.
1535 %
1536 %  The format of the InvokeDelegate method is:
1537 %
1538 %      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
1539 %        const char *decode,const char *encode,ExceptionInfo *exception)
1540 %
1541 %  A description of each parameter follows:
1542 %
1543 %    o image_info: the imageInfo.
1544 %
1545 %    o image: the image.
1546 %
1547 %    o exception: return any errors or warnings in this structure.
1548 %
1549 */
1550
1551 static MagickBooleanType CopyDelegateFile(const char *source,
1552   const char *destination,const MagickBooleanType overwrite)
1553 {
1554   int
1555     destination_file,
1556     source_file;
1557
1558   MagickBooleanType
1559     status;
1560
1561   register size_t
1562     i;
1563
1564   size_t
1565     length,
1566     quantum;
1567
1568   ssize_t
1569     count;
1570
1571   struct stat
1572     attributes;
1573
1574   unsigned char
1575     *buffer;
1576
1577   /*
1578     Copy source file to destination.
1579   */
1580   assert(source != (const char *) NULL);
1581   assert(destination != (char *) NULL);
1582   if (overwrite == MagickFalse)
1583     {
1584       status=GetPathAttributes(destination,&attributes);
1585       if (status != MagickFalse)
1586         return(MagickTrue);
1587     }
1588   destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
1589   if (destination_file == -1)
1590     return(MagickFalse);
1591   source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
1592   if (source_file == -1)
1593     {
1594       (void) close(destination_file);
1595       return(MagickFalse);
1596     }
1597   quantum=(size_t) MagickMaxBufferExtent;
1598   if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
1599     quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
1600   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
1601   if (buffer == (unsigned char *) NULL)
1602     {
1603       (void) close(source_file);
1604       (void) close(destination_file);
1605       return(MagickFalse);
1606     }
1607   length=0;
1608   for (i=0; ; i+=count)
1609   {
1610     count=(ssize_t) read(source_file,buffer,quantum);
1611     if (count <= 0)
1612       break;
1613     length=(size_t) count;
1614     count=(ssize_t) write(destination_file,buffer,length);
1615     if ((size_t) count != length)
1616       break;
1617   }
1618   (void) close(destination_file);
1619   (void) close(source_file);
1620   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1621   return(i != 0 ? MagickTrue : MagickFalse);
1622 }
1623
1624 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
1625   Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
1626 {
1627   char
1628     *command,
1629     **commands,
1630     input_filename[MagickPathExtent],
1631     output_filename[MagickPathExtent];
1632
1633   const DelegateInfo
1634     *delegate_info;
1635
1636   MagickBooleanType
1637     status,
1638     temporary;
1639
1640   PolicyRights
1641     rights;
1642
1643   register ssize_t
1644     i;
1645
1646   /*
1647     Get delegate.
1648   */
1649   assert(image_info != (ImageInfo *) NULL);
1650   assert(image_info->signature == MagickCoreSignature);
1651   assert(image != (Image *) NULL);
1652   assert(image->signature == MagickCoreSignature);
1653   if (image->debug != MagickFalse)
1654     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1655   rights=ExecutePolicyRights;
1656   if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
1657     {
1658       errno=EPERM;
1659       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1660         "NotAuthorized","`%s'",decode);
1661       return(MagickFalse);
1662     }
1663   if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
1664     {
1665       errno=EPERM;
1666       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1667         "NotAuthorized","`%s'",encode);
1668       return(MagickFalse);
1669     }
1670   temporary=*image->filename == '\0' ? MagickTrue : MagickFalse;
1671   if ((temporary != MagickFalse) && (AcquireUniqueFilename(image->filename) ==
1672       MagickFalse))
1673     {
1674       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
1675         image->filename);
1676       return(MagickFalse);
1677     }
1678   delegate_info=GetDelegateInfo(decode,encode,exception);
1679   if (delegate_info == (DelegateInfo *) NULL)
1680     {
1681       if (temporary != MagickFalse)
1682         (void) RelinquishUniqueFileResource(image->filename);
1683       (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1684         "NoTagFound","`%s'",decode ? decode : encode);
1685       return(MagickFalse);
1686     }
1687   if (*image_info->filename == '\0')
1688     {
1689       if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
1690         {
1691           if (temporary != MagickFalse)
1692             (void) RelinquishUniqueFileResource(image->filename);
1693           ThrowFileException(exception,FileOpenError,
1694             "UnableToCreateTemporaryFile",image_info->filename);
1695           return(MagickFalse);
1696         }
1697       image_info->temporary=MagickTrue;
1698     }
1699   if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
1700         (delegate_info->encode != (char *) NULL)) ||
1701        ((encode != (const char *) NULL) &&
1702         (delegate_info->decode != (char *) NULL))))
1703     {
1704       char
1705         *magick;
1706
1707       ImageInfo
1708         *clone_info;
1709
1710       register Image
1711         *p;
1712
1713       /*
1714         Delegate requires a particular image format.
1715       */
1716       if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
1717         {
1718           ThrowFileException(exception,FileOpenError,
1719             "UnableToCreateTemporaryFile",image_info->unique);
1720           return(MagickFalse);
1721         }
1722       magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
1723         delegate_info->encode : delegate_info->decode,exception);
1724       if (magick == (char *) NULL)
1725         {
1726           (void) RelinquishUniqueFileResource(image_info->unique);
1727           if (temporary != MagickFalse)
1728             (void) RelinquishUniqueFileResource(image->filename);
1729           (void) ThrowMagickException(exception,GetMagickModule(),
1730             DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1731           return(MagickFalse);
1732         }
1733       LocaleUpper(magick);
1734       clone_info=CloneImageInfo(image_info);
1735       (void) CopyMagickString((char *) clone_info->magick,magick,
1736         MagickPathExtent);
1737       if (LocaleCompare(magick,"NULL") != 0)
1738         (void) CopyMagickString(image->magick,magick,MagickPathExtent);
1739       magick=DestroyString(magick);
1740       (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:",
1741         delegate_info->decode);
1742       (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
1743         exception);
1744       (void) CopyMagickString(clone_info->filename,image_info->filename,
1745         MagickPathExtent);
1746       (void) CopyMagickString(image_info->filename,image->filename,
1747         MagickPathExtent);
1748       for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1749       {
1750         (void) FormatLocaleString(p->filename,MagickPathExtent,"%s:%s",
1751           delegate_info->decode,clone_info->filename);
1752         status=WriteImage(clone_info,p,exception);
1753         if (status == MagickFalse)
1754           {
1755             (void) RelinquishUniqueFileResource(image_info->unique);
1756             if (temporary != MagickFalse)
1757               (void) RelinquishUniqueFileResource(image->filename);
1758             clone_info=DestroyImageInfo(clone_info);
1759             (void) ThrowMagickException(exception,GetMagickModule(),
1760               DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1761             return(MagickFalse);
1762           }
1763         if (clone_info->adjoin != MagickFalse)
1764           break;
1765       }
1766       (void) RelinquishUniqueFileResource(image_info->unique);
1767       clone_info=DestroyImageInfo(clone_info);
1768     }
1769   /*
1770     Invoke delegate.
1771   */
1772   commands=StringToList(delegate_info->commands);
1773   if (commands == (char **) NULL)
1774     {
1775       if (temporary != MagickFalse)
1776         (void) RelinquishUniqueFileResource(image->filename);
1777       (void) ThrowMagickException(exception,GetMagickModule(),
1778         ResourceLimitError,"MemoryAllocationFailed","`%s'",
1779         decode ? decode : encode);
1780       return(MagickFalse);
1781     }
1782   command=(char *) NULL;
1783   status=MagickTrue;
1784   (void) CopyMagickString(output_filename,image_info->filename,
1785     MagickPathExtent);
1786   (void) CopyMagickString(input_filename,image->filename,MagickPathExtent);
1787   for (i=0; commands[i] != (char *) NULL; i++)
1788   {
1789     (void) AcquireUniqueSymbolicLink(output_filename,image_info->filename);
1790     if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
1791       {
1792         ThrowFileException(exception,FileOpenError,
1793           "UnableToCreateTemporaryFile",image_info->unique);
1794         break;
1795       }
1796     if (LocaleCompare(decode,"SCAN") != 0)
1797       {
1798         status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1799         if (status == MagickFalse)
1800           {
1801             ThrowFileException(exception,FileOpenError,
1802               "UnableToCreateTemporaryFile",input_filename);
1803             break;
1804           }
1805       }
1806     status=MagickTrue;
1807     command=InterpretDelegateProperties(image_info,image,commands[i],exception);
1808     if (command != (char *) NULL)
1809       {
1810         /*
1811           Execute delegate.
1812         */
1813         if (ExternalDelegateCommand(delegate_info->spawn,image_info->verbose,
1814           command,(char *) NULL,exception) != 0)
1815           status=MagickFalse;
1816         if (delegate_info->spawn != MagickFalse)
1817           {
1818             ssize_t
1819               count;
1820
1821             /*
1822               Wait for input file to 'disappear', or maximum 2 seconds.
1823             */
1824             count=20;
1825             while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
1826               (void) MagickDelay(100);  /* sleep 0.1 seconds */
1827           }
1828         command=DestroyString(command);
1829       }
1830     if (LocaleCompare(decode,"SCAN") != 0)
1831       {
1832         if (CopyDelegateFile(image->filename,input_filename,MagickFalse) == MagickFalse)
1833           (void) RelinquishUniqueFileResource(input_filename);
1834       }
1835     if ((strcmp(input_filename,output_filename) != 0) &&
1836         (CopyDelegateFile(image_info->filename,output_filename,MagickTrue) == MagickFalse))
1837       (void) RelinquishUniqueFileResource(output_filename);
1838     if (image_info->temporary != MagickFalse)
1839       (void) RelinquishUniqueFileResource(image_info->filename);
1840     (void) RelinquishUniqueFileResource(image_info->unique);
1841     (void) RelinquishUniqueFileResource(image_info->filename);
1842     (void) RelinquishUniqueFileResource(image->filename);
1843     if (status == MagickFalse)
1844       {
1845         (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1846           "DelegateFailed","`%s'",commands[i]);
1847         break;
1848       }
1849     commands[i]=DestroyString(commands[i]);
1850   }
1851   (void) CopyMagickString(image_info->filename,output_filename,
1852     MagickPathExtent);
1853   (void) CopyMagickString(image->filename,input_filename,MagickPathExtent);
1854   /*
1855     Relinquish resources.
1856   */
1857   for ( ; commands[i] != (char *) NULL; i++)
1858     commands[i]=DestroyString(commands[i]);
1859   commands=(char **) RelinquishMagickMemory(commands);
1860   if (temporary != MagickFalse)
1861     (void) RelinquishUniqueFileResource(image->filename);
1862   return(status);
1863 }
1864 \f
1865 /*
1866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867 %                                                                             %
1868 %                                                                             %
1869 %                                                                             %
1870 %  L i s t D e l e g a t e I n f o                                            %
1871 %                                                                             %
1872 %                                                                             %
1873 %                                                                             %
1874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1875 %
1876 %  ListDelegateInfo() lists the image formats to a file.
1877 %
1878 %  The format of the ListDelegateInfo method is:
1879 %
1880 %      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1881 %
1882 %  A description of each parameter follows.
1883 %
1884 %    o file:  An pointer to a FILE.
1885 %
1886 %    o exception: return any errors or warnings in this structure.
1887 %
1888 */
1889 MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1890   ExceptionInfo *exception)
1891 {
1892   const DelegateInfo
1893     **delegate_info;
1894
1895   char
1896     **commands,
1897     delegate[MagickPathExtent];
1898
1899   const char
1900     *path;
1901
1902   register ssize_t
1903     i;
1904
1905   size_t
1906     number_delegates;
1907
1908   ssize_t
1909     j;
1910
1911   if (file == (const FILE *) NULL)
1912     file=stdout;
1913   delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1914   if (delegate_info == (const DelegateInfo **) NULL)
1915     return(MagickFalse);
1916   path=(const char *) NULL;
1917   for (i=0; i < (ssize_t) number_delegates; i++)
1918   {
1919     if (delegate_info[i]->stealth != MagickFalse)
1920       continue;
1921     if ((path == (const char *) NULL) ||
1922         (LocaleCompare(path,delegate_info[i]->path) != 0))
1923       {
1924         if (delegate_info[i]->path != (char *) NULL)
1925           (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1926         (void) FormatLocaleFile(file,"Delegate                Command\n");
1927         (void) FormatLocaleFile(file,
1928           "-------------------------------------------------"
1929           "------------------------------\n");
1930       }
1931     path=delegate_info[i]->path;
1932     *delegate='\0';
1933     if (delegate_info[i]->encode != (char *) NULL)
1934       (void) CopyMagickString(delegate,delegate_info[i]->encode,
1935         MagickPathExtent);
1936     (void) ConcatenateMagickString(delegate,"        ",MagickPathExtent);
1937     delegate[8]='\0';
1938     commands=StringToList(delegate_info[i]->commands);
1939     if (commands == (char **) NULL)
1940       continue;
1941     (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
1942       delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1943       delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1944     StripString(commands[0]);
1945     (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
1946     for (j=1; commands[j] != (char *) NULL; j++)
1947     {
1948       StripString(commands[j]);
1949       (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
1950     }
1951     for (j=0; commands[j] != (char *) NULL; j++)
1952       commands[j]=DestroyString(commands[j]);
1953     commands=(char **) RelinquishMagickMemory(commands);
1954   }
1955   (void) fflush(file);
1956   delegate_info=(const DelegateInfo **)
1957     RelinquishMagickMemory((void *) delegate_info);
1958   return(MagickTrue);
1959 }
1960 \f
1961 /*
1962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 %                                                                             %
1964 %                                                                             %
1965 %                                                                             %
1966 +   L o a d D e l e g a t e C a c h e                                         %
1967 %                                                                             %
1968 %                                                                             %
1969 %                                                                             %
1970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971 %
1972 %  LoadDelegateCache() loads the delegate configurations which provides a
1973 %  mapping between delegate attributes and a delegate name.
1974 %
1975 %  The format of the LoadDelegateCache method is:
1976 %
1977 %      MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
1978 %        const char *xml,const char *filename,const size_t depth,
1979 %        ExceptionInfo *exception)
1980 %
1981 %  A description of each parameter follows:
1982 %
1983 %    o xml:  The delegate list in XML format.
1984 %
1985 %    o filename:  The delegate list filename.
1986 %
1987 %    o depth: depth of <include /> statements.
1988 %
1989 %    o exception: return any errors or warnings in this structure.
1990 %
1991 */
1992 static MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
1993   const char *xml,const char *filename,const size_t depth,
1994   ExceptionInfo *exception)
1995 {
1996   char
1997     keyword[MagickPathExtent],
1998     *token;
1999
2000   const char
2001     *q;
2002
2003   DelegateInfo
2004     *delegate_info;
2005
2006   MagickStatusType
2007     status;
2008
2009   size_t
2010     extent;
2011
2012   /*
2013     Load the delegate map file.
2014   */
2015   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2016     "Loading delegate configuration file \"%s\" ...",filename);
2017   if (xml == (const char *) NULL)
2018     return(MagickFalse);
2019   status=MagickTrue;
2020   delegate_info=(DelegateInfo *) NULL;
2021   token=AcquireString(xml);
2022   extent=strlen(token)+MagickPathExtent;
2023   for (q=(const char *) xml; *q != '\0'; )
2024   {
2025     /*
2026       Interpret XML.
2027     */
2028     GetNextToken(q,&q,extent,token);
2029     if (*token == '\0')
2030       break;
2031     (void) CopyMagickString(keyword,token,MagickPathExtent);
2032     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2033       {
2034         /*
2035           Doctype element.
2036         */
2037         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2038           GetNextToken(q,&q,extent,token);
2039         continue;
2040       }
2041     if (LocaleNCompare(keyword,"<!--",4) == 0)
2042       {
2043         /*
2044           Comment element.
2045         */
2046         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2047           GetNextToken(q,&q,extent,token);
2048         continue;
2049       }
2050     if (LocaleCompare(keyword,"<include") == 0)
2051       {
2052         /*
2053           Include element.
2054         */
2055         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2056         {
2057           (void) CopyMagickString(keyword,token,MagickPathExtent);
2058           GetNextToken(q,&q,extent,token);
2059           if (*token != '=')
2060             continue;
2061           GetNextToken(q,&q,extent,token);
2062           if (LocaleCompare(keyword,"file") == 0)
2063             {
2064               if (depth > 200)
2065                 (void) ThrowMagickException(exception,GetMagickModule(),
2066                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2067               else
2068                 {
2069                   char
2070                     path[MagickPathExtent],
2071                     *file_xml;
2072
2073                   GetPathComponent(filename,HeadPath,path);
2074                   if (*path != '\0')
2075                     (void) ConcatenateMagickString(path,DirectorySeparator,
2076                       MagickPathExtent);
2077                   if (*token == *DirectorySeparator)
2078                     (void) CopyMagickString(path,token,MagickPathExtent);
2079                   else
2080                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
2081                   file_xml=FileToXML(path,~0UL);
2082                   if (file_xml != (char *) NULL)
2083                     {
2084                       status&=LoadDelegateCache(cache,file_xml,path,
2085                         depth+1,exception);
2086                       file_xml=DestroyString(file_xml);
2087                     }
2088                 }
2089             }
2090         }
2091         continue;
2092       }
2093     if (LocaleCompare(keyword,"<delegate") == 0)
2094       {
2095         /*
2096           Delegate element.
2097         */
2098         delegate_info=(DelegateInfo *) AcquireMagickMemory(
2099           sizeof(*delegate_info));
2100         if (delegate_info == (DelegateInfo *) NULL)
2101           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2102         (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
2103         delegate_info->path=ConstantString(filename);
2104         delegate_info->thread_support=MagickTrue;
2105         delegate_info->signature=MagickCoreSignature;
2106         continue;
2107       }
2108     if (delegate_info == (DelegateInfo *) NULL)
2109       continue;
2110     if (LocaleCompare(keyword,"/>") == 0)
2111       {
2112         status=AppendValueToLinkedList(cache,delegate_info);
2113         if (status == MagickFalse)
2114           (void) ThrowMagickException(exception,GetMagickModule(),
2115             ResourceLimitError,"MemoryAllocationFailed","`%s'",
2116             delegate_info->commands);
2117         delegate_info=(DelegateInfo *) NULL;
2118         continue;
2119       }
2120     GetNextToken(q,(const char **) NULL,extent,token);
2121     if (*token != '=')
2122       continue;
2123     GetNextToken(q,&q,extent,token);
2124     GetNextToken(q,&q,extent,token);
2125     switch (*keyword)
2126     {
2127       case 'C':
2128       case 'c':
2129       {
2130         if (LocaleCompare((char *) keyword,"command") == 0)
2131           {
2132             char
2133               *commands;
2134
2135             commands=AcquireString(token);
2136 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
2137             if (strchr(commands,'@') != (char *) NULL)
2138               {
2139                 char
2140                   path[MagickPathExtent];
2141
2142                 NTGhostscriptEXE(path,MagickPathExtent);
2143                 (void) SubstituteString((char **) &commands,"@PSDelegate@",
2144                   path);
2145                 (void) SubstituteString((char **) &commands,"\\","/");
2146               }
2147             (void) SubstituteString((char **) &commands,"&quot;","\"");
2148 #else
2149             (void) SubstituteString((char **) &commands,"&quot;","'");
2150 #endif
2151             (void) SubstituteString((char **) &commands,"&amp;","&");
2152             (void) SubstituteString((char **) &commands,"&gt;",">");
2153             (void) SubstituteString((char **) &commands,"&lt;","<");
2154             delegate_info->commands=commands;
2155             break;
2156           }
2157         break;
2158       }
2159       case 'D':
2160       case 'd':
2161       {
2162         if (LocaleCompare((char *) keyword,"decode") == 0)
2163           {
2164             delegate_info->decode=ConstantString(token);
2165             delegate_info->mode=1;
2166             break;
2167           }
2168         break;
2169       }
2170       case 'E':
2171       case 'e':
2172       {
2173         if (LocaleCompare((char *) keyword,"encode") == 0)
2174           {
2175             delegate_info->encode=ConstantString(token);
2176             delegate_info->mode=(-1);
2177             break;
2178           }
2179         break;
2180       }
2181       case 'M':
2182       case 'm':
2183       {
2184         if (LocaleCompare((char *) keyword,"mode") == 0)
2185           {
2186             delegate_info->mode=1;
2187             if (LocaleCompare(token,"bi") == 0)
2188               delegate_info->mode=0;
2189             else
2190               if (LocaleCompare(token,"encode") == 0)
2191                 delegate_info->mode=(-1);
2192             break;
2193           }
2194         break;
2195       }
2196       case 'S':
2197       case 's':
2198       {
2199         if (LocaleCompare((char *) keyword,"spawn") == 0)
2200           {
2201             delegate_info->spawn=IsStringTrue(token);
2202             break;
2203           }
2204         if (LocaleCompare((char *) keyword,"stealth") == 0)
2205           {
2206             delegate_info->stealth=IsStringTrue(token);
2207             break;
2208           }
2209         break;
2210       }
2211       case 'T':
2212       case 't':
2213       {
2214         if (LocaleCompare((char *) keyword,"thread-support") == 0)
2215           {
2216             delegate_info->thread_support=IsStringTrue(token);
2217             if (delegate_info->thread_support == MagickFalse)
2218               delegate_info->semaphore=AcquireSemaphoreInfo();
2219             break;
2220           }
2221         break;
2222       }
2223       default:
2224         break;
2225     }
2226   }
2227   token=(char *) RelinquishMagickMemory(token);
2228   return(status != 0 ? MagickTrue : MagickFalse);
2229 }