summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Liddell <chris.liddell@artifex.com>2017-11-17 15:17:03 +0000
committerRobin Watts <Robin.Watts@artifex.com>2018-12-07 14:17:55 -0500
commitabb742af3affbe00da625a1272d682ac5fd4c964 (patch)
treea201eae99bee574f5cf0fa2ffa208d9928c07e37
parenteab61428b3fa1e4078e71febefe406dad499814e (diff)
downloadghostpdl-abb742af3affbe00da625a1272d682ac5fd4c964.tar.gz
Commit of gpdl-shared-device branch.
This commit is a squashed version of the gpdl-shared-device branch. Essentially this is a first version of the new language switching mechanism. This does not build as part as "all", but rather as "experimental" or "gpdl".
-rw-r--r--Resource/Init/gs_cet.ps47
-rw-r--r--Resource/Init/gs_init.ps51
-rw-r--r--base/gp_mspol.c4
-rw-r--r--base/gs.mak17
-rw-r--r--base/gsalloc.c10
-rw-r--r--base/gsdevice.c2
-rw-r--r--base/gsiodev.c2
-rw-r--r--base/gsiodevs.c6
-rw-r--r--base/gslibctx.c112
-rw-r--r--base/gslibctx.h31
-rw-r--r--base/gsmalloc.c10
-rw-r--r--base/gsmalloc.h7
-rw-r--r--base/gsmchunk.c2
-rw-r--r--base/gsmemory.c2
-rw-r--r--base/gsmemory.h4
-rw-r--r--base/gsmemret.c2
-rw-r--r--base/gsstate.c8
-rw-r--r--base/gsutil.c5
-rw-r--r--base/gxdownscale.c217
-rw-r--r--base/gxdownscale.h35
-rw-r--r--configure.ac2
-rw-r--r--devices/devs.mak15
-rw-r--r--devices/gdevchameleon.c672
-rw-r--r--gpdl/psi/psitop.c405
-rw-r--r--pcl/pcl/pctop.c112
-rw-r--r--pcl/pl/pjparsei.c46
-rw-r--r--pcl/pl/pl.mak3
-rw-r--r--pcl/pl/plapi.c193
-rw-r--r--pcl/pl/plapi.h149
-rw-r--r--pcl/pl/plmain.c677
-rw-r--r--pcl/pl/plmain.h11
-rw-r--r--pcl/pl/pltop.c133
-rw-r--r--pcl/pl/pltop.h59
-rw-r--r--pcl/pl/plwmainc.c10
-rw-r--r--pcl/pl/realmain.c40
-rw-r--r--pcl/pxl/pxtop.c109
-rw-r--r--psi/dwdll.h2
-rw-r--r--psi/dwnodll.c2
-rw-r--r--psi/gsdll2.def2
-rw-r--r--psi/gsdll32.def2
-rw-r--r--psi/gsdll32metro.def2
-rw-r--r--psi/gsdll64.def2
-rw-r--r--psi/gsdll64metro.def2
-rw-r--r--psi/gsdllARM32metro.def2
-rw-r--r--psi/ialloc.c2
-rw-r--r--psi/iapi.c376
-rw-r--r--psi/iapi.h20
-rw-r--r--psi/icstate.h1
-rw-r--r--psi/igc.c6
-rw-r--r--psi/imain.c165
-rw-r--r--psi/imain.h26
-rw-r--r--psi/imainarg.c156
-rw-r--r--psi/imainarg.h7
-rw-r--r--psi/imemory.h2
-rw-r--r--psi/iminst.h5
-rw-r--r--psi/int.mak17
-rw-r--r--psi/interp.c60
-rw-r--r--psi/ireclaim.c6
-rw-r--r--psi/msvc.mak8
-rw-r--r--psi/opextern.h2
-rw-r--r--psi/psapi.c512
-rw-r--r--psi/psapi.h127
-rw-r--r--psi/zdevice.c31
-rw-r--r--psi/zfont.c2
-rw-r--r--psi/ziodevsc.c17
-rw-r--r--windows/ghostscript.vcproj16
-rw-r--r--xps/xpstop.c101
67 files changed, 3891 insertions, 1000 deletions
diff --git a/Resource/Init/gs_cet.ps b/Resource/Init/gs_cet.ps
index 4261e7956..3faa18e3d 100644
--- a/Resource/Init/gs_cet.ps
+++ b/Resource/Init/gs_cet.ps
@@ -73,6 +73,53 @@ dup 7 -1 put
% and GS_CHAR_FILL are now dynamic. Force CPSI compatibility.
//true .setCPSImode
+% Some QL jobs (/23-12B.PS for example) do:
+% '(%stdin) (r) file'
+% expecting that they are being read from stdin.
+% if that is not the case, they block waiting for input
+% from stdin.
+% This hooks the 'file' operator', so if a job tries to
+% open %stdin, and we're *not* reading the job from stdin
+% it'll return currentfile instead.
+/ofile /file load def
+/file
+{
+ 1 index (%stdin) eq 2 index (%stdin%) eq or
+ {
+ ofile dup currentfile eq not
+ {
+ pop currentfile
+ }if
+ }
+ {
+ ofile
+ } ifelse
+} bind odef
+currentdict /ofile undef
+
+% One QL job (23-12B.PS) effectively does:
+% (%stdin) (r) file 0 setfileposition
+% expecting it to throw an ioerror (stdin not being a positionable
+% stream.
+% With the above 'file' hook, when running from a file
+% rather than stdin, setfileposition will succeed, and we hit
+% an infinite loop - '0 setfileposition' meaning we restart intepreting
+% from the beginning of the file.
+% Hook setfileposition to throw an error attempting to reposition
+% the current file.
+/osetfileposition /setfileposition load def
+/setfileposition
+{
+ 1 index currentfile eq
+ {
+ /setfileposition cvx /ioerror signalerror
+ }
+ {
+ osetfileposition
+ } ifelse
+} bind odef
+currentdict /osetfileposition undef
+
setglobal
% Remove all but the default page size (the 0 entry in the InputAttributes
diff --git a/Resource/Init/gs_init.ps b/Resource/Init/gs_init.ps
index dbd7f4ce4..124a65960 100644
--- a/Resource/Init/gs_init.ps
+++ b/Resource/Init/gs_init.ps
@@ -1239,33 +1239,46 @@ end
/=== { ===only (\n) print } bind def
% Create the initialization queue.
-
-/.delayed_init_queue 10 dict def
+1183615869 internaldict dup
+/.delayed_init_queue 10 dict put
/.schedule_init % <priority> <proc> .schedule_init -
{
- //.delayed_init_queue 2 index known {
+ 1183615869 internaldict begin
+ .delayed_init_queue 2 index known {
+ end
(.delayed_init_queue priority conflict with ) print 1 index =
/.schedule_init cvx /configurationerror signalerror
} if
- //.delayed_init_queue 3 1 roll .growput
+ .delayed_init_queue 3 1 roll .growput
+ end
} bind def
+begin
/.execute_scheduled_inits % - .execute_scheduled_inits -
{
- { 0 //null //.delayed_init_queue { % maxp {} p {}
+ 2 dict begin
+ /.newdelayed_init_queue
+ mark
+ 1183615869 internaldict /.delayed_init_queue get {} forall
+ .dicttomark def
+ {
+ 0 //null .newdelayed_init_queue { % maxp {} p {}
3 index 2 index lt {
4 2 roll
} if
pop pop
} forall
- exch //.delayed_init_queue exch undef
+ exch .newdelayed_init_queue exch undef
dup //null eq {
pop exit
} if
exec
} loop
+ currentdict /.newdelayed_init_queue undef
+ end
} bind def
+end
(END PROCS) VMDEBUG
@@ -2025,9 +2038,21 @@ gsave
} {
{ }
} ifelse def
-<1b> cvn { % UEL is <esc>%-12345X and acts the same as ^D
- currentfile (%-12345X) .peekstring pop (%-12345X) eq <04> cvn load if
-} bind def
+<1b> cvn
+.actonuel % UEL is <esc>%-12345X and acts the same as ^D
+{systemdict (.forceinterp_exit) cvn known {//true} {//false} ifelse}
+{//false} ifelse
+
+{
+ {
+ currentfile (%-12345X) .peekstring pop (%-12345X) eq
+ { currentfile .forceinterp_exit } if
+ }
+}
+{
+ {currentfile (%-12345X) .peekstring pop (%-12345X) eq <04> cvn load if}
+} ifelse bind def
+
<1b45> cvn { } def % PJL reset prologue (ESC E)
<1b451b> cvn <1b> cvn load def % PJL reset epilogue (ESC E + UEL)
(\001M) cvn % TBCP initiator
@@ -2265,6 +2290,7 @@ SAFER { .setsafeglobal } if
/.patterntypes /.shadingtypes /.wheredict /.renderingintentdict
/.currentmatrix /.setmatrix
/.setlinecap /.setlinejoin /.sizeimagebox /.systemvmcheck
+ /.forceinterp_exit /.actonuel
% Used by a free user in the Library of Congress. Apparently this is used to
% draw a partial page, which is then filled in by the results of a barcode
@@ -2454,9 +2480,10 @@ $error /.nosetlocal //false put
} ifelse
% Execute scheduled inits :
-//.execute_scheduled_inits exec
-currentdict /.execute_scheduled_inits undef
-currentdict /.delayed_init_queue undef
+1183615869 internaldict /.execute_scheduled_inits get exec
+currentdict /.schedule_init undef
+%currentdict /.execute_scheduled_inits undef
+%currentdict /.delayed_init_queue undef
% Make global and local FontDirectory read-only.
FontDirectory readonly pop
diff --git a/base/gp_mspol.c b/base/gp_mspol.c
index fc5303b38..ad0dfa300 100644
--- a/base/gp_mspol.c
+++ b/base/gp_mspol.c
@@ -38,8 +38,8 @@ gp_check_interrupts(const gs_memory_t *mem)
mem = gs_lib_ctx_get_non_gc_memory_t();
}
#endif
- if (mem && mem->gs_lib_ctx && mem->gs_lib_ctx->poll_fn)
- return (*mem->gs_lib_ctx->poll_fn)(mem->gs_lib_ctx->caller_handle);
+ if (mem && mem->gs_lib_ctx && mem->gs_lib_ctx->core->poll_fn)
+ return (*mem->gs_lib_ctx->core->poll_fn)(mem->gs_lib_ctx->core->caller_handle);
return 0;
}
#endif
diff --git a/base/gs.mak b/base/gs.mak
index 40c3a9dd6..39939a2a1 100644
--- a/base/gs.mak
+++ b/base/gs.mak
@@ -397,6 +397,7 @@ DEVICE_DEVS_ALL=$(DEVICE_DEVS) $(DEVICE_DEVS1) \
PSI_DEVS_ALL=$(GSPLAT_DEVS_ALL) \
$(PSI_FEATURE_DEVS) \
+ $(PSD)iapi.dev \
$(FEATURE_DEVS) \
$(FEATURE_DEVS_EXTRA) \
$(DEVICE_DEVS_ALL)
@@ -473,18 +474,26 @@ $(ld_tr) : \
$(EXP)$(GENCONF_XE) $(devs_tr) -h $(gconfxx_h) $(CONFILES) $(CONFLDTR) $(ld_tr)
$(EXP)$(ECHOGS_XE) -a $(gconfxx_h) $(GCONFIG_EXTRAS)
+gsnoapi_tr=$(GLGENDIR)$(D)gsnoapi.tr
gs_tr=$(GLGENDIR)$(D)gs.tr
igs_tr=$(GLGENDIR)$(D)igs.tr
gsld_tr=$(GLGENDIR)$(D)gsld.tr
-$(gs_tr): $(GS_MAK) $(GLSRCDIR)$(D)version.mak $(GENCONF_XE) $(ECHOGS_XE) $(ld_tr) $(devs_tr) $(PSI_DEVS_ALL) \
- $(GLGENDIR)$(D)libcore.dev $(MAKEDIRS)
+gsnoapild_tr=$(GLGENDIR)$(D)gsnoapild.tr
+$(gsnoapi_tr): $(GS_MAK) $(GLSRCDIR)$(D)version.mak $(GENCONF_XE) $(ECHOGS_XE) $(ld_tr) $(devs_tr) $(PSI_DEVS_ALL)\
+ $(GLGENDIR)$(D)libcore.dev $(MAKEDIRS)
$(EXP)$(ECHOGS_XE) -w $(igs_tr) - -include $(PSI_FEATURE_DEVS)
$(EXP)$(GENCONF_XE) $(igs_tr) -h $(iconfxx_h) $(CONFILES) $(CONFLDTR) $(gsld_tr)
$(EXP)$(ECHOGS_XE) -w $(iconfig_h) -R $(iconfxx_h)
- $(EXP)$(ECHOGS_XE) -w $(gs_tr) -R $(devs_tr)
- $(EXP)$(ECHOGS_XE) -a $(gs_tr) -R $(igs_tr)
+ $(EXP)$(ECHOGS_XE) -w $(gsnoapi_tr) -R $(devs_tr)
+ $(EXP)$(ECHOGS_XE) -a $(gsnoapi_tr) -R $(igs_tr)
+ $(EXP)$(GENCONF_XE) $(gsnoapi_tr) -h $(GLGENDIR)$(D)unused.h $(CONFILES) $(CONFLDTR) $(gsnoapild_tr)
+
+$(gs_tr): $(gsnoapi_tr)
+ $(EXP)$(ECHOGS_XE) -w $(gs_tr) -R $(gsnoapi_tr)
+ $(EXP)$(ECHOGS_XE) -a $(gs_tr) - -include $(PSD)iapi.dev
$(EXP)$(GENCONF_XE) $(gs_tr) -h $(GLGENDIR)$(D)unused.h $(CONFILES) $(CONFLDTR) $(gsld_tr)
+
pcl_tr=$(GLGENDIR)$(D)pcl.tr
ipcl_tr=$(GLGENDIR)$(D)ipcl.tr
pclld_tr=$(GLGENDIR)$(D)pclld.tr
diff --git a/base/gsalloc.c b/base/gsalloc.c
index 110ad36e0..a83f9c270 100644
--- a/base/gsalloc.c
+++ b/base/gsalloc.c
@@ -2340,19 +2340,23 @@ trim_obj(gs_ref_memory_t *mem, obj_header_t *obj, uint size, clump_t *cp)
/* Register a root. */
static int
-i_register_root(gs_memory_t * mem, gs_gc_root_t * rp, gs_ptr_type_t ptype,
+i_register_root(gs_memory_t * mem, gs_gc_root_t ** rpp, gs_ptr_type_t ptype,
void **up, client_name_t cname)
{
gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
+ gs_gc_root_t *rp;
- if (rp == NULL) {
+ if (rpp == NULL || *rpp == NULL) {
rp = gs_raw_alloc_struct_immovable(imem->non_gc_memory, &st_gc_root_t,
"i_register_root");
if (rp == 0)
return_error(gs_error_VMerror);
rp->free_on_unregister = true;
- } else
+ *rpp = rp;
+ } else {
+ rp = *rpp;
rp->free_on_unregister = false;
+ }
if_debug3m('8', mem, "[8]register root(%s) 0x%lx -> 0x%lx\n",
client_name_string(cname), (ulong)rp, (ulong)up);
rp->ptype = ptype;
diff --git a/base/gsdevice.c b/base/gsdevice.c
index 5f298be16..4c58e35ee 100644
--- a/base/gsdevice.c
+++ b/base/gsdevice.c
@@ -1219,7 +1219,7 @@ gx_device_open_output_file(const gx_device * dev, char *fname,
code = gs_note_error(gs_error_undefinedfilename);
goto done;
}
- *pfile = dev->memory->gs_lib_ctx->fstdout;
+ *pfile = dev->memory->gs_lib_ctx->core->fstdout;
/* Force stdout to binary. */
code = gp_setmode_binary(*pfile, true);
goto done;
diff --git a/base/gsiodev.c b/base/gsiodev.c
index d05526cc0..536d478ad 100644
--- a/base/gsiodev.c
+++ b/base/gsiodev.c
@@ -91,7 +91,7 @@ gs_iodev_init(gs_memory_t * mem)
table[i] = NULL;
}
- code = gs_register_struct_root(mem, mem->gs_lib_ctx->io_device_table_root,
+ code = gs_register_struct_root(mem, &mem->gs_lib_ctx->io_device_table_root,
(void **)&libctx->io_device_table,
"io_device_table");
if (code < 0)
diff --git a/base/gsiodevs.c b/base/gsiodevs.c
index f98a489aa..b13d21218 100644
--- a/base/gsiodevs.c
+++ b/base/gsiodevs.c
@@ -71,7 +71,7 @@ stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
gs_memory_t * mem)
{
return stdio_open(iodev, access, ps, mem, 'r',
- mem->gs_lib_ctx->fstdin, sread_file);
+ mem->gs_lib_ctx->core->fstdin, sread_file);
}
const gx_io_device gs_iodev_stdin = iodev_stdio("%stdin%", stdin_open);
@@ -80,7 +80,7 @@ stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
gs_memory_t * mem)
{
return stdio_open(iodev, access, ps, mem, 'w',
- mem->gs_lib_ctx->fstdout, swrite_file);
+ mem->gs_lib_ctx->core->fstdout, swrite_file);
}
const gx_io_device gs_iodev_stdout = iodev_stdio("%stdout%", stdout_open);
@@ -89,6 +89,6 @@ stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
gs_memory_t * mem)
{
return stdio_open(iodev, access, ps, mem, 'w',
- mem->gs_lib_ctx->fstderr, swrite_file);
+ mem->gs_lib_ctx->core->fstderr, swrite_file);
}
const gx_io_device gs_iodev_stderr = iodev_stdio("%stderr%", stderr_open);
diff --git a/base/gslibctx.c b/base/gslibctx.c
index a72011aec..63c3ae489 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -95,7 +95,7 @@ gs_lib_ctx_set_default_device_list(const gs_memory_t *mem, const char* dev_list_
gs_lib_ctx_t *p_ctx = mem->gs_lib_ctx;
gs_memory_t *ctx_mem = p_ctx->memory;
int code = 0;
-
+
result = (char *)gs_alloc_bytes(ctx_mem, list_str_len + 1,
"gs_lib_ctx_set_default_device_list");
@@ -142,9 +142,9 @@ gs_lib_ctx_alloc_root_structure(gs_memory_t *mem, gs_gc_root_ptr *rp)
return code;
}
-int gs_lib_ctx_init( gs_memory_t *mem )
+int gs_lib_ctx_init(gs_lib_ctx_t *ctx, gs_memory_t *mem)
{
- gs_lib_ctx_t *pio = 0;
+ gs_lib_ctx_t *pio = NULL;
/* Check the non gc allocator is being passed in */
if (mem == 0 || mem != mem->non_gc_memory)
@@ -160,18 +160,48 @@ int gs_lib_ctx_init( gs_memory_t *mem )
pio = (gs_lib_ctx_t*)gs_alloc_bytes_immovable(mem,
sizeof(gs_lib_ctx_t),
"gs_lib_ctx_init");
- if( pio == 0 )
+ if(pio == NULL)
return -1;
/* Wholesale blanking is cheaper than retail, and scales better when new
* fields are added. */
memset(pio, 0, sizeof(*pio));
+
+ if (ctx != NULL) {
+ pio->core = ctx->core;
+ gx_monitor_enter((gx_monitor_t *)(pio->core->monitor));
+ pio->core->refs++;
+ gx_monitor_leave((gx_monitor_t *)(pio->core->monitor));
+ } else {
+ pio->core = (gs_lib_ctx_core_t *)gs_alloc_bytes_immovable(mem,
+ sizeof(gs_lib_ctx_core_t),
+ "gs_lib_ctx_init(core)");
+ if (pio->core == NULL) {
+ gs_free_object(mem, pio, "gs_lib_ctx_init");
+ return -1;
+ }
+ memset(pio->core, 0, sizeof(*pio->core));
+
+ pio->core->monitor = gx_monitor_alloc(mem);
+ if (pio->core->monitor == NULL) {
+ gs_free_object(mem, pio->core, "gs_lib_ctx_init");
+ gs_free_object(mem, pio, "gs_lib_ctx_init");
+ return -1;
+ }
+ pio->core->refs = 1;
+ pio->core->memory = mem;
+
+ /* Set the non-zero "shared" things */
+ gs_lib_ctx_get_real_stdio(&pio->core->fstdin, &pio->core->fstdout, &pio->core->fstderr );
+ pio->core->stdin_is_interactive = true;
+ /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
+ pio->core->gs_next_id = 5; /* Cloned contexts share the state */
+ /* Set scanconverter to 1 (default) */
+ pio->core->scanconverter = GS_SCANCONVERTER_DEFAULT;
+ }
+
/* Now set the non zero/false/NULL things */
pio->memory = mem;
- gs_lib_ctx_get_real_stdio(&pio->fstdin, &pio->fstdout, &pio->fstderr );
- pio->stdin_is_interactive = true;
- /* id's 1 through 4 are reserved for Device color spaces; see gscspace.h */
- pio->gs_next_id = 5; /* this implies that each thread has its own complete state */
/* Need to set this before calling gs_lib_ctx_set_icc_directory. */
mem->gs_lib_ctx = pio;
@@ -197,9 +227,6 @@ int gs_lib_ctx_init( gs_memory_t *mem )
pio->client_check_file_permission = NULL;
gp_get_realtime(pio->real_time_0);
- /* Set scanconverter to 1 (default) */
- pio->scanconverter = GS_SCANCONVERTER_DEFAULT;
-
if (gs_lib_ctx_alloc_root_structure(mem, &pio->name_table_root))
goto Failure;
@@ -231,10 +258,11 @@ void gs_lib_ctx_fin(gs_memory_t *mem)
{
gs_lib_ctx_t *ctx;
gs_memory_t *ctx_mem;
+ int refs;
if (!mem || !mem->gs_lib_ctx)
return;
-
+
ctx = mem->gs_lib_ctx;
ctx_mem = ctx->memory;
@@ -242,7 +270,7 @@ void gs_lib_ctx_fin(gs_memory_t *mem)
gscms_destroy(ctx_mem);
gs_free_object(ctx_mem, ctx->profiledir,
"gs_lib_ctx_fin");
-
+
gs_free_object(ctx_mem, ctx->default_device_list,
"gs_lib_ctx_fin");
@@ -254,6 +282,15 @@ void gs_lib_ctx_fin(gs_memory_t *mem)
mem_err_print = NULL;
#endif
remove_ctx_pointers(ctx_mem);
+
+ gx_monitor_enter((gx_monitor_t *)(ctx->core->monitor));
+ refs = --ctx->core->refs;
+ gx_monitor_leave((gx_monitor_t *)(ctx->core->monitor));
+ if (refs == 0) {
+ gx_monitor_free((gx_monitor_t *)(ctx->core->monitor));
+ gs_free_object(ctx->core->memory, ctx->core, "gs_lib_ctx_fin");
+ }
+
gs_free_object(ctx_mem, ctx, "gs_lib_ctx_init");
}
@@ -278,6 +315,13 @@ void gs_lib_ctx_set_cms_context( const gs_memory_t *mem, void *cms_context )
mem->gs_lib_ctx->cms_context = cms_context;
}
+int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem )
+{
+ if (mem == NULL)
+ return 0;
+ return mem->gs_lib_ctx->core->act_on_uel;
+}
+
/* Provide a single point for all "C" stdout and stderr.
*/
@@ -286,19 +330,20 @@ int outwrite(const gs_memory_t *mem, const char *str, int len)
int code;
FILE *fout;
gs_lib_ctx_t *pio = mem->gs_lib_ctx;
+ gs_lib_ctx_core_t *core = pio->core;
if (len == 0)
return 0;
- if (pio->stdout_is_redirected) {
- if (pio->stdout_to_stderr)
+ if (core->stdout_is_redirected) {
+ if (core->stdout_to_stderr)
return errwrite(mem, str, len);
- fout = pio->fstdout2;
+ fout = core->fstdout2;
}
- else if (pio->stdout_fn) {
- return (*pio->stdout_fn)(pio->caller_handle, str, len);
+ else if (core->stdout_fn) {
+ return (*core->stdout_fn)(core->caller_handle, str, len);
}
else {
- fout = pio->fstdout;
+ fout = core->fstdout;
}
code = fwrite(str, 1, len, fout);
fflush(fout);
@@ -316,6 +361,7 @@ int errwrite(const gs_memory_t *mem, const char *str, int len)
{
int code;
gs_lib_ctx_t *ctx;
+ gs_lib_ctx_core_t *core;
if (len == 0)
return 0;
if (mem == NULL) {
@@ -330,26 +376,28 @@ int errwrite(const gs_memory_t *mem, const char *str, int len)
ctx = mem->gs_lib_ctx;
if (ctx == NULL)
return 0;
- if (ctx->stderr_fn)
- return (*ctx->stderr_fn)(ctx->caller_handle, str, len);
+ core = ctx->core;
+ if (core->stderr_fn)
+ return (*core->stderr_fn)(core->caller_handle, str, len);
- code = fwrite(str, 1, len, ctx->fstderr);
- fflush(ctx->fstderr);
+ code = fwrite(str, 1, len, core->fstderr);
+ fflush(core->fstderr);
return code;
}
void outflush(const gs_memory_t *mem)
{
- if (mem->gs_lib_ctx->stdout_is_redirected) {
- if (mem->gs_lib_ctx->stdout_to_stderr) {
- if (!mem->gs_lib_ctx->stderr_fn)
- fflush(mem->gs_lib_ctx->fstderr);
+ gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
+ if (core->stdout_is_redirected) {
+ if (core->stdout_to_stderr) {
+ if (!core->stderr_fn)
+ fflush(core->fstderr);
}
else
- fflush(mem->gs_lib_ctx->fstdout2);
+ fflush(core->fstdout2);
}
- else if (!mem->gs_lib_ctx->stdout_fn)
- fflush(mem->gs_lib_ctx->fstdout);
+ else if (!core->stdout_fn)
+ fflush(core->fstdout);
}
#ifndef GS_THREADSAFE
@@ -361,8 +409,8 @@ void errflush_nomem(void)
void errflush(const gs_memory_t *mem)
{
- if (!mem->gs_lib_ctx->stderr_fn)
- fflush(mem->gs_lib_ctx->fstderr);
+ if (!mem->gs_lib_ctx->core->stderr_fn)
+ fflush(mem->gs_lib_ctx->core->fstderr);
/* else nothing to flush */
}
diff --git a/base/gslibctx.h b/base/gslibctx.h
index 348bde00e..137abe32b 100644
--- a/base/gslibctx.h
+++ b/base/gslibctx.h
@@ -39,9 +39,10 @@ typedef struct gs_font_dir_s gs_font_dir;
typedef int (*client_check_file_permission_t) (gs_memory_t *mem, const char *fname, const int len, const char *permission);
-typedef struct gs_lib_ctx_s
-{
- gs_memory_t *memory; /* mem->gs_lib_ctx->memory == mem */
+typedef struct {
+ void *monitor;
+ int refs;
+ gs_memory_t *memory;
FILE *fstdin;
FILE *fstdout;
FILE *fstderr;
@@ -56,6 +57,18 @@ typedef struct gs_lib_ctx_s
int (GSDLLCALL *stderr_fn)(void *caller_handle, const char *str, int len);
int (GSDLLCALL *poll_fn)(void *caller_handle);
ulong gs_next_id; /* gs_id initialized here, private variable of gs_next_ids() */
+ /* True if we are emulating CPSI. Ideally this would be in the imager
+ * state, but this can't be done due to problems detecting changes in it
+ * for the clist based devices. */
+ bool CPSI_mode;
+ int scanconverter;
+ int act_on_uel;
+} gs_lib_ctx_core_t;
+
+typedef struct gs_lib_ctx_s
+{
+ gs_memory_t *memory; /* mem->gs_lib_ctx->memory == mem */
+ gs_lib_ctx_core_t *core;
void *top_of_system; /* use accessor functions to walk down the system
* to the desired structure gs_lib_ctx_get_*()
*/
@@ -84,10 +97,6 @@ typedef struct gs_lib_ctx_s
/* font directory - see gsfont.h */
gs_font_dir *font_dir;
gs_gc_root_ptr font_dir_root;
- /* True if we are emulating CPSI. Ideally this would be in the imager
- * state, but this can't be done due to problems detecting changes in it
- * for the clist based devices. */
- bool CPSI_mode;
/* Keep the path for the ICCProfiles here so devices and the icc_manager
* can get to it. Prevents needing two copies, one in the icc_manager
* and one in the device */
@@ -97,7 +106,6 @@ typedef struct gs_lib_ctx_s
gs_fapi_server **fapi_servers;
char *default_device_list;
int gcsignal;
- int scanconverter;
void *sjpxd_private; /* optional for use of jpx codec */
} gs_lib_ctx_t;
@@ -114,7 +122,7 @@ enum {
* it is the responsibility of the gs_memory_t objects to copy
* the pointer to subsequent memory objects.
*/
-int gs_lib_ctx_init( gs_memory_t *mem );
+int gs_lib_ctx_init( gs_lib_ctx_t *ctx, gs_memory_t *mem );
/** Called when the lowest level allocator (the one which the lib_ctx was
* initialised under) is about to be destroyed. The lib_ctx should tidy up
@@ -125,6 +133,7 @@ gs_lib_ctx_t *gs_lib_ctx_get_interp_instance( const gs_memory_t *mem );
void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem );
void gs_lib_ctx_set_cms_context( const gs_memory_t *mem, void *cms_context );
+int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem );
#ifndef GS_THREADSAFE
/* HACK to get at non garbage collection memory pointer
@@ -152,8 +161,8 @@ gs_lib_ctx_get_default_device_list(const gs_memory_t *mem, char** dev_list_str,
int
gs_check_file_permission (gs_memory_t *mem, const char *fname, const int len, const char *permission);
-#define IS_LIBCTX_STDOUT(mem, f) (f == mem->gs_lib_ctx->fstdout)
-#define IS_LIBCTX_STDERR(mem, f) (f == mem->gs_lib_ctx->fstderr)
+#define IS_LIBCTX_STDOUT(mem, f) (f == mem->gs_lib_ctx->core->fstdout)
+#define IS_LIBCTX_STDERR(mem, f) (f == mem->gs_lib_ctx->core->fstderr)
/* Functions to init/fin JPX decoder libctx entry */
int sjpxd_create(gs_memory_t *mem);
diff --git a/base/gsmalloc.c b/base/gsmalloc.c
index d17647a05..4c2e2161f 100644
--- a/base/gsmalloc.c
+++ b/base/gsmalloc.c
@@ -424,7 +424,7 @@ gs_heap_free_string(gs_memory_t * mem, byte * data, uint nbytes,
gs_heap_free_object(mem, data, cname);
}
static int
-gs_heap_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
+gs_heap_register_root(gs_memory_t * mem, gs_gc_root_t ** rp,
gs_ptr_type_t ptype, void **up, client_name_t cname)
{
return 0;
@@ -582,13 +582,19 @@ gs_malloc_unwrap(gs_memory_t *wrapped)
gs_memory_t *
gs_malloc_init(void)
{
+ return gs_malloc_init_with_context(NULL);
+}
+
+gs_memory_t *
+gs_malloc_init_with_context(gs_lib_ctx_t *ctx)
+{
gs_malloc_memory_t *malloc_memory_default = gs_malloc_memory_init();
gs_memory_t *memory_t_default;
if (malloc_memory_default == NULL)
return NULL;
- if (gs_lib_ctx_init((gs_memory_t *)malloc_memory_default) != 0) {
+ if (gs_lib_ctx_init(ctx, (gs_memory_t *)malloc_memory_default) != 0) {
gs_malloc_release((gs_memory_t *)malloc_memory_default);
return NULL;
}
diff --git a/base/gsmalloc.h b/base/gsmalloc.h
index 76bd322ef..32e44c869 100644
--- a/base/gsmalloc.h
+++ b/base/gsmalloc.h
@@ -42,7 +42,14 @@ gs_malloc_memory_t *gs_malloc_memory_init(void);
gs_memory_free_all((gs_memory_t *)mem, FREE_ALL_EVERYTHING,\
"gs_malloc_memory_release")
+/* Get a basic malloc based allocator, built on a new
+ * gs_lib_ctx instance. */
gs_memory_t * gs_malloc_init(void);
+/* Get a basic malloc based allocator, built on a
+ * gs_lib_ctx instance, cloned from this supplied one.
+ * If ctx == NULL, this behaves as gs_malloc_init.
+ */
+gs_memory_t * gs_malloc_init_with_context(gs_lib_ctx_t *ctx);
void gs_malloc_release(gs_memory_t *mem);
#define gs_malloc(mem, nelts, esize, cname)\
diff --git a/base/gsmchunk.c b/base/gsmchunk.c
index 151935f63..3a4ff131f 100644
--- a/base/gsmchunk.c
+++ b/base/gsmchunk.c
@@ -1409,7 +1409,7 @@ chunk_object_type(const gs_memory_t * mem, const void *ptr)
}
static int
-chunk_register_root(gs_memory_t * mem, gs_gc_root_t * rp, gs_ptr_type_t ptype,
+chunk_register_root(gs_memory_t * mem, gs_gc_root_t ** rp, gs_ptr_type_t ptype,
void **up, client_name_t cname)
{
return 0;
diff --git a/base/gsmemory.c b/base/gsmemory.c
index f56f26f8f..b88361023 100644
--- a/base/gsmemory.c
+++ b/base/gsmemory.c
@@ -212,7 +212,7 @@ gs_struct_type_name(gs_memory_type_ptr_t pstype)
/* Register a structure root. */
int
-gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root,
+gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t **root,
void **pp, client_name_t cname)
{
return gs_register_root(mem, root, ptr_struct_type, pp, cname);
diff --git a/base/gsmemory.h b/base/gsmemory.h
index 4683e5aca..343d1666a 100644
--- a/base/gsmemory.h
+++ b/base/gsmemory.h
@@ -355,7 +355,7 @@ typedef struct gs_memory_procs_s {
*/
#define gs_memory_proc_register_root(proc)\
- int proc(gs_memory_t *mem, gs_gc_root_t *root, gs_ptr_type_t ptype,\
+ int proc(gs_memory_t *mem, gs_gc_root_t **root, gs_ptr_type_t ptype,\
void **pp, client_name_t cname)
#define gs_register_root(mem, root, ptype, pp, cname)\
(*(mem)->procs.register_root)(mem, root, ptype, pp, cname)
@@ -431,7 +431,7 @@ void *gs_resize_struct_array(gs_memory_t *mem, void *obj, uint num_elements,
client_name_t cname);
/* Register a structure root. This just calls gs_register_root. */
-int gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root,
+int gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t **root,
void **pp, client_name_t cname);
/* Define no-op freeing procedures for use by enable_free. */
diff --git a/base/gsmemret.c b/base/gsmemret.c
index 77f398470..489195f74 100644
--- a/base/gsmemret.c
+++ b/base/gsmemret.c
@@ -314,7 +314,7 @@ gs_forward_free_string(gs_memory_t * mem, byte * data, uint nbytes,
DO_FORWARD(target->procs.free_string(target, data, nbytes, cname));
}
static int
-gs_retrying_register_root(gs_memory_t * mem, gs_gc_root_t * rp,
+gs_retrying_register_root(gs_memory_t * mem, gs_gc_root_t ** rp,
gs_ptr_type_t ptype, void **up, client_name_t cname)
{
RETURN_RETRYING(
diff --git a/base/gsstate.c b/base/gsstate.c
index 1386acc8d..6eaf369c9 100644
--- a/base/gsstate.c
+++ b/base/gsstate.c
@@ -715,7 +715,7 @@ gs_setcpsimode(gs_memory_t *mem, bool mode)
{
gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
- libctx->CPSI_mode = mode;
+ libctx->core->CPSI_mode = mode;
}
/* currentcpsimode */
@@ -724,7 +724,7 @@ gs_currentcpsimode(const gs_memory_t * mem)
{
gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
- return libctx->CPSI_mode;
+ return libctx->core->CPSI_mode;
}
/* The edgebuffer based scanconverter can only cope with values of 0
@@ -748,7 +748,7 @@ gs_setscanconverter(gs_gstate * gs, int converter)
{
gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(gs->memory);
- libctx->scanconverter = converter;
+ libctx->core->scanconverter = converter;
sanitize_fill_adjust(gs);
}
@@ -759,7 +759,7 @@ gs_getscanconverter(const gs_memory_t * mem)
{
gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
- return libctx->scanconverter;
+ return libctx->core->scanconverter;
}
/* setrenderingintent
diff --git a/base/gsutil.c b/base/gsutil.c
index d17da4001..f9706a80d 100644
--- a/base/gsutil.c
+++ b/base/gsutil.c
@@ -32,9 +32,10 @@
ulong
gs_next_ids(const gs_memory_t *mem, uint count)
{
- ulong id = mem->gs_lib_ctx->gs_next_id;
+ gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
+ ulong id = core->gs_next_id;
- mem->gs_lib_ctx->gs_next_id += count;
+ core->gs_next_id += count;
return id;
}
diff --git a/base/gxdownscale.c b/base/gxdownscale.c
index 2a7b4347f..113e38d3d 100644
--- a/base/gxdownscale.c
+++ b/base/gxdownscale.c
@@ -21,6 +21,12 @@
#include "assert_.h"
#include "ets.h"
+/* Nasty inline declaration, as gxht_thresh.h requires penum */
+void gx_ht_threshold_row_bit_sub(byte *contone, byte *threshold_strip,
+ int contone_stride, byte *halftone,
+ int dithered_stride, int width, int num_rows,
+ int offset_bits);
+
enum
{
MAX_ETS_PLANES = 8
@@ -874,6 +880,81 @@ static void down_core4(gx_downscaler_t *ds,
pack_8to1(out_buffer, outp, awidth*4);
}
+static void down_core4_ht(gx_downscaler_t *ds,
+ byte *out_buffer, /* Guaranteed aligned */
+ byte *in_buffer, /* Not guaranteed aligned */
+ int row,
+ int plane /* unused */,
+ int span)
+{
+ int pad_white, y;
+ int factor = ds->factor;
+ int i;
+ int nc = ds->early_cm ? ds->post_cm_num_comps : ds->num_comps;
+ byte *downscaled_data = ds->inbuf;
+
+ pad_white = (ds->awidth - ds->width) * factor * 4;
+ if (pad_white < 0)
+ pad_white = 0;
+
+ if (pad_white)
+ {
+ unsigned char *inp = in_buffer + ds->width * factor * 4;
+ for (y = factor; y > 0; y--)
+ {
+ memset(inp, 0xFF, pad_white);
+ inp += span;
+ }
+ }
+
+ /* Color conversion has already happened. Do any downscale required. */
+ if (ds->ets_downscale)
+ ds->ets_downscale(ds, downscaled_data, in_buffer, row, plane, span);
+ else if ((31 & (intptr_t)in_buffer) == 0)
+ downscaled_data = in_buffer; /* Already aligned! Yay! */
+ else
+ memcpy(downscaled_data, in_buffer, nc*ds->width); /* Copy to align */
+
+ /* Do the halftone */
+ for (i = 0; i < nc; i++)
+ {
+ /* Make the expanded threshold row */
+ byte *d = ds->htrow + i;
+ int len = ds->width;
+ const byte *srow = ds->ht[i].data + ds->ht[i].stride * ((row + ds->ht[i].y_phase) % ds->ht[i].h);
+ {
+ int o = ds->ht[i].x_phase;
+ int run = ds->ht[i].w - o;
+ const byte *s = &srow[o];
+ if (run > len)
+ run = len;
+ len -= run;
+ do {
+ *d = *s++;
+ d += nc;
+ } while (--run);
+ }
+ while (len)
+ {
+ const byte *s = srow;
+ int run = ds->ht[i].w;
+ if (run > len)
+ run = len;
+ len -= run;
+ do {
+ *d = *s++;
+ d += nc;
+ }
+ while (--run);
+ }
+ }
+
+ /* Do the halftone */
+ gx_ht_threshold_row_bit_sub(downscaled_data, ds->htrow, 0,
+ out_buffer, 0,
+ ds->width * nc, 1, 0);
+}
+
static void down_core4_ets(gx_downscaler_t *ds,
byte *out_buffer,
byte *in_buffer,
@@ -1769,11 +1850,40 @@ static int init_ets(gx_downscaler_t *ds, int num_planes, gx_downscale_core *down
ds->ets_config = ets_create(ds->dev->memory, &params);
if (ds->ets_config == NULL)
- return gs_error_VMerror;
+ return gs_note_error(gs_error_VMerror);
return 0;
}
+static int init_ht(gx_downscaler_t *ds, int num_planes, gx_downscale_core *downscale_core)
+{
+ int nc = ds->early_cm ? ds->post_cm_num_comps : ds->num_comps;
+
+ ds->ets_downscale = downscale_core;
+
+ /* Allocate us a row (with padding for alignment) so we can hold the
+ * expanded threshold array. */
+ ds->htrow_alloc = gs_alloc_bytes(ds->dev->memory, ds->width * nc + 64,
+ "gx_downscaler(htrow)");
+ if (ds->htrow_alloc == NULL)
+ return gs_error_VMerror;
+ /* Make an aligned version */
+ ds->htrow = ds->htrow_alloc + ((32-(intptr_t)ds->htrow_alloc) & 31);
+
+ /* Allocate us a row (with padding for alignment) for the downscaled data. */
+ ds->inbuf_alloc = gs_alloc_bytes(ds->dev->memory, ds->width * nc + 64,
+ "gx_downscaler(inbuf)");
+ if (ds->inbuf_alloc == NULL)
+ {
+ gs_free_object(ds->dev->memory, ds->htrow_alloc, "gx_downscaler(htrow)");
+ ds->htrow_alloc = ds->htrow = NULL;
+ return gs_error_VMerror;
+ }
+ /* Make an aligned version */
+ ds->inbuf = ds->inbuf_alloc + ((32-(intptr_t)ds->inbuf_alloc) & 31);
+
+ return 0;
+}
int gx_downscaler_init_planar(gx_downscaler_t *ds,
gx_device *dev,
@@ -2102,6 +2212,8 @@ int gx_downscaler_init_trapped_cm(gx_downscaler_t *ds,
0);
}
+static gx_downscaler_ht_t bogus_ets_halftone;
+
int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
gx_device *dev,
int src_bpc,
@@ -2112,13 +2224,74 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
int (*adjust_width_proc)(int, int),
int adjust_width,
int trap_w,
- int trap_h,
+ int trap_h,
const int *comp_order,
gx_downscale_cm_fn *apply_cm,
void *apply_cm_arg,
int post_cm_num_comps,
int ets)
{
+ return gx_downscaler_init_trapped_cm_halftone(ds,
+ dev,
+ src_bpc,
+ dst_bpc,
+ num_comps,
+ factor,
+ mfs,
+ adjust_width_proc,
+ adjust_width,
+ trap_w,
+ trap_h,
+ comp_order,
+ apply_cm,
+ apply_cm_arg,
+ post_cm_num_comps,
+ &bogus_ets_halftone);
+}
+
+
+static gx_downscale_core *
+select_8_to_8_core(int nc, int factor)
+{
+ if (factor == 1)
+ return NULL; /* No sense doing anything */
+ if (nc == 1)
+ {
+ if (factor == 4)
+ return &down_core8_4;
+ else if (factor == 3)
+ return &down_core8_3;
+ else if (factor == 2)
+ return &down_core8_2;
+ else
+ return &down_core8;
+ }
+ else if (nc == 3)
+ return &down_core24;
+ else if (nc == 4)
+ return &down_core32;
+
+ return NULL;
+}
+
+int
+gx_downscaler_init_trapped_cm_halftone(gx_downscaler_t *ds,
+ gx_device *dev,
+ int src_bpc,
+ int dst_bpc,
+ int num_comps,
+ int factor,
+ int mfs,
+ int (*adjust_width_proc)(int, int),
+ int adjust_width,
+ int trap_w,
+ int trap_h,
+ const int *comp_order,
+ gx_downscale_cm_fn *apply_cm,
+ void *apply_cm_arg,
+ int post_cm_num_comps,
+ gx_downscaler_ht_t *ht)
+{
int size;
int post_size;
int span;
@@ -2159,6 +2332,9 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
ds->apply_cm_arg = apply_cm_arg;
ds->early_cm = dst_bpc < src_bpc;
ds->post_cm_num_comps = post_cm_num_comps;
+ ds->ht = ht;
+ ds->dst_bpc = dst_bpc;
+ ds->num_comps = num_comps;
code = check_trapping(dev->memory, trap_w, trap_h, num_comps, comp_order);
if (code < 0)
@@ -2193,13 +2369,20 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
{
if (mfs > 1)
core = &down_core4_mfs;
- else if (ets)
+ else if (ht == &bogus_ets_halftone)
{
- code = init_ets(ds, 4, core);
+ code = init_ets(ds, 4, select_8_to_8_core(nc, factor));
if (code)
goto cleanup;
core = &down_core4_ets;
}
+ else if (ht != NULL)
+ {
+ code = init_ht(ds, 4, select_8_to_8_core(nc, factor));
+ if (code)
+ goto cleanup;
+ core = &down_core4_ht;
+ }
else
core = &down_core4;
}
@@ -2207,7 +2390,7 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
{
if (mfs > 1)
core = &down_core_mfs;
- else if (ets)
+ else if (ht == &bogus_ets_halftone)
{
code = init_ets(ds, 1, core);
if (code)
@@ -2227,21 +2410,8 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
}
else if ((factor == 1) && (src_bpc == dst_bpc))
break;
- else if ((src_bpc == 8) && (dst_bpc == 8) && (nc == 1))
- {
- if (factor == 4)
- core = &down_core8_4;
- else if (factor == 3)
- core = &down_core8_3;
- else if (factor == 2)
- core = &down_core8_2;
- else
- core = &down_core8;
- }
- else if ((src_bpc == 8) && (dst_bpc == 8) && (nc == 3))
- core = &down_core24;
- else if ((src_bpc == 8) && (dst_bpc == 8) && (nc == 4))
- core = &down_core32;
+ else if (src_bpc == 8 && dst_bpc == 8)
+ core = select_8_to_8_core(nc, factor);
/* If we found one, or we have nothing to fallback to, exit */
if (core || !ds->early_cm)
@@ -2290,13 +2460,13 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
}
if (dst_bpc == 1) {
ds->errors = (int *)gs_alloc_bytes(dev->memory,
- num_comps*(awidth+3)*sizeof(int),
+ nc*(awidth+3)*sizeof(int),
"gx_downscaler(errors)");
if (ds->errors == NULL) {
code = gs_note_error(gs_error_VMerror);
goto cleanup;
}
- memset(ds->errors, 0, num_comps * (awidth+3) * sizeof(int));
+ memset(ds->errors, 0, nc * (awidth+3) * sizeof(int));
}
}
@@ -2324,6 +2494,9 @@ void gx_downscaler_fin(gx_downscaler_t *ds)
ds->errors = NULL;
gs_free_object(ds->dev->memory, ds->scaled_data, "gx_downscaler(scaled_data)");
ds->scaled_data = NULL;
+ gs_free_object(ds->dev->memory, ds->htrow_alloc, "gx_downscaler(htrow)");
+ ds->htrow = NULL;
+ ds->htrow_alloc = NULL;
if (ds->claptrap)
ClapTrap_Fin(ds->dev->memory, ds->claptrap);
diff --git a/base/gxdownscale.h b/base/gxdownscale.h
index a436816e6..cea2cfabf 100644
--- a/base/gxdownscale.h
+++ b/base/gxdownscale.h
@@ -44,6 +44,16 @@ typedef int (gx_downscale_cm_fn)(void *arg,
int h,
int raster);
+typedef struct gx_downscaler_ht_s
+{
+ int w;
+ int h;
+ int stride;
+ int x_phase;
+ int y_phase;
+ byte *data;
+} gx_downscaler_ht_t;
+
/* The following structure definitions should really be considered
* private, and are exposed here only because it enables us to define
* gx_downscaler_t's on the stack, thus avoiding mallocs.
@@ -67,12 +77,14 @@ struct gx_downscaler_s {
int factor; /* Factor to downscale */
byte *mfs_data; /* MinFeatureSize data */
int src_bpc; /* Source bpc */
+ int dst_bpc; /* Destination bpc */
int *errors; /* Error diffusion table */
byte *scaled_data;/* Downscaled data (only used for non
* integer downscales). */
int scaled_span;/* Num bytes in scaled scanline */
gx_downscale_core *down_core; /* Core downscaling function */
gs_get_bits_params_t params; /* Params if in planar mode */
+ int num_comps; /* Number of components as rendered */
int num_planes; /* Number of planes if planar, 0 otherwise */
ClapTrap *claptrap; /* ClapTrap pointer (if trapping) */
@@ -89,6 +101,12 @@ struct gx_downscaler_s {
byte *pre_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
byte *post_cm[GS_CLIENT_COLOR_MAX_COMPONENTS];
+
+ gx_downscaler_ht_t *ht;
+ byte *htrow;
+ byte *htrow_alloc;
+ byte *inbuf;
+ byte *inbuf_alloc;
};
/* To use the downscaler:
@@ -221,6 +239,23 @@ int gx_downscaler_init_trapped_cm_ets(gx_downscaler_t *ds,
int post_cm_num_comps,
int ets);
+int gx_downscaler_init_trapped_cm_halftone(gx_downscaler_t *ds,
+ gx_device *dev,
+ int src_bpc,
+ int dst_bpc,
+ int num_comps,
+ int factor,
+ int mfs,
+ int (*adjust_width_proc)(int, int),
+ int adjust_width,
+ int trap_w,
+ int trap_h,
+ const int *comp_order,
+ gx_downscale_cm_fn *apply_cm,
+ void *apply_cm_arg,
+ int post_cm_num_comps,
+ gx_downscaler_ht_t *ht);
+
int gx_downscaler_init_planar(gx_downscaler_t *ds,
gx_device *dev,
gs_get_bits_params_t *params,
diff --git a/configure.ac b/configure.ac
index 8ecaccc53..d78e20f02 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2007,7 +2007,7 @@ if test "x$XPS_TARGET" != "x" && test "x$PCL_TARGET" != "x" ; then
[name of the GhostPDL executible (if the source is available, ignored otherwise) [[gpdl]]]),
[GPDL="$with_gpdl"],[GPDL='gpdl'])
-# GPDL_TARGET=gpdl
+ GPDL_TARGET=gpdl
GPDL_MAK="\$(GPDLSRCDIR)\$(D)gpdl.mak"
fi
fi
diff --git a/devices/devs.mak b/devices/devs.mak
index e8654e566..99823eea8 100644
--- a/devices/devs.mak
+++ b/devices/devs.mak
@@ -131,6 +131,7 @@ DEVGEN=$(DEVGENDIR)$(D)
# bmp256 8-bit (256-color) .BMP file format
# bmp16m 24-bit .BMP file format
# bmp32b 32-bit pseudo-.BMP file format
+# chameleon Plain bits, rgb/mono/cmyk runtime configurable.
# jpeg JPEG format, RGB output
# jpeggray JPEG format, gray output
# jpegcmyk JPEG format, cmyk output
@@ -1126,6 +1127,20 @@ $(DEVOBJ)gdevbit.$(OBJ) : $(DEVSRC)gdevbit.c $(PDEVH)\
$(gsutil_h) $(DEVS_MAK) $(MAKEDIRS)
$(DEVCC) $(DEVO_)gdevbit.$(OBJ) $(C_) $(DEVSRC)gdevbit.c
+### --------------------- The chameleon device ---------------------- ###
+
+chameleon_=$(DEVOBJ)gdevchameleon.$(OBJ) $(DEVOBJ)gdevdcrd.$(OBJ)
+
+$(DD)chameleon.dev : $(chameleon_) $(GLD)page.dev $(GLD)cielib.dev $(GDEV) \
+ $(DEVS_MAK) $(MAKEDIRS)
+ $(SETPDEV2) $(DD)chameleon $(chameleon_)
+ $(ADDMOD) $(DD)chameleon -include $(GLD)cielib
+
+$(DEVOBJ)gdevchameleon.$(OBJ) : $(DEVSRC)gdevchameleon.c $(PDEVH)\
+ $(gsparam_h) $(gdevdcrd_h) $(gscrd_h) $(gscrdp_h) $(gxlum_h) $(gxdcconv_h)\
+ $(gsutil_h) $(DEVS_MAK) $(MAKEDIRS)
+ $(DEVCC) $(DEVO_)gdevchameleon.$(OBJ) $(C_) $(DEVSRC)gdevchameleon.c
+
### ------------------------- .BMP file formats ------------------------- ###
gdevbmp_h=$(DEVSRC)gdevbmp.h
diff --git a/devices/gdevchameleon.c b/devices/gdevchameleon.c
new file mode 100644
index 000000000..c944b92a8
--- /dev/null
+++ b/devices/gdevchameleon.c
@@ -0,0 +1,672 @@
+/* Copyright (C) 2001-2018 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Chameleon devices to allow for changing bit depths/colors at runtime. */
+
+#include "gdevprn.h"
+#include "gsparam.h"
+#include "gscrd.h"
+#include "gscrdp.h"
+#include "gxlum.h"
+#include "gxdcconv.h"
+#include "gdevdcrd.h"
+#include "gxdownscale.h"
+#include "gxdevsop.h"
+
+/* Define the device parameters. */
+#ifndef X_DPI
+# define X_DPI 72
+#endif
+#ifndef Y_DPI
+# define Y_DPI 72
+#endif
+
+/* The device descriptor */
+static dev_proc_encode_color(chameleon_mono_encode_color);
+static dev_proc_encode_color(chameleon_rgb_encode_color);
+static dev_proc_encode_color(chameleon_cmyk_encode_color);
+static dev_proc_decode_color(chameleon_mono_decode_color);
+static dev_proc_decode_color(chameleon_rgb_decode_color);
+static dev_proc_decode_color(chameleon_cmyk_decode_color);
+static dev_proc_get_params(chameleon_get_params);
+static dev_proc_put_params(chameleon_put_params);
+static dev_proc_print_page(chameleon_print_page);
+static dev_proc_dev_spec_op(chameleon_spec_op);
+
+struct gx_device_chameleon_s {
+ gx_device_common;
+ gx_prn_device_common;
+ int num_components;
+ int bpc;
+ int dst_num_components;
+ int dst_bpc;
+ int output_as_pxm;
+ bool language_uses_rops;
+ gx_downscaler_params downscale;
+};
+typedef struct gx_device_chameleon_s gx_device_chameleon;
+
+static const gx_device_procs chameleon_procs =
+{ gdev_prn_open,
+ gx_default_get_initial_matrix,
+ NULL, /* sync_output */
+ /* Since the print_page doesn't alter the device, this device can print in the background */
+ gdev_prn_bg_output_page,
+ gdev_prn_close,
+ chameleon_rgb_encode_color, /* map_rgb_color */
+ chameleon_rgb_decode_color, /* map_color_rgb */
+ NULL, /* fill_rectangle */
+ NULL, /* tile_rectangle */
+ NULL, /* copy_mono */
+ NULL, /* copy_color */
+ NULL, /* draw_line */
+ NULL, /* get_bits */
+ chameleon_get_params,
+ chameleon_put_params,
+ chameleon_rgb_encode_color, /* map_cmyk_color */
+ NULL, /* get_xfont_procs */
+ NULL, /* get_xfont_device */
+ NULL, /* map_rgb_alpha_color */
+ gx_page_device_get_page_device, /* get_page_device */
+ NULL, /* get_alpha_bits */
+ NULL, /* copy_alpha */
+ NULL, /* get_band */
+ NULL, /* copy_rop */
+ NULL, /* fill_path */
+ NULL, /* stroke_path */
+ NULL, /* fill_mask */
+ NULL, /* fill_trapezoid */
+ NULL, /* fill_parallelogram */
+ NULL, /* fill_triangle */
+ NULL, /* draw_thin_line */
+ NULL, /* begin_image */
+ NULL, /* image_data */
+ NULL, /* end_image */
+ NULL, /* strip_tile_rectangle */
+ NULL, /* strip_copy_rop */
+ NULL, /* get_clipping_box */
+ NULL, /* begin_typed_image */
+ NULL, /* get_bits_rectangle */
+ NULL, /* map_color_rgb_alpha */
+ NULL, /* create_compositor */
+ NULL, /* get_hardware_params */
+ NULL, /* text_begin */
+ NULL, /* finish_copydevice */
+ NULL, /* begin_transparency_group */
+ NULL, /* end_transparency_group */
+ NULL, /* begin_transparency_mask */
+ NULL, /* end_transparency_mask */
+ NULL, /* discard_transparency_layer */
+ NULL, /* get_color_mapping_procs */
+ NULL, /* get_color_comp_index */
+ chameleon_rgb_encode_color,/* encode_color */
+ chameleon_rgb_decode_color, /* decode_color */
+ NULL, /* pattern_manage */
+ NULL, /* fill_rectangle_hl_color */
+ NULL, /* include_color_space */
+ NULL, /* fill_linear_color_scanline */
+ NULL, /* fill_linear_color_trapezoid */
+ NULL, /* fill_linear_color_triangle */
+ NULL, /* update_spot_equivalent_colors */
+ NULL, /* ret_devn_params */
+ NULL, /* fillpage */
+ NULL, /* push_transparency_state */
+ NULL, /* pop_transparency_state */
+ NULL, /* put_image */
+ chameleon_spec_op /* dev_spec_op */
+};
+
+const gx_device_chameleon gs_chameleon_device =
+{prn_device_body(gx_device_chameleon, chameleon_procs, "chameleon",
+ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
+ X_DPI, Y_DPI,
+ 0, 0, 0, 0, /* margins */
+ 4, /* 3 colors (by default) */
+ 4, /* depth */
+ 15, /* max grey */
+ 15, /* max color */
+ 16, /* dither greys */
+ 16, /* dither colors */
+ chameleon_print_page),
+ 4, /* Default to CMYK output */
+ 1, /* Default to 1bpc output */
+ 4, /* Default to CMYK output */
+ 1, /* Default to 1bpc output */
+ 0, /* Default to outputting headerless data */
+ 0, /* Default to not ropping */
+ GX_DOWNSCALER_PARAMS_DEFAULTS
+};
+
+/* Map gray to color. */
+/* Note that 1-bit monochrome is a special case. */
+static gx_color_index
+chameleon_mono_encode_color(gx_device * dev, const gx_color_value cv[])
+{
+ int bpc = dev->color_info.depth;
+ int drop = sizeof(gx_color_value) * 8 - bpc;
+ gx_color_value gray = cv[0];
+
+ return (bpc == 1 ? gx_max_color_value - gray : gray) >> drop;
+}
+
+static gx_color_index
+chameleon_rgb_encode_color(gx_device * dev, const gx_color_value cv[])
+{
+ if (dev->color_info.depth == 24)
+ return gx_color_value_to_byte(cv[2]) +
+ ((uint) gx_color_value_to_byte(cv[1]) << 8) +
+ ((ulong) gx_color_value_to_byte(cv[0]) << 16);
+ else {
+ COLROUND_VARS;
+ /* The following needs special handling to avoid bpc=5 when depth=16 */
+ int bpc = dev->color_info.depth == 16 ? 4 : dev->color_info.depth / 3;
+ COLROUND_SETUP(bpc);
+
+ return (((COLROUND_ROUND(cv[0]) << bpc) +
+ COLROUND_ROUND(cv[1])) << bpc) +
+ COLROUND_ROUND(cv[2]);
+ }
+}
+
+/* Map CMYK to color. */
+static gx_color_index
+chameleon_cmyk_encode_color(gx_device * dev, const gx_color_value cv[])
+{
+ int bpc = dev->color_info.depth / 4;
+ int drop = sizeof(gx_color_value) * 8 - bpc;
+ gx_color_index color =
+ (((((((gx_color_index) cv[0] >> drop) << bpc) +
+ (cv[1] >> drop)) << bpc) +
+ (cv[2] >> drop)) << bpc) +
+ (cv[3] >> drop);
+
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/* Map color to RGB. This has 3 separate cases, but since it is rarely */
+/* used, we do a case test rather than providing 3 separate routines. */
+static int
+chameleon_mono_decode_color(gx_device * dev, gx_color_index color, gx_color_value cv[4])
+{
+ int depth = dev->color_info.depth;
+ int ncomp = dev->color_info.num_components;
+ int bpc = depth / ncomp;
+ uint mask = (1 << bpc) - 1;
+
+#define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
+
+ cv[0] = cv[1] = cv[2] =
+ (depth == 1 ? (color ? 0 : gx_max_color_value) :
+ cvalue(color));
+ return 0;
+#undef cvalue
+}
+
+static int
+chameleon_rgb_decode_color(gx_device * dev, gx_color_index color, gx_color_value cv[4])
+{
+ int depth = dev->color_info.depth;
+ int ncomp = dev->color_info.num_components;
+ int bpc = depth / ncomp;
+ uint mask = (1 << bpc) - 1;
+
+#define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
+
+ gx_color_index cshift = color;
+
+ cv[2] = cvalue(cshift & mask);
+ cshift >>= bpc;
+ cv[1] = cvalue(cshift & mask);
+ cv[0] = cvalue(cshift >> bpc);
+ return 0;
+#undef cvalue
+}
+
+static int
+chameleon_cmyk_decode_color(gx_device * dev, gx_color_index color, gx_color_value cv[4])
+{
+ int depth = dev->color_info.depth;
+ int ncomp = dev->color_info.num_components;
+ int bpc = depth / ncomp;
+ uint mask = (1 << bpc) - 1;
+
+#define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask))
+
+ gx_color_index cshift = color;
+ uint c, m, y, k;
+
+ k = cshift & mask;
+ cshift >>= bpc;
+ y = cshift & mask;
+ cshift >>= bpc;
+ m = cshift & mask;
+ c = cshift >> bpc;
+ /* We use our improved conversion rule.... */
+ cv[0] = cvalue((mask - c) * (mask - k) / mask);
+ cv[1] = cvalue((mask - m) * (mask - k) / mask);
+ cv[2] = cvalue((mask - y) * (mask - k) / mask);
+ return 0;
+#undef cvalue
+}
+
+/* # So long, oh, I hate to see you go */
+static void
+reconfigure_baby(gx_device_chameleon *pcdev)
+{
+ int bpc = pcdev->dst_bpc;
+ int num_comps = pcdev->dst_num_components;
+
+ if (pcdev->language_uses_rops) {
+ bpc = 8;
+ num_comps = 3;
+ }
+
+ if (pcdev->bpc != bpc ||
+ pcdev->num_components != num_comps) {
+
+ gs_closedevice((gx_device *)pcdev);
+
+ pcdev->bpc = bpc;
+ pcdev->num_components = num_comps;
+
+ switch (num_comps * bpc) {
+ case 1*1: case 1*2: case 1*4: case 1*8:
+ case 4*4: case 4*8:
+ pcdev->color_info.depth = bpc * num_comps;
+ break;
+ case 3*1:
+ pcdev->color_info.depth = 4;
+ break;
+ case 3*2:
+ pcdev->color_info.depth = 8;
+ break;
+ case 3*4:
+ pcdev->color_info.depth = 16;
+ break;
+ }
+ pcdev->color_info.max_gray = pcdev->color_info.max_color =
+ (pcdev->color_info.dither_grays = pcdev->color_info.dither_colors = 1<<bpc) - 1;
+
+ set_dev_proc(pcdev, map_cmyk_color, NULL);
+ set_dev_proc(pcdev, map_rgb_color, NULL);
+ set_dev_proc(pcdev, map_color_rgb, NULL);
+ set_dev_proc(pcdev, encode_color,
+ num_comps == 1 ? chameleon_mono_encode_color :
+ num_comps == 4 ? chameleon_cmyk_encode_color :
+ chameleon_rgb_encode_color);
+ set_dev_proc(pcdev, decode_color,
+ num_comps == 1 ? chameleon_mono_decode_color :
+ num_comps == 4 ? chameleon_cmyk_decode_color :
+ chameleon_rgb_decode_color);
+
+ /* Reset the separable and linear shift, masks, bits. */
+ set_linear_color_bits_mask_shift((gx_device *)pcdev);
+ pcdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
+ pcdev->bpc = bpc;
+ pcdev->num_components = num_comps;
+ }
+}
+
+/* Get parameters. We provide a default CRD. */
+static int
+chameleon_get_params(gx_device * pdev, gs_param_list * plist)
+{
+ int code, ecode;
+ gx_device_chameleon *pcdev = (gx_device_chameleon *)pdev;
+
+ ecode = gdev_prn_get_params(pdev, plist);
+ code = sample_device_crd_get_params(pdev, plist, "CRDDefault");
+ if (code < 0)
+ ecode = code;
+
+ if ((code = param_write_int(plist, "DstBitDepth", &pcdev->dst_bpc)) < 0)
+ ecode = code;
+ if ((code = param_write_int(plist, "DstComponents", &pcdev->dst_num_components)) < 0)
+ ecode = code;
+ if ((code = gx_downscaler_write_params(plist, &pcdev->downscale, 0)) < 0)
+ ecode = code;
+ if ((code = param_write_int(plist, "OutputAsPXM", &pcdev->output_as_pxm)) < 0)
+ ecode = code;
+ if ((code = param_write_bool(plist, "LanguageUsesROPs", &pcdev->language_uses_rops)) < 0)
+ ecode = code;
+
+ return ecode;
+}
+
+/* Set parameters. We allow setting the number of bits per component, and number of components. */
+static int
+chameleon_put_params(gx_device * pdev, gs_param_list * plist)
+{
+ gx_device_chameleon *pcdev = (gx_device_chameleon *)pdev;
+ gx_device_color_info save_info;
+ int pxm = pcdev->output_as_pxm;
+ int dst_num_comps = pcdev->dst_num_components;
+ int dst_bpc = pcdev->dst_bpc;
+ bool language_uses_rops = pcdev->language_uses_rops;
+ int ecode;
+ int code;
+ const char *vname;
+
+ ecode = gx_downscaler_read_params(plist, &pcdev->downscale, 0);
+
+ if ((code = param_read_int(plist, (vname = "DstBitDepth"), &dst_bpc)) != 1) {
+ if (code < 0)
+ ecode = code;
+ else
+ switch (dst_bpc) {
+ case 1: case 2: case 4: case 8: break;
+ default:
+ param_signal_error(plist, vname,
+ ecode = gs_error_rangecheck);
+ }
+ }
+
+ if ((code = param_read_int(plist, (vname = "DstComponents"), &dst_num_comps)) != 1) {
+ if (code < 0)
+ ecode = code;
+ else
+ switch (dst_num_comps) {
+ case 1: case 3: case 4: break;
+ default:
+ param_signal_error(plist, vname,
+ ecode = gs_error_rangecheck);
+ }
+ }
+
+ if ((code = param_read_int(plist, (vname = "OutputAsPXM"), &pxm)) != 1) {
+ if (code == gs_error_typecheck)
+ pxm = 1;
+ else if (code < 0)
+ ecode = code;
+ else
+ pxm = !!pxm;
+ }
+
+ if ((code = param_read_bool(plist, (vname = "LanguageUsesROPs"), &language_uses_rops)) != 1) {
+ if (code == gs_error_typecheck)
+ language_uses_rops = false;
+ else if (code < 0)
+ ecode = code;
+ }
+
+ ecode = gdev_prn_put_params(pdev, plist);
+ if (ecode < 0)
+ return ecode;
+
+ pcdev->dst_bpc = dst_bpc;
+ pcdev->dst_num_components = dst_num_comps;
+ pcdev->output_as_pxm = pxm;
+ pcdev->language_uses_rops = language_uses_rops;
+
+ reconfigure_baby(pcdev);
+
+ return 0;
+}
+
+static int
+chameleon_spec_op(gx_device *dev_, int op, void *data, int datasize)
+{
+ gx_device_chameleon *dev = (gx_device_chameleon *)dev_;
+
+ if (op == gxdso_supports_iccpostrender) {
+ return true;
+ }
+ return gdev_prn_dev_spec_op(dev_, op, data, datasize);
+}
+
+static int
+craprgbtocmyk(void *arg,
+ byte **dst,
+ byte **src,
+ int w,
+ int h,
+ int raster)
+{
+ byte *d = *dst;
+ byte *s = *src;
+
+ while (w--) {
+ int c = 255-*s++;
+ int m = 255-*s++;
+ int y = 255-*s++;
+ int k = c;
+ if (k > m)
+ k = m;
+ if (k > y)
+ k = y;
+ *d++ = c - k;
+ *d++ = m - k;
+ *d++ = y - k;
+ *d++ = k;
+ }
+
+ return 0;
+}
+
+static int
+header_4x1(FILE *file, gx_device_chameleon *pcdev)
+{
+ fprintf(file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n",
+ pcdev->width, pcdev->height);
+ return 0;
+}
+
+static int
+write_4x1(const byte *data, int n, FILE *file)
+{
+ byte b[8];
+ n -= 4;
+ while (n > 0) {
+ byte d = *data++;
+ b[0] = (d & 128) ? 255 : 0;
+ b[1] = (d & 64) ? 255 : 0;
+ b[2] = (d & 32) ? 255 : 0;
+ b[3] = (d & 16) ? 255 : 0;
+ b[4] = (d & 8) ? 255 : 0;
+ b[5] = (d & 4) ? 255 : 0;
+ b[6] = (d & 2) ? 255 : 0;
+ b[7] = (d & 1) ? 255 : 0;
+ fwrite(b, 1, 8, file);
+ n -= 8;
+ }
+ if (n == 0) {
+ byte d = *data;
+ b[0] = (d & 128) ? 255 : 0;
+ b[1] = (d & 64) ? 255 : 0;
+ b[2] = (d & 32) ? 255 : 0;
+ b[3] = (d & 16) ? 255 : 0;
+ fwrite(b, 1, 4, file);
+ }
+ return 0;
+}
+
+static int
+header_3x8(FILE *file, gx_device_chameleon *pcdev)
+{
+ fprintf(file, "P6\n%d %d 255\n",
+ pcdev->width, pcdev->height);
+ return 0;
+}
+
+static int
+do_fwrite(const byte *data, int n, FILE *file)
+{
+ return fwrite(data, 1, (n+7)>>3, file);
+}
+
+static int tiff_chunky_post_cm(void *arg, byte **dst, byte **src, int w, int h,
+ int raster)
+{
+ gsicc_bufferdesc_t input_buffer_desc, output_buffer_desc;
+ gsicc_link_t *icclink = (gsicc_link_t*)arg;
+
+ gsicc_init_buffer(&input_buffer_desc, icclink->num_input, 1, false,
+ false, false, 0, raster, h, w);
+ gsicc_init_buffer(&output_buffer_desc, icclink->num_output, 1, false,
+ false, false, 0, raster, h, w);
+ icclink->procs.map_buffer(NULL, icclink, &input_buffer_desc, &output_buffer_desc,
+ src[0], dst[0]);
+ return 0;
+}
+
+static byte ht_data[256] =
+{
+ 0x0E, 0x8E, 0x2E, 0xAE, 0x06, 0x86, 0x26, 0xA6, 0x0C, 0x8C, 0x2C, 0xAC, 0x04, 0x84, 0x24, 0xA4,
+ 0xCE, 0x4E, 0xEE, 0x6E, 0xC6, 0x46, 0xE6, 0x66, 0xCC, 0x4C, 0xEC, 0x6C, 0xC4, 0x44, 0xE4, 0x64,
+ 0x3E, 0xBE, 0x1E, 0x9E, 0x36, 0xB6, 0x16, 0x96, 0x3C, 0xBC, 0x1C, 0x9C, 0x34, 0xB4, 0x14, 0x94,
+ 0xFE, 0x7E, 0xDE, 0x5E, 0xF6, 0x76, 0xD6, 0x56, 0xFC, 0x7C, 0xDC, 0x5C, 0xF4, 0x74, 0xD4, 0x54,
+ 0x01, 0x81, 0x21, 0xA1, 0x09, 0x89, 0x29, 0xA9, 0x03, 0x83, 0x23, 0xA3, 0x0B, 0x8B, 0x2B, 0xAB,
+ 0xC1, 0x41, 0xE1, 0x61, 0xC9, 0x49, 0xE9, 0x69, 0xC3, 0x43, 0xE3, 0x63, 0xCB, 0x4B, 0xEB, 0x6B,
+ 0x31, 0xB1, 0x11, 0x91, 0x39, 0xB9, 0x19, 0x99, 0x33, 0xB3, 0x13, 0x93, 0x3B, 0xBB, 0x1B, 0x9B,
+ 0xF1, 0x71, 0xD1, 0x51, 0xF9, 0x79, 0xD9, 0x59, 0xF3, 0x73, 0xD3, 0x53, 0xFB, 0x7B, 0xDB, 0x5B,
+ 0x0D, 0x8D, 0x2D, 0xAD, 0x05, 0x85, 0x25, 0xA5, 0x0F, 0x8F, 0x2F, 0xAF, 0x07, 0x87, 0x27, 0xA7,
+ 0xCD, 0x4D, 0xED, 0x6D, 0xC5, 0x45, 0xE5, 0x65, 0xCF, 0x4F, 0xEF, 0x6F, 0xC7, 0x47, 0xE7, 0x67,
+ 0x3D, 0xBD, 0x1D, 0x9D, 0x35, 0xB5, 0x15, 0x95, 0x3F, 0xBF, 0x1F, 0x9F, 0x37, 0xB7, 0x17, 0x97,
+ 0xFD, 0x7D, 0xDD, 0x5D, 0xF5, 0x75, 0xD5, 0x55, 0xFF, 0x7F, 0xDF, 0x5F, 0xF7, 0x77, 0xD7, 0x57,
+ 0x02, 0x82, 0x22, 0xA2, 0x0A, 0x8A, 0x2A, 0xAA, 0x01 /*0x00*/, 0x80, 0x20, 0xA0, 0x08, 0x88, 0x28, 0xA8,
+ 0xC2, 0x42, 0xE2, 0x62, 0xCA, 0x4A, 0xEA, 0x6A, 0xC0, 0x40, 0xE0, 0x60, 0xC8, 0x48, 0xE8, 0x68,
+ 0x32, 0xB2, 0x12, 0x92, 0x3A, 0xBA, 0x1A, 0x9A, 0x30, 0xB0, 0x10, 0x90, 0x38, 0xB8, 0x18, 0x98,
+ 0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A, 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58
+};
+
+static gx_downscaler_ht_t default_ht[4] =
+{
+ { 16, 16, 16, 0, 0, ht_data },
+ { 16, 16, 16, 0, 0, ht_data },
+ { 16, 16, 16, 0, 0, ht_data },
+ { 16, 16, 16, 0, 0, ht_data }
+};
+
+/* Send the page to the printer. */
+static int
+chameleon_print_page(gx_device_printer * pdev, FILE * prn_stream)
+{ /* Just dump the bits on the file. */
+ gx_device_chameleon *pcdev = (gx_device_chameleon *)pdev;
+ /* If the file is 'nul', don't even do the writes. */
+ int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
+ byte *in, *in_alloc;
+ byte *data;
+ int nul;
+ int line_count = pdev->height;
+ int i, code;
+ gx_downscaler_t ds = { NULL };
+ int depth = pdev->color_info.depth;
+ int factor = pcdev->downscale.downscale_factor;
+ int mfs = pcdev->downscale.min_feature_size;
+ int pxm = pcdev->output_as_pxm;
+ int dst_bpp;
+ int (*write)(const byte *, int, FILE *) = do_fwrite;
+ int (*header)(FILE *, gx_device_chameleon *) = NULL;
+ int bitwidth;
+ gx_downscale_cm_fn *col_convert = NULL;
+ void *col_convert_arg = NULL;
+
+ switch (pcdev->dst_num_components * pcdev->dst_bpc) {
+ case 1*1: case 1*2: case 1*4: case 1*8:
+ case 4*4: case 4*8: case 3*8:
+ dst_bpp = pcdev->dst_num_components * pcdev->dst_bpc;
+ break;
+ case 3*1:
+ dst_bpp = 4;
+ break;
+ case 3*2:
+ dst_bpp = 8;
+ break;
+ case 3*4:
+ dst_bpp = 12;
+ break;
+ default:
+ return gs_error_rangecheck;
+ }
+
+ bitwidth = pdev->width * dst_bpp;
+ line_size = (bitwidth+7)>>3;
+ in_alloc = gs_alloc_bytes(pdev->memory, line_size+32, "chameleon_print_page(in)");
+ if (in_alloc == 0)
+ return_error(gs_error_VMerror);
+ in = in_alloc + ((32-(intptr_t)in_alloc) & 31);
+
+ if (!strcmp(pdev->fname, "nul") || !strcmp(pdev->fname, "/dev/null"))
+ write = NULL;
+ else if (pxm) {
+ switch (pcdev->dst_num_components) {
+ case 4:
+ if (pcdev->dst_bpc == 1)
+ header = header_4x1, write = write_4x1;
+ break;
+ case 3:
+ if (pcdev->dst_bpc == 8)
+ header = header_3x8;
+ break;
+ }
+ }
+
+ /* If we have a post render profile, and the number of components
+ * of that is compatible with the desired destination number of
+ * components, then use that. */
+ if (pcdev->icc_struct->postren_profile &&
+ pcdev->icc_struct->postren_profile->num_comps == pcdev->dst_num_components) {
+ col_convert = tiff_chunky_post_cm;
+ col_convert_arg = pcdev->icc_struct->postren_profile;
+ }
+ /* Can we get away with no conversion? */
+ else if (pcdev->num_components == pcdev->dst_num_components &&
+ pcdev->bpc == pcdev->dst_bpc) {
+ /* Nothing to do */
+ }
+ /* Otherwise, use some inbuilt crap conversions */
+ else if (pcdev->num_components == 3 && pcdev->bpc == 8 && pcdev->dst_num_components == 4) {
+ col_convert = craprgbtocmyk;
+ col_convert_arg = NULL;
+ } else {
+ emprintf(pdev->memory, "Chameleon device doesn't support this color conversion.\n");
+ return gs_error_rangecheck;
+ }
+
+ code = gx_downscaler_init_trapped_cm_halftone
+ (&ds,
+ (gx_device *)pdev,
+ pcdev->bpc,
+ pcdev->dst_bpc,
+ pcdev->num_components,
+ pcdev->downscale.downscale_factor,
+ pcdev->downscale.min_feature_size,
+ NULL, 0, /* Adjust width */
+ 0, 0, NULL, /* Trapping w/h/comp_order */
+ col_convert, col_convert_arg, /* Color Management */
+ pcdev->dst_num_components,
+ default_ht);
+ if (code < 0)
+ goto cleanup;
+
+ if (header) {
+ code = header(prn_stream, pcdev);
+ if (code < 0)
+ goto cleanup;
+ }
+
+ for (i = 0; i < line_count; i++) {
+ code = gx_downscaler_getbits(&ds, in, i);
+ if (code < 0)
+ break;
+ if (write != NULL)
+ write(in, bitwidth, prn_stream);
+ }
+ gx_downscaler_fin(&ds);
+cleanup:
+ gs_free_object(pdev->memory, in_alloc, "chameleon_print_page(in)");
+ return code;
+}
diff --git a/gpdl/psi/psitop.c b/gpdl/psi/psitop.c
index 778837ffd..2a5e6b59e 100644
--- a/gpdl/psi/psitop.c
+++ b/gpdl/psi/psitop.c
@@ -21,6 +21,7 @@
#include "imain.h"
#include "imainarg.h"
#include "iapi.h"
+#include "psapi.h"
#include "string_.h"
#include "gdebug.h"
#include "gp.h"
@@ -39,6 +40,7 @@
#include "gxstate.h"
#include "plparse.h"
#include "pltop.h"
+#include "plmain.h"
#include "gzstate.h"
#include "gsicc_manage.h"
@@ -55,17 +57,112 @@ extern int zflush(i_ctx_t *);
* PS interpreter instance: derived from pl_interp_implementation_t
*/
typedef struct ps_interp_instance_s {
- pl_interp_implementation_t pl;
+ gs_memory_t *memory;
+ uint bytes_fed;
+ gs_lib_ctx_t *psapi_instance;
} ps_interp_instance_t;
static int
+check_token(int token_type, const char *s, const char *e, int *score)
+{
+ /* Empty tokens are always OK */
+ if (s == e)
+ return 0;
+
+ switch (token_type) {
+ case 'a':
+ /* Angle bracket - mainly to catch << */
+ break;
+ case 'n':
+ /* Name */
+ /* FIXME: Check it's a valid name */
+ break;
+ case 'd':
+ /* Dictionary */
+ break;
+ case 'i':
+ /* int - ok by construction. */
+ return 0;
+ case 'f':
+ /* float - ok by construction. */
+ return 0;
+ }
+
+#define TOKEN_CHECK(n) else if (e-s == strlen(n) && memcmp(s, n, e-s) == 0) { score[0] += e-s; score[1]++; }
+
+ if (0) {}
+ TOKEN_CHECK("dup")
+ TOKEN_CHECK("exch")
+ TOKEN_CHECK("grestore")
+ TOKEN_CHECK("gsave")
+ TOKEN_CHECK("idiv")
+ TOKEN_CHECK("lineto")
+ TOKEN_CHECK("mod")
+ TOKEN_CHECK("mul")
+ TOKEN_CHECK("moveto")
+ TOKEN_CHECK("setflat")
+ TOKEN_CHECK("setlinecap")
+ TOKEN_CHECK("setlinejoin")
+ TOKEN_CHECK("showpage")
+ TOKEN_CHECK("stroke")
+ TOKEN_CHECK("translate")
+ TOKEN_CHECK("systemdict")
+
+ if (score[0] > 1024 && score[2] >= 3)
+ return 1;
+ if (score[0] < -1024)
+ return 1;
+
+ return 0;
+}
+
+static int
+score_comment(const char *s, const char *e, int *score)
+{
+#define COMMENT_CHECK(n) else if (e-s >= strlen(n) && memcmp(s, n, strlen(n)) == 0) { score[0] += 100; score[1]++; }
+
+ if (0) {}
+ COMMENT_CHECK("!PS")
+ COMMENT_CHECK("%Title:")
+ COMMENT_CHECK("%Version:")
+ COMMENT_CHECK("%Creator:")
+ COMMENT_CHECK("%CreationDate:")
+ COMMENT_CHECK("%Document")
+ COMMENT_CHECK("%BoundingBox:")
+ COMMENT_CHECK("%HiResBoundingBox:")
+ COMMENT_CHECK("%Pages:")
+ COMMENT_CHECK("%+ procset")
+ COMMENT_CHECK("%End")
+ COMMENT_CHECK("%Begin")
+ COMMENT_CHECK("%Copyright")
+ else {
+ score[0]++; score[1]++;
+ }
+
+ if (score[0] > 1024 && score[1] >= 3)
+ return 1;
+
+ return 0;
+}
+
+static int
ps_detect_language(const char *s, int len)
{
/* For postscript, we look for %! */
if (len >= 2) {
- /* Be careful to avoid shell scripts (e.g. #!/bin/bash) if possible */
- if (s[0] == '%' && s[1] == '!' && (len < 3 || s[2] != '/'))
+ if (s[0] != '%' || s[1] != '!') {
+ /* Not what we were looking for */
+ } else if (len >= 12 && memcmp(s+2, "Postscript", 10) == 0) {
+ return 100;
+ } else if (len >= 4 && memcmp(s+2, "PS", 2) == 0) {
+ return 100;
+ } else if (len >= 3 && s[2] == '/') {
+ /* Looks like a shell script. Don't want that. */
return 0;
+ } else {
+ /* If it begins %!, then it's PROBABLY postscript */
+ return 80;
+ }
}
/* For PDF, we allow for leading crap, then a postscript version marker */
{
@@ -79,7 +176,7 @@ ps_detect_language(const char *s, int len)
t[5] >= '1' && t[5] <= '9' &&
t[6] == '.' &&
t[7] >= '0' && t[7] <= '9') {
- return 0;
+ return 100;
}
if (memcmp(t, "%!PS-Adobe-", 11) == 0 &&
t[11] >= '0' && t[11] <= '9' &&
@@ -89,14 +186,115 @@ ps_detect_language(const char *s, int len)
t[19] >= '0' && t[19] <= '9' &&
t[20] == '.' &&
t[21] >= '0' && t[21] <= '9') {
- return 0;
+ return 100;
}
t++;
left--;
}
}
- return 1;
+ /* Now we do some seriously hairy stuff */
+ {
+ const char *t = s;
+ const char *token = t;
+ int left = len;
+ int token_type = 0;
+ int score[2] = { 0, 0 };
+
+ while (left--) {
+ if (*t == '%') {
+ if (check_token(token_type, token, t, score))
+ break;
+ /* Skip to end of line */
+ left--;
+ token = ++t;
+ while (left && *t != '\r' && *t != '\n') {
+ left--; t++;
+ }
+ if (score_comment(token, t, score))
+ break;
+ /* Skip any combination of newlines */
+ while (left && (*t == '\r' || *t == '\n')) {
+ left--; t++;
+ }
+ token_type = 0;
+ continue;
+ } else if (*t == 27) {
+ /* Give up if we meet an ESC. It could be a UEL. */
+ break;
+ } else if (*t <= 32 || *t > 127) {
+ if (check_token(token_type, token, t, score))
+ break;
+ if (*t != 9 && *t != 10 && *t != 12 && *t != 13 && *t != 32)
+ score[0]--;
+ token = t+1;
+ token_type = 0;
+ } else if (*t == '/') {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t+1;
+ token_type = 'n';
+ } else if (*t == '[' || *t == ']' || *t == '{' || *t == '}') {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t+1;
+ token_type = 0;
+ } else if (*t == '<') {
+ if (token_type == 'a') {
+ /* << */
+ token = t+1;
+ token_type = 'd';
+ } else if (token_type == 'd') {
+ /* <<< ???!? */
+ score[0] -= 10;
+ } else {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t+1;
+ token_type = 'a';
+ }
+ } else if (*t == '>') {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t+1;
+ token_type = 0;
+ } else if (*t >= '0' && *t <= '9') {
+ if (token_type == 'i') {
+ /* Keep going */
+ } else if (token_type == 'f') {
+ /* Keep going */
+ } else {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t;
+ token_type = 'i';
+ }
+ } else if (*t == '.') {
+ if (token_type == 'f') {
+ /* seems unlikely */
+ score[0]--;
+ break;
+ } else if (token_type == 'i') {
+ token = t;
+ token_type = 'f';
+ } else {
+ if (check_token(token_type, token, t, score))
+ break;
+ token = t;
+ token_type = 'f';
+ }
+ } else {
+ /* Assume anything else goes into the token */
+ }
+ t++;
+ }
+ if (score[0] < 0 || score[1] < 3)
+ return 0; /* Unlikely to be PS */
+ else if (score[0] > 0)
+ return 75; /* Could be PS */
+ }
+
+ return 0;
}
/* Get implementation's characteristics */
@@ -130,30 +328,98 @@ ps_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *
"ps_impl_allocate_interp_instance");
int code;
-
+#define GS_MAX_NUM_ARGS 10
+ const char *gsargs[GS_MAX_NUM_ARGS] = {0};
+ int nargs = 0;
+
if (!psi)
return gs_error_VMerror;
-
- code = gsapi_new_instance(&impl->interp_client_data, NULL);
+
+ gsargs[nargs++] = "gpdl";
+ /* We start gs with the nullpage device, and replace the device with the
+ * set_device call from the language independent code.
+ */
+ gsargs[nargs++] = "-dNODISPLAY";
+ /* As we're "printer targetted, use a jobserver */
+ gsargs[nargs++] = "-dJOBSERVER";
+
+ psi->memory = mem;
+ psi->bytes_fed = 0;
+ psi->psapi_instance = gs_lib_ctx_get_interp_instance(mem);
+ code = psapi_new_instance(&psi->psapi_instance, NULL);
if (code < 0)
gs_free_object(mem, psi, "ps_impl_allocate_interp_instance");
+
+ impl->interp_client_data = psi;
+
+ /* Tell gs not to ignore a UEL, but do an interpreter exit */
+ psapi_act_on_uel(psi->psapi_instance);
+
+ code = psapi_init_with_args01(psi->psapi_instance, nargs, (char **)gsargs);
+ if (code < 0) {
+ psapi_delete_instance(psi->psapi_instance);
+ gs_free_object(mem, psi, "ps_impl_allocate_interp_instance");
+ }
return code;
}
-/* Set a device into an interpreter instance */
+/*
+ * Get the allocator with which to allocate a device
+ */
+static gs_memory_t *
+ps_impl_get_device_memory(pl_interp_implementation_t *impl)
+{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+
+ return psapi_get_device_memory(psi->psapi_instance);
+}
+
static int
-ps_impl_set_device(pl_interp_implementation_t *impl, gx_device *device)
+ps_impl_set_param(pl_interp_implementation_t *impl,
+ pl_set_param_type type,
+ const char *param,
+ const void *val)
{
- /* Nothing to PS/PDF manages it's own device */
- return 0;
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+
+ return psapi_set_param(psi->psapi_instance, type, param, val);
}
+static int
+ps_impl_post_args_init(pl_interp_implementation_t *impl)
+{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ const float *resolutions;
+ const long *page_sizes;
+
+ pl_main_get_forced_geometry(psi->memory, &resolutions, &page_sizes);
+ psapi_force_geometry(psi->psapi_instance, resolutions, page_sizes);
+
+ return psapi_init_with_args2(psi->psapi_instance);
+}
/* Prepare interp instance for the next "job" */
static int
-ps_impl_init_job(pl_interp_implementation_t *impl)
+ps_impl_init_job(pl_interp_implementation_t *impl,
+ gx_device *device)
{
- return gsapi_init_with_args(impl->interp_client_data, 0, NULL);
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ int exit_code;
+ int code = 0;
+
+ /* Any error after here *must* reset the device to null */
+ if (code >= 0)
+ code = psapi_set_device(psi->psapi_instance, device);
+
+ if (code >= 0)
+ code = psapi_run_string(psi->psapi_instance, "erasepage", 0, &exit_code);
+
+ if (code < 0) {
+ int code1 = psapi_set_device(psi->psapi_instance, NULL);
+ (void)code1;
+ }
+
+ return code;
}
/* Not complete. */
@@ -161,15 +427,92 @@ static int
ps_impl_process_file(pl_interp_implementation_t *impl, char *filename)
{
/* NB incomplete */
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ int exit_code;
+
+ return psapi_run_file(psi->psapi_instance, filename, 0, &exit_code);
+}
+
+/* Do any setup for parser per-cursor */
+static int /* ret 0 or +ve if ok, else -ve error code */
+ps_impl_process_begin(pl_interp_implementation_t * impl)
+{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
int exit_code;
- return gsapi_run_file(impl->interp_client_data, filename, 0, &exit_code);
+
+ psi->bytes_fed = 0;
+ return psapi_run_string_begin(psi->psapi_instance, 0, &exit_code);
+}
+
+/* TODO: in some fashion have gs pass back how far into the input buffer it
+ * had read, so we don't need to explicitly search the buffer for the UEL
+ */
+static int
+ps_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
+{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ const unsigned int len = pr->limit - pr->ptr;
+ int code, exit_code = 0;
+
+ code = psapi_run_string_continue(psi->psapi_instance, (const char *)pr->ptr + 1, len, 0, &exit_code);
+ if (exit_code == gs_error_InterpreterExit) {
+ int64_t offset;
+
+ offset = psapi_get_uel_offset(psi->psapi_instance) - psi->bytes_fed;
+ pr->ptr += offset;
+ psi->bytes_fed += offset + 1;
+
+#ifdef SEND_CTRLD_AFTER_UEL
+ {
+ const char eot[1] = {4};
+ code = psapi_run_string_continue(psi->psapi_instance, eot, 1, 0, &exit_code);
+ (void)code; /* Ignoring code here */
+ }
+#endif
+ return gs_error_InterpreterExit;
+ }
+ else {
+ pr->ptr = pr->limit;
+ psi->bytes_fed += len;
+ }
+ return code;
+}
+
+static int /* ret 0 or +ve if ok, else -ve error code */
+ps_impl_process_end(pl_interp_implementation_t * impl)
+{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ int exit_code, code;
+
+ code = psapi_run_string_end(psi->psapi_instance, 0, &exit_code);
+
+ if (exit_code == gs_error_InterpreterExit || code == gs_error_NeedInput)
+ code = 0;
+
+ return code;
}
/* Not implemented */
static int
ps_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
{
- return 0;
+ const byte *p = cursor->ptr;
+ const byte *rlimit = cursor->limit;
+
+ /* Skip to, but leave UEL in buffer for PJL to find later */
+ for (; p < rlimit; ++p)
+ if (p[1] == '\033') {
+ uint avail = rlimit - p;
+
+ if (memcmp(p + 1, "\033%-12345X", min(avail, 9)))
+ continue;
+ if (avail < 9)
+ break;
+ cursor->ptr = p;
+ return 1; /* found eoj */
+ }
+ cursor->ptr = p;
+ return 0; /* need more */
}
/* Parser action for end-of-file */
@@ -194,23 +537,24 @@ ps_impl_report_errors(pl_interp_implementation_t *impl, /* interp instance
static int
ps_impl_dnit_job(pl_interp_implementation_t *impl)
{
- return 0;
-}
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
-/* Remove a device from an interpreter instance */
-static int
-ps_impl_remove_device(pl_interp_implementation_t *impl)
-{
- return 0;
+ return psapi_set_device(psi->psapi_instance, NULL);
}
/* Deallocate a interpreter instance */
static int
ps_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
{
+ ps_interp_instance_t *psi = (ps_interp_instance_t *)impl->interp_client_data;
+ int code;
- int code = gsapi_exit(impl->interp_client_data);
- gsapi_delete_instance(impl->interp_client_data);
+ if (psi == NULL)
+ return 0;
+ code = psapi_exit(psi->psapi_instance);
+ psapi_delete_instance(psi->psapi_instance);
+ gs_free_object(psi->memory, psi, "ps_impl_allocate_interp_instance");
+ impl->interp_client_data = NULL;
return code;
}
@@ -218,15 +562,18 @@ ps_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
const pl_interp_implementation_t ps_implementation = {
ps_impl_characteristics,
ps_impl_allocate_interp_instance,
- ps_impl_set_device,
+ ps_impl_get_device_memory,
+ ps_impl_set_param,
+ ps_impl_post_args_init,
ps_impl_init_job,
ps_impl_process_file,
- NULL, /* process */
+ ps_impl_process_begin,
+ ps_impl_process,
+ ps_impl_process_end,
ps_impl_flush_to_eoj,
ps_impl_process_eof,
ps_impl_report_errors,
ps_impl_dnit_job,
- ps_impl_remove_device,
ps_impl_deallocate_interp_instance,
NULL
};
diff --git a/pcl/pcl/pctop.c b/pcl/pcl/pctop.c
index f0d981dea..383f3fcfc 100644
--- a/pcl/pcl/pctop.c
+++ b/pcl/pcl/pctop.c
@@ -40,6 +40,7 @@
#include "pcpalet.h"
#include "rtgmode.h"
#include "gsicc_manage.h"
+#include "pcparam.h"
/* Configuration table for modules */
extern const pcl_init_t pcparse_init;
@@ -168,9 +169,30 @@ typedef struct pcl_interp_instance_s
static int
pcl_detect_language(const char *s, int length)
{
+ int count;
+ int len;
+
if (length < 2)
- return 1;
- return memcmp(s, "\033E", 2);
+ return 0;
+ if (s[0] == 27) {
+ if (s[1] == 'E')
+ return 100;
+ return 80;
+ }
+
+ /* Count the number of ESC's */
+ for (count = 0, len = length; len > 0; len--, s++)
+ {
+ if (*s == 27)
+ count++;
+ }
+
+ if (count > 10 || count > length/20)
+ return 80;
+ if (count > 0)
+ return 20;
+
+ return 0;
}
/* Get implementation's characteristics */
@@ -252,7 +274,7 @@ pcl_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
}
pcli->pcs.pjls = pl_main_get_pjl_instance(mem);
-
+
/* Return success */
impl->interp_client_data = pcli;
return 0;
@@ -265,12 +287,12 @@ pcl_get_personality(pl_interp_implementation_t * impl, gx_device * device)
{
pcl_interp_instance_t *pcli = impl->interp_client_data;
char *personality = pl_main_get_pcl_personality(pcli->memory);
-
+
if (!strcmp(personality, "PCL5C"))
return pcl5c;
else if (!strcmp(personality, "PCL5E"))
return pcl5e;
- /*
+ /*
* match RTL or any string containing "GL" we see many variants in
* test files: HPGL/2, HPGL2 etc.
*/
@@ -291,21 +313,20 @@ pcl_set_icc_params(pl_interp_implementation_t * impl, gs_gstate * pgs)
return pl_set_icc_params(pcli->memory, pgs);
}
-/* Set a device into an interperter instance */
+/* Prepare interp instance for the next "job" */
static int /* ret 0 ok, else -ve error code */
-pcl_impl_set_device(pl_interp_implementation_t * impl, /* interp instance to use */
- gx_device * device /* device to set (open or closed) */
- )
+pcl_impl_init_job(pl_interp_implementation_t * impl, /* interp instance to start job in */
+ gx_device * device)
{
-
- int code;
+ int code = 0;
pcl_interp_instance_t *pcli = impl->interp_client_data;
gs_memory_t *mem = pcli->memory;
-
enum
{ Sbegin, Ssetdevice, Sinitg, Sgsave1, Spclgsave, Sreset, Serase,
Sdone } stage;
+ pcl_process_init(&pcli->pst);
+
stage = Sbegin;
/* Set parameters from the main instance */
@@ -385,19 +406,22 @@ pcl_impl_set_device(pl_interp_implementation_t * impl, /* interp instance to
case Sbegin: /* nothing left to undo */
break;
}
+
+ /* Warn the device we use ROPs */
+ if (code == 0) {
+ code = put_param1_bool(&pcli->pcs, "LanguageUsesROPs", true);
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ }
+
return code;
}
-/* Prepare interp instance for the next "job" */
-static int /* ret 0 ok, else -ve error code */
-pcl_impl_init_job(pl_interp_implementation_t * impl /* interp instance to start job in */
- )
+/* Do any setup for parser per-cursor */
+static int /* ret 0 or +ve if ok, else -ve error code */
+pcl_impl_process_begin(pl_interp_implementation_t * impl)
{
- int code = 0;
- pcl_interp_instance_t *pcli = impl->interp_client_data;
-
- pcl_process_init(&pcli->pst);
- return code;
+ return 0;
}
/* Parse a cursor-full of data */
@@ -412,6 +436,12 @@ pcl_impl_process(pl_interp_implementation_t * impl, /* interp instance to
return code;
}
+static int /* ret 0 or +ve if ok, else -ve error code */
+pcl_impl_process_end(pl_interp_implementation_t * impl)
+{
+ return 0;
+}
+
/* Skip to end of job ret 1 if done, 0 ok but EOJ not found, else -ve error code */
static int
pcl_impl_flush_to_eoj(pl_interp_implementation_t * impl, /* interp instance to flush for */
@@ -469,24 +499,12 @@ pcl_impl_report_errors(pl_interp_implementation_t * impl, /* interp instance to
/* Wrap up interp instance after a "job" */
static int /* ret 0 ok, else -ve error code */
-pcl_impl_dnit_job(pl_interp_implementation_t * impl /* interp instance to wrap up job in */
- )
+pcl_impl_dnit_job(pl_interp_implementation_t * impl) /* interp instance to wrap up job in */
{
pcl_interp_instance_t *pcli = impl->interp_client_data;
pcl_state_t *pcs = &pcli->pcs;
-
- if (pcs->raster_state.graphics_mode)
- return pcl_end_graphics_mode(pcs);
- return 0;
-}
-
-/* Remove a device from an interperter instance */
-static int /* ret 0 ok, else -ve error code */
-pcl_impl_remove_device(pl_interp_implementation_t * impl /* interp instance to use */
- )
-{
int code;
- pcl_interp_instance_t *pcli = impl->interp_client_data;
+ gx_device *device = gs_currentdevice(pcs->pgs);
/* Note: "PCL" grestore. */
code = pcl_grestore(&pcli->pcs);
@@ -498,7 +516,22 @@ pcl_impl_remove_device(pl_interp_implementation_t * impl /* interp instance to
if (code < 0)
return code;
- return pcl_do_resets(&pcli->pcs, pcl_reset_permanent);
+ code = pcl_do_resets(&pcli->pcs, pcl_reset_permanent);
+ if (code < 0)
+ return code;
+
+ if (pcs->raster_state.graphics_mode)
+ code = pcl_end_graphics_mode(pcs);
+
+ if (code >= 0) {
+ /* Warn the device that ROP usage has come to an end */
+ code = put_param1_bool(&pcli->pcs, "LanguageUsesROPs", false);
+
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ }
+
+ return code;
}
/* Deallocate a interpreter instance */
@@ -545,15 +578,18 @@ pcl_end_page_top(pcl_state_t * pcs, int num_copies, int flush)
pl_interp_implementation_t pcl_implementation = {
pcl_impl_characteristics,
pcl_impl_allocate_interp_instance,
- pcl_impl_set_device,
+ NULL,
+ NULL,
+ NULL,
pcl_impl_init_job,
NULL, /* process_file */
+ pcl_impl_process_begin,
pcl_impl_process,
+ pcl_impl_process_end,
pcl_impl_flush_to_eoj,
pcl_impl_process_eof,
pcl_impl_report_errors,
pcl_impl_dnit_job,
- pcl_impl_remove_device,
pcl_impl_deallocate_interp_instance,
NULL
};
diff --git a/pcl/pl/pjparsei.c b/pcl/pl/pjparsei.c
index dc060edf5..63ef55960 100644
--- a/pcl/pl/pjparsei.c
+++ b/pcl/pl/pjparsei.c
@@ -35,8 +35,10 @@ pjl_detect_language(const char *s, int len)
if (len && *s == '\n')
s++, len--;
if (len < 4)
- return 1;
- return memcmp(s, "@PJL", 4);
+ return 0;
+ if (memcmp(s, "@PJL", 4) == 0)
+ return 100;
+ return 0;
}
/* Get implementation's characteristics */
@@ -71,19 +73,10 @@ pjl_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
return 0;
}
-/* Set a device into an interperter instance */
-static int /* ret 0 ok, else -ve error code */
-pjl_impl_set_device(pl_interp_implementation_t *impl, /* interp instance to use */
- gx_device * device /* device to set (open or closed) */
- )
-{
- return 0;
-}
-
/* Prepare interp instance for the next "job" */
static int /* ret 0 ok, else -ve error code */
-pjl_impl_init_job(pl_interp_implementation_t *impl /* interp instance to start job in */
- )
+pjl_impl_init_job(pl_interp_implementation_t *impl, /* interp instance to start job in */
+ gx_device *device)
{
pjl_parser_state *pjls = impl->interp_client_data;
if (pjls == NULL)
@@ -93,6 +86,12 @@ pjl_impl_init_job(pl_interp_implementation_t *impl /* interp instance to s
return 0;
}
+static int
+pjl_impl_process_begin(pl_interp_implementation_t *impl /* interp instance to process data job in */)
+{
+ return 0;
+}
+
/* Parse a cursor-full of data */
/* The parser reads data from the input
@@ -113,6 +112,12 @@ pjl_impl_process(pl_interp_implementation_t *impl, /* interp instance to p
return code == 1 ? e_ExitLanguage : code;
}
+static int
+pjl_impl_process_end(pl_interp_implementation_t *impl /* interp instance to process data job in */)
+{
+ return 0;
+}
+
/* Skip to end of job ret 1 if done, 0 ok but EOJ not found, else -ve error code */
static int
pjl_impl_flush_to_eoj(pl_interp_implementation_t * impl, /* interp impl to flush for */
@@ -149,14 +154,6 @@ pjl_impl_dnit_job(pl_interp_implementation_t * impl /* interp impl to wrap
return 0;
}
-/* Remove a device from an interperter impl */
-static int /* ret 0 ok, else -ve error code */
-pjl_impl_remove_device(pl_interp_implementation_t * impl /* interp impl to use */
- )
-{
- return 0;
-}
-
/* Deallocate a interpreter impl */
static int /* ret 0 ok, else -ve error code */
pjl_impl_deallocate_interp_instance(pl_interp_implementation_t * impl /* impl to dealloc */
@@ -171,15 +168,18 @@ pjl_impl_deallocate_interp_instance(pl_interp_implementation_t * impl /* imp
pl_interp_implementation_t pjl_implementation = {
pjl_impl_characteristics,
pjl_impl_allocate_interp_instance,
- pjl_impl_set_device,
+ NULL,
+ NULL,
+ NULL,
pjl_impl_init_job,
NULL, /* process_file */
+ pjl_impl_process_begin,
pjl_impl_process,
+ pjl_impl_process_end,
pjl_impl_flush_to_eoj,
pjl_impl_process_eof,
pjl_impl_report_errors,
pjl_impl_dnit_job,
- pjl_impl_remove_device,
pjl_impl_deallocate_interp_instance,
NULL, /* instance */
};
diff --git a/pcl/pl/pl.mak b/pcl/pl/pl.mak
index f7432f2c2..1dd061059 100644
--- a/pcl/pl/pl.mak
+++ b/pcl/pl/pl.mak
@@ -352,7 +352,8 @@ $(PLOBJ)plmain.$(OBJ): $(PLSRC)plmain.c $(AK) $(string__h)\
$(gsalloc_h) $(gsargs_h) $(gp_h) $(gsdevice_h) $(gslib_h) $(gslibctx_h)\
$(gxdevice_h) $(gsparam_h) $(pjtop_h) $(plapi_h) $(plparse_h)\
$(plmain_h) $(pltop_h) $(stream_h) $(strmio_h) $(gsargs_h) $(dwtrace_h) $(vdtrace_h)\
- $(gxclpage_h) $(gdevprn_h) $(gxiodev_h) $(PL_MAK) $(MAKEDIRS)
+ $(gxclpage_h) $(gdevprn_h) $(gxiodev_h) $(assert__h)\
+ $(PL_MAK) $(MAKEDIRS)
$(PLCCC) $(PLSRC)plmain.c $(PLO_)plmain.$(OBJ)
# Real top level; provides main that just calls pl_main
diff --git a/pcl/pl/plapi.c b/pcl/pl/plapi.c
index f6673f45b..177b78d76 100644
--- a/pcl/pl/plapi.c
+++ b/pcl/pl/plapi.c
@@ -20,8 +20,27 @@
#include "gserrors.h"
#include "gsexit.h"
+#include "gp.h"
+#include "gscdefs.h"
+#include "gsmemory.h"
+
+/* Return revision numbers and strings of Ghostscript. */
+/* Used for determining if wrong GSDLL loaded. */
+/* This may be called before any other function. */
+GSDLLEXPORT int GSDLLAPI
+gsapi_revision(gsapi_revision_t *pr, int rvsize)
+{
+ if (rvsize < sizeof(gsapi_revision_t))
+ return sizeof(gsapi_revision_t);
+ pr->product = gs_product;
+ pr->copyright = gs_copyright;
+ pr->revision = gs_revision;
+ pr->revisiondate = gs_revisiondate;
+ return 0;
+}
+
GSDLLEXPORT int GSDLLAPI
-plapi_new_instance(void **lib, void *caller_handle)
+gsapi_new_instance(void **lib, void *caller_handle)
{
gs_memory_t *heap_mem = gs_malloc_init();
gs_memory_t *chunk_mem;
@@ -49,7 +68,24 @@ plapi_new_instance(void **lib, void *caller_handle)
}
GSDLLEXPORT int GSDLLAPI
-plapi_init_with_args(void *lib, int argc, char **argv)
+gsapi_set_stdio(void *instance,
+ int (GSDLLCALLPTR stdin_fn)(void *caller_handle, char *buf, int len),
+ int (GSDLLCALLPTR stdout_fn)(void *caller_handle, const char *str, int len),
+ int (GSDLLCALLPTR stderr_fn)(void *caller_handle, const char *str, int len))
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+
+ if (ctx == NULL)
+ return gs_error_Fatal;
+ ctx->core->stdin_fn = stdin_fn;
+ ctx->core->stdout_fn = stdout_fn;
+ ctx->core->stderr_fn = stderr_fn;
+
+ return 0;
+}
+
+GSDLLEXPORT int GSDLLAPI
+gsapi_init_with_args(void *lib, int argc, char **argv)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -59,17 +95,17 @@ plapi_init_with_args(void *lib, int argc, char **argv)
}
GSDLLEXPORT int GSDLLAPI
-plapi_run_file(void *lib, const char *file_name)
+gsapi_run_file(void *lib, const char *file_name)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
return gs_error_Fatal;
-
+
return pl_main_run_file(pl_main_get_instance(ctx->memory), file_name);
}
GSDLLEXPORT int GSDLLAPI
-plapi_exit(void *lib)
+gsapi_exit(void *lib)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -79,7 +115,7 @@ plapi_exit(void *lib)
}
GSDLLEXPORT int GSDLLAPI
-plapi_delete_instance(void *lib)
+gsapi_delete_instance(void *lib)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -88,9 +124,18 @@ plapi_delete_instance(void *lib)
return pl_main_delete_instance(pl_main_get_instance(ctx->memory));
}
-/* Set the display callback structure */
+GSDLLEXPORT int GSDLLAPI gsapi_set_poll(void *instance,
+ int (GSDLLCALLPTR poll_fn)(void *caller_handle))
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ if (instance == NULL)
+ return gs_error_Fatal;
+ ctx->core->poll_fn = poll_fn;
+ return 0;
+}
+
GSDLLEXPORT int GSDLLAPI
-plapi_set_display_callback(void *lib, void *callback)
+gsapi_set_display_callback(void *lib, display_callback *callback)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -100,7 +145,133 @@ plapi_set_display_callback(void *lib, void *callback)
}
GSDLLEXPORT int GSDLLAPI
-plapi_run_string_begin(void *lib)
+gsapi_set_default_device_list(void *instance, char *list, int listlen)
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ if (instance == NULL)
+ return gs_error_Fatal;
+ return gs_lib_ctx_set_default_device_list(ctx->memory, list, listlen);
+}
+
+GSDLLEXPORT int GSDLLAPI
+gsapi_get_default_device_list(void *instance, char **list, int *listlen)
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ if (instance == NULL)
+ return gs_error_Fatal;
+ return gs_lib_ctx_get_default_device_list(ctx->memory, list, listlen);
+}
+
+static int utf16le_get_codepoint(FILE *file, const char **astr)
+{
+ int c;
+ int rune;
+ int trail;
+
+ /* This code spots the BOM for 16bit LE and ignores it. Strictly speaking
+ * this may be wrong, as we are only supposed to ignore it at the beginning
+ * of the string, but if anyone is stupid enough to use ZWNBSP (zero width
+ * non breaking space) in the middle of their strings, then they deserve
+ * what they get. */
+ /* We spot the BOM for 16bit BE and treat that as EOF. We'd rather give
+ * up on dealing with a broken file than try to run something we know to
+ * be wrong. */
+
+ do {
+ if (file) {
+ rune = fgetc(file);
+ if (rune == EOF)
+ return EOF;
+ c = fgetc(file);
+ if (c == EOF)
+ return EOF;
+ rune += c<<8;
+ } else {
+ rune = (*astr)[0] | ((*astr)[1]<<8);
+ if (rune != 0)
+ (*astr) += 2;
+ else
+ return EOF;
+ }
+ if (rune == 0xFEFF) /* BOM - ignore it */
+ continue;
+ if (rune == 0xFFFE) /* BOM for BE - hopelessly broken */
+ return EOF;
+ if (rune < 0xD800 || rune >= 0xE000)
+ return rune;
+ if (rune >= 0xDC00) /* Found a trailing surrogate pair. Skip it */
+ continue;
+lead: /* We've just read a leading surrogate */
+ rune -= 0xD800;
+ rune <<= 10;
+ if (file) {
+ trail = fgetc(file);
+ if (trail == EOF)
+ return EOF;
+ c = fgetc(file);
+ if (c == EOF)
+ return EOF;
+ trail += c<<8;
+ } else {
+ trail = (*astr)[0] | ((*astr)[1]<<8);
+ if (trail != 0)
+ (*astr) += 2;
+ else
+ return EOF;
+ }
+ if (trail < 0xd800 || trail >= 0xE000) {
+ if (rune == 0xFEFF) /* BOM - ignore it. */
+ continue;
+ if (rune == 0xFFFE) /* BOM for BE - hopelessly broken. */
+ return EOF;
+ /* No trail surrogate was found, so skip the lead surrogate and
+ * return the rune we landed on. */
+ return trail;
+ }
+ if (trail < 0xdc00) {
+ /* We found another leading surrogate. */
+ rune = trail;
+ goto lead;
+ }
+ break;
+ } while (1);
+
+ return rune + (trail-0xDC00) + 0x10000;
+}
+
+/* Initialise the interpreter */
+GSDLLEXPORT int GSDLLAPI
+gsapi_set_arg_encoding(void *instance, int encoding)
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ if (instance == NULL)
+ return gs_error_Fatal;
+
+ if (encoding == PL_ARG_ENCODING_LOCAL) {
+#if defined(__WIN32__) && !defined(METRO)
+ /* For windows, we need to set it up so that we convert from 'local'
+ * format (in this case whatever codepage is set) to utf8 format. At
+ * the moment, all the other OS we care about provide utf8 anyway.
+ */
+ pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), gp_local_arg_encoding_get_codepoint);
+#else
+ pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), NULL);
+#endif /* WIN32 */
+ return 0;
+ }
+ if (encoding == PL_ARG_ENCODING_UTF8) {
+ pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), NULL);
+ return 0;
+ }
+ if (encoding == PL_ARG_ENCODING_UTF16LE) {
+ pl_main_set_arg_decode(pl_main_get_instance(ctx->memory), utf16le_get_codepoint);
+ return 0;
+ }
+ return gs_error_Fatal;
+}
+
+GSDLLEXPORT int GSDLLAPI
+gsapi_run_string_begin(void *lib)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -109,7 +280,7 @@ plapi_run_string_begin(void *lib)
}
GSDLLEXPORT int GSDLLAPI
-plapi_run_string_continue(void *lib, const char *str, unsigned int length)
+gsapi_run_string_continue(void *lib, const char *str, unsigned int length)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
@@ -118,7 +289,7 @@ plapi_run_string_continue(void *lib, const char *str, unsigned int length)
}
GSDLLEXPORT int GSDLLAPI
-plapi_run_string_end(void *lib)
+gsapi_run_string_end(void *lib)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)lib;
if (lib == NULL)
diff --git a/pcl/pl/plapi.h b/pcl/pl/plapi.h
index 48dc66bb8..7ab7a2814 100644
--- a/pcl/pl/plapi.h
+++ b/pcl/pl/plapi.h
@@ -17,8 +17,8 @@
/* plapi.h */
/* pcl6 as a library or dll api */
-#ifndef plapi_INCLUDED
-# define plapi_INCLUDED
+#ifndef gsapi_INCLUDED
+# define gsapi_INCLUDED
/*
* This API level is intended to hide everything behind
@@ -46,12 +46,18 @@
# ifndef GSDLLAPI
# define GSDLLAPI __stdcall
# endif
+# ifndef GSDLLCALL
+# define GSDLLCALL __stdcall
+# endif
#endif /* _Windows */
#if defined(OS2) && defined(__IBMC__)
# ifndef GSDLLAPI
# define GSDLLAPI _System
# endif
+# ifndef GSDLLCALL
+# define GSDLLCALL _System
+# endif
#endif /* OS2 && __IBMC */
#ifdef __MACINTOSH__
@@ -64,11 +70,21 @@
#ifndef GSDLLAPI
# define GSDLLAPI
#endif
+#ifndef GSDLLCALL
+# define GSDLLCALL
+#endif
#if defined(__IBMC__)
# define GSDLLAPIPTR * GSDLLAPI
+# define GSDLLCALLPTR * GSDLLCALL
#else
# define GSDLLAPIPTR GSDLLAPI *
+# define GSDLLCALLPTR GSDLLCALL *
+#endif
+
+#ifndef display_callback_DEFINED
+# define display_callback_DEFINED
+typedef struct display_callback_s display_callback;
#endif
#ifdef _Windows
@@ -76,22 +92,131 @@ GSDLLEXPORT int GSDLLAPI
pl_wchar_to_utf8(char *out, const void *in);
#endif
-GSDLLEXPORT int GSDLLAPI plapi_run_file(void *instance, const char *file_name);
+typedef struct gsapi_revision_s {
+ const char *product;
+ const char *copyright;
+ long revision;
+ long revisiondate;
+} gsapi_revision_t;
+
+/* Get version numbers and strings.
+ * This is safe to call at any time.
+ * You should call this first to make sure that the correct version
+ * of GhostPDL is being used.
+ * pr is a pointer to a revision structure.
+ * len is the size of this structure in bytes.
+ * Returns 0 if OK, or if len too small (additional parameters
+ * have been added to the structure) it will return the required
+ * size of the structure.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_revision(gsapi_revision_t *pr, int len);
+
+/* Create a new instance of GhostPDL.
+ * This instance is passed to most other API functions.
+ * The caller_handle will be provided to callback functions.
+ *
+ * On success: Returns 0, with *instance set to the newly created
+ * instance handle.
+ * On error: (such as the maximum number of instances being exceeded)
+ * this will return <0 and set *instance=NULL.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_new_instance(void **instance, void *caller_handle);
-GSDLLEXPORT int GSDLLAPI plapi_exit(void *instance);
+/* Destroy an instance of GhostPDL
+ * Before you call this, GhostPDL must have finished.
+ * If GhostPDL has been initialised, you must call gsapi_exit()
+ * before gsapi_delete_instance.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_delete_instance(void *instance);
+
+/* Set the callback functions for stdio
+ * The stdin callback function should return the number of
+ * characters read, 0 for EOF, or -1 for error.
+ * The stdout and stderr callback functions should return
+ * the number of characters written.
+ * If a callback address is NULL, the real stdio will be used.
+ */
+GSDLLEXPORT int GSDLLAPI
+gsapi_set_stdio(void *instance,
+ int (GSDLLCALLPTR stdin_fn)(void *caller_handle, char *buf, int len),
+ int (GSDLLCALLPTR stdout_fn)(void *caller_handle, const char *str, int len),
+ int (GSDLLCALLPTR stderr_fn)(void *caller_handle, const char *str, int len));
+
+/* Set the callback function for polling.
+ * This is used for handling window events or cooperative
+ * multitasking. This function will only be called if
+ * Ghostscript was compiled with CHECK_INTERRUPTS
+ * as described in gpcheck.h.
+ * The polling function should return 0 if all is well,
+ * and negative if it wants ghostscript to abort.
+ * The polling function must be fast.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_set_poll(void *instance,
+ int (GSDLLCALLPTR poll_fn)(void *caller_handle));
-GSDLLEXPORT int GSDLLAPI plapi_init_with_args(void *instance, int argc, char **argv);
+/* Set the display device callback structure.
+ * If the display device is used, this must be called
+ * after gsapi_new_instance() and before gsapi_init_with_args().
+ * See gdevdisp.h for more details.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_set_display_callback(
+ void *instance, display_callback *callback);
+
+/* Set the string containing the list of default device names
+ * for example "display x11alpha x11 bbox". Allows the calling
+ * application to influence which device(s) gs will try in order
+ * to select the default device
+ *
+ * If this is to be called, it must be called after
+ * gsapi_new_instance() and before gsapi_init_with_args().
+ */
+GSDLLEXPORT int GSDLLAPI
+gsapi_set_default_device_list(void *instance, char *list, int listlen);
-GSDLLEXPORT int GSDLLAPI plapi_new_instance(void **instance, void *caller_handle);
+/* Returns a pointer to the current default device string.
+ */
+GSDLLEXPORT int GSDLLAPI
+gsapi_get_default_device_list(void *instance, char **list, int *listlen);
+
+/* Set the encoding used for the args. By default we assume
+ * 'local' encoding. For windows this equates to whatever the current
+ * codepage is. For linux this is utf8.
+ *
+ * Use of this API (gsapi) with 'local' encodings (and hence without calling
+ * this function) is now deprecated!
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_set_arg_encoding(void *instance,
+ int encoding);
+
+enum {
+ PL_ARG_ENCODING_LOCAL = 0,
+ PL_ARG_ENCODING_UTF8 = 1,
+ PL_ARG_ENCODING_UTF16LE = 2
+};
+
+/* Initialise the interpreter.
+ * If this returns gs_error_Quit, then the interpreter quit due to
+ * an explicit .quit. This is not an error. You must call gsapi_exit()
+ * and gsapi_destroy_instance(). You may not call any other plapi
+ * functions.
+ * If this returns gs_error_Info, then usage info should be displayed.
+ * This is not an error. You must call gsapi_exit() and
+ * gsapi_destroy_instance(). You may not call any other plapi functions.
+ * If this returns another negative value, this is an error.
+ * Normal return is 0 or greater. Callers can then call other
+ * gsapi_run... functions if required, ending with gsapi_exit and
+ * gsapi_destroy_instance.
+ */
+GSDLLEXPORT int GSDLLAPI gsapi_init_with_args(void *instance, int argc, char **argv);
-GSDLLEXPORT int GSDLLAPI plapi_delete_instance(void *instance);
+GSDLLEXPORT int GSDLLAPI gsapi_run_file(void *instance, const char *file_name);
-GSDLLEXPORT int GSDLLAPI plapi_set_display_callback(void *lib, void *callback);
+GSDLLEXPORT int GSDLLAPI gsapi_exit(void *instance);
-GSDLLEXPORT int GSDLLAPI plapi_run_string_begin(void *instance);
+GSDLLEXPORT int GSDLLAPI gsapi_run_string_begin(void *instance);
-GSDLLEXPORT int GSDLLAPI plapi_run_string_continue(void *instance, const char *str, unsigned int length);
+GSDLLEXPORT int GSDLLAPI gsapi_run_string_continue(void *instance, const char *str, unsigned int length);
-GSDLLEXPORT int GSDLLAPI plapi_run_string_end(void *instance);
+GSDLLEXPORT int GSDLLAPI gsapi_run_string_end(void *instance);
-#endif /* plapi_INCLUDED */
+#endif /* gsapi_INCLUDED */
diff --git a/pcl/pl/plmain.c b/pcl/pl/plmain.c
index 043ab92bf..bdcb66d3c 100644
--- a/pcl/pl/plmain.c
+++ b/pcl/pl/plmain.c
@@ -18,6 +18,7 @@
/* Main program command-line interpreter for PCL interpreters */
#include "string_.h"
#include <stdlib.h> /* atof */
+#include "assert_.h"
#include "gdebug.h"
#include "gscdefs.h"
#include "gsio.h"
@@ -87,12 +88,16 @@ struct pl_main_instance_s
{
/* The following are set at initialization time. */
gs_memory_t *memory;
+ gs_memory_t *device_memory;
long base_time[2]; /* starting time */
int error_report; /* -E# */
bool pause; /* -dNOPAUSE => false */
int first_page; /* -dFirstPage= */
int last_page; /* -dLastPage= */
gx_device *device;
+ gs_gc_root_t *device_root;
+ pl_main_get_codepoint_t *get_codepoint;
+ /* Get next 'unicode' codepoint */
pl_interp_implementation_t *implementation; /*-L<Language>*/
@@ -102,7 +107,9 @@ struct pl_main_instance_s
bool interpolate;
bool nocache;
bool page_set_on_command_line;
+ long page_size[2];
bool res_set_on_command_line;
+ float res[2];
bool high_level_device;
#ifndef OMIT_SAVED_PAGES_TEST
bool saved_pages_test_mode;
@@ -119,17 +126,11 @@ struct pl_main_instance_s
arg_list args;
pl_interp_implementation_t **implementations;
pl_interp_implementation_t *curr_implementation;
- pl_interp_implementation_t *desired_implementation;
byte buf[8192]; /* languages read buffer */
void *disp; /* display device pointer NB wrong - remove */
};
-/* ---------------- Static data for memory management ------------------ */
-
-static gs_gc_root_t device_root;
-
-
/* ---------------- Forward decls ------------------ */
static int pl_main_languages_init(gs_memory_t * mem, pl_main_instance_t * inst);
@@ -209,7 +210,7 @@ pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[])
gs_param_list_set_persistent_keys((gs_param_list *)&inst->params, false);
arg_init(&inst->args, (const char **)argv, argc, pl_main_arg_fopen, NULL,
- NULL, mem);
+ inst->get_codepoint, mem);
/* Create PDL instances, etc */
if (pl_main_languages_init(mem, inst) < 0) {
@@ -219,7 +220,7 @@ pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[])
inst->curr_implementation = pjli = inst->implementations[0];
/* initialize pjl, needed for option processing. */
- if (pl_init_job(pjli) < 0) {
+ if (pl_init_job(pjli, inst->device) < 0) {
return gs_error_Fatal;
}
@@ -256,25 +257,53 @@ pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[])
int
-pl_main_run_string_begin(void *instance)
+pl_main_run_string_begin(pl_main_instance_t *minst)
{
- return 0;
+ return pl_process_begin(minst->curr_implementation);
}
int
-pl_main_run_string_continue(void *instance, const char *str, unsigned int length)
+pl_main_run_string_continue(pl_main_instance_t *minst, const char *str, unsigned int length)
{
- return 0;
+ stream_cursor_read cursor;
+
+ cursor.ptr = (const byte *)str-1; /* -1 because of gs's stupid stream convention */
+ cursor.limit = cursor.ptr + length;
+ return pl_process(minst->curr_implementation, &cursor);
}
int
-pl_main_run_string_end(void *instance)
+pl_main_run_string_end(pl_main_instance_t *minst)
{
- return 0;
+ return pl_process_end(minst->curr_implementation);
}
-int
-pl_main_run_file(pl_main_instance_t *minst, const char *filename)
+static int
+revert_to_pjli(pl_main_instance_t *minst)
+{
+ pl_interp_implementation_t *pjli =
+ minst->implementations[0];
+ int code;
+
+ /* If we're already in PJL, don't clear the state. */
+ if (minst->curr_implementation == pjli)
+ return 0;
+
+ if (minst->curr_implementation) {
+ code = pl_dnit_job(minst->curr_implementation);
+ if (code < 0) {
+ minst->curr_implementation = NULL;
+ return code;
+ }
+ }
+ minst->curr_implementation = pjli;
+ code = pl_init_job(minst->curr_implementation, minst->device);
+
+ return code;
+}
+
+static int
+pl_main_run_file_utf8(pl_main_instance_t *minst, const char *filename)
{
bool new_job = true;
pl_interp_implementation_t *pjli =
@@ -283,20 +312,40 @@ pl_main_run_file(pl_main_instance_t *minst, const char *filename)
stream *s;
int code = 0;
bool is_stdin = filename[0] == '-' && filename[1] == 0;
+ bool use_process_file = false;
+ bool first_job = true;
+ pl_interp_implementation_t *desired_implementation = NULL;
s = sfopen(filename, "r", mem);
if (s == NULL)
- return gs_error_Fatal;
+ return gs_error_undefinedfilename;
+
+ /* This function can run in 2 modes. Either it can run a file directly
+ * using the run_file mechanism, or it can feed the data piecemeal
+ * using the run_string mechanism. Which one depends on several things:
+ *
+ * If we're being piped data, then we have to use run_string.
+ * If we are entered (as is usually the case) with PJL as the selected
+ * interpreter, then we do a quick assessment of the file contents to
+ * pick an interpreter. If the first interpreter has a run_file method
+ * then we'll use that.
+ *
+ * This means that files that start with PJL data will always be run
+ * using run_string.
+ */
for (;;) {
if_debug1m('I', mem, "[i][file pos=%ld]\n",
sftell(s));
+ /* Check for EOF and prepare the next block of data. */
if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s)) {
if_debug0m('I', mem, "End of of data\n");
+ if (pl_process_end(minst->curr_implementation) < 0)
+ goto error_fatal;
pl_process_eof(minst->curr_implementation);
- if (pl_dnit_job(minst->curr_implementation) < 0)
- return gs_error_Fatal;
+ if (revert_to_pjli(minst) < 0)
+ goto error_fatal_reverted;
break;
}
code = s_process_read_buf(s);
@@ -304,102 +353,163 @@ pl_main_run_file(pl_main_instance_t *minst, const char *filename)
break;
if (new_job) {
- if_debug0m('I', mem, "Selecting PDL\n");
- minst->desired_implementation = pl_select_implementation(pjli, minst, s);
- if (minst->curr_implementation != minst->desired_implementation) {
- code = pl_remove_device(minst->curr_implementation);
- if (code >= 0)
- code = pl_set_device(minst->desired_implementation, minst->device);
- if (code < 0) {
- minst->curr_implementation = minst->desired_implementation;
- return gs_error_Fatal;
+ /* The only time the current implementation won't be PJL,
+ * is if someone has preselected a particular language
+ * before calling this function. */
+ if (minst->curr_implementation == pjli) {
+ /* Autodetect the language based on the content. */
+ desired_implementation = pl_select_implementation(pjli, minst, s);
+
+ /* Possibly this never happens? But attempt to cope anyway. */
+ if (desired_implementation == NULL)
+ goto flush_to_end_of_job;
+ if (gs_debug_c('I') || gs_debug_c(':'))
+ dmlprintf1(mem, "PDL detected as %s\n",
+ pl_characteristics(desired_implementation)->language);
+
+ /* If the language implementation needs changing, change it. */
+ if (desired_implementation != pjli) {
+ code = pl_dnit_job(pjli);
+ minst->curr_implementation = NULL;
+ if (code >= 0)
+ code = pl_init_job(desired_implementation, minst->device);
+ if (code < 0)
+ goto error_fatal;
+ minst->curr_implementation = desired_implementation;
}
}
- minst->curr_implementation = minst->desired_implementation;
-
- /* Don't reset PJL if there is PJL state from the command line arguments. */
- if (minst->curr_implementation == pjli) {
- if (minst->pjl_from_args == false) {
- if (pl_init_job(pjli) < 0)
- return gs_error_Fatal;
- } else
- minst->pjl_from_args = false;
- } else {
- if (pl_init_job(minst->curr_implementation) < 0)
- return gs_error_Fatal;
+ if (minst->curr_implementation != pjli) {
+ if_debug1m('I', mem, "initialised (%s)\n",
+ pl_characteristics(minst->curr_implementation)->language);
+ if (first_job &&
+ !is_stdin &&
+ minst->curr_implementation->proc_process_file) {
+ /* If we aren't being piped data, and this interpreter
+ * is capable of coping with running a file directly,
+ * let's do that. */
+ use_process_file = true;
+ break;
+ }
}
- if_debug1m('I', mem, "selected and initializing (%s)\n",
- pl_characteristics(minst->curr_implementation)->language);
+ first_job = false;
new_job = false;
- }
- if (minst->curr_implementation) {
- /* Special case when the job resides in a seekable file and
- the implementation has a function to process a file at a
- time. */
- if (minst->curr_implementation->proc_process_file
- && !is_stdin) {
- if_debug1m('I', mem, "processing job from file (%s)\n",
- filename);
-
- code = pl_process_file(minst->curr_implementation, (char *)filename);
- if (code < 0) {
- errprintf(mem, "Warning interpreter exited with error code %d\n",
- code);
- }
- if (pl_dnit_job(minst->curr_implementation) < 0)
- return gs_error_Fatal;
-
- break; /* break out of the loop to process the next file */
- }
+ if (pl_process_begin(minst->curr_implementation) < 0)
+ goto error_fatal;
+ }
- code = pl_process(minst->curr_implementation, &s->cursor.r);
- if_debug1m('I', mem, "processing (%s) job\n",
- pl_characteristics(minst->curr_implementation)->language);
- if (code == e_ExitLanguage) {
- if (pl_dnit_job(minst->curr_implementation) < 0)
- return gs_error_Fatal;
-
- new_job = true;
-
- if (minst->curr_implementation != pjli)
- if (pl_init_job(pjli) < 0)
- return gs_error_Fatal;
-
- } else if (code < 0) { /* error and not exit language */
- dmprintf1(mem,
- "Warning interpreter exited with error code %d\n",
- code);
- dmprintf(mem, "Flushing to end of job\n");
- /* flush eoj may require more data */
- while ((pl_flush_to_eoj(minst->curr_implementation, &s->cursor.r)) == 0) {
- int code2;
- if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s)) {
- if_debug0m('I', mem,
- "end of data found while flushing\n");
- break;
- }
- code2 = s_process_read_buf(s);
- if (code2 < 0)
- break;
+ if_debug2m('I', mem, "processing (%s) job from offset %ld\n",
+ pl_characteristics(minst->curr_implementation)->language,
+ sftell(s));
+ code = pl_process(minst->curr_implementation, &s->cursor.r);
+ if_debug2m('I', mem, "processed (%s) job to offset %ld\n",
+ pl_characteristics(minst->curr_implementation)->language,
+ sftell(s));
+ if (code == gs_error_NeedInput || code >= 0) {
+ continue;
+ }
+ if (code != e_ExitLanguage) {
+ /* error and not exit language */
+ dmprintf1(mem,
+ "Warning interpreter exited with error code %d\n",
+ code);
+flush_to_end_of_job:
+ dmprintf(mem, "Flushing to end of job\n");
+ /* flush eoj may require more data */
+ while ((pl_flush_to_eoj(minst->curr_implementation, &s->cursor.r)) == 0) {
+ int code2;
+ if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s)) {
+ if_debug0m('I', mem,
+ "end of data found while flushing\n");
+ break;
}
- pl_report_errors(minst->curr_implementation, code,
- sftell(s),
- minst->error_report > 0);
- if (pl_dnit_job(minst->curr_implementation) < 0)
- return gs_error_Fatal;
- if (pl_init_job(pjli) < 0)
- return gs_error_Fatal;
-
- code = 0;
- new_job = true;
+ code2 = s_process_read_buf(s);
+ if (code2 < 0)
+ break;
}
+ pl_report_errors(minst->curr_implementation, code,
+ sftell(s),
+ minst->error_report > 0);
}
+
+ if (pl_process_end(minst->curr_implementation) < 0)
+ goto error_fatal;
+ new_job = true;
+ /* Always revert to PJL after each job. We avoid reinitialising PJL
+ * if we are already in PJL to avoid clearing the state. */
+ if (revert_to_pjli(minst))
+ goto error_fatal_reverted;
}
sfclose(s);
+ s = NULL;
+ if (use_process_file)
+ {
+ if_debug1m('I', mem, "processing job from file (%s)\n",
+ filename);
+
+ code = pl_process_file(minst->curr_implementation, (char *)filename);
+ if (code == gs_error_InterpreterExit)
+ code = 0;
+ if (code < 0) {
+ errprintf(mem, "Warning interpreter exited with error code %d\n",
+ code);
+ }
+ }
+ if (revert_to_pjli(minst) < 0)
+ goto error_fatal_reverted;
return 0;
+
+error_fatal:
+ revert_to_pjli(minst);
+error_fatal_reverted:
+ sfclose(s);
+ return gs_error_Fatal;
+}
+
+void
+pl_main_set_arg_decode(pl_main_instance_t *minst,
+ pl_main_get_codepoint_t *get_codepoint)
+{
+ if (minst == NULL)
+ return;
+
+ minst->get_codepoint = get_codepoint;
+}
+
+int
+pl_main_run_file(pl_main_instance_t *minst, const char *file_name)
+{
+ char *d, *temp;
+ const char *c = file_name;
+ char dummy[6];
+ int rune, code, len;
+
+ if (minst == NULL)
+ return 0;
+
+ /* Convert the file_name to utf8 */
+ if (minst->get_codepoint) {
+ len = 1;
+ while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
+ len += codepoint_to_utf8(dummy, rune);
+ temp = (char *)gs_alloc_bytes_immovable(minst->memory, len, "gsapi_run_file");
+ if (temp == NULL)
+ return gs_error_VMerror;
+ c = file_name;
+ d = temp;
+ while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
+ d += codepoint_to_utf8(d, rune);
+ *d = 0;
+ }
+ else {
+ temp = (char *)file_name;
+ }
+ code = pl_main_run_file_utf8(minst, temp);
+ if (temp != file_name)
+ gs_free_object(minst->memory, temp, "gsapi_run_file");
+ return code;
}
int
@@ -412,6 +522,15 @@ pl_main_delete_instance(pl_main_instance_t *minst)
if (minst == NULL)
return 0;
+ /* close and deallocate the device */
+ if (minst->device) {
+ gs_closedevice(minst->device);
+ gs_unregister_root(minst->device->memory, minst->device_root,
+ "pl_main_languages_delete_instance");
+ minst->device_root = NULL;
+ gx_device_retain(minst->device, false);
+ minst->device = NULL;
+ }
mem = minst->memory;
impl = minst->implementations;
if (impl != NULL) {
@@ -427,14 +546,6 @@ pl_main_delete_instance(pl_main_instance_t *minst)
gs_free_object(mem, impl, "pl_main_languages_delete_instance()");
}
- /* close and deallocate the device */
- if (minst->device) {
- gs_closedevice(minst->device);
- gs_unregister_root(minst->device->memory, &device_root,
- "pl_main_languages_delete_instance");
- gx_device_retain(minst->device, false);
- minst->device = NULL;
- }
gs_iodev_finit(mem);
gs_lib_finit(0, 0, mem);
@@ -452,16 +563,17 @@ pl_main_delete_instance(pl_main_instance_t *minst)
int
pl_to_exit(gs_memory_t *mem)
{
+ int ret = 0;
pl_main_instance_t *minst = mem->gs_lib_ctx->top_of_system;
/* Deselect last-selected device */
if (minst->curr_implementation
- && pl_remove_device(minst->curr_implementation) < 0) {
- return -1;
+ && pl_dnit_job(minst->curr_implementation) < 0) {
+ ret = -1;
}
gs_c_param_list_release(&minst->params);
arg_finit(&minst->args);
- return 0;
+ return ret;
}
static int /* 0 ok, else -1 error */
@@ -486,7 +598,7 @@ pl_main_languages_init(gs_memory_t * mem, /* deallocator for devices */
goto pmui_err;
minst->implementations = impls;
- minst->curr_implementation = minst->desired_implementation = NULL;
+ minst->curr_implementation = NULL;
memset(impls, 0, sz);
/* Create & init PDL all instances. Could do this lazily to save memory, */
@@ -555,7 +667,7 @@ pl_main_alloc_instance(gs_memory_t * mem)
memset(minst, 0, sizeof(*minst));
- minst->memory = mem;
+ minst->memory = minst->device_memory = mem;
minst->pjl_from_args = false;
minst->error_report = -1;
@@ -587,12 +699,14 @@ pl_main_alloc_instance(gs_memory_t * mem)
/* Create a default device if not already defined. */
static int
-pl_top_create_device(pl_main_instance_t * pti, int index, bool is_default)
+pl_top_create_device(pl_main_instance_t * pti, int index)
{
int code = 0;
- if (!is_default || !pti->device) {
+ if (!pti->device) {
const gx_device *dev;
+ pl_interp_implementation_t **impl;
+ gs_memory_t *mem = pti->device_memory;
/* We assume that nobody else changes pti->device,
and this function is called from this module only.
Due to that device_root is always consistent with pti->device,
@@ -609,7 +723,20 @@ pl_top_create_device(pl_main_instance_t * pti, int index, bool is_default)
gs_lib_device_list((const gx_device * const **)&list, NULL);
dev = list[index];
}
- code = gs_copydevice(&pti->device, dev, pti->memory);
+ for (impl = pti->implementations; *impl != 0; ++impl) {
+ mem = pl_get_device_memory(*impl);
+ if (mem)
+ break;
+ }
+ if (mem)
+ pti->device_memory = mem;
+#ifdef DEBUG
+ for (; *impl != 0; ++impl) {
+ mem = pl_get_device_memory(*impl);
+ assert(mem == NULL || mem == pti->device_memory);
+ }
+#endif
+ code = gs_copydevice(&pti->device, dev, pti->device_memory);
if (code < 0)
return code;
@@ -617,7 +744,8 @@ pl_top_create_device(pl_main_instance_t * pti, int index, bool is_default)
if (pti->device == NULL)
return gs_error_VMerror;
- gs_register_struct_root(pti->memory, &device_root,
+ pti->device_root = NULL;
+ gs_register_struct_root(pti->device_memory, &pti->device_root,
(void **)&pti->device,
"pl_top_create_device");
@@ -696,23 +824,26 @@ parse_floats(gs_memory_t * mem, uint arg_count, char *arg, float *f)
return float_index;
}
+#define argcmp(A, S, L) \
+ (!strncmp(A, S, L) && (A[L] == 0 || A[L] == '='))
+
static int check_for_special_int(pl_main_instance_t * pmi, const char *arg, int b)
{
- if (!strncmp(arg, "BATCH", 5))
- return (b == 0) ? 0 : gs_note_error(gs_error_rangecheck);
- if (!strncmp(arg, "NOPAUSE", 6)) {
+ if (argcmp(arg, "BATCH", 5))
+ return (b == 1) ? 0 : gs_note_error(gs_error_rangecheck);
+ if (argcmp(arg, "NOPAUSE", 7)) {
pmi->pause = !b;
return 0;
}
- if (!strncmp(arg, "DOINTERPOLATE", 13)) {
+ if (argcmp(arg, "DOINTERPOLATE", 13)) {
pmi->interpolate = !!b;
return 0;
}
- if (!strncmp(arg, "NOCACHE", 7)) {
+ if (argcmp(arg, "NOCACHE", 7)) {
pmi->nocache = !!b;
return 0;
}
- if (!strncmp(arg, "SCANCONVERTERTYPE", 17)) {
+ if (argcmp(arg, "SCANCONVERTERTYPE", 17)) {
pmi->scanconverter = b;
return 0;
}
@@ -721,11 +852,11 @@ static int check_for_special_int(pl_main_instance_t * pmi, const char *arg, int
static int check_for_special_float(pl_main_instance_t * pmi, const char *arg, float f)
{
- if (!strncmp(arg, "BATCH", 5) ||
- !strncmp(arg, "NOPAUSE", 6) ||
- !strncmp(arg, "DOINTERPOLATE", 13) ||
- !strncmp(arg, "NOCACHE", 7) ||
- !strncmp(arg, "SCANCONVERTERTYPE", 17)) {
+ if (argcmp(arg, "BATCH", 5) ||
+ argcmp(arg, "NOPAUSE", 7) ||
+ argcmp(arg, "DOINTERPOLATE", 13) ||
+ argcmp(arg, "NOCACHE", 7) ||
+ argcmp(arg, "SCANCONVERTERTYPE", 17)) {
return gs_note_error(gs_error_rangecheck);
}
return 1;
@@ -733,17 +864,50 @@ static int check_for_special_float(pl_main_instance_t * pmi, const char *arg, fl
static int check_for_special_str(pl_main_instance_t * pmi, const char *arg, gs_param_string *f)
{
- if (!strncmp(arg, "BATCH", 5) ||
- !strncmp(arg, "NOPAUSE", 6) ||
- !strncmp(arg, "DOINTERPOLATE", 13) ||
- !strncmp(arg, "NOCACHE", 7) ||
- !strncmp(arg, "SCANCONVERTERTYPE", 17)) {
+ if (argcmp(arg, "BATCH", 5) ||
+ argcmp(arg, "NOPAUSE", 7) ||
+ argcmp(arg, "DOINTERPOLATE", 13) ||
+ argcmp(arg, "NOCACHE", 7) ||
+ argcmp(arg, "SCANCONVERTERTYPE", 17)) {
return gs_note_error(gs_error_rangecheck);
}
return 1;
}
static int
+pass_param_to_languages(pl_main_instance_t *pmi,
+ pl_set_param_type type,
+ const char *param,
+ const void *value)
+{
+ pl_interp_implementation_t **imp;
+ int code = 0;
+
+ for (imp = pmi->implementations; *imp != NULL; imp++) {
+ code = pl_set_param(*imp, type, param, value);
+ if (code != 0)
+ break;
+ }
+
+ return code;
+}
+
+static int
+pl_main_post_args_init(pl_main_instance_t * pmi)
+{
+ pl_interp_implementation_t **imp;
+ int code = 0;
+
+ for (imp = pmi->implementations; *imp != NULL; imp++) {
+ code = pl_post_args_init(*imp);
+ if (code != 0)
+ break;
+ }
+
+ return code;
+}
+
+static int
pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
pl_interp_implementation_t * pjli)
{
@@ -751,6 +915,7 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
bool help = false;
char *arg;
gs_c_param_list *params = &pmi->params;
+ int device_index = -1;
gs_c_param_list_write_more(params);
while ((code = arg_next(pal, (const char **)&arg, pmi->memory)) > 0 && *arg == '-') {
@@ -843,73 +1008,86 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
float vf;
bool bval = true;
char buffer[128];
+ pl_set_param_type spt_type = pl_spt_invalid;
+ const void *spt_val = NULL;
+ static const char const_true_string[] = "true";
if (eqp || (eqp = strchr(arg, '#')))
value = eqp + 1;
else {
/* -dDefaultBooleanIs_TRUE */
- code = check_for_special_int(pmi, arg, (int)bval);
- if (code < 0) code = 0;
- if (code == 1)
- code =
- param_write_bool((gs_param_list *) params,
- arg, &bval);
- break;
+ value = const_true_string;
+ eqp = arg + strlen(arg);
}
+ /* Arrange for a null terminated copy of the key name in buffer. */
+ if (eqp-arg >= sizeof(buffer)-1) {
+ dmprintf1(pmi->memory, "Command line key is too long: %s\n", arg);
+ return -1;
+ }
+ strncpy(buffer, arg, eqp - arg);
+ buffer[eqp - arg] = '\0';
+ code = 0;
if (value && value[0] == '/') {
+ /* We have a name! */
gs_param_string str;
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
- param_string_from_transient_string(str, value + 1);
code = check_for_special_str(pmi, arg, &str);
- if (code == 1)
- code = param_write_name((gs_param_list *) params,
- buffer, &str);
- break;
- }
- /* Search for a non-decimal 'radix' number */
- else if (strchr(value, '#')) {
- int base, number = 0;
- char *val = strchr(value, '#');
+ if (code <= 0)
+ break;
+
+ param_string_from_transient_string(str, value + 1);
+ code = param_write_name((gs_param_list *) params,
+ buffer, &str);
+ spt_type = pl_spt_name;
+ spt_val = value+1;
+ } else if (strchr(value, '#')) {
+ /* We have a non-decimal 'radix' number */
+ int base = 0;
+ const char *val = strchr(value, '#');
+ const char *v = value;
+ char c;
+
+ while ((c = *v++) >= '0' && c <= '9')
+ base = base*10 + (c - '0');
+ if (*v != '#') {
+ dmprintf1(pmi->memory, "Malformed base value for radix. %s",
+ value);
+ return -1;
+ }
- *val++ = 0x00;
- sscanf(value, "%d", &base);
if (base < 2 || base > 36) {
- dmprintf1(pmi->memory, "Value out of range %s",
+ dmprintf1(pmi->memory, "Base out of range %s",
value);
return -1;
}
+ vi = 0;
while (*val) {
- if (*val >= '0' && *val <= '9') {
- number = number * base + (*val - '0');
- } else {
- if (*val >= 'A' && *val <= 'Z') {
- number = number * base + (*val - 'A');
+ if (*val >= '0' && *val < ('0'+(base<=10?base:10))) {
+ vi = vi * base + (*val - '0');
+ } else if (base > 10) {
+ if (*val >= 'A' && *val < 'A'+base-10) {
+ vi = vi * base + (*val - 'A' + 10);
+ } else if (*val >= 'a' && *val < 'a'+base-10) {
+ vi = vi * base + (*val - 'a' + 10);
} else {
- if (*val >= 'a' && *val <= 'z') {
- number = number * base + (*val - 'a');
- } else {
- dmprintf1(pmi->memory,
- "Value out of range %s",
- val);
- return -1;
- }
+ dmprintf1(pmi->memory,
+ "Value out of range %s\n",
+ val);
+ return -1;
}
}
val++;
}
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
- code = check_for_special_int(pmi, arg, number);
+ code = check_for_special_int(pmi, arg, vi);
if (code < 0) code = 0;
- if (code == 1)
- code =
- param_write_int((gs_param_list *) params,
- buffer, &number);
+ if (code <= 0)
+ break;
+ code = param_write_int((gs_param_list *) params,
+ buffer, &vi);
+ spt_type = pl_spt_int;
+ spt_val = &vi;
} else if ((!strchr(value, '.')) &&
- /* search for an int (no decimal), if fail try a float */
(sscanf(value, "%d", &vi) == 1)) {
/* Here we have an int -- check for a scaling suffix */
char suffix = eqp[strlen(eqp) - 1];
@@ -932,51 +1110,63 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
default:
break; /* not a valid suffix or last char was digit */
}
- /* create a null terminated string for the key */
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
code = check_for_special_int(pmi, arg, vi);
if (code < 0) code = 0;
- if (code == 1)
- code =
- param_write_int((gs_param_list *) params,
- buffer, &vi);
+ if (code <= 0)
+ break;
+ code = param_write_int((gs_param_list *) params,
+ buffer, &vi);
+ spt_type = pl_spt_int;
+ spt_val = &vi;
} else if (sscanf(value, "%f", &vf) == 1) {
- /* create a null terminated string. NB duplicated code. */
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
+ /* We have a float */
code = check_for_special_float(pmi, arg, vf);
- if (code == 1)
- code =
- param_write_float((gs_param_list *) params,
+ if (code <= 0)
+ break;
+ code = param_write_float((gs_param_list *) params,
buffer, &vf);
+ spt_type = pl_spt_float;
+ spt_val = &vf;
+ } else if (!strcmp(value, "null")) {
+ code = check_for_special_int(pmi, arg, (int)bval);
+ if (code < 0) code = 0;
+ if (code <= 0)
+ break;
+ code = param_write_null((gs_param_list *) params,
+ buffer);
+ spt_type = pl_spt_null;
+ spt_val = NULL;
} else if (!strcmp(value, "true")) {
/* bval = true; */
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
code = check_for_special_int(pmi, arg, (int)bval);
if (code < 0) code = 0;
- if (code == 1)
- code =
- param_write_bool((gs_param_list *) params,
- buffer, &bval);
+ if (code <= 0)
+ break;
+ code = param_write_bool((gs_param_list *) params,
+ buffer, &bval);
+ spt_type = pl_spt_bool;
+ spt_val = (void*)1;
} else if (!strcmp(value, "false")) {
bval = false;
- strncpy(buffer, arg, eqp - arg);
- buffer[eqp - arg] = '\0';
code = check_for_special_int(pmi, arg, (int)bval);
if (code < 0) code = 0;
- if (code == 1)
- code =
- param_write_bool((gs_param_list *) params,
- buffer, &bval);
+ if (code <= 0)
+ break;
+ code = param_write_bool((gs_param_list *) params,
+ buffer, &bval);
+ spt_type = pl_spt_bool;
+ spt_val = NULL;
} else {
dmprintf(pmi->memory,
- "Usage for -d is -d<option>=[<integer>|<float>|true|false]\n");
+ "Usage for -d is -d<option>=[<integer>|<float>|null|true|false|name]\n");
continue;
}
+ if (code < 0)
+ return code;
+ code = pass_param_to_languages(pmi, spt_type, buffer, spt_val);
+ if (code < 0)
+ return code;
}
- break;
case 'E':
if (*arg == 0)
gs_debug['#'] = 1;
@@ -999,8 +1189,11 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
code =
param_write_int_array((gs_param_list *) params,
"HWSize", &ia);
- if (code >= 0)
+ if (code >= 0) {
pmi->page_set_on_command_line = true;
+ pmi->page_size[0] = geom[0];
+ pmi->page_size[1] = geom[1];
+ }
}
break;
case 'H':
@@ -1190,8 +1383,11 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
code =
param_write_float_array((gs_param_list *) params,
"HWResolution", &fa);
- if (code == 0)
+ if (code == 0) {
pmi->res_set_on_command_line = true;
+ pmi->res[0] = res[0];
+ pmi->res[1] = res[1];
+ }
}
break;
case 's':
@@ -1209,12 +1405,13 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
}
value = eqp + 1;
if (!strncmp(arg, "DEVICE", 6)) {
- code = pl_top_create_device(pmi,
- get_device_index(pmi->
- memory,
- value),
- false);
-
+ if (device_index != -1) {
+ dmprintf(pmi->memory, "DEVICE can only be set once!\n");
+ return -1;
+ }
+ device_index = get_device_index(pmi->memory, value);
+ if (device_index == -1)
+ return -1;
/* check for icc settings */
} else
if (!strncmp
@@ -1238,12 +1435,22 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
} else {
char buffer[128];
+ if (eqp-arg >= sizeof(buffer)-1) {
+ dmprintf1(pmi->memory, "Command line key is too long: %s\n", arg);
+ return -1;
+ }
strncpy(buffer, arg, eqp - arg);
buffer[eqp - arg] = '\0';
+
param_string_from_transient_string(str, value);
code =
param_write_string((gs_param_list *) params,
buffer, &str);
+ if (code < 0)
+ return code;
+ code = pass_param_to_languages(pmi, pl_spt_string, buffer, value);
+ if (code < 0)
+ return code;
}
}
break;
@@ -1271,8 +1478,14 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
return code;
}
+ /* Do any last minute language specific device initialisation
+ * (i.e. let gs_init.ps do its worst). */
+ code = pl_main_post_args_init(pmi);
+ if (code < 0)
+ return code;
+
gs_c_param_list_read(params);
- code = pl_top_create_device(pmi, -1, true); /* create default device if needed */
+ code = pl_top_create_device(pmi, device_index); /* create default device if needed */
if (code < 0)
return code;
@@ -1285,7 +1498,9 @@ pl_main_process_options(pl_main_instance_t * pmi, arg_list * pal,
return 0;
do {
- code = pl_main_run_file(pmi, arg);
+ code = pl_main_run_file_utf8(pmi, arg);
+ if (code == gs_error_undefinedfilename)
+ errprintf(pmi->memory, "Failed to open file '%s'\n", arg);
if (code < 0)
return code;
} while ((code = arg_next(pal, (const char **)&arg, pmi->memory)) > 0);
@@ -1303,6 +1518,8 @@ pl_auto_sense(pl_main_instance_t *minst, const char *name, int buffer_length)
pl_interp_implementation_t **impls = minst->implementations;
pl_interp_implementation_t **impl;
size_t uel_len = strlen(PJL_UEL);
+ pl_interp_implementation_t *best = NULL;
+ int max_score = 0;
/* first check for a UEL */
if (buffer_length >= uel_len) {
@@ -1310,12 +1527,16 @@ pl_auto_sense(pl_main_instance_t *minst, const char *name, int buffer_length)
return impls[0];
}
+ /* Defaults to language 1 (if there is one): PJL is language 0, PCL is language 1. */
+ best = impls[1] ? impls[1] : impls[0];
for (impl = impls; *impl != NULL; ++impl) {
- if (pl_characteristics(*impl)->auto_sense(name, buffer_length) == 0)
- return *impl;
+ int score = pl_characteristics(*impl)->auto_sense(name, buffer_length);
+ if (score > max_score) {
+ best = *impl;
+ max_score = score;
+ }
}
- /* Defaults to language 1 (if there is one): PJL is language 0, PCL is language 1. */
- return impls[1] ? impls[1] : impls[0];
+ return best;
}
/* either the (1) implementation has been selected on the command line or
@@ -1374,7 +1595,7 @@ pl_log_string(const gs_memory_t * mem, const char *str, int wait_for_key)
{
errwrite(mem, str, strlen(str));
if (wait_for_key)
- (void)fgetc(mem->gs_lib_ctx->fstdin);
+ (void)fgetc(mem->gs_lib_ctx->core->fstdin);
}
pl_interp_implementation_t *
@@ -1409,6 +1630,24 @@ bool pl_main_get_res_set_on_command_line(const gs_memory_t *mem)
return pl_main_get_instance(mem)->res_set_on_command_line;
}
+void pl_main_get_forced_geometry(const gs_memory_t *mem, const float **resolutions, const long **dimensions)
+{
+ pl_main_instance_t *minst = pl_main_get_instance(mem);
+
+ if (resolutions) {
+ if (minst->res_set_on_command_line)
+ *resolutions = minst->res;
+ else
+ *resolutions = NULL;
+ }
+ if (dimensions) {
+ if (minst->page_set_on_command_line)
+ *dimensions = minst->page_size;
+ else
+ *dimensions = NULL;
+ }
+}
+
bool pl_main_get_high_level_device(const gs_memory_t *mem)
{
return pl_main_get_instance(mem)->high_level_device;
diff --git a/pcl/pl/plmain.h b/pcl/pl/plmain.h
index 61b871fed..ad29edd68 100644
--- a/pcl/pl/plmain.h
+++ b/pcl/pl/plmain.h
@@ -55,9 +55,9 @@ int pl_main_set_display_callback(pl_main_instance_t *inst, void *callback);
int pl_main_run_file(pl_main_instance_t *minst, const char *filename);
int pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[]);
int pl_main_delete_instance(pl_main_instance_t *minst);
-int pl_main_run_string_begin(void *instance);
-int pl_main_run_string_continue(void *instance, const char *str, unsigned int length);
-int pl_main_run_string_end(void *instance);
+int pl_main_run_string_begin(pl_main_instance_t *minst);
+int pl_main_run_string_continue(pl_main_instance_t *minst, const char *str, unsigned int length);
+int pl_main_run_string_end(pl_main_instance_t *minst);
int pl_to_exit(gs_memory_t *mem);
/* instance accessors */
@@ -66,9 +66,14 @@ bool pl_main_get_nocache(const gs_memory_t *mem);
bool pl_main_get_page_set_on_command_line(const gs_memory_t *mem);
bool pl_main_get_res_set_on_command_line(const gs_memory_t *mem);
bool pl_main_get_high_level_device(const gs_memory_t *mem);
+void pl_main_get_forced_geometry(const gs_memory_t *mem, const float **resolutions, const long **dimensions);
int pl_main_get_scanconverter(const gs_memory_t *mem);
pl_main_instance_t *pl_main_get_instance(const gs_memory_t *mem);
+typedef int pl_main_get_codepoint_t(FILE *, const char **);
+void pl_main_set_arg_decode(pl_main_instance_t *minst,
+ pl_main_get_codepoint_t *get_codepoint);
+
/* retrieve the PJL instance so languages can query PJL. */
bool pl_main_get_pjl_from_args(const gs_memory_t *mem); /* pjl was passed on the command line */
diff --git a/pcl/pl/pltop.c b/pcl/pl/pltop.c
index a27d70821..5b8669416 100644
--- a/pcl/pl/pltop.c
+++ b/pcl/pl/pltop.c
@@ -24,6 +24,9 @@
#include "gsstruct.h"
#include "gsdevice.h"
#include "pltop.h"
+#include "gserrors.h"
+#include "stream.h"
+#include "strmio.h"
/* Get implementation's characteristics */
const pl_interp_characteristics_t * /* always returns a descriptor */
@@ -35,27 +38,48 @@ pl_characteristics(const pl_interp_implementation_t * impl) /* implementati
/* Do instance interpreter allocation/init. No device is set yet */
int /* ret 0 ok, else -ve error code */
pl_allocate_interp_instance(pl_interp_implementation_t * impl,
- gs_memory_t * mem /* allocator to allocate instance from */
- )
+ gs_memory_t * mem) /* allocator to allocate instance from */
{
return impl->proc_allocate_interp_instance(impl, mem);
}
-/* Get and interpreter prefered device memory allocator if any */
-int /* ret 0 ok, else -ve error code */
-pl_set_device(pl_interp_implementation_t * impl, /* interp instance to use */
- gx_device * device /* device to set (open or closed) */
- )
+/*
+ * Get the allocator with which to allocate a device
+ */
+gs_memory_t *
+pl_get_device_memory(pl_interp_implementation_t *impl)
{
- return impl->proc_set_device(impl, device);
+ if (impl->proc_get_device_memory == NULL)
+ return NULL;
+ return impl->proc_get_device_memory(impl);
+}
+
+int
+pl_set_param(pl_interp_implementation_t *impl,
+ pl_set_param_type type,
+ const char *param,
+ const void *value)
+{
+ if (impl->proc_set_param == NULL)
+ return 0;
+
+ return impl->proc_set_param(impl, type, param, value);
+}
+
+int pl_post_args_init(pl_interp_implementation_t *impl)
+{
+ if (impl->proc_post_args_init == NULL)
+ return 0;
+
+ return impl->proc_post_args_init(impl);
}
/* Prepare interp instance for the next "job" */
int /* ret 0 ok, else -ve error code */
-pl_init_job(pl_interp_implementation_t * impl /* interp instance to start job in */
- )
+pl_init_job(pl_interp_implementation_t * impl, /* interp instance to start job in */
+ gx_device * device) /* device to set (open or closed) */
{
- return impl->proc_init_job(impl);
+ return impl->proc_init_job(impl, device);
}
/* Parse a random access seekable file.
@@ -66,7 +90,50 @@ pl_init_job(pl_interp_implementation_t * impl /* interp instance to start jo
int
pl_process_file(pl_interp_implementation_t * impl, char *filename)
{
- return impl->proc_process_file(impl, filename);
+ gs_memory_t *mem;
+ int code, code1;
+ stream *s;
+
+ if (impl->proc_process_file != NULL)
+ return impl->proc_process_file(impl, filename);
+
+ /* We have to process the file in chunks. */
+ mem = pl_get_device_memory(impl);
+ code = 0;
+
+ s = sfopen(filename, "r", mem);
+ if (s == NULL)
+ return gs_error_undefinedfilename;
+
+ code = pl_process_begin(impl);
+
+ while (code == gs_error_NeedInput || code >= 0) {
+ if (s->cursor.r.ptr == s->cursor.r.limit && sfeof(s))
+ break;
+ code = s_process_read_buf(s);
+ if (code < 0)
+ break;
+
+ code = pl_process(impl, &s->cursor.r);
+ if_debug2m('I', mem, "processed (%s) job to offset %ld\n",
+ pl_characteristics(impl)->language,
+ sftell(s));
+ }
+
+ code1 = pl_process_end(impl);
+ if (code >= 0 && code1 < 0)
+ code = code1;
+
+ sfclose(s);
+
+ return code;
+}
+
+/* Do setup to for parsing cursor-fulls of data */
+int
+pl_process_begin(pl_interp_implementation_t * impl) /* interp instance to process data job in */
+{
+ return impl->proc_process_begin(impl);
}
/* Parse a cursor-full of data */
@@ -78,37 +145,39 @@ pl_process_file(pl_interp_implementation_t * impl, char *filename)
* other <0 value - an error was detected.
*/
int
-pl_process(pl_interp_implementation_t * impl, /* interp instance to process data job in */
- stream_cursor_read * cursor /* data to process */
- )
+pl_process(pl_interp_implementation_t * impl, /* interp instance to process data job in */
+ stream_cursor_read * cursor) /* data to process */
{
return impl->proc_process(impl, cursor);
}
+int
+pl_process_end(pl_interp_implementation_t * impl) /* interp instance to process data job in */
+{
+ return impl->proc_process_end(impl);
+}
+
/* Skip to end of job ret 1 if done, 0 ok but EOJ not found, else -ve error code */
int
-pl_flush_to_eoj(pl_interp_implementation_t * impl, /* interp instance to flush for */
- stream_cursor_read * cursor /* data to process */
- )
+pl_flush_to_eoj(pl_interp_implementation_t * impl, /* interp instance to flush for */
+ stream_cursor_read * cursor)/* data to process */
{
return impl->proc_flush_to_eoj(impl, cursor);
}
/* Parser action for end-of-file (also resets after unexpected EOF) */
int /* ret 0 or +ve if ok, else -ve error code */
-pl_process_eof(pl_interp_implementation_t * impl /* interp instance to process data job in */
- )
+pl_process_eof(pl_interp_implementation_t * impl) /* interp instance to process data job in */
{
return impl->proc_process_eof(impl);
}
/* Report any errors after running a job */
int /* ret 0 ok, else -ve error code */
-pl_report_errors(pl_interp_implementation_t * impl, /* interp instance to wrap up job in */
- int code, /* prev termination status */
- long file_position, /* file position of error, -1 if unknown */
- bool force_to_cout /* force errors to cout */
- )
+pl_report_errors(pl_interp_implementation_t * impl, /* interp instance to wrap up job in */
+ int code, /* prev termination status */
+ long file_position, /* file position of error, -1 if unknown */
+ bool force_to_cout) /* force errors to cout */
{
return impl->proc_report_errors
(impl, code, file_position, force_to_cout);
@@ -116,24 +185,14 @@ pl_report_errors(pl_interp_implementation_t * impl, /* interp instance to
/* Wrap up interp instance after a "job" */
int /* ret 0 ok, else -ve error code */
-pl_dnit_job(pl_interp_implementation_t * impl /* interp instance to wrap up job in */
- )
+pl_dnit_job(pl_interp_implementation_t * impl) /* interp instance to wrap up job in */
{
return impl->proc_dnit_job(impl);
}
-/* Remove a device from an interperter instance */
-int /* ret 0 ok, else -ve error code */
-pl_remove_device(pl_interp_implementation_t * impl /* interp instance to use */
- )
-{
- return impl->proc_remove_device(impl);
-}
-
/* Deallocate a interpreter instance */
int /* ret 0 ok, else -ve error code */
-pl_deallocate_interp_instance(pl_interp_implementation_t * impl /* instance to dealloc */
- )
+pl_deallocate_interp_instance(pl_interp_implementation_t * impl) /* instance to dealloc */
{
if (impl->interp_client_data == NULL)
return 0;
diff --git a/pcl/pl/pltop.h b/pcl/pl/pltop.h
index e2ae33171..a109cd717 100644
--- a/pcl/pl/pltop.h
+++ b/pcl/pl/pltop.h
@@ -41,7 +41,7 @@ typedef struct pl_interp_characteristics_s
{
const char *language; /* generic language should correspond with
HP documented PJL name */
- int (*auto_sense)(const char *string, int length); /* routine used to detect language - 0 is detected, non-zero not detected */
+ int (*auto_sense)(const char *string, int length); /* routine used to detect language - returns a score: 0 is definitely not, 100 is definitely yes. */
const char *manufacturer; /* manuf str */
const char *version; /* version str */
const char *build_date; /* build date str */
@@ -63,27 +63,59 @@ int pl_allocate_interp_instance(pl_interp_implementation_t *, gs_memory_t *);
typedef int (*pl_interp_proc_allocate_interp_instance_t) (pl_interp_implementation_t *,
gs_memory_t *);
+
+/*
+ * Get the allocator with which to allocate a device
+ * NOTE: only one interpreter is permitted to return a
+ * allocator.
+ */
+gs_memory_t *
+pl_get_device_memory(pl_interp_implementation_t *);
+typedef gs_memory_t * (*pl_interp_proc_get_device_memory_t) (pl_interp_implementation_t *);
+
/*
- * Set a device, possibly shared, into the graphics state of the language.
+ * Pass a parameter/value to a language.
*/
+typedef enum {
+ pl_spt_invalid = -1,
+ pl_spt_null = 0, /* void * is NULL */
+ pl_spt_bool = 1, /* void * is NULL (false) or non-NULL (true) */
+ pl_spt_int = 2, /* void * is a pointer to an int */
+ pl_spt_float = 3, /* void * is a float * */
+ pl_spt_name = 4, /* void * is a char * */
+ pl_spt_string = 5 /* void * is a char * */
+} pl_set_param_type;
+int pl_set_param(pl_interp_implementation_t *, pl_set_param_type type, const char *param, const void *value);
+typedef int (*pl_interp_proc_set_param_t) (pl_interp_implementation_t *,
+ pl_set_param_type,
+ const char *,
+ const void *);
-int pl_set_device(pl_interp_implementation_t *, gx_device *);
-typedef int (*pl_interp_proc_set_device_t) (pl_interp_implementation_t *,
- gx_device *);
+/*
+ * Do any language specific init required after the args have been sent.
+ */
+int pl_post_args_init(pl_interp_implementation_t *);
+typedef int (*pl_interp_proc_post_args_init_t) (pl_interp_implementation_t *);
/*
* Work to be done when a job begins.
*/
-int pl_init_job(pl_interp_implementation_t *);
-typedef int (*pl_interp_proc_init_job_t) (pl_interp_implementation_t *);
+int pl_init_job(pl_interp_implementation_t *, gx_device *);
+typedef int (*pl_interp_proc_init_job_t) (pl_interp_implementation_t *, gx_device *);
/*
* Process a stream of PDL data.
*/
+int pl_process_begin(pl_interp_implementation_t *);
+typedef int (*pl_interp_proc_process_begin_t) (pl_interp_implementation_t *);
+
int pl_process(pl_interp_implementation_t *, stream_cursor_read *);
typedef int (*pl_interp_proc_process_t) (pl_interp_implementation_t *,
stream_cursor_read *);
+int pl_process_end(pl_interp_implementation_t *);
+typedef int (*pl_interp_proc_process_end_t) (pl_interp_implementation_t *);
+
/*
* The process_file function is an optional optimized path for
* languages that want to use a random access file. If this function
@@ -121,12 +153,6 @@ int pl_dnit_job(pl_interp_implementation_t *);
typedef int (*pl_interp_proc_dnit_job_t) (pl_interp_implementation_t *);
/*
- * Remove the device from the graphics state and reset.
- */
-int pl_remove_device(pl_interp_implementation_t *);
-typedef int (*pl_interp_proc_remove_device_t) (pl_interp_implementation_t *);
-
-/*
* Free everything.
*/
int pl_deallocate_interp_instance(pl_interp_implementation_t *);
@@ -140,15 +166,18 @@ struct pl_interp_implementation_s
/* Procedure vector */
pl_interp_proc_characteristics_t proc_characteristics;
pl_interp_proc_allocate_interp_instance_t proc_allocate_interp_instance;
- pl_interp_proc_set_device_t proc_set_device;
+ pl_interp_proc_get_device_memory_t proc_get_device_memory;
+ pl_interp_proc_set_param_t proc_set_param;
+ pl_interp_proc_post_args_init_t proc_post_args_init;
pl_interp_proc_init_job_t proc_init_job;
pl_interp_proc_process_file_t proc_process_file;
+ pl_interp_proc_process_begin_t proc_process_begin;
pl_interp_proc_process_t proc_process;
+ pl_interp_proc_process_end_t proc_process_end;
pl_interp_proc_flush_to_eoj_t proc_flush_to_eoj;
pl_interp_proc_process_eof_t proc_process_eof;
pl_interp_proc_report_errors_t proc_report_errors;
pl_interp_proc_dnit_job_t proc_dnit_job;
- pl_interp_proc_remove_device_t proc_remove_device;
pl_interp_proc_deallocate_interp_instance_t
proc_deallocate_interp_instance;
void *interp_client_data;
diff --git a/pcl/pl/plwmainc.c b/pcl/pl/plwmainc.c
index 26d238be2..d6c6148c4 100644
--- a/pcl/pl/plwmainc.c
+++ b/pcl/pl/plwmainc.c
@@ -353,7 +353,7 @@ main_utf8(int argc, char *argv[])
hwndforeground = GetForegroundWindow(); /* assume this is ours */
#endif
- if (plapi_new_instance(&instance, NULL) < 0) {
+ if (gsapi_new_instance(&instance, NULL) < 0) {
fprintf(stderr, "Cannot create instance\n");
return 1;
}
@@ -384,7 +384,7 @@ main_utf8(int argc, char *argv[])
nargc = argc;
nargv = argv;
#else
- plapi_set_display_callback(instance, &display);
+ gsapi_set_display_callback(instance, &display);
{
int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
DISPLAY_DEPTH_1 | DISPLAY_BIGENDIAN | DISPLAY_BOTTOMFIRST;
@@ -420,11 +420,11 @@ main_utf8(int argc, char *argv[])
nargv[2] = ddpi;
memcpy(&nargv[3], &argv[1], argc * sizeof(char *));
#endif
- code = plapi_init_with_args(instance, nargc, nargv);
- code1 = plapi_exit(instance);
+ code = gsapi_init_with_args(instance, nargc, nargv);
+ code1 = gsapi_exit(instance);
if (code == 0 || (code == gs_error_Quit && code1 != 0))
code = code1;
- plapi_delete_instance(instance);
+ gsapi_delete_instance(instance);
#ifndef METRO
free(nargv);
diff --git a/pcl/pl/realmain.c b/pcl/pl/realmain.c
index 2f261f549..3fc48edc2 100644
--- a/pcl/pl/realmain.c
+++ b/pcl/pl/realmain.c
@@ -25,31 +25,31 @@ main(int argc, char *argv[])
{
int code, code1;
void *minst;
+ size_t uel_len = strlen(PJL_UEL);
- code = plapi_new_instance(&minst, (void *)0);
+ code = gsapi_new_instance(&minst, (void *)0);
if (code < 0)
- return EXIT_FAILURE;
-
- if (code == 0)
- code = plapi_init_with_args(minst, argc, argv);
-
- if (code == 0) {
- size_t uel_len = strlen(PJL_UEL);
- if (
- (code = plapi_run_string_begin(minst) < 0) ||
- (code = plapi_run_string_continue(minst, PJL_UEL, uel_len) < 0) ||
- (code = plapi_run_string_end(minst) < 0)
- )
- ; /* nothing */
- }
-
- code1 = plapi_exit(minst);
+ return EXIT_FAILURE;
+
+ if (code >= 0)
+ code = gsapi_init_with_args(minst, argc, argv);
+
+ if (code >= 0)
+ code = gsapi_run_string_begin(minst);
+ if (code >= 0)
+ code = gsapi_run_string_continue(minst, PJL_UEL, uel_len);
+ if (code >= 0)
+ code = gsapi_run_string_end(minst);
+ if (code == gs_error_InterpreterExit)
+ code = 0;
+
+ code1 = gsapi_exit(minst);
if ((code == 0) || (code == gs_error_Quit))
- code = code1;
+ code = code1;
- plapi_delete_instance(minst);
+ gsapi_delete_instance(minst);
if ((code == 0) || (code == gs_error_Quit))
- return EXIT_SUCCESS;
+ return EXIT_SUCCESS;
return EXIT_FAILURE;
}
diff --git a/pcl/pxl/pxtop.c b/pcl/pxl/pxtop.c
index 050d9fa64..944403fea 100644
--- a/pcl/pxl/pxtop.c
+++ b/pcl/pxl/pxtop.c
@@ -44,6 +44,7 @@
#include "pltop.h"
#include "plmain.h"
#include "gsicc_manage.h"
+#include "gxdevsop.h"
/* Imported operators */
px_operator_proc(pxEndPage);
@@ -141,8 +142,10 @@ static int
pxl_detect_language(const char *s, int len)
{
if (len < 11)
- return 1;
- return memcmp(s, ") HP-PCL XL", 11);
+ return 0;
+ if (memcmp(s, ") HP-PCL XL", 11) == 0)
+ return 100;
+ return 0;
}
/* Get implementation's characteristics */
@@ -221,19 +224,49 @@ pxl_set_icc_params(pl_interp_implementation_t * impl, gs_gstate * pgs)
return pl_set_icc_params(pxli->memory, pgs);
}
-/* Set a device into an interperter instance */
-/* ret 0 ok, else -ve error code */
-static int
-pxl_impl_set_device(pl_interp_implementation_t * impl,
- gx_device * device)
+/*
+ * Set a Boolean parameter.
+ */
+static int
+put_param_bool(pxl_interp_instance_t *pxli, gs_param_name pkey, bool value)
{
+ gs_c_param_list list;
int code;
+
+ gs_c_param_list_write(&list, pxli->memory);
+ code = param_write_bool((gs_param_list *) & list, pkey, &value);
+ if (code >= 0) {
+ gs_c_param_list_read(&list);
+
+ code = gs_gstate_putdeviceparams(pxli->pgs,
+ gs_currentdevice(pxli->pgs),
+ (gs_param_list *) &list);
+ }
+
+ gs_c_param_list_release(&list);
+ return code;
+}
+
+/* Prepare interp instance for the next "job" */
+/* ret 0 ok, else -ve error code */
+static int
+pxl_impl_init_job(pl_interp_implementation_t * impl,
+ gx_device * device)
+{
+ int code = 0;
pxl_interp_instance_t *pxli = impl->interp_client_data;
px_state_t *pxs = pxli->pxs;
gs_memory_t *mem = pxli->memory;
enum { Sbegin, Ssetdevice, Sinitg, Sgsave, Serase, Sdone } stage;
+ px_reset_errors(pxli->pxs);
+ px_process_init(pxli->st, true);
+
+ /* set input status to: expecting stream header */
+ px_stream_header_init(&pxli->headerState, pxli->st, pxli->pxs);
+ pxli->processState = PSHeader;
+
stage = Sbegin;
pxs->interpolate = pl_main_get_interpolate(mem);
@@ -295,25 +328,23 @@ pxl_impl_set_device(pl_interp_implementation_t * impl,
case Sbegin: /* nothing left to undo */
break;
}
+
+ /* Warn the device that PXL uses ROPs. */
+ if (code == 0) {
+ code = put_param_bool(pxli, "LanguageUsesROPs", true);
+
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ }
+
return code;
}
-/* Prepare interp instance for the next "job" */
-/* ret 0 ok, else -ve error code */
+/* Do any setup for parser per-cursor */
static int
-pxl_impl_init_job(pl_interp_implementation_t * impl)
+pxl_impl_process_begin(pl_interp_implementation_t * impl)
{
- int code = 0;
- pxl_interp_instance_t *pxli = impl->interp_client_data;
-
- px_reset_errors(pxli->pxs);
- px_process_init(pxli->st, true);
-
- /* set input status to: expecting stream header */
- px_stream_header_init(&pxli->headerState, pxli->st, pxli->pxs);
- pxli->processState = PSHeader;
-
- return code;
+ return 0;
}
/* Parse a cursor-full of data */
@@ -372,6 +403,13 @@ pxl_impl_process(pl_interp_implementation_t * impl,
return code;
}
+static int
+pxl_impl_process_end(pl_interp_implementation_t * impl)
+{
+ return 0;
+}
+
+
/* Skip to end of job ret 1 if done, 0 ok but EOJ not found, else -ve error code */
static int
pxl_impl_flush_to_eoj(pl_interp_implementation_t * impl,
@@ -457,23 +495,25 @@ pxl_impl_report_errors(pl_interp_implementation_t * impl,
static int
pxl_impl_dnit_job(pl_interp_implementation_t * impl)
{
+ int code;
pxl_interp_instance_t *pxli = impl->interp_client_data;
+ gx_device *device = gs_currentdevice(pxli->pgs);
px_stream_header_dnit(&pxli->headerState);
px_state_cleanup(pxli->pxs);
px_process_init(pxli->st, true);
- return 0;
-}
+ /* return to original gstate */
+ code = gs_grestore_only(pxli->pgs); /* destroys gs_save stack */
-/* Remove a device from an interperter instance */
-/* ret 0 ok, else -ve error code */
-static int
-pxl_impl_remove_device(pl_interp_implementation_t * impl)
-{
- pxl_interp_instance_t *pxli = impl->interp_client_data;
+ /* Warn the device that ROP usage has come to an end */
+ if (code >= 0) {
+ code = put_param_bool(pxli, "LanguageUsesROPs", false);
- /* return to original gstate */
- return gs_grestore_only(pxli->pgs); /* destroys gs_save stack */
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ }
+
+ return code;
}
/* Deallocate a interpreter instance */
@@ -511,15 +551,18 @@ pxl_end_page_top(px_state_t * pxls, int num_copies, int flush)
pl_interp_implementation_t pxl_implementation = {
pxl_impl_characteristics,
pxl_impl_allocate_interp_instance,
- pxl_impl_set_device,
+ NULL,
+ NULL,
+ NULL,
pxl_impl_init_job,
NULL, /* process_file */
+ pxl_impl_process_begin,
pxl_impl_process,
+ pxl_impl_process_end,
pxl_impl_flush_to_eoj,
pxl_impl_process_eof,
pxl_impl_report_errors,
pxl_impl_dnit_job,
- pxl_impl_remove_device,
pxl_impl_deallocate_interp_instance,
NULL
};
diff --git a/psi/dwdll.h b/psi/dwdll.h
index e68012c0a..0926c5f0a 100644
--- a/psi/dwdll.h
+++ b/psi/dwdll.h
@@ -40,6 +40,8 @@ typedef struct GSDLL_S {
PFN_gsapi_set_arg_encoding set_arg_encoding;
PFN_gsapi_set_default_device_list set_default_device_list;
PFN_gsapi_get_default_device_list get_default_device_list;
+ PFN_gsapi_get_device_memory get_device_memory;
+ PFN_gsapi_set_device set_device;
} GSDLL;
/* Load the Ghostscript DLL.
diff --git a/psi/dwnodll.c b/psi/dwnodll.c
index b3987b820..800297b88 100644
--- a/psi/dwnodll.c
+++ b/psi/dwnodll.c
@@ -42,6 +42,8 @@ int load_dll(GSDLL *gsdll, char *last_error, int len)
gsdll->exit = &gsapi_exit;
gsdll->set_default_device_list = &gsapi_set_default_device_list;
gsdll->get_default_device_list = &gsapi_get_default_device_list;
+ gsdll->get_device_memory = &gsapi_get_device_memory;
+ gsdll->set_device = &gsapi_set_device;
return 0;
}
diff --git a/psi/gsdll2.def b/psi/gsdll2.def
index b6e198ef0..088cc2a6d 100644
--- a/psi/gsdll2.def
+++ b/psi/gsdll2.def
@@ -19,3 +19,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/gsdll32.def b/psi/gsdll32.def
index deccca22f..0d44d1726 100644
--- a/psi/gsdll32.def
+++ b/psi/gsdll32.def
@@ -31,3 +31,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/gsdll32metro.def b/psi/gsdll32metro.def
index 391d9aba3..c1bdfcd27 100644
--- a/psi/gsdll32metro.def
+++ b/psi/gsdll32metro.def
@@ -31,3 +31,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/gsdll64.def b/psi/gsdll64.def
index 0e1e4a56e..46e4a2995 100644
--- a/psi/gsdll64.def
+++ b/psi/gsdll64.def
@@ -31,3 +31,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/gsdll64metro.def b/psi/gsdll64metro.def
index d2a0649ec..b1af06c1e 100644
--- a/psi/gsdll64metro.def
+++ b/psi/gsdll64metro.def
@@ -31,3 +31,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/gsdllARM32metro.def b/psi/gsdllARM32metro.def
index 371d4cd5c..769cf6677 100644
--- a/psi/gsdllARM32metro.def
+++ b/psi/gsdllARM32metro.def
@@ -31,3 +31,5 @@ EXPORTS
gsapi_set_arg_encoding
gsapi_set_default_device_list
gsapi_get_default_device_list
+ gsapi_get_device_memory
+ gsapi_set_device
diff --git a/psi/ialloc.c b/psi/ialloc.c
index 947759d6d..12af9b6c5 100644
--- a/psi/ialloc.c
+++ b/psi/ialloc.c
@@ -168,7 +168,7 @@ ialloc_trace_space(const gs_ref_memory_t *imem)
/* Register a ref root. */
int
-gs_register_ref_root(gs_memory_t *mem, gs_gc_root_t *root,
+gs_register_ref_root(gs_memory_t *mem, gs_gc_root_t **root,
void **pp, client_name_t cname)
{
return gs_register_root(mem, root, ptr_ref_type, pp, cname);
diff --git a/psi/iapi.c b/psi/iapi.c
index 49116b449..914badcaa 100644
--- a/psi/iapi.c
+++ b/psi/iapi.c
@@ -23,6 +23,7 @@
#include "gstypes.h"
#include "gdebug.h"
#include "iapi.h" /* Public API */
+#include "psapi.h"
#include "iref.h"
#include "iminst.h"
#include "imain.h"
@@ -33,14 +34,9 @@
#include "gp.h"
#include "gsargs.h"
-#ifndef GS_THREADSAFE
-/* Number of threads to allow per process. Unless GS_THREADSAFE is defined
- * more than 1 is guaranteed to fail.
- */
-static int gsapi_instance_counter = 0;
-static const int gsapi_instance_max = 1;
-#endif
-
+typedef struct { int a[GS_ARG_ENCODING_LOCAL == PS_ARG_ENCODING_LOCAL ? 1 : -1]; } compile_time_assert_0;
+typedef struct { int a[GS_ARG_ENCODING_UTF8 == PS_ARG_ENCODING_UTF8 ? 1 : -1]; } compile_time_assert_1;
+typedef struct { int a[GS_ARG_ENCODING_UTF16LE == PS_ARG_ENCODING_UTF16LE ? 1 : -1]; } compile_time_assert_2;
/* Return revision numbers and strings of Ghostscript. */
/* Used for determining if wrong GSDLL loaded. */
@@ -57,26 +53,6 @@ gsapi_revision(gsapi_revision_t *pr, int rvsize)
return 0;
}
-#ifdef METRO
-static int GSDLLCALL metro_stdin(void *v, char *buf, int len)
-{
- return 0;
-}
-
-static int GSDLLCALL metro_stdout(void *v, const char *str, int len)
-{
-#ifdef DEBUG
- OutputDebugStringWRT(str, len);
-#endif
- return len;
-}
-
-static int GSDLLCALL metro_stderr(void *v, const char *str, int len)
-{
- return metro_stdout(v, str, len);
-}
-#endif
-
/* Create a new instance of Ghostscript.
* First instance per process call with *pinstance == NULL
* next instance in a proces call with *pinstance == copy of valid_instance pointer
@@ -85,52 +61,7 @@ static int GSDLLCALL metro_stderr(void *v, const char *str, int len)
GSDLLEXPORT int GSDLLAPI
gsapi_new_instance(void **pinstance, void *caller_handle)
{
- gs_memory_t *mem = NULL;
- gs_main_instance *minst = NULL;
-
- if (pinstance == NULL)
- return gs_error_Fatal;
-
-#ifndef GS_THREADSAFE
- /* limited to 1 instance, till it works :) */
- if ( gsapi_instance_counter >= gsapi_instance_max )
- return gs_error_Fatal;
- ++gsapi_instance_counter;
-#endif
-
- if (*pinstance == NULL)
- /* first instance in this process */
- mem = gs_malloc_init();
- else {
- /* nothing different for second thread initialization
- * seperate memory, ids, only stdio is process shared.
- */
- mem = gs_malloc_init();
-
- }
- if (mem == NULL)
- return gs_error_Fatal;
- minst = gs_main_alloc_instance(mem);
- if (minst == NULL) {
- gs_malloc_release(mem);
- return gs_error_Fatal;
- }
- mem->gs_lib_ctx->top_of_system = (void*) minst;
- mem->gs_lib_ctx->caller_handle = caller_handle;
- mem->gs_lib_ctx->custom_color_callback = NULL;
-#ifdef METRO
- mem->gs_lib_ctx->stdin_fn = metro_stdin;
- mem->gs_lib_ctx->stdout_fn = metro_stdout;
- mem->gs_lib_ctx->stderr_fn = metro_stderr;
-#else
- mem->gs_lib_ctx->stdin_fn = NULL;
- mem->gs_lib_ctx->stdout_fn = NULL;
- mem->gs_lib_ctx->stderr_fn = NULL;
-#endif
- mem->gs_lib_ctx->poll_fn = NULL;
-
- *pinstance = (void*)(mem->gs_lib_ctx);
- return gsapi_set_arg_encoding(*pinstance, GS_ARG_ENCODING_LOCAL);
+ return psapi_new_instance((gs_lib_ctx_t **)pinstance, caller_handle);
}
/* Destroy an instance of Ghostscript */
@@ -140,27 +71,7 @@ gsapi_new_instance(void **pinstance, void *caller_handle)
GSDLLEXPORT void GSDLLAPI
gsapi_delete_instance(void *instance)
{
- gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if ((ctx != NULL)) {
- gs_memory_t *mem = (gs_memory_t *)(ctx->memory);
- gs_main_instance *minst = get_minst_from_memory(ctx->memory);
-
- ctx->caller_handle = NULL;
- ctx->stdin_fn = NULL;
- ctx->stdout_fn = NULL;
- ctx->stderr_fn = NULL;
- ctx->poll_fn = NULL;
- minst->display = NULL;
-
- gs_free_object(mem, minst, "init_main_instance");
-
- /* Release the memory (frees up everything) */
- gs_malloc_release(mem);
-
-#ifndef GS_THREADSAFE
- --gsapi_instance_counter;
-#endif
- }
+ psapi_delete_instance(instance);
}
/* Set the callback functions for stdio */
@@ -173,9 +84,9 @@ gsapi_set_stdio(void *instance,
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
if (instance == NULL)
return gs_error_Fatal;
- ctx->stdin_fn = stdin_fn;
- ctx->stdout_fn = stdout_fn;
- ctx->stderr_fn = stderr_fn;
+ ctx->core->stdin_fn = stdin_fn;
+ ctx->core->stdout_fn = stdout_fn;
+ ctx->core->stderr_fn = stderr_fn;
return 0;
}
@@ -187,7 +98,7 @@ gsapi_set_poll(void *instance,
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
if (instance == NULL)
return gs_error_Fatal;
- ctx->poll_fn = poll_fn;
+ ctx->core->poll_fn = poll_fn;
return 0;
}
@@ -222,122 +133,19 @@ gsapi_get_default_device_list(void *instance, char **list, int *listlen)
return gs_lib_ctx_get_default_device_list(ctx->memory, list, listlen);
}
-static int utf16le_get_codepoint(FILE *file, const char **astr)
-{
- int c;
- int rune;
- int trail;
-
- /* This code spots the BOM for 16bit LE and ignores it. Strictly speaking
- * this may be wrong, as we are only supposed to ignore it at the beginning
- * of the string, but if anyone is stupid enough to use ZWNBSP (zero width
- * non breaking space) in the middle of their strings, then they deserve
- * what they get. */
- /* We spot the BOM for 16bit BE and treat that as EOF. We'd rather give
- * up on dealing with a broken file than try to run something we know to
- * be wrong. */
-
- do {
- if (file) {
- rune = fgetc(file);
- if (rune == EOF)
- return EOF;
- c = fgetc(file);
- if (c == EOF)
- return EOF;
- rune += c<<8;
- } else {
- rune = (*astr)[0] | ((*astr)[1]<<8);
- if (rune != 0)
- (*astr) += 2;
- else
- return EOF;
- }
- if (rune == 0xFEFF) /* BOM - ignore it */
- continue;
- if (rune == 0xFFFE) /* BOM for BE - hopelessly broken */
- return EOF;
- if (rune < 0xD800 || rune >= 0xE000)
- return rune;
- if (rune >= 0xDC00) /* Found a trailing surrogate pair. Skip it */
- continue;
-lead: /* We've just read a leading surrogate */
- rune -= 0xD800;
- rune <<= 10;
- if (file) {
- trail = fgetc(file);
- if (trail == EOF)
- return EOF;
- c = fgetc(file);
- if (c == EOF)
- return EOF;
- trail += c<<8;
- } else {
- trail = (*astr)[0] | ((*astr)[1]<<8);
- if (trail != 0)
- (*astr) += 2;
- else
- return EOF;
- }
- if (trail < 0xd800 || trail >= 0xE000) {
- if (rune == 0xFEFF) /* BOM - ignore it. */
- continue;
- if (rune == 0xFFFE) /* BOM for BE - hopelessly broken. */
- return EOF;
- /* No trail surrogate was found, so skip the lead surrogate and
- * return the rune we landed on. */
- return trail;
- }
- if (trail < 0xdc00) {
- /* We found another leading surrogate. */
- rune = trail;
- goto lead;
- }
- break;
- } while (1);
-
- return rune + (trail-0xDC00) + 0x10000;
-}
-
/* Initialise the interpreter */
GSDLLEXPORT int GSDLLAPI
gsapi_set_arg_encoding(void *instance, int encoding)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- if (encoding == GS_ARG_ENCODING_LOCAL) {
-#if defined(__WIN32__) && !defined(METRO)
- /* For windows, we need to set it up so that we convert from 'local'
- * format (in this case whatever codepage is set) to utf8 format. At
- * the moment, all the other OS we care about provide utf8 anyway.
- */
- gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), gp_local_arg_encoding_get_codepoint);
-#else
- gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
-#endif /* WIN32 */
- return 0;
- }
- if (encoding == GS_ARG_ENCODING_UTF8) {
- gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
- return 0;
- }
- if (encoding == GS_ARG_ENCODING_UTF16LE) {
- gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), utf16le_get_codepoint);
- return 0;
- }
- return gs_error_Fatal;
+ return psapi_set_arg_encoding(ctx, encoding);
}
GSDLLEXPORT int GSDLLAPI
gsapi_init_with_args(void *instance, int argc, char **argv)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- return gs_main_init_with_args(get_minst_from_memory(ctx->memory), argc, argv);
+ return psapi_init_with_args(ctx, argc, argv);
}
/* The gsapi_run_* functions are like gs_main_run_* except
@@ -347,106 +155,74 @@ gsapi_init_with_args(void *instance, int argc, char **argv)
/* Setup up a suspendable run_string */
GSDLLEXPORT int GSDLLAPI
-gsapi_run_string_begin(void *instance, int user_errors,
- int *pexit_code)
+gsapi_run_string_begin(void *instance,
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- return gs_main_run_string_begin(get_minst_from_memory(ctx->memory),
- user_errors, pexit_code,
- &(get_minst_from_memory(ctx->memory)->error_object));
+ return psapi_run_string_begin(ctx, user_errors, pexit_code);
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_string_continue(void *instance,
- const char *str, uint length, int user_errors, int *pexit_code)
+gsapi_run_string_continue(void *instance,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- return gs_main_run_string_continue(get_minst_from_memory(ctx->memory),
- str, length, user_errors, pexit_code,
- &(get_minst_from_memory(ctx->memory)->error_object));
+ return psapi_run_string_continue(ctx, str, length, user_errors, pexit_code);
}
GSDLLEXPORT int GSDLLAPI
gsapi_run_string_end(void *instance,
- int user_errors, int *pexit_code)
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- return gs_main_run_string_end(get_minst_from_memory(ctx->memory),
- user_errors, pexit_code,
- &(get_minst_from_memory(ctx->memory)->error_object));
+ return psapi_run_string_end(ctx, user_errors, pexit_code);
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_string_with_length(void *instance,
- const char *str, uint length, int user_errors, int *pexit_code)
+gsapi_run_string_with_length(void *instance,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- return gs_main_run_string_with_length(get_minst_from_memory(ctx->memory),
- str, length, user_errors, pexit_code,
- &(get_minst_from_memory(ctx->memory)->error_object));
+ return psapi_run_string_with_length(ctx, str, length, user_errors, pexit_code);
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_string(void *instance,
- const char *str, int user_errors, int *pexit_code)
+gsapi_run_string(void *instance,
+ const char *str,
+ int user_errors,
+ int *pexit_code)
{
- return gsapi_run_string_with_length(instance,
- str, (uint)strlen(str), user_errors, pexit_code);
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ return psapi_run_string_with_length(ctx,
+ str,
+ (unsigned int)strlen(str),
+ user_errors,
+ pexit_code);
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_file(void *instance, const char *file_name,
- int user_errors, int *pexit_code)
+gsapi_run_file(void *instance,
+ const char *file_name,
+ int user_errors,
+ int *pexit_code)
{
- char *d, *temp;
- const char *c = file_name;
- char dummy[6];
- int rune, code, len;
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- gs_main_instance *minst;
- if (instance == NULL)
- return gs_error_Fatal;
- minst = get_minst_from_memory(ctx->memory);
-
- /* Convert the file_name to utf8 */
- if (minst->get_codepoint) {
- len = 1;
- while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
- len += codepoint_to_utf8(dummy, rune);
- temp = (char *)gs_alloc_bytes_immovable(ctx->memory, len, "gsapi_run_file");
- if (temp == NULL)
- return 0;
- c = file_name;
- d = temp;
- while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
- d += codepoint_to_utf8(d, rune);
- *d = 0;
- }
- else {
- temp = (char *)file_name;
- }
- code = gs_main_run_file(minst, temp, user_errors, pexit_code,
- &(minst->error_object));
- if (temp != file_name)
- gs_free_object(ctx->memory, temp, "gsapi_run_file");
- return code;
+ return psapi_run_file(ctx, file_name, user_errors, pexit_code);
}
#ifdef __WIN32__
GSDLLEXPORT int GSDLLAPI
-gsapi_init_with_argsW(void *instance, int argc, wchar_t **argv)
+gsapi_init_with_argsW(void *instance,
+ int argc,
+ wchar_t **argv)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
int code;
@@ -455,16 +231,18 @@ gsapi_init_with_argsW(void *instance, int argc, wchar_t **argv)
return gs_error_Fatal;
old = gs_main_inst_get_arg_decode(get_minst_from_memory(ctx->memory));
- code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF16LE);
+ code = psapi_set_arg_encoding(ctx, PS_ARG_ENCODING_UTF16LE);
if (code != 0)
return code;
- code = gsapi_init_with_args(instance, 2*argc, (char **)argv);
+ code = psapi_init_with_args(ctx, 2*argc, (char **)argv);
gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), old);
return code;
}
GSDLLEXPORT int GSDLLAPI
-gsapi_init_with_argsA(void *instance, int argc, char **argv)
+gsapi_init_with_argsA(void *instance,
+ int argc,
+ char **argv)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
int code;
@@ -473,17 +251,19 @@ gsapi_init_with_argsA(void *instance, int argc, char **argv)
return gs_error_Fatal;
old = gs_main_inst_get_arg_decode(get_minst_from_memory(ctx->memory));
- code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_LOCAL);
+ code = psapi_set_arg_encoding(ctx, PS_ARG_ENCODING_LOCAL);
if (code != 0)
return code;
- code = gsapi_init_with_args(instance, 2*argc, (char **)argv);
+ code = psapi_init_with_args(ctx, 2*argc, (char **)argv);
gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), old);
return code;
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_fileW(void *instance, const wchar_t *file_name,
- int user_errors, int *pexit_code)
+gsapi_run_fileW(void *instance,
+ const wchar_t *file_name,
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
int code;
@@ -492,17 +272,19 @@ gsapi_run_fileW(void *instance, const wchar_t *file_name,
return gs_error_Fatal;
old = gs_main_inst_get_arg_decode(get_minst_from_memory(ctx->memory));
- code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_UTF16LE);
+ code = psapi_set_arg_encoding(ctx, PS_ARG_ENCODING_UTF16LE);
if (code != 0)
return code;
- code = gsapi_run_file(instance, (const char *)file_name, user_errors, pexit_code);
+ code = psapi_run_file(ctx, (const char *)file_name, user_errors, pexit_code);
gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), old);
return code;
}
GSDLLEXPORT int GSDLLAPI
-gsapi_run_fileA(void *instance, const char *file_name,
- int user_errors, int *pexit_code)
+gsapi_run_fileA(void *instance,
+ const char *file_name,
+ int user_errors,
+ int *pexit_code)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
int code;
@@ -511,25 +293,37 @@ gsapi_run_fileA(void *instance, const char *file_name,
return gs_error_Fatal;
old = gs_main_inst_get_arg_decode(get_minst_from_memory(ctx->memory));
- code = gsapi_set_arg_encoding(instance, GS_ARG_ENCODING_LOCAL);
+ code = psapi_set_arg_encoding(ctx, PS_ARG_ENCODING_LOCAL);
if (code != 0)
return code;
- code = gsapi_run_file(instance, (const char *)file_name, user_errors, pexit_code);
+ code = psapi_run_file(ctx, (const char *)file_name, user_errors, pexit_code);
gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), old);
return code;
}
#endif
+/* Retrieve the memory allocator for the interpreter instance */
+GSDLLEXPORT gs_memory_t * GSDLLAPI
+gsapi_get_device_memory(void *instance)
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ return psapi_get_device_memory(ctx);
+}
+
+/* Retrieve the memory allocator for the interpreter instance */
+GSDLLEXPORT int GSDLLAPI
+gsapi_set_device(void *instance, gx_device *pdev)
+{
+ gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
+ return psapi_set_device(ctx, pdev);
+}
+
/* Exit the interpreter */
GSDLLEXPORT int GSDLLAPI
gsapi_exit(void *instance)
{
gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance;
- if (instance == NULL)
- return gs_error_Fatal;
-
- gs_to_exit(ctx->memory, 0);
- return 0;
+ return psapi_exit(ctx);
}
/* end of iapi.c */
diff --git a/psi/iapi.h b/psi/iapi.h
index 4155cbf03..f4120c546 100644
--- a/psi/iapi.h
+++ b/psi/iapi.h
@@ -112,6 +112,16 @@ extern "C" {
typedef struct display_callback_s display_callback;
#endif
+#ifndef gs_memory_DEFINED
+# define gs_memory_DEFINED
+typedef struct gs_memory_s gs_memory_t;
+#endif
+
+#ifndef gx_device_DEFINED
+# define gx_device_DEFINED
+typedef struct gx_device_s gx_device;
+#endif
+
typedef struct gsapi_revision_s {
const char *product;
const char *copyright;
@@ -296,6 +306,14 @@ gsapi_run_fileW(void *instance,
const wchar_t *file_name, int user_errors, int *pexit_code);
#endif
+/* Retrieve the memory allocator for the interpreter instance */
+GSDLLEXPORT gs_memory_t * GSDLLAPI
+gsapi_get_device_memory(void *instance);
+
+/* Set the device */
+GSDLLEXPORT int GSDLLAPI
+gsapi_set_device(void *instance, gx_device *pdev);
+
/* Exit the interpreter.
* This must be called on shutdown if gsapi_init_with_args()
* has been called, and just before gsapi_delete_instance().
@@ -353,6 +371,8 @@ typedef int (GSDLLAPIPTR PFN_gsapi_run_fileA)(void *instance,
typedef int (GSDLLAPIPTR PFN_gsapi_run_fileW)(void *instance,
const wchar_t *file_name, int user_errors, int *pexit_code);
#endif
+typedef gs_memory_t * (GSDLLAPIPTR PFN_gsapi_get_device_memory)(void *instance);
+typedef gs_memory_t * (GSDLLAPIPTR PFN_gsapi_set_device)(void *instance, gx_device *pdev);
typedef int (GSDLLAPIPTR PFN_gsapi_exit)(void *instance);
#ifdef __MACOS__
diff --git a/psi/icstate.h b/psi/icstate.h
index 4c6a14d44..492800ed3 100644
--- a/psi/icstate.h
+++ b/psi/icstate.h
@@ -70,6 +70,7 @@ struct gs_context_state_s {
int (*time_slice_proc)(i_ctx_t **); /* Time slice procedure */
int time_slice_ticks; /* Ticks before next slice */
int (*reschedule_proc)(i_ctx_t **); /* Reschedule procedure */
+ gs_offset_t uel_position; /* The file position at which we last hit UEL */
/* Put the stacks at the end to minimize other offsets. */
dict_stack_t dict_stack;
diff --git a/psi/igc.c b/psi/igc.c
index fce3d00f3..a2d016432 100644
--- a/psi/igc.c
+++ b/psi/igc.c
@@ -238,11 +238,13 @@ gs_gc_reclaim(vm_spaces * pspaces, bool global)
/* Register the allocators themselves as roots, */
/* so we mark and relocate the change and save lists properly. */
- for_spaces(ispace, max_trace)
+ for_spaces(ispace, max_trace) {
+ rp = &space_roots[ispace];
gs_register_struct_root((gs_memory_t *)space_memories[ispace],
- &space_roots[ispace],
+ &rp,
(void **)&space_memories[ispace],
"gc_top_level");
+ }
end_phase(state.heap,"register space roots");
diff --git a/psi/imain.c b/psi/imain.c
index fc5bbc2e5..1b84604a9 100644
--- a/psi/imain.c
+++ b/psi/imain.c
@@ -38,7 +38,7 @@
#include "oper.h"
#include "iconf.h" /* for gs_init_* imports */
#include "idebug.h"
-#include "idict.h"
+#include "iddict.h"
#include "iname.h" /* for name_init */
#include "dstack.h"
#include "estack.h"
@@ -192,7 +192,7 @@ gs_main_init1(gs_main_instance * minst)
goto fail;
}
mem->gs_lib_ctx->gs_name_table = nt;
- code = gs_register_struct_root(mem, mem->gs_lib_ctx->name_table_root,
+ code = gs_register_struct_root(mem, &mem->gs_lib_ctx->name_table_root,
(void **)&mem->gs_lib_ctx->gs_name_table,
"the_gs_name_table");
if (code < 0)
@@ -225,7 +225,7 @@ fail:
*/
static int
gs_main_interpret(gs_main_instance *minst, ref * pref, int user_errors,
- int *pexit_code, ref * perror_object)
+ int *pexit_code, ref * perror_object)
{
int code;
@@ -233,7 +233,7 @@ gs_main_interpret(gs_main_instance *minst, ref * pref, int user_errors,
minst->i_ctx_p->lib_path = &minst->lib_path;
code = gs_interpret(&minst->i_ctx_p, pref,
- user_errors, pexit_code, perror_object);
+ user_errors, pexit_code, perror_object);
return code;
}
@@ -630,7 +630,7 @@ gs_main_run_string_begin(gs_main_instance * minst, int user_errors,
make_const_string(&rstr, avm_foreign | a_readonly | a_executable,
strlen(setup), (const byte *)setup);
code = gs_main_interpret(minst, &rstr, user_errors, pexit_code,
- perror_object);
+ perror_object);
return (code == gs_error_NeedInput ? 0 : code == 0 ? gs_error_Fatal : code);
}
/* Continue running a string with the option of suspending. */
@@ -645,8 +645,16 @@ gs_main_run_string_continue(gs_main_instance * minst, const char *str,
make_const_string(&rstr, avm_foreign | a_readonly, length,
(const byte *)str);
return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
- perror_object);
+ perror_object);
}
+uint
+gs_main_get_uel_offset(gs_main_instance * minst)
+{
+ if (minst->i_ctx_p == NULL)
+ return 0;
+ return (uint)minst->i_ctx_p->uel_position;
+}
+
/* Signal EOF when suspended. */
int
gs_main_run_string_end(gs_main_instance * minst, int user_errors,
@@ -656,7 +664,79 @@ gs_main_run_string_end(gs_main_instance * minst, int user_errors,
make_empty_const_string(&rstr, avm_foreign | a_readonly);
return gs_main_interpret(minst, &rstr, user_errors, pexit_code,
- perror_object);
+ perror_object);
+}
+
+gs_memory_t *
+gs_main_get_device_memory(gs_main_instance * minst)
+{
+ gs_memory_t *dev_mem = NULL;
+ if (minst && minst->init_done >= 1) {
+ i_ctx_t * i_ctx_p = minst->i_ctx_p;
+ dev_mem = imemory_global->stable_memory;
+ }
+ return dev_mem;
+}
+
+int
+gs_main_set_device(gs_main_instance * minst, gx_device *pdev)
+{
+ i_ctx_t *i_ctx_p = minst->i_ctx_p;
+ ref error_object;
+ int code;
+
+ if (pdev == NULL) {
+ /* Leave job encapsulation, restore the graphics state gsaved below (so back to the nullpage device)
+ and re-enter job encapsulation.
+ We rely on the end of job encapsulation restore to the put the gstate stack back how it was when
+ we entered job encapsulation below, so the grestore will pickup the correct gstate.
+ */
+ code = gs_main_run_string(minst,
+ "true 0 startjob pop grestore false 0 startjob pop",
+ 0, &code, &error_object);
+ if (code < 0) goto done;
+ }
+ else {
+ /* Leave job encapsulation, and save the graphics state (including the device: nullpage)
+ Store the page size in a dictionary, which we'll use to configure the incoming device */
+ code = gs_main_run_string(minst,
+ "true 0 startjob pop gsave "
+ /* /PageSize /GetDeviceParam .special_op will either return:
+ * /PageSize [ <width> <height> ] true (if it exists) or
+ * false (if it does not) */
+ "<< /PageSize /GetDeviceParam .special_op "
+ /* If we wanted to force a default pagesize, we'd do:
+ * "not { /PageSize [595 842] } if "
+ * but for now we'll just leave the default as it is, and do: */
+ "pop "
+ ">> "
+ , 0, &code, &error_object);
+ if (code < 0) goto done;
+ /* First call goes to the C directly to actually set the device. This
+ * avoids the SAFER checks. */
+ code = zsetdevice_no_safer(i_ctx_p, pdev);
+ if (code < 0) goto done;
+ code = zcurrentoutputdevice(i_ctx_p);
+ if (code < 0) goto done;
+ code = gs_main_run_string(minst,
+ /* Set the device again to the same one. This determines
+ * whether to erase page or not, but passes the safer
+ * checks as the device is unchanged. */
+ "setdevice "
+ "setpagedevice "
+ /* GS specifics: Force the cached copy of the params to be updated. */
+ "currentpagedevice pop "
+ /* Setup the halftone */
+ ".setdefaultscreen "
+ /* Re-run the scheduled initialisation procs, in case we've just set pdfwrite */
+ "1183615869 internaldict /.execute_scheduled_inits get exec "
+ /* Re-enter job encapsulation */
+ "false 0 startjob pop "
+ , 0, &code, &error_object);
+ if (code < 0) goto done;
+ }
+done:
+ return code;
}
/* ------ Operand stack access ------ */
@@ -875,6 +955,7 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
int exit_code;
ref error_object;
char *tempnames = NULL;
+ gs_lib_ctx_core_t *core;
/* NB: need to free gs_name_table
*/
@@ -960,6 +1041,7 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
gx_device *pdev = i_ctx_p->pgs->device;
const char * dname = pdev->dname;
gs_gc_root_t dev_root;
+ gs_gc_root_t *dev_root_ptr = &dev_root;
/* There is a chance that, during the call to gs_main_run_string(), the interpreter may
* decide to call the garbager - the device is in gc memory, and the only reference to it
* (in the gstate) has been removed, thus it can be destroyed by the garbager.
@@ -967,7 +1049,7 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
* Register the device as a gc 'root' so it will be implicitely marked by garbager, and
* and thus surive until control returns here.
*/
- if (gs_register_struct_root(pdev->memory, &dev_root, (void **)&pdev, "gs_main_finit") < 0) {
+ if (gs_register_struct_root(pdev->memory, &dev_root_ptr, (void **)&pdev, "gs_main_finit") < 0) {
free(tempnames);
return_error(gs_error_Fatal);
}
@@ -993,7 +1075,7 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
emprintf2(imemory, "UNKNOWN ERROR %d closing %s device.\n", code, dname);
}
}
- gs_unregister_root(pdev->memory, &dev_root, "gs_main_finit");
+ gs_unregister_root(pdev->memory, dev_root_ptr, "gs_main_finit");
rc_decrement(pdev, "gs_main_finit"); /* device might be freed */
if (exit_status == 0 || exit_status == gs_error_Quit)
exit_status = code;
@@ -1029,15 +1111,16 @@ gs_main_finit(gs_main_instance * minst, int exit_status, int code)
}
/* clean up redirected stdout */
- if (minst->heap->gs_lib_ctx->fstdout2
- && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstdout)
- && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstderr)) {
- fclose(minst->heap->gs_lib_ctx->fstdout2);
- minst->heap->gs_lib_ctx->fstdout2 = (FILE *)NULL;
+ core = minst->heap->gs_lib_ctx->core;
+ if (core->fstdout2
+ && (core->fstdout2 != core->fstdout)
+ && (core->fstdout2 != core->fstderr)) {
+ fclose(core->fstdout2);
+ core->fstdout2 = (FILE *)NULL;
}
- minst->heap->gs_lib_ctx->stdout_is_redirected = 0;
- minst->heap->gs_lib_ctx->stdout_to_stderr = 0;
+ minst->heap->gs_lib_ctx->core->stdout_is_redirected = 0;
+ minst->heap->gs_lib_ctx->core->stdout_to_stderr = 0;
/* remove any temporary files, after ghostscript has closed files */
if (tempnames) {
char *p = tempnames;
@@ -1127,3 +1210,53 @@ gs_main_dump_stack(gs_main_instance *minst, int code, ref * perror_object)
debug_dump_stack(minst->heap, &e_stack, "Execution stack");
debug_dump_stack(minst->heap, &d_stack, "Dictionary stack");
}
+
+int
+gs_main_force_resolutions(gs_main_instance * minst, const float *resolutions)
+{
+ ref value;
+ int code;
+
+ if (resolutions == NULL)
+ return 0;
+
+ if (minst == NULL)
+ return gs_error_Fatal;
+
+ make_true(&value);
+ code = i_initial_enter_name(minst->i_ctx_p, "FIXEDRESOLUTION", &value);
+ if (code < 0)
+ return code;
+ make_real(&value, resolutions[0]);
+ code = i_initial_enter_name(minst->i_ctx_p, "DEVICEXRESOLUTION", &value);
+ if (code < 0)
+ return code;
+ make_real(&value, resolutions[1]);
+ return i_initial_enter_name(minst->i_ctx_p, "DEVICEYRESOLUTION", &value);
+}
+
+int
+gs_main_force_dimensions(gs_main_instance *minst, const long *dimensions)
+{
+ i_ctx_t *i_ctx_p;
+ ref value;
+ int code = 0;
+
+ if (dimensions == NULL)
+ return 0;
+ if (minst == NULL)
+ return gs_error_Fatal;
+
+ i_ctx_p = minst->i_ctx_p;
+
+ make_true(&value);
+ code = i_initial_enter_name(minst->i_ctx_p, "FIXEDMEDIA", &value);
+ if (code < 0)
+ return code;
+ make_int(&value, dimensions[0]);
+ code = i_initial_enter_name(minst->i_ctx_p, "DEVICEWIDTH", &value);
+ if (code < 0)
+ return code;
+ make_int(&value, dimensions[1]);
+ return i_initial_enter_name(minst->i_ctx_p, "DEVICEHEIGHT", &value);
+}
diff --git a/psi/imain.h b/psi/imain.h
index 708d139e6..374ce2e2a 100644
--- a/psi/imain.h
+++ b/psi/imain.h
@@ -169,6 +169,13 @@ int gs_main_run_string_with_length(gs_main_instance * minst,
int user_errors, int *pexit_code,
ref * perror_object);
+/* Version of gs_main_run_file that works for PDF files. */
+int gs_main_run_file2(gs_main_instance *minst,
+ const char *fname,
+ int user_errors,
+ int *pexit_code,
+ ref *perror_object);
+
/*
* Open the file for gs_main_run_file. This is an internal routine
* that is only exported for some special clients.
@@ -198,6 +205,25 @@ int gs_main_run_string_continue(gs_main_instance * minst,
int gs_main_run_string_end(gs_main_instance * minst, int user_errors,
int *pexit_code, ref * perror_object);
+/* This procedure returns the offset at which the last UEL was
+ * encountered during parsing. This is only defined after
+ * a gs_error_InterpreterExit has been returned (and in particular
+ * after a .forceinterp_exit has been called). Calling this
+ * in other circumstances will get undefined results. */
+uint gs_main_get_uel_offset(gs_main_instance * minst);
+
+gs_memory_t *
+gs_main_get_device_memory(gs_main_instance * minst);
+
+int
+gs_main_set_device(gs_main_instance * minst, gx_device *pdev);
+
+int
+gs_main_force_resolutions(gs_main_instance * minst, const float *resolutions);
+
+int
+gs_main_force_dimensions(gs_main_instance * minst, const long *resolutions);
+
/* ---------------- Operand stack access ---------------- */
/*
diff --git a/psi/imainarg.c b/psi/imainarg.c
index 5c8016a8c..6ccd839bf 100644
--- a/psi/imainarg.c
+++ b/psi/imainarg.c
@@ -95,8 +95,8 @@ static int argproc(gs_main_instance *, const char *);
static int run_buffered(gs_main_instance *, const char *);
static int esc_strlen(const char *);
static void esc_strcat(char *, const char *);
-static int runarg(gs_main_instance *, const char *, const char *, const char *, int);
-static int run_string(gs_main_instance *, const char *, int);
+static int runarg(gs_main_instance *, const char *, const char *, const char *, int, int, int *, ref *);
+static int run_string(gs_main_instance *, const char *, int, int, int *, ref *);
static int run_finish(gs_main_instance *, int, int, ref *);
static int try_stdout_redirect(gs_main_instance * minst,
const char *command, const char *filename);
@@ -131,7 +131,7 @@ set_debug_flags(const char *arg, char *flags)
}
int
-gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
+gs_main_init_with_args01(gs_main_instance * minst, int argc, char *argv[])
{
const char *arg;
arg_list args;
@@ -256,24 +256,43 @@ gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
}
}
}
- if (code < 0)
- return code;
-
- code = gs_main_init2(minst);
- if (code < 0)
- return code;
if (gs_debug[':']) {
int i;
- dmprintf1(minst->heap, "%% Init done, instance 0x%p, with args: ", minst);
+ dmprintf1(minst->heap, "%% Init (Part 1/2) done, instance 0x%p, with args: ", minst);
for (i=1; i<argc; i++)
dmprintf1(minst->heap, "%s ", argv[i]);
dmprintf(minst->heap, "\n");
}
+ return code;
+}
+
+int
+gs_main_init_with_args2(gs_main_instance * minst)
+{
+ int code;
+
+ code = gs_main_init2(minst);
+ if (code < 0)
+ return code;
+
+ if (gs_debug[':'])
+ dmprintf1(minst->heap, "%% Init (Part 2/2) done, instance 0x%p.", minst);
+
if (!minst->run_start)
return gs_error_Quit;
- return code ;
+ return code;
+}
+
+int
+gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[])
+{
+ int code = gs_main_init_with_args01(minst, argc, argv);
+
+ if (code < 0)
+ return code;
+ return gs_main_init_with_args2(minst);
}
/*
@@ -296,7 +315,7 @@ gs_arg_get_codepoint *gs_main_inst_get_arg_decode(gs_main_instance * minst)
int
gs_main_run_start(gs_main_instance * minst)
{
- return run_string(minst, "systemdict /start get exec", runFlush);
+ return run_string(minst, "systemdict /start get exec", runFlush, minst->user_errors, NULL, NULL);
}
/* Process switches. Return 0 if processed, 1 for unknown switch, */
@@ -315,10 +334,10 @@ swproc(gs_main_instance * minst, const char *arg, arg_list * pal)
return 1;
case 0: /* read stdin as a file char-by-char */
/* This is a ******HACK****** for Ghostview. */
- minst->heap->gs_lib_ctx->stdin_is_interactive = true;
+ minst->heap->gs_lib_ctx->core->stdin_is_interactive = true;
goto run_stdin;
case '_': /* read stdin with normal buffering */
- minst->heap->gs_lib_ctx->stdin_is_interactive = false;
+ minst->heap->gs_lib_ctx->core->stdin_is_interactive = false;
run_stdin:
minst->run_start = false; /* don't run 'start' */
/* Set NOPAUSE so showpage won't try to read from stdin. */
@@ -329,7 +348,7 @@ run_stdin:
if (code < 0)
return code;
- code = run_string(minst, ".runstdin", runFlush);
+ code = run_string(minst, ".runstdin", runFlush, minst->user_errors, NULL, NULL);
if (code < 0)
return code;
/* If in saved_pages_test_mode, print and flush previous job before the next file */
@@ -432,19 +451,19 @@ run_stdin:
else
code = gs_main_init2(minst);
if (code >= 0)
- code = run_string(minst, "userdict/ARGUMENTS[", 0);
+ code = run_string(minst, "userdict/ARGUMENTS[", 0, minst->user_errors, NULL, NULL);
if (code >= 0)
while ((code = arg_next(pal, (const char **)&arg, minst->heap)) > 0) {
- code = runarg(minst, "", arg, "", runInit);
+ code = runarg(minst, "", arg, "", runInit, minst->user_errors, NULL, NULL);
if (code < 0)
break;
}
if (code >= 0)
- code = runarg(minst, "]put", psarg, ".runfile", runInit | runFlush);
+ code = runarg(minst, "]put", psarg, ".runfile", runInit | runFlush, minst->user_errors, NULL, NULL);
arg_free((char *)psarg, minst->heap);
if (code >= 0)
code = gs_error_Quit;
-
+
return code;
}
case 'A': /* trace allocator */
@@ -490,7 +509,7 @@ run_stdin:
(arg[0] == '-' && !isdigit((unsigned char)arg[1]))
)
break;
- code = runarg(minst, "", arg, ".runstring", 0);
+ code = runarg(minst, "", arg, ".runstring", 0, minst->user_errors, NULL, NULL);
if (code < 0)
return code;
}
@@ -585,20 +604,15 @@ run_stdin:
break;
case 'g': /* define device geometry */
{
- long width, height;
- ref value;
+ long dimensions[2];
if ((code = gs_main_init1(minst)) < 0)
return code;
- if (sscanf((const char *)arg, "%ldx%ld", &width, &height) != 2) {
+ if (sscanf((const char *)arg, "%ldx%ld", &dimensions[0], &dimensions[1]) != 2) {
puts(minst->heap, "-g must be followed by <width>x<height>");
return gs_error_Fatal;
}
- make_int(&value, width);
- i_initial_enter_name(minst->i_ctx_p, "DEVICEWIDTH", &value);
- make_int(&value, height);
- i_initial_enter_name(minst->i_ctx_p, "DEVICEHEIGHT", &value);
- i_initial_enter_name(minst->i_ctx_p, "FIXEDMEDIA", &vtrue);
+ gs_main_force_dimensions(minst, dimensions);
break;
}
case 'h': /* print help */
@@ -719,24 +733,19 @@ run_stdin:
break;
case 'r': /* define device resolution */
{
- float xres, yres;
- ref value;
+ float res[2];
if ((code = gs_main_init1(minst)) < 0)
return code;
- switch (sscanf((const char *)arg, "%fx%f", &xres, &yres)) {
+ switch (sscanf((const char *)arg, "%fx%f", &res[0], &res[0])) {
default:
puts(minst->heap, "-r must be followed by <res> or <xres>x<yres>");
return gs_error_Fatal;
case 1: /* -r<res> */
- yres = xres;
+ res[1] = res[0];
/* fall through */
case 2: /* -r<xres>x<yres> */
- make_real(&value, xres);
- i_initial_enter_name(minst->i_ctx_p, "DEVICEXRESOLUTION", &value);
- make_real(&value, yres);
- i_initial_enter_name(minst->i_ctx_p, "DEVICEYRESOLUTION", &value);
- i_initial_enter_name(minst->i_ctx_p, "FIXEDRESOLUTION", &vtrue);
+ gs_main_force_resolutions(minst, res);
}
break;
}
@@ -954,7 +963,7 @@ argproc(gs_main_instance * minst, const char *arg)
return run_buffered(minst, arg);
} else {
/* Run file directly in the normal way. */
- return runarg(minst, "", arg, ".runfile", runInit | runFlush);
+ return runarg(minst, "", arg, ".runfile", runInit | runFlush, minst->user_errors, NULL, NULL);
}
}
static int
@@ -999,8 +1008,14 @@ run_buffered(gs_main_instance * minst, const char *arg)
return run_finish(minst, code, exit_code, &error_object);
}
static int
-runarg(gs_main_instance * minst, const char *pre, const char *arg,
- const char *post, int options)
+runarg(gs_main_instance *minst,
+ const char *pre,
+ const char *arg,
+ const char *post,
+ int options,
+ int user_errors,
+ int *pexit_code,
+ ref *perror_object)
{
int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
int code;
@@ -1021,24 +1036,45 @@ runarg(gs_main_instance * minst, const char *pre, const char *arg,
esc_strcat(line, arg);
strcat(line, post);
minst->i_ctx_p->starting_arg_file = true;
- code = run_string(minst, line, options);
+ code = run_string(minst, line, options, user_errors, pexit_code, perror_object);
minst->i_ctx_p->starting_arg_file = false;
gs_free_object(minst->heap, line, "runarg");
return code;
}
+int
+gs_main_run_file2(gs_main_instance *minst,
+ const char *filename,
+ int user_errors,
+ int *pexit_code,
+ ref *perror_object)
+{
+ return runarg(minst, "", filename, ".runfile", runFlush, user_errors, pexit_code, perror_object);
+}
static int
-run_string(gs_main_instance * minst, const char *str, int options)
+run_string(gs_main_instance *minst,
+ const char *str,
+ int options,
+ int user_errors,
+ int *pexit_code,
+ ref *perror_object)
{
int exit_code;
ref error_object;
- int code = gs_main_run_string(minst, str, minst->user_errors,
- &exit_code, &error_object);
+ int code;
+
+ if (pexit_code == NULL)
+ pexit_code = &exit_code;
+ if (perror_object == NULL)
+ perror_object = &error_object;
+
+ code = gs_main_run_string(minst, str, user_errors,
+ pexit_code, perror_object);
if ((options & runFlush) || code != 0) {
zflush(minst->i_ctx_p); /* flush stdout */
zflushpage(minst->i_ctx_p); /* force display update */
}
- return run_finish(minst, code, exit_code, &error_object);
+ return run_finish(minst, code, *pexit_code, perror_object);
}
static int
run_finish(gs_main_instance *minst, int code, int exit_code,
@@ -1049,9 +1085,12 @@ run_finish(gs_main_instance *minst, int code, int exit_code,
case 0:
break;
case gs_error_Fatal:
- emprintf1(minst->heap,
- "Unrecoverable error, exit code %d\n",
- exit_code);
+ if (exit_code == gs_error_InterpreterExit)
+ code = exit_code;
+ else
+ emprintf1(minst->heap,
+ "Unrecoverable error, exit code %d\n",
+ exit_code);
break;
default:
gs_main_dump_stack(minst, code, perror_object);
@@ -1072,28 +1111,29 @@ static int
try_stdout_redirect(gs_main_instance * minst,
const char *command, const char *filename)
{
+ gs_lib_ctx_core_t *core = minst->heap->gs_lib_ctx->core;
if (strcmp(command, "stdout") == 0) {
- minst->heap->gs_lib_ctx->stdout_to_stderr = 0;
- minst->heap->gs_lib_ctx->stdout_is_redirected = 0;
+ core->stdout_to_stderr = 0;
+ core->stdout_is_redirected = 0;
/* If stdout already being redirected and it is not stdout
* or stderr, close it
*/
- if (minst->heap->gs_lib_ctx->fstdout2
- && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstdout)
- && (minst->heap->gs_lib_ctx->fstdout2 != minst->heap->gs_lib_ctx->fstderr)) {
- fclose(minst->heap->gs_lib_ctx->fstdout2);
- minst->heap->gs_lib_ctx->fstdout2 = (FILE *)NULL;
+ if (core->fstdout2
+ && (core->fstdout2 != core->fstdout)
+ && (core->fstdout2 != core->fstderr)) {
+ fclose(core->fstdout2);
+ core->fstdout2 = (FILE *)NULL;
}
/* If stdout is being redirected, set minst->fstdout2 */
if ( (filename != 0) && strlen(filename) &&
strcmp(filename, "-") && strcmp(filename, "%stdout") ) {
if (strcmp(filename, "%stderr") == 0) {
- minst->heap->gs_lib_ctx->stdout_to_stderr = 1;
+ core->stdout_to_stderr = 1;
}
- else if ((minst->heap->gs_lib_ctx->fstdout2 =
+ else if ((core->fstdout2 =
gp_fopen(filename, "w")) == (FILE *)NULL)
return_error(gs_error_invalidfileaccess);
- minst->heap->gs_lib_ctx->stdout_is_redirected = 1;
+ core->stdout_is_redirected = 1;
}
return 0;
}
diff --git a/psi/imainarg.h b/psi/imainarg.h
index 86a21ce28..7b6d278a1 100644
--- a/psi/imainarg.h
+++ b/psi/imainarg.h
@@ -35,6 +35,13 @@ typedef struct gs_main_instance_s gs_main_instance;
int gs_main_init_with_args(gs_main_instance * minst, int argc, char *argv[]);
/*
+ * Split init functions; gs_main_init_with_args01 and 2 together do
+ * the same as gs_main_init_with_args, but allow for additional
+ * options to be processed in between. */
+int gs_main_init_with_args01(gs_main_instance * minst, int argc, char *argv[]);
+int gs_main_init_with_args2(gs_main_instance * minst);
+
+/*
* Run the 'start' procedure (after processing the command line).
*/
int gs_main_run_start(gs_main_instance * minst);
diff --git a/psi/imemory.h b/psi/imemory.h
index 7d1ce1217..e1a5b676d 100644
--- a/psi/imemory.h
+++ b/psi/imemory.h
@@ -60,7 +60,7 @@ int gs_alloc_string_ref(gs_ref_memory_t * mem, ref * psref,
/* Register a ref root. This just calls gs_register_root. */
/* Note that ref roots are a little peculiar: they assume that */
/* the ref * that they point to points to a *statically* allocated ref. */
-int gs_register_ref_root(gs_memory_t *mem, gs_gc_root_t *root,
+int gs_register_ref_root(gs_memory_t *mem, gs_gc_root_t **root,
void **pp, client_name_t cname);
/*
diff --git a/psi/iminst.h b/psi/iminst.h
index e3c49687f..6a68e75ec 100644
--- a/psi/iminst.h
+++ b/psi/iminst.h
@@ -25,6 +25,11 @@
typedef struct gs_main_instance_s gs_main_instance;
#endif
+#ifndef display_callback_DEFINED
+# define display_callback_DEFINED
+typedef struct display_callback_s display_callback;
+#endif
+
/*
* Define the structure of a search path. Currently there is only one,
* but there might be more someday.
diff --git a/psi/int.mak b/psi/int.mak
index 88ce38ad1..836eb165c 100644
--- a/psi/int.mak
+++ b/psi/int.mak
@@ -535,7 +535,8 @@ $(PSOBJ)zpath.$(OBJ) : $(PSSRC)zpath.c $(OP) $(math__h)\
# Define the base PostScript language interpreter.
# This is the subset of PostScript Level 1 required by our PDF reader.
-INT1=$(PSOBJ)iapi.$(OBJ) $(PSOBJ)icontext.$(OBJ) $(PSOBJ)idebug.$(OBJ)
+INTAPI=$(PSOBJ)iapi.$(OBJ)
+INT1=$(PSOBJ)psapi.$(OBJ) $(PSOBJ)icontext.$(OBJ) $(PSOBJ)idebug.$(OBJ)
INT2=$(PSOBJ)idict.$(OBJ) $(PSOBJ)idparam.$(OBJ) $(PSOBJ)idstack.$(OBJ)
INT3=$(PSOBJ)iinit.$(OBJ) $(PSOBJ)interp.$(OBJ)
INT4=$(PSOBJ)iparam.$(OBJ) $(PSOBJ)ireclaim.$(OBJ) $(PSOBJ)iplugin.$(OBJ)
@@ -620,6 +621,12 @@ $(PSD)psbase.dev : $(ECHOGS_XE) $(INT_OBJS)\
$(ADDMOD) $(PSD)psbase -include $(GLD)fapi_ps
$(ADDMOD) $(PSD)psbase -replace $(GLD)gsiodevs
+$(PSD)iapi.dev : $(ECHOGS_XE) $(INT_OBJS)\
+ $(PSD)isupport.dev $(PSD)nobtoken.dev $(PSD)nousparm.dev\
+ $(GLD)rld.dev $(GLD)rle.dev $(GLD)sfile.dev $(PSD)dscparse.dev \
+ $(PSD)fapi_ps.dev $(INTAPI) $(INT_MAK) $(MAKEDIRS)
+ $(SETMOD) $(PSD)iapi $(INTAPI)
+
# -------------------------- Feature definitions -------------------------- #
# ---------------- Full Level 1 interpreter ---------------- #
@@ -1919,6 +1926,12 @@ $(PSOBJ)iapi.$(OBJ) : $(PSSRC)iapi.c $(AK)\
$(INT_MAK) $(MAKEDIRS)
$(PSCC) $(PSO_)iapi.$(OBJ) $(C_) $(PSSRC)iapi.c
+$(PSOBJ)psapi.$(OBJ) : $(PSSRC)psapi.c $(AK)\
+ $(string__h) $(ierrors_h) $(gscdefs_h) $(gstypes_h) $(iapi_h)\
+ $(iref_h) $(imain_h) $(imainarg_h) $(iminst_h) $(gslibctx_h)\
+ $(INT_MAK) $(MAKEDIRS)
+ $(PSCC) $(PSO_)psapi.$(OBJ) $(C_) $(PSSRC)psapi.c
+
$(PSOBJ)icontext.$(OBJ) : $(PSSRC)icontext.c $(GH)\
$(gsstruct_h) $(gxalloc_h)\
$(dstack_h) $(ierrors_h) $(estack_h) $(files_h)\
@@ -1953,7 +1966,7 @@ $(PSOBJ)imain.$(OBJ) : $(PSSRC)imain.c $(GH) $(memory__h) $(string__h)\
$(gp_h) $(gscdefs_h) $(gslib_h) $(gsmatrix_h) $(gsutil_h)\
$(gspaint_h) $(gxclpage_h) $(gxalloc_h) $(gxdevice_h) $(gzstate_h)\
$(dstack_h) $(ierrors_h) $(estack_h) $(files_h)\
- $(ialloc_h) $(iconf_h) $(idebug_h) $(idict_h) $(idisp_h) $(iinit_h)\
+ $(ialloc_h) $(iconf_h) $(idebug_h) $(iddict_h) $(idisp_h) $(iinit_h)\
$(iname_h) $(interp_h) $(iplugin_h) $(isave_h) $(iscan_h) $(ivmspace_h)\
$(iinit_h) $(main_h) $(oper_h) $(ostack_h)\
$(sfilter_h) $(store_h) $(stream_h) $(strimpl_h) $(zfile_h)\
diff --git a/psi/interp.c b/psi/interp.c
index 6dc0ddae1..281a20d83 100644
--- a/psi/interp.c
+++ b/psi/interp.c
@@ -136,6 +136,7 @@ struct stats_interp_s {
static int estack_underflow(i_ctx_t *);
static int interp(i_ctx_t **, const ref *, ref *);
static int interp_exit(i_ctx_t *);
+static int zforceinterp_exit(i_ctx_t *i_ctx_p);
static void set_gc_signal(i_ctx_t *, int);
static int copy_stack(i_ctx_t *, const ref_stack_t *, int skip, ref *);
static int oparray_pop(i_ctx_t *);
@@ -146,6 +147,7 @@ static int errorexec_pop(i_ctx_t *);
static int errorexec_cleanup(i_ctx_t *);
static int zsetstackprotect(i_ctx_t *);
static int zcurrentstackprotect(i_ctx_t *);
+static int zactonuel(i_ctx_t *);
/* Stack sizes */
@@ -279,8 +281,10 @@ const op_def interp2_op_defs[] = {
{"2.errorexec", zerrorexec},
{"0.finderrorobject", zfinderrorobject},
{"0%interp_exit", interp_exit},
+ {"0.forceinterp_exit", zforceinterp_exit},
{"0%oparray_pop", oparray_pop},
{"0%errorexec_pop", errorexec_pop},
+ {"0.actonuel", zactonuel},
op_def_end(0)
};
@@ -433,7 +437,7 @@ int
interp_reclaim(i_ctx_t **pi_ctx_p, int space)
{
i_ctx_t *i_ctx_p = *pi_ctx_p;
- gs_gc_root_t ctx_root;
+ gs_gc_root_t ctx_root, *r = &ctx_root;
int code;
#ifdef DEBUG
@@ -441,11 +445,11 @@ interp_reclaim(i_ctx_t **pi_ctx_p, int space)
return 0;
#endif
- gs_register_struct_root(imemory_system, &ctx_root,
+ gs_register_struct_root(imemory_system, &r,
(void **)pi_ctx_p, "interp_reclaim(pi_ctx_p)");
code = (*idmemory->reclaim)(idmemory, space);
i_ctx_p = *pi_ctx_p; /* may have moved */
- gs_unregister_root(imemory_system, &ctx_root, "interp_reclaim(pi_ctx_p)");
+ gs_unregister_root(imemory_system, r, "interp_reclaim(pi_ctx_p)");
return code;
}
@@ -465,10 +469,10 @@ gs_interpret(i_ctx_t **pi_ctx_p, ref * pref, int user_errors, int *pexit_code,
ref * perror_object)
{
i_ctx_t *i_ctx_p = *pi_ctx_p;
- gs_gc_root_t error_root;
+ gs_gc_root_t error_root, *r = &error_root;
int code;
- gs_register_ref_root(imemory_system, &error_root,
+ gs_register_ref_root(imemory_system, &r,
(void **)&perror_object, "gs_interpret");
code = gs_call_interp(pi_ctx_p, pref, user_errors, pexit_code,
perror_object);
@@ -499,12 +503,12 @@ again:
make_null(perror_object);
o_stack.requested = e_stack.requested = d_stack.requested = 0;
while (*gc_signal) { /* Some routine below triggered a GC. */
- gs_gc_root_t epref_root;
+ gs_gc_root_t epref_root, *r = &epref_root;
*gc_signal = 0;
/* Make sure that doref will get relocated properly if */
/* a garbage collection happens with epref == &doref. */
- gs_register_ref_root(imemory_system, &epref_root,
+ gs_register_ref_root(imemory_system, &r,
(void **)&epref, "gs_call_interp(epref)");
code = interp_reclaim(pi_ctx_p, -1);
i_ctx_p = *pi_ctx_p;
@@ -727,6 +731,38 @@ interp_exit(i_ctx_t *i_ctx_p)
return gs_error_InterpreterExit;
}
+/* Only used (currently) with language switching:
+ * allows the PS interpreter to co-exist with the
+ * PJL interpreter.
+ */
+static int
+zforceinterp_exit(i_ctx_t *i_ctx_p)
+{
+ os_ptr op = osp;
+ stream *s;
+
+ check_file(s, op);
+ i_ctx_p->uel_position = stell(s)-1;
+ /* resetfile */
+ if (file_is_valid(s, op))
+ sreset(s);
+
+ if (!gs_lib_ctx_get_act_on_uel((gs_memory_t *)(i_ctx_p->memory.current)))
+ return 0;
+
+ gs_interp_reset(i_ctx_p);
+ /* gs_interp_reset() actually leaves the op stack one entry below
+ * the bottom of the stack, and that can cause problems depending
+ * on the interpreter state at the end of the job.
+ * So push a null object, and the return code before continuing.
+ */
+ push(2);
+ op = osp;
+ make_null(op - 1);
+ make_int(op, gs_error_InterpreterExit);
+ return_error(gs_error_Quit);
+}
+
/* Set the GC signal for all VMs. */
static void
set_gc_signal(i_ctx_t *i_ctx_p, int value)
@@ -2017,3 +2053,13 @@ zcurrentstackprotect(i_ctx_t *i_ctx_p)
make_bool(op, ep->value.opproc == oparray_cleanup);
return 0;
}
+
+static int
+zactonuel(i_ctx_t *i_ctx_p)
+{
+ os_ptr op = osp;
+
+ push(1);
+ make_bool(op, !!gs_lib_ctx_get_act_on_uel((gs_memory_t *)(i_ctx_p->memory.current)));
+ return 0;
+}
diff --git a/psi/ireclaim.c b/psi/ireclaim.c
index 8c1562d94..653ab5f85 100644
--- a/psi/ireclaim.c
+++ b/psi/ireclaim.c
@@ -156,12 +156,12 @@ gs_vmreclaim(gs_dual_memory_t *dmem, bool global)
{
void *ctxp = i_ctx_p;
- gs_gc_root_t context_root;
+ gs_gc_root_t context_root, *r = &context_root;
- gs_register_struct_root((gs_memory_t *)lmem, &context_root,
+ gs_register_struct_root((gs_memory_t *)lmem, &r,
&ctxp, "i_ctx_p root");
GS_RECLAIM(&dmem->spaces, global);
- gs_unregister_root((gs_memory_t *)lmem, &context_root, "i_ctx_p root");
+ gs_unregister_root((gs_memory_t *)lmem, r, "i_ctx_p root");
i_ctx_p = ctxp;
dmem = &i_ctx_p->memory;
}
diff --git a/psi/msvc.mak b/psi/msvc.mak
index 6a2ed1cdc..125b92a28 100644
--- a/psi/msvc.mak
+++ b/psi/msvc.mak
@@ -267,9 +267,9 @@ PCL_TARGET=gpcl6
XPS_TARGET=gxps
!endif
-# !if $(BUILD_GPDL)
-# GPDL_TARGET=gpdl
-# !endif
+!if $(BUILD_GPDL)
+GPDL_TARGET=gpdl
+!endif
PCL_XPS_TARGETS=$(PCL_TARGET) $(XPS_TARGET)
@@ -1457,7 +1457,7 @@ DEVICE_DEVS8=$(DD)pcxmono.dev $(DD)pcxgray.dev $(DD)pcx16.dev $(DD)pcx256.dev $(
DEVICE_DEVS9=$(DD)pbm.dev $(DD)pbmraw.dev $(DD)pgm.dev $(DD)pgmraw.dev $(DD)pgnm.dev $(DD)pgnmraw.dev $(DD)pkmraw.dev
DEVICE_DEVS10=$(DD)tiffcrle.dev $(DD)tiffg3.dev $(DD)tiffg32d.dev $(DD)tiffg4.dev $(DD)tifflzw.dev $(DD)tiffpack.dev
DEVICE_DEVS11=$(DD)bmpmono.dev $(DD)bmpgray.dev $(DD)bmp16.dev $(DD)bmp256.dev $(DD)bmp16m.dev $(DD)tiff12nc.dev $(DD)tiff24nc.dev $(DD)tiff48nc.dev $(DD)tiffgray.dev $(DD)tiff32nc.dev $(DD)tiff64nc.dev $(DD)tiffsep.dev $(DD)tiffsep1.dev $(DD)tiffscaled.dev $(DD)tiffscaled8.dev $(DD)tiffscaled24.dev $(DD)tiffscaled32.dev $(DD)tiffscaled4.dev
-DEVICE_DEVS12=$(DD)bit.dev $(DD)bitrgb.dev $(DD)bitcmyk.dev $(DD)bitrgbtags.dev
+DEVICE_DEVS12=$(DD)bit.dev $(DD)bitrgb.dev $(DD)bitcmyk.dev $(DD)bitrgbtags.dev $(DD)chameleon.dev
DEVICE_DEVS13=$(DD)pngmono.dev $(DD)pngmonod.dev $(DD)pnggray.dev $(DD)png16.dev $(DD)png256.dev $(DD)png16m.dev $(DD)pngalpha.dev $(DD)fpng.dev $(DD)psdcmykog.dev
DEVICE_DEVS14=$(DD)jpeg.dev $(DD)jpeggray.dev $(DD)jpegcmyk.dev $(DD)pdfimage8.dev $(DD)pdfimage24.dev $(DD)pdfimage32.dev $(DD)PCLm.dev
DEVICE_DEVS15=$(DD)pdfwrite.dev $(DD)ps2write.dev $(DD)eps2write.dev $(DD)txtwrite.dev $(DD)pxlmono.dev $(DD)pxlcolor.dev $(DD)xpswrite.dev $(DD)inkcov.dev $(DD)ink_cov.dev
diff --git a/psi/opextern.h b/psi/opextern.h
index 543b1b3d8..f1c5b45df 100644
--- a/psi/opextern.h
+++ b/psi/opextern.h
@@ -148,6 +148,8 @@ int zcurrentdevice(i_ctx_t *);
int ztoken(i_ctx_t *);
int ztokenexec(i_ctx_t *);
int zwrite(i_ctx_t *);
+int zcurrentoutputdevice(i_ctx_t *i_ctx_p);
+int zsetdevice_no_safer(i_ctx_t *i_ctx_p, gx_device *new_dev);
int zspec_op(i_ctx_t *i_ctx_p);
#endif /* opextern_INCLUDED */
diff --git a/psi/psapi.c b/psi/psapi.c
new file mode 100644
index 000000000..90613e6a5
--- /dev/null
+++ b/psi/psapi.c
@@ -0,0 +1,512 @@
+/* Copyright (C) 2001-2018 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+
+/* Private internal API to Ghostscript interpreter */
+
+#include "string_.h"
+#include "ierrors.h"
+#include "gscdefs.h"
+#include "gstypes.h"
+#include "gdebug.h"
+#include "psapi.h" /* Public API */
+#include "iref.h"
+#include "iminst.h"
+#include "imain.h"
+#include "imainarg.h"
+#include "gsmemory.h"
+#include "gsmalloc.h"
+#include "gslibctx.h"
+#include "gp.h"
+#include "gsargs.h"
+#include "ialloc.h"
+#include "icstate.h"
+#include "store.h"
+#include "iname.h"
+#include "interp.h"
+
+#ifndef GS_THREADSAFE
+/* Number of threads to allow per process. Unless GS_THREADSAFE is defined
+ * more than 1 is guaranteed to fail.
+ */
+static int gsapi_instance_counter = 0;
+static const int gsapi_instance_max = 1;
+#endif
+
+
+#ifdef METRO
+static int GSDLLCALL metro_stdin(void *v, char *buf, int len)
+{
+ return 0;
+}
+
+static int GSDLLCALL metro_stdout(void *v, const char *str, int len)
+{
+#ifdef DEBUG
+ OutputDebugStringWRT(str, len);
+#endif
+ return len;
+}
+
+static int GSDLLCALL metro_stderr(void *v, const char *str, int len)
+{
+ return metro_stdout(v, str, len);
+}
+#endif
+
+/* Create a new instance of Ghostscript.
+ * First instance per process call with *pinstance == NULL
+ * next instance in a proces call with *pinstance == copy of valid_instance pointer
+ * *pinstance is set to a new instance pointer.
+ */
+int
+psapi_new_instance(gs_lib_ctx_t **pinstance,
+ void *caller_handle)
+{
+ gs_memory_t *mem = NULL;
+ gs_main_instance *minst = NULL;
+
+ if (pinstance == NULL)
+ return gs_error_Fatal;
+
+#ifndef GS_THREADSAFE
+ /* limited to 1 instance, till it works :) */
+ if ( gsapi_instance_counter >= gsapi_instance_max )
+ return gs_error_Fatal;
+ ++gsapi_instance_counter;
+#endif
+
+ mem = gs_malloc_init_with_context(*pinstance);
+ if (mem == NULL)
+ return gs_error_Fatal;
+ minst = gs_main_alloc_instance(mem);
+ if (minst == NULL) {
+ gs_malloc_release(mem);
+ return gs_error_Fatal;
+ }
+ mem->gs_lib_ctx->top_of_system = (void*) minst;
+ mem->gs_lib_ctx->core->caller_handle = caller_handle;
+ mem->gs_lib_ctx->core->custom_color_callback = NULL;
+#ifdef METRO
+ mem->gs_lib_ctx->core->stdin_fn = metro_stdin;
+ mem->gs_lib_ctx->core->stdout_fn = metro_stdout;
+ mem->gs_lib_ctx->core->stderr_fn = metro_stderr;
+#else
+ mem->gs_lib_ctx->core->stdin_fn = NULL;
+ mem->gs_lib_ctx->core->stdout_fn = NULL;
+ mem->gs_lib_ctx->core->stderr_fn = NULL;
+#endif
+ mem->gs_lib_ctx->core->poll_fn = NULL;
+
+ *pinstance = mem->gs_lib_ctx;
+ return psapi_set_arg_encoding(*pinstance, PS_ARG_ENCODING_LOCAL);
+}
+
+/* Set an instance of Ghostscript to respond to UEL (universal
+ * exit language) strings in the input. */
+void
+psapi_act_on_uel(gs_lib_ctx_t *ctx)
+{
+ ctx->core->act_on_uel = 1;
+}
+
+/* Destroy an instance of Ghostscript */
+/* We do not support multiple instances, so make sure
+ * we use the default instance only once.
+ */
+void
+psapi_delete_instance(gs_lib_ctx_t *ctx)
+{
+ gs_memory_t *mem;
+ gs_main_instance *minst;
+
+ if (ctx == NULL)
+ return;
+
+ mem = (gs_memory_t *)(ctx->memory);
+ minst = get_minst_from_memory(ctx->memory);
+
+ ctx->core->caller_handle = NULL;
+ ctx->core->stdin_fn = NULL;
+ ctx->core->stdout_fn = NULL;
+ ctx->core->stderr_fn = NULL;
+ ctx->core->poll_fn = NULL;
+ minst->display = NULL;
+
+ gs_free_object(mem, minst, "init_main_instance");
+
+ /* Release the memory (frees up everything) */
+ gs_malloc_release(mem);
+
+#ifndef GS_THREADSAFE
+ --gsapi_instance_counter;
+#endif
+}
+
+static int utf16le_get_codepoint(FILE *file, const char **astr)
+{
+ int c;
+ int rune;
+ int trail;
+
+ /* This code spots the BOM for 16bit LE and ignores it. Strictly speaking
+ * this may be wrong, as we are only supposed to ignore it at the beginning
+ * of the string, but if anyone is stupid enough to use ZWNBSP (zero width
+ * non breaking space) in the middle of their strings, then they deserve
+ * what they get. */
+ /* We spot the BOM for 16bit BE and treat that as EOF. We'd rather give
+ * up on dealing with a broken file than try to run something we know to
+ * be wrong. */
+
+ do {
+ if (file) {
+ rune = fgetc(file);
+ if (rune == EOF)
+ return EOF;
+ c = fgetc(file);
+ if (c == EOF)
+ return EOF;
+ rune += c<<8;
+ } else {
+ rune = (*astr)[0] | ((*astr)[1]<<8);
+ if (rune != 0)
+ (*astr) += 2;
+ else
+ return EOF;
+ }
+ if (rune == 0xFEFF) /* BOM - ignore it */
+ continue;
+ if (rune == 0xFFFE) /* BOM for BE - hopelessly broken */
+ return EOF;
+ if (rune < 0xD800 || rune >= 0xE000)
+ return rune;
+ if (rune >= 0xDC00) /* Found a trailing surrogate pair. Skip it */
+ continue;
+lead: /* We've just read a leading surrogate */
+ rune -= 0xD800;
+ rune <<= 10;
+ if (file) {
+ trail = fgetc(file);
+ if (trail == EOF)
+ return EOF;
+ c = fgetc(file);
+ if (c == EOF)
+ return EOF;
+ trail += c<<8;
+ } else {
+ trail = (*astr)[0] | ((*astr)[1]<<8);
+ if (trail != 0)
+ (*astr) += 2;
+ else
+ return EOF;
+ }
+ if (trail < 0xd800 || trail >= 0xE000) {
+ if (rune == 0xFEFF) /* BOM - ignore it. */
+ continue;
+ if (rune == 0xFFFE) /* BOM for BE - hopelessly broken. */
+ return EOF;
+ /* No trail surrogate was found, so skip the lead surrogate and
+ * return the rune we landed on. */
+ return trail;
+ }
+ if (trail < 0xdc00) {
+ /* We found another leading surrogate. */
+ rune = trail;
+ goto lead;
+ }
+ break;
+ } while (1);
+
+ return rune + (trail-0xDC00) + 0x10000;
+}
+
+/* Initialise the interpreter */
+int
+psapi_set_arg_encoding(gs_lib_ctx_t *ctx, int encoding)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ if (encoding == PS_ARG_ENCODING_LOCAL) {
+#if defined(__WIN32__) && !defined(METRO)
+ /* For windows, we need to set it up so that we convert from 'local'
+ * format (in this case whatever codepage is set) to utf8 format. At
+ * the moment, all the other OS we care about provide utf8 anyway.
+ */
+ gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), gp_local_arg_encoding_get_codepoint);
+#else
+ gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
+#endif /* WIN32 */
+ return 0;
+ }
+ if (encoding == PS_ARG_ENCODING_UTF8) {
+ gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), NULL);
+ return 0;
+ }
+ if (encoding == PS_ARG_ENCODING_UTF16LE) {
+ gs_main_inst_arg_decode(get_minst_from_memory(ctx->memory), utf16le_get_codepoint);
+ return 0;
+ }
+ return gs_error_Fatal;
+}
+
+int
+psapi_init_with_args(gs_lib_ctx_t *ctx, int argc, char **argv)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_init_with_args(get_minst_from_memory(ctx->memory), argc, argv);
+}
+
+int
+psapi_init_with_args01(gs_lib_ctx_t *ctx, int argc, char **argv)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_init_with_args01(get_minst_from_memory(ctx->memory), argc, argv);
+}
+
+int
+psapi_init_with_args2(gs_lib_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_init_with_args2(get_minst_from_memory(ctx->memory));
+}
+
+int
+psapi_set_param(gs_lib_ctx_t *ctx,
+ psapi_sptype type,
+ const char *param,
+ const void *val)
+{
+ gs_main_instance *minst = get_minst_from_memory(ctx->memory);
+ ref value;
+ int code = 0;
+ i_ctx_t *i_ctx_p = minst->i_ctx_p;
+ uint space = icurrent_space;
+
+ ialloc_set_space(idmemory, avm_system);
+ switch (type) {
+ case psapi_spt_null:
+ make_null(&value);
+ break;
+ case psapi_spt_bool:
+ if (val)
+ make_true(&value);
+ else
+ make_false(&value);
+ break;
+ case psapi_spt_int:
+ make_int(&value, *(int *)val);
+ break;
+ case psapi_spt_float:
+ make_real(&value, *(float *)val);
+ break;
+ case psapi_spt_string:
+ if (val == NULL)
+ make_empty_string(&value, a_readonly);
+ else {
+ size_t len = strlen(val);
+ byte *body = ialloc_string(len, "-s");
+
+ if (body == NULL)
+ return gs_error_Fatal;
+ memcpy(body, val, len);
+ make_const_string(&value, a_readonly | avm_system, len, body);
+ }
+ break;
+ case psapi_spt_name:
+ code = name_ref(ctx->memory, val, strlen(val), &value, 1);
+ break;
+ default:
+ break;
+ }
+ ialloc_set_space(idmemory, space);
+ /* Enter the name in systemdict. */
+ i_initial_enter_name_copy(minst->i_ctx_p, param, &value);
+
+ return code;
+}
+
+/* The gsapi_run_* functions are like gs_main_run_* except
+ * that the error_object is omitted.
+ * An error object in minst is used instead.
+ */
+
+/* Setup up a suspendable run_string */
+int
+psapi_run_string_begin(gs_lib_ctx_t *ctx,
+ int user_errors,
+ int *pexit_code)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_run_string_begin(get_minst_from_memory(ctx->memory),
+ user_errors, pexit_code,
+ &(get_minst_from_memory(ctx->memory)->error_object));
+}
+
+int
+psapi_run_string_continue(gs_lib_ctx_t *ctx,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_run_string_continue(get_minst_from_memory(ctx->memory),
+ str, length, user_errors, pexit_code,
+ &(get_minst_from_memory(ctx->memory)->error_object));
+}
+
+uint
+psapi_get_uel_offset(gs_lib_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return 0;
+
+ return gs_main_get_uel_offset(get_minst_from_memory(ctx->memory));
+}
+
+int
+psapi_run_string_end(gs_lib_ctx_t *ctx,
+ int user_errors,
+ int *pexit_code)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_run_string_end(get_minst_from_memory(ctx->memory),
+ user_errors, pexit_code,
+ &(get_minst_from_memory(ctx->memory)->error_object));
+}
+
+int
+psapi_run_string_with_length(gs_lib_ctx_t *ctx,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_run_string_with_length(get_minst_from_memory(ctx->memory),
+ str, length, user_errors, pexit_code,
+ &(get_minst_from_memory(ctx->memory)->error_object));
+}
+
+int
+psapi_run_string(gs_lib_ctx_t *ctx,
+ const char *str,
+ int user_errors,
+ int *pexit_code)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ return gs_main_run_string(get_minst_from_memory(ctx->memory),
+ str, user_errors, pexit_code,
+ &(get_minst_from_memory(ctx->memory)->error_object));
+}
+
+int
+psapi_run_file(gs_lib_ctx_t *ctx,
+ const char *file_name,
+ int user_errors,
+ int *pexit_code)
+{
+ char *d, *temp;
+ const char *c = file_name;
+ char dummy[6];
+ int rune, code, len;
+ gs_main_instance *minst;
+ if (ctx == NULL)
+ return gs_error_Fatal;
+ minst = get_minst_from_memory(ctx->memory);
+
+ /* Convert the file_name to utf8 */
+ if (minst->get_codepoint) {
+ len = 1;
+ while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
+ len += codepoint_to_utf8(dummy, rune);
+ temp = (char *)gs_alloc_bytes_immovable(ctx->memory, len, "gsapi_run_file");
+ if (temp == NULL)
+ return 0;
+ c = file_name;
+ d = temp;
+ while ((rune = minst->get_codepoint(NULL, &c)) >= 0)
+ d += codepoint_to_utf8(d, rune);
+ *d = 0;
+ }
+ else {
+ temp = (char *)file_name;
+ }
+ code = gs_main_run_file2(minst, temp, user_errors, pexit_code,
+ &(minst->error_object));
+ if (temp != file_name)
+ gs_free_object(ctx->memory, temp, "gsapi_run_file");
+ return code;
+}
+
+/* Retrieve the memory allocator for the interpreter instance */
+gs_memory_t *
+psapi_get_device_memory(gs_lib_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return NULL;
+ return gs_main_get_device_memory(get_minst_from_memory(ctx->memory));
+}
+
+/* Retrieve the memory allocator for the interpreter instance */
+int
+psapi_set_device(gs_lib_ctx_t *ctx, gx_device *pdev)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+ return gs_main_set_device(get_minst_from_memory(ctx->memory), pdev);
+}
+
+/* Exit the interpreter */
+int
+psapi_exit(gs_lib_ctx_t *ctx)
+{
+ if (ctx == NULL)
+ return gs_error_Fatal;
+
+ gs_to_exit(ctx->memory, 0);
+ return 0;
+}
+
+int
+psapi_force_geometry(gs_lib_ctx_t *ctx, const float *resolutions, const long *dimensions)
+{
+ int code;
+
+ if (ctx == NULL)
+ return gs_error_Fatal;
+ code = gs_main_force_resolutions(get_minst_from_memory(ctx->memory), resolutions);
+ if (code < 0)
+ return code;
+ return gs_main_force_dimensions(get_minst_from_memory(ctx->memory), dimensions);
+}
diff --git a/psi/psapi.h b/psi/psapi.h
new file mode 100644
index 000000000..d76fc33b4
--- /dev/null
+++ b/psi/psapi.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 2001-2018 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
+ CA 94945, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+
+/*
+ * Internal API for Ghostscript interpreter.
+ */
+
+#ifndef psapi_INCLUDED
+# define psapi_INCLUDED
+
+#include "gsmemory.h"
+#include "gsdevice.h"
+
+int
+psapi_set_arg_encoding(gs_lib_ctx_t *instance,
+ int encoding);
+
+/* Must match iapi.h and plapi.h */
+enum {
+ PS_ARG_ENCODING_LOCAL = 0,
+ PS_ARG_ENCODING_UTF8 = 1,
+ PS_ARG_ENCODING_UTF16LE = 2
+};
+
+int
+psapi_new_instance(gs_lib_ctx_t **pinstance,
+ void *caller_handle);
+
+void
+psapi_delete_instance(gs_lib_ctx_t *instance);
+
+void
+psapi_act_on_uel(gs_lib_ctx_t *instance);
+
+int
+psapi_init_with_args(gs_lib_ctx_t *instance,
+ int argc,
+ char **argv);
+int
+psapi_init_with_args01(gs_lib_ctx_t *instance,
+ int argc,
+ char **argv);
+int
+psapi_init_with_args2(gs_lib_ctx_t *instance);
+
+typedef enum {
+ psapi_spt_invalid = -1,
+ psapi_spt_null = 0, /* void * is NULL */
+ psapi_spt_bool = 1, /* void * is NULL (false) or non-NULL (true) */
+ psapi_spt_int = 2, /* void * is a pointer to an int */
+ psapi_spt_float = 3, /* void * is a float * */
+ psapi_spt_name = 4, /* void * is a char * */
+ psapi_spt_string = 5 /* void * is a char * */
+} psapi_sptype;
+int
+psapi_set_param(gs_lib_ctx_t *ctx,
+ psapi_sptype type,
+ const char *param,
+ const void *val);
+
+int
+psapi_run_string_begin(gs_lib_ctx_t *instance,
+ int user_errors,
+ int *pexit_code);
+
+int
+psapi_run_string_continue(gs_lib_ctx_t *instance,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code);
+
+unsigned int
+psapi_get_uel_offset(gs_lib_ctx_t *instance);
+
+int
+psapi_run_string_end(gs_lib_ctx_t *instance,
+ int user_errors,
+ int *pexit_code);
+
+int
+psapi_run_string_with_length(gs_lib_ctx_t *instance,
+ const char *str,
+ unsigned int length,
+ int user_errors,
+ int *pexit_code);
+
+int
+psapi_run_string(gs_lib_ctx_t *ctx,
+ const char *str,
+ int user_errors,
+ int *pexit_code);
+
+int
+psapi_run_file(gs_lib_ctx_t *instance,
+ const char *file_name,
+ int user_errors,
+ int *pexit_code);
+
+gs_memory_t *
+psapi_get_device_memory(gs_lib_ctx_t *instance);
+
+int
+psapi_set_device(gs_lib_ctx_t *instance,
+ gx_device *pdev);
+
+int
+psapi_exit(gs_lib_ctx_t *instance);
+
+int
+psapi_force_geometry(gs_lib_ctx_t *ctx, const float *resolutions, const long *dimensions);
+
+#endif /* psapi_INCLUDED */
diff --git a/psi/zdevice.c b/psi/zdevice.c
index e0ce71892..65ae0811a 100644
--- a/psi/zdevice.c
+++ b/psi/zdevice.c
@@ -86,7 +86,7 @@ zcurrentdevice(i_ctx_t *i_ctx_p)
the *device* object, rather than the dictionary describing
the device and device state.
*/
-static int
+int
zcurrentoutputdevice(i_ctx_t *i_ctx_p)
{
os_ptr op = osp;
@@ -503,6 +503,26 @@ zputdeviceparams(i_ctx_t *i_ctx_p)
return 0;
}
+int
+zsetdevice_no_safer(i_ctx_t *i_ctx_p, gx_device *new_dev)
+{
+ gx_device *dev = gs_currentdevice(igs);
+ int code;
+
+ dev->ShowpageCount = 0;
+
+ if (new_dev == NULL)
+ return gs_note_error(gs_error_undefined);
+
+ code = gs_setdevice_no_erase(igs, new_dev);
+ if (code < 0)
+ return code;
+
+ invalidate_stack_devices(i_ctx_p);
+ clear_pagedevice(istate);
+ return code;
+}
+
/* <device> .setdevice <eraseflag> */
/* Note that .setdevice clears the current pagedevice. */
int
@@ -538,15 +558,8 @@ zsetdevice(i_ctx_t *i_ctx_p)
if(ndev != odev) /* don't allow a different device */
return_error(gs_error_invalidaccess);
}
- dev->ShowpageCount = 0;
-
- code = gs_setdevice_no_erase(igs, op->value.pdevice);
- if (code < 0)
- return code;
-
+ code = zsetdevice_no_safer(i_ctx_p, op->value.pdevice);
make_bool(op, code != 0); /* erase page if 1 */
- invalidate_stack_devices(i_ctx_p);
- clear_pagedevice(istate);
return code;
}
diff --git a/psi/zfont.c b/psi/zfont.c
index f6c5ae113..0c6342ea1 100644
--- a/psi/zfont.c
+++ b/psi/zfont.c
@@ -67,7 +67,7 @@ zfont_init(i_ctx_t *i_ctx_p)
return gs_error_VMerror;
ifont_dir->ccache.mark_glyph = zfont_mark_glyph_name;
ifont_dir->global_glyph_code = zfont_global_glyph_code;
- return gs_register_struct_root(imemory, imemory->gs_lib_ctx->font_dir_root,
+ return gs_register_struct_root(imemory, &imemory->gs_lib_ctx->font_dir_root,
(void **)&ifont_dir, "ifont_dir");
}
diff --git a/psi/ziodevsc.c b/psi/ziodevsc.c
index 99d379a04..20b4151fb 100644
--- a/psi/ziodevsc.c
+++ b/psi/ziodevsc.c
@@ -77,14 +77,14 @@ const gx_io_device gs_iodev_stderr =
static int
stdin_init(gx_io_device * iodev, gs_memory_t * mem)
{
- mem->gs_lib_ctx->stdin_is_interactive = true;
+ mem->gs_lib_ctx->core->stdin_is_interactive = true;
return 0;
}
static void
stdin_finit(gx_io_device * iodev, gs_memory_t * mem)
{
- mem->gs_lib_ctx->stdin_is_interactive = false;
+ mem->gs_lib_ctx->core->stdin_is_interactive = false;
return;
}
@@ -97,19 +97,20 @@ s_stdin_read_process(stream_state * st, stream_cursor_read * ignore_pr,
int wcount = (int)(pw->limit - pw->ptr);
int count;
gs_memory_t *mem = st->memory;
+ gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
if (wcount <= 0)
return 0;
/* do the callout */
- if (mem->gs_lib_ctx->stdin_fn)
- count = (*mem->gs_lib_ctx->stdin_fn)
- (mem->gs_lib_ctx->caller_handle, (char *)pw->ptr + 1,
- mem->gs_lib_ctx->stdin_is_interactive ? 1 : wcount);
+ if (core->stdin_fn)
+ count = (*core->stdin_fn)
+ (core->caller_handle, (char *)pw->ptr + 1,
+ core->stdin_is_interactive ? 1 : wcount);
else
count = gp_stdin_read((char *)pw->ptr + 1, wcount,
- mem->gs_lib_ctx->stdin_is_interactive,
- mem->gs_lib_ctx->fstdin);
+ core->stdin_is_interactive,
+ core->fstdin);
pw->ptr += (count < 0) ? 0 : count;
return ((count < 0) ? ERRC : (count == 0) ? EOFC : count);
diff --git a/windows/ghostscript.vcproj b/windows/ghostscript.vcproj
index 15f00cb62..dfbcb55fb 100644
--- a/windows/ghostscript.vcproj
+++ b/windows/ghostscript.vcproj
@@ -2321,6 +2321,10 @@
RelativePath="..\base\gstext.c"
>
</File>
+ <File
+ RelativePath="..\base\gstiffio.c"
+ >
+ </File>
<File
RelativePath="..\base\gstrap.c"
>
@@ -5693,6 +5697,10 @@
RelativePath="..\devices\gdevcfax.c"
>
</File>
+ <File
+ RelativePath="..\devices\gdevchameleon.c"
+ >
+ </File>
<File
RelativePath="..\devices\gdevcif.c"
>
@@ -8027,6 +8035,14 @@
RelativePath="..\psi\iutil2.c"
>
</File>
+ <File
+ RelativePath="..\psi\psapi.c"
+ >
+ </File>
+ <File
+ RelativePath="..\psi\psapi.h"
+ >
+ </File>
<File
RelativePath="..\psi\sfilter1.c"
>
diff --git a/xps/xpstop.c b/xps/xpstop.c
index 7ca14e021..7c382d24c 100644
--- a/xps/xpstop.c
+++ b/xps/xpstop.c
@@ -59,8 +59,10 @@ static int
xps_detect_language(const char *s, int len)
{
if (len < 2)
- return 1;
- return memcmp(s, "PK", 2);
+ return 0;
+ if (memcmp(s, "PK", 2) == 0)
+ return 100;
+ return 0;
}
static const pl_interp_characteristics_t *
@@ -165,14 +167,33 @@ xps_imp_allocate_interp_instance(pl_interp_implementation_t *impl,
return 0;
}
+/* Prepare interp instance for the next "job" */
static int
-xps_imp_set_device(pl_interp_implementation_t *impl, gx_device *pdevice)
+xps_imp_init_job(pl_interp_implementation_t *impl,
+ gx_device *pdevice)
{
xps_interp_instance_t *instance = impl->interp_client_data;
xps_context_t *ctx = instance->ctx;
gs_c_param_list list;
int code;
+ if (gs_debug_c('|'))
+ xps_zip_trace = 1;
+ if (gs_debug_c('|'))
+ xps_doc_trace = 1;
+
+ ctx->font_table = xps_hash_new(ctx);
+ ctx->colorspace_table = xps_hash_new(ctx);
+
+ ctx->start_part = NULL;
+
+ ctx->use_transparency = 1;
+ if (getenv("XPS_DISABLE_TRANSPARENCY"))
+ ctx->use_transparency = 0;
+
+ ctx->opacity_only = 0;
+ ctx->fill_rule = 0;
+
code = gs_setdevice_no_erase(ctx->pgs, pdevice);
if (code < 0)
goto cleanup_setdevice;
@@ -241,6 +262,13 @@ xps_imp_process_file(pl_interp_implementation_t *impl, char *filename)
return code;
}
+/* Do any setup for parser per-cursor */
+static int /* ret 0 or +ve if ok, else -ve error code */
+xps_impl_process_begin(pl_interp_implementation_t * impl)
+{
+ return 0;
+}
+
/* Parse a cursor-full of data */
static int
xps_imp_process(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
@@ -273,6 +301,12 @@ xps_imp_process(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
return 0;
}
+static int /* ret 0 or +ve if ok, else -ve error code */
+xps_impl_process_end(pl_interp_implementation_t * impl)
+{
+ return 0;
+}
+
/* Skip to end of job.
* Return 1 if done, 0 ok but EOJ not found, else negative error code.
*/
@@ -320,33 +354,6 @@ xps_imp_report_errors(pl_interp_implementation_t *impl,
return 0;
}
-/* Prepare interp instance for the next "job" */
-static int
-xps_imp_init_job(pl_interp_implementation_t *impl)
-{
- xps_interp_instance_t *instance = impl->interp_client_data;
- xps_context_t *ctx = instance->ctx;
-
- if (gs_debug_c('|'))
- xps_zip_trace = 1;
- if (gs_debug_c('|'))
- xps_doc_trace = 1;
-
- ctx->font_table = xps_hash_new(ctx);
- ctx->colorspace_table = xps_hash_new(ctx);
-
- ctx->start_part = NULL;
-
- ctx->use_transparency = 1;
- if (getenv("XPS_DISABLE_TRANSPARENCY"))
- ctx->use_transparency = 0;
-
- ctx->opacity_only = 0;
- ctx->fill_rule = 0;
-
- return 0;
-}
-
static void xps_free_key_func(xps_context_t *ctx, void *ptr)
{
xps_free(ctx, ptr);
@@ -363,7 +370,10 @@ xps_imp_dnit_job(pl_interp_implementation_t *impl)
{
xps_interp_instance_t *instance = impl->interp_client_data;
xps_context_t *ctx = instance->ctx;
- int i;
+ int i, code;
+
+ /* return to original gstate */
+ code = gs_grestore_only(ctx->pgs); /* destroys gs_save stack */
if (gs_debug_c('|'))
xps_debug_fixdocseq(ctx);
@@ -379,18 +389,7 @@ xps_imp_dnit_job(pl_interp_implementation_t *impl)
xps_free_fixed_pages(ctx);
xps_free_fixed_documents(ctx);
- return 0;
-}
-
-/* Remove a device from an interperter instance */
-static int
-xps_imp_remove_device(pl_interp_implementation_t *impl)
-{
- xps_interp_instance_t *instance = impl->interp_client_data;
- xps_context_t *ctx = instance->ctx;
-
- /* return to original gstate */
- return gs_grestore_only(ctx->pgs); /* destroys gs_save stack */
+ return code;
}
/* Deallocate a interpreter instance */
@@ -402,8 +401,15 @@ xps_imp_deallocate_interp_instance(pl_interp_implementation_t *impl)
gs_memory_t *mem = ctx->memory;
/* language clients don't free the font cache machinery */
+ rc_decrement_cs(ctx->gray_lin, "xps_imp_deallocate_interp_instance");
+ rc_decrement_cs(ctx->gray, "xps_imp_deallocate_interp_instance");
+ rc_decrement_cs(ctx->cmyk, "xps_imp_deallocate_interp_instance");
+ rc_decrement_cs(ctx->srgb, "xps_imp_deallocate_interp_instance");
+ rc_decrement_cs(ctx->scrgb, "xps_imp_deallocate_interp_instance");
- // free gstate?
+ gs_gstate_free(ctx->pgs);
+
+ gs_free_object(mem, ctx->fontdir, "xps_imp_deallocate_interp_instance");
gs_free_object(mem, ctx, "xps_imp_deallocate_interp_instance");
gs_free_object(mem, instance, "xps_imp_deallocate_interp_instance");
@@ -415,15 +421,18 @@ pl_interp_implementation_t xps_implementation =
{
xps_imp_characteristics,
xps_imp_allocate_interp_instance,
- xps_imp_set_device,
+ NULL,
+ NULL,
+ NULL,
xps_imp_init_job,
xps_imp_process_file,
+ xps_impl_process_begin,
xps_imp_process,
+ xps_impl_process_end,
xps_imp_flush_to_eoj,
xps_imp_process_eof,
xps_imp_report_errors,
xps_imp_dnit_job,
- xps_imp_remove_device,
xps_imp_deallocate_interp_instance,
NULL,
};