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

ken at ghostscript.com ken at ghostscript.com
Tue Oct 16 00:54:08 PDT 2007


Author: ken
Date: 2007-10-16 00:54:08 -0700 (Tue, 16 Oct 2007)
New Revision: 8296

Modified:
   trunk/gs/lib/opdfread.ps
   trunk/gs/src/gdevpsf1.c
Log:
ps2write: When encountering font names which contain unfortunate characters
such as white space, or delimiters, emit the name as an escaped string and 
'cvn' instead of a literal name.

DETAILS:
Bug #689420 "Errors with ps2write and special chars in FontName"

Patch from SaGS with some minor improvements.

Fonts whose name contains white space, or delimiter characters (eg /,(,[ etc)
were being written into the type 1 font stream using the name unchanged. This 
causes the resulting PostScript to fail on any PostScript interpreter. The 
exact error varies depending on the placement of the invalid character and 
the following data.

This is now handled by emitting the font name as a string, and using the cvn
operator to convert the string to a name, escaping characters if required. 
Note that both the C portion of the code needs to change, in order to write 
escaped names, and the PostScript prolog in order to undo any name escapement.

1. (gdevpsf1.c) write_font_name, check to see if the font name contains any
   characters which we need to escape. If so, then use the existing routine
   's_PSSE_template.process' to convert the name to an escaped character 
   sequence.

   Update the write_font_name routine so that it optionally writes a name
   to the output. If the name does not need escaping, then simply prepend a
   '/' to make a literal name, otherwise append a 'cvn' to convert the 
   escaped string to a name. When writing out the font header we just need
   the font name as a human readable string. When writing the /FontName
   entry in the font dictionary we need a PostScript name, either a literal
   or a PostScript escaped string converted to a name. (see below)

2. (gdevpsf1.c) psf_write_type1_font, alter the use of write_font_name in two
   places. Firstly to emit the name as part of the font comment, secondly to
   put the name as the value for the /FontName key in the fotn dictionary. In
   the first case we write it as a simple string, in the second as a name.

3. (opdfread.ps) The TypeDameons procedure extracts the FontName from the Font
   dictionary in the body of the job. Since the FontName can now be escaped,
   we need to undo the escapement before defining the font. Firstly we define
   a new procedure 'UnPDFEscape', secondly we call this when dealing with the
   FontName and the BaseFont keys, in order to convert the escaped name back
   to a normal name, so that the font can be found with findfont.

EXPECTED DIFFERENCES:
None

Modified: trunk/gs/lib/opdfread.ps
===================================================================
--- trunk/gs/lib/opdfread.ps	2007-10-16 00:36:28 UTC (rev 8295)
+++ trunk/gs/lib/opdfread.ps	2007-10-16 07:54:08 UTC (rev 8296)
@@ -925,6 +925,35 @@
   /Subtype get 1 index exch /FontFileType exch put
 } bind def
 
+/UnPDFEscape {	% <namepdf> UnPDFEscape <nameps>
+  dup dup length string cvs				    % /namepdf (name)
+  dup (#) search {
+    % name contains PDF-style escapes ("#hh") that need to be removed
+    {												% ... (po..st) (#) (pre)
+      pop											% ... (po..st) (#)
+      (16#--) 2 index 0 2 getinterval				% ... (po..st) (#) (16#--) (po)
+      1 index 3 2 getinterval copy pop				% ... (po..st) (#) (16#po)
+      cvi											% ... (po..st) (#) 16#po
+      0 exch put									% ... (po..st); 16#po patched into (#)
+      0												% ... (po..st) 0
+      1 index 2 1 index length 2 sub getinterval    % ... (po..st) 0 (..st)
+      3 copy putinterval							% ... (..stst) 0 (XXst)
+      length										% ... (..stst) 0 LEN_OF_(po..st)-2
+      3 copy exch put								% ... (..st\0t) 0 LEN_OF_(po..st)-2
+      getinterval									% ... (..st), stored at begining of old (po..st)
+      (#) search not {
+	pop exit				    % /namepdf (nameps\0..)
+      } if
+    } loop
+    % we have a '\0' marker (not allowed in PDF names) after all usefull characters
+    (\0) search pop exch pop exch pop
+    cvn
+    exch pop
+  } {
+    pop pop
+  } ifelse
+} bind def
+
 /TypeDaemons <<  % <id> <obj> proc <id> <obj>
   /Page 
   { //PDFR_DEBUG {
@@ -944,6 +973,9 @@
   { //PDFR_DEBUG {
       (Recognized a font descriptor.) =
     } if
+    dup /FontName //knownget exec {
+	1 index /FontName 3 -1 roll //UnPDFEscape exec put
+    } if
     {
       dup dup /FontFile known {/FontFile} {/FontFile2} ifelse 
       //knownget exec {                                 % id obj ff
@@ -963,6 +995,7 @@
       (Recognized a font resource.) =
     } if
     dup /BaseFont //knownget exec {
+      //UnPDFEscape exec 2 copy /BaseFont exch put
       % cache the installed font (if any) before replacing it.
       //PDFReader /RemoveFontNamePrefix get exec
       currentglobal exch % A hack against HP LaserJet 1320 bug :

Modified: trunk/gs/src/gdevpsf1.c
===================================================================
--- trunk/gs/src/gdevpsf1.c	2007-10-16 00:36:28 UTC (rev 8295)
+++ trunk/gs/src/gdevpsf1.c	2007-10-16 07:54:08 UTC (rev 8296)
@@ -88,12 +88,39 @@
 /* Write the font name. */
 static void
 write_font_name(stream *s, const gs_font_type1 *pfont,
-		const gs_const_string *alt_font_name)
+		const gs_const_string *alt_font_name, bool as_name)
 {
-    if (alt_font_name)
-	stream_write(s, alt_font_name->data, alt_font_name->size);
-    else
-	stream_write(s, pfont->font_name.chars, pfont->font_name.size);
+    const byte *c;
+    const byte *name = (alt_font_name ? alt_font_name->data : pfont->font_name.chars);
+    int         n    = (alt_font_name ? alt_font_name->size : pfont->font_name.size);
+
+    if (n == 0)
+	/* empty name, may need to write it as empty string */
+	stream_puts(s, (as_name ? "/" : "()"));
+    else {
+	for (c = (byte *)"()<>[]{}/% \n\r\t\b\f\004\033"; *c; c++)
+	    if (memchr(name, *c, n))
+		break;
+	if (*c || memchr(name, 0, n)) {
+	    /* name contains whitespace (NUL included) or a PostScript separator */
+	    byte pssebuf[1 + 4 * gs_font_name_max + 1]; /* "(" + "\ooo" * gs_font_name_max + ")" */
+	    stream_cursor_read  r;
+	    stream_cursor_write w;
+
+	    pssebuf[0] = '(';
+	    r.limit = (r.ptr = name - 1) + n;
+	    w.limit = (w.ptr = pssebuf) + sizeof pssebuf - 1;
+	    s_PSSE_template.process(NULL, &r, &w, true);
+	    stream_write(s, pssebuf, w.ptr - pssebuf + 1);
+	    if (as_name)
+		stream_puts(s, " cvn");
+	} else {
+	    /* name without any special characters */
+	    if (as_name)
+		stream_putc(s, '/');
+	    stream_write(s, name, n);
+	}
+    }
 }
 /*
  * Write the Encoding array.  This is a separate procedure only for
@@ -390,7 +417,7 @@
     /* Write the font header. */
 
     stream_puts(s, "%!FontType1-1.0: ");
-    write_font_name(s, pfont, alt_font_name);
+    write_font_name(s, pfont, alt_font_name, false);
     stream_puts(s, "\n11 dict begin\n");
 
     /* Write FontInfo. */
@@ -418,8 +445,8 @@
 
     /* Write the main font dictionary. */
 
-    stream_puts(s, "/FontName /");
-    write_font_name(s, pfont, alt_font_name);
+    stream_puts(s, "/FontName ");
+    write_font_name(s, pfont, alt_font_name, true);
     stream_puts(s, " def\n");
     code = write_Encoding(s, pfont, options, glyphs.subset_glyphs,
 			  glyphs.subset_size, glyphs.notdef);



More information about the gs-cvs mailing list