xref: /plan9/sys/src/cmd/gs/src/gdevpdfu.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999, 2000, 2001 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpdfu.c,v 1.89 2005/10/18 09:05:58 leonardo Exp $ */
18 /* Output utilities for PDF-writing driver */
19 #include "memory_.h"
20 #include "jpeglib_.h"		/* for sdct.h */
21 #include "string_.h"
22 #include "gx.h"
23 #include "gserrors.h"
24 #include "gscdefs.h"
25 #include "gsdsrc.h"
26 #include "gsfunc.h"
27 #include "gsfunc3.h"
28 #include "gdevpdfx.h"
29 #include "gdevpdfo.h"
30 #include "gdevpdfg.h"
31 #include "gdevpdtd.h"
32 #include "scanchar.h"
33 #include "strimpl.h"
34 #include "sa85x.h"
35 #include "scfx.h"
36 #include "sdct.h"
37 #include "slzwx.h"
38 #include "spngpx.h"
39 #include "srlx.h"
40 #include "sarc4.h"
41 #include "smd5.h"
42 #include "sstring.h"
43 #include "szlibx.h"
44 
45 /* Define the size of internal stream buffers. */
46 /* (This is not a limitation, it only affects performance.) */
47 #define sbuf_size 512
48 
49 /* Optionally substitute other filters for FlateEncode for debugging. */
50 #if 1
51 #  define compression_filter_name "FlateDecode"
52 #  define compression_filter_template s_zlibE_template
53 #  define compression_filter_state stream_zlib_state
54 #else
55 #  define compression_filter_name "LZWDecode"
56 #  define compression_filter_template s_LZWE_template
57 #  define compression_filter_state stream_LZW_state
58 #endif
59 
60 /* Import procedures for writing filter parameters. */
61 extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
62 extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state);
63 
64 #define CHECK(expr)\
65   BEGIN if ((code = (expr)) < 0) return code; END
66 
67 /* GC descriptors */
68 extern_st(st_pdf_color_space);
69 extern_st(st_pdf_font_resource);
70 extern_st(st_pdf_char_proc);
71 extern_st(st_pdf_font_descriptor);
72 public_st_pdf_resource();
73 private_st_pdf_x_object();
74 private_st_pdf_pattern();
75 
76 /* ---------------- Utilities ---------------- */
77 
78 /*
79  * Strip whitespace and comments from a line of PostScript code as possible.
80  * Return a pointer to any string that remains, or NULL if none.
81  * Note that this may store into the string.
82  */
83 /* This function copied from geninit.c . */
84 private char *
doit(char * line,bool intact)85 doit(char *line, bool intact)
86 {
87     char *str = line;
88     char *from;
89     char *to;
90     int in_string = 0;
91 
92     if (intact)
93 	return str;
94     while (*str == ' ' || *str == '\t')		/* strip leading whitespace */
95 	++str;
96     if (*str == 0)		/* all whitespace */
97 	return NULL;
98     if (!strncmp(str, "%END", 4))	/* keep these for .skipeof */
99 	return str;
100     if (str[0] == '%')    /* comment line */
101 	return NULL;
102     /*
103      * Copy the string over itself removing:
104      *  - All comments not within string literals;
105      *  - Whitespace adjacent to '[' ']' '{' '}';
106      *  - Whitespace before '/' '(' '<';
107      *  - Whitespace after ')' '>'.
108      */
109     for (to = from = str; (*to = *from) != 0; ++from, ++to) {
110 	switch (*from) {
111 	    case '%':
112 		if (!in_string)
113 		    break;
114 		continue;
115 	    case ' ':
116 	    case '\t':
117 		if (to > str && !in_string && strchr(" \t>[]{})", to[-1]))
118 		    --to;
119 		continue;
120 	    case '(':
121 	    case '<':
122 	    case '/':
123 	    case '[':
124 	    case ']':
125 	    case '{':
126 	    case '}':
127 		if (to > str && !in_string && strchr(" \t", to[-1]))
128 		    *--to = *from;
129                 if (*from == '(')
130                     ++in_string;
131               	continue;
132 	    case ')':
133 		--in_string;
134 		continue;
135 	    case '\\':
136 		if (from[1] == '\\' || from[1] == '(' || from[1] == ')')
137 		    *++to = *++from;
138 		continue;
139 	    default:
140 		continue;
141 	}
142 	break;
143     }
144     /* Strip trailing whitespace. */
145     while (to > str && (to[-1] == ' ' || to[-1] == '\t'))
146 	--to;
147     *to = 0;
148     return str;
149 }
150 
151 
152 private int
copy_ps_file_stripping(stream * s,const char * fname,bool HaveTrueTypes)153 copy_ps_file_stripping(stream *s, const char *fname, bool HaveTrueTypes)
154 {
155     FILE *f;
156     char buf[1024], *p, *q  = buf;
157     int n, l = 0, m = sizeof(buf) - 1, outl = 0;
158     bool skipping = false;
159 
160     f = gp_fopen(fname, "rb");
161     if (f == NULL)
162 	return_error(gs_error_undefinedfilename);
163     n = fread(buf, 1, m, f);
164     buf[n] = 0;
165     do {
166 	if (*q == '\r' || *q == '\n') {
167 	    q++;
168 	    continue;
169 	}
170 	p = strchr(q, '\r');
171 	if (p == NULL)
172 	    p = strchr(q, '\n');
173 	if (p == NULL) {
174 	    if (n < m)
175 		p = buf + n;
176 	    else {
177 		strcpy(buf, q);
178 		l = strlen(buf);
179 		m = sizeof(buf) - 1 - l;
180 		if (!m) {
181 		    eprintf1("The procset %s contains a too long line.", fname);
182 		    return_error(gs_error_ioerror);
183 		}
184 		n = fread(buf + l, 1, m, f);
185 		n += l;
186 		m += l;
187 		buf[n] = 0;
188 		q = buf;
189 		continue;
190 	    }
191 	}
192 	*p = 0;
193 	if (q[0] == '%')
194 	    l = 0;
195 	else {
196 	    q = doit(q, false);
197 	    if (q == NULL)
198 		l = 0;
199 	    else
200 		l = strlen(q);
201 	}
202 	if (l) {
203 	    if (!HaveTrueTypes && !strcmp("%%beg TrueType", q))
204 		skipping = true;
205 	    if (!skipping) {
206 		outl += l + 1;
207 		if (outl > 100) {
208 		    q[l] = '\r';
209 		    outl = 0;
210 		} else
211 		    q[l] = ' ';
212 		stream_write(s, q, l + 1);
213 	    }
214 	    if (!HaveTrueTypes && !strcmp("%%end TrueType", q))
215 		skipping = false;
216 	}
217 	q = p + 1;
218     } while (n == m || q < buf + n);
219     if (outl)
220 	stream_write(s, "\r", 1);
221     fclose(f);
222     return 0;
223 }
224 
225 private int
copy_procsets(stream * s,const gs_param_string * path,bool HaveTrueTypes)226 copy_procsets(stream *s, const gs_param_string *path, bool HaveTrueTypes)
227 {
228     char fname[gp_file_name_sizeof];
229     const byte *p = path->data, *e = path->data + path->size;
230     int l, i = 0, code;
231     const char *tt_encs[] = {"gs_agl.ps", "gs_mgl_e.ps"};
232 
233     if (p != NULL) {
234 	for (;; i++) {
235 	    const byte *c = memchr(p, gp_file_name_list_separator, e - p);
236 	    int k;
237 
238 	    if (c == NULL)
239 		c = e;
240 	    l = c - p;
241 	    if (l > 0) {
242 		if (l > sizeof(fname) - 1)
243 		    return_error(gs_error_limitcheck);
244 		memcpy(fname, p, l);
245 		fname[l] = 0;
246 		if (!HaveTrueTypes) {
247 		    for (k = count_of(tt_encs) - 1; k >= 0; k--) {
248 			int L = strlen(tt_encs[k]);
249 
250 			if (!strcmp(fname + strlen(fname) - L, tt_encs[k]))
251 			    break;
252 		    }
253 		}
254 		if (HaveTrueTypes || k < 0) {
255 		    code = copy_ps_file_stripping(s, fname, HaveTrueTypes);
256 		    if (code < 0)
257 			return code;
258 		}
259 	    }
260 	    if (c == e)
261 		break;
262 	    p = c + 1;
263 	}
264     }
265     if (!i)
266 	return_error(gs_error_undefinedfilename);
267     return 0;
268 }
269 
270 private int
encode(stream ** s,const stream_template * t,gs_memory_t * mem)271 encode(stream **s, const stream_template *t, gs_memory_t *mem)
272 {
273     stream_state *st = s_alloc_state(mem, t->stype, "pdf_open_document.encode");
274 
275     if (st == 0)
276 	return_error(gs_error_VMerror);
277     if (t->set_defaults)
278 	t->set_defaults(st);
279     if (s_add_filter(s, t, st, mem) == 0) {
280 	gs_free_object(mem, st, "pdf_open_document.encode");
281 	return_error(gs_error_VMerror);
282     }
283     return 0;
284 }
285 
286 /* ------ Document ------ */
287 
288 /* Open the document if necessary. */
289 int
pdf_open_document(gx_device_pdf * pdev)290 pdf_open_document(gx_device_pdf * pdev)
291 {
292     if (!is_in_page(pdev) && pdf_stell(pdev) == 0) {
293 	stream *s = pdev->strm;
294 	int level = (int)(pdev->CompatibilityLevel * 10 + 0.5);
295 
296 	pdev->binary_ok = !pdev->params.ASCII85EncodePages;
297 	if (pdev->ForOPDFRead && pdev->OPDFReadProcsetPath.size) {
298 	    int code, status;
299 
300 	    stream_write(s, (byte *)"%!PS-Adobe-2.0\r", 15);
301 	    if (pdev->params.CompressPages || pdev->CompressEntireFile) {
302 		/*  When CompressEntireFile is true and ASCII85EncodePages is false,
303 		    the ASCII85Encode filter is applied, rather one may expect the opposite.
304 		    Keeping it so due to no demand for this mode.
305 		    A right implementation should compute the length of the compressed procset,
306 		    write out an invocation of SubFileDecode filter, and write the length to
307 		    there assuming the output file is positionable. */
308 		stream_write(s, (byte *)"currentfile /ASCII85Decode filter /LZWDecode filter cvx exec\r", 61);
309 		code = encode(&s, &s_A85E_template, pdev->pdf_memory);
310 		if (code < 0)
311 		    return code;
312 		code = encode(&s, &s_LZWE_template, pdev->pdf_memory);
313 		if (code < 0)
314 		    return code;
315 	    }
316 	    code = copy_procsets(s, &pdev->OPDFReadProcsetPath, pdev->HaveTrueTypes);
317 	    if (code < 0)
318 		return code;
319 	    if (!pdev->CompressEntireFile) {
320 		status = s_close_filters(&s, pdev->strm);
321 		if (status < 0)
322 		    return_error(gs_error_ioerror);
323 	    } else
324 		pdev->strm = s;
325 	}
326 	pprintd2(s, "%%PDF-%d.%d\n", level / 10, level % 10);
327 	pdev->binary_ok = !pdev->params.ASCII85EncodePages;
328 	if (pdev->binary_ok)
329 	    stream_puts(s, "%\307\354\217\242\n");
330     }
331     /*
332      * Determine the compression method.  Currently this does nothing.
333      * It also isn't clear whether the compression method can now be
334      * changed in the course of the document.
335      *
336      * Flate compression is available starting in PDF 1.2.  Since we no
337      * longer support any older PDF versions, we ignore UseFlateCompression
338      * and always use Flate compression.
339      */
340     if (!pdev->params.CompressPages)
341 	pdev->compression = pdf_compress_none;
342     else
343 	pdev->compression = pdf_compress_Flate;
344     return 0;
345 }
346 
347 /* ------ Objects ------ */
348 
349 /* Allocate an object ID. */
350 private long
pdf_next_id(gx_device_pdf * pdev)351 pdf_next_id(gx_device_pdf * pdev)
352 {
353     return (pdev->next_id)++;
354 }
355 
356 /*
357  * Return the current position in the output.  Note that this may be in the
358  * main output file, the asides file, or the pictures file.  If the current
359  * file is the pictures file, positions returned by pdf_stell must only be
360  * used locally (for computing lengths or patching), since there is no way
361  * to map them later to the eventual position in the output file.
362  */
363 long
pdf_stell(gx_device_pdf * pdev)364 pdf_stell(gx_device_pdf * pdev)
365 {
366     stream *s = pdev->strm;
367     long pos = stell(s);
368 
369     if (s == pdev->asides.strm)
370 	pos += ASIDES_BASE_POSITION;
371     return pos;
372 }
373 
374 /* Allocate an ID for a future object. */
375 long
pdf_obj_ref(gx_device_pdf * pdev)376 pdf_obj_ref(gx_device_pdf * pdev)
377 {
378     long id = pdf_next_id(pdev);
379     long pos = pdf_stell(pdev);
380 
381     fwrite(&pos, sizeof(pos), 1, pdev->xref.file);
382     return id;
383 }
384 
385 /* Begin an object, optionally allocating an ID. */
386 long
pdf_open_obj(gx_device_pdf * pdev,long id)387 pdf_open_obj(gx_device_pdf * pdev, long id)
388 {
389     stream *s = pdev->strm;
390 
391     if (id <= 0) {
392 	id = pdf_obj_ref(pdev);
393     } else {
394 	long pos = pdf_stell(pdev);
395 	FILE *tfile = pdev->xref.file;
396 	long tpos = ftell(tfile);
397 
398 	fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
399 	      SEEK_SET);
400 	fwrite(&pos, sizeof(pos), 1, tfile);
401 	fseek(tfile, tpos, SEEK_SET);
402     }
403     pprintld1(s, "%ld 0 obj\n", id);
404     return id;
405 }
406 long
pdf_begin_obj(gx_device_pdf * pdev)407 pdf_begin_obj(gx_device_pdf * pdev)
408 {
409     return pdf_open_obj(pdev, 0L);
410 }
411 
412 /* End an object. */
413 int
pdf_end_obj(gx_device_pdf * pdev)414 pdf_end_obj(gx_device_pdf * pdev)
415 {
416     stream_puts(pdev->strm, "endobj\n");
417     return 0;
418 }
419 
420 /* ------ Page contents ------ */
421 
422 /* Handle transitions between contexts. */
423 private int
424     none_to_stream(gx_device_pdf *), stream_to_text(gx_device_pdf *),
425     string_to_text(gx_device_pdf *), text_to_stream(gx_device_pdf *),
426     stream_to_none(gx_device_pdf *);
427 typedef int (*context_proc) (gx_device_pdf *);
428 private const context_proc context_procs[4][4] =
429 {
430     {0, none_to_stream, none_to_stream, none_to_stream},
431     {stream_to_none, 0, stream_to_text, stream_to_text},
432     {text_to_stream, text_to_stream, 0, 0},
433     {string_to_text, string_to_text, string_to_text, 0}
434 };
435 
436 /* Compute an object encryption key. */
437 private int
pdf_object_key(const gx_device_pdf * pdev,gs_id object_id,byte key[16])438 pdf_object_key(const gx_device_pdf * pdev, gs_id object_id, byte key[16])
439 {
440     md5_state_t md5;
441     md5_byte_t zero[2] = {0, 0}, t;
442     int KeySize = pdev->KeyLength / 8;
443 
444     md5_init(&md5);
445     md5_append(&md5, pdev->EncryptionKey, KeySize);
446     t = (byte)(object_id >>  0);  md5_append(&md5, &t, 1);
447     t = (byte)(object_id >>  8);  md5_append(&md5, &t, 1);
448     t = (byte)(object_id >> 16);  md5_append(&md5, &t, 1);
449     md5_append(&md5, zero, 2);
450     md5_finish(&md5, key);
451     return min(KeySize + 5, 16);
452 }
453 
454 /* Initialize encryption. */
455 int
pdf_encrypt_init(const gx_device_pdf * pdev,gs_id object_id,stream_arcfour_state * psarc4)456 pdf_encrypt_init(const gx_device_pdf * pdev, gs_id object_id, stream_arcfour_state *psarc4)
457 {
458     byte key[16];
459 
460     return s_arcfour_set_key(psarc4, key, pdf_object_key(pdev, object_id, key));
461 }
462 
463 
464 /* Add the encryption filter. */
465 int
pdf_begin_encrypt(gx_device_pdf * pdev,stream ** s,gs_id object_id)466 pdf_begin_encrypt(gx_device_pdf * pdev, stream **s, gs_id object_id)
467 {
468     gs_memory_t *mem = pdev->v_memory;
469     stream_arcfour_state *ss;
470     md5_byte_t key[16];
471     int code, keylength;
472 
473     if (!pdev->KeyLength)
474 	return 0;
475     keylength = pdf_object_key(pdev, object_id, key);
476     ss = gs_alloc_struct(mem, stream_arcfour_state,
477 		    s_arcfour_template.stype, "psdf_encrypt");
478     if (ss == NULL)
479 	return_error(gs_error_VMerror);
480     code = s_arcfour_set_key(ss, key, keylength);
481     if (code < 0)
482 	return code;
483     if (s_add_filter(s, &s_arcfour_template, (stream_state *)ss, mem) == 0)
484 	return_error(gs_error_VMerror);
485     return 0;
486     /* IMPORTANT NOTE :
487        We don't encrypt streams written into temporary files,
488        because they can be used for comparizon
489        (for example, for merging equal images).
490        Instead that the encryption is applied in pdf_copy_data,
491        when the stream is copied to the output file.
492      */
493 }
494 
495 /* Remove the encryption filter. */
496 void
pdf_end_encrypt(gx_device_pdf * pdev)497 pdf_end_encrypt(gx_device_pdf * pdev)
498 {
499     if (pdev->KeyLength) {
500 	stream *s = pdev->strm;
501 	stream *fs = s->strm;
502 
503 	sclose(s);
504 	gs_free_object(pdev->pdf_memory, s->cbuf, "encrypt buffer");
505 	gs_free_object(pdev->pdf_memory, s, "encrypt stream");
506 	pdev->strm = fs;
507     }
508 }
509 
510 /* Enter stream context. */
511 private int
none_to_stream(gx_device_pdf * pdev)512 none_to_stream(gx_device_pdf * pdev)
513 {
514     stream *s;
515     int code;
516 
517     if (pdev->contents_id != 0)
518 	return_error(gs_error_Fatal);	/* only 1 contents per page */
519     pdev->compression_at_page_start = pdev->compression;
520     if (pdev->ResourcesBeforeUsage) {
521 	pdf_resource_t *pres;
522 
523 	code = pdf_enter_substream(pdev, resourcePage, gs_no_id, &pres,
524 		    true, pdev->params.CompressPages);
525 	if (code < 0)
526 	    return code;
527 	pdev->contents_id = pres->object->id;
528 	pdev->contents_length_id = gs_no_id; /* inapplicable */
529 	pdev->contents_pos = -1; /* inapplicable */
530 	s = pdev->strm;
531     } else {
532     	pdev->contents_id = pdf_begin_obj(pdev);
533 	pdev->contents_length_id = pdf_obj_ref(pdev);
534 	s = pdev->strm;
535 	pprintld1(s, "<</Length %ld 0 R", pdev->contents_length_id);
536 	if (pdev->compression == pdf_compress_Flate)
537 	    pprints1(s, "/Filter /%s", compression_filter_name);
538 	stream_puts(s, ">>\nstream\n");
539 	pdev->contents_pos = pdf_stell(pdev);
540 	code = pdf_begin_encrypt(pdev, &s, pdev->contents_id);
541 	if (code < 0)
542 	    return code;
543 	pdev->strm = s;
544 	if (pdev->compression == pdf_compress_Flate) {	/* Set up the Flate filter. */
545 	    const stream_template *template = &compression_filter_template;
546 	    stream *es = s_alloc(pdev->pdf_memory, "PDF compression stream");
547 	    byte *buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
548 				       "PDF compression buffer");
549 	    compression_filter_state *st =
550 		gs_alloc_struct(pdev->pdf_memory, compression_filter_state,
551 				template->stype, "PDF compression state");
552 
553 	    if (es == 0 || st == 0 || buf == 0)
554 		return_error(gs_error_VMerror);
555 	    s_std_init(es, buf, sbuf_size, &s_filter_write_procs,
556 		       s_mode_write);
557 	    st->memory = pdev->pdf_memory;
558 	    st->template = template;
559 	    es->state = (stream_state *) st;
560 	    es->procs.process = template->process;
561 	    es->strm = s;
562 	    (*template->set_defaults) ((stream_state *) st);
563 	    (*template->init) ((stream_state *) st);
564 	    pdev->strm = s = es;
565 	}
566     }
567     /*
568      * Scale the coordinate system.  Use an extra level of q/Q for the
569      * sake of poorly designed PDF tools that assume that the contents
570      * stream restores the CTM.
571      */
572     pprintg2(s, "q %g 0 0 %g 0 0 cm\n",
573 	     72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
574     if (pdev->CompatibilityLevel >= 1.3) {
575 	/* Set the default rendering intent. */
576 	if (pdev->params.DefaultRenderingIntent != ri_Default) {
577 	    static const char *const ri_names[] = { psdf_ri_names };
578 
579 	    pprints1(s, "/%s ri\n",
580 		     ri_names[(int)pdev->params.DefaultRenderingIntent]);
581 	}
582     }
583     pdev->AR4_save_bug = false;
584     return PDF_IN_STREAM;
585 }
586 /* Enter text context from stream context. */
587 private int
stream_to_text(gx_device_pdf * pdev)588 stream_to_text(gx_device_pdf * pdev)
589 {
590     int code;
591 
592     /*
593      * Bizarrely enough, Acrobat Reader cares how the final font size is
594      * obtained -- the CTM (cm), text matrix (Tm), and font size (Tf)
595      * are *not* all equivalent.  In particular, it seems to use the
596      * product of the text matrix and font size to decide how to
597      * anti-alias characters.  Therefore, we have to temporarily patch
598      * the CTM so that the scale factors are unity.  What a nuisance!
599      */
600     code = pdf_save_viewer_state(pdev, pdev->strm);
601     if (code < 0)
602 	return 0;
603     pprintg2(pdev->strm, "%g 0 0 %g 0 0 cm BT\n",
604 	     pdev->HWResolution[0] / 72.0, pdev->HWResolution[1] / 72.0);
605     pdev->procsets |= Text;
606     code = pdf_from_stream_to_text(pdev);
607     return (code < 0 ? code : PDF_IN_TEXT);
608 }
609 /* Exit string context to text context. */
610 private int
string_to_text(gx_device_pdf * pdev)611 string_to_text(gx_device_pdf * pdev)
612 {
613     int code = pdf_from_string_to_text(pdev);
614 
615     return (code < 0 ? code : PDF_IN_TEXT);
616 }
617 /* Exit text context to stream context. */
618 private int
text_to_stream(gx_device_pdf * pdev)619 text_to_stream(gx_device_pdf * pdev)
620 {
621     int code;
622 
623     stream_puts(pdev->strm, "ET\n");
624     code = pdf_restore_viewer_state(pdev, pdev->strm);
625     if (code < 0)
626 	return code;
627     pdf_reset_text(pdev);	/* because of Q */
628     return PDF_IN_STREAM;
629 }
630 /* Exit stream context. */
631 private int
stream_to_none(gx_device_pdf * pdev)632 stream_to_none(gx_device_pdf * pdev)
633 {
634     stream *s = pdev->strm;
635     long length;
636 
637     if (pdev->ResourcesBeforeUsage) {
638 	int code = pdf_exit_substream(pdev);
639 
640 	if (code < 0)
641 	    return code;
642     } else {
643 	if (pdev->vgstack_depth)
644 	    pdf_restore_viewer_state(pdev, s);
645 	if (pdev->compression_at_page_start == pdf_compress_Flate) {	/* Terminate the Flate filter. */
646 	    stream *fs = s->strm;
647 
648 	    sclose(s);
649 	    gs_free_object(pdev->pdf_memory, s->cbuf, "zlib buffer");
650 	    gs_free_object(pdev->pdf_memory, s, "zlib stream");
651 	    pdev->strm = s = fs;
652 	}
653 	pdf_end_encrypt(pdev);
654     	s = pdev->strm;
655 	length = pdf_stell(pdev) - pdev->contents_pos;
656 	stream_puts(s, "endstream\n");
657 	pdf_end_obj(pdev);
658 	pdf_open_obj(pdev, pdev->contents_length_id);
659 	pprintld1(s, "%ld\n", length);
660 	pdf_end_obj(pdev);
661     }
662     return PDF_IN_NONE;
663 }
664 
665 /* Begin a page contents part. */
666 int
pdf_open_contents(gx_device_pdf * pdev,pdf_context_t context)667 pdf_open_contents(gx_device_pdf * pdev, pdf_context_t context)
668 {
669     int (*proc) (gx_device_pdf *);
670 
671     while ((proc = context_procs[pdev->context][context]) != 0) {
672 	int code = (*proc) (pdev);
673 
674 	if (code < 0)
675 	    return code;
676 	pdev->context = (pdf_context_t) code;
677     }
678     pdev->context = context;
679     return 0;
680 }
681 
682 /* Close the current contents part if we are in one. */
683 int
pdf_close_contents(gx_device_pdf * pdev,bool last)684 pdf_close_contents(gx_device_pdf * pdev, bool last)
685 {
686     if (pdev->context == PDF_IN_NONE)
687 	return 0;
688     if (last) {			/* Exit from the clipping path gsave. */
689 	int code = pdf_open_contents(pdev, PDF_IN_STREAM);
690 
691 	if (code < 0)
692 	    return code;
693 	stream_puts(pdev->strm, "Q\n");	/* See none_to_stream. */
694 	pdf_close_text_contents(pdev);
695     }
696     return pdf_open_contents(pdev, PDF_IN_NONE);
697 }
698 
699 /* ------ Resources et al ------ */
700 
701 /* Define the allocator descriptors for the resource types. */
702 const char *const pdf_resource_type_names[] = {
703     PDF_RESOURCE_TYPE_NAMES
704 };
705 const gs_memory_struct_type_t *const pdf_resource_type_structs[] = {
706     PDF_RESOURCE_TYPE_STRUCTS
707 };
708 
709 /* Cancel a resource (do not write it into PDF). */
710 int
pdf_cancel_resource(gx_device_pdf * pdev,pdf_resource_t * pres,pdf_resource_type_t rtype)711 pdf_cancel_resource(gx_device_pdf * pdev, pdf_resource_t *pres, pdf_resource_type_t rtype)
712 {
713     /* fixme : remove *pres from resource chain. */
714     pres->where_used = 0;
715     pres->object->written = true;
716     if (rtype == resourceXObject || rtype == resourceCharProc || rtype == resourceOther
717 	) {
718 	int code = cos_stream_release_pieces((cos_stream_t *)pres->object);
719 
720 	if (code < 0)
721 	    return code;
722     }
723     cos_release(pres->object, "pdf_cancel_resource");
724     return 0;
725 }
726 
727 /* Remove a resource. */
728 void
pdf_forget_resource(gx_device_pdf * pdev,pdf_resource_t * pres1,pdf_resource_type_t rtype)729 pdf_forget_resource(gx_device_pdf * pdev, pdf_resource_t *pres1, pdf_resource_type_t rtype)
730 {   /* fixme : optimize. */
731     pdf_resource_t **pchain = pdev->resources[rtype].chains;
732     pdf_resource_t *pres;
733     pdf_resource_t **pprev = &pdev->last_resource;
734     int i;
735 
736     for (; (pres = *pprev) != 0; pprev = &pres->prev)
737 	if (pres == pres1) {
738 	    *pprev = pres->prev;
739 	    break;
740 	}
741     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
742 	pprev = pchain + i;
743 	for (; (pres = *pprev) != 0; pprev = &pres->next)
744 	    if (pres == pres1) {
745 		*pprev = pres->next;
746 		COS_RELEASE(pres->object, "pdf_forget_resource");
747 		gs_free_object(pdev->pdf_memory, pres->object, "pdf_forget_resource");
748 		gs_free_object(pdev->pdf_memory, pres, "pdf_forget_resource");
749 		break;
750 	    }
751     }
752 }
753 
754 private int
nocheck(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1)755 nocheck(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
756 {
757     return 1;
758 }
759 
760 
761 /* Substitute a resource with a same one. */
762 int
pdf_substitute_resource(gx_device_pdf * pdev,pdf_resource_t ** ppres,pdf_resource_type_t rtype,int (* eq)(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1),bool write)763 pdf_substitute_resource(gx_device_pdf *pdev, pdf_resource_t **ppres,
764 	pdf_resource_type_t rtype,
765 	int (*eq)(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1),
766 	bool write)
767 {
768     pdf_resource_t *pres1 = *ppres;
769     int code;
770 
771     code = pdf_find_same_resource(pdev, rtype, ppres, (eq ? eq : nocheck));
772     if (code < 0)
773 	return code;
774     if (code != 0) {
775 	code = pdf_cancel_resource(pdev, (pdf_resource_t *)pres1, rtype);
776 	if (code < 0)
777 	    return code;
778 	pdf_forget_resource(pdev, pres1, rtype);
779 	return 0;
780     } else {
781 	pdf_reserve_object_id(pdev, pres1, gs_no_id);
782 	if (write) {
783 	    code = cos_write_object(pres1->object, pdev);
784 	    if (code < 0)
785 		return code;
786 	    pres1->object->written = 1;
787 	}
788 	return 1;
789     }
790 }
791 
792 /* Find a resource of a given type by gs_id. */
793 pdf_resource_t *
pdf_find_resource_by_gs_id(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid)794 pdf_find_resource_by_gs_id(gx_device_pdf * pdev, pdf_resource_type_t rtype,
795 			   gs_id rid)
796 {
797     pdf_resource_t **pchain = PDF_RESOURCE_CHAIN(pdev, rtype, rid);
798     pdf_resource_t **pprev = pchain;
799     pdf_resource_t *pres;
800 
801     for (; (pres = *pprev) != 0; pprev = &pres->next)
802 	if (pres->rid == rid) {
803 	    if (pprev != pchain) {
804 		*pprev = pres->next;
805 		pres->next = *pchain;
806 		*pchain = pres;
807 	    }
808 	    return pres;
809 	}
810     return 0;
811 }
812 
813 /* Find resource by resource id. */
814 pdf_resource_t *
pdf_find_resource_by_resource_id(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id id)815 pdf_find_resource_by_resource_id(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id id)
816 {
817     pdf_resource_t **pchain = pdev->resources[rtype].chains;
818     pdf_resource_t *pres;
819     int i;
820 
821     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
822 	for (pres = pchain[i]; pres != 0; pres = pres->next) {
823 	    if (pres->object->id == id)
824 		return pres;
825 	}
826     }
827     return 0;
828 }
829 
830 
831 /* Find same resource. */
832 int
pdf_find_same_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,pdf_resource_t ** ppres,int (* eq)(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1))833 pdf_find_same_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, pdf_resource_t **ppres,
834 	int (*eq)(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1))
835 {
836     pdf_resource_t **pchain = pdev->resources[rtype].chains;
837     pdf_resource_t *pres;
838     cos_object_t *pco0 = (*ppres)->object;
839     int i;
840 
841     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
842 	for (pres = pchain[i]; pres != 0; pres = pres->next) {
843 	    if (!pres->named && *ppres != pres) {
844 		cos_object_t *pco1 = pres->object;
845 		int code = pco0->cos_procs->equal(pco0, pco1, pdev);
846 
847 		if (code < 0)
848 		    return code;
849 		if (code > 0) {
850 		    code = eq(pdev, *ppres, pres);
851 		    if (code < 0)
852 			return code;
853 		    if (code > 0) {
854 			*ppres = pres;
855 			return 1;
856 		    }
857 		}
858 	    }
859 	}
860     }
861     return 0;
862 }
863 
864 /* Drop resources by a condition. */
865 void
pdf_drop_resources(gx_device_pdf * pdev,pdf_resource_type_t rtype,int (* cond)(gx_device_pdf * pdev,pdf_resource_t * pres))866 pdf_drop_resources(gx_device_pdf * pdev, pdf_resource_type_t rtype,
867 	int (*cond)(gx_device_pdf * pdev, pdf_resource_t *pres))
868 {
869     pdf_resource_t **pchain = pdev->resources[rtype].chains;
870     pdf_resource_t **pprev;
871     pdf_resource_t *pres;
872     int i;
873 
874     for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
875 	pprev = pchain + i;
876 	for (; (pres = *pprev) != 0; ) {
877 	    if (cond(pdev, pres)) {
878 		*pprev = pres->next;
879 		pres->next = pres; /* A temporary mark - see below */
880 	    } else
881 		pprev = &pres->next;
882 	}
883     }
884     pprev = &pdev->last_resource;
885     for (; (pres = *pprev) != 0; )
886 	if (pres->next == pres) {
887 	    *pprev = pres->prev;
888 	    COS_RELEASE(pres->object, "pdf_drop_resources");
889 	    gs_free_object(pdev->pdf_memory, pres->object, "pdf_drop_resources");
890 	    gs_free_object(pdev->pdf_memory, pres, "pdf_drop_resources");
891 	} else
892 	    pprev = &pres->prev;
893 }
894 
895 /* Print resource statistics. */
896 void
pdf_print_resource_statistics(gx_device_pdf * pdev)897 pdf_print_resource_statistics(gx_device_pdf * pdev)
898 {
899 
900     int rtype;
901 
902     for (rtype = 0; rtype < NUM_RESOURCE_TYPES; rtype++) {
903 	pdf_resource_t **pchain = pdev->resources[rtype].chains;
904 	pdf_resource_t *pres;
905 	const char *name = pdf_resource_type_names[rtype];
906 	int i, n = 0;
907 
908 	for (i = 0; i < NUM_RESOURCE_CHAINS; i++) {
909 	    for (pres = pchain[i]; pres != 0; pres = pres->next, n++);
910 	}
911 	dprintf3("Resource type %d (%s) has %d instances.\n", rtype,
912 		(name ? name : ""), n);
913     }
914 }
915 
916 
917 /* Begin an object logically separate from the contents. */
918 long
pdf_open_separate(gx_device_pdf * pdev,long id)919 pdf_open_separate(gx_device_pdf * pdev, long id)
920 {
921     pdf_open_document(pdev);
922     pdev->asides.save_strm = pdev->strm;
923     pdev->strm = pdev->asides.strm;
924     return pdf_open_obj(pdev, id);
925 }
926 long
pdf_begin_separate(gx_device_pdf * pdev)927 pdf_begin_separate(gx_device_pdf * pdev)
928 {
929     return pdf_open_separate(pdev, 0L);
930 }
931 
932 void
pdf_reserve_object_id(gx_device_pdf * pdev,pdf_resource_t * pres,long id)933 pdf_reserve_object_id(gx_device_pdf * pdev, pdf_resource_t *pres, long id)
934 {
935     pres->object->id = (id == 0 ? pdf_obj_ref(pdev) : id);
936     sprintf(pres->rname, "R%ld", pres->object->id);
937 }
938 
939 /* Begin an aside (resource, annotation, ...). */
940 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)941 pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
942 		const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
943 		long id)
944 {
945     pdf_resource_t *pres;
946     cos_object_t *object;
947 
948     if (pst == NULL)
949 	pst = &st_pdf_resource;
950     pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
951 			   "pdf_alloc_aside(resource)");
952     if (pres == 0)
953 	return_error(gs_error_VMerror);
954     object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
955     if (object == 0)
956 	return_error(gs_error_VMerror);
957     memset(pres + 1, 0, pst->ssize - sizeof(*pres));
958     pres->object = object;
959     if (id < 0) {
960 	object->id = -1L;
961 	pres->rname[0] = 0;
962     } else
963 	pdf_reserve_object_id(pdev, pres, id);
964     pres->next = *plist;
965     *plist = pres;
966     pres->prev = pdev->last_resource;
967     pdev->last_resource = pres;
968     pres->named = false;
969     pres->global = false;
970     pres->where_used = pdev->used_mask;
971     *ppres = pres;
972     return 0;
973 }
974 int
pdf_begin_aside(gx_device_pdf * pdev,pdf_resource_t ** plist,const gs_memory_struct_type_t * pst,pdf_resource_t ** ppres)975 pdf_begin_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
976 		const gs_memory_struct_type_t * pst, pdf_resource_t ** ppres)
977 {
978     long id = pdf_begin_separate(pdev);
979 
980     if (id < 0)
981 	return (int)id;
982     return pdf_alloc_aside(pdev, plist, pst, ppres, id);
983 }
984 
985 /* Begin a resource of a given type. */
986 int
pdf_begin_resource_body(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)987 pdf_begin_resource_body(gx_device_pdf * pdev, pdf_resource_type_t rtype,
988 			gs_id rid, pdf_resource_t ** ppres)
989 {
990     int code = pdf_begin_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
991 			       pdf_resource_type_structs[rtype], ppres);
992 
993     if (code >= 0)
994 	(*ppres)->rid = rid;
995     return code;
996 }
997 int
pdf_begin_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)998 pdf_begin_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
999 		   pdf_resource_t ** ppres)
1000 {
1001     int code = pdf_begin_resource_body(pdev, rtype, rid, ppres);
1002 
1003     if (code >= 0 && pdf_resource_type_names[rtype] != 0) {
1004 	stream *s = pdev->strm;
1005 
1006 	pprints1(s, "<</Type%s", pdf_resource_type_names[rtype]);
1007 	pprintld1(s, "/Name/R%ld", (*ppres)->object->id);
1008     }
1009     return code;
1010 }
1011 
1012 /* Allocate a resource, but don't open the stream. */
1013 int
pdf_alloc_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres,long id)1014 pdf_alloc_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
1015 		   pdf_resource_t ** ppres, long id)
1016 {
1017     int code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
1018 			       pdf_resource_type_structs[rtype], ppres, id);
1019 
1020     if (code >= 0)
1021 	(*ppres)->rid = rid;
1022     return code;
1023 }
1024 
1025 /* Get the object id of a resource. */
1026 long
pdf_resource_id(const pdf_resource_t * pres)1027 pdf_resource_id(const pdf_resource_t *pres)
1028 {
1029     return pres->object->id;
1030 }
1031 
1032 /* End an aside or other separate object. */
1033 int
pdf_end_separate(gx_device_pdf * pdev)1034 pdf_end_separate(gx_device_pdf * pdev)
1035 {
1036     int code = pdf_end_obj(pdev);
1037 
1038     pdev->strm = pdev->asides.save_strm;
1039     pdev->asides.save_strm = 0;
1040     return code;
1041 }
1042 int
pdf_end_aside(gx_device_pdf * pdev)1043 pdf_end_aside(gx_device_pdf * pdev)
1044 {
1045     return pdf_end_separate(pdev);
1046 }
1047 
1048 /* End a resource. */
1049 int
pdf_end_resource(gx_device_pdf * pdev)1050 pdf_end_resource(gx_device_pdf * pdev)
1051 {
1052     return pdf_end_aside(pdev);
1053 }
1054 
1055 /*
1056  * Write the Cos objects for resources local to a content stream.  Formerly,
1057  * this procedure also freed such objects, but this doesn't work, because
1058  * resources of one type might refer to resources of another type.
1059  */
1060 int
pdf_write_resource_objects(gx_device_pdf * pdev,pdf_resource_type_t rtype)1061 pdf_write_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype)
1062 {
1063     int j, code = 0;
1064 
1065     for (j = 0; j < NUM_RESOURCE_CHAINS && code >= 0; ++j) {
1066 	pdf_resource_t *pres = pdev->resources[rtype].chains[j];
1067 
1068 	for (; pres != 0; pres = pres->next)
1069 	    if ((!pres->named || pdev->ForOPDFRead)
1070 		&& !pres->object->written)
1071 		code = cos_write_object(pres->object, pdev);
1072 
1073     }
1074     return code;
1075 }
1076 
1077 /*
1078  * Reverse resource chains.
1079  * ps2write uses it with page resources.
1080  * Assuming only the 0th chain contauns something.
1081  */
1082 void
pdf_reverse_resource_chain(gx_device_pdf * pdev,pdf_resource_type_t rtype)1083 pdf_reverse_resource_chain(gx_device_pdf *pdev, pdf_resource_type_t rtype)
1084 {
1085     pdf_resource_t *pres = pdev->resources[rtype].chains[0];
1086     pdf_resource_t *pres1, *pres0 = pres, *pres2;
1087 
1088     if (pres == NULL)
1089 	return;
1090     pres1 = pres->next;
1091     for (;;) {
1092 	if (pres1 == NULL)
1093 	    break;
1094 	pres2 = pres1->next;
1095 	pres1->next = pres;
1096 	pres = pres1;
1097 	pres1 = pres2;
1098     }
1099     pres0->next = NULL;
1100     pdev->resources[rtype].chains[0] = pres;
1101 }
1102 
1103 
1104 /*
1105  * Free unnamed Cos objects for resources local to a content stream,
1106  * since they can't be used again.
1107  */
1108 int
pdf_free_resource_objects(gx_device_pdf * pdev,pdf_resource_type_t rtype)1109 pdf_free_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype)
1110 {
1111     int j;
1112 
1113     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
1114 	pdf_resource_t **prev = &pdev->resources[rtype].chains[j];
1115 	pdf_resource_t *pres;
1116 
1117 	while ((pres = *prev) != 0) {
1118 	    if (pres->named) {	/* named, don't free */
1119 		prev = &pres->next;
1120 	    } else {
1121 		cos_free(pres->object, "pdf_free_resource_objects");
1122 		pres->object = 0;
1123 		*prev = pres->next;
1124 	    }
1125 	}
1126     }
1127     return 0;
1128 }
1129 
1130 /* Write and free all resource objects. */
1131 
1132 int
pdf_write_and_free_all_resource_objects(gx_device_pdf * pdev)1133 pdf_write_and_free_all_resource_objects(gx_device_pdf *pdev)
1134 {
1135     int i, code = 0, code1;
1136 
1137     for (i = 0; i < NUM_RESOURCE_TYPES; ++i) {
1138 	code1 = pdf_write_resource_objects(pdev, i);
1139 	if (code >= 0)
1140 	    code = code1;
1141     }
1142     code1 = pdf_finish_font_descriptors(pdev, pdf_release_FontDescriptor_components);
1143     if (code >= 0)
1144 	code = code1;
1145     for (i = 0; i < NUM_RESOURCE_TYPES; ++i) {
1146 	code1 = pdf_free_resource_objects(pdev, i);
1147 	if (code >= 0)
1148 	    code = code1;
1149     }
1150     return code;
1151 }
1152 
1153 /*
1154  * Store the resource sets for a content stream (page or XObject).
1155  * Sets page->{procsets, resource_ids[]}.
1156  */
1157 int
pdf_store_page_resources(gx_device_pdf * pdev,pdf_page_t * page)1158 pdf_store_page_resources(gx_device_pdf *pdev, pdf_page_t *page)
1159 {
1160     int i;
1161 
1162     /* Write any resource dictionaries. */
1163 
1164     for (i = 0; i <= resourceFont; ++i) {
1165 	stream *s = 0;
1166 	int j;
1167 
1168 	page->resource_ids[i] = 0;
1169 	for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
1170 	    pdf_resource_t *pres = pdev->resources[i].chains[j];
1171 
1172 	    for (; pres != 0; pres = pres->next) {
1173 		if (pres->where_used & pdev->used_mask) {
1174 		    long id = pres->object->id;
1175 
1176 		    if (s == 0) {
1177 			page->resource_ids[i] = pdf_begin_separate(pdev);
1178 			s = pdev->strm;
1179 			stream_puts(s, "<<");
1180 		    }
1181 		    pprints1(s, "/%s\n", pres->rname);
1182 		    pprintld1(s, "%ld 0 R", id);
1183 		    pres->where_used -= pdev->used_mask;
1184 		}
1185 	    }
1186 	}
1187 	if (s) {
1188 	    stream_puts(s, ">>\n");
1189 	    pdf_end_separate(pdev);
1190 	    if (i != resourceFont)
1191 		pdf_write_resource_objects(pdev, i);
1192 	}
1193     }
1194     page->procsets = pdev->procsets;
1195     return 0;
1196 }
1197 
1198 /* Copy data from a temporary file to a stream. */
1199 void
pdf_copy_data(stream * s,FILE * file,long count,stream_arcfour_state * ss)1200 pdf_copy_data(stream *s, FILE *file, long count, stream_arcfour_state *ss)
1201 {
1202     long left = count;
1203     byte buf[sbuf_size];
1204 
1205     while (left > 0) {
1206 	uint copy = min(left, sbuf_size);
1207 
1208 	fread(buf, 1, copy, file);
1209 	if (ss)
1210 	    s_arcfour_process_buffer(ss, buf, copy);
1211 	stream_write(s, buf, copy);
1212 	left -= copy;
1213     }
1214 }
1215 
1216 
1217 /* Copy data from a temporary file to a stream,
1218    which may be targetted to the same file. */
1219 void
pdf_copy_data_safe(stream * s,FILE * file,long position,long count)1220 pdf_copy_data_safe(stream *s, FILE *file, long position, long count)
1221 {
1222     long left = count;
1223 
1224     while (left > 0) {
1225 	byte buf[sbuf_size];
1226 	long copy = min(left, (long)sbuf_size);
1227 	long end_pos = ftell(file);
1228 
1229 	fseek(file, position + count - left, SEEK_SET);
1230 	fread(buf, 1, copy, file);
1231 	fseek(file, end_pos, SEEK_SET);
1232 	stream_write(s, buf, copy);
1233 	sflush(s);
1234 	left -= copy;
1235     }
1236 }
1237 
1238 /* ------ Pages ------ */
1239 
1240 /* Get or assign the ID for a page. */
1241 /* Returns 0 if the page number is out of range. */
1242 long
pdf_page_id(gx_device_pdf * pdev,int page_num)1243 pdf_page_id(gx_device_pdf * pdev, int page_num)
1244 {
1245     cos_dict_t *Page;
1246 
1247     if (page_num < 1)
1248 	return 0;
1249     if (page_num >= pdev->num_pages) {	/* Grow the pages array. */
1250 	uint new_num_pages =
1251 	    max(page_num + 10, pdev->num_pages << 1);
1252 	pdf_page_t *new_pages =
1253 	    gs_resize_object(pdev->pdf_memory, pdev->pages, new_num_pages,
1254 			     "pdf_page_id(resize pages)");
1255 
1256 	if (new_pages == 0)
1257 	    return 0;
1258 	memset(&new_pages[pdev->num_pages], 0,
1259 	       (new_num_pages - pdev->num_pages) * sizeof(pdf_page_t));
1260 	pdev->pages = new_pages;
1261 	pdev->num_pages = new_num_pages;
1262     }
1263     if ((Page = pdev->pages[page_num - 1].Page) == 0) {
1264 	pdev->pages[page_num - 1].Page = Page =
1265 	    cos_dict_alloc(pdev, "pdf_page_id");
1266 	Page->id = pdf_obj_ref(pdev);
1267     }
1268     return Page->id;
1269 }
1270 
1271 /* Get the page structure for the current page. */
1272 pdf_page_t *
pdf_current_page(gx_device_pdf * pdev)1273 pdf_current_page(gx_device_pdf *pdev)
1274 {
1275     return &pdev->pages[pdev->next_page];
1276 }
1277 
1278 /* Get the dictionary object for the current page. */
1279 cos_dict_t *
pdf_current_page_dict(gx_device_pdf * pdev)1280 pdf_current_page_dict(gx_device_pdf *pdev)
1281 {
1282     if (pdf_page_id(pdev, pdev->next_page + 1) <= 0)
1283 	return 0;
1284     return pdev->pages[pdev->next_page].Page;
1285 }
1286 
1287 /* Write saved page- or document-level information. */
1288 int
pdf_write_saved_string(gx_device_pdf * pdev,gs_string * pstr)1289 pdf_write_saved_string(gx_device_pdf * pdev, gs_string * pstr)
1290 {
1291     if (pstr->data != 0) {
1292 	stream_write(pdev->strm, pstr->data, pstr->size);
1293 	gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
1294 		       "pdf_write_saved_string");
1295 	pstr->data = 0;
1296     }
1297     return 0;
1298 }
1299 
1300 /* Open a page for writing. */
1301 int
pdf_open_page(gx_device_pdf * pdev,pdf_context_t context)1302 pdf_open_page(gx_device_pdf * pdev, pdf_context_t context)
1303 {
1304     if (!is_in_page(pdev)) {
1305 	int code;
1306 
1307 	if (pdf_page_id(pdev, pdev->next_page + 1) == 0)
1308 	    return_error(gs_error_VMerror);
1309 	code = pdf_open_document(pdev);
1310 	if (code < 0)
1311 	    return code;
1312     }
1313     /* Note that context may be PDF_IN_NONE here. */
1314     return pdf_open_contents(pdev, context);
1315 }
1316 
1317 
1318 /*  Go to the unclipped stream context. */
1319 int
pdf_unclip(gx_device_pdf * pdev)1320 pdf_unclip(gx_device_pdf * pdev)
1321 {
1322     const int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
1323     /* When ResourcesBeforeUsage != 0, one sbstack element
1324        appears from the page contents stream. */
1325 
1326     if (pdev->sbstack_depth <= bottom) {
1327 	int code = pdf_open_page(pdev, PDF_IN_STREAM);
1328 
1329 	if (code < 0)
1330 	    return code;
1331     }
1332     if (pdev->context > PDF_IN_STREAM) {
1333 	int code = pdf_open_contents(pdev, PDF_IN_STREAM);
1334 
1335 	if (code < 0)
1336 	    return code;
1337     }
1338     if (pdev->vgstack_depth > pdev->vgstack_bottom) {
1339 	int code = pdf_restore_viewer_state(pdev, pdev->strm);
1340 
1341 	if (code < 0)
1342 	    return code;
1343 	code = pdf_remember_clip_path(pdev, NULL);
1344 	if (code < 0)
1345 	    return code;
1346 	pdev->clip_path_id = pdev->no_clip_path_id;
1347     }
1348     return 0;
1349 }
1350 
1351 
1352 /* ------ Miscellaneous output ------ */
1353 
1354 /* Generate the default Producer string. */
1355 void
pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])1356 pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])
1357 {
1358     sprintf(buf, ((gs_revision % 100) == 0 ? "(%s %1.1f)" : "(%s %1.2f)"),
1359 	    gs_product, gs_revision / 100.0);
1360 }
1361 
1362 /* Write matrix values. */
1363 void
pdf_put_matrix(gx_device_pdf * pdev,const char * before,const gs_matrix * pmat,const char * after)1364 pdf_put_matrix(gx_device_pdf * pdev, const char *before,
1365 	       const gs_matrix * pmat, const char *after)
1366 {
1367     stream *s = pdev->strm;
1368 
1369     if (before)
1370 	stream_puts(s, before);
1371     pprintg6(s, "%g %g %g %g %g %g ",
1372 	     pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
1373     if (after)
1374 	stream_puts(s, after);
1375 }
1376 
1377 /*
1378  * Write a name, with escapes for unusual characters.  Since we only support
1379  * PDF 1.2 and above, we can use an escape sequence for anything except a
1380  * null <00>, and the machinery for selecting the put_name_chars procedure
1381  * depending on CompatibilityLevel is no longer needed.
1382  */
1383 private int
pdf_put_name_chars_1_2(stream * s,const byte * nstr,uint size)1384 pdf_put_name_chars_1_2(stream *s, const byte *nstr, uint size)
1385 {
1386     uint i;
1387 
1388     for (i = 0; i < size; ++i) {
1389 	uint c = nstr[i];
1390 	char hex[4];
1391 
1392 	switch (c) {
1393 	    default:
1394 		if (c >= 0x21 && c <= 0x7e) {
1395 		    stream_putc(s, (byte)c);
1396 		    break;
1397 		}
1398 		/* falls through */
1399 	    case '#':
1400 	    case '%':
1401 	    case '(': case ')':
1402 	    case '<': case '>':
1403 	    case '[': case ']':
1404 	    case '{': case '}':
1405 	    case '/':
1406 		sprintf(hex, "#%02x", c);
1407 		stream_puts(s, hex);
1408 		break;
1409 	    case 0:
1410 		stream_puts(s, "BnZr"); /* arbitrary */
1411 	}
1412     }
1413     return 0;
1414 }
1415 pdf_put_name_chars_proc_t
pdf_put_name_chars_proc(const gx_device_pdf * pdev)1416 pdf_put_name_chars_proc(const gx_device_pdf *pdev)
1417 {
1418     return &pdf_put_name_chars_1_2;
1419 }
1420 int
pdf_put_name_chars(const gx_device_pdf * pdev,const byte * nstr,uint size)1421 pdf_put_name_chars(const gx_device_pdf *pdev, const byte *nstr, uint size)
1422 {
1423     return pdf_put_name_chars_proc(pdev)(pdev->strm, nstr, size);
1424 }
1425 int
pdf_put_name(const gx_device_pdf * pdev,const byte * nstr,uint size)1426 pdf_put_name(const gx_device_pdf *pdev, const byte *nstr, uint size)
1427 {
1428     stream_putc(pdev->strm, '/');
1429     return pdf_put_name_chars(pdev, nstr, size);
1430 }
1431 
1432 /* Write an encoded string with encryption. */
1433 private int
pdf_encrypt_encoded_string(const gx_device_pdf * pdev,const byte * str,uint size,gs_id object_id)1434 pdf_encrypt_encoded_string(const gx_device_pdf *pdev, const byte *str, uint size, gs_id object_id)
1435 {
1436     stream sinp, sstr, sout;
1437     stream_PSSD_state st;
1438     stream_state so;
1439     byte buf[100], bufo[100];
1440     stream_arcfour_state sarc4;
1441 
1442     if (pdf_encrypt_init(pdev, object_id, &sarc4) < 0) {
1443 	/* The interface can't pass an error. */
1444 	stream_write(pdev->strm, str, size);
1445 	return size;
1446     }
1447     sread_string(&sinp, str + 1, size);
1448     s_init(&sstr, NULL);
1449     sstr.close_at_eod = false;
1450     s_init_state((stream_state *)&st, &s_PSSD_template, NULL);
1451     s_init_filter(&sstr, (stream_state *)&st, buf, sizeof(buf), &sinp);
1452     s_init(&sout, NULL);
1453     s_init_state(&so, &s_PSSE_template, NULL);
1454     s_init_filter(&sout, &so, bufo, sizeof(bufo), pdev->strm);
1455     stream_putc(pdev->strm, '(');
1456     for (;;) {
1457 	uint n;
1458 	int code = sgets(&sstr, buf, sizeof(buf), &n);
1459 
1460 	if (n > 0) {
1461 	    s_arcfour_process_buffer(&sarc4, buf, n);
1462 	    stream_write(&sout, buf, n);
1463 	}
1464 	if (code == EOFC)
1465 	    break;
1466 	if (code < 0 || n < sizeof(buf)) {
1467 	    /* The interface can't pass an error. */
1468 	    break;
1469 	}
1470     }
1471     sclose(&sout); /* Writes ')'. */
1472     return stell(&sinp) + 1;
1473 }
1474 
1475 /* Write an encoded string with possible encryption. */
1476 private int
pdf_put_encoded_string(const gx_device_pdf * pdev,const byte * str,uint size,gs_id object_id)1477 pdf_put_encoded_string(const gx_device_pdf *pdev, const byte *str, uint size, gs_id object_id)
1478 {
1479     if (!pdev->KeyLength || object_id == (gs_id)-1) {
1480 	stream_write(pdev->strm, str, size);
1481 	return 0;
1482     } else
1483 	return pdf_encrypt_encoded_string(pdev, str, size, object_id);
1484 }
1485 /* Write an encoded hexadecimal string with possible encryption. */
1486 private int
pdf_put_encoded_hex_string(const gx_device_pdf * pdev,const byte * str,uint size,gs_id object_id)1487 pdf_put_encoded_hex_string(const gx_device_pdf *pdev, const byte *str, uint size, gs_id object_id)
1488 {
1489     eprintf("Unimplemented function : pdf_put_encoded_hex_string\n");
1490     stream_write(pdev->strm, str, size);
1491     return_error(gs_error_unregistered);
1492 }
1493 /*  Scan an item in a serialized array or dictionary.
1494     This is a very simplified Postscript lexical scanner.
1495     It assumes the serialization with pdf===only defined in gs/lib/gs_pdfwr.ps .
1496     We only need to select strings and encrypt them.
1497     Other items are passed identically.
1498     Note we don't reconstruct the nesting of arrays|dictionaries.
1499 */
1500 private int
pdf_scan_item(const gx_device_pdf * pdev,const byte * p,uint l,gs_id object_id)1501 pdf_scan_item(const gx_device_pdf * pdev, const byte * p, uint l, gs_id object_id)
1502 {
1503     const byte *q = p;
1504     int n = l;
1505 
1506     if (*q == ' ' || *q == 't' || *q == '\r' || *q == '\n')
1507 	return (l > 0 ? 1 : 0);
1508     for (q++, n--; n; q++, n--) {
1509 	if (*q == ' ' || *q == 't' || *q == '\r' || *q == '\n')
1510 	    return q - p;
1511 	if (*q == '/' || *q == '[' || *q == ']' || *q == '{' || *q == '}' || *q == '(' || *q == '<')
1512 	    return q - p;
1513 	/* Note : immediate names are not allowed in PDF. */
1514     }
1515     return l;
1516 }
1517 
1518 /* Write a serialized array or dictionary with possible encryption. */
1519 private int
pdf_put_composite(const gx_device_pdf * pdev,const byte * vstr,uint size,gs_id object_id)1520 pdf_put_composite(const gx_device_pdf * pdev, const byte * vstr, uint size, gs_id object_id)
1521 {
1522     if (!pdev->KeyLength || object_id == (gs_id)-1) {
1523 	stream_write(pdev->strm, vstr, size);
1524     } else {
1525 	const byte *p = vstr;
1526 	int l = size, n;
1527 
1528 	for (;l > 0 ;) {
1529 	    if (*p == '(')
1530 		n = pdf_encrypt_encoded_string(pdev, p, l, object_id);
1531 	    else {
1532 		n = pdf_scan_item(pdev, p, l, object_id);
1533 		stream_write(pdev->strm, p, n);
1534 	    }
1535 	    l -= n;
1536 	    p += n;
1537 	}
1538     }
1539     return 0;
1540 }
1541 
1542 /*
1543  * Write a string in its shortest form ( () or <> ).  Note that
1544  * this form is different depending on whether binary data are allowed.
1545  * We wish PDF supported ASCII85 strings ( <~ ~> ), but it doesn't.
1546  */
1547 int
pdf_put_string(const gx_device_pdf * pdev,const byte * str,uint size)1548 pdf_put_string(const gx_device_pdf * pdev, const byte * str, uint size)
1549 {
1550     psdf_write_string(pdev->strm, str, size,
1551 		      (pdev->binary_ok ? PRINT_BINARY_OK : 0));
1552     return 0;
1553 }
1554 
1555 /* Write a value, treating names specially. */
1556 int
pdf_write_value(const gx_device_pdf * pdev,const byte * vstr,uint size,gs_id object_id)1557 pdf_write_value(const gx_device_pdf * pdev, const byte * vstr, uint size, gs_id object_id)
1558 {
1559     if (size > 0 && vstr[0] == '/')
1560 	return pdf_put_name(pdev, vstr + 1, size - 1);
1561     else if (size > 3 && vstr[0] == 0 && vstr[1] == 0 && vstr[size - 1] == 0)
1562 	return pdf_put_name(pdev, vstr + 3, size - 4);
1563     else if (size > 1 && (vstr[0] == '[' || vstr[0] == '{'))
1564 	return pdf_put_composite(pdev, vstr, size, object_id);
1565     else if (size > 2 && vstr[0] == '<' && vstr[1] == '<')
1566 	return pdf_put_composite(pdev, vstr, size, object_id);
1567     else if (size > 1 && vstr[0] == '(')
1568 	return pdf_put_encoded_string(pdev, vstr, size, object_id);
1569     else if (size > 1 && vstr[0] == '<')
1570 	return pdf_put_encoded_hex_string(pdev, vstr, size, object_id);
1571     stream_write(pdev->strm, vstr, size);
1572     return 0;
1573 }
1574 
1575 /* Store filters for a stream. */
1576 /* Currently this only saves parameters for CCITTFaxDecode. */
1577 int
pdf_put_filters(cos_dict_t * pcd,gx_device_pdf * pdev,stream * s,const pdf_filter_names_t * pfn)1578 pdf_put_filters(cos_dict_t *pcd, gx_device_pdf *pdev, stream *s,
1579 		const pdf_filter_names_t *pfn)
1580 {
1581     const char *filter_name = 0;
1582     bool binary_ok = true;
1583     stream *fs = s;
1584     cos_dict_t *decode_parms = 0;
1585     int code;
1586 
1587     for (; fs != 0; fs = fs->strm) {
1588 	const stream_state *st = fs->state;
1589 	const stream_template *template = st->template;
1590 
1591 #define TEMPLATE_IS(atemp)\
1592   (template->process == (atemp).process)
1593 	if (TEMPLATE_IS(s_A85E_template))
1594 	    binary_ok = false;
1595 	else if (TEMPLATE_IS(s_CFE_template)) {
1596 	    cos_param_list_writer_t writer;
1597 	    stream_CF_state cfs;
1598 
1599 	    decode_parms =
1600 		cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
1601 	    if (decode_parms == 0)
1602 		return_error(gs_error_VMerror);
1603 	    CHECK(cos_param_list_writer_init(&writer, decode_parms, 0));
1604 	    /*
1605 	     * If EndOfBlock is true, we mustn't write a Rows value.
1606 	     * This is a hack....
1607 	     */
1608 	    cfs = *(const stream_CF_state *)st;
1609 	    if (cfs.EndOfBlock)
1610 		cfs.Rows = 0;
1611 	    CHECK(s_CF_get_params((gs_param_list *)&writer, &cfs, false));
1612 	    filter_name = pfn->CCITTFaxDecode;
1613 	} else if (TEMPLATE_IS(s_DCTE_template))
1614 	    filter_name = pfn->DCTDecode;
1615 	else if (TEMPLATE_IS(s_zlibE_template))
1616 	    filter_name = pfn->FlateDecode;
1617 	else if (TEMPLATE_IS(s_LZWE_template))
1618 	    filter_name = pfn->LZWDecode;
1619 	else if (TEMPLATE_IS(s_PNGPE_template)) {
1620 	    /* This is a predictor for FlateDecode or LZWEncode. */
1621 	    const stream_PNGP_state *const ss =
1622 		(const stream_PNGP_state *)st;
1623 
1624 	    decode_parms =
1625 		cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
1626 	    if (decode_parms == 0)
1627 		return_error(gs_error_VMerror);
1628 	    CHECK(cos_dict_put_c_key_int(decode_parms, "/Predictor",
1629 					 ss->Predictor));
1630 	    CHECK(cos_dict_put_c_key_int(decode_parms, "/Columns",
1631 					 ss->Columns));
1632 	    if (ss->Colors != 1)
1633 		CHECK(cos_dict_put_c_key_int(decode_parms, "/Colors",
1634 					     ss->Colors));
1635 	    if (ss->BitsPerComponent != 8)
1636 		CHECK(cos_dict_put_c_key_int(decode_parms,
1637 					     "/BitsPerComponent",
1638 					     ss->BitsPerComponent));
1639 	} else if (TEMPLATE_IS(s_RLE_template))
1640 	    filter_name = pfn->RunLengthDecode;
1641 #undef TEMPLATE_IS
1642     }
1643     if (filter_name) {
1644 	if (binary_ok) {
1645 	    CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, filter_name));
1646 	    if (decode_parms)
1647 		CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
1648 						COS_OBJECT(decode_parms)));
1649 	} else {
1650 	    cos_array_t *pca =
1651 		cos_array_alloc(pdev, "pdf_put_image_filters(Filters)");
1652 
1653 	    if (pca == 0)
1654 		return_error(gs_error_VMerror);
1655 	    CHECK(cos_array_add_c_string(pca, pfn->ASCII85Decode));
1656 	    CHECK(cos_array_add_c_string(pca, filter_name));
1657 	    CHECK(cos_dict_put_c_key_object(pcd, pfn->Filter,
1658 					    COS_OBJECT(pca)));
1659 	    if (decode_parms) {
1660 		pca = cos_array_alloc(pdev,
1661 				      "pdf_put_image_filters(DecodeParms)");
1662 		if (pca == 0)
1663 		    return_error(gs_error_VMerror);
1664 		CHECK(cos_array_add_c_string(pca, "null"));
1665 		CHECK(cos_array_add_object(pca, COS_OBJECT(decode_parms)));
1666 		CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
1667 						COS_OBJECT(pca)));
1668 	    }
1669 	}
1670     } else if (!binary_ok)
1671 	CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, pfn->ASCII85Decode));
1672     return 0;
1673 }
1674 
1675 /* Add a Flate compression filter to a binary writer. */
1676 private int
pdf_flate_binary(gx_device_pdf * pdev,psdf_binary_writer * pbw)1677 pdf_flate_binary(gx_device_pdf *pdev, psdf_binary_writer *pbw)
1678 {
1679     const stream_template *template = (pdev->CompatibilityLevel < 1.3 ?
1680 		    &s_LZWE_template : &s_zlibE_template);
1681     stream_state *st = s_alloc_state(pdev->pdf_memory, template->stype,
1682 				     "pdf_write_function");
1683 
1684     if (st == 0)
1685 	return_error(gs_error_VMerror);
1686     if (template->set_defaults)
1687 	template->set_defaults(st);
1688     return psdf_encode_binary(pbw, template, st);
1689 }
1690 
1691 /*
1692  * Begin a data stream.  The client has opened the object and written
1693  * the << and any desired dictionary keys.
1694  */
1695 int
pdf_begin_data(gx_device_pdf * pdev,pdf_data_writer_t * pdw)1696 pdf_begin_data(gx_device_pdf *pdev, pdf_data_writer_t *pdw)
1697 {
1698     return pdf_begin_data_stream(pdev, pdw,
1699 				 DATA_STREAM_BINARY | DATA_STREAM_COMPRESS, 0);
1700 }
1701 
1702 int
pdf_append_data_stream_filters(gx_device_pdf * pdev,pdf_data_writer_t * pdw,int orig_options,gs_id object_id)1703 pdf_append_data_stream_filters(gx_device_pdf *pdev, pdf_data_writer_t *pdw,
1704 		      int orig_options, gs_id object_id)
1705 {
1706     stream *s = pdev->strm;
1707     int options = orig_options;
1708 #define USE_ASCII85 1
1709 #define USE_FLATE 2
1710     static const char *const fnames[4] = {
1711 	"", "/Filter/ASCII85Decode", "/Filter/FlateDecode",
1712 	"/Filter[/ASCII85Decode/FlateDecode]"
1713     };
1714     static const char *const fnames1_2[4] = {
1715 	"", "/Filter/ASCII85Decode", "/Filter/LZWDecode",
1716 	"/Filter[/ASCII85Decode/LZWDecode]"
1717     };
1718     int filters = 0;
1719     int code;
1720 
1721     if (options & DATA_STREAM_COMPRESS) {
1722 	filters |= USE_FLATE;
1723 	options |= DATA_STREAM_BINARY;
1724     }
1725     if ((options & DATA_STREAM_BINARY) && !pdev->binary_ok)
1726 	filters |= USE_ASCII85;
1727     if (!(options & DATA_STREAM_NOLENGTH)) {
1728 	stream_puts(s, (pdev->CompatibilityLevel < 1.3 ?
1729 	    fnames1_2[filters] : fnames[filters]));
1730 	if (pdev->ResourcesBeforeUsage) {
1731 	    pdw->length_pos = stell(s) + 8;
1732 	    stream_puts(s, "/Length             >>stream\n");
1733 	    pdw->length_id = -1;
1734 	} else {
1735 	    pdw->length_pos = -1;
1736 	    pdw->length_id = pdf_obj_ref(pdev);
1737 	    pprintld1(s, "/Length %ld 0 R>>stream\n", pdw->length_id);
1738 	}
1739     }
1740     if (options & DATA_STREAM_ENCRYPT) {
1741 	code = pdf_begin_encrypt(pdev, &s, object_id);
1742 	if (code < 0)
1743 	    return code;
1744 	pdev->strm = s;
1745 	pdw->encrypted = true;
1746     } else
1747     	pdw->encrypted = false;
1748     if (options & DATA_STREAM_BINARY) {
1749 	code = psdf_begin_binary((gx_device_psdf *)pdev, &pdw->binary);
1750 	if (code < 0)
1751 	    return code;
1752     } else {
1753 	code = 0;
1754 	pdw->binary.target = pdev->strm;
1755 	pdw->binary.dev = (gx_device_psdf *)pdev;
1756 	pdw->binary.strm = pdev->strm;
1757     }
1758     pdw->start = stell(s);
1759     if (filters & USE_FLATE)
1760 	code = pdf_flate_binary(pdev, &pdw->binary);
1761     return code;
1762 #undef USE_ASCII85
1763 #undef USE_FLATE
1764 }
1765 
1766 int
pdf_begin_data_stream(gx_device_pdf * pdev,pdf_data_writer_t * pdw,int options,gs_id object_id)1767 pdf_begin_data_stream(gx_device_pdf *pdev, pdf_data_writer_t *pdw,
1768 		      int options, gs_id object_id)
1769 {   int code;
1770     /* object_id is an unused rudiment from the old code,
1771        when the encription was applied when creating the stream.
1772        The new code encrypts than copying stream from the temporary file. */
1773     pdw->pdev = pdev;  /* temporary for backward compatibility of pdf_end_data prototype. */
1774     pdw->binary.target = pdev->strm;
1775     pdw->binary.dev = (gx_device_psdf *)pdev;
1776     pdw->binary.strm = 0;		/* for GC in case of failure */
1777     code = pdf_open_aside(pdev, resourceOther, gs_no_id, &pdw->pres, !object_id,
1778 		options);
1779     if (object_id != 0)
1780 	pdf_reserve_object_id(pdev, pdw->pres, object_id);
1781     pdw->binary.strm = pdev->strm;
1782     return code;
1783 }
1784 
1785 /* End a data stream. */
1786 int
pdf_end_data(pdf_data_writer_t * pdw)1787 pdf_end_data(pdf_data_writer_t *pdw)
1788 {   int code;
1789 
1790     code = pdf_close_aside(pdw->pdev);
1791     if (code < 0)
1792 	return code;
1793     code = COS_WRITE_OBJECT(pdw->pres->object, pdw->pdev);
1794     if (code < 0)
1795 	return code;
1796     return 0;
1797 }
1798 
1799 /* Create a Function object. */
1800 private int pdf_function_array(gx_device_pdf *pdev, cos_array_t *pca,
1801 			       const gs_function_info_t *pinfo);
1802 int
pdf_function_scaled(gx_device_pdf * pdev,const gs_function_t * pfn,const gs_range_t * pranges,cos_value_t * pvalue)1803 pdf_function_scaled(gx_device_pdf *pdev, const gs_function_t *pfn,
1804 		    const gs_range_t *pranges, cos_value_t *pvalue)
1805 {
1806     if (pranges == NULL)
1807 	return pdf_function(pdev, pfn, pvalue);
1808     {
1809 	/*
1810 	 * Create a temporary scaled function.  Note that the ranges
1811 	 * represent the inverse scaling from what gs_function_make_scaled
1812 	 * expects.
1813 	 */
1814 	gs_memory_t *mem = pdev->pdf_memory;
1815 	gs_function_t *psfn;
1816 	gs_range_t *ranges = (gs_range_t *)
1817 	    gs_alloc_byte_array(mem, pfn->params.n, sizeof(gs_range_t),
1818 				"pdf_function_scaled");
1819 	int i, code;
1820 
1821 	if (ranges == 0)
1822 	    return_error(gs_error_VMerror);
1823 	for (i = 0; i < pfn->params.n; ++i) {
1824 	    double rbase = pranges[i].rmin;
1825 	    double rdiff = pranges[i].rmax - rbase;
1826 	    double invbase = -rbase / rdiff;
1827 
1828 	    ranges[i].rmin = invbase;
1829 	    ranges[i].rmax = invbase + 1.0 / rdiff;
1830 	}
1831 	code = gs_function_make_scaled(pfn, &psfn, ranges, mem);
1832 	if (code >= 0) {
1833 	    code = pdf_function(pdev, psfn, pvalue);
1834 	    gs_function_free(psfn, true, mem);
1835 	}
1836 	gs_free_object(mem, ranges, "pdf_function_scaled");
1837 	return code;
1838     }
1839 }
1840 private int
pdf_function_aux(gx_device_pdf * pdev,const gs_function_t * pfn,pdf_resource_t ** ppres)1841 pdf_function_aux(gx_device_pdf *pdev, const gs_function_t *pfn,
1842 	     pdf_resource_t **ppres)
1843 {
1844     gs_function_info_t info;
1845     cos_param_list_writer_t rlist;
1846     pdf_resource_t *pres;
1847     cos_object_t *pcfn;
1848     cos_dict_t *pcd;
1849     int code = pdf_alloc_resource(pdev, resourceFunction, gs_no_id, &pres, -1);
1850 
1851     if (code < 0) {
1852 	*ppres = 0;
1853 	return code;
1854     }
1855     *ppres = pres;
1856     pcfn = pres->object;
1857     gs_function_get_info(pfn, &info);
1858     if (FunctionType(pfn) == function_type_ArrayedOutput) {
1859 	/*
1860 	 * Arrayed Output Functions are used internally to represent
1861 	 * Shading Function entries that are arrays of Functions.
1862 	 * They require special handling.
1863 	 */
1864 	cos_array_t *pca;
1865 
1866 	cos_become(pcfn, cos_type_array);
1867 	pca = (cos_array_t *)pcfn;
1868 	return pdf_function_array(pdev, pca, &info);
1869     }
1870     if (info.DataSource != 0) {
1871 	psdf_binary_writer writer;
1872 	stream *save = pdev->strm;
1873 	cos_stream_t *pcos;
1874 	stream *s;
1875 
1876 	cos_become(pcfn, cos_type_stream);
1877 	pcos = (cos_stream_t *)pcfn;
1878 	pcd = cos_stream_dict(pcos);
1879 	s = cos_write_stream_alloc(pcos, pdev, "pdf_function");
1880 	if (s == 0)
1881 	    return_error(gs_error_VMerror);
1882 	pdev->strm = s;
1883 	code = psdf_begin_binary((gx_device_psdf *)pdev, &writer);
1884 	if (code >= 0 && info.data_size > 30	/* 30 is arbitrary */
1885 	    )
1886 	    code = pdf_flate_binary(pdev, &writer);
1887 	if (code >= 0) {
1888 	    static const pdf_filter_names_t fnames = {
1889 		PDF_FILTER_NAMES
1890 	    };
1891 
1892 	    code = pdf_put_filters(pcd, pdev, writer.strm, &fnames);
1893 	}
1894 	if (code >= 0) {
1895 	    byte buf[100];		/* arbitrary */
1896 	    ulong pos;
1897 	    uint count;
1898 	    const byte *ptr;
1899 
1900 	    for (pos = 0; pos < info.data_size; pos += count) {
1901 		count = min(sizeof(buf), info.data_size - pos);
1902 		data_source_access_only(info.DataSource, pos, count, buf,
1903 					&ptr);
1904 		stream_write(writer.strm, ptr, count);
1905 	    }
1906 	    code = psdf_end_binary(&writer);
1907 	    sclose(s);
1908 	}
1909 	pdev->strm = save;
1910 	if (code < 0)
1911 	    return code;
1912     } else {
1913 	cos_become(pcfn, cos_type_dict);
1914 	pcd = (cos_dict_t *)pcfn;
1915     }
1916     if (info.Functions != 0) {
1917 	cos_array_t *functions =
1918 	    cos_array_alloc(pdev, "pdf_function(Functions)");
1919 	cos_value_t v;
1920 
1921 	if (functions == 0)
1922 	    return_error(gs_error_VMerror);
1923 	if ((code = pdf_function_array(pdev, functions, &info)) < 0 ||
1924 	    (code = cos_dict_put_c_key(pcd, "/Functions",
1925 				       COS_OBJECT_VALUE(&v, functions))) < 0
1926 	    ) {
1927 	    COS_FREE(functions, "pdf_function(Functions)");
1928 	    return code;
1929 	}
1930     }
1931     code = cos_param_list_writer_init(&rlist, pcd, PRINT_BINARY_OK);
1932     if (code < 0)
1933 	return code;
1934     return gs_function_get_params(pfn, (gs_param_list *)&rlist);
1935 }
1936 private int
functions_equal(gx_device_pdf * pdev,pdf_resource_t * pres0,pdf_resource_t * pres1)1937 functions_equal(gx_device_pdf * pdev, pdf_resource_t *pres0, pdf_resource_t *pres1)
1938 {
1939     return true;
1940 }
1941 int
pdf_function(gx_device_pdf * pdev,const gs_function_t * pfn,cos_value_t * pvalue)1942 pdf_function(gx_device_pdf *pdev, const gs_function_t *pfn, cos_value_t *pvalue)
1943 {
1944     pdf_resource_t *pres;
1945     int code = pdf_function_aux(pdev, pfn, &pres);
1946 
1947     if (code < 0)
1948 	return code;
1949     code = pdf_substitute_resource(pdev, &pres, resourceFunction, functions_equal, false);
1950     if (code < 0)
1951 	return code;
1952     COS_OBJECT_VALUE(pvalue, pres->object);
1953     return 0;
1954 }
pdf_function_array(gx_device_pdf * pdev,cos_array_t * pca,const gs_function_info_t * pinfo)1955 private int pdf_function_array(gx_device_pdf *pdev, cos_array_t *pca,
1956 			       const gs_function_info_t *pinfo)
1957 {
1958     int i, code = 0;
1959     cos_value_t v;
1960 
1961     for (i = 0; i < pinfo->num_Functions; ++i) {
1962 	if ((code = pdf_function(pdev, pinfo->Functions[i], &v)) < 0 ||
1963 	    (code = cos_array_add(pca, &v)) < 0
1964 	    ) {
1965 	    break;
1966 	}
1967     }
1968     return code;
1969 }
1970 
1971 
1972 /* Write a Function object. */
1973 int
pdf_write_function(gx_device_pdf * pdev,const gs_function_t * pfn,long * pid)1974 pdf_write_function(gx_device_pdf *pdev, const gs_function_t *pfn, long *pid)
1975 {
1976     cos_value_t value;
1977     int code = pdf_function(pdev, pfn, &value);
1978 
1979     if (code < 0)
1980 	return code;
1981     *pid = value.contents.object->id;
1982     return 0;
1983 }
1984 
1985 /* Write a FontBBox dictionary element. */
1986 int
pdf_write_font_bbox(gx_device_pdf * pdev,const gs_int_rect * pbox)1987 pdf_write_font_bbox(gx_device_pdf *pdev, const gs_int_rect *pbox)
1988 {
1989     stream *s = pdev->strm;
1990     /*
1991      * AR 4 doesn't like fonts with empty FontBBox, which
1992      * happens when the font contains only space characters.
1993      * Small bbox causes AR 4 to display a hairline. So we use
1994      * the full BBox.
1995      */
1996     int x = pbox->q.x + ((pbox->p.x == pbox->q.x) ? 1000 : 0);
1997     int y = pbox->q.y + ((pbox->p.y == pbox->q.y) ? 1000 : 0);
1998 
1999     pprintd4(s, "/FontBBox[%d %d %d %d]",
2000 	     pbox->p.x, pbox->p.y, x, y);
2001     return 0;
2002 }
2003