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