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