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