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