1 /*
2 Copyright 1999-2020 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(length+1,sizeof(char *));
35 else
36 {
37 offset=strlen(*messages);
38 *messages=(char *) ResizeQuantumMemory(*messages,offset+length+1,
39 sizeof(char *));
40 }
41 if (*messages == (char *) NULL)
42 return(0);
43 (void) memcpy(*messages+offset,message,length);
44 (*messages)[length+offset] ='\0';
45 return(length);
46 }
47 #endif
48
InvokeGhostscriptDelegate(const MagickBooleanType verbose,const char * command,char * message,ExceptionInfo * exception)49 static MagickBooleanType InvokeGhostscriptDelegate(
50 const MagickBooleanType verbose,const char *command,char *message,
51 ExceptionInfo *exception)
52 {
53 int
54 status;
55
56 #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
57 #define SetArgsStart(command,args_start) \
58 if (args_start == (const char *) NULL) \
59 { \
60 if (*command != '"') \
61 args_start=strchr(command,' '); \
62 else \
63 { \
64 args_start=strchr(command+1,'"'); \
65 if (args_start != (const char *) NULL) \
66 args_start++; \
67 } \
68 }
69
70 #define ExecuteGhostscriptCommand(command,status) \
71 { \
72 status=ExternalDelegateCommand(MagickFalse,verbose,command,message, \
73 exception); \
74 if (status == 0) \
75 return(MagickTrue); \
76 if (status < 0) \
77 return(MagickFalse); \
78 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, \
79 "FailedToExecuteCommand","`%s' (%d)",command,status); \
80 return(MagickFalse); \
81 }
82
83 char
84 **argv,
85 *errors;
86
87 const char
88 *args_start = (const char *) NULL;
89
90 const GhostInfo
91 *ghost_info;
92
93 gs_main_instance
94 *interpreter;
95
96 gsapi_revision_t
97 revision;
98
99 int
100 argc,
101 code;
102
103 register ssize_t
104 i;
105
106 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
107 ghost_info=NTGhostscriptDLLVectors();
108 #else
109 GhostInfo
110 ghost_info_struct;
111
112 ghost_info=(&ghost_info_struct);
113 (void) memset(&ghost_info_struct,0,sizeof(ghost_info_struct));
114 ghost_info_struct.delete_instance=(void (*)(gs_main_instance *))
115 gsapi_delete_instance;
116 ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit;
117 ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *))
118 gsapi_new_instance;
119 ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **))
120 gsapi_init_with_args;
121 ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int,
122 int *)) gsapi_run_string;
123 ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int (*)(void *,char *,
124 int),int (*)(void *,const char *,int),int (*)(void *, const char *, int)))
125 gsapi_set_stdio;
126 ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision;
127 #endif
128 if (ghost_info == (GhostInfo *) NULL)
129 ExecuteGhostscriptCommand(command,status);
130 if ((ghost_info->revision)(&revision,sizeof(revision)) != 0)
131 revision.revision=0;
132 if (verbose != MagickFalse)
133 {
134 (void) fprintf(stdout,"[ghostscript library %.2f]",(double)
135 revision.revision/100.0);
136 SetArgsStart(command,args_start);
137 (void) fputs(args_start,stdout);
138 }
139 interpreter=(gs_main_instance *) NULL;
140 errors=(char *) NULL;
141 status=(ghost_info->new_instance)(&interpreter,(void *) &errors);
142 if (status < 0)
143 ExecuteGhostscriptCommand(command,status);
144 code=0;
145 argv=StringToArgv(command,&argc);
146 if (argv == (char **) NULL)
147 {
148 (ghost_info->delete_instance)(interpreter);
149 return(MagickFalse);
150 }
151 (void) (ghost_info->set_stdio)(interpreter,(int (MagickDLLCall *)(void *,
152 char *,int)) NULL,GhostscriptDelegateMessage,GhostscriptDelegateMessage);
153 status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1);
154 if (status == 0)
155 status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n",
156 0,&code);
157 (ghost_info->exit)(interpreter);
158 (ghost_info->delete_instance)(interpreter);
159 for (i=0; i < (ssize_t) argc; i++)
160 argv[i]=DestroyString(argv[i]);
161 argv=(char **) RelinquishMagickMemory(argv);
162 if (status != 0)
163 {
164 SetArgsStart(command,args_start);
165 if (status == -101) /* quit */
166 (void) FormatLocaleString(message,MaxTextExtent,
167 "[ghostscript library %.2f]%s: %s",(double) revision.revision/100.0,
168 args_start,errors);
169 else
170 {
171 (void) ThrowMagickException(exception,GetMagickModule(),
172 DelegateError,"PostscriptDelegateFailed",
173 "`[ghostscript library %.2f]%s': %s",(double) revision.revision/
174 100.0,args_start,errors);
175 if (errors != (char *) NULL)
176 errors=DestroyString(errors);
177 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
178 "Ghostscript returns status %d, exit code %d",status,code);
179 return(MagickFalse);
180 }
181 }
182 if (errors != (char *) NULL)
183 errors=DestroyString(errors);
184 return(MagickTrue);
185 #else
186 status=ExternalDelegateCommand(MagickFalse,verbose,command,(char *) NULL,
187 exception);
188 return(status == 0 ? MagickTrue : MagickFalse);
189 #endif
190 }
191
IsGhostscriptRendered(const char * path)192 static MagickBooleanType IsGhostscriptRendered(const char *path)
193 {
194 MagickBooleanType
195 status;
196
197 struct stat
198 attributes;
199
200 if ((path == (const char *) NULL) || (*path == '\0'))
201 return(MagickFalse);
202 status=GetPathAttributes(path,&attributes);
203 if ((status != MagickFalse) && S_ISREG(attributes.st_mode) &&
204 (attributes.st_size > 0))
205 return(MagickTrue);
206 return(MagickFalse);
207 }
208
ReadGhostScriptXMPProfile(MagickByteBuffer * buffer,StringInfo ** profile)209 static void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer,
210 StringInfo **profile)
211 {
212 #define BeginXMPPacket "?xpacket begin="
213 #define EndXMPPacket "<?xpacket end="
214
215 int
216 c;
217
218 MagickBooleanType
219 found_end,
220 status;
221
222 register char
223 *p;
224
225 size_t
226 length;
227
228 ssize_t
229 count;
230
231 if (*profile != (StringInfo *) NULL)
232 return;
233 status=CompareMagickByteBuffer(buffer,BeginXMPPacket,strlen(BeginXMPPacket));
234 if (status == MagickFalse)
235 return;
236 length=8192;
237 *profile=AcquireStringInfo(length);
238 found_end=MagickFalse;
239 p=(char *) GetStringInfoDatum(*profile);
240 *p++='<';
241 count=1;
242 for (c=ReadMagickByteBuffer(buffer); c != EOF; c=ReadMagickByteBuffer(buffer))
243 {
244 if (count == (ssize_t) length)
245 {
246 length<<=1;
247 SetStringInfoLength(*profile,length);
248 p=(char *) GetStringInfoDatum(*profile)+count;
249 }
250 count++;
251 *p++=(char) c;
252 if (found_end == MagickFalse)
253 found_end=CompareMagickByteBuffer(buffer,EndXMPPacket,
254 strlen(EndXMPPacket));
255 else
256 {
257 if (c == (int) '>')
258 break;
259 }
260 }
261 SetStringInfoLength(*profile,(size_t) count);
262 }
263
264 #endif
265