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