[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2466-g70d25d8

[email protected] (Ken Sharp) Mon, 18 Nov 2019 17:23:54 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, pdfi has been updated
       via  70d25d8ffdd55c6c57e50541e68772b4bc341196 (commit)
      from  bb630cc20b3a1fe6a65266b0e42384d3fead94af (commit)

----------------------------------------------------------------------
commit 70d25d8ffdd55c6c57e50541e68772b4bc341196
Author: Ken Sharp <[email protected]>
Date:   Mon Nov 18 17:23:03 2019 +0000

    Merge master

diff --git a/Makefile.in b/Makefile.in
index a4317da..4f99d10 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -63,6 +63,14 @@ GPDLSRCDIR=@srcdir@/gpdl
 GPDLGENDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
 GPDLOBJDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
 
+URFSRCDIR=@srcdir@/urf
+URFGENDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
+URFOBJDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
+
+IMGSRCDIR=@srcdir@/gpdl/image
+IMGGENDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
+IMGOBJDIR=./$(BUILDDIRPREFIX)@OBJDIR_BSDMAKE_WORKAROUND@
+
 CONTRIBDIR=@srcdir@/contrib
 
 # Do not edit the next group of lines.
@@ -336,6 +344,12 @@ LCMS2_CFLAGS=-DSHARE_LCMS=$(SHARE_LCMS) @LCMS2_ENDIAN@ @SQRTF_SUBST@  @LCMS2_PTR
 # Options are currently lcms or lcms2
 WHICH_CMS=@WHICHLCMS@
 
+# Do we have URF support?
+ENABLE_URF=@ENABLEURF@
+GPDL_URF_TOP_OBJ=@GPDL_URF_TOP_OBJ@
+URF_INCLUDE=@URF_INCLUDE@
+URF_DEV=@URF_DEV@
+SURFX_H=@SURFX_H@
 
 EXPATSRCDIR=@EXPATDIR@
 EXPAT_CFLAGS=@EXPAT_CFLAGS@
@@ -570,7 +584,7 @@ FEATURE_DEVS=$(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev $(GLD)psl3lib.dev
 	     $(GLD)seprlib.dev $(GLD)translib.dev $(GLD)cidlib.dev $(GLD)psf0lib.dev $(GLD)psf1lib.dev\
              $(GLD)psf2lib.dev $(GLD)lzwd.dev $(GLD)sicclib.dev \
              $(GLD)sjbig2.dev $(GLD)sjpx.dev $(GLD)ramfs.dev \
-             $(GLD)pwgd.dev $(GLD)siscale.dev
+             $(GLD)pwgd.dev $(GLD)siscale.dev $(URF_DEV)
 
 #FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev
 #FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)ttfont.dev $(GLD)pipe.dev
diff --git a/Resource/Init/gs_cidfm.ps b/Resource/Init/gs_cidfm.ps
index 5eb25f0..cd9ed88 100644
--- a/Resource/Init/gs_cidfm.ps
+++ b/Resource/Init/gs_cidfm.ps
@@ -120,7 +120,12 @@ currentdict end def
       (DroidSansFallback.ttf)
     } if
   } if
-  concatstrings
+  % If CIDFSubstFont looks like a path/file (rather than just file)
+  % use it without the CIDFSubstPath string
+  dup .file_name_directory_separator rsearch
+  {pop pop pop exch pop}
+  {pop concatstrings}
+  ifelse
   % The CSI data just has to be valid, the substition machinery will
   % generally overwrite it with appropriate values for the missing font.
   /CSI  [(Identity) 0]
diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps
index 0fd4164..8c41aba 100644
--- a/Resource/Init/gs_lev2.ps
+++ b/Resource/Init/gs_lev2.ps
@@ -660,7 +660,7 @@ currentuserparams /WaitTimeout known
     % Search for valid (iccprofiles) directory as a sibling to (Resource)
     % and set it as a default if found.
     LIBPATH {
-      (Resource) search {
+      (Resource) rsearch {
         exch pop exch pop (iccprofiles) concatstrings
         .file_name_separator concatstrings
         dup (default_gray.icc) concatstrings status {
diff --git a/Resource/Init/gs_res.ps b/Resource/Init/gs_res.ps
index 068514b..5559e6a 100644
--- a/Resource/Init/gs_res.ps
+++ b/Resource/Init/gs_res.ps
@@ -284,7 +284,7 @@ systemdict begin
     dup .file_name_current eq {
       pop
     } {
-      (Resource) search {
+      (Resource) rsearch {
         exch concatstrings
         exch pop
         .file_name_separator concatstrings exit
diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps
index d4a3701..2f8b610 100644
--- a/Resource/Init/pdf_draw.ps
+++ b/Resource/Init/pdf_draw.ps
@@ -3104,7 +3104,10 @@ end
       % Scaling due to -dPDFFitPage is not undone, to keep the correct border width
       % compared to the size of the surrounding marks.
       //systemdict /NoUserUnit .knownget not { //false } if not
-      //systemdict /PDFFitPage known not and {	% UserUnit is ignored if -dPDFFitPage
+      //systemdict /PDFFitPage known not and
+      % Don't apply USerUnit if we are passing it to the device
+      /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse not and
+      {	% UserUnit is ignored if -dPDFFitPage
         Page /UserUnit knownoget { div } if
       } if
       {} 2 index /S knownoget {
@@ -3148,7 +3151,10 @@ end
       % Scaling due to -dPDFFitPage is not undone, to keep the correct border width
       % compared to the size of the surrounding marks.
       //systemdict /NoUserUnit .knownget not { //false } if not
-      //systemdict /PDFFitPage known not and {	% UserUnit is ignored if -dPDFFitPage
+      //systemdict /PDFFitPage known not and
+      % Don't apply USerUnit if we are passing it to the device
+      /PassUserUnit /GetDeviceParam .special_op {exch pop} {//false} ifelse not and
+      {	% UserUnit is ignored if -dPDFFitPage
         Page /UserUnit knownoget { div } if
       } if
       {} 2 index /S knownoget {
@@ -3631,6 +3637,7 @@ currentdict /set_bc_color undef
       } ifelse
       //endannottransparency exec
       grestore
+      //false
     }ifelse
   } bind executeonly def
 
diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps
index 81b7af1..60deb64 100644
--- a/Resource/Init/pdf_font.ps
+++ b/Resource/Init/pdf_font.ps
@@ -857,176 +857,222 @@ setglobal
 /.pdfdfndict mark
   /defaultfontname /Helvetica
 .dicttomark readonly def
+
+% This code attempts to use the FontName and FontDescriptor to find a
+% 'better' match for a missing font than the default font. There
+% are a list of fonts and mappings here (TTfonts) and in gs_font.ps
+% (.substitutefaces) which we can use to map from a requested font
+% family name to a substitute family. If that fails we check the
+% FontDescriptor Flags to attempt a (very slightly) better match.
+% We use Times-Roman for serif fonts and Helvetica for non-serif.
+% This all seems pretty poor to me, but its long-standing, so we
+% won't attempt to meddle with it.
+/pdfsubstitutefont {
+  % Stack: font-res fontname fontdesc
+
+  dup /Flags oget
+  dup 16#40 and -6 bitshift		% 1, oblique/italic
+  1 index 16#40000 and -17 bitshift add	% 2, bold
+  exch 16#2 and 2 bitshift add	% 8, serif
+
+  % We should look at the fixed flag, too.
+  % Stack: font-res fontname fontdesc properties
+
+  % Even though /FontName is a required key in FontDescriptor dict
+  % (As of the PDF 1.4 Reference Manual), In the case of missing
+  % /FontName key, we substitue /BaseFont for the value of /FontName.
+  % Yet another case of broken PDF's that Adobe Reader accepts.
+  1 index dup /FontName known
+  {
+    /FontName oget
+    dup type /nametype ne
+    {
+      (   **** Error: /FontName in FontDescriptor is not a name.\n)
+      pdfformaterror
+      (               Output may be incorrect.\n) pdfformaterror
+      cvn
+    } if
+  }
+  {
+    (   **** Error: FontDescriptor missing required /FontName key. BaseFont name used.\n)
+    pdfformaterror
+    (               Output may be incorrect.\n) pdfformaterror
+    pop 2 index		% grab the BaseFont from the stack.
+  } ifelse
+  .remove_font_name_prefix
+  exch
+
+  % Analyzes font name and extract "Bold" and "Narrow" properties
+  % which are not described by the FontDescriptor Flags.
+  % We also allow the font name analysis to override the Flags setting
+  % for Italic/Oblique as this gives us results more consistent with
+  % Acrobat.
+  0 2 index //.fontnameproperties exec 7 and or
+
+  % Rebind the default font name to Helvetica so that
+  % fonts with no properties are handled correctly.
+  //.pdfdfndict begin .substitutefontname end
+
+  % Stack: font-res fontname fontdesc substname|null
+  Fontmap 1 index known
+  {//false}
+  { .buildnativefontmap pop NativeFontmap 1 index known not}
+  ifelse
+
+  {
+    % No available good substitution, use the standard one.
+    pop 1 index .substitutefont
+  } if
+
+  dup 3 index ne
+  {
+    QUIET not
+    {
+      (Substituting font ) print dup =only
+      ( for ) print 2 index =only (.) = flush
+    } if
+    % Send a warning to the device, in case its pdfwrite and we are in PDF/A mode
+    % In that case the substituted font may not (probably doesn't) have glyphs which
+    % match the /Widths of the original font, and that will cause a fault with PDF/A
+    % so we need to let the device know.
+    /SubstitutedFont /EventInfo .special_op
+  } if
+
+  pdffindcachedfont
+  % Stack: font-res fontname fontdesc font
+
+  % Some non-compliant files are missing FirstChar/LastChar,
+  % despite referencing a non-base14 font
+  3 index /FirstChar knownoget
+  {
+    0                                       % push an initial value for accumating the Widths
+    0 string                                % and an empty string to interrogate the font
+    7 index /Widths knownoget
+    {
+      0 1 2 index length 1 sub
+      {
+        dup 2 index exch get
+        dup type /packedarraytype eq {exec} if % Handle entries which are indirect references (seriously ? !!)
+        dup 0 gt                              % We ignore entries of zero in the widths array
+        {
+          exch 5 index add                    % add FirstChar to the idx to get a char code
+          dup 64 gt 1 index 91 lt and         % we only want to consider A~Z and....
+          1 index 96 gt 2 index 123 lt and or % ... a~z
+          {
+            exch
+            5 -1 roll add 4 1 roll            % add the width to the accumulator on the stack
+            1 string dup 0 4 -1 roll put
+            3 -1 roll concatstrings exch      % add the char code to the string
+          }
+          {
+            pop pop
+          } ifelse
+        }
+        {
+           pop pop
+        } ifelse
+      } for
+      pop           % get rid of the Widths array
+      3 -1 roll pop % get rid of the FirstChar value
+      dup length dup 0 gt
+      {
+        3 -1 roll exch div  % calculate an average width from the Widths array
+        gsave
+        2 index 10 scalefont setfont
+        exch dup length exch stringwidth
+        grestore
+        pop 100 mul exch div div
+        % Only make the font smaller/narrower, not larger/wider
+        dup 1.0 lt
+        {
+          0 0 2 index 0 0 6 array astore
+          exch //true .copyfontdict
+          dup /FontMatrix get 3 -1 roll matrix concatmatrix
+          exch dup 3 -1 roll /FontMatrix exch put
+          % we don't need to definfont here, we can leave that to .completefont below
+        }
+        {
+          pop
+        } ifelse
+      }
+      {
+        % no suitable Widths entries - carry on and hope for the best......
+        pop pop pop
+      } ifelse
+    }
+    {
+      % Broken file: no Widths array for non-base14 font - carry on and hope for the best......
+      (   **** Warning: Widths array missing in FontDescriptor for non-base14 font\n)
+      pdfformatwarning
+      pop pop pop
+    } ifelse
+  }
+  {
+    (   **** Warning: FirstChar value missing in FontDescriptor for non-base14 font\n)
+    pdfformatwarning
+  } ifelse
+  % Stack: font-res fontname fontdesc font
+
+  % If this is a small-caps font, replace the CharString
+  % entries for a..z.
+  exch /Flags oget 16#20000 and 0 ne
+  {
+    //true .copyfontdict
+    dup /CharStrings 2 copy get dup length dict .copydict
+    % stack: font-res fontname font font /CharStrings CharStringsdict
+    5 index /FirstChar get 97 .max
+    6 index /LastChar get 122 .min 1 exch
+    {
+
+      % Stack: font-res fontname font' font' /CharStrings charstrings code
+      % Note that this only remaps a-z, not accented characters.
+      6 index /Widths oget 1 index 8 index /FirstChar get sub oget
+      1 string dup 0 5 -1 roll put
+
+      % Stack: font-res font' font' /CharStrings charstrings code
+      %   width (x)
+      2 index exch dup cvn exch
+      dup 0 2 copy get 32 sub put 4 -1 roll
+      {
+        % Stack: operand (X) width
+        0 setcharwidth exch pop
+        currentfont /FontMatrix get matrix invertmatrix concat
+        0.7 dup scale 0 0 moveto show
+      } /exec cvx 4 packedarray cvx put
+    } for put
+  } if
+
+  dup /FontName get 2 index ne
+  {
+    //true .copyfontdict
+    2 copy exch /FontName exch put
+  } if
+  exch pop .completefont
+} bind executeonly def
+
 /pdffindfont {		% <font-resource> <fontname> pdffindfont <font>
-                % If the font isn't available, synthesize one based on
-                % its descriptor.
-  dup /Font resourcestatus {
+  % If the font isn't available, synthesize one based on
+  % its descriptor.
+  dup /Font resourcestatus
+  {
     pop pop pdffindcachedfont
-  } {
+  }
+  {
     1 index /FontDescriptor knownoget {
-                % Stack: font-res fontname fontdesc
-      dup /Flags oget
-      dup 16#40 and -6 bitshift		% 1, oblique/italic
-      1 index 16#40000 and -17 bitshift add	% 2, bold
-      exch 16#2 and 2 bitshift add	% 8, serif
-                % We should look at the fixed flag, too.
-                % Stack: font-res fontname fontdesc properties
-
-                % Even though /FontName is a required key in FontDescriptor dict
-                % (As of the PDF 1.4 Reference Manual), In the case of missing
-                % /FontName key, we substitue /BaseFont for the value of /FontName.
-                % Yet another case of broken PDF's that Adobe Reader accepts.
-      1 index dup /FontName known {
-        /FontName oget
-        dup type /nametype ne {
-          (   **** Error: /FontName in FontDescriptor is not a name.\n)
-          pdfformaterror
-          (               Output may be incorrect.\n) pdfformaterror
-          cvn
-        } if
-      } {
-        (   **** Error: FontDescriptor missing required /FontName key. BaseFont name used.\n)
-        pdfformaterror
-        (               Output may be incorrect.\n) pdfformaterror
-        pop 2 index		% grab the BaseFont from the stack.
-      } ifelse
-      .remove_font_name_prefix
-      exch
-                % Analyzes font name and extract "Bold" and "Narrow" properties
-                % which are not described by the FontDescriptor Flags.
-                % We also allow the font name analysis to override the Flags setting
-                % for Italic/Oblique as this gives us results more consistent with
-                % Acrobat.
-      0 2 index //.fontnameproperties exec 7 and or
-                % Rebind the default font name to Helvetica so that
-                % fonts with no properties are handled correctly.
-      //.pdfdfndict begin .substitutefontname end
-                % Stack: font-res fontname fontdesc substname|null
-      Fontmap 1 index known
-      {//false}
-      { .buildnativefontmap pop NativeFontmap 1 index known not} ifelse
-
+      /SUBSTFONT where not
       {
-                % No available good substitution, use the standard one.
-        pop 1 index .substitutefont
-      } if
-      dup 3 index ne {
-        QUIET not {
-        (Substituting font ) print dup =only
-        ( for ) print 2 index =only (.) = flush
-        } if
-        % Send a warning to the device, in case its pdfwrite and we are in PDF/A mode
-        % In that case the substituted font may not (probably doesn't) have glyphs which
-        % match the /Widths of the original font, and that will cause a fault with PDF/A
-        % so we need to let the device know.
-        /SubstitutedFont /EventInfo .special_op
-      } if
-      pdffindcachedfont
-                % Stack: font-res fontname fontdesc font
-
-      % Some non-compliant files are missing FirstChar/LastChar,
-      % despite referencing a non-base14 font
-      3 index /FirstChar knownoget
-      {
-        0                                       % push an initial value for accumating the Widths
-        0 string                                % and an empty string to interrogate the font
-        7 index /Widths knownoget
-        {
-          0 1 2 index length 1 sub
-          {
-            dup 2 index exch get
-            dup type /packedarraytype eq {exec} if % Handle entries which are indirect references (seriously ? !!)
-            dup 0 gt                              % We ignore entries of zero in the widths array
-            {
-              exch 5 index add                    % add FirstChar to the idx to get a char code
-              dup 64 gt 1 index 91 lt and         % we only want to consider A~Z and....
-              1 index 96 gt 2 index 123 lt and or % ... a~z
-              {
-                exch
-                5 -1 roll add 4 1 roll            % add the width to the accumulator on the stack
-                1 string dup 0 4 -1 roll put
-                3 -1 roll concatstrings exch      % add the char code to the string
-              }
-              {
-                pop pop
-              } ifelse
-            }
-            {
-               pop pop
-            } ifelse
-          } for
-          pop           % get rid of the Widths array
-          3 -1 roll pop % get rid of the FirstChar value
-          dup length dup 0 gt
-          {
-            3 -1 roll exch div % calculate an average width from the Widths array
-
-            gsave
-            2 index 10 scalefont setfont
-            exch dup length exch stringwidth
-            grestore
-            pop 100 mul exch div div
-            % Only make the font smaller/narrower, not larger/wider
-            dup 1.0 lt
-            {
-              0 0 2 index 0 0 6 array astore
-              exch //true .copyfontdict
-              dup /FontMatrix get 3 -1 roll matrix concatmatrix
-              exch dup 3 -1 roll /FontMatrix exch put
-              % we don't need to definfont here, we can leave that to .completefont below
-            }
-            {
-              pop
-            } ifelse
-          }
-          {
-            % no suitable Widths entries - carry on and hope for the best......
-            pop pop pop
-          } ifelse
-        }
-        {
-          % Broken file: no Widths array for non-base14 font - carry on and hope for the best......
-          (   **** Warning: Widths array missing in FontDescriptor for non-base14 font\n)
-          pdfformatwarning
-          pop pop pop
-        } ifelse
+        pdfsubstitutefont
       }
       {
-        (   **** Warning: FirstChar value missing in FontDescriptor for non-base14 font\n)
-        pdfformatwarning
-      } ifelse
-                % Stack: font-res fontname fontdesc font
-                % If this is a small-caps font, replace the CharString
-                % entries for a..z.
-
-      exch /Flags oget 16#20000 and 0 ne {
-        //true .copyfontdict
-        dup /CharStrings 2 copy get dup length dict .copydict
-        % stack: font-res fontname font font /CharStrings CharStringsdict
-        5 index /FirstChar get 97 .max
-        6 index /LastChar get 122 .min 1 exch {
-                % Stack: font-res fontname font' font' /CharStrings charstrings code
-                % Note that this only remaps a-z, not accented characters.
-          6 index /Widths oget 1 index 8 index /FirstChar get sub oget
-          1 string dup 0 5 -1 roll put
-                % Stack: font-res font' font' /CharStrings charstrings code
-                %   width (x)
-          2 index exch dup cvn exch
-          dup 0 2 copy get 32 sub put 4 -1 roll {
-                        % Stack: operand (X) width
-            0 setcharwidth exch pop
-            currentfont /FontMatrix get matrix invertmatrix concat
-            0.7 dup scale 0 0 moveto show
-          } /exec cvx 4 packedarray cvx put
-        } for put
-      } if
-      dup /FontName get 2 index ne {
-        //true .copyfontdict
-        2 copy exch /FontName exch put
-      } if
-      exch pop .completefont
-    } {
-                % No descriptor available, use the default algorithm.
+        % User has defined SUBSTFONT, use the defined substitute font, do not
+        % try to be clever
+        pop                 % the dictionary containing SUBSTFONT
+        pop                 % the FontDescriptor
+        pdffindcachedfont
+      }ifelse
+    }
+    {
+      % No descriptor available, use the default algorithm.
       pdffindcachedfont
     } ifelse
   } ifelse
@@ -2473,23 +2519,22 @@ currentdict /bndef undef
       % if the font was defined in-line, we won't have a object number
       dup /.gs.pdfobj# .knownget not { //null } if
     } {
-        dup /FontDescriptor knownoget {
           % if the font was defined in-line, we won't have a object number
-          dup /.gs.pdfobj# .knownget not { //null }if
-          dup //null eq {
-            exch pop
-          }{
-            exch dup /FontFile knownoget not {
-             dup /FontFile2 knownoget not {
-                dup /FontFile3 knownoget not {
-                  pop pop //null
-                } {pop pop}ifelse
+      dup /.gs.pdfobj# .knownget not { //null }if
+      dup //null eq not {
+         1 index /FontDescriptor knownoget {
+           dup /FontFile knownoget not {
+           dup /FontFile2 knownoget not {
+              dup /FontFile3 knownoget not {
+                pop pop //null
               } {pop pop}ifelse
-            }{pop pop}ifelse
-          }ifelse
-        }{
-          //null
-        } ifelse
+            } {pop pop}ifelse
+           }{pop pop}ifelse
+         }
+         {
+           pop //null
+         } ifelse
+      }if
     } ifelse
     3 1 roll
 
diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps
index 7c608c8..d771b1e 100644
--- a/Resource/Init/pdf_main.ps
+++ b/Resource/Init/pdf_main.ps
@@ -2505,9 +2505,26 @@ end readonly def
       1
     } {
       1 index /UserUnit knownoget {
-        PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if
+        /PassUserUnit /GetDeviceParam .special_op {
+          exch pop dup {
+            [ /UserUnit 4 -1 roll .pdfputparams pop pop 1 exch
+          } if
+        }{
+          //false
+        }ifelse
+
+        not {
+          PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if
+        } if
       } {
-        1
+        /PassUserUnit /GetDeviceParam .special_op {
+          exch pop {
+            [ /UserUnit 1 .pdfputparams pop pop
+          } if
+          1
+        }{
+          1
+        } ifelse
       } ifelse
     } ifelse
   } ifelse
@@ -2585,8 +2602,23 @@ currentdict /PDF2PS_matrix_key undef
     % Set the page size.
     //systemdict /NoUserUnit .knownget not { //false } if not {
       3 index /UserUnit knownoget {
-        dup 4 -1 roll mul 3 1 roll mul
-      } if
+        /PassUserUnit /GetDeviceParam .special_op {
+          exch pop dup {
+            [ /UserUnit 4 -1 roll .pdfputparams pop pop
+          } if
+        }{
+          //false
+        }ifelse
+        not {
+          dup 4 -1 roll mul 3 1 roll mul
+        } if
+      } {
+        /PassUserUnit /GetDeviceParam .special_op {
+          exch pop {
+            [ /UserUnit 1 .pdfputparams pop pop
+          } if
+        }if
+      } ifelse
     } if
   } ifelse
   2 array astore /PageSize exch def
diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps
index cc25751..28f2b35 100644
--- a/Resource/Init/pdf_ops.ps
+++ b/Resource/Init/pdf_ops.ps
@@ -1678,25 +1678,35 @@ end readonly def
                         % operations when the CTM is singular.
                         % Work around this here.
                   {
-                    matrix currentmatrix dup dup
-                    dup 0 get 0 eq 1 index 1 get 0 eq and {
-                      dup dup 2 get 0 eq { 0 }{ 1 } ifelse 1 put
-                    } if
-                    dup 2 get 0 eq 1 index 3 get 0 eq and {
-                      dup dup 1 get 0 eq { 3 }{ 2 } ifelse 1 put
-                    } if
-                    setmatrix
-                    currentpoint
-                    % don't worry about transparency for invisible text
-                    4 index settextfillstate show % Tr was set to graphic state.
-                    moveto
-                    setmatrix
-                    % now set the currentpoint using the original matrix
-                    gsave
-                    setmatrix
-                    //false charpath currentpoint newpath
-                    grestore
-                    moveto
+                    matrix currentmatrix
+                    % Previously we tested specifically for a scale factor of 0,
+                    % but bug #701875 has a CTM which is minute, but not zero. If
+                    % we try to use that at anything except low resolution FreeType
+                    % ends up trying to deal with glyph metrics where one dimension is 0
+                    % and it throws an error. So instead of looking for zero, we'll look
+                    % for a really tiny CTM.
+                    % We also used to patch up the CTM, and still use it, but frankly
+                    % this is too much trouble. If the CTM is tiny then the displacement
+                    % due to drawing the text will also be tiny. Negligible in fact.
+                    % So if its that small then lets just ignore it.
+                    dup 0 get abs 0.00001 lt 1 index 1 get 0.00001 abs lt and not {
+                      dup 2 get abs 0.00001 lt 1 index 3 get abs 0.00001 lt and not {
+                        pop
+                        currentpoint
+                        % don't worry about transparency for invisible text
+                        2 index settextfillstate show % Tr was set to graphic state.
+                        moveto
+                        % now set the currentpoint using the original matrix
+                        gsave
+                        //false charpath currentpoint newpath
+                        grestore
+                        moveto
+                      } {
+                        pop pop
+                      }ifelse
+                    } {
+                      pop pop
+                    }ifelse
                   }
                 } {
                   { //false charpath textrenderingprocs .currenttextrenderingmode  get exec }
diff --git a/base/gdevdevn.c b/base/gdevdevn.c
index 00932ad..737f022 100644
--- a/base/gdevdevn.c
+++ b/base/gdevdevn.c
@@ -1395,7 +1395,9 @@ spotcmyk_print_page(gx_device_printer * pdev, gp_file * prn_stream)
 
     /* Now create the output bit image files */
     for (; lnum < bottom; ++lnum) {
-        gdev_prn_get_bits(pdev, lnum, in, &data);
+        code = gdev_prn_get_bits(pdev, lnum, in, &data);
+        if (code < 0)
+            goto prn_done;
         /* Now put the pcm data into the output file */
         if (npcmcolors) {
             first_bit = bpc * (ncomp - npcmcolors);
diff --git a/base/gdevdflt.c b/base/gdevdflt.c
index 964f0aa..d493068 100644
--- a/base/gdevdflt.c
+++ b/base/gdevdflt.c
@@ -2123,7 +2123,8 @@ transform_pixel_region_render_skew(gx_device *dev, gx_default_transform_pixel_re
     return (code < 0 ? code : 1);
     /* Save position if error, in case we resume. */
 err:
-    buffer[0] = prev;
+    /* Only set buffer[0] if we've managed to set prev to something valid. */
+    if (prev != &initial_run[0]) buffer[0] = prev;
     return code;
 }
 
diff --git a/base/gdevvec.c b/base/gdevvec.c
index 351228b..7136d76 100644
--- a/base/gdevvec.c
+++ b/base/gdevvec.c
@@ -630,6 +630,11 @@ gdev_vector_dopath_init(gdev_vector_dopath_state_t *state,
         gs_make_scaling(vdev->scale.x, vdev->scale.y, &state->scale_mat);
     }
     state->first = true;
+
+    /* This is purely to prevent Coverity from thinking gdev_vector_dopath()
+    could use uninitialised state->start.x. */
+    state->start.x = 0;
+    state->start.y = 0;
 }
 
 /*
diff --git a/base/gpmisc.c b/base/gpmisc.c
index 96052fc..fd4bc5e 100644
--- a/base/gpmisc.c
+++ b/base/gpmisc.c
@@ -743,7 +743,7 @@ gp_open_printer(const gs_memory_t *mem,
                       char         fname[gp_file_name_sizeof],
                       int          binary_mode)
 {
-    gp_file *file;
+    gp_file *file = NULL;
     gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
     gs_fs_list_t *fs = ctx->core->fs;
 
@@ -770,7 +770,7 @@ gp_open_scratch_file(const gs_memory_t *mem,
                      char              *fname,
                      const char        *mode)
 {
-    gp_file *file;
+    gp_file *file = NULL;
     gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
     gs_fs_list_t *fs = ctx->core->fs;
 
@@ -800,7 +800,7 @@ gp_open_scratch_file_rm(const gs_memory_t *mem,
                         char              *fname,
                         const char        *mode)
 {
-    gp_file *file;
+    gp_file *file = NULL;
     gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
     gs_fs_list_t *fs = ctx->core->fs;
 
diff --git a/base/gsicc_create.c b/base/gsicc_create.c
index d073257..ef46460 100644
--- a/base/gsicc_create.c
+++ b/base/gsicc_create.c
@@ -1206,7 +1206,7 @@ add_lutAtoBtype(unsigned char *input_ptr, gsicc_lutatob *lutatobparts)
     }
     /* Then the matrix */
     if (lutatobparts->matrix != NULL) {
-        add_matrixwithbias(curr_ptr,&(lutatobparts->matrix->cu.u),true);
+        add_matrixwithbias(curr_ptr,(float*) lutatobparts->matrix,true);
         curr_ptr += (12*4);
         /* M curves */
         if (lutatobparts->m_curves != NULL) {
@@ -1537,7 +1537,7 @@ create_lutAtoBprofile(unsigned char **pp_buffer_in, icHeader *header,
     /* Multiply the matrix in the AtoB object by the cam so that the data
        is in D50 */
     if (lutatobparts->matrix == NULL) {
-        gsicc_create_copy_matrix3(cam, &(temp_matrix.cu.u));
+        gsicc_create_copy_matrix3(cam, (float*) &temp_matrix);
         lutatobparts->matrix = &temp_matrix;
     } else {
         if (yonly) {
@@ -1759,7 +1759,7 @@ gsicc_create_abc_merge(gsicc_lutatob *atob_parts, gs_matrix3 *matrixLMN,
        to the mapping of X=Y by the identity table.  If there are b_curves
        these have an output that is 16 bit. */
     if (atob_parts->b_curves == NULL) {
-        scale_matrix(&(atob_parts->matrix->cu.u), 2.0);
+        scale_matrix((float*) atob_parts->matrix, 2.0);
     }
     return 0;
 }
diff --git a/base/gxclrast.c b/base/gxclrast.c
index 30c7e36..b75054f 100644
--- a/base/gxclrast.c
+++ b/base/gxclrast.c
@@ -608,6 +608,7 @@ in:                             /* Initialize for a new page. */
     }
     if (target != 0)
         (*dev_proc(target, get_clipping_box))(target, &target_box);
+    memset(&gs_gstate, 0, sizeof(gs_gstate));
     GS_STATE_INIT_VALUES_CLIST((&gs_gstate));
     code = gs_gstate_initialize(&gs_gstate, mem);
     /* Remove the ICC link cache and replace with the device link cache
diff --git a/base/gxhintn.c b/base/gxhintn.c
index 1e3e429..dc28c00 100644
--- a/base/gxhintn.c
+++ b/base/gxhintn.c
@@ -467,8 +467,9 @@ static void t1_hinter__compute_rat_transform_coef(t1_hinter * self)
 }
 
 static inline void t1_hinter__adjust_matrix_precision(t1_hinter * self, fixed xx, fixed yy)
-{   fixed x = any_abs(xx), y = any_abs(yy);
-    fixed c = (x > y ? x : y);
+{
+    ufixed x = any_abs(xx), y = any_abs(yy);
+    ufixed c = (x > y ? x : y);
 
     while (c >= self->max_import_coord) {
         /* Reduce the precision of ctmf to allow products to fit into 32 bits : */
diff --git a/base/gxiscale.c b/base/gxiscale.c
index 72e3257..3eec2f7 100644
--- a/base/gxiscale.c
+++ b/base/gxiscale.c
@@ -1204,6 +1204,7 @@ image_render_interpolate(gx_image_enum * penum, const byte * buffer,
             int scaled_x_prev = 0;
             gx_dda_fixed save_x_dda = pss->params.scale_dda.x;
 
+            devc.type = gx_dc_type_none; /* Needed for coverity, in call to color_is_pure() if color_handler is NULL. */
             stream_w.limit = out + pss->params.WidthOut *
                 max(spp_decode * sizeofPixelOut, ARCH_SIZEOF_COLOR_INDEX) - 1;
             stream_w.ptr = stream_w.limit - width * spp_decode * sizeofPixelOut;
diff --git a/base/lib.mak b/base/lib.mak
index 2ffeb64..810af0a 100644
--- a/base/lib.mak
+++ b/base/lib.mak
@@ -595,6 +595,7 @@ spprint_h=$(GLSRC)spprint.h
 spsdf_h=$(GLSRC)spsdf.h
 srlx_h=$(GLSRC)srlx.h
 spwgx_h=$(GLSRC)spwgx.h
+surfx_h=$(SURFX_H)
 sstring_h=$(GLSRC)sstring.h
 strimpl_h=$(GLSRC)strimpl.h
 szlibx_h=$(GLSRC)szlibx.h
@@ -1942,6 +1943,16 @@ $(GLOBJ)spwgd.$(OBJ) : $(GLSRC)spwgd.c $(AK) $(stdio__h) $(memory__h)\
  $(spwgx_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
 	$(GLCC) $(GLO_)spwgd.$(OBJ) $(C_) $(GLSRC)spwgd.c
 
+# ---------------- URF RunLength decode filter ---------------- #
+
+urfd_=$(GLOBJ)surfd.$(OBJ)
+$(GLD)urfd.dev : $(LIB_MAK) $(ECHOGS_XE) $(urfd_) $(LIB_MAK) $(MAKEDIRS)
+	$(SETMOD) $(GLD)urfd $(urfd_)
+
+$(GLOBJ)surfd.$(OBJ) : $(URFSRCDIR)$(D)surfd.c $(AK) $(stdio__h) $(memory__h)\
+ $(surfx_h) $(strimpl_h) $(LIB_MAK) $(MAKEDIRS)
+	$(GLCC) $(GLO_)surfd.$(OBJ) $(C_) $(URFSRCDIR)$(D)surfd.c
+
 # ---------------- String encoding/decoding filters ---------------- #
 # These are used by the PostScript and PDF writers, and also by the
 # PostScript interpreter.
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/base/unix-gcc.mak b/base/unix-gcc.mak
index c6445bb..8fea6eb 100644
--- a/base/unix-gcc.mak
+++ b/base/unix-gcc.mak
@@ -530,7 +530,7 @@ FEATURE_DEVS=$(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev $(GLD)psl3lib.dev
 	     $(GLD)seprlib.dev $(GLD)translib.dev $(GLD)cidlib.dev $(GLD)psf0lib.dev $(GLD)psf1lib.dev\
              $(GLD)psf2lib.dev $(GLD)lzwd.dev $(GLD)sicclib.dev \
              $(GLD)sjbig2.dev $(GLD)sjpx.dev $(GLD)ramfs.dev \
-             $(GLD)pwgd.dev
+             $(GLD)pwgd.dev $(GLD)urfd.dev
 
 
 
diff --git a/configure.ac b/configure.ac
index 201c363..de761cb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -919,9 +919,6 @@ UFST_CFLAGS=
 UFST_LIB_EXT=
 FAPIUFST_MAK="\$(GLSRCDIR)\$(D)stub.mak"
 
-AC_ARG_ENABLE([fapi], AC_HELP_STRING([--disable-fapi],
-       [Force use of the (deprecated) Artifex font scaler/renderer]))
-
 if test x"$enable_fapi" != xno; then
 
   dnl UFST detection
@@ -989,7 +986,7 @@ if test x"$enable_fapi" != xno; then
 
     if test x"$FTSRCDIR" = x"src"; then
       AC_MSG_RESULT([no])
-      if test "x$PKGCONFIG" != x; then
+      if test x"$PKGCONFIG" != x""; then
         AC_MSG_CHECKING(for system freetype2 >= 2.4.2 with pkg-config)
             # pkg-config needs the libtool version, which != the freetype2 version <sigh!>
             # There is a table of corresponding ft2<->libtool numbers in freetype/docs/VERSION.DLL
@@ -1001,7 +998,6 @@ if test x"$enable_fapi" != xno; then
                 SHARE_FT=1
             else
                 AC_MSG_RESULT(no)
-                AC_MSG_WARN([freetype library source not found...using native rasterizer])
                 AFS=1
             fi
       else
@@ -1035,6 +1031,10 @@ if test x"$enable_fapi" != xno; then
   fi
 fi
 
+if test x"$FT_BRIDGE" != x"1"; then
+  AC_MSG_ERROR([No usable Freetype source or library found])
+fi
+
 AC_SUBST(INSERT_UFST_BRIDGE_EQUAL_ONE)
 AC_SUBST(UFST_ROOT)
 AC_SUBST(UFST_CFLAGS)
@@ -1849,6 +1849,33 @@ AC_SUBST(JPXDIR)
 AC_SUBST(SHARE_JPX)
 AC_SUBST(JPXDEVS)
 
+ENABLEURF=
+URF_DEVS=''
+URF_INCLUDE=
+URF_DEV=
+SURFX_H=
+AC_ARG_WITH([urf], AC_HELP_STRING([--without-urf],
+    [do not try to include URF support]))
+
+if test x$with_urf != xno; then
+  AC_MSG_CHECKING([for URF support])
+  if test -d $srcdir/urf; then
+    AC_MSG_RESULT([yes])
+    ENABLEURF="$(D_)URF_INCLUDED$(_D)"
+    URF_DEVS='urfgray urfrgb urfcmyk'
+    GPDL_URF_TOP_OBJ=$(GPDLOBJ)/$(GPDL_URF_TOP_OBJ_FILE)
+    URF_INCLUDE=$(I_)$(URFSRCDIR)$(_I)
+    URF_DEV=$(GLD)urfd.dev
+    SURFX_H=SURFX_H=$(URFSRCDIR)$(D)surfx.h
+fi
+fi
+
+AC_SUBST(ENABLEURF)
+AC_SUBST(GPDL_URF_TOP_OBJ)
+AC_SUBST(URF_INCLUDE)
+AC_SUBST(URF_DEV)
+AC_SUBST(SURFX_H)
+
 AC_ARG_WITH([cal], AC_HELP_STRING([--without-cal],
     [do not try to use the CAL library for acceleration]))
 
@@ -2191,6 +2218,7 @@ AC_ARG_ENABLE([compile-inits], AC_HELP_STRING([--disable-compile-inits],
 AC_SUBST(COMPILE_INITS)
 
 dnl look for drivers to compile...
+APPLE_DEVICES_REQUESTED="no"
 AC_ARG_WITH(drivers,
 [  --with-drivers=LIST     Drivers to support, separated by commas.
                           Either list the drivers or use aliases:
@@ -2233,6 +2261,10 @@ if test "x$driversfile" != x; then
         drivers="`tr '\n' ',' <$driversfile`"
 fi
 
+if echo $drivers | grep 'APPLE\|iwhi\|iwlo\|iwlq' >/dev/null; then
+   APPLE_DEVICES_REQUESTED="yes"
+fi
+
 dnl Check which drivers we'd like to support.
 P_DEVS0=""
 F_DEVS0=""
@@ -2251,6 +2283,7 @@ EPSON_DEVS='eps9high eps9mid epson epsonc escp lp8000 lq850 photoex st800 stcolo
 CANON_DEVS='bj10e bj200 bjc600 bjc800 lbp8 lips3 bjcmono bjcgray bjccmyk bjccolor'
 LEXMARK_DEVS='lxm5700m lxm3200 lex2050 lex3200 lex5700 lex7000'
 BROTHER_DEVS='hl7x0 hl1240 hl1250'
+APPLE_DEVS='appledmp iwhi iwlo iwlq'
 IBM_DEVS='ibmpro jetp3852'
 OKI_DEVS='oki182 okiibm oki4w'
 JAPAN_DEVS='lips4 lips4v ljet4pjl lj4dithp dj505j picty180 lips2p bjc880j pr201 pr150 pr1000 pr1000_4 jj100 bj10v bj10vh mj700v2c mj500c mj6000c mj8000c fmpr fmlbp ml600 lbp310 lbp320 md50Mono md50Eco md1xMono escpage lp2000 npdl rpdl'
@@ -2293,7 +2326,7 @@ while test -n "$drivers"; do
                 fi
                 ;;
         PRINTERS)
-                P_DEVS0="$P_DEVS0 $CANON_DEVS $EPSON_DEVS $HP_DEVS $LEXMARK_DEVS $BROTHER_DEVS $IBM_DEVS $OKI_DEVS $JAPAN_DEVS $MISC_PDEVS $ETS_HALFTONING_DEVS"
+                P_DEVS0="$P_DEVS0 $CANON_DEVS $EPSON_DEVS $HP_DEVS $LEXMARK_DEVS $BROTHER_DEVS $APPLE_DEVS $IBM_DEVS $OKI_DEVS $JAPAN_DEVS $MISC_PDEVS $ETS_HALFTONING_DEVS $URF_DEVS"
                 IJS_DEVS0="$IJSDEVS"
                 if test x$ac_cv_lib_dl_dlopen != xno -a x$found_iconv != xno; then
                         P_DEVS0="$P_DEVS0 $OPVP_DEVS"
@@ -2307,6 +2340,10 @@ while test -n "$drivers"; do
                 JBIG2_DEVS="$JBIG2FILEDEVS"
                 PNG_DEVS0="$PNGDEVS"
                 ;;
+        APPLE)
+                # All Apple printers
+                P_DEVS0="$P_DEVS0 $APPLE_DEVS"
+                ;;
         BMP)
                 # BMP file format
                 F_DEVS0="$F_DEVS0 $BMP_DEVS"
@@ -2498,6 +2535,14 @@ if test -n "$X11_DEVS0"; then
     X11_DEVS=`(for i in $X11_DEVS0; do d='$(DD)'${i}.dev; if ( grep '^'$d $noncontribmakefiles  2>&1 >/dev/null) || ( ! test -z "$CONTRIBINCLUDE" ); then echo $d; fi; done) | sort | uniq | tr '\012\015' '  '`
 fi
 
+# if the user explicitly requested the Apple devices, then hard fail if they aren't available
+if test x"$APPLE_DEVICES_REQUESTED" = x"yes" ; then
+  APDEVS=`echo $P_DEVS | grep 'APPLE\|iwhi\|iwlo\|iwlq'`
+  if test -z "$APDEVS" ; then
+    AC_MSG_ERROR([Requested Apple device(s) not available (iwhi, iwlo, and/or iwlq)])
+  fi
+fi
+
 AC_SUBST(P_DEVS)
 AC_SUBST(F_DEVS)
 AC_SUBST(CUPS_DEVS)
diff --git a/contrib/contrib.mak b/contrib/contrib.mak
index ec02a73..bb26640 100644
--- a/contrib/contrib.mak
+++ b/contrib/contrib.mak
@@ -141,6 +141,30 @@ CONTRIBSRC=$(CONTRIBDIR)$(D)
 
 ###### ----------------------- End of catalog ----------------------- ######
 
+### --------------------- The Apple printer devices --------------------- ###
+### Note: these drivers were contributed by users.                        ###
+###                                                                       ###
+### Maintained by Mike Galatean contact via https://bugs.ghostscript.com  ###
+###                                                                       ###
+
+appledmp_=$(DEVOBJ)gdevadmp.$(OBJ)
+
+$(DEVOBJ)gdevadmp.$(OBJ) : $(CONTRIBSRC)gdevadmp.c $(PDEVH) $(CONTRIB_MAK) $(MAKEDIRS)
+	$(DEVCC) $(DEVO_)gdevadmp.$(OBJ) $(C_) $(CONTRIBSRC)gdevadmp.c
+
+$(DD)appledmp.dev : $(appledmp_) $(DD)page.dev $(CONTRIB_MAK) $(MAKEDIRS)
+	$(SETPDEV) $(DD)appledmp $(appledmp_)
+
+$(DD)iwhi.dev : $(appledmp_) $(DD)page.dev $(CONTRIB_MAK) $(MAKEDIRS)
+	$(SETPDEV) $(DD)iwhi $(appledmp_)
+
+$(DD)iwlo.dev : $(appledmp_) $(DD)page.dev $(CONTRIB_MAK) $(MAKEDIRS)
+	$(SETPDEV) $(DD)iwlo $(appledmp_)
+
+$(DD)iwlq.dev : $(appledmp_) $(DD)page.dev $(CONTRIB_MAK) $(MAKEDIRS)
+	$(SETPDEV) $(DD)iwlq $(appledmp_)
+
+
 ### ----------------- The BJC-210/240/250/250ex/265/1000 ---------------- ###
 
 ### 
diff --git a/contrib/gdevadmp.c b/contrib/gdevadmp.c
new file mode 100644
index 0000000..d48c0da
--- /dev/null
+++ b/contrib/gdevadmp.c
@@ -0,0 +1,410 @@
+/* Copyright (C) 2001-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.
+*/
+
+/*
+ * Apple DMP / Imagewriter driver
+ *
+ * This is a modification of Mark Wedel's Apple DMP and
+ * Jonathan Luckey's Imagewriter II driver to
+ * support the Imagewriter LQ's higher resolution (320x216):
+ *      appledmp:  120dpi x  72dpi is still supported (yuck)
+ *	iwlo:	   160dpi x  72dpi
+ *	iwhi:	   160dpi x 144dpi
+ *      iwlq:      320dpi x 216dpi
+ *
+ * This is also my first attempt to work with gs. I have not included the LQ's
+ * ability to print in colour. Perhaps at a later date I will tackle that.
+ *
+ * BTW, to get your Imagewriter LQ serial printer to work with a PC, attach it
+ * with a nullmodem serial cable.
+ *
+ * Scott Barker ([email protected])
+ */
+
+/*
+ * This is a modification of Mark Wedel's Apple DMP driver to
+ * support 2 higher resolutions:
+ *      appledmp:  120dpi x  72dpi is still supported (yuck)
+ *	iwlo:	   160dpi x  72dpi
+ *	iwhi:	   160dpi x 144dpi
+ *
+ * The Imagewriter II is a bit odd.  In pinfeed mode, it thinks its
+ * First line is 1 inch from the top of the page. If you set the top
+ * form so that it starts printing at the top of the page, and print
+ * to near the bottom, it thinks it has run onto the next page and
+ * the formfeed will skip a whole page.  As a work around, I reverse
+ * the paper about a 1.5 inches at the end of the page before the
+ * formfeed to make it think its on the 'right' page.  bah. hack!
+ *
+ * This is  my first attempt to work with gs, so your milage may vary
+ *
+ * Jonathan Luckey ([email protected])
+ */
+
+/* This is a bare bones driver I developed for my apple Dot Matrix Printer.
+ * This code originally was from the epson driver, but I removed a lot
+ * of stuff that was not needed.
+ *
+ * The Dot Matrix Printer was a predecessor to the apple Imagewriter.  Its
+ * main difference being that it was parallel.
+ *
+ * This code should work fine on Imagewriters, as they have a superset
+ * of commands compared to the DMP printer.
+ *
+ * This driver does not produce the smalles output files possible.  To
+ * do that, it should look through the output strings and find repeat
+ * occurances of characters, and use the escape sequence that allows
+ * printing repeat sequences.  However, as I see it, this the limiting
+ * factor in printing is not transmission speed to the printer itself,
+ * but rather, how fast the print head can move.  This is assuming the
+ * printer is set up with a reasonable speed (9600 bps)
+ *
+ * WHAT THE CODE DOES AND DOES NOT DO:
+ *
+ * To print out images, it sets the printer for unidirection printing
+ * and 15 cpi (120 dpi). IT sets line feed to 1/9 of an inch (72 dpi).
+ * When finished, it sets things back to bidirection print, 1/8" line
+ * feeds, and 12 cpi.  There does not appear to be a way to reset
+ * things to initial values.
+ *
+ * This code does not set for 8 bit characters (which is required). It
+ * also assumes that carriage return/newline is needed, and not just
+ * carriage return.  These are all switch settings on the DMP, and
+ * I have configured them for 8 bit data and cr only.
+ *
+ * You can search for the strings Init and Reset to find the strings
+ * that set up the printer and clear things when finished, and change
+ * them to meet your needs.
+ *
+ * Also, you need to make sure that the printer daemon (assuming unix)
+ * doesn't change the data as it is being printed.  I have set my
+ * printcap file (sunos 4.1.1) with the string:
+ * ms=pass8,-opost
+ * and it works fine.
+ *
+ * Feel free to improve this code if you want.  However, please make
+ * sure that the old DMP will still be supported by any changes.  This
+ * may mean making an imagewriter device, and just copying this file
+ * to something like gdevimage.c.
+ *
+ * The limiting factor of the DMP is the vertical resolution.  However, I
+ * see no way to do anything about this.  Horizontal resolution could
+ * be increased by using 17 cpi (136 dpi).  I believe the Imagewriter
+ * supports 24 cpi (192 dpi).  However, the higher dpi, the slower
+ * the printing.
+ *
+ * Dot Matrix Code by Mark Wedel ([email protected])
+ *
+ *
+ * As of Oct 2019, maintained by Mike Galatean (contact through https://bugs.ghostscript.com )
+ *
+ */
+
+#include "gdevprn.h"
+
+/* The device descriptors */
+static dev_proc_print_page(dmp_print_page);
+
+/* Standard DMP device */
+const gx_device_printer far_data gs_appledmp_device =
+prn_device(prn_bg_procs, "appledmp",	/* The print_page proc is compatible with allowing bg printing */
+        85,				/* width_10ths, 8.5" */
+        110,				/* height_10ths, 11" */
+        120, 72,			/* X_DPI, Y_DPI */
+        0, 0.5, 0.5, 0,		/* margins */
+        1, dmp_print_page);
+
+/*  lowrez Imagewriter device */
+const gx_device_printer far_data gs_iwlo_device =
+prn_device(prn_bg_procs, "iwlo",	/* The print_page proc is compatible with allowing bg printing */
+        85,				/* width_10ths, 8.5" */
+        110,				/* height_10ths, 11" */
+        160, 72,			/* X_DPI, Y_DPI */
+        0, 0.5, 0.5, 0,		/* margins */
+        1, dmp_print_page);
+
+/*  hirez Imagewriter device */
+const gx_device_printer far_data gs_iwhi_device =
+prn_device(prn_bg_procs, "iwhi",	/* The print_page proc is compatible with allowing bg printing */
+        85,				/* width_10ths, 8.5" */
+        110,				/* height_10ths, 11" */
+        160, 144,			/* X_DPI, Y_DPI */
+        0, 0.5, 0.5, 0,		/* margins */
+        1, dmp_print_page);
+
+/* LQ hirez Imagewriter device */
+const gx_device_printer far_data gs_iwlq_device =
+prn_device(prn_bg_procs, "iwlq",	/* The print_page proc is compatible with allowing bg printing */
+        85,				/* width_10ths, 8.5" */
+        110,				/* height_10ths, 11" */
+        320, 216,
+        0, 0, 0.5, 0,		/* margins */
+        1, dmp_print_page);
+
+/* ------ Internal routines ------ */
+
+#define DMP 1
+#define IWLO 2
+#define IWHI 3
+#define IWLQ 4
+
+/* Send the page to the printer. */
+static int
+dmp_print_page(gx_device_printer *pdev, gp_file *gprn_stream)
+{
+        int dev_type;
+
+        int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+        /* Note that in_size is a multiple of 8. */
+        int in_size = line_size * 8;
+        /* FIXME: It would be better if this device used the gp_file and the gp_ API,
+         * rather than this "back door" approach
+         */
+        FILE *prn_stream = gp_get_file(gprn_stream);
+
+
+        byte *buf1 = (byte *)gs_malloc(pdev->memory, in_size, 1, "dmp_print_page(buf1)");
+        byte *buf2 = (byte *)gs_malloc(pdev->memory, in_size, 1, "dmp_print_page(buf2)");
+        byte *prn = (byte *)gs_malloc(pdev->memory, 3*in_size, 1, "dmp_print_page(prn)");
+
+        byte *in = buf1;
+        byte *out = buf2;
+        int lnum = 0;
+
+        /* Check allocations */
+        if ( buf1 == 0 || buf2 == 0 || prn == 0 )
+        {
+                if ( buf1 )
+                        gs_free(pdev->memory, (char *)buf1, in_size, 1,
+                        "dmp_print_page(buf1)");
+                if ( buf2 )
+                        gs_free(pdev->memory, (char *)buf2, in_size, 1,
+                        "dmp_print_page(buf2)");
+                if ( prn )
+                        gs_free(pdev->memory, (char *)prn, in_size, 1,
+                        "dmp_print_page(prn)");
+                return_error(gs_error_VMerror);
+        }
+
+        if ( pdev->y_pixels_per_inch == 216 )
+                dev_type = IWLQ;
+        else if ( pdev->y_pixels_per_inch == 144 )
+                dev_type = IWHI;
+        else if ( pdev->x_pixels_per_inch == 160 )
+                dev_type = IWLO;
+        else
+                dev_type = DMP;
+
+        /* Initialize the printer and reset the margins. */
+
+        fputs("\r\n\033>\033T16", prn_stream);
+
+        switch(dev_type)
+        {
+        case IWLQ:
+                fputs("\033P\033a3", prn_stream);
+                break;
+        case IWHI:
+        case IWLO:
+                fputs("\033P", prn_stream);
+                break;
+        case DMP:
+        default:
+                fputs("\033q", prn_stream);
+                break;
+        }
+
+        /* Print lines of graphics */
+        while ( lnum < pdev->height )
+        {
+                byte *inp;
+                byte *in_end;
+                byte *out_end;
+                int lcnt,ltmp;
+                int count, passes;
+                byte *prn_blk, *prn_end, *prn_tmp;
+
+/* The apple DMP printer seems to be odd in that the bit order on
+ * each line is reverse what might be expected.  Meaning, an
+ * underscore would be done as a series of 0x80, while on overscore
+ * would be done as a series of 0x01.  So we get each
+ * scan line in reverse order.
+ */
+
+                switch (dev_type)
+                {
+                case IWLQ: passes = 3; break;
+                case IWHI: passes = 2; break;
+                case IWLO:
+                case DMP:
+                default: passes = 1; break;
+                }
+
+                for (count = 0; count < passes; count++)
+                {
+                        for (lcnt=0; lcnt<8; lcnt++)
+                        {
+                                switch(dev_type)
+                                {
+                                case IWLQ: ltmp = lcnt + 8*count; break;
+                                case IWHI: ltmp = 2*lcnt + count; break;
+                                case IWLO:
+                                case DMP:
+                                default: ltmp = lcnt; break;
+                                }
+
+                                if ((lnum+ltmp)>pdev->height)
+                                        memset(in+lcnt*line_size,0,line_size);
+                                else
+                                        gdev_prn_copy_scan_lines(pdev,
+                                        lnum+ltmp, in + line_size*(7 - lcnt),
+                                        line_size);
+                        }
+
+                        out_end = out;
+                        inp = in;
+                        in_end = inp + line_size;
+                        for ( ; inp < in_end; inp++, out_end += 8 )
+                        {
+                                gdev_prn_transpose_8x8(inp, line_size,
+                                out_end, 1);
+                        }
+
+                        out_end = out;
+
+                        switch (dev_type)
+                        {
+                        case IWLQ: prn_end = prn + count; break;
+                        case IWHI: prn_end = prn + in_size*count; break;
+                        case IWLO:
+                        case DMP:
+                        default: prn_end = prn; break;
+                        }
+
+                        while ( (int)(out_end-out) < in_size)
+                        {
+                                *prn_end = *(out_end++);
+                                if ((dev_type) == IWLQ) prn_end += 3;
+                                else prn_end++;
+                        }
+                }
+
+                switch (dev_type)
+                {
+                case IWLQ:
+                        prn_blk = prn;
+                        prn_end = prn_blk + in_size * 3;
+                        while (prn_end > prn && prn_end[-1] == 0 &&
+                                prn_end[-2] == 0 && prn_end[-3] == 0)
+                        {
+                                prn_end -= 3;
+                        }
+                        while (prn_blk < prn_end && prn_blk[0] == 0 &&
+                                prn_blk[1] == 0 && prn_blk[2] == 0)
+                        {
+                                prn_blk += 3;
+                        }
+                        if (prn_end != prn_blk)
+                        {
+                                if ((prn_blk - prn) > 7)
+                                        fprintf(prn_stream,"\033U%04d%c%c%c",
+                                                (int)((prn_blk - prn)/3),
+                                                0, 0, 0);
+                                else
+                                        prn_blk = prn;
+                                fprintf(prn_stream,"\033C%04d",
+                                        (int)((prn_end - prn_blk)/3));
+                                fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
+                                        prn_stream);
+                        }
+                        break;
+                case IWHI:
+                        for (count = 0; count < 2; count++)
+                        {
+                                prn_blk = prn_tmp = prn + in_size*count;
+                                prn_end = prn_blk + in_size;
+                                while (prn_end > prn_blk && prn_end[-1] == 0)
+                                        prn_end--;
+                                while (prn_blk < prn_end && prn_blk[0] == 0)
+                                        prn_blk++;
+                                if (prn_end != prn_blk)
+                                {
+                                        if ((prn_blk - prn_tmp) > 7)
+                                                fprintf(prn_stream,
+                                                        "\033V%04d%c",
+                                                        (int)(prn_blk-prn_tmp),
+                                                         0);
+                                        else
+                                                prn_blk = prn_tmp;
+                                        fprintf(prn_stream,"\033G%04d",
+                                                (int)(prn_end - prn_blk));
+                                        fwrite(prn_blk, 1,
+                                                (int)(prn_end - prn_blk),
+                                                prn_stream);
+                                }
+                                if (!count) fputs("\033T01\r\n",prn_stream);
+                        }
+                        fputs("\033T15",prn_stream);
+                        break;
+                case IWLO:
+                case DMP:
+                default:
+                        prn_blk = prn;
+                        prn_end = prn_blk + in_size;
+                        while (prn_end > prn_blk && prn_end[-1] == 0)
+                                prn_end--;
+                        while (prn_blk < prn_end && prn_blk[0] == 0)
+                                prn_blk++;
+                        if (prn_end != prn_blk)
+                        {
+                                if ((prn_blk - prn) > 7)
+                                        fprintf(prn_stream,"\033V%04d%c",
+                                                (int)(prn_blk - prn), 0);
+                                else
+                                        prn_blk = prn;
+                                fprintf(prn_stream,"\033G%04d",
+                                        (int)(prn_end - prn_blk));
+                                fwrite(prn_blk, 1, (int)(prn_end - prn_blk),
+                                        prn_stream);
+                        }
+                        break;
+                }
+
+                fputs("\r\n",prn_stream);
+
+                switch (dev_type)
+                {
+                        case IWLQ: lnum += 24 ; break;
+                        case IWHI: lnum += 16 ; break;
+                        case IWLO:
+                        case DMP:
+                        default: lnum += 8 ; break;
+                }
+        }
+
+        /* ImageWriter will skip a whole page if too close to end */
+        /* so skip back more than an inch */
+        if ( !(dev_type == DMP) )
+                fputs("\033T99\n\n\033r\n\n\n\n\033f", prn_stream);
+
+        /* Formfeed and Reset printer */
+        fputs("\033T16\f\033<\033B\033E", prn_stream);
+        fflush(prn_stream);
+
+        gs_free(pdev->memory, (char *)prn, in_size, 1, "dmp_print_page(prn)");
+        gs_free(pdev->memory, (char *)buf2, in_size, 1, "dmp_print_page(buf2)");
+        gs_free(pdev->memory, (char *)buf1, in_size, 1, "dmp_print_page(buf1)");
+        return 0;
+}
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;
diff --git a/contrib/gdevlx32.c b/contrib/gdevlx32.c
index 0dd5d27..20b01fa 100644
--- a/contrib/gdevlx32.c
+++ b/contrib/gdevlx32.c
@@ -2220,7 +2220,7 @@ static int
 fill_mono_buffer(pagedata *gendata, int vline)
 {
         byte *in_data, *data;
-        int i, ret, ofs;
+        int i, ret, ofs, code = 0;
 
         /* Initialize the "data" pointer, that will be used to
          * scan all the lines in the buffer, and the "ofs" pointer
@@ -2242,8 +2242,10 @@ fill_mono_buffer(pagedata *gendata, int vline)
         while(vline < gendata->numvlines)
         {
                 /* Ask Ghostscript for one rasterized line */
-                gdev_prn_get_bits((gx_device_printer *)gendata->dev,
+                code = gdev_prn_get_bits((gx_device_printer *)gendata->dev,
                                                                                         vline, data+ofs, &in_data);
+                if (code < 0)
+                    return code;
 
                 /* And check if it's all zero: if not, break out of
                  * the loop. This nice trick with memcpy it's by Stephen
@@ -2301,8 +2303,10 @@ fill_mono_buffer(pagedata *gendata, int vline)
                         /* If we are not at the end of the page, copy one more
                          * scanline into the buffer.
                          */
-                        gdev_prn_get_bits((gx_device_printer *)gendata->dev,
+                        code = gdev_prn_get_bits((gx_device_printer *)gendata->dev,
                                                                                                 vline, data+ofs, &in_data);
+                        if (code < 0)
+                            return code;
                         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata->numrbytes);
                 }
 
@@ -2333,7 +2337,7 @@ static int
 init_buffer(pagedata *gendata)
 {
         byte *in_data, *data;
-        int i, ret, p1, p2, ofs;
+        int i, ret, p1, p2, ofs, code = 0;
 
         data = gendata->scanbuf;
         ofs = gendata->goffset;
@@ -2375,8 +2379,11 @@ init_buffer(pagedata *gendata)
 
                 if(i < gendata->numvlines)
                 {
-                        gdev_prn_get_bits((gx_device_printer *)gendata->dev,
+                        code = gdev_prn_get_bits((gx_device_printer *)gendata->dev,
                                                                                                 i, data+ofs, &in_data);
+                        if (code < 0)
+                            return code;
+
                         if(in_data != data+ofs)memcpy(data+ofs, in_data, gendata->numrbytes);
                 }
 
diff --git a/contrib/gdevlx7.c b/contrib/gdevlx7.c
index 9f0f127..37f9697 100644
--- a/contrib/gdevlx7.c
+++ b/contrib/gdevlx7.c
@@ -581,6 +581,7 @@ lxmgen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
    int lr_shift=((lxm_device*)pdev)->headSeparation;
    byte *obp[LX7_BSW_H];    /* pointers to buffer lines */
    int bufHeight;
+   int code = 0;
 
    /* initiate vres mapping variable */
    vres=LXR_600; /* default vertical resolution */
@@ -689,19 +690,24 @@ lxmgen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
       int c1200;     /* testing empty line for 1200dpi... */
 
       /* copy one line & test for all zeroes */
-      gdev_prn_get_bits(pdev, pheight-prest, /* current line No. */
+      code = gdev_prn_get_bits(pdev, pheight-prest, /* current line No. */
             pbuf,                /* our buffer if needed */
             &ppbuf);             /* returns pointer to scanline
                                   * either our buffer or
                                   * gs internal data buffer
                                   */
+      if (code < 0)
+          goto error;
+
       if (vres==LXR_1200 && (pheight-prest+LXH_DSKIP1<pheight))
       {
-         gdev_prn_get_bits(pdev, pheight-prest+LXH_DSKIP1,
+         code = gdev_prn_get_bits(pdev, pheight-prest+LXH_DSKIP1,
                                   /* current line No. */
             pbuf+bwidth,                /* our buffer if needed */
             &ppbuf2);
        c1200=LX_LINE_EMPTY(ppbuf2,bwidth);
+         if (code < 0)
+             goto error;
       }
       else
          c1200=1;
@@ -791,13 +797,14 @@ lxmgen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
    /* eject page */
    lex_eject(prn_stream);
+error:
    gs_free(pdev->memory->non_gc_memory, (char*)pbuf,rpbufsize, 1, "lxmgen_print_page(pbuf)");
    gs_free(pdev->memory->non_gc_memory, (char*)outbuf,OUT_BUF_SIZE, 1, "lxmgen_print_page(outbuf)");
 
 #ifdef DEBUG
    dprintf1("[%s] print_page() end\n",pdev->dname);
 #endif
-   return 0;
+   return code;
 }
 
    static int
diff --git a/contrib/gdevmd2k.c b/contrib/gdevmd2k.c
index 374ca0e..afc82e9 100644
--- a/contrib/gdevmd2k.c
+++ b/contrib/gdevmd2k.c
@@ -486,7 +486,7 @@ alps_print_page(gx_device_printer *pdev, gp_file *prn_stream,
     int c_comp, num_comp = pdev->color_info.num_components;
     int n_comp = (dev_alps->mediaType == 1 ? 3 : num_comp);
     int *error, *ep;
-    int i, j;
+    int i, j, code = 0;
 
     /* allocate memory */
     work = (byte *)gs_malloc(pdev->memory->non_gc_memory, 3+sizeof(int), line_size,
@@ -528,7 +528,9 @@ alps_print_page(gx_device_printer *pdev, gp_file *prn_stream,
         for(y = 0; y < y_height; y ++) {
             uint len = line_size;
 
-            gdev_prn_get_bits(pdev, y, in, &dp);
+            code = gdev_prn_get_bits(pdev, y, in, &dp);
+            if (code < 0)
+                return code;
 
             switch (pdev->color_info.depth) {
             case 4:
diff --git a/contrib/japanese/gdev10v.c b/contrib/japanese/gdev10v.c
index aa641de..f4c349d 100644
--- a/contrib/japanese/gdev10v.c
+++ b/contrib/japanese/gdev10v.c
@@ -219,7 +219,8 @@ bj10v_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         int x_skip_unit = bytes_per_column * (xres / 180);
         int y_skip_unit = (yres / 180);
         byte *in = (byte *)gs_malloc(pdev->memory->non_gc_memory, 8, line_size, "bj10v_print_page(in)");
-        byte *out = (byte *)gs_malloc(pdev->memory->non_gc_memory, bits_per_column, line_size, "bj10v_print_page(out)");
+        /* We need one extra byte in <out> for our sentinel. */
+        byte *out = (byte *)gs_malloc(pdev->memory->non_gc_memory, bits_per_column * line_size + 1, 1, "bj10v_print_page(out)");
         int lnum = 0;
         int y_skip = 0;
         int code = 0;
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;
diff --git a/devices/devs.mak b/devices/devs.mak
index 0183de7..64aaa90 100644
--- a/devices/devs.mak
+++ b/devices/devs.mak
@@ -1947,6 +1947,25 @@ $(DEVOBJ)gdevpdfimg.$(OBJ) : $(DEVSRC)gdevpdfimg.c $(AK) $(gdevkrnlsclass_h) \
   $(slzwx_h) $(szlibx_h) $(jpeglib__h) $(sdct_h) $(srlx_h) $(gsicc_cache_h) $(sjpeg_h)
 	$(DEVCC) $(DEVO_)gdevpdfimg.$(OBJ) $(C_) $(DEVSRC)gdevpdfimg.c
 
+### -------- URF device --------------------- ###
+urf=$(DEVOBJ)gdevurf.$(OBJ)
+$(DD)urfgray.dev : $(urf) $(GLD)page.dev $(GDEV) $(DEVS_MAK) $(MAKEDIRS)
+	$(SETPDEV2) $(DD)urfgray $(urf)
+	$(ADDMOD) $(DD)urfgray -include $(GLD)page
+
+$(DD)urfrgb.dev : $(urf) $(GLD)page.dev $(GDEV) $(DEVS_MAK) $(MAKEDIRS)
+	$(SETPDEV2) $(DD)urfrgb $(urf)
+	$(ADDMOD) $(DD)urfrgb -include $(GLD)page
+
+$(DD)urfcmyk.dev : $(urf) $(GLD)page.dev $(GDEV) $(DEVS_MAK) $(MAKEDIRS)
+	$(SETPDEV2) $(DD)urfcmyk $(urf)
+	$(ADDMOD) $(DD)urfcmyk -include $(GLD)page
+
+$(DEVOBJ)gdevurf.$(OBJ) : $(URFSRCDIR)$(D)gdevurf.c $(AK) $(PDEVH) \
+ $(gsparam_h) $(gdevdcrd_h) $(gscrd_h) $(gscrdp_h) $(gxlum_h) $(gxdcconv_h)\
+ $(gsutil_h) $(DEVS_MAK) $(MAKEDIRS)
+	$(DEVCC) $(DEVO_)gdevurf.$(OBJ) $(C_) $(URFSRCDIR)$(D)gdevurf.c
+
 # Dependencies:
 $(DEVSRC)gxfcopy.h:$(GLSRC)gsfont.h
 $(DEVSRC)gxfcopy.h:$(GLSRC)gsmatrix.h
diff --git a/devices/gdev3852.c b/devices/gdev3852.c
index d984fa1..8438835 100644
--- a/devices/gdev3852.c
+++ b/devices/gdev3852.c
@@ -65,6 +65,7 @@ jetp3852_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     unsigned int count,tempcnt;
     unsigned char vtp,cntc1,cntc2;
     int line_size_color_plane;
+    int code = 0;
 
     byte data[DATA_SIZE];
     byte plane_data[LINE_SIZE * 3];
@@ -90,8 +91,10 @@ jetp3852_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
         for ( lnum = 0; lnum < pdev->height; lnum++ ) {
             byte *end_data = data + line_size;
-            gdev_prn_copy_scan_lines(pdev, lnum,
+            code = gdev_prn_copy_scan_lines(pdev, lnum,
                                      (byte *)data, line_size);
+            if (code < 0)
+                break;
             /* Remove trailing 0s. */
             while ( end_data > data && end_data[-1] == 0 )
                 end_data--;
@@ -173,5 +176,5 @@ jetp3852_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     /* eject page */
     gp_fputs("\014", prn_stream);
 
-    return 0;
+    return code;;
 }
diff --git a/devices/gdev4081.c b/devices/gdev4081.c
index fe40b2c..bd5c52d 100644
--- a/devices/gdev4081.c
+++ b/devices/gdev4081.c
@@ -38,21 +38,19 @@ r4081_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
         int out_size = ((pdev->width + 7) & -8) ;
         byte *out = (byte *)gs_malloc(pdev->memory, out_size, 1, "r4081_print_page(out)");
-        int lnum = 0;
+        int lnum = 0, code = 0;
         int last = pdev->height;
 
         /* Check allocations */
         if ( out == 0 )
-        {	if ( out )
-                        gs_free(pdev->memory, (char *)out, out_size, 1,
-                                "r4081_print_page(out)");
-                return -1;
-        }
+                return_error(gs_error_VMerror);
 
         /* find the first line which has something to print */
         while ( lnum < last )
         {
-                gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+                code = gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+                if (code < 0)
+                     goto xit;
                 if ( out[0] != 0 ||
                      memcmp((char *)out, (char *)out+1, line_size-1)
                    )
@@ -62,7 +60,9 @@ r4081_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
         /* find the last line which has something to print */
         while (last > lnum) {
-                gdev_prn_copy_scan_lines(pdev, last-1, (byte *)out, line_size);
+                code = gdev_prn_copy_scan_lines(pdev, last-1, (byte *)out, line_size);
+                if (code < 0)
+                     goto xit;
                 if ( out[0] != 0 ||
                      memcmp((char *)out, (char *)out+1, line_size-1)
                    )
@@ -77,7 +77,9 @@ r4081_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         /* Print lines of graphics */
         while ( lnum < last )
            {
-                gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+                code = gdev_prn_copy_scan_lines(pdev, lnum, (byte *)out, line_size);
+                if (code < 0)
+                     goto xit;
                 gp_fwrite(out, sizeof(char), line_size, prn_stream);
                 lnum ++;
            }
@@ -85,6 +87,7 @@ r4081_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         /* Eject the page and reinitialize the printer */
         gp_fputs("\f\033\rP", prn_stream);
 
+xit:
         gs_free(pdev->memory, (char *)out, out_size, 1, "r4081_print_page(out)");
-        return 0;
+        return code;
 }
diff --git a/devices/gdev4693.c b/devices/gdev4693.c
index 7e18054..baa975c 100644
--- a/devices/gdev4693.c
+++ b/devices/gdev4693.c
@@ -83,7 +83,7 @@ t4693d_print_page(gx_device_printer *dev, gp_file *ps_stream)
         char *p;
         ushort data_size = line_size/prn_dev->width;
         int checksum;
-        int lnum;
+        int lnum, code = 0;
         int i;
 #if !ARCH_IS_BIG_ENDIAN
         byte swap;
@@ -121,12 +121,14 @@ t4693d_print_page(gx_device_printer *dev, gp_file *ps_stream)
         /* write header */
         if (gp_fwrite(header,1,22,ps_stream) != 22) {
                 errprintf(dev->memory, "Could not write header (t4693d).\n");
-                gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-                return_error(gs_error_ioerror);
+                code = gs_note_error(gs_error_ioerror);
+                goto xit;
         }
 
         for (lnum = 0; lnum < prn_dev->height; lnum++) {
-                gdev_prn_copy_scan_lines(prn_dev,lnum,data,line_size);
+                code = gdev_prn_copy_scan_lines(prn_dev,lnum,data,line_size);
+                if (code < 0)
+                    goto xit;
 
                 for (i = 0; i < line_size; i += data_size) {
 
@@ -147,32 +149,33 @@ t4693d_print_page(gx_device_printer *dev, gp_file *ps_stream)
                                 break;
                         default:
                                 errprintf(dev->memory,"Bad depth (%d) t4693d.\n",depth);
-                                gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-                                return_error(gs_error_rangecheck);
+                                code = gs_note_error(gs_error_rangecheck);
+                                goto xit;
                         }
 
                         if (gp_fwrite(&data[i],1,data_size,ps_stream) != data_size) {
                                 errprintf(dev->memory,"Could not write pixel (t4693d).\n");
-                                gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-                                return_error(gs_error_ioerror);
+                                code = gs_note_error(gs_error_ioerror);
+                                goto xit;
                         }
 
                 }
 
                 if (gp_fputc(0x02,ps_stream) != 0x02) {
                         errprintf(dev->memory,"Could not write EOL (t4693d).\n");
-                        gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-                        return_error(gs_error_ioerror);
+                        code = gs_note_error(gs_error_ioerror);
+                        goto xit;
                 }
 
         }
 
         if (gp_fputc(0x01,ps_stream) != 0x01) {
                 errprintf(dev->memory,"Could not write EOT (t4693d).\n");
-                gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-                return_error(gs_error_ioerror);
+                code = gs_note_error(gs_error_ioerror);
+                /* fall through to xit: */
         }
 
+xit:
         gs_free(dev->memory, data, line_size, 1, "t4693d_print_page");
-        return(0);
+        return(code);
 }
diff --git a/devices/gdev8510.c b/devices/gdev8510.c
index 7d235b5..17938f7 100644
--- a/devices/gdev8510.c
+++ b/devices/gdev8510.c
@@ -68,9 +68,13 @@ m8510_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         while ( lnum < pdev->height ) {
                 /* get a raster */
                 for (i = 7; i >= 0; i--) {
-                        gdev_prn_copy_scan_lines(pdev, lnum, &in1[i*line_size], line_size);
+                        code = gdev_prn_copy_scan_lines(pdev, lnum, &in1[i*line_size], line_size);
+                        if (code < 0)
+                            goto out;
                         lnum++;
-                        gdev_prn_copy_scan_lines(pdev, lnum, &in2[i*line_size], line_size);
+                        code = gdev_prn_copy_scan_lines(pdev, lnum, &in2[i*line_size], line_size);
+                        if (code < 0)
+                            goto out;
                         lnum++;
                 }
 
diff --git a/devices/gdevatx.c b/devices/gdevatx.c
index fd68386..08c8ba5 100644
--- a/devices/gdevatx.c
+++ b/devices/gdevatx.c
@@ -202,7 +202,9 @@ atx_print_page(gx_device_printer *pdev, gp_file *f, int max_width_bytes)
         byte *end;
         int count;
 
-        gdev_prn_get_bits(pdev, lnum, buf, &row);
+        code = gdev_prn_get_bits(pdev, lnum, buf, &row);
+        if (code < 0)
+            goto done;
         /* Clear any trailing padding bits */
         row[endidx] &= mask;
         /* Find the end of the non-blank data. */
diff --git a/devices/gdevbit.c b/devices/gdevbit.c
index 98ef8d4..d0c7711 100644
--- a/devices/gdevbit.c
+++ b/devices/gdevbit.c
@@ -792,19 +792,22 @@ bit_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     int bottom = ((gx_device_bit *)pdev)->LastLine >= pdev->height ?  pdev->height - 1 :
                  ((gx_device_bit *)pdev)->LastLine;
     int line_count = any_abs(bottom - lnum);
-    int i, step = lnum > bottom ? -1 : 1;
+    int code = 0, i, step = lnum > bottom ? -1 : 1;
 
     if (in == 0)
         return_error(gs_error_VMerror);
     if ((lnum == 0) && (bottom == 0))
         line_count = pdev->height - 1;		/* default when LastLine == 0, FirstLine == 0 */
     for (i = 0; i <= line_count; i++, lnum += step) {
-        gdev_prn_get_bits(pdev, lnum, in, &data);
+        code = gdev_prn_get_bits(pdev, lnum, in, &data);
+        if (code < 0)
+            goto done;
         if (!nul)
             gp_fwrite(data, 1, line_size, prn_stream);
     }
+done:
     gs_free_object(pdev->memory, in, "bit_print_page(in)");
-    return 0;
+    return code;
 }
 
 /* For tags device go ahead and add in the size so that we can strip and create
@@ -835,10 +838,11 @@ bittags_print_page(gx_device_printer * pdev, gp_file * prn_stream)
         line_count = pdev->height - 1;		/* default when LastLine == 0, FirstLine == 0 */
     for (i = 0; i <= line_count; i++, lnum += step) {
         if ((code = gdev_prn_get_bits(pdev, lnum, in, &data)) < 0)
-            return code;
+            goto done;
         if (!nul)
             gp_fwrite(data, 1, line_size, prn_stream);
     }
+done:
     gs_free_object(pdev->memory, in, "bit_print_page(in)");
     return 0;
 }
diff --git a/devices/gdevbj10.c b/devices/gdevbj10.c
index 00f8569..3423ebc 100644
--- a/devices/gdevbj10.c
+++ b/devices/gdevbj10.c
@@ -312,7 +312,8 @@ bj10e_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
                 /* Copy 1 scan line and test for all zero. */
                 code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
-                if ( code < 0 ) goto xit;
+                if ( code < 0 )
+                    goto fin;
                 /* The mem... or str... functions should be faster than */
                 /* the following code, but all systems seem to implement */
                 /* them so badly that this code is faster. */
diff --git a/devices/gdevbmp.c b/devices/gdevbmp.c
index 3c6630e..f8ce596 100644
--- a/devices/gdevbmp.c
+++ b/devices/gdevbmp.c
@@ -162,7 +162,9 @@ bmp_print_page(gx_device_printer * pdev, gp_file * file)
     /* BMP files want the image in bottom-to-top order! */
 
     for (y = pdev->height - 1; y >= 0; y--) {
-        gdev_prn_copy_scan_lines(pdev, y, row, raster);
+        code = gdev_prn_copy_scan_lines(pdev, y, row, raster);
+        if (code < 0)
+            goto done;
         gp_fwrite((const char *)row, bmp_raster, 1, file);
     }
 
diff --git a/devices/gdevccr.c b/devices/gdevccr.c
index 9fb22f3..2080d78 100644
--- a/devices/gdevccr.c
+++ b/devices/gdevccr.c
@@ -145,6 +145,7 @@ ccr_print_page(gx_device_printer *pdev, gp_file *pstream)
   int cmy, c, m, y;
   byte *in;
   byte *data;
+  int code = 0;
 
   if((in = (byte *)gs_malloc(pdev->memory, line_size, 1, "gsline")) == NULL)
      return_error(gs_error_VMerror);
@@ -156,7 +157,9 @@ ccr_print_page(gx_device_printer *pdev, gp_file *pstream)
     }
 
   for ( l = 0; l < lnum; l++ )
-     {	gdev_prn_get_bits(pdev, l, in, &data);
+     {  code = gdev_prn_get_bits(pdev, l, in, &data);
+        if (code < 0)
+            goto xit;
         if(alloc_line(pdev->memory, &linebuf[l], pixnum))
           {
             gs_free(pdev->memory, in, line_size, 1, "gsline");
@@ -191,9 +194,10 @@ write_cpass(linebuf, lnum, CPASS, pstream);
 CCFILEEND(pstream);
 
 /* clean up */
+xit:
 gs_free(pdev->memory, in, line_size, 1, "gsline");
 free_rb_line( pdev->memory, linebuf, lnum, pixnum );
-return 0;
+return code;
 }
 
 /* ------ Internal routines ------ */
diff --git a/devices/gdevcdj.c b/devices/gdevcdj.c
index bfe60b5..50a1d62 100644
--- a/devices/gdevcdj.c
+++ b/devices/gdevcdj.c
@@ -2022,6 +2022,7 @@ hp_colour_print_page(gx_device_printer * pdev, gp_file * prn_stream, int ptype)
   int compression = 0;
   int scan = 0;
   int *errors[2];
+  int code = 0;
   const char *cid_string = (const char*) 0;
   byte *data[4], *plane_data[4][4], *out_data;
   byte *out_row, *out_row_alt;
@@ -2414,7 +2415,9 @@ hp_colour_print_page(gx_device_printer * pdev, gp_file * prn_stream, int ptype)
       word *data_words = (word *)data[scan];
       register word *end_data = data_words + line_size_words;
 
-      gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);
+      code = gdev_prn_copy_scan_lines(pdev, lnum, data[scan], line_size);
+      if (code < 0)
+          goto xit;
 
       /* Mask off 1-bits beyond the line width. */
       end_data[-1] &= rmask;
@@ -2744,11 +2747,12 @@ hp_colour_print_page(gx_device_printer * pdev, gp_file * prn_stream, int ptype)
   } else
     gp_fputs("\033&l0H", prn_stream);
 
+xit:
   /* free temporary storage */
   gs_free(pdev->memory, (char *) eg.storage, eg.storage_size_words, W, "ep_print_buffer");
   gs_free(pdev->memory, (char *) storage, storage_size_words, W, "hp_colour_print_page");
 
-  return 0;
+  return code;
 }
 
 /*
diff --git a/devices/gdevcfax.c b/devices/gdevcfax.c
index d6fbebc..6f6419a 100644
--- a/devices/gdevcfax.c
+++ b/devices/gdevcfax.c
@@ -149,7 +149,9 @@ cfax_stream_print_page_width(gx_device_printer * pdev, gp_file * prn_stream,
         if (code < 0)
             return_error(gs_error_limitcheck);
         /* Now, get the bits and encode them */
-        gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+        code = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+        if (code < 0)
+            goto done;
         if (col_size > in_size) {
             memset(in + in_size , 0, col_size - in_size);
         }
diff --git a/devices/gdevcif.c b/devices/gdevcif.c
index 217e43d..66f61ce 100644
--- a/devices/gdevcif.c
+++ b/devices/gdevcif.c
@@ -46,10 +46,12 @@ 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 */
+        int code = 0;
 
         if (in == 0)
                 return_error(gs_error_VMerror);
@@ -57,7 +59,7 @@ cif_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 #ifdef CLUSTER
         fname = "clusterout";
 #else
-        fname = pdev->fname;
+        fname = (const char *)(pdev->fname);
 #endif
         if ((s = strchr(fname, '.')) == NULL)
                 length = strlen(fname) + 1;
@@ -72,7 +74,9 @@ cif_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         gs_free(pdev->memory, s, length+1, 1, "cif_print_page(s)");
 
    for (lnum = 0; lnum < pdev->height; lnum++) {
-      gdev_prn_copy_scan_lines(pdev, lnum, in, line_size);
+      code = gdev_prn_copy_scan_lines(pdev, lnum, in, line_size);
+      if (code < 0)
+          goto xit;
       length = 0;
       for (scanline = 0; scanline < line_size; scanline++)
 #ifdef TILE			/* original, simple, inefficient algorithm */
@@ -98,6 +102,7 @@ cif_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 #endif
    }
         gp_fprintf(prn_stream, "DF;\nC1;\nE\n");
+xit:
         gs_free(pdev->memory, in, line_size, 1, "cif_print_page(in)");
-        return 0;
+        return code;
 }
diff --git a/devices/gdevclj.c b/devices/gdevclj.c
index 0081ed4..542bb8e 100644
--- a/devices/gdevclj.c
+++ b/devices/gdevclj.c
@@ -428,6 +428,7 @@ clj_print_page(
     double                  fs_res = pdev->HWResolution[0] / 72.0;
     double                  ss_res = pdev->HWResolution[1] / 72.0;
     int			    imageable_width, imageable_height;
+    int                     code = 0;
 
     /* no paper size at this point is a serious error */
     if (psize == 0)
@@ -479,7 +480,9 @@ clj_print_page(
     for (i = 0; i < imageable_height; i++) {
         int     clen[3];
 
-        gdev_prn_copy_scan_lines(pdev, i, data, lsize);
+        code = gdev_prn_copy_scan_lines(pdev, i, data, lsize);
+        if (code < 0)
+            goto xit;
 
         /* The 'lsize' bytes of data have the blank margin area at the end due	*/
         /* to the 'initial_matrix' offsets that are applied.			*/
@@ -503,11 +506,12 @@ clj_print_page(
     /* PCL will take care of blank lines at the end */
     gp_fputs("\033*rC\f", prn_stream);
 
+xit:
     /* free the buffers used */
     gs_free_object(mem, cdata[0], "clj_print_page(cdata)");
     gs_free_object(mem, data, "clj_print_page(data)");
 
-    return 0;
+    return code;
 }
 
 /* CLJ device methods */
diff --git a/devices/gdevcljc.c b/devices/gdevcljc.c
index 703f263..6593326 100644
--- a/devices/gdevcljc.c
+++ b/devices/gdevcljc.c
@@ -68,7 +68,7 @@ cljc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
 
         code = gdev_prn_copy_scan_lines(pdev, i, (byte *) data, raster);
         if (code < 0)
-            break;
+            goto out;
         compressed_size = gdev_pcl_mode3compress(raster, data, prow, cdata);
         gp_fprintf(prn_stream, "\033*b%dW", compressed_size);
         gp_fwrite(cdata, sizeof(byte), compressed_size, prn_stream);
diff --git a/devices/gdevdjtc.c b/devices/gdevdjtc.c
index fa4681a..5fb1a4b 100644
--- a/devices/gdevdjtc.c
+++ b/devices/gdevdjtc.c
@@ -75,6 +75,7 @@ djet500c_print_page(gx_device_printer *pdev, gp_file *fprn)
     byte *plane3=NULL;
     int bitSize=0;
     int planeSize=0;
+    int code = 0;
 
     /* select the most compressed mode available & clear tmp storage */
     /* put printer in known state */
@@ -122,7 +123,9 @@ djet500c_print_page(gx_device_printer *pdev, gp_file *fprn)
         {
             byte *endData;
 
-            gdev_prn_copy_scan_lines(pdev, lnum, bitData, lineSize);
+            code = gdev_prn_copy_scan_lines(pdev, lnum, bitData, lineSize);
+            if (code < 0)
+                goto xit;
 
             /* Identify and skip blank lines */
             endData = bitData + lineSize;
@@ -149,6 +152,10 @@ djet500c_print_page(gx_device_printer *pdev, gp_file *fprn)
                     plane1=(byte*)malloc(planeSize+8);
                     plane2=(byte*)malloc(planeSize+8);
                     plane3=(byte*)malloc(planeSize+8);
+                    if (plane1 == NULL || plane2 == NULL || plane3 == NULL) {
+                        code = gs_error_VMerror;
+                        goto xit;
+                    }
                 }
                 /* Transpose the data to get pixel planes. */
                 for (k=i=0; k<lineLen; i+=8, k++)
@@ -207,13 +214,14 @@ djet500c_print_page(gx_device_printer *pdev, gp_file *fprn)
     /* eject page */
     gp_fputs("\033&l0H", fprn);
 
+xit:
     /* release allocated memory */
     if (bitData) free(bitData);
     if (plane1) free(plane1);
     if (plane2) free(plane2);
     if (plane3) free(plane3);
 
-    return 0;
+    return code;
 }
 
 /*
diff --git a/devices/gdevdm24.c b/devices/gdevdm24.c
index ae7484c..62b7ba8 100644
--- a/devices/gdevdm24.c
+++ b/devices/gdevdm24.c
@@ -64,7 +64,7 @@ dot24_print_page (gx_device_printer *pdev, gp_file *prn_stream, char *init_strin
   int y_passes;
   int dots_per_space;
   int bytes_per_space;
-  int skip = 0, lnum = 0, ypass;
+  int skip = 0, lnum = 0, code = 0, ypass;
 
   xres = (int)pdev->x_pixels_per_inch;
   yres = (int)pdev->y_pixels_per_inch;
@@ -76,7 +76,7 @@ dot24_print_page (gx_device_printer *pdev, gp_file *prn_stream, char *init_strin
     /* We divide by bytes_per_space later on. */
     return_error(gs_error_rangecheck);
   }
-  
+
   bits_per_column = (y_high ? 48 : 24);
   line_size = gdev_prn_raster (pdev);
   in_size = line_size * bits_per_column;
@@ -111,7 +111,9 @@ dot24_print_page (gx_device_printer *pdev, gp_file *prn_stream, char *init_strin
       int lcnt;
 
       /* Copy 1 scan line and test for all zero. */
-      gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
+      code = gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
+      if (code < 0)
+          goto xit;
       if (in[0] == 0
           && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
         {
@@ -138,27 +140,40 @@ dot24_print_page (gx_device_printer *pdev, gp_file *prn_stream, char *init_strin
       /* Copy the rest of the scan lines. */
       if (y_high)
         {
+          /* NOTE: even though fixed to not ignore return < 0 from gdev_prn_copy_scan_lines, */
+          /*       this code seems wrong -- it doesn't seem to match the 'else' method.      */
           inp = in + line_size;
-          for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
-            if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
-                                           line_size))
+          for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size) {
+            code = gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp, line_size);
+            if (code < 0)
+                goto xit;
+            if (code == 0)
               {
+                /* Pad with lines of zeros. */
                 memset (inp, 0, (24 - lcnt) * line_size);
                 break;
               }
+          }
           inp = in + line_size * 24;
-          for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
-            if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
-                                           line_size))
+          for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size) {
+            code = gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp, line_size);
+            if (code < 0)
+                goto xit;
+            if (code == 0)
               {
+                /* Pad with lines of zeros. */
                 memset (inp, 0, (24 - lcnt) * line_size);
                 break;
               }
+          }
         }
       else
         {
-          lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
+          code = gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
                                                in_size - line_size);
+          if (code < 0)
+              goto xit;
+          lcnt = code + 1;	/* FIXME: why +1 */
           if (lcnt < 24)
             /* Pad with lines of zeros. */
             memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
@@ -242,10 +257,11 @@ dot24_print_page (gx_device_printer *pdev, gp_file *prn_stream, char *init_strin
   gp_fputs ("\f\033@", prn_stream);
   gp_fflush (prn_stream);
 
+xit:
   gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)");
   gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)");
 
-  return 0;
+  return code;
 }
 
 /* Output a single graphics command. */
diff --git a/devices/gdevepsc.c b/devices/gdevepsc.c
index 49e83f0..f6fa2b3 100644
--- a/devices/gdevepsc.c
+++ b/devices/gdevepsc.c
@@ -184,7 +184,7 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     int last_pass;
     int dots_per_space; 
     int bytes_per_space;
-    int skip = 0, lnum = 0, pass;
+    int skip = 0, lnum = 0, code = 0, pass;
 
     byte *color_in;
     int color_line_size, color_in_size;
@@ -232,7 +232,7 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
         if (out)
             gs_free(pdev->memory, (char *)out, out_size + 1, 1,
                     "epsc_print_page(out)");
-        return -1;
+        return_error(gs_error_VMerror);
     }
 
     /* Initialize the printer and reset the margins. */
@@ -248,7 +248,7 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
                     "epsc_print_page(in)");
             gs_free(pdev->memory, (char *)out, out_size + 1, 1,
                     "epsc_print_page(out)");
-            return (-1);
+            return_error(gs_error_VMerror);
         }
     } else {
         color_in = in;
@@ -263,7 +263,9 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
         byte *nextmono = NULL;  /* position to map next color */
 
         /* Copy 1 scan line and test for all zero. */
-        gdev_prn_copy_scan_lines(pdev, lnum, color_in, color_line_size);
+        code = gdev_prn_copy_scan_lines(pdev, lnum, color_in, color_line_size);
+        if (code < 0)
+            goto xit;
 
         if (color_in[0] == 0 &&
             !memcmp((char *)color_in, (char *)color_in + 1,
@@ -283,9 +285,12 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
             gp_fprintf(prn_stream, "\033J%c", skip);
 
         /* Copy the rest of the scan lines. */
-        lcnt = 1 + gdev_prn_copy_scan_lines(pdev, lnum + 1,
+        code = gdev_prn_copy_scan_lines(pdev, lnum + 1,
                                             color_in + color_line_size,
                                             color_in_size - color_line_size);
+         if (code < 0)
+             goto xit;
+         lcnt = code + 1;
 
         if (lcnt < 8 * y_mult) {
             memset((char *)(color_in + lcnt * color_line_size), 0,
@@ -453,13 +458,14 @@ epsc_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     /* Eject the page and reinitialize the printer */
     gp_fputs("\f\033@", prn_stream);
 
+xit:
     gs_free(pdev->memory, (char *)out, out_size + 1, 1,
             "epsc_print_page(out)");
     gs_free(pdev->memory, (char *)in, in_size + 1, 1, "epsc_print_page(in)");
     if (gx_device_has_color(pdev))
         gs_free(pdev->memory, (char *)color_in, color_in_size + 1, 1,
                 "epsc_print_page(rin)");
-    return 0;
+    return code;
 }
 
 /* Output a single graphics command. */
diff --git a/devices/gdevepsn.c b/devices/gdevepsn.c
index 3e53883..c69e4b5 100644
--- a/devices/gdevepsn.c
+++ b/devices/gdevepsn.c
@@ -159,22 +159,38 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
         int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
         /* Note that in_size is a multiple of 8. */
         int in_size = line_size * (8 * in_y_mult);
-        byte *buf1;
-        byte *buf2;
+        byte *buf1 = NULL;
+        byte *buf2 = NULL;
         byte *in;
         byte *out;
         int out_y_mult = (y_24pin ? 3 : 1);
         int x_dpi = (int)pdev->x_pixels_per_inch;
-        char start_graphics =
-                (y_24pin ? graphics_modes_24 : graphics_modes_9)[x_dpi / 60];
-        int first_pass = (start_graphics & DD ? 1 : 0);
-        int last_pass = first_pass * (y_9pin_high == 2 ? 1 : 2);
         int y_passes = (y_9pin_high ? 3 : 1);
         int dots_per_space = x_dpi / 10;	/* pica space = 1/10" */
         int bytes_per_space = dots_per_space * out_y_mult;
         int tab_min_pixels = x_dpi * MIN_TAB_10THS / 10;
         int skip = 0, lnum = 0, pass, ypass;
+        int code = 0;
         
+        char start_graphics;
+        int first_pass;
+        int last_pass;
+
+        if (y_24pin) {
+            if (x_dpi / 60 >= sizeof(graphics_modes_24) / sizeof(graphics_modes_24[0])) {
+                return_error(gs_error_rangecheck);
+            }
+            start_graphics = graphics_modes_24[x_dpi / 60];
+        }
+        else {
+            if (x_dpi / 60 >= sizeof(graphics_modes_9) / sizeof(graphics_modes_9[0])) {
+                return_error(gs_error_rangecheck);
+            }
+            start_graphics = graphics_modes_9[x_dpi / 60];
+        }
+        first_pass = (start_graphics & DD ? 1 : 0);
+        last_pass = first_pass * (y_9pin_high == 2 ? 1 : 2);
+
         if (bytes_per_space == 0) {
             /* This avoids divide by zero later on, bug 701843. */
             return_error(gs_error_rangecheck);
@@ -187,12 +203,9 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
         
 
         /* Check allocations */
-        if ( buf1 == 0 || buf2 == 0 )
-        {	if ( buf1 )
-                  gs_free(pdev->memory, (char *)buf1, in_size, 1, "eps_print_page(buf1)");
-                if ( buf2 )
-                  gs_free(pdev->memory, (char *)buf2, in_size, 1, "eps_print_page(buf2)");
-                return_error(gs_error_VMerror);
+        if ( buf1 == 0 || buf2 == 0 ) {
+            code = gs_error_VMerror;
+            goto xit;
         }
 
         /* Initialize the printer and reset the margins. */
@@ -218,7 +231,9 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
                 int lcnt;
 
                 /* Copy 1 scan line and test for all zero. */
-                gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                if (code < 0)
+                    goto xit;
                 if ( in_data[0] == 0 &&
                      !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
                    )
@@ -240,7 +255,9 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
                 }
 
                 /* Copy the the scan lines. */
-                lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                code = lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                if (code < 0)
+                    goto xit;
                 if ( lcnt < 8 * in_y_mult )
                 {	/* Pad with lines of zeros. */
                         memset(in + lcnt * line_size, 0,
@@ -255,7 +272,7 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
                         /* can't print neighboring dots. */
                         int i;
                         for ( i = 0; i < line_size * in_y_mult; ++i )
-                                in_data[i] |= in_data[i + line_size];
+                                in[i] |= in[i + line_size];
                 }
 
                 if ( y_9pin_high )
@@ -402,9 +419,14 @@ eps_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high,
         gp_fputs(end_string, prn_stream);
         gp_fflush(prn_stream);
 
-        gs_free(pdev->memory, (char *)buf2, in_size, 1, "eps_print_page(buf2)");
-        gs_free(pdev->memory, (char *)buf1, in_size, 1, "eps_print_page(buf1)");
-        return 0;
+xit:
+        if ( buf1 )
+            gs_free(pdev->memory, (char *)buf1, in_size, 1, "eps_print_page(buf1)");
+        if ( buf2 )
+            gs_free(pdev->memory, (char *)buf2, in_size, 1, "eps_print_page(buf2)");
+        if (code < 0)
+            return_error(code);
+        return code;
 }
 
 /* Output a single graphics command. */
diff --git a/devices/gdevescp.c b/devices/gdevescp.c
index 0004319..005fa58 100644
--- a/devices/gdevescp.c
+++ b/devices/gdevescp.c
@@ -119,7 +119,7 @@ escp2_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         byte *out = buf2;
 
         int skip, lnum, top, bottom, left, width;
-        int count, i;
+        int code = 0, count, i;
 
         /*
         ** Check for valid resolution:
@@ -141,12 +141,9 @@ escp2_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         ** Check buffer allocations:
         */
 
-        if ( buf1 == 0 || buf2 == 0 )
-        {	if ( buf1 )
-                  gs_free(pdev->memory, (char *)buf1, in_size, 1, "escp2_print_page(buf1)");
-                if ( buf2 )
-                  gs_free(pdev->memory, (char *)buf2, in_size, 1, "escp2_print_page(buf2)");
-                return_error(gs_error_VMerror);
+        if ( buf1 == 0 || buf2 == 0 ) {
+           code = gs_error_VMerror;
+           goto xit;
         }
 
         /*
@@ -218,14 +215,18 @@ escp2_print_page(gx_device_printer *pdev, gp_file *prn_stream)
                 ** Check buffer for 0 data. We can't do this mid-band
                 */
 
-                gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                if (code < 0)
+                   goto xit;
                 while ( in_data[0] == 0 &&
                         !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
                         lnum < bottom )
                 {
                         lnum++;
                         skip++;
-                        gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                        code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                        if (code < 0)
+                            goto xit;
                 }
 
                 if(lnum == bottom ) break;	/* finished with this page */
@@ -241,7 +242,9 @@ escp2_print_page(gx_device_printer *pdev, gp_file *prn_stream)
                    skip = 0;
                 }
 
-                lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                code = lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                if (lcnt < 0)
+                    goto xit;
 
                 /*
                 ** Check to see if we don't have enough data to fill an entire
@@ -403,7 +406,13 @@ escp2_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         gp_fputs("\f\033@", prn_stream);
         gp_fflush(prn_stream);
 
-        gs_free(pdev->memory, (char *)buf2, in_size, 1, "escp2_print_page(buf2)");
-        gs_free(pdev->memory, (char *)buf1, in_size, 1, "escp2_print_page(buf1)");
-        return 0;
+xit:
+	if ( buf1 )
+            gs_free(pdev->memory, (char *)buf1, in_size, 1, "escp2_print_page(buf1)");
+        if ( buf2 )
+            gs_free(pdev->memory, (char *)buf2, in_size, 1, "escp2_print_page(buf2)");
+        if (code < 0)
+           return_error(code);
+
+        return code;
 }
diff --git a/devices/gdevgprf.c b/devices/gdevgprf.c
index ff383e5..492b1c2 100644
--- a/devices/gdevgprf.c
+++ b/devices/gdevgprf.c
@@ -372,6 +372,8 @@ gprf_prn_open(gx_device * pdev)
         pdev_gprf->icclink = gsicc_alloc_link_dev(pdev_gprf->memory,
             profile_struct->device_profile[0], profile_struct->postren_profile,
             &rendering_params);
+        if (pdev_gprf->icclink == NULL)
+            code = gs_error_VMerror;
     }
     return code;
 }
diff --git a/devices/gdevhl7x.c b/devices/gdevhl7x.c
index 786449d..1a3e594 100644
--- a/devices/gdevhl7x.c
+++ b/devices/gdevhl7x.c
@@ -108,7 +108,7 @@ typedef struct {
 
 typedef struct {
   short  previousSize;
-  Byte   previousData[1500]; /* Size bigger than any possible line */
+  Byte*  previousData;
   short  nbBlankLines;
   short  nbLinesSent;
   short  pageWidth;
@@ -139,7 +139,9 @@ static int dumpPage(gx_device_printer * pSource,
                       ByteList          * pCommandList,
                       Summary           * pSummary
                       );
-static void initSummary(Summary * s,short pw, short ph, short resolution);
+static int initSummary(gx_device_printer* pdev, Summary * s,short pw, short ph, short resolution);
+
+static void freeSummary(gx_device_printer* pdev, Summary * s);
 
 static void resetPreviousData(Summary * s);
 
@@ -319,6 +321,7 @@ static int
 hl7x0_print_page(gx_device_printer *pdev, gp_file *printStream, int ptype,
   int dots_per_inch, ByteList *initCommand)
 {
+  int code;
         /* UTILE*/
   /* Command for a formFeed (we can't use strings because of the zeroes...)*/
   Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'};
@@ -338,12 +341,17 @@ hl7x0_print_page(gx_device_printer *pdev, gp_file *printStream, int ptype,
         /* bool dupset = pdev->Duplex_set >= 0; */
         Summary pageSummary;
         ByteList commandsBuffer;
-        initSummary(&pageSummary,
+        if ( storage == 0 )	/* can't allocate working area */
+                return_error(gs_error_VMerror);
+        code = initSummary(pdev,
+                    &pageSummary,
                     line_size,
                     num_rows,
                     x_dpi);
-        if ( storage == 0 )	/* can't allocate working area */
-                return_error(gs_error_VMerror);
+        if (code < 0) {
+            gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page");
+            return code;
+        }
         initByteList(&commandsBuffer, storage, sizeOfBuffer,0 );
         /* PLUS A MOI */
         if ( pdev->PageCount == 0 )
@@ -358,9 +366,11 @@ hl7x0_print_page(gx_device_printer *pdev, gp_file *printStream, int ptype,
                             storage + sizeOfBuffer, /* The line buffer is after the dump buffer */
                             &commandsBuffer,
                             &pageSummary);
+            if (result < 0)
+                goto xit;
           dumpToPrinter(&commandsBuffer,printStream);
 
-        } while (result == DumpContinue);
+        } while (result == DumpContinue);	/* NB: at end  of page, result will be DumpFinished == 0 */
 
         /* end raster graphics and eject page */
         initByteList(&formFeedCommand,
@@ -369,10 +379,12 @@ hl7x0_print_page(gx_device_printer *pdev, gp_file *printStream, int ptype,
                      sizeof(FormFeed)); /* First free byte */
         dumpToPrinter(&formFeedCommand, printStream);
 
+xit:
         /* free temporary storage */
+        freeSummary(pdev, &pageSummary);
         gs_free(pdev->memory, (char *)storage, storage_size_words, 1, "hl7X0_print_page");
 
-        return 0; /* If we reach this line, it means there was no error */
+        return result; /* If we reach this line, it means there was no error */
 }
 
 /*
@@ -413,14 +425,23 @@ return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8;
 /*
  * First values in a Summary
  */
-static void initSummary(Summary * s,short pw, short ph, short resolution){
+static int initSummary(gx_device_printer* pdev, Summary * s,short pw, short ph, short resolution){
   s->previousSize = -1 ;
+  s->previousData = gs_malloc(pdev->memory, pw, 1, "initSummary");
   s->nbBlankLines = 1;
   s->nbLinesSent = 0;
   s->pageWidth = pw; /* In Bytes */
   s->pageHeight = ph;
   s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ;
   s->resolution = resolution;
+  if (!s->previousData) {
+    return_error(gs_error_VMerror);
+  }
+  return 0;
+}
+
+static void freeSummary(gx_device_printer* pdev, Summary * s) {
+  gs_free(pdev->memory, s->previousData, s->pageWidth, 1, "freeSummary");
 }
 
 /*
@@ -445,6 +466,8 @@ static int dumpPage(gx_device_printer * pSource,
   short  lineNB;
   short usefulLength;
   short tmpLength;
+  int code = 0;
+
   /* Initializations */
   /* Make room for size of commands buffer */
   pSaveCommandStart = currentPosition(pCommandList);
@@ -454,10 +477,12 @@ static int dumpPage(gx_device_printer * pSource,
   for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ;
        lineNB < pSummary->pageHeight ; lineNB ++ ) {
     /* Fetch the line and put it into the buffer */
-    gdev_prn_copy_scan_lines(pSource,
+    code = gdev_prn_copy_scan_lines(pSource,
                              lineNB,
                              pLineTmp,
                              pSummary->pageWidth);
+    if (code < 0)
+        return code;
 
     usefulLength =  stripTrailingBlanks(pLineTmp,pSummary->pageWidth);
     if (usefulLength != 0) {
diff --git a/devices/gdevicov.c b/devices/gdevicov.c
index 4f4d7f5..517ca4f 100644
--- a/devices/gdevicov.c
+++ b/devices/gdevicov.c
@@ -37,18 +37,20 @@
 static int
 cov_write_page(gx_device_printer *pdev, gp_file *file)
 {
-    int code = 0;
+    int code = 0, ecode = 0;
     int raster = gdev_prn_raster(pdev);
     int height = pdev->height;
     byte *line = gs_alloc_bytes(pdev->memory, raster, "ink coverage plugin buffer");
     int y;
     uint64_t c_pix = 0, m_pix = 0, y_pix = 0, k_pix = 0, total_pix = 0;
 
+    if (line == NULL)
+        return gs_error_VMerror;
     for (y = 0; y < height; y++) {
         byte *row, *end;
 
-        code = gdev_prn_get_bits(pdev, y, line, &row);
-        if (code < 0)
+        ecode = gdev_prn_get_bits(pdev, y, line, &row);
+        if (ecode < 0)
             break;
         end = row + raster;
 
@@ -90,14 +92,14 @@ cov_write_page(gx_device_printer *pdev, gp_file *file)
         }
     }
 
-    return 0;
+    return (code > 0) ? ecode : 0;
 }
 
 /*  cov_write_page2 gave ink coverage values not ratecoverage */
 
 static int cov_write_page_ink(gx_device_printer *pdev, gp_file *file)
 {
-    int code = 0;
+    int code = 0, ecode = 0;
     int raster = gdev_prn_raster(pdev);
     int height = pdev->height;
 	double dc_pix=0;
@@ -109,11 +111,13 @@ static int cov_write_page_ink(gx_device_printer *pdev, gp_file *file)
     int y;
     uint64_t  total_pix = 0;
 
+    if (line == NULL)
+        return gs_error_VMerror;
     for (y = 0; y < height; y++) {
         byte *row, *end;
 
-        code = gdev_prn_get_bits(pdev, y, line, &row);
-        if (code < 0)
+        ecode = gdev_prn_get_bits(pdev, y, line, &row);
+        if (ecode < 0)
             break;
         end = row + raster;
 
@@ -159,7 +163,7 @@ static int cov_write_page_ink(gx_device_printer *pdev, gp_file *file)
         }
     }
 
-    return 0;
+    return (code > 0) ? ecode : 0;
 }
 
 static const gx_device_procs cov_procs =
diff --git a/devices/gdevifno.c b/devices/gdevifno.c
index 31aa514..22d5837 100644
--- a/devices/gdevifno.c
+++ b/devices/gdevifno.c
@@ -281,6 +281,7 @@ inferno_print_page(gx_device_printer *pdev, gp_file *f)
         int gsbpl;
         ulong u;
         ushort us;
+        int code = 0;
 
         inferno_device *bdev = (inferno_device *) pdev;
         Rectangle r;
@@ -319,7 +320,10 @@ inferno_print_page(gx_device_printer *pdev, gp_file *f)
          * to save all the ldepth lookups.
          */
         for(y=0; y<pdev->height; y++) {
-                gdev_prn_get_bits(pdev, y, buf, &p);
+
+                code = gdev_prn_get_bits(pdev, y, buf, &p);
+                if (code < 0)
+                    goto xit;
                 for(x=0; x<pdev->width; x++) {
                         us = (p[2*x]<<8) | p[2*x+1];
 
@@ -372,12 +376,13 @@ inferno_print_page(gx_device_printer *pdev, gp_file *f)
                         return_error(gs_error_Fatal);
                 }
         }
-        gs_free_object(bdev->memory, buf, "inferno line buffer");
         if(writeimageblock(w, nil, 0, bdev->memory) == ERROR) {
                 return_error(gs_error_Fatal);
         }
+xit:
+        gs_free_object(bdev->memory, buf, "inferno line buffer");
 
-        return 0;
+        return code;
 }
 
 /*
diff --git a/devices/gdevimgn.c b/devices/gdevimgn.c
index 7340c8d..7c707bd 100644
--- a/devices/gdevimgn.c
+++ b/devices/gdevimgn.c
@@ -379,6 +379,7 @@ imagen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
   /* page totals */
   int totalBlankSwatches;
   int totalGreySwatches;
+  int code = 0;
 
   /* ----------------------------------------- */
   /* Start of routine                          */
@@ -406,8 +407,8 @@ imagen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
   swatchMap = (byte *)gs_malloc(pdev->memory, BIGSIZE,swatchCount / BIGSIZE + 1,
         "imagen_print_page(swatchMap)" );
 
-  if ( in == 0 || out == 0 )
-    return -1;
+  if ( in == 0 || out == 0 || swatchMap == 0)
+    goto xit;
 
   /* Initialize the page */
   iWrite(prn_stream,iPAGE);
@@ -450,7 +451,9 @@ imagen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
       } /* for temp */
 
       /* get one line */
-      gdev_prn_copy_scan_lines(pdev, lnum + swatchLine, in, line_size);
+      code = gdev_prn_copy_scan_lines(pdev, lnum + swatchLine, in, line_size);
+      if (code < 0)
+          goto xit;
       DebugMsg(5,"Got scan line %d ", lnum + swatchLine);
       DebugMsg(5,"line %d \n", swatchLine);
 
@@ -553,6 +556,7 @@ imagen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
   gp_fflush(prn_stream);
 
+xit:
   gs_free(pdev->memory, (char *)out, TotalBytesPerSw, swatchCount+1, "imagen_print_page(out)");
   gs_free(pdev->memory, (char *)swatchMap, BIGSIZE, swatchCount / BIGSIZE + 1,
         "imagen_print_page(swatchMap)" );
@@ -564,6 +568,6 @@ imagen_print_page(gx_device_printer *pdev, gp_file *prn_stream)
   DebugMsg(1,"%s\n","End of imagen_print_page");
 
   /* ----------------------------------------- */
-  return 0;
+  return code;
 
 } /* imagen_print_page */
diff --git a/devices/gdevjbig2.c b/devices/gdevjbig2.c
index ce85aa2..0555081 100644
--- a/devices/gdevjbig2.c
+++ b/devices/gdevjbig2.c
@@ -89,7 +89,7 @@ jbig2_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     swrite_file(&fstrm, prn_stream, fbuf, fbuf_size);
     s_init(&cstrm, mem);
     s_std_init(&cstrm, jbuf, jbuf_size, &s_filter_write_procs,
-               s_mode_write);
+               s_devices/gdevescp.cmode_write);
     cstrm.state = (stream_state *) & state;
     cstrm.procs.process = state.templat->process;
     cstrm.strm = &fstrm;
@@ -108,7 +108,9 @@ jbig2_print_page(gx_device_printer * pdev, gp_file * prn_stream)
             code = gs_note_error(gs_error_ioerror);
             goto done;
         }
-        gdev_prn_get_bits(pdev, lnum, in, &data);        
+        code = gdev_prn_get_bits(pdev, lnum, in, &data);
+        if (code < 0)
+            goto done;
         sputs(&cstrm, data, state.stride, &ignore_used);
     }
 
diff --git a/devices/gdevjpx.c b/devices/gdevjpx.c
index 0ba4e1a..e38f540 100644
--- a/devices/gdevjpx.c
+++ b/devices/gdevjpx.c
@@ -209,7 +209,9 @@ jpx_print_page(gx_device_printer * pdev, gp_file * prn_stream)
             code = gs_note_error(gs_error_ioerror);
             goto done;
         }
-        gdev_prn_get_bits(pdev, lnum, in, &data);
+        code = gdev_prn_get_bits(pdev, lnum, in, &data);
+        if (code < 0)
+            goto done;
         sputs(&cstrm, data, state.stride, &ignore_used);
     }
 
diff --git a/devices/gdevl31s.c b/devices/gdevl31s.c
index 0871920..b21b18c 100644
--- a/devices/gdevl31s.c
+++ b/devices/gdevl31s.c
@@ -180,6 +180,8 @@ lj3100sw_print_page_copies(gx_device_printer *pdev, gp_file *prn_stream, int num
         gs_memory_t *mem = pdev->memory;
         byte *in = (byte *)gs_malloc(mem, line_size, 1, "lj3100sw_print_page");
         byte *data;
+        int ecode = 0;
+
         if (in == 0)
                 return_error(gs_error_VMerror);
         if (gdev_prn_file_is_new(pdev)) {
@@ -211,7 +213,10 @@ lj3100sw_print_page_copies(gx_device_printer *pdev, gp_file *prn_stream, int num
                         int count = 0;
                         int bit_index = 0;
                         uint tmp = 0;
-                        gdev_prn_get_bits(pdev, i, in, &data);
+
+                        ecode = gdev_prn_get_bits(pdev, i, in, &data);
+                        if (ecode < 0)
+                            goto xit;
                         for (j = 0; j <= printer_width; j++) {
                                 int xoffset = (printer_width - paper_width) / 2;
                                 int newcolor = 0;
@@ -261,8 +266,9 @@ lj3100sw_print_page_copies(gx_device_printer *pdev, gp_file *prn_stream, int num
         for (i = 0; i < 4 * ppdev->NumCopies; i++)
                 lj3100sw_output_section_header(prn_stream, 54, 0, 0);
 
+xit:
         gs_free(mem, (char *)in, line_size, 1, "lj3100sw_print_page");
-        return 0;
+        return ecode;
 }
 
 static int
diff --git a/devices/gdevlbp8.c b/devices/gdevlbp8.c
index 5b99cf2..3136772 100644
--- a/devices/gdevlbp8.c
+++ b/devices/gdevlbp8.c
@@ -108,6 +108,7 @@ can_print_page(gx_device_printer *pdev, gp_file *prn_stream,
         char *out_data;
         int last_line_nro = 0;
         int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
+        int code = 0;
 
         data = (char *)gs_alloc_bytes(pdev->memory,
                                       line_size*2,
@@ -124,8 +125,10 @@ can_print_page(gx_device_printer *pdev, gp_file *prn_stream,
 
             for ( lnum = 0; lnum < pdev->height; lnum++ ) {
                 char *end_data = data + line_size;
-                gdev_prn_copy_scan_lines(pdev, lnum,
-                                         (byte *)data, line_size);
+                code = gdev_prn_copy_scan_lines(pdev, lnum,
+                                               (byte *)data, line_size);
+                if (code < 0)
+                    goto xit;
                 /* Mask off 1-bits beyond the line width. */
                 end_data[-1] &= rmask;
                 /* Remove trailing 0s. */
@@ -199,9 +202,10 @@ can_print_page(gx_device_printer *pdev, gp_file *prn_stream,
         if (end != NULL)
             (void)gp_fwrite(end, end_size, 1, prn_stream);
 
+xit:
         gs_free_object(pdev->memory, data, "lbp8_line_buffer");
 
-        return 0;
+        return code;
 }
 
 /* Print an LBP-8 page. */
diff --git a/devices/gdevlj56.c b/devices/gdevlj56.c
index 4a473e0..6199e5b 100644
--- a/devices/gdevlj56.c
+++ b/devices/gdevlj56.c
@@ -192,7 +192,7 @@ ljet5_print_page(gx_device_printer * pdev, gp_file * prn_stream)
 
         code = gdev_prn_copy_scan_lines(pdev, lnum, (byte *) line, line_size);
         if (code < 0)
-            goto fin;
+            goto done;
         px_put_us(s, lnum);
         PX_PUT_LIT(s, line_header);
         ncompr = gdev_pcl_mode2compress_padded(line, line + line_size_words,
@@ -202,7 +202,6 @@ ljet5_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     }
 
     /* Finish up. */
-  fin:
     spputc(s, pxtEndImage);
     spputc(s, pxtEndPage);
     sflush(s);
diff --git a/devices/gdevlp8k.c b/devices/gdevlp8k.c
index 55af94d..58ae070 100644
--- a/devices/gdevlp8k.c
+++ b/devices/gdevlp8k.c
@@ -193,18 +193,13 @@ lp8000_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         byte *out = buf2;
 
         int lnum, top, bottom, left, width;
-        int count, left1, left2, left0;
+        int code = 0, count, left1, left2, left0;
 
 /* Check  memory allocations  */
 
-        if ( buf1 == 0 || buf2 == 0 )
-        {       if ( buf1 )
-                gs_free(pdev->memory, (char *)buf1, in_size, 1, "lp8000_print_page(buf1)");
-
-                if ( buf2 )
-                gs_free(pdev->memory, (char *)buf2, in_size, 1, "lp8000_print_page(buf2)");
-
-          return_error(gs_error_VMerror);
+        if ( buf1 == 0 || buf2 == 0 ) {
+            code = gs_error_VMerror;
+            goto xit;
         }
 
 /* Initialize the printer */
@@ -265,19 +260,25 @@ starting X value of the printer line.
                 ** Check buffer for 0 data.
                 */
 
-                gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                if (code < 0)
+                    goto xit;
                 while ( in_data[0] == 0 &&
                         !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1) &&
                         lnum < bottom )
                 {
                         lnum++;
-                        gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                        code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                        if (code < 0)
+                            goto xit;
                 }
 
                 if(lnum == bottom ) break;
                 /* finished with this page */
 
-                (void)gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                code = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+                if (code < 0)
+                    goto xit;
 
                 inp = in  + left;
                 in_end = inp + width;
@@ -397,7 +398,14 @@ Y coordinate of the printer equals (lnum - 60)
 
         gp_fflush(prn_stream);
 
-        gs_free(pdev->memory, (char *)buf2, in_size, 1, "lp8000_print_page(buf2)");
-        gs_free(pdev->memory, (char *)buf1, in_size, 1, "lp8000_print_page(buf1)");
-        return 0;
+xit:
+        if ( buf1 )
+           gs_free(pdev->memory, (char *)buf1, in_size, 1, "lp8000_print_page(buf1)");
+        if ( buf2 )
+           gs_free(pdev->memory, (char *)buf2, in_size, 1, "lp8000_print_page(buf2)");
+
+        if (code < 0)
+            return_error(code);
+
+        return code;
 }
diff --git a/devices/gdevlxm.c b/devices/gdevlxm.c
index 4b0f26e..fe577c3 100644
--- a/devices/gdevlxm.c
+++ b/devices/gdevlxm.c
@@ -146,6 +146,7 @@ lxm5700m_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     int lnum,minX, maxX, i, l, highestX, leastX, extent;
     int direction = RIGHTWARD;
     int lastY = 0;
+    int code = 0;
 
     int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
     /* Note that in_size is a multiple of 8. */
@@ -158,12 +159,8 @@ lxm5700m_print_page(gx_device_printer *pdev, gp_file *prn_stream)
 
     /* Check allocations */
     if ( buf1 == 0 || swipeBuf == 0 ) {
-        if ( buf1 )
-quit_ignomiously: /* and a goto into an if statement is pretty ignomious! */
-        gs_free(pdev->memory, (char *)buf1, in_size, 1, "lxm_print_page(buf1)");
-        if ( swipeBuf )
-            gs_free(pdev->memory, (char *)swipeBuf, swipeBuf_size, 1, "lxm_print_page(swipeBuf)");
-        return_error(gs_error_VMerror);
+        code = gs_error_VMerror;
+        goto xit;
     }
 
     {	/* Initialize the printer and reset the margins. */
@@ -186,7 +183,9 @@ quit_ignomiously: /* and a goto into an if statement is pretty ignomious! */
 
             for (l=lnum; l<pdev->height; l++) {
                 /* Copy 1 scan line and test for all zero. */
-                gdev_prn_get_bits(pdev, l, in, &in_data);
+                code = gdev_prn_get_bits(pdev, l, in, &in_data);
+                if (code < 0)
+                    goto xit;
                 if ( in_data[0] != 0 ||
                      memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
                      ) {
@@ -211,7 +210,9 @@ quit_ignomiously: /* and a goto into an if statement is pretty ignomious! */
         }
 
         /* Copy the the scan lines. */
-        lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+        code = lcnt = gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
+        if (code < 0)
+            goto xit;
         if ( lcnt < swipeHeight ) {
             /* Pad with lines of zeros. */
             memset(in + lcnt * line_size, 0,
@@ -251,7 +252,7 @@ quit_ignomiously: /* and a goto into an if statement is pretty ignomious! */
                 size_t  outp_offset = outp - swipeBuf;\
                 size_t  swipeBuf_size_new = swipeBuf_size * 2;\
                 byte*   swipeBuf_new = gs_malloc(pdev->memory, swipeBuf_size_new, 1, "lxm_print_page(swipeBuf_new)");\
-                if (!swipeBuf_new) goto quit_ignomiously;\
+                if (!swipeBuf_new) { code = gs_error_VMerror; goto xit; }\
                 memcpy(swipeBuf_new, swipeBuf, swipeBuf_size);\
                 gs_free(pdev->memory, swipeBuf, swipeBuf_size, 1, "lxm_print_page(swipeBuf)");\
                 swipeBuf_size = swipeBuf_size_new;\
@@ -372,9 +373,14 @@ quit_ignomiously: /* and a goto into an if statement is pretty ignomious! */
     }
     gp_fflush(prn_stream);
 
-    gs_free(pdev->memory, (char *)swipeBuf, swipeBuf_size, 1, "lxm_print_page(swipeBuf)");
-    gs_free(pdev->memory, (char *)buf1, in_size, 1, "lxm_print_page(buf1)");
-    return 0;
+xit:
+    if ( buf1 )
+        gs_free(pdev->memory, (char *)buf1, in_size, 1, "lxm_print_page(buf1)");
+    if ( swipeBuf )
+        gs_free(pdev->memory, (char *)swipeBuf, swipeBuf_size, 1, "lxm_print_page(swipeBuf)");
+    if (code < 0)
+        return_error(code);
+    return code;
 }
 
 /*
diff --git a/devices/gdevmgr.c b/devices/gdevmgr.c
index 07761da..c6b6605 100644
--- a/devices/gdevmgr.c
+++ b/devices/gdevmgr.c
@@ -131,18 +131,20 @@ mgr_begin_page(gx_device_mgr *bdev, gp_file *pstream, mgr_cursor *pcur)
         return 0;
 }
 
-/* Advance to the next row.  Return 0 if more, 1 if done. */
+/* Advance to the next row.  Return 0 if more, 1 if done. <0 if error */
 static int
 mgr_next_row(mgr_cursor *pcur)
-{	if ( pcur->lnum >= pcur->dev->height )
+{	int code = 0;
+
+        if ( pcur->lnum >= pcur->dev->height )
         {	gs_free(((gx_device_printer *)pcur->dev)->memory,
                         (char *)pcur->data, pcur->line_size, 1,
                         "mgr_next_row(done)");
                 return 1;
-           }
-        gdev_prn_copy_scan_lines((gx_device_printer *)pcur->dev,
+         }
+        code = gdev_prn_copy_scan_lines((gx_device_printer *)pcur->dev,
                                  pcur->lnum++, pcur->data, pcur->line_size);
-        return 0;
+        return code < 0 ? code : 0;
 }
 
 /* ------ Individual page printing routines ------ */
@@ -219,6 +221,8 @@ mgrN_print_page(gx_device_printer *pdev, gp_file *pstream)
 
         if ( bdev->mgr_depth != 8 )
             data = (byte *)gs_malloc(pdev->memory, mgr_line_size, 1, "mgrN_print_page");
+        if (data == NULL)
+            return_error(gs_error_VMerror);
 
         while ( !(code = mgr_next_row(&cur)) )
            {
@@ -306,6 +310,8 @@ cmgrN_print_page(gx_device_printer *pdev, gp_file *pstream)
 	}
         mgr_line_size = mgr_wide / (8 / bdev->mgr_depth);
         data = (byte *)gs_malloc(pdev->memory, mgr_line_size, 1, "cmgrN_print_page");
+        if (data == NULL)
+            return_error(gs_error_VMerror);
 
         if ( bdev->mgr_depth == 8 ) {
             memset( table, 0, sizeof(table) );
diff --git a/devices/gdevn533.c b/devices/gdevn533.c
index 5130bd3..3572036 100644
--- a/devices/gdevn533.c
+++ b/devices/gdevn533.c
@@ -163,7 +163,7 @@ nwp533_close(gx_device *dev)
 static int
 nwp533_print_page(gx_device_printer *dev, gp_file *prn_stream)
 {
-  int lnum;
+  int lnum, code = 0;
   int line_size = gdev_mem_bytes_per_scan_line(dev);
   byte *in;
   int printer_file;
@@ -174,6 +174,8 @@ nwp533_print_page(gx_device_printer *dev, gp_file *prn_stream)
       line_size += 4 - (line_size % 4);
     }
   in = (byte *) gs_malloc(dev->memory, line_size, 1, "nwp533_output_page(in)");
+  if (in == NULL)
+      return_error(gs_error_VMerror);
  restart:
   if(ioctl(printer_file, LBIOCSTOP, 0) < 0)
     {
@@ -186,7 +188,9 @@ nwp533_print_page(gx_device_printer *dev, gp_file *prn_stream)
 
   for ( lnum = 0; lnum < dev->height; lnum++)
     {
-      gdev_prn_copy_scan_lines(prn_dev, lnum, in, line_size);
+      code = gdev_prn_copy_scan_lines(prn_dev, lnum, in, line_size);
+      if (code < 0)
+          goto xit;
       if(write(printer_file, in, line_size) != line_size)
         {
           perror("Writting to output");
@@ -201,7 +205,8 @@ nwp533_print_page(gx_device_printer *dev, gp_file *prn_stream)
       perror("Starting print");
       return_error(gs_error_ioerror);
     }
+xit:
   gs_free(dev->memory, in, line_size, 1, "nwp533_output_page(in)");
 
-  return 0;
+  return code;
 }
diff --git a/devices/gdevokii.c b/devices/gdevokii.c
index 97a1c3b..3350f6d 100644
--- a/devices/gdevokii.c
+++ b/devices/gdevokii.c
@@ -111,6 +111,7 @@ okiibm_print_page1(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high
         int y_passes;
         int skip = 0, lnum = 0, pass, ypass;
         int y_step = 0;
+        int code = 0;
 
         x_dpi = pdev->x_pixels_per_inch;
         if (x_dpi / 60 >= sizeof(graphics_modes_9)/sizeof(graphics_modes_9[0])) {
@@ -132,12 +133,9 @@ okiibm_print_page1(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high
         y_step = 0;
 
         /* Check allocations */
-        if ( buf1 == 0 || buf2 == 0 )
-        {	if ( buf1 )
-                  gs_free(pdev->memory, (char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
-                if ( buf2 )
-                  gs_free(pdev->memory, (char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
-                return_error(gs_error_VMerror);
+        if ( buf1 == 0 || buf2 == 0 ) {
+            code = gs_error_VMerror;
+            goto xit;
         }
 
         /* Initialize the printer. */
@@ -153,7 +151,9 @@ okiibm_print_page1(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high
                 int lcnt;
 
                 /* Copy 1 scan line and test for all zero. */
-                gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
+                if (code < 0)
+                    goto xit;
                 if ( in_data[0] == 0 &&
                      !memcmp((char *)in_data, (char *)in_data + 1, line_size - 1)
                    )
@@ -264,8 +264,13 @@ okiibm_print_page1(gx_device_printer *pdev, gp_file *prn_stream, int y_9pin_high
         gp_fwrite(end_string, 1, end_length, prn_stream);
         gp_fflush(prn_stream);
 
-        gs_free(pdev->memory, (char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
-        gs_free(pdev->memory, (char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
+xit:
+        if ( buf1 )
+            gs_free(pdev->memory, (char *)buf1, in_size, 1, "okiibm_print_page(buf1)");
+        if ( buf2 )
+            gs_free(pdev->memory, (char *)buf2, in_size, 1, "okiibm_print_page(buf2)");
+        if (code < 0)
+            return_error(code);
         return 0;
 }
 
diff --git a/devices/gdevpbm.c b/devices/gdevpbm.c
index 647349e..412d010 100644
--- a/devices/gdevpbm.c
+++ b/devices/gdevpbm.c
@@ -1054,6 +1054,8 @@ pnmcmyk_print_page(gx_device_printer *pdev, gp_file *pstream)
             !strncmp(pdev->fname, "/dev/null", min(strlen(pdev->fname), 9));
         int (*row_proc) (gx_device_printer *, byte *, int, gp_file *);
 
+        if (data == NULL)
+            return_error(gs_error_VMerror);
         if (!output_is_nul) {
             if (gp_fprintf(pstream, "P5\n") < 0) {	/* PGM raw */
                 code = gs_note_error(gs_error_ioerror);
diff --git a/devices/gdevpdfimg.c b/devices/gdevpdfimg.c
index bbeefc8..998574c 100644
--- a/devices/gdevpdfimg.c
+++ b/devices/gdevpdfimg.c
@@ -271,6 +271,10 @@ static int gdev_pdf_image_begin_page(gx_device_pdf_image *pdf_dev,
                     profile_struct->device_profile[0], profile_struct->postren_profile,
                     &rendering_params);
             }
+            if (pdf_dev->icclink == NULL) {
+                gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
+                return_error(gs_error_VMerror);
+            }
             /* If it is identity, release it now and set link to NULL */
             if (pdf_dev->icclink->is_identity) {
                 pdf_dev->icclink->procs.free_link(pdf_dev->icclink);
@@ -281,8 +285,10 @@ static int gdev_pdf_image_begin_page(gx_device_pdf_image *pdf_dev,
 
         /* Set up the stream and insert the file header */
         pdf_dev->strm = s_alloc(pdf_dev->memory->non_gc_memory, "pdfimage_open_temp_stream(strm)");
-        if (pdf_dev->strm == 0)
+        if (pdf_dev->strm == 0) {
+            gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
             return_error(gs_error_VMerror);
+        }
         pdf_dev->strm_buf = gs_alloc_bytes(pdf_dev->memory->non_gc_memory, pdf_dev->width * (pdf_dev->color_info.depth / 8),
                                        "pdfimage_open_temp_stream(strm_buf)");
         if (pdf_dev->strm_buf == 0) {
@@ -290,6 +296,7 @@ static int gdev_pdf_image_begin_page(gx_device_pdf_image *pdf_dev,
             gs_free_object(pdf_dev->memory->non_gc_memory, pdf_dev->strm,
                            "pdfimage_open_temp_stream(strm)");
             pdf_dev->strm = 0;
+            gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
             return_error(gs_error_VMerror);
         }
         swrite_file(pdf_dev->strm, pdf_dev->file, pdf_dev->strm_buf, pdf_dev->width * (pdf_dev->color_info.depth / 8));
@@ -1276,6 +1283,10 @@ static int gdev_PCLm_begin_page(gx_device_pdf_image *pdf_dev,
                     profile_struct->device_profile[0], profile_struct->postren_profile,
                     &rendering_params);
             }
+            if (pdf_dev->icclink == NULL) {
+                gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
+                return_error(gs_error_VMerror);
+            }
             /* If it is identity, release it now and set link to NULL */
             if (pdf_dev->icclink->is_identity) {
                 pdf_dev->icclink->procs.free_link(pdf_dev->icclink);
@@ -1286,8 +1297,10 @@ static int gdev_PCLm_begin_page(gx_device_pdf_image *pdf_dev,
 
         /* Set up the stream and insert the file header */
         pdf_dev->strm = s_alloc(pdf_dev->memory->non_gc_memory, "pdfimage_open_temp_stream(strm)");
-        if (pdf_dev->strm == 0)
+        if (pdf_dev->strm == 0) {
+            gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
             return_error(gs_error_VMerror);
+        }
         pdf_dev->strm_buf = gs_alloc_bytes(pdf_dev->memory->non_gc_memory, 512,
                                        "pdfimage_open_temp_stream(strm_buf)");
         if (pdf_dev->strm_buf == 0) {
@@ -1295,6 +1308,7 @@ static int gdev_PCLm_begin_page(gx_device_pdf_image *pdf_dev,
             gs_free_object(pdf_dev->memory->non_gc_memory, pdf_dev->strm,
                            "pdfimage_open_temp_stream(strm)");
             pdf_dev->strm = 0;
+            gs_free_object(pdf_dev->memory->non_gc_memory, page, "pdfimage create new page");
             return_error(gs_error_VMerror);
         }
         swrite_file(pdf_dev->strm, pdf_dev->file, pdf_dev->strm_buf, 512);
diff --git a/devices/gdevperm.c b/devices/gdevperm.c
index fe2295e..f2a5e38 100644
--- a/devices/gdevperm.c
+++ b/devices/gdevperm.c
@@ -135,8 +135,8 @@ perm_print_page(gx_device_printer *pdev, gp_file *pstream)
     gx_device_perm_t * const dev = (gx_device_perm_t *)pdev;
     int ncomp = dev->num_std_colorant_names;
     int raw_raster = pdev->width * ncomp;
-    byte *raw_line;
-    byte *cooked_line;
+    byte *raw_line = NULL;
+    byte *cooked_line = NULL;
     byte *row;
     int code = 0;
     int mode = dev->mode;
@@ -145,9 +145,15 @@ perm_print_page(gx_device_printer *pdev, gp_file *pstream)
     fprintf(pstream, "P6\n%d %d\n255\n", dev->width, dev->height);
     raw_line = gs_alloc_bytes(pdev->memory, raw_raster, "perm_print_page");
     cooked_line = gs_alloc_bytes(pdev->memory, dev->width * 3, "perm_print_page");
+    if (raw_line == NULL || cooked_line == NULL) {
+        gs_free_object(pdev->memory, raw_line, "perm_print_page");
+        return_error(gs_error_VMerror);
+    }
     for (y = 0; y < dev->height; y++) {
         int x;
         code = gdev_prn_get_bits(pdev, y, raw_line, &row);
+        if (code < 0)
+            break;
         for (x = 0; x < dev->width; x++) {
             int c, m, y, k;
             int r, g, b;
diff --git a/devices/gdevphex.c b/devices/gdevphex.c
index f5fac8a..f3ca504 100644
--- a/devices/gdevphex.c
+++ b/devices/gdevphex.c
@@ -947,8 +947,8 @@ static	void	ScheduleMiddle( SCHEDUL *p );
 static	void	ScheduleTrailing( SCHEDUL *p );
 static	void	ScheduleBand( SCHEDUL *p, int mask );
 
-static	void	RenderPage( RENDER *p );
-static	void	RenderLine( RENDER *p, int line );
+static	int	RenderPage( RENDER *p );
+static	int	RenderLine( RENDER *p, int line );
 static	int		IsScanlineEmpty( RENDER *p, byte *line );
 
 static	int		RleCompress( RAWLINE *raw, int min, int max, byte *rle_data );
@@ -1682,6 +1682,7 @@ static	int		photoex_print_page( PDEV *device, gp_file *stream )
 {
 int			pixels;						/* Length of the line 				*/
 int			x;							/* Work vars						*/
+int			code = 0;
 EDEV		*dev;						/* Our device						*/
 RENDER		*render;					/* Rendering info					*/
 
@@ -1791,7 +1792,9 @@ double		psize;
 
         /* Render the page and send image data to printer */
 
-        RenderPage( render );
+        code = RenderPage( render );
+        if (code < 0)
+            goto xit;
 
         /* Eject the paper, reset printer */
 
@@ -1799,10 +1802,10 @@ double		psize;
         SendReset( stream );
 
         /* Release the memory and return */
-
+xit:
         gs_free( dev->memory, render->dbuff, pixels, sizeof( long ), "PhotoEX" );
         gs_free( dev->memory, render, 1, sizeof( RENDER ), "PhotoEX" );
-        return( 0 );
+        return( code );
 }
 
 /*
@@ -1810,7 +1813,7 @@ double		psize;
 *	~~~~~~~~~~~~~~
 */
 
-static	void	RenderPage( RENDER *p )
+static	int	RenderPage( RENDER *p )
 {
 int		last_done;					/* The last line rendered				*/
 int		last_need;					/* The largest line number we need		*/
@@ -1819,6 +1822,7 @@ int		last_band;					/* Indicates the last band				*/
 int		min, max;					/* Min/max active bytes in a raw line	*/
 int		phase;						/* 1440dpi X weave offset				*/
 int		i, j, l, col;
+int		code = 0;
 
         p->htone_thold = HalftoneThold( p );
         p->htone_last  = -1 - p->htone_thold;
@@ -1842,7 +1846,11 @@ int		i, j, l, col;
                 last_need = last_done;
                 for ( i = NOZZLES-1 ; i >= 0 && p->schedule.head[ i ] == -1 ; i-- );
                 if ( i >= 0 ) last_need = p->schedule.head[ i ];
-                while ( last_need > last_done ) RenderLine( p, ++last_done );
+                while ( last_need > last_done ) {
+                    code = RenderLine( p, ++last_done );
+                    if (code < 0)
+                       return code;	/* punt */
+                }
 
                 /* Now loop through the colours and build the data stream */
 
@@ -1932,6 +1940,8 @@ int		i, j, l, col;
                 move_down += p->schedule.down;
 
         } while	( ! last_band );
+
+        return code;
 }
 
 /*
@@ -1944,14 +1954,16 @@ int		i, j, l, col;
 *	When it sees a nonempty line again, it restarts the renderer.
 */
 
-static	void	RenderLine( RENDER *p, int line )
+static	int	RenderLine( RENDER *p, int line )
 {
 byte	*data;
-int		i;
+int		i, code = 0;
 
         /* Get the line from Ghostscript and see if its empty */
 
-        gdev_prn_get_bits( (PDEV *) p->dev, line, p->dbuff, &data );
+        code = gdev_prn_get_bits( (PDEV *) p->dev, line, p->dbuff, &data );
+        if (code < 0)
+            return code;
 
         if ( IsScanlineEmpty( p, data ) ) {
 
@@ -1994,6 +2006,7 @@ int		i;
                 HalftoneLine( p, line, data );
                 p->htone_last = line;
         }
+        return 0;
 }
 
 /*
diff --git a/devices/gdevpjet.c b/devices/gdevpjet.c
index e794b0a..d9fc76f 100644
--- a/devices/gdevpjet.c
+++ b/devices/gdevpjet.c
@@ -99,9 +99,10 @@ pj_common_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_origin,
 {
         int line_size;
         int data_size;
-        byte *data;
-        byte *plane_data;
-        byte *temp;
+        byte *data = NULL;
+        byte *plane_data = NULL;
+        byte *temp = NULL;
+        int code = 0;
 
         /* We round up line_size to a multiple of 8 bytes */
         /* because that's the unit of transposition from pixels to planes. */
@@ -154,8 +155,10 @@ pj_common_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_origin,
                 int num_blank_lines = 0;
                 for ( lnum = 0; lnum < pdev->height; lnum++ )
                    {	byte *end_data = data + line_size;
-                        gdev_prn_copy_scan_lines(pdev, lnum,
+                        code = gdev_prn_copy_scan_lines(pdev, lnum,
                                                  (byte *)data, line_size);
+                        if (code < 0)
+                            goto xit;
                         /* Remove trailing 0s. */
                         while ( end_data > data && end_data[-1] == 0 )
                                 end_data--;
@@ -223,11 +226,12 @@ pj_common_print_page(gx_device_printer *pdev, gp_file *prn_stream, int y_origin,
         /* end the page */
         gp_fputs(end_page, prn_stream);
 
+xit:
         gs_free(pdev->memory, (char *)data, data_size, 1, "paintjet_print_page(data)");
         gs_free(pdev->memory, (char *)plane_data, line_size * 3, 1, "paintjet_print_page(plane_data)");
         gs_free(pdev->memory, temp, line_size * 2, 1, "paintjet_print_page(temp)");
 
-        return 0;
+        return code;
 }
 
 /*
diff --git a/devices/gdevpsim.c b/devices/gdevpsim.c
index 3c85c31..7a194c6 100644
--- a/devices/gdevpsim.c
+++ b/devices/gdevpsim.c
@@ -143,7 +143,7 @@ static int
 psmono_print_page(gx_device_printer * pdev, gp_file * prn_stream)
 {
     int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
-    int lnum;
+    int lnum, code = 0;
     byte *line = gs_alloc_bytes(pdev->memory, line_size, "psmono_print_page");
     byte invert = (pdev->color_info.depth == 1 ? 0xff : 0);
     gx_device_pswrite_common_t pswrite_common;
@@ -167,7 +167,9 @@ psmono_print_page(gx_device_printer * pdev, gp_file * prn_stream)
         int left = line_size;
         byte *data;
 
-        gdev_prn_get_bits(pdev, lnum, line, &data);
+        code = gdev_prn_get_bits(pdev, lnum, line, &data);
+        if (code < 0)
+            goto xit;
         p = data;
         /* Loop invariant: p + left = data + line_size. */
 #define min_repeat_run 10
@@ -216,10 +218,11 @@ psmono_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     /* Clean up and return. */
     fputs("\n", prn_stream);
     psw_write_page_trailer(prn_stream, 1, true);
+xit:
     gs_free_object(pdev->memory, line, "psmono_print_page");
     if (ferror(prn_stream))
         return_error(gs_error_ioerror);
-    return 0;
+    return code;
 }
 
 /* Close the file. */
@@ -307,7 +310,7 @@ psrgb_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     int width = pdev->width;
     byte *lbuf = gs_alloc_bytes(mem, width * 3,
                                 "psrgb_print_page(lbuf)");
-    int lnum;
+    int lnum, code = 0;
     stream fs, a85s, rls;
     stream_A85E_state a85state;
     stream_RLE_state rlstate;
@@ -354,7 +357,9 @@ psrgb_print_page(gx_device_printer * pdev, gp_file * prn_stream)
         byte *data;
         int i, c;
 
-        gdev_prn_get_bits(pdev, lnum, lbuf, &data);
+        code = gdev_prn_get_bits(pdev, lnum, lbuf, &data);
+        if (code < 0)
+            goto xit;
         for (c = 0; c < 3; ++c) {
             const byte *p;
 
@@ -369,7 +374,10 @@ psrgb_print_page(gx_device_printer * pdev, gp_file * prn_stream)
     sflush(&fs);
     fputs("\n", prn_stream);
     psw_write_page_trailer(prn_stream, 1, true);
+xit:
     gs_free_object(mem, lbuf, "psrgb_print_page(lbuf)");
+    if (code < 0)
+        return_error(code);
     if (ferror(prn_stream))
         return_error(gs_error_ioerror);
     return 0;
diff --git a/devices/gdevrinkj.c b/devices/gdevrinkj.c
index cc144d7..509edd0 100644
--- a/devices/gdevrinkj.c
+++ b/devices/gdevrinkj.c
@@ -818,6 +818,9 @@ rinkj_add_lut(rinkj_device *rdev, rinkj_lutset *lutset, char plane, gp_file *f)
     if (n_graph < 0 || n_graph > 256)
         return -1;
     chain = (rinkj_lutchain *)gs_alloc_bytes(rdev->memory, sizeof(rinkj_lutchain), "rinkj_add_lut");
+    if (chain == NULL) {
+        return -1;
+    }
     chain->next = NULL;
     chain->n_graph = n_graph;
     chain->graph_x = (double *)gs_alloc_bytes(rdev->memory, sizeof(double) * n_graph, "rinkj_add_lut");
@@ -972,14 +975,23 @@ rinkj_write_image_data(gx_device_printer *pdev, RinkjDevice *cmyk_dev)
     n_planes = n_planes_in + rdev->separation_names.num_names;
     if_debug1m('r', rdev->memory, "[r]n_planes = %d\n", n_planes);
     xsb = pdev->width;
-    for (i = 0; i < n_planes_out; i++)
+    for (i = 0; i < n_planes_out; i++) {
         plane_data[i] = gs_alloc_bytes(pdev->memory, xsb, "rinkj_write_image_data");
-
+        if (plane_data[i] == NULL) {
+            while (--i >= 0)
+                gs_free_object(pdev->memory, plane_data[i], "rinkj_write_image_data");
+            return_error(gs_error_VMerror);
+        }
+    }
     if (rdev->icc_link != NULL) {
 
         cache = (rinkj_color_cache_entry *)gs_alloc_bytes(pdev->memory, RINKJ_CCACHE_SIZE * sizeof(rinkj_color_cache_entry), "rinkj_write_image_data");
-        if (cache == NULL)
-            return gs_note_error(gs_error_VMerror);
+        if (cache == NULL) {
+            /* i == n_planes_out from above */
+            while (--i >= 0)
+                gs_free_object(pdev->memory, plane_data[i], "rinkj_write_image_data");
+            return_error(gs_error_VMerror);
+        }
 
         /* Set up cache so that none of the keys will hit. */
 
@@ -999,11 +1011,15 @@ rinkj_write_image_data(gx_device_printer *pdev, RinkjDevice *cmyk_dev)
     split_plane_data[6] = plane_data[3];
 
     line = gs_alloc_bytes(pdev->memory, raster, "rinkj_write_image_data");
+    if (line == NULL)
+        goto xit;
     for (y = 0; y < pdev->height; y++) {
         byte *row;
         int x;
 
         code = gdev_prn_get_bits(pdev, y, line, &row);
+        if (code < 0)
+            goto xit;
 
         if (rdev->icc_link == NULL) {
             int rowix = 0;
@@ -1115,6 +1131,7 @@ rinkj_write_image_data(gx_device_printer *pdev, RinkjDevice *cmyk_dev)
     }
 
     rinkj_device_write(cmyk_dev, NULL);
+xit:
     for (i = 0; i < n_planes_in; i++)
         gs_free_object(pdev->memory, plane_data[i], "rinkj_write_image_data");
     gs_free_object(pdev->memory, line, "rinkj_write_image_data");
diff --git a/devices/gdevsppr.c b/devices/gdevsppr.c
index 144187e..ee3c581 100644
--- a/devices/gdevsppr.c
+++ b/devices/gdevsppr.c
@@ -115,7 +115,8 @@ sparc_print_page(gx_device_printer *pdev, FILE *prn)
   struct lpvi_page lpvipage;
   struct lpvi_err lpvierr;
   char *out_buf;
-  int out_size;
+  int out_size, code = 0;
+
   if (ioctl(fileno(prn),LPVIIOC_GETPAGE,&lpvipage)!=0)
     {
     errprintf(pdev->memory, "sparc_print_page: LPVIIOC_GETPAGE failed\n");
@@ -132,7 +133,12 @@ sparc_print_page(gx_device_printer *pdev, FILE *prn)
     }
   out_size=lpvipage.bitmap_width*lpvipage.page_length;
   out_buf=gs_malloc(pdev->memory, out_size,1,"sparc_print_page: out_buf");
-  gdev_prn_copy_scan_lines(pdev,0,out_buf,out_size);
+  if (out_buf == NULL)
+      return_error(gs_error_VMerror);
+
+  code = gdev_prn_copy_scan_lines(pdev,0,out_buf,out_size);
+  if (code < 0)
+    goto xit;
   while (write(fileno(prn),out_buf,out_size)!=out_size)
     {
     if (ioctl(fileno(prn),LPVIIOC_GETERR,&lpvierr)!=0)
@@ -182,6 +188,7 @@ sparc_print_page(gx_device_printer *pdev, FILE *prn)
     errprintf(pdev->memory, "OK.\n");
     warning=0;
     }
+xit:
   gs_free(pdev->memory, out_buf,out_size,1,"sparc_print_page: out_buf");
-  return 0;
+  return code;
   }
diff --git a/devices/gdevstc.c b/devices/gdevstc.c
index 9040f06..951ded0 100644
--- a/devices/gdevstc.c
+++ b/devices/gdevstc.c
@@ -362,6 +362,7 @@ stc_print_page(gx_device_printer * pdev, gp_file *prn_stream)
 
    int    prt_pixels;    /* Number of pixels printed */
    byte  *col_line;      /* A Line with a byte per pixel */
+   int   code = 0;
 
 #define OK4GO        ((flags &   STCOK4GO)              != 0)
 #define SORRY        ( flags &= ~STCOK4GO)
@@ -591,7 +592,11 @@ stc_print_page(gx_device_printer * pdev, gp_file *prn_stream)
 
                   if(sd->stc.buf_y < sd->stc.prt_scans) {  /* Test for White */
 
-                     gdev_prn_get_bits(pdev,sd->stc.buf_y,ext_line,&ext_data);
+                     code = gdev_prn_get_bits(pdev,sd->stc.buf_y,ext_line,&ext_data);
+                     if (code < 0) {
+                         SORRY;
+                         goto xit;
+                    }
 
                      color = stc_iswhite(sd,prt_pixels,ext_data) ? ext_size : 0;
 
@@ -747,6 +752,7 @@ stc_print_page(gx_device_printer * pdev, gp_file *prn_stream)
  *** Release the dynamic memory
  ***/
 
+xit:
    if(ext_line != NULL)
       gs_free(sd->memory, ext_line,ext_size,1,"stc_print_page/ext_line");
 
diff --git a/devices/gdevtfnx.c b/devices/gdevtfnx.c
index 578e964..d9593cd 100644
--- a/devices/gdevtfnx.c
+++ b/devices/gdevtfnx.c
@@ -126,13 +126,6 @@ tiff12_print_page(gx_device_printer * pdev, gp_file * file)
     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
     int code;
 
-    /* open the TIFF device */
-    if (gdev_prn_file_is_new(pdev)) {
-        tfdev->tif = tiff_from_filep(pdev, pdev->dname, file, tfdev->BigEndian, tfdev->UseBigTIFF);
-        if (!tfdev->tif)
-            return_error(gs_error_invalidfileaccess);
-    }
-
     code = gdev_tiff_begin_page(tfdev, file);
     if (code < 0)
         return code;
@@ -189,13 +182,6 @@ tiff_rgb_print_page(gx_device_printer * pdev, gp_file * file)
     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
     int code;
 
-    /* open the TIFF device */
-    if (gdev_prn_file_is_new(pdev)) {
-        tfdev->tif = tiff_from_filep(pdev, pdev->dname, file, tfdev->BigEndian, tfdev->UseBigTIFF);
-        if (!tfdev->tif)
-            return_error(gs_error_invalidfileaccess);
-    }
-
     code = gdev_tiff_begin_page(tfdev, file);
     if (code < 0)
         return code;
diff --git a/devices/gdevtifs.c b/devices/gdevtifs.c
index 2a52d3b..2d612ba 100644
--- a/devices/gdevtifs.c
+++ b/devices/gdevtifs.c
@@ -331,6 +331,9 @@ int gdev_tiff_begin_page(gx_device_tiff *tfdev,
                     profile_struct->device_profile[0], profile_struct->postren_profile,
                     &rendering_params);
             }
+            if (tfdev->icclink == NULL) {
+                return_error(gs_error_VMerror);
+            }
             /* If it is identity, release it now and set link to NULL */
             if (tfdev->icclink->is_identity) {
                 tfdev->icclink->procs.free_link(tfdev->icclink);
@@ -477,7 +480,7 @@ tiff_print_page(gx_device_printer *dev, TIFF *tif, int min_feature_size)
     for (row = 0; row < dev->height && code >= 0; row++) {
         code = gdev_prn_copy_scan_lines(dev, row, data, size);
         if (code < 0)
-            break;
+            goto cleanup;
         if (min_feature_size > 1) {
             filtered_count = min_feature_size_process(data, min_feature_data);
             if (filtered_count == 0)
diff --git a/devices/gdevtknk.c b/devices/gdevtknk.c
index cd88a42..35d98bf 100644
--- a/devices/gdevtknk.c
+++ b/devices/gdevtknk.c
@@ -125,6 +125,7 @@ tekink_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     register byte bdata,mdata,ydata,cdata;
     register byte mask,inbyte;
     register byte *indataend,*outdataend;
+    int code = 0;
 
     /* Allocate a temporary buffer for color separation.
        The buffer is partitioned into an input buffer and four
@@ -134,7 +135,8 @@ tekink_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
     color_line_size=(pdev->width+7)/8;
     indata1=(byte *)malloc(line_size+4*(color_line_size+1));
-    if (indata1==NULL) return -1;
+    if (indata1==NULL)
+        return_error(gs_error_VMerror);
     /* pointers to the partions */
     indataend=indata1+line_size;
     bdata1=indataend;
@@ -150,7 +152,9 @@ tekink_print_page(gx_device_printer *pdev, gp_file *prn_stream)
     scan_lines=pdev->height;
     for (scan_line=0;scan_line<scan_lines;scan_line++){
         /* get data */
-        gdev_prn_copy_scan_lines(pdev,scan_line,indata1,line_size);
+        code = gdev_prn_copy_scan_lines(pdev,scan_line,indata1,line_size);
+        if (code < 0)
+            goto xit;
         /* Separate data into color planes */
         bdatap = bdata1+1;
         mdatap = mdata1+1;
@@ -248,7 +252,8 @@ tekink_print_page(gx_device_printer *pdev, gp_file *prn_stream)
         gp_fputs("\f",prn_stream);
     }
 
+xit:
     /* Deallocate temp buffer */
     free(indata1);
-    return 0;
+    return code;
 }
diff --git a/devices/gdevtsep.c b/devices/gdevtsep.c
index bb905b7..5b0429b 100644
--- a/devices/gdevtsep.c
+++ b/devices/gdevtsep.c
@@ -1796,6 +1796,9 @@ tiffsep_prn_open(gx_device * pdev)
                 profile_struct->device_profile[0], profile_struct->postren_profile,
                 &rendering_params);
         }
+        if (pdev_sep->icclink == NULL) {
+            return_error(gs_error_VMerror);
+        }
         /* If it is identity, release it now and set link to NULL */
         if (pdev_sep->icclink->is_identity) {
             pdev_sep->icclink->procs.free_link(pdev_sep->icclink);
diff --git a/devices/gdevwpr2.c b/devices/gdevwpr2.c
index 3f834b5..29af469 100644
--- a/devices/gdevwpr2.c
+++ b/devices/gdevwpr2.c
@@ -571,9 +571,12 @@ win_pr2_print_page(gx_device_printer * pdev, gp_file * file)
             lines = scan_lines - y;
         else
             lines = yslice;
-        for (i = 0; i < lines; i++)
-            gdev_prn_copy_scan_lines(pdev, y + i,
+        for (i = 0; i < lines; i++) {
+            code = gdev_prn_copy_scan_lines(pdev, y + i,
                               row + (bmp_raster * (lines - 1 - i)), raster);
+            if (code < 0)
+                goto xit;
+        }
 
         if (ratio > 1) {
             StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
@@ -618,6 +621,7 @@ win_pr2_print_page(gx_device_printer * pdev, gp_file * file)
             ShowWindow(wdev->hDlgModeless, SW_HIDE);
     }
 
+xit:
     GlobalUnlock(hrow);
     GlobalFree(hrow);
 
diff --git a/devices/gdevxcf.c b/devices/gdevxcf.c
index 39c7283..a7e6617 100644
--- a/devices/gdevxcf.c
+++ b/devices/gdevxcf.c
@@ -1270,11 +1270,18 @@ xcf_write_image_data(xcf_write_ctx *xc, gx_device_printer *pdev)
     tile_data = (byte **)gs_alloc_bytes(pdev->memory,
                                         xc->n_tiles_x * sizeof(byte *),
                                         "xcf_write_image_data");
+    if (line == NULL || tile_data ==  NULL) {
+        code = gs_error_VMerror;
+        goto xit;
+    }
+    memset(tile_data, 0, xc->n_tiles_x * sizeof(byte *));
     for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
         int tile_bytes = xcf_tile_sizeof(xc, tile_i) * bytes_pp;
 
         tile_data[tile_i] = gs_alloc_bytes(pdev->memory, tile_bytes,
                                            "xcf_write_image_data");
+        if (tile_data[tile_i] == NULL)
+            goto xit;
     }
     for (tile_j = 0; tile_j < xc->n_tiles_y; tile_j++) {
         int y0, y1;
@@ -1285,6 +1292,8 @@ xcf_write_image_data(xcf_write_ctx *xc, gx_device_printer *pdev)
         y1 = min(xc->height, y0 + TILE_HEIGHT);
         for (y = y0; y < y1; y++) {
             code = gdev_prn_get_bits(pdev, y, line, &row);
+            if (code < 0)
+                goto xit;
             if (link == NULL)
                 xcf_shuffle_to_tile(xc, tile_data, row, y);
             else
@@ -1303,9 +1312,12 @@ xcf_write_image_data(xcf_write_ctx *xc, gx_device_printer *pdev)
         }
     }
 
-    for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
-        gs_free_object(pdev->memory, tile_data[tile_i],
-                "xcf_write_image_data");
+xit:
+    if (tile_data != NULL) {
+        for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
+            gs_free_object(pdev->memory, tile_data[tile_i],
+                    "xcf_write_image_data");
+        }
     }
     gs_free_object(pdev->memory, tile_data, "xcf_write_image_data");
     gs_free_object(pdev->memory, line, "xcf_write_image_data");
diff --git a/devices/gdevxcmp.c b/devices/gdevxcmp.c
index 0aa7331..5cf5a56 100644
--- a/devices/gdevxcmp.c
+++ b/devices/gdevxcmp.c
@@ -134,13 +134,16 @@ alloc_std_cmap(gx_device_X *xdev, bool colored)
 
 /* Allocate the dynamic color table, if needed and possible. */
 /* Uses: vinfo, cman.num_rgb.  Sets: cman.dynamic.*. */
-static void
+/* Return true if the allocation was successful. */
+static bool
 alloc_dynamic_colors(gx_device_X * xdev, int num_colors)
 {
     if (num_colors > 0) {
         xdev->cman.dynamic.colors = (x11_color_t **)
             gs_malloc(xdev->memory, sizeof(x11_color_t *), xdev->cman.num_rgb,
                       "x11 cman.dynamic.colors");
+        if (xdev->cman.dynamic.colors == NULL)
+            return false;
         if (xdev->cman.dynamic.colors) {
             int i;
 
@@ -152,6 +155,7 @@ alloc_dynamic_colors(gx_device_X * xdev, int num_colors)
             xdev->cman.dynamic.used = 0;
         }
     }
+    return true;
 }
 
 /* Allocate an X color, updating the reverse map. */
@@ -388,8 +392,9 @@ gdev_x_setup_colors(gx_device_X * xdev)
         }
 
         /* Allocate the dynamic color table. */
-        alloc_dynamic_colors(xdev, CUBE(xdev->cman.num_rgb) -
-                             CUBE(xdev->color_info.dither_colors));
+        if (!alloc_dynamic_colors(xdev, CUBE(xdev->cman.num_rgb) -
+                             CUBE(xdev->color_info.dither_colors)))
+            return_error(gs_error_VMerror);
 #undef CUBE
 #undef CBRT
         break;
@@ -436,8 +441,9 @@ grayscale:
         }
 
         /* Allocate the dynamic color table. */
-        alloc_dynamic_colors(xdev, xdev->cman.num_rgb -
-                             xdev->color_info.dither_grays);
+        if (!alloc_dynamic_colors(xdev, xdev->cman.num_rgb -
+                             xdev->color_info.dither_grays))
+            return_error(gs_error_VMerror);
         break;
     case 'M':
 monochrome:
diff --git a/devices/vector/gdevagl.h b/devices/vector/gdevagl.h
index e509f89..e356922 100644
--- a/devices/vector/gdevagl.h
+++ b/devices/vector/gdevagl.h
@@ -33,5 +33,5 @@ typedef struct treble_glyph_list_s {
 
 typedef struct quad_glyph_list_s {
   const char *Glyph;
-  short Unicode[4];
+  unsigned short Unicode[4];
 } quad_glyph_list_t;
diff --git a/devices/vector/gdevpdf.c b/devices/vector/gdevpdf.c
index d918d60..b25a4a6 100644
--- a/devices/vector/gdevpdf.c
+++ b/devices/vector/gdevpdf.c
@@ -1020,6 +1020,7 @@ pdf_close_page(gx_device_pdf * pdev, int num_copies)
         page->contents_id = pdev->contents_id;
         page->NumCopies_set = pdev->NumCopies_set;
         page->NumCopies = pdev->NumCopies;
+        page->UserUnit = pdev->UserUnit;
         pdf_record_usage(pdev, pdev->contents_id, pdev->next_page);
         pdf_record_usage(pdev, pdev->contents_length_id, pdev->next_page);
         pdf_record_usage(pdev, page->Page->id, pdev->next_page);
@@ -1337,6 +1338,9 @@ pdf_write_page(gx_device_pdf *pdev, int page_num)
                 bleedbox[0], bleedbox[1], bleedbox[2], bleedbox[3]);
     }
     pdf_print_orientation(pdev, page);
+    if (page->UserUnit != 1)
+        pprintg1(s, "/UserUnit %g\n", page->UserUnit);
+
     pprintld1(s, "/Parent %ld 0 R\n", pdev->Pages->id);
     if (pdev->ForOPDFRead && pdev->DoNumCopies && !pdev->ProduceDSC) {
         if (page->NumCopies_set)
diff --git a/devices/vector/gdevpdfb.h b/devices/vector/gdevpdfb.h
index a47fec8..e1ca236 100644
--- a/devices/vector/gdevpdfb.h
+++ b/devices/vector/gdevpdfb.h
@@ -289,7 +289,8 @@ const gx_device_pdf PDF_DEVICE_IDENT =
  -1,                    /* Last Form ID, start with -1 which means 'none' */
  0,                     /* ExtensionMetadata */
  0,                     /* PDFFormName */
- 0                      /* PassThroughWriter */
+ 0,                     /* PassThroughWriter */
+ 1.0                    /* UserUnit */
 };
 
 #else
diff --git a/devices/vector/gdevpdfe.c b/devices/vector/gdevpdfe.c
index 877b7b1..1c54070 100644
--- a/devices/vector/gdevpdfe.c
+++ b/devices/vector/gdevpdfe.c
@@ -651,8 +651,7 @@ pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
         {
 
             pdf_xml_tag_open_beg(s, "rdf:Description");
-            pdf_xml_attribute_name(s, "rdf:about");
-            pdf_xml_attribute_value(s, instance_uuid);
+            pdf_xml_copy(s, " rdf:about=\"\"");
             pdf_xml_attribute_name(s, "xmlns:pdf");
             pdf_xml_attribute_value(s, "http://ns.adobe.com/pdf/1.3/");
 
@@ -689,8 +688,7 @@ pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
             }
 
             pdf_xml_tag_open_beg(s, "rdf:Description");
-            pdf_xml_attribute_name(s, "rdf:about");
-            pdf_xml_attribute_value(s, instance_uuid);
+            pdf_xml_copy(s, " rdf:about=\"\"");
             pdf_xml_attribute_name(s, "xmlns:xmp");
             pdf_xml_attribute_value(s, "http://ns.adobe.com/xap/1.0/");
             pdf_xml_tag_end(s);
@@ -723,8 +721,7 @@ pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
             pdf_xml_newline(s);
 
             pdf_xml_tag_open_beg(s, "rdf:Description");
-            pdf_xml_attribute_name(s, "rdf:about");
-            pdf_xml_attribute_value(s, instance_uuid);
+            pdf_xml_copy(s, " rdf:about=\"\"");
             pdf_xml_attribute_name(s, "xmlns:xapMM");
             pdf_xml_attribute_value(s, "http://ns.adobe.com/xap/1.0/mm/");
             pdf_xml_attribute_name(s, "xapMM:DocumentID");
@@ -733,8 +730,7 @@ pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
             pdf_xml_newline(s);
 
             pdf_xml_tag_open_beg(s, "rdf:Description");
-            pdf_xml_attribute_name(s, "rdf:about");
-            pdf_xml_attribute_value(s, instance_uuid);
+            pdf_xml_copy(s, " rdf:about=\"\"");
             pdf_xml_attribute_name(s, "xmlns:dc");
             pdf_xml_attribute_value(s, "http://purl.org/dc/elements/1.1/");
             pdf_xml_attribute_name(s, "dc:format");
@@ -808,8 +804,7 @@ pdf_write_document_metadata(gx_device_pdf *pdev, const byte digest[6])
             pdf_xml_newline(s);
             if (pdev->PDFA != 0) {
                 pdf_xml_tag_open_beg(s, "rdf:Description");
-                pdf_xml_attribute_name(s, "rdf:about");
-                pdf_xml_attribute_value(s, instance_uuid);
+                pdf_xml_copy(s, " rdf:about=\"\"");
                 pdf_xml_attribute_name(s, "xmlns:pdfaid");
                 pdf_xml_attribute_value(s, "http://www.aiim.org/pdfa/ns/id/");
                 pdf_xml_attribute_name(s, "pdfaid:part");
diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c
index fed96e4..2f9cea0 100644
--- a/devices/vector/gdevpdfi.c
+++ b/devices/vector/gdevpdfi.c
@@ -1878,7 +1878,7 @@ pdf_image_end_image_data(gx_image_enum_common_t * info, bool draw_last,
     pdf_image_enum *pie = (pdf_image_enum *)info;
     int height = pie->writer.height;
     int data_height = height - pie->rows_left;
-    int code = 0;
+    int code = 0, ecode;
 
     if (pie->writer.pres)
         ((pdf_x_object_t *)pie->writer.pres)->data_height = data_height;
@@ -1920,6 +1920,12 @@ pdf_image_end_image_data(gx_image_enum_common_t * info, bool draw_last,
     if (pie->initial_colorspace != pdev->pcm_color_info_index)
         pdf_set_process_color_model(pdev, pie->initial_colorspace);
 
+    /* Clean up any outstanding streams before freeing the enumerator */
+    while (pie->writer.alt_writer_count-- > 0) {
+        ecode = psdf_end_binary(&(pie->writer.binary[pie->writer.alt_writer_count]));
+        if (ecode < 0 && code >= 0) code  = ecode;
+    }
+
     gx_image_free_enum(&info);
     return code;
 }
diff --git a/devices/vector/gdevpdfp.c b/devices/vector/gdevpdfp.c
index df2ff37..2f29dba 100644
--- a/devices/vector/gdevpdfp.c
+++ b/devices/vector/gdevpdfp.c
@@ -127,6 +127,7 @@ static const gs_param_item_t pdf_param_items[] = {
     pi("FastWebView", gs_param_type_bool, Linearise),
     pi("NoOutputFonts", gs_param_type_bool, FlattenFonts),
     pi("WantsPageLabels", gs_param_type_bool, WantsPageLabels),
+    pi("UserUnit", gs_param_type_float, UserUnit),
 #undef pi
     gs_param_item_end
 };
@@ -237,6 +238,14 @@ gdev_pdf_get_param(gx_device *dev, char *Param, void *list)
     if (strcmp(Param, "ForOPDFRead") == 0) {
         return(param_write_bool(plist, "ForOPDFRead", &pdev->ForOPDFRead));
     }
+    if (strcmp(Param, "PassUserUnit") == 0) {
+        bool dummy;
+        if (pdev->CompatibilityLevel > 1.5)
+            dummy = true;
+        else
+            dummy = false;
+        return(param_write_bool(plist, "PassUserUnit", &dummy));
+    }
     if (!pdev->is_ps2write) {
         if (strcmp(Param, "pdfmark")  == 0){
             return(param_write_null(plist, "pdfmark"));
@@ -559,6 +568,16 @@ gdev_pdf_put_params_impl(gx_device * dev, const gx_device_pdf * save_dev, gs_par
     if (cl < 1.2) {
         pdev->HaveCFF = false;
     }
+
+    ecode = param_read_float(plist, "UserUnit", &pdev->UserUnit);
+    if (ecode < 0)
+        goto fail;
+    if (pdev->UserUnit == 0 || (pdev->UserUnit != 1 && pdev->CompatibilityLevel < 1.6)) {
+        ecode = gs_note_error(gs_error_rangecheck);
+        param_signal_error(plist, "UserUnit", ecode);
+        goto fail;
+    }
+
     ecode = gdev_psdf_put_params(dev, plist);
     if (ecode < 0)
         goto fail;
diff --git a/devices/vector/gdevpdfx.h b/devices/vector/gdevpdfx.h
index f42d9f1..ad484ed 100644
--- a/devices/vector/gdevpdfx.h
+++ b/devices/vector/gdevpdfx.h
@@ -326,6 +326,7 @@ typedef struct pdf_page_s {
     pdf_page_dsc_info_t dsc_info;
     bool NumCopies_set; /* ps2write only. */
     int NumCopies;      /* ps2write only. */
+    float UserUnit;     /* pdfwrite only */
 } pdf_page_t;
 #define private_st_pdf_page()        /* in gdevpdf.c */\
   gs_private_st_ptrs2(st_pdf_page, pdf_page_t, "pdf_page_t",\
@@ -901,6 +902,7 @@ struct gx_device_pdf_s {
                                      * doing JPEG pass through we write the JPEG data here, and don't write
                                      * anything in the image processing routines.
                                      */
+    float UserUnit;
 };
 
 #define is_in_page(pdev)\
diff --git a/devices/vector/gdevtxtw.c b/devices/vector/gdevtxtw.c
index 5158418..7738321 100644
--- a/devices/vector/gdevtxtw.c
+++ b/devices/vector/gdevtxtw.c
@@ -2111,7 +2111,8 @@ txt_add_fragment(gx_device_txtwrite_t *tdev, textw_text_enum_t *penum)
         penum->TextBufferIndex, sizeof(float), "txtwrite alloc widths array");
     if (!penum->text_state->Widths)
         return gs_note_error(gs_error_VMerror);
-    memcpy(penum->text_state->Widths, penum->Widths, penum->TextBufferIndex * sizeof(float));
+    memset(penum->text_state->Widths, 0x00, penum->TextBufferIndex * sizeof(float));
+    memcpy(penum->text_state->Widths, penum->Widths, penum->text.size * sizeof(float));
 
     unsorted_entry->Unicode_Text = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
         penum->TextBufferIndex, sizeof(unsigned short), "txtwrite alloc sorted text buffer");
@@ -2123,7 +2124,8 @@ txt_add_fragment(gx_device_txtwrite_t *tdev, textw_text_enum_t *penum)
         penum->TextBufferIndex, sizeof(float), "txtwrite alloc widths array");
     if (!unsorted_entry->Widths)
         return gs_note_error(gs_error_VMerror);
-    memcpy(unsorted_entry->Widths, penum->Widths, penum->TextBufferIndex * sizeof(float));
+    memset(unsorted_entry->Widths, 0x00, penum->TextBufferIndex * sizeof(float));
+    memcpy(unsorted_entry->Widths, penum->Widths, penum->text.size * sizeof(float));
 
     unsorted_entry->FontName = (char *)gs_malloc(tdev->memory->stable_memory,
         (strlen(penum->text_state->FontName) + 1), sizeof(unsigned char), "txtwrite alloc sorted text buffer");
diff --git a/doc/Language.htm b/doc/Language.htm
index 5f112a1..d8f9deb 100644
--- a/doc/Language.htm
+++ b/doc/Language.htm
@@ -463,6 +463,10 @@ Ghostscript's model generalizes that of PDF 1.4 in that Ghostscript
 maintains separate alpha and mask values for opacity and shape, rather than
 a single value with a Boolean that says whether it represents opacity or
 shape.</p>
+<p>
+What follows is a subset of all the custom operators related to transparency, but
+covers the most useful, most common requirements.
+</p>
 
 <h5><a name="Transparency_graphics_state_operators"></a>Graphics state
 operators</h5>
@@ -495,23 +499,43 @@ the blending mode is <code>/Compatible</code>.</dd>
 </dl>
 
 <dl>
+<dt><code>- .currentblendmode &lt;modename&gt;</code></dt>
+<dd>Returns the graphics state blend mode on the stack.
+</dl>
+
+<dl>
 <dt><code>&lt;0..1&gt; .setopacityalpha -</code></dt>
 <dd>Sets the opacity alpha value in the graphics state.
 The initial opacity alpha value is 1.</dd>
 </dl>
 
 <dl>
+<dt><code>- .currentopacityalpha &lt;0..1&gt;</code></dt>
+<dd>Returns the graphics state opacity alpha on the stack.</dd>
+</dl>
+
+<dl>
 <dt><code>&lt;0..1&gt; .setshapealpha -</code></dt>
 <dd>Sets the shape alpha value in the graphics state.
 The initial shape alpha value is 1.</dd>
 </dl>
 
 <dl>
+<dt><code>- .currentshapealpha &lt;0..1&gt;</code></dt>
+<dd>Returns the graphics state shape alpha on the stack.</dd>
+</dl>
+
+<dl>
 <dt><code>&lt;bool&gt; .settextknockout -</code></dt>
 <dd>Sets the text knockout flag in the graphics state.
 The initial value of the text knockout flag is <code>true</code>.</dd>
 </dl>
 
+<dl>
+<dt><code>- .currenttextknockout &lt;bool&gt;</code></dt>
+<dd>Returns the graphics state text knockout on the stack..</dd>
+</dl>
+
 <h5><a name="Transparency_rendering_stack_operators"></a>Rendering stack
 operators</h5>
 
diff --git a/gpdl/gpdl.mak b/gpdl/gpdl.mak
index 6a1bbc7..3864a92 100644
--- a/gpdl/gpdl.mak
+++ b/gpdl/gpdl.mak
@@ -17,6 +17,9 @@ GPDL_MAK=$(GPDLSRCDIR)$(D)gpdl.mak
 
 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)
@@ -26,9 +29,18 @@ GLGEN=$(GLGENDIR)$(D)
 GPDL_PSI_TOP_OBJ_FILE=psitop.$(OBJ)
 GPDL_PSI_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PSI_TOP_OBJ_FILE)
 
-GPDL_PSI_TOP_OBJS=$(GPDL_PSI_TOP_OBJ) $(GPDLOBJ)gpdlimpl.$(OBJ)
+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_PWG_TOP_OBJ_FILE=pwgtop.$(OBJ)
+GPDL_PWG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PWG_TOP_OBJ_FILE)
+
+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)
 
-LANG_CFLAGS=$(D_)PCL_INCLUDED$(_D) $(D_)PSI_INCLUDED$(_D) $(D_)XPS_INCLUDED$(_D)
 
 GPDLCC=$(CC_) $(LANG_CFLAGS) $(I_)$(PSSRCDIR)$(_I) $(I_)$(PLSRCDIR)$(_I) $(I_)$(GLSRCDIR)$(_I) $(I_)$(DEVSRCDIR)$(_I) $(I_)$(GLGENDIR)$(_I) $(C_)
 
@@ -50,3 +62,21 @@ $(GPDL_PSI_TOP_OBJ): $(GPDLPSISRC)psitop.c $(AK) $(stdio__h)\
  $(gsnogc_h) $(pltop_h) $(psitop_h) $(plparse_h) $(gsicc_manage_h)\
  $(plfont_h) $(uconfig_h)
 	$(GPDLCC) $(GPDLPSISRC)psitop.c $(GPDLO_)$(GPDL_PSI_TOP_OBJ_FILE)
+
+# Note that we don't use $(GPDL_URF_TOP_OBJ) as the target of the
+# next make rule, as this expands to "" in builds that don't use
+# URF.
+$(GPDLOBJ)/$(GPDL_URF_TOP_OBJ_FILE): $(GPDLURFSRC)urftop.c $(AK)\
+ $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(surfx_h) $(strimpl_h)\
+ $(gscoord_h) $(pltop_h)
+	$(GPDLCC) $(GPDLURFSRC)urftop.c $(GPDLO_)$(GPDL_URF_TOP_OBJ_FILE)
+
+$(GPDL_IMG_TOP_OBJ): $(GPDLIMGSRC)imagetop.c $(AK)\
+ $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(strimpl_h) $(gscoord_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/image/imagetop.c b/gpdl/image/imagetop.c
new file mode 100644
index 0000000..b3232dc
--- /dev/null
+++ b/gpdl/image/imagetop.c
@@ -0,0 +1,855 @@
+/* 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.
+*/
+
+/* imagetop.c */
+/* Top-level API implementation of "Image" Language Interface */
+
+#include "pltop.h"
+#include "gserrors.h"
+#include "gxdevice.h"
+#include "gsstate.h"
+#include "strimpl.h"
+#include "gscoord.h"
+#include "jpeglib.h"
+#include "setjmp_.h"
+#include "sjpeg.h"
+
+/* Forward decls */
+
+/************************************************************/
+/******** Language wrapper implementation (see pltop.h) *****/
+/************************************************************/
+
+typedef enum
+{
+    ii_state_identifying = 0,
+    ii_state_jpeg,
+    ii_state_jpeg_header,
+    ii_state_jpeg_start,
+    ii_state_jpeg_rows,
+    ii_state_jpeg_finish,
+    ii_state_flush
+} ii_state;
+
+typedef struct {
+    struct jpeg_error_mgr pub;
+    jmp_buf setjmp_buffer;
+} img_error_mgr;
+
+/*
+ * Image interpreter instance
+ */
+typedef struct img_interp_instance_s {
+    gs_memory_t       *memory;
+    gs_memory_t       *cmemory;
+    gx_device         *dev;
+    gx_device         *nulldev;
+
+    gs_color_space    *gray;
+    gs_color_space    *rgb;
+    gs_color_space    *cmyk;
+
+    /* Image parser state machine */
+    ii_state           state;
+
+    int                pages;
+
+    uint8_t            bpp;
+    uint8_t            cs;
+    uint32_t           width;
+    uint32_t           height;
+    uint32_t           xresolution;
+    uint32_t           yresolution;
+
+    uint32_t           num_comps;
+    uint32_t           byte_width;
+    uint32_t           y;
+
+    uint32_t           bytes_available_on_entry;
+
+    gs_image_t         image;
+    gs_image_enum     *penum;
+    gs_gstate         *pgs;
+
+    struct jpeg_decompress_struct cinfo;
+    struct jpeg_source_mgr        jsrc;
+    size_t             bytes_to_skip;
+    img_error_mgr      jerr;
+
+    byte              *samples;
+
+} img_interp_instance_t;
+
+static int
+img_detect_language(const char *s, int len)
+{
+    const byte *hdr = (const byte *)s;
+    if (len >= 11) {
+        if (hdr[0] == 0xFF && hdr[1] == 0xd8 && hdr[2] == 0xff && hdr[3] == 0xe0 &&
+            strncmp("JFIF", s+6, 5) == 0)
+            return 100;
+    }
+    /* FIXME: Other formats go here */
+
+    return 0;
+}
+
+static const pl_interp_characteristics_t img_characteristics = {
+    "IMAGE",
+    img_detect_language,
+    "Artifex",
+    "0.01",
+    "11 Nov 2019",
+    1 /* minimum input size */
+};
+
+/* GS's fakakta jpeg integration insists on putting a
+ * memory structure pointer in the decompress structs client data.
+ * This is no good to find our instance from. We therefore find
+ * it by offsetting back from the address of the cinfo. This is
+ * a nasty bit of casting, so wrap it in a macro. */
+#define IMG_FROM_CINFO(CINFO) \
+    (img_interp_instance_t *)(((char *)(CINFO))-offsetof(img_interp_instance_t,cinfo))
+
+
+/* Get implementation's characteristics */
+static const pl_interp_characteristics_t * /* always returns a descriptor */
+img_impl_characteristics(const pl_interp_implementation_t *impl)     /* implementation of interpreter to alloc */
+{
+  return &img_characteristics;
+}
+
+static void
+img_deallocate(img_interp_instance_t *img)
+{
+    if (img == NULL)
+        return;
+
+    rc_decrement_cs(img->gray, "img_deallocate");
+    rc_decrement_cs(img->rgb, "img_deallocate");
+    rc_decrement_cs(img->cmyk, "img_deallocate");
+
+    if (img->pgs != NULL)
+        gs_gstate_free_chain(img->pgs);
+    gs_free_object(img->memory, img, "img_impl_allocate_interp_instance");
+}
+
+/* Deallocate a interpreter instance */
+static int
+img_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    img_deallocate(img);
+    impl->interp_client_data = NULL;
+
+    return 0;
+}
+
+/* Do per-instance interpreter allocation/init. */
+static int
+img_impl_allocate_interp_instance(pl_interp_implementation_t *impl, gs_memory_t *mem)
+{
+    int code;
+    img_interp_instance_t *img
+        = (img_interp_instance_t *)gs_alloc_bytes(mem,
+                                                  sizeof(img_interp_instance_t),
+                                                  "img_impl_allocate_interp_instance");
+    if (!img)
+        return_error(gs_error_VMerror);
+    memset(img, 0, sizeof(*img));
+
+    img->memory = mem;
+    img->pgs = gs_gstate_alloc(mem);
+    if (img->pgs == NULL)
+        goto failVM;
+
+    /* Push one save level onto the stack to assuage the memory handling */
+    code = gs_gsave(img->pgs);
+    if (code < 0)
+        goto fail;
+
+    code = gsicc_init_iccmanager(img->pgs);
+    if (code < 0)
+        goto fail;
+
+    img->gray = gs_cspace_new_ICC(mem, img->pgs, 1);
+    img->rgb  = gs_cspace_new_ICC(mem, img->pgs, 3);
+    img->cmyk = gs_cspace_new_ICC(mem, img->pgs, 4);
+
+    impl->interp_client_data = img;
+
+    return 0;
+
+failVM:
+    code = gs_note_error(gs_error_VMerror);
+fail:
+    (void)img_deallocate(img);
+    return code;
+}
+
+/*
+ * Get the allocator with which to allocate a device
+ */
+static gs_memory_t *
+img_impl_get_device_memory(pl_interp_implementation_t *impl)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    return img->dev ? img->dev->memory : NULL;
+}
+
+#if 0 /* UNUSED */
+static int
+img_impl_set_param(pl_interp_implementation_t *impl,
+                   pl_set_param_type           type,
+                   const char                 *param,
+                   const void                 *val)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    /* No params set here */
+    return 0;
+}
+
+static int
+img_impl_add_path(pl_interp_implementation_t *impl,
+                  const char                 *path)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    /* No paths to add */
+    return 0;
+}
+
+static int
+img_impl_post_args_init(pl_interp_implementation_t *impl)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    /* No post args processing */
+    return 0;
+}
+#endif
+
+/* Prepare interp instance for the next "job" */
+static int
+img_impl_init_job(pl_interp_implementation_t *impl,
+                  gx_device                  *device)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    img->dev = device;
+    img->state = ii_state_identifying;
+
+    return 0;
+}
+
+#if 0 /* UNUSED */
+static int
+img_impl_run_prefix_commands(pl_interp_implementation_t *impl,
+                             const char                 *prefix)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    return 0;
+}
+
+static int
+img_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
+{
+    img_interp_instance_t *img = (img_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 */
+img_impl_process_begin(pl_interp_implementation_t * impl)
+{
+    img_interp_instance_t *img = (img_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(img_interp_instance_t *img, 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 void
+img_jpeg_init_source(j_decompress_ptr cinfo)
+{
+    /* We've already inited the source */
+}
+
+static boolean
+img_fill_input_buffer(j_decompress_ptr cinfo)
+{
+    return FALSE; /* We've filled the buffer already */
+}
+
+static void
+img_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+    img_interp_instance_t *img = IMG_FROM_CINFO(cinfo);
+    size_t n = cinfo->src->bytes_in_buffer;
+
+    if (n > num_bytes)
+        n = num_bytes;
+    img->jsrc.next_input_byte += num_bytes;
+    img->jsrc.bytes_in_buffer -= n;
+}
+
+static boolean
+img_resync_to_restart(j_decompress_ptr cinfo, int desired)
+{
+    return FALSE;
+}
+
+static void
+img_term_source(j_decompress_ptr cinfo)
+{
+}
+
+static void
+img_error_exit(j_common_ptr cinfo)
+{
+    img_error_mgr *jerr = (img_error_mgr *)cinfo->err;
+
+    longjmp(jerr->setjmp_buffer, 1);
+}
+
+static int
+fill_jpeg_source(img_interp_instance_t *img, stream_cursor_read * pr)
+{
+    size_t n = pr->limit - pr->ptr;
+    size_t skip = img->bytes_to_skip;
+
+    /* Skip any bytes we are supposed to be skipping. */
+    if (skip > 0) {
+        if (skip > n)
+            skip = n;
+        pr->ptr += skip;
+        n -= skip;
+        img->bytes_to_skip -= skip;
+        if (img->bytes_to_skip != 0)
+            return 1; /* Still more to skip */
+    }
+
+    /* Set up for the call into the jpeg lib */
+    img->jsrc.next_input_byte = pr->ptr+1;
+    img->jsrc.bytes_in_buffer = pr->limit - pr->ptr;
+    img->bytes_available_on_entry = img->jsrc.bytes_in_buffer;
+
+    return 0;
+}
+
+static int
+consume_jpeg_data(img_interp_instance_t *img, stream_cursor_read *pr)
+{
+    size_t bytes_read = img->jsrc.next_input_byte - (pr->ptr+1);
+    size_t n = pr->limit - pr->ptr;
+
+    if (n > bytes_read)
+        n = bytes_read;
+    pr->ptr += n;
+    bytes_read -= n;
+
+    /* We need to skip the next bytes_read bytes */
+    img->bytes_to_skip = bytes_read;
+
+    return (pr->limit - pr->ptr == img->bytes_available_on_entry);
+}
+
+static int
+img_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+    int code = 0;
+    int need_more_data;
+
+    do
+    {
+        need_more_data = 0;
+        switch(img->state)
+        {
+        case ii_state_identifying:
+        {
+            const byte *hdr;
+            /* Try and get us 11 bytes */
+            code = ensure_bytes(img, pr, 11);
+            if (code < 0)
+                return code;
+            hdr = pr->ptr+1;
+            if (hdr[0] == 0xFF && hdr[1] == 0xd8 && hdr[2] == 0xff && hdr[3] == 0xe0 &&
+                memcmp("JFIF", hdr+6, 5) == 0)
+            {
+                img->state = ii_state_jpeg;
+                break;
+            }
+            img->state = ii_state_flush;
+            break;
+        }
+        case ii_state_jpeg:
+            code = gs_jpeg_mem_init(img->memory, (j_common_ptr)&img->cinfo);
+            if (code < 0) {
+                img->state = ii_state_flush;
+                break;
+            }
+
+            img->cinfo.err = jpeg_std_error(&img->jerr.pub);
+            img->jerr.pub.error_exit = img_error_exit;
+            if (setjmp(img->jerr.setjmp_buffer)) {
+                img->state = ii_state_flush;
+                break;
+            }
+
+            jpeg_create_decompress(&img->cinfo);
+
+            img->cinfo.src = &img->jsrc;
+            img->jsrc.init_source = img_jpeg_init_source;
+            img->jsrc.fill_input_buffer = img_fill_input_buffer;
+            img->jsrc.skip_input_data = img_skip_input_data;
+            img->jsrc.resync_to_restart = img_resync_to_restart;
+            img->jsrc.term_source = img_term_source;
+
+            img->state = ii_state_jpeg_header;
+            break;
+        case ii_state_jpeg_header:
+        {
+            int ok;
+            gs_color_space *cs;
+            float scale, xext, yext, xoffset, yoffset;
+
+            if (fill_jpeg_source(img, pr)) {
+                need_more_data = 1;
+                break; /* No bytes left after skipping */
+            }
+            if (setjmp(img->jerr.setjmp_buffer)) {
+                jpeg_destroy_decompress(&img->cinfo);
+                img->state = ii_state_flush;
+                break;
+            }
+            ok = jpeg_read_header(&img->cinfo, TRUE);
+            need_more_data = consume_jpeg_data(img, pr);
+            if (ok == JPEG_SUSPENDED)
+                break;
+            need_more_data = 0;
+
+            img->width = img->cinfo.image_width;
+            img->height = img->cinfo.image_height;
+            img->num_comps = img->cinfo.num_components;
+            img->bpp = 8 * img->num_comps;
+            switch(img->num_comps) {
+            default:
+            case 1:
+                cs = img->gray;
+                img->cinfo.out_color_space = JCS_GRAYSCALE;
+                break;
+            case 3:
+                cs = img->rgb;
+                img->cinfo.out_color_space = JCS_RGB;
+                break;
+            case 4:
+                cs = img->cmyk;
+                img->cinfo.out_color_space = JCS_CMYK;
+                break;
+            }
+
+            /* Find us some X and Y resolutions */
+            img->xresolution = img->cinfo.X_density;
+            img->yresolution = img->cinfo.Y_density;
+            if (img->xresolution == 0)
+                img->xresolution = img->yresolution;
+            if (img->yresolution == 0)
+                img->yresolution = img->xresolution;
+            if (img->xresolution == 0)
+                img->xresolution = 72;
+            if (img->yresolution == 0)
+                img->yresolution = 72;
+
+            /* Scale to fit, if too large. */
+            scale = 1.0f;
+            if (img->width * 72 > img->dev->width * img->xresolution)
+                scale = ((float)img->dev->width * img->xresolution) / (img->width * 72);
+            if (scale * img->height * 72 > img->dev->height * img->yresolution)
+                scale = ((float)img->dev->height * img->yresolution) / (img->height * 72);
+
+            /* Centre */
+            xext = ((float)img->width * 72 * scale / img->xresolution);
+            xoffset = (img->dev->width - xext)/2;
+            yext = ((float)img->height * 72 * scale / img->yresolution);
+            yoffset = (img->dev->height - yext)/2;
+
+
+            /* Now we've got the data from the image header, we can
+             * make the gs image instance */
+            img->byte_width = (img->bpp>>3)*img->width;
+
+            img->nulldev = gs_currentdevice(img->pgs);
+            rc_increment(img->nulldev);
+            code = gs_setdevice_no_erase(img->pgs, img->dev);
+            if (code < 0) {
+                img->state = ii_state_flush;
+                break;
+            }
+            gs_initmatrix(img->pgs);
+
+            code = gs_translate(img->pgs, xoffset, img->dev->height-yoffset);
+            if (code >= 0)
+                code = gs_scale(img->pgs, scale, -scale);
+            if (code >= 0)
+                code = gs_erasepage(img->pgs);
+            if (code < 0) {
+                img->state = ii_state_flush;
+                break;
+            }
+
+            img->samples = gs_alloc_bytes(img->memory, img->byte_width, "img_impl_process(samples)");
+            if (img->samples == NULL) {
+                img->state = ii_state_flush;
+                break;
+            }
+
+            memset(&img->image, 0, sizeof(img->image));
+            gs_image_t_init(&img->image, cs);
+            img->image.BitsPerComponent = img->bpp/img->num_comps;
+            img->image.Width = img->width;
+            img->image.Height = img->height;
+
+            img->image.ImageMatrix.xx = img->xresolution / 72.0;
+            img->image.ImageMatrix.yy = img->yresolution / 72.0;
+
+            img->penum = gs_image_enum_alloc(img->memory, "img_impl_process(penum)");
+            if (img->penum == NULL) {
+                code = gs_note_error(gs_error_VMerror);
+                img->state = ii_state_flush;
+                return code;
+            }
+
+            code = gs_image_init(img->penum,
+                                 &img->image,
+                                 false,
+                                 false,
+                                 img->pgs);
+            if (code < 0) {
+                img->state = ii_state_flush;
+                return code;
+            }
+
+            img->state = ii_state_jpeg_start;
+            break;
+        }
+        case ii_state_jpeg_start:
+        {
+            int ok;
+            if (fill_jpeg_source(img, pr)) {
+                need_more_data = 1;
+                break; /* No bytes left after skipping */
+            }
+            if (setjmp(img->jerr.setjmp_buffer)) {
+                jpeg_destroy_decompress(&img->cinfo);
+                img->state = ii_state_flush;
+                break;
+            }
+            ok = jpeg_start_decompress(&img->cinfo);
+            (void)consume_jpeg_data(img, pr);
+            if (ok == FALSE)
+                break;
+            img->state = ii_state_jpeg_rows;
+            break;
+        }
+        case ii_state_jpeg_rows:
+        {
+            int rows_decoded;
+            unsigned int used;
+
+            if (fill_jpeg_source(img, pr)) {
+                need_more_data = 1;
+                break; /* No bytes left after skipping */
+            }
+            if (setjmp(img->jerr.setjmp_buffer)) {
+                jpeg_destroy_decompress(&img->cinfo);
+                img->state = ii_state_flush;
+                break;
+            }
+            rows_decoded = jpeg_read_scanlines(&img->cinfo, &img->samples, 1);
+            need_more_data = consume_jpeg_data(img, pr);
+            if (rows_decoded == 0)
+                break; /* Not enough data for a scanline yet */
+            need_more_data = 0;
+
+            code = gs_image_next(img->penum, img->samples, img->byte_width, &used);
+            if (code < 0) {
+                img->state = ii_state_flush;
+                break;
+            }
+            img->y++;
+            if (img->y == img->height) {
+                code = gs_image_cleanup_and_free_enum(img->penum, img->pgs);
+                img->penum = NULL;
+                if (code < 0) {
+                    img->state = ii_state_flush;
+                    break;
+                }
+                code = pl_finish_page(img->memory->gs_lib_ctx->top_of_system,
+                                      img->pgs, 1, true);
+                if (code < 0) {
+                    img->state = ii_state_flush;
+                    break;
+                }
+                img->state = ii_state_jpeg_finish;
+            }
+            break;
+        }
+        case ii_state_jpeg_finish:
+        {
+            int ok;
+
+            if (fill_jpeg_source(img, pr)) {
+                need_more_data = 1;
+                break; /* No bytes left after skipping */
+            }
+            if (setjmp(img->jerr.setjmp_buffer)) {
+                jpeg_destroy_decompress(&img->cinfo);
+                img->state = ii_state_flush;
+                break;
+            }
+            ok = jpeg_finish_decompress(&img->cinfo);
+            need_more_data = consume_jpeg_data(img, pr);
+            if (ok == FALSE)
+                break;
+            need_more_data = 0;
+            img->state = ii_state_flush;
+            break;
+        }
+        default:
+        case ii_state_flush:
+            if (setjmp(img->jerr.setjmp_buffer))
+                break;
+            jpeg_destroy_decompress(&img->cinfo);
+
+            gs_jpeg_mem_term((j_common_ptr)&img->cinfo);
+
+            if (img->penum) {
+                (void)gs_image_cleanup_and_free_enum(img->penum, img->pgs);
+                img->penum = NULL;
+            }
+
+            gs_free_object(img->memory, img->samples, "img_impl_process(samples)");
+            img->samples = NULL;
+            /* We want to bin any data we get up to, but not including
+             * a UEL. */
+            return flush_to_uel(pr);
+        }
+    } while (!need_more_data);
+
+    return code;
+}
+
+static int
+img_impl_process_end(pl_interp_implementation_t * impl)
+{
+    img_interp_instance_t *img = (img_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
+img_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
+img_impl_process_eof(pl_interp_implementation_t *impl)
+{
+    return 0;
+}
+
+/* Report any errors after running a job */
+static int
+img_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
+img_impl_dnit_job(pl_interp_implementation_t *impl)
+{
+    img_interp_instance_t *img = (img_interp_instance_t *)impl->interp_client_data;
+
+    if (img->nulldev) {
+        int code = gs_setdevice(img->pgs, img->nulldev);
+        img->dev = NULL;
+        rc_decrement(img->nulldev, "img_impl_dnit_job(nulldevice)");
+        img->nulldev = NULL;
+        return code;
+    }
+    return 0;
+}
+
+/* Parser implementation descriptor */
+const pl_interp_implementation_t img_implementation = {
+  img_impl_characteristics,
+  img_impl_allocate_interp_instance,
+  img_impl_get_device_memory,
+  NULL, /* img_impl_set_param */
+  NULL, /* img_impl_add_path */
+  NULL, /* img_impl_post_args_init */
+  img_impl_init_job,
+  NULL, /* img_impl_run_prefix_commands */
+  NULL, /* img_impl_process_file */
+  img_impl_process_begin,
+  img_impl_process,
+  img_impl_process_end,
+  img_impl_flush_to_eoj,
+  img_impl_process_eof,
+  img_impl_report_errors,
+  img_impl_dnit_job,
+  img_impl_deallocate_interp_instance,
+  NULL
+};
diff --git a/gpdl/psi/gpdlpsi.mak b/gpdl/psi/gpdlpsi.mak
deleted file mode 100644
index 84bddb1..0000000
--- a/gpdl/psi/gpdlpsi.mak
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (C) 2001-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.
-#
-
-# makefile for PS Interface (PSI) to Ghostscript PostScript.
-# Users of this makefile must define the following:
-#	PSSRCDIR - the PS interpreter source directory
-#	GLSRCDIR - the GS library source directory
-#	GLGENDIR - the GS library generated file directory
-#	PLSRCDIR - the PCL* support library source directory
-#	PLOBJDIR - the PCL* support library object / executable directory
-#	PSISRCDIR - the source directory
-#	PSIGENDIR - the directory for source files generated during building
-#	PSIOBJDIR - the object / executable directory
-#	PSI_TOP_OBJ - object file to top-level interpreter API
-
-PLOBJ=$(PLOBJDIR)$(D)
-
-PSISRC=$(PSISRCDIR)$(D)
-PSIGEN=$(PSIGENDIR)$(D)
-PSIOBJ=$(PSIOBJDIR)$(D)
-PSIO_=$(O_)$(PSIOBJ)
-
-PSICCC=$(CC_) $(I_)$(PSISRCDIR)$(_I) $(I_)$(PSIGENDIR)$(_I) $(I_)$(PLSRCDIR)$(_I) $(I_)$(PSSRCDIR)$(_I) $(I_)$(GLSRCDIR)$(_I) $(I_)$(GLGENDIR)$(_I) $(C_)
-
-# Define the name of this makefile.
-PSI_MAK=$(PSISRC)psi.mak
-
-psi.clean: psi.config-clean psi.clean-not-config-clean
-
-psi.clean-not-config-clean: clean_gs
-	$(RM_) $(PSIOBJ)*.$(OBJ)
-	$(RM_) $(PSIOBJ)devs.tr6
-
-# devices are still created in the current directory.  Until that 
-# is fixed we will have to remove them from both directories.
-psi.config-clean:
-	$(RM_) $(PSIOBJ)*.dev
-	$(RM_) *.dev
-
-################ PS Language Interface ################
-
-# Top-level API
-$(PSI_TOP_OBJ): $(PSISRC)psitop.c $(AK) $(stdio__h)\
- $(string__h) $(gdebug_h) $(gp_h) $(gsdevice_h) $(gserrors_h) $(gsmemory_h)\
- $(gsstate_h) $(gsstruct_h) $(gspaint_h) $(gstypes_h) $(gxalloc_h) $(gxstate_h)\
- $(gsnogc_h) $(pltop_h) $(psitop_h) $(plparse_h) $(gsicc_manage_h)\
- $(PSIGEN)pconf.h $(plfont_h) $(uconfig_h) $(pconfig_h)
-	$(PSICCC) $(PSISRC)psitop.c $(O_)$(PSI_TOP_OBJ)
-
-$(PSIOBJ)psi.dev: $(PSI_MAK) $(ECHOGS_XE) $(PLOBJ)pjl.dev 
-	$(SETMOD) $(PSIOBJ)psi $(PSI_TOP_OBJ)
-	$(ADDMOD) $(PSIOBJ)psi -include $(PLOBJ)pl $(PLOBJ)pjl
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/jbig2dec/jbig2.c b/jbig2dec/jbig2.c
index 97018ea..3d9f270 100644
--- a/jbig2dec/jbig2.c
+++ b/jbig2dec/jbig2.c
@@ -191,12 +191,14 @@ jbig2_get_uint16(const byte *bptr)
     return get_uint16(bptr);
 }
 
+/* coverity[ -tainted_data_return ] */
 int32_t
 jbig2_get_int32(const byte *bptr)
 {
     return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
 }
 
+/* coverity[ -tainted_data_return ] */
 uint32_t
 jbig2_get_uint32(const byte *bptr)
 {
diff --git a/jbig2dec/jbig2_halftone.c b/jbig2dec/jbig2_halftone.c
index 69bd21e..e67c6d1 100644
--- a/jbig2dec/jbig2_halftone.c
+++ b/jbig2dec/jbig2_halftone.c
@@ -50,6 +50,12 @@ jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *im
     uint32_t i;
     int j;
 
+    if (N == 0) {
+        /* We've wrapped. */
+        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "params->GRAYMAX out of range");
+        return NULL;
+    }
+
     /* allocate a new struct */
     new = jbig2_new(ctx, Jbig2PatternDict, 1);
     if (new != NULL) {
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];
diff --git a/pcl/pcl/pcindxed.c b/pcl/pcl/pcindxed.c
index a174c7e..25637b7 100644
--- a/pcl/pcl/pcindxed.c
+++ b/pcl/pcl/pcindxed.c
@@ -208,8 +208,18 @@ unshare_indexed_cspace(pcl_cs_indexed_t ** ppindexed)
            pindexed->palette.size);
     memcpy(pnew->pen_widths, pindexed->pen_widths,
            num_entries * sizeof(float));
-    memcpy(pnew->norm, pindexed->norm, 3 * sizeof(pindexed->norm[0]));
-    memcpy(pnew->Decode, pindexed->Decode, 6 * sizeof(float));
+
+    /* Coverity thinks next memcpy() might need to be memmove(), so we
+    explicitly check for the buffers being equal. */
+    if (pnew->norm != pindexed->norm) {
+        memcpy(pnew->norm, pindexed->norm, 3 * sizeof(pindexed->norm[0]));
+    }
+
+    /* Coverity thinks next memcpy() might need to be memmove(), so we
+    explicitly check for the buffers being equal. */
+    if (pnew->Decode != pindexed->Decode) {
+        memcpy(pnew->Decode, pindexed->Decode, 6 * sizeof(float));
+    }
 
     return 0;
 }
diff --git a/pcl/pcl/pcwhtidx.c b/pcl/pcl/pcwhtidx.c
index 0f3141c..00ada33 100644
--- a/pcl/pcl/pcwhtidx.c
+++ b/pcl/pcl/pcwhtidx.c
@@ -217,7 +217,8 @@ pcl_cmap_map_raster(const pcl_cs_indexed_t * pindexed,
 
     /* allocate a new raster if necessary (pack scanlines) */
     if (must_copy) {
-        long nbytes = pin_pixinfo->size.x * pin_pixinfo->pix_depth;
+        /* Cast to long to avoid coverity warning about sign extension. */
+        long nbytes = (long) pin_pixinfo->size.x * pin_pixinfo->pix_depth;
 
         nbytes = ((nbytes + 7) / 8);
         pout_pixinfo->raster = nbytes;
diff --git a/pcl/pcl/pgdraw.c b/pcl/pcl/pgdraw.c
index 0a4baf3..9d17414 100644
--- a/pcl/pcl/pgdraw.c
+++ b/pcl/pcl/pgdraw.c
@@ -440,7 +440,7 @@ hpgl_set_graphics_line_attribute_state(hpgl_state_t * pgls,
      * is not documented PCLTRM.  Pen widths are maintained in
      * plotter units
      */
-    if (render_mode != hpgl_rm_character && pen_wid <= 14.0) {
+    if (pen_wid <= 14.0) {
         hpgl_call(gs_setlinejoin(pgls->pgs, gs_join_none));
         hpgl_call(gs_setlinecap(pgls->pgs, gs_cap_butt));
         hpgl_call(gs_setlinewidth(pgls->pgs, pen_wid));
@@ -450,7 +450,6 @@ hpgl_set_graphics_line_attribute_state(hpgl_state_t * pgls,
 
     switch (render_mode) {
 
-        case hpgl_rm_character:
         case hpgl_rm_polygon:
         case hpgl_rm_clip_and_fill_polygon:
             hpgl_call(gs_setlinejoin(pgls->pgs, gs_join_round));
diff --git a/pcl/pl/pjparse.c b/pcl/pl/pjparse.c
index 72c1be7..1060caf 100644
--- a/pcl/pl/pjparse.c
+++ b/pcl/pl/pjparse.c
@@ -731,8 +731,7 @@ pjl_search_for_file(pjl_parser_state_t * pst, char *pathname, char *filename,
     struct stat stbuf;
 
     /* should check length */
-    strcpy(fontfilename, pathname);
-    strcat(fontfilename, "/*");
+    snprintf(fontfilename, sizeof(fontfilename), "%s/*", pathname);
     fe = gs_enumerate_files_init(pst->mem, fontfilename, strlen(fontfilename));
     if (fe) {
         do {
diff --git a/pcl/pl/plfont.c b/pcl/pl/plfont.c
index 514c105..9982701 100644
--- a/pcl/pl/plfont.c
+++ b/pcl/pl/plfont.c
@@ -406,7 +406,7 @@ pl_glyph_name(gs_font * pfont, gs_glyph glyph, gs_const_string * pstr)
         }
         /* skip over the post header */
         numGlyphs = u16(postp + 32);
-        if (glyph < 0 || glyph > numGlyphs - 1) {
+        if (glyph > numGlyphs - 1) {
             if_debug1m('=', pfont->memory,
                        "[=]glyph index %lx out of range\n", glyph);
             return -1;
@@ -414,7 +414,7 @@ pl_glyph_name(gs_font * pfont, gs_glyph glyph, gs_const_string * pstr)
         /* glyph name index starts at post + 34 each entry is 2 bytes */
         glyph_name_index = u16(postp + 34 + (glyph * 2));
         /* this shouldn't happen */
-        if (glyph_name_index < 0 && glyph_name_index > 0x7fff)
+        if (glyph_name_index > 0x7fff)
             return -1;
         /* mac easy */
         if (glyph_name_index < 258) {
diff --git a/pcl/pl/plimpl.c b/pcl/pl/plimpl.c
index 5fa03ae..2b5b0dd 100644
--- a/pcl/pl/plimpl.c
+++ b/pcl/pl/plimpl.c
@@ -37,6 +37,12 @@ extern pl_interp_implementation_t svg_implementation;
 
 extern pl_interp_implementation_t ps_implementation;
 
+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,
@@ -53,6 +59,15 @@ pl_interp_implementation_t *pdl_implementations[] = {
 #ifdef PDF_INCLUDED
     &pdf_implementation,
 #endif
+#ifdef URF_INCLUDED
+    &urf_implementation,
+#endif
+#ifdef IMG_INCLUDED
+    &img_implementation,
+#endif
+#ifdef PWG_INCLUDED
+    &pwg_implementation,
+#endif
     0
 };
 
@@ -66,4 +81,3 @@ const gs_ptr_procs_t ptr_string_procs = { NULL, NULL, NULL };
 const gs_ptr_procs_t ptr_const_string_procs = { NULL, NULL, NULL };
 const gs_ptr_procs_t ptr_name_index_procs = { NULL, NULL, NULL };
 #endif
-
diff --git a/pcl/pl/pllfont.c b/pcl/pl/pllfont.c
index f0b9f19..4bf49d6 100644
--- a/pcl/pl/pllfont.c
+++ b/pcl/pl/pllfont.c
@@ -255,7 +255,7 @@ pl_fill_in_mt_font(gs_font_base * pfont, pl_font_t * plfont, ushort handle,
             pfont->FontBBox.p.x = pfont->FontBBox.p.y =
                 pfont->FontBBox.q.x = pfont->FontBBox.q.y = 0;
 
-            uid_set_UniqueID(&pfont->UID, unique_id | (handle << 16));
+            uid_set_UniqueID(&pfont->UID, unique_id | ( ((long) handle) << 16));
             pfont->encoding_index = 1;      /****** WRONG ******/
             pfont->nearest_encoding_index = 1;      /****** WRONG ******/
         }
@@ -308,7 +308,7 @@ pl_load_ufst_lineprinter(gs_memory_t * mem, pl_dict_t * pfontdict,
             if (use_unicode_names_for_keys)
                 code = pl_dict_put(pfontdict,
                             (const byte *)resident_table[i].unicode_fontname,
-                            32, pplfont);
+                            sizeof(resident_table[i].unicode_fontname), pplfont);
             else {
                 byte key[3];
 
@@ -540,8 +540,9 @@ pl_load_built_in_mtype_fonts(const char *pathname, gs_memory_t * mem,
                     }
                     if (use_unicode_names_for_keys)
                         code = pl_dict_put(pfontdict,
-                                    (const byte *)resident_table[j].
-                                    unicode_fontname, 32, plfont);
+                                    (const byte *)resident_table[j].unicode_fontname,
+                                    sizeof(resident_table[j].unicode_fontname),
+                                    plfont);
                     else {
                         key[2] = (byte) j;
                         key[0] = key[1] = 0;
@@ -702,7 +703,8 @@ pl_load_built_in_fonts(const char *pathname, gs_memory_t * mem,
                    residentp->character_complement, 8);
             if (use_unicode_names_for_keys)
                 code = pl_dict_put(pfontdict,
-                                   (const byte *)residentp->unicode_fontname, 32,
+                                   (const byte *)residentp->unicode_fontname,
+                                   sizeof(residentp->unicode_fontname),
                                    plfont);
             else {
                 key[2] = (byte) (residentp - resident_table);
diff --git a/psi/dscparse.c b/psi/dscparse.c
index e754a82..0c34eb1 100644
--- a/psi/dscparse.c
+++ b/psi/dscparse.c
@@ -3822,7 +3822,7 @@ dsc_dcs2_fixup(CDSC *dsc)
         DSC_OFFSET *pbegin;
         DSC_OFFSET *pend;
         DSC_OFFSET end;
-        CDCS2 *pdcs = dsc->dcs2;
+        CDCS2 *pdcs = NULL;
         /* Now treat the initial EPS file as a single page without
          * headers or trailer, so page extraction will fetch the
          * the correct separation. */
@@ -3888,6 +3888,14 @@ dsc_dcs2_fixup(CDSC *dsc)
             *pbegin = *pend;
         end = 0;	/* end of composite is start of first separation */
 
+        /* we used to do this where the pointer is declared, but Coverity points out
+         * that dsc_alloc_string can call dsc_reset which can free dsc and dsc->dcs2.
+         * By deferring the initialisation to here we can ensure we don't have a
+         * dangling pointer. This makes me suspiciouos that DCS (not DSC!) comments
+         * have never worked properly.
+         */
+        pdcs = dsc->dcs2;
+
         while (pdcs) {
             page_number = dsc->page_count;
             if ((pdcs->begin) && (pdcs->colourname != NULL)) {
diff --git a/psi/imainarg.c b/psi/imainarg.c
index 76653f3..c5d74ca 100644
--- a/psi/imainarg.c
+++ b/psi/imainarg.c
@@ -509,7 +509,9 @@ run_stdin:
                             break;
                     }
                 if (code >= 0)
-                    code = runarg(minst, "]put", psarg, ".runfile", runInit | runFlush, minst->user_errors, NULL, NULL);
+                    code = run_string(minst, "]put", 0, minst->user_errors, NULL, NULL);
+                if (code >= 0)
+                    code = argproc(minst, psarg);
                 arg_free((char *)psarg, minst->heap);
                 if (code >= 0)
                     code = gs_error_Quit;
diff --git a/psi/int.mak b/psi/int.mak
index d34c2e7..f339ccf 100644
--- a/psi/int.mak
+++ b/psi/int.mak
@@ -358,7 +358,7 @@ $(PSOBJ)zfilter.$(OBJ) : $(PSSRC)zfilter.c $(OP) $(memory__h)\
  $(files_h) $(ialloc_h) $(idict_h) $(idparam_h) $(ifilter_h) $(ilevel_h)\
  $(sfilter_h) $(srlx_h) $(sstring_h) $(stream_h) $(strimpl_h)\
  $(INT_MAK) $(MAKEDIRS)
-	$(PSCC) $(PSO_)zfilter.$(OBJ) $(C_) $(PSSRC)zfilter.c
+	$(PSCC) $(ENABLE_URF) $(URF_INCLUDE) $(PSO_)zfilter.$(OBJ) $(C_) $(PSSRC)zfilter.c
 
 $(PSOBJ)zfproc.$(OBJ) : $(PSSRC)zfproc.c $(GH) $(memory__h) $(stat__h)\
  $(oper_h)\
diff --git a/psi/msvc.mak b/psi/msvc.mak
index c811b7b..61e7dfa 100644
--- a/psi/msvc.mak
+++ b/psi/msvc.mak
@@ -244,6 +244,26 @@ GPDLGENDIR=$(GLGENDIR)
 GPDLOBJDIR=$(GLOBJDIR)
 !endif
 
+!ifndef URFSRCDIR
+URFSRCDIR=.\urf
+!endif
+!ifndef URFGENDIR
+URFGENDIR=$(GLGENDIR)
+!endif
+!ifndef URFOBJDIR
+URFOBJDIR=$(GLOBJDIR)
+!endif
+
+!ifndef IMGSRCDIR
+IMGSRCDIR=.\gpdl\img
+!endif
+!ifndef IMGGENDIR
+IMGGENDIR=$(GLGENDIR)
+!endif
+!ifndef IMGOBJDIR
+IMGOBJDIR=$(GLOBJDIR)
+!endif
+
 CONTRIBDIR=.\contrib
 
 # Can we build PCL and XPS and PDF
@@ -594,6 +614,28 @@ WITH_CUPS=0
 WITH_CUPS=0
 !endif
 
+# Should we build URF...
+!ifdef WITH_URF
+!if "$(WITH_URF)"!="0"
+WITH_URF=1
+!else
+WITH_URF=0
+!endif
+!else
+!if exist ("$(URFSRCDIR)")
+WITH_URF=1
+!else
+WITH_URF=0
+!endif
+!endif
+!if "$(WITH_URF)"=="1"
+ENABLE_URF=$(D_)URF_INCLUDED$(_D)
+GPDL_URF_TOP_OBJ=$(GPDLOBJ)/$(GPDL_URF_TOP_OBJ_FILE)
+URF_INCLUDE=$(I_)$(URFSRCDIR)$(_I)
+URF_DEV=$(GLD)urfd.dev
+SURFX_H=$(URFSRCDIR)$(D)surfx.h
+!endif
+
 # Should we build using CAL....
 CALSRCDIR=cal
 !ifdef WITH_CAL
@@ -1473,7 +1515,7 @@ FEATURE_DEVS=$(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev $(GLD)psl3lib.dev
 	     $(GLD)seprlib.dev $(GLD)translib.dev $(GLD)cidlib.dev $(GLD)psf0lib.dev $(GLD)psf1lib.dev\
              $(GLD)psf2lib.dev $(GLD)lzwd.dev $(GLD)sicclib.dev $(GLD)mshandle.dev $(GLD)mspoll.dev \
              $(GLD)ramfs.dev $(GLD)sjpx.dev $(GLD)sjbig2.dev \
-             $(GLD)pwgd.dev $(GLD)siscale.dev
+             $(GLD)pwgd.dev $(GLD)siscale.dev $(URF_DEV)
 
 
 !ifndef METRO
@@ -1536,6 +1578,9 @@ DEVICE_DEVS16=$(DD)bbox.dev $(DD)plib.dev $(DD)plibg.dev $(DD)plibm.dev $(DD)pli
 !if "$(WITH_CUPS)" == "1"
 DEVICE_DEVS16=$(DEVICE_DEVS16) $(DD)cups.dev
 !endif
+!if "$(WITH_URF)" == "1"
+DEVICE_DEVS16=$(DEVICE_DEVS16) $(DD)urfgray.dev $(DD)urfrgb.dev $(DD)urfcmyk.dev
+!endif
 # Overflow for DEVS3,4,5,6,9
 DEVICE_DEVS17=$(DD)ljet3.dev $(DD)ljet3d.dev $(DD)ljet4.dev $(DD)ljet4d.dev
 DEVICE_DEVS18=$(DD)pj.dev $(DD)pjxl.dev $(DD)pjxl300.dev $(DD)jetp3852.dev $(DD)r4081.dev
diff --git a/psi/zfilter.c b/psi/zfilter.c
index dd06c75..dfe3a1d 100644
--- a/psi/zfilter.c
+++ b/psi/zfilter.c
@@ -32,6 +32,10 @@
 #include "ifilter.h"
 #include "files.h"		/* for filter_open, file_d'_buffer_size */
 
+#ifdef URF_INCLUDED
+#include "urffilter.c"
+#endif
+
 /* <source> ASCIIHexEncode/filter <file> */
 /* <source> <dict> ASCIIHexEncode/filter <file> */
 static int
@@ -497,6 +501,9 @@ const op_def zfilter_op_defs[] = {
     {"2RunLengthEncode", zRLE},
     {"1RunLengthDecode", zRLD},
     {"1PWGDecode", zPWGD},
+#ifdef URF_INCLUDED
+    {"1URFDecode", zURFD},
+#endif
     {"3SubFileDecode", zSFD},
     {"1.EOFDecode", zEOFD},
     op_def_end(0)
diff --git a/windows/ghostpdl.vcproj b/windows/ghostpdl.vcproj
index bfddbd2..c105cc3 100644
--- a/windows/ghostpdl.vcproj
+++ b/windows/ghostpdl.vcproj
@@ -310,6 +310,30 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="urf"
+			>
+			<File
+				RelativePath="..\gpdl\urf\urftop.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="image"
+			>
+			<File
+				RelativePath="..\gpdl\image\imagetop.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="pwg"
+			>
+			<File
+				RelativePath="..\gpdl\pwg\pwgtop.c"
+				>
+			</File>
+		</Filter>
 	</Files>
 	<Globals>
 	</Globals>
diff --git a/windows/ghostscript.vcproj b/windows/ghostscript.vcproj
index b7cc9d5..c06c7b1 100644
--- a/windows/ghostscript.vcproj
+++ b/windows/ghostscript.vcproj
@@ -9628,6 +9628,26 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="urf"
+			>
+			<File
+				RelativePath="..\urf\gdevurf.c"
+				>
+			</File>
+			<File
+				RelativePath="..\urf\surfd.c"
+				>
+			</File>
+			<File
+				RelativePath="..\urf\surfx.h"
+				>
+			</File>
+			<File
+				RelativePath="..\urf\urffilter.c"
+				>
+			</File>
+		</Filter>
 	</Files>
 	<Globals>
 	</Globals>
diff --git a/xps/xpsimage.c b/xps/xpsimage.c
index 94a8f5f..e08a068 100644
--- a/xps/xpsimage.c
+++ b/xps/xpsimage.c
@@ -264,6 +264,7 @@ xps_paint_image_brush_imp(xps_context_t *ctx, xps_image_t *image, int alpha)
 
     gsimage.Interpolate = 1;
 
+    /* FIXME: leak enum in case of error */
     penum = gs_image_enum_alloc(ctx->memory, "xps_parse_image_brush (gs_image_enum_alloc)");
     if (!penum)
         return gs_throw(gs_error_VMerror, "gs_enum_allocate failed");
diff --git a/xps/xpsjxr.c b/xps/xpsjxr.c
index 89eaf19..e12bbee 100644
--- a/xps/xpsjxr.c
+++ b/xps/xpsjxr.c
@@ -203,7 +203,11 @@ xps_decode_jpegxr(xps_context_t *ctx, byte *buf, int len, xps_image_t *output)
         xps_free(ctx, name);
         return gs_throw(gs_error_invalidfileaccess, "cannot write to scratch file");
     }
-    xps_fseek(file, 0, SEEK_SET);
+    rc = xps_fseek(file, 0, SEEK_SET);
+    if (rc != 0) {
+        xps_free(ctx, name);
+        return gs_throw(gs_error_invalidfileaccess, "cannot write to scratch file");
+    }
 
     container = jxr_create_container();
     rc = jxr_read_image_container(container, gp_get_file(file));
@@ -236,11 +240,19 @@ xps_decode_jpegxr(xps_context_t *ctx, byte *buf, int len, xps_image_t *output)
     state.output = output;
     jxr_set_user_data(image, &state);
 
-    xps_fseek(file, offset, SEEK_SET);
+    rc = xps_fseek(file, offset, SEEK_SET);
+    if (rc != 0) {
+        xps_free(ctx, name);
+        jxr_destroy_container(container);
+        jxr_destroy(image);
+        return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc));
+    }
+
     rc = jxr_read_image_bitstream(image, gp_get_file(file));
     if (rc < 0) {
         xps_free(ctx, name);
         jxr_destroy_container(container);
+        jxr_destroy(image);
         return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc));
     }
 
@@ -265,11 +277,19 @@ xps_decode_jpegxr(xps_context_t *ctx, byte *buf, int len, xps_image_t *output)
         state.output = output;
         jxr_set_user_data(image, &state);
 
-        xps_fseek(file, alpha_offset, SEEK_SET);
+        rc = xps_fseek(file, alpha_offset, SEEK_SET);
+        if (rc != 0) {
+            xps_free(ctx, name);
+            jxr_destroy_container(container);
+            jxr_destroy(image);
+            return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc));
+        }
+
         rc = jxr_read_image_bitstream(image, gp_get_file(file));
         if (rc < 0) {
             xps_free(ctx, name);
             jxr_destroy_container(container);
+            jxr_destroy(image);
             return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc));
         }
 
diff --git a/xps/xpstop.c b/xps/xpstop.c
index 49d31c7..a53cc7a 100644
--- a/xps/xpstop.c
+++ b/xps/xpstop.c
@@ -127,6 +127,7 @@ xps_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
         return gs_error_VMerror;
     }
 
+    /* FIXME: check return value */
     gsicc_init_iccmanager(pgs);
     memset(ctx, 0, sizeof(xps_context_t));
 


Summary of changes:
 Makefile.in                 |  16 +-
 Resource/Init/gs_cidfm.ps   |   7 +-
 Resource/Init/gs_lev2.ps    |   2 +-
 Resource/Init/gs_res.ps     |   2 +-
 Resource/Init/pdf_draw.ps   |  11 +-
 Resource/Init/pdf_font.ps   | 387 +++++++++++---------
 Resource/Init/pdf_main.ps   |  40 ++-
 Resource/Init/pdf_ops.ps    |  48 ++-
 base/gdevdevn.c             |   4 +-
 base/gdevdflt.c             |   3 +-
 base/gdevvec.c              |   5 +
 base/gpmisc.c               |   6 +-
 base/gsicc_create.c         |   6 +-
 base/gxclrast.c             |   1 +
 base/gxhintn.c              |   5 +-
 base/gxiscale.c             |   1 +
 base/lib.mak                |  11 +
 base/spwgd.c                |  11 +-
 base/unix-gcc.mak           |   2 +-
 configure.ac                |  57 ++-
 contrib/contrib.mak         |  24 ++
 contrib/gdevadmp.c          | 410 +++++++++++++++++++++
 contrib/gdevdj9.c           |   2 +-
 contrib/gdevlx32.c          |  17 +-
 contrib/gdevlx7.c           |  13 +-
 contrib/gdevmd2k.c          |   6 +-
 contrib/japanese/gdev10v.c  |   3 +-
 contrib/japanese/gdevlbp3.c |   4 +-
 devices/devs.mak            |  19 +
 devices/gdev3852.c          |   7 +-
 devices/gdev4081.c          |  23 +-
 devices/gdev4693.c          |  29 +-
 devices/gdev8510.c          |   8 +-
 devices/gdevatx.c           |   4 +-
 devices/gdevbit.c           |  12 +-
 devices/gdevbj10.c          |   3 +-
 devices/gdevbmp.c           |   4 +-
 devices/gdevccr.c           |   8 +-
 devices/gdevcdj.c           |   8 +-
 devices/gdevcfax.c          |   4 +-
 devices/gdevcif.c           |  13 +-
 devices/gdevclj.c           |   8 +-
 devices/gdevcljc.c          |   2 +-
 devices/gdevdjtc.c          |  12 +-
 devices/gdevdm24.c          |  38 +-
 devices/gdevepsc.c          |  18 +-
 devices/gdevepsn.c          |  58 ++-
 devices/gdevescp.c          |  35 +-
 devices/gdevgprf.c          |   2 +
 devices/gdevhl7x.c          |  43 ++-
 devices/gdevicov.c          |  20 +-
 devices/gdevifno.c          |  11 +-
 devices/gdevimgn.c          |  12 +-
 devices/gdevjbig2.c         |   6 +-
 devices/gdevjpx.c           |   4 +-
 devices/gdevl31s.c          |  10 +-
 devices/gdevlbp8.c          |  10 +-
 devices/gdevlj56.c          |   3 +-
 devices/gdevlp8k.c          |  38 +-
 devices/gdevlxm.c           |  30 +-
 devices/gdevmgr.c           |  16 +-
 devices/gdevn533.c          |  11 +-
 devices/gdevokii.c          |  23 +-
 devices/gdevpbm.c           |   2 +
 devices/gdevpdfimg.c        |  18 +-
 devices/gdevperm.c          |  10 +-
 devices/gdevphex.c          |  33 +-
 devices/gdevpjet.c          |  14 +-
 devices/gdevpsim.c          |  18 +-
 devices/gdevrinkj.c         |  25 +-
 devices/gdevsppr.c          |  13 +-
 devices/gdevstc.c           |   8 +-
 devices/gdevtfnx.c          |  14 -
 devices/gdevtifs.c          |   5 +-
 devices/gdevtknk.c          |  11 +-
 devices/gdevtsep.c          |   3 +
 devices/gdevwpr2.c          |   8 +-
 devices/gdevxcf.c           |  18 +-
 devices/gdevxcmp.c          |  16 +-
 devices/vector/gdevagl.h    |   2 +-
 devices/vector/gdevpdf.c    |   4 +
 devices/vector/gdevpdfb.h   |   3 +-
 devices/vector/gdevpdfe.c   |  15 +-
 devices/vector/gdevpdfi.c   |   8 +-
 devices/vector/gdevpdfp.c   |  19 +
 devices/vector/gdevpdfx.h   |   2 +
 devices/vector/gdevtxtw.c   |   6 +-
 doc/Language.htm            |  24 ++
 gpdl/gpdl.mak               |  34 +-
 gpdl/image/imagetop.c       | 855 ++++++++++++++++++++++++++++++++++++++++++++
 gpdl/psi/gpdlpsi.mak        |  64 ----
 gpdl/pwg/pwgtop.c           | 718 +++++++++++++++++++++++++++++++++++++
 jbig2dec/jbig2.c            |   2 +
 jbig2dec/jbig2_halftone.c   |   6 +
 jpegxr/cw_emit.c            |   2 +-
 pcl/pcl/pcindxed.c          |  14 +-
 pcl/pcl/pcwhtidx.c          |   3 +-
 pcl/pcl/pgdraw.c            |   3 +-
 pcl/pl/pjparse.c            |   3 +-
 pcl/pl/plfont.c             |   4 +-
 pcl/pl/plimpl.c             |  16 +-
 pcl/pl/pllfont.c            |  12 +-
 psi/dscparse.c              |  10 +-
 psi/imainarg.c              |   4 +-
 psi/int.mak                 |   2 +-
 psi/msvc.mak                |  47 ++-
 psi/zfilter.c               |   7 +
 windows/ghostpdl.vcproj     |  24 ++
 windows/ghostscript.vcproj  |  20 ++
 xps/xpsimage.c              |   1 +
 xps/xpsjxr.c                |  26 +-
 xps/xpstop.c                |   1 +
 112 files changed, 3263 insertions(+), 570 deletions(-)
 create mode 100644 contrib/gdevadmp.c
 create mode 100644 gpdl/image/imagetop.c
 delete mode 100644 gpdl/psi/gpdlpsi.mak
 create mode 100644 gpdl/pwg/pwgtop.c