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