Fix for 687555, /rangecheck in --array-- when loading some (large) CMaps, 3rd version

Alex Cherepanov <[email protected]> Wed, 01 Sep 2004 01:12:48 -0400
Newsgroups gmane.comp.printing.ghostscript.patches
Organization Coscript Software
Message-ID <[email protected]>
[LOG MESSAGE]
Use extra level of nested arrays instead of concatenating CMap data
in a single array to accommodate CMap's with >= 64K elements.
Work around bugs in Adobe-CNS1-ETen-B5 and Adobe-Korea1-H-Mac files.
Fix bug 587555

[DETAILS]
Adobe-CNS1-ETen-B5 file defines Adobe-CNS1-ETenms-B5 resource which
caused /undefined resource error. For this file the patch changes
CMapName back to Adobe-CNS1-ETen-B5. A new CMap file
Adobe-CNS1-ETenms-B5 is added to the CMap collection.

/Adobe-Korea1-H-Mac failed with /undefined in endcmap because the file
has a duplicate trailer. The patch recognizes the offending file
and skips the duplicate code.

[COMMENTS]
Re Igor's suggestion to use the dictionary I can take a look into the
issue. Hoverer, the internal representation of the CMap doesn't need to
be similar to CMap resource. We can optimize the latter in C but leave
the former unchanged.

_______________________________________________
gs-code-review mailing list
[email protected]
http://www.ghostscript.com/mailman/listinfo/gs-code-review
687555c.diff (text/plain, 9.4 KB)
Index: gs/lib/gs_cmap.ps
===================================================================
RCS file: /cvs/ghostscript/gs/lib/gs_cmap.ps,v
retrieving revision 1.17
diff -b -u -r1.17 gs_cmap.ps
--- gs/lib/gs_cmap.ps	12 Apr 2003 18:08:18 -0000	1.17
+++ gs/lib/gs_cmap.ps	1 Sep 2004 04:36:42 -0000
@@ -22,7 +22,7 @@
 [
    /CMERGE_DEBUG
    /USE_CIDCHAR_AS_RANGE
-] {dup where {pop pop} { currentdict exch false def pop } ifelse} forall
+] {dup where {pop pop} { currentdict exch //false def pop } ifelse} forall
 
 % ---------------- Public operators ---------------- %
 
@@ -65,7 +65,7 @@
 	} ifelse findresource
       } if
       exch CMap /FontMatrices get dup length 2 index gt {
-	exch get dup null eq { pop } { makefont } ifelse
+	exch get dup //null eq { pop } { makefont } ifelse
       } {
 	pop pop
       } ifelse
@@ -85,9 +85,9 @@
 % Our internal .CodeMapData structure closely mirrors the structures
 % defined in gxfcmap.h (q.v.).  () indicate a string, [] indicate an array,
 % ? indicates a Boolean, # indicates an integer, {} for grouping.
-%	[[(first) (last) ...]		% code space ranges
-%	 [(prefix) (key_size,?is_range,value_type,value_size) (keys...)
-%	   {(values...) | [value ...]} #font_index	% code mappings
+%	[[[(first) (last) ...]+]		% code space ranges
+%	 [[(prefix) (key_size,?is_range,value_type,value_size) (keys...)
+%	   {(values...) | [value ...]} #font_index ]+]	% code mappings
 %	  ...]
 %	 <<same>>		% notdef mappings
 %	]
@@ -106,40 +106,68 @@
 % ------ Font-level operators ------ %
 
 /begincmap {		% - begincmap -
-  /.CodeMapData [[] [] []] def
+  /.CodeMapData [[[]] [[]] [[]]] def
   /FontMatrices [] def
   /.FontIndex 0 def
   /.TempMaps [20 dict 50 dict 50 dict] def
-  /CodeMap null def		% for .buildcmap
+  /CodeMap //null def		% for .buildcmap
 } bind def
+
 /endcmap {		% - endcmap -
   .rewriteTempMapsNotDef
+
+  CMAPDEBUG {
+    2 (*** undefined charmap ***)
+    1 (*** defined charmap ***)
+    0 (*** code space ranges ***)
+    3 { =
+      .TempMaps exch get
+      0 1 2 index length 1 sub {
+        dup == (\t) print
+        1 index exch get ==
+      } for
+      pop
+    } repeat
+  } if
+  
+  /.CodeMapData dup load [ exch
+    .TempMaps aload pop begin begin begin 
+    {
+      [ exch aload pop
+        0 1 currentdict length 1 sub { 
+           currentdict exch get 
+        } for 
+      ]
+      end
+    } forall
+  ] .endmap def
+
   CMAPDEBUG {
-    (*** defined charmap ***\n) print
-    .TempMaps 1 get {exch == (\t) print ==} forall
-    (*** undefined charmap ***\n) print
-    .TempMaps 2 get {exch == (\t) print ==} forall
-  } if
-  10 dict begin 0 1 2 {
-    /i exch def
-		% Append data from .TempMaps to .CodeMapData.
-    /t .TempMaps i get def
-    .CodeMapData i get length t { exch pop length add } forall
-    CMAPDEBUG { (requested array size ) print dup == } if
-    array /a exch def
-    a 0 .CodeMapData i get .putmore
-    0 1 t length 1 sub {
-      t exch get .putmore
-    } for pop pop
-    .CodeMapData i a put
-  } for end
+    (*** Content of .CodeMapData ***) =
+    0 .CodeMapData { exch dup == 1 add exch (\t) print == } forall
+    pop
+  } if
+
   currentdict /.TempMaps undef
-  /.CodeMapData .CodeMapData .endmap def
   /FontMatrices FontMatrices .endmap def
-} bind def
 
-/.putmore {		% <array> <i> <array2> .putmore <array> <i+len(array2)>
-  3 copy putinterval length add
+  % Fix Adobe-CNS1-ETen-B5 file that defines Adobe-CNS1-ETenms-B5 CMap
+  currentdict /CMapName .knownget {
+    /Adobe-CNS1-ETenms-B5 eq {
+      currentdict /XUID .knownget {
+        dup length 4 eq {
+          1212 25335 10 1 //true
+          6 -1 roll { 3 -1 roll eq and } forall {
+            /CMapName /Adobe-CNS1-ETen-B5 def
+          } if
+        } {
+          pop
+        } ifelse
+      } if
+    } if
+  } if
+
+
 } bind def
 
 /.endmap {		% <map> .endmap <map>
@@ -164,6 +192,7 @@
 /begincodespacerange {	% <count> begincodespacerange -
   pop mark
 } bind def
+
 /endcodespacerange {	% <code_lo> <code_hi> ... endcodespacerange -
   0 .appendmap
 } bind def
@@ -186,6 +215,7 @@
     /FontMatrices exch def
   } if
 } bind def
+
 /endusematrix {		% <matrix> endusematrix -
   FontMatrices 3 1 roll put
 } bind def
@@ -504,18 +534,28 @@
       dup length dict .copydict exch .setglobal
     } if
     dup gcheck 2 index gcheck not and {
-      exch .currentglobal exch true .setglobal
+      exch .currentglobal exch //true .setglobal
       dup length string copy exch .setglobal exch
     } if dup /CMapName 3 index put
   } if
-  dup /CodeMap get null eq { .buildcmap } if
+  dup /CodeMap get //null eq { .buildcmap } if
   /Generic /Category findresource /DefineResource get exec
-} put
+
+  % Skip duplicate trailer in /Adobe-Korea1-H-Mac
+  dup /CMapName get /Adobe-Korea1-H-Mac eq {
+    currentfile 128 string .peekstring pop
+    (CMapName currentdict /CMap defineresource) search {
+      2 { currentfile exch readstring pop pop } repeat
+    } if
+    pop
+  } if
+
+} bind put
 /Category defineresource pop
 	% We might have loaded CID font support already.
 /CIDInit /ProcSet 2 copy { findresource } .internalstopped
 	% An interior `stopped' might have reset VM allocation to local.
-true .setglobal
+//true .setglobal
  { pop pop 3 -1 roll }
  { dup length 4 index length add dict .copydict 4 -1 roll exch .copydict }
 ifelse exch defineresource pop
Index: gs/src/zfcmap.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/zfcmap.c,v
retrieving revision 1.15
diff -b -u -r1.15 zfcmap.c
--- gs/src/zfcmap.c	4 Aug 2004 19:36:13 -0000	1.15
+++ gs/src/zfcmap.c	1 Sep 2004 04:36:42 -0000
@@ -14,7 +14,7 @@
   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
 */
 
-/* $Id: zfcmap.c,v 1.15 2004/08/04 19:36:13 stefan Exp $ */
+/* $Id: zfcmap.c,v 1.14 2003/04/10 11:58:25 igor Exp $ */
 /* CMap creation operator */
 #include "memory_.h"
 #include "ghost.h"
@@ -63,14 +63,26 @@
 private int
 acquire_code_ranges(gs_cmap_adobe1_t *cmap, const ref *pref, gs_memory_t *mem)
 {
-    uint num_ranges;
+    uint num_ranges = 0;
     gx_code_space_range_t *ranges;
-    uint i;
+    uint i, j, elem_sz;
+    ref elem;
 
-    if (!r_is_array(pref) || (num_ranges = r_size(pref)) == 0 ||
-	num_ranges & 1)
+    if (!r_is_array(pref))
+	return_error(e_rangecheck);
+    for (i=0; i < r_size(pref); i++) {
+        int code = array_get(mem, pref, i, &elem);
+        if (code < 0)
+            return code;
+        elem_sz = r_size(&elem);
+        if (elem_sz & 1)
+	    return_error(e_rangecheck);
+        num_ranges += elem_sz;
+    }
+    if (num_ranges == 0)
 	return_error(e_rangecheck);
     num_ranges >>= 1;
+
     ranges = (gx_code_space_range_t *)
 	gs_alloc_byte_array(mem, num_ranges, sizeof(gx_code_space_range_t),
 			    "acquire_code_ranges");
@@ -78,12 +90,16 @@
 	return_error(e_VMerror);
     cmap->code_space.ranges = ranges;
     cmap->code_space.num_ranges = num_ranges;
-    for (i = 0; i < num_ranges; ++i, ++ranges) {
+
+    for (i = 0; i < r_size(pref); i++) {
+        array_get(mem, pref, i, &elem);
+        elem_sz = r_size(&elem);
+        for (j = 0; j < elem_sz; j += 2) {
 	ref rfirst, rlast;
 	int size;
 
-	array_get(mem, pref, i * 2L, &rfirst);
-	array_get(mem, pref, i * 2L + 1, &rlast);
+	    array_get(mem, &elem, j, &rfirst);
+	    array_get(mem, &elem, j + 1, &rlast);
 	if (!r_has_type(&rfirst, t_string) ||
 	    !r_has_type(&rlast, t_string) ||
 	    (size = r_size(&rfirst)) == 0 || size > MAX_CMAP_CODE_SIZE ||
@@ -93,6 +109,8 @@
 	memcpy(ranges->first, rfirst.value.bytes, size);
 	memcpy(ranges->last, rlast.value.bytes, size);
 	ranges->size = size;
+            ++ranges;
+        }
     }
     return 0;
 }
@@ -102,12 +120,23 @@
 acquire_code_map(gx_code_map_t *pcmap, const ref *pref, gs_cmap_adobe1_t *root,
 		 gs_memory_t *mem)
 {
-    uint num_lookup;
+    uint num_lookup = 0;
     gx_cmap_lookup_range_t *pclr;
     long i;
+    ref elem;
+    uint elem_sz;
 
-    if (!r_is_array(pref) || (num_lookup = r_size(pref)) % 5 != 0)
+    if (!r_is_array(pref))
+	return_error(e_rangecheck);
+    for (i=0; i < r_size(pref); i++) {
+        int code = array_get(mem, pref, i, &elem);
+        if (code < 0)
+            return code;
+        elem_sz = r_size(&elem);
+        if (elem_sz % 5 != 0)
 	return_error(e_rangecheck);
+        num_lookup += elem_sz;
+    }
     num_lookup /= 5;
     pclr = gs_alloc_struct_array(mem, num_lookup, gx_cmap_lookup_range_t,
 				 &st_cmap_lookup_range_element,
@@ -117,14 +146,20 @@
     memset(pclr, 0, sizeof(*pclr) * num_lookup);
     pcmap->lookup = pclr;
     pcmap->num_lookup = num_lookup;
-    for (i = 0; i < num_lookup * 5; i += 5, ++pclr) {
+    
+   
+    for (i = 0; i < r_size(pref); i++) {
+        uint j;
+        array_get(mem, pref, i, &elem);
+        elem_sz = r_size(&elem);
+        for (j = 0; j < elem_sz; j += 5) {
 	ref rprefix, rmisc, rkeys, rvalues, rfxs;
 
-	array_get(mem, pref, i, &rprefix);
-	array_get(mem, pref, i + 1, &rmisc);
-	array_get(mem, pref, i + 2, &rkeys);
-	array_get(mem, pref, i + 3, &rvalues);
-	array_get(mem, pref, i + 4, &rfxs);
+	    array_get(mem, &elem, j, &rprefix);
+	    array_get(mem, &elem, j + 1, &rmisc);
+	    array_get(mem, &elem, j + 2, &rkeys);
+	    array_get(mem, &elem, j + 3, &rvalues);
+	    array_get(mem, &elem, j + 4, &rfxs);
 
 	if (!r_has_type(&rprefix, t_string) ||
 	    !r_has_type(&rmisc, t_string) ||
@@ -206,6 +241,8 @@
 	}
 	check_int_leu_only(rfxs, 0xff);
 	pclr->font_index = (int)rfxs.value.intval;
+            ++pclr;
+        }
     }
     return 0;
 }
Adobe-CNS1-ETenms-B5 (application/postscript, 1.1 KB) - not displayed