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