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