[gs-commits] ghostpdl branch, master, updated. jbig2dec-0.14-1875-g7fc7881

[email protected] (Robin Watts) Fri, 15 Nov 2019 19:37:33 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, master has been updated
       via  7fc7881b00a43fe1017e593846a0baf28e8837db (commit)
       via  161adc70e0d6625618c5a6afcb5e04161acc2e2c (commit)
       via  b8de03bdb8696517bff0259e827ece4f5746663c (commit)
       via  58bee0ad2c67888a52fa02e31de3120673525fda (commit)
       via  372e4f29d3fcbfeaa83a5ee8cc530cbb948edab7 (commit)
      from  194c53ed02d657159a7be894b6d4b54ce1f435d4 (commit)

----------------------------------------------------------------------
commit 7fc7881b00a43fe1017e593846a0baf28e8837db
Author: Robin Watts <[email protected]>
Date:   Fri Nov 15 18:50:56 2019 +0000

    Add simple PWG "interpreter" for gpdl.

diff --git a/base/spwgd.c b/base/spwgd.c
index 19ec764..cb04cb7 100644
--- a/base/spwgd.c
+++ b/base/spwgd.c
@@ -171,8 +171,17 @@ data_produced:
     }
 }
 
+static void
+s_PWGD_release(stream_state * st)
+{
+    stream_PWGD_state *const ss = (stream_PWGD_state *) st;
+
+    gs_free_object(st->memory, ss->line_buffer, "PWGD(close)");
+    ss->line_buffer = NULL;
+}
+
 /* Stream template */
 const stream_template s_PWGD_template = {
-    &st_PWGD_state, s_PWGD_init, s_PWGD_process, 1, 1, NULL,
+    &st_PWGD_state, s_PWGD_init, s_PWGD_process, 1, 1, s_PWGD_release,
     s_PWGD_set_defaults
 };
diff --git a/gpdl/gpdl.mak b/gpdl/gpdl.mak
index b2f39aa..3864a92 100644
--- a/gpdl/gpdl.mak
+++ b/gpdl/gpdl.mak
@@ -19,6 +19,7 @@ GPDLSRC=$(GPDLSRCDIR)$(D)
 GPDLPSISRC=$(GPDLSRCDIR)$(D)psi$(D)
 GPDLURFSRC=$(URFSRCDIR)$(D)
 GPDLIMGSRC=$(GPDLSRCDIR)$(D)image$(D)
+GPDLPWGSRC=$(GPDLSRCDIR)$(D)pwg$(D)
 
 GPDLOBJ=$(GPDLOBJDIR)$(D)
 GPDLGEN=$(GPDLGENDIR)$(D)
@@ -33,9 +34,12 @@ GPDL_URF_TOP_OBJ_FILE=urftop.$(OBJ)
 GPDL_IMG_TOP_OBJ_FILE=imagetop.$(OBJ)
 GPDL_IMG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_IMG_TOP_OBJ_FILE)
 
-GPDL_PSI_TOP_OBJS=$(GPDL_IMG_TOP_OBJ) $(GPDL_URF_TOP_OBJ) $(GPDL_PSI_TOP_OBJ) $(GPDLOBJ)gpdlimpl.$(OBJ)
+GPDL_PWG_TOP_OBJ_FILE=pwgtop.$(OBJ)
+GPDL_PWG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PWG_TOP_OBJ_FILE)
 
-LANG_CFLAGS=$(D_)PCL_INCLUDED$(_D) $(D_)PSI_INCLUDED$(_D) $(D_)XPS_INCLUDED$(_D) $(ENABLE_URF) $(D_)IMG_INCLUDED$(_D)
+GPDL_PSI_TOP_OBJS=$(GPDL_PWG_TOP_OBJ) $(GPDL_IMG_TOP_OBJ) $(GPDL_URF_TOP_OBJ) $(GPDL_PSI_TOP_OBJ) $(GPDLOBJ)gpdlimpl.$(OBJ)
+
+LANG_CFLAGS=$(D_)PCL_INCLUDED$(_D) $(D_)PSI_INCLUDED$(_D) $(D_)XPS_INCLUDED$(_D) $(ENABLE_URF) $(D_)IMG_INCLUDED$(_D) $(D_)PWG_INCLUDED$(_D)
 
 
 GPDLCC=$(CC_) $(LANG_CFLAGS) $(I_)$(PSSRCDIR)$(_I) $(I_)$(PLSRCDIR)$(_I) $(I_)$(GLSRCDIR)$(_I) $(I_)$(DEVSRCDIR)$(_I) $(I_)$(GLGENDIR)$(_I) $(C_)
@@ -69,5 +73,10 @@ $(GPDLOBJ)/$(GPDL_URF_TOP_OBJ_FILE): $(GPDLURFSRC)urftop.c $(AK)\
 
 $(GPDL_IMG_TOP_OBJ): $(GPDLIMGSRC)imagetop.c $(AK)\
  $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(strimpl_h) $(gscoord_h)\
- $(gsstate_h) $(jpeglib_h) $(setjmp__h) $(sjpeg_h)
+ $(jpeglib_h) $(setjmp__h) $(sjpeg_h) $(pltop_h)
 	$(GPDLCC) $(II)$(JI_)$(_I) $(GPDLIMGSRC)imagetop.c $(GPDLO_)$(GPDL_IMG_TOP_OBJ_FILE)
+
+$(GPDL_PWG_TOP_OBJ): $(GPDLPWGSRC)pwgtop.c $(AK)\
+ $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(spwgx_h) $(strimpl_h)\
+ $(gscoord_h) $(pltop_h)
+	$(GPDLCC) $(II)$(JI_)$(_I) $(GPDLPWGSRC)pwgtop.c $(GPDLO_)$(GPDL_PWG_TOP_OBJ_FILE)
diff --git a/gpdl/pwg/pwgtop.c b/gpdl/pwg/pwgtop.c
new file mode 100644
index 0000000..5e7549e
--- /dev/null
+++ b/gpdl/pwg/pwgtop.c
@@ -0,0 +1,718 @@
+/* Copyright (C) 2019 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.
+*/
+
+/* pwgtop.c */
+/* Top-level API implementation of "PWG" Language Interface */
+
+#include "pltop.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gsstate.h"
+#include "spwgx.h"
+#include "strimpl.h"
+#include "gscoord.h"
+
+/* Forward decls */
+
+/************************************************************/
+/******** Language wrapper implementation (see pltop.h) *****/
+/************************************************************/
+
+typedef enum
+{
+    ii_state_identifying = 0,
+    ii_state_pwg,
+    ii_state_pwg_header,
+    ii_state_pwg_data,
+    ii_state_flush
+} ii_state;
+
+/*
+ * PWG interpreter instance
+ */
+typedef struct pwg_interp_instance_s {
+    gs_memory_t       *memory;
+    gx_device         *dev;
+    gx_device         *nulldev;
+
+    gs_color_space    *gray;
+    gs_color_space    *rgb;
+    gs_color_space    *cmyk;
+
+    /* PWG parser state machine */
+    ii_state           state;
+
+    int                pages;
+
+    uint32_t           bpc;
+    uint32_t           bpp;
+    uint32_t           bpl;
+    uint32_t           colororder;
+    uint32_t           cs;
+    uint32_t           duplexMode;
+    uint32_t           printQuality;
+    uint32_t           mediaType;
+    uint32_t           copies;
+    uint32_t           width;
+    uint32_t           height;
+    uint32_t           xresolution;
+    uint32_t           yresolution;
+
+    uint32_t           num_comps;
+    uint32_t           byte_width;
+    uint32_t           x;
+    uint32_t           y;
+
+    gs_image_t         image;
+    gs_image_enum     *penum;
+    gs_gstate         *pgs;
+
+    stream_PWGD_state  pwgd_state;
+    byte               stream_buffer[2048];
+
+} pwg_interp_instance_t;
+
+static int
+pwg_detect_language(const char *s, int len)
+{
+    /* For postscript, we look for %! */
+    if (len >= 4) {
+        if (memcmp(s, "RaS2", 4) == 0)
+            return 100;
+    }
+
+    return 0;
+}
+
+static const pl_interp_characteristics_t pwg_characteristics = {
+    "PWG",
+    pwg_detect_language,
+    "Artifex",
+    "0.01",
+    "13 Nov 2019",
+    1 /* minimum input size */
+};
+
+/* Get implementation's characteristics */
+static const pl_interp_characteristics_t * /* always returns a descriptor */
+pwg_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
+{
+  return &pwg_characteristics;
+}
+
+static void
+pwg_deallocate(pwg_interp_instance_t *pwg)
+{
+    if (pwg == NULL)
+        return;
+
+    rc_decrement_cs(pwg->gray, "pwg_deallocate");
+    rc_decrement_cs(pwg->rgb, "pwg_deallocate");
+    rc_decrement_cs(pwg->cmyk, "pwg_deallocate");
+
+    if (pwg->pgs != NULL)
+        gs_gstate_free_chain(pwg->pgs);
+    gs_free_object(pwg->memory, pwg, "pwg_impl_allocate_interp_instance");
+}
+
+/* Deallocate a interpreter instance */
+static int
+pwg_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    pwg_deallocate(pwg);
+    impl->interp_client_data = NULL;
+
+    return 0;
+}
+
+/* Do per-instance interpreter allocation/init. */
+static int
+pwg_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
+{
+    int code;
+    pwg_interp_instance_t *pwg
+        = (pwg_interp_instance_t *)gs_alloc_bytes(mem,
+                                                  sizeof(pwg_interp_instance_t),
+                                                  "pwg_impl_allocate_interp_instance");
+    if (!pwg)
+        return_error(gs_error_VMerror);
+    memset(pwg, 0, sizeof(*pwg));
+
+    pwg->memory = mem;
+    pwg->pgs = gs_gstate_alloc(mem);
+    if (pwg->pgs == NULL)
+        goto failVM;
+
+    /* Push one save level onto the stack to assuage the memory handling */
+    code = gs_gsave(pwg->pgs);
+    if (code < 0)
+        goto fail;
+
+    code = gsicc_init_iccmanager(pwg->pgs);
+    if (code < 0)
+        goto fail;
+
+    pwg->gray = gs_cspace_new_ICC(mem, pwg->pgs, 1);
+    pwg->rgb  = gs_cspace_new_ICC(mem, pwg->pgs, 3);
+    pwg->cmyk = gs_cspace_new_ICC(mem, pwg->pgs, 4);
+
+    impl->interp_client_data = pwg;
+
+    return 0;
+
+failVM:
+    code = gs_note_error(gs_error_VMerror);
+fail:
+    (void)pwg_deallocate(pwg);
+    return code;
+}
+
+/*
+ * Get the allocator with which to allocate a device
+ */
+static gs_memory_t *
+pwg_impl_get_device_memory(pl_interp_implementation_t *impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    return pwg->dev ? pwg->dev->memory : NULL;
+}
+
+#if 0 /* UNUSED */
+static int
+pwg_impl_set_param(pl_interp_implementation_t *impl,
+                   pl_set_param_type           type,
+                   const char                 *param,
+                   const void                 *val)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    /* No params set here */
+    return 0;
+}
+
+static int
+pwg_impl_add_path(pl_interp_implementation_t *impl,
+                  const char                 *path)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    /* No paths to add */
+    return 0;
+}
+
+static int
+pwg_impl_post_args_init(pl_interp_implementation_t *impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    /* No post args processing */
+    return 0;
+}
+#endif
+
+/* Prepare interp instance for the next "job" */
+static int
+pwg_impl_init_job(pl_interp_implementation_t *impl,
+                  gx_device                  *device)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    pwg->dev = device;
+    pwg->state = ii_state_identifying;
+
+    return 0;
+}
+
+#if 0 /* UNUSED */
+static int
+pwg_impl_run_prefix_commands(pl_interp_implementation_t *impl,
+                             const char                 *prefix)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    return 0;
+}
+
+static int
+pwg_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    return 0;
+}
+#endif
+
+/* Do any setup for parser per-cursor */
+static int                      /* ret 0 or +ve if ok, else -ve error code */
+pwg_impl_process_begin(pl_interp_implementation_t * impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    return 0;
+}
+
+/* Ensure we have 'required' bytes to read, and further ensure
+ * that we have no UEL's within those bytes. */
+static int
+ensure_bytes(pwg_interp_instance_t *pwg, stream_cursor_read *pr, int required)
+{
+    int n;
+    const uint8_t *p = pr->ptr+1;
+    const uint8_t *q;
+    int avail;
+
+    /* Find out how many bytes we need to check */
+    n = pr->limit - pr->ptr;
+    if (n > required)
+        n = required;
+
+    /* Make sure there are no UELs in that block */
+    q = p + n;
+    while (p != q) {
+        while (p != q && *p != '\033')
+            p++;
+        if (p == q)
+            break;
+        avail = pr->limit - pr->ptr;
+        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
+            /* At least a partial match to a UEL */
+            return avail < 9 ? gs_error_NeedInput : gs_error_InterpreterExit;
+        }
+        p++;
+    }
+
+    /* If we have enough bytes, great, if not, get some more */
+    return (n < required) ? gs_error_NeedInput : 0;
+}
+
+static int
+flush_to_uel(stream_cursor_read *pr)
+{
+    const uint8_t *p = pr->ptr+1;
+    const uint8_t *q = pr->limit+1;
+    int avail;
+
+    while (p != q) {
+        while (p != q && *p != '\033')
+            p++;
+        if (p == q)
+            break;
+        avail = pr->limit - pr->ptr;
+        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
+            /* At least a partial match to a UEL. Bin everything to
+             * the start of the match. */
+            pr->ptr = p-1;
+            if (avail == 9) /* Complete match. Exit! */
+                return gs_error_InterpreterExit;
+            /* Partial match. Get more data. */
+            return gs_error_NeedInput;
+        }
+        p++;
+    }
+
+    pr->ptr = pr->limit;
+
+    return 0;
+}
+
+static int
+bytes_until_uel(const stream_cursor_read *pr)
+{
+    const uint8_t *p = pr->ptr+1;
+    const uint8_t *q = pr->limit+1;
+    int avail;
+
+    while (p != q) {
+        while (p != q && *p != '\033')
+            p++;
+        if (p == q)
+            break;
+        avail = pr->limit - pr->ptr;
+        if (memcmp(p, "\033%-12345X", min(avail, 9)) == 0) {
+            /* At least a partial match to a UEL. Everything up to
+             * the start of the match is up for grabs. */
+            return p - (pr->ptr+1);
+        }
+        p++;
+    }
+
+    return pr->limit - pr->ptr;
+}
+
+static int
+get32be(stream_cursor_read *pr)
+{
+    int v = pr->ptr[1] << 24;
+    v |= pr->ptr[2] << 16;
+    v |= pr->ptr[3] << 8;
+    v |= pr->ptr[4];
+    pr->ptr += 4;
+
+    return v;
+}
+
+static int
+get8(stream_cursor_read *pr)
+{
+    return *++(pr->ptr);
+}
+
+static int
+pwg_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+    int code = 0;
+    gs_color_space *cs;
+
+    /* Loop while we have bytes to read */
+    while (pr->limit > pr->ptr)
+    {
+        switch(pwg->state)
+        {
+        case ii_state_identifying:
+            /* Try and get us 4 bytes for "RaS2" */
+            code = ensure_bytes(pwg, pr, 4);
+            if (code < 0)
+                return code;
+            if (memcmp("RaS2", (const char *)pr->ptr+1, 4) == 0)
+            {
+                pr->ptr += 4;
+                pwg->state = ii_state_pwg_header;
+                break;
+            }
+            pwg->state = ii_state_flush;
+            break;
+        case ii_state_pwg_header:
+            /* Try and get us 1796 bytes for the page header */
+            code = ensure_bytes(pwg, pr, 1796);
+            if (code < 0)
+                return code;
+	    pr->ptr          += 64;            /* CString PwgRaster */
+	    pr->ptr          += 64;            /* CString MediaColor */
+	    pr->ptr          += 64;            /* CString MediaType */
+	    pr->ptr          += 64;            /* CString PrintContentOptimize */
+	    pr->ptr          += 1-(256-267);   /* Reserved */
+            (void)get32be(pr);                 /* WhenEnum CutMedia */
+            pwg->duplexMode   = !!get32be(pr); /* Boolean Duplex */
+	    pwg->xresolution  = get32be(pr);
+	    pwg->yresolution  = get32be(pr);
+	    pr->ptr          += 1-(284-299);   /* Reserved */
+	    (void)!!get32be(pr);               /* Boolean InsertSheet */
+	    (void)get32be(pr);                 /* WhenEnum Jog */
+	    (void)get32be(pr);                 /* EdgeEnum LeadingEdge FeedDirection */
+	    pr->ptr          += 1-(312-323);   /* Reserved */
+	    (void)get32be(pr);                 /* MediaPosition */
+	    (void)get32be(pr);                 /* MediaWeightMetric */
+	    pr->ptr          += 1-(332-339);   /* Reserved */
+	    pwg->copies       = get32be(pr);   /* NumCopies */
+            if (pwg->copies == 0)
+                pwg->copies = 1;
+	    (void)get32be(pr);                 /* OrientationEnum Orientation OrientationRequested */
+	    pr->ptr          += 1-(348-351);   /* Reserved */
+	    (void)get32be(pr);                 /* UnsignedInt PageSize */
+	    (void)get32be(pr);                 /* UnsignedInt PageSize */
+	    pr->ptr          += 1-(360-367);   /* Reserved */
+	    (void)!!get32be(pr);               /* Boolean Tumble */
+            pwg->width        = get32be(pr);   /* Width */
+            pwg->height       = get32be(pr);   /* Height */
+	    pr->ptr          += 1-(380-383);   /* Reserved */
+            pwg->bpc          = get32be(pr);   /* Bits Per Color */
+            pwg->bpp          = get32be(pr);   /* Bits Per Pixel */
+            pwg->bpl          = get32be(pr);   /* Bytes Per Line */
+	    pwg->colororder   = get32be(pr);   /* ColorOrderEnum ColorOrder */
+	    pwg->cs           = get32be(pr);   /* ColorSpaceEnum ColorSpace */
+	    pr->ptr          += 1-(404-419);   /* Reserved */
+	    (void)get32be(pr);                 /* NumColors */
+	    pr->ptr          += 1-(424-451);   /* Reserved */
+	    (void)get32be(pr);                 /* TotalPageCount */
+	    (void)get32be(pr);                 /* CrossFeedTransform */
+	    (void)get32be(pr);                 /* FeedTransform */
+	    (void)get32be(pr);                 /* ImageBoxLeft */
+	    (void)get32be(pr);                 /* ImageBoxTop */
+	    (void)get32be(pr);                 /* ImageBoxRight */
+	    (void)get32be(pr);                 /* ImageBoxBottom */
+	    (void)get32be(pr);                 /* SrgbColor AlternatePrimary */
+            pwg->printQuality = get32be(pr);   /* PrintQuality */
+	    pr->ptr          += 1-(488-507);   /* Reserved */
+	    (void)get32be(pr);                 /* VendorIdentifier */
+	    (void)get32be(pr);                 /* VendorLength */
+	    pr->ptr          += 1-(516-1603);  /* VendorData */
+	    pr->ptr          += 1-(1604-1667); /* Reserved */
+	    pr->ptr          += 1-(1668-1731); /* RenderingIntent */
+	    pr->ptr          += 1-(1732-1795); /* PageSizeName */
+
+            /* Decode the header */
+	    if (pwg->colororder != 0)
+	      goto bad_header; /* 0 = chunky = only defined one so far */
+
+            switch(pwg->cs) {
+            case 3:  /* DeviceBlack */
+            case 18: /* Sgray */
+            case 48: /* Device1 (Device color, 1 colorant) */
+                pwg->num_comps = 1;
+                cs = pwg->gray;
+                break;
+            case 1:  /* DeviceRGB */
+            case 19: /* sRGB */
+            case 20: /* AdobeRGB */
+                pwg->num_comps = 3;
+                cs = pwg->rgb;
+                break;
+            case 6: /* DeviceCMYK */
+                pwg->num_comps = 4;
+                cs = pwg->cmyk;
+                break;
+            default:
+                goto bad_header;
+            }
+            if (pwg->bpc != 8)
+                goto bad_header;
+            if (pwg->bpp != 8*pwg->num_comps && pwg->bpp != 16*pwg->num_comps) {
+bad_header:
+                pwg->state = ii_state_flush;
+                break;
+            }
+            pwg->byte_width = (pwg->bpp>>3)*pwg->width;
+            if (pwg->bpl != pwg->byte_width)
+                goto bad_header;
+
+            pwg->nulldev = gs_currentdevice(pwg->pgs);
+            rc_increment(pwg->nulldev);
+            code = gs_setdevice_no_erase(pwg->pgs, pwg->dev);
+            if (code < 0)
+                goto early_flush;
+            gs_initmatrix(pwg->pgs);
+
+            code = gs_scale(pwg->pgs, 1.0, -1.0);
+            if (code >= 0)
+                code = gs_translate(pwg->pgs, 0.0, -pwg->dev->height);
+            if (code >= 0)
+                code = gs_erasepage(pwg->pgs);
+            if (code < 0)
+                goto early_flush;
+
+            memset(&pwg->image, 0, sizeof(pwg->image));
+            gs_image_t_init(&pwg->image, cs);
+            pwg->image.BitsPerComponent = pwg->bpp/pwg->num_comps;
+            pwg->image.Width = pwg->width;
+            pwg->image.Height = pwg->height;
+
+            pwg->image.ImageMatrix.xx = pwg->xresolution / 72.0;
+            pwg->image.ImageMatrix.yy = pwg->yresolution / 72.0;
+
+            pwg->penum = gs_image_enum_alloc(pwg->memory, "pwg_impl_process(penum)");
+            if (pwg->penum == NULL) {
+                code = gs_note_error(gs_error_VMerror);
+                goto early_flush;
+            }
+
+            code = gs_image_init(pwg->penum,
+                                 &pwg->image,
+                                 false,
+                                 false,
+                                 pwg->pgs);
+            if (code < 0)
+                goto early_flush;
+
+            s_init_state((stream_state *)&pwg->pwgd_state, &s_PWGD_template, pwg->memory);
+            if (s_PWGD_template.set_defaults)
+                s_PWGD_template.set_defaults((stream_state *)&pwg->pwgd_state);
+
+            pwg->pwgd_state.width = pwg->width;
+            pwg->pwgd_state.bpp = pwg->bpp;
+
+            code = (s_PWGD_template.init)((stream_state *)&pwg->pwgd_state);
+            if (code < 0)
+                goto early_flush;
+            pwg->x = pwg->y = 0;
+            pwg->state = ii_state_pwg_data;
+            break;
+        case ii_state_pwg_data:
+        {
+            int n = bytes_until_uel(pr);
+            stream_cursor_read local_r;
+            stream_cursor_write local_w;
+            int status;
+            unsigned int used;
+            int decoded_any = 0;
+
+            local_r.ptr = pr->ptr;
+            local_r.limit = local_r.ptr + n;
+
+            do {
+                local_w.ptr = pwg->stream_buffer-1;
+                local_w.limit = local_w.ptr + sizeof(pwg->stream_buffer);
+
+                status = (s_PWGD_template.process)((stream_state *)&pwg->pwgd_state,
+                                                                   &local_r, &local_w,
+                                                                   true);
+                /* status = 0 => need data
+                 *          1 => need output space */
+                /* Copy the updated pointer back */
+                pr->ptr = local_r.ptr;
+                if (local_w.ptr + 1 == pwg->stream_buffer)
+                    break; /* Failed to decode any data */
+                decoded_any = 1;
+
+                code = gs_image_next(pwg->penum, pwg->stream_buffer, local_w.ptr + 1 - pwg->stream_buffer, &used);
+                if (code < 0)
+                    goto flush;
+
+                pwg->x += used;
+                while (pwg->x >= pwg->byte_width) {
+                    pwg->x -= pwg->byte_width;
+                    pwg->y++;
+                }
+                /* Loop while we haven't had all the lines, the decompression
+                 * didn't ask for more data, and the decompression didn't give
+                 * us more data. */
+            } while (pwg->y < pwg->height);
+
+            if (pwg->y == pwg->height) {
+                code = gs_image_cleanup_and_free_enum(pwg->penum, pwg->pgs);
+                pwg->penum = NULL;
+                if (code < 0)
+                    goto flush;
+                code = pl_finish_page(pwg->memory->gs_lib_ctx->top_of_system,
+                                      pwg->pgs, pwg->copies, true);
+                if (code < 0)
+                    goto flush;
+                if (pwg->pages > 0) {
+                    pwg->pages--;
+                    /* If we've reached the expected end, we should probably flush to UEL */
+                    if (pwg->pages == 0)
+                        pwg->state = ii_state_flush;
+                }
+                if (pwg->pwgd_state.templat->release)
+                    pwg->pwgd_state.templat->release((stream_state *)&pwg->pwgd_state);
+                pwg->state = ii_state_pwg_header;
+            } else if (decoded_any == 0) {
+                /* Failed to make progress. Just give up to avoid livelocking. */
+                goto flush;
+            }
+            break;
+        }
+        default:
+        case ii_state_flush:
+            if (0) {
+flush:
+                if (pwg->pwgd_state.templat->release)
+                    pwg->pwgd_state.templat->release((stream_state *)&pwg->pwgd_state);
+early_flush:
+                pwg->state = ii_state_flush;
+            }
+            /* We want to bin any data we get up to, but not including
+             * a UEL. */
+            return flush_to_uel(pr);
+        }
+    }
+
+    return code;
+}
+
+static int
+pwg_impl_process_end(pl_interp_implementation_t * impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+    int code = 0;
+
+    /* FIXME: */
+    if (code == gs_error_InterpreterExit || code == gs_error_NeedInput)
+        code = 0;
+
+    return code;
+}
+
+/* Not implemented */
+static int
+pwg_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
+{
+    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
+pwg_impl_process_eof(pl_interp_implementation_t *impl)
+{
+    return 0;
+}
+
+/* Report any errors after running a job */
+static int
+pwg_impl_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 0;
+}
+
+/* Wrap up interp instance after a "job" */
+static int
+pwg_impl_dnit_job(pl_interp_implementation_t *impl)
+{
+    pwg_interp_instance_t *pwg = (pwg_interp_instance_t *)impl->interp_client_data;
+
+    if (pwg->nulldev) {
+        int code = gs_setdevice(pwg->pgs, pwg->nulldev);
+        pwg->dev = NULL;
+        rc_decrement(pwg->nulldev, "pwg_impl_dnit_job(nulldevice)");
+        pwg->nulldev = NULL;
+        return code;
+    }
+    return 0;
+}
+
+/* Parser implementation descriptor */
+const pl_interp_implementation_t pwg_implementation = {
+  pwg_impl_characteristics,
+  pwg_impl_allocate_interp_instance,
+  pwg_impl_get_device_memory,
+  NULL, /* pwg_impl_set_param */
+  NULL, /* pwg_impl_add_path */
+  NULL, /* pwg_impl_post_args_init */
+  pwg_impl_init_job,
+  NULL, /* pwg_impl_run_prefix_commands */
+  NULL, /* pwg_impl_process_file */
+  pwg_impl_process_begin,
+  pwg_impl_process,
+  pwg_impl_process_end,
+  pwg_impl_flush_to_eoj,
+  pwg_impl_process_eof,
+  pwg_impl_report_errors,
+  pwg_impl_dnit_job,
+  pwg_impl_deallocate_interp_instance,
+  NULL
+};
diff --git a/pcl/pl/plimpl.c b/pcl/pl/plimpl.c
index ebfe3a4..dddefee 100644
--- a/pcl/pl/plimpl.c
+++ b/pcl/pl/plimpl.c
@@ -39,6 +39,8 @@ extern pl_interp_implementation_t urf_implementation;
 
 extern pl_interp_implementation_t img_implementation;
 
+extern pl_interp_implementation_t pwg_implementation;
+
 /* Zero-terminated list of pointers to implementations */
 pl_interp_implementation_t *pdl_implementations[] = {
     &pjl_implementation,
@@ -58,6 +60,9 @@ pl_interp_implementation_t *pdl_implementations[] = {
 #ifdef IMG_INCLUDED
     &img_implementation,
 #endif
+#ifdef PWG_INCLUDED
+    &pwg_implementation,
+#endif
     0
 };
 
diff --git a/windows/ghostpdl.vcproj b/windows/ghostpdl.vcproj
index 0d35c34..c105cc3 100644
--- a/windows/ghostpdl.vcproj
+++ b/windows/ghostpdl.vcproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
 	Version="8.00"
@@ -326,6 +326,14 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="pwg"
+			>
+			<File
+				RelativePath="..\gpdl\pwg\pwgtop.c"
+				>
+			</File>
+		</Filter>
 	</Files>
 	<Globals>
 	</Globals>

----------------------------------------------------------------------
commit 161adc70e0d6625618c5a6afcb5e04161acc2e2c
Author: Robin Watts <[email protected]>
Date:   Fri Nov 15 18:49:23 2019 +0000

    Squash a warning about an ininitialised variable.

diff --git a/jpegxr/cw_emit.c b/jpegxr/cw_emit.c
index cda26fe..cefa11a 100644
--- a/jpegxr/cw_emit.c
+++ b/jpegxr/cw_emit.c
@@ -133,7 +133,7 @@ int jxrc_set_separate_alpha_image_plane(jxr_container_t cp, unsigned int alpha_p
 
 static void emit_ifd(jxr_container_t cp)
 {
-    unsigned long ifd_mark;
+    unsigned long ifd_mark = 0;
     int idx;
     struct ifd_table ifd[64];
     unsigned char buf[1024];

----------------------------------------------------------------------
commit b8de03bdb8696517bff0259e827ece4f5746663c
Author: Robin Watts <[email protected]>
Date:   Fri Nov 15 18:48:55 2019 +0000

    Squash a float -> int warning.

diff --git a/contrib/japanese/gdevlbp3.c b/contrib/japanese/gdevlbp3.c
index 096aecf..8cbc2ce 100644
--- a/contrib/japanese/gdevlbp3.c
+++ b/contrib/japanese/gdevlbp3.c
@@ -137,8 +137,8 @@ BoundImage(gx_device_printer *pDev, struct bounding *pBox)
                 height*10/Yres < 98 ? a5 :\
                 height*10/Yres < 109 ? b5 :\
                 height*10/Yres < 116 ? letter : a4;
-        Xsize = Xres * mm_to_inch(PaperInfo[paper].w-100) / 160;
-        Ysize = Yres * mm_to_inch(PaperInfo[paper].h-100) / 10;
+        Xsize = (int)(Xres * mm_to_inch(PaperInfo[paper].w-100) / 160);
+        Ysize = (int)(Yres * mm_to_inch(PaperInfo[paper].h-100) / 10);
         /* ----==== Allocate momory ====---- */
         if (LineSize < Xsize*2+1) {
                 LineSize = Xsize*2+1;

----------------------------------------------------------------------
commit 58bee0ad2c67888a52fa02e31de3120673525fda
Author: Robin Watts <[email protected]>
Date:   Fri Nov 15 18:48:26 2019 +0000

    Squash a double -> float warning.

diff --git a/contrib/gdevdj9.c b/contrib/gdevdj9.c
index ef53373..af0ef5b 100644
--- a/contrib/gdevdj9.c
+++ b/contrib/gdevdj9.c
@@ -684,7 +684,7 @@ cdj970_put_params(gx_device * pdev, gs_param_list * plist)
         return code;
     if ((code = cdj_put_param_int(plist, "Duplex", &duplex, 0, 2, code)) < 0)
         return code;
-    if ((code = cdj_put_param_float(plist, "MasterGamma", &mastergamma, 0.1, 9.0, code)) < 0)
+    if ((code = cdj_put_param_float(plist, "MasterGamma", &mastergamma, 0.1f, 9.0, code)) < 0)
         return code;
     if ((code = cdj_put_param_float(plist, "GammaValC", &gammavalc, 0.0, 9.0, code)) < 0)
         return code;

----------------------------------------------------------------------
commit 372e4f29d3fcbfeaa83a5ee8cc530cbb948edab7
Author: Robin Watts <[email protected]>
Date:   Wed Nov 13 18:08:20 2019 +0000

    Squash a warning in gdevcif due to dropping const.

diff --git a/devices/gdevcif.c b/devices/gdevcif.c
index 7de92e8..66f61ce 100644
--- a/devices/gdevcif.c
+++ b/devices/gdevcif.c
@@ -46,7 +46,8 @@ cif_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 {	int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
         int lnum;
         byte *in = (byte *)gs_malloc(pdev->memory, line_size, 1, "cif_print_page(in)");
-        char *s, *fname;
+        char *s;
+        const char *fname;
         int scanline, scanbyte;
         int length, start; /* length is the number of successive 1 bits, */
                            /* start is the set of 1 bit start position */
@@ -58,7 +59,7 @@ cif_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 #ifdef CLUSTER
         fname = "clusterout";
 #else
-        fname = (char *)(pdev->fname);
+        fname = (const char *)(pdev->fname);
 #endif
         if ((s = strchr(fname, '.')) == NULL)
                 length = strlen(fname) + 1;


Summary of changes:
 base/spwgd.c                |  11 +-
 contrib/gdevdj9.c           |   2 +-
 contrib/japanese/gdevlbp3.c |   4 +-
 devices/gdevcif.c           |   5 +-
 gpdl/gpdl.mak               |  15 +-
 gpdl/pwg/pwgtop.c           | 718 ++++++++++++++++++++++++++++++++++++++++++++
 jpegxr/cw_emit.c            |   2 +-
 pcl/pl/plimpl.c             |   5 +
 windows/ghostpdl.vcproj     |  10 +-
 9 files changed, 761 insertions(+), 11 deletions(-)
 create mode 100644 gpdl/pwg/pwgtop.c