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