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=\""autotrace" -output-format svg -output-file "%o" "%i"\"/>"
98 " <delegate decode=\"avi:decode\" stealth=\"True\" command=\""mplayer" "%i" -really-quiet -ao null -vo png:z=3\"/>"
99 " <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\""xdg-open" http://imagemagick.org/; rm "%i"\"/>"
100 " <delegate decode=\"cgm\" thread-support=\"False\" command=\""ralcgm" -d ps -oC < "%i" > "%o" 2> "%u"\"/>"
101 " <delegate decode=\"dng:decode\" command=\""ufraw-batch" --silent --create-id=also --out-type=png --out-depth=16 "--output=%u.png" "%i"\"/>"
102 " <delegate decode=\"edit\" stealth=\"True\" command=\""xterm" -title "Edit Image Comment" -e vi "%o"\"/>"
103 " <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"\"/>"
104 " <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"\"/>"
105 " <delegate decode=\"fig\" command=\""fig2dev" -L ps "%i" "%o"\"/>"
106 " <delegate decode=\"hpg\" command=\""hp2xx" -q -m eps -f `basename "%o"` "%i" mv -f `basename "%o"` "%o"\"/>"
107 " <delegate decode=\"hpgl\" command=\""hp2xx" -q -m eps -f `basename "%o"` "%i" mv -f `basename "%o"` "%o"\"/>"
108 " <delegate decode=\"htm\" command=\""html2ps" -U -o "%o" "%i"\"/>"
109 " <delegate decode=\"html\" command=\""html2ps" -U -o "%o" "%i"\"/>"
110 " <delegate decode=\"https\" command=\""curl" -s -k -L -o "%o" "https:%M"\"/>"
111 " <delegate decode=\"ilbm\" command=\""ilbmtoppm" "%i" > "%o"\"/>"
112 " <delegate decode=\"man\" command=\""groff" -man -Tps "%i" > "%o"\"/>"
113 " <delegate decode=\"video:decode\" command=\""ffmpeg" -nostdin -v -1 -i "%i" -vframes %S -vcodec pam -an -f rawvideo -y "%u.pam" 2> "%u"\"/>"
114 " <delegate encode=\"video:encode\" stealth=\"True\" command=\""ffmpeg" -nostdin -v -1 -i "%M%%d.pam" -plays %I "%u.%m" 2> "%u"\"/>"
115 " <delegate decode=\"pcl:color\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ppmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>"
116 " <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bmpsep8" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>"
117 " <delegate decode=\"pcl:mono\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pbmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>"
118 " <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=eps2write" "-sOutputFile=%o" "-f%i"\"/>"
119 " <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"\"/>"
120 " <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\""ppmtoilbm" -24if "%i" > "%o"\"/>"
121 " <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\""gimp" "%i"\"/>"
122 " <delegate decode=\"pov\" command=\""povray" "+i"%i"" -D0 +o"%o" +fn%q +w%w +h%h +a -q9 -kfi"%s" -kff"%n" "convert" -concatenate "%o*.png" "%o"\"/>"
123 " <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=eps2write" "-sOutputFile=%o" "-f%i"\"/>"
124 " <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"\"/>"
125 " <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr "%i"\"/>"
126 " <delegate decode=\"ps:alpha\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>"
127 " <delegate decode=\"ps:bbox\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bbox" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>"
128 " <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bmpsep8" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>"
129 " <delegate decode=\"ps:color\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pnmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>"
130 " <delegate decode=\"ps:mono\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pnmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>"
131 " <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\""rawtorle" -o "%o" -v "%i"\"/>"
132 " <delegate decode=\"scan\" command=\""scanimage" -d "%i" > "%o"\"/>"
133 " <delegate encode=\"show\" spawn=\"True\" command=\""display" -immutable -delay 0 -title "%M"\" "%i"\"/>"
134 " <delegate decode=\"shtml\" command=\""html2ps" -U -o "%o" "%i"\"/>"
135 " <delegate decode=\"svg\" command=\""rsvg" "%i" "%o"\"/>"
136 " <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\""enscript" -o "%o" "%i"\"/>"
137 " <delegate encode=\"win\" spawn=\"True\" command=\""display" -immutable -delay 0 -title "%M"\" "%i"\"/>"
138 " <delegate decode=\"wmf\" command=\""wmf2eps" -o "%o" "%i"\"/>"
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("<",p,4) == 0)
1105 {
1106 *q++='<';
1107 p+=3;
1108 }
1109 else
1110 if (LocaleNCompare(">",p,4) == 0)
1111 {
1112 *q++='>';
1113 p+=3;
1114 }
1115 else
1116 if (LocaleNCompare("&",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,""","\"");
2275 #else
2276 (void) SubstituteString((char **) &commands,""","'");
2277 #endif
2278 (void) SubstituteString((char **) &commands,"&","&");
2279 (void) SubstituteString((char **) &commands,">",">");
2280 (void) SubstituteString((char **) &commands,"<","<");
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