source: ImageMagick/trunk/MagickCore/delegate.c @ 6967

Revision 6967, 58.7 KB checked in by cristy, 16 months ago (diff)
Line 
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%                               John Cristy                                   %
16%                               October 1998                                  %
17%                                                                             %
18%                                                                             %
19%  Copyright 1999-2012 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%    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*/
48#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"
55#include "MagickCore/delegate-private.h"
56#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"
61#include "MagickCore/policy.h"
62#include "MagickCore/resource_.h"
63#include "MagickCore/semaphore.h"
64#include "MagickCore/string_.h"
65#include "MagickCore/token.h"
66#include "MagickCore/utility.h"
67#include "MagickCore/utility-private.h"
68#include "MagickCore/xml-tree.h"
69
70/*
71  Define declarations.
72*/
73#define DelegateFilename  "delegates.xml"
74
75/*
76  Declare delegate map.
77*/
78static const char
79  *DelegateMap = (const char *)
80    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
81    "<delegatemap>"
82    "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
83    "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
84    "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/\"/>"
85    "  <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;\"/>"
86    "  <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;\"/>"
87    "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
88    "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
89    "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
90    "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
91    "  <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;\"/>"
92    "  <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;\"/>"
93    "  <delegate decode=\"hpgl\" command=\"if [ -e hp2xx -o -e /usr/bin/hp2xx ]; then     hp2xx -q -m eps -f `basename &quot;%o&quot;` &quot;%i&quot;     mv -f `basename &quot;%o&quot;` &quot;%o   else     echo &quot;You need to install hp2xx to use HPGL files with ImageMagick.&quot;     exit 1   fi\"/>"
94    "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
95    "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
96    "  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
97    "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
98    "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
99    "  <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; -i &quot;%i&quot; -vcodec pam -an -f rawvideo -y &quot;%u0.pam&quot; 2;&gt; &quot;%Z&quot;\"/>"
100    "  <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\"&quot;ffmpeg&quot; &quot;%M%%d.jpg&quot; &quot;%u.%m&quot; 2;&gt; &quot;%Z&quot;\"/>"
101    "  <delegate decode=\"pcl:color\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=ppmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
102    "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=bmpsep8&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
103    "  <delegate decode=\"pcl:mono\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pbmraw&quot; -dTextAlphaBits=%u -dGraphicsAlphaBits=%u &quot;-r%s&quot; %s &quot;-sOutputFile=%s&quot; &quot;%s&quot;\"/>"
104    "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
105    "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
106    "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
107    "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
108    "  <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;\"/>"
109    "  <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
110    "  <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
111    "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
112    "  <delegate decode=\"ps:alpha\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &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;\"/>"
113    "  <delegate decode=\"ps:bbox\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &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;\"/>"
114    "  <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &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;\"/>"
115    "  <delegate decode=\"ps:color\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &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;\"/>"
116    "  <delegate decode=\"ps:mono\" stealth=\"True\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &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;\"/>"
117    "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
118    "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
119    "  <delegate encode=\"show\" spawn=\"True\" command=\"&quot;/usr/local/bin/display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
120    "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
121    "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
122    "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
123    "  <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\"&quot;/usr/local/bin/display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;temporary:%i&quot;\"/>"
124    "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
125    "</delegatemap>";
126
127/*
128  Global declaractions.
129*/
130static LinkedListInfo
131  *delegate_list = (LinkedListInfo *) NULL;
132
133static SemaphoreInfo
134  *delegate_semaphore = (SemaphoreInfo *) NULL;
135
136static volatile MagickBooleanType
137  instantiate_delegate = MagickFalse;
138
139/*
140  Forward declaractions.
141*/
142static MagickBooleanType
143  InitializeDelegateList(ExceptionInfo *),
144  LoadDelegateLists(const char *,ExceptionInfo *);
145
146/*
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148%                                                                             %
149%                                                                             %
150%                                                                             %
151+   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                         %
152%                                                                             %
153%                                                                             %
154%                                                                             %
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156%
157%  DelegateComponentGenesis() instantiates the delegate component.
158%
159%  The format of the DelegateComponentGenesis method is:
160%
161%      MagickBooleanType DelegateComponentGenesis(void)
162%
163*/
164MagickPrivate MagickBooleanType DelegateComponentGenesis(void)
165{
166  AcquireSemaphoreInfo(&delegate_semaphore);
167  return(MagickTrue);
168}
169
170/*
171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172%                                                                             %
173%                                                                             %
174%                                                                             %
175%   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                         %
176%                                                                             %
177%                                                                             %
178%                                                                             %
179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180%
181%  DelegateComponentTerminus() destroys the delegate component.
182%
183%  The format of the DelegateComponentTerminus method is:
184%
185%      DelegateComponentTerminus(void)
186%
187*/
188
189static void *DestroyDelegate(void *delegate_info)
190{
191  register DelegateInfo
192    *p;
193
194  p=(DelegateInfo *) delegate_info;
195  if (p->path != (char *) NULL)
196    p->path=DestroyString(p->path);
197  if (p->decode != (char *) NULL)
198    p->decode=DestroyString(p->decode);
199  if (p->encode != (char *) NULL)
200    p->encode=DestroyString(p->encode);
201  if (p->commands != (char *) NULL)
202    p->commands=DestroyString(p->commands);
203  p=(DelegateInfo *) RelinquishMagickMemory(p);
204  return((void *) NULL);
205}
206
207MagickPrivate void DelegateComponentTerminus(void)
208{
209  if (delegate_semaphore == (SemaphoreInfo *) NULL)
210    AcquireSemaphoreInfo(&delegate_semaphore);
211  LockSemaphoreInfo(delegate_semaphore);
212  if (delegate_list != (LinkedListInfo *) NULL)
213    delegate_list=DestroyLinkedList(delegate_list,DestroyDelegate);
214  instantiate_delegate=MagickFalse;
215  UnlockSemaphoreInfo(delegate_semaphore);
216  DestroySemaphoreInfo(&delegate_semaphore);
217}
218
219/*
220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221%                                                                             %
222%                                                                             %
223%                                                                             %
224%   G e t D e l e g a t e C o m m a n d                                       %
225%                                                                             %
226%                                                                             %
227%                                                                             %
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229%
230%  GetDelegateCommand() replaces any embedded formatting characters with the
231%  appropriate image attribute and returns the resulting command.
232%
233%  The format of the GetDelegateCommand method is:
234%
235%      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
236%        const char *decode,const char *encode,ExceptionInfo *exception)
237%
238%  A description of each parameter follows:
239%
240%    o command: Method GetDelegateCommand returns the command associated
241%      with specified delegate tag.
242%
243%    o image_info: the image info.
244%
245%    o image: the image.
246%
247%    o decode: Specifies the decode delegate we are searching for as a
248%      character string.
249%
250%    o encode: Specifies the encode delegate we are searching for as a
251%      character string.
252%
253%    o exception: return any errors or warnings in this structure.
254%
255*/
256MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
257  const char *decode,const char *encode,ExceptionInfo *exception)
258{
259  char
260    *command,
261    **commands;
262
263  const DelegateInfo
264    *delegate_info;
265
266  register ssize_t
267    i;
268
269  assert(image_info != (ImageInfo *) NULL);
270  assert(image_info->signature == MagickSignature);
271  assert(image != (Image *) NULL);
272  assert(image->signature == MagickSignature);
273  if (image->debug != MagickFalse)
274    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
275  delegate_info=GetDelegateInfo(decode,encode,exception);
276  if (delegate_info == (const DelegateInfo *) NULL)
277    {
278      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
279        "NoTagFound","`%s'",decode ? decode : encode);
280      return((char *) NULL);
281    }
282  commands=StringToList(delegate_info->commands);
283  if (commands == (char **) NULL)
284    {
285      (void) ThrowMagickException(exception,GetMagickModule(),
286        ResourceLimitError,"MemoryAllocationFailed","`%s'",
287        decode ? decode : encode);
288      return((char *) NULL);
289    }
290  command=InterpretImageProperties(image_info,image,commands[0],exception);
291  if (command == (char *) NULL)
292    (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
293      "MemoryAllocationFailed","`%s'",commands[0]);
294  /*
295    Relinquish resources.
296  */
297  for (i=0; commands[i] != (char *) NULL; i++)
298    commands[i]=DestroyString(commands[i]);
299  commands=(char **) RelinquishMagickMemory(commands);
300  return(command);
301}
302
303/*
304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305%                                                                             %
306%                                                                             %
307%                                                                             %
308%   G e t D e l e g a t e C o m m a n d s                                     %
309%                                                                             %
310%                                                                             %
311%                                                                             %
312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313%
314%  GetDelegateCommands() returns the commands associated with a delegate.
315%
316%  The format of the GetDelegateCommands method is:
317%
318%      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
319%
320%  A description of each parameter follows:
321%
322%    o delegate_info:  The delegate info.
323%
324*/
325MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
326{
327  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
328  assert(delegate_info != (DelegateInfo *) NULL);
329  assert(delegate_info->signature == MagickSignature);
330  return(delegate_info->commands);
331}
332
333/*
334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335%                                                                             %
336%                                                                             %
337%                                                                             %
338%   G e t D e l e g a t e I n f o                                             %
339%                                                                             %
340%                                                                             %
341%                                                                             %
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343%
344%  GetDelegateInfo() returns any delegates associated with the specified tag.
345%
346%  The format of the GetDelegateInfo method is:
347%
348%      const DelegateInfo *GetDelegateInfo(const char *decode,
349%        const char *encode,ExceptionInfo *exception)
350%
351%  A description of each parameter follows:
352%
353%    o decode: Specifies the decode delegate we are searching for as a
354%      character string.
355%
356%    o encode: Specifies the encode delegate we are searching for as a
357%      character string.
358%
359%    o exception: return any errors or warnings in this structure.
360%
361*/
362MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
363  const char *encode,ExceptionInfo *exception)
364{
365  register const DelegateInfo
366    *p;
367
368  assert(exception != (ExceptionInfo *) NULL);
369  if ((delegate_list == (LinkedListInfo *) NULL) ||
370      (instantiate_delegate == MagickFalse))
371    if (InitializeDelegateList(exception) == MagickFalse)
372      return((const DelegateInfo *) NULL);
373  if ((delegate_list == (LinkedListInfo *) NULL) ||
374      (IsLinkedListEmpty(delegate_list) != MagickFalse))
375    return((const DelegateInfo *) NULL);
376  if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
377    return((const DelegateInfo *) GetValueFromLinkedList(delegate_list,0));
378  /*
379    Search for named delegate.
380  */
381  LockSemaphoreInfo(delegate_semaphore);
382  ResetLinkedListIterator(delegate_list);
383  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
384  while (p != (const DelegateInfo *) NULL)
385  {
386    if (p->mode > 0)
387      {
388        if (LocaleCompare(p->decode,decode) == 0)
389          break;
390        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
391        continue;
392      }
393    if (p->mode < 0)
394      {
395        if (LocaleCompare(p->encode,encode) == 0)
396          break;
397        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
398        continue;
399      }
400    if (LocaleCompare(decode,p->decode) == 0)
401      if (LocaleCompare(encode,p->encode) == 0)
402        break;
403    if (LocaleCompare(decode,"*") == 0)
404      if (LocaleCompare(encode,p->encode) == 0)
405        break;
406    if (LocaleCompare(decode,p->decode) == 0)
407      if (LocaleCompare(encode,"*") == 0)
408        break;
409    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
410  }
411  if (p != (const DelegateInfo *) NULL)
412    (void) InsertValueInLinkedList(delegate_list,0,
413      RemoveElementByValueFromLinkedList(delegate_list,p));
414  UnlockSemaphoreInfo(delegate_semaphore);
415  return(p);
416}
417
418/*
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420%                                                                             %
421%                                                                             %
422%                                                                             %
423%   G e t D e l e g a t e I n f o L i s t                                     %
424%                                                                             %
425%                                                                             %
426%                                                                             %
427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428%
429%  GetDelegateInfoList() returns any delegates that match the specified pattern.
430%
431%  The delegate of the GetDelegateInfoList function is:
432%
433%      const DelegateInfo **GetDelegateInfoList(const char *pattern,
434%        size_t *number_delegates,ExceptionInfo *exception)
435%
436%  A description of each parameter follows:
437%
438%    o pattern: Specifies a pointer to a text string containing a pattern.
439%
440%    o number_delegates:  This integer returns the number of delegates in the
441%      list.
442%
443%    o exception: return any errors or warnings in this structure.
444%
445*/
446
447#if defined(__cplusplus) || defined(c_plusplus)
448extern "C" {
449#endif
450
451static int DelegateInfoCompare(const void *x,const void *y)
452{
453  const DelegateInfo
454    **p,
455    **q;
456
457  p=(const DelegateInfo **) x,
458  q=(const DelegateInfo **) y;
459  if (LocaleCompare((*p)->path,(*q)->path) == 0)
460    {
461      if ((*p)->decode == (char *) NULL)
462        if (((*p)->encode != (char *) NULL) &&
463            ((*q)->encode != (char *) NULL))
464          return(strcmp((*p)->encode,(*q)->encode));
465      if (((*p)->decode != (char *) NULL) &&
466          ((*q)->decode != (char *) NULL))
467        return(strcmp((*p)->decode,(*q)->decode));
468    }
469  return(LocaleCompare((*p)->path,(*q)->path));
470}
471
472#if defined(__cplusplus) || defined(c_plusplus)
473}
474#endif
475
476MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
477  size_t *number_delegates,ExceptionInfo *exception)
478{
479  const DelegateInfo
480    **delegates;
481
482  register const DelegateInfo
483    *p;
484
485  register ssize_t
486    i;
487
488  /*
489    Allocate delegate list.
490  */
491  assert(pattern != (char *) NULL);
492  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
493  assert(number_delegates != (size_t *) NULL);
494  *number_delegates=0;
495  p=GetDelegateInfo("*","*",exception);
496  if (p == (const DelegateInfo *) NULL)
497    return((const DelegateInfo **) NULL);
498  delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
499    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
500  if (delegates == (const DelegateInfo **) NULL)
501    return((const DelegateInfo **) NULL);
502  /*
503    Generate delegate list.
504  */
505  LockSemaphoreInfo(delegate_semaphore);
506  ResetLinkedListIterator(delegate_list);
507  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
508  for (i=0; p != (const DelegateInfo *) NULL; )
509  {
510    if ((p->stealth == MagickFalse) &&
511        ((GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse) ||
512         (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse)))
513      delegates[i++]=p;
514    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
515  }
516  UnlockSemaphoreInfo(delegate_semaphore);
517  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
518  delegates[i]=(DelegateInfo *) NULL;
519  *number_delegates=(size_t) i;
520  return(delegates);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525%                                                                             %
526%                                                                             %
527%                                                                             %
528%   G e t D e l e g a t e L i s t                                             %
529%                                                                             %
530%                                                                             %
531%                                                                             %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533%
534%  GetDelegateList() returns any image format delegates that match the
535%  specified  pattern.
536%
537%  The format of the GetDelegateList function is:
538%
539%      char **GetDelegateList(const char *pattern,
540%        size_t *number_delegates,ExceptionInfo *exception)
541%
542%  A description of each parameter follows:
543%
544%    o pattern: Specifies a pointer to a text string containing a pattern.
545%
546%    o number_delegates:  This integer returns the number of delegates
547%      in the list.
548%
549%    o exception: return any errors or warnings in this structure.
550%
551*/
552
553#if defined(__cplusplus) || defined(c_plusplus)
554extern "C" {
555#endif
556
557static int DelegateCompare(const void *x,const void *y)
558{
559  register const char
560    **p,
561    **q;
562
563  p=(const char **) x;
564  q=(const char **) y;
565  return(LocaleCompare(*p,*q));
566}
567
568#if defined(__cplusplus) || defined(c_plusplus)
569}
570#endif
571
572MagickExport char **GetDelegateList(const char *pattern,
573  size_t *number_delegates,ExceptionInfo *exception)
574{
575  char
576    **delegates;
577
578  register const DelegateInfo
579    *p;
580
581  register ssize_t
582    i;
583
584  /*
585    Allocate delegate list.
586  */
587  assert(pattern != (char *) NULL);
588  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
589  assert(number_delegates != (size_t *) NULL);
590  *number_delegates=0;
591  p=GetDelegateInfo("*","*",exception);
592  if (p == (const DelegateInfo *) NULL)
593    return((char **) NULL);
594  delegates=(char **) AcquireQuantumMemory((size_t)
595    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
596  if (delegates == (char **) NULL)
597    return((char **) NULL);
598  LockSemaphoreInfo(delegate_semaphore);
599  ResetLinkedListIterator(delegate_list);
600  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
601  for (i=0; p != (const DelegateInfo *) NULL; )
602  {
603    if ((p->stealth == MagickFalse) &&
604        (GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse))
605      delegates[i++]=ConstantString(p->decode);
606    if ((p->stealth == MagickFalse) &&
607        (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse))
608      delegates[i++]=ConstantString(p->encode);
609    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
610  }
611  UnlockSemaphoreInfo(delegate_semaphore);
612  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
613  delegates[i]=(char *) NULL;
614  *number_delegates=(size_t) i;
615  return(delegates);
616}
617
618/*
619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620%                                                                             %
621%                                                                             %
622%                                                                             %
623%   G e t D e l e g a t e M o d e                                             %
624%                                                                             %
625%                                                                             %
626%                                                                             %
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628%
629%  GetDelegateMode() returns the mode of the delegate.
630%
631%  The format of the GetDelegateMode method is:
632%
633%      ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
634%
635%  A description of each parameter follows:
636%
637%    o delegate_info:  The delegate info.
638%
639*/
640MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info)
641{
642  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
643  assert(delegate_info != (DelegateInfo *) NULL);
644  assert(delegate_info->signature == MagickSignature);
645  return(delegate_info->mode);
646}
647
648/*
649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650%                                                                             %
651%                                                                             %
652%                                                                             %
653+   G e t D e l e g a t e T h r e a d S u p p o r t                           %
654%                                                                             %
655%                                                                             %
656%                                                                             %
657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658%
659%  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
660%  threads.
661%
662%  The format of the GetDelegateThreadSupport method is:
663%
664%      MagickBooleanType GetDelegateThreadSupport(
665%        const DelegateInfo *delegate_info)
666%
667%  A description of each parameter follows:
668%
669%    o delegate_info:  The delegate info.
670%
671*/
672MagickExport MagickBooleanType GetDelegateThreadSupport(
673  const DelegateInfo *delegate_info)
674{
675  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
676  assert(delegate_info != (DelegateInfo *) NULL);
677  assert(delegate_info->signature == MagickSignature);
678  return(delegate_info->thread_support);
679}
680
681/*
682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683%                                                                             %
684%                                                                             %
685%                                                                             %
686+   I n i t i a l i z e D e l e g a t e L i s t                               %
687%                                                                             %
688%                                                                             %
689%                                                                             %
690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691%
692%  InitializeDelegateList() initializes the delegate list.
693%
694%  The format of the InitializeDelegateList method is:
695%
696%      MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
697%
698%  A description of each parameter follows.
699%
700%    o exception: return any errors or warnings in this structure.
701%
702*/
703static MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
704{
705  if ((delegate_list == (LinkedListInfo *) NULL) &&
706      (instantiate_delegate == MagickFalse))
707    {
708      if (delegate_semaphore == (SemaphoreInfo *) NULL)
709        AcquireSemaphoreInfo(&delegate_semaphore);
710      LockSemaphoreInfo(delegate_semaphore);
711      if ((delegate_list == (LinkedListInfo *) NULL) &&
712          (instantiate_delegate == MagickFalse))
713        {
714          (void) LoadDelegateLists(DelegateFilename,exception);
715          instantiate_delegate=MagickTrue;
716        }
717      UnlockSemaphoreInfo(delegate_semaphore);
718    }
719  return(delegate_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
720}
721
722/*
723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724%                                                                             %
725%                                                                             %
726%                                                                             %
727%   I n v o k e D e l e g a t e                                               %
728%                                                                             %
729%                                                                             %
730%                                                                             %
731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732%
733%  InvokeDelegate replaces any embedded formatting characters with the
734%  appropriate image attribute and executes the resulting command.  MagickFalse
735%  is returned if the commands execute with success otherwise MagickTrue.
736%
737%  The format of the InvokeDelegate method is:
738%
739%      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
740%        const char *decode,const char *encode,ExceptionInfo *exception)
741%
742%  A description of each parameter follows:
743%
744%    o image_info: the imageInfo.
745%
746%    o image: the image.
747%
748%    o exception: return any errors or warnings in this structure.
749%
750*/
751
752static inline size_t MagickMin(const size_t x,const size_t y)
753{
754  if (x < y)
755    return(x);
756  return(y);
757}
758
759static MagickBooleanType CopyDelegateFile(const char *source,
760  const char *destination)
761{
762  int
763    destination_file,
764    source_file;
765
766  register size_t
767    i;
768
769  size_t
770    length,
771    quantum;
772
773  ssize_t
774    count;
775
776  struct stat
777    attributes;
778
779  unsigned char
780    *buffer;
781
782  /*
783    Copy source file to destination.
784  */
785  assert(source != (const char *) NULL);
786  assert(destination != (char *) NULL);
787  destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
788  if (destination_file == -1)
789    return(MagickFalse);
790  source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
791  if (source_file == -1)
792    {
793      (void) close(destination_file);
794      return(MagickFalse);
795    }
796  quantum=(size_t) MagickMaxBufferExtent;
797  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
798    quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
799  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
800  if (buffer == (unsigned char *) NULL)
801    {
802      (void) close(source_file);
803      (void) close(destination_file);
804      return(MagickFalse);
805    }
806  length=0;
807  for (i=0; ; i+=count)
808  {
809    count=(ssize_t) read(source_file,buffer,quantum);
810    if (count <= 0)
811      break;
812    length=(size_t) count;
813    count=(ssize_t) write(destination_file,buffer,length);
814    if ((size_t) count != length)
815      break;
816  }
817  (void) close(destination_file);
818  (void) close(source_file);
819  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
820  return(i != 0 ? MagickTrue : MagickFalse);
821}
822
823MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
824  Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
825{
826  char
827    *command,
828    **commands,
829    input_filename[MaxTextExtent],
830    output_filename[MaxTextExtent];
831
832  const DelegateInfo
833    *delegate_info;
834
835  MagickBooleanType
836    status,
837    temporary;
838
839  register ssize_t
840    i;
841
842  PolicyRights
843    rights;
844
845  /*
846    Get delegate.
847  */
848  assert(image_info != (ImageInfo *) NULL);
849  assert(image_info->signature == MagickSignature);
850  assert(image != (Image *) NULL);
851  assert(image->signature == MagickSignature);
852  if (image->debug != MagickFalse)
853    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
854  rights=ExecutePolicyRights;
855  if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
856    {
857      errno=EPERM;
858      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
859        "NotAuthorized","`%s'",decode);
860      return(MagickFalse);
861    }
862  if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
863    {
864      errno=EPERM;
865      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
866        "NotAuthorized","`%s'",encode);
867      return(MagickFalse);
868    }
869  temporary=(*image->filename == '\0') ? MagickTrue : MagickFalse;
870  if (temporary != MagickFalse)
871    if (AcquireUniqueFilename(image->filename) == MagickFalse)
872      {
873        ThrowFileException(exception,FileOpenError,
874          "UnableToCreateTemporaryFile",image->filename);
875        return(MagickFalse);
876      }
877  delegate_info=GetDelegateInfo(decode,encode,exception);
878  if (delegate_info == (DelegateInfo *) NULL)
879    {
880      if (temporary != MagickFalse)
881        (void) RelinquishUniqueFileResource(image->filename);
882      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
883        "NoTagFound","`%s'",decode ? decode : encode);
884      return(MagickFalse);
885    }
886  if (*image_info->filename == '\0')
887    {
888      if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
889        {
890          if (temporary != MagickFalse)
891            (void) RelinquishUniqueFileResource(image->filename);
892          ThrowFileException(exception,FileOpenError,
893            "UnableToCreateTemporaryFile",image_info->filename);
894          return(MagickFalse);
895        }
896      image_info->temporary=MagickTrue;
897    }
898  if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
899        (delegate_info->encode != (char *) NULL)) ||
900       ((encode != (const char *) NULL) &&
901        (delegate_info->decode != (char *) NULL))))
902    {
903      char
904        *magick;
905
906      ImageInfo
907        *clone_info;
908
909      register Image
910        *p;
911
912      /*
913        Delegate requires a particular image format.
914      */
915      if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
916        {
917          ThrowFileException(exception,FileOpenError,
918            "UnableToCreateTemporaryFile",image_info->unique);
919          return(MagickFalse);
920        }
921      if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
922        {
923          (void) RelinquishUniqueFileResource(image_info->zero);
924          ThrowFileException(exception,FileOpenError,
925            "UnableToCreateTemporaryFile",image_info->zero);
926          return(MagickFalse);
927        }
928      magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
929        delegate_info->encode : delegate_info->decode,exception);
930      if (magick == (char *) NULL)
931        {
932          (void) RelinquishUniqueFileResource(image_info->unique);
933          (void) RelinquishUniqueFileResource(image_info->zero);
934          if (temporary != MagickFalse)
935            (void) RelinquishUniqueFileResource(image->filename);
936          (void) ThrowMagickException(exception,GetMagickModule(),
937            DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
938          return(MagickFalse);
939        }
940      LocaleUpper(magick);
941      clone_info=CloneImageInfo(image_info);
942      (void) CopyMagickString((char *) clone_info->magick,magick,
943        MaxTextExtent);
944      if (LocaleCompare(magick,"NULL") != 0)
945        (void) CopyMagickString(image->magick,magick,MaxTextExtent);
946      magick=DestroyString(magick);
947      (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
948        delegate_info->decode);
949      (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
950        exception);
951      (void) CopyMagickString(clone_info->filename,image_info->filename,
952        MaxTextExtent);
953      (void) CopyMagickString(image_info->filename,image->filename,
954        MaxTextExtent);
955      for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
956      {
957        (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
958          delegate_info->decode,clone_info->filename);
959        status=WriteImage(clone_info,p,exception);
960        if (status == MagickFalse)
961          {
962            (void) RelinquishUniqueFileResource(image_info->unique);
963            (void) RelinquishUniqueFileResource(image_info->zero);
964            if (temporary != MagickFalse)
965              (void) RelinquishUniqueFileResource(image->filename);
966            clone_info=DestroyImageInfo(clone_info);
967            (void) ThrowMagickException(exception,GetMagickModule(),
968              DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
969            return(MagickFalse);
970          }
971        if (clone_info->adjoin != MagickFalse)
972          break;
973      }
974      (void) RelinquishUniqueFileResource(image_info->unique);
975      (void) RelinquishUniqueFileResource(image_info->zero);
976      clone_info=DestroyImageInfo(clone_info);
977    }
978  /*
979    Invoke delegate.
980  */
981  commands=StringToList(delegate_info->commands);
982  if (commands == (char **) NULL)
983    {
984      if (temporary != MagickFalse)
985        (void) RelinquishUniqueFileResource(image->filename);
986      (void) ThrowMagickException(exception,GetMagickModule(),
987        ResourceLimitError,"MemoryAllocationFailed","`%s'",
988        decode ? decode : encode);
989      return(MagickFalse);
990    }
991  command=(char *) NULL;
992  status=MagickFalse;
993  (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
994  (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
995  for (i=0; commands[i] != (char *) NULL; i++)
996  {
997    status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
998    if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
999      {
1000        ThrowFileException(exception,FileOpenError,
1001          "UnableToCreateTemporaryFile",image_info->unique);
1002        break;
1003      }
1004    if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
1005      {
1006        (void) RelinquishUniqueFileResource(image_info->unique);
1007        ThrowFileException(exception,FileOpenError,
1008          "UnableToCreateTemporaryFile",image_info->zero);
1009        break;
1010      }
1011    if (LocaleCompare(decode,"SCAN") != 0)
1012      {
1013        status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1014        if (status == MagickFalse)
1015          {
1016            ThrowFileException(exception,FileOpenError,
1017              "UnableToCreateTemporaryFile",input_filename);
1018            break;
1019          }
1020      }
1021    status=MagickFalse;
1022    command=InterpretImageProperties(image_info,image,commands[i],exception);
1023    if (command != (char *) NULL)
1024      {
1025        /*
1026          Execute delegate.
1027        */
1028        status=SystemCommand(delegate_info->spawn,image_info->verbose,command,
1029          exception) != 0 ? MagickTrue : MagickFalse;
1030        if (delegate_info->spawn != MagickFalse)
1031          (void) sleep(2);
1032        command=DestroyString(command);
1033      }
1034    if (LocaleCompare(decode,"SCAN") != 0)
1035      {
1036        if (CopyDelegateFile(image->filename,input_filename) == MagickFalse)
1037          (void) RelinquishUniqueFileResource(input_filename);
1038      }
1039    if (CopyDelegateFile(image_info->filename,output_filename) == MagickFalse)
1040      (void) RelinquishUniqueFileResource(output_filename);
1041    if (image_info->temporary != MagickFalse)
1042      (void) RelinquishUniqueFileResource(image_info->filename);
1043    (void) RelinquishUniqueFileResource(image_info->unique);
1044    (void) RelinquishUniqueFileResource(image_info->zero);
1045    (void) RelinquishUniqueFileResource(image_info->filename);
1046    (void) RelinquishUniqueFileResource(image->filename);
1047    if (status != MagickFalse)
1048      {
1049        (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1050          "DelegateFailed","`%s'",commands[i]);
1051        break;
1052      }
1053    commands[i]=DestroyString(commands[i]);
1054  }
1055  (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1056  (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1057  /*
1058    Relinquish resources.
1059  */
1060  for ( ; commands[i] != (char *) NULL; i++)
1061    commands[i]=DestroyString(commands[i]);
1062  commands=(char **) RelinquishMagickMemory(commands);
1063  if (temporary != MagickFalse)
1064    (void) RelinquishUniqueFileResource(image->filename);
1065  return(status == MagickFalse ? MagickTrue : MagickFalse);
1066}
1067
1068/*
1069%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070%                                                                             %
1071%                                                                             %
1072%                                                                             %
1073%  L i s t D e l e g a t e I n f o                                            %
1074%                                                                             %
1075%                                                                             %
1076%                                                                             %
1077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078%
1079%  ListDelegateInfo() lists the image formats to a file.
1080%
1081%  The format of the ListDelegateInfo method is:
1082%
1083%      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1084%
1085%  A description of each parameter follows.
1086%
1087%    o file:  An pointer to a FILE.
1088%
1089%    o exception: return any errors or warnings in this structure.
1090%
1091*/
1092MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1093  ExceptionInfo *exception)
1094{
1095  const DelegateInfo
1096    **delegate_info;
1097
1098  char
1099    **commands,
1100    delegate[MaxTextExtent];
1101
1102  const char
1103    *path;
1104
1105  register ssize_t
1106    i;
1107
1108  size_t
1109    number_delegates;
1110
1111  ssize_t
1112    j;
1113
1114  if (file == (const FILE *) NULL)
1115    file=stdout;
1116  delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1117  if (delegate_info == (const DelegateInfo **) NULL)
1118    return(MagickFalse);
1119  path=(const char *) NULL;
1120  for (i=0; i < (ssize_t) number_delegates; i++)
1121  {
1122    if (delegate_info[i]->stealth != MagickFalse)
1123      continue;
1124    if ((path == (const char *) NULL) ||
1125        (LocaleCompare(path,delegate_info[i]->path) != 0))
1126      {
1127        if (delegate_info[i]->path != (char *) NULL)
1128          (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1129        (void) FormatLocaleFile(file,"Delegate                Command\n");
1130        (void) FormatLocaleFile(file,
1131          "-------------------------------------------------"
1132          "------------------------------\n");
1133      }
1134    path=delegate_info[i]->path;
1135    *delegate='\0';
1136    if (delegate_info[i]->encode != (char *) NULL)
1137      (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
1138    (void) ConcatenateMagickString(delegate,"        ",MaxTextExtent);
1139    delegate[8]='\0';
1140    commands=StringToList(delegate_info[i]->commands);
1141    if (commands == (char **) NULL)
1142      continue;
1143    (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
1144      delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1145      delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1146    StripString(commands[0]);
1147    (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
1148    for (j=1; commands[j] != (char *) NULL; j++)
1149    {
1150      StripString(commands[j]);
1151      (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
1152    }
1153    for (j=0; commands[j] != (char *) NULL; j++)
1154      commands[j]=DestroyString(commands[j]);
1155    commands=(char **) RelinquishMagickMemory(commands);
1156  }
1157  (void) fflush(file);
1158  delegate_info=(const DelegateInfo **)
1159    RelinquishMagickMemory((void *) delegate_info);
1160  return(MagickTrue);
1161}
1162
1163/*
1164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165%                                                                             %
1166%                                                                             %
1167%                                                                             %
1168+   L o a d D e l e g a t e L i s t                                           %
1169%                                                                             %
1170%                                                                             %
1171%                                                                             %
1172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173%
1174%  LoadDelegateList() loads the delegate configuration file which provides a
1175%  mapping between delegate attributes and a delegate name.
1176%
1177%  The format of the LoadDelegateList method is:
1178%
1179%      MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
1180%        const size_t depth,ExceptionInfo *exception)
1181%
1182%  A description of each parameter follows:
1183%
1184%    o xml:  The delegate list in XML format.
1185%
1186%    o filename:  The delegate list filename.
1187%
1188%    o depth: depth of <include /> statements.
1189%
1190%    o exception: return any errors or warnings in this structure.
1191%
1192*/
1193static MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
1194  const size_t depth,ExceptionInfo *exception)
1195{
1196  char
1197    keyword[MaxTextExtent],
1198    *token;
1199
1200  const char
1201    *q;
1202
1203  DelegateInfo
1204    *delegate_info;
1205
1206  MagickBooleanType
1207    status;
1208
1209  /*
1210    Load the delegate map file.
1211  */
1212  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1213    "Loading delegate configuration file \"%s\" ...",filename);
1214  if (xml == (const char *) NULL)
1215    return(MagickFalse);
1216  if (delegate_list == (LinkedListInfo *) NULL)
1217    {
1218      delegate_list=NewLinkedList(0);
1219      if (delegate_list == (LinkedListInfo *) NULL)
1220        {
1221          ThrowFileException(exception,ResourceLimitError,
1222            "MemoryAllocationFailed",filename);
1223          return(MagickFalse);
1224        }
1225    }
1226  status=MagickTrue;
1227  delegate_info=(DelegateInfo *) NULL;
1228  token=AcquireString(xml);
1229  for (q=(const char *) xml; *q != '\0'; )
1230  {
1231    /*
1232      Interpret XML.
1233    */
1234    GetMagickToken(q,&q,token);
1235    if (*token == '\0')
1236      break;
1237    (void) CopyMagickString(keyword,token,MaxTextExtent);
1238    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1239      {
1240        /*
1241          Doctype element.
1242        */
1243        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1244          GetMagickToken(q,&q,token);
1245        continue;
1246      }
1247    if (LocaleNCompare(keyword,"<!--",4) == 0)
1248      {
1249        /*
1250          Comment element.
1251        */
1252        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1253          GetMagickToken(q,&q,token);
1254        continue;
1255      }
1256    if (LocaleCompare(keyword,"<include") == 0)
1257      {
1258        /*
1259          Include element.
1260        */
1261        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1262        {
1263          (void) CopyMagickString(keyword,token,MaxTextExtent);
1264          GetMagickToken(q,&q,token);
1265          if (*token != '=')
1266            continue;
1267          GetMagickToken(q,&q,token);
1268          if (LocaleCompare(keyword,"file") == 0)
1269            {
1270              if (depth > 200)
1271                (void) ThrowMagickException(exception,GetMagickModule(),
1272                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1273              else
1274                {
1275                  char
1276                    path[MaxTextExtent],
1277                    *xml;
1278
1279                  GetPathComponent(filename,HeadPath,path);
1280                  if (*path != '\0')
1281                    (void) ConcatenateMagickString(path,DirectorySeparator,
1282                      MaxTextExtent);
1283                  if (*token == *DirectorySeparator)
1284                    (void) CopyMagickString(path,token,MaxTextExtent);
1285                  else
1286                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
1287                  xml=FileToString(path,~0,exception);
1288                  if (xml != (char *) NULL)
1289                    {
1290                      status=LoadDelegateList(xml,path,depth+1,exception);
1291                      xml=(char *) RelinquishMagickMemory(xml);
1292                    }
1293                }
1294            }
1295        }
1296        continue;
1297      }
1298    if (LocaleCompare(keyword,"<delegate") == 0)
1299      {
1300        /*
1301          Delegate element.
1302        */
1303        delegate_info=(DelegateInfo *) AcquireMagickMemory(
1304          sizeof(*delegate_info));
1305        if (delegate_info == (DelegateInfo *) NULL)
1306          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1307        (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
1308        delegate_info->path=ConstantString(filename);
1309        delegate_info->signature=MagickSignature;
1310        continue;
1311      }
1312    if (delegate_info == (DelegateInfo *) NULL)
1313      continue;
1314    if (LocaleCompare(keyword,"/>") == 0)
1315      {
1316        status=AppendValueToLinkedList(delegate_list,delegate_info);
1317        if (status == MagickFalse)
1318          (void) ThrowMagickException(exception,GetMagickModule(),
1319            ResourceLimitError,"MemoryAllocationFailed","`%s'",
1320            delegate_info->commands);
1321        delegate_info=(DelegateInfo *) NULL;
1322      }
1323    GetMagickToken(q,(const char **) NULL,token);
1324    if (*token != '=')
1325      continue;
1326    GetMagickToken(q,&q,token);
1327    GetMagickToken(q,&q,token);
1328    switch (*keyword)
1329    {
1330      case 'C':
1331      case 'c':
1332      {
1333        if (LocaleCompare((char *) keyword,"command") == 0)
1334          {
1335            char
1336              *commands;
1337
1338            commands=AcquireString(token);
1339#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1340            if (strchr(commands,'@') != (char *) NULL)
1341              {
1342                char
1343                  path[MaxTextExtent];
1344
1345                NTGhostscriptEXE(path,MaxTextExtent);
1346                (void) SubstituteString((char **) &commands,"@PSDelegate@",
1347                  path);
1348                (void) SubstituteString((char **) &commands,"\\","/");
1349              }
1350#endif
1351            (void) SubstituteString((char **) &commands,"&amp;","&");
1352            (void) SubstituteString((char **) &commands,"&quot;","\"");
1353            (void) SubstituteString((char **) &commands,"&gt;",">");
1354            (void) SubstituteString((char **) &commands,"&lt;","<");
1355            delegate_info->commands=commands;
1356            break;
1357          }
1358        break;
1359      }
1360      case 'D':
1361      case 'd':
1362      {
1363        if (LocaleCompare((char *) keyword,"decode") == 0)
1364          {
1365            delegate_info->decode=ConstantString(token);
1366            delegate_info->mode=1;
1367            break;
1368          }
1369        break;
1370      }
1371      case 'E':
1372      case 'e':
1373      {
1374        if (LocaleCompare((char *) keyword,"encode") == 0)
1375          {
1376            delegate_info->encode=ConstantString(token);
1377            delegate_info->mode=(-1);
1378            break;
1379          }
1380        break;
1381      }
1382      case 'M':
1383      case 'm':
1384      {
1385        if (LocaleCompare((char *) keyword,"mode") == 0)
1386          {
1387            delegate_info->mode=1;
1388            if (LocaleCompare(token,"bi") == 0)
1389              delegate_info->mode=0;
1390            else
1391              if (LocaleCompare(token,"encode") == 0)
1392                delegate_info->mode=(-1);
1393            break;
1394          }
1395        break;
1396      }
1397      case 'S':
1398      case 's':
1399      {
1400        if (LocaleCompare((char *) keyword,"spawn") == 0)
1401          {
1402            delegate_info->spawn=IsMagickTrue(token);
1403            break;
1404          }
1405        if (LocaleCompare((char *) keyword,"stealth") == 0)
1406          {
1407            delegate_info->stealth=IsMagickTrue(token);
1408            break;
1409          }
1410        break;
1411      }
1412      case 'T':
1413      case 't':
1414      {
1415        if (LocaleCompare((char *) keyword,"thread-support") == 0)
1416          {
1417            delegate_info->thread_support=IsMagickTrue(token);
1418            break;
1419          }
1420        break;
1421      }
1422      default:
1423        break;
1424    }
1425  }
1426  token=(char *) RelinquishMagickMemory(token);
1427  return(status);
1428}
1429
1430/*
1431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432%                                                                             %
1433%                                                                             %
1434%                                                                             %
1435%  L o a d D e l e g a t e L i s t s                                          %
1436%                                                                             %
1437%                                                                             %
1438%                                                                             %
1439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440%
1441%  LoadDelegateList() loads one or more delegate configuration file which
1442%  provides a mapping between delegate attributes and a delegate name.
1443%
1444%  The format of the LoadDelegateLists method is:
1445%
1446%      MagickBooleanType LoadDelegateLists(const char *filename,
1447%        ExceptionInfo *exception)
1448%
1449%  A description of each parameter follows:
1450%
1451%    o filename: the font file name.
1452%
1453%    o exception: return any errors or warnings in this structure.
1454%
1455*/
1456static MagickBooleanType LoadDelegateLists(const char *filename,
1457  ExceptionInfo *exception)
1458{
1459#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
1460  return(LoadDelegateList(DelegateMap,"built-in",0,exception));
1461#else
1462  const StringInfo
1463    *option;
1464
1465  LinkedListInfo
1466    *options;
1467
1468  MagickStatusType
1469    status;
1470
1471  status=MagickFalse;
1472  options=GetConfigureOptions(filename,exception);
1473  option=(const StringInfo *) GetNextValueInLinkedList(options);
1474  while (option != (const StringInfo *) NULL)
1475  {
1476    status|=LoadDelegateList((const char *) GetStringInfoDatum(option),
1477      GetStringInfoPath(option),0,exception);
1478    option=(const StringInfo *) GetNextValueInLinkedList(options);
1479  }
1480  options=DestroyConfigureOptions(options);
1481  if ((delegate_list == (LinkedListInfo *) NULL) ||
1482      (IsLinkedListEmpty(delegate_list) != MagickFalse))
1483    status|=LoadDelegateList(DelegateMap,"built-in",0,exception);
1484  return(status != 0 ? MagickTrue : MagickFalse);
1485#endif
1486}
Note: See TracBrowser for help on using the repository browser.