Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 1 | /* |
Cristy | d842011 | 2021-01-01 14:52:00 -0500 | [diff] [blame] | 2 | Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 3 | dedicated to making software imaging solutions freely available. |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 4 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 5 | You may not use this file except in compliance with the License. You may |
| 6 | obtain a copy of the License at |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 7 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 8 | https://imagemagick.org/script/license.php |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 9 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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 | |
Cristy | c8ab8d9 | 2019-07-13 09:15:22 -0400 | [diff] [blame] | 19 | #include "coders/bytebuffer-private.h" |
| 20 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 21 | #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) |
| 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) |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 34 | *messages=(char *) AcquireQuantumMemory((size_t) length+1,sizeof(char *)); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 35 | else |
| 36 | { |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 37 | offset=(ssize_t) strlen(*messages); |
| 38 | *messages=(char *) ResizeQuantumMemory(*messages,(size_t) (offset+length+ |
| 39 | 1),sizeof(char *)); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 40 | } |
| 41 | if (*messages == (char *) NULL) |
| 42 | return(0); |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 43 | (void) memcpy(*messages+offset,message,(size_t) length); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 44 | (*messages)[length+offset] ='\0'; |
| 45 | return(length); |
| 46 | } |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 47 | |
Dirk Lemstra | 512fbb5 | 2020-09-15 20:32:55 +0200 | [diff] [blame] | 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 | } |
Dirk Lemstra | a7daffd | 2020-09-19 10:06:26 +0200 | [diff] [blame] | 59 | #endif |
Dirk Lemstra | 512fbb5 | 2020-09-15 20:32:55 +0200 | [diff] [blame] | 60 | |
Dirk Lemstra | db93320 | 2021-01-05 21:51:15 +0100 | [diff] [blame] | 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 | |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 79 | static inline MagickBooleanType InvokeGhostscriptDelegate( |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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 | |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 113 | int |
| 114 | argc, |
| 115 | code; |
| 116 | |
Cristy | f2dc1dd | 2020-12-28 13:59:26 -0500 | [diff] [blame] | 117 | ssize_t |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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) |
Dirk Lemstra | db93320 | 2021-01-05 21:51:15 +0100 | [diff] [blame] | 143 | return(ExecuteGhostscriptCommand(verbose,command,message,exception)); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 144 | if (verbose != MagickFalse) |
| 145 | { |
Dirk Lemstra | 512fbb5 | 2020-09-15 20:32:55 +0200 | [diff] [blame] | 146 | (void) fprintf(stdout,"[ghostscript library %.2f]", |
| 147 | GhostscriptVersion(ghost_info)); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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) |
Dirk Lemstra | db93320 | 2021-01-05 21:51:15 +0100 | [diff] [blame] | 155 | return(ExecuteGhostscriptCommand(verbose,command,message,exception)); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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, |
Dirk Lemstra | 512fbb5 | 2020-09-15 20:32:55 +0200 | [diff] [blame] | 179 | "[ghostscript library %.2f]%s: %s",GhostscriptVersion(ghost_info), |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 180 | args_start,errors); |
| 181 | else |
| 182 | { |
| 183 | (void) ThrowMagickException(exception,GetMagickModule(), |
| 184 | DelegateError,"PostscriptDelegateFailed", |
Dirk Lemstra | 512fbb5 | 2020-09-15 20:32:55 +0200 | [diff] [blame] | 185 | "`[ghostscript library %.2f]%s': %s",GhostscriptVersion(ghost_info), |
| 186 | args_start,errors); |
Dirk Lemstra | ea97913 | 2019-07-11 21:38:52 +0200 | [diff] [blame] | 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 | |
| 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 | |
Cristy | c60d328 | 2020-07-26 09:55:35 -0400 | [diff] [blame] | 221 | static inline void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer, |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 222 | StringInfo **profile) |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 223 | { |
| 224 | #define BeginXMPPacket "?xpacket begin=" |
| 225 | #define EndXMPPacket "<?xpacket end=" |
| 226 | |
| 227 | int |
| 228 | c; |
| 229 | |
| 230 | MagickBooleanType |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 231 | found_end, |
| 232 | status; |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 233 | |
Cristy | f2dc1dd | 2020-12-28 13:59:26 -0500 | [diff] [blame] | 234 | char |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 235 | *p; |
| 236 | |
| 237 | size_t |
| 238 | length; |
| 239 | |
| 240 | ssize_t |
| 241 | count; |
| 242 | |
| 243 | if (*profile != (StringInfo *) NULL) |
| 244 | return; |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 245 | status=CompareMagickByteBuffer(buffer,BeginXMPPacket,strlen(BeginXMPPacket)); |
| 246 | if (status == MagickFalse) |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 247 | return; |
| 248 | length=8192; |
| 249 | *profile=AcquireStringInfo(length); |
| 250 | found_end=MagickFalse; |
| 251 | p=(char *) GetStringInfoDatum(*profile); |
| 252 | *p++='<'; |
| 253 | count=1; |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 254 | for (c=ReadMagickByteBuffer(buffer); c != EOF; c=ReadMagickByteBuffer(buffer)) |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 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) |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 265 | found_end=CompareMagickByteBuffer(buffer,EndXMPPacket, |
| 266 | strlen(EndXMPPacket)); |
Dirk Lemstra | 8bdcc02 | 2019-07-12 10:22:51 +0200 | [diff] [blame] | 267 | else |
| 268 | { |
| 269 | if (c == (int) '>') |
| 270 | break; |
| 271 | } |
| 272 | } |
| 273 | SetStringInfoLength(*profile,(size_t) count); |
| 274 | } |
| 275 | |
Cristy | b13bbd7 | 2019-07-13 09:06:57 -0400 | [diff] [blame] | 276 | #endif |