1 
2 /* Copyright (C) 2001-2006 Artifex Software, Inc.
3    All Rights Reserved.
4 
5    This software is provided AS-IS with no warranty, either express or
6    implied.
7 
8    This software is distributed under license and may not be copied, modified
9    or distributed except as expressly authorized under the terms of that
10    license.  Refer to licensing information at http://www.artifex.com/
11    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
12    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
13 */
14 
15 /* $Id: gdevpdti.c 9811 2009-06-22 07:41:34Z ken $ */
16 /* Bitmap font implementation for pdfwrite */
17 #include "memory_.h"
18 #include "gx.h"
19 #include "gxpath.h"
20 #include "gserrors.h"
21 #include "gsutil.h"
22 #include "gdevpdfx.h"
23 #include "gdevpdfg.h"
24 #include "gdevpdtf.h"
25 #include "gdevpdti.h"
26 #include "gdevpdts.h"
27 #include "gdevpdtw.h"
28 #include "gdevpdtt.h"
29 #include "gdevpdfo.h"
30 
31 /* ---------------- Private ---------------- */
32 
33 /* Define the structure for a CharProc pseudo-resource. */
34 /*typedef struct pdf_char_proc_s pdf_char_proc_t;*/  /* gdevpdfx.h */
35 struct pdf_char_proc_s {
36     pdf_resource_common(pdf_char_proc_t);
37     pdf_char_proc_ownership_t *owner_fonts; /* fonts using this charproc. */
38     int y_offset;		/* of character (0,0) */
39     int x_offset;		/* of character (0,0) */
40     gs_point real_width;        /* Not used with synthesised bitmap fonts. */
41     gs_point v;			/* Not used with synthesised bitmap fonts. */
42 };
43 
44 /* The descriptor is public for pdf_resource_type_structs. */
45 gs_public_st_suffix_add1(st_pdf_char_proc, pdf_char_proc_t,
46   "pdf_char_proc_t", pdf_char_proc_enum_ptrs, pdf_char_proc_reloc_ptrs,
47   st_pdf_resource, owner_fonts);
48 
49 struct pdf_char_proc_ownership_s {
50     pdf_char_proc_t *char_proc;
51     pdf_char_proc_ownership_t *font_next;	/* next char_proc for same font */
52     pdf_char_proc_ownership_t *char_next;	/* next char_proc for same charproc */
53     pdf_font_resource_t *font;
54     gs_char char_code;		/* Character code in PDF font. */
55     gs_glyph glyph;		/* Glyph id in Postscript font. */
56     gs_const_string char_name;
57     bool duplicate_char_name;
58 };
59 gs_private_st_strings1_ptrs4(st_pdf_char_proc_ownership, pdf_char_proc_ownership_t,
60   "pdf_char_proc_ownership_t", pdf_char_proc_ownership_enum_ptrs,
61   pdf_char_proc_ownership_reloc_ptrs, char_name, char_proc, char_next, font_next, font);
62 
63 gs_private_st_ptrs1(st_pdf_bitmap_fonts, pdf_bitmap_fonts_t,
64   "pdf_bitmap_fonts_t", pdf_bitmap_fonts_enum_ptrs,
65   pdf_bitmap_fonts_reloc_ptrs, open_font);
66 
67 static inline long
pdf_char_proc_id(const pdf_char_proc_t * pcp)68 pdf_char_proc_id(const pdf_char_proc_t *pcp)
69 {
70     return pdf_resource_id((const pdf_resource_t *)pcp);
71 }
72 
73 /* Assign a code for a char_proc. */
74 static int
assign_char_code(gx_device_pdf * pdev,gs_text_enum_t * pte)75 assign_char_code(gx_device_pdf * pdev, gs_text_enum_t *pte)
76 {
77     pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
78     pdf_font_resource_t *pdfont = pbfs->open_font; /* Type 3 */
79     int i, c = 0, code;
80     uint operation = pte->text.operation;
81 
82     if (pbfs->bitmap_encoding_id == 0)
83 	pbfs->bitmap_encoding_id = pdf_obj_ref(pdev);
84     if (pdfont == 0 || pdfont->u.simple.LastChar == 255 ||
85 	!pbfs->use_open_font
86 	) {
87 	/* Start a new synthesized font. */
88 	char *pc;
89 
90 	code = pdf_font_type3_alloc(pdev, &pdfont, pdf_write_contents_bitmap);
91 	if (code < 0)
92 	    return code;
93         pdfont->u.simple.s.type3.bitmap_font = true;
94 	if (pbfs->open_font == 0)
95 	    pdfont->rname[0] = 0;
96 	else
97 	    strcpy(pdfont->rname, pbfs->open_font->rname);
98 	pdfont->u.simple.s.type3.FontBBox.p.x = 0;
99 	pdfont->u.simple.s.type3.FontBBox.p.y = 0;
100 	pdfont->u.simple.s.type3.FontBBox.q.x = 0;
101 	pdfont->u.simple.s.type3.FontBBox.q.y = 0;
102 	pdfont->mark_glyph = NULL;
103 	gs_make_identity(&pdfont->u.simple.s.type3.FontMatrix);
104 	/*
105 	 * We "increment" the font name as a radix-26 "number".
106 	 * This cannot possibly overflow.
107 	 */
108 	for (pc = pdfont->rname; *pc == 'Z'; ++pc)
109 	    *pc = '@';
110 	if ((*pc)++ == 0)
111 	    *pc = 'A', pc[1] = 0;
112 	pbfs->open_font = pdfont;
113 	pbfs->use_open_font = true;
114 	pdfont->u.simple.FirstChar = 255;
115     }
116     if ((operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) ||
117         (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR))) {
118 	unsigned char p = *pte->text.data.bytes;
119 	unsigned char index = p / 8, bit = 0x01 << (p % 8);
120 
121 	if (pdfont->used[index] & bit) {
122     	    for (i = 0;i < 256;i++) {
123 		index = i / 8;
124 		bit = 0x01 << (i % 8);
125 		if (!(pdfont->used[index] & bit)) {
126 		    c = i;
127 		    break;
128 		}
129 	    }
130 	} else
131 	    c = p;
132 	pdfont->used[index] |= bit;
133 	if (c > pdfont->u.simple.LastChar)
134 	    pdfont->u.simple.LastChar = c;
135 
136     } else {
137 	unsigned char index, bit;
138         c = ++(pdfont->u.simple.LastChar);
139 	index = c / 8;
140 	bit = 0x01 << (c % 8);
141 	pdfont->used[index] |= bit;
142     }
143     if (c < pdfont->u.simple.FirstChar)
144         pdfont->u.simple.FirstChar = c;
145 
146     pdfont->Widths[c] = psdf_round(pdev->char_width.x, 100, 10); /* See
147 			pdf_write_Widths about rounding. We need to provide
148 			a compatible data for Tj. */
149     if (c > pbfs->max_embedded_code)
150 	pbfs->max_embedded_code = c;
151 
152     return c;
153 }
154 
155 /* Write the contents of a Type 3 bitmap or vector font resource. */
156 int
pdf_write_contents_bitmap(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)157 pdf_write_contents_bitmap(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
158 {
159     stream *s = pdev->strm;
160     const pdf_char_proc_ownership_t *pcpo;
161     long diff_id = 0;
162     int code;
163 
164     if (pdfont->u.simple.s.type3.bitmap_font)
165 	diff_id = pdev->text->bitmap_fonts->bitmap_encoding_id;
166     else {
167 	/* See comment in pdf_write_encoding. */
168         diff_id = pdf_obj_ref(pdev);
169     }
170     code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
171     if (code < 0)
172 	return code;
173     stream_puts(s, "/CharProcs <<");
174     /* Write real characters. */
175     for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo;
176 	 pcpo = pcpo->char_next
177 	 ) {
178 	if (pdfont->u.simple.s.type3.bitmap_font)
179 	    pprintld2(s, "/a%ld %ld 0 R\n", (long)pcpo->char_code,
180 		      pdf_char_proc_id(pcpo->char_proc));
181 	else if (!pcpo-> duplicate_char_name) {
182 	    pdf_put_name(pdev, pcpo->char_name.data, pcpo->char_name.size);
183 	    pprintld1(s, " %ld 0 R\n", pdf_char_proc_id(pcpo->char_proc));
184 	}
185     }
186     stream_puts(s, ">>");
187     pprintg6(s, "/FontMatrix[%g %g %g %g %g %g]",
188 	    (float)pdfont->u.simple.s.type3.FontMatrix.xx,
189 	    (float)pdfont->u.simple.s.type3.FontMatrix.xy,
190 	    (float)pdfont->u.simple.s.type3.FontMatrix.yx,
191 	    (float)pdfont->u.simple.s.type3.FontMatrix.yy,
192 	    (float)pdfont->u.simple.s.type3.FontMatrix.tx,
193 	    (float)pdfont->u.simple.s.type3.FontMatrix.ty);
194     code = pdf_finish_write_contents_type3(pdev, pdfont);
195     if (code < 0)
196 	return code;
197     s = pdev->strm; /* pdf_finish_write_contents_type3 changes pdev->strm . */
198     if (!pdfont->u.simple.s.type3.bitmap_font && diff_id > 0) {
199 	code = pdf_write_encoding(pdev, pdfont, diff_id, 0);
200 	if (code < 0)
201 	    return code;
202     }
203     return 0;
204 }
205 
206 /* ---------------- Public ---------------- */
207 
208 /*
209  * Allocate and initialize bookkeeping for bitmap fonts.
210  */
211 pdf_bitmap_fonts_t *
pdf_bitmap_fonts_alloc(gs_memory_t * mem)212 pdf_bitmap_fonts_alloc(gs_memory_t *mem)
213 {
214     pdf_bitmap_fonts_t *pbfs =
215 	gs_alloc_struct(mem, pdf_bitmap_fonts_t, &st_pdf_bitmap_fonts,
216 			"pdf_bitmap_fonts_alloc");
217 
218     if (pbfs == 0)
219 	return 0;
220     memset(pbfs, 0, sizeof(*pbfs));
221     pbfs->max_embedded_code = -1;
222     return pbfs;
223 }
224 
225 /*
226  * Update text state at the end of a page.
227  */
228 void
pdf_close_text_page(gx_device_pdf * pdev)229 pdf_close_text_page(gx_device_pdf *pdev)
230 {
231     /*
232      * When Acrobat Reader 3 prints a file containing a Type 3 font with a
233      * non-standard Encoding, it apparently only emits the subset of the
234      * font actually used on the page.  Thus, if the "Download Fonts Once"
235      * option is selected, characters not used on the page where the font
236      * first appears will not be defined, and hence will print as blank if
237      * used on subsequent pages.  Thus, we can't allow a Type 3 font to
238      * add additional characters on subsequent pages.
239      */
240     if (pdev->CompatibilityLevel <= 1.2)
241 	pdev->text->bitmap_fonts->use_open_font = false;
242 }
243 
244 int
pdf_charproc_y_offset(pdf_char_proc_t * pcp)245 pdf_charproc_y_offset(pdf_char_proc_t *pcp)
246 {
247     return pcp->y_offset;
248 }
249 
250 int
pdf_charproc_x_offset(pdf_char_proc_t * pcp)251 pdf_charproc_x_offset(pdf_char_proc_t *pcp)
252 {
253     return pcp->x_offset;
254 }
255 
256 /* Attach a CharProc to a font. */
257 static int
pdf_attach_charproc(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,pdf_char_proc_t * pcp,gs_glyph glyph,gs_char char_code,const gs_const_string * gnstr)258 pdf_attach_charproc(gx_device_pdf * pdev, pdf_font_resource_t *pdfont, pdf_char_proc_t *pcp,
259 		    gs_glyph glyph, gs_char char_code, const gs_const_string *gnstr)
260 {
261     pdf_char_proc_ownership_t *pcpo;
262     bool duplicate_char_name = false;
263 
264     for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
265 	if (pcpo->glyph == glyph && pcpo->char_code == char_code)
266 	    return 0;
267     }
268     if (!pdfont->u.simple.s.type3.bitmap_font) {
269 	for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
270 	    if (!bytes_compare(pcpo->char_name.data, pcpo->char_name.size, gnstr->data, gnstr->size)) {
271 		duplicate_char_name = true;
272 		break;
273 	    }
274 	}
275     }
276     pcpo = gs_alloc_struct(pdev->pdf_memory,
277 	    pdf_char_proc_ownership_t, &st_pdf_char_proc_ownership, "pdf_attach_charproc");
278 
279     if (pcpo == NULL)
280 	return_error(gs_error_VMerror);
281     pcpo->font = pdfont;
282     pcpo->char_next = pdfont->u.simple.s.type3.char_procs;
283     pdfont->u.simple.s.type3.char_procs = pcpo;
284     pcpo->char_proc = pcp;
285     pcpo->font_next = pcp->owner_fonts;
286     pcp->owner_fonts = pcpo;
287     pcpo->char_code = char_code;
288     pcpo->glyph = glyph;
289     if (gnstr == NULL) {
290 	pcpo->char_name.data = 0;
291 	pcpo->char_name.size = 0;
292     } else
293 	pcpo->char_name = *gnstr;
294     pcpo->duplicate_char_name = duplicate_char_name;
295     return 0;
296 }
297 
298 /* Begin a CharProc for a synthesized (bitmap) font. */
299 int
pdf_begin_char_proc(gx_device_pdf * pdev,int w,int h,int x_width,int y_offset,int x_offset,gs_id id,pdf_char_proc_t ** ppcp,pdf_stream_position_t * ppos)300 pdf_begin_char_proc(gx_device_pdf * pdev, int w, int h, int x_width,
301 		    int y_offset, int x_offset, gs_id id, pdf_char_proc_t ** ppcp,
302 		    pdf_stream_position_t * ppos)
303 {
304     int char_code = 0;
305     pdf_bitmap_fonts_t *const pbfs = pdev->text->bitmap_fonts;
306     pdf_font_resource_t *font;
307     pdf_resource_t *pres;
308     pdf_char_proc_t *pcp;
309     int code;
310 
311     char_code = assign_char_code(pdev, pdev->pte);
312     font = pbfs->open_font; /* Type 3 */
313     code = pdf_begin_resource(pdev, resourceCharProc, id, &pres);
314     if (code < 0)
315 	return code;
316     pcp = (pdf_char_proc_t *) pres;
317     code = pdf_attach_charproc(pdev, font, pcp, GS_NO_GLYPH, char_code, NULL);
318     if (code < 0)
319 	return code;
320     pres->object->written = true;
321     {
322 	stream *s = pdev->strm;
323 
324 	/*
325 	 * The resource file is positionable, so rather than use an
326 	 * object reference for the length, we'll go back and fill it in
327 	 * at the end of the definition.  Take 1M as the longest
328 	 * definition we can handle.  (This used to be 10K, but there was
329 	 * a real file that exceeded this limit.)
330 	 */
331 	stream_puts(s, "<</Length       >>stream\n");
332 	ppos->start_pos = stell(s);
333     }
334     code = pdf_begin_encrypt(pdev, &pdev->strm, pres->object->id);
335     if (code < 0)
336 	return code;
337     pcp->y_offset = y_offset;
338     pcp->x_offset = x_offset;
339     font->u.simple.s.type3.FontBBox.q.x =
340 	max(font->u.simple.s.type3.FontBBox.q.x, w);
341     font->u.simple.s.type3.FontBBox.q.y =
342 	max(font->u.simple.s.type3.FontBBox.q.y, y_offset + h);
343     font->u.simple.s.type3.max_y_offset =
344 	max(font->u.simple.s.type3.max_y_offset, h + (h >> 2));
345     *ppcp = pcp;
346     return 0;
347 }
348 
349 /* End a CharProc. */
350 int
pdf_end_char_proc(gx_device_pdf * pdev,pdf_stream_position_t * ppos)351 pdf_end_char_proc(gx_device_pdf * pdev, pdf_stream_position_t * ppos)
352 {
353     stream *s;
354     long start_pos, end_pos, length;
355 
356     pdf_end_encrypt(pdev);
357     s = pdev->strm;
358     start_pos = ppos->start_pos;
359     end_pos = stell(s);
360     length = end_pos - start_pos;
361     if (length > 999999)
362 	return_error(gs_error_limitcheck);
363     sseek(s, start_pos - 15);
364     pprintd1(s, "%d", length);
365     sseek(s, end_pos);
366     if (pdev->PDFA)
367 	stream_puts(s, "\n");
368     stream_puts(s, "endstream\n");
369     pdf_end_separate(pdev);
370     return 0;
371 }
372 
373 /* Mark glyph names for garbager. */
374 void
pdf_mark_glyph_names(const pdf_font_resource_t * pdfont,const gs_memory_t * memory)375 pdf_mark_glyph_names(const pdf_font_resource_t *pdfont, const gs_memory_t *memory)
376 {
377     if (pdfont->mark_glyph == NULL) {
378 	/* Synthesised bitmap fonts pass here. */
379 	return;
380     }
381     if (pdfont->u.simple.Encoding != NULL) {
382 	 int i;
383 
384 	 for (i = 0; i < 256; i++)
385 	     if (pdfont->u.simple.Encoding[i].glyph != GS_NO_GLYPH)
386 		pdfont->mark_glyph(memory, pdfont->u.simple.Encoding[i].glyph, pdfont->mark_glyph_data);
387      }
388     if (pdfont->FontType == ft_user_defined) {
389 	const pdf_char_proc_ownership_t *pcpo = pdfont->u.simple.s.type3.char_procs;
390 
391 	for (; pcpo != NULL; pcpo = pcpo->font_next)
392 	    pdfont->mark_glyph(memory, pcpo->glyph, pdfont->mark_glyph_data);
393     }
394 }
395 
396 /* Put out a reference to an image as a character in a synthesized font. */
397 int
pdf_do_char_image(gx_device_pdf * pdev,const pdf_char_proc_t * pcp,const gs_matrix * pimat)398 pdf_do_char_image(gx_device_pdf * pdev, const pdf_char_proc_t * pcp,
399 		  const gs_matrix * pimat)
400 {
401     /* We need to choose a font, which use the charproc.
402        In most cases it is the last font, which the charproc is attached to.
403        If the charproc is substituted, it causes a font change. */
404     const pdf_char_proc_ownership_t * pcpo = pcp->owner_fonts;
405     pdf_font_resource_t *pdfont = pcpo->font;
406     byte ch = pcpo->char_code;
407     pdf_text_state_values_t values;
408 
409     values.character_spacing = 0;
410     values.pdfont = pdfont;
411     values.size = 1;
412     values.matrix = *pimat;
413     values.render_mode = 0;
414     values.word_spacing = 0;
415     pdf_set_text_state_values(pdev, &values);
416     pdf_append_chars(pdev, &ch, 1, pdfont->Widths[ch] * pimat->xx, 0.0, false);
417     return 0;
418 }
419 
420 /*
421  * Write the Encoding for bitmap fonts, if needed.
422  */
423 int
pdf_write_bitmap_fonts_Encoding(gx_device_pdf * pdev)424 pdf_write_bitmap_fonts_Encoding(gx_device_pdf *pdev)
425 {
426     pdf_bitmap_fonts_t *pbfs = pdev->text->bitmap_fonts;
427 
428     if (pbfs->bitmap_encoding_id) {
429 	stream *s;
430 	int i;
431 
432 	pdf_open_separate(pdev, pbfs->bitmap_encoding_id);
433 	s = pdev->strm;
434 	/*
435 	 * Even though the PDF reference documentation says that a
436 	 * BaseEncoding key is required unless the encoding is
437 	 * "based on the base font's encoding" (and there is no base
438 	 * font in this case), Acrobat 2.1 gives an error if the
439 	 * BaseEncoding key is present.
440 	 */
441 	stream_puts(s, "<</Type/Encoding/Differences[0");
442 	for (i = 0; i <= pbfs->max_embedded_code; ++i) {
443 	    if (!(i & 15))
444 		stream_puts(s, "\n");
445 	    pprintd1(s, "/a%d", i);
446 	}
447 	stream_puts(s, "\n] >>\n");
448 	pdf_end_separate(pdev);
449 	pbfs->bitmap_encoding_id = 0;
450     }
451     return 0;
452 }
453 
454 /*
455  * Start charproc accumulation for a Type 3 font.
456  */
457 int
pdf_start_charproc_accum(gx_device_pdf * pdev)458 pdf_start_charproc_accum(gx_device_pdf *pdev)
459 {
460     pdf_char_proc_t *pcp;
461     pdf_resource_t *pres;
462     int code = pdf_enter_substream(pdev, resourceCharProc, gs_next_ids(pdev->memory, 1),
463 				   &pres, false, pdev->CompressFonts);
464 
465     if (code < 0)
466        return code;
467     pcp = (pdf_char_proc_t *)pres;
468     pcp->owner_fonts = NULL;
469     return 0;
470 }
471 
472 /*
473  * Install charproc accumulator for a Type 3 font.
474  */
475 int
pdf_set_charproc_attrs(gx_device_pdf * pdev,gs_font * font,const double * pw,int narg,gs_text_cache_control_t control,gs_char ch)476 pdf_set_charproc_attrs(gx_device_pdf *pdev, gs_font *font, const double *pw, int narg,
477 		gs_text_cache_control_t control, gs_char ch)
478 {
479     pdf_font_resource_t *pdfont;
480     pdf_resource_t *pres = pdev->accumulating_substream_resource;
481     pdf_char_proc_t *pcp;
482     int code;
483 
484     code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
485     if (code < 0)
486 	return code;
487     pcp = (pdf_char_proc_t *)pres;
488     pcp->owner_fonts = NULL;
489     pcp->real_width.x = pw[font->WMode && narg > 6 ? 6 : 0];
490     pcp->real_width.y = pw[font->WMode && narg > 6 ? 7 : 1];
491     pcp->v.x = (narg > 8 ? pw[8] : 0);
492     pcp->v.y = (narg > 8 ? pw[9] : 0);
493     if (control == TEXT_SET_CHAR_WIDTH) {
494 	/* PLRM 5.7.1 "BuildGlyph" reads : "Normally, it is unnecessary and
495 	undesirable to initialize the current color parameter, because show
496 	is defined to paint glyphs with the current color."
497 	However comparefiles/Bug687044.ps doesn't follow that. */
498 	pdev->skip_colors = false;
499 	pprintg1(pdev->strm, "%g 0 d0\n", (float)pw[0]);
500     } else {
501 	pdev->skip_colors = true;
502 	pprintg6(pdev->strm, "%g %g %g %g %g %g d1\n",
503 	    (float)pw[0], (float)0.0, (float)pw[2],
504 	    (float)pw[3], (float)pw[4], (float)pw[5]);
505 	pdfont->u.simple.s.type3.cached[ch >> 3] |= 0x80 >> (ch & 7);
506     }
507     return 0;
508 }
509 
510 /*
511  * Open a stream object in the temporary file.
512  */
513 
514 int
pdf_open_aside(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id id,pdf_resource_t ** ppres,bool reserve_object_id,int options)515 pdf_open_aside(gx_device_pdf *pdev, pdf_resource_type_t rtype,
516 	gs_id id, pdf_resource_t **ppres, bool reserve_object_id, int options)
517 {
518     int code;
519     pdf_resource_t *pres;
520     stream *s, *save_strm = pdev->strm;
521     pdf_data_writer_t writer;
522     static const pdf_filter_names_t fnames = {
523 	PDF_FILTER_NAMES
524     };
525 
526     pdev->streams.save_strm = pdev->strm;
527     code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, id),
528 		pdf_resource_type_structs[rtype], &pres, reserve_object_id ? 0 : -1);
529     if (code < 0)
530 	return code;
531     cos_become(pres->object, cos_type_stream);
532     s = cos_write_stream_alloc((cos_stream_t *)pres->object, pdev, "pdf_enter_substream");
533     if (s == 0)
534 	return_error(gs_error_VMerror);
535     pdev->strm = s;
536     code = pdf_append_data_stream_filters(pdev, &writer,
537 			     options | DATA_STREAM_NOLENGTH, pres->object->id);
538     if (code < 0) {
539 	pdev->strm = save_strm;
540 	return code;
541     }
542     code = pdf_put_filters((cos_dict_t *)pres->object, pdev, writer.binary.strm, &fnames);
543     if (code < 0) {
544 	pdev->strm = save_strm;
545 	return code;
546     }
547     pdev->strm = writer.binary.strm;
548     *ppres = pres;
549     return 0;
550 }
551 
552 /*
553  * Close a stream object in the temporary file.
554  */
555 int
pdf_close_aside(gx_device_pdf * pdev)556 pdf_close_aside(gx_device_pdf *pdev)
557 {
558     /* We should call pdf_end_data here, but we don't want to put pdf_data_writer_t
559        into pdf_substream_save stack to simplify garbager descriptors.
560        Use a lower level functions instead that. */
561     stream *s = pdev->strm;
562     int status = s_close_filters(&s, cos_write_stream_from_pipeline(s));
563     cos_stream_t *pcs = cos_stream_from_pipeline(s);
564     int code = 0;
565 
566     if (status < 0)
567 	 code = gs_note_error(gs_error_ioerror);
568     pcs->is_open = false;
569     sclose(s);
570     pdev->strm = pdev->streams.save_strm;
571     return code;
572 }
573 
574 /*
575  * Enter the substream accumulation mode.
576  */
577 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)578 pdf_enter_substream(gx_device_pdf *pdev, pdf_resource_type_t rtype,
579 	gs_id id, pdf_resource_t **ppres, bool reserve_object_id, bool compress)
580 {
581     int sbstack_ptr = pdev->sbstack_depth;
582     pdf_resource_t *pres;
583     stream *save_strm = pdev->strm;
584     int code;
585 
586     if (pdev->sbstack_depth >= pdev->sbstack_size)
587 	return_error(gs_error_unregistered); /* Must not happen. */
588     if (pdev->sbstack[sbstack_ptr].text_state == 0) {
589 	pdev->sbstack[sbstack_ptr].text_state = pdf_text_state_alloc(pdev->pdf_memory);
590 	if (pdev->sbstack[sbstack_ptr].text_state == 0)
591 	    return_error(gs_error_VMerror);
592     }
593     code = pdf_open_aside(pdev, rtype, id, &pres, reserve_object_id,
594 		    (compress ? DATA_STREAM_COMPRESS : 0));
595     if (code < 0)
596 	return code;
597     code = pdf_save_viewer_state(pdev, NULL);
598     if (code < 0) {
599 	pdev->strm = save_strm;
600 	return code;
601     }
602     pdev->sbstack[sbstack_ptr].context = pdev->context;
603     pdf_text_state_copy(pdev->sbstack[sbstack_ptr].text_state, pdev->text->text_state);
604     pdf_set_text_state_default(pdev->text->text_state);
605     pdev->sbstack[sbstack_ptr].clip_path = pdev->clip_path;
606     pdev->clip_path = 0;
607     pdev->sbstack[sbstack_ptr].clip_path_id = pdev->clip_path_id;
608     pdev->clip_path_id = pdev->no_clip_path_id;
609     pdev->sbstack[sbstack_ptr].vgstack_bottom = pdev->vgstack_bottom;
610     pdev->vgstack_bottom = pdev->vgstack_depth;
611     pdev->sbstack[sbstack_ptr].strm = save_strm;
612     pdev->sbstack[sbstack_ptr].procsets = pdev->procsets;
613     pdev->sbstack[sbstack_ptr].substream_Resources = pdev->substream_Resources;
614     pdev->sbstack[sbstack_ptr].skip_colors = pdev->skip_colors;
615     pdev->sbstack[sbstack_ptr].font3 = pdev->font3;
616     pdev->sbstack[sbstack_ptr].accumulating_substream_resource = pdev->accumulating_substream_resource;
617     pdev->sbstack[sbstack_ptr].charproc_just_accumulated = pdev->charproc_just_accumulated;
618     pdev->sbstack[sbstack_ptr].accumulating_a_global_object = pdev->accumulating_a_global_object;
619     pdev->sbstack[sbstack_ptr].pres_soft_mask_dict = pdev->pres_soft_mask_dict;
620     pdev->sbstack[sbstack_ptr].objname = pdev->objname;
621     pdev->sbstack[sbstack_ptr].last_charpath_op = pdev->last_charpath_op;
622     pdev->skip_colors = false;
623     pdev->charproc_just_accumulated = false;
624     pdev->pres_soft_mask_dict = NULL;
625     pdev->objname.data = NULL;
626     pdev->objname.size = 0;
627     /* Do not reset pdev->accumulating_a_global_object - it inherits. */
628     pdev->sbstack_depth++;
629     pdev->procsets = 0;
630     pdev->font3 = 0;
631     pdev->context = PDF_IN_STREAM;
632     pdev->accumulating_substream_resource = pres;
633     pdev->last_charpath_op = 0;
634     /* Do not alter type3charpath, inherit the current value. We need to know if */
635     /* we are inside a charpath operation, and only reset this when the charpath */
636     /* is complete */
637     pdf_reset_graphics(pdev);
638     *ppres = pres;
639     return 0;
640 }
641 
642 /*
643  * Exit the substream accumulation mode.
644  */
645 int
pdf_exit_substream(gx_device_pdf * pdev)646 pdf_exit_substream(gx_device_pdf *pdev)
647 {
648     int code, code1;
649     int sbstack_ptr;
650 
651     if (pdev->sbstack_depth <= 0)
652 	return_error(gs_error_unregistered); /* Must not happen. */
653     code = pdf_open_contents(pdev, PDF_IN_STREAM);
654     sbstack_ptr = pdev->sbstack_depth - 1;
655     while (pdev->vgstack_depth > pdev->vgstack_bottom) {
656 	code1 = pdf_restore_viewer_state(pdev, pdev->strm);
657 	if (code >= 0)
658 	    code = code1;
659     }
660     if (pdev->clip_path != 0)
661 	gx_path_free(pdev->clip_path, "pdf_end_charproc_accum");
662     code1 = pdf_close_aside(pdev);
663     if (code1 < 0 && code >= 0)
664 	code = code1;
665     pdev->context = pdev->sbstack[sbstack_ptr].context;
666     pdf_text_state_copy(pdev->text->text_state, pdev->sbstack[sbstack_ptr].text_state);
667     pdev->clip_path = pdev->sbstack[sbstack_ptr].clip_path;
668     pdev->sbstack[sbstack_ptr].clip_path = 0;
669     pdev->clip_path_id = pdev->sbstack[sbstack_ptr].clip_path_id;
670     pdev->vgstack_bottom = pdev->sbstack[sbstack_ptr].vgstack_bottom;
671     pdev->strm = pdev->sbstack[sbstack_ptr].strm;
672     pdev->sbstack[sbstack_ptr].strm = 0;
673     pdev->procsets = pdev->sbstack[sbstack_ptr].procsets;
674     pdev->substream_Resources = pdev->sbstack[sbstack_ptr].substream_Resources;
675     pdev->sbstack[sbstack_ptr].substream_Resources = 0;
676     pdev->skip_colors = pdev->sbstack[sbstack_ptr].skip_colors;
677     pdev->font3 = pdev->sbstack[sbstack_ptr].font3;
678     pdev->sbstack[sbstack_ptr].font3 = 0;
679     pdev->accumulating_substream_resource = pdev->sbstack[sbstack_ptr].accumulating_substream_resource;
680     pdev->sbstack[sbstack_ptr].accumulating_substream_resource = 0;
681     pdev->charproc_just_accumulated = pdev->sbstack[sbstack_ptr].charproc_just_accumulated;
682     pdev->accumulating_a_global_object = pdev->sbstack[sbstack_ptr].accumulating_a_global_object;
683     pdev->pres_soft_mask_dict = pdev->sbstack[sbstack_ptr].pres_soft_mask_dict;
684     pdev->objname = pdev->sbstack[sbstack_ptr].objname;
685     pdev->last_charpath_op = pdev->sbstack[sbstack_ptr].last_charpath_op;
686     pdev->sbstack_depth = sbstack_ptr;
687     code1 = pdf_restore_viewer_state(pdev, NULL);
688     if (code1 < 0 && code >= 0)
689 	code = code1;
690     return code;
691 }
692 
693 static bool
pdf_is_same_charproc_attrs1(gx_device_pdf * pdev,pdf_char_proc_t * pcp0,pdf_char_proc_t * pcp1)694 pdf_is_same_charproc_attrs1(gx_device_pdf *pdev, pdf_char_proc_t *pcp0, pdf_char_proc_t *pcp1)
695 {
696     if (pcp0->real_width.x != pcp1->real_width.x)
697 	return false;
698     if (pcp0->real_width.y != pcp1->real_width.y)
699 	return false;
700     if (pcp0->v.x != pcp1->v.x)
701 	return false;
702     if (pcp0->v.y != pcp1->v.y)
703 	return false;
704     return true;
705 }
706 
707 typedef struct charproc_compatibility_data_s {
708     const pdf_char_glyph_pairs_t *cgp;
709     pdf_font_resource_t *pdfont;
710     gs_char char_code;
711     gs_glyph glyph;
712     gs_font *font;
713 } charproc_compatibility_data_t;
714 
715 static bool
is_char_code_used(pdf_font_resource_t * pdfont,gs_char char_code)716 is_char_code_used(pdf_font_resource_t *pdfont, gs_char char_code)
717 {
718     pdf_char_proc_ownership_t *pcpo;
719 
720     for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
721 	if (pcpo->char_code == char_code) {
722 	    return true;
723 	}
724     }
725     return false;
726 }
727 
728 static int
pdf_is_charproc_compatible(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1)729 pdf_is_charproc_compatible(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
730 {
731     charproc_compatibility_data_t *data = (charproc_compatibility_data_t *)pdev->find_resource_param;
732     pdf_char_proc_t *pcp0 = (pdf_char_proc_t *)pres0;
733     pdf_char_proc_t *pcp1 = (pdf_char_proc_t *)pres1;
734     pdf_font_resource_t *pdfont = data->pdfont;
735     pdf_char_proc_ownership_t *pcpo;
736     pdf_font_cache_elem_t **e;
737     bool can_add_to_current_font = false, computed_can_add_to_current_font = false;
738 
739     /* Does it have same attributes ? */
740     if (!pdf_is_same_charproc_attrs1(pdev, pcp0, pcp1))
741 	return 0;
742     /* Is it from same font ? */
743     for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
744 	if (pdfont == pcpo->font) {
745 	    /* Check for encoding conflict. */
746 	    if (pcpo->char_code == data->char_code && pcpo->glyph == data->glyph)
747 		return 1; /* Same char code. */
748 	    if (!computed_can_add_to_current_font) {
749 		can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
750 		computed_can_add_to_current_font = true;
751 	    }
752 	    if (can_add_to_current_font)
753 		return 1; /* No conflict. */
754 	}
755     }
756     /* Look for another font with same encoding,
757        because we want to reduce the number of new fonts.
758        We also restrict with ones attached to same PS font,
759        otherwise it creates too mixed fonts and disturbs word breaks.
760      */
761     e = pdf_locate_font_cache_elem(pdev, data->font);
762     if (e != NULL) {
763 	for (pcpo = pcp1->owner_fonts; pcpo != NULL; pcpo = pcpo->char_next) {
764 	    if (pcpo->char_code != data->char_code || pcpo->glyph != data->glyph)
765 		continue; /* Need same Encoding to generate a proper ToUnicode. */
766 	    if (pdfont->u.simple.s.type3.bitmap_font != pcpo->font->u.simple.s.type3.bitmap_font)
767 		continue;
768 	    if (memcmp(&pdfont->u.simple.s.type3.FontMatrix, &pcpo->font->u.simple.s.type3.FontMatrix,
769 			sizeof(pdfont->u.simple.s.type3.FontMatrix)))
770 		continue;
771 	    if (data->cgp != NULL) {
772 		if (!pdf_check_encoding_compatibility(pcpo->font, data->cgp->s, data->cgp->num_all_chars))
773 		    continue;
774 	    }
775 	    if ((*e)->pdfont != pcpo->font)
776 		continue;
777 	    data->pdfont = pcpo->font; /* Switch to the other font. */
778 	    return 1;
779 	}
780     }
781     /* Check whether it can be added into the current font. */
782     if (!computed_can_add_to_current_font)
783 	can_add_to_current_font = !is_char_code_used(pdfont, data->char_code);
784     if (!can_add_to_current_font) {
785 	/* Can't substitute due to encoding conflict. */
786 	return 0;
787     }
788     /* The current font will share it with another font. */
789     return 1;
790 }
791 
792 static int
pdf_find_same_charproc_aux(gx_device_pdf * pdev,pdf_font_resource_t ** ppdfont,pdf_char_proc_t ** ppcp)793 pdf_find_same_charproc_aux(gx_device_pdf *pdev,
794 	    pdf_font_resource_t **ppdfont, pdf_char_proc_t **ppcp)
795 {
796     pdf_char_proc_ownership_t *pcpo;
797     int code;
798 
799     /* fixme: this passes parameters to pdf_is_charproc_compatible
800        through special gx_device_pdf field pdev->find_resource_param
801        due to prototype limitation of pdf_find_same_resource.
802        It would be better to change the client data argument type in there to void. */
803     for (pcpo = (*ppdfont)->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
804 	pdf_char_proc_t *pcp = pcpo->char_proc;
805 
806 	if (*ppcp != pcp && pdf_is_same_charproc_attrs1(pdev, *ppcp, pcp)) {
807     	    cos_object_t *pco0 = pcp->object;
808     	    cos_object_t *pco1 = (*ppcp)->object;
809 
810 	    code = pco0->cos_procs->equal(pco0, pco1, pdev);
811 	    if (code < 0) {
812 		return code;
813 	    }
814 	    if (code) {
815 		*ppcp = pcp;
816 		return 1;
817 	    }
818 	}
819     }
820     return pdf_find_same_resource(pdev, resourceCharProc, (pdf_resource_t **)ppcp, pdf_is_charproc_compatible);
821 }
822 static int
pdf_find_same_charproc(gx_device_pdf * pdev,pdf_font_resource_t ** ppdfont,const pdf_char_glyph_pairs_t * cgp,pdf_char_proc_t ** ppcp,gs_glyph glyph,gs_char char_code,gs_font * font)823 pdf_find_same_charproc(gx_device_pdf *pdev,
824 	    pdf_font_resource_t **ppdfont, const pdf_char_glyph_pairs_t *cgp,
825 	    pdf_char_proc_t **ppcp, gs_glyph glyph, gs_char char_code,
826 	    gs_font *font)
827 {
828     charproc_compatibility_data_t data;
829     int code;
830 
831     data.cgp = cgp;
832     data.pdfont = *ppdfont;
833     data.char_code = char_code;
834     data.glyph = glyph;
835     data.font = font;
836     pdev->find_resource_param = &data;
837     code = pdf_find_same_charproc_aux(pdev, ppdfont, ppcp);
838     pdev->find_resource_param = NULL;
839     *ppdfont = data.pdfont;
840     return code;
841 }
842 
843 static bool
pdf_is_charproc_defined(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,gs_char ch)844 pdf_is_charproc_defined(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, gs_char ch)
845 {
846     pdf_char_proc_ownership_t *pcpo;
847 
848     for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
849 	if (pcpo->char_code == ch)
850 	    return true;
851     }
852     return false;
853 }
854 
855 static int
complete_adding_char(gx_device_pdf * pdev,gs_font * font,gs_glyph glyph,gs_char ch,pdf_char_proc_t * pcp,const gs_const_string * gnstr)856 complete_adding_char(gx_device_pdf *pdev, gs_font *font,
857 		     gs_glyph glyph, gs_char ch, pdf_char_proc_t *pcp,
858 		     const gs_const_string *gnstr)
859 {
860     pdf_font_resource_t *pdfont;
861     double *real_widths;
862     byte *glyph_usage;
863     int char_cache_size, width_cache_size;
864     pdf_encoding_element_t *pet;
865     int code;
866 
867     code = pdf_attached_font_resource(pdev, font, &pdfont,
868 		&glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
869     if (code < 0)
870 	return code;
871     code = pdf_attach_charproc(pdev, pdfont, pcp, glyph, ch, gnstr);
872     if (code < 0)
873 	return code;
874     if (ch >= char_cache_size || ch >= width_cache_size)
875 	return_error(gs_error_unregistered); /* Must not happen. */
876     pet = &pdfont->u.simple.Encoding[ch];
877     pdfont->Widths[ch] = pcp->real_width.x;
878     real_widths[ch * 2    ] = pcp->real_width.x;
879     real_widths[ch * 2 + 1] = pcp->real_width.y;
880     glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
881     pdfont->used[ch >> 3] |= 0x80 >> (ch & 7);
882     if (pdfont->u.simple.v != NULL && font->WMode) {
883 	pdfont->u.simple.v[ch].x = pcp->v.x;
884 	pdfont->u.simple.v[ch].y = pcp->v.x;
885     }
886     pet->glyph = glyph;
887     pet->str = *gnstr;
888     pet->is_difference = true;
889     if (pdfont->u.simple.LastChar < (int)ch)
890 	pdfont->u.simple.LastChar = (int)ch;
891     if (pdfont->u.simple.FirstChar > (int)ch)
892 	pdfont->u.simple.FirstChar = (int)ch;
893     return 0;
894 }
895 
896 static int
pdf_char_widths_from_charprocs(gx_device_pdf * pdev,gs_font * font)897 pdf_char_widths_from_charprocs(gx_device_pdf *pdev, gs_font *font)
898 {
899     pdf_font_resource_t *pdfont;
900     double *real_widths;
901     byte *glyph_usage;
902     int char_cache_size, width_cache_size;
903     pdf_char_proc_ownership_t *pcpo;
904     int code;
905 
906     code = pdf_attached_font_resource(pdev, font, &pdfont,
907 		&glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
908     if (code < 0)
909 	return code;
910     for (pcpo = pdfont->u.simple.s.type3.char_procs; pcpo != NULL; pcpo = pcpo->char_next) {
911 	pdf_char_proc_t *pcp = pcpo->char_proc;
912 	gs_char ch = pcpo->char_code;
913 
914 	real_widths[ch * 2    ] = pcp->real_width.x;
915 	real_widths[ch * 2 + 1] = pcp->real_width.y;
916 	glyph_usage[ch / 8] |= 0x80 >> (ch & 7);
917     }
918     return 0;
919 }
920 
921 
922 /*
923  * Complete charproc accumulation for a Type 3 font.
924  */
925 int
pdf_end_charproc_accum(gx_device_pdf * pdev,gs_font * font,const pdf_char_glyph_pairs_t * cgp,gs_glyph glyph,gs_char output_char_code,const gs_const_string * gnstr)926 pdf_end_charproc_accum(gx_device_pdf *pdev, gs_font *font, const pdf_char_glyph_pairs_t *cgp,
927 		       gs_glyph glyph, gs_char output_char_code, const gs_const_string *gnstr)
928 {
929     int code;
930     pdf_resource_t *pres = (pdf_resource_t *)pdev->accumulating_substream_resource;
931     /* We could use pdfont->u.simple.s.type3.char_procs insted the thing above
932        unless the font is defined recursively.
933        But we don't want such assumption. */
934     pdf_char_proc_t *pcp = (pdf_char_proc_t *)pres;
935     pdf_font_resource_t *pdfont;
936     gs_char ch = output_char_code;
937     bool checking_glyph_variation = false;
938 
939     if (ch == GS_NO_CHAR)
940 	return_error(gs_error_unregistered); /* Must not happen. */
941     if (ch >= 256)
942 	return_error(gs_error_unregistered); /* Must not happen. */
943     code = pdf_attached_font_resource(pdev, font, &pdfont, NULL, NULL, NULL, NULL);
944     if (code < 0)
945 	return code;
946     if (pdfont != (pdf_font_resource_t *)pdev->font3)
947 	return_error(gs_error_unregistered); /* Must not happen. */
948     code = pdf_exit_substream(pdev);
949     if (code < 0)
950 	return code;
951     if (!(pdfont->used[ch >> 3] & (0x80 >> (ch & 7))) ||
952 	!(pdfont->u.simple.s.type3.cached[ch >> 3] & (0x80 >> (ch & 7)))) {
953 	/* First appearence or not cached - check for duplicates. */
954 	pdf_font_resource_t *pdfont1 = pdfont;
955 
956 	checking_glyph_variation = true;
957 	/* CAUTION : a possible font change. */
958 	code = pdf_find_same_charproc(pdev, &pdfont, cgp, &pcp, glyph, ch, font);
959 	if (code < 0)
960 	    return code;
961 	if (code != 0) {
962 	    code = pdf_cancel_resource(pdev, pres, resourceCharProc);
963 	    if (code < 0)
964 		return code;
965 	    pdf_forget_resource(pdev, pres, resourceCharProc);
966 	    if (pdfont1 != pdfont) {
967 		code = pdf_attach_font_resource(pdev, font, pdfont);
968 		if (code < 0)
969 		    return code;
970 		code = pdf_char_widths_from_charprocs(pdev, font);
971 		if (code < 0)
972 		    return code;
973 	    }
974 	    pdev->charproc_just_accumulated = true;
975 	    return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
976 	}
977 	if (pdf_is_charproc_defined(pdev, pdfont, ch)) {
978 	    /* Encoding conflict after a font change. */
979 	    gs_font *base_font = font, *below;
980 
981 	    while ((below = base_font->base) != base_font &&
982 		    base_font->procs.same_font(base_font, below, FONT_SAME_OUTLINES))
983 		base_font = below;
984 	    code = pdf_make_font3_resource(pdev, base_font, &pdfont);
985 	    if (code < 0)
986 		return code;
987 	    code = pdf_attach_font_resource(pdev, font, pdfont);
988 	    if (code < 0)
989 		return code;
990 	}
991     }
992     pdf_reserve_object_id(pdev, pres, 0);
993     if (checking_glyph_variation)
994 	pdev->charproc_just_accumulated = true;
995     return complete_adding_char(pdev, font, glyph, ch, pcp, gnstr);
996 }
997 
998 /* Add procsets to substream Resources. */
999 int
pdf_add_procsets(cos_dict_t * pcd,pdf_procset_t procsets)1000 pdf_add_procsets(cos_dict_t *pcd, pdf_procset_t procsets)
1001 {
1002     char str[5 + 7 + 7 + 7 + 5 + 2];
1003     cos_value_t v;
1004 
1005     strcpy(str, "[/PDF");
1006     if (procsets & ImageB)
1007 	strcat(str, "/ImageB");
1008     if (procsets & ImageC)
1009 	strcat(str, "/ImageC");
1010     if (procsets & ImageI)
1011 	strcat(str, "/ImageI");
1012     if (procsets & Text)
1013 	strcat(str, "/Text");
1014     strcat(str, "]");
1015     cos_string_value(&v, (byte *)str, strlen(str));
1016     return cos_dict_put_c_key(pcd, "/ProcSet", &v);
1017 }
1018 
1019 /* Add a resource to substream Resources. */
1020 int
pdf_add_resource(gx_device_pdf * pdev,cos_dict_t * pcd,const char * key,pdf_resource_t * pres)1021 pdf_add_resource(gx_device_pdf *pdev, cos_dict_t *pcd, const char *key, pdf_resource_t *pres)
1022 {
1023     if (pcd != 0) {
1024 	const cos_value_t *v = cos_dict_find(pcd, (const byte *)key, strlen(key));
1025 	cos_dict_t *list;
1026 	int code;
1027 	char buf[10 + (sizeof(long) * 8 / 3 + 1)], buf1[sizeof(pres->rname) + 1];
1028 
1029 	if (pdev->ForOPDFRead && !pres->global && pdev->accumulating_a_global_object) {
1030 	    pres->global = true;
1031 	    code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
1032 	    if (code < 0)
1033 		return code;
1034 	}
1035 	sprintf(buf, "%ld 0 R\n", pres->object->id);
1036 	if (v != NULL) {
1037 	    if (v->value_type != COS_VALUE_OBJECT &&
1038 		v->value_type != COS_VALUE_RESOURCE)
1039 		return_error(gs_error_unregistered); /* Must not happen. */
1040 	    list = (cos_dict_t *)v->contents.object;
1041 	    if (list->cos_procs != &cos_dict_procs)
1042 		return_error(gs_error_unregistered); /* Must not happen. */
1043 	} else {
1044 	    list = cos_dict_alloc(pdev, "pdf_add_resource");
1045 	    if (list == NULL)
1046 		return_error(gs_error_VMerror);
1047 	    code = cos_dict_put_c_key_object((cos_dict_t *)pcd, key, (cos_object_t *)list);
1048 	    if (code < 0)
1049 		return code;
1050 	}
1051 	buf1[0] = '/';
1052 	strcpy(buf1 + 1, pres->rname);
1053 	return cos_dict_put_string(list, (const byte *)buf1, strlen(buf1),
1054 			(const byte *)buf, strlen(buf));
1055     }
1056     return 0;
1057 }
1058 
1059