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