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