diff options
Diffstat (limited to 'pxl/pxtop.c')
-rw-r--r-- | pxl/pxtop.c | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/pxl/pxtop.c b/pxl/pxtop.c new file mode 100644 index 000000000..85f15123a --- /dev/null +++ b/pxl/pxtop.c @@ -0,0 +1,687 @@ +/* Portions Copyright (C) 2001 artofcode LLC. + Portions Copyright (C) 1996, 2001 Artifex Software Inc. + Portions Copyright (C) 1988, 2000 Aladdin Enterprises. + This software is based in part on the work of the Independent JPEG Group. + All Rights Reserved. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ or + contact Artifex Software, Inc., 101 Lucas Valley Road #110, + San Rafael, CA 94903, (415)492-9861, for further information. */ +/*$Id$ */ + +/* pxtop.c */ +/* Top-level API implementation of PCL/XL */ + +#include "stdio_.h" +#include "string_.h" +#include "gdebug.h" +#include "gserrors.h" +#include "gstypes.h" +#include "gsmemory.h" +#include "gsnogc.h" +#include "gsstate.h" /* must precede gsdevice.h */ +#include "gsdevice.h" +#include "gsstruct.h" /* for gxalloc.h */ +#include "gspaint.h" +#include "gxalloc.h" +#include "gxstate.h" +#include "plparse.h" +#include "pxattr.h" /* for pxparse.h */ +#include "pxerrors.h" +#include "pxoper.h" +#include "pxstate.h" +#include "pxfont.h" +#include "pxvalue.h" /* for pxparse.h */ +#include "pxparse.h" +#include "pxptable.h" +#include "pxstate.h" +#include "pltop.h" + +/* Define the table of pointers to initialization data. */ + +typedef int (*px_init_proc) ( px_state_t * ); + +int pxfont_init(px_state_t *pxs ); +int pxerrors_init(px_state_t *pxs ); + +const px_init_proc px_init_table[] = { + &pxfont_init, + &pxerrors_init, + 0 +}; + +/* Imported operators */ +px_operator_proc(pxEndPage); +px_operator_proc(pxBeginSession); + +/* Forward decls */ +static int pxl_end_page_top(px_state_t *pxs, int num_copies, int flush); +static int px_top_init(px_parser_state_t *st, px_state_t *pxs, bool big_endian); + + +/* ------------ PCXL stream header processor ------- */ +/* State used to process an XL stream header */ +typedef struct px_stream_header_process_s { + enum {PSHPReady, PSHPSkipping, PSHPDone} state; + px_parser_state_t *st; /* parser state to refer to */ + px_state_t *pxs; /* xl state to refer to */ +} px_stream_header_process_t; + + +/* Initialize stream header processor */ +static void +px_stream_header_init( + px_stream_header_process_t *process, /* header state to init */ + px_parser_state_t *st, /* parser state to refer to */ + px_state_t *pxs /* xl state to refer to */ +) +{ + process->state = PSHPReady; + process->st = st; + process->pxs = pxs; +} + +/* Process stream header input */ +static int /* ret -ve error, 0 if needs more input, 1 if done successfully */ +px_stream_header_process( + px_stream_header_process_t *process, /* header state to refer */ + stream_cursor_read *cursor /* cusor to read data */ +) +{ + while (cursor->ptr != cursor->limit) + { + byte chr; + switch (process->state) + { + case PSHPReady: + process->state = PSHPSkipping; /* switch to next state */ + switch ( (chr = *++cursor->ptr) ) + { + case '(': + px_top_init(process->st, process->pxs, true); + break; + case ')': + px_top_init(process->st, process->pxs, false); + break; + default: + /* Initialize state to avoid confusion */ + px_top_init(process->st, process->pxs, true); + return gs_note_error(errorUnsupportedBinding); + } + break; + case PSHPSkipping: + if ( (chr = *++cursor->ptr) == '\n' ) + { + process->state = PSHPDone; + return 1; + } + break; + case PSHPDone: + default: + /* Shouldn't ever come here */ + return gs_note_error(errorIllegalStreamHeader); + } + } + + return 0; /* need more input */ +} + +/* De-initialize stream header processor */ +static void +px_stream_header_dnit( + px_stream_header_process_t *process /* header state to dnit */ +) +{ + /* empty proc */ +} + +/************************************************************/ +/******** Language wrapper implementation (see pltop.h) *****/ +/************************************************************/ + +/* + * PXL interpeter: derived from pl_interp_t + */ +typedef struct pxl_interp_s { + pl_interp_t pl; /* common part: must be first */ + gs_memory_t *memory; /* memory allocator to use */ +} pxl_interp_t; + +/* + * PXL interpreter instance: derived from pl_interp_instance_t + */ +typedef struct pxl_interp_instance_s { + pl_interp_instance_t pl; /* common part: must be first */ + gs_memory_t *memory; /* memory allocator to use */ + px_parser_state_t *st; /* parser state */ + px_state_t *pxs; /* interp state */ + gs_state *pgs; /* grafix state */ + pl_page_action_t pre_page_action; /* action before page out */ + void *pre_page_closure; /* closure to call pre_page_action with */ + pl_page_action_t post_page_action; /* action before page out */ + void *post_page_closure;/* closure to call post_page_action with */ + enum {PSHeader, PSXL, PSDone} + processState; /* interp's processing state */ + px_stream_header_process_t + headerState; /* used to decode stream header */ +} pxl_interp_instance_t; + + +/* Get implemtation's characteristics */ +const pl_interp_characteristics_t * /* always returns a descriptor */ +pxl_impl_characteristics( + const pl_interp_implementation_t *impl /* implementation of interpereter to alloc */ +) +{ + /* version and build date are not currently used */ +#define PXLVERSION NULL +#define PXLBUILDDATE NULL + static pl_interp_characteristics_t pxl_characteristics = { + "PCLXL", + ") HP-PCL XL", + "Artifex", + PXLVERSION, + PXLBUILDDATE, + px_parser_min_input_size + }; + return &pxl_characteristics; +} + +/* Don't need to do anything to PXL interpreter */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_allocate_interp( + pl_interp_t **interp, /* RETURNS abstract interpreter struct */ + const pl_interp_implementation_t *impl, /* implementation of interpereter to alloc */ + gs_memory_t *mem /* allocator to allocate interp from */ +) +{ + static pl_interp_t pi; /* there's only one interpreter */ + + /* There's only one PXL interp, so return the static */ + *interp = π + return 0; /* success */ +} + +/* Do per-instance interpreter allocation/init. No device is set yet */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_allocate_interp_instance( + pl_interp_instance_t **instance, /* RETURNS instance struct */ + pl_interp_t *interp, /* dummy interpreter */ + gs_memory_t *mem /* allocator to allocate instance from */ +) +{ + /* Allocate everything up front */ + pxl_interp_instance_t *pxli /****** SHOULD HAVE A STRUCT DESCRIPTOR ******/ + = (pxl_interp_instance_t *)gs_alloc_bytes( mem, + sizeof(pxl_interp_instance_t), + "pxl_allocate_interp_instance(pxl_interp_instance_t)" + ); + gs_state *pgs = gs_state_alloc(mem); + px_parser_state_t *st = px_process_alloc(mem); /* parser init, cheap */ + px_state_t *pxs = px_state_alloc(mem); /* inits interp state, potentially expensive */ + /* If allocation error, deallocate & return */ + if (!pxli || !pgs || !st || !pxs) { + if (!pxli) + gs_free_object(mem, pxli, "pxl_impl_allocate_interp_instance(pxl_interp_instance_t)"); + if (!pgs) + gs_state_free(pgs); + if (!st) + px_process_release(st); + if (!pxs) + px_state_release(pxs); + return gs_error_VMerror; + } + + /* Setup pointers to allocated mem within instance */ + pxli->memory = mem; + pxli->pgs = pgs; + pxli->pxs = pxs; + pxli->st = st; + + /* zero-init pre/post page actions for now */ + pxli->pre_page_action = 0; + pxli->post_page_action = 0; + + /* General init of pxl_state */ + px_state_init(pxs, pgs); /*pgs only needed to set pxs as pgs' client */ + pxs->client_data = pxli; + pxs->end_page = pxl_end_page_top; /* after px_state_init */ + + /* Return success */ + *instance = (pl_interp_instance_t *)pxli; + return 0; +} + +/* Set a client language into an interperter instance */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_set_client_instance( + pl_interp_instance_t *instance, /* interp instance to use */ + pl_interp_instance_t *client, /* client to set */ + pl_interp_instance_clients_t which_client +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + if ( which_client == PCL_CLIENT ) + pxli->pxs->pcls = client; + else if ( which_client == PJL_CLIENT ) + pxli->pxs->pjls = client; + /* ignore unknown clients */ + return 0; +} + +/* Set an interpreter instance's pre-page action */ +static int /* ret 0 ok, else -ve err */ +pxl_impl_set_pre_page_action( + pl_interp_instance_t *instance, /* interp instance to use */ + pl_page_action_t action, /* action to execute (rets 1 to abort w/o err) */ + void *closure /* closure to call action with */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + pxli->pre_page_action = action; + pxli->pre_page_closure = closure; + return 0; +} + +/* Set an interpreter instance's post-page action */ +static int /* ret 0 ok, else -ve err */ +pxl_impl_set_post_page_action( + pl_interp_instance_t *instance, /* interp instance to use */ + pl_page_action_t action, /* action to execute */ + void *closure /* closure to call action with */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + pxli->post_page_action = action; + pxli->post_page_closure = closure; + return 0; +} + +/* Set a device into an interperter instance */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_set_device( + pl_interp_instance_t *instance, /* interp instance to use */ + gx_device *device /* device to set (open or closed) */ +) +{ + int code; + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + enum {Sbegin, Ssetdevice, Sinitg, Sgsave, Serase, Sdone} stage; + stage = Sbegin; + gs_opendevice(device); + + /* Set the device into the gstate */ + stage = Ssetdevice; + if ((code = gs_setdevice_no_erase(pxli->pgs, device)) < 0) /* can't erase yet */ + goto pisdEnd; + + /* Init XL graphics */ + stage = Sinitg; + if ((code = px_initgraphics(pxli->pxs)) < 0) + goto pisdEnd; + + /* Do inits of gstate that may be reset by setdevice */ + gs_setaccuratecurves(pxli->pgs, true); /* All H-P languages want accurate curves. */ + + /* gsave and grestore (among other places) assume that */ + /* there are at least 2 gstates on the graphics stack. */ + /* Ensure that now. */ + stage = Sgsave; + if ( (code = gs_gsave(pxli->pgs)) < 0) + goto pisdEnd; + + stage = Serase; + if ( (code = gs_erasepage(pxli->pgs)) < 0 ) + goto pisdEnd; + + stage = Sdone; /* success */ + + /* Unwind any errors */ +pisdEnd: + switch (stage) { + case Sdone: /* don't undo success */ + break; + + case Serase: /* gs_erasepage failed */ + /* undo gsave */ + gs_grestore_only(pxli->pgs); /* destroys gs_save stack */ + /* fall thru to next */ + case Sgsave: /* gsave failed */ + case Sinitg: + /* undo setdevice */ + gs_nulldevice(pxli->pgs); + /* fall thru to next */ + + case Ssetdevice: /* gs_setdevice failed */ + case Sbegin: /* nothing left to undo */ + break; + } + return code; +} + +static int +pxl_impl_get_device_memory( + pl_interp_instance_t *instance, /* interp instance to use */ + gs_memory_t **pmem) +{ + return 0; +} + +/* Prepare interp instance for the next "job" */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_init_job( + pl_interp_instance_t *instance /* interp instance to start job in */ +) +{ + int code = 0; + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + 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; +} + +/* Parse a cursor-full of data */ +static int /* ret 0 or +ve if ok, else -ve error code */ +pxl_impl_process( + pl_interp_instance_t *instance, /* interp instance to process data job in */ + stream_cursor_read *cursor /* data to process */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + int code; + + /* Process some input */ + switch (pxli->processState) + { + case PSDone: + return e_ExitLanguage; + case PSHeader: /* Input stream header */ + code = px_stream_header_process(&pxli->headerState, cursor); + if (code == 0) + break; /* need more input later */ + else + /* stream header termination */ + if (code < 0) + { + pxli->processState = PSDone; + return code; /* return error */ + } + else + { + code = 0; + pxli->processState = PSXL; + } + /* fall thru to PSXL */ + case PSXL: /* PCL XL */ + code = px_process(pxli->st, pxli->pxs, cursor); + if ( code == e_ExitLanguage ) + { pxli->processState = PSDone; + code = 0; + } + else if ( code == errorWarningsReported ) + { /* The parser doesn't skip over the EndSession */ + /* operator, because an "error" occurred. */ + cursor->ptr++; + } + else if (code < 0) + /* Map library error codes to PCL XL codes when possible. */ + switch ( code ) + { +#define subst(gs_error, px_error)\ + case gs_error: code = px_error; break + subst(gs_error_invalidfont, errorIllegalFontData); + subst(gs_error_limitcheck, errorInternalOverflow); + subst(gs_error_nocurrentpoint, errorCurrentCursorUndefined); + subst(gs_error_rangecheck, errorIllegalAttributeValue); + subst(gs_error_VMerror, errorInsufficientMemory); +#undef subst + } + break; /* may need more input later */ + } + + return code; +} + +/* 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_instance_t *instance, /* interp instance to flush for */ + stream_cursor_read *cursor /* data to process */ +) +{ + 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 */ +static int /* ret 0 or +ve if ok, else -ve error code */ +pxl_impl_process_eof( + pl_interp_instance_t *instance /* interp instance to process data job in */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + + px_state_cleanup(pxli->pxs); + + return 0; +} + +/* Report any errors after running a job */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_report_errors( + pl_interp_instance_t *instance, /* 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 */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + px_parser_state_t *st = pxli->st; + px_state_t *pxs = pxli->pxs; + int report = pxs->error_report; + const char *subsystem = + (code <= px_error_next ? "KERNEL" : "GRAPHICS"); + char message[px_max_error_line+1]; + int N = 0; + int y; + + if (code >= 0) + return code; /* not really an error */ + if ( report & eErrorPage ) + y = px_begin_error_page(pxs); + while ( (N = px_error_message_line(message, N, subsystem, + code, st, pxs)) >= 0 + ) + { if ( (report & eBackChannel) || force_to_cout ) + errprintf(message); + if ( report & eErrorPage ) + y = px_error_page_show(message, y, pxs); + } + if ( ((report & pxeErrorReport_next) && file_position != -1L) || force_to_cout ) + errprintf("file position of error = %ld\n", file_position); + if ( report & eErrorPage ) + { px_args_t args; + args.pv[0] = 0; + pxEndPage(&args, pxs); + } + px_reset_errors(pxs); + + return code; +} + +/* Wrap up interp instance after a "job" */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_dnit_job( + pl_interp_instance_t *instance /* interp instance to wrap up job in */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + px_stream_header_dnit(&pxli->headerState); + px_state_cleanup(pxli->pxs); + return 0; +} + +/* Remove a device from an interperter instance */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_remove_device( + pl_interp_instance_t *instance /* interp instance to use */ +) +{ + int code = 0; /* first error status encountered */ + int error; + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + /* return to original gstate */ + gs_grestore_only(pxli->pgs); /* destroys gs_save stack */ + /* Deselect device */ + /* NB */ + error = gs_nulldevice(pxli->pgs); + if (code >= 0) + code = error; + + return code; +} + +/* Deallocate a interpreter instance */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_deallocate_interp_instance( + pl_interp_instance_t *instance /* instance to dealloc */ +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)instance; + gs_memory_t *mem = pxli->memory; + + px_dict_release(&pxli->pxs->font_dict); + px_dict_release(&pxli->pxs->builtin_font_dict); + /* do total dnit of interp state */ + px_state_finit(pxli->pxs); + /* free halftone cache */ + gs_state_free(pxli->pgs); + px_process_release(pxli->st); + px_state_release(pxli->pxs); + gs_free_object(mem, pxli, "pxl_impl_deallocate_interp_instance(pxl_interp_instance_t)"); + return 0; +} + +/* Do static deinit of PXL interpreter */ +static int /* ret 0 ok, else -ve error code */ +pxl_impl_deallocate_interp( + pl_interp_t *interp /* interpreter to deallocate */ +) +{ + /* nothing to do */ + return 0; +} + +/* + * End-of-page called back by PXL + */ +static int +pxl_end_page_top( + px_state_t * pxls, + int num_copies, + int flush +) +{ + pxl_interp_instance_t *pxli = (pxl_interp_instance_t *)(pxls->client_data); + pl_interp_instance_t *instance = (pl_interp_instance_t *)pxli; + int code = 0; + + /* do pre-page action */ + if (pxli->pre_page_action) + { + code = pxli->pre_page_action(instance, pxli->pre_page_closure); + if (code < 0) + return code; + if (code != 0) + return 0; /* code > 0 means abort w/no error */ + } + + /* output the page */ + code = gs_output_page(pxli->pgs, num_copies, flush); + if (code < 0) + return code; + + /* do post-page action */ + if (pxli->post_page_action) + { + code = pxli->post_page_action(instance, pxli->post_page_closure); + if (code < 0) + return code; + } + + return 0; +} + +/* Parser implementation descriptor */ +const pl_interp_implementation_t pxl_implementation = { + pxl_impl_characteristics, + pxl_impl_allocate_interp, + pxl_impl_allocate_interp_instance, + pxl_impl_set_client_instance, + pxl_impl_set_pre_page_action, + pxl_impl_set_post_page_action, + pxl_impl_set_device, + pxl_impl_init_job, + pxl_impl_process, + 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, + pxl_impl_deallocate_interp, + pxl_impl_get_device_memory, +}; + +/* ---------- Utility Procs ----------- */ +/* Initialize the parser state, and session parameters in case we get */ +/* an error before the session is established. */ +static int +px_top_init(px_parser_state_t *st, px_state_t *pxs, bool big_endian) +{ + px_args_t args; + px_value_t v[3]; + + px_process_init(st, big_endian); + + /* Measure */ + v[0].type = pxd_scalar | pxd_ubyte; + v[0].value.i = eInch; + args.pv[0] = &v[0]; + /* UnitsPerMeasure */ + v[1].type = pxd_xy | pxd_uint16; + v[1].value.ia[0] = v[1].value.ia[1] = 100; /* arbitrary */ + args.pv[1] = &v[1]; + /* ErrorReporting */ + v[2].type = pxd_scalar | pxd_ubyte; + v[2].value.i = eErrorPage; + args.pv[2] = &v[2]; + { + int code = pxBeginSession(&args, pxs); + if ( code < 0 ) + return code; + } + return 0; +} |