[gs-commits] ghostpdl branch, gs9.28-temp-for-testing, created. ghostpdl-9.28rc1-16-g3a9b8ab

[email protected] (Robin Watts)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, gs9.28-temp-for-testing has been created
        at  3a9b8ab4233e8157194092a43638d9f88d94ff92 (commit)


----------------------------------------------------------------------
commit 3a9b8ab4233e8157194092a43638d9f88d94ff92
Author: Robin Watts <[email protected]>
Date:   Wed Aug 21 17:49:32 2019 +0100

    Update bmpcmp.c to read psdrgb rather than psdbgr.

diff --git a/toolbin/bmpcmp.c b/toolbin/bmpcmp.c
index 3d047e5..e558641 100644
--- a/toolbin/bmpcmp.c
+++ b/toolbin/bmpcmp.c
@@ -1255,7 +1255,8 @@ static void *psd_read(ImageReader *im,
             }
             ptr += *span * h + 1;
         } else if (n == 3) {
-            /* RGB */
+            /* RGB (reverse to get BGR) */
+            ptr += 2;
             for (z = 0; z < n; z++)
             {
                 for (y = 0; y < h; y++)
@@ -1269,8 +1270,9 @@ static void *psd_read(ImageReader *im,
                     ptr -= w*N + *span;
                     line -= w;
                 }
-                ptr += *span * h + 1;
+                ptr += *span * h - 1;
             }
+            ptr += 4;
             for (y = 0; y < h; y++)
             {
                 for (x = 0; x < w; x++)
@@ -1320,7 +1322,8 @@ static void *psd_read(ImageReader *im,
             }
             ptr += *span * h + 1;
         } else if (n == 3) {
-            /* RGB */
+            /* RGB (reverse to get BGR) */
+            ptr += 2;
             for (z = 0; z < n; z++)
             {
                 for (y = 0; y < h; y++)
@@ -1335,8 +1338,9 @@ static void *psd_read(ImageReader *im,
                     ptr -= w*N + *span;
                     line -= w*2;
                 }
-                ptr += *span * h + 1;
+                ptr += *span * h - 1;
             }
+            ptr += 4;
             for (y = 0; y < h; y++)
             {
                 for (x = 0; x < w; x++)
@@ -2515,7 +2519,7 @@ static void untag_bmp(unsigned char *bmp,
         for (x = 0; x < w; x++)
         {
             int R, G, B, T, r, g, b;
- 
+
             T = *bmp++;
             R = *bmp++;
             G = *bmp++;

----------------------------------------------------------------------
commit 6fb54d64afde00a23f2b358062ac72b3f2a223d6
Author: Chris Liddell <[email protected]>
Date:   Wed Aug 21 15:33:27 2019 +0100

    Fix commit ec0b35fed3de: "Handle directory separators..."
    
    The logic in the above fix was wrong.

diff --git a/base/gpmisc.c b/base/gpmisc.c
index 30137b6..494e165 100644
--- a/base/gpmisc.c
+++ b/base/gpmisc.c
@@ -975,8 +975,8 @@ validate(const gs_memory_t *mem,
                 /* PATH=abcd pattern=abc */
                 break; /* No match */
             } else if (*a != *b
-                       && gs_file_name_check_separator(a, 1, a)
-                       != gs_file_name_check_separator(b, 1, b)) {
+                       && (gs_file_name_check_separator(a, 1, a) == 1
+                       && gs_file_name_check_separator(b, 1, b) == 1)) {
                 /* On Windows we can get random combinations of "/" and "\" as directory
                  * separators, and we want "C:\" to match C:/" hence using the pair of
                  * gs_file_name_check_separator() calls */

----------------------------------------------------------------------
commit ece0c97f7c85af0dbd31532da4a7bef2c1f6fd0c
Author: Robin Watts <[email protected]>
Date:   Wed Aug 21 14:28:20 2019 +0100

    Bug 701451: Fix clist color_usage calculations for shadings.
    
    Or rather, don't attempt to calculate them badly, and just
    use the safe "all colors" value.

diff --git a/base/gxclrect.c b/base/gxclrect.c
index 07f398f..a4b5982 100644
--- a/base/gxclrect.c
+++ b/base/gxclrect.c
@@ -425,21 +425,6 @@ clist_fill_rectangle_hl_color(gx_device *dev, const gs_fixed_rect *rect,
     return 0;
 }
 
-static void update_color_use_frac_array(uchar num_colors, const frac31 *color,
-    cmd_rects_enum_t *re)
-{
-    uchar k;
-
-    if (color == NULL)
-        return;
-
-    for (k = 0; k < num_colors; k++){
-        if (color[k] != 0) {
-            re->pcls->color_usage.or |= (1<<k);
-        }
-    }
-}
-
 static inline int
 clist_write_fill_trapezoid(gx_device * dev,
     const gs_fixed_edge *left, const gs_fixed_edge *right,
@@ -517,14 +502,11 @@ clist_write_fill_trapezoid(gx_device * dev,
         } else {
             /* Even with pdcolor NULL, we may still have colors packed in
                c0, c1, c2 or c3 */
-            update_color_use_frac_array(dev->color_info.num_components, c0, &re);
-            update_color_use_frac_array(dev->color_info.num_components, c1, &re);
-            update_color_use_frac_array(dev->color_info.num_components, c2, &re);
-            update_color_use_frac_array(dev->color_info.num_components, c3, &re);
+            re.pcls->color_usage.or |= gx_color_usage_all(cdev);
             code = 0;
         }
         if (code >= 0) {
-            /* Dont't want to shorten the trapezoid by the band boundary,
+            /* Don't want to shorten the trapezoid by the band boundary,
                keeping in mind a further optimization with writing same data to all bands. */
             code = cmd_write_trapezoid_cmd(cdev, re.pcls, cmd_opv_fill_trapezoid, left, right,
                                       ybot, ytop, options, fa, c0, c1, c2, c3);

----------------------------------------------------------------------
commit 75da8d9a2054f5a08817c42adbb2fa967cc9dad7
Author: Ken Sharp <[email protected]>
Date:   Wed Aug 21 10:10:51 2019 +0100

    PDF interpreter - review .forceput security
    
    Bug #701450 "Safer Mode Bypass by .forceput Exposure in .pdfexectoken"
    
    By abusing the error handler it was possible to get the PDFDEBUG portion
    of .pdfexectoken, which uses .forceput left readable.
    
    Add an executeonly appropriately to make sure that clause isn't readable
    no mstter what.
    
    Review all the uses of .forceput searching for similar cases, add
    executeonly as required to secure those. All cases in the PostScript
    support files seem to be covered already.

diff --git a/Resource/Init/pdf_base.ps b/Resource/Init/pdf_base.ps
index 2e28cdd..02503ee 100644
--- a/Resource/Init/pdf_base.ps
+++ b/Resource/Init/pdf_base.ps
@@ -157,7 +157,7 @@ currentdict /num-chars-dict .undef
     {
       dup ==only () = flush
     } ifelse % PDFSTEP
-  } if % PDFDEBUG
+  } executeonly if % PDFDEBUG
   2 copy .knownget {
     exch pop exch pop exch pop exec
   } {
diff --git a/Resource/Init/pdf_draw.ps b/Resource/Init/pdf_draw.ps
index 11eb485..fe3fc56 100644
--- a/Resource/Init/pdf_draw.ps
+++ b/Resource/Init/pdf_draw.ps
@@ -501,8 +501,8 @@ end
       (        Output may be incorrect.\n) pdfformaterror
       //pdfdict /.gs_warning_issued //true .forceput
       PDFSTOPONERROR { /gs /undefined signalerror } if
-    } if
-  }
+    } executeonly if
+  } executeonly
   ifelse
 } bind executeonly def
 
@@ -1152,7 +1152,7 @@ currentdict end readonly def
           .setglobal
           pdfformaterror
         } executeonly ifelse
-      }
+      } executeonly
       {
         currentglobal //pdfdict gcheck .setglobal
         //pdfdict /.Qqwarning_issued //true .forceput
@@ -1160,8 +1160,8 @@ currentdict end readonly def
         pdfformaterror
       } executeonly ifelse
       end
-    } ifelse
-  } loop
+    } executeonly ifelse
+  } executeonly loop
   {
     (\n   **** Error: File has unbalanced q/Q operators \(too many q's\)\n               Output may be incorrect.\n)
     //pdfdict /.Qqwarning_issued .knownget
@@ -1175,14 +1175,14 @@ currentdict end readonly def
         .setglobal
         pdfformaterror
       } executeonly ifelse
-    }
+    } executeonly
     {
       currentglobal //pdfdict gcheck .setglobal
       //pdfdict /.Qqwarning_issued //true .forceput
       .setglobal
       pdfformaterror
     } executeonly ifelse
-  } if
+  } executeonly if
   pop
 
   % restore pdfemptycount
diff --git a/Resource/Init/pdf_font.ps b/Resource/Init/pdf_font.ps
index da07da5..81b7af1 100644
--- a/Resource/Init/pdf_font.ps
+++ b/Resource/Init/pdf_font.ps
@@ -638,7 +638,7 @@ currentdict end readonly def
                   currentglobal 2 index dup gcheck setglobal
                   /FontInfo 5 dict dup 5 1 roll .forceput
                   setglobal
-                } if
+                } executeonly if
                 dup /GlyphNames2Unicode .knownget not {
                   //true                        % No existing G2U, make one
                 } {
@@ -668,10 +668,12 @@ currentdict end readonly def
                 pop                                     % font-res font-dict encoding|null font-info
                 pop                                     % font-res font-dict encoding|null
                 //false                                 % We built a GlyphNames2Unicode table, don't need to process further
-              }{
+              } executeonly
+              {
                 //true                                  % name is not Identity-V or H, fail by falling through
               }ifelse
-          } {
+          } executeonly
+          {
             //true
           } ifelse                                      % not a name, try as a dictionary (as specified)
 
@@ -759,9 +761,9 @@ currentdict end readonly def
           PDFDEBUG {
             (.processToUnicode end) =
           } if
-        } if
-      } if
-    } stopped
+        } executeonly if
+      } executeonly if
+    } executeonly stopped
     {
       .dstackdepth 1 countdictstack 1 sub
       {pop end} for
@@ -1298,19 +1300,20 @@ currentdict /eexec_pdf_param_dict .undef
                 //pdfdict /.Qqwarning_issued //true .forceput
               } executeonly if
               Q
-            } repeat
+            } executeonly repeat
             Q
-          } PDFfile fileposition 2 .execn % Keep pdfcount valid.
+          } executeonly PDFfile fileposition 2 .execn % Keep pdfcount valid.
           PDFfile exch setfileposition
-        } ifelse
-      } {
+        } executeonly ifelse
+      } executeonly
+      {
         % PDF Type 3 fonts don't use .notdef
         % d1 implementation adjusts the width as needed
         0 0 0 0 0 0
         pdfopdict /d1 get exec
       } ifelse
       end end
-    } bdef
+    } executeonly bdef
     dup currentdict Encoding .processToUnicode
     currentdict end .completefont exch pop
 } bind executeonly odef
@@ -2124,9 +2127,9 @@ currentdict /CMap_read_dict undef
           (Will continue, but content may be missing.) = flush
         } ifelse
       } if
-    } if
+    } executeonly if
     /findresource cvx /undefined signalerror
-  } loop
+  } executeonly loop
 } bind executeonly odef
 
 /buildCIDType0 {	% <CIDFontType0-font-resource> buildCIDType0 <font>
diff --git a/Resource/Init/pdf_main.ps b/Resource/Init/pdf_main.ps
index 00d7e36..7690bae 100644
--- a/Resource/Init/pdf_main.ps
+++ b/Resource/Init/pdf_main.ps
@@ -2771,15 +2771,15 @@ currentdict /PDF2PS_matrix_key undef
           .setglobal
           pdfformaterror
         } executeonly ifelse
-      }
+      } executeonly
       {
         currentglobal //pdfdict gcheck .setglobal
         //pdfdict /.Qqwarning_issued //true .forceput
         .setglobal
         pdfformaterror
       } executeonly ifelse
-    } if
-  } if
+    } executeonly if
+  } executeonly if
   pop
   count PDFexecstackcount sub { pop } repeat
   (after exec) VMDEBUG
diff --git a/Resource/Init/pdf_ops.ps b/Resource/Init/pdf_ops.ps
index a15c8c6..d594035 100644
--- a/Resource/Init/pdf_ops.ps
+++ b/Resource/Init/pdf_ops.ps
@@ -192,14 +192,14 @@ currentdict /gput_always_allow .undef
         .setglobal
         pdfformaterror
       } executeonly ifelse
-    }
+    } executeonly
     {
       currentglobal //pdfdict gcheck .setglobal
       //pdfdict /.Qqwarning_issued //true .forceput
       .setglobal
       pdfformaterror
     } executeonly ifelse
-  } if
+  } executeonly if
 } bind executeonly odef
 
 % Save PDF gstate
@@ -446,11 +446,12 @@ currentdict /gput_always_allow .undef
   dup type /booleantype eq {
     .currentSMask type /dicttype eq {
       .currentSMask /Processed 2 index .forceput
-  } executeonly
-  {
+    } executeonly
+    {
       .setSMask
-  }ifelse
-  }{
+    }ifelse
+  } executeonly
+  {
   .setSMask
   }ifelse
 

----------------------------------------------------------------------
commit 4b510ef5b1397d473734c51a6756ec23d64d2d63
Author: Chris Liddell <[email protected]>
Date:   Wed Aug 21 10:56:02 2019 +0100

    Handle directory separators in access control matching
    
    On Windows, we end up dealing with a mishmash of "/" and "\" as directory
    separators, so a simple equality check isn't sufficient.
    
    Since there is already (platform specific) function for checking whether a
    string (or part thereof) is a directory separation, use it.

diff --git a/base/gpmisc.c b/base/gpmisc.c
index 386dd2b..30137b6 100644
--- a/base/gpmisc.c
+++ b/base/gpmisc.c
@@ -974,7 +974,12 @@ validate(const gs_memory_t *mem,
                  }
                 /* PATH=abcd pattern=abc */
                 break; /* No match */
-            } else if (*a != *b) {
+            } else if (*a != *b
+                       && gs_file_name_check_separator(a, 1, a)
+                       != gs_file_name_check_separator(b, 1, b)) {
+                /* On Windows we can get random combinations of "/" and "\" as directory
+                 * separators, and we want "C:\" to match C:/" hence using the pair of
+                 * gs_file_name_check_separator() calls */
                 break;
             }
             a++, b++;

----------------------------------------------------------------------
commit bca2b4da5e4a78026546ad779bd929c8ac282be1
Author: Michael Vrhel <[email protected]>
Date:   Tue Aug 20 21:50:18 2019 -0700

    Disable use of alternate tint transform ICC profile
    
    A prior commit introduced the use of color management
    if the DeviceN or Separation device had an ICC profile
    associated with the colorants.  While there is an argument
    for doing this, it is not the standard behavior seen in
    AR.  Disabling for now and will likely turn this into a
    command line option.

diff --git a/base/gxcmap.c b/base/gxcmap.c
index b2cde83..417a2ea 100644
--- a/base/gxcmap.c
+++ b/base/gxcmap.c
@@ -37,6 +37,15 @@
 #include "gsicc.h"
 #include "gxdevsop.h"
 
+/* If enabled, this makes use of the alternate transform
+   ICC profile for mapping separation and
+   DeviceN colorants from CMYK to output
+   ICC color space iff the profiles make
+   sense.  We should probably make this yet
+   another color command line option. Disabling
+   it for now for the current release. */
+#define USE_ALT_MAP 0
+
 /* Structure descriptor */
 public_st_device_color();
 static
@@ -1366,13 +1375,15 @@ devicen_sep_icc_cmyk(frac cm_comps[], const gs_gstate * pgs,
             src_profile = pcs->params.device_n.devn_process_space->cmm_icc_profile_data;
         } else if (pcs->base_space != NULL &&
             pcs->base_space->cmm_icc_profile_data != NULL &&
-            pcs->base_space->cmm_icc_profile_data->data_cs == gsCMYK) {
+            pcs->base_space->cmm_icc_profile_data->data_cs == gsCMYK &&
+            USE_ALT_MAP) {
             src_profile = pcs->base_space->cmm_icc_profile_data;
         }
     } else if (gs_color_space_get_index(pcs) == gs_color_space_index_Separation) {
         if (pcs->base_space != NULL &&
             pcs->base_space->cmm_icc_profile_data != NULL &&
-            pcs->base_space->cmm_icc_profile_data->data_cs == gsCMYK) {
+            pcs->base_space->cmm_icc_profile_data->data_cs == gsCMYK &&
+            USE_ALT_MAP) {
             src_profile = pcs->base_space->cmm_icc_profile_data;
         }
     }

----------------------------------------------------------------------
commit cab13732d2e5f0a2762cb159bee21350e854dcf7
Author: Robin Watts <[email protected]>
Date:   Tue Aug 20 18:48:49 2019 +0100

    Fix crashes in RAW_DUMP debug code.
    
    Dump the buffer before freeing the device, or the pointer will no
    longer be valid.
    
    Also, don't access through ppatdev14 when we know it's NULL.

diff --git a/base/gdevp14.c b/base/gdevp14.c
index 90b5298..6a7a8a7 100644
--- a/base/gdevp14.c
+++ b/base/gdevp14.c
@@ -2056,8 +2056,6 @@ pdf14_get_buffer_information(const gx_device * dev,
             transbuff->mem = buf->memory;
             buf->data = NULL;  /* So that the buffer is not freed */
         }
-        /* Go ahead and free up the pdf14 device */
-        dev_proc(dev, close_device)((gx_device *)dev);
 #if RAW_DUMP
         /* Dump the buffer that should be going into the pattern */;
         dump_raw_buffer(buf->memory,
@@ -2067,6 +2065,8 @@ pdf14_get_buffer_information(const gx_device * dev,
                         transbuff->deep);
         global_index++;
 #endif
+        /* Go ahead and free up the pdf14 device */
+        dev_proc(dev, close_device)((gx_device *)dev);
     } else {
         /* Here we are coming from one of the fill image / pattern / mask
            operations */
@@ -2869,7 +2869,7 @@ pdf14_fill_path(gx_device *dev,	const gs_gstate *pgs,
                 } else {
                      gx_pattern_trans_t *patt_trans =
                                         pdcolor->colors.pattern.p_tile->ttrans;
-                     dump_raw_buffer(ppatdev14->ctx->memory,
+                     dump_raw_buffer(patt_trans->mem,
                                      patt_trans->rect.q.y-patt_trans->rect.p.y,
                                      patt_trans->rect.q.x-patt_trans->rect.p.x,
                                      patt_trans->n_chan,

----------------------------------------------------------------------
commit 9ee7306701276499c7a75c65a98d46898afe3e15
Author: Robin Watts <[email protected]>
Date:   Tue Aug 20 18:47:09 2019 +0100

    Fix deep color transparency pattern copying problem.
    
    The following test:
    
      tests/pdf/pattrans_solid_nonrect.pdf.psdcmyk16.300.1..gs
    
    among others, was showing problems, due to us treating the offset
    as bytes rather than shorts.

diff --git a/base/gxp1fill.c b/base/gxp1fill.c
index a77804a..bb4efc8 100644
--- a/base/gxp1fill.c
+++ b/base/gxp1fill.c
@@ -780,7 +780,7 @@ tile_rect_trans_simple(int xmin, int ymin, int xmax, int ymax,
     left_copy_width = left_copy_rem_end - left_copy_start;
     if (left_copy_width < 0)
         left_copy_width = 0;
-    left_copy_offset = left_copy_start-ptile->ttrans->rect.p.x;
+    left_copy_offset = (left_copy_start-ptile->ttrans->rect.p.x)<<deep;
 
     /* Now the middle part */
     num_full_tiles = (int)fastfloor((float) (w - left_width)/ (float) tile_width);

----------------------------------------------------------------------
commit 283436158b5ab3c3286ef6f3e6f71e9b9b5f6424
Author: Robin Watts <[email protected]>
Date:   Tue Aug 20 14:29:33 2019 +0100

    Avoid signed overflow in deep transparency calculations.

diff --git a/base/gxblend.c b/base/gxblend.c
index aaadca8..15b8e9b 100644
--- a/base/gxblend.c
+++ b/base/gxblend.c
@@ -1920,7 +1920,7 @@ art_pdf_composite_pixel_alpha_16_inline(uint16_t *gs_restrict dst, uint16_t *gs_
     /* todo: verify that a_r is nonzero in all cases */
 
     /* Compute a_s / a_r in 16.16 format */
-    src_scale = ((a_s << 16) + (a_r >> 1)) / a_r;
+    src_scale = ((unsigned int)((a_s << 16) + (a_r >> 1))) / a_r;
 
     if (first_spot != 0) {
         /* Do compositing with blending */
@@ -2184,7 +2184,7 @@ art_pdf_recomposite_group_16(uint16_t *gs_restrict *dstp, uint16_t *gs_restrict
         if (src_alpha_g != 65535 && dst_alpha != 0) {
             /* Uncomposite the color. In other words, solve
                "src = (src, src_alpha_g) over dst" for src */
-            scale = (dst_alpha * 65535 + (src_alpha_g>>1)) / src_alpha_g -
+            scale = ((unsigned int)(dst_alpha * 65535 + (src_alpha_g>>1))) / src_alpha_g -
                 dst_alpha;
             for (i = 0; i < n_chan; i++) {
                 int si, di;

----------------------------------------------------------------------
commit d2a6be4518833082eba7f6d972df6fb8079002c5
Author: Robin Watts <[email protected]>
Date:   Tue Aug 20 12:24:03 2019 +0100

    Fix overflow in deep color blending.
    
    Multiplying a 16bit unsigned value with a 16 bit signed value
    in a 32bit int means we lose the sign bit. Sacrifice a bit of
    accuracy to avoid that.

diff --git a/base/gxblend.c b/base/gxblend.c
index 0e29fc9..aaadca8 100644
--- a/base/gxblend.c
+++ b/base/gxblend.c
@@ -1934,6 +1934,8 @@ art_pdf_composite_pixel_alpha_16_inline(uint16_t *gs_restrict dst, uint16_t *gs_
                 dst[i] += (src_scale * (blend[i] - dst[i]) + 0x8000) >> 16;
             }
         } else {
+            int a_b2 = a_b>>1;
+            int ss2 = src_scale>>1;
             for (i = 0; i < first_spot; i++) {
                 int c_bl;		/* Result of blend function */
 
@@ -1941,8 +1943,8 @@ art_pdf_composite_pixel_alpha_16_inline(uint16_t *gs_restrict dst, uint16_t *gs_
                 c_b = dst[i];
                 c_bl = blend[i];
 
-                c_s += (a_b * (c_bl - c_s) + 0x8000) >> 16;
-                c_b += (src_scale * (c_s - c_b) + 0x8000) >> 16;
+                c_s += (a_b2 * (c_bl - c_s) + 0x4000) >> 15;
+                c_b += (ss2 * (c_s - c_b) + 0x4000) >> 15;
                 dst[i] = c_b;
             }
         }

----------------------------------------------------------------------
commit 3d53812ceb4b8d2efaae805f04a508d793873330
Author: Ken Sharp <[email protected]>
Date:   Tue Aug 20 10:10:28 2019 +0100

    make .forceput inaccessible
    
    Bug #701343, #701344, #701345
    
    More defensive programming. We don't want people to access .forecput
    even though it is no longer sufficient to bypass SAFER. The exploit
    in #701343 didn't work anyway because of earlier work to stop the error
    handler being used, but nevertheless, prevent access to .forceput from
    .setuserparams2.

diff --git a/Resource/Init/gs_lev2.ps b/Resource/Init/gs_lev2.ps
index 4cc7f82..0fd4164 100644
--- a/Resource/Init/gs_lev2.ps
+++ b/Resource/Init/gs_lev2.ps
@@ -158,7 +158,7 @@ end
     {
       pop pop
     } ifelse
-  } forall
+  } executeonly forall
         % A context switch might have occurred during the above loop,
         % causing the interpreter-level parameters to be reset.
         % Set them again to the new values.  From here on, we are safe,
@@ -229,9 +229,9 @@ end
        { pop pop
        }
       ifelse
-    }
+    } executeonly
    forall pop
-} .bind odef
+} .bind executeonly odef
 
 % Initialize the passwords.
 % NOTE: the names StartJobPassword and SystemParamsPassword are known to
diff --git a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps
index c158a8f..422e66e 100644
--- a/Resource/Init/gs_pdfwr.ps
+++ b/Resource/Init/gs_pdfwr.ps
@@ -658,11 +658,11 @@ currentdict /.pdfmarkparams .undef
           systemdict /.pdf_hooked_DSC_Creator //true .forceput
         } executeonly if
         pop
-      } if
+      } executeonly if
     } {
       pop
     } ifelse
-  }
+  } executeonly
   {
     pop
   } ifelse

----------------------------------------------------------------------
commit 5cd7e498ed865e408ffb0f3be2172260edfa2993
Author: Chris Liddell <[email protected]>
Date:   Mon Aug 19 10:03:57 2019 +0100

    Handle drag'n'drop file name/paths
    
    Because we now run by default with the file access permission active,
    we need to do additional work for Windows drag and drop files, so they don't
    throw an invalidaccess error (since we implement drag and drop by sending
    characters to the gs console to do '(file) run').
    
    The problem is, we cannot add the file to read list, send the characters to the
    console, and remove the file from the read list because, although SendMessage()
    blocks until the message is handles, WriteConsoleInput() does not block until
    the console buffers are consumed (i.e. it is asynchronous). So, there is no
    certainty when the final SendMessage() in WM_DROPFILES case is finished that
    Ghostcript will actually have run the file.
    
    So, we create a list of dropped file names, add them to the permit read list,
    when the next WM_DROPFILES event happens, or a WM_DESTROY event, we drop
    file names from the permit read list before, if necessary, adding the current
    ones.

diff --git a/psi/dwimg.c b/psi/dwimg.c
index c38a2c3..62f7f5f 100644
--- a/psi/dwimg.c
+++ b/psi/dwimg.c
@@ -51,6 +51,10 @@
 static const char szImgName2[] = "Ghostscript Image";
 static const char szTrcName2[] = "Ghostscript Graphical Trace";
 
+/* These two are defined in dwmain.c/dwmainc.c because they need access to the gsdll and instance */
+int dwmain_add_file_control_path(const TCHAR *pathfile);
+void dwmain_remove_file_control_path(const TCHAR *pathfile);
+
 /* Forward references */
 LRESULT CALLBACK WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
 
@@ -1157,6 +1161,8 @@ WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
     RECT rect;
     int nVscrollInc, nHscrollInc;
     IMAGE *img;
+    static int cFiles = 0;
+    static char** szFiles = NULL;
 
     if (message == WM_CREATE) {
         /* Object is stored in window extra data.
@@ -1455,32 +1461,50 @@ WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             if (img->hwndtext)
                 SendMessage(img->hwndtext, message, wParam, lParam);
             else {
-                char *szFile;
-                int i, cFiles;
+                int i, lcFiles, code;
                 unsigned int Len, error;
                 const char *p;
                 const char *szDragPre = "\r(";
                 const char *szDragPost = ") run\r";
                 HDROP hdrop = (HDROP)wParam;
-                cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
-                for (i=0; i<cFiles; i++) {
+                for (i = 0; szFiles != NULL && i < cFiles; i++) {
+                    if (szFiles[i] != NULL) {
+                        dwmain_remove_file_control_path(szFiles[i]);
+                            free(szFiles[i]);
+                            szFiles[i] = NULL;
+                    }
+                }
+                lcFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
+                if (cFiles < lcFiles) {
+                    free(szFiles);
+                    szFiles = malloc(lcFiles * sizeof(char*));
+                    if (!szFiles) {
+                        cFiles = 0;
+                        return 0;
+                    }
+                    memset(szFiles, 0x00, lcFiles * sizeof(char*));
+                    cFiles = lcFiles;
+                }
+                for (i=0; i<lcFiles; i++) {
                     Len = DragQueryFile(hdrop, i, NULL, 0);
-                    szFile = malloc(Len+1);
-                    if (szFile != 0) {
-                        error = DragQueryFile(hdrop, i, szFile, Len+1);
+                    szFiles[i] = malloc(Len+1);
+                    if (szFiles[i] != 0) {
+                        error = DragQueryFile(hdrop, i, szFiles[i], Len+1);
                         if (error != 0) {
-                            for (p=szDragPre; *p; p++)
-                                SendMessage(hwnd,WM_CHAR,*p,1L);
-                            for (p=szFile; *p; p++) {
-                                if (*p == '\\')
-                                    SendMessage(hwnd,WM_CHAR,'/',1L);
-                                else
+                            code = dwmain_add_file_control_path(szFiles[i]);
+                            if (code >= 0){
+                                for (p=szDragPre; *p; p++)
+                                    SendMessage(hwnd,WM_CHAR,*p,1L);
+                                for (p=szFiles[i]; *p; p++) {
+                                    if (*p == '\\')
+                                        SendMessage(hwnd,WM_CHAR,'/',1L);
+                                    else
+                                        SendMessage(hwnd,WM_CHAR,*p,1L);
+                                }
+                                for (p=szDragPost; *p; p++)
                                     SendMessage(hwnd,WM_CHAR,*p,1L);
                             }
-                            for (p=szDragPost; *p; p++)
-                                SendMessage(hwnd,WM_CHAR,*p,1L);
                         }
-                        free(szFile);
                     }
                 }
                 DragFinish(hdrop);
@@ -1493,12 +1517,25 @@ WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
                     img->cx, img->cy);
                 win_set_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf);
             }
+            { /* Get rid of left over drag'n'drop file names*/
+                int i;
+                for (i = 0; szFiles != NULL && i < cFiles; i++) {
+                    if (szFiles[i] != NULL) {
+                        dwmain_remove_file_control_path(szFiles[i]);
+                        free(szFiles[i]);
+                        szFiles[i] = NULL;
+                    }
+                }
+                free(szFiles);
+                szFiles = NULL;
+                cFiles = 0;
+            }
             DragAcceptFiles(hwnd, FALSE);
             break;
 
     }
 
-        return DefWindowProc(hwnd, message, wParam, lParam);
+    return DefWindowProc(hwnd, message, wParam, lParam);
 }
 
 /* Repaint a section of the window. */
diff --git a/psi/dwmain.c b/psi/dwmain.c
index 224dd29..ebddbb5 100644
--- a/psi/dwmain.c
+++ b/psi/dwmain.c
@@ -97,6 +97,45 @@ static int GSDLLCALL gsdll_poll(void *handle)
 {
     return poll();
 }
+
+/* make a file readable, for drag'n'drop */
+int dwmain_add_file_control_path(const TCHAR *pathfile)
+{
+    LPSTR p;
+    int code, i;
+    p = malloc(wchar_to_utf8(NULL, (wchar_t *)pathfile));
+    if (p) {
+        wchar_to_utf8(p, (wchar_t *)pathfile);
+        for (i = 0; i < strlen(p); i++) {
+            if (p[i] == '\\') {
+                p[i] = '/';
+            }
+        }
+        code = gsdll.add_control_path(instance, GS_PERMIT_FILE_READING, p);
+        free(p);
+    }
+    else {
+        code = -1;
+    }
+    return code;
+}
+void dwmain_remove_file_control_path(const TCHAR *pathfile)
+{
+    LPSTR p;
+    int i;
+    p = malloc(wchar_to_utf8(NULL, (wchar_t *)pathfile));
+    if (p) {
+        wchar_to_utf8(p, (wchar_t *)pathfile);
+        for (i = 0; i < strlen(p); i++) {
+            if (p[i] == '\\') {
+                p[i] = '/';
+            }
+        }
+        gsdll.remove_control_path(instance, GS_PERMIT_FILE_READING, p);
+        free(p);
+    }
+}
+
 /*********************************************************************/
 
 /* new dll display device */
diff --git a/psi/dwmainc.c b/psi/dwmainc.c
index 9e7558f..cc0db1f 100644
--- a/psi/dwmainc.c
+++ b/psi/dwmainc.c
@@ -109,6 +109,44 @@ gsdll_stderr(void *instance, const char *str, int len)
     return len;
 }
 
+/* make a file readable, for drag'n'drop */
+/* In this version (for the console app) TCHAR is just char */
+int dwmain_add_file_control_path(const TCHAR *pathfile)
+{
+    int i, code;
+    char *p = (char *)pathfile;
+
+    for (i = 0; i < strlen(p); i++) {
+        if (p[i] == '\\') {
+            p[i] = '/';
+        }
+    }
+    code = gsdll.add_control_path(instance, GS_PERMIT_FILE_READING, (const char *)p);
+    for (i = 0; i < strlen(p); i++) {
+        if (p[i] == '/') {
+            p[i] = '\\';
+        }
+    }
+    return code;
+}
+void dwmain_remove_file_control_path(const TCHAR *pathfile)
+{
+    int i;
+    char *p = (char *)pathfile;
+
+    for (i = 0; i < strlen(p); i++) {
+        if (p[i] == '\\') {
+            p[i] = '/';
+        }
+    }
+    gsdll.remove_control_path(instance, GS_PERMIT_FILE_READING, (const char *)p);
+    for (i = 0; i < strlen(p); i++) {
+        if (p[i] == '/') {
+            p[i] = '\\';
+        }
+    }
+}
+
 /* stdio functions - versions that translate to/from utf-8 */
 static int GSDLLCALL
 gsdll_stdin_utf8(void *instance, char *buf, int len)
diff --git a/psi/dwtext.c b/psi/dwtext.c
index 750c216..984ea45 100644
--- a/psi/dwtext.c
+++ b/psi/dwtext.c
@@ -50,6 +50,10 @@
 #define M_COPY_CLIP 1
 #define M_PASTE_CLIP 2
 
+/* These two are defined in dwmain.c/dwmainc.c because they need access to the gsdll and instance */
+int dwmain_add_file_control_path(const TCHAR *pathfile);
+void dwmain_remove_file_control_path(const TCHAR *pathfile);
+
 LRESULT CALLBACK WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
 static void text_error(char *message);
 static void text_new_line(TW *tw);
@@ -736,33 +740,52 @@ int ch;
 void
 text_drag_drop(TW *tw, HDROP hdrop)
 {
-    TCHAR *szFile;
-    int i, cFiles;
+    int i, cFiles, code;
     unsigned int Len, error;
     const char *p;
     const TCHAR *t;
     if ( (tw->DragPre==NULL) || (tw->DragPost==NULL) )
             return;
 
+    for (i = 0; tw->szFiles && i < tw->cFiles; i++) {
+        if (tw->szFiles[i] != NULL) {
+            dwmain_remove_file_control_path(tw->szFiles[i]);
+            free(tw->szFiles[i]);
+            tw->szFiles[i] = NULL;
+        }
+    }
+
     cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPTSTR)NULL, 0);
+    if (tw->cFiles < cFiles) {
+        free(tw->szFiles);
+        tw->szFiles = malloc(cFiles * sizeof(char*));
+        if (tw->szFiles == NULL) {
+            tw->cFiles = 0;
+            return;
+        }
+        memset(tw->szFiles, 0x00, cFiles * sizeof(char*));
+        tw->cFiles = cFiles;
+    }
     for (i=0; i<cFiles; i++) {
         Len = DragQueryFile(hdrop, i, NULL, 0);
-        szFile = (TCHAR *)malloc((Len+1)*sizeof(TCHAR));
-        if (szFile != 0) {
-            error = DragQueryFile(hdrop, i, szFile, Len+1);
+        tw->szFiles[i] = (TCHAR *)malloc((Len+1)*sizeof(TCHAR));
+        if (tw->szFiles[i] != 0) {
+            error = DragQueryFile(hdrop, i, tw->szFiles[i], Len+1);
             if (error != 0) {
-                for (p=tw->DragPre; *p; p++)
-                    SendMessage(tw->hwnd,WM_CHAR,*p,1L);
-                for (t=szFile; *t; t++) {
-                    if (*t == '\\')
-                        SendMessage(tw->hwnd,WM_CHAR,'/',1L);
-                    else
-                        SendMessage(tw->hwnd,WM_CHAR,*t,1L);
+                code = dwmain_add_file_control_path(tw->szFiles[i]);
+                if (code >= 0) {
+                    for (p=tw->DragPre; *p; p++)
+                        SendMessage(tw->hwnd,WM_CHAR,*p,1L);
+                    for (t=tw->szFiles[i]; *t; t++) {
+                        if (*t == '\\')
+                            SendMessage(tw->hwnd,WM_CHAR,'/',1L);
+                        else
+                            SendMessage(tw->hwnd,WM_CHAR,*t,1L);
+                    }
+                    for (p=tw->DragPost; *p; p++)
+                        SendMessage(tw->hwnd,WM_CHAR,*p,1L);
                 }
-                for (p=tw->DragPost; *p; p++)
-                    SendMessage(tw->hwnd,WM_CHAR,*p,1L);
             }
-            free(szFile);
         }
     }
     DragFinish(hdrop);
@@ -1155,6 +1178,17 @@ WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
             if (tw->hfont)
                 DeleteFont(tw->hfont);
             tw->hfont = (HFONT)0;
+            {/* Remove left over drag'n'drop file names */
+                int i;
+                for (i = 0; tw->szFiles != NULL && i < tw->cFiles; i++) {
+                    dwmain_remove_file_control_path(tw->szFiles[i]);
+                    free(tw->szFiles[i]);
+                    tw->szFiles[i] = NULL;
+                }
+                free(tw->szFiles);
+                tw->szFiles = NULL;
+                tw->cFiles = 0;
+            }
             tw->quitnow = TRUE;
             PostQuitMessage(0);
             break;
diff --git a/psi/dwtext.h b/psi/dwtext.h
index 46b8e23..4a02d5c 100644
--- a/psi/dwtext.h
+++ b/psi/dwtext.h
@@ -72,6 +72,8 @@ typedef struct TEXTWINDOW_S {
 
     int x, y, cx, cy;	/* window position */
     int utf8shift;
+    TCHAR** szFiles;
+    int cFiles;
 } TW;
 
 /* Create new TW structure */

----------------------------------------------------------------------
commit 84152fe70bbe7261a0cebe49ff5bb5e6b6eb8a5a
Author: Robin Watts <[email protected]>
Date:   Fri Aug 16 15:43:32 2019 +0100

    Squash warnings in claptrap.
    
    Thanks to William Bader for highlighting these.

diff --git a/base/claptrap-planar.c b/base/claptrap-planar.c
index 84a486c..4686365 100644
--- a/base/claptrap-planar.c
+++ b/base/claptrap-planar.c
@@ -43,7 +43,7 @@ inline static void process_at_pixel(ClapTrap      * gs_restrict ct,
     /* Use local vars to avoid pointer aliasing */
     int            width        = ct->width;
     int            height       = ct->height;
-    int            num_comps    = ct->num_comps;
+    int            num_comp_lim = ct->num_comps;
     int            max_x_offset = ct->max_x_offset;
     int            max_y_offset = ct->max_y_offset;
     int            span         = ct->span;
@@ -60,7 +60,7 @@ inline static void process_at_pixel(ClapTrap      * gs_restrict ct,
     unsigned char *ppc;
 
     assert((first_comp != 1) ^ (prev_comp == -1));
-    assert((last_comp != 1) ^ (comp == ct->comp_order[num_comps-1]));
+    assert((last_comp != 1) ^ (comp == ct->comp_order[num_comp_lim]));
 
     /* Work out the search region bounds */
     sy = y - max_y_offset;
@@ -150,6 +150,7 @@ int ClapTrap_GetLinePlanar(ClapTrap       * gs_restrict ct,
     int x;
     int line_offset;
     unsigned char *process;
+    int num_comp_lim = ct->num_comps;
 
     /* Read in as many lines as we need */
     max_y = ct->y + ct->max_y_offset;
@@ -192,7 +193,7 @@ int ClapTrap_GetLinePlanar(ClapTrap       * gs_restrict ct,
         {
             process_at_pixel(ct, buffer[comp], x, 1, 1, 1, 0, -1, comp, line_offset, p++);
         }
-        for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
+        for (comp_idx = 1; comp_idx < num_comp_lim; comp_idx++)
         {
             prev_comp = comp;
             p = process;
@@ -243,7 +244,7 @@ int ClapTrap_GetLinePlanar(ClapTrap       * gs_restrict ct,
         {
             process_at_pixel(ct, buffer[comp], x, 1, 0, 1, 0, -1, comp, line_offset, p++);
         }
-        for (comp_idx = 1; comp_idx < ct->num_comps-1; comp_idx++)
+        for (comp_idx = 1; comp_idx < num_comp_lim; comp_idx++)
         {
             prev_comp = comp;
             p = process;

----------------------------------------------------------------------
commit 4ed0979561161b1a6d1454539061165a862a84ab
Author: Robin Watts <[email protected]>
Date:   Fri Aug 16 15:28:49 2019 +0100

    Squash warning in gdevpsd.c
    
    Thanks to William Bader for spotting this.

diff --git a/devices/gdevpsd.c b/devices/gdevpsd.c
index 9212ff9..b1e014b 100644
--- a/devices/gdevpsd.c
+++ b/devices/gdevpsd.c
@@ -1300,12 +1300,13 @@ psd_write_image_data(psd_write_ctx *xc, gx_device_printer *pdev)
                 goto cleanup;
             }
         }
-        if (j < xc->height-1)
+        if (j < xc->height-1) {
             code = gp_fseek(xc->f, -((gs_offset_t)num_comp * xc->height - 1) * octets_per_line, SEEK_CUR);
             if (code < 0) {
                 code = gs_note_error(gs_error_ioerror);
                 goto cleanup;
             }
+	}
     }
 
 cleanup:

----------------------------------------------------------------------
commit 1f82ea70dfa18dcd236d60fe69c3108257b40919
Author: Robin Watts <[email protected]>
Date:   Fri Aug 16 13:08:14 2019 +0100

    Squash some compiler warnings.

diff --git a/base/gslibctx.c b/base/gslibctx.c
index 5cf141c..64258e1 100644
--- a/base/gslibctx.c
+++ b/base/gslibctx.c
@@ -900,7 +900,7 @@ gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *arg)
             if (arg[2] == 0)
                 break;
             p = arg+2;
-            while (p == 32)
+            while (*p == 32)
                 p++;
             elide = 1;
             break;
@@ -1044,7 +1044,7 @@ gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *arg)
     return 0;
 }
 
-int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char ***argv)
+int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv)
 {
     gs_lib_ctx_core_t *core;
 
diff --git a/base/gslibctx.h b/base/gslibctx.h
index f35f85e..1425014 100644
--- a/base/gslibctx.h
+++ b/base/gslibctx.h
@@ -272,6 +272,6 @@ gs_lib_ctx_stash_sanitized_arg(gs_lib_ctx_t *ctx, const char *argv);
 int
 gs_lib_ctx_stash_exe(gs_lib_ctx_t *ctx, const char *argv);
 
-int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char ***argv);
+int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv);
 
 #endif /* GSLIBCTX_H */
diff --git a/devices/gdevpdfimg.c b/devices/gdevpdfimg.c
index 1007853..31b42fb 100644
--- a/devices/gdevpdfimg.c
+++ b/devices/gdevpdfimg.c
@@ -189,10 +189,11 @@ const gx_device_pdf_image gs_pdfimage32_device = {
 static int
 pdfimage_write_args_comment(gx_device_pdf_image *pdev, stream *s)
 {
-    char **argv = NULL, *arg;
+    const char * const *argv = NULL;
+    const char *arg;
     int towrite, length, i, j, argc;
 
-    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, (const char ***)&argv);
+    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, &argv);
 
     stream_write(s, (byte *)"%%Invocation:", 13);
     length = 12;
diff --git a/devices/vector/gdevpdfu.c b/devices/vector/gdevpdfu.c
index 74f8dc3..0b2b640 100644
--- a/devices/vector/gdevpdfu.c
+++ b/devices/vector/gdevpdfu.c
@@ -402,10 +402,11 @@ encode(stream **s, const stream_template *t, gs_memory_t *mem)
 int
 pdfwrite_fwrite_args_comment(gx_device_pdf *pdev, gp_file *f)
 {
-    char **argv = NULL, *arg;
+    const char * const *argv = NULL;
+    const char *arg;
     int towrite, length, i, j, argc;
 
-    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, (const char ***)&argv);
+    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, &argv);
 
     gp_fwrite("%%Invocation:", 13, 1, f);
     length = 12;
@@ -450,10 +451,11 @@ pdfwrite_fwrite_args_comment(gx_device_pdf *pdev, gp_file *f)
 int
 pdfwrite_write_args_comment(gx_device_pdf *pdev, stream *s)
 {
-    char **argv = NULL, *arg;
+    const char * const *argv = NULL;
+    const char *arg;
     int towrite, length, i, j, argc;
 
-    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, (const char ***)&argv);
+    argc = gs_lib_ctx_get_args(pdev->memory->gs_lib_ctx, &argv);
 
     stream_write(s, (byte *)"%%Invocation:", 13);
     length = 12;
diff --git a/pcl/pl/plmain.c b/pcl/pl/plmain.c
index e7152a3..73f45fe 100644
--- a/pcl/pl/plmain.c
+++ b/pcl/pl/plmain.c
@@ -180,7 +180,6 @@ pl_main_init_with_args(pl_main_instance_t *inst, int argc, char *argv[])
 {
     gs_memory_t *mem = inst->memory;
     pl_interp_implementation_t *pjli;
-    int code;
 
     gp_init();
     /* debug flags we reset this out of gs_lib_init0 which sets these

----------------------------------------------------------------------
commit 3bf47403e4cb305222834dca4ab49ce892b838f2
Author: Chris Liddell <[email protected]>
Date:   Fri Aug 16 11:45:01 2019 +0100

    Fix X11 device ICC profile memory leaks
    
    When the x11 devices are running in "buffered mode" (i.e. we render to a
    pixmap, then blit the pixmap to the X11 Window), we create a memory device
    which actually does the rendering.
    
    The memory device takes a reference to the ICC profiles from the x11 device
    and it is reference counted.
    
    Firstly, we always incremented the reference count, ignoring the posibility
    that we were resizing an existing memory device rather than creating a new one.
    
    Secondly, when shutting down the x11 device, we ignored posibility that
    buffering was in force, and failed to free the memory device - most of the
    memory was hoovered up by the garbager, but the ICC profile data isn't in
    gc memory, hence showing a leak.
    
    So, fix the memory device ICC reference counting, and reconfigure the device
    as non-buffering before we shut it down.

diff --git a/devices/gdevxini.c b/devices/gdevxini.c
index 98c743a..3b46b18 100644
--- a/devices/gdevxini.c
+++ b/devices/gdevxini.c
@@ -634,6 +634,7 @@ x_set_buffer(gx_device_X * xdev)
             xdev->buffer = buffer;
             mdev->width = xdev->width;
             mdev->height = xdev->height;
+            rc_decrement(mdev->icc_struct, "x_set_buffer");
             mdev->icc_struct = xdev->icc_struct;
             rc_increment(xdev->icc_struct);
             mdev->color_info = xdev->orig_color_info;
@@ -939,6 +940,8 @@ gdev_x_put_params(gx_device * dev, gs_param_list * plist)
 int
 gdev_x_close(gx_device_X *xdev)
 {
+    long MaxBitmap = xdev->space_params.MaxBitmap;
+
     if (xdev->ghostview)
         gdev_x_send_event(xdev, xdev->DONE);
     if (xdev->vinfo) {
@@ -952,5 +955,10 @@ gdev_x_close(gx_device_X *xdev)
         XFreeGC(xdev->dpy, xdev->gc);
 
     XCloseDisplay(xdev->dpy);
+    /* MaxBitmap == 0 ensures x_set_buffer() configures as non-buffering */
+    xdev->space_params.MaxBitmap = 0;
+    x_set_buffer(xdev);
+    xdev->space_params.MaxBitmap = MaxBitmap;
+
     return 0;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.