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