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