[gs-cvs] rev 8329 - in trunk/gs: lib src

alexcher at ghostscript.com alexcher at ghostscript.com
Sun Oct 28 10:17:48 PDT 2007


Author: alexcher
Date: 2007-10-28 10:17:47 -0700 (Sun, 28 Oct 2007)
New Revision: 8329

Modified:
   trunk/gs/lib/pdf_base.ps
   trunk/gs/lib/pdf_sec.ps
   trunk/gs/src/itoken.h
   trunk/gs/src/ztoken.c
   trunk/gs/src/zusparam.c
Log:
Change pdf_base.ps::.pdfrun and pdf_sec.ps::.decpdfrun to ensure
"PDFScanRules" == "true" while scanning the PDF, and if necessary revert
it back to "null" before returning. Thanks to SaGS for the patch. Bug 688598.

DETAILS:
The bug is triggered by the construct "//DeviceGray" found in  the sample PDF.
The following command fails with the same error as GSView, and for the
same reason:

    pdfopt.bat media_365163.pdf output.pdf

When Ghostscript interprets a PDF directly, most of the job is done by
LIB\pdf_main.ps::dopdfpages which sets "PDFScanRules" correctly. However,
the initial part of scanning the PDF (trailer dict, ...), and the rebuild
logic scan the PDF with wrong "PDFScanRules". Also GS's own various tools
and GSView don't set/ reset it as needed.

Implementation details:

(A) ".pdfrun" and ".decpdfrun" dinamically construct procedures that do the
real work and immediately execute them. The patch changes  these procedures
to include setting/ restoring "PDFScanRules". If "PDFScanRules" == "true"
already, then "setuserparams" is not called at all, so normally
(when ".[dec]pdfrun" executed during "dopdfpages") there's practically no
impact on performance.

There are also "token" calls outside these 2 procedures, but these calls are
for scanning the xref and "# # obj" lines, which don't contain PDF name
objects.

(B) ".getuserparam" GS-specific operator changed to recognize scanner options
too ("PDFScanRules" and "PDFScanInvNum"). This is needed by ".[dec]pdfrun"
for restoring "PDFScanRules"; also used for an optimization (to omit calling
"setuserparams" when not actually needed).

Note:
    For "Process[DSC]Comment" it returns "true" if a procedure 
    is set, and not the actual procedure. To retrive the 
    procedures (or null if none set), use "currentuserparams". 

(C) ".currentuserparams" is NOT modified, so it does not return scanner
options. If it did, these ended up being put into "userparams" and be
affected by "save"/ "restore" (see the  redefinition of "restore" in
gs_lev2.ps).

DIFFERENCES:
None.


Modified: trunk/gs/lib/pdf_base.ps
===================================================================
--- trunk/gs/lib/pdf_base.ps	2007-10-28 14:40:48 UTC (rev 8328)
+++ trunk/gs/lib/pdf_base.ps	2007-10-28 17:17:47 UTC (rev 8329)
@@ -177,10 +177,18 @@
     } ifelse
   } ifelse
 } bind def
+/PDFScanRules_true << /PDFScanRules true >> def
+/PDFScanRules_null << /PDFScanRules null >> def
 /.pdfrun {			% <file> <opdict> .pdfrun -
 	% Construct a procedure with the stack depth, file and opdict
 	% bound into it.
-  1 index cvlit count 2 sub 3 1 roll mark mark 5 2 roll
+  1 index cvlit count 2 sub 3 1 roll mark
+  /PDFScanRules .getuserparam //null eq {
+    //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
+    mark 7 4 roll
+  } {
+    mark 5 2 roll
+  } ifelse
   {	% Stack: ..operands.. count opdict file
     { token } stopped {
       dup type /filetype eq { pop } if % pop the operand if it is restored
@@ -211,12 +219,17 @@
     } ifelse
   }
   aload pop .packtomark cvx
-  /loop cvx 2 packedarray cvx
-  { stopped /PDFsource } aload pop
-  PDFsource
+  { loop } 0 get 2 packedarray cvx
+  { stopped } 0 get
+  /PDFScanRules .getuserparam //null eq {
+    //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
+  } if
+  /PDFsource PDFsource
   { store { stop } if } aload pop .packtomark cvx
   /PDFsource 3 -1 roll store exec
 } bind def
+currentdict /PDFScanRules_true undef
+currentdict /PDFScanRules_null undef
 
 % Execute a file, like .pdfrun, for a marking context.
 % This temporarily rebinds LocalResources and DefaultQstate.

Modified: trunk/gs/lib/pdf_sec.ps
===================================================================
--- trunk/gs/lib/pdf_sec.ps	2007-10-28 14:40:48 UTC (rev 8328)
+++ trunk/gs/lib/pdf_sec.ps	2007-10-28 17:17:47 UTC (rev 8329)
@@ -313,9 +313,17 @@
 } bind def
 
 % As .pdfrun, but decrypt strings with key <key>.
+/PDFScanRules_true << /PDFScanRules true >> def
+/PDFScanRules_null << /PDFScanRules null >> def
 /.decpdfrun			% <file> <keystring> <opdict> .decpdfrun -
  {	% Construct a procedure with the file, opdict and key bound into it.
-   2 index cvlit mark mark 5 2 roll
+   2 index cvlit mark
+   /PDFScanRules .getuserparam //null eq {
+     //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
+     mark 7 4 roll
+   } {
+     mark 5 2 roll
+   } ifelse
     { .pdftoken not { (%%EOF) cvn cvx } if
       dup xcheck
        { PDFDEBUG { dup == flush } if
@@ -374,12 +382,17 @@
       ifelse
     }
    aload pop .packtomark cvx
-   /loop cvx 2 packedarray cvx
-    { stopped /PDFsource } aload pop
-   PDFsource
+   { loop } 0 get 2 packedarray cvx
+    { stopped } 0 get
+   /PDFScanRules .getuserparam //null eq {
+     //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
+   } if
+   /PDFsource PDFsource
     { store { stop } if } aload pop .packtomark cvx 
    /PDFsource 3 -1 roll store exec
  } bind def
+currentdict /PDFScanRules_true undef
+currentdict /PDFScanRules_null undef
 
 % Run the code to resolve an object reference.
 /pdf_run_resolve

Modified: trunk/gs/src/itoken.h
===================================================================
--- trunk/gs/src/itoken.h	2007-10-28 14:40:48 UTC (rev 8328)
+++ trunk/gs/src/itoken.h	2007-10-28 17:17:47 UTC (rev 8329)
@@ -40,5 +40,10 @@
  * setuserparams.  (We might move this procedure somewhere else eventually.)
  */
 int ztoken_scanner_options(const ref *upref, int old_options);
+/*
+ * Get the value for a scanner option.
+ * return -1 if no such option, 1/0 for on/off and option's name in *pname as a C string
+ */
+int ztoken_get_scanner_option(const ref *psref, int options, const char **pname);
 
 #endif /* itoken_INCLUDED */

Modified: trunk/gs/src/ztoken.c
===================================================================
--- trunk/gs/src/ztoken.c	2007-10-28 14:40:48 UTC (rev 8328)
+++ trunk/gs/src/ztoken.c	2007-10-28 17:17:47 UTC (rev 8329)
@@ -312,6 +312,18 @@
     return o_push_estack;
 }
 
+typedef struct named_scanner_option_s {
+    const char *pname;
+    int option;
+} named_scanner_option_t;
+static const named_scanner_option_t named_options[] = {
+    {"PDFScanRules", SCAN_PDF_RULES},
+    {"ProcessComment", SCAN_PROCESS_COMMENTS},
+    {"ProcessDSCComment", SCAN_PROCESS_DSC_COMMENTS},
+    {"PDFScanInvNum", SCAN_PDF_INV_NUM},
+    {"PDFScanUnsigned", SCAN_PDF_UNSIGNED}
+};
+
 /*
  * Update the cached scanner_options in the context state after doing a
  * setuserparams.  (We might move this procedure somewhere else eventually.)
@@ -319,17 +331,6 @@
 int
 ztoken_scanner_options(const ref *upref, int old_options)
 {
-    typedef struct named_scanner_option_s {
-	const char *pname;
-	int option;
-    } named_scanner_option_t;
-    static const named_scanner_option_t named_options[] = {
-	{"ProcessComment", SCAN_PROCESS_COMMENTS},
-	{"ProcessDSCComment", SCAN_PROCESS_DSC_COMMENTS},
-	{"PDFScanRules", SCAN_PDF_RULES},
-	{"PDFScanInvNum", SCAN_PDF_INV_NUM},
-	{"PDFScanUnsigned", SCAN_PDF_UNSIGNED}
-    };
     int options = old_options;
     int i;
 
@@ -348,7 +349,25 @@
     }
     return options;
 }
+/*
+ * Get the value for a scanner option.
+ * return -1 if no such option, 1/0 for on/off and option's name in *pname as a C string
+ */
+int
+ztoken_get_scanner_option(const ref *psref, int options, const char **pname)
+{
+    const named_scanner_option_t *pnso;
 
+    for (pnso = named_options + countof(named_options); pnso-- != named_options;) {
+	if (!bytes_compare((const byte *)pnso->pname, strlen(pnso->pname),
+			psref->value.const_bytes, r_size(psref))) {
+	    *pname = pnso->pname;
+	    return (options & pnso->option ? 1 : 0);
+	}
+    }
+    return -1;
+}
+
 /* ------ Initialization procedure ------ */
 
 const op_def ztoken_op_defs[] =

Modified: trunk/gs/src/zusparam.c
===================================================================
--- trunk/gs/src/zusparam.c	2007-10-28 14:40:48 UTC (rev 8328)
+++ trunk/gs/src/zusparam.c	2007-10-28 17:17:47 UTC (rev 8329)
@@ -684,6 +684,30 @@
 		return code;
 	}
     }
+    if (psref) {
+	/*
+	 * Scanner options can be read, but only individually by .getuserparam.
+	 * This avoids putting them into userparams, and being affected by save/restore.
+	 */
+	const char *pname;
+	bool val;
+	int code;
+
+	switch (ztoken_get_scanner_option(psref, i_ctx_p->scanner_options, &pname)) {
+	    case 0:
+		code = param_write_null(plist, pname);
+		break;
+	    case 1:
+		val = true;
+		code = param_write_bool(plist, pname, &val);
+		break;
+	    default:
+		code = 0;
+		break;
+	}
+	if (code < 0)
+	    return code;
+    }
 #if ENABLE_CUSTOM_COLOR_CALLBACK
     if (pset == &system_param_set) {
         /* The custom_color callback pointer */



More information about the gs-cvs mailing list