Fix: Bug 687560 "Invalid PDF if /BP pdfmarks with non-unique /_objdef"

"SaGS" <[email protected]> Mon, 30 Aug 2004 00:22:23 +0300
Newsgroups gmane.comp.printing.ghostscript.patches
Message-ID <[email protected]>
Hi all,
Attached is a proposed fix for bug 687560. I added rather extensive comments
to the bug report; for details on this patch, please see
http://bugs.ghostscript.com/show_bug.cgi?id=687560, especially comment #6.

_______________________________________________
gs-code-review mailing list
[email protected]
http://www.ghostscript.com/mailman/listinfo/gs-code-review
Bug687560.diff (application/octet-stream, 22.8 KB)
Index: src/gdevpdfi.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfi.c,v
retrieving revision 1.56
diff -u -r1.56 gdevpdfi.c
--- src/gdevpdfi.c	4 Aug 2004 19:36:12 -0000	1.56
+++ src/gdevpdfi.c	29 Aug 2004 20:53:56 -0000
@@ -893,7 +893,7 @@
 	    return 1;
 	case pattern_manage__start_accum:
 	    code = pdf_enter_substream(pdev, resourcePattern, id, &pres, true, 
-		    pdev->CompressFonts/* Have no better switch.*/);
+		    pdev->CompressFonts/* Have no better switch.*/, NULL);
 	    if (code < 0)
 		return code;
 	    pres->rid = id;
Index: src/gdevpdfm.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfm.c,v
retrieving revision 1.45
diff -u -r1.45 gdevpdfm.c
--- src/gdevpdfm.c	15 Jul 2004 16:39:08 -0000	1.45
+++ src/gdevpdfm.c	29 Aug 2004 20:54:04 -0000
@@ -1040,6 +1040,31 @@
     return size + 1;
 }
 
+/* Create a unique distill-time objname for driver's internal use */
+private int
+pdf_unique_objname (char *objname)
+{
+    static long n_objname = 0; /* (no need to be context-specific) */
+    /* Notes:
+     * - Names generated by different pdf_unique_objname() calls are different because
+     *   n_objname is incremented with each call.
+     * - All names generated by pdf_unique_objname() are different from all names coming
+     *   from PostScript code because they are not enclosed in "{}".
+     */
+    return sprintf (objname,"?%ld",n_objname++);
+}
+
+/* Contants that define various methods to deal with duplicate distill-time names */
+#define PDF_NAMECOLLISION_NONAME   0x0001 /* not a named object (so no collision possible)  */
+#define PDF_NAMECOLLISION_NONE     0x0002 /* no name collision				    */
+#define PDF_NAMECOLLISION_ERRCODE  0x0004 /* error, "return code"			    */
+#define PDF_NAMECOLLISION_ERRTYPE  0x0008 /* "return_error(gs_error_typecheck)"		    */
+#define PDF_NAMECOLLISION_ERRRANGE 0x0010 /* "return_error(gs_error_rangecheck)"	    */
+#define PDF_NAMECOLLISION_REBUILD  0x0020 /* "rebuid" the same object, discard old copy	    */
+#define PDF_NAMECOLLISION_KEEPOLD  0x0040 /* keep old copy, discard new one		    */
+#define PDF_NAMECOLLISION_BACKUP   0x0080 /* "backup" previous copy, then create a new obj  */
+#define PDF_NAMECOLLISION_FWDOBJ   0x0100 /* false collision due to a forward reference	    */
+
 /* Start a XObject. */
 private int
 start_XObject(gx_device_pdf * pdev, bool compress, cos_stream_t **ppcs,
@@ -1048,27 +1073,175 @@
     cos_stream_t *pcs;
     cos_value_t value;
     int code;
+    int oper; /* one or more of the PDF_NAMECOLLISION_* values */
+    cos_object_t *pcoprev;
 
     code = pdf_open_page(pdev, PDF_IN_STREAM);
     if (code < 0)
 	return code;
-    code = pdf_enter_substream(pdev, resourceXObject, gs_no_id, &pres, true, 
-		pdev->CompressFonts /* Have no better switch*/);
-    if (code < 0)
-	return code;
-    pcs = (cos_stream_t *)pres->object;
-    pdev->substream_Resources = cos_dict_alloc(pdev, "start_XObject");
-    if (!pdev->substream_Resources)
-	return_error(gs_error_VMerror);
-    code = cos_dict_put(pdev->local_named_objects, objname->data,
-			    objname->size, cos_object_value(&value, pres->object));
-    if (code < 0)
-	return code;
-    pres->named = true;
-    pres->where_used = 0;	/* initially not used */
-    pcs->pres = pres;
-    *ppcs = pcs;
-    return 0;
+
+    oper = 0;
+    if (objname) {
+	/* check for duplicate name and see which methods are suitable for resolving the conflict */
+	switch (code = pdf_find_named(pdev, objname, &pcoprev)) {
+	    case gs_error_undefined:	/* new name */
+		oper = PDF_NAMECOLLISION_NONE;
+		break;
+	    case 0:				/* duplicate name */
+		if (cos_type(pcoprev) == cos_type_generic)
+		    /* (assumes named generic objects in pdev->local_named_objects are 
+			created only as a result of finding forward references) */
+		    oper = PDF_NAMECOLLISION_FWDOBJ | PDF_NAMECOLLISION_REBUILD;
+		else if (cos_type(pcoprev) != cos_type_stream)
+		    /* do not accept changing the type of an object */
+		    oper = PDF_NAMECOLLISION_ERRTYPE;
+		else if (pcoprev->is_graphics && pcoprev->is_open)
+		    /* do not accept redefining a Form XObject while it is being built */
+		    oper = PDF_NAMECOLLISION_ERRRANGE;
+		else
+		    oper = PDF_NAMECOLLISION_KEEPOLD | PDF_NAMECOLLISION_REBUILD | PDF_NAMECOLLISION_BACKUP;
+		break;
+	    default:			/* misc errors */
+		oper = PDF_NAMECOLLISION_ERRCODE;
+		break;
+	}
+    } else
+	oper = PDF_NAMECOLLISION_NONAME;
+    /* cannot rebuild an object that is already written */
+    if ((oper &PDF_NAMECOLLISION_REBUILD) && pcoprev->written)
+	oper &= ~PDF_NAMECOLLISION_REBUILD;
+    /* favor PDF_NAMECOLLISION_FWDOBJ over PDF_NAMECOLLISION_REBUILD */
+    if (oper &PDF_NAMECOLLISION_FWDOBJ)
+	oper &= ~PDF_NAMECOLLISION_REBUILD;
+    /* favor PDF_NAMECOLLISION_REBUILD over PDF_NAMECOLLISION_KEEPOLD over PDF_NAMECOLLISION_BACKUP */
+    if (oper &PDF_NAMECOLLISION_REBUILD)
+	oper &= ~(PDF_NAMECOLLISION_BACKUP|PDF_NAMECOLLISION_KEEPOLD);
+    if (oper &PDF_NAMECOLLISION_BACKUP)
+	oper &= ~(PDF_NAMECOLLISION_KEEPOLD);
+    /* the various methods of resolving name conflicts */
+    switch (oper) {
+	case PDF_NAMECOLLISION_ERRCODE:
+	    return code;
+	case PDF_NAMECOLLISION_ERRTYPE:
+	    return_error(gs_error_typecheck);
+	case PDF_NAMECOLLISION_ERRRANGE:
+	    return_error(gs_error_rangecheck);
+	default:
+	    /* should never happen; if it does, the decision code above is incomplete */
+	    return_error(gs_error_unknownerror);
+	case PDF_NAMECOLLISION_REBUILD:	{
+	    pdf_resource_t *presprev = pcoprev->pres;
+	    long oldid = pcoprev->id;
+	    /* "rebuid" the same object, discarding the old copy
+	     * - create a new generic object, as if encountering a forward reference
+	     * - assign this object the same id as the old copy and reuse the resource
+	     * - the old object gets freed while the new one is inserted into
+	     *   pdev->local_named_objects by pdf_create_named()
+	     * - continue as if we have to create an object that was forward referenced
+	     */
+	    if (presprev)
+		presprev->object = NULL;   /* diconnect resource from old object... */
+	    pcoprev->pres = NULL;	    /* ... (prevent it to be freed) */
+	    code = pdf_create_named(pdev,objname,cos_type_generic,&pcoprev,oldid);
+	    if (code < 0)
+		return code;
+	    pcoprev->pres = presprev;
+	    pdf_obj_ref_reused(pdev,oldid);
+	    pcoprev->is_graphics = true;
+	    pcoprev->pres->named = true;
+	    }
+	    oper = PDF_NAMECOLLISION_FWDOBJ; /* continue as for a "forward" object...*/
+	case PDF_NAMECOLLISION_FWDOBJ:
+	    /* false collision due to a forward reference, resolved by "continuing" with
+	     * the old object from where pdf_replace_names() left off
+	     * - pass the old object to pdf_enter_substream() so it will "continue"
+	     *   with it instead of creating a new one
+	     * - do not add the object to pdev->local_named_objects, it's already there
+	     * - pcoprev->named/where_used already in place
+	     */
+	    code = pdf_enter_substream(pdev, resourceXObject, gs_no_id, &pres, true,
+			pdev->CompressFonts /* Have no better switch*/, pcoprev);
+	    if (code < 0)
+		return code;
+	    pcs = (cos_stream_t *)pres->object;
+	    pdev->substream_Resources = cos_dict_alloc(pdev, "start_XObject(FWDOBJ)");
+	    if (!pdev->substream_Resources)
+		return_error(gs_error_VMerror);
+	    if (code < 0)
+		return code;
+	    pcs->pres = pres;
+	    *ppcs = pcs;
+	    return 0;
+	case PDF_NAMECOLLISION_KEEPOLD:
+	    /* keep old copy, discard new one
+	     * - create a "temporary object" without an ID
+	     * - do not add the object to pdev->local_named_objects, because:
+	     *	    - adding it removes the old object
+	     *	    - it does not have an ID, so it must not be accessible by name since 
+	     *	      we cannot create references ("n 0 R") to it
+	     * - pdfmark_EP() will discard the object
+	     */
+	    code = pdf_enter_substream(pdev, resourceXObject, gs_no_id, &pres, false,
+			pdev->CompressFonts /* Have no better switch*/, NULL);
+	    if (code < 0)
+		return code;
+	    pcs = (cos_stream_t *)pres->object;
+	    pdev->substream_Resources = cos_dict_alloc(pdev, "start_XObject(KEEPOLD)");
+	    if (!pdev->substream_Resources)
+		return_error(gs_error_VMerror);
+	    pres->named = true;
+	    pres->where_used = 0;	/* initially not used */
+	    pcs->pres = pres;
+	    *ppcs = pcs;
+	    return 0;
+	case PDF_NAMECOLLISION_BACKUP:
+	    /* "backup" previous copy, then create a new object
+	     * (an object name is treated like a variable: pdfmarks that create objects
+	     * "assign" a (new) value to it, and each reference to the object takes
+	     * into account the most recent value (in execution order))
+	     * - replace the key in pdev->local_named_objects with a unique one
+	     * - continue as if no name conflict
+	     */
+	    {	char unique[1+10+1]; /* '?' + long + '\0' */
+	    code = cos_dict_rename(pdev->local_named_objects,
+				   objname->data,objname->size,
+				   (const byte *)unique,pdf_unique_objname(unique));
+	    if (code < 0)
+		return code;
+	    }
+	    oper = PDF_NAMECOLLISION_NONE; /* continue as for PDF_NAMECOLLISION_NONE... */
+	case PDF_NAMECOLLISION_NONAME:
+	   /* object does not have a name
+	    * - same as PDF_NAMECOLLISION_NONE, except the object is not registered
+	    *   in pdev->local_named_objects.
+	    */
+	case PDF_NAMECOLLISION_NONE:
+	   /* no name conflict
+	    * - create the object normally and initialize all its fields
+	    * - do assign the object an id
+	    * - register the object in pdev->local_named_objects
+	    */
+	    code = pdf_enter_substream(pdev, resourceXObject, gs_no_id, &pres, true,
+				       pdev->CompressFonts /* Have no better switch*/, NULL);
+	    if (code < 0)
+		return code;
+	    pcs = (cos_stream_t *)pres->object;
+	    pdev->substream_Resources = cos_dict_alloc(pdev, "start_XObject(NONAMECOLLISION)");
+	    if (!pdev->substream_Resources)
+		return_error(gs_error_VMerror);
+	    if (!(oper &PDF_NAMECOLLISION_NONAME))
+		code = cos_dict_put(pdev->local_named_objects, objname->data,
+				    objname->size, cos_object_value(&value, pres->object));
+	    else
+		DO_NOTHING;
+	    if (code < 0)
+		return code;
+	    pres->named = !(oper &PDF_NAMECOLLISION_NONAME);
+	    pres->where_used = 0;	/* initially not used */
+	    pcs->pres = pres;
+	    *ppcs = pcs;
+	    return 0;
+    }
 }
 
 /* PS pdfmark */
@@ -1108,7 +1281,7 @@
 	    code = pdf_enter_substream(pdev, 
 			resourceXObject /* A stub. Actually it's not a resource. */, 
 			gs_no_id, &pres, true, 
-			pdev->CompressFonts /* Have no better switch*/);
+			pdev->CompressFonts /* Have no better switch*/, NULL);
 	    if (code < 0)
 		return code;
 	    pcs = (cos_stream_t *)pres->object;
@@ -1458,13 +1631,23 @@
 	   const gs_matrix * pctm, const gs_param_string * no_objname)
 {
     int code;
+    pdf_resource_t *pres_cancel;
 
-    code = pdf_add_procsets(pdev->substream_Resources, pdev->procsets);
-    if (code < 0)
-	return code;
+    pres_cancel = pdev->accumulating_substream_resource;
+    if (pres_cancel->object->id > 0) pres_cancel = NULL;
+    if (!pres_cancel) {
+	code = pdf_add_procsets(pdev->substream_Resources, pdev->procsets);
+	if (code < 0)
+	    return code;
+    }
     code = pdf_exit_substream(pdev);
     if (code < 0)
 	return code;
+    if (pres_cancel) {
+	code = pdf_cancel_resource(pdev, pres_cancel, resourceXObject);
+	if (code < 0)
+	    return code;
+	}
     return 0;
 }
 
@@ -1478,10 +1661,31 @@
 
     if (count != 1)
 	return_error(gs_error_rangecheck);
-    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_stream, &pco)) < 0)
+    if ((code = pdf_refer_named(pdev, &pairs[0], &pco)) < 0)
+	/* misc errors */
 	return code;
-    if (pco->is_open || !pco->is_graphics)
-	return_error(gs_error_rangecheck);
+    if (cos_type(pco) == cos_type_generic) {
+	/* forward reference
+	 * - use the object without additional checks
+	 * - be sure it has an associated resource structure, since we need to 
+	 *   store some information in object->pres->where_used
+	 * - don't turn it into a stream object (let it remain a generic one), since
+	 *   the object is not yet finalized and references to it are still "forward"
+	 */
+	if (pco->pres == 0) {
+	    code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, resourceXObject, gs_no_id),
+				   pdf_resource_type_structs[resourceXObject], &pco->pres, 0, pco);
+	    if (pco->pres == 0)
+		return_error(gs_error_VMerror);
+	}
+	pco->pres->named = true;
+	pco->is_graphics = true;
+    } else if (cos_type(pco) == cos_type_stream) {
+	/* object exists as a stream */
+	if (!pco->is_graphics || pco->is_open)
+	    return_error(gs_error_rangecheck);
+    } else
+	return_error(gs_error_typecheck);
     code = pdf_open_contents(pdev, PDF_IN_STREAM);
     if (code < 0)
 	return code;
Index: src/gdevpdfo.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfo.c,v
retrieving revision 1.30
diff -u -r1.30 gdevpdfo.c
--- src/gdevpdfo.c	8 Jun 2004 11:43:03 -0000	1.30
+++ src/gdevpdfo.c	29 Aug 2004 20:54:09 -0000
@@ -986,6 +986,36 @@
     return cos_dict_put_c_key(pcd, key, cos_c_string_value(&cvalue, value));
 }
 
+/* "Rename" a dict entry by changing the key without affecting the value */
+int
+cos_dict_rename(cos_dict_t *pcd, const byte *oldkey_data, uint oldkey_size,
+		  const byte *newkey_data, uint newkey_size)
+{
+    gs_memory_t *mem = COS_OBJECT_MEMORY(pcd);
+    cos_dict_element_t **ppcde = &pcd->elements;
+    cos_dict_element_t *next;
+    byte *copied_key_data;
+    int code;
+
+    while ((next = *ppcde) != 0)
+	if (bytes_compare(next->key.data, next->key.size, oldkey_data, oldkey_size))
+	    ppcde = &next->next;
+	else {
+	    copied_key_data = gs_alloc_string(mem, newkey_size,"cos_dict_rename(new key)");
+	    if (copied_key_data == 0)
+		return_error(gs_error_VMerror);
+	    memcpy(copied_key_data, newkey_data, newkey_size);
+	    if (next->owns_key)
+		gs_free_const_string(mem, next->key.data, next->key.size,
+					"cos_dict_rename(old key)");
+	    next->key.data = copied_key_data;
+	    next->key.size = newkey_size;
+	    next->owns_key = true;
+	    return 0;
+	}
+    return_error(gs_error_undefined);
+}
+
 /* Move all the elements from one dict to another. */
 int
 cos_dict_move_all(cos_dict_t *pcdto, cos_dict_t *pcdfrom)
Index: src/gdevpdfo.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfo.h,v
retrieving revision 1.19
diff -u -r1.19 gdevpdfo.h
--- src/gdevpdfo.h	8 Jun 2004 11:43:04 -0000	1.19
+++ src/gdevpdfo.h	29 Aug 2004 20:54:11 -0000
@@ -251,6 +251,9 @@
 int cos_dict_put_string(cos_dict_t *, const byte *, uint, const byte *, uint);
 int cos_dict_put_string_copy(cos_dict_t *pcd, const char *key, const char *value);
 int cos_dict_put_c_strings(cos_dict_t *, const char *, const char *);
+/* rename an entry by changing the key without affecting the value */
+int cos_dict_rename(cos_dict_t *pcd, const byte *oldkey_data, uint oldkey_size,
+		  const byte *newkey_data, uint newkey_size);
 /* move all the elements from one dict to another */
 int cos_dict_move_all(cos_dict_t *, cos_dict_t *);
     /* stream */
Index: src/gdevpdfu.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfu.c,v
retrieving revision 1.58
diff -u -r1.58 gdevpdfu.c
--- src/gdevpdfu.c	24 Aug 2004 17:51:31 -0000	1.58
+++ src/gdevpdfu.c	29 Aug 2004 20:54:17 -0000
@@ -140,6 +140,21 @@
     fwrite(&pos, sizeof(pos), 1, pdev->xref.file);
     return id;
 }
+/* Reuse an ID from an existing object.
+   Similar to pdf_obj_ref(), but receives an ID to reuse instead of allocating a new one */
+long
+pdf_obj_ref_reused(gx_device_pdf * pdev, long id)
+{
+    long pos = pdf_stell(pdev);
+    FILE *tfile = pdev->xref.file;
+    long tpos = ftell(tfile);
+
+    fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
+	    SEEK_SET);
+    fwrite(&pos, sizeof(pos), 1, tfile);
+    fseek(tfile, tpos, SEEK_SET);
+    return id;
+}
 
 /* Begin an object, optionally allocating an ID. */
 long
@@ -281,7 +296,7 @@
 	pdf_resource_t *pres;
 
 	code = pdf_enter_substream(pdev, resourcePage, gs_no_id, &pres, 
-		    true, pdev->params.CompressPages);
+		    true, pdev->params.CompressPages, NULL);
 	if (code < 0)
 	    return code;
 	pdev->contents_id = pres->object->id;
@@ -572,16 +587,35 @@
 int
 pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
 		const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
-		long id)
+		long id, cos_object_t *pcofwd)
 {
     pdf_resource_t *pres;
     cos_object_t *object;
 
     if (pst == NULL)
 	pst = &st_pdf_resource;
-    pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
-			   "pdf_alloc_aside(resource)");
-    object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
+    if (pcofwd) {
+	/* received a "forward" object to use instead of allocating a new object */
+	object = pcofwd;
+	id = object->id; /* "forward" objects already have ids */
+	pres = object->pres;
+    } else {
+	object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
+	pres = 0;
+    }
+    if (pres == 0) {
+	pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
+			       "pdf_alloc_aside(resource)");
+	if (pres) {
+	    pres->next = *plist;
+	    *plist = pres;
+	    pres->prev = pdev->last_resource;
+	    pdev->last_resource = pres;
+	    pres->named = false;
+	    pres->where_used = pdev->used_mask;
+	}
+    } else
+	DO_NOTHING; /* "forward" object already has an associated resource */
     if (pres == 0 || object == 0) {
 	return_error(gs_error_VMerror);
     }
@@ -591,12 +625,6 @@
 	pres->rname[0] = 0;
     } else
 	pdf_reserve_object_id(pdev, pres, id);
-    pres->next = *plist;
-    *plist = pres;
-    pres->prev = pdev->last_resource;
-    pdev->last_resource = pres;
-    pres->named = false;
-    pres->where_used = pdev->used_mask;
     *ppres = pres;
     return 0;
 }
@@ -608,7 +636,7 @@
 
     if (id < 0)
 	return (int)id;
-    return pdf_alloc_aside(pdev, plist, pst, ppres, id);
+    return pdf_alloc_aside(pdev, plist, pst, ppres, id, NULL);
 }
 
 /* Begin a resource of a given type. */
@@ -644,7 +672,7 @@
 		   pdf_resource_t ** ppres, long id)
 {
     int code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
-			       pdf_resource_type_structs[rtype], ppres, id);
+			       pdf_resource_type_structs[rtype], ppres, id, NULL);
 
     if (code >= 0)
 	(*ppres)->rid = rid;
@@ -1321,7 +1349,7 @@
     pdw->binary.dev = (gx_device_psdf *)pdev;
     pdw->binary.strm = 0;		/* for GC in case of failure */
     code = pdf_open_aside(pdev, resourceOther, gs_no_id, &pdw->pres, !object_id, 
-		(options & DATA_STREAM_COMPRESS ? true : false));
+		(options & DATA_STREAM_COMPRESS ? true : false), NULL);
     if (object_id != 0)
 	pdf_reserve_object_id(pdev, pdw->pres, object_id);
     pdw->binary.strm = pdev->strm;
Index: src/gdevpdfx.h
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdfx.h,v
retrieving revision 1.100
diff -u -r1.100 gdevpdfx.h
--- src/gdevpdfx.h	24 Aug 2004 17:51:31 -0000	1.100
+++ src/gdevpdfx.h	29 Aug 2004 20:54:22 -0000
@@ -700,6 +700,9 @@
 
 /* Allocate an ID for a future object. */
 long pdf_obj_ref(gx_device_pdf * pdev);
+/* Reuse an ID from an existing object.
+   Similar to pdf_obj_ref(), but receives an ID to reuse instead of allocating a new one */
+long pdf_obj_ref_reused(gx_device_pdf * pdev, long id);
 
 /* Read the current position in the output stream. */
 long pdf_stell(gx_device_pdf * pdev);
@@ -743,7 +746,7 @@
 /* Begin an aside (resource, annotation, ...). */
 int pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
 		const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
-		long id);
+		long id, cos_object_t *pcofwd);
 /* Begin an aside (resource, annotation, ...). */
 int pdf_begin_aside(gx_device_pdf * pdev, pdf_resource_t **plist,
 		    const gs_memory_struct_type_t * pst,
@@ -1116,15 +1119,15 @@
 int pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font);
 
 /* Open a stream object in the temporary file. */
-int pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
-	gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress);
+int pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, gs_id id,
+	pdf_resource_t **ppres, bool reserve_object_id, bool compress, cos_object_t *pcofwd);
 
 /* Close a stream object in the temporary file. */
 int pdf_close_aside(gx_device_pdf *pdev);
 
 /* Enter the substream accumulation mode. */
-int pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
-		gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress);
+int pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, gs_id id,
+		pdf_resource_t **ppres, bool reserve_object_id, bool compress, cos_object_t *pcofwd);
 
 /* Exit the substream accumulation mode. */
 int pdf_exit_substream(gx_device_pdf *pdev);
Index: src/gdevpdti.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevpdti.c,v
retrieving revision 1.36
diff -u -r1.36 gdevpdti.c
--- src/gdevpdti.c	4 Aug 2004 19:36:12 -0000	1.36
+++ src/gdevpdti.c	29 Aug 2004 20:54:25 -0000
@@ -386,7 +386,7 @@
     pdf_char_proc_t *pcp;
     pdf_resource_t *pres;
     int code = pdf_enter_substream(pdev, resourceCharProc, gs_next_ids(pdev->memory, 1), 
-				   &pres, false, pdev->CompressFonts);
+				   &pres, false, pdev->CompressFonts, NULL);
 
     if (code < 0)
        return code;
@@ -447,8 +447,8 @@
  */
 
 int
-pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
-	gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress) 
+pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype, gs_id id, 
+	pdf_resource_t **ppres, bool reserve_object_id, bool compress, cos_object_t *pcofwd)
 {
     int code;
     pdf_resource_t *pres;
@@ -460,7 +460,7 @@
 
     pdev->streams.save_strm = pdev->strm;
     code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
-		pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
+		pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1, pcofwd);
     if (code < 0)
 	return code;
     cos_become(pres->object, cos_type_stream);
@@ -517,8 +517,8 @@
  * Enter the substream accumulation mode.
  */
 int
-pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, 
-	gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress) 
+pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype, gs_id id,
+	pdf_resource_t **ppres, bool reserve_object_id, bool compress, cos_object_t *pcofwd)
 {
     int sbstack_ptr = pdev->sbstack_depth;
     pdf_resource_t *pres;
@@ -532,7 +532,7 @@
 	if (pdev->sbstack[sbstack_ptr].text_state == 0)
 	    return_error(gs_error_VMerror);
     }
-    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id, compress);
+    code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id, compress, pcofwd);
     if (code < 0)
 	return code;
     code = pdf_save_viewer_state(pdev, NULL);