root / ImageMagick / trunk / magick / delegate.c

Revision 12706, 55.3 kB (checked in by cristy, 2 days ago)
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-2008 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/resource_.h"
61#include "magick/semaphore.h"
62#include "magick/string_.h"
63#include "magick/token.h"
64#include "magick/utility.h"
65#include "magick/xml-tree.h"
66
67/*
68  Define declarations.
69*/
70#define DelegateFilename  "delegates.xml"
71
72/*
73  Declare delegate map.
74*/
75static const char
76  *DelegateMap = (const char *)
77    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
78    "<delegatemap>"
79    "  <delegate decode=\"autotrace\" stealth=\"True\" command=\"&quot;autotrace&quot; -output-format svg -output-file &quot;%o&quot; &quot;%i&quot;\"/>"
80    "  <delegate decode=\"avi:decode\" stealth=\"True\" command=\"&quot;mplayer&quot; &quot;%i&quot; -really-quiet -ao null -vo png:z=3\"/>"
81    "  <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\"&quot;xdg-open&quot; http://www.imagemagick.org/\"/>"
82    "  <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;\"/>"
83    "  <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;\"/>"
84    "  <delegate decode=\"edit\" stealth=\"True\" command=\"&quot;xterm&quot; -title &quot;Edit Image Comment&quot; -e vi &quot;%o&quot;\"/>"
85    "  <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pdfwrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
86    "  <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
87    "  <delegate decode=\"fig\" command=\"&quot;fig2dev&quot; -L ps &quot;%i&quot; &quot;%o&quot;\"/>"
88    "  <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;\"/>"
89    "  <delegate decode=\"hdr\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&quot;\"/>"
90    "  <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;\"/>"
91    "  <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\"/>"
92    "  <delegate decode=\"htm\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
93    "  <delegate decode=\"html\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
94    "  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"
95    "  <delegate decode=\"ilbm\" command=\"&quot;ilbmtoppm&quot; &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
96    "  <delegate decode=\"man\" command=\"&quot;groff&quot; -man -Tps &quot;%i&quot; &gt; &quot;%o&quot;\"/>"
97    "  <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;\"/>"
98    "  <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;\"/>"
99    "  <delegate decode=\"pcl:color\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -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;\"/>"
100    "  <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -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;\"/>"
101    "  <delegate decode=\"pcl:mono\" stealth=\"True\" command=\"&quot;pcl6&quot; -dQUIET -dSAFER -dPARANOIDSAFE -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;\"/>"
102    "  <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=epswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
103    "  <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\"&quot;gs&quot; -q -dQUIET -dSAFER -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pswrite&quot; &quot;-sOutputFile=%o&quot; &quot;-f%i&quot;\"/>"
104    "  <delegate decode=\"pic\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&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 -dPARANOIDSAFE -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 -dPARANOIDSAFE -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 -dPARANOIDSAFE -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 -dPARANOIDSAFE -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 -dPARANOIDSAFE -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=0 &quot;-sDEVICE=pam&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 -dPARANOIDSAFE -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 -dPARANOIDSAFE -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=\"rad\" command=\"&quot;ra_pfm&quot; &quot;%i&quot; &quot;%o&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\" stealth=\"True\" spawn=\"True\" command=\"&quot;/usr/local/bin/display&quot; -immutable -delay 0 -window-group %g -title &quot;%l of %f&quot; &quot;tmp:%i&quot;\"/>"
120    "  <delegate decode=\"shtml\" command=\"&quot;html2ps&quot; -U -o &quot;%o&quot; &quot;%i&quot;\"/>"
121    "  <delegate decode=\"svg\" command=\"&quot;wmf2eps&quot; -o &quot;%o&quot; &quot;%i&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;tmp:%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 s t r o y D e l e g a t e L i s t                                     %
152%                                                                             %
153%                                                                             %
154%                                                                             %
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156%
157%  DestroyDelegateList() deallocates memory associated with the delegates list.
158%
159%  The format of the DestroyDelegateList method is:
160%
161%      DestroyDelegateList(void)
162%
163*/
164
165static void *DestroyDelegate(void *delegate_info)
166{
167  register DelegateInfo
168    *p;
169
170  p=(DelegateInfo *) delegate_info;
171  if (p->path != (char *) NULL)
172    p->path=DestroyString(p->path);
173  if (p->decode != (char *) NULL)
174    p->decode=DestroyString(p->decode);
175  if (p->encode != (char *) NULL)
176    p->encode=DestroyString(p->encode);
177  if (p->commands != (char *) NULL)
178    p->commands=DestroyString(p->commands);
179  p=(DelegateInfo *) RelinquishMagickMemory(p);
180  return((void *) NULL);
181}
182
183
184MagickExport void DestroyDelegateList(void)
185{
186  AcquireSemaphoreInfo(&delegate_semaphore);
187  if (delegate_list != (LinkedListInfo *) NULL)
188    delegate_list=DestroyLinkedList(delegate_list,DestroyDelegate);
189  instantiate_delegate=MagickFalse;
190  RelinquishSemaphoreInfo(delegate_semaphore);
191  DestroySemaphoreInfo(&delegate_semaphore);
192}
193
194/*
195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196%                                                                             %
197%                                                                             %
198%                                                                             %
199%   G e t D e l e g a t e C o m m a n d                                       %
200%                                                                             %
201%                                                                             %
202%                                                                             %
203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204%
205%  GetDelegateCommand() replaces any embedded formatting characters with the
206%  appropriate image attribute and returns the resulting command.
207%
208%  The format of the GetDelegateCommand method is:
209%
210%      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
211%        const char *decode,const char *encode,ExceptionInfo *exception)
212%
213%  A description of each parameter follows:
214%
215%    o command: Method GetDelegateCommand returns the command associated
216%      with specified delegate tag.
217%
218%    o image_info: the image info.
219%
220%    o image: the image.
221%
222%    o decode: Specifies the decode delegate we are searching for as a
223%      character string.
224%
225%    o encode: Specifies the encode delegate we are searching for as a
226%      character string.
227%
228%    o exception: Return any errors or warnings in this structure.
229%
230*/
231MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
232  const char *decode,const char *encode,ExceptionInfo *exception)
233{
234  char
235    *command,
236    **commands;
237
238  const DelegateInfo
239    *delegate_info;
240
241  register long
242    i;
243
244  assert(image_info != (ImageInfo *) NULL);
245  assert(image_info->signature == MagickSignature);
246  assert(image != (Image *) NULL);
247  assert(image->signature == MagickSignature);
248  if (image->debug != MagickFalse)
249    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
250  delegate_info=GetDelegateInfo(decode,encode,exception);
251  if (delegate_info == (const DelegateInfo *) NULL)
252    {
253      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
254        "NoTagFound","`%s'",decode ? decode : encode);
255      return((char *) NULL);
256    }
257  commands=StringToList(delegate_info->commands);
258  if (commands == (char **) NULL)
259    {
260      (void) ThrowMagickException(exception,GetMagickModule(),
261        ResourceLimitError,"MemoryAllocationFailed","`%s'",
262        decode ? decode : encode);
263      return((char *) NULL);
264    }
265  command=InterpretImageProperties(image_info,image,commands[0]);
266  if (command == (char *) NULL)
267    (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
268      "MemoryAllocationFailed","`%s'",commands[0]);
269  /*
270    Relinquish resources.
271  */
272  for (i=0; commands[i] != (char *) NULL; i++)
273    commands[i]=DestroyString(commands[i]);
274  commands=(char **) RelinquishMagickMemory(commands);
275  return(command);
276}
277
278/*
279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280%                                                                             %
281%                                                                             %
282%                                                                             %
283%   G e t D e l e g a t e C o m m a n d s                                     %
284%                                                                             %
285%                                                                             %
286%                                                                             %
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288%
289%  GetDelegateCommands() returns the commands associated with a delegate.
290%
291%  The format of the GetDelegateCommands method is:
292%
293%      const char *GetDelegateCommands(const DelegateInfo *delegate_info)
294%
295%  A description of each parameter follows:
296%
297%    o delegate_info:  The delegate info.
298%
299*/
300MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info)
301{
302  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
303  assert(delegate_info != (DelegateInfo *) NULL);
304  assert(delegate_info->signature == MagickSignature);
305  return(delegate_info->commands);
306}
307
308/*
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310%                                                                             %
311%                                                                             %
312%                                                                             %
313%   G e t D e l e g a t e I n f o                                             %
314%                                                                             %
315%                                                                             %
316%                                                                             %
317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318%
319%  GetDelegateInfo() returns any delegates associated with the specified tag.
320%
321%  The format of the GetDelegateInfo method is:
322%
323%      const DelegateInfo *GetDelegateInfo(const char *decode,
324%        const char *encode,ExceptionInfo *exception)
325%
326%  A description of each parameter follows:
327%
328%    o decode: Specifies the decode delegate we are searching for as a
329%      character string.
330%
331%    o encode: Specifies the encode delegate we are searching for as a
332%      character string.
333%
334%    o exception: Return any errors or warnings in this structure.
335%
336*/
337MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
338  const char *encode,ExceptionInfo *exception)
339{
340  register const DelegateInfo
341    *p;
342
343  assert(exception != (ExceptionInfo *) NULL);
344  if ((delegate_list == (LinkedListInfo *) NULL) ||
345      (instantiate_delegate == MagickFalse))
346    if (InitializeDelegateList(exception) == MagickFalse)
347      return((const DelegateInfo *) NULL);
348  if ((delegate_list == (LinkedListInfo *) NULL) ||
349      (IsLinkedListEmpty(delegate_list) != MagickFalse))
350    return((const DelegateInfo *) NULL);
351  if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
352    return((const DelegateInfo *) GetValueFromLinkedList(delegate_list,0));
353  /*
354    Search for named delegate.
355  */
356  AcquireSemaphoreInfo(&delegate_semaphore);
357  ResetLinkedListIterator(delegate_list);
358  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
359  while (p != (const DelegateInfo *) NULL)
360  {
361    if (p->mode > 0)
362      {
363        if (LocaleCompare(p->decode,decode) == 0)
364          break;
365        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
366        continue;
367      }
368    if (p->mode < 0)
369      {
370        if (LocaleCompare(p->encode,encode) == 0)
371          break;
372        p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
373        continue;
374      }
375    if (LocaleCompare(decode,p->decode) == 0)
376      if (LocaleCompare(encode,p->encode) == 0)
377        break;
378    if (LocaleCompare(decode,"*") == 0)
379      if (LocaleCompare(encode,p->encode) == 0)
380        break;
381    if (LocaleCompare(decode,p->decode) == 0)
382      if (LocaleCompare(encode,"*") == 0)
383        break;
384    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
385  }
386  if (p != (const DelegateInfo *) NULL)
387    (void) InsertValueInLinkedList(delegate_list,0,
388      RemoveElementByValueFromLinkedList(delegate_list,p));
389  RelinquishSemaphoreInfo(delegate_semaphore);
390  return(p);
391}
392
393/*
394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395%                                                                             %
396%                                                                             %
397%                                                                             %
398%   G e t D e l e g a t e I n f o L i s t                                     %
399%                                                                             %
400%                                                                             %
401%                                                                             %
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403%
404%  GetDelegateInfoList() returns any delegates that match the specified pattern.
405%
406%  The delegate of the GetDelegateInfoList function is:
407%
408%      const DelegateInfo **GetDelegateInfoList(const char *pattern,
409%        unsigned long *number_delegates,ExceptionInfo *exception)
410%
411%  A description of each parameter follows:
412%
413%    o pattern: Specifies a pointer to a text string containing a pattern.
414%
415%    o number_delegates:  This integer returns the number of delegates in the
416%      list.
417%
418%    o exception: Return any errors or warnings in this structure.
419%
420*/
421
422#if defined(__cplusplus) || defined(c_plusplus)
423extern "C" {
424#endif
425
426static int DelegateInfoCompare(const void *x,const void *y)
427{
428  const DelegateInfo
429    **p,
430    **q;
431
432  p=(const DelegateInfo **) x,
433  q=(const DelegateInfo **) y;
434  if (LocaleCompare((*p)->path,(*q)->path) == 0)
435    {
436      if ((*p)->decode == (char *) NULL)
437        if (((*p)->encode != (char *) NULL) &&
438            ((*q)->encode != (char *) NULL))
439          return(strcmp((*p)->encode,(*q)->encode));
440      if (((*p)->decode != (char *) NULL) &&
441          ((*q)->decode != (char *) NULL))
442        return(strcmp((*p)->decode,(*q)->decode));
443    }
444  return(LocaleCompare((*p)->path,(*q)->path));
445}
446
447#if defined(__cplusplus) || defined(c_plusplus)
448}
449#endif
450
451MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern,
452  unsigned long *number_delegates,ExceptionInfo *exception)
453{
454  const DelegateInfo
455    **delegates;
456
457  register const DelegateInfo
458    *p;
459
460  register long
461    i;
462
463  /*
464    Allocate delegate list.
465  */
466  assert(pattern != (char *) NULL);
467  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
468  assert(number_delegates != (unsigned long *) NULL);
469  *number_delegates=0;
470  p=GetDelegateInfo("*","*",exception);
471  if (p == (const DelegateInfo *) NULL)
472    return((const DelegateInfo **) NULL);
473  delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t)
474    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
475  if (delegates == (const DelegateInfo **) NULL)
476    return((const DelegateInfo **) NULL);
477  /*
478    Generate delegate list.
479  */
480  AcquireSemaphoreInfo(&delegate_semaphore);
481  ResetLinkedListIterator(delegate_list);
482  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
483  for (i=0; p != (const DelegateInfo *) NULL; )
484  {
485    if ((p->stealth == MagickFalse) &&
486        ((GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse) ||
487         (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse)))
488      delegates[i++]=p;
489    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
490  }
491  RelinquishSemaphoreInfo(delegate_semaphore);
492  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare);
493  delegates[i]=(DelegateInfo *) NULL;
494  *number_delegates=(unsigned long) i;
495  return(delegates);
496}
497
498/*
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500%                                                                             %
501%                                                                             %
502%                                                                             %
503%   G e t D e l e g a t e L i s t                                             %
504%                                                                             %
505%                                                                             %
506%                                                                             %
507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508%
509%  GetDelegateList() returns any image format delegates that match the
510%  specified  pattern.
511%
512%  The format of the GetDelegateList function is:
513%
514%      char **GetDelegateList(const char *pattern,
515%        unsigned long *number_delegates,ExceptionInfo *exception)
516%
517%  A description of each parameter follows:
518%
519%    o pattern: Specifies a pointer to a text string containing a pattern.
520%
521%    o number_delegates:  This integer returns the number of delegates
522%      in the list.
523%
524%    o exception: Return any errors or warnings in this structure.
525%
526*/
527
528#if defined(__cplusplus) || defined(c_plusplus)
529extern "C" {
530#endif
531
532static int DelegateCompare(const void *x,const void *y)
533{
534  register const char
535    **p,
536    **q;
537
538  p=(const char **) x;
539  q=(const char **) y;
540  return(LocaleCompare(*p,*q));
541}
542
543#if defined(__cplusplus) || defined(c_plusplus)
544}
545#endif
546
547MagickExport char **GetDelegateList(const char *pattern,
548  unsigned long *number_delegates,ExceptionInfo *exception)
549{
550  char
551    **delegates;
552
553  register const DelegateInfo
554    *p;
555
556  register long
557    i;
558
559  /*
560    Allocate delegate list.
561  */
562  assert(pattern != (char *) NULL);
563  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
564  assert(number_delegates != (unsigned long *) NULL);
565  *number_delegates=0;
566  p=GetDelegateInfo("*","*",exception);
567  if (p == (const DelegateInfo *) NULL)
568    return((char **) NULL);
569  delegates=(char **) AcquireQuantumMemory((size_t)
570    GetNumberOfElementsInLinkedList(delegate_list)+1UL,sizeof(*delegates));
571  if (delegates == (char **) NULL)
572    return((char **) NULL);
573  AcquireSemaphoreInfo(&delegate_semaphore);
574  ResetLinkedListIterator(delegate_list);
575  p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
576  for (i=0; p != (const DelegateInfo *) NULL; )
577  {
578    if ((p->stealth == MagickFalse) &&
579        (GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse))
580      delegates[i++]=ConstantString(p->decode);
581    if ((p->stealth == MagickFalse) &&
582        (GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse))
583      delegates[i++]=ConstantString(p->encode);
584    p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_list);
585  }
586  RelinquishSemaphoreInfo(delegate_semaphore);
587  qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare);
588  delegates[i]=(char *) NULL;
589  *number_delegates=(unsigned long) i;
590  return(delegates);
591}
592
593/*
594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
595%                                                                             %
596%                                                                             %
597%                                                                             %
598%   G e t D e l e g a t e M o d e                                             %
599%                                                                             %
600%                                                                             %
601%                                                                             %
602%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603%
604%  GetDelegateMode() returns the mode of the delegate.
605%
606%  The format of the GetDelegateMode method is:
607%
608%      long GetDelegateMode(const DelegateInfo *delegate_info)
609%
610%  A description of each parameter follows:
611%
612%    o delegate_info:  The delegate info.
613%
614*/
615MagickExport long GetDelegateMode(const DelegateInfo *delegate_info)
616{
617  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
618  assert(delegate_info != (DelegateInfo *) NULL);
619  assert(delegate_info->signature == MagickSignature);
620  return(delegate_info->mode);
621}
622
623/*
624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625%                                                                             %
626%                                                                             %
627%                                                                             %
628+   G e t D e l e g a t e T h r e a d S u p p o r t                           %
629%                                                                             %
630%                                                                             %
631%                                                                             %
632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633%
634%  GetDelegateThreadSupport() returns MagickTrue if the delegate supports
635%  threads.
636%
637%  The format of the GetDelegateThreadSupport method is:
638%
639%      MagickBooleanType GetDelegateThreadSupport(
640%        const DelegateInfo *delegate_info)
641%
642%  A description of each parameter follows:
643%
644%    o delegate_info:  The delegate info.
645%
646*/
647MagickExport MagickBooleanType GetDelegateThreadSupport(
648  const DelegateInfo *delegate_info)
649{
650  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
651  assert(delegate_info != (DelegateInfo *) NULL);
652  assert(delegate_info->signature == MagickSignature);
653  return(delegate_info->thread_support);
654}
655
656/*
657%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658%                                                                             %
659%                                                                             %
660%                                                                             %
661+   I n i t i a l i z e D e l e g a t e L i s t                               %
662%                                                                             %
663%                                                                             %
664%                                                                             %
665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666%
667%  InitializeDelegateList() initializes the delegate list.
668%
669%  The format of the InitializeDelegateList method is:
670%
671%      MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
672%
673%  A description of each parameter follows.
674%
675%    o exception: Return any errors or warnings in this structure.
676%
677*/
678static MagickBooleanType InitializeDelegateList(ExceptionInfo *exception)
679{
680  if ((delegate_list == (LinkedListInfo *) NULL) &&
681      (instantiate_delegate == MagickFalse))
682    {
683      AcquireSemaphoreInfo(&delegate_semaphore);
684      if ((delegate_list == (LinkedListInfo *) NULL) &&
685          (instantiate_delegate == MagickFalse))
686        {
687          (void) LoadDelegateLists(DelegateFilename,exception);
688          instantiate_delegate=MagickTrue;
689        }
690      RelinquishSemaphoreInfo(delegate_semaphore);
691    }
692  return(delegate_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
693}
694
695/*
696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697%                                                                             %
698%                                                                             %
699%                                                                             %
700%   I n v o k e D e l e g a t e                                               %
701%                                                                             %
702%                                                                             %
703%                                                                             %
704%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705%
706%  InvokeDelegate replaces any embedded formatting characters with the
707%  appropriate image attribute and executes the resulting command.  MagickFalse
708%  is returned if the commands execute with success otherwise MagickTrue.
709%
710%  The format of the InvokeDelegate method is:
711%
712%      MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image,
713%        const char *decode,const char *encode,ExceptionInfo *exception)
714%
715%  A description of each parameter follows:
716%
717%    o image_info: the imageInfo.
718%
719%    o image: the image.
720%
721%    o exception: Return any errors or warnings in this structure.
722%
723*/
724
725static inline size_t MagickMin(const size_t x,const size_t y)
726{
727  if (x < y)
728    return(x);
729  return(y);
730}
731
732static MagickBooleanType CopyDelegateFile(const char *source,
733  const char *destination)
734{
735  int
736    destination_file,
737    source_file;
738
739  MagickBooleanType
740    status;
741
742  register size_t
743    i;
744
745  size_t
746    length,
747    quantum;
748
749  ssize_t
750    count;
751
752  struct stat
753    attributes;
754
755  unsigned char
756    *buffer;
757
758  /*
759    Return if destination file already exists and is not empty.
760  */
761  assert(source != (const char *) NULL);
762  assert(destination != (char *) NULL);
763  status=GetPathAttributes(destination,&attributes);
764  if ((status != MagickFalse) && (attributes.st_size != 0))
765    return(MagickTrue);
766  /*
767    Copy source file to destination.
768  */
769  destination_file=open(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
770  if (destination_file == -1)
771    return(MagickFalse);
772  source_file=open(source,O_RDONLY | O_BINARY);
773  if (source_file == -1)
774    {
775      (void) close(destination_file);
776      return(MagickFalse);
777    }
778  quantum=(size_t) MagickMaxBufferExtent;
779  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
780    quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent);
781  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
782  if (buffer == (unsigned char *) NULL)
783    {
784      (void) close(source_file);
785      (void) close(destination_file);
786      return(MagickFalse);
787    }
788  length=0;
789  for (i=0; ; i+=count)
790  {
791    count=(ssize_t) read(source_file,buffer,quantum);
792    if (count <= 0)
793      break;
794    length=(size_t) count;
795    count=(ssize_t) write(destination_file,buffer,length);
796    if ((size_t) count != length)
797      break;
798  }
799  (void) close(destination_file);
800  (void) close(source_file);
801  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
802  return(i != 0 ? MagickTrue : MagickFalse);
803}
804
805MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info,
806  Image *image,const char *decode,const char *encode,ExceptionInfo *exception)
807{
808  char
809    *command,
810    **commands,
811    input_filename[MaxTextExtent],
812    output_filename[MaxTextExtent];
813
814  const DelegateInfo
815    *delegate_info;
816
817  register long
818    i;
819
820  MagickBooleanType
821    status,
822    temporary;
823
824  /*
825    Get delegate.
826  */
827  assert(image_info != (ImageInfo *) NULL);
828  assert(image_info->signature == MagickSignature);
829  assert(image != (Image *) NULL);
830  assert(image->signature == MagickSignature);
831  if (image->debug != MagickFalse)
832    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
833  temporary=(*image->filename == '\0') ? MagickTrue : MagickFalse;
834  if (temporary != MagickFalse)
835    if (AcquireUniqueFilename(image->filename) == MagickFalse)
836      {
837        ThrowFileException(exception,FileOpenError,
838          "UnableToCreateTemporaryFile",image->filename);
839        return(MagickFalse);
840      }
841  delegate_info=GetDelegateInfo(decode,encode,exception);
842  if (delegate_info == (DelegateInfo *) NULL)
843    {
844      if (temporary != MagickFalse)
845        (void) RelinquishUniqueFileResource(image->filename);
846      (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
847        "NoTagFound","`%s'",decode ? decode : encode);
848      return(MagickFalse);
849    }