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