source: ImageMagick/branches/ImageMagick-6/magick/delegate.c @ 8015

Revision 8015, 59.0 KB checked in by anthony, 13 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 "magick/studio.h"
49#include "magick/property.h"
50#include "magick/blob.h"
51#include "magick/client.h"
52#include "magick/configure.h"
53#include "magick/constitute.h"
54#include "magick/delegate.h"
55#include "magick/exception.h"
56#include "magick/exception-private.h"
57#include "magick/hashmap.h"
58#include "magick/list.h"
59#include "magick/memory_.h"
60#include "magick/policy.h"
61#include "magick/resource_.h"
62#include "magick/semaphore.h"
63#include "magick/string_.h"
64#include "magick/token.h"
65#include "magick/utility.h"
66#include "magick/utility-private.h"
67#include "magick/xml-tree.h"
68
69/*
70  Define declarations.
71*/
72#define DelegateFilename  "delegates.xml"
73
74/*
75  Declare delegate map.
76*/
77static const char
78  *DelegateMap = (const char *)
79    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
80    "<delegatemap>"
81    "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
82    "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
83    "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/; rm &quot;%i&quot;\"/>"
84    "  <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;\"/>"
85    "  <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;\"/>"
86    "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
87    "  <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;\"/>"
88    "  <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;\"/>"
89    "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
90    "  <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;\"/>"
91    "  <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;\"/>"
92    "  <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\"/>"
93    "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
94    "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
95    "  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
96    "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
97    "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
98    "  <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;\"/>"
99    "  <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;\"/>"
100    "  <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;\"/>"
101    "  <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;\"/>"
102    "  <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;\"/>"
103    "  <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;\"/>"
104    "  <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;\"/>"
105    "  <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\"&quot;ppmtoilbm&quot; -24if &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
106    "  <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\"&quot;gimp&quot; &quot;%i&quot;\"/>"
107    "  <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;\"/>"
108    "  <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;\"/>"
109    "  <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;\"/>"
110    "  <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr &quot;%i&quot;\"/>"
111    "  <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;\"/>"
112    "  <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;\"/>"
113    "  <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;\"/>"
114    "  <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;\"/>"
115    "  <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;\"/>"
116    "  <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\"&quot;rawtorle&quot; -o &quot;%o&quot; -v &quot;%i&quot;\"/>"
117    "  <delegate decode=\"scan\" command=\"&quot;scanimage&quot; -d &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
118    "  <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;\"/>"
119    "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
120    "  <delegate decode=\"svg\" command=\"&quot;rsvg&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
121    "  <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\"&quot;enscript&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
122    "  <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;\"/>"
123    "  <delegate decode=\"wmf\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&quot;\"/>"
124    "</delegatemap>";
125
126/*
127  Global declaractions.
128*/
129static LinkedListInfo
130  *delegate_list = (LinkedListInfo *) NULL;
131
132static SemaphoreInfo
133  *delegate_semaphore = (SemaphoreInfo *) NULL;
134
135static volatile MagickBooleanType
136  instantiate_delegate = MagickFalse;
137
138/*
139  Forward declaractions.
140*/
141static MagickBooleanType
142  InitializeDelegateList(ExceptionInfo *),
143  LoadDelegateLists(const char *,ExceptionInfo *);
144
145/*
146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147%                                                                             %
148%                                                                             %
149%                                                                             %
150+   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                         %
151%                                                                             %
152%                                                                             %
153%                                                                             %
154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
155%
156%  DelegateComponentGenesis() instantiates the delegate component.
157%
158%  The format of the DelegateComponentGenesis method is:
159%
160%      MagickBooleanType DelegateComponentGenesis(void)
161%
162*/
163MagickExport MagickBooleanType DelegateComponentGenesis(void)
164{
165  AcquireSemaphoreInfo(&delegate_semaphore);
166  return(MagickTrue);
167}
168
169/*
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%                                                                             %
172%                                                                             %
173%                                                                             %
174%   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                         %
175%                                                                             %
176%                                                                             %
177%                                                                             %
178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179%
180%  DelegateComponentTerminus() destroys the delegate component.
181%
182%  The format of the DelegateComponentTerminus method is:
183%
184%      DelegateComponentTerminus(void)
185%
186*/
187
188static void *DestroyDelegate(void *delegate_info)
189{
190  register DelegateInfo
191    *p;
192
193  p=(DelegateInfo *) delegate_info;
194  if (p->path != (char *) NULL)
195    p->path=DestroyString(p->path);
196  if (p->decode != (char *) NULL)
197    p->decode=DestroyString(p->decode);
198  if (p->encode != (char *) NULL)
199    p->encode=DestroyString(p->encode);
200  if (p->commands != (char *) NULL)
201    p->commands=DestroyString(p->commands);
202  p=(DelegateInfo *) RelinquishMagickMemory(p);
203  return((void *) NULL);
204}
205
206
207MagickExport 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]);
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  MagickBooleanType
767    status;
768
769  register size_t
770    i;
771
772  size_t
773    length,
774    quantum;
775
776  ssize_t
777    count;
778
779  struct stat
780    attributes;
781
782  unsigned char
783    *buffer;
784
785  /*
786    Copy source file to destination.
787  */
788  assert(source != (const char *) NULL);
789  assert(destination != (char *) NULL);
790  status=GetPathAttributes(destination,&attributes);
791  if ((status != MagickFalse) && (attributes.st_size != 0))
792    return(MagickTrue);
793  destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
794  if (destination_file == -1)
795    return(MagickFalse);
796  source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
797  if (source_file == -1)
798    {
799      (void) close(destination_file);
800      return(MagickFalse);
801    }
802  quantum=(size_t) MagickMaxBufferExtent;
803  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
804    quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
805  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
806  if (buffer == (unsigned char *) NULL)
807    {
808      (void) close(source_file);
809      (void) close(destination_file);
810      return(MagickFalse);
811    }
812  length=0;
813  for (i=0; ; i+=count)
814  {
815    count=(ssize_t) read(source_file,buffer,quantum);
816    if (count <= 0)
817      break;
818    length=(size_t) count;
819    count=(ssize_t) write(destination_file,buffer,length);
820    if ((size_t) count != length)
821      break;
822  }
823  (void) close(destination_file);
824  (void) close(source_file);
825  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
826  return(i != 0 ? MagickTrue : MagickFalse);
827}
828
829MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
830  Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
831{
832  char
833    *command,
834    **commands,
835    input_filename[MaxTextExtent],
836    output_filename[MaxTextExtent];
837
838  const DelegateInfo
839    *delegate_info;
840
841  MagickBooleanType
842    status,
843    temporary;
844
845  register ssize_t
846    i;
847
848  PolicyRights
849    rights;
850
851  /*
852    Get delegate.
853  */
854  assert(image_info != (ImageInfo *) NULL);
855  assert(image_info->signature == MagickSignature);
856  assert(image != (Image *) NULL);
857  assert(image->signature == MagickSignature);
858  if (image->debug != MagickFalse)
859    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
860  rights=ExecutePolicyRights;
861  if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse)
862    {
863      errno=EPERM;
864      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
865        "NotAuthorized","`%s'",decode);
866      return(MagickFalse);
867    }
868  if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse)
869    {
870      errno=EPERM;
871      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
872        "NotAuthorized","`%s'",encode);
873      return(MagickFalse);
874    }
875  temporary=(*image->filename == '\0') ? MagickTrue : MagickFalse;
876  if (temporary != MagickFalse)
877    if (AcquireUniqueFilename(image->filename) == MagickFalse)
878      {
879        ThrowFileException(exception,FileOpenError,
880          "UnableToCreateTemporaryFile",image->filename);
881        return(MagickFalse);
882      }
883  delegate_info=GetDelegateInfo(decode,encode,exception);
884  if (delegate_info == (DelegateInfo *) NULL)
885    {
886      if (temporary != MagickFalse)
887        (void) RelinquishUniqueFileResource(image->filename);
888      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
889        "NoTagFound","`%s'",decode ? decode : encode);
890      return(MagickFalse);
891    }
892  if (*image_info->filename == '\0')
893    {
894      if (AcquireUniqueFilename(image_info->filename) == MagickFalse)
895        {
896          if (temporary != MagickFalse)
897            (void) RelinquishUniqueFileResource(image->filename);
898          ThrowFileException(exception,FileOpenError,
899            "UnableToCreateTemporaryFile",image_info->filename);
900          return(MagickFalse);
901        }
902      image_info->temporary=MagickTrue;
903    }
904  if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) &&
905        (delegate_info->encode != (char *) NULL)) ||
906       ((encode != (const char *) NULL) &&
907        (delegate_info->decode != (char *) NULL))))
908    {
909      char
910        *magick;
911
912      ImageInfo
913        *clone_info;
914
915      register Image
916        *p;
917
918      /*
919        Delegate requires a particular image format.
920      */
921      if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
922        {
923          ThrowFileException(exception,FileOpenError,
924            "UnableToCreateTemporaryFile",image_info->unique);
925          return(MagickFalse);
926        }
927      if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
928        {
929          (void) RelinquishUniqueFileResource(image_info->unique);
930          ThrowFileException(exception,FileOpenError,
931            "UnableToCreateTemporaryFile",image_info->zero);
932          return(MagickFalse);
933        }
934      magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ?
935        delegate_info->encode : delegate_info->decode);
936      if (magick == (char *) NULL)
937        {
938          (void) RelinquishUniqueFileResource(image_info->unique);
939          (void) RelinquishUniqueFileResource(image_info->zero);
940          if (temporary != MagickFalse)
941            (void) RelinquishUniqueFileResource(image->filename);
942          (void) ThrowMagickException(exception,GetMagickModule(),
943            DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
944          return(MagickFalse);
945        }
946      LocaleUpper(magick);
947      clone_info=CloneImageInfo(image_info);
948      (void) CopyMagickString((char *) clone_info->magick,magick,
949        MaxTextExtent);
950      if (LocaleCompare(magick,"NULL") != 0)
951        (void) CopyMagickString(image->magick,magick,MaxTextExtent);
952      magick=DestroyString(magick);
953      (void) FormatLocaleString(clone_info->filename,MaxTextExtent,"%s:",
954        delegate_info->decode);
955      (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image),
956        exception);
957      (void) CopyMagickString(clone_info->filename,image_info->filename,
958        MaxTextExtent);
959      (void) CopyMagickString(image_info->filename,image->filename,
960        MaxTextExtent);
961      for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
962      {
963        (void) FormatLocaleString(p->filename,MaxTextExtent,"%s:%s",
964          delegate_info->decode,clone_info->filename);
965        status=WriteImage(clone_info,p);
966        if (status == MagickFalse)
967          {
968            (void) RelinquishUniqueFileResource(image_info->unique);
969            (void) RelinquishUniqueFileResource(image_info->zero);
970            if (temporary != MagickFalse)
971              (void) RelinquishUniqueFileResource(image->filename);
972            clone_info=DestroyImageInfo(clone_info);
973            (void) ThrowMagickException(exception,GetMagickModule(),
974              DelegateError,"DelegateFailed","`%s'",decode ? decode : encode);
975            return(MagickFalse);
976          }
977        if (clone_info->adjoin != MagickFalse)
978          break;
979      }
980      (void) RelinquishUniqueFileResource(image_info->unique);
981      (void) RelinquishUniqueFileResource(image_info->zero);
982      clone_info=DestroyImageInfo(clone_info);
983    }
984  /*
985    Invoke delegate.
986  */
987  commands=StringToList(delegate_info->commands);
988  if (commands == (char **) NULL)
989    {
990      if (temporary != MagickFalse)
991        (void) RelinquishUniqueFileResource(image->filename);
992      (void) ThrowMagickException(exception,GetMagickModule(),
993        ResourceLimitError,"MemoryAllocationFailed","`%s'",
994        decode ? decode : encode);
995      return(MagickFalse);
996    }
997  command=(char *) NULL;
998  status=MagickFalse;
999  (void) CopyMagickString(output_filename,image_info->filename,MaxTextExtent);
1000  (void) CopyMagickString(input_filename,image->filename,MaxTextExtent);
1001  for (i=0; commands[i] != (char *) NULL; i++)
1002  {
1003    status=AcquireUniqueSymbolicLink(output_filename,image_info->filename);
1004    if (AcquireUniqueFilename(image_info->unique) == MagickFalse)
1005      {
1006        ThrowFileException(exception,FileOpenError,
1007          "UnableToCreateTemporaryFile",image_info->unique);
1008        break;
1009      }
1010    if (AcquireUniqueFilename(image_info->zero) == MagickFalse)
1011      {
1012        (void) RelinquishUniqueFileResource(image_info->unique);
1013        ThrowFileException(exception,FileOpenError,
1014          "UnableToCreateTemporaryFile",image_info->zero);
1015        break;
1016      }
1017    if (LocaleCompare(decode,"SCAN") != 0)
1018      {
1019        status=AcquireUniqueSymbolicLink(input_filename,image->filename);
1020        if (status == MagickFalse)
1021          {
1022            ThrowFileException(exception,FileOpenError,
1023              "UnableToCreateTemporaryFile",input_filename);
1024            break;
1025          }
1026      }
1027    status=MagickFalse;
1028    command=InterpretImageProperties(image_info,image,commands[i]);
1029    if (command != (char *) NULL)
1030      {
1031        /*
1032          Execute delegate.
1033        */
1034        status=SystemCommand(delegate_info->spawn,image_info->verbose,command,
1035          exception) != 0 ? MagickTrue : MagickFalse;
1036        /* If spawn, wait for input file to 'disappear', or maximum 5 secs */
1037        if (delegate_info->spawn != MagickFalse) {
1038#if 1
1039            ssize_t count=50;  /* 50 x 0.1 sec sleeps maximum */
1040            while( count > 0 && access_utf8(image->filename,F_OK) == 0 )
1041              (void) usleep(100000);  /* sleep 0.1 seconds */
1042#else
1043            (void) sleep(2);
1044#endif
1045          }
1046        command=DestroyString(command);
1047      }
1048    if (LocaleCompare(decode,"SCAN") != 0)
1049      {
1050        if (CopyDelegateFile(image->filename,input_filename) == MagickFalse)
1051          (void) RelinquishUniqueFileResource(input_filename);
1052      }
1053    if (CopyDelegateFile(image_info->filename,output_filename) == MagickFalse)
1054      (void) RelinquishUniqueFileResource(output_filename);
1055    if (image_info->temporary != MagickFalse)
1056      (void) RelinquishUniqueFileResource(image_info->filename);
1057    (void) RelinquishUniqueFileResource(image_info->unique);
1058    (void) RelinquishUniqueFileResource(image_info->zero);
1059    (void) RelinquishUniqueFileResource(image_info->filename);
1060    (void) RelinquishUniqueFileResource(image->filename);
1061    if (status != MagickFalse)
1062      {
1063        (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
1064          "DelegateFailed","`%s'",commands[i]);
1065        break;
1066      }
1067    commands[i]=DestroyString(commands[i]);
1068  }
1069  (void) CopyMagickString(image_info->filename,output_filename,MaxTextExtent);
1070  (void) CopyMagickString(image->filename,input_filename,MaxTextExtent);
1071  /*
1072    Relinquish resources.
1073  */
1074  for ( ; commands[i] != (char *) NULL; i++)
1075    commands[i]=DestroyString(commands[i]);
1076  commands=(char **) RelinquishMagickMemory(commands);
1077  if (temporary != MagickFalse)
1078    (void) RelinquishUniqueFileResource(image->filename);
1079  return(status == MagickFalse ? MagickTrue : MagickFalse);
1080}
1081
1082/*
1083%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084%                                                                             %
1085%                                                                             %
1086%                                                                             %
1087%  L i s t D e l e g a t e I n f o                                            %
1088%                                                                             %
1089%                                                                             %
1090%                                                                             %
1091%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092%
1093%  ListDelegateInfo() lists the image formats to a file.
1094%
1095%  The format of the ListDelegateInfo method is:
1096%
1097%      MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1098%
1099%  A description of each parameter follows.
1100%
1101%    o file:  An pointer to a FILE.
1102%
1103%    o exception: return any errors or warnings in this structure.
1104%
1105*/
1106MagickExport MagickBooleanType ListDelegateInfo(FILE *file,
1107  ExceptionInfo *exception)
1108{
1109  const DelegateInfo
1110    **delegate_info;
1111
1112  char
1113    **commands,
1114    delegate[MaxTextExtent];
1115
1116  const char
1117    *path;
1118
1119  register ssize_t
1120    i;
1121
1122  size_t
1123    number_delegates;
1124
1125  ssize_t
1126    j;
1127
1128  if (file == (const FILE *) NULL)
1129    file=stdout;
1130  delegate_info=GetDelegateInfoList("*",&number_delegates,exception);
1131  if (delegate_info == (const DelegateInfo **) NULL)
1132    return(MagickFalse);
1133  path=(const char *) NULL;
1134  for (i=0; i < (ssize_t) number_delegates; i++)
1135  {
1136    if (delegate_info[i]->stealth != MagickFalse)
1137      continue;
1138    if ((path == (const char *) NULL) ||
1139        (LocaleCompare(path,delegate_info[i]->path) != 0))
1140      {
1141        if (delegate_info[i]->path != (char *) NULL)
1142          (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path);
1143        (void) FormatLocaleFile(file,"Delegate                Command\n");
1144        (void) FormatLocaleFile(file,
1145          "-------------------------------------------------"
1146          "------------------------------\n");
1147      }
1148    path=delegate_info[i]->path;
1149    *delegate='\0';
1150    if (delegate_info[i]->encode != (char *) NULL)
1151      (void) CopyMagickString(delegate,delegate_info[i]->encode,MaxTextExtent);
1152    (void) ConcatenateMagickString(delegate,"        ",MaxTextExtent);
1153    delegate[8]='\0';
1154    commands=StringToList(delegate_info[i]->commands);
1155    if (commands == (char **) NULL)
1156      continue;
1157    (void) FormatLocaleFile(file,"%11s%c=%c%s  ",delegate_info[i]->decode ?
1158      delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ',
1159      delegate_info[i]->mode >= 0 ? '>' : ' ',delegate);
1160    StripString(commands[0]);
1161    (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]);
1162    for (j=1; commands[j] != (char *) NULL; j++)
1163    {
1164      StripString(commands[j]);
1165      (void) FormatLocaleFile(file,"                     \"%s\"\n",commands[j]);
1166    }
1167    for (j=0; commands[j] != (char *) NULL; j++)
1168      commands[j]=DestroyString(commands[j]);
1169    commands=(char **) RelinquishMagickMemory(commands);
1170  }
1171  (void) fflush(file);
1172  delegate_info=(const DelegateInfo **)
1173    RelinquishMagickMemory((void *) delegate_info);
1174  return(MagickTrue);
1175}
1176
1177/*
1178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179%                                                                             %
1180%                                                                             %
1181%                                                                             %
1182+   L o a d D e l e g a t e L i s t                                           %
1183%                                                                             %
1184%                                                                             %
1185%                                                                             %
1186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187%
1188%  LoadDelegateList() loads the delegate configuration file which provides a
1189%  mapping between delegate attributes and a delegate name.
1190%
1191%  The format of the LoadDelegateList method is:
1192%
1193%      MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
1194%        const size_t depth,ExceptionInfo *exception)
1195%
1196%  A description of each parameter follows:
1197%
1198%    o xml:  The delegate list in XML format.
1199%
1200%    o filename:  The delegate list filename.
1201%
1202%    o depth: depth of <include /> statements.
1203%
1204%    o exception: return any errors or warnings in this structure.
1205%
1206*/
1207static MagickBooleanType LoadDelegateList(const char *xml,const char *filename,
1208  const size_t depth,ExceptionInfo *exception)
1209{
1210  char
1211    keyword[MaxTextExtent],
1212    *token;
1213
1214  const char
1215    *q;
1216
1217  DelegateInfo
1218    *delegate_info;
1219
1220  MagickBooleanType
1221    status;
1222
1223  /*
1224    Load the delegate map file.
1225  */
1226  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1227    "Loading delegate configuration file \"%s\" ...",filename);
1228  if (xml == (const char *) NULL)
1229    return(MagickFalse);
1230  if (delegate_list == (LinkedListInfo *) NULL)
1231    {
1232      delegate_list=NewLinkedList(0);
1233      if (delegate_list == (LinkedListInfo *) NULL)
1234        {
1235          ThrowFileException(exception,ResourceLimitError,
1236            "MemoryAllocationFailed",filename);
1237          return(MagickFalse);
1238        }
1239    }
1240  status=MagickTrue;
1241  delegate_info=(DelegateInfo *) NULL;
1242  token=AcquireString(xml);
1243  for (q=(const char *) xml; *q != '\0'; )
1244  {
1245    /*
1246      Interpret XML.
1247    */
1248    GetMagickToken(q,&q,token);
1249    if (*token == '\0')
1250      break;
1251    (void) CopyMagickString(keyword,token,MaxTextExtent);
1252    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1253      {
1254        /*
1255          Doctype element.
1256        */
1257        while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1258          GetMagickToken(q,&q,token);
1259        continue;
1260      }
1261    if (LocaleNCompare(keyword,"<!--",4) == 0)
1262      {
1263        /*
1264          Comment element.
1265        */
1266        while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1267          GetMagickToken(q,&q,token);
1268        continue;
1269      }
1270    if (LocaleCompare(keyword,"<include") == 0)
1271      {
1272        /*
1273          Include element.
1274        */
1275        while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1276        {
1277          (void) CopyMagickString(keyword,token,MaxTextExtent);
1278          GetMagickToken(q,&q,token);
1279          if (*token != '=')
1280            continue;
1281          GetMagickToken(q,&q,token);
1282          if (LocaleCompare(keyword,"file") == 0)
1283            {
1284              if (depth > 200)
1285                (void) ThrowMagickException(exception,GetMagickModule(),
1286                  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1287              else
1288                {
1289                  char
1290                    path[MaxTextExtent],
1291                    *xml;
1292
1293                  GetPathComponent(filename,HeadPath,path);
1294                  if (*path != '\0')
1295                    (void) ConcatenateMagickString(path,DirectorySeparator,
1296                      MaxTextExtent);
1297                  if (*token == *DirectorySeparator)
1298                    (void) CopyMagickString(path,token,MaxTextExtent);
1299                  else
1300                    (void) ConcatenateMagickString(path,token,MaxTextExtent);
1301                  xml=FileToString(path,~0,exception);
1302                  if (xml != (char *) NULL)
1303                    {
1304                      status=LoadDelegateList(xml,path,depth+1,exception);
1305                      xml=(char *) RelinquishMagickMemory(xml);
1306                    }
1307                }
1308            }
1309        }
1310        continue;
1311      }
1312    if (LocaleCompare(keyword,"<delegate") == 0)
1313      {
1314        /*
1315          Delegate element.
1316        */
1317        delegate_info=(DelegateInfo *) AcquireMagickMemory(
1318          sizeof(*delegate_info));
1319        if (delegate_info == (DelegateInfo *) NULL)
1320          ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1321        (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info));
1322        delegate_info->path=ConstantString(filename);
1323        delegate_info->signature=MagickSignature;
1324        continue;
1325      }
1326    if (delegate_info == (DelegateInfo *) NULL)
1327      continue;
1328    if (LocaleCompare(keyword,"/>") == 0)
1329      {
1330        status=AppendValueToLinkedList(delegate_list,delegate_info);
1331        if (status == MagickFalse)
1332          (void) ThrowMagickException(exception,GetMagickModule(),
1333            ResourceLimitError,"MemoryAllocationFailed","`%s'",
1334            delegate_info->commands);
1335        delegate_info=(DelegateInfo *) NULL;
1336      }
1337    GetMagickToken(q,(const char **) NULL,token);
1338    if (*token != '=')
1339      continue;
1340    GetMagickToken(q,&q,token);
1341    GetMagickToken(q,&q,token);
1342    switch (*keyword)
1343    {
1344      case 'C':
1345      case 'c':
1346      {
1347        if (LocaleCompare((char *) keyword,"command") == 0)
1348          {
1349            char
1350              *commands;
1351
1352            commands=AcquireString(token);
1353#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1354            if (strchr(commands,'@') != (char *) NULL)
1355              {
1356                char
1357                  path[MaxTextExtent];
1358
1359                NTGhostscriptEXE(path,MaxTextExtent);
1360                (void) SubstituteString((char **) &commands,"@PSDelegate@",
1361                  path);
1362                (void) SubstituteString((char **) &commands,"\\","/");
1363              }
1364#endif
1365            (void) SubstituteString((char **) &commands,"&amp;","&");
1366            (void) SubstituteString((char **) &commands,"&quot;","\"");
1367            (void) SubstituteString((char **) &commands,"&gt;",">");
1368            (void) SubstituteString((char **) &commands,"&lt;","<");
1369            delegate_info->commands=commands;
1370            break;
1371          }
1372        break;
1373      }
1374      case 'D':
1375      case 'd':
1376      {
1377        if (LocaleCompare((char *) keyword,"decode") == 0)
1378          {
1379            delegate_info->decode=ConstantString(token);
1380            delegate_info->mode=1;
1381            break;
1382          }
1383        break;
1384      }
1385      case 'E':
1386      case 'e':
1387      {
1388        if (LocaleCompare((char *) keyword,"encode") == 0)
1389          {
1390            delegate_info->encode=ConstantString(token);
1391            delegate_info->mode=(-1);
1392            break;
1393          }
1394        break;
1395      }
1396      case 'M':
1397      case 'm':
1398      {
1399        if (LocaleCompare((char *) keyword,"mode") == 0)
1400          {
1401            delegate_info->mode=1;
1402            if (LocaleCompare(token,"bi") == 0)
1403              delegate_info->mode=0;
1404            else
1405              if (LocaleCompare(token,"encode") == 0)
1406                delegate_info->mode=(-1);
1407            break;
1408          }
1409        break;
1410      }
1411      case 'S':
1412      case 's':
1413      {
1414        if (LocaleCompare((char *) keyword,"spawn") == 0)
1415          {
1416            delegate_info->spawn=IsMagickTrue(token);
1417            break;
1418          }
1419        if (LocaleCompare((char *) keyword,"stealth") == 0)
1420          {
1421            delegate_info->stealth=IsMagickTrue(token);
1422            break;
1423          }
1424        break;
1425      }
1426      case 'T':
1427      case 't':
1428      {
1429        if (LocaleCompare((char *) keyword,"thread-support") == 0)
1430          {
1431            delegate_info->thread_support=IsMagickTrue(token);
1432            break;
1433          }
1434        break;
1435      }
1436      default:
1437        break;
1438    }
1439  }
1440  token=(char *) RelinquishMagickMemory(token);
1441  return(status);
1442}
1443
1444/*
1445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446%                                                                             %
1447%                                                                             %
1448%                                                                             %
1449%  L o a d D e l e g a t e L i s t s                                          %
1450%                                                                             %
1451%                                                                             %
1452%                                                                             %
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454%
1455%  LoadDelegateList() loads one or more delegate configuration file which
1456%  provides a mapping between delegate attributes and a delegate name.
1457%
1458%  The format of the LoadDelegateLists method is:
1459%
1460%      MagickBooleanType LoadDelegateLists(const char *filename,
1461%        ExceptionInfo *exception)
1462%
1463%  A description of each parameter follows:
1464%
1465%    o filename: the font file name.
1466%
1467%    o exception: return any errors or warnings in this structure.
1468%
1469*/
1470static MagickBooleanType LoadDelegateLists(const char *filename,
1471  ExceptionInfo *exception)
1472{
1473#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
1474  return(LoadDelegateList(DelegateMap,"built-in",0,exception));
1475#else
1476  const StringInfo
1477    *option;
1478
1479  LinkedListInfo
1480    *options;
1481
1482  MagickStatusType
1483    status;
1484
1485  status=MagickFalse;
1486  options=GetConfigureOptions(filename,exception);
1487  option=(const StringInfo *) GetNextValueInLinkedList(options);
1488  while (option != (const StringInfo *) NULL)
1489  {
1490    status|=LoadDelegateList((const char *) GetStringInfoDatum(option),
1491      GetStringInfoPath(option),0,exception);
1492    option=(const StringInfo *) GetNextValueInLinkedList(options);
1493  }
1494  options=DestroyConfigureOptions(options);
1495  if ((delegate_list == (LinkedListInfo *) NULL) ||
1496      (IsLinkedListEmpty(delegate_list) != MagickFalse))
1497    status|=LoadDelegateList(DelegateMap,"built-in",0,exception);
1498  return(status != 0 ? MagickTrue : MagickFalse);
1499#endif
1500}
Note: See TracBrowser for help on using the repository browser.