| /* |
| Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization |
| dedicated to making software imaging solutions freely available. |
| |
| You may not use this file except in compliance with the License. You may |
| obtain a copy of the License at |
| |
| https://imagemagick.org/script/license.php |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| #ifndef MAGICK_GHOSTSCRIPT_BUFFER_PRIVATE_H |
| #define MAGICK_GHOSTSCRIPT_BUFFER_PRIVATE_H |
| |
| #include "coders/bytebuffer-private.h" |
| |
| #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) |
| static int MagickDLLCall GhostscriptDelegateMessage(void *handle, |
| const char *message,int length) |
| { |
| char |
| **messages; |
| |
| ssize_t |
| offset; |
| |
| offset=0; |
| messages=(char **) handle; |
| if (*messages == (char *) NULL) |
| *messages=(char *) AcquireQuantumMemory((size_t) length+1,sizeof(char *)); |
| else |
| { |
| offset=(ssize_t) strlen(*messages); |
| *messages=(char *) ResizeQuantumMemory(*messages,(size_t) (offset+length+ |
| 1),sizeof(char *)); |
| } |
| if (*messages == (char *) NULL) |
| return(0); |
| (void) memcpy(*messages+offset,message,(size_t) length); |
| (*messages)[length+offset] ='\0'; |
| return(length); |
| } |
| |
| static double GhostscriptVersion(const GhostInfo *ghost_info) |
| { |
| gsapi_revision_t |
| revision; |
| |
| if ((ghost_info->revision)(&revision,(int) sizeof(revision)) != 0) |
| return(0.0); |
| if (revision.revision > 1000) |
| return(revision.revision/1000.0); |
| return(revision.revision/100.0); |
| } |
| #endif |
| |
| static inline MagickBooleanType ExecuteGhostscriptCommand( |
| const MagickBooleanType verbose,const char *command,char *message, |
| ExceptionInfo *exception) |
| { |
| int |
| status; |
| |
| status=ExternalDelegateCommand(MagickFalse,verbose,command,message, |
| exception); |
| if (status == 0) |
| return(MagickTrue); |
| if (status < 0) |
| return(MagickFalse); |
| (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, |
| "FailedToExecuteCommand","`%s' (%d)",command,status); |
| return(MagickFalse); |
| } |
| |
| static inline MagickBooleanType InvokeGhostscriptDelegate( |
| const MagickBooleanType verbose,const char *command,char *message, |
| ExceptionInfo *exception) |
| { |
| int |
| status; |
| |
| #if defined(MAGICKCORE_GS_DELEGATE) || defined(MAGICKCORE_WINDOWS_SUPPORT) |
| #define SetArgsStart(command,args_start) \ |
| if (args_start == (const char *) NULL) \ |
| { \ |
| if (*command != '"') \ |
| args_start=strchr(command,' '); \ |
| else \ |
| { \ |
| args_start=strchr(command+1,'"'); \ |
| if (args_start != (const char *) NULL) \ |
| args_start++; \ |
| } \ |
| } |
| |
| char |
| **argv, |
| *errors; |
| |
| const char |
| *args_start = (const char *) NULL; |
| |
| const GhostInfo |
| *ghost_info; |
| |
| gs_main_instance |
| *interpreter; |
| |
| int |
| argc, |
| code; |
| |
| ssize_t |
| i; |
| |
| #if defined(MAGICKCORE_WINDOWS_SUPPORT) |
| ghost_info=NTGhostscriptDLLVectors(); |
| #else |
| GhostInfo |
| ghost_info_struct; |
| |
| ghost_info=(&ghost_info_struct); |
| (void) memset(&ghost_info_struct,0,sizeof(ghost_info_struct)); |
| ghost_info_struct.delete_instance=(void (*)(gs_main_instance *)) |
| gsapi_delete_instance; |
| ghost_info_struct.exit=(int (*)(gs_main_instance *)) gsapi_exit; |
| ghost_info_struct.new_instance=(int (*)(gs_main_instance **,void *)) |
| gsapi_new_instance; |
| ghost_info_struct.init_with_args=(int (*)(gs_main_instance *,int,char **)) |
| gsapi_init_with_args; |
| ghost_info_struct.run_string=(int (*)(gs_main_instance *,const char *,int, |
| int *)) gsapi_run_string; |
| ghost_info_struct.set_stdio=(int (*)(gs_main_instance *,int (*)(void *,char *, |
| int),int (*)(void *,const char *,int),int (*)(void *, const char *, int))) |
| gsapi_set_stdio; |
| ghost_info_struct.revision=(int (*)(gsapi_revision_t *,int)) gsapi_revision; |
| #endif |
| if (ghost_info == (GhostInfo *) NULL) |
| return(ExecuteGhostscriptCommand(verbose,command,message,exception)); |
| if (verbose != MagickFalse) |
| { |
| (void) fprintf(stdout,"[ghostscript library %.2f]", |
| GhostscriptVersion(ghost_info)); |
| SetArgsStart(command,args_start); |
| (void) fputs(args_start,stdout); |
| } |
| interpreter=(gs_main_instance *) NULL; |
| errors=(char *) NULL; |
| status=(ghost_info->new_instance)(&interpreter,(void *) &errors); |
| if (status < 0) |
| return(ExecuteGhostscriptCommand(verbose,command,message,exception)); |
| code=0; |
| argv=StringToArgv(command,&argc); |
| if (argv == (char **) NULL) |
| { |
| (ghost_info->delete_instance)(interpreter); |
| return(MagickFalse); |
| } |
| (void) (ghost_info->set_stdio)(interpreter,(int (MagickDLLCall *)(void *, |
| char *,int)) NULL,GhostscriptDelegateMessage,GhostscriptDelegateMessage); |
| status=(ghost_info->init_with_args)(interpreter,argc-1,argv+1); |
| if (status == 0) |
| status=(ghost_info->run_string)(interpreter,"systemdict /start get exec\n", |
| 0,&code); |
| (ghost_info->exit)(interpreter); |
| (ghost_info->delete_instance)(interpreter); |
| for (i=0; i < (ssize_t) argc; i++) |
| argv[i]=DestroyString(argv[i]); |
| argv=(char **) RelinquishMagickMemory(argv); |
| if (status != 0) |
| { |
| SetArgsStart(command,args_start); |
| if (status == -101) /* quit */ |
| (void) FormatLocaleString(message,MaxTextExtent, |
| "[ghostscript library %.2f]%s: %s",GhostscriptVersion(ghost_info), |
| args_start,errors); |
| else |
| { |
| (void) ThrowMagickException(exception,GetMagickModule(), |
| DelegateError,"PostscriptDelegateFailed", |
| "`[ghostscript library %.2f]%s': %s",GhostscriptVersion(ghost_info), |
| args_start,errors); |
| if (errors != (char *) NULL) |
| errors=DestroyString(errors); |
| (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
| "Ghostscript returns status %d, exit code %d",status,code); |
| return(MagickFalse); |
| } |
| } |
| if (errors != (char *) NULL) |
| errors=DestroyString(errors); |
| return(MagickTrue); |
| #else |
| status=ExternalDelegateCommand(MagickFalse,verbose,command,(char *) NULL, |
| exception); |
| return(status == 0 ? MagickTrue : MagickFalse); |
| #endif |
| } |
| |
| static MagickBooleanType IsGhostscriptRendered(const char *path) |
| { |
| MagickBooleanType |
| status; |
| |
| struct stat |
| attributes; |
| |
| if ((path == (const char *) NULL) || (*path == '\0')) |
| return(MagickFalse); |
| status=GetPathAttributes(path,&attributes); |
| if ((status != MagickFalse) && S_ISREG(attributes.st_mode) && |
| (attributes.st_size > 0)) |
| return(MagickTrue); |
| return(MagickFalse); |
| } |
| |
| static inline void ReadGhostScriptXMPProfile(MagickByteBuffer *buffer, |
| StringInfo **profile) |
| { |
| #define BeginXMPPacket "?xpacket begin=" |
| #define EndXMPPacket "<?xpacket end=" |
| |
| int |
| c; |
| |
| MagickBooleanType |
| found_end, |
| status; |
| |
| char |
| *p; |
| |
| size_t |
| length; |
| |
| ssize_t |
| count; |
| |
| if (*profile != (StringInfo *) NULL) |
| return; |
| status=CompareMagickByteBuffer(buffer,BeginXMPPacket,strlen(BeginXMPPacket)); |
| if (status == MagickFalse) |
| return; |
| length=8192; |
| *profile=AcquireStringInfo(length); |
| found_end=MagickFalse; |
| p=(char *) GetStringInfoDatum(*profile); |
| *p++='<'; |
| count=1; |
| for (c=ReadMagickByteBuffer(buffer); c != EOF; c=ReadMagickByteBuffer(buffer)) |
| { |
| if (count == (ssize_t) length) |
| { |
| length<<=1; |
| SetStringInfoLength(*profile,length); |
| p=(char *) GetStringInfoDatum(*profile)+count; |
| } |
| count++; |
| *p++=(char) c; |
| if (found_end == MagickFalse) |
| found_end=CompareMagickByteBuffer(buffer,EndXMPPacket, |
| strlen(EndXMPPacket)); |
| else |
| { |
| if (c == (int) '>') |
| break; |
| } |
| } |
| SetStringInfoLength(*profile,(size_t) count); |
| } |
| |
| #endif |