Coverage Report

Created: 2022-10-31 07:00

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