1 /* Copyright (C) 1999, 2000, 2001 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevpdfu.c,v 1.16.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /* Output utilities for PDF-writing driver */
21 #include "memory_.h"
22 #include "jpeglib_.h"		/* for sdct.h */
23 #include "string_.h"
24 #include "gx.h"
25 #include "gserrors.h"
26 #include "gscdefs.h"
27 #include "gsdsrc.h"
28 #include "gsfunc.h"
29 #include "gdevpdfx.h"
30 #include "gdevpdfo.h"
31 #include "scanchar.h"
32 #include "strimpl.h"
33 #include "sa85x.h"
34 #include "scfx.h"
35 #include "sdct.h"
36 #include "slzwx.h"
37 #include "spngpx.h"
38 #include "srlx.h"
39 #include "sstring.h"
40 #include "szlibx.h"
41 
42 /* Define the size of internal stream buffers. */
43 /* (This is not a limitation, it only affects performance.) */
44 #define sbuf_size 512
45 
46 /* Optionally substitute other filters for FlateEncode for debugging. */
47 #if 1
48 #  define compression_filter_name "FlateDecode"
49 #  define compression_filter_template s_zlibE_template
50 #  define compression_filter_state stream_zlib_state
51 #else
52 #  include "slzwx.h"
53 #  define compression_filter_name "LZWDecode"
54 #  define compression_filter_template s_LZWE_template
55 #  define compression_filter_state stream_LZW_state
56 #endif
57 
58 /* Import procedures for writing filter parameters. */
59 extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
60 extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state);
61 
62 #define CHECK(expr)\
63   BEGIN if ((code = (expr)) < 0) return code; END
64 
65 /* GC descriptors */
66 extern_st(st_pdf_font);
67 extern_st(st_pdf_char_proc);
68 extern_st(st_pdf_font_descriptor);
69 public_st_pdf_resource();
70 private_st_pdf_x_object();
71 
72 /* ---------------- Utilities ---------------- */
73 
74 /* ------ Document ------ */
75 
76 /* Open the document if necessary. */
77 void
pdf_open_document(gx_device_pdf * pdev)78 pdf_open_document(gx_device_pdf * pdev)
79 {
80     if (!is_in_page(pdev) && pdf_stell(pdev) == 0) {
81 	stream *s = pdev->strm;
82 	int level = (int)(pdev->CompatibilityLevel * 10 + 0.5);
83 
84 	pprintd2(s, "%%PDF-%d.%d\n", level / 10, level % 10);
85 	pdev->binary_ok = !pdev->params.ASCII85EncodePages;
86 	if (pdev->binary_ok)
87 	    stream_puts(s, "%\307\354\217\242\n");
88     }
89     /*
90      * Determine the compression method.  Currently this does nothing.
91      * It also isn't clear whether the compression method can now be
92      * changed in the course of the document.
93      *
94      * The following algorithm is per an update to TN # 5151 by
95      * Adobe Developer Support.
96      */
97     if (!pdev->params.CompressPages)
98 	pdev->compression = pdf_compress_none;
99     else if (pdev->CompatibilityLevel < 1.2)
100 	pdev->compression = pdf_compress_LZW;
101     else if (pdev->params.UseFlateCompression)
102 	pdev->compression = pdf_compress_Flate;
103     else
104 	pdev->compression = pdf_compress_LZW;
105 }
106 
107 /* ------ Objects ------ */
108 
109 /* Allocate an object ID. */
110 private long
pdf_next_id(gx_device_pdf * pdev)111 pdf_next_id(gx_device_pdf * pdev)
112 {
113     return (pdev->next_id)++;
114 }
115 
116 /*
117  * Return the current position in the output.  Note that this may be in the
118  * main output file, the asides file, or the pictures file.  If the current
119  * file is the pictures file, positions returned by pdf_stell must only be
120  * used locally (for computing lengths or patching), since there is no way
121  * to map them later to the eventual position in the output file.
122  */
123 long
pdf_stell(gx_device_pdf * pdev)124 pdf_stell(gx_device_pdf * pdev)
125 {
126     stream *s = pdev->strm;
127     long pos = stell(s);
128 
129     if (s == pdev->asides.strm)
130 	pos += ASIDES_BASE_POSITION;
131     return pos;
132 }
133 
134 /* Allocate an ID for a future object. */
135 long
pdf_obj_ref(gx_device_pdf * pdev)136 pdf_obj_ref(gx_device_pdf * pdev)
137 {
138     long id = pdf_next_id(pdev);
139     long pos = pdf_stell(pdev);
140 
141     fwrite(&pos, sizeof(pos), 1, pdev->xref.file);
142     return id;
143 }
144 
145 /* Begin an object, optionally allocating an ID. */
146 long
pdf_open_obj(gx_device_pdf * pdev,long id)147 pdf_open_obj(gx_device_pdf * pdev, long id)
148 {
149     stream *s = pdev->strm;
150 
151     if (id <= 0) {
152 	id = pdf_obj_ref(pdev);
153     } else {
154 	long pos = pdf_stell(pdev);
155 	FILE *tfile = pdev->xref.file;
156 	long tpos = ftell(tfile);
157 
158 	fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
159 	      SEEK_SET);
160 	fwrite(&pos, sizeof(pos), 1, tfile);
161 	fseek(tfile, tpos, SEEK_SET);
162     }
163     pprintld1(s, "%ld 0 obj\n", id);
164     return id;
165 }
166 long
pdf_begin_obj(gx_device_pdf * pdev)167 pdf_begin_obj(gx_device_pdf * pdev)
168 {
169     return pdf_open_obj(pdev, 0L);
170 }
171 
172 /* End an object. */
173 int
pdf_end_obj(gx_device_pdf * pdev)174 pdf_end_obj(gx_device_pdf * pdev)
175 {
176     stream_puts(pdev->strm, "endobj\n");
177     return 0;
178 }
179 
180 /* ------ Page contents ------ */
181 
182 /* Handle transitions between contexts. */
183 private int
184     none_to_stream(P1(gx_device_pdf *)), stream_to_text(P1(gx_device_pdf *)),
185     string_to_text(P1(gx_device_pdf *)), text_to_stream(P1(gx_device_pdf *)),
186     stream_to_none(P1(gx_device_pdf *));
187 typedef int (*context_proc) (P1(gx_device_pdf *));
188 private const context_proc context_procs[4][4] =
189 {
190     {0, none_to_stream, none_to_stream, none_to_stream},
191     {stream_to_none, 0, stream_to_text, stream_to_text},
192     {text_to_stream, text_to_stream, 0, 0},
193     {string_to_text, string_to_text, string_to_text, 0}
194 };
195 
196 /* Enter stream context. */
197 private int
none_to_stream(gx_device_pdf * pdev)198 none_to_stream(gx_device_pdf * pdev)
199 {
200     stream *s;
201 
202     if (pdev->contents_id != 0)
203 	return_error(gs_error_Fatal);	/* only 1 contents per page */
204     pdev->contents_id = pdf_begin_obj(pdev);
205     pdev->contents_length_id = pdf_obj_ref(pdev);
206     s = pdev->strm;
207     pprintld1(s, "<</Length %ld 0 R", pdev->contents_length_id);
208     if (pdev->compression == pdf_compress_Flate)
209 	pprints1(s, "/Filter /%s", compression_filter_name);
210     stream_puts(s, ">>\nstream\n");
211     pdev->contents_pos = pdf_stell(pdev);
212     if (pdev->compression == pdf_compress_Flate) {	/* Set up the Flate filter. */
213 	const stream_template *template = &compression_filter_template;
214 	stream *es = s_alloc(pdev->pdf_memory, "PDF compression stream");
215 	byte *buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
216 				   "PDF compression buffer");
217 	compression_filter_state *st =
218 	    gs_alloc_struct(pdev->pdf_memory, compression_filter_state,
219 			    template->stype, "PDF compression state");
220 
221 	if (es == 0 || st == 0 || buf == 0)
222 	    return_error(gs_error_VMerror);
223 	s_std_init(es, buf, sbuf_size, &s_filter_write_procs,
224 		   s_mode_write);
225 	st->memory = pdev->pdf_memory;
226 	st->template = template;
227 	es->state = (stream_state *) st;
228 	es->procs.process = template->process;
229 	es->strm = s;
230 	(*template->set_defaults) ((stream_state *) st);
231 	(*template->init) ((stream_state *) st);
232 	pdev->strm = s = es;
233     }
234     /*
235      * Scale the coordinate system.  Use an extra level of q/Q for the
236      * sake of poorly designed PDF tools that assume that the contents
237      * stream restores the CTM.
238      */
239     pprintg2(s, "q %g 0 0 %g 0 0 cm\n",
240 	     72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
241     if (pdev->CompatibilityLevel >= 1.3) {
242 	/* Set the default rendering intent. */
243 	if (pdev->params.DefaultRenderingIntent != ri_Default) {
244 	    static const char *const ri_names[] = { psdf_ri_names };
245 
246 	    pprints1(s, "/%s ri\n",
247 		     ri_names[(int)pdev->params.DefaultRenderingIntent]);
248 	}
249     }
250     /* Do a level of gsave for the clipping path. */
251     stream_puts(s, "q\n");
252     return PDF_IN_STREAM;
253 }
254 /* Enter text context from stream context. */
255 private int
stream_to_text(gx_device_pdf * pdev)256 stream_to_text(gx_device_pdf * pdev)
257 {
258     /*
259      * Bizarrely enough, Acrobat Reader cares how the final font size is
260      * obtained -- the CTM (cm), text matrix (Tm), and font size (Tf)
261      * are *not* all equivalent.  In particular, it seems to use the
262      * product of the text matrix and font size to decide how to
263      * anti-alias characters.  Therefore, we have to temporarily patch
264      * the CTM so that the scale factors are unity.  What a nuisance!
265      */
266     pprintg2(pdev->strm, "q %g 0 0 %g 0 0 cm BT\n",
267 	     pdev->HWResolution[0] / 72.0, pdev->HWResolution[1] / 72.0);
268     pdev->procsets |= Text;
269     gs_make_identity(&pdev->text.matrix);
270     pdev->text.line_start.x = pdev->text.line_start.y = 0;
271     pdev->text.buffer_count = 0;
272     return PDF_IN_TEXT;
273 }
274 /* Exit string context to text context. */
275 private int
string_to_text(gx_device_pdf * pdev)276 string_to_text(gx_device_pdf * pdev)
277 {
278     pdf_put_string(pdev, pdev->text.buffer, pdev->text.buffer_count);
279     stream_puts(pdev->strm, (pdev->text.use_leading ? "'\n" : "Tj\n"));
280     pdev->text.use_leading = false;
281     pdev->text.buffer_count = 0;
282     return PDF_IN_TEXT;
283 }
284 /* Exit text context to stream context. */
285 private int
text_to_stream(gx_device_pdf * pdev)286 text_to_stream(gx_device_pdf * pdev)
287 {
288     stream_puts(pdev->strm, "ET Q\n");
289     pdf_reset_text(pdev);	/* because of Q */
290     return PDF_IN_STREAM;
291 }
292 /* Exit stream context. */
293 private int
stream_to_none(gx_device_pdf * pdev)294 stream_to_none(gx_device_pdf * pdev)
295 {
296     stream *s = pdev->strm;
297     long length;
298 
299     /* Close the extra q/Q for poorly designed PDF tools. */
300     stream_puts(s, "Q\n");
301     if (pdev->compression == pdf_compress_Flate) {	/* Terminate the Flate filter. */
302 	stream *fs = s->strm;
303 
304 	sclose(s);
305 	gs_free_object(pdev->pdf_memory, s->cbuf, "zlib buffer");
306 	gs_free_object(pdev->pdf_memory, s, "zlib stream");
307 	pdev->strm = s = fs;
308     }
309     length = pdf_stell(pdev) - pdev->contents_pos;
310     stream_puts(s, "endstream\n");
311     pdf_end_obj(pdev);
312     pdf_open_obj(pdev, pdev->contents_length_id);
313     pprintld1(s, "%ld\n", length);
314     pdf_end_obj(pdev);
315     return PDF_IN_NONE;
316 }
317 
318 /* Begin a page contents part. */
319 int
pdf_open_contents(gx_device_pdf * pdev,pdf_context_t context)320 pdf_open_contents(gx_device_pdf * pdev, pdf_context_t context)
321 {
322     int (*proc) (P1(gx_device_pdf *));
323 
324     while ((proc = context_procs[pdev->context][context]) != 0) {
325 	int code = (*proc) (pdev);
326 
327 	if (code < 0)
328 	    return code;
329 	pdev->context = (pdf_context_t) code;
330     }
331     pdev->context = context;
332     return 0;
333 }
334 
335 /* Close the current contents part if we are in one. */
336 int
pdf_close_contents(gx_device_pdf * pdev,bool last)337 pdf_close_contents(gx_device_pdf * pdev, bool last)
338 {
339     if (pdev->context == PDF_IN_NONE)
340 	return 0;
341     if (last) {			/* Exit from the clipping path gsave. */
342 	pdf_open_contents(pdev, PDF_IN_STREAM);
343 	stream_puts(pdev->strm, "Q\n");
344 	pdev->text.font = 0;
345     }
346     return pdf_open_contents(pdev, PDF_IN_NONE);
347 }
348 
349 /* ------ Resources et al ------ */
350 
351 /* Define the allocator descriptors for the resource types. */
352 const char *const pdf_resource_type_names[] = {
353     PDF_RESOURCE_TYPE_NAMES
354 };
355 const gs_memory_struct_type_t *const pdf_resource_type_structs[] = {
356     PDF_RESOURCE_TYPE_STRUCTS
357 };
358 
359 /* Find a resource of a given type by gs_id. */
360 pdf_resource_t *
pdf_find_resource_by_gs_id(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid)361 pdf_find_resource_by_gs_id(gx_device_pdf * pdev, pdf_resource_type_t rtype,
362 			   gs_id rid)
363 {
364     pdf_resource_t **pchain = PDF_RESOURCE_CHAIN(pdev, rtype, rid);
365     pdf_resource_t **pprev = pchain;
366     pdf_resource_t *pres;
367 
368     for (; (pres = *pprev) != 0; pprev = &pres->next)
369 	if (pres->rid == rid) {
370 	    if (pprev != pchain) {
371 		*pprev = pres->next;
372 		pres->next = *pchain;
373 		*pchain = pres;
374 	    }
375 	    return pres;
376 	}
377     return 0;
378 }
379 
380 /* Begin an object logically separate from the contents. */
381 long
pdf_open_separate(gx_device_pdf * pdev,long id)382 pdf_open_separate(gx_device_pdf * pdev, long id)
383 {
384     pdf_open_document(pdev);
385     pdev->asides.save_strm = pdev->strm;
386     pdev->strm = pdev->asides.strm;
387     return pdf_open_obj(pdev, id);
388 }
389 long
pdf_begin_separate(gx_device_pdf * pdev)390 pdf_begin_separate(gx_device_pdf * pdev)
391 {
392     return pdf_open_separate(pdev, 0L);
393 }
394 
395 /* Begin an aside (resource, annotation, ...). */
396 private 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)397 pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
398 		const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
399 		long id)
400 {
401     pdf_resource_t *pres;
402     cos_object_t *object;
403 
404     if (pst == NULL)
405 	pst = &st_pdf_resource;
406     pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
407 			   "pdf_alloc_aside(resource)");
408     object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
409     if (pres == 0 || object == 0) {
410 	return_error(gs_error_VMerror);
411     }
412     if (id < 0) {
413 	object->id = -1L;
414 	pres->rname[0] = 0;
415     } else {
416 	object->id = (id == 0 ? pdf_obj_ref(pdev) : id);
417 	sprintf(pres->rname, "R%ld", object->id);
418     }
419     pres->next = *plist;
420     *plist = pres;
421     pres->prev = pdev->last_resource;
422     pdev->last_resource = pres;
423     pres->named = false;
424     pres->where_used = pdev->used_mask;
425     pres->object = object;
426     *ppres = pres;
427     return 0;
428 }
429 int
pdf_begin_aside(gx_device_pdf * pdev,pdf_resource_t ** plist,const gs_memory_struct_type_t * pst,pdf_resource_t ** ppres)430 pdf_begin_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
431 		const gs_memory_struct_type_t * pst, pdf_resource_t ** ppres)
432 {
433     long id = pdf_begin_separate(pdev);
434 
435     if (id < 0)
436 	return (int)id;
437     return pdf_alloc_aside(pdev, plist, pst, ppres, id);
438 }
439 
440 /* Begin a resource of a given type. */
441 int
pdf_begin_resource_body(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)442 pdf_begin_resource_body(gx_device_pdf * pdev, pdf_resource_type_t rtype,
443 			gs_id rid, pdf_resource_t ** ppres)
444 {
445     int code = pdf_begin_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
446 			       pdf_resource_type_structs[rtype], ppres);
447 
448     if (code >= 0)
449 	(*ppres)->rid = rid;
450     return code;
451 }
452 int
pdf_begin_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)453 pdf_begin_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
454 		   pdf_resource_t ** ppres)
455 {
456     int code = pdf_begin_resource_body(pdev, rtype, rid, ppres);
457 
458     if (code >= 0 && pdf_resource_type_names[rtype] != 0) {
459 	stream *s = pdev->strm;
460 
461 	pprints1(s, "<</Type%s", pdf_resource_type_names[rtype]);
462 	pprintld1(s, "/Name/R%ld", (*ppres)->object->id);
463     }
464     return code;
465 }
466 
467 /* Allocate a resource, but don't open the stream. */
468 int
pdf_alloc_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres,long id)469 pdf_alloc_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
470 		   pdf_resource_t ** ppres, long id)
471 {
472     int code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
473 			       pdf_resource_type_structs[rtype], ppres, id);
474 
475     if (code >= 0)
476 	(*ppres)->rid = rid;
477     return code;
478 }
479 
480 /* Get the object id of a resource. */
481 long
pdf_resource_id(const pdf_resource_t * pres)482 pdf_resource_id(const pdf_resource_t *pres)
483 {
484     return pres->object->id;
485 }
486 
487 /* End an aside or other separate object. */
488 int
pdf_end_separate(gx_device_pdf * pdev)489 pdf_end_separate(gx_device_pdf * pdev)
490 {
491     int code = pdf_end_obj(pdev);
492 
493     pdev->strm = pdev->asides.save_strm;
494     pdev->asides.save_strm = 0;
495     return code;
496 }
497 int
pdf_end_aside(gx_device_pdf * pdev)498 pdf_end_aside(gx_device_pdf * pdev)
499 {
500     return pdf_end_separate(pdev);
501 }
502 
503 /* End a resource. */
504 int
pdf_end_resource(gx_device_pdf * pdev)505 pdf_end_resource(gx_device_pdf * pdev)
506 {
507     return pdf_end_aside(pdev);
508 }
509 
510 /*
511  * Write and release the Cos objects for resources local to a content stream.
512  * We must write all the objects before freeing any of them, because
513  * they might refer to each other.
514  */
515 int
pdf_write_resource_objects(gx_device_pdf * pdev,pdf_resource_type_t rtype)516 pdf_write_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype)
517 {
518     int j;
519 
520     /* Write objects. */
521     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
522 	pdf_resource_t *pres = pdev->resources[rtype].chains[j];
523 
524 	for (; pres != 0; pres = pres->next)
525 	    if (!pres->named && !pres->object->written)
526 		cos_write_object(pres->object, pdev);
527     }
528 
529     /* Free unnamed objects, which can't be used again. */
530     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
531 	pdf_resource_t **prev = &pdev->resources[rtype].chains[j];
532 	pdf_resource_t *pres;
533 
534 	while ((pres = *prev) != 0) {
535 	    if (pres->named) {	/* named, don't free */
536 		prev = &pres->next;
537 	    } else {
538 		cos_free(pres->object, "pdf_write_resource_objects");
539 		pres->object = 0;
540 		*prev = pres->next;
541 	    }
542 	}
543     }
544 
545     return 0;
546 }
547 
548 /*
549  * Store the resource sets for a content stream (page or XObject).
550  * Sets page->{procsets, resource_ids[]}.
551  */
552 int
pdf_store_page_resources(gx_device_pdf * pdev,pdf_page_t * page)553 pdf_store_page_resources(gx_device_pdf *pdev, pdf_page_t *page)
554 {
555 
556     /* Write out any resource dictionaries. */
557 
558     {
559 	int i;
560 
561 	for (i = 0; i <= resourceFont; ++i) {
562 	    stream *s = 0;
563 	    int j;
564 
565 	    page->resource_ids[i] = 0;
566 	    for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
567 		pdf_resource_t *pres = pdev->resources[i].chains[j];
568 
569 		for (; pres != 0; pres = pres->next) {
570 		    if (pres->where_used & pdev->used_mask) {
571 			long id = pres->object->id;
572 
573 			if (s == 0) {
574 			    page->resource_ids[i] = pdf_begin_separate(pdev);
575 			    s = pdev->strm;
576 			    stream_puts(s, "<<");
577 			}
578 			pprints1(s, "/%s\n", pres->rname);
579 			pprintld1(s, "%ld 0 R", id);
580 			pres->where_used -= pdev->used_mask;
581 		    }
582 		}
583 	    }
584 	    if (s) {
585 		stream_puts(s, ">>\n");
586 		pdf_end_separate(pdev);
587 		if (i != resourceFont)
588 		    pdf_write_resource_objects(pdev, i);
589 	    }
590 	}
591     }
592 
593     page->procsets = pdev->procsets;
594     return 0;
595 }
596 
597 /* Copy data from a temporary file to a stream. */
598 void
pdf_copy_data(stream * s,FILE * file,long count)599 pdf_copy_data(stream *s, FILE *file, long count)
600 {
601     long left = count;
602     byte buf[sbuf_size];
603 
604     while (left > 0) {
605 	uint copy = min(left, sbuf_size);
606 
607 	fread(buf, 1, sbuf_size, file);
608 	stream_write(s, buf, copy);
609 	left -= copy;
610     }
611 }
612 
613 /* ------ Pages ------ */
614 
615 /* Get or assign the ID for a page. */
616 /* Returns 0 if the page number is out of range. */
617 long
pdf_page_id(gx_device_pdf * pdev,int page_num)618 pdf_page_id(gx_device_pdf * pdev, int page_num)
619 {
620     cos_dict_t *Page;
621 
622     if (page_num < 1)
623 	return 0;
624     if (page_num >= pdev->num_pages) {	/* Grow the pages array. */
625 	uint new_num_pages =
626 	    max(page_num + 10, pdev->num_pages << 1);
627 	pdf_page_t *new_pages =
628 	    gs_resize_object(pdev->pdf_memory, pdev->pages, new_num_pages,
629 			     "pdf_page_id(resize pages)");
630 
631 	if (new_pages == 0)
632 	    return 0;
633 	memset(&new_pages[pdev->num_pages], 0,
634 	       (new_num_pages - pdev->num_pages) * sizeof(pdf_page_t));
635 	pdev->pages = new_pages;
636 	pdev->num_pages = new_num_pages;
637     }
638     if ((Page = pdev->pages[page_num - 1].Page) == 0) {
639 	pdev->pages[page_num - 1].Page = Page =
640 	    cos_dict_alloc(pdev, "pdf_page_id");
641 	Page->id = pdf_obj_ref(pdev);
642     }
643     return Page->id;
644 }
645 
646 /* Get the page structure for the current page. */
647 pdf_page_t *
pdf_current_page(gx_device_pdf * pdev)648 pdf_current_page(gx_device_pdf *pdev)
649 {
650     return &pdev->pages[pdev->next_page];
651 }
652 
653 /* Get the dictionary object for the current page. */
654 cos_dict_t *
pdf_current_page_dict(gx_device_pdf * pdev)655 pdf_current_page_dict(gx_device_pdf *pdev)
656 {
657     if (pdf_page_id(pdev, pdev->next_page + 1) <= 0)
658 	return 0;
659     return pdev->pages[pdev->next_page].Page;
660 }
661 
662 /* Write saved page- or document-level information. */
663 int
pdf_write_saved_string(gx_device_pdf * pdev,gs_string * pstr)664 pdf_write_saved_string(gx_device_pdf * pdev, gs_string * pstr)
665 {
666     if (pstr->data != 0) {
667 	stream_write(pdev->strm, pstr->data, pstr->size);
668 	gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
669 		       "pdf_write_saved_string");
670 	pstr->data = 0;
671     }
672     return 0;
673 }
674 
675 /* Open a page for writing. */
676 int
pdf_open_page(gx_device_pdf * pdev,pdf_context_t context)677 pdf_open_page(gx_device_pdf * pdev, pdf_context_t context)
678 {
679     if (!is_in_page(pdev)) {
680 	if (pdf_page_id(pdev, pdev->next_page + 1) == 0)
681 	    return_error(gs_error_VMerror);
682 	pdf_open_document(pdev);
683     }
684     /* Note that context may be PDF_IN_NONE here. */
685     return pdf_open_contents(pdev, context);
686 }
687 
688 /* ------ Miscellaneous output ------ */
689 
690 /* Generate the default Producer string. */
691 void
pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])692 pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])
693 {
694     sprintf(buf, ((gs_revision % 100) == 0 ? "(%s %1.1f)" : "(%s %1.2f)"),
695 	    gs_product, gs_revision / 100.0);
696 }
697 
698 /* Write matrix values. */
699 void
pdf_put_matrix(gx_device_pdf * pdev,const char * before,const gs_matrix * pmat,const char * after)700 pdf_put_matrix(gx_device_pdf * pdev, const char *before,
701 	       const gs_matrix * pmat, const char *after)
702 {
703     stream *s = pdev->strm;
704 
705     if (before)
706 	stream_puts(s, before);
707     pprintg6(s, "%g %g %g %g %g %g ",
708 	     pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
709     if (after)
710 	stream_puts(s, after);
711 }
712 
713 /*
714  * Write a name, with escapes for unusual characters.  In PDF 1.1, we have
715  * no choice but to replace these characters with '?'; in PDF 1.2, we can
716  * use an escape sequence for anything except a null <00>.
717  */
718 private int
pdf_put_name_chars_1_1(stream * s,const byte * nstr,uint size)719 pdf_put_name_chars_1_1(stream *s, const byte *nstr, uint size)
720 {
721     uint i;
722 
723     for (i = 0; i < size; ++i) {
724 	uint c = nstr[i];
725 
726 	switch (c) {
727 	    default:
728 		if (c >= 0x21 && c <= 0x7e) {
729 		    stream_putc(s, c);
730 		    break;
731 		}
732 		/* falls through */
733 	    case '%':
734 	    case '(': case ')':
735 	    case '<': case '>':
736 	    case '[': case ']':
737 	    case '{': case '}':
738 	    case '/':
739 	    case 0:
740 		stream_putc(s, '?');
741 	}
742     }
743     return 0;
744 }
745 private int
pdf_put_name_chars_1_2(stream * s,const byte * nstr,uint size)746 pdf_put_name_chars_1_2(stream *s, const byte *nstr, uint size)
747 {
748     uint i;
749 
750     for (i = 0; i < size; ++i) {
751 	uint c = nstr[i];
752 	char hex[4];
753 
754 	switch (c) {
755 	    default:
756 		if (c >= 0x21 && c <= 0x7e) {
757 		    stream_putc(s, c);
758 		    break;
759 		}
760 		/* falls through */
761 	    case '#':
762 	    case '%':
763 	    case '(': case ')':
764 	    case '<': case '>':
765 	    case '[': case ']':
766 	    case '{': case '}':
767 	    case '/':
768 		sprintf(hex, "#%02x", c);
769 		stream_puts(s, hex);
770 		break;
771 	    case 0:
772 		stream_putc(s, '?');
773 	}
774     }
775     return 0;
776 }
777 pdf_put_name_chars_proc_t
pdf_put_name_chars_proc(const gx_device_pdf * pdev)778 pdf_put_name_chars_proc(const gx_device_pdf *pdev)
779 {
780     return (pdev->CompatibilityLevel >= 1.2 ? pdf_put_name_chars_1_2 :
781 	    pdf_put_name_chars_1_1);
782 }
783 void
pdf_put_name_chars(const gx_device_pdf * pdev,const byte * nstr,uint size)784 pdf_put_name_chars(const gx_device_pdf *pdev, const byte *nstr, uint size)
785 {
786     DISCARD(pdf_put_name_chars_proc(pdev)(pdev->strm, nstr, size));
787 }
788 void
pdf_put_name(const gx_device_pdf * pdev,const byte * nstr,uint size)789 pdf_put_name(const gx_device_pdf *pdev, const byte *nstr, uint size)
790 {
791     stream_putc(pdev->strm, '/');
792     pdf_put_name_chars(pdev, nstr, size);
793 }
794 
795 /*
796  * Write a string in its shortest form ( () or <> ).  Note that
797  * this form is different depending on whether binary data are allowed.
798  * We wish PDF supported ASCII85 strings ( <~ ~> ), but it doesn't.
799  */
800 void
pdf_put_string(const gx_device_pdf * pdev,const byte * str,uint size)801 pdf_put_string(const gx_device_pdf * pdev, const byte * str, uint size)
802 {
803     psdf_write_string(pdev->strm, str, size,
804 		      (pdev->binary_ok ? PRINT_BINARY_OK : 0));
805 }
806 
807 /* Write a value, treating names specially. */
808 void
pdf_write_value(const gx_device_pdf * pdev,const byte * vstr,uint size)809 pdf_write_value(const gx_device_pdf * pdev, const byte * vstr, uint size)
810 {
811     if (size > 0 && vstr[0] == '/')
812 	pdf_put_name(pdev, vstr + 1, size - 1);
813     else
814 	stream_write(pdev->strm, vstr, size);
815 }
816 
817 /* Store filters for a stream. */
818 /* Currently this only saves parameters for CCITTFaxDecode. */
819 int
pdf_put_filters(cos_dict_t * pcd,gx_device_pdf * pdev,stream * s,const pdf_filter_names_t * pfn)820 pdf_put_filters(cos_dict_t *pcd, gx_device_pdf *pdev, stream *s,
821 		const pdf_filter_names_t *pfn)
822 {
823     const char *filter_name = 0;
824     bool binary_ok = true;
825     stream *fs = s;
826     cos_dict_t *decode_parms = 0;
827     int code;
828 
829     for (; fs != 0; fs = fs->strm) {
830 	const stream_state *st = fs->state;
831 	const stream_template *template = st->template;
832 
833 #define TEMPLATE_IS(atemp)\
834   (template->process == (atemp).process)
835 	if (TEMPLATE_IS(s_A85E_template))
836 	    binary_ok = false;
837 	else if (TEMPLATE_IS(s_CFE_template)) {
838 	    cos_param_list_writer_t writer;
839 	    stream_CF_state cfs;
840 
841 	    decode_parms =
842 		cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
843 	    if (decode_parms == 0)
844 		return_error(gs_error_VMerror);
845 	    CHECK(cos_param_list_writer_init(&writer, decode_parms, 0));
846 	    /*
847 	     * If EndOfBlock is true, we mustn't write out a Rows value.
848 	     * This is a hack....
849 	     */
850 	    cfs = *(const stream_CF_state *)st;
851 	    if (cfs.EndOfBlock)
852 		cfs.Rows = 0;
853 	    CHECK(s_CF_get_params((gs_param_list *)&writer, &cfs, false));
854 	    filter_name = pfn->CCITTFaxDecode;
855 	} else if (TEMPLATE_IS(s_DCTE_template))
856 	    filter_name = pfn->DCTDecode;
857 	else if (TEMPLATE_IS(s_zlibE_template))
858 	    filter_name = pfn->FlateDecode;
859 	else if (TEMPLATE_IS(s_LZWE_template))
860 	    filter_name = pfn->LZWDecode;
861 	else if (TEMPLATE_IS(s_PNGPE_template)) {
862 	    /* This is a predictor for FlateDecode or LZWEncode. */
863 	    const stream_PNGP_state *const ss =
864 		(const stream_PNGP_state *)st;
865 
866 	    decode_parms =
867 		cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
868 	    if (decode_parms == 0)
869 		return_error(gs_error_VMerror);
870 	    CHECK(cos_dict_put_c_key_int(decode_parms, "/Predictor",
871 					 ss->Predictor));
872 	    CHECK(cos_dict_put_c_key_int(decode_parms, "/Columns",
873 					 ss->Columns));
874 	    if (ss->Colors != 1)
875 		CHECK(cos_dict_put_c_key_int(decode_parms, "/Colors",
876 					     ss->Colors));
877 	    if (ss->BitsPerComponent != 8)
878 		CHECK(cos_dict_put_c_key_int(decode_parms,
879 					     "/BitsPerComponent",
880 					     ss->BitsPerComponent));
881 	} else if (TEMPLATE_IS(s_RLE_template))
882 	    filter_name = pfn->RunLengthDecode;
883 #undef TEMPLATE_IS
884     }
885     if (filter_name) {
886 	if (binary_ok) {
887 	    CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, filter_name));
888 	    if (decode_parms)
889 		CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
890 						COS_OBJECT(decode_parms)));
891 	} else {
892 	    cos_array_t *pca =
893 		cos_array_alloc(pdev, "pdf_put_image_filters(Filters)");
894 
895 	    if (pca == 0)
896 		return_error(gs_error_VMerror);
897 	    CHECK(cos_array_add_c_string(pca, pfn->ASCII85Decode));
898 	    CHECK(cos_array_add_c_string(pca, filter_name));
899 	    CHECK(cos_dict_put_c_key_object(pcd, pfn->Filter,
900 					    COS_OBJECT(pca)));
901 	    if (decode_parms) {
902 		pca = cos_array_alloc(pdev,
903 				      "pdf_put_image_filters(DecodeParms)");
904 		if (pca == 0)
905 		    return_error(gs_error_VMerror);
906 		CHECK(cos_array_add_c_string(pca, "null"));
907 		CHECK(cos_array_add_object(pca, COS_OBJECT(decode_parms)));
908 		CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
909 						COS_OBJECT(pca)));
910 	    }
911 	}
912     } else if (!binary_ok)
913 	CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, pfn->ASCII85Decode));
914     return 0;
915 }
916 
917 /* Add a Flate compression filter to a binary writer. */
918 private int
pdf_flate_binary(gx_device_pdf * pdev,psdf_binary_writer * pbw)919 pdf_flate_binary(gx_device_pdf *pdev, psdf_binary_writer *pbw)
920 {
921     const stream_template *template = &s_zlibE_template;
922     stream_state *st = s_alloc_state(pdev->pdf_memory, template->stype,
923 				     "pdf_write_function");
924 
925     if (st == 0)
926 	return_error(gs_error_VMerror);
927     if (template->set_defaults)
928 	template->set_defaults(st);
929     return psdf_encode_binary(pbw, template, st);
930 }
931 
932 /*
933  * Begin a data stream.  The client has opened the object and written
934  * the << and any desired dictionary keys.
935  */
936 int
pdf_begin_data_binary(gx_device_pdf * pdev,pdf_data_writer_t * pdw,bool data_is_binary)937 pdf_begin_data_binary(gx_device_pdf *pdev, pdf_data_writer_t *pdw,
938 		      bool data_is_binary)
939 {
940     long length_id = pdf_obj_ref(pdev);
941     stream *s = pdev->strm;
942 #define USE_ASCII85 1
943 #define USE_FLATE 2
944     static const char *const fnames[4] = {
945 	"", "/Filter/ASCII85Decode", "/Filter/FlateDecode",
946 	"/Filter[/ASCII85Decode/FlateDecode]"
947     };
948     int filters = 0;
949     int code;
950 
951     if (pdev->CompatibilityLevel >= 1.2) {
952 	filters |= USE_FLATE;
953 	data_is_binary = true;
954     }
955     if (data_is_binary && !pdev->binary_ok)
956 	filters |= USE_ASCII85;
957     stream_puts(s, fnames[filters]);
958     pprintld1(s, "/Length %ld 0 R>>stream\n", length_id);
959     code = psdf_begin_binary((gx_device_psdf *)pdev, &pdw->binary);
960     if (code < 0)
961 	return code;
962     pdw->start = stell(s);
963     pdw->length_id = length_id;
964     if (filters & USE_FLATE)
965 	code = pdf_flate_binary(pdev, &pdw->binary);
966     return code;
967 #undef USE_ASCII85
968 #undef USE_FLATE
969 }
970 
971 /* End a data stream. */
972 int
pdf_end_data(pdf_data_writer_t * pdw)973 pdf_end_data(pdf_data_writer_t *pdw)
974 {
975     gx_device_pdf *pdev = (gx_device_pdf *)pdw->binary.dev;
976     int code = psdf_end_binary(&pdw->binary);
977     long length = stell(pdev->strm) - pdw->start;
978 
979     if (code < 0)
980 	return code;
981     stream_puts(pdev->strm, "\nendstream\n");
982     pdf_end_separate(pdev);
983     pdf_open_separate(pdev, pdw->length_id);
984     pprintld1(pdev->strm, "%ld\n", length);
985     return pdf_end_separate(pdev);
986 }
987 
988 /* Create a Function object. */
989 int
pdf_function(gx_device_pdf * pdev,const gs_function_t * pfn,cos_value_t * pvalue)990 pdf_function(gx_device_pdf *pdev, const gs_function_t *pfn,
991 	     cos_value_t *pvalue)
992 {
993     gs_function_info_t info;
994     cos_param_list_writer_t rlist;
995     pdf_resource_t *pres;
996     cos_object_t *pcfn;
997     cos_dict_t *pcd;
998     cos_value_t v;
999     int code = pdf_alloc_resource(pdev, resourceFunction, gs_no_id, &pres, 0L);
1000 
1001     if (code < 0)
1002 	return code;
1003     pcfn = pres->object;
1004     gs_function_get_info(pfn, &info);
1005     if (info.DataSource != 0) {
1006 	psdf_binary_writer writer;
1007 	stream *save = pdev->strm;
1008 	cos_stream_t *pcos;
1009 	stream *s;
1010 
1011 	cos_become(pcfn, cos_type_stream);
1012 	pcos = (cos_stream_t *)pcfn;
1013 	pcd = cos_stream_dict(pcos);
1014 	s = cos_write_stream_alloc(pcos, pdev, "pdf_function");
1015 	if (s == 0)
1016 	    return_error(gs_error_VMerror);
1017 	pdev->strm = s;
1018 	code = psdf_begin_binary((gx_device_psdf *)pdev, &writer);
1019 	if (code >= 0 && info.data_size > 30 &&	/* 30 is arbitrary */
1020 	    pdev->CompatibilityLevel >= 1.2
1021 	    )
1022 	    code = pdf_flate_binary(pdev, &writer);
1023 	if (code >= 0) {
1024 	    static const pdf_filter_names_t fnames = {
1025 		PDF_FILTER_NAMES
1026 	    };
1027 
1028 	    code = pdf_put_filters(pcd, pdev, writer.strm, &fnames);
1029 	}
1030 	if (code >= 0) {
1031 	    byte buf[100];		/* arbitrary */
1032 	    ulong pos;
1033 	    uint count;
1034 	    const byte *ptr;
1035 
1036 	    for (pos = 0; pos < info.data_size; pos += count) {
1037 		count = min(sizeof(buf), info.data_size - pos);
1038 		data_source_access_only(info.DataSource, pos, count, buf,
1039 					&ptr);
1040 		stream_write(writer.strm, ptr, count);
1041 	    }
1042 	    code = psdf_end_binary(&writer);
1043 	    sclose(s);
1044 	}
1045 	pdev->strm = save;
1046 	if (code < 0)
1047 	    return code;
1048     } else {
1049 	cos_become(pcfn, cos_type_dict);
1050 	pcd = (cos_dict_t *)pcfn;
1051     }
1052     if (info.Functions != 0) {
1053 	int i;
1054 	cos_array_t *functions =
1055 	    cos_array_alloc(pdev, "pdf_function(Functions)");
1056 
1057 	if (functions == 0)
1058 	    return_error(gs_error_VMerror);
1059 	for (i = 0; i < info.num_Functions; ++i) {
1060 	    if ((code = pdf_function(pdev, info.Functions[i], &v)) < 0 ||
1061 		(code = cos_array_add(functions, &v)) < 0
1062 		) {
1063 		COS_FREE(functions, "pdf_function(Functions)");
1064 		return code;
1065 	    }
1066 	}
1067 	code = cos_dict_put_c_key(pcd, "/Functions",
1068 				  COS_OBJECT_VALUE(&v, functions));
1069 	if (code < 0) {
1070 	    COS_FREE(functions, "pdf_function(Functions)");
1071 	    return code;
1072 	}
1073     }
1074     code = cos_param_list_writer_init(&rlist, pcd, PRINT_BINARY_OK);
1075     if (code < 0)
1076 	return code;
1077     code = gs_function_get_params(pfn, (gs_param_list *)&rlist);
1078     if (code < 0)
1079 	return code;
1080     COS_OBJECT_VALUE(pvalue, pcd);
1081     return 0;
1082 }
1083 
1084 /* Write a Function object. */
1085 int
pdf_write_function(gx_device_pdf * pdev,const gs_function_t * pfn,long * pid)1086 pdf_write_function(gx_device_pdf *pdev, const gs_function_t *pfn, long *pid)
1087 {
1088     cos_value_t value;
1089     int code = pdf_function(pdev, pfn, &value);
1090 
1091     if (code < 0)
1092 	return code;
1093     *pid = value.contents.object->id;
1094     return 0;
1095 }
1096