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