~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to src/gdevpdfu.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

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