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