1 /*
2 Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization
3 dedicated to making software imaging solutions freely available.
4
5 You may not use this file except in compliance with the License. You may
6 obtain a copy of the License at
7
8 https://imagemagick.org/script/license.php
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 #ifndef MAGICK_GHOSTSCRIPT_BUFFER_PRIVATE_H
17 #define MAGICK_GHOSTSCRIPT_BUFFER_PRIVATE_H
18
19 #include "coders/bytebuffer-private.h"
20
21 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
GhostscriptDelegateMessage(void * handle,const char * message,int length)22 static int MagickDLLCall GhostscriptDelegateMessage(void *handle,
23 const char *message,int length)
24 {
25 char
26 **messages;
27
28 ssize_t
29 offset;
30
31 offset=0;
32 messages=(char **) handle;
33 if (*messages == (char *) NULL)
34 *messages=(char *) AcquireQuantumMemory((size_t) length+1,sizeof(char *));
35 else
36 {
37 offset=(ssize_t) strlen(*messages);
38 *messages=(char *) ResizeQuantumMemory(*messages,(size_t) (offset+length+
39 1),sizeof(char *));
40 }
41 if (*messages == (char *) NULL)
42 return(0);
43 (void) memcpy(*messages+offset,message,(size_t) length);
44 (*messages)[length+offset] ='\0';
45 return(length);
46 }
47
GhostscriptVersion(const GhostInfo * ghost_info)48 static double GhostscriptVersion(const GhostInfo *ghost_info)
49 {
50 gsapi_revision_t
51 revision;
52
53 if ((ghost_info->revision)(&revision,(int) sizeof(revision)) != 0)
54 return(0.0);
55 if (revision.revision > 1000)
56 return(revision.revision/1000.0);
57 return(revision.revision/100.0);
58 }
59 #endif
60
ExecuteGhostscriptCommand(const MagickBooleanType verbose,const char * command,char * message,ExceptionInfo * exception)61 static inline MagickBooleanType ExecuteGhostscriptCommand(
62 const MagickBooleanType verbose,const char *command,char *message,
63 ExceptionInfo *exception)
64 {
65 int
66 status;
67
68 status=ExternalDelegateCommand(MagickFalse,verbose,command,message,
69 exception);
70 if (status == 0)
71 return(MagickTrue);
72 if (status < 0)
73 return(MagickFalse);
74 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
75 "FailedToExecuteCommand","`%s' (%d)",command,status);
76 return(MagickFalse);
77 }
78
InvokeGhostscriptDelegate(const MagickBooleanType verbose,const char * command,char * message,ExceptionInfo * exception)79 static inline MagickBooleanType InvokeGhostscriptDelegate(
80 const MagickBooleanType verbose,const char *command,char *message,
81 ExceptionInfo *exception)
82 {
83 int
84 status;
85
86 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
87 #define SetArgsStart(command,args_start) \
88 if (args_start == (const char *) NULL) \
89 { \
90 if (*command != '"') \
91 args_start=strchr(command,' '); \
92 else \
93 { \
94 args_start=strchr(command+1,'"'); \
95 if (args_start != (const char *) NULL) \
96 args_start++; \
97 } \
98 }
99
100 char
101 **argv,
102 *errors;
103
104 const char
105 *args_start = (const char *) NULL;
106
107 const GhostInfo
108 *ghost_info;
109
110 gs_main_instance
111 *interpreter;
112
113 int
114 argc,
115 code;
116
117 ssize_t
118 i;
119
120 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
121 ghost_info=NTGhostscriptDLLVectors();
122 #else
123 GhostInfo
124 ghost_info_struct;
125
126 ghost_info=(&ghost_info_struct);
127 (void) memset(&ghost_info_struct,0,sizeof(ghost_info_struct));
128 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
129 gsapi_delete_instance;
130 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
131 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
132 gsapi_new_instance;
133 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
134 gsapi_init_with_args;
135 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
136 int *)) gsapi_run_string;
137 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int (*)(void *,char *,
138 int),int (*)(void *,const char *,int),int (*)(void *, const char *, int)))
139 gsapi_set_stdio;
140 ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision;
141 #endif
142 if (ghost_info == (GhostInfo *) NULL)
143 return(ExecuteGhostscriptCommand(verbose,command,message,exception));
144 if (verbose != MagickFalse)
145 {
146 (void) fprintf(stdout,"[ghostscript library %.2f]",
147 GhostscriptVersion(ghost_info));
148 SetArgsStart(command,args_start);
149 (void) fputs(args_start,stdout);
150 }
151 interpreter=(gs_main_instance *) NULL;
152 errors=(char *) NULL;
153 status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
154 if (status < 0)
155 return(ExecuteGhostscriptCommand(verbose,command,message,exception));
156 code=0;
157 argv=StringToArgv(command,&argc);
158 if (argv == (char **) NULL)
159 {
160 (ghost_info->delete_instance)(interpreter);
161 return(MagickFalse);
162 }
163 (void) (ghost_info->set_stdio)(interpreter,(int (MagickDLLCall *)(void *,
164 char *,int)) NULL,GhostscriptDelegateMessage,GhostscriptDelegateMessage);
165 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
166 if (status == 0)
167 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
168 0,&code);
169 (ghost_info->exit)(interpreter);
170 (ghost_info->delete_instance)(interpreter);
171 for (i=0; i < (ssize_t) argc; i++)
172 argv[i]=DestroyString(argv[i]);
173 argv=(char **) RelinquishMagickMemory(argv);
174 if (status != 0)
175 {
176 SetArgsStart(command,args_start);
177 if (status == -101) /* quit */
178 (void) FormatLocaleString(message,MaxTextExtent,
179 "[ghostscript library %.2f]%s: %s",GhostscriptVersion(ghost_info),
180 args_start,errors);
181 else
182 {
183 (void) ThrowMagickException(exception,GetMagickModule(),
184 DelegateError,"PostscriptDelegateFailed",
185 "`[ghostscript library %.2f]%s': %s",GhostscriptVersion(ghost_info),
186 args_start,errors);
187 if (errors != (char *) NULL)
188 errors=DestroyString(errors);
189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
190 "Ghostscript returns status %d, exit code %d",status,code);
191 return(MagickFalse);
192 }
193 }
194 if (errors != (char *) NULL)
195 errors=DestroyString(errors);
196 return(MagickTrue);
197 #else
198 status=ExternalDelegateCommand(MagickFalse,verbose,command,(char *) NULL,
199 exception);
200 return(status == 0 ? MagickTrue : MagickFalse);
201 #endif
202 }
203
IsGhostscriptRendered(const char * path)204 static MagickBooleanType IsGhostscriptRendered(const char *path)
205 {
206 MagickBooleanType
207 status;
208
209 struct stat
210 attributes;
211
212 if ((path == (const char *) NULL) || (*path == '\0'))
213 return(MagickFalse);
214 status=GetPathAttributes(path,&attributes);
215 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
216 (attributes.st_size > 0))
217 return(MagickTrue);
218 return(MagickFalse);
219 }
220
ReadGhostScriptXMPProfile(MagickByteBuffer * buffer,StringInfo ** profile)221 static inline void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer,
222 StringInfo **profile)
223 {
224 #define BeginXMPPacket "?xpacket begin="
225 #define EndXMPPacket "<?xpacket end="
226
227 int
228 c;
229
230 MagickBooleanType
231 found_end,
232 status;
233
234 char
235 *p;
236
237 size_t
238 length;
239
240 ssize_t
241 count;
242
243 if (*profile != (StringInfo *) NULL)
244 return;
245 status=CompareMagickByteBuffer(buffer,BeginXMPPacket,strlen(BeginXMPPacket));
246 if (status == MagickFalse)
247 return;
248 length=8192;
249 *profile=AcquireStringInfo(length);
250 found_end=MagickFalse;
251 p=(char *) GetStringInfoDatum(*profile);
252 *p++='<';
253 count=1;
254 for (c=ReadMagickByteBuffer(buffer); c != EOF; c=ReadMagickByteBuffer(buffer))
255 {
256 if (count == (ssize_t) length)
257 {
258 length<<=1;
259 SetStringInfoLength(*profile,length);
260 p=(char *) GetStringInfoDatum(*profile)+count;
261 }
262 count++;
263 *p++=(char) c;
264 if (found_end == MagickFalse)
265 found_end=CompareMagickByteBuffer(buffer,EndXMPPacket,
266 strlen(EndXMPPacket));
267 else
268 {
269 if (c == (int) '>')
270 break;
271 }
272 }
273 SetStringInfoLength(*profile,(size_t) count);
274 }
275
276 #endif
277