MagickCore  6.9.12-56
Convert, Edit, Or Compose Bitmap Images
 All Data Structures
delegate.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % DDDD EEEEE L EEEEE GGGG AAA TTTTT EEEEE %
6 % D D E L E G A A T E %
7 % D D EEE L EEE G GG AAAAA T EEE %
8 % D D E L E G G A A T E %
9 % DDDD EEEEE LLLLL EEEEE GGG A A T EEEEE %
10 % %
11 % %
12 % MagickCore Methods to Read/Write/Invoke Delegates %
13 % %
14 % Software Design %
15 % Cristy %
16 % October 1998 %
17 % %
18 % %
19 % Copyright 1999-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 */
184 static LinkedListInfo *AcquireDelegateCache(const char *filename,
185  ExceptionInfo *exception)
186 {
188  *cache;
189 
190  cache=NewLinkedList(0);
191 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
192  {
193  const StringInfo
194  *option;
195 
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 */
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 
259 static void *DestroyDelegate(void *delegate_info)
260 {
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 
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 */
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 
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 (IsEventLogging() != 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  {
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 
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 (IsEventLogging() != 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 
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 (IsEventLogging() != 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 */
1236 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
1237 {
1238  if (IsEventLogging() != MagickFalse)
1239  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1240  assert(delegate_info != (DelegateInfo *) NULL);
1241  assert(delegate_info->signature == MagickCoreSignature);
1242  return(delegate_info->commands);
1243 }
1244 
1245 /*
1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % %
1248 % %
1249 % %
1250 % G e t D e l e g a t e I n f o %
1251 % %
1252 % %
1253 % %
1254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 %
1256 % GetDelegateInfo() returns any delegates associated with the specified tag.
1257 %
1258 % The format of the GetDelegateInfo method is:
1259 %
1260 % const DelegateInfo *GetDelegateInfo(const char *decode,
1261 % const char *encode,ExceptionInfo *exception)
1262 %
1263 % A description of each parameter follows:
1264 %
1265 % o decode: Specifies the decode delegate we are searching for as a
1266 % character string.
1267 %
1268 % o encode: Specifies the encode delegate we are searching for as a
1269 % character string.
1270 %
1271 % o exception: return any errors or warnings in this structure.
1272 %
1273 */
1274 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
1275  const char *encode,ExceptionInfo *exception)
1276 {
1277  const DelegateInfo
1278  *p;
1279 
1280  assert(exception != (ExceptionInfo *) NULL);
1281  if (IsDelegateCacheInstantiated(exception) == MagickFalse)
1282  return((const DelegateInfo *) NULL);
1283  /*
1284  Search for named delegate.
1285  */
1286  LockSemaphoreInfo(delegate_semaphore);
1287  ResetLinkedListIterator(delegate_cache);
1288  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1289  if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
1290  {
1291  UnlockSemaphoreInfo(delegate_semaphore);
1292  return(p);
1293  }
1294  while (p != (const DelegateInfo *) NULL)
1295  {
1296  if (p->mode > 0)
1297  {
1298  if (LocaleCompare(p->decode,decode) == 0)
1299  break;
1300  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1301  continue;
1302  }
1303  if (p->mode < 0)
1304  {
1305  if (LocaleCompare(p->encode,encode) == 0)
1306  break;
1307  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1308  continue;
1309  }
1310  if (LocaleCompare(decode,p->decode) == 0)
1311  if (LocaleCompare(encode,p->encode) == 0)
1312  break;
1313  if (LocaleCompare(decode,"*") == 0)
1314  if (LocaleCompare(encode,p->encode) == 0)
1315  break;
1316  if (LocaleCompare(decode,p->decode) == 0)
1317  if (LocaleCompare(encode,"*") == 0)
1318  break;
1319  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1320  }
1321  if (p != (const DelegateInfo *) NULL)
1322  (void) InsertValueInLinkedList(delegate_cache,0,
1323  RemoveElementByValueFromLinkedList(delegate_cache,p));
1324  UnlockSemaphoreInfo(delegate_semaphore);
1325  return(p);
1326 }
1327 
1328 /*
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 % %
1331 % %
1332 % %
1333 % G e t D e l e g a t e I n f o L i s t %
1334 % %
1335 % %
1336 % %
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1338 %
1339 % GetDelegateInfoList() returns any delegates that match the specified pattern.
1340 %
1341 % The delegate of the GetDelegateInfoList function is:
1342 %
1343 % const DelegateInfo **GetDelegateInfoList(const char *pattern,
1344 % size_t *number_delegates,ExceptionInfo *exception)
1345 %
1346 % A description of each parameter follows:
1347 %
1348 % o pattern: Specifies a pointer to a text string containing a pattern.
1349 %
1350 % o number_delegates: This integer returns the number of delegates in the
1351 % list.
1352 %
1353 % o exception: return any errors or warnings in this structure.
1354 %
1355 */
1356 
1357 #if defined(__cplusplus) || defined(c_plusplus)
1358 extern "C" {
1359 #endif
1360 
1361 static int DelegateInfoCompare(const void *x,const void *y)
1362 {
1363  const DelegateInfo
1364  **p,
1365  **q;
1366 
1367  int
1368  cmp;
1369 
1370  p=(const DelegateInfo **) x,
1371  q=(const DelegateInfo **) y;
1372  cmp=LocaleCompare((*p)->path,(*q)->path);
1373  if (cmp == 0)
1374  {
1375  if ((*p)->decode == (char *) NULL)
1376  if (((*p)->encode != (char *) NULL) &&
1377  ((*q)->encode != (char *) NULL))
1378  return(strcmp((*p)->encode,(*q)->encode));
1379  if (((*p)->decode != (char *) NULL) &&
1380  ((*q)->decode != (char *) NULL))
1381  return(strcmp((*p)->decode,(*q)->decode));
1382  }
1383  return(cmp);
1384 }
1385 
1386 #if defined(__cplusplus) || defined(c_plusplus)
1387 }
1388 #endif
1389 
1390 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
1391  size_t *number_delegates,ExceptionInfo *exception)
1392 {
1393  const DelegateInfo
1394  **delegates;
1395 
1396  const DelegateInfo
1397  *p;
1398 
1399  ssize_t
1400  i;
1401 
1402  /*
1403  Allocate delegate list.
1404  */
1405  assert(pattern != (char *) NULL);
1406  assert(number_delegates != (size_t *) NULL);
1407  if (IsEventLogging() != MagickFalse)
1408  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1409  *number_delegates=0;
1410  p=GetDelegateInfo("*","*",exception);
1411  if (p == (const DelegateInfo *) NULL)
1412  return((const DelegateInfo **) NULL);
1413  delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
1414  GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
1415  if (delegates == (const DelegateInfo **) NULL)
1416  return((const DelegateInfo **) NULL);
1417  /*
1418  Generate delegate list.
1419  */
1420  LockSemaphoreInfo(delegate_semaphore);
1421  ResetLinkedListIterator(delegate_cache);
1422  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1423  for (i=0; p != (const DelegateInfo *) NULL; )
1424  {
1425  if ((p->stealth == MagickFalse) &&
1426  ((GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse) ||
1427  (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse)))
1428  delegates[i++]=p;
1429  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1430  }
1431  UnlockSemaphoreInfo(delegate_semaphore);
1432  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
1433  delegates[i]=(DelegateInfo *) NULL;
1434  *number_delegates=(size_t) i;
1435  return(delegates);
1436 }
1437 
1438 /*
1439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 % %
1441 % %
1442 % %
1443 % G e t D e l e g a t e L i s t %
1444 % %
1445 % %
1446 % %
1447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 %
1449 % GetDelegateList() returns any image format delegates that match the
1450 % specified pattern.
1451 %
1452 % The format of the GetDelegateList function is:
1453 %
1454 % char **GetDelegateList(const char *pattern,
1455 % size_t *number_delegates,ExceptionInfo *exception)
1456 %
1457 % A description of each parameter follows:
1458 %
1459 % o pattern: Specifies a pointer to a text string containing a pattern.
1460 %
1461 % o number_delegates: This integer returns the number of delegates
1462 % in the list.
1463 %
1464 % o exception: return any errors or warnings in this structure.
1465 %
1466 */
1467 
1468 #if defined(__cplusplus) || defined(c_plusplus)
1469 extern "C" {
1470 #endif
1471 
1472 static int DelegateCompare(const void *x,const void *y)
1473 {
1474  const char
1475  **p,
1476  **q;
1477 
1478  p=(const char **) x;
1479  q=(const char **) y;
1480  return(LocaleCompare(*p,*q));
1481 }
1482 
1483 #if defined(__cplusplus) || defined(c_plusplus)
1484 }
1485 #endif
1486 
1487 MagickExport char **GetDelegateList(const char *pattern,
1488  size_t *number_delegates,ExceptionInfo *exception)
1489 {
1490  char
1491  **delegates;
1492 
1493  const DelegateInfo
1494  *p;
1495 
1496  ssize_t
1497  i;
1498 
1499  /*
1500  Allocate delegate list.
1501  */
1502  assert(pattern != (char *) NULL);
1503  assert(number_delegates != (size_t *) NULL);
1504  if (IsEventLogging() != MagickFalse)
1505  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
1506  *number_delegates=0;
1507  p=GetDelegateInfo("*","*",exception);
1508  if (p == (const DelegateInfo *) NULL)
1509  return((char **) NULL);
1510  delegates=(char **) AcquireQuantumMemory((size_t)
1511  GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
1512  if (delegates == (char **) NULL)
1513  return((char **) NULL);
1514  LockSemaphoreInfo(delegate_semaphore);
1515  ResetLinkedListIterator(delegate_cache);
1516  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1517  for (i=0; p != (const DelegateInfo *) NULL; )
1518  {
1519  if ((p->stealth == MagickFalse) &&
1520  (GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse))
1521  delegates[i++]=ConstantString(p->decode);
1522  if ((p->stealth == MagickFalse) &&
1523  (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse))
1524  delegates[i++]=ConstantString(p->encode);
1525  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
1526  }
1527  UnlockSemaphoreInfo(delegate_semaphore);
1528  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
1529  delegates[i]=(char *) NULL;
1530  *number_delegates=(size_t) i;
1531  return(delegates);
1532 }
1533 
1534 /*
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 % %
1537 % %
1538 % %
1539 % G e t D e l e g a t e M o d e %
1540 % %
1541 % %
1542 % %
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 %
1545 % GetDelegateMode() returns the mode of the delegate.
1546 %
1547 % The format of the GetDelegateMode method is:
1548 %
1549 % ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
1550 %
1551 % A description of each parameter follows:
1552 %
1553 % o delegate_info: The delegate info.
1554 %
1555 */
1556 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
1557 {
1558  if (IsEventLogging() != MagickFalse)
1559  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1560  assert(delegate_info != (DelegateInfo *) NULL);
1561  assert(delegate_info->signature == MagickCoreSignature);
1562  return(delegate_info->mode);
1563 }
1564 
1565 /*
1566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567 % %
1568 % %
1569 % %
1570 + G e t D e l e g a t e T h r e a d S u p p o r t %
1571 % %
1572 % %
1573 % %
1574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575 %
1576 % GetDelegateThreadSupport() returns MagickTrue if the delegate supports
1577 % threads.
1578 %
1579 % The format of the GetDelegateThreadSupport method is:
1580 %
1581 % MagickBooleanType GetDelegateThreadSupport(
1582 % const DelegateInfo *delegate_info)
1583 %
1584 % A description of each parameter follows:
1585 %
1586 % o delegate_info: The delegate info.
1587 %
1588 */
1589 MagickExport MagickBooleanType GetDelegateThreadSupport(
1590  const DelegateInfo *delegate_info)
1591 {
1592  if (IsEventLogging() != MagickFalse)
1593  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1594  assert(delegate_info != (DelegateInfo *) NULL);
1595  assert(delegate_info->signature == MagickCoreSignature);
1596  return(delegate_info->thread_support);
1597 }
1598 
1599 /*
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % %
1602 % %
1603 % %
1604 + 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 %
1605 % %
1606 % %
1607 % %
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 %
1610 % IsDelegateCacheInstantiated() determines if the delegate cache is
1611 % instantiated. If not, it instantiates the cache and returns it.
1612 %
1613 % The format of the IsDelegateInstantiated method is:
1614 %
1615 % MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
1616 %
1617 % A description of each parameter follows.
1618 %
1619 % o exception: return any errors or warnings in this structure.
1620 %
1621 */
1622 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
1623 {
1624  if (delegate_cache == (LinkedListInfo *) NULL)
1625  {
1626  if (delegate_semaphore == (SemaphoreInfo *) NULL)
1627  ActivateSemaphoreInfo(&delegate_semaphore);
1628  LockSemaphoreInfo(delegate_semaphore);
1629  if (delegate_cache == (LinkedListInfo *) NULL)
1630  delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
1631  UnlockSemaphoreInfo(delegate_semaphore);
1632  }
1633  return(delegate_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
1634 }
1635 
1636 /*
1637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 % %
1639 % %
1640 % %
1641 % I n v o k e D e l e g a t e %
1642 % %
1643 % %
1644 % %
1645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1646 %
1647 % InvokeDelegate replaces any embedded formatting characters with the
1648 % appropriate image attribute and executes the resulting command. MagickFalse
1649 % is returned if the commands execute with success otherwise MagickTrue.
1650 %
1651 % The format of the InvokeDelegate method is:
1652 %
1653 % MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
1654 % const char *decode,const char *encode,ExceptionInfo *exception)
1655 %
1656 % A description of each parameter follows:
1657 %
1658 % o image_info: the imageInfo.
1659 %
1660 % o image: the image.
1661 %
1662 % o exception: return any errors or warnings in this structure.
1663 %
1664 */
1665 
1666 static MagickBooleanType CopyDelegateFile(const char *source,
1667  const char *destination,const MagickBooleanType overwrite)
1668 {
1669  int
1670  destination_file,
1671  source_file;
1672 
1673  MagickBooleanType
1674  status;
1675 
1676  size_t
1677  i;
1678 
1679  size_t
1680  length,
1681  quantum;
1682 
1683  ssize_t
1684  count;
1685 
1686  struct stat
1687  attributes;
1688 
1689  unsigned char
1690  *buffer;
1691 
1692  /*
1693  Copy source file to destination.
1694  */
1695  assert(source != (const char *) NULL);
1696  assert(destination != (char *) NULL);
1697  if (overwrite == MagickFalse)
1698  {
1699  status=GetPathAttributes(destination,&attributes);
1700  if (status != MagickFalse)
1701  return(MagickTrue);
1702  }
1703  destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
1704  if (destination_file == -1)
1705  return(MagickFalse);
1706  source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
1707  if (source_file == -1)
1708  {
1709  (void) close(destination_file);
1710  return(MagickFalse);
1711  }
1712  quantum=(size_t) MagickMaxBufferExtent;
1713  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
1714  quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
1715  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
1716  if (buffer == (unsigned char *) NULL)
1717  {
1718  (void) close(source_file);
1719  (void) close(destination_file);
1720  return(MagickFalse);
1721  }
1722  length=0;
1723  for (i=0; ; i+=count)
1724  {
1725  count=(ssize_t) read(source_file,buffer,quantum);
1726  if (count <= 0)
1727  break;
1728  length=(size_t) count;
1729  count=(ssize_t) write(destination_file,buffer,length);
1730  if ((size_t) count != length)
1731  break;
1732  }
1733  (void) close(destination_file);
1734  (void) close(source_file);
1735  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1736  return(i != 0 ? MagickTrue : MagickFalse);
1737 }
1738 
1739 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
1740  Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
1741 {
1742  char
1743  *command,
1744  **commands,
1745  input_filename[MaxTextExtent],
1746  output_filename[MaxTextExtent];
1747 
1748  const DelegateInfo
1749  *delegate_info;
1750 
1751  MagickBooleanType
1752  status,
1753  temporary;
1754 
1755  PolicyRights
1756  rights;
1757 
1758  ssize_t
1759  i;
1760 
1761  /*
1762  Get delegate.
1763  */
1764  assert(image_info != (ImageInfo *) NULL);
1765  assert(image_info->signature == MagickCoreSignature);
1766  assert(image != (Image *) NULL);
1767  assert(image->signature == MagickCoreSignature);
1768  if (IsEventLogging() != MagickFalse)
1769  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1770  rights=ExecutePolicyRights;
1771  if ((decode != (const char *) NULL) &&
1772  (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse))
1773  {
1774  errno=EPERM;
1775  (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1776  "NotAuthorized","`%s'",decode);
1777  return(MagickFalse);
1778  }
1779  if ((encode != (const char *) NULL) &&
1780  (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse))
1781  {
1782  errno=EPERM;
1783  (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1784  "NotAuthorized","`%s'",encode);
1785  return(MagickFalse);
1786  }
1787  temporary=(*image->filename == '\0') ? MagickTrue : MagickFalse;
1788  if (temporary != MagickFalse)
1789  if (AcquireUniqueFilename(image->filename) == MagickFalse)
1790  {
1791  ThrowFileException(exception,FileOpenError,
1792  "UnableToCreateTemporaryFile",image->filename);
1793  return(MagickFalse);
1794  }
1795  delegate_info=GetDelegateInfo(decode,encode,exception);
1796  if (delegate_info == (DelegateInfo *) NULL)
1797  {
1798  if (temporary != MagickFalse)
1799  (void) RelinquishUniqueFileResource(image->filename);
1800  (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1801  "NoTagFound","`%s'",decode ? decode : encode);
1802  return(MagickFalse);
1803  }
1804  if (*image_info->filename == '\0')
1805  {
1806  if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
1807  {
1808  if (temporary != MagickFalse)
1809  (void) RelinquishUniqueFileResource(image->filename);
1810  ThrowFileException(exception,FileOpenError,
1811  "UnableToCreateTemporaryFile",image_info->filename);
1812  return(MagickFalse);
1813  }
1814  image_info->temporary=MagickTrue;
1815  }
1816  if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
1817  (delegate_info->encode != (char *) NULL)) ||
1818  ((encode != (const char *) NULL) &&
1819  (delegate_info->decode != (char *) NULL))))
1820  {
1821  char
1822  *magick;
1823 
1824  ImageInfo
1825  *clone_info;
1826 
1827  Image
1828  *p;
1829 
1830  /*
1831  Delegate requires a particular image format.
1832  */
1833  if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
1834  {
1835  ThrowFileException(exception,FileOpenError,
1836  "UnableToCreateTemporaryFile",image_info->unique);
1837  return(MagickFalse);
1838  }
1839  if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
1840  {
1841  (void) RelinquishUniqueFileResource(image_info->unique);
1842  ThrowFileException(exception,FileOpenError,
1843  "UnableToCreateTemporaryFile",image_info->zero);
1844  return(MagickFalse);
1845  }
1846  magick=InterpretDelegateProperties(image_info,image,
1847  decode != (char *) NULL ? delegate_info->encode :
1848  delegate_info->decode);
1849  if (magick == (char *) NULL)
1850  {
1851  (void) RelinquishUniqueFileResource(image_info->unique);
1852  (void) RelinquishUniqueFileResource(image_info->zero);
1853  if (temporary != MagickFalse)
1854  (void) RelinquishUniqueFileResource(image->filename);
1855  (void) ThrowMagickException(exception,GetMagickModule(),
1856  DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1857  return(MagickFalse);
1858  }
1859  LocaleUpper(magick);
1860  clone_info=CloneImageInfo(image_info);
1861  (void) CopyMagickString((char *) clone_info->magick,magick,MaxTextExtent);
1862  if (LocaleCompare(magick,"NULL") != 0)
1863  (void) CopyMagickString(image->magick,magick,MaxTextExtent);
1864  magick=DestroyString(magick);
1865  (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
1866  delegate_info->decode);
1867  (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
1868  exception);
1869  (void) CopyMagickString(clone_info->filename,image_info->filename,
1870  MaxTextExtent);
1871  (void) CopyMagickString(image_info->filename,image->filename,
1872  MaxTextExtent);
1873  for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1874  {
1875  (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
1876  delegate_info->decode,clone_info->filename);
1877  status=WriteImage(clone_info,p);
1878  if (status == MagickFalse)
1879  {
1880  (void) RelinquishUniqueFileResource(image_info->unique);
1881  (void) RelinquishUniqueFileResource(image_info->zero);
1882  if (temporary != MagickFalse)
1883  (void) RelinquishUniqueFileResource(image->filename);
1884  clone_info=DestroyImageInfo(clone_info);
1885  (void) ThrowMagickException(exception,GetMagickModule(),
1886  DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
1887  return(MagickFalse);
1888  }
1889  if (clone_info->adjoin != MagickFalse)
1890  break;
1891  }
1892  (void) RelinquishUniqueFileResource(image_info->unique);
1893  (void) RelinquishUniqueFileResource(image_info->zero);
1894  clone_info=DestroyImageInfo(clone_info);
1895  }
1896  /*
1897  Invoke delegate.
1898  */
1899  commands=StringToList(delegate_info->commands);
1900  if (commands == (char **) NULL)
1901  {
1902  if (temporary != MagickFalse)
1903  (void) RelinquishUniqueFileResource(image->filename);
1904  (void) ThrowMagickException(exception,GetMagickModule(),
1905  ResourceLimitError,"MemoryAllocationFailed","`%s'",
1906  decode ? decode : encode);
1907  return(MagickFalse);
1908  }
1909  command=(char *) NULL;
1910  status=MagickFalse;
1911  (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
1912  (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
1913  for (i=0; commands[i] != (char *) NULL; i++)
1914  {
1915  status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
1916  if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
1917  {
1918  ThrowFileException(exception,FileOpenError,
1919  "UnableToCreateTemporaryFile",image_info->unique);
1920  break;
1921  }
1922  if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
1923  {
1924  (void) RelinquishUniqueFileResource(image_info->unique);
1925  ThrowFileException(exception,FileOpenError,
1926  "UnableToCreateTemporaryFile",image_info->zero);
1927  break;
1928  }
1929  if (LocaleCompare(decode,"SCAN") != 0)
1930  {
1931  status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1932  if (status == MagickFalse)
1933  {
1934  ThrowFileException(exception,FileOpenError,
1935  "UnableToCreateTemporaryFile",input_filename);
1936  break;
1937  }
1938  }
1939  status=MagickFalse;
1940  command=InterpretDelegateProperties(image_info,image,commands[i]);
1941  if (command != (char *) NULL)
1942  {
1943  /*
1944  Execute delegate.
1945  */
1946  status=ExternalDelegateCommand(delegate_info->spawn,image_info->verbose,
1947  command,(char *) NULL,exception) != 0 ? MagickTrue : MagickFalse;
1948  if (delegate_info->spawn != MagickFalse)
1949  {
1950  ssize_t
1951  count;
1952 
1953  /*
1954  Wait for input file to 'disappear', or maximum 2 seconds.
1955  */
1956  count=20;
1957  while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
1958  (void) MagickDelay(100); /* sleep 0.1 seconds */
1959  }
1960  command=DestroyString(command);
1961  }
1962  if (LocaleCompare(decode,"SCAN") != 0)
1963  {
1964  if (CopyDelegateFile(image->filename,input_filename,MagickFalse) == MagickFalse)
1965  (void) RelinquishUniqueFileResource(input_filename);
1966  }
1967  if ((strcmp(input_filename,output_filename) != 0) &&
1968  (CopyDelegateFile(image_info->filename,output_filename,MagickTrue) == MagickFalse))
1969  (void) RelinquishUniqueFileResource(output_filename);
1970  if (image_info->temporary != MagickFalse)
1971  (void) RelinquishUniqueFileResource(image_info->filename);
1972  (void) RelinquishUniqueFileResource(image_info->unique);
1973  (void) RelinquishUniqueFileResource(image_info->zero);
1974  (void) RelinquishUniqueFileResource(image_info->filename);
1975  (void) RelinquishUniqueFileResource(image->filename);
1976  if (status != MagickFalse)
1977  {
1978  (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1979  "DelegateFailed","`%s'",commands[i]);
1980  break;
1981  }
1982  commands[i]=DestroyString(commands[i]);
1983  }
1984  (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1985  (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1986  /*
1987  Relinquish resources.
1988  */
1989  for ( ; commands[i] != (char *) NULL; i++)
1990  commands[i]=DestroyString(commands[i]);
1991  commands=(char **) RelinquishMagickMemory(commands);
1992  if (temporary != MagickFalse)
1993  (void) RelinquishUniqueFileResource(image->filename);
1994  return(status == MagickFalse ? MagickTrue : MagickFalse);
1995 }
1996 
1997 /*
1998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 % %
2000 % %
2001 % %
2002 % L i s t D e l e g a t e I n f o %
2003 % %
2004 % %
2005 % %
2006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007 %
2008 % ListDelegateInfo() lists the image formats to a file.
2009 %
2010 % The format of the ListDelegateInfo method is:
2011 %
2012 % MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
2013 %
2014 % A description of each parameter follows.
2015 %
2016 % o file: An pointer to a FILE.
2017 %
2018 % o exception: return any errors or warnings in this structure.
2019 %
2020 */
2021 MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
2022  ExceptionInfo *exception)
2023 {
2024  const DelegateInfo
2025  **delegate_info;
2026 
2027  char
2028  **commands,
2029  delegate[MaxTextExtent];
2030 
2031  const char
2032  *path;
2033 
2034  ssize_t
2035  i;
2036 
2037  size_t
2038  number_delegates;
2039 
2040  ssize_t
2041  j;
2042 
2043  if (file == (const FILE *) NULL)
2044  file=stdout;
2045  delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
2046  if (delegate_info == (const DelegateInfo **) NULL)
2047  return(MagickFalse);
2048  path=(const char *) NULL;
2049  for (i=0; i < (ssize_t) number_delegates; i++)
2050  {
2051  if (delegate_info[i]->stealth != MagickFalse)
2052  continue;
2053  if ((path == (const char *) NULL) ||
2054  (LocaleCompare(path,delegate_info[i]->path) != 0))
2055  {
2056  if (delegate_info[i]->path != (char *) NULL)
2057  (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
2058  (void) FormatLocaleFile(file,"Delegate Command\n");
2059  (void) FormatLocaleFile(file,
2060  "-------------------------------------------------"
2061  "------------------------------\n");
2062  }
2063  path=delegate_info[i]->path;
2064  *delegate='\0';
2065  if (delegate_info[i]->encode != (char *) NULL)
2066  (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
2067  (void) ConcatenateMagickString(delegate," ",MaxTextExtent);
2068  delegate[8]='\0';
2069  commands=StringToList(delegate_info[i]->commands);
2070  if (commands == (char **) NULL)
2071  continue;
2072  (void) FormatLocaleFile(file,"%11s%c=%c%s ",delegate_info[i]->decode ?
2073  delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
2074  delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
2075  StripString(commands[0]);
2076  (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
2077  for (j=1; commands[j] != (char *) NULL; j++)
2078  {
2079  StripString(commands[j]);
2080  (void) FormatLocaleFile(file," \"%s\"\n",commands[j]);
2081  }
2082  for (j=0; commands[j] != (char *) NULL; j++)
2083  commands[j]=DestroyString(commands[j]);
2084  commands=(char **) RelinquishMagickMemory(commands);
2085  }
2086  (void) fflush(file);
2087  delegate_info=(const DelegateInfo **)
2088  RelinquishMagickMemory((void *) delegate_info);
2089  return(MagickTrue);
2090 }
2091 
2092 /*
2093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2094 % %
2095 % %
2096 % %
2097 + L o a d D e l e g a t e L i s t %
2098 % %
2099 % %
2100 % %
2101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102 %
2103 % LoadDelegateCache() loads the delegate configurations which provides a
2104 % mapping between delegate attributes and a delegate name.
2105 %
2106 % The format of the LoadDelegateCache method is:
2107 %
2108 % MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
2109 % const char *xml,const char *filename,const size_t depth,
2110 % ExceptionInfo *exception)
2111 %
2112 % A description of each parameter follows:
2113 %
2114 % o xml: The delegate list in XML format.
2115 %
2116 % o filename: The delegate list filename.
2117 %
2118 % o depth: depth of <include /> statements.
2119 %
2120 % o exception: return any errors or warnings in this structure.
2121 %
2122 */
2123 static MagickBooleanType LoadDelegateCache(LinkedListInfo *cache,
2124  const char *xml,const char *filename,const size_t depth,
2125  ExceptionInfo *exception)
2126 {
2127  char
2128  keyword[MaxTextExtent],
2129  *token;
2130 
2131  const char
2132  *q;
2133 
2134  DelegateInfo
2135  *delegate_info;
2136 
2137  MagickStatusType
2138  status;
2139 
2140  size_t
2141  extent;
2142 
2143  /*
2144  Load the delegate map file.
2145  */
2146  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2147  "Loading delegate configuration file \"%s\" ...",filename);
2148  if (xml == (const char *) NULL)
2149  return(MagickFalse);
2150  status=MagickTrue;
2151  delegate_info=(DelegateInfo *) NULL;
2152  token=AcquireString(xml);
2153  extent=strlen(token)+MaxTextExtent;
2154  for (q=(const char *) xml; *q != '\0'; )
2155  {
2156  /*
2157  Interpret XML.
2158  */
2159  (void) GetNextToken(q,&q,extent,token);
2160  if (*token == '\0')
2161  break;
2162  (void) CopyMagickString(keyword,token,MaxTextExtent);
2163  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
2164  {
2165  /*
2166  Doctype element.
2167  */
2168  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
2169  (void) GetNextToken(q,&q,extent,token);
2170  continue;
2171  }
2172  if (LocaleNCompare(keyword,"<!--",4) == 0)
2173  {
2174  /*
2175  Comment element.
2176  */
2177  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
2178  (void) GetNextToken(q,&q,extent,token);
2179  continue;
2180  }
2181  if (LocaleCompare(keyword,"<include") == 0)
2182  {
2183  /*
2184  Include element.
2185  */
2186  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
2187  {
2188  (void) CopyMagickString(keyword,token,MaxTextExtent);
2189  (void) GetNextToken(q,&q,extent,token);
2190  if (*token != '=')
2191  continue;
2192  (void) GetNextToken(q,&q,extent,token);
2193  if (LocaleCompare(keyword,"file") == 0)
2194  {
2195  if (depth > MagickMaxRecursionDepth)
2196  (void) ThrowMagickException(exception,GetMagickModule(),
2197  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
2198  else
2199  {
2200  char
2201  path[MaxTextExtent],
2202  *xml;
2203 
2204  GetPathComponent(filename,HeadPath,path);
2205  if (*path != '\0')
2206  (void) ConcatenateMagickString(path,DirectorySeparator,
2207  MaxTextExtent);
2208  if (*token == *DirectorySeparator)
2209  (void) CopyMagickString(path,token,MaxTextExtent);
2210  else
2211  (void) ConcatenateMagickString(path,token,MaxTextExtent);
2212  xml=FileToXML(path,~0UL);
2213  if (xml != (char *) NULL)
2214  {
2215  status&=LoadDelegateCache(cache,xml,path,depth+1,
2216  exception);
2217  xml=(char *) RelinquishMagickMemory(xml);
2218  }
2219  }
2220  }
2221  }
2222  continue;
2223  }
2224  if (LocaleCompare(keyword,"<delegate") == 0)
2225  {
2226  /*
2227  Delegate element.
2228  */
2229  delegate_info=(DelegateInfo *) AcquireQuantumMemory(1,
2230  sizeof(*delegate_info));
2231  if (delegate_info == (DelegateInfo *) NULL)
2232  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2233  (void) memset(delegate_info,0,sizeof(*delegate_info));
2234  delegate_info->path=ConstantString(filename);
2235  delegate_info->thread_support=MagickTrue;
2236  delegate_info->signature=MagickCoreSignature;
2237  continue;
2238  }
2239  if (delegate_info == (DelegateInfo *) NULL)
2240  continue;
2241  if ((LocaleCompare(keyword,"/>") == 0) ||
2242  (LocaleCompare(keyword,"</policy>") == 0))
2243  {
2244  status=AppendValueToLinkedList(cache,delegate_info);
2245  if (status == MagickFalse)
2246  (void) ThrowMagickException(exception,GetMagickModule(),
2247  ResourceLimitError,"MemoryAllocationFailed","`%s'",
2248  delegate_info->commands);
2249  delegate_info=(DelegateInfo *) NULL;
2250  continue;
2251  }
2252  (void) GetNextToken(q,(const char **) NULL,extent,token);
2253  if (*token != '=')
2254  continue;
2255  (void) GetNextToken(q,&q,extent,token);
2256  (void) GetNextToken(q,&q,extent,token);
2257  switch (*keyword)
2258  {
2259  case 'C':
2260  case 'c':
2261  {
2262  if (LocaleCompare((char *) keyword,"command") == 0)
2263  {
2264  char
2265  *commands;
2266 
2267  commands=AcquireString(token);
2268 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
2269  if (strchr(commands,'@') != (char *) NULL)
2270  {
2271  char
2272  path[MaxTextExtent];
2273 
2274  NTGhostscriptEXE(path,MaxTextExtent);
2275  (void) SubstituteString((char **) &commands,"@PSDelegate@",
2276  path);
2277  (void) SubstituteString((char **) &commands,"\\","/");
2278  }
2279  (void) SubstituteString((char **) &commands,"&quot;","\"");
2280 #else
2281  (void) SubstituteString((char **) &commands,"&quot;","'");
2282 #endif
2283  (void) SubstituteString((char **) &commands,"&amp;","&");
2284  (void) SubstituteString((char **) &commands,"&gt;",">");
2285  (void) SubstituteString((char **) &commands,"&lt;","<");
2286  if (delegate_info->commands != (char *) NULL)
2287  delegate_info->commands=DestroyString(delegate_info->commands);
2288  delegate_info->commands=commands;
2289  break;
2290  }
2291  break;
2292  }
2293  case 'D':
2294  case 'd':
2295  {
2296  if (LocaleCompare((char *) keyword,"decode") == 0)
2297  {
2298  delegate_info->decode=ConstantString(token);
2299  delegate_info->mode=1;
2300  break;
2301  }
2302  break;
2303  }
2304  case 'E':
2305  case 'e':
2306  {
2307  if (LocaleCompare((char *) keyword,"encode") == 0)
2308  {
2309  delegate_info->encode=ConstantString(token);
2310  delegate_info->mode=(-1);
2311  break;
2312  }
2313  break;
2314  }
2315  case 'M':
2316  case 'm':
2317  {
2318  if (LocaleCompare((char *) keyword,"mode") == 0)
2319  {
2320  delegate_info->mode=1;
2321  if (LocaleCompare(token,"bi") == 0)
2322  delegate_info->mode=0;
2323  else
2324  if (LocaleCompare(token,"encode") == 0)
2325  delegate_info->mode=(-1);
2326  break;
2327  }
2328  break;
2329  }
2330  case 'S':
2331  case 's':
2332  {
2333  if (LocaleCompare((char *) keyword,"spawn") == 0)
2334  {
2335  delegate_info->spawn=IsMagickTrue(token);
2336  break;
2337  }
2338  if (LocaleCompare((char *) keyword,"stealth") == 0)
2339  {
2340  delegate_info->stealth=IsMagickTrue(token);
2341  break;
2342  }
2343  break;
2344  }
2345  case 'T':
2346  case 't':
2347  {
2348  if (LocaleCompare((char *) keyword,"thread-support") == 0)
2349  {
2350  delegate_info->thread_support=IsMagickTrue(token);
2351  if (delegate_info->thread_support == MagickFalse)
2352  delegate_info->semaphore=AllocateSemaphoreInfo();
2353  break;
2354  }
2355  break;
2356  }
2357  default:
2358  break;
2359  }
2360  }
2361  token=(char *) RelinquishMagickMemory(token);
2362  return(status != 0 ? MagickTrue : MagickFalse);
2363 }
Definition: image.h:152