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