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