blob: 66eff852ba2eea8c0a015bb0e7a9bc868b283d87 [file] [log] [blame]
Dirk Lemstraea979132019-07-11 21:38:52 +02001/*
Cristyd8420112021-01-01 14:52:00 -05002 Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization
Dirk Lemstraea979132019-07-11 21:38:52 +02003 dedicated to making software imaging solutions freely available.
Cristyc60d3282020-07-26 09:55:35 -04004
Dirk Lemstraea979132019-07-11 21:38:52 +02005 You may not use this file except in compliance with the License. You may
6 obtain a copy of the License at
Cristyc60d3282020-07-26 09:55:35 -04007
Dirk Lemstraea979132019-07-11 21:38:52 +02008 https://imagemagick.org/script/license.php
Cristyc60d3282020-07-26 09:55:35 -04009
Dirk Lemstraea979132019-07-11 21:38:52 +020010 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
Cristyc8ab8d92019-07-13 09:15:22 -040019#include "coders/bytebuffer-private.h"
20
Dirk Lemstraea979132019-07-11 21:38:52 +020021#if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT)
22static 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)
Cristyc60d3282020-07-26 09:55:35 -040034 *messages=(char *) AcquireQuantumMemory((size_t) length+1,sizeof(char *));
Dirk Lemstraea979132019-07-11 21:38:52 +020035 else
36 {
Cristyc60d3282020-07-26 09:55:35 -040037 offset=(ssize_t) strlen(*messages);
38 *messages=(char *) ResizeQuantumMemory(*messages,(size_t) (offset+length+
39 1),sizeof(char *));
Dirk Lemstraea979132019-07-11 21:38:52 +020040 }
41 if (*messages == (char *) NULL)
42 return(0);
Cristyc60d3282020-07-26 09:55:35 -040043 (void) memcpy(*messages+offset,message,(size_t) length);
Dirk Lemstraea979132019-07-11 21:38:52 +020044 (*messages)[length+offset] ='\0';
45 return(length);
46}
Dirk Lemstraea979132019-07-11 21:38:52 +020047
Dirk Lemstra512fbb52020-09-15 20:32:55 +020048static 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}
Dirk Lemstraa7daffd2020-09-19 10:06:26 +020059#endif
Dirk Lemstra512fbb52020-09-15 20:32:55 +020060
Dirk Lemstradb933202021-01-05 21:51:15 +010061static 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
Cristyc60d3282020-07-26 09:55:35 -040079static inline MagickBooleanType InvokeGhostscriptDelegate(
Dirk Lemstraea979132019-07-11 21:38:52 +020080 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
Dirk Lemstraea979132019-07-11 21:38:52 +0200100 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
Dirk Lemstraea979132019-07-11 21:38:52 +0200113 int
114 argc,
115 code;
116
Cristyf2dc1dd2020-12-28 13:59:26 -0500117 ssize_t
Dirk Lemstraea979132019-07-11 21:38:52 +0200118 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)
Dirk Lemstradb933202021-01-05 21:51:15 +0100143 return(ExecuteGhostscriptCommand(verbose,command,message,exception));
Dirk Lemstraea979132019-07-11 21:38:52 +0200144 if (verbose != MagickFalse)
145 {
Dirk Lemstra512fbb52020-09-15 20:32:55 +0200146 (void) fprintf(stdout,"[ghostscript library %.2f]",
147 GhostscriptVersion(ghost_info));
Dirk Lemstraea979132019-07-11 21:38:52 +0200148 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)
Dirk Lemstradb933202021-01-05 21:51:15 +0100155 return(ExecuteGhostscriptCommand(verbose,command,message,exception));
Dirk Lemstraea979132019-07-11 21:38:52 +0200156 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,
Dirk Lemstra512fbb52020-09-15 20:32:55 +0200179 "[ghostscript library %.2f]%s: %s",GhostscriptVersion(ghost_info),
Dirk Lemstraea979132019-07-11 21:38:52 +0200180 args_start,errors);
181 else
182 {
183 (void) ThrowMagickException(exception,GetMagickModule(),
184 DelegateError,"PostscriptDelegateFailed",
Dirk Lemstra512fbb52020-09-15 20:32:55 +0200185 "`[ghostscript library %.2f]%s': %s",GhostscriptVersion(ghost_info),
186 args_start,errors);
Dirk Lemstraea979132019-07-11 21:38:52 +0200187 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
204static 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
Cristyc60d3282020-07-26 09:55:35 -0400221static inline void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer,
Cristyb13bbd72019-07-13 09:06:57 -0400222 StringInfo **profile)
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200223{
224#define BeginXMPPacket "?xpacket begin="
225#define EndXMPPacket "<?xpacket end="
226
227 int
228 c;
229
230 MagickBooleanType
Cristyb13bbd72019-07-13 09:06:57 -0400231 found_end,
232 status;
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200233
Cristyf2dc1dd2020-12-28 13:59:26 -0500234 char
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200235 *p;
236
237 size_t
238 length;
239
240 ssize_t
241 count;
242
243 if (*profile != (StringInfo *) NULL)
244 return;
Cristyb13bbd72019-07-13 09:06:57 -0400245 status=CompareMagickByteBuffer(buffer,BeginXMPPacket,strlen(BeginXMPPacket));
246 if (status == MagickFalse)
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200247 return;
248 length=8192;
249 *profile=AcquireStringInfo(length);
250 found_end=MagickFalse;
251 p=(char *) GetStringInfoDatum(*profile);
252 *p++='<';
253 count=1;
Cristyb13bbd72019-07-13 09:06:57 -0400254 for (c=ReadMagickByteBuffer(buffer); c != EOF; c=ReadMagickByteBuffer(buffer))
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200255 {
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)
Cristyb13bbd72019-07-13 09:06:57 -0400265 found_end=CompareMagickByteBuffer(buffer,EndXMPPacket,
266 strlen(EndXMPPacket));
Dirk Lemstra8bdcc022019-07-12 10:22:51 +0200267 else
268 {
269 if (c == (int) '>')
270 break;
271 }
272 }
273 SetStringInfoLength(*profile,(size_t) count);
274}
275
Cristyb13bbd72019-07-13 09:06:57 -0400276#endif