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