-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGSAPI.php
More file actions
227 lines (199 loc) · 9.55 KB
/
GSAPI.php
File metadata and controls
227 lines (199 loc) · 9.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<?php
declare(strict_types=1);
namespace Fawno\GhostscriptAPI;
use FFI;
use FFI\CData;
use Fawno\GhostscriptAPI\GSAPIException;
use Fawno\GhostscriptAPI\FFIExtended;
class GSAPI extends FFIExtended {
public const GS_ARG_ENCODING_LOCAL = 0;
public const GS_ARG_ENCODING_UTF8 = 1;
public const GS_ARG_ENCODING_UTF16LE = 2;
public const GS_PERMIT_FILE_READING = 0;
public const GS_PERMIT_FILE_WRITING = 1;
public const GS_PERMIT_FILE_CONTROL = 2;
public const GS_SPT_INVALID = -1;
/** void * is NULL */
public const GS_SPT_NULL = 0;
/** void * is a pointer to an int (0 false, non-zero true). */
public const GS_SPT_BOOL = 1;
/** void * is a pointer to an int */
public const GS_SPT_INT = 2;
/** void * is a float * */
public const GS_SPT_FLOAT = 3;
/** void * is a char * */
public const GS_SPT_NAME = 4;
/** void * is a char * */
public const GS_SPT_STRING = 5;
/** void * is a long * */
public const GS_SPT_LONG = 6;
/** void * is an int64_t * */
public const GS_SPT_I64 = 7;
/** void * is a size_t * */
public const GS_SPT_SIZE_T = 8;
/** void * is a pointer to a char * to be parsed */
public const GS_SPT_PARSED = 9;
/**
* Setting a typed param causes it to be instantly fed to to the
* device. This can cause the device to reinitialise itself. Hence,
* setting a sequence of typed params can cause the device to reset
* itself several times. Accordingly, if you OR the type with
* gs_spt_more_to_come, the param will held ready to be passed into
* the device, and will only actually be sent when the next typed
* param is set without this flag (or on device init). Not valid
* for get_typed_param.
*
* @var 1 << 31
*/
public const GS_SPT_MORE_TO_COME = 1 << 31;
protected const PARAMS = [
'',
'-dSAFER',
'-dBATCH',
'-dNOPAUSE',
];
protected CData $gsapi_revision;
protected CData $instance;
protected const HEADER = <<<EOT
typedef struct gsapi_revision_s { const char *product; const char *copyright; long revision; long revisiondate; } gsapi_revision_t;
typedef struct display_callback_s display_callback;
typedef struct gs_memory_s gs_memory_t;
typedef struct gp_file_s gp_file;
typedef int (*gs_callout)(void *instance, void *callout_handle, const char *device_name, int id, int size, void *data);
typedef enum {
gs_spt_invalid = -1,
gs_spt_null = 0, /* void * is NULL */
gs_spt_bool = 1, /* void * is a pointer to an int (0 false, non-zero true). */
gs_spt_int = 2, /* void * is a pointer to an int */
gs_spt_float = 3, /* void * is a float * */
gs_spt_name = 4, /* void * is a char * */
gs_spt_string = 5, /* void * is a char * */
gs_spt_long = 6, /* void * is a long * */
gs_spt_i64 = 7, /* void * is an int64_t * */
gs_spt_size_t = 8, /* void * is a size_t * */
gs_spt_parsed = 9, /* void * is a pointer to a char * to be parsed */
/* Setting a typed param causes it to be instantly fed to to the
* device. This can cause the device to reinitialise itself. Hence,
* setting a sequence of typed params can cause the device to reset
* itself several times. Accordingly, if you OR the type with
* gs_spt_more_to_come, the param will held ready to be passed into
* the device, and will only actually be sent when the next typed
* param is set without this flag (or on device init). Not valid
* for get_typed_param. */
gs_spt_more_to_come = 1<<31
} gs_set_param_type;
typedef struct {
int (*open_file)(const gs_memory_t *mem,
void *secret,
const char *fname,
const char *mode,
gp_file **file);
int (*open_pipe)(const gs_memory_t *mem,
void *secret,
const char *fname,
char *rfname, /* 4096 bytes */
const char *mode,
gp_file **file);
int (*open_scratch)(const gs_memory_t *mem,
void *secret,
const char *prefix,
char *rfname, /* 4096 bytes */
const char *mode,
int rm,
gp_file **file);
int (*open_printer)(const gs_memory_t *mem,
void *secret,
char *fname, /* 4096 bytes */
int binary,
gp_file **file);
int (*open_handle)(const gs_memory_t *mem,
void *secret,
char *fname, /* 4096 bytes */
const char *mode,
gp_file **file);
} gsapi_fs_t;
int gsapi_revision (gsapi_revision_t *pr, int len);
int gsapi_new_instance (void **pinstance, void *caller_handle);
void gsapi_delete_instance (void *instance);
int gsapi_set_stdio_with_handle (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), void *caller_handle);
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_set_poll_with_handle (void *instance, int(*poll_fn)(void *caller_handle), void *caller_handle);
int gsapi_set_poll (void *instance, int(*poll_fn)(void *caller_handle));
int gsapi_set_display_callback (void *instance, display_callback *callback);
int gsapi_register_callout (void *instance, gs_callout callout, void *callout_handle);
void gsapi_deregister_callout (void *instance, gs_callout callout, void *callout_handle);
int gsapi_set_arg_encoding (void *instance, int encoding);
int gsapi_get_default_device_list(void *instance, char **list, int *listlen);
int gsapi_set_default_device_list(void *instance, const char *list, int listlen);
int gsapi_run_string_begin (void *instance, int user_errors, int *pexit_code);
int gsapi_run_string_continue (void *instance, const char *str, unsigned int length, int user_errors, int *pexit_code);
int gsapi_run_string_end (void *instance, int user_errors, int *pexit_code);
int gsapi_run_string_with_length (void *instance, const char *str, unsigned int length, int user_errors, int *pexit_code);
int gsapi_run_string (void *instance, const char *str, int user_errors, int *pexit_code);
int gsapi_run_file (void *instance, const char *file_name, int user_errors, int *pexit_code);
int gsapi_init_with_args (void *instance, int argc, char **argv);
int gsapi_exit (void *instance);
int gsapi_set_param(void *instance, const char *param, const void *value, gs_set_param_type type);
int gsapi_get_param(void *instance, const char *param, void *value, gs_set_param_type type);
int gsapi_enumerate_params(void *instance, void **iter, const char **key, gs_set_param_type *type);
int gsapi_add_control_path(void *instance, int type, const char *path);
int gsapi_remove_control_path(void *instance, int type, const char *path);
void gsapi_purge_control_paths(void *instance, int type);
void gsapi_activate_path_control(void *instance, int enable);
int gsapi_is_path_control_active(void *instance);
int gsapi_add_fs (void *instance, gsapi_fs_t *fs, void *secret);
void gsapi_remove_fs (void *instance, gsapi_fs_t *fs, void *secret);
EOT;
public function __construct(string $lib_path) {
if (!is_file($lib_path)) {
throw new GSAPIException(sprintf('% not found', $lib_path));
}
$this->ffi = FFI::cdef(self::HEADER, $lib_path);
$this->gsapi_revision = $this->ffi->new('gsapi_revision_t');
if (0 == $this->ffi->gsapi_revision(FFI::addr($this->gsapi_revision), FFI::sizeof($this->gsapi_revision))) {
if ($this->gsapi_revision->revision < 956) {
throw new GSAPIException('Need at least Ghostscript 9.18');
}
} else {
throw new GSAPIException('Revision structure size is incorrect');
}
if (0 !== $code = $this->new_instance()) {
throw new GSAPIException('Error creating new gsapi instance', $code);
}
}
public function exit_instance () : int {
return $this->ffi->gsapi_exit($this->instance);
}
public function delete_instance () : void {
$this->ffi->gsapi_delete_instance($this->instance);
}
public function new_instance () : int {
$this->instance = $this->ffi->new('void *');
return $this->ffi->gsapi_new_instance(FFI::addr($this->instance), null);
}
public function renew_instance () : void {
if (0 !== $code = $this->exit_instance()) {
throw new GSAPIException('Error shutdown instance', $code);
}
$this->delete_instance();
if (0 !== $code = $this->new_instance()) {
throw new GSAPIException('Error creating new gsapi instance', $code);
}
}
public function set_stdio (object $stdin_fn, object $stdout_fn, object $stderr_fn) : int {
return $this->ffi->gsapi_set_stdio($this->instance, $stdin_fn, $stdout_fn, $stderr_fn);
}
public function set_arg_encoding (int $encoding) : int {
return $this->ffi->gsapi_set_arg_encoding($this->instance, $encoding);
}
public function init_with_args (array $argv) : int {
$params = array_merge(self::PARAMS, $argv);
$argc = count($params);
$argv = $this->argsPtr($params);
return $this->ffi->gsapi_init_with_args($this->instance, $argc, $argv);
}
public function run_with_args (array $argv) : void {
$this->init_with_args($argv);
$this->renew_instance();
}
}