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