w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

Ghostscript.cpp
Go to the documentation of this file.
1 /*************************************************************************
2 ** Ghostscript.cpp **
3 ** **
4 ** This file is part of dvisvgm -- a fast DVI to SVG converter **
5 ** Copyright (C) 2005-2021 Martin Gieseking <martin.gieseking@uos.de> **
6 ** **
7 ** This program is free software; you can redistribute it and/or **
8 ** modify it under the terms of the GNU General Public License as **
9 ** published by the Free Software Foundation; either version 3 of **
10 ** the License, or (at your option) any later version. **
11 ** **
12 ** This program is distributed in the hope that it will be useful, but **
13 ** WITHOUT ANY WARRANTY; without even the implied warranty of **
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
15 ** GNU General Public License for more details. **
16 ** **
17 ** You should have received a copy of the GNU General Public License **
18 ** along with this program; if not, see <http://www.gnu.org/licenses/>. **
19 *************************************************************************/
20 
21 #include <config.h>
22 #include "FilePath.hpp"
23 #include "Ghostscript.hpp"
24 #include "utility.hpp"
25 #if !defined(DISABLE_GS)
26 #include <cstring>
27 #include <iomanip>
28 #include <sstream>
29 #if defined(HAVE_LIBGS)
30  #include <ghostscript/ierrors.h>
31 #else
32  #include "ierrors.h"
33  #include "FileFinder.hpp"
34 #endif
35 
36 using namespace std;
37 
38 // name of Ghostscript shared library set by the user
40 
41 #ifndef HAVE_LIBGS
42 
43 #ifdef _WIN32
44 /** Looks up the path of the Ghostscript DLL in the Windows registry and returns it.
45  * If there is no proper registry entry, the returned string is empty. */
46 static string get_path_from_registry () {
47 #ifdef RRF_RT_REG_SZ // RegGetValueA and RRF_RT_REG_SZ may not be defined for some oldish MinGW
48  REGSAM mode = KEY_READ|KEY_QUERY_VALUE;
49 #ifdef KEY_WOW64_64KEY
50 #ifdef _WIN64
51  mode |= KEY_WOW64_64KEY;
52 #else
53  mode |= KEY_WOW64_32KEY;
54 #endif
55 #endif
56  for (const char *gs_company : {"GPL", "GNU", "AFPL", "Aladdin"}) {
57  const string reg_path = string("SOFTWARE\\") + gs_company + " Ghostscript";
58  for (HKEY reg_root : {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}) {
59  HKEY hkey;
60  if (RegOpenKeyExA(reg_root, reg_path.c_str(), 0, mode, &hkey) == ERROR_SUCCESS) {
61  char subkey[16];
62  for (int k=0; RegEnumKeyA(hkey, k, subkey, 16) == ERROR_SUCCESS; k++) {
63  istringstream iss(subkey);
64  int major_version;
65  iss >> major_version;
66  if (major_version >= 7) {
67  char dll_path[512]; // path to Ghostscript DLL stored in the registry
68  DWORD length = 512;
69  if (RegGetValueA(hkey, subkey, "GS_DLL", RRF_RT_REG_SZ, nullptr, dll_path, &length) == ERROR_SUCCESS) {
70  RegCloseKey(hkey);
71  return dll_path;
72  }
73  }
74  }
75  RegCloseKey(hkey);
76  }
77  }
78  }
79 #endif // RRF_RT_REG_SZ
80  return "";
81 }
82 #endif // _WIN32
83 
84 #if defined(_WIN32) && !defined(_WIN64)
85 static string get_gsdll32 () {
86  string pathstr;
87 #if defined(TEXLIVEWIN32)
88  char exepath[256];
89  if (GetModuleFileNameA(NULL, exepath, 256)) {
90  FilePath path(exepath);
91  path.set(path.absolute(false)+"/../../tlpkg/tlgs");
92  pathstr = util::replace(path.absolute(false)+"/", "/", "\\");
93  string envvar = "GS_LIB=";
94  for (string dirs : {"lib", "fonts", "Resource\\Init", "Resource", "kanji"})
95  envvar += pathstr+dirs+";";
96  _putenv(envvar.c_str());
97  pathstr += "bin\\";
98  }
99 #endif
100  return pathstr+"gsdll32.dll";
101 }
102 #endif // _WIN32 && !_WIN64
103 
104 
105 /** Try to detect name of the Ghostscript shared library depending on the user settings.
106  * @param[in] fname path/filename given by the user
107  * @return name of Ghostscript shared library */
108 static string get_libgs (const string &fname) {
109  if (!fname.empty())
110  return fname;
111 #ifdef MIKTEX
112 #if defined(_WIN64)
113  const char *gsdll = "mgsdll64.dll";
114 #else
115  const char *gsdll = "mgsdll32.dll";
116 #endif
117  // try to look up the Ghostscript DLL coming with MiKTeX
118  if (const char *gsdll_path = FileFinder::instance().lookup(gsdll))
119  return gsdll_path;
120 #endif // MIKTEX
121 #if defined(_WIN32)
122  // try to look up the path of the Ghostscript DLL in the Windows registry
123  string gsdll_path = get_path_from_registry();
124  if (!gsdll_path.empty())
125  return gsdll_path;
126 #endif //_WIN32
127 #if defined(_WIN64)
128  return "gsdll64.dll";
129 #elif defined(_WIN32)
130  return get_gsdll32();
131 #else
132  // try to find libgs.so.X on the user's system
133  const int abi_min=7, abi_max=9; // supported libgs ABI versions
134  for (int i=abi_max; i >= abi_min; i--) {
135 #if defined(__CYGWIN__)
136  string dlname = "cyggs-" + to_string(i) + ".dll";
137 #else
138  string dlname = "libgs.so." + to_string(i);
139 #endif
140  DLLoader loader(dlname);
141  if (loader.loaded())
142  return dlname;
143 #if defined(__APPLE__)
144  dlname = "libgs." + to_string(i) + ".dylib";
145  if (loader.loadLibrary(dlname))
146  return dlname;
147  dlname = "libgs.dylib." + to_string(i);
148  if (loader.loadLibrary(dlname))
149  return dlname;
150 #endif
151  }
152 #endif
153  // no appropriate library found
154  return "";
155 }
156 #endif // !HAVE_LIBGS
157 
158 
159 /** Loads the Ghostscript library but does not create an instance. This
160  * constructor should only be used to call available() and revision(). */
162 #if !defined(HAVE_LIBGS)
163  : DLLoader(get_libgs(LIBGS_NAME))
164 #endif
165 {
166 }
167 
168 
169 /** Tries to load the shared library and to initialize Ghostscript.
170  * @param[in] argc number of parameters in array argv
171  * @param[in] argv parameters passed to Ghostscript
172  * @param[in] caller this parameter is passed to all callback functions */
173 Ghostscript::Ghostscript (int argc, const char **argv, void *caller)
174 #if !defined(HAVE_LIBGS)
175  : DLLoader(get_libgs(LIBGS_NAME))
176 #endif
177 {
178  init(argc, argv, caller);
179 }
180 
181 
182 /** Exits Ghostscript and unloads the dynamic library. */
184  if (_inst) {
185  this->exit();
186  delete_instance();
187  }
188 }
189 
190 
191 bool Ghostscript::init (int argc, const char **argv, void *caller) {
192  if (!_inst) {
193  int status = new_instance(&_inst, caller);
194  if (status < 0)
195  _inst = nullptr;
196  else {
197  init_with_args(argc, const_cast<char**>(argv));
198  }
199  }
200  return _inst != nullptr;
201 }
202 
203 
204 /** Returns true if Ghostscript library was found and can be loaded. */
206 #if defined(HAVE_LIBGS)
207  return true;
208 #else
209  gsapi_revision_t rev;
210  return loaded() && revision(&rev);
211 #endif
212 }
213 
214 
215 /** Retrieves version information about Ghostscript.
216  * @param[out] r takes the revision information (see GS API documentation for further details)
217  * @return true on success */
219 #if defined(HAVE_LIBGS)
220  return (gsapi_revision(r, sizeof(gsapi_revision_t)) == 0);
221 #else
222  if (auto fn = LOAD_SYMBOL(gsapi_revision))
223  return (fn(r, sizeof(gsapi_revision_t)) == 0);
224  return false;
225 #endif
226 }
227 
228 
229 /** Returns the revision number of the GS library. */
232  if (revision(&r))
233  return static_cast<int>(r.revision);
234  return 0;
235 }
236 
237 
238 /** Returns the revision of the GS library as a string of the form "MAJOR.MINOR". */
240  string revstr;
241  if (int rev = revision()) {
242  if (rev < 1000) { // until GS 9.52
243  revstr = to_string(rev/100) + ".";
244  if (rev % 100 < 10)
245  revstr += "0";
246  revstr += to_string(rev%100);
247  }
248  else { // as of GS 9.52.1, see ghostpdl/base/gsmisc.c
249  int major = rev / 1000;
250  int minor = (rev - major*1000)/10;
251  int patch = rev % 10;
252  revstr = to_string(major) + "." + to_string(minor) + "." + to_string(patch);
253  }
254  }
255  return revstr;
256 }
257 
258 
259 /** Creates a new instance of Ghostscript. This method is called by the constructor and
260  * should not be used elsewhere.
261  * @param[out] psinst handle of newly created instance (or 0 on error)
262  * @param[in] caller pointer forwarded to callback functions */
263 int Ghostscript::new_instance (void **psinst, void *caller) {
264 #if defined(HAVE_LIBGS)
265  return gsapi_new_instance(psinst, caller);
266 #else
267  if (auto fn = LOAD_SYMBOL(gsapi_new_instance))
268  return fn(psinst, caller);
269  *psinst = nullptr;
270  return 0;
271 #endif
272 }
273 
274 
275 /** Destroys the current instance of Ghostscript. This method is called by the destructor
276  * and should not be used elsewhere. */
278 #if defined(HAVE_LIBGS)
280 #else
282  fn(_inst);
283 #endif
284 }
285 
286 
287 /** Exits the interpreter. Must be called before destroying the GS instance. */
289 #if defined(HAVE_LIBGS)
290  return gsapi_exit(_inst);
291 #else
292  if (auto fn = LOAD_SYMBOL(gsapi_exit))
293  return fn(_inst);
294  return 0;
295 #endif
296 }
297 
298 
299 /** Sets the I/O callback functions.
300  * @param[in] in pointer to stdin handler
301  * @param[in] out pointer to stdout handler
302  * @param[in] err pointer to stderr handler */
304 #if defined(HAVE_LIBGS)
305  return gsapi_set_stdio(_inst, in, out, err);
306 #else
307  if (auto fn = LOAD_SYMBOL(gsapi_set_stdio))
308  return fn(_inst, in, out, err);
309  return 0;
310 #endif
311 }
312 
313 
314 /** Initializes Ghostscript with a set of optional parameters. This
315  * method is called by the constructor and should not be used elsewhere.
316  * @param[in] argc number of paramters
317  * @param[in] argv parameters passed to Ghostscript */
319 #if defined(HAVE_LIBGS)
321 #else
322  if (auto fn = LOAD_SYMBOL(gsapi_init_with_args))
323  return fn(_inst, argc, argv);
324  return 0;
325 #endif
326 }
327 
328 
329 /** Tells Ghostscript that several calls of run_string_continue will follow. */
330 int Ghostscript::run_string_begin (int user_errors, int *pexit_code) {
331 #if defined(HAVE_LIBGS)
332  return gsapi_run_string_begin(_inst, user_errors, pexit_code);
333 #else
335  return fn(_inst, user_errors, pexit_code);
336  *pexit_code = 0;
337  return 0;
338 #endif
339 }
340 
341 
342 /** Executes a chunk of PostScript commands given by a buffer of characters. The size of
343  * this buffer must not exceed 64KB. Longer programs can be split into arbitrary smaller chunks
344  * and passed to Ghostscript by successive calls of run_string_continue.
345  * @param[in] str buffer containing the PostScript code
346  * @param[in] length number of characters in buffer
347  * @param[in] user_errors if non-negative, the default PS error values will be generated, otherwise this value is returned
348  * @param[out] pexit_code takes the PS error code */
349 int Ghostscript::run_string_continue (const char *str, unsigned length, int user_errors, int *pexit_code) {
350 #if defined(HAVE_LIBGS)
351  return gsapi_run_string_continue(_inst, str, length, user_errors, pexit_code);
352 #else
354  return fn(_inst, str, length, user_errors, pexit_code);
355  *pexit_code = 0;
356  return 0;
357 #endif
358 }
359 
360 
361 /** Terminates the successive code feeding. Must be called after the last call of run_string_continue. */
362 int Ghostscript::run_string_end (int user_errors, int *pexit_code) {
363 #if defined(HAVE_LIBGS)
364  return gsapi_run_string_end(_inst, user_errors, pexit_code);
365 #else
366  if (auto fn = LOAD_SYMBOL(gsapi_run_string_end))
367  return fn(_inst, user_errors, pexit_code);
368  *pexit_code = 0;
369  return 0;
370 #endif
371 }
372 
373 
374 const char* Ghostscript::error_name (int code) {
375  if (code < 0)
376  code = -code;
377  const char *error_names[] = { ERROR_NAMES };
378  if (code == 0 || (size_t)code > sizeof(error_names)/sizeof(error_names[0]))
379  return nullptr;
380 #if defined(HAVE_LIBGS)
381  // use array defined in libgs to avoid linking the error strings into the binary
382  return gs_error_names[code-1];
383 #elif defined(_WIN32)
384  // gs_error_names is private in the Ghostscript DLL so we can't access it here
385  return error_names[code-1];
386 #else
387  if (auto error_names = loadSymbol<const char**>("gs_error_names"))
388  return error_names[code-1];
389  return nullptr;
390 #endif
391 }
392 
393 #endif // !DISABLE_GS
int __cdecl _putenv(char const *_EnvString)
#define LOAD_SYMBOL(sym)
Definition: DLLoader.hpp:70
static string get_libgs(const string &fname)
int code
Definition: aftopl.c:52
int lookup(const char *)
#define mode
Definition: aptex-macros.h:510
const char * envvar
Definition: automatic.cc:74
bool loaded() const
Definition: DLLoader.hpp:39
bool loadLibrary(const std::string &dlname)
Definition: DLLoader.cpp:35
static FileFinder & instance()
Definition: FileFinder.cpp:78
int(*)(void *caller, char *buf, int len) Stdin
Definition: Ghostscript.hpp:70
void delete_instance()
int(*)(void *caller, const char *str, int len) Stdout
Definition: Ghostscript.hpp:71
bool init(int argc, const char **argv, void *caller=nullptr)
int run_string_continue(const char *str, unsigned int length, int user_errors, int *pexit_code)
int init_with_args(int argc, char **argv)
void * _inst
Ghostscript handle needed to call the gsapi_foo functions.
Definition: Ghostscript.hpp:99
const char * error_name(int code)
static std::string LIBGS_NAME
Definition: Ghostscript.hpp:91
int run_string_begin(int user_errors, int *pexit_code)
int set_stdio(Stdin in, Stdout out, Stderr err)
int run_string_end(int user_errors, int *pexit_code)
int new_instance(void **psinst, void *caller)
std::string revisionstr()
bool available()
int(*)(void *caller, const char *str, int len) Stderr
Definition: Ghostscript.hpp:72
int gsapi_run_string_begin(void *instance, int user_errors, int *pexit_code)
void gsapi_delete_instance(void *instance)
int gsapi_exit(void *instance)
int gsapi_new_instance(void **pinstance, void *caller_handle)
int gsapi_run_string_end(void *instance, int user_errors, int *pexit_code)
int gsapi_set_stdio(void *instance, int(*stdin_fn)(void *caller_handle, char *buf, int len), int(*stdout_fn)(void *caller_handle, const char *str, int len), int(*stderr_fn)(void *caller_handle, const char *str, int len))
int gsapi_init_with_args(void *instance, int argc, char **argv)
int gsapi_run_string_continue(void *instance, const char *str, unsigned int length, int user_errors, int *pexit_code)
int gsapi_revision(gsapi_revision_t *pr, int len)
GSDLL gsdll
Definition: dwmaincgsdll.c:102
FILE * out
Definition: hbf2gf.c:286
const char *const gs_error_names[]
#define ERROR_NAMES
Definition: ierrors.h:90
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p scientific i
Definition: afcover.h:80
int major
Definition: pdfcolor.c:526
int minor
Definition: pdfcolor.c:527
#define string
Definition: ctangleboot.c:111
#define length(c)
Definition: ctangleboot.c:65
unsigned int DWORD
Definition: mktexlib.h:49
@ err
Definition: mtxline.h:24
string fn
Definition: fc-lang.py:335
STL namespace.
std::string replace(std::string str, const std::string &find, const std::string &repl)
Definition: utility.cpp:117
int k
Definition: otp-parser.c:70
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld init[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
char * fname
Definition: plain2.c:121
int r
Definition: ppmqvga.c:68
void to_string(struct val *vp)
Definition: strexpr.c:150
#define status
Slot * iss
Definition: opcodes.h:276
#define str(s)
Definition: sh6.c:399
static FILE * in
Definition: squeeze.c:36
Definition: inftrees.h:24
pointer path
Definition: t1imager.h:36
#define argv
Definition: xmain.c:270
#define argc
Definition: xmain.c:269