blob: 0df9dd579cb8e1907f37e112b0edf9b929062fc0 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000015% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000016% October 1998 %
17% %
18% %
cristyfe676ee2013-11-18 13:03:38 +000019% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000020% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/studio.h"
49#include "MagickCore/property.h"
50#include "MagickCore/blob.h"
51#include "MagickCore/client.h"
52#include "MagickCore/configure.h"
53#include "MagickCore/constitute.h"
54#include "MagickCore/delegate.h"
cristy5ff4eaf2011-09-03 01:38:02 +000055#include "MagickCore/delegate-private.h"
cristy4c08aed2011-07-01 19:47:50 +000056#include "MagickCore/exception.h"
57#include "MagickCore/exception-private.h"
58#include "MagickCore/hashmap.h"
59#include "MagickCore/list.h"
60#include "MagickCore/memory_.h"
cristy1e37e8f2014-02-21 17:05:37 +000061#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000062#include "MagickCore/policy.h"
63#include "MagickCore/resource_.h"
64#include "MagickCore/semaphore.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/token.h"
67#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000068#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000069#include "MagickCore/xml-tree.h"
cristy3291f512014-03-16 22:16:22 +000070#include "MagickCore/xml-tree-private.h"
cristy3ed852e2009-09-05 21:47:34 +000071
72/*
73 Define declarations.
74*/
75#define DelegateFilename "delegates.xml"
76
77/*
78 Declare delegate map.
79*/
80static const char
81 *DelegateMap = (const char *)
82 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
83 "<delegatemap>"
84 " <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
85 " <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
anthonyb8071362012-05-23 03:56:25 +000086 " <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +000087 " <delegate decode=\"cgm\" thread-support=\"False\" command=\"&quot;ralcgm&quot; -d ps -oC &lt; &quot;%i&quot; &gt; &quot;%o&quot; 2&gt; &quot;%u&quot;\"/>"
88 " <delegate decode=\"dng:decode\" command=\"&quot;/usr/bin/ufraw-batch&quot; --silent --wb=camera --black-point=auto --exposure=auto --create-id=also --out-type=ppm16 &quot;--output=%u.pnm&quot; &quot;%i&quot;\"/>"
89 " <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
cristya7bb1c42012-11-18 00:27:49 +000090 " <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
91 " <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +000092 " <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
93 " <delegate decode=\"gplt\" command=\"&quot;echo&quot; &quot;set size 1.25,0.62 set terminal postscript portrait color solid; set output &quot;%o&quot;; load &quot;%i&quot;&quot; &gt; &quot;%u&quot;;&quot;gnuplot&quot; &quot;%u&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +000094 " <delegate decode=\"hpg\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot; mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
cristy7c278052012-11-18 01:09:35 +000095 " <delegate decode=\"hpgl\" command=\"&quot;hp2xx&quot; -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot; mv -f `basename &quot;%o&quot;` &quot;%o&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +000096 " <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
97 " <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
98 " <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
99 " <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
100 " <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
anthony4e3d06f2012-05-23 03:58:38 +0000101 " <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -v -1 -vframes %S -i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u.pam&quot; 2&gt; &quot;%Z&quot;\"/>"
102 " <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2&gt; &quot;%Z&quot;\"/>"
cristya7bb1c42012-11-18 00:27:49 +0000103 " <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;\"/>"
104 " <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&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;\"/>"
105 " <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;\"/>"
106 " <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
107 " <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000108 " <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
109 " <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
110 " <delegate decode=\"pov\" command=\"&quot;povray&quot; &quot;+i&quot;%i&quot;&quot; -D0 +o&quot;%o&quot; +fn%q +w%w +h%h +a -q9 -kfi&quot;%s&quot; -kff&quot;%n&quot; &quot;convert&quot; -concatenate &quot;%o*.png&quot; &quot;%o&quot;\"/>"
cristya7bb1c42012-11-18 00:27:49 +0000111 " <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
112 " <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000113 " <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
cristya7bb1c42012-11-18 00:27:49 +0000114 " <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -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;\"/>"
115 " <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 &quot;-sDEVICE=bbox&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;-f%s&quot; &quot;-f%s&quot;\"/>"
116 " <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -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;-f%s&quot; &quot;-f%s&quot;\"/>"
117 " <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -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;\"/>"
118 " <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -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;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000119 " <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
120 " <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
anthonyb8071362012-05-23 03:56:25 +0000121 " <delegate encode=\"show\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000122 " <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
cristy4689cf02010-02-17 21:15:45 +0000123 " <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000124 " <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
anthonyb8071362012-05-23 03:56:25 +0000125 " <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
cristy3ed852e2009-09-05 21:47:34 +0000126 " <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
127 "</delegatemap>";
128
129/*
130 Global declaractions.
131*/
132static LinkedListInfo
cristy86e5ac92014-03-16 19:27:39 +0000133 *delegate_cache = (LinkedListInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000134
135static SemaphoreInfo
136 *delegate_semaphore = (SemaphoreInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000137
138/*
139 Forward declaractions.
140*/
141static MagickBooleanType
cristy86e5ac92014-03-16 19:27:39 +0000142 IsDelegateCacheInstantiated(ExceptionInfo *),
cristycd2cd182014-03-18 12:10:55 +0000143 LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t,
144 ExceptionInfo *);
cristy86e5ac92014-03-16 19:27:39 +0000145
146/*
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148% %
149% %
150% %
151% A c q u i r e D e l e g a t e C a c h e %
152% %
153% %
154% %
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156%
157% AcquireDelegateCache() caches one or more delegate configurations which
158% provides a mapping between delegate attributes and a delegate name.
159%
160% The format of the AcquireDelegateCache method is:
161%
162% LinkedListInfo *AcquireDelegateCache(const char *filename,
163% ExceptionInfo *exception)
164%
165% A description of each parameter follows:
166%
167% o filename: the font file name.
168%
169% o exception: return any errors or warnings in this structure.
170%
171*/
172static LinkedListInfo *AcquireDelegateCache(const char *filename,
173 ExceptionInfo *exception)
174{
cristy86e5ac92014-03-16 19:27:39 +0000175 LinkedListInfo
cristy66f8c5f2014-03-17 00:12:14 +0000176 *delegate_cache;
cristy86e5ac92014-03-16 19:27:39 +0000177
178 MagickStatusType
179 status;
180
181 delegate_cache=NewLinkedList(0);
182 if (delegate_cache == (LinkedListInfo *) NULL)
183 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
184 status=MagickTrue;
cristy191ba5c2014-03-16 21:26:40 +0000185#if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
cristy86e5ac92014-03-16 19:27:39 +0000186 {
cristy66f8c5f2014-03-17 00:12:14 +0000187 const StringInfo
188 *option;
189
190 LinkedListInfo
191 *options;
192
193 options=GetConfigureOptions(filename,exception);
cristy86e5ac92014-03-16 19:27:39 +0000194 option=(const StringInfo *) GetNextValueInLinkedList(options);
cristy66f8c5f2014-03-17 00:12:14 +0000195 while (option != (const StringInfo *) NULL)
196 {
cristycd2cd182014-03-18 12:10:55 +0000197 status&=LoadDelegateCache(delegate_cache,(const char *)
198 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
cristy66f8c5f2014-03-17 00:12:14 +0000199 option=(const StringInfo *) GetNextValueInLinkedList(options);
200 }
201 options=DestroyConfigureOptions(options);
cristy86e5ac92014-03-16 19:27:39 +0000202 }
cristy191ba5c2014-03-16 21:26:40 +0000203#endif
cristy191ba5c2014-03-16 21:26:40 +0000204 if (IfMagickTrue(IsLinkedListEmpty(delegate_cache)))
cristycd2cd182014-03-18 12:10:55 +0000205 status&=LoadDelegateCache(delegate_cache,DelegateMap,"built-in",0,
206 exception);
cristy86e5ac92014-03-16 19:27:39 +0000207 return(delegate_cache);
cristy86e5ac92014-03-16 19:27:39 +0000208}
cristy3ed852e2009-09-05 21:47:34 +0000209
210/*
211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
212% %
213% %
214% %
cristyf34a1452009-10-24 22:29:27 +0000215+ 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 %
cristy3ed852e2009-09-05 21:47:34 +0000216% %
217% %
218% %
219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220%
cristyf34a1452009-10-24 22:29:27 +0000221% DelegateComponentGenesis() instantiates the delegate component.
cristy3ed852e2009-09-05 21:47:34 +0000222%
cristyf34a1452009-10-24 22:29:27 +0000223% The format of the DelegateComponentGenesis method is:
cristy3ed852e2009-09-05 21:47:34 +0000224%
cristyf34a1452009-10-24 22:29:27 +0000225% MagickBooleanType DelegateComponentGenesis(void)
226%
227*/
cristy5ff4eaf2011-09-03 01:38:02 +0000228MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000229{
cristy3d162a92014-02-16 14:05:06 +0000230 delegate_semaphore=AcquireSemaphoreInfo();
cristyf34a1452009-10-24 22:29:27 +0000231 return(MagickTrue);
232}
233
234/*
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236% %
237% %
238% %
239% 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 %
240% %
241% %
242% %
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244%
245% DelegateComponentTerminus() destroys the delegate component.
246%
247% The format of the DelegateComponentTerminus method is:
248%
249% DelegateComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000250%
251*/
252
253static void *DestroyDelegate(void *delegate_info)
254{
255 register DelegateInfo
256 *p;
257
258 p=(DelegateInfo *) delegate_info;
259 if (p->path != (char *) NULL)
260 p->path=DestroyString(p->path);
261 if (p->decode != (char *) NULL)
262 p->decode=DestroyString(p->decode);
263 if (p->encode != (char *) NULL)
264 p->encode=DestroyString(p->encode);
265 if (p->commands != (char *) NULL)
266 p->commands=DestroyString(p->commands);
cristy191ba5c2014-03-16 21:26:40 +0000267 if (p->semaphore != (SemaphoreInfo *) NULL)
268 p->semaphore=RelinquishSemaphoreInfo(&p->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000269 p=(DelegateInfo *) RelinquishMagickMemory(p);
270 return((void *) NULL);
271}
272
cristy5ff4eaf2011-09-03 01:38:02 +0000273MagickPrivate void DelegateComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000274{
cristy18b17442009-10-25 18:36:48 +0000275 if (delegate_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +0000276 ActivateSemaphoreInfo(&delegate_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000277 LockSemaphoreInfo(delegate_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000278 if (delegate_cache != (LinkedListInfo *) NULL)
279 delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate);
cristyf84a1932010-01-03 18:00:18 +0000280 UnlockSemaphoreInfo(delegate_semaphore);
cristy3d162a92014-02-16 14:05:06 +0000281 RelinquishSemaphoreInfo(&delegate_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000282}
283
284/*
285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286% %
287% %
288% %
289% G e t D e l e g a t e C o m m a n d %
290% %
291% %
292% %
293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294%
295% GetDelegateCommand() replaces any embedded formatting characters with the
296% appropriate image attribute and returns the resulting command.
297%
298% The format of the GetDelegateCommand method is:
299%
300% char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
301% const char *decode,const char *encode,ExceptionInfo *exception)
302%
303% A description of each parameter follows:
304%
305% o command: Method GetDelegateCommand returns the command associated
306% with specified delegate tag.
307%
308% o image_info: the image info.
309%
310% o image: the image.
311%
312% o decode: Specifies the decode delegate we are searching for as a
313% character string.
314%
315% o encode: Specifies the encode delegate we are searching for as a
316% character string.
317%
318% o exception: return any errors or warnings in this structure.
319%
320*/
321MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
322 const char *decode,const char *encode,ExceptionInfo *exception)
323{
324 char
325 *command,
326 **commands;
327
328 const DelegateInfo
329 *delegate_info;
330
cristybb503372010-05-27 20:51:26 +0000331 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000332 i;
333
334 assert(image_info != (ImageInfo *) NULL);
335 assert(image_info->signature == MagickSignature);
336 assert(image != (Image *) NULL);
337 assert(image->signature == MagickSignature);
anthony59c44432012-05-23 04:41:25 +0000338 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +0000339 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
anthony59c44432012-05-23 04:41:25 +0000340
cristy3ed852e2009-09-05 21:47:34 +0000341 delegate_info=GetDelegateInfo(decode,encode,exception);
342 if (delegate_info == (const DelegateInfo *) NULL)
343 {
344 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
cristyefe601c2013-01-05 17:51:12 +0000345 "NoTagFound","`%s'",decode ? decode : encode);
cristy3ed852e2009-09-05 21:47:34 +0000346 return((char *) NULL);
347 }
348 commands=StringToList(delegate_info->commands);
349 if (commands == (char **) NULL)
350 {
351 (void) ThrowMagickException(exception,GetMagickModule(),
cristy014ead12013-04-29 08:47:36 +0000352 ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode :
353 encode);
cristy3ed852e2009-09-05 21:47:34 +0000354 return((char *) NULL);
355 }
cristy014ead12013-04-29 08:47:36 +0000356 command=InterpretImageProperties((ImageInfo *) image_info,image,commands[0],
357 exception);
cristy3ed852e2009-09-05 21:47:34 +0000358 if (command == (char *) NULL)
359 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
cristyefe601c2013-01-05 17:51:12 +0000360 "MemoryAllocationFailed","`%s'",commands[0]);
cristy3ed852e2009-09-05 21:47:34 +0000361 /*
362 Relinquish resources.
363 */
364 for (i=0; commands[i] != (char *) NULL; i++)
365 commands[i]=DestroyString(commands[i]);
366 commands=(char **) RelinquishMagickMemory(commands);
367 return(command);
368}
369
370/*
371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372% %
373% %
374% %
375% G e t D e l e g a t e C o m m a n d s %
376% %
377% %
378% %
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380%
381% GetDelegateCommands() returns the commands associated with a delegate.
382%
383% The format of the GetDelegateCommands method is:
384%
385% const char *GetDelegateCommands(const DelegateInfo *delegate_info)
386%
387% A description of each parameter follows:
388%
389% o delegate_info: The delegate info.
390%
391*/
392MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
393{
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
anthony59c44432012-05-23 04:41:25 +0000395
cristy3ed852e2009-09-05 21:47:34 +0000396 assert(delegate_info != (DelegateInfo *) NULL);
397 assert(delegate_info->signature == MagickSignature);
398 return(delegate_info->commands);
399}
400
401/*
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403% %
404% %
405% %
406% G e t D e l e g a t e I n f o %
407% %
408% %
409% %
410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411%
412% GetDelegateInfo() returns any delegates associated with the specified tag.
413%
414% The format of the GetDelegateInfo method is:
415%
416% const DelegateInfo *GetDelegateInfo(const char *decode,
417% const char *encode,ExceptionInfo *exception)
418%
419% A description of each parameter follows:
420%
421% o decode: Specifies the decode delegate we are searching for as a
422% character string.
423%
424% o encode: Specifies the encode delegate we are searching for as a
425% character string.
426%
427% o exception: return any errors or warnings in this structure.
428%
429*/
430MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
431 const char *encode,ExceptionInfo *exception)
432{
433 register const DelegateInfo
434 *p;
435
436 assert(exception != (ExceptionInfo *) NULL);
cristycd2cd182014-03-18 12:10:55 +0000437 if (IfMagickFalse(IsDelegateCacheInstantiated(exception)))
438 return((const DelegateInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000439 /*
440 Search for named delegate.
441 */
cristyf84a1932010-01-03 18:00:18 +0000442 LockSemaphoreInfo(delegate_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000443 ResetLinkedListIterator(delegate_cache);
444 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy49d4d222014-03-16 00:37:58 +0000445 if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
446 {
447 UnlockSemaphoreInfo(delegate_semaphore);
448 return(p);
449 }
cristy3ed852e2009-09-05 21:47:34 +0000450 while (p != (const DelegateInfo *) NULL)
451 {
452 if (p->mode > 0)
453 {
454 if (LocaleCompare(p->decode,decode) == 0)
455 break;
cristy86e5ac92014-03-16 19:27:39 +0000456 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000457 continue;
458 }
459 if (p->mode < 0)
460 {
461 if (LocaleCompare(p->encode,encode) == 0)
462 break;
cristy86e5ac92014-03-16 19:27:39 +0000463 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000464 continue;
465 }
466 if (LocaleCompare(decode,p->decode) == 0)
467 if (LocaleCompare(encode,p->encode) == 0)
468 break;
469 if (LocaleCompare(decode,"*") == 0)
470 if (LocaleCompare(encode,p->encode) == 0)
471 break;
472 if (LocaleCompare(decode,p->decode) == 0)
473 if (LocaleCompare(encode,"*") == 0)
474 break;
cristy86e5ac92014-03-16 19:27:39 +0000475 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000476 }
477 if (p != (const DelegateInfo *) NULL)
cristy86e5ac92014-03-16 19:27:39 +0000478 (void) InsertValueInLinkedList(delegate_cache,0,
479 RemoveElementByValueFromLinkedList(delegate_cache,p));
cristyf84a1932010-01-03 18:00:18 +0000480 UnlockSemaphoreInfo(delegate_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000481 return(p);
482}
483
484/*
485%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486% %
487% %
488% %
489% G e t D e l e g a t e I n f o L i s t %
490% %
491% %
492% %
493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494%
495% GetDelegateInfoList() returns any delegates that match the specified pattern.
496%
497% The delegate of the GetDelegateInfoList function is:
498%
499% const DelegateInfo **GetDelegateInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000500% size_t *number_delegates,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000501%
502% A description of each parameter follows:
503%
504% o pattern: Specifies a pointer to a text string containing a pattern.
505%
506% o number_delegates: This integer returns the number of delegates in the
507% list.
508%
509% o exception: return any errors or warnings in this structure.
510%
511*/
512
513#if defined(__cplusplus) || defined(c_plusplus)
514extern "C" {
515#endif
516
517static int DelegateInfoCompare(const void *x,const void *y)
518{
519 const DelegateInfo
520 **p,
521 **q;
522
523 p=(const DelegateInfo **) x,
524 q=(const DelegateInfo **) y;
525 if (LocaleCompare((*p)->path,(*q)->path) == 0)
526 {
527 if ((*p)->decode == (char *) NULL)
528 if (((*p)->encode != (char *) NULL) &&
529 ((*q)->encode != (char *) NULL))
530 return(strcmp((*p)->encode,(*q)->encode));
531 if (((*p)->decode != (char *) NULL) &&
532 ((*q)->decode != (char *) NULL))
533 return(strcmp((*p)->decode,(*q)->decode));
534 }
535 return(LocaleCompare((*p)->path,(*q)->path));
536}
537
538#if defined(__cplusplus) || defined(c_plusplus)
539}
540#endif
541
542MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000543 size_t *number_delegates,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000544{
545 const DelegateInfo
546 **delegates;
547
548 register const DelegateInfo
549 *p;
550
cristybb503372010-05-27 20:51:26 +0000551 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000552 i;
553
554 /*
555 Allocate delegate list.
556 */
anthony59c44432012-05-23 04:41:25 +0000557 assert(number_delegates != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000558 assert(pattern != (char *) NULL);
559 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
anthony59c44432012-05-23 04:41:25 +0000560
cristy3ed852e2009-09-05 21:47:34 +0000561 *number_delegates=0;
562 p=GetDelegateInfo("*","*",exception);
563 if (p == (const DelegateInfo *) NULL)
564 return((const DelegateInfo **) NULL);
565 delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000566 GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
cristy3ed852e2009-09-05 21:47:34 +0000567 if (delegates == (const DelegateInfo **) NULL)
568 return((const DelegateInfo **) NULL);
569 /*
570 Generate delegate list.
571 */
cristyf84a1932010-01-03 18:00:18 +0000572 LockSemaphoreInfo(delegate_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000573 ResetLinkedListIterator(delegate_cache);
574 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000575 for (i=0; p != (const DelegateInfo *) NULL; )
576 {
anthony59c44432012-05-23 04:41:25 +0000577 if( IfMagickFalse(p->stealth) &&
578 ( IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) ||
579 IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse))) )
cristy3ed852e2009-09-05 21:47:34 +0000580 delegates[i++]=p;
cristy86e5ac92014-03-16 19:27:39 +0000581 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000582 }
cristyf84a1932010-01-03 18:00:18 +0000583 UnlockSemaphoreInfo(delegate_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000584 qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
585 delegates[i]=(DelegateInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000586 *number_delegates=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000587 return(delegates);
588}
589
590/*
591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592% %
593% %
594% %
595% G e t D e l e g a t e L i s t %
596% %
597% %
598% %
599%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
600%
601% GetDelegateList() returns any image format delegates that match the
602% specified pattern.
603%
604% The format of the GetDelegateList function is:
605%
606% char **GetDelegateList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000607% size_t *number_delegates,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000608%
609% A description of each parameter follows:
610%
611% o pattern: Specifies a pointer to a text string containing a pattern.
612%
613% o number_delegates: This integer returns the number of delegates
614% in the list.
615%
616% o exception: return any errors or warnings in this structure.
617%
618*/
619
620#if defined(__cplusplus) || defined(c_plusplus)
621extern "C" {
622#endif
623
624static int DelegateCompare(const void *x,const void *y)
625{
626 register const char
627 **p,
628 **q;
629
630 p=(const char **) x;
631 q=(const char **) y;
632 return(LocaleCompare(*p,*q));
633}
634
635#if defined(__cplusplus) || defined(c_plusplus)
636}
637#endif
638
639MagickExport char **GetDelegateList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000640 size_t *number_delegates,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000641{
642 char
643 **delegates;
644
645 register const DelegateInfo
646 *p;
647
cristybb503372010-05-27 20:51:26 +0000648 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000649 i;
650
651 /*
652 Allocate delegate list.
653 */
654 assert(pattern != (char *) NULL);
655 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
anthony59c44432012-05-23 04:41:25 +0000656
cristybb503372010-05-27 20:51:26 +0000657 assert(number_delegates != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000658 *number_delegates=0;
659 p=GetDelegateInfo("*","*",exception);
660 if (p == (const DelegateInfo *) NULL)
661 return((char **) NULL);
662 delegates=(char **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000663 GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates));
cristy3ed852e2009-09-05 21:47:34 +0000664 if (delegates == (char **) NULL)
665 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000666 LockSemaphoreInfo(delegate_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000667 ResetLinkedListIterator(delegate_cache);
668 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000669 for (i=0; p != (const DelegateInfo *) NULL; )
670 {
anthony59c44432012-05-23 04:41:25 +0000671 if( IfMagickFalse(p->stealth) &&
672 IfMagickTrue(GlobExpression(p->decode,pattern,MagickFalse)) )
cristy3ed852e2009-09-05 21:47:34 +0000673 delegates[i++]=ConstantString(p->decode);
anthony59c44432012-05-23 04:41:25 +0000674 if( IfMagickFalse(p->stealth) &&
675 IfMagickTrue(GlobExpression(p->encode,pattern,MagickFalse)) )
cristy3ed852e2009-09-05 21:47:34 +0000676 delegates[i++]=ConstantString(p->encode);
cristy86e5ac92014-03-16 19:27:39 +0000677 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache);
cristy3ed852e2009-09-05 21:47:34 +0000678 }
cristyf84a1932010-01-03 18:00:18 +0000679 UnlockSemaphoreInfo(delegate_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000680 qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
681 delegates[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000682 *number_delegates=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000683 return(delegates);
684}
685
686/*
687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688% %
689% %
690% %
691% G e t D e l e g a t e M o d e %
692% %
693% %
694% %
695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696%
697% GetDelegateMode() returns the mode of the delegate.
698%
699% The format of the GetDelegateMode method is:
700%
cristybb503372010-05-27 20:51:26 +0000701% ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
cristy3ed852e2009-09-05 21:47:34 +0000702%
703% A description of each parameter follows:
704%
705% o delegate_info: The delegate info.
706%
707*/
cristybb503372010-05-27 20:51:26 +0000708MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
cristy3ed852e2009-09-05 21:47:34 +0000709{
710 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
anthony59c44432012-05-23 04:41:25 +0000711
cristy3ed852e2009-09-05 21:47:34 +0000712 assert(delegate_info != (DelegateInfo *) NULL);
713 assert(delegate_info->signature == MagickSignature);
714 return(delegate_info->mode);
715}
716
717/*
718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
719% %
720% %
721% %
722+ G e t D e l e g a t e T h r e a d S u p p o r t %
723% %
724% %
725% %
726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727%
728% GetDelegateThreadSupport() returns MagickTrue if the delegate supports
729% threads.
730%
731% The format of the GetDelegateThreadSupport method is:
732%
733% MagickBooleanType GetDelegateThreadSupport(
734% const DelegateInfo *delegate_info)
735%
736% A description of each parameter follows:
737%
738% o delegate_info: The delegate info.
739%
740*/
741MagickExport MagickBooleanType GetDelegateThreadSupport(
742 const DelegateInfo *delegate_info)
743{
744 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
anthony59c44432012-05-23 04:41:25 +0000745
cristy3ed852e2009-09-05 21:47:34 +0000746 assert(delegate_info != (DelegateInfo *) NULL);
747 assert(delegate_info->signature == MagickSignature);
748 return(delegate_info->thread_support);
749}
750
751/*
752%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
753% %
754% %
755% %
cristy86e5ac92014-03-16 19:27:39 +0000756+ 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 %
cristy3ed852e2009-09-05 21:47:34 +0000757% %
758% %
759% %
760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761%
cristy86e5ac92014-03-16 19:27:39 +0000762% IsDelegateCacheInstantiated() determines if the delegate list is instantiated.
cristy904e5912014-03-15 19:53:14 +0000763% If not, it instantiates the list and returns it.
cristy3ed852e2009-09-05 21:47:34 +0000764%
cristy904e5912014-03-15 19:53:14 +0000765% The format of the IsDelegateInstantiated method is:
cristy3ed852e2009-09-05 21:47:34 +0000766%
cristy86e5ac92014-03-16 19:27:39 +0000767% MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000768%
769% A description of each parameter follows.
770%
771% o exception: return any errors or warnings in this structure.
772%
773*/
cristy86e5ac92014-03-16 19:27:39 +0000774static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000775{
cristy86e5ac92014-03-16 19:27:39 +0000776 if (delegate_cache == (LinkedListInfo *) NULL)
777 {
778 if (delegate_semaphore == (SemaphoreInfo *) NULL)
779 ActivateSemaphoreInfo(&delegate_semaphore);
780 LockSemaphoreInfo(delegate_semaphore);
781 if (delegate_cache == (LinkedListInfo *) NULL)
782 delegate_cache=AcquireDelegateCache(DelegateFilename,exception);
783 UnlockSemaphoreInfo(delegate_semaphore);
784 }
785 return(IsMagickNotNULL(delegate_cache));
cristy3ed852e2009-09-05 21:47:34 +0000786}
787
788/*
789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790% %
791% %
792% %
793% I n v o k e D e l e g a t e %
794% %
795% %
796% %
797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798%
799% InvokeDelegate replaces any embedded formatting characters with the
800% appropriate image attribute and executes the resulting command. MagickFalse
801% is returned if the commands execute with success otherwise MagickTrue.
802%
803% The format of the InvokeDelegate method is:
804%
805% MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
806% const char *decode,const char *encode,ExceptionInfo *exception)
807%
808% A description of each parameter follows:
809%
810% o image_info: the imageInfo.
811%
812% o image: the image.
813%
814% o exception: return any errors or warnings in this structure.
815%
816*/
817
818static inline size_t MagickMin(const size_t x,const size_t y)
819{
820 if (x < y)
821 return(x);
822 return(y);
823}
824
825static MagickBooleanType CopyDelegateFile(const char *source,
826 const char *destination)
827{
828 int
829 destination_file,
830 source_file;
831
cristy53ac66f2012-03-11 02:56:37 +0000832 MagickBooleanType
833 status;
834
cristy3ed852e2009-09-05 21:47:34 +0000835 register size_t
836 i;
837
838 size_t
839 length,
840 quantum;
841
842 ssize_t
843 count;
844
845 struct stat
846 attributes;
847
848 unsigned char
849 *buffer;
850
851 /*
cristy2dfb1df2012-02-25 14:16:09 +0000852 Copy source file to destination.
cristy3ed852e2009-09-05 21:47:34 +0000853 */
854 assert(source != (const char *) NULL);
855 assert(destination != (char *) NULL);
cristy53ac66f2012-03-11 02:56:37 +0000856 status=GetPathAttributes(destination,&attributes);
anthony59c44432012-05-23 04:41:25 +0000857 if( IfMagickTrue(status) && (attributes.st_size != 0))
cristy53ac66f2012-03-11 02:56:37 +0000858 return(MagickTrue);
cristy18c6c272011-09-23 14:40:37 +0000859 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000860 if (destination_file == -1)
861 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000862 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000863 if (source_file == -1)
864 {
865 (void) close(destination_file);
866 return(MagickFalse);
867 }
868 quantum=(size_t) MagickMaxBufferExtent;
869 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
870 quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
871 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
872 if (buffer == (unsigned char *) NULL)
873 {
874 (void) close(source_file);
875 (void) close(destination_file);
876 return(MagickFalse);
877 }
878 length=0;
879 for (i=0; ; i+=count)
880 {
881 count=(ssize_t) read(source_file,buffer,quantum);
882 if (count <= 0)
883 break;
884 length=(size_t) count;
885 count=(ssize_t) write(destination_file,buffer,length);
886 if ((size_t) count != length)
887 break;
888 }
889 (void) close(destination_file);
890 (void) close(source_file);
891 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
anthony59c44432012-05-23 04:41:25 +0000892 return(IsMagickTrue(i!=0));
cristy3ed852e2009-09-05 21:47:34 +0000893}
894
895MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
896 Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
897{
898 char
899 *command,
900 **commands,
901 input_filename[MaxTextExtent],
902 output_filename[MaxTextExtent];
903
904 const DelegateInfo
905 *delegate_info;
906
907 MagickBooleanType
908 status,
909 temporary;
910
cristybb503372010-05-27 20:51:26 +0000911 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000912 i;
913
914 PolicyRights
915 rights;
916
917 /*
918 Get delegate.
919 */
920 assert(image_info != (ImageInfo *) NULL);
921 assert(image_info->signature == MagickSignature);
922 assert(image != (Image *) NULL);
923 assert(image->signature == MagickSignature);
anthony59c44432012-05-23 04:41:25 +0000924 if( IfMagickTrue(image->debug) )
cristy3ed852e2009-09-05 21:47:34 +0000925 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
anthony59c44432012-05-23 04:41:25 +0000926
cristy3ed852e2009-09-05 21:47:34 +0000927 rights=ExecutePolicyRights;
anthony59c44432012-05-23 04:41:25 +0000928 if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,decode)) )
cristy3ed852e2009-09-05 21:47:34 +0000929 {
cristya9197f62010-01-12 02:23:34 +0000930 errno=EPERM;
cristy3ed852e2009-09-05 21:47:34 +0000931 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
cristyefe601c2013-01-05 17:51:12 +0000932 "NotAuthorized","`%s'",decode);
cristy3ed852e2009-09-05 21:47:34 +0000933 return(MagickFalse);
934 }
anthony59c44432012-05-23 04:41:25 +0000935 if( IfMagickFalse(IsRightsAuthorized(DelegatePolicyDomain,rights,encode)) )
cristy3ed852e2009-09-05 21:47:34 +0000936 {
cristya9197f62010-01-12 02:23:34 +0000937 errno=EPERM;
cristy3ed852e2009-09-05 21:47:34 +0000938 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
cristyefe601c2013-01-05 17:51:12 +0000939 "NotAuthorized","`%s'",encode);
cristy3ed852e2009-09-05 21:47:34 +0000940 return(MagickFalse);
941 }
anthony59c44432012-05-23 04:41:25 +0000942 temporary=IsMagickTrue(*image->filename == '\0');
943 if( IfMagickTrue(temporary) )
944 if( IfMagickFalse(AcquireUniqueFilename(image->filename)) )
cristy3ed852e2009-09-05 21:47:34 +0000945 {
946 ThrowFileException(exception,FileOpenError,
947 "UnableToCreateTemporaryFile",image->filename);
948 return(MagickFalse);
949 }
950 delegate_info=GetDelegateInfo(decode,encode,exception);
951 if (delegate_info == (DelegateInfo *) NULL)
952 {
anthony59c44432012-05-23 04:41:25 +0000953 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +0000954 (void) RelinquishUniqueFileResource(image->filename);
955 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
cristyefe601c2013-01-05 17:51:12 +0000956 "NoTagFound","`%s'",decode ? decode : encode);
cristy3ed852e2009-09-05 21:47:34 +0000957 return(MagickFalse);
958 }
959 if (*image_info->filename == '\0')
960 {
anthony59c44432012-05-23 04:41:25 +0000961 if( IfMagickFalse(AcquireUniqueFilename(image_info->filename)) )
cristy3ed852e2009-09-05 21:47:34 +0000962 {
anthony59c44432012-05-23 04:41:25 +0000963 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +0000964 (void) RelinquishUniqueFileResource(image->filename);
965 ThrowFileException(exception,FileOpenError,
966 "UnableToCreateTemporaryFile",image_info->filename);
967 return(MagickFalse);
968 }
969 image_info->temporary=MagickTrue;
970 }
cristyfc7f59b2011-09-16 00:41:11 +0000971 if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
cristy3ed852e2009-09-05 21:47:34 +0000972 (delegate_info->encode != (char *) NULL)) ||
973 ((encode != (const char *) NULL) &&
974 (delegate_info->decode != (char *) NULL))))
975 {
976 char
977 *magick;
978
979 ImageInfo
980 *clone_info;
981
982 register Image
983 *p;
984
985 /*
986 Delegate requires a particular image format.
987 */
anthony59c44432012-05-23 04:41:25 +0000988 if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
cristy3ed852e2009-09-05 21:47:34 +0000989 {
990 ThrowFileException(exception,FileOpenError,
991 "UnableToCreateTemporaryFile",image_info->unique);
992 return(MagickFalse);
993 }
anthony59c44432012-05-23 04:41:25 +0000994 if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
cristy3ed852e2009-09-05 21:47:34 +0000995 {
anthony2ec9bd92012-05-20 05:43:24 +0000996 (void) RelinquishUniqueFileResource(image_info->unique);
cristy3ed852e2009-09-05 21:47:34 +0000997 ThrowFileException(exception,FileOpenError,
998 "UnableToCreateTemporaryFile",image_info->zero);
999 return(MagickFalse);
1000 }
1001 magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
cristy018f07f2011-09-04 21:15:19 +00001002 delegate_info->encode : delegate_info->decode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001003 if (magick == (char *) NULL)
1004 {
1005 (void) RelinquishUniqueFileResource(image_info->unique);
1006 (void) RelinquishUniqueFileResource(image_info->zero);
anthony59c44432012-05-23 04:41:25 +00001007 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +00001008 (void) RelinquishUniqueFileResource(image->filename);
1009 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001010 DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
cristy3ed852e2009-09-05 21:47:34 +00001011 return(MagickFalse);
1012 }
1013 LocaleUpper(magick);
1014 clone_info=CloneImageInfo(image_info);
1015 (void) CopyMagickString((char *) clone_info->magick,magick,
1016 MaxTextExtent);
1017 if (LocaleCompare(magick,"NULL") != 0)
1018 (void) CopyMagickString(image->magick,magick,MaxTextExtent);
1019 magick=DestroyString(magick);
cristyb51dff52011-05-19 16:55:47 +00001020 (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
cristy3ed852e2009-09-05 21:47:34 +00001021 delegate_info->decode);
cristyd965a422010-03-03 17:47:35 +00001022 (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
1023 exception);
cristy3ed852e2009-09-05 21:47:34 +00001024 (void) CopyMagickString(clone_info->filename,image_info->filename,
1025 MaxTextExtent);
1026 (void) CopyMagickString(image_info->filename,image->filename,
1027 MaxTextExtent);
1028 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1029 {
cristyb51dff52011-05-19 16:55:47 +00001030 (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
cristy3ed852e2009-09-05 21:47:34 +00001031 delegate_info->decode,clone_info->filename);
cristy6f9e0d32011-08-28 16:32:09 +00001032 status=WriteImage(clone_info,p,exception);
anthony59c44432012-05-23 04:41:25 +00001033 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00001034 {
1035 (void) RelinquishUniqueFileResource(image_info->unique);
1036 (void) RelinquishUniqueFileResource(image_info->zero);
anthony59c44432012-05-23 04:41:25 +00001037 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +00001038 (void) RelinquishUniqueFileResource(image->filename);
1039 clone_info=DestroyImageInfo(clone_info);
1040 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001041 DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
cristy3ed852e2009-09-05 21:47:34 +00001042 return(MagickFalse);
1043 }
anthony59c44432012-05-23 04:41:25 +00001044 if( IfMagickTrue(clone_info->adjoin) )
cristy3ed852e2009-09-05 21:47:34 +00001045 break;
1046 }
1047 (void) RelinquishUniqueFileResource(image_info->unique);
1048 (void) RelinquishUniqueFileResource(image_info->zero);
1049 clone_info=DestroyImageInfo(clone_info);
1050 }
1051 /*
1052 Invoke delegate.
1053 */
1054 commands=StringToList(delegate_info->commands);
1055 if (commands == (char **) NULL)
1056 {
anthony59c44432012-05-23 04:41:25 +00001057 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +00001058 (void) RelinquishUniqueFileResource(image->filename);
1059 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001060 ResourceLimitError,"MemoryAllocationFailed","`%s'",
cristy3ed852e2009-09-05 21:47:34 +00001061 decode ? decode : encode);
1062 return(MagickFalse);
1063 }
1064 command=(char *) NULL;
1065 status=MagickFalse;
1066 (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
1067 (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
1068 for (i=0; commands[i] != (char *) NULL; i++)
1069 {
1070 status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
anthony59c44432012-05-23 04:41:25 +00001071 if( IfMagickFalse(AcquireUniqueFilename(image_info->unique)) )
cristy3ed852e2009-09-05 21:47:34 +00001072 {
1073 ThrowFileException(exception,FileOpenError,
1074 "UnableToCreateTemporaryFile",image_info->unique);
1075 break;
1076 }
anthony59c44432012-05-23 04:41:25 +00001077 if( IfMagickFalse(AcquireUniqueFilename(image_info->zero)) )
cristy3ed852e2009-09-05 21:47:34 +00001078 {
1079 (void) RelinquishUniqueFileResource(image_info->unique);
1080 ThrowFileException(exception,FileOpenError,
1081 "UnableToCreateTemporaryFile",image_info->zero);
1082 break;
1083 }
1084 if (LocaleCompare(decode,"SCAN") != 0)
1085 {
1086 status=AcquireUniqueSymbolicLink(input_filename,image->filename);
anthony59c44432012-05-23 04:41:25 +00001087 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00001088 {
1089 ThrowFileException(exception,FileOpenError,
1090 "UnableToCreateTemporaryFile",input_filename);
1091 break;
1092 }
1093 }
1094 status=MagickFalse;
cristy018f07f2011-09-04 21:15:19 +00001095 command=InterpretImageProperties(image_info,image,commands[i],exception);
cristy3ed852e2009-09-05 21:47:34 +00001096 if (command != (char *) NULL)
1097 {
1098 /*
1099 Execute delegate.
1100 */
anthony59c44432012-05-23 04:41:25 +00001101 status=IsMagickTrue(SystemCommand(delegate_info->spawn,
cristy77f69392012-05-26 01:15:25 +00001102 image_info->verbose,command,exception) != 0);
1103 if (IfMagickTrue(delegate_info->spawn))
1104 {
1105 ssize_t
1106 count;
1107
1108 /*
cristy47ef5e92013-03-20 23:29:45 +00001109 Wait for input file to 'disappear', or maximum 10 seconds.
cristy77f69392012-05-26 01:15:25 +00001110 */
cristy47ef5e92013-03-20 23:29:45 +00001111 count=100;
cristy3fe49df2012-05-26 01:17:56 +00001112 while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0))
cristy58399382012-05-26 12:44:41 +00001113 (void) MagickDelay(100); /* sleep 0.1 seconds */
anthony2ec9bd92012-05-20 05:43:24 +00001114 }
cristy3ed852e2009-09-05 21:47:34 +00001115 command=DestroyString(command);
1116 }
1117 if (LocaleCompare(decode,"SCAN") != 0)
1118 {
anthony59c44432012-05-23 04:41:25 +00001119 if( IfMagickFalse(CopyDelegateFile(image->filename,input_filename)) )
cristy3ed852e2009-09-05 21:47:34 +00001120 (void) RelinquishUniqueFileResource(input_filename);
1121 }
anthony59c44432012-05-23 04:41:25 +00001122 if( IfMagickFalse(CopyDelegateFile(image_info->filename,output_filename)) )
cristy3ed852e2009-09-05 21:47:34 +00001123 (void) RelinquishUniqueFileResource(output_filename);
anthony59c44432012-05-23 04:41:25 +00001124 if( IfMagickTrue(image_info->temporary) )
cristy3ed852e2009-09-05 21:47:34 +00001125 (void) RelinquishUniqueFileResource(image_info->filename);
1126 (void) RelinquishUniqueFileResource(image_info->unique);
1127 (void) RelinquishUniqueFileResource(image_info->zero);
1128 (void) RelinquishUniqueFileResource(image_info->filename);
1129 (void) RelinquishUniqueFileResource(image->filename);
anthony59c44432012-05-23 04:41:25 +00001130 if( IfMagickTrue(status) )
cristy3ed852e2009-09-05 21:47:34 +00001131 {
1132 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
cristyefe601c2013-01-05 17:51:12 +00001133 "DelegateFailed","`%s'",commands[i]);
cristy3ed852e2009-09-05 21:47:34 +00001134 break;
1135 }
1136 commands[i]=DestroyString(commands[i]);
1137 }
1138 (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1139 (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1140 /*
1141 Relinquish resources.
1142 */
1143 for ( ; commands[i] != (char *) NULL; i++)
1144 commands[i]=DestroyString(commands[i]);
1145 commands=(char **) RelinquishMagickMemory(commands);
anthony59c44432012-05-23 04:41:25 +00001146 if( IfMagickTrue(temporary) )
cristy3ed852e2009-09-05 21:47:34 +00001147 (void) RelinquishUniqueFileResource(image->filename);
anthony59c44432012-05-23 04:41:25 +00001148 return(IsMagickFalse(status));
cristy3ed852e2009-09-05 21:47:34 +00001149}
1150
1151/*
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153% %
1154% %
1155% %
1156% L i s t D e l e g a t e I n f o %
1157% %
1158% %
1159% %
1160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161%
1162% ListDelegateInfo() lists the image formats to a file.
1163%
1164% The format of the ListDelegateInfo method is:
1165%
1166% MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1167%
1168% A description of each parameter follows.
1169%
1170% o file: An pointer to a FILE.
1171%
1172% o exception: return any errors or warnings in this structure.
1173%
1174*/
1175MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1176 ExceptionInfo *exception)
1177{
1178 const DelegateInfo
1179 **delegate_info;
1180
1181 char
1182 **commands,
1183 delegate[MaxTextExtent];
1184
1185 const char
1186 *path;
1187
cristybb503372010-05-27 20:51:26 +00001188 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001189 i;
1190
cristybb503372010-05-27 20:51:26 +00001191 size_t
cristy3ed852e2009-09-05 21:47:34 +00001192 number_delegates;
1193
cristy9d314ff2011-03-09 01:30:28 +00001194 ssize_t
1195 j;
1196
cristy3ed852e2009-09-05 21:47:34 +00001197 if (file == (const FILE *) NULL)
1198 file=stdout;
1199 delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1200 if (delegate_info == (const DelegateInfo **) NULL)
1201 return(MagickFalse);
1202 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +00001203 for (i=0; i < (ssize_t) number_delegates; i++)
cristy3ed852e2009-09-05 21:47:34 +00001204 {
anthony59c44432012-05-23 04:41:25 +00001205 if( IfMagickTrue(delegate_info[i]->stealth) )
cristy3ed852e2009-09-05 21:47:34 +00001206 continue;
1207 if ((path == (const char *) NULL) ||
1208 (LocaleCompare(path,delegate_info[i]->path) != 0))
1209 {
1210 if (delegate_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +00001211 (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1212 (void) FormatLocaleFile(file,"Delegate Command\n");
cristy1e604812011-05-19 18:07:50 +00001213 (void) FormatLocaleFile(file,
1214 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +00001215 "------------------------------\n");
1216 }
1217 path=delegate_info[i]->path;
1218 *delegate='\0';
1219 if (delegate_info[i]->encode != (char *) NULL)
1220 (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
1221 (void) ConcatenateMagickString(delegate," ",MaxTextExtent);
1222 delegate[8]='\0';
1223 commands=StringToList(delegate_info[i]->commands);
1224 if (commands == (char **) NULL)
1225 continue;
cristyb51dff52011-05-19 16:55:47 +00001226 (void) FormatLocaleFile(file,"%11s%c=%c%s ",delegate_info[i]->decode ?
cristy3ed852e2009-09-05 21:47:34 +00001227 delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1228 delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1229 StripString(commands[0]);
cristyb51dff52011-05-19 16:55:47 +00001230 (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
cristy3ed852e2009-09-05 21:47:34 +00001231 for (j=1; commands[j] != (char *) NULL; j++)
1232 {
1233 StripString(commands[j]);
cristyb51dff52011-05-19 16:55:47 +00001234 (void) FormatLocaleFile(file," \"%s\"\n",commands[j]);
cristy3ed852e2009-09-05 21:47:34 +00001235 }
1236 for (j=0; commands[j] != (char *) NULL; j++)
1237 commands[j]=DestroyString(commands[j]);
1238 commands=(char **) RelinquishMagickMemory(commands);
1239 }
1240 (void) fflush(file);
1241 delegate_info=(const DelegateInfo **)
1242 RelinquishMagickMemory((void *) delegate_info);
1243 return(MagickTrue);
1244}
1245
1246/*
1247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248% %
1249% %
1250% %
1251+ L o a d D e l e g a t e L i s t %
1252% %
1253% %
1254% %
1255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256%
cristy86e5ac92014-03-16 19:27:39 +00001257% LoadDelegateCache() loads the delegate configurations which provides a
cristy3ed852e2009-09-05 21:47:34 +00001258% mapping between delegate attributes and a delegate name.
1259%
cristy86e5ac92014-03-16 19:27:39 +00001260% The format of the LoadDelegateCache method is:
cristy3ed852e2009-09-05 21:47:34 +00001261%
cristycd2cd182014-03-18 12:10:55 +00001262% MagickBooleanType LoadDelegateCache(LinkedListInfo *delegate_cache,
1263% const char *xml,const char *filename,const size_t depth,
1264% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001265%
1266% A description of each parameter follows:
1267%
1268% o xml: The delegate list in XML format.
1269%
1270% o filename: The delegate list filename.
1271%
1272% o depth: depth of <include /> statements.
1273%
1274% o exception: return any errors or warnings in this structure.
1275%
1276*/
cristycd2cd182014-03-18 12:10:55 +00001277static MagickBooleanType LoadDelegateCache(LinkedListInfo *delegate_cache,
1278 const char *xml,const char *filename,const size_t depth,
1279 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001280{
1281 char
1282 keyword[MaxTextExtent],
1283 *token;
1284
1285 const char
1286 *q;
1287
1288 DelegateInfo
1289 *delegate_info;
1290
1291 MagickBooleanType
1292 status;
1293
1294 /*
1295 Load the delegate map file.
1296 */
1297 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1298 "Loading delegate configuration file \"%s\" ...",filename);
1299 if (xml == (const char *) NULL)
1300 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001301 status=MagickTrue;
1302 delegate_info=(DelegateInfo *) NULL;
1303 token=AcquireString(xml);
1304 for (q=(const char *) xml; *q != '\0'; )
1305 {
1306 /*
1307 Interpret XML.
1308 */
1309 GetMagickToken(q,&q,token);
1310 if (*token == '\0')
1311 break;
1312 (void) CopyMagickString(keyword,token,MaxTextExtent);
1313 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1314 {
1315 /*
1316 Doctype element.
1317 */
1318 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1319 GetMagickToken(q,&q,token);
1320 continue;
1321 }
1322 if (LocaleNCompare(keyword,"<!--",4) == 0)
1323 {
1324 /*
1325 Comment element.
1326 */
1327 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1328 GetMagickToken(q,&q,token);
1329 continue;
1330 }
1331 if (LocaleCompare(keyword,"<include") == 0)
1332 {
1333 /*
1334 Include element.
1335 */
1336 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1337 {
1338 (void) CopyMagickString(keyword,token,MaxTextExtent);
1339 GetMagickToken(q,&q,token);
1340 if (*token != '=')
1341 continue;
1342 GetMagickToken(q,&q,token);
1343 if (LocaleCompare(keyword,"file") == 0)
1344 {
1345 if (depth > 200)
1346 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001347 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
cristy3ed852e2009-09-05 21:47:34 +00001348 else
1349 {
1350 char
1351 path[MaxTextExtent],
1352 *xml;
1353
1354 GetPathComponent(filename,HeadPath,path);
1355 if (*path != '\0')
1356 (void) ConcatenateMagickString(path,DirectorySeparator,
1357 MaxTextExtent);
1358 if (*token == *DirectorySeparator)
1359 (void) CopyMagickString(path,token,MaxTextExtent);
1360 else
1361 (void) ConcatenateMagickString(path,token,MaxTextExtent);
cristy3291f512014-03-16 22:16:22 +00001362 xml=FileToXML(path,~0UL);
cristy3ed852e2009-09-05 21:47:34 +00001363 if (xml != (char *) NULL)
1364 {
cristycd2cd182014-03-18 12:10:55 +00001365 status&=LoadDelegateCache(delegate_cache,xml,path,
1366 depth+1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001367 xml=(char *) RelinquishMagickMemory(xml);
1368 }
1369 }
1370 }
1371 }
1372 continue;
1373 }
1374 if (LocaleCompare(keyword,"<delegate") == 0)
1375 {
1376 /*
1377 Delegate element.
1378 */
1379 delegate_info=(DelegateInfo *) AcquireMagickMemory(
1380 sizeof(*delegate_info));
1381 if (delegate_info == (DelegateInfo *) NULL)
1382 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1383 (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
1384 delegate_info->path=ConstantString(filename);
1385 delegate_info->signature=MagickSignature;
1386 continue;
1387 }
1388 if (delegate_info == (DelegateInfo *) NULL)
1389 continue;
1390 if (LocaleCompare(keyword,"/>") == 0)
1391 {
cristy86e5ac92014-03-16 19:27:39 +00001392 status=AppendValueToLinkedList(delegate_cache,delegate_info);
anthony59c44432012-05-23 04:41:25 +00001393 if( IfMagickFalse(status) )
cristy3ed852e2009-09-05 21:47:34 +00001394 (void) ThrowMagickException(exception,GetMagickModule(),
cristyefe601c2013-01-05 17:51:12 +00001395 ResourceLimitError,"MemoryAllocationFailed","`%s'",
cristy3ed852e2009-09-05 21:47:34 +00001396 delegate_info->commands);
1397 delegate_info=(DelegateInfo *) NULL;
cristyd45122f2014-01-14 23:46:16 +00001398 continue;
cristy3ed852e2009-09-05 21:47:34 +00001399 }
1400 GetMagickToken(q,(const char **) NULL,token);
1401 if (*token != '=')
1402 continue;
1403 GetMagickToken(q,&q,token);
1404 GetMagickToken(q,&q,token);
1405 switch (*keyword)
1406 {
1407 case 'C':
1408 case 'c':
1409 {
1410 if (LocaleCompare((char *) keyword,"command") == 0)
1411 {
1412 char
1413 *commands;
1414
1415 commands=AcquireString(token);
cristy0157aea2010-04-24 21:12:18 +00001416#if defined(MAGICKCORE_WINDOWS_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +00001417 if (strchr(commands,'@') != (char *) NULL)
1418 {
1419 char
1420 path[MaxTextExtent];
1421
1422 NTGhostscriptEXE(path,MaxTextExtent);
1423 (void) SubstituteString((char **) &commands,"@PSDelegate@",
1424 path);
1425 (void) SubstituteString((char **) &commands,"\\","/");
1426 }
1427#endif
1428 (void) SubstituteString((char **) &commands,"&amp;","&");
1429 (void) SubstituteString((char **) &commands,"&quot;","\"");
1430 (void) SubstituteString((char **) &commands,"&gt;",">");
1431 (void) SubstituteString((char **) &commands,"&lt;","<");
1432 delegate_info->commands=commands;
1433 break;
1434 }
1435 break;
1436 }
1437 case 'D':
1438 case 'd':
1439 {
1440 if (LocaleCompare((char *) keyword,"decode") == 0)
1441 {
1442 delegate_info->decode=ConstantString(token);
1443 delegate_info->mode=1;
1444 break;
1445 }
1446 break;
1447 }
1448 case 'E':
1449 case 'e':
1450 {
1451 if (LocaleCompare((char *) keyword,"encode") == 0)
1452 {
1453 delegate_info->encode=ConstantString(token);
1454 delegate_info->mode=(-1);
1455 break;
1456 }
1457 break;
1458 }
1459 case 'M':
1460 case 'm':
1461 {
1462 if (LocaleCompare((char *) keyword,"mode") == 0)
1463 {
1464 delegate_info->mode=1;
1465 if (LocaleCompare(token,"bi") == 0)
1466 delegate_info->mode=0;
1467 else
1468 if (LocaleCompare(token,"encode") == 0)
1469 delegate_info->mode=(-1);
1470 break;
1471 }
1472 break;
1473 }
1474 case 'S':
1475 case 's':
1476 {
1477 if (LocaleCompare((char *) keyword,"spawn") == 0)
1478 {
anthony6f201312012-03-30 04:08:15 +00001479 delegate_info->spawn=IsStringTrue(token);
cristy3ed852e2009-09-05 21:47:34 +00001480 break;
1481 }
1482 if (LocaleCompare((char *) keyword,"stealth") == 0)
1483 {
anthony6f201312012-03-30 04:08:15 +00001484 delegate_info->stealth=IsStringTrue(token);
cristy3ed852e2009-09-05 21:47:34 +00001485 break;
1486 }
1487 break;
1488 }
1489 case 'T':
1490 case 't':
1491 {
1492 if (LocaleCompare((char *) keyword,"thread-support") == 0)
1493 {
anthony6f201312012-03-30 04:08:15 +00001494 delegate_info->thread_support=IsStringTrue(token);
cristy191ba5c2014-03-16 21:26:40 +00001495 if (delegate_info->thread_support != MagickFalse)
1496 delegate_info->semaphore=AcquireSemaphoreInfo();
cristy3ed852e2009-09-05 21:47:34 +00001497 break;
1498 }
1499 break;
1500 }
1501 default:
1502 break;
1503 }
1504 }
1505 token=(char *) RelinquishMagickMemory(token);
1506 return(status);
1507}