Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpdfm.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
/* pdfmark processing for PDF-writing driver */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsutil.h"   /* for bytes_compare */
23
#include "gdevpdfx.h"
24
#include "gdevpdfo.h"
25
#include "szlibx.h"
26
#include "slzwx.h"
27
28
/* GC descriptors */
29
private_st_pdf_article();
30
31
/*
32
 * The pdfmark pseudo-parameter indicates the occurrence of a pdfmark
33
 * operator in the input file.  Its "value" is the arguments of the operator,
34
 * passed through essentially unchanged:
35
 *      (key, value)*, CTM, type
36
 */
37
38
/*
39
 * Define an entry in a table of pdfmark-processing procedures.
40
 * (The actual table is at the end of this file, to avoid the need for
41
 * forward declarations for the procedures.)
42
 */
43
65.2k
#define PDFMARK_NAMEABLE 1  /* allows _objdef */
44
65.2k
#define PDFMARK_ODD_OK 2  /* OK if odd # of parameters */
45
65.2k
#define PDFMARK_KEEP_NAME 4  /* don't substitute reference for name */
46
                                /* in 1st argument */
47
65.2k
#define PDFMARK_NO_REFS 8  /* don't substitute references for names */
48
                                /* anywhere */
49
65.2k
#define PDFMARK_TRUECTM 16  /* pass the true CTM to the procedure, */
50
                                /* not the one transformed to reflect the default user space */
51
typedef struct pdfmark_name_s {
52
    const char *mname;
53
    pdfmark_proc((*proc));
54
    byte options;
55
} pdfmark_name;
56
57
/* ---------------- Public utilities ---------------- */
58
59
/* Compare a C string and a gs_param_string. */
60
bool
61
pdf_key_eq(const gs_param_string * pcs, const char *str)
62
6.68M
{
63
6.68M
    return (strlen(str) == pcs->size && pcs->data &&
64
6.68M
            !strncmp(str, (const char *)pcs->data, pcs->size));
65
6.68M
}
66
67
/* Scan an integer out of a parameter string. */
68
int
69
pdfmark_scan_int(const gs_param_string * pstr, int *pvalue)
70
7.13k
{
71
7.13k
#define MAX_INT_STR 20
72
7.13k
    uint size = pstr->size;
73
7.13k
    char str[MAX_INT_STR + 1];
74
75
7.13k
    if (size > MAX_INT_STR)
76
0
        return_error(gs_error_limitcheck);
77
7.13k
    memcpy(str, pstr->data, size);
78
7.13k
    str[size] = 0;
79
7.13k
    return (sscanf(str, "%d", pvalue) == 1 ? 0 :
80
7.13k
            gs_note_error(gs_error_rangecheck));
81
7.13k
#undef MAX_INT_STR
82
7.13k
}
83
84
/* ---------------- Private utilities ---------------- */
85
86
/* Find a key in a dictionary. */
87
static bool
88
pdfmark_find_key(const char *key, const gs_param_string * pairs, uint count,
89
                 gs_param_string * pstr)
90
21.3k
{
91
21.3k
    uint i;
92
93
166k
    for (i = 0; i < count; i += 2)
94
159k
        if (pdf_key_eq(&pairs[i], key)) {
95
14.2k
            *pstr = pairs[i + 1];
96
14.2k
            return true;
97
14.2k
        }
98
7.10k
    pstr->data = 0;
99
7.10k
    pstr->size = 0;
100
7.10k
    return false;
101
21.3k
}
102
103
/*
104
 * Get the page number for a page referenced by number or as /Next or /Prev.
105
 * The result may be 0 if the page number is 0 or invalid.
106
 */
107
static int
108
pdfmark_page_number(gx_device_pdf * pdev, const gs_param_string * pnstr)
109
7.10k
{
110
7.10k
    int page = pdev->next_page + 1;
111
112
7.10k
    if (pnstr->data == 0);
113
7.10k
    else if (pdf_key_eq(pnstr, "/Next"))
114
0
        ++page;
115
7.10k
    else if (pdf_key_eq(pnstr, "/Prev"))
116
0
        --page;
117
7.10k
    else if (pdfmark_scan_int(pnstr, &page) < 0)
118
0
        page = 0;
119
7.10k
    return page;
120
7.10k
}
121
122
/*
123
 * This routine checks the page number is inside the valid range FirstPage->LastPage
124
 * and if it is, and FirstPage is not 0, it updates the page number by rebasing it to
125
 * the new FirstPage. If all conditions are met we also update the 'max_referred_page'
126
 * which we check during closedown, and emit a warning if a reference should somehow
127
 * point outside the valid range of pages in the document. This can happen if we reference
128
 * a destination page that we haven't created yet, and when we get to the end of the
129
 * job we discover we never did create it.
130
 */
131
static int
132
update_max_page_reference(gx_device_pdf * pdev, int *page)
133
7.10k
{
134
7.10k
    if (*page < pdev->FirstPage || (pdev->LastPage != 0 && *page > pdev->LastPage)) {
135
0
        emprintf1(pdev->memory, "Destination page %d lies outside the valid page range.\n", *page);
136
0
        return -1;
137
0
    }
138
7.10k
    else {
139
7.10k
        if (pdev->FirstPage != 0)
140
0
            *page = (*page - pdev->FirstPage) + 1;
141
142
7.10k
        if (pdev->max_referred_page < *page)
143
422
            pdev->max_referred_page = *page;
144
7.10k
    }
145
7.10k
    return 0;
146
7.10k
}
147
148
/* Construct a destination string specified by /Page and/or /View. */
149
/* Return 0 if none (but still fill in a default), 1 or 2 if present */
150
/* (1 if only one of /Page or /View, 2 if both), <0 if error. */
151
static int
152
pdfmark_make_dest(char dstr[MAX_DEST_STRING], gx_device_pdf * pdev,
153
                  const char *Page_key, const char *View_key,
154
                  const gs_param_string * pairs, uint count, uint RequirePage)
155
7.10k
{
156
7.10k
    gs_param_string page_string, view_string;
157
7.10k
    int present =
158
7.10k
        pdfmark_find_key(Page_key, pairs, count, &page_string) +
159
7.10k
        pdfmark_find_key(View_key, pairs, count, &view_string);
160
7.10k
    int page=0;
161
7.10k
    gs_param_string action;
162
7.10k
    int len, code = 0;
163
164
7.10k
    if (present || RequirePage)
165
7.10k
        page = pdfmark_page_number(pdev, &page_string);
166
167
7.10k
    if (view_string.size == 0)
168
0
        param_string_from_string(view_string, "[/XYZ null null null]");
169
7.10k
    if (page == 0)
170
0
        strcpy(dstr, "[null ");
171
7.10k
    else if (pdfmark_find_key("/Action", pairs, count, &action) &&
172
7.10k
             pdf_key_eq(&action, "/GoToR")
173
7.10k
        )
174
0
        gs_snprintf(dstr, MAX_DEST_STRING, "[%d ", page - 1);
175
7.10k
    else {
176
7.10k
        code = update_max_page_reference(pdev, &page);
177
7.10k
        if (code < 0)
178
0
            return code;
179
7.10k
        gs_snprintf(dstr, MAX_DEST_STRING, "[%ld 0 R ", pdf_page_id(pdev, page));
180
7.10k
    }
181
7.10k
    len = strlen(dstr);
182
7.10k
    if (len + view_string.size > MAX_DEST_STRING)
183
0
        return_error(gs_error_limitcheck);
184
7.10k
    if (view_string.data[0] != '[' ||
185
7.10k
        view_string.data[view_string.size - 1] != ']'
186
7.10k
        )
187
0
        return_error(gs_error_rangecheck);
188
7.10k
    memcpy(dstr + len, view_string.data + 1, view_string.size - 1);
189
7.10k
    dstr[len + view_string.size - 1] = 0;
190
7.10k
    return present;
191
7.10k
}
192
193
/*
194
 * If a named destination is specified by a string, convert it to a name,
195
 * update *dstr, and return 1; otherwise return 0.
196
 */
197
static int
198
pdfmark_coerce_dest(gs_param_string *dstr, char dest[MAX_DEST_STRING])
199
0
{
200
0
    const byte *data = dstr->data;
201
0
    uint size = dstr->size;
202
0
    if (size == 0 || data[0] != '(')
203
0
        return 0;
204
    /****** HANDLE ESCAPES ******/
205
0
    memcpy(dest, data, size - 1);
206
0
    dest[0] = '/';
207
0
    dest[size - 1] = 0;
208
0
    dstr->data = (byte *)dest;
209
0
    dstr->size = size - 1;
210
0
    return 1;
211
0
}
212
213
/* Put pairs in a dictionary. */
214
static int
215
pdfmark_put_c_pair(cos_dict_t *pcd, const char *key,
216
                   const gs_param_string * pvalue)
217
64.4k
{
218
64.4k
    return cos_dict_put_c_key_string(pcd, key, pvalue->data, pvalue->size);
219
64.4k
}
220
static int
221
pdfmark_put_pair(cos_dict_t *pcd, const gs_param_string * pair)
222
305k
{
223
305k
    return cos_dict_put_string(pcd, pair->data, pair->size,
224
305k
                               pair[1].data, pair[1].size);
225
305k
}
226
227
/* Scan a Rect value. */
228
static int
229
pdfmark_scan_rect(gs_rect * prect, const gs_param_string * str,
230
                  const gs_matrix * pctm)
231
57.3k
{
232
57.3k
    uint size = str->size;
233
57.3k
    double v[4];
234
114k
#define MAX_RECT_STRING 100
235
57.3k
    char chars[MAX_RECT_STRING + 3];
236
57.3k
    int end_check;
237
238
57.3k
    if (str->size > MAX_RECT_STRING)
239
0
        return_error(gs_error_limitcheck);
240
57.3k
    memcpy(chars, str->data, size);
241
57.3k
    strcpy(chars + size, " 0");
242
57.3k
    if (sscanf(chars, "[%lg %lg %lg %lg]%d",
243
57.3k
               &v[0], &v[1], &v[2], &v[3], &end_check) != 5
244
57.3k
        )
245
12
        return_error(gs_error_rangecheck);
246
57.3k
    gs_point_transform(v[0], v[1], pctm, &prect->p);
247
57.3k
    gs_point_transform(v[2], v[3], pctm, &prect->q);
248
57.3k
    return 0;
249
57.3k
}
250
251
/* Make a Rect value. */
252
static void
253
pdfmark_make_rect(char str[MAX_RECT_STRING], const gs_rect * prect)
254
57.3k
{
255
    /*
256
     * We have to use a stream and pprintf, rather than sprintf,
257
     * because printf formats can't express the PDF restrictions on
258
     * the form of the output.
259
     */
260
57.3k
    stream s;
261
262
57.3k
    s_init(&s, NULL);
263
57.3k
    swrite_string(&s, (byte *)str, MAX_RECT_STRING - 1);
264
57.3k
    pprintg4(&s, "[%g %g %g %g]",
265
57.3k
             prect->p.x, prect->p.y, prect->q.x, prect->q.y);
266
57.3k
    str[stell(&s)] = 0;
267
57.3k
}
268
269
16.1k
#define MAX_BORDER_STRING 100
270
/* Write a transformed Border value on a stream. */
271
static int
272
pdfmark_write_border(stream *s, const gs_param_string *str,
273
                     const gs_matrix *pctm)
274
8.07k
{
275
8.07k
    int i;
276
277
73.7k
    for (i = 0; i < str->size; i++)
278
65.6k
        stream_putc(s, str->data[i]);
279
8.07k
    return 0;
280
8.07k
}
281
282
/* Put an element in a stream's dictionary. */
283
static int
284
cos_stream_put_c_strings(cos_stream_t *pcs, const char *key, const char *value)
285
0
{
286
0
    return cos_dict_put_c_strings(cos_stream_dict(pcs), key, value);
287
0
}
288
289
static int
290
setup_pdfmark_stream_no_compression(gx_device_psdf *pdev0,
291
                        cos_stream_t *pco)
292
0
{
293
    /* This function is for pdfwrite only. */
294
0
    gx_device_pdf *pdev = (gx_device_pdf *)pdev0;
295
0
    gs_memory_t *mem = pdev->pdf_memory;
296
297
0
    pco->input_strm = cos_write_stream_alloc(pco, pdev,
298
0
                                  "setup_pdfmark_stream_compression");
299
0
    if (pco->input_strm == 0)
300
0
        return_error(gs_error_VMerror);
301
0
    if (!pdev->binary_ok) {
302
0
        stream_state *ss = s_alloc_state(mem, s_A85E_template.stype,
303
0
                          "setup_pdfmark_stream_compression");
304
0
        if (ss == 0)
305
0
            return_error(gs_error_VMerror);
306
0
        if (s_add_filter(&pco->input_strm, &s_A85E_template, ss, mem) == 0) {
307
0
            gs_free_object(mem, ss, "setup_image_compression");
308
0
            return_error(gs_error_VMerror);
309
0
        }
310
0
    }
311
0
    return 0;
312
0
}
313
314
/* Setup pdfmak stream compression. */
315
static int
316
setup_pdfmark_stream_compression(gx_device_psdf *pdev0,
317
                        cos_stream_t *pco)
318
25
{
319
    /* This function is for pdfwrite only. */
320
25
    gx_device_pdf *pdev = (gx_device_pdf *)pdev0;
321
25
    gs_memory_t *mem = pdev->pdf_memory;
322
25
    static const pdf_filter_names_t fnames = {
323
25
        PDF_FILTER_NAMES
324
25
    };
325
25
    const stream_template *templat =
326
25
        (pdev->params.UseFlateCompression &&
327
25
         pdev->version >= psdf_version_ll3 ?
328
25
         &s_zlibE_template : &s_LZWE_template);
329
25
    stream_state *st;
330
331
25
    pco->input_strm = cos_write_stream_alloc(pco, pdev,
332
25
                                  "setup_pdfmark_stream_compression");
333
25
    if (pco->input_strm == 0)
334
0
        return_error(gs_error_VMerror);
335
25
    if (!pdev->binary_ok) {
336
0
        stream_state *ss = s_alloc_state(mem, s_A85E_template.stype,
337
0
                          "setup_pdfmark_stream_compression");
338
0
        if (ss == 0)
339
0
            return_error(gs_error_VMerror);
340
0
        if (s_add_filter(&pco->input_strm, &s_A85E_template, ss, mem) == 0) {
341
0
            gs_free_object(mem, ss, "setup_image_compression");
342
0
            return_error(gs_error_VMerror);
343
0
        }
344
0
    }
345
25
    st = s_alloc_state(mem, templat->stype,
346
25
                            "setup_pdfmark_stream_compression");
347
25
    if (st == 0)
348
0
        return_error(gs_error_VMerror);
349
25
    if (templat->set_defaults)
350
25
        (*templat->set_defaults) (st);
351
25
    if (s_add_filter(&pco->input_strm, templat, st, mem) == 0) {
352
0
        gs_free_object(mem, st, "setup_image_compression");
353
0
        return_error(gs_error_VMerror);
354
0
    }
355
25
    return pdf_put_filters(cos_stream_dict(pco), pdev, pco->input_strm, &fnames);
356
25
}
357
358
static int
359
pdfmark_bind_named_object(gx_device_pdf *pdev, const gs_const_string *objname,
360
                          pdf_resource_t **pres)
361
0
{
362
0
    int code;
363
364
0
    if (objname != NULL && objname->size) {
365
0
        const cos_value_t *v = cos_dict_find(pdev->local_named_objects, objname->data, objname->size);
366
367
0
        if (v != NULL) {
368
0
            if (v->value_type == COS_VALUE_OBJECT) {
369
0
                if (cos_type(v->contents.object) == &cos_generic_procs) {
370
                    /* The object was referred but not defined.
371
                       Use the old object id.
372
                       The old object stub to be dropped. */
373
0
                    pdf_reserve_object_id(pdev, *pres, v->contents.object->id);
374
0
                } else if (!v->contents.object->written) {
375
                    /* We can't know whether the old object was referred or not.
376
                       Write it out for a consistent result in any case. */
377
0
                    code = cos_write_object(v->contents.object, pdev, resourceOther);
378
379
0
                    if (code < 0)
380
0
                        return code;
381
0
                    v->contents.object->written = true;
382
0
                }
383
0
            } else
384
0
                return_error(gs_error_rangecheck); /* Must not happen. */
385
0
        }
386
0
    }
387
0
    if ((*pres)->object->id == -1) {
388
0
        if(objname != NULL && objname->size)
389
0
            code = pdf_substitute_resource(pdev, pres, resourceXObject, NULL, false);
390
0
        else
391
0
            code = pdf_substitute_resource(pdev, pres, resourceXObject, NULL, true);
392
0
        (*pres)->where_used |= pdev->used_mask;
393
0
        if (code < 0)
394
0
            return code;
395
0
    } else {
396
        /* Unfortunately we can't apply pdf_substitute_resource,
397
           because the object may already be referred by its id.
398
           Redundant objects may happen in this case.
399
           For better results users should define objects before usage.
400
         */
401
0
    }
402
0
    if (objname != NULL && objname->size) {
403
0
        cos_value_t value;
404
405
0
        code = cos_dict_put(pdev->local_named_objects, objname->data,
406
0
                            objname->size, cos_object_value(&value, (cos_object_t *)(*pres)->object));
407
0
        if (code < 0)
408
0
            return code;
409
0
    }
410
0
    return 0;
411
0
}
412
413
/* ---------------- Miscellaneous pdfmarks ---------------- */
414
415
/*
416
 * Create the dictionary for an annotation or outline.  For some
417
 * unfathomable reason, PDF requires the following key substitutions
418
 * relative to pdfmarks:
419
 *   In annotation and link dictionaries:
420
 *     /Action => /A, /Color => /C, /Title => /T
421
 *   In outline directionaries:
422
 *     /Action => /A, but *not* /Color or /Title
423
 *   In Action subdictionaries:
424
 *     /Dest => /D, /File => /F, /Subtype => /S
425
 * and also the following substitutions:
426
 *     /Action /Launch /File xxx =>
427
 *       /A << /S /Launch /F xxx >>
428
 *     /Action /GoToR /File xxx /Dest yyy =>
429
 *       /A << /S /GoToR /F xxx /D yyy' >>
430
 *     /Action /Article /Dest yyy =>
431
 *       /A << /S /Thread /D yyy' >>
432
 *     /Action /GoTo => drop the Action key
433
 * Also, \n in Contents strings must be replaced with \r.
434
 * Also, an outline dictionary with no action, Dest, Page, or View has an
435
 * implied GoTo action with Dest = [{ThisPage} /XYZ null null null].
436
 * Note that for Thread actions, the Dest is not a real destination,
437
 * and must not be processed as one.
438
 *
439
 * We always treat /A and /F as equivalent to /Action and /File
440
 * respectively.  The pdfmark and PDF documentation is so confused on the
441
 * issue of when the long and short names should be used that we only give
442
 * this a 50-50 chance of being right.
443
 *
444
 * Note that we must transform Rect and Border coordinates.
445
 */
446
447
typedef struct ao_params_s {
448
    gx_device_pdf *pdev;  /* for pdfmark_make_dest */
449
    const char *subtype;  /* default Subtype in top-level dictionary */
450
    long src_pg;    /* set to SrcPg - 1 if any */
451
} ao_params_t;
452
static int
453
pdfmark_put_ao_pairs(gx_device_pdf * pdev, cos_dict_t *pcd,
454
                     const gs_param_string * pairs, uint count,
455
                     const gs_matrix * pctm, ao_params_t * params,
456
                     bool for_outline)
457
57.4k
{
458
57.4k
    const gs_param_string *Action = 0;
459
57.4k
    const gs_param_string *File = 0;
460
57.4k
    const gs_param_string *URI = 0;
461
57.4k
    gs_param_string Dest;
462
57.4k
    gs_param_string Subtype;
463
57.4k
    uint i;
464
57.4k
    int code;
465
57.4k
    char dest[MAX_DEST_STRING];
466
57.4k
    bool coerce_dest = false;
467
468
57.4k
    Subtype.data = 0;
469
57.4k
    Subtype.size = 0;
470
57.4k
    Dest.data = 0;
471
57.4k
    Dest.size = 0;
472
57.4k
    if (params->subtype)
473
57.3k
        param_string_from_string(Subtype, params->subtype);
474
87
    else
475
87
        Subtype.data = 0;
476
491k
    for (i = 0; i < count; i += 2) {
477
434k
        const gs_param_string *pair = &pairs[i];
478
434k
        long src_pg;
479
480
434k
        if (pdf_key_eq(pair, "/SrcPg")){
481
0
            unsigned char *buf0 = (unsigned char *)gs_alloc_bytes(pdev->memory, (pair[1].size + 1) * sizeof(unsigned char),
482
0
                        "pdf_xmp_write_translated");
483
0
            memcpy(buf0, pair[1].data, pair[1].size);
484
0
            buf0[pair[1].size] = 0x00;
485
0
            if (sscanf((char *)buf0, "%ld", &src_pg) == 1)
486
0
                params->src_pg = src_pg - 1;
487
0
            gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
488
0
        }
489
434k
        else if (!for_outline && pdf_key_eq(pair, "/Color"))
490
0
            pdfmark_put_c_pair(pcd, "/C", pair + 1);
491
434k
        else if (!for_outline && pdf_key_eq(pair, "/Title"))
492
0
            pdfmark_put_c_pair(pcd, "/T", pair + 1);
493
434k
        else if (pdf_key_eq(pair, "/Action") || pdf_key_eq(pair, "/A"))
494
119
            Action = pair;
495
        /* Previously also catered for '/F', but at the top level (outside an
496
         * Action dict which is handled below), a /F can only be the Flags for
497
         * the annotation, not a File or JavaScript action.
498
         */
499
434k
        else if (pdf_key_eq(pair, "/File") /* || pdf_key_eq(pair, "/F")*/)
500
0
            File = pair;
501
434k
        else if (pdf_key_eq(pair, "/Dest")) {
502
0
            Dest = pair[1];
503
0
            coerce_dest = true;
504
0
        }
505
434k
        else if (pdf_key_eq(pair, "/URI")) {
506
0
            URI = pair;   /* save it for placing into the Action dict */
507
0
        }
508
434k
        else if (pdf_key_eq(pair, "/Page") || pdf_key_eq(pair, "/View")) {
509
            /* Make a destination even if this is for an outline. */
510
14.2k
            if (Dest.data == 0) {
511
7.10k
                code = pdfmark_make_dest(dest, params->pdev, "/Page", "/View",
512
7.10k
                                         pairs, count, 0);
513
7.10k
                if (code >= 0) {
514
7.10k
                    param_string_from_string(Dest, dest);
515
7.10k
                    if (for_outline)
516
87
                        coerce_dest = false;
517
7.10k
                } else {
518
0
                    emprintf(pdev->memory, "   **** Warning: Outline has invalid link that was discarded.\n");
519
0
                    return gs_note_error(gs_error_rangecheck);
520
0
                }
521
7.10k
            }
522
419k
        } else if (pdf_key_eq(pair, "/Subtype"))
523
57.3k
            Subtype = pair[1];
524
        /*
525
         * We also have to replace all occurrences of \n in Contents
526
         * strings with \r.  Unfortunately, they probably have already
527
         * been converted to \012....
528
         */
529
362k
        else if (pdf_key_eq(pair, "/Contents")) {
530
20.0k
            byte *cstr;
531
20.0k
            uint csize = pair[1].size;
532
20.0k
            cos_value_t *pcv;
533
20.0k
            uint i, j;
534
535
            /*
536
             * Copy the string into value storage, then update it in place.
537
             */
538
20.0k
            pdfmark_put_pair(pcd, pair);
539
            /* Break const so we can update the (copied) string. */
540
20.0k
            pcv = (cos_value_t *)cos_dict_find_c_key(pcd, "/Contents");
541
20.0k
            if (pcv == NULL)
542
0
                return_error(gs_error_ioerror); /* shouldn't be possible */
543
20.0k
            cstr = pcv->contents.chars.data;
544
            /* Loop invariant: j <= i < csize. */
545
397k
            for (i = j = 0; i < csize;)
546
377k
                if (csize - i >= 2 && !memcmp(cstr + i, "\\n", 2) &&
547
377k
                    (i == 0 || cstr[i - 1] != '\\')
548
377k
                    ) {
549
0
                    cstr[j] = '\\', cstr[j + 1] = 'r';
550
0
                    i += 2, j += 2;
551
377k
                } else if (csize - i >= 4 && !memcmp(cstr + i, "\\012", 4) &&
552
377k
                           (i == 0 || cstr[i - 1] != '\\')
553
377k
                    ) {
554
0
                    cstr[j] = '\\', cstr[j + 1] = 'r';
555
0
                    i += 4, j += 2;
556
0
                } else
557
377k
                    cstr[j++] = cstr[i++];
558
20.0k
            if (j != i)
559
0
                pcv->contents.chars.data =
560
0
                    gs_resize_string(pdev->pdf_memory, cstr, csize, j,
561
20.0k
                                     "pdfmark_put_ao_pairs");
562
342k
        } else if (pdf_key_eq(pair, "/Rect")) {
563
57.3k
            gs_rect rect;
564
57.3k
            char rstr[MAX_RECT_STRING];
565
57.3k
            int code = pdfmark_scan_rect(&rect, pair + 1, pctm);
566
567
57.3k
            if (code < 0)
568
12
                return code;
569
57.3k
            pdfmark_make_rect(rstr, &rect);
570
57.3k
            cos_dict_put_c_key_string(pcd, "/Rect", (byte *)rstr,
571
57.3k
                                      strlen(rstr));
572
285k
        } else if (pdf_key_eq(pair, "/Border")) {
573
8.07k
            stream s;
574
8.07k
            char bstr[MAX_BORDER_STRING + 1];
575
8.07k
            int code;
576
577
8.07k
            s_init(&s, NULL);
578
8.07k
            swrite_string(&s, (byte *)bstr, MAX_BORDER_STRING + 1);
579
8.07k
            code = pdfmark_write_border(&s, pair + 1, pctm);
580
8.07k
            if (code < 0)
581
0
                return code;
582
8.07k
            if (stell(&s) > MAX_BORDER_STRING)
583
0
                return_error(gs_error_limitcheck);
584
8.07k
            bstr[stell(&s)] = 0;
585
8.07k
            cos_dict_put_c_key_string(pcd, "/Border", (byte *)bstr,
586
8.07k
                                      strlen(bstr));
587
277k
        } else if (for_outline && pdf_key_eq(pair, "/Count"))
588
277k
            DO_NOTHING;
589
277k
        else {
590
277k
            int i, j=0;
591
277k
            unsigned char *temp, *buf0 = (unsigned char *)gs_alloc_bytes(pdev->memory, pair[1].size * 2 * sizeof(unsigned char),
592
277k
                        "pdf_xmp_write_translated");
593
277k
            if (buf0 == NULL)
594
0
                return_error(gs_error_VMerror);
595
6.05M
            for (i = 0; i < pair[1].size; i++) {
596
5.77M
                byte c = pair[1].data[i];
597
598
5.77M
                buf0[j++] = c;
599
                /* Acrobat doesn't like the 'short' escapes. and wants them as octal....
600
                 * I beliwvw this should be considered an Acrtobat bug, either escapes
601
                 * can be used, or not, we shouldn't have to force them to octal.
602
                 */
603
5.77M
                if (c == '\\') {
604
739
                    switch(pair[1].data[i + 1]) {
605
0
                        case 'b':
606
0
                            buf0[j++] = '0';
607
0
                            buf0[j++] = '1';
608
0
                            buf0[j++] = '0';
609
0
                            i++;
610
0
                            break;
611
0
                        case 'f':
612
0
                            buf0[j++] = '0';
613
0
                            buf0[j++] = '1';
614
0
                            buf0[j++] = '4';
615
0
                            i++;
616
0
                            break;
617
7
                        case 'n':
618
7
                            buf0[j++] = '0';
619
7
                            buf0[j++] = '1';
620
7
                            buf0[j++] = '2';
621
7
                            i++;
622
7
                            break;
623
2
                        case 'r':
624
2
                            buf0[j++] = '0';
625
2
                            buf0[j++] = '1';
626
2
                            buf0[j++] = '5';
627
2
                            i++;
628
2
                            break;
629
0
                        case 't':
630
0
                            buf0[j++] = '0';
631
0
                            buf0[j++] = '1';
632
0
                            buf0[j++] = '1';
633
0
                            i++;
634
0
                            break;
635
5
                        case '\\':
636
5
                            buf0[j++] = '1';
637
5
                            buf0[j++] = '3';
638
5
                            buf0[j++] = '4';
639
5
                            i++;
640
5
                            break;
641
725
                        default:
642
725
                            break;
643
739
                    }
644
739
                }
645
5.77M
            }
646
277k
            i = pair[1].size;
647
277k
            temp = (unsigned char *)pair[1].data;
648
277k
            ((gs_param_string *)pair)[1].data = buf0;
649
277k
            ((gs_param_string *)pair)[1].size = j;
650
651
277k
            pdfmark_put_pair(pcd, pair);
652
653
277k
            ((gs_param_string *)pair)[1].data = temp;
654
277k
            ((gs_param_string *)pair)[1].size = i;
655
277k
            gs_free_object(pdev->memory, buf0, "pdf_xmp_write_translated");
656
277k
        }
657
434k
    }
658
57.4k
    if (!for_outline && pdf_key_eq(&Subtype, "/Link")) {
659
8.00k
        if (Action) {
660
            /* Don't delete the Dest for GoTo or file-GoToR. */
661
119
            if (pdf_key_eq(Action + 1, "/GoTo") ||
662
119
                (File && pdf_key_eq(Action + 1, "/GoToR"))
663
119
                )
664
119
                DO_NOTHING;
665
119
            else
666
119
                Dest.data = 0;
667
119
        }
668
8.00k
    }
669
670
    /* Now handle the deferred keys. */
671
57.4k
    if (Action) {
672
119
        const byte *astr = Action[1].data;
673
119
        const uint asize = Action[1].size;
674
675
119
        if ((File != 0 || Dest.data != 0 || URI != 0) &&
676
119
            (pdf_key_eq(Action + 1, "/Launch") ||
677
0
             (pdf_key_eq(Action + 1, "/GoToR") && File) ||
678
0
             pdf_key_eq(Action + 1, "/Article"))
679
119
            ) {
680
0
            cos_dict_t *adict;
681
0
            cos_value_t avalue;
682
683
0
            if (pdf_key_eq(Action + 1, "/Launch") && pdev->PDFA != 0) {
684
0
                switch (pdev->PDFACompatibilityPolicy) {
685
                    /* Default behaviour matches Adobe Acrobat, warn and continue,
686
                     * output file will not be PDF/A compliant
687
                     */
688
0
                    case 0:
689
0
                        emprintf(pdev->memory,
690
0
                                 "Launch annotations not permitted in PDF/A, reverting to normal PDF output\n");
691
0
                        pdev->AbortPDFAX = true;
692
0
                        pdev->PDFA = 0;
693
0
                        break;
694
                        /* Since the annotation would break PDF/A compatibility, do not
695
                         * include it, but warn the user that it has been dropped.
696
                         */
697
0
                    case 1:
698
0
                        emprintf(pdev->memory,
699
0
                                 "Launch annotations not permitted in PDF/A,  cannot drop annotation, aborting conversion\n");
700
0
                        return_error (gs_error_typecheck);
701
0
                        break;
702
0
                    case 2:
703
0
                        emprintf(pdev->memory,
704
0
                                 "Launch annotations not permitted in PDF/A,  aborting conversion\n");
705
0
                        return_error (gs_error_typecheck);
706
0
                        break;
707
0
                    default:
708
0
                        emprintf(pdev->memory,
709
0
                                 "Launch annotations not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
710
0
                        pdev->AbortPDFAX = true;
711
0
                        pdev->PDFA = 0;
712
0
                        break;
713
0
                }
714
0
            }
715
716
0
            adict = cos_dict_alloc(pdev, "action dict");
717
0
            if (adict == 0)
718
0
                return_error(gs_error_VMerror);
719
0
            if (!for_outline) {
720
                /* We aren't sure whether this is really needed.... */
721
0
                code = cos_dict_put_c_strings(adict, "/Type", "/Action");
722
0
                if (code < 0)
723
0
                    return code;
724
0
            }
725
0
            if (pdf_key_eq(Action + 1, "/Article")) {
726
0
                code = cos_dict_put_c_strings(adict, "/S", "/Thread");
727
0
                if (code < 0)
728
0
                    return code;
729
0
                coerce_dest = false; /* Dest is not a real destination */
730
0
            }
731
0
            else
732
0
                pdfmark_put_c_pair(adict, "/S", Action + 1);
733
0
            if (Dest.data) {
734
0
                if (coerce_dest)
735
0
                    pdfmark_coerce_dest(&Dest, dest);
736
0
                pdfmark_put_c_pair(adict, "/D", &Dest);
737
0
                Dest.data = 0;  /* so we don't write it again */
738
0
            }
739
0
            if (File) {
740
0
                pdfmark_put_c_pair(adict, "/F", File + 1);
741
0
                File = 0; /* so we don't write it again */
742
0
            }
743
0
            if (URI) {
744
                /* Adobe Distiller puts a /URI key from pdfmark into the */
745
                /* Action dict with /S /URI as Subtype */
746
0
                pdfmark_put_pair(adict, URI);
747
0
                code = cos_dict_put_c_strings(adict, "/S", "/URI");
748
0
                if (code < 0)
749
0
                    return code;
750
0
            }
751
0
            cos_dict_put(pcd, (const byte *)"/A", 2,
752
0
                         COS_OBJECT_VALUE(&avalue, adict));
753
119
        } else if (asize >= 4 && !memcmp(astr, "<<", 2)) {
754
            /* Replace occurrences of /Dest, /File, and /Subtype. */
755
38
            const byte *scan = astr + 2;
756
38
            const byte *end = astr + asize;
757
38
            gs_param_string key, value;
758
38
            cos_dict_t *adict = cos_dict_alloc(pdev, "action dict");
759
38
            cos_value_t avalue;
760
38
            int code = 0;
761
762
38
            if (adict == 0)
763
0
                return_error(gs_error_VMerror);
764
38
            if (URI) {
765
                /* Adobe Distiller puts a /URI key from pdfmark into the */
766
                /* Action dict with /S /URI as Subtype */
767
0
                pdfmark_put_pair(adict, URI);
768
0
                if(cos_dict_put_c_strings(adict, "/S", "/URI") < 0)
769
0
                    return code;
770
0
            }
771
140
            while ((code = pdf_scan_token(&scan, end, &key.data)) > 0) {
772
140
                key.size = scan - key.data;
773
140
                if (key.data[0] != '/' ||
774
140
                    (code = pdf_scan_token_composite(&scan, end, &value.data)) != 1)
775
38
                    break;
776
102
                value.size = scan - value.data;
777
102
                if (pdev->PDFA != 0 && (pdf_key_eq(&key, "/Subtype") || pdf_key_eq(&key, "/S"))) {
778
0
                    if (pdf_key_eq(&value, "/Launch")) {
779
0
                        switch (pdev->PDFACompatibilityPolicy) {
780
                            /* Default behaviour matches Adobe Acrobat, warn and continue,
781
                             * output file will not be PDF/A compliant
782
                             */
783
0
                            case 0:
784
0
                                emprintf(pdev->memory,
785
0
                                         "Launch annotations not permitted in PDF/A, reverting to normal PDF output\n");
786
0
                                pdev->AbortPDFAX = true;
787
0
                                pdev->PDFA = 0;
788
0
                                break;
789
                                /* Since the annotation would break PDF/A compatibility, do not
790
                                 * include it, but warn the user that it has been dropped.
791
                                 */
792
0
                            case 1:
793
0
                                emprintf(pdev->memory,
794
0
                                         "Launch annotations not permitted in PDF/A,  cannot drop annotation, aborting conversion\n");
795
0
                                gs_free_object(pdev->memory->stable_memory, adict,  "action dict");
796
0
                                return_error (gs_error_typecheck);
797
0
                                break;
798
0
                            case 2:
799
0
                                emprintf(pdev->memory,
800
0
                                         "Launch annotations not permitted in PDF/A,  aborting conversion\n");
801
0
                                gs_free_object(pdev->memory->stable_memory, adict,  "action dict");
802
0
                                return_error (gs_error_typecheck);
803
0
                                break;
804
0
                            default:
805
0
                                emprintf(pdev->memory,
806
0
                                         "Launch annotations not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
807
0
                                pdev->AbortPDFAX = true;
808
0
                                pdev->PDFA = 0;
809
0
                                break;
810
0
                        }
811
0
                    }
812
0
                }
813
102
                if (pdf_key_eq(&key, "/Dest") || pdf_key_eq(&key, "/D")) {
814
1
                    param_string_from_string(key, "/D");
815
1
                    if (value.data[0] == '(' && pdev->CompatibilityLevel < 1.2) {
816
0
                        int i;
817
818
0
                        for (i = 0;i < value.size; i++) {
819
0
                            if (value.data[i] == '\\') {
820
0
                                emprintf(pdev->memory,
821
0
                                         "Link Destination contains characters which cannot be represented in a name.\nDestinations cannot be strings in versions prior to PDF 1.2. Annotation removed in the output.\n");
822
0
                                return gs_error_typecheck;
823
0
                            }
824
0
                        }
825
                        /****** FIXME: DETECT ESCAPES ******/
826
0
                        pdfmark_coerce_dest(&value, dest);
827
0
                    }
828
101
                } else if (pdf_key_eq(&key, "/File"))
829
0
                    param_string_from_string(key, "/F");
830
101
                else if (pdf_key_eq(&key, "/Subtype"))
831
0
                    param_string_from_string(key, "/S");
832
102
                cos_dict_put_string(adict, key.data, key.size,
833
102
                                    value.data, value.size);
834
102
            }
835
38
            if (code <= 0 || !pdf_key_eq(&key, ">>")) {
836
0
                cos_free((cos_object_t *)adict, "action dict");
837
0
                return_error(gs_error_rangecheck);
838
0
            }
839
38
            cos_dict_put(pcd, (const byte *)"/A", 2,
840
38
                         COS_OBJECT_VALUE(&avalue, adict));
841
81
        } else if (pdf_key_eq(Action + 1, "/GoTo"))
842
0
            pdfmark_put_pair(pcd, Action);
843
81
        else if (Action[1].size < 30) {
844
            /* Hack: we could substitute names in pdfmark_process,
845
               now should recognize whether it was done.
846
               Not a perfect method though.
847
               Go with it for a while. */
848
81
            char buf[30];
849
81
            int d0, d1;
850
851
81
            memcpy(buf, Action[1].data, Action[1].size);
852
81
            buf[Action[1].size] = 0;
853
81
            if (sscanf(buf, "%d %d R", &d0, &d1) == 2)
854
81
                pdfmark_put_pair(pcd, Action);
855
81
        }
856
119
    }
857
    /*
858
     * If we have /Dest or /File without the right kind of action,
859
     * simply write it at the top level.  This doesn't seem right,
860
     * but I'm not sure what else to do.
861
     */
862
57.4k
    if (Dest.data) {
863
7.10k
        if (coerce_dest)
864
0
            pdfmark_coerce_dest(&Dest, dest);
865
        /*
866
         * For PDF 1.2 or better  we write a Names tree, but in this case the names
867
         * are required to be (counter-intuitively) strings, NOT name objects....
868
         */
869
7.10k
        if (pdev->CompatibilityLevel > 1.1) {
870
7.10k
            gs_param_string DestString;
871
7.10k
            int i = 0, j;
872
7.10k
            char *D;
873
874
            /*
875
             * If the name has any 'unusual' characters, it is 'escaped' by starting with NULLs
876
             * I suspect we no longer need that, but here we remove the escaping NULLs
877
             */
878
7.10k
            if (Dest.size > 3 && Dest.data[0] == 0x00 && Dest.data[1] == 0x00 && Dest.data[Dest.size - 1] == 0x00) {
879
0
                i = 2;
880
0
                if (Dest.size > 5 && Dest.data[2] == 0x00 && Dest.data[3] == 0x00)
881
0
                    i += 2;
882
                /* If it has preceeding NULLs, then it has a terminating NULL as well, get rid of that too */
883
0
                Dest.size--;
884
0
            }
885
886
7.10k
            if (Dest.data[i] == '/') {
887
0
                i++;
888
889
0
                DestString.data = gs_alloc_bytes(pdev->memory->stable_memory, (Dest.size * 2) + 1, "DEST pdfmark temp string");
890
0
                if (DestString.data == 0)
891
0
                    return_error(gs_error_VMerror);
892
0
                DestString.size = (Dest.size * 2) + 1;
893
0
                DestString.persistent = 0;
894
0
                D = (char *)DestString.data;
895
0
                D[0] = '(';
896
0
                for (j=1;i<Dest.size;i++, j++) {
897
0
                    if (Dest.data[i] == '(' || Dest.data[i] == ')') {
898
0
                        D[j++] = '\\';
899
0
                    }
900
0
                    D[j] = Dest.data[i];
901
0
                }
902
0
                D[j++] = ')';
903
0
                DestString.size = j;
904
0
                pdfmark_put_c_pair(pcd, "/Dest", &DestString);
905
0
                gs_free_object(pdev->memory->stable_memory, D, "DEST pdfmark temp string");
906
0
            } else
907
7.10k
                pdfmark_put_c_pair(pcd, "/Dest", &Dest);
908
7.10k
        } else
909
0
            pdfmark_put_c_pair(pcd, "/Dest", &Dest);
910
50.3k
    } else if (for_outline && !Action) {
911
        /* Make an implicit destination. */
912
0
        char dstr[1 + (sizeof(long) * 8 / 3 + 1) + 25 + 1];
913
0
        long page_id = pdf_page_id(pdev, pdev->next_page + 1);
914
915
0
        gs_snprintf(dstr, MAX_DEST_STRING, "[%ld 0 R /XYZ null null null]", page_id);
916
0
        cos_dict_put_c_key_string(pcd, "/Dest", (const unsigned char*) dstr,
917
0
                                  strlen(dstr));
918
0
    }
919
57.4k
    if (File)
920
0
        pdfmark_put_pair(pcd, File);
921
57.4k
    if (Subtype.data)
922
57.3k
        pdfmark_put_c_pair(pcd, "/Subtype", &Subtype);
923
57.4k
    return 0;
924
57.4k
}
925
926
/* Copy an annotation dictionary. */
927
static int
928
pdfmark_annot(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
929
              const gs_matrix * pctm, const gs_param_string *objname,
930
              const char *subtype)
931
57.3k
{
932
57.3k
    ao_params_t params;
933
57.3k
    cos_dict_t *pcd;
934
57.3k
    int page_index = pdev->next_page;
935
57.3k
    cos_array_t *annots;
936
57.3k
    cos_value_t value;
937
57.3k
    int code;
938
939
    /* Annotations are only permitted in PDF/A if they have the
940
     * Print flag enabled, so we need to prescan for that here.
941
     */
942
57.3k
    if(pdev->PDFA != 0) {
943
0
        int i, Flags = 0;
944
        /* Check all the keys to see if we have a /F (Flags) key/value pair defined */
945
0
        for (i = 0; i < count; i += 2) {
946
0
            const gs_param_string *pair = &pairs[i];
947
948
0
            if (pdf_key_eq(pair, "/F")) {
949
0
                char Buffer[32];
950
951
0
                pair = &pairs[i+1];
952
0
                memcpy(Buffer, pair->data, pair->size);
953
0
                Buffer[pair->size] = 0x00;
954
0
                code = sscanf(Buffer, "%ld", (long *)&Flags);
955
0
                if (code != 1)
956
0
                    emprintf(pdev->memory,
957
0
                             "Annotation has an invalid /Flags attribute\n");
958
0
                break;
959
0
            }
960
0
        }
961
        /* Check the Print flag, PDF/A annotations *must* be set to print */
962
0
        if ((Flags & 4) == 0){
963
0
            switch (pdev->PDFACompatibilityPolicy) {
964
                /* Default behaviour matches Adobe Acrobat, warn and continue,
965
                 * output file will not be PDF/A compliant
966
                 */
967
0
                case 0:
968
0
                    emprintf(pdev->memory,
969
0
                             "Annotation set to non-printing,\n not permitted in PDF/A, reverting to normal PDF output\n");
970
0
                    pdev->AbortPDFAX = true;
971
0
                    pdev->PDFA = 0;
972
0
                    break;
973
                    /* Since the annotation would break PDF/A compatibility, do not
974
                     * include it, but warn the user that it has been dropped.
975
                     */
976
0
                case 1:
977
0
                    emprintf(pdev->memory,
978
0
                             "Annotation set to non-printing,\n not permitted in PDF/A, annotation will not be present in output file\n");
979
0
                    return 0;
980
0
                    break;
981
0
                case 2:
982
0
                    emprintf(pdev->memory,
983
0
                             "Annotation set to non-printing,\n not permitted in PDF/A, aborting conversion\n");
984
0
                    return_error(gs_error_invalidfont);
985
0
                    break;
986
0
                default:
987
0
                    emprintf(pdev->memory,
988
0
                             "Annotation set to non-printing,\n not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
989
0
                    pdev->AbortPDFAX = true;
990
0
                    pdev->PDFA = 0;
991
0
                    break;
992
0
            }
993
0
        }
994
0
    }
995
57.3k
    if (pdev->PDFX != 0) {
996
0
        gs_param_string Subtype;
997
0
        bool discard = true;
998
0
        pdf_page_t *page = 0L;
999
1000
0
        page = &pdev->pages[pdev->next_page];
1001
1002
0
        if (subtype) {
1003
0
            param_string_from_string(Subtype, subtype);
1004
0
            if (pdf_key_eq(&Subtype, "/TrapNet") ||
1005
0
                pdf_key_eq(&Subtype, "/PrinterMark"))
1006
0
                discard = false;
1007
0
        }
1008
0
        if (discard) {
1009
0
            int i;
1010
0
            for (i = 0; i < count; i += 2) {
1011
0
                const gs_param_string *pair = &pairs[i];
1012
0
                if (pdf_key_eq(pair, "/Rect")) {
1013
0
                    gs_rect rect;
1014
0
                    const cos_value_t *v_trimbox, *v_bleedbox, *v_artbox, *v_cropbox;
1015
0
                    const byte *p;
1016
0
                    char buf[100];
1017
0
                    int size, code;
1018
0
                    float temp[4]; /* the type is float for sscanf. */
1019
0
                    double pagebox[4] = {0, 0};
1020
1021
0
                    pagebox[2] = pdev->MediaSize[0];
1022
0
                    pagebox[3] = pdev->MediaSize[1];
1023
1024
0
                    v_cropbox = v_bleedbox = v_trimbox = v_artbox = 0x0L;
1025
1026
0
                    code = pdfmark_scan_rect(&rect, pair + 1, pctm);
1027
1028
0
                    if (code < 0)
1029
0
                        return code;
1030
1031
0
                    if (page && page->Page) {
1032
0
                        v_trimbox = cos_dict_find_c_key(page->Page, "/TrimBox");
1033
0
                        v_bleedbox = cos_dict_find_c_key(page->Page, "/BleedBox");
1034
0
                        v_artbox = cos_dict_find_c_key(page->Page, "/ArtBox");
1035
0
                        v_cropbox = cos_dict_find_c_key(page->Page, "/CropBox");
1036
0
                    }
1037
1038
0
                    if (v_cropbox != NULL && v_cropbox->value_type == COS_VALUE_SCALAR) {
1039
0
                        p = v_cropbox->contents.chars.data;
1040
0
                        size = min (v_cropbox->contents.chars.size, sizeof(buf) - 1);
1041
0
                        memcpy(buf, p, size);
1042
0
                        buf[size] = 0;
1043
0
                        if (sscanf(buf, "[ %g %g %g %g ]",
1044
0
                                &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1045
0
                            if (temp[0] > pagebox[0]) pagebox[0] = temp[0];
1046
0
                            if (temp[1] > pagebox[1]) pagebox[1] = temp[1];
1047
0
                        }
1048
0
                    }
1049
0
                    if (v_bleedbox != NULL && v_bleedbox->value_type == COS_VALUE_SCALAR) {
1050
0
                        p = v_bleedbox->contents.chars.data;
1051
0
                        size = min (v_bleedbox->contents.chars.size, sizeof(buf) - 1);
1052
0
                        memcpy(buf, p, size);
1053
0
                        buf[size] = 0;
1054
0
                        if (sscanf(buf, "[ %g %g %g %g ]",
1055
0
                                &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1056
0
                            if (temp[0] > pagebox[0]) pagebox[0] = temp[0];
1057
0
                            if (temp[1] > pagebox[1]) pagebox[1] = temp[1];
1058
0
                        }
1059
0
                    }
1060
0
                    if (v_trimbox != NULL && v_trimbox->value_type == COS_VALUE_SCALAR) {
1061
0
                        p = v_trimbox->contents.chars.data;
1062
0
                        size = min (v_trimbox->contents.chars.size, sizeof(buf) - 1);
1063
0
                        memcpy(buf, p, size);
1064
0
                        buf[size] = 0;
1065
0
                        if (sscanf(buf, "[ %g %g %g %g ]",
1066
0
                                &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1067
0
                            if (temp[0] > pagebox[0]) pagebox[0] = temp[0];
1068
0
                            if (temp[1] > pagebox[1]) pagebox[1] = temp[1];
1069
0
                        }
1070
0
                    }
1071
0
                    if (v_artbox != NULL && v_artbox->value_type == COS_VALUE_SCALAR) {
1072
0
                        p = v_artbox->contents.chars.data;
1073
0
                        size = min (v_artbox->contents.chars.size, sizeof(buf) - 1);
1074
0
                        memcpy(buf, p, size);
1075
0
                        buf[size] = 0;
1076
0
                        if (sscanf(buf, "[ %g %g %g %g ]",
1077
0
                                &temp[0], &temp[1], &temp[2], &temp[3]) == 4) {
1078
0
                            if (temp[0] > pagebox[0]) pagebox[0] = temp[0];
1079
0
                            if (temp[1] > pagebox[1]) pagebox[1] = temp[1];
1080
0
                        }
1081
0
                    }
1082
0
                    if (v_cropbox == 0 && v_trimbox == 0 && v_artbox == 0 && v_bleedbox == 0) {
1083
0
                        if (pdev->PDFXTrimBoxToMediaBoxOffset.size >= 4 &&
1084
0
                                    pdev->PDFXTrimBoxToMediaBoxOffset.data[0] >= 0 &&
1085
0
                                    pdev->PDFXTrimBoxToMediaBoxOffset.data[1] >= 0 &&
1086
0
                                    pdev->PDFXTrimBoxToMediaBoxOffset.data[2] >= 0 &&
1087
0
                                    pdev->PDFXTrimBoxToMediaBoxOffset.data[3] >= 0) {
1088
0
                            pagebox[0] += pdev->PDFXTrimBoxToMediaBoxOffset.data[0];
1089
0
                            pagebox[1] += pdev->PDFXTrimBoxToMediaBoxOffset.data[3];
1090
0
                            pagebox[2] -= pdev->PDFXTrimBoxToMediaBoxOffset.data[1];
1091
0
                            pagebox[3] -= pdev->PDFXTrimBoxToMediaBoxOffset.data[2];
1092
0
                        } else if (pdev->PDFXBleedBoxToTrimBoxOffset.size >= 4 &&
1093
0
                                pdev->PDFXBleedBoxToTrimBoxOffset.data[0] >= 0 &&
1094
0
                                pdev->PDFXBleedBoxToTrimBoxOffset.data[1] >= 0 &&
1095
0
                                pdev->PDFXBleedBoxToTrimBoxOffset.data[2] >= 0 &&
1096
0
                                pdev->PDFXBleedBoxToTrimBoxOffset.data[3] >= 0) {
1097
0
                            pagebox[0] -= pdev->PDFXBleedBoxToTrimBoxOffset.data[0];
1098
0
                            pagebox[1] -= pdev->PDFXBleedBoxToTrimBoxOffset.data[3];
1099
0
                            pagebox[2] += pdev->PDFXBleedBoxToTrimBoxOffset.data[1];
1100
0
                            pagebox[3] += pdev->PDFXBleedBoxToTrimBoxOffset.data[2];
1101
0
                        }
1102
0
                    }
1103
1104
0
                    if (rect.p.x > pagebox[2] || rect.q.x < pagebox[0] ||
1105
0
                        rect.p.y > pagebox[3] || rect.q.y < pagebox[1])
1106
0
                        break;
1107
0
                    switch (pdev->PDFACompatibilityPolicy) {
1108
                        /* Default behaviour matches Adobe Acrobat, warn and continue,
1109
                         * output file will not be PDF/A compliant
1110
                         */
1111
0
                        case 0:
1112
0
                            emprintf(pdev->memory,
1113
0
                                     "Annotation (not TrapNet or PrinterMark) on page,\n not permitted in PDF/X, reverting to normal PDF output\n");
1114
0
                            pdev->AbortPDFAX = true;
1115
0
                            pdev->PDFX = 0;
1116
0
                            break;
1117
                            /* Since the annotation would break PDF/A compatibility, do not
1118
                             * include it, but warn the user that it has been dropped.
1119
                             */
1120
0
                        case 1:
1121
0
                            emprintf(pdev->memory,
1122
0
                                     "Annotation (not TrapNet or PrinterMark) on page,\n not permitted in PDF/X, annotation will not be present in output file\n");
1123
0
                            return 0;
1124
0
                            break;
1125
0
                        case 2:
1126
0
                            emprintf(pdev->memory,
1127
0
                                     "Annotation (not TrapNet or PrinterMark) on page,\n not permitted in PDF/X, aborting conversion\n");
1128
0
                            return_error(gs_error_invalidfont);
1129
0
                            break;
1130
0
                        default:
1131
0
                            emprintf(pdev->memory,
1132
0
                                     "Annotation s(not TrapNet or PrinterMark) on page,\n not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
1133
0
                            pdev->AbortPDFAX = true;
1134
0
                            pdev->PDFX = 0;
1135
0
                            break;
1136
0
                    }
1137
0
                    break;
1138
0
                }
1139
0
            }
1140
0
            if (i > count) {
1141
0
                switch (pdev->PDFACompatibilityPolicy) {
1142
                    /* Default behaviour matches Adobe Acrobat, warn and continue,
1143
                     * output file will not be PDF/A compliant
1144
                     */
1145
0
                    case 0:
1146
0
                        emprintf(pdev->memory,
1147
0
                                 "Annotation (not TrapNet or PrinterMark) potentially on page (no /Rect in dict),\n not permitted in PDF/X, reverting to normal PDF output\n");
1148
0
                        pdev->AbortPDFAX = true;
1149
0
                        pdev->PDFX = 0;
1150
0
                        break;
1151
                        /* Since the annotation would break PDF/A compatibility, do not
1152
                         * include it, but warn the user that it has been dropped.
1153
                         */
1154
0
                    case 1:
1155
0
                        emprintf(pdev->memory,
1156
0
                                 "Annotation (not TrapNet or PrinterMark) potentially on page (no /Rect in dict),\n not permitted in PDF/X, annotation will not be present in output file\n");
1157
0
                        return 0;
1158
0
                        break;
1159
0
                    case 2:
1160
0
                        emprintf(pdev->memory,
1161
0
                                 "Annotation (not TrapNet or PrinterMark) potentially on page (no /Rect in dict),\n not permitted in PDF/X, aborting conversion\n");
1162
0
                        return_error(gs_error_invalidfont);
1163
0
                        break;
1164
0
                    default:
1165
0
                        emprintf(pdev->memory,
1166
0
                                 "Annotation s(not TrapNet or PrinterMark) potentially on page (no /Rect in dict),\n not permitted in PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
1167
0
                        pdev->AbortPDFAX = true;
1168
0
                        pdev->PDFX = 0;
1169
0
                        break;
1170
0
                }
1171
0
            }
1172
0
        }
1173
0
    }
1174
57.3k
    params.pdev = pdev;
1175
57.3k
    params.subtype = subtype;
1176
57.3k
    params.src_pg = -1;
1177
57.3k
    code = pdf_make_named_dict(pdev, objname, &pcd, true);
1178
57.3k
    if (code < 0)
1179
0
        return code;
1180
57.3k
    code = cos_dict_put_c_strings(pcd, "/Type", "/Annot");
1181
57.3k
    if (code < 0) {
1182
0
        cos_free((cos_object_t *)pcd, "pdfmark_annot");
1183
0
        return code;
1184
0
    }
1185
57.3k
    code = pdfmark_put_ao_pairs(pdev, pcd, pairs, count, pctm, &params, false);
1186
57.3k
    if (code < 0) {
1187
12
        cos_free((cos_object_t *)pcd, "pdfmark_annot");
1188
12
        return code;
1189
12
    }
1190
57.3k
    if (params.src_pg >= 0)
1191
0
        page_index = params.src_pg;
1192
57.3k
    if (pdf_page_id(pdev, page_index + 1) <= 0) {
1193
0
        cos_free((cos_object_t *)pcd, "pdfmark_annot");
1194
0
        return_error(gs_error_rangecheck);
1195
0
    }
1196
57.3k
    annots = pdev->pages[page_index].Annots;
1197
57.3k
    if (annots == 0) {
1198
1.97k
        annots = cos_array_alloc(pdev, "pdfmark_annot");
1199
1.97k
        if (annots == 0) {
1200
0
            cos_free((cos_object_t *)pcd, "pdfmark_annot");
1201
0
            return_error(gs_error_VMerror);
1202
0
        }
1203
1.97k
        pdev->pages[page_index].Annots = annots;
1204
1.97k
    }
1205
57.3k
    if (!objname) {
1206
        /* Write the annotation now. */
1207
57.3k
        COS_WRITE_OBJECT(pcd, pdev, resourceAnnotation);
1208
57.3k
        COS_RELEASE(pcd, "pdfmark_annot");
1209
57.3k
    }
1210
57.3k
    return cos_array_add(annots,
1211
57.3k
                         cos_object_value(&value, COS_OBJECT(pcd)));
1212
57.3k
}
1213
1214
/* ANN pdfmark */
1215
static int
1216
pdfmark_ANN(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1217
            const gs_matrix * pctm, const gs_param_string * objname)
1218
49.3k
{
1219
49.3k
    return pdfmark_annot(pdev, pairs, count, pctm, objname, "/Text");
1220
49.3k
}
1221
1222
/* LNK pdfmark (obsolescent) */
1223
static int
1224
pdfmark_LNK(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1225
            const gs_matrix * pctm, const gs_param_string * objname)
1226
8.00k
{
1227
8.00k
    return pdfmark_annot(pdev, pairs, count, pctm, objname, "/Link");
1228
8.00k
}
1229
1230
/* Write and release one node of the outline tree. */
1231
static int
1232
pdfmark_write_outline(gx_device_pdf * pdev, pdf_outline_node_t * pnode,
1233
                      long next_id)
1234
87
{
1235
87
    stream *s;
1236
87
    int code = 0;
1237
1238
87
    pdf_open_separate(pdev, pnode->id, resourceOutline);
1239
87
    if (pnode->action != NULL)
1240
87
        pnode->action->id = pnode->id;
1241
0
    else {
1242
0
        emprintf1(pdev->memory,
1243
0
                  "pdfmark error: Outline node %ld has no action or destination.\n",
1244
0
                  pnode->id);
1245
0
        code = gs_note_error(gs_error_undefined);
1246
0
    }
1247
87
    s = pdev->strm;
1248
87
    stream_puts(s, "<< ");
1249
87
    if (pnode->action != NULL)
1250
87
        cos_dict_elements_write(pnode->action, pdev);
1251
87
    if (pnode->count)
1252
3
        pprintd1(s, "/Count %d ", pnode->count);
1253
87
    pprintld1(s, "/Parent %ld 0 R\n", pnode->parent_id);
1254
87
    if (pnode->prev_id)
1255
35
        pprintld1(s, "/Prev %ld 0 R\n", pnode->prev_id);
1256
87
    if (next_id)
1257
35
        pprintld1(s, "/Next %ld 0 R\n", next_id);
1258
87
    if (pnode->first_id)
1259
3
        pprintld2(s, "/First %ld 0 R /Last %ld 0 R\n",
1260
3
                  pnode->first_id, pnode->last_id);
1261
87
    stream_puts(s, ">>\n");
1262
87
    pdf_end_separate(pdev, resourceOutline);
1263
87
    if (pnode->action != NULL)
1264
87
        COS_FREE(pnode->action, "pdfmark_write_outline");
1265
87
    pnode->action = 0;
1266
87
    return code;
1267
87
}
1268
1269
/* Adjust the parent's count when writing an outline node. */
1270
static void
1271
pdfmark_adjust_parent_count(pdf_outline_level_t * plevel)
1272
5
{
1273
5
    pdf_outline_level_t *parent = plevel - 1;
1274
5
    int count = plevel->last.count;
1275
1276
5
    if (count > 0) {
1277
0
        if (parent->last.count < 0)
1278
0
            parent->last.count -= count;
1279
0
        else
1280
0
            parent->last.count += count;
1281
0
    }
1282
5
}
1283
1284
/*
1285
 * Close the current level of the outline tree.  Note that if we are at
1286
 * the end of the document, some of the levels may be incomplete if the
1287
 * Count values were incorrect.
1288
 */
1289
int
1290
pdfmark_close_outline(gx_device_pdf * pdev)
1291
52
{
1292
52
    int depth = pdev->outline_depth;
1293
52
    pdf_outline_level_t *plevel = &pdev->outline_levels[depth];
1294
52
    int code = 0;
1295
1296
52
    if (plevel->last.id) { /* check for incomplete tree */
1297
52
        code = pdfmark_write_outline(pdev, &plevel->last, 0);
1298
52
    }
1299
52
    if (depth > 0) {
1300
3
        plevel[-1].last.last_id = plevel->last.id;
1301
3
        pdfmark_adjust_parent_count(plevel);
1302
3
        --plevel;
1303
3
        if (plevel->last.count < 0)
1304
0
            pdev->closed_outline_depth--;
1305
3
        pdev->outline_depth--;
1306
3
    }
1307
52
    return code;
1308
52
}
1309
1310
/* OUT pdfmark */
1311
static int
1312
pdfmark_OUT(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1313
            const gs_matrix * pctm, const gs_param_string * no_objname)
1314
87
{
1315
87
    int depth = pdev->outline_depth;
1316
87
    pdf_outline_level_t *plevel = &pdev->outline_levels[depth];
1317
87
    int sub_count = 0;
1318
87
    uint i;
1319
87
    pdf_outline_node_t node;
1320
87
    ao_params_t ao;
1321
87
    int code;
1322
1323
388
    for (i = 0; i < count; i += 2) {
1324
301
        const gs_param_string *pair = &pairs[i];
1325
1326
301
        if (pdf_key_eq(pair, "/Count"))
1327
30
            pdfmark_scan_int(pair + 1, &sub_count);
1328
301
    }
1329
87
    if (sub_count != 0 && depth == pdev->max_outline_depth - 1) {
1330
0
        pdf_outline_level_t *new_ptr;
1331
1332
0
        new_ptr = (pdf_outline_level_t *)gs_alloc_bytes(pdev->pdf_memory, (pdev->max_outline_depth + INITIAL_MAX_OUTLINE_DEPTH) * sizeof(pdf_outline_level_t) * sizeof(pdf_outline_level_t), "outline_levels array");
1333
0
        if (!new_ptr)
1334
0
            return_error(gs_error_VMerror);
1335
0
        memcpy (new_ptr, pdev->outline_levels, pdev->max_outline_depth * sizeof(pdf_outline_level_t));
1336
0
        gs_free_object(pdev->pdf_memory, pdev->outline_levels, "outline_levels array");
1337
0
        pdev->outline_levels = new_ptr;
1338
0
        pdev->max_outline_depth += INITIAL_MAX_OUTLINE_DEPTH;
1339
0
        plevel = &pdev->outline_levels[depth];
1340
0
    }
1341
87
    node.action = cos_dict_alloc(pdev, "pdfmark_OUT");
1342
87
    if (node.action == 0)
1343
0
        return_error(gs_error_VMerror);
1344
87
    ao.pdev = pdev;
1345
87
    ao.subtype = 0;
1346
87
    ao.src_pg = -1;
1347
87
    code = pdfmark_put_ao_pairs(pdev, node.action, pairs, count, pctm, &ao,
1348
87
                                true);
1349
87
    if (code < 0) {
1350
0
        cos_free((cos_object_t *)node.action, "pdfmark_OUT");
1351
0
        return code;
1352
0
    }
1353
87
    if (pdev->outlines_id == 0)
1354
49
        pdev->outlines_id = pdf_obj_ref(pdev);
1355
87
    node.id = pdf_obj_ref(pdev);
1356
87
    node.parent_id =
1357
87
        (depth == 0 ? pdev->outlines_id : plevel[-1].last.id);
1358
87
    node.prev_id = plevel->last.id;
1359
87
    node.first_id = node.last_id = 0;
1360
87
    node.count = sub_count;
1361
    /* Add this node to the outline at the current level. */
1362
87
    if (plevel->first.id == 0) { /* First node at this level. */
1363
52
        if (depth > 0)
1364
3
            plevel[-1].last.first_id = node.id;
1365
52
        node.prev_id = 0;
1366
52
        plevel->first = node;
1367
52
        plevel->first.action = 0; /* never used */
1368
52
    } else {     /* Write the previous node. */
1369
35
        if (depth > 0)
1370
2
            pdfmark_adjust_parent_count(plevel);
1371
35
        pdfmark_write_outline(pdev, &plevel->last, node.id);
1372
35
    }
1373
87
    plevel->last = node;
1374
87
    plevel->left--;
1375
87
    if (!pdev->closed_outline_depth)
1376
87
        pdev->outlines_open++;
1377
    /* If this node has sub-nodes, descend one level. */
1378
87
    if (sub_count != 0) {
1379
3
        pdev->outline_depth++;
1380
3
        ++plevel;
1381
3
        plevel->left = (sub_count > 0 ? sub_count : -sub_count);
1382
3
        plevel->first.id = 0;
1383
3
        plevel->last.count = plevel->last.id = 0;
1384
3
        plevel->first.action = plevel->last.action = 0; /* for GC */
1385
3
        if (sub_count < 0)
1386
0
            pdev->closed_outline_depth++;
1387
84
    } else {
1388
87
        while ((depth = pdev->outline_depth) > 0 &&
1389
87
               pdev->outline_levels[depth].left == 0
1390
84
            )
1391
3
            pdfmark_close_outline(pdev);
1392
84
    }
1393
87
    return 0;
1394
87
}
1395
1396
/* Write an article bead. */
1397
static int
1398
pdfmark_write_bead(gx_device_pdf * pdev, const pdf_bead_t * pbead)
1399
0
{
1400
0
    stream *s;
1401
0
    char rstr[MAX_RECT_STRING];
1402
1403
0
    pdf_open_separate(pdev, pbead->id, resourceArticle);
1404
0
    s = pdev->strm;
1405
0
    pprintld3(s, "<</T %ld 0 R/V %ld 0 R/N %ld 0 R",
1406
0
              pbead->article_id, pbead->prev_id, pbead->next_id);
1407
0
    if (pbead->page_id != 0)
1408
0
        pprintld1(s, "/P %ld 0 R", pbead->page_id);
1409
0
    pdfmark_make_rect(rstr, &pbead->rect);
1410
0
    pprints1(s, "/R%s>>\n", rstr);
1411
0
    return pdf_end_separate(pdev, resourceArticle);
1412
0
}
1413
1414
/* Finish writing an article, and release its data. */
1415
int
1416
pdfmark_write_article(gx_device_pdf * pdev, const pdf_article_t * part)
1417
0
{
1418
0
    pdf_article_t art;
1419
0
    stream *s;
1420
1421
0
    art = *part;
1422
0
    if (art.last.id == 0) {
1423
        /* Only one bead in the article. */
1424
0
        art.first.prev_id = art.first.next_id = art.first.id;
1425
0
    } else {
1426
        /* More than one bead in the article. */
1427
0
        art.first.prev_id = art.last.id;
1428
0
        art.last.next_id = art.first.id;
1429
0
        pdfmark_write_bead(pdev, &art.last);
1430
0
    }
1431
0
    pdfmark_write_bead(pdev, &art.first);
1432
0
    pdf_open_separate(pdev, art.contents->id, resourceArticle);
1433
0
    s = pdev->strm;
1434
0
    pprintld1(s, "<</F %ld 0 R/I<<", art.first.id);
1435
0
    cos_dict_elements_write(art.contents, pdev);
1436
0
    stream_puts(s, ">> >>\n");
1437
0
    return pdf_end_separate(pdev, resourceArticle);
1438
0
}
1439
1440
/* ARTICLE pdfmark */
1441
static int
1442
pdfmark_ARTICLE(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1443
                const gs_matrix * pctm, const gs_param_string * no_objname)
1444
0
{
1445
0
    gs_memory_t *mem = pdev->pdf_memory;
1446
0
    gs_param_string title;
1447
0
    gs_param_string rectstr;
1448
0
    gs_rect rect;
1449
0
    long bead_id;
1450
0
    pdf_article_t *part;
1451
0
    int code;
1452
1453
0
    if (!pdfmark_find_key("/Title", pairs, count, &title) ||
1454
0
        !pdfmark_find_key("/Rect", pairs, count, &rectstr)
1455
0
        )
1456
0
        return_error(gs_error_rangecheck);
1457
0
    if ((code = pdfmark_scan_rect(&rect, &rectstr, pctm)) < 0)
1458
0
        return code;
1459
0
    bead_id = pdf_obj_ref(pdev);
1460
1461
    /* Find the article with this title, or create one. */
1462
0
    for (part = pdev->articles; part != 0; part = part->next) {
1463
0
        const cos_value_t *a_title =
1464
0
            cos_dict_find_c_key(part->contents, "/Title");
1465
1466
0
        if (a_title != 0 && !COS_VALUE_IS_OBJECT(a_title) &&
1467
0
            !bytes_compare(a_title->contents.chars.data,
1468
0
                           a_title->contents.chars.size,
1469
0
                           title.data, title.size))
1470
0
            break;
1471
0
    }
1472
0
    if (part == 0) {   /* Create the article. */
1473
0
        cos_dict_t *contents =
1474
0
            cos_dict_alloc(pdev, "pdfmark_ARTICLE(contents)");
1475
1476
0
        if (contents == 0)
1477
0
            return_error(gs_error_VMerror);
1478
0
        part = gs_alloc_struct(mem, pdf_article_t, &st_pdf_article,
1479
0
                               "pdfmark_ARTICLE(article)");
1480
0
        if (part == 0 || contents == 0) {
1481
0
            gs_free_object(mem, part, "pdfmark_ARTICLE(article)");
1482
0
            if (contents)
1483
0
                COS_FREE(contents, "pdfmark_ARTICLE(contents)");
1484
0
            return_error(gs_error_VMerror);
1485
0
        }
1486
0
        contents->id = pdf_obj_ref(pdev);
1487
0
        part->next = pdev->articles;
1488
0
        pdev->articles = part;
1489
0
        cos_dict_put_string(contents, (const byte *)"/Title", 6,
1490
0
                            title.data, title.size);
1491
0
        part->first.id = part->last.id = 0;
1492
0
        part->contents = contents;
1493
0
    }
1494
    /*
1495
     * Add the bead to the article.  This is similar to what we do for
1496
     * outline nodes, except that articles have only a page number and
1497
     * not View/Dest.
1498
     */
1499
0
    if (part->last.id == 0) {
1500
0
        part->first.next_id = bead_id;
1501
0
        part->last.id = part->first.id;
1502
0
    } else {
1503
0
        part->last.next_id = bead_id;
1504
0
        pdfmark_write_bead(pdev, &part->last);
1505
0
    }
1506
0
    part->last.prev_id = part->last.id;
1507
0
    part->last.id = bead_id;
1508
0
    part->last.article_id = part->contents->id;
1509
0
    part->last.next_id = 0;
1510
0
    part->last.rect = rect;
1511
0
    {
1512
0
        gs_param_string page_string;
1513
0
        int page = 0;
1514
0
        uint i;
1515
1516
0
        pdfmark_find_key("/Page", pairs, count, &page_string);
1517
0
        page = pdfmark_page_number(pdev, &page_string);
1518
0
        code = update_max_page_reference(pdev, &page);
1519
0
        if (code < 0)
1520
0
            return code;
1521
0
        part->last.page_id = pdf_page_id(pdev, page);
1522
0
        for (i = 0; i < count; i += 2) {
1523
0
            if (pdf_key_eq(&pairs[i], "/Rect") || pdf_key_eq(&pairs[i], "/Page"))
1524
0
                continue;
1525
0
            pdfmark_put_pair(part->contents, &pairs[i]);
1526
0
        }
1527
0
    }
1528
0
    if (part->first.id == 0) { /* This is the first bead of the article. */
1529
0
        part->first = part->last;
1530
0
        part->last.id = 0;
1531
0
    }
1532
0
    return 0;
1533
0
}
1534
1535
/* EMBED pdfmark */
1536
static int
1537
pdfmark_EMBED(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1538
             const gs_matrix * pctm, const gs_param_string * objname)
1539
0
{
1540
0
    gs_param_string key;
1541
0
    int i;
1542
1543
0
    if (pdev->CompatibilityLevel < 1.4)
1544
0
        return_error(gs_error_undefined);
1545
0
    if (pdev->PDFA > 0 && pdev->PDFA < 2) {
1546
0
        switch(pdev->PDFACompatibilityPolicy) {
1547
0
            default:
1548
0
            case 0:
1549
0
                emprintf(pdev->memory,
1550
0
                "The PDF/A-1 specifcation prohibits the embedding of files, reverting to normal PDF output.\n");
1551
0
                pdev->AbortPDFAX = true;
1552
0
                pdev->PDFX = 0;
1553
0
                return 0;
1554
0
            case 1:
1555
0
                emprintf(pdev->memory,
1556
0
                "The PDF/A-1 specifcation prohibits the embedding of files, pdfamrk operatoin ignored.\n");
1557
0
                break;
1558
0
            case 2:
1559
0
                return_error(gs_error_undefined);
1560
0
        }
1561
0
    }
1562
0
    if (pdev->PDFA > 0 && pdev->PDFA < 3) {
1563
0
        emprintf(pdev->memory,
1564
0
        "The PDF/A-2 specifcation only permits the embedding of PDF/A-1 or PDF/A-2 files.\n");
1565
0
        emprintf(pdev->memory,
1566
0
        "The pdfwrite device has not validated this embedded file, output may not conform to PDF/A-2.\n");
1567
0
    }
1568
0
    if (!pdfmark_find_key("/FS", pairs, count, &key))
1569
0
        return_error(gs_error_rangecheck);
1570
0
    if (!pdfmark_find_key("/Name", pairs, count, &key))
1571
0
        return_error(gs_error_rangecheck);
1572
0
    if (!pdev->EmbeddedFiles) {
1573
0
        pdev->EmbeddedFiles = cos_dict_alloc(pdev, "pdfmark_EMBED(EmbeddedFiles)");
1574
0
        if (pdev->EmbeddedFiles == 0)
1575
0
            return_error(gs_error_VMerror);
1576
0
        pdev->EmbeddedFiles->id = pdf_obj_ref(pdev);
1577
0
    }
1578
1579
0
    for (i = 0; i < count; i += 2) {
1580
0
        if (pdf_key_eq(&pairs[i], "/FS")) {
1581
0
            return cos_dict_put_string(pdev->EmbeddedFiles, key.data, key.size,
1582
0
                               pairs[i+1].data, pairs[i+1].size);
1583
0
        }
1584
0
    }
1585
0
    return 0;
1586
0
}
1587
1588
/* DEST pdfmark */
1589
static int
1590
pdfmark_DEST(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1591
             const gs_matrix * pctm, const gs_param_string * objname)
1592
0
{
1593
0
    int present;
1594
0
    char dest[MAX_DEST_STRING];
1595
0
    gs_param_string key;
1596
0
    cos_value_t value;
1597
0
    cos_dict_t *ddict;
1598
0
    int i, code;
1599
1600
0
    if (!pdfmark_find_key("/Dest", pairs, count, &key) ||
1601
0
        (present =
1602
0
         pdfmark_make_dest(dest, pdev, "/Page", "/View", pairs, count, 1)) < 0
1603
0
        )
1604
0
        return_error(gs_error_rangecheck);
1605
0
    cos_string_value(&value, (byte *)dest, strlen(dest));
1606
0
    if (!pdev->Dests) {
1607
0
        pdev->Dests = cos_dict_alloc(pdev, "pdfmark_DEST(Dests)");
1608
0
        if (pdev->Dests == 0)
1609
0
            return_error(gs_error_VMerror);
1610
0
        pdev->Dests->id = pdf_obj_ref(pdev);
1611
0
    }
1612
1613
    /*
1614
     * Create the destination as a dictionary with a D key.
1615
     */
1616
0
    code = pdf_make_named_dict(pdev, objname, &ddict, false);
1617
0
    ddict->id = pdf_obj_ref(pdev);
1618
1619
0
    if (code < 0)
1620
0
        return code;
1621
0
    code = cos_dict_put_c_key_string(ddict, "/D", (byte *)dest,
1622
0
                                     strlen(dest));
1623
0
    for (i = 0; code >= 0 && i < count; i += 2)
1624
0
        if (!pdf_key_eq(&pairs[i], "/Dest") &&
1625
0
            !pdf_key_eq(&pairs[i], "/Page") &&
1626
0
            !pdf_key_eq(&pairs[i], "/View")
1627
0
            )
1628
0
            code = pdfmark_put_pair(ddict, &pairs[i]);
1629
0
    if (code < 0)
1630
0
        return code;
1631
0
    COS_WRITE_OBJECT(ddict, pdev, resourceOther);
1632
0
    COS_OBJECT_VALUE(&value, ddict);
1633
0
    COS_RELEASE(ddict, "pdfmark_DEST(Dests dict)");
1634
1635
0
    return cos_dict_put(pdev->Dests, key.data, key.size, &value);
1636
0
}
1637
1638
/* Check that pass-through PostScript code is a string. */
1639
static bool
1640
ps_source_ok(const gs_memory_t *mem, const gs_param_string * psource)
1641
0
{
1642
0
    if (psource->size >= 2 && psource->data[0] == '(' &&
1643
0
        psource->data[psource->size - 1] == ')'
1644
0
        )
1645
0
        return true;
1646
0
    else {
1647
0
        int i;
1648
0
        lprintf("bad PS passthrough: ");
1649
0
        for (i=0; i<psource->size; i++)
1650
0
            errprintf(mem, "%c", psource->data[i]);
1651
0
        errprintf(mem, "\n");
1652
0
        return false;
1653
0
    }
1654
0
}
1655
1656
/* Write the contents of pass-through PostScript code. */
1657
/* Return the size written on the file. */
1658
static uint
1659
pdfmark_write_ps(stream *s, const gs_param_string * psource)
1660
0
{
1661
    /****** REMOVE ESCAPES WITH PSSDecode, SEE gdevpdfr p. 2 ******/
1662
0
    uint size = psource->size - 2;
1663
1664
0
    stream_write(s, psource->data + 1, size);
1665
0
    stream_putc(s, '\n');
1666
0
    return size + 1;
1667
0
}
1668
1669
/* Start a XObject. */
1670
static int
1671
start_XObject(gx_device_pdf * pdev, bool compress, cos_stream_t **ppcs)
1672
0
{   pdf_resource_t *pres;
1673
0
    cos_stream_t *pcs;
1674
0
    int code;
1675
1676
0
    code = pdf_open_page(pdev, PDF_IN_STREAM);
1677
0
    if (code < 0)
1678
0
        return code;
1679
0
    code = pdf_enter_substream(pdev, resourceXObject, gs_no_id, &pres, false,
1680
0
                pdev->CompressStreams);
1681
0
    if (code < 0)
1682
0
        return code;
1683
0
    pdev->accumulating_a_global_object = true;
1684
0
    pcs = (cos_stream_t *)pres->object;
1685
0
    pdev->substream_Resources = cos_dict_alloc(pdev, "start_XObject");
1686
0
    if (!pdev->substream_Resources)
1687
0
        return_error(gs_error_VMerror);
1688
0
    if (pdev->ForOPDFRead) {
1689
0
        code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
1690
0
        if (code < 0)
1691
0
            return code;
1692
0
    }
1693
0
    pres->named = true;
1694
0
    pres->where_used = 0; /* initially not used */
1695
0
    pcs->pres = pres;
1696
0
    *ppcs = pcs;
1697
0
    return 0;
1698
0
}
1699
1700
/* PS pdfmark */
1701
0
#define MAX_PS_INLINE 100
1702
static int
1703
pdfmark_PS(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1704
           const gs_matrix * pctm, const gs_param_string * objname)
1705
0
{
1706
0
    gs_param_string source;
1707
0
    gs_param_string level1;
1708
1709
0
    if (!pdfmark_find_key("/DataSource", pairs, count, &source) ||
1710
0
        !ps_source_ok(pdev->memory, &source) ||
1711
0
        (pdfmark_find_key("/Level1", pairs, count, &level1) &&
1712
0
         !ps_source_ok(pdev->memory, &level1))
1713
0
        )
1714
0
        return_error(gs_error_rangecheck);
1715
0
    if (level1.data == 0 && source.size <= MAX_PS_INLINE && objname == 0) {
1716
        /* Insert the PostScript code in-line */
1717
0
        int code = pdf_open_contents(pdev, PDF_IN_STREAM);
1718
0
        stream *s;
1719
1720
0
        if (code < 0)
1721
0
            return code;
1722
0
        s = pdev->strm;
1723
0
        stream_write(s, source.data, source.size);
1724
0
        stream_puts(s, " PS\n");
1725
0
    } else {
1726
        /* Put the PostScript code in a resource. */
1727
0
        cos_stream_t *pcs;
1728
0
        int code;
1729
0
        gs_id level1_id = gs_no_id;
1730
0
        pdf_resource_t *pres;
1731
1732
0
        if (level1.data != 0) {
1733
0
            pdf_resource_t *pres;
1734
1735
0
            code = pdf_enter_substream(pdev,
1736
0
                        resourceXObject,
1737
0
                        gs_no_id, &pres, true,
1738
0
                        pdev->CompressStreams);
1739
0
            if (code < 0)
1740
0
                return code;
1741
0
            pcs = (cos_stream_t *)pres->object;
1742
0
            if (pdev->ForOPDFRead && objname != 0) {
1743
0
                code = cos_dict_put_c_key_bool((cos_dict_t *)pres->object, "/.Global", true);
1744
0
                if (code < 0)
1745
0
                    return code;
1746
0
            }
1747
0
            pres->named = (objname != 0);
1748
0
            pres->where_used = 0;
1749
0
            pcs->pres = pres;
1750
0
            DISCARD(pdfmark_write_ps(pdev->strm, &level1));
1751
0
            code = pdf_exit_substream(pdev);
1752
0
            if (code < 0)
1753
0
                return code;
1754
0
            code = cos_write_object(pres->object, pdev, resourceOther);
1755
0
            if (code < 0)
1756
0
                return code;
1757
0
            level1_id = pres->object->id;
1758
0
        }
1759
0
        code = start_XObject(pdev, pdev->params.CompressPages, &pcs);
1760
0
        if (code < 0)
1761
0
            return code;
1762
0
        pres = pdev->accumulating_substream_resource;
1763
0
        code = cos_stream_put_c_strings(pcs, "/Type", "/XObject");
1764
0
        if (code < 0)
1765
0
            return code;
1766
0
        code = cos_stream_put_c_strings(pcs, "/Subtype", "/PS");
1767
0
        if (code < 0)
1768
0
            return code;
1769
0
        if (level1_id != gs_no_id) {
1770
0
            char r[MAX_DEST_STRING];
1771
1772
0
            gs_snprintf(r, sizeof(r), "%ld 0 R", level1_id);
1773
0
            code = cos_dict_put_c_key_string(cos_stream_dict(pcs), "/Level1",
1774
0
                                             (byte *)r, strlen(r));
1775
0
            if (code < 0)
1776
0
                return code;
1777
0
        }
1778
0
        DISCARD(pdfmark_write_ps(pdev->strm, &source));
1779
0
        code = pdf_exit_substream(pdev);
1780
0
        if (code < 0)
1781
0
            return code;
1782
0
        {   gs_const_string objname1, *pon = NULL;
1783
1784
0
            if (objname != NULL) {
1785
0
                objname1.data = objname->data;
1786
0
                objname1.size = objname->size;
1787
0
                pon = &objname1;
1788
0
            }
1789
0
            code = pdfmark_bind_named_object(pdev, pon, &pres);
1790
0
            if (code < 0)
1791
0
                return code;
1792
0
        }
1793
0
        code = pdf_open_contents(pdev, PDF_IN_STREAM);
1794
0
        if (code < 0)
1795
0
            return code;
1796
0
        pcs->pres->where_used |= pdev->used_mask;
1797
0
        pprintld1(pdev->strm, "/R%ld Do\n", pcs->id);
1798
0
    }
1799
0
    return 0;
1800
0
}
1801
1802
/* Common code for pdfmarks that do PUT into a specific object. */
1803
static int
1804
pdfmark_put_pairs(cos_dict_t *pcd, gs_param_string * pairs, uint count)
1805
6.20k
{
1806
6.20k
    int code = 0, i;
1807
1808
6.20k
    if (count & 1)
1809
0
        return_error(gs_error_rangecheck);
1810
11.3k
    for (i = 0; code >= 0 && i < count; i += 2)
1811
5.18k
        code = pdfmark_put_pair(pcd, pairs + i);
1812
6.20k
    return code;
1813
6.20k
}
1814
1815
/* PAGES pdfmark */
1816
static int
1817
pdfmark_PAGES(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1818
              const gs_matrix * pctm, const gs_param_string * no_objname)
1819
0
{
1820
0
    return pdfmark_put_pairs(pdev->Pages, pairs, count);
1821
0
}
1822
1823
/* PAGE pdfmark */
1824
static int
1825
pdfmark_PAGE(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1826
             const gs_matrix * pctm, const gs_param_string * no_objname)
1827
6.03k
{
1828
6.03k
    return pdfmark_put_pairs(pdf_current_page_dict(pdev), pairs, count);
1829
6.03k
}
1830
1831
/* Add a page label for the current page. The last label on a page
1832
 * overrides all previous labels for this page. Unlabeled pages will get
1833
 * empty page labels. label == NULL flushes the last label */
1834
static int
1835
pdfmark_add_pagelabel(gx_device_pdf * pdev, const gs_param_string *label)
1836
11.2k
{
1837
11.2k
    cos_value_t value;
1838
11.2k
    cos_dict_t *dict = 0;
1839
11.2k
    int code = 0;
1840
1841
    /* create label dict (and page label array if not present yet) */
1842
11.2k
    if (label != 0) {
1843
0
        if (!pdev->PageLabels) {
1844
0
            pdev->PageLabels = cos_array_alloc(pdev,
1845
0
                    "pdfmark_add_pagelabel(PageLabels)");
1846
0
            if (pdev->PageLabels == 0)
1847
0
                return_error(gs_error_VMerror);
1848
0
            pdev->PageLabels->id = pdf_obj_ref(pdev);
1849
1850
            /* empty label for unlabled pages before first labled page */
1851
0
            pdev->PageLabels_current_page = 0;
1852
0
            pdev->PageLabels_current_label = cos_dict_alloc(pdev,
1853
0
                                           "pdfmark_add_pagelabel(first)");
1854
0
            if (pdev->PageLabels_current_label == 0)
1855
0
                return_error(gs_error_VMerror);
1856
0
        }
1857
1858
0
        dict = cos_dict_alloc(pdev, "pdfmark_add_pagelabel(dict)");
1859
0
        if (dict == 0)
1860
0
            return_error(gs_error_VMerror);
1861
1862
0
        code = cos_dict_put_c_key(dict, "/P", cos_string_value(&value,
1863
0
            label->data, label->size));
1864
0
        if (code < 0) {
1865
0
            COS_FREE(dict, "pdfmark_add_pagelabel(dict)");
1866
0
            return code;
1867
0
        }
1868
0
    }
1869
1870
    /* flush current label */
1871
11.2k
    if (label == 0 || pdev->next_page != pdev->PageLabels_current_page) {
1872
        /* handle current label */
1873
11.2k
        if (pdev->PageLabels_current_label) {
1874
0
            if (code >= 0) {
1875
0
                code = cos_array_add_int(pdev->PageLabels,
1876
0
                        pdev->PageLabels_current_page);
1877
0
                if (code >= 0)
1878
0
                    code = cos_array_add(pdev->PageLabels,
1879
0
                            COS_OBJECT_VALUE(&value,
1880
0
                                pdev->PageLabels_current_label));
1881
0
            }
1882
0
            pdev->PageLabels_current_label = 0;
1883
0
        }
1884
1885
        /* handle unlabled pages between current labeled page and
1886
         * next labeled page */
1887
11.2k
        if (pdev->PageLabels) {
1888
0
            if (pdev->next_page - pdev->PageLabels_current_page > 1) {
1889
0
                cos_dict_t *tmp = cos_dict_alloc(pdev,
1890
0
                        "pdfmark_add_pagelabel(tmp)");
1891
0
                if (tmp == 0)
1892
0
                    return_error(gs_error_VMerror);
1893
1894
0
                code = cos_array_add_int(pdev->PageLabels,
1895
0
                        pdev->PageLabels_current_page + 1);
1896
0
                if (code >= 0)
1897
0
                    code = cos_array_add(pdev->PageLabels,
1898
0
                            COS_OBJECT_VALUE(&value, tmp));
1899
0
            }
1900
0
        }
1901
11.2k
    }
1902
1903
    /* new current label */
1904
11.2k
    if (pdev->PageLabels_current_label)
1905
0
        COS_FREE(pdev->PageLabels_current_label,
1906
11.2k
                "pdfmark_add_pagelabel(current_label)");
1907
11.2k
    pdev->PageLabels_current_label = dict;
1908
11.2k
    pdev->PageLabels_current_page = pdev->next_page;
1909
1910
11.2k
    return code;
1911
11.2k
}
1912
1913
/* Close the pagelabel numtree.*/
1914
int
1915
pdfmark_end_pagelabels(gx_device_pdf * pdev)
1916
11.2k
{
1917
11.2k
    return pdfmark_add_pagelabel(pdev, 0);
1918
11.2k
}
1919
1920
/* [ /Label string /PlateColor string pdfmark */
1921
/* FIXME: /PlateColor is ignored */
1922
static int
1923
pdfmark_PAGELABEL(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1924
             const gs_matrix * pctm, const gs_param_string * no_objname)
1925
0
{
1926
0
    gs_param_string key;
1927
1928
0
    if (pdev->CompatibilityLevel >= 1.3) {
1929
0
        if (pdfmark_find_key("/Label", pairs, count, &key)) {
1930
0
            return pdfmark_add_pagelabel(pdev, &key);
1931
0
        }
1932
0
    }
1933
0
    return 0;
1934
0
}
1935
1936
static int is_XMP_Key(const gs_param_string *param)
1937
0
{
1938
0
    if (pdf_key_eq(param, "/Title"))
1939
0
        return 1;
1940
0
    if (pdf_key_eq(param, "/Author"))
1941
0
        return 1;
1942
0
    if (pdf_key_eq(param, "/Subject"))
1943
0
        return 1;
1944
0
    if (pdf_key_eq(param, "/Keywords"))
1945
0
        return 1;
1946
0
    if (pdf_key_eq(param, "/Creator"))
1947
0
        return 1;
1948
0
    if (pdf_key_eq(param, "/Producer"))
1949
0
        return 1;
1950
    /* These two aren't string data types and so won't affect anything
1951
     * in the DOCINFO pdfmark, which is the only client for this code currently
1952
     * but we may want to use this in future for other purposed.
1953
     */
1954
0
    if (pdf_key_eq(param, "/CreationDate"))
1955
0
        return 1;
1956
0
    if (pdf_key_eq(param, "/ModDate"))
1957
0
        return 1;
1958
0
    return 0;
1959
0
}
1960
1961
/* DOCINFO pdfmark */
1962
static int
1963
pdfmark_DOCINFO(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
1964
                const gs_matrix * pctm, const gs_param_string * no_objname)
1965
1.36k
{
1966
    /*
1967
     * We could use pdfmark_put_pairs(pdev->Info, pairs, count), except
1968
     * that we want to replace "Distiller" with our own name as the
1969
     * Producer.
1970
     */
1971
1.36k
    cos_dict_t *const pcd = pdev->Info;
1972
1.36k
    int code = 0, i;
1973
1974
1.36k
    if (count & 1)
1975
0
        return_error(gs_error_rangecheck);
1976
4.91k
    for (i = 0; code >= 0 && i < count; i += 2) {
1977
3.54k
        const gs_param_string *pair = pairs + i;
1978
1979
3.54k
        if (pdev->CompatibilityLevel >= 2.0) {
1980
0
            if (!pdf_key_eq(pairs + i, "/ModDate") && !pdf_key_eq(pairs + i, "/CreationDate"))
1981
0
                continue;
1982
0
        }
1983
1984
3.54k
        if (pdev->PDFA !=0 && is_XMP_Key(pair)) {
1985
0
            const gs_param_string *p = pairs + i + 1;
1986
0
            bool abort = false;
1987
1988
0
            if (p->size > 9 && memcmp(p->data, "(\\376\\377", 9) == 0)
1989
0
                abort = true;
1990
0
            else {
1991
0
                int j;
1992
0
                for (j = 0;j < p->size;j++)
1993
0
                {
1994
0
                    if (p->data[j] == '\\' || p->data[j] > 0x7F || p->data[j] < 0x20)
1995
0
                    {
1996
0
                        abort = true;
1997
0
                        break;
1998
0
                    }
1999
0
                }
2000
0
            }
2001
0
            if (abort == true)
2002
0
            {
2003
                /* Can't handle UTF16BE in PDF/A1, so abort this pair or abort PDF/A or just abort,
2004
                 * depending on PDFACompatibilityPolicy
2005
                 */
2006
0
                switch (pdev->PDFACompatibilityPolicy) {
2007
0
                    case 0:
2008
0
                        emprintf(pdev->memory,
2009
0
                         "Text string detected in DOCINFO cannot be represented in XMP for PDF/A1, reverting to normal PDF output\n");
2010
0
                        pdev->AbortPDFAX = true;
2011
0
                        pdev->PDFX = 0;
2012
0
                        break;
2013
0
                    case 1:
2014
0
                        emprintf(pdev->memory,
2015
0
                         "Text string detected in DOCINFO cannot be represented in XMP for PDF/A1, discarding DOCINFO\n");
2016
0
                        continue;
2017
0
                        break;
2018
0
                    case 2:
2019
0
                        emprintf(pdev->memory,
2020
0
                         "Text string detected in DOCINFO cannot be represented in XMP for PDF/A1, aborting conversion.\n");
2021
                        /* If we don't return a fatal error then zputdeviceparams simply ignores it (!) */
2022
0
                        return_error(gs_error_Fatal);
2023
0
                        break;
2024
0
                    default:
2025
0
                        break;
2026
0
                }
2027
0
            }
2028
0
        }
2029
3.54k
        if (pdf_key_eq(pairs + i, "/Producer")) {
2030
0
            string_match_params params;
2031
0
            params = string_match_params_default;
2032
0
            params.ignore_case = true;
2033
2034
0
            if (!string_match((const byte *)GS_PRODUCTFAMILY, strlen(GS_PRODUCTFAMILY), (const byte *)"GPL Ghostscript", 15, &params))
2035
0
                code = pdfmark_put_pair(pcd, pair);
2036
0
        } else
2037
3.54k
            code = pdfmark_put_pair(pcd, pair);
2038
3.54k
        if (code < 0)
2039
0
            break;
2040
3.54k
    }
2041
1.36k
    return code;
2042
1.36k
}
2043
2044
/* DOCVIEW pdfmark */
2045
static int
2046
pdfmark_DOCVIEW(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2047
                const gs_matrix * pctm, const gs_param_string * no_objname)
2048
0
{
2049
0
    char dest[MAX_DEST_STRING];
2050
0
    int code = 0;
2051
2052
0
    if (count & 1)
2053
0
        return_error(gs_error_rangecheck);
2054
0
    code = pdfmark_make_dest(dest, pdev, "/Page", "/View", pairs, count, 0);
2055
0
    if (code < 0)
2056
0
        return gs_note_error(gs_error_rangecheck);
2057
2058
0
    if (code > 0) {
2059
0
        int i;
2060
2061
0
        code = cos_dict_put_c_key_string(pdev->Catalog, "/OpenAction",
2062
0
                                         (byte *)dest, strlen(dest));
2063
0
        for (i = 0; code >= 0 && i < count; i += 2)
2064
0
            if (!(pdf_key_eq(&pairs[i], "/Page") ||
2065
0
                  pdf_key_eq(&pairs[i], "/View"))
2066
0
                )
2067
0
                code = pdfmark_put_pair(pdev->Catalog, pairs + i);
2068
0
        return code;
2069
0
    } else
2070
0
        return pdfmark_put_pairs(pdev->Catalog, pairs, count);
2071
0
}
2072
2073
/* ---------------- Named object pdfmarks ---------------- */
2074
2075
/* [ /BBox [llx lly urx ury] /_objdef {obj} /BP pdfmark */
2076
static int
2077
pdfmark_BP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2078
           const gs_matrix * pctm, const gs_param_string * objname)
2079
0
{
2080
0
    gs_rect bbox;
2081
0
    cos_stream_t *pcs;
2082
0
    int code;
2083
0
    gs_matrix ictm;
2084
0
    byte bbox_str[6 + 6 * 15], matrix_str[6 + 6 * 15];
2085
0
    char chars[MAX_RECT_STRING + 1];
2086
0
    int bbox_str_len, matrix_str_len;
2087
0
    stream s;
2088
2089
0
    if (objname == 0 || count != 2 || !pdf_key_eq(&pairs[0], "/BBox"))
2090
0
        return_error(gs_error_rangecheck);
2091
0
    code = gs_matrix_invert(pctm, &ictm);
2092
0
    if (code < 0)
2093
0
        return code;
2094
0
    if (pairs[1].size > MAX_RECT_STRING)
2095
0
        return_error(gs_error_limitcheck);
2096
0
    memcpy(chars, pairs[1].data, pairs[1].size);
2097
0
    chars[pairs[1].size] = 0;
2098
0
    if (sscanf(chars, "[%lg %lg %lg %lg]",
2099
0
               &bbox.p.x, &bbox.p.y, &bbox.q.x, &bbox.q.y) != 4)
2100
0
        return_error(gs_error_rangecheck);
2101
0
    if ((pdev->used_mask << 1) == 0)
2102
0
        return_error(gs_error_limitcheck);
2103
0
    code = start_XObject(pdev, pdev->params.CompressPages, &pcs);
2104
0
    if (code < 0)
2105
0
        return code;
2106
0
    { byte *s = gs_alloc_string(pdev->memory, objname->size, "pdfmark_PS");
2107
2108
0
        if (s == NULL)
2109
0
            return_error(gs_error_VMerror);
2110
0
        memcpy(s, objname->data, objname->size);
2111
0
        pdev->objname.data = s;
2112
0
        pdev->objname.size = objname->size;
2113
0
    }
2114
0
    pcs->is_graphics = true;
2115
0
    gs_bbox_transform(&bbox, pctm, &bbox);
2116
0
    s_init(&s, NULL);
2117
0
    swrite_string(&s, bbox_str, sizeof(bbox_str));
2118
0
    pprintg4(&s, "[%g %g %g %g]",
2119
0
            bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
2120
0
    bbox_str_len = stell(&s);
2121
0
    swrite_string(&s, matrix_str, sizeof(bbox_str));
2122
0
    pprintg6(&s, "[%g %g %g %g %g %g]",
2123
0
            ictm.xx, ictm.xy, ictm.yx, ictm.yy, ictm.tx, ictm.ty);
2124
0
    matrix_str_len = stell(&s);
2125
0
    if ((code = cos_stream_put_c_strings(pcs, "/Type", "/XObject")) < 0 ||
2126
0
        (code = cos_stream_put_c_strings(pcs, "/Subtype", "/Form")) < 0 ||
2127
0
        (code = cos_stream_put_c_strings(pcs, "/FormType", "1")) < 0 ||
2128
0
        (code = cos_dict_put_c_key_string(cos_stream_dict(pcs), "/BBox",
2129
0
                                          bbox_str, bbox_str_len)) < 0 ||
2130
0
        (code = cos_dict_put_c_key_string(cos_stream_dict(pcs), "/Matrix",
2131
0
                                      matrix_str, matrix_str_len)) < 0 ||
2132
0
        (code = cos_dict_put_c_key_object(cos_stream_dict(pcs), "/Resources",
2133
0
                                          COS_OBJECT(pdev->substream_Resources))) < 0
2134
0
        )
2135
0
        return code;
2136
    /* Don't add to local_named_objects untill the object is created
2137
       to prevent pending references, which may appear
2138
       if /PUT pdfmark executes before pdf_substitute_resource in pdfmark_EP
2139
       drops this object.
2140
    */
2141
0
    pdev->FormDepth++;
2142
0
    return 0;
2143
0
}
2144
2145
/* [ /EP pdfmark */
2146
static int
2147
pdfmark_EP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2148
           const gs_matrix * pctm, const gs_param_string * no_objname)
2149
0
{
2150
0
    int code;
2151
0
    pdf_resource_t *pres = pdev->accumulating_substream_resource;
2152
0
    gs_const_string objname = pdev->objname;
2153
2154
    /* We are not currently accumulating a resource, this suggests an /EP
2155
     * without an opening /BP. This is (obviously) an error, Distiller throws
2156
     * an 'undefined' error, so we will too.
2157
     */
2158
0
    if (pres == NULL)
2159
0
        return_error(gs_error_undefined);
2160
2161
0
    if (pdev->CompatibilityLevel <= 1.7) {
2162
0
        code = pdf_add_procsets(pdev->substream_Resources, pdev->procsets);
2163
0
        if (code < 0)
2164
0
            return code;
2165
0
    }
2166
0
    code = pdf_exit_substream(pdev);
2167
0
    if (code < 0)
2168
0
        return code;
2169
0
    code = pdfmark_bind_named_object(pdev, &objname, &pres);
2170
0
    if (code < 0)
2171
0
        return 0;
2172
0
    gs_free_const_string(pdev->memory, objname.data, objname.size, "pdfmark_EP");
2173
0
    pdev->FormDepth--;
2174
0
    return 0;
2175
0
}
2176
2177
/* [ {obj} /SP pdfmark */
2178
static int
2179
pdfmark_SP(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2180
           const gs_matrix * pctm, const gs_param_string * no_objname)
2181
0
{
2182
0
    cos_object_t *pco;    /* stream */
2183
0
    int code;
2184
2185
0
    if (count != 1)
2186
0
        return_error(gs_error_rangecheck);
2187
0
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_stream, &pco)) < 0)
2188
0
        return code;
2189
0
    if (pco->is_open || !pco->is_graphics)
2190
0
        return_error(gs_error_rangecheck);
2191
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2192
0
    if (code < 0)
2193
0
        return code;
2194
0
    pdf_put_matrix(pdev, "q ", pctm, "cm");
2195
0
    pprintld1(pdev->strm, "/R%ld Do Q\n", pco->id);
2196
0
    pco->pres->where_used |= pdev->used_mask;
2197
2198
0
    code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pco->pres);
2199
0
    if (code < 0)
2200
0
        return code;
2201
2202
0
    return 0;
2203
0
}
2204
2205
/* [ /_objdef {array} /type /array /OBJ pdfmark */
2206
/* [ /_objdef {dict} /type /dict /OBJ pdfmark */
2207
/* [ /_objdef {stream} /type /stream /OBJ pdfmark */
2208
static int
2209
pdfmark_OBJ(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2210
            const gs_matrix * pctm, const gs_param_string * objname)
2211
171
{
2212
171
    cos_type_t cotype;
2213
171
    cos_object_t *pco;
2214
171
    bool stream = false;
2215
171
    int code;
2216
2217
171
    if (objname == 0 || count != 2 || !pdf_key_eq(&pairs[0], "/type"))
2218
0
        return_error(gs_error_rangecheck);
2219
171
    if (pdf_key_eq(&pairs[1], "/array"))
2220
0
        cotype = cos_type_array;
2221
171
    else if (pdf_key_eq(&pairs[1], "/dict"))
2222
146
        cotype = cos_type_dict;
2223
25
    else if ((stream = pdf_key_eq(&pairs[1], "/stream")))
2224
25
        cotype = cos_type_stream;
2225
0
    else
2226
0
        return_error(gs_error_rangecheck);
2227
171
    if ((code = pdf_make_named(pdev, objname, cotype, &pco, true)) < 0) {
2228
        /*
2229
         * For Distiller compatibility, allows multiple /OBJ pdfmarks with
2230
         * the same name and type, even though the pdfmark specification
2231
         * doesn't say anything about this being legal.
2232
         */
2233
0
        if (code == gs_error_rangecheck &&
2234
0
            pdf_refer_named(pdev, objname, &pco) >= 0 &&
2235
0
            cos_type(pco) == cotype
2236
0
            )
2237
0
            return 0;   /* already exists, but OK */
2238
0
        return code;
2239
0
    }
2240
171
    if (stream) {
2241
25
        if (pdev->CompressStreams)
2242
25
            return setup_pdfmark_stream_compression((gx_device_psdf *)pdev,
2243
25
                                                     (cos_stream_t *)pco);
2244
0
        else
2245
0
            return setup_pdfmark_stream_no_compression((gx_device_psdf *)pdev,
2246
0
                                                     (cos_stream_t *)pco);
2247
25
    }
2248
146
    return 0;
2249
171
}
2250
2251
/* [ {array} index value /PUT pdfmark */
2252
/* Dictionaries are converted to .PUTDICT */
2253
/* Streams are converted to .PUTSTREAM */
2254
static int
2255
pdfmark_PUT(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2256
            const gs_matrix * pctm, const gs_param_string * no_objname)
2257
0
{
2258
0
    cos_object_t *pco;
2259
0
    cos_value_t value;
2260
0
    int code, index;
2261
2262
0
    if (count != 3)
2263
0
        return_error(gs_error_rangecheck);
2264
0
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_array, &pco)) < 0)
2265
0
        return code;
2266
0
    if ((code = pdfmark_scan_int(&pairs[1], &index)) < 0)
2267
0
        return code;
2268
0
    if (index < 0)
2269
0
        return_error(gs_error_rangecheck);
2270
0
    if (pco->written)
2271
0
        return_error(gs_error_rangecheck);
2272
0
    return cos_array_put((cos_array_t *)pco, index,
2273
0
                cos_string_value(&value, pairs[2].data, pairs[2].size));
2274
0
}
2275
2276
/* [ {dict} key value ... /.PUTDICT pdfmark */
2277
/* [ {stream} key value ... /.PUTDICT pdfmark */
2278
/*
2279
 * Adobe's pdfmark documentation doesn't allow PUTDICT with a stream,
2280
 * but it's reasonable and unambiguous, and Acrobat Distiller accepts it,
2281
 * so we do too.
2282
 */
2283
static int
2284
pdfmark_PUTDICT(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2285
                const gs_matrix * pctm, const gs_param_string * no_objname)
2286
171
{
2287
171
    cos_object_t *pco;
2288
171
    int code, i;
2289
2290
171
    if ((code = pdf_refer_named(pdev, &pairs[0], &pco)) < 0)
2291
0
        return code;
2292
171
    if (cos_type(pco) != cos_type_dict && cos_type(pco) != cos_type_stream)
2293
0
        return_error(gs_error_typecheck);
2294
171
    if (pco->written)
2295
0
        return_error(gs_error_rangecheck);
2296
2297
    /* If this is a stream, and we are doing PDF/A output, and the stream
2298
     * is a Metadata stream, then we must not write it compressed. Bizarrely PDF/A
2299
     * excludes this.
2300
     */
2301
171
    if (cos_type(pco) == cos_type_stream && pdev->PDFA) {
2302
0
        for (i=0;i<count;i++) {
2303
0
            if (pairs[i].size == 9 && strncmp((const char *)pairs[i].data, "/Metadata", 9) == 0) {
2304
0
                cos_dict_t *pcd = (cos_dict_t *)pco;
2305
2306
                /* Close the compressed stream */
2307
0
                gs_free_object(pdev->pdf_memory, pco->input_strm, "free old stream, replacing with new stream");
2308
                /* And create a new uncompressed stream */
2309
0
                code = setup_pdfmark_stream_no_compression((gx_device_psdf *)pdev,
2310
0
                                                     (cos_stream_t *)pco);
2311
0
                if (code < 0)
2312
0
                    return code;
2313
2314
                /* We also need to remove any compression filters from the stream dictionary
2315
                 * The only possible error here is that the key isn't found, which is possible
2316
                 * and we don't care, so ignore the return code.
2317
                 */
2318
0
                cos_dict_delete_c_key(pcd, "/Filter");
2319
0
                cos_dict_delete_c_key(pcd, "/DecodeParams");
2320
0
            }
2321
0
        }
2322
0
    }
2323
2324
171
    return pdfmark_put_pairs((cos_dict_t *)pco, pairs + 1, count - 1);
2325
171
}
2326
2327
/* [ {stream} string ... /.PUTSTREAM pdfmark */
2328
static int
2329
pdfmark_PUTSTREAM(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2330
                  const gs_matrix * pctm, const gs_param_string * no_objname)
2331
25
{
2332
25
    cos_object_t *pco;
2333
25
    int code, i;
2334
25
    uint l;
2335
2336
25
    if (count < 2)
2337
0
        return_error(gs_error_rangecheck);
2338
25
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_stream, &pco)) < 0)
2339
0
        return code;
2340
25
    if (!pco->is_open)
2341
0
        return_error(gs_error_rangecheck);
2342
50
    for (i = 1; i < count; ++i)
2343
25
        if (sputs(pco->input_strm, pairs[i].data, pairs[i].size, &l) != 0)
2344
0
            return_error(gs_error_ioerror);
2345
25
    if (pco->written)
2346
0
        return_error(gs_error_rangecheck);
2347
25
    return code;
2348
25
}
2349
2350
/* [ {array} value /APPEND pdfmark */
2351
static int
2352
pdfmark_APPEND(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2353
               const gs_matrix * pctm, const gs_param_string * objname)
2354
0
{
2355
0
    cos_object_t *pco;
2356
0
    cos_value_t value;
2357
0
    int code;
2358
2359
0
    if (count != 2)
2360
0
        return_error(gs_error_rangecheck);
2361
0
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_array, &pco)) < 0)
2362
0
        return code;
2363
0
    return cos_array_add((cos_array_t *)pco,
2364
0
                cos_string_value(&value, pairs[1].data, pairs[1].size));
2365
0
}
2366
2367
/* [ {array} index value ... /.PUTINTERVAL pdfmark */
2368
static int
2369
pdfmark_PUTINTERVAL(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2370
                 const gs_matrix * pctm, const gs_param_string * no_objname)
2371
0
{
2372
0
    cos_object_t *pco;
2373
0
    cos_value_t value;
2374
0
    int code, index, i;
2375
2376
0
    if (count < 2)
2377
0
        return_error(gs_error_rangecheck);
2378
0
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_array, &pco)) < 0)
2379
0
        return code;
2380
0
    if ((code = pdfmark_scan_int(&pairs[1], &index)) < 0)
2381
0
        return code;
2382
0
    if (index < 0)
2383
0
        return_error(gs_error_rangecheck);
2384
0
    for (i = 2; code >= 0 && i < count; ++i)
2385
0
        code = cos_array_put((cos_array_t *)pco, index + i - 2,
2386
0
                cos_string_value(&value, pairs[i].data, pairs[i].size));
2387
0
    return code;
2388
0
}
2389
2390
/* [ {stream} /CLOSE pdfmark */
2391
static int
2392
pdfmark_CLOSE(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2393
              const gs_matrix * pctm, const gs_param_string * no_objname)
2394
25
{
2395
25
    cos_object_t *pco;
2396
25
    int code;
2397
2398
25
    if (count != 1)
2399
0
        return_error(gs_error_rangecheck);
2400
25
    if ((code = pdf_get_named(pdev, &pairs[0], cos_type_stream, &pco)) < 0)
2401
0
        return code;
2402
25
    if (!pco->is_open)
2403
0
        return_error(gs_error_rangecheck);
2404
    /* Currently we don't do anything special when closing a stream. */
2405
25
    pco->is_open = false;
2406
25
    return 0;
2407
25
}
2408
2409
/* [ /NamespacePush pdfmark */
2410
static int
2411
pdfmark_NamespacePush(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2412
                      const gs_matrix *pctm, const gs_param_string *objname)
2413
0
{
2414
0
    if (count != 0)
2415
0
        return_error(gs_error_rangecheck);
2416
0
    return pdf_push_namespace(pdev);
2417
0
}
2418
2419
/* [ /NamespacePop pdfmark */
2420
static int
2421
pdfmark_NamespacePop(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2422
                     const gs_matrix *pctm, const gs_param_string *objname)
2423
0
{
2424
0
    if (count != 0)
2425
0
        return_error(gs_error_rangecheck);
2426
0
    cos_dict_objects_write(pdev->local_named_objects, pdev);
2427
0
    return pdf_pop_namespace(pdev);
2428
0
}
2429
2430
/* [ /_objdef {image} /NI pdfmark */
2431
static int
2432
pdfmark_NI(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2433
           const gs_matrix *pctm, const gs_param_string *objname)
2434
0
{
2435
0
    cos_object_t *pco;
2436
0
    int code;
2437
2438
0
    if (objname == 0 || count != 0)
2439
0
        return_error(gs_error_rangecheck);
2440
0
    code = pdf_make_named(pdev, objname, cos_type_dict, &pco, true);
2441
0
    if (code < 0)
2442
0
        return code;
2443
0
    return cos_array_add_object(pdev->NI_stack, pco);
2444
0
}
2445
2446
/* ---------------- Named content pdfmarks ---------------- */
2447
2448
/* [ tag /MP pdfmark */
2449
static int
2450
pdfmark_MP(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2451
           const gs_matrix *pctm, const gs_param_string *objname)
2452
0
{
2453
0
    int code;
2454
0
    char *tag;
2455
2456
0
    if (count != 1) return_error(gs_error_rangecheck);
2457
2458
0
    tag = (char *)gs_alloc_bytes(pdev->memory, (pairs[0].size + 1) * sizeof(unsigned char),
2459
0
                "pdfmark_MP");
2460
0
    memcpy(tag, pairs[0].data, pairs[0].size);
2461
0
    tag[pairs[0].size] = 0x00;
2462
2463
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2464
0
    if (code < 0) return code;
2465
2466
0
    pprints1(pdev->strm, "%s MP\n", tag);
2467
2468
0
    gs_free_object(pdev->memory, tag, "pdfmark_MP");
2469
0
    return 0;
2470
0
}
2471
2472
/* [ tag propdict /DP pdfmark */
2473
static int
2474
pdfmark_DP(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2475
           const gs_matrix *pctm, const gs_param_string *objname)
2476
0
{
2477
0
    int code;
2478
0
    cos_object_t *pco;
2479
0
    char *cstring;
2480
0
    pdf_resource_t *pres;
2481
2482
0
    if (count != 2) return_error(gs_error_rangecheck);
2483
2484
    /* check tag for /Name object syntax */
2485
0
    if ((pairs[0].data)[0] != '/') return_error(gs_error_rangecheck);
2486
2487
    /* check propdict for {object name} syntax */
2488
0
    if (pdf_objname_is_valid(pairs[1].data, pairs[1].size))
2489
0
    {
2490
0
        code = pdf_refer_named(pdev, &pairs[1], &pco);
2491
0
        if(code < 0) return code;
2492
0
    }
2493
0
    else /* << inline prop dict >> */
2494
0
    {
2495
        /* strip << and >> */
2496
0
        if ((pairs[1].data)[0]=='<'&&(pairs[1].data)[1]=='<')
2497
0
        {
2498
0
            int ix = 0;
2499
0
            byte *p = (byte *)pairs[1].data;
2500
2501
            /* Fortunately we don't use the 'size' when freeing the memory
2502
             * so we can quickly copy the string content up two places and reduce
2503
             * the size by 2 to remove the '<<'. This saves an alloc and free of the
2504
             * string data.
2505
             */
2506
0
            for (ix = 0; ix < pairs[1].size - 2;ix++)
2507
0
                p[ix] = pairs[1].data[ix + 2];
2508
0
            pairs[1].size-=2;
2509
0
        }
2510
0
        else
2511
0
            return_error(gs_error_rangecheck);
2512
2513
0
        if ((pairs[1].data)[pairs[1].size-1]=='>'&&(pairs[1].data)[pairs[1].size-2]=='>')
2514
0
            pairs[1].size-=2;
2515
2516
        /* convert inline propdict to C string with object names replaced by refs */
2517
0
        code = pdf_replace_names(pdev, &pairs[1], &pairs[1]);
2518
0
        if (code<0) return code;
2519
0
        cstring = (char *)gs_alloc_bytes(pdev->memory, (pairs[1].size + 1) * sizeof(unsigned char),
2520
0
            "pdfmark_DP");
2521
0
        memcpy(cstring, pairs[1].data, pairs[1].size);
2522
0
        cstring[pairs[1].size] = 0x00;
2523
2524
0
        code = pdf_make_named_dict(pdev, NULL, (cos_dict_t**) &pco, true);
2525
0
        if (code<0) return code;
2526
2527
        /* copy inline propdict to new object */
2528
0
        code = cos_dict_put_c_strings((cos_dict_t*) pco, cstring, "");
2529
0
        if(code < 0) return code;
2530
0
        COS_WRITE_OBJECT(pco, pdev, resourceProperties);
2531
0
        COS_RELEASE(pco, "pdfmark_DP");
2532
0
        gs_free_object(pdev->memory, cstring, "pdfmark_DP");
2533
0
    }
2534
2535
0
    pres = pdf_find_resource_by_resource_id(pdev, resourceProperties, pco->id);
2536
0
    if (pres==0){
2537
0
        if ((code = pdf_alloc_resource(pdev, resourceProperties, pco->id, &(pco->pres), pco->id))<0)
2538
0
            return code;
2539
0
    }
2540
2541
0
    cstring = (char *)gs_alloc_bytes(pdev->memory, (pairs[0].size + 1) * sizeof(unsigned char),
2542
0
                "pdfmark_DP");
2543
0
    memcpy(cstring, pairs[0].data, pairs[0].size);
2544
0
    cstring[pairs[0].size] = 0x00;
2545
2546
    /* make sure we write to the correct stream */
2547
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2548
0
    if (code < 0) return code;
2549
2550
0
    pprints1(pdev->strm, "%s", cstring); /* write tag */
2551
0
    pprintld1(pdev->strm, "/R%ld DP\n", pco->id);
2552
0
    pco->pres->where_used |= pdev->used_mask;
2553
0
    if ((code = pdf_add_resource(pdev, pdev->substream_Resources, "/Properties", pco->pres))<0)
2554
0
        return code;
2555
2556
0
    gs_free_object(pdev->memory, cstring, "pdfmark_DP");
2557
0
    return 0;
2558
0
}
2559
2560
/* [ tag /BMC pdfmark */
2561
static int
2562
pdfmark_BMC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2563
            const gs_matrix *pctm, const gs_param_string *objname)
2564
0
{
2565
0
    int code;
2566
0
    char *tag;
2567
2568
0
    if (count != 1) return_error(gs_error_rangecheck);
2569
2570
0
    tag = (char *)gs_alloc_bytes(pdev->memory, (pairs[0].size + 1) * sizeof(unsigned char),
2571
0
                "pdfmark_BMC");
2572
0
    memcpy(tag, pairs[0].data, pairs[0].size);
2573
0
    tag[pairs[0].size] = 0x00;
2574
2575
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2576
0
    if (code < 0) return code;
2577
2578
0
    pprints1(pdev->strm, "%s BMC\n", tag);
2579
2580
0
    gs_free_object(pdev->memory, tag, "pdfmark_BMC");
2581
0
    return 0;
2582
0
}
2583
2584
/* [ tag propdict /BDC pdfmark */
2585
static int
2586
pdfmark_BDC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2587
            const gs_matrix *pctm, const gs_param_string *objname)
2588
0
{
2589
0
    int code;
2590
0
    cos_object_t *pco;
2591
0
    char *cstring;
2592
0
    pdf_resource_t *pres;
2593
2594
0
    if (count != 2) return_error(gs_error_rangecheck);
2595
2596
    /* check tag for /Name object syntax */
2597
0
    if ((pairs[0].data)[0] != '/') return_error(gs_error_rangecheck);
2598
2599
    /* check propdict for {object name} syntax */
2600
0
    if (pdf_objname_is_valid(pairs[1].data, pairs[1].size))
2601
0
    {
2602
0
        code = pdf_refer_named(pdev, &pairs[1], &pco);
2603
0
        if(code < 0) return code;
2604
0
    }
2605
0
    else /* << inline prop dict >> */
2606
0
    {
2607
        /* strip << and >> */
2608
0
        if ((pairs[1].data)[0]=='<'&&(pairs[1].data)[1]=='<')
2609
0
        {
2610
0
            int ix = 0;
2611
0
            byte *p = (byte *)pairs[1].data;
2612
2613
            /* Fortunately we don't use the 'size' when freeing the memory
2614
             * so we can quickly copy the string content up two places and reduce
2615
             * the size by 2 to remove the '<<'. This saves an alloc and free of the
2616
             * string data.
2617
             */
2618
0
            for (ix = 0; ix < pairs[1].size - 2;ix++)
2619
0
                p[ix] = pairs[1].data[ix + 2];
2620
0
            pairs[1].size-=2;
2621
0
        }
2622
0
        else
2623
0
            return_error(gs_error_rangecheck);
2624
2625
0
        if ((pairs[1].data)[pairs[1].size-1]=='>'&&(pairs[1].data)[pairs[1].size-2]=='>')
2626
0
            pairs[1].size-=2;
2627
2628
        /* convert inline propdict to C string with object names replaced by refs */
2629
0
        code = pdf_replace_names(pdev, &pairs[1], &pairs[1]);
2630
0
        if (code<0) return code;
2631
0
        cstring = (char *)gs_alloc_bytes(pdev->memory, (pairs[1].size + 1) * sizeof(unsigned char),
2632
0
            "pdfmark_BDC");
2633
0
        memcpy(cstring, pairs[1].data, pairs[1].size);
2634
0
        cstring[pairs[1].size] = 0x00;
2635
2636
0
        code = pdf_make_named_dict(pdev, NULL, (cos_dict_t**) &pco, true);
2637
0
        if (code<0) return code;
2638
2639
        /* copy inline propdict to new object */
2640
0
        code = cos_dict_put_c_strings((cos_dict_t*) pco, cstring, "");
2641
0
        if(code < 0) return code;
2642
0
        COS_WRITE_OBJECT(pco, pdev, resourceProperties);
2643
0
        COS_RELEASE(pco, "pdfmark_BDC");
2644
0
        gs_free_object(pdev->memory, cstring, "pdfmark_BDC");
2645
0
    }
2646
2647
0
    pres = pdf_find_resource_by_resource_id(pdev, resourceProperties, pco->id);
2648
0
    if (pres==0){
2649
0
        if ((code = pdf_alloc_resource(pdev, resourceProperties, pco->id, &(pco->pres), pco->id))<0)
2650
0
            return code;
2651
0
    }
2652
2653
0
    cstring = (char *)gs_alloc_bytes(pdev->memory, (pairs[0].size + 1) * sizeof(unsigned char),
2654
0
                "pdfmark_BDC");
2655
0
    memcpy(cstring, pairs[0].data, pairs[0].size);
2656
0
    cstring[pairs[0].size] = 0x00;
2657
2658
    /* make sure we write to the correct stream */
2659
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2660
0
    if (code < 0) return code;
2661
2662
0
    pprints1(pdev->strm, "%s", cstring); /* write tag */
2663
0
    pprintld1(pdev->strm, "/R%ld BDC\n", pco->id);
2664
0
    pco->pres->where_used |= pdev->used_mask;
2665
0
    if ((code = pdf_add_resource(pdev, pdev->substream_Resources, "/Properties", pco->pres))<0)
2666
0
        return code;
2667
2668
0
    gs_free_object(pdev->memory, cstring, "pdfmark_BDC");
2669
0
    return 0;
2670
0
}
2671
2672
/* [ /EMC pdfmark */
2673
static int
2674
pdfmark_EMC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2675
            const gs_matrix *pctm, const gs_param_string *objname)
2676
0
{
2677
0
    int code;
2678
2679
0
    code = pdf_open_contents(pdev, PDF_IN_STREAM);
2680
0
    if (code < 0) return code;
2681
0
    stream_puts(pdev->strm, "EMC\n");
2682
2683
0
    return 0;
2684
0
}
2685
2686
/* ---------------- Document structure pdfmarks ---------------- */
2687
2688
/* [ newsubtype1 stdsubtype1 ... /StRoleMap pdfmark */
2689
static int
2690
pdfmark_StRoleMap(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2691
                  const gs_matrix *pctm, const gs_param_string *objname)
2692
0
{
2693
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2694
0
}
2695
2696
/* [ class1 {attrobj1} ... /StClassMap pdfmark */
2697
static int
2698
pdfmark_StClassMap(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2699
                   const gs_matrix *pctm, const gs_param_string *objname)
2700
0
{
2701
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2702
0
}
2703
2704
/*
2705
 * [ [/_objdef {objname}] /Subtype name [/Title string] [/Alt string]
2706
 *   [/ID string] [/Class name] [/At index] [/Bookmark dict] [action_pairs...]
2707
 *   /StPNE pdfmark
2708
 */
2709
static int
2710
pdfmark_StPNE(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2711
              const gs_matrix *pctm, const gs_param_string *objname)
2712
0
{
2713
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2714
0
}
2715
2716
/* [ [/Title string] [/Open bool] [action_pairs...] /StBookmarkRoot pdfmark */
2717
static int
2718
pdfmark_StBookmarkRoot(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2719
                       const gs_matrix *pctm, const gs_param_string *objname)
2720
0
{
2721
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2722
0
}
2723
2724
/* [ [/E {elt}] /StPush pdfmark */
2725
static int
2726
pdfmark_StPush(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2727
               const gs_matrix *pctm, const gs_param_string *objname)
2728
0
{
2729
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2730
0
}
2731
2732
/* [ /StPop pdfmark */
2733
static int
2734
pdfmark_StPop(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2735
              const gs_matrix *pctm, const gs_param_string *objname)
2736
0
{
2737
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2738
0
}
2739
2740
/* [ /StPopAll pdfmark */
2741
static int
2742
pdfmark_StPopAll(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2743
                 const gs_matrix *pctm, const gs_param_string *objname)
2744
0
{
2745
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2746
0
}
2747
2748
/* [ [/T tagname] [/At index] /StBMC pdfmark */
2749
static int
2750
pdfmark_StBMC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2751
              const gs_matrix *pctm, const gs_param_string *objname)
2752
0
{
2753
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2754
0
}
2755
2756
/* [ [/P propdict] [/T tagname] [/At index] /StBDC pdfmark */
2757
static int
2758
pdfmark_StBDC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2759
              const gs_matrix *pctm, const gs_param_string *objname)
2760
0
{
2761
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2762
0
}
2763
2764
/* [ /Obj {obj} [/At index] /StOBJ pdfmark */
2765
static int
2766
pdfmark_StOBJ(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2767
              const gs_matrix *pctm, const gs_param_string *objname)
2768
0
{
2769
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2770
0
}
2771
2772
/* [ /Obj {obj} /StAttr pdfmark */
2773
static int
2774
pdfmark_StAttr(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2775
               const gs_matrix *pctm, const gs_param_string *objname)
2776
0
{
2777
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2778
0
}
2779
2780
/* [ /StoreName name /StStore pdfmark */
2781
static int
2782
pdfmark_StStore(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2783
                const gs_matrix *pctm, const gs_param_string *objname)
2784
0
{
2785
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2786
0
}
2787
2788
/* [ /StoreName name /StRetrieve pdfmark */
2789
static int
2790
pdfmark_StRetrieve(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
2791
                   const gs_matrix *pctm, const gs_param_string *objname)
2792
0
{
2793
0
    return 0;     /****** NOT IMPLEMENTED YET ******/
2794
0
}
2795
2796
static int
2797
pdfmark_Metadata(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2798
             const gs_matrix * pctm, const gs_param_string * objname)
2799
0
{
2800
0
    int i;
2801
0
    gs_param_string key;
2802
0
    char data[10] = "/Metadata";
2803
2804
0
    if (pdev->CompatibilityLevel < 1.4) {
2805
0
        dmprintf(pdev->pdf_memory, "Cannot add Metadata to PDF files with version earlier than 1.4.\n");
2806
0
        return 0;
2807
0
    }
2808
0
    if (pdev->PDFA != 0)
2809
0
        dmprintf(pdev->pdf_memory, "Warning: PDF/A output requires specific metadata, this pdfmark has overridden that,\n         output conformance cannot be guaranteed\n");
2810
0
    if (pdev->PDFX != 0)
2811
0
        dmprintf(pdev->pdf_memory, "Warning: PDF/X output requires specific metadata, this pdfmark has overridden that,\n         output conformance cannot be guaranteed\n");
2812
2813
0
    if(pdev->ExtensionMetadata) {
2814
0
        dmprintf(pdev->pdf_memory, "Extension metadata exists when /Metadata pdfmark executed, discarding extension metadata.\n");
2815
0
        gs_free_object(pdev->pdf_memory->stable_memory, pdev->ExtensionMetadata, "Extension metadata discarded on /Metadata pdfmark");
2816
0
    }
2817
2818
0
    if (!pdev->Catalog) {
2819
0
        gs_param_string nstr;
2820
2821
0
        param_string_from_string(nstr, "{Catalog}");
2822
0
        pdf_create_named_dict(pdev, &nstr, &pdev->Catalog, 0L);
2823
0
    }
2824
2825
0
    key.data = (const byte *)&data;
2826
0
    key.size = 9;
2827
2828
0
    for (i = 0; i < count; i += 2) {
2829
0
        if (pdf_key_eq(&pairs[i], "{Catalog}")) {
2830
0
            return cos_dict_put_string(pdev->Catalog, key.data, key.size,
2831
0
                               pairs[i+1].data, pairs[i+1].size);
2832
0
        }
2833
0
    }
2834
0
    return 0;
2835
0
}
2836
2837
static int
2838
pdfmark_Ext_Metadata(gx_device_pdf * pdev, gs_param_string * pairs, uint count,
2839
             const gs_matrix * pctm, const gs_param_string * objname)
2840
0
{
2841
0
    int i, j=0;
2842
2843
0
    if (pdev->CompatibilityLevel < 1.4) {
2844
0
        dmprintf(pdev->pdf_memory, "Cannot add Metadata to PDF files with version earlier than 1.4.\n");
2845
0
        return 0;
2846
0
    }
2847
2848
0
    if (cos_dict_find_c_key(pdev->Catalog, "/Metadata")) {
2849
0
        dmprintf(pdev->pdf_memory, "Cannot add extension to Metadata specified with the /Metadata pdfmark\n");
2850
0
        return 0;
2851
0
    }
2852
2853
0
    if(pdev->ExtensionMetadata) {
2854
0
        dmprintf(pdev->pdf_memory, "Extension metadata already defined, discarding old data.\n");
2855
0
        gs_free_object(pdev->pdf_memory->stable_memory, pdev->ExtensionMetadata, "Extension metadata");
2856
0
    }
2857
0
    pdev->ExtensionMetadata = (char *)gs_alloc_bytes(pdev->pdf_memory->stable_memory, pairs[1].size - 1, "Extension metadata");
2858
0
    memset(pdev->ExtensionMetadata, 0x00, pairs[1].size - 1);
2859
0
    for (i=1;i<pairs[1].size - 1;i++) {
2860
0
        if (pairs[1].data[i] == '\\') {
2861
0
            switch(pairs[1].data[i+1]) {
2862
0
                case '(':
2863
0
                case ')':
2864
0
                case '\\':
2865
0
                    pdev->ExtensionMetadata[j++] = pairs[1].data[i+1];
2866
0
                    i++;
2867
0
                    break;
2868
0
                case 'r':
2869
0
                    pdev->ExtensionMetadata[j++] = 0x0D;
2870
0
                    i++;
2871
0
                    break;
2872
0
                case 'n':
2873
0
                    pdev->ExtensionMetadata[j++] = 0x0A;
2874
0
                    i++;
2875
0
                    break;
2876
0
                case 't':
2877
0
                    pdev->ExtensionMetadata[j++] = 0x09;
2878
0
                    i++;
2879
0
                    break;
2880
0
                case 'b':
2881
0
                    pdev->ExtensionMetadata[j++] = 0x08;
2882
0
                    i++;
2883
0
                    break;
2884
0
                case 'f':
2885
0
                    pdev->ExtensionMetadata[j++] = 0x0C;
2886
0
                    i++;
2887
0
                    break;
2888
0
                default:
2889
0
                    if((pairs[1].data[i+1]) >= 0x30 && (pairs[1].data[i+1]) <= 0x39) {
2890
0
                        pdev->ExtensionMetadata[j++] = (pairs[1].data[i+1] - 0x30) * 64 + (pairs[1].data[i+2] - 0x30) * 8 + (pairs[1].data[i+3] - 0x30);
2891
0
                        i += 3;
2892
0
                    } else
2893
0
                        pdev->ExtensionMetadata[j++] = pairs[1].data[i];
2894
0
                    break;
2895
0
            }
2896
0
        } else
2897
0
            pdev->ExtensionMetadata[j++] = pairs[1].data[i];
2898
0
    }
2899
0
    return 0;
2900
0
}
2901
/* ---------------- Dispatch ---------------- */
2902
2903
/*
2904
 * Define the pdfmark types we know about.
2905
 */
2906
static const pdfmark_name mark_names[] =
2907
{
2908
        /* Miscellaneous. */
2909
    {"ANN",          pdfmark_ANN,         PDFMARK_NAMEABLE},
2910
    {"LNK",          pdfmark_LNK,         PDFMARK_NAMEABLE},
2911
    {"OUT",          pdfmark_OUT,         0},
2912
    {"ARTICLE",      pdfmark_ARTICLE,     0},
2913
    {"DEST",         pdfmark_DEST,        PDFMARK_NAMEABLE},
2914
    {"EMBED",        pdfmark_EMBED,       PDFMARK_NAMEABLE},
2915
    {"PS",           pdfmark_PS,          PDFMARK_NAMEABLE},
2916
    {"PAGES",        pdfmark_PAGES,       0},
2917
    {"PAGE",         pdfmark_PAGE,        0},
2918
    {"PAGELABEL",    pdfmark_PAGELABEL,   0},
2919
    {"DOCINFO",      pdfmark_DOCINFO,     0},
2920
    {"DOCVIEW",      pdfmark_DOCVIEW,     0},
2921
        /* Named objects. */
2922
    {"BP",           pdfmark_BP,          PDFMARK_NAMEABLE | PDFMARK_TRUECTM},
2923
    {"EP",           pdfmark_EP,          0},
2924
    {"SP",           pdfmark_SP,          PDFMARK_ODD_OK | PDFMARK_KEEP_NAME | PDFMARK_TRUECTM},
2925
    {"OBJ",          pdfmark_OBJ,         PDFMARK_NAMEABLE},
2926
    {"PUT",          pdfmark_PUT,         PDFMARK_ODD_OK | PDFMARK_KEEP_NAME},
2927
    {".PUTDICT",     pdfmark_PUTDICT,     PDFMARK_ODD_OK | PDFMARK_KEEP_NAME},
2928
    {".PUTINTERVAL", pdfmark_PUTINTERVAL, PDFMARK_ODD_OK | PDFMARK_KEEP_NAME},
2929
    {".PUTSTREAM",   pdfmark_PUTSTREAM,   PDFMARK_ODD_OK | PDFMARK_KEEP_NAME |
2930
                                          PDFMARK_NO_REFS},
2931
    {"APPEND",       pdfmark_APPEND,      PDFMARK_KEEP_NAME},
2932
    {"CLOSE",        pdfmark_CLOSE,       PDFMARK_ODD_OK | PDFMARK_KEEP_NAME},
2933
    {"NamespacePush", pdfmark_NamespacePush, 0},
2934
    {"NamespacePop", pdfmark_NamespacePop, 0},
2935
    {"NI",           pdfmark_NI,          PDFMARK_NAMEABLE},
2936
        /* Marked content. */
2937
    {"MP",           pdfmark_MP,          PDFMARK_ODD_OK},
2938
    {"DP",           pdfmark_DP,          0},
2939
    {"BMC",          pdfmark_BMC,         PDFMARK_ODD_OK},
2940
    {"BDC",          pdfmark_BDC,         PDFMARK_NO_REFS},
2941
    {"EMC",          pdfmark_EMC,         0},
2942
        /* Document structure. */
2943
    {"StRoleMap",    pdfmark_StRoleMap,   0},
2944
    {"StClassMap",   pdfmark_StClassMap,  0},
2945
    {"StPNE",        pdfmark_StPNE,       PDFMARK_NAMEABLE},
2946
    {"StBookmarkRoot", pdfmark_StBookmarkRoot, 0},
2947
    {"StPush",       pdfmark_StPush,       0},
2948
    {"StPop",        pdfmark_StPop,        0},
2949
    {"StPopAll",     pdfmark_StPopAll,     0},
2950
    {"StBMC",        pdfmark_StBMC,        0},
2951
    {"StBDC",        pdfmark_StBDC,        0},
2952
    /* EMC is listed under "Marked content" above. */
2953
    {"StOBJ",        pdfmark_StOBJ,        0},
2954
    {"StAttr",       pdfmark_StAttr,       0},
2955
    {"StStore",      pdfmark_StStore,      0},
2956
    {"StRetrieve",   pdfmark_StRetrieve,   0},
2957
    /* Metadata and extension */
2958
    {"Metadata",     pdfmark_Metadata,     0},
2959
    {"Ext_Metadata", pdfmark_Ext_Metadata, 0},
2960
        /* End of list. */
2961
    {0, 0}
2962
};
2963
2964
/* Process a pdfmark. */
2965
int
2966
pdfmark_process(gx_device_pdf * pdev, const gs_param_string_array * pma)
2967
65.2k
{
2968
65.2k
    const gs_param_string *data = pma->data;
2969
65.2k
    uint size = pma->size;
2970
65.2k
    const gs_param_string *pts = &data[size - 1];
2971
65.2k
    const gs_param_string *objname = 0;
2972
65.2k
    gs_matrix ctm;
2973
65.2k
    const pdfmark_name *pmn;
2974
65.2k
    int code = 0;
2975
2976
65.2k
    { int cnt, len = pts[-1].size;
2977
65.2k
        char buf[200]; /* 6 doubles should fit (%g == -0.14285714285714285e-101 = 25 chars) */
2978
2979
65.2k
        if (len > sizeof(buf) - 1)
2980
0
            return_error(gs_error_rangecheck);
2981
65.2k
        memcpy(buf, pts[-1].data, len);
2982
65.2k
        buf[len] = 0;
2983
65.2k
        cnt = sscanf(buf, "[%g %g %g %g %g %g]",
2984
65.2k
                   &ctm.xx, &ctm.xy, &ctm.yx, &ctm.yy, &ctm.tx, &ctm.ty);
2985
65.2k
        if (cnt != 6)
2986
0
            return_error(gs_error_rangecheck);
2987
65.2k
    }
2988
65.2k
    size -= 2;      /* remove CTM & pdfmark name */
2989
141k
    for (pmn = mark_names; pmn->mname != 0; ++pmn)
2990
141k
        if (pdf_key_eq(pts, pmn->mname)) {
2991
65.2k
            gs_memory_t *mem = pdev->pdf_memory;
2992
65.2k
            int odd_ok = (pmn->options & PDFMARK_ODD_OK) != 0;
2993
65.2k
            gs_param_string *pairs;
2994
65.2k
            int j, index;
2995
2996
            /*
2997
             * Our coordinate system is scaled so that user space is always
2998
             * default user space.  Adjust the CTM to match this, except if this
2999
             * particular pdfmark requires the "true" CTM.
3000
             */
3001
65.2k
            if (pmn->options & PDFMARK_TRUECTM)
3002
65.2k
                DO_NOTHING;
3003
65.2k
            else {
3004
65.2k
                double xscale = 72.0 / pdev->HWResolution[0],
3005
65.2k
                       yscale = 72.0 / pdev->HWResolution[1];
3006
65.2k
                ctm.xx *= xscale, ctm.xy *= yscale;
3007
65.2k
                ctm.yx *= xscale, ctm.yy *= yscale;
3008
65.2k
                ctm.tx *= xscale, ctm.ty *= yscale;
3009
65.2k
            }
3010
65.2k
            if (size & !odd_ok)
3011
0
                return_error(gs_error_rangecheck);
3012
65.2k
            if (pmn->options & PDFMARK_NAMEABLE) {
3013
                /* Look for an object name. */
3014
491k
                for (j = 0; j < size; j += 2) {
3015
434k
                    if (pdf_key_eq(&data[j], "/_objdef")) {
3016
171
                        objname = &data[j + 1];
3017
171
                        if (!pdf_objname_is_valid(objname->data,
3018
171
                                                  objname->size)
3019
171
                            )
3020
0
                            return_error(gs_error_rangecheck);
3021
                        /* Save the pairs without the name. */
3022
171
                        size -= 2;
3023
171
                        pairs = (gs_param_string *)
3024
171
                            gs_alloc_byte_array(mem, size,
3025
171
                                                sizeof(gs_param_string),
3026
171
                                                "pdfmark_process(pairs)");
3027
171
                        if (!pairs)
3028
0
                            return_error(gs_error_VMerror);
3029
3030
513
                        for (index=0;index < size;index++)
3031
342
                            pairs[index].data = NULL;
3032
171
                        for (index=0;index < j;index++) {
3033
0
                            pairs[index].data = gs_alloc_bytes(mem, data[index].size, "pdfmark_process(pairs)");
3034
0
                            if (pairs[index].data == NULL)
3035
0
                                goto error;
3036
0
                            memcpy((byte *)pairs[index].data, data[index].data, data[index].size);
3037
0
                            pairs[index].size = data[index].size;
3038
0
                            pairs[index].persistent = 1;
3039
0
                        }
3040
513
                        for (index=j+2;index < size + 2;index++) {
3041
342
                            pairs[index - 2].data = gs_alloc_bytes(mem, data[index].size, "pdfmark_process(pairs)");
3042
342
                            if (pairs[index - 2].data == NULL)
3043
0
                                goto error;
3044
342
                            memcpy((byte *)pairs[index - 2].data, data[index].data, data[index].size);
3045
342
                            pairs[index - 2].size = data[index].size;
3046
342
                            pairs[index - 2].persistent = 1;
3047
342
                        }
3048
171
                        goto copied;
3049
171
                    }
3050
434k
                }
3051
57.5k
            }
3052
            /* Save all the pairs. */
3053
65.0k
            pairs = (gs_param_string *)
3054
65.0k
                gs_alloc_byte_array(mem, size, sizeof(gs_param_string),
3055
65.0k
                                    "pdfmark_process(pairs)");
3056
65.0k
            if (!pairs)
3057
0
                return_error(gs_error_VMerror);
3058
951k
            for (j=0;j < size;j++)
3059
886k
                pairs[j].data = NULL;
3060
951k
            for (j=0;j < size;j++) {
3061
886k
                pairs[j].data = gs_alloc_bytes(mem, data[j].size, "pdfmark_process(pairs)");
3062
886k
                if (pairs[j].data == NULL)
3063
0
                    goto error;
3064
886k
                memcpy((byte *)pairs[j].data, data[j].data, data[j].size);
3065
886k
                pairs[j].size = data[j].size;
3066
886k
                pairs[j].persistent = 1;
3067
886k
            }
3068
65.2k
copied:   /* Substitute object references for names. */
3069
65.2k
            if (!(pmn->options & PDFMARK_NO_REFS)) {
3070
65.2k
                for (j = (pmn->options & PDFMARK_KEEP_NAME ? 1 : 1 - odd_ok);
3071
509k
                     j < size; j += 2 - odd_ok
3072
443k
                     ) {
3073
443k
                    code = pdf_replace_names(pdev, &pairs[j], &pairs[j]);
3074
443k
                    if (code < 0) {
3075
0
                        gs_free_object(mem, pairs, "pdfmark_process(pairs)");
3076
0
                        return code;
3077
0
                    }
3078
443k
                }
3079
65.2k
            }
3080
65.2k
            code = (*pmn->proc) (pdev, pairs, size, &ctm, objname);
3081
65.2k
error:
3082
951k
            for (j=0;j < size;j++)
3083
886k
                gs_free_object(mem, (byte *)pairs[j].data, "pdfmark_process(pairs)");
3084
65.2k
            gs_free_object(mem, pairs, "pdfmark_process(pairs)");
3085
65.2k
            break;
3086
65.2k
        }
3087
65.2k
    return code;
3088
65.2k
}