Coverage Report

Created: 2025-12-31 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_doc.c
Line
Count
Source
1
/* Copyright (C) 2020-2025 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Functions to deal with PDF structure, such as retrieving
17
 * the Info, Catalog, Root dictionaries, and finding resources
18
 * and page dictionaries.
19
 */
20
21
#include "ghostpdf.h"
22
#include "pdf_stack.h"
23
#include "pdf_deref.h"
24
#include "pdf_array.h"
25
#include "pdf_dict.h"
26
#include "pdf_loop_detect.h"
27
#include "pdf_misc.h"
28
#include "pdf_repair.h"
29
#include "pdf_doc.h"
30
#include "pdf_mark.h"
31
#include "pdf_colour.h"
32
#include "pdf_device.h"
33
34
int pdfi_read_Root(pdf_context *ctx)
35
48.5k
{
36
48.5k
    pdf_obj *o, *o1;
37
48.5k
    pdf_dict *d;
38
48.5k
    int code;
39
40
48.5k
    if (ctx->args.pdfdebug)
41
0
        outprintf(ctx->memory, "%% Reading Root dictionary\n");
42
43
    /* Unusual code. This is because if the entry in the trailer dictionary causes
44
     * us to repair the file, the Trailer dictionary in the context can be replaced.
45
     * This counts it down and frees it, potentially while pdfi_dict_get is still
46
     * using it! Rather than countup and down in the dict_get routine, which is
47
     * normally unnecessary, count it up and down round the access here.
48
     */
49
48.5k
    d = ctx->Trailer;
50
48.5k
    pdfi_countup(d);
51
48.5k
    code = pdfi_dict_get(ctx, d, "Root", &o1);
52
48.5k
    if (code < 0) {
53
1.13k
        pdfi_countdown(d);
54
1.13k
        return code;
55
1.13k
    }
56
47.3k
    pdfi_countdown(d);
57
58
47.3k
    if (pdfi_type_of(o1) == PDF_INDIRECT) {
59
0
        code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o1)->ref_object_num,  ((pdf_indirect_ref *)o1)->ref_generation_num, &o);
60
0
        pdfi_countdown(o1);
61
0
        if (code < 0)
62
0
            return code;
63
64
0
        if (pdfi_type_of(o) != PDF_DICT) {
65
0
            pdfi_countdown(o);
66
0
            return_error(gs_error_typecheck);
67
0
        }
68
69
0
        code = pdfi_dict_put(ctx, ctx->Trailer, "Root", o);
70
0
        if (code < 0) {
71
0
            pdfi_countdown(o);
72
0
            return code;
73
0
        }
74
0
        o1 = o;
75
47.3k
    } else {
76
47.3k
        if (pdfi_type_of(o1) != PDF_DICT) {
77
257
            pdfi_countdown(o1);
78
257
            if (ctx->Root == NULL)
79
103
                return_error(gs_error_typecheck);
80
154
            return 0;
81
257
        }
82
47.3k
    }
83
84
47.1k
    code = pdfi_dict_get_type(ctx, (pdf_dict *)o1, "Type", PDF_NAME, &o);
85
47.1k
    if (code < 0) {
86
353
        bool known = false;
87
88
353
        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, E_PDF_MISSINGTYPE, "pdfi_read_Root", NULL)) < 0) {
89
0
            pdfi_countdown(o1);
90
0
            return code;
91
0
        }
92
93
        /* Missing the *required* /Type key! See if it has /Pages at least, if it does carry on */
94
353
        code = pdfi_dict_known(ctx, (pdf_dict *)o1, "Pages", &known);
95
353
        if (code < 0 || known == false) {
96
125
            pdfi_countdown(o1);
97
125
            return code;
98
125
        }
99
353
    }
100
46.7k
    else {
101
46.7k
        if (pdfi_name_strcmp((pdf_name *)o, "Catalog") != 0){
102
707
            pdf_obj *pages = NULL;
103
104
            /* Bug #706038 has a Root dictionary with /Type /Calalog which (of course) Acrobat
105
             * happily opens :-( So if we find a /Type and it's not /Catalog, try and see if
106
             * we have a /Pages key (the only other required entry). If we do assume that the
107
             * Type is wrong and use this dictionary, otherwise fall back to seeing if we
108
             * have a repaired Root. See above for handling a missing /Type.....
109
             */
110
707
            code = pdfi_dict_get_type(ctx, (pdf_dict *)o1, "Pages", PDF_DICT, &pages);
111
707
            if (code < 0) {
112
369
                pdfi_countdown(o);
113
369
                pdfi_countdown(o1);
114
                /* If we repaired the file, we may already have spotted a potential Root dictionary
115
                 * so if the one we found here isn't valid, try the one we found when scanning
116
                 */
117
369
                if (ctx->Root == NULL) {
118
86
                    pdfi_set_error(ctx, 0, NULL, E_PDF_NO_ROOT, "pdfi_read_Root", NULL);
119
86
                    return_error(gs_error_syntaxerror);
120
86
                }
121
283
                return 0;
122
369
            }
123
338
            pdfi_countdown(pages);
124
338
            if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_BAD_ROOT_TYPE, "pdfi_read_Root", NULL)) < 0) {
125
0
                pdfi_countdown(o);
126
0
                pdfi_countdown(o1);
127
0
                return code;
128
0
            }
129
338
        }
130
46.3k
        pdfi_countdown(o);
131
46.3k
    }
132
133
46.6k
    if (ctx->args.pdfdebug)
134
0
        outprintf(ctx->memory, "\n");
135
    /* We don't pdfi_countdown(o1) now, because we've transferred our
136
     * reference to the pointer in the pdf_context structure.
137
     */
138
46.6k
    pdfi_countdown(ctx->Root); /* If file was repaired it might be set already */
139
46.6k
    ctx->Root = (pdf_dict *)o1;
140
46.6k
    return 0;
141
47.1k
}
142
143
static int Info_check_dict(pdf_context *ctx, pdf_dict *d);
144
145
static int Info_check_array(pdf_context *ctx, pdf_array *a)
146
5.08k
{
147
5.08k
    int code = 0, i = 0;
148
5.08k
    pdf_obj *array_obj = NULL;
149
150
5.08k
    code = pdfi_loop_detector_mark(ctx);
151
5.08k
    if (code < 0)
152
0
        return code;
153
154
46.8k
    for (i = 0;i < pdfi_array_size(a); i++) {
155
42.3k
        code = pdfi_array_fetch_recursing(ctx, a, i, &array_obj, true, true);
156
42.3k
        if (code < 0)
157
358
            goto error;
158
159
42.0k
        switch(pdfi_type_of(array_obj)) {
160
1.15k
            case PDF_DICT:
161
1.15k
                if (array_obj->object_num != 0) {
162
1.10k
                    code = pdfi_loop_detector_add_object(ctx, array_obj->object_num);
163
1.10k
                    if (code < 0)
164
0
                        goto error;
165
1.10k
                }
166
1.15k
                code = Info_check_dict(ctx, (pdf_dict *)array_obj);
167
1.15k
                if (code < 0) {
168
287
                    if (array_obj->object_num != 0) {
169
287
                        pdf_indirect_ref *i_o;
170
171
287
                        code = pdfi_object_alloc(ctx, PDF_INDIRECT, 0, (pdf_obj **)&i_o);
172
287
                        if (code < 0)
173
0
                            goto error;
174
287
                        i_o->ref_generation_num = array_obj->generation_num;
175
287
                        i_o->ref_object_num = array_obj->object_num;
176
287
                        i_o->indirect_num = array_obj->object_num;
177
287
                        i_o->indirect_gen = array_obj->generation_num;
178
287
                        code = pdfi_array_put(ctx, a, i, (pdf_obj *)i_o);
179
287
                        if (code < 0)
180
0
                            return code;
181
287
                    }
182
287
                    goto error;
183
287
                }
184
871
                break;
185
871
            case PDF_ARRAY:
186
268
                if (array_obj->object_num != 0) {
187
54
                    code = pdfi_loop_detector_add_object(ctx, array_obj->object_num);
188
54
                    if (code < 0)
189
0
                        goto error;
190
54
                }
191
268
                code = Info_check_array(ctx, (pdf_array *)array_obj);
192
268
                if (code < 0) {
193
18
                    if (array_obj->object_num != 0) {
194
18
                        pdf_indirect_ref *i_o;
195
196
18
                        code = pdfi_object_alloc(ctx, PDF_INDIRECT, 0, (pdf_obj **)&i_o);
197
18
                        if (code < 0)
198
0
                            goto error;
199
18
                        i_o->ref_generation_num = array_obj->generation_num;
200
18
                        i_o->ref_object_num = array_obj->object_num;
201
18
                        i_o->indirect_num = array_obj->object_num;
202
18
                        i_o->indirect_gen = array_obj->generation_num;
203
18
                        code = pdfi_array_put(ctx, a, i, (pdf_obj *)i_o);
204
18
                        if (code < 0)
205
0
                            return code;
206
18
                    }
207
18
                    goto error;
208
18
                }
209
250
                break;
210
40.5k
            default:
211
40.5k
                break;
212
42.0k
        }
213
214
41.7k
        pdfi_countdown(array_obj);
215
41.7k
        array_obj = NULL;
216
41.7k
    }
217
5.08k
error:
218
5.08k
    pdfi_countdown(array_obj);
219
5.08k
    pdfi_loop_detector_cleartomark(ctx);
220
5.08k
    return code;
221
5.08k
}
222
223
static int Info_check_dict(pdf_context *ctx, pdf_dict *d)
224
4.25k
{
225
4.25k
    int code = 0;
226
4.25k
    uint64_t index = 0;
227
4.25k
    pdf_name *Key = NULL;
228
4.25k
    pdf_obj *Value = NULL;
229
230
4.25k
    code = pdfi_loop_detector_mark(ctx);
231
4.25k
    if (code < 0)
232
0
        return code;
233
234
4.25k
    code = pdfi_dict_first(ctx, d, (pdf_obj **)&Key, &Value, &index);
235
4.25k
    if (code < 0) {
236
456
        if (code == gs_error_undefined)
237
371
            code = 0;
238
456
        goto error;
239
456
    }
240
241
15.2k
    while (code >= 0) {
242
14.9k
        switch(pdfi_type_of(Value)) {
243
2.23k
            case PDF_DICT:
244
2.23k
                if (Value->object_num != 0) {
245
1.17k
                    code = pdfi_loop_detector_add_object(ctx, Value->object_num);
246
1.17k
                    if (code < 0)
247
0
                        goto error;
248
1.17k
                }
249
2.23k
                code = Info_check_dict(ctx, (pdf_dict *)Value);
250
2.23k
                if (code < 0)
251
477
                    goto error;
252
1.75k
                break;
253
2.95k
            case PDF_ARRAY:
254
2.95k
                if (Value->object_num != 0) {
255
171
                    code = pdfi_loop_detector_add_object(ctx, Value->object_num);
256
171
                    if (code < 0)
257
0
                        goto error;
258
171
                }
259
2.95k
                code = Info_check_array(ctx, (pdf_array *)Value);
260
2.95k
                if (code < 0)
261
306
                    goto error;
262
2.65k
                break;
263
9.74k
            default:
264
9.74k
                break;
265
14.9k
        }
266
14.1k
        pdfi_countdown(Key);
267
14.1k
        Key = NULL;
268
14.1k
        pdfi_countdown(Value);
269
14.1k
        Value = NULL;
270
271
14.1k
        code = pdfi_dict_next(ctx, d, (pdf_obj **)&Key, &Value, &index);
272
14.1k
        if (code == gs_error_undefined) {
273
2.74k
            code = 0;
274
2.74k
            break;
275
2.74k
        }
276
14.1k
    }
277
4.25k
error:
278
4.25k
    pdfi_countdown(Key);
279
4.25k
    pdfi_countdown(Value);
280
4.25k
    pdfi_loop_detector_cleartomark(ctx);
281
4.25k
    return code;
282
3.80k
}
283
284
static int pdfi_sanitize_Info_references(pdf_context *ctx, pdf_dict *Info)
285
30.5k
{
286
30.5k
    int code = 0;
287
30.5k
    uint64_t index = 0;
288
30.5k
    pdf_name *Key = NULL;
289
30.5k
    pdf_obj *Value = NULL;
290
291
30.9k
restart_scan:
292
30.9k
    code = pdfi_loop_detector_mark(ctx);
293
30.9k
    if (code < 0)
294
0
        return code;
295
296
30.9k
    code = pdfi_dict_first(ctx, Info, (pdf_obj **)&Key, &Value, &index);
297
30.9k
    if (code == gs_error_undefined) {
298
571
        code = 0;
299
571
        goto error;
300
571
    }
301
302
150k
    while (code >= 0) {
303
150k
        switch(pdfi_type_of(Value)) {
304
869
            case PDF_DICT:
305
869
                code = Info_check_dict(ctx, (pdf_dict *)Value);
306
869
                break;
307
1.86k
            case PDF_ARRAY:
308
1.86k
                code = Info_check_array(ctx, (pdf_array *)Value);
309
1.86k
                break;
310
148k
            default:
311
148k
                code = 0;
312
148k
                break;
313
150k
        }
314
150k
        pdfi_countdown(Value);
315
150k
        Value = NULL;
316
150k
        if (code < 0) {
317
409
            code = pdfi_dict_delete_pair(ctx, Info, Key);
318
409
            if (code < 0)
319
0
                goto error;
320
409
            pdfi_countdown(Key);
321
409
            Key = NULL;
322
323
409
            pdfi_loop_detector_cleartomark(ctx);
324
409
            goto restart_scan;
325
409
        }
326
150k
        pdfi_countdown(Key);
327
150k
        Key = NULL;
328
329
150k
        pdfi_loop_detector_cleartomark(ctx);
330
150k
        code = pdfi_loop_detector_mark(ctx);
331
150k
        if (code < 0) {
332
0
            pdfi_countdown(Key);
333
0
            pdfi_countdown(Value);
334
0
            return code;
335
0
        }
336
337
150k
        code = pdfi_dict_next(ctx, Info, (pdf_obj **)&Key, &Value, &index);
338
150k
        if (code == gs_error_undefined) {
339
29.8k
            code = 0;
340
29.8k
            break;
341
29.8k
        }
342
150k
    }
343
30.5k
error:
344
30.5k
    pdfi_countdown(Key);
345
30.5k
    pdfi_countdown(Value);
346
30.5k
    pdfi_loop_detector_cleartomark(ctx);
347
30.5k
    return code;
348
30.3k
}
349
350
int pdfi_read_Info(pdf_context *ctx)
351
47.1k
{
352
47.1k
    pdf_dict *Info;
353
47.1k
    int code;
354
47.1k
    pdf_dict *d;
355
356
47.1k
    if (ctx->args.pdfdebug)
357
0
        outprintf(ctx->memory, "%% Reading Info dictionary\n");
358
359
    /* See comment in pdfi_read_Root() for details */
360
47.1k
    d = ctx->Trailer;
361
47.1k
    pdfi_countup(d);
362
47.1k
    code = pdfi_dict_get_type(ctx, ctx->Trailer, "Info", PDF_DICT, (pdf_obj **)&Info);
363
47.1k
    pdfi_countdown(d);
364
47.1k
    if (code < 0)
365
16.6k
        return code;
366
367
30.5k
    if (ctx->args.pdfdebug)
368
0
        outprintf(ctx->memory, "\n");
369
370
30.5k
    code = pdfi_loop_detector_mark(ctx);
371
30.5k
    if (code < 0)
372
0
        goto error;
373
30.5k
    if (Info->object_num != 0) {
374
30.5k
        code = pdfi_loop_detector_add_object(ctx, Info->object_num);
375
30.5k
        if (code < 0)
376
0
            goto error1;
377
30.5k
    } else {
378
0
        if ((code = pdfi_set_warning_stop(ctx, 0, NULL, W_PDF_INFO_NOT_INDIRECT, "pdfi_read_Info", "")) < 0)
379
0
            goto error1;
380
0
    }
381
382
    /* sanitize Info for circular references */
383
30.5k
    code = pdfi_sanitize_Info_references(ctx, Info);
384
30.5k
    if (code < 0)
385
86
        goto error1;
386
387
30.4k
    (void)pdfi_loop_detector_cleartomark(ctx);
388
389
30.4k
    pdfi_pdfmark_write_docinfo(ctx, Info);
390
391
    /* We don't pdfi_countdown(Info) now, because we've transferred our
392
     * reference to the pointer in the pdf_context structure.
393
     */
394
30.4k
    ctx->Info = Info;
395
30.4k
    return 0;
396
397
86
error1:
398
86
    pdfi_loop_detector_cleartomark(ctx);
399
86
error:
400
86
    pdfi_countdown(Info);
401
86
    return code;
402
86
}
403
404
int pdfi_read_Pages(pdf_context *ctx)
405
91.8k
{
406
91.8k
    pdf_obj *o, *o1;
407
91.8k
    pdf_array *a = NULL;
408
91.8k
    int code, pagecount = 0;
409
91.8k
    double d;
410
411
91.8k
    if (ctx->args.pdfdebug)
412
0
        outprintf(ctx->memory, "%% Reading Pages dictionary\n");
413
414
91.8k
    code = pdfi_dict_get(ctx, ctx->Root, "Pages", &o1);
415
91.8k
    if (code < 0)
416
2.41k
        return code;
417
418
89.4k
    if (pdfi_type_of(o1) == PDF_INDIRECT) {
419
0
        code = pdfi_dereference(ctx, ((pdf_indirect_ref *)o1)->ref_object_num,  ((pdf_indirect_ref *)o1)->ref_generation_num, &o);
420
0
        pdfi_countdown(o1);
421
0
        if (code < 0)
422
0
            return code;
423
424
0
        if (pdfi_type_of(o) != PDF_DICT) {
425
0
            pdfi_countdown(o);
426
0
            if (pdfi_type_of(o) == PDF_INDIRECT)
427
0
                pdfi_set_error(ctx, 0, NULL, E_PDF_BADPAGEDICT, "pdfi_read_Pages", (char *)"*** Error: Something is wrong with the Pages dictionary.  Giving up.");
428
0
            else
429
0
                pdfi_set_error(ctx, 0, NULL, E_PDF_BADPAGEDICT, "pdfi_read_Pages", (char *)"*** Error: Something is wrong with the Pages dictionary.  Giving up.\n           Double indirect reference.  Loop in Pages tree?");
430
0
            return_error(gs_error_typecheck);
431
0
        }
432
433
0
        code = pdfi_dict_put(ctx, ctx->Root, "Pages", o);
434
0
        if (code < 0) {
435
0
            pdfi_countdown(o);
436
0
            return code;
437
0
        }
438
0
        o1 = o;
439
89.4k
    } else {
440
89.4k
        if (pdfi_type_of(o1) != PDF_DICT) {
441
138
            pdfi_countdown(o1);
442
138
            return_error(gs_error_typecheck);
443
138
        }
444
89.4k
    }
445
446
89.2k
    if (ctx->args.pdfdebug)
447
0
        outprintf(ctx->memory, "\n");
448
449
    /* Acrobat allows the Pages Count to be a floating point number (!) */
450
    /* sample w_a.PDF from Bug688419 (not on the cluster, maybe it should be?) has no /Count entry because
451
     * The Root dictionary Pages key points directly to a single dictionary of type /Page. This is plainly
452
     * illegal but Acrobat can deal with it. We do so by ignoring the error her, and adding logic in
453
     * pdfi_get_page_dict() which notes that ctx->PagesTree is NULL and tries to get the single Page
454
     * dictionary from the Root instead of using the PagesTree.
455
     */
456
89.2k
    code = pdfi_dict_get_number(ctx, (pdf_dict *)o1, "Count", &d);
457
89.2k
    if (code < 0) {
458
748
        if (code == gs_error_undefined) {
459
719
            pdf_name *n = NULL;
460
            /* It may be that the Root dictionary Pages entry points directly to a sinlge Page dictionary
461
             * See if the dictionary has a Type of /Page, if so don't throw an error and the pdf_page.c
462
             * logic in pdfi_get_page_dict() logic will take care of it.
463
             */
464
719
            code = pdfi_dict_get_type(ctx, (pdf_dict *)o1, "Type", PDF_NAME, (pdf_obj **)&n);
465
719
            if (code == 0) {
466
675
                if(pdfi_name_is(n, "Page")) {
467
566
                    ctx->num_pages = 1;
468
566
                    code = 0;
469
566
                }
470
109
                else
471
109
                    code = gs_error_undefined;
472
675
                pdfi_countdown(n);
473
675
            }
474
719
        }
475
748
        pdfi_countdown(o1);
476
748
        return code;
477
748
    }
478
479
88.5k
    if (floor(d) != d) {
480
0
        pdfi_countdown(o1);
481
0
        return_error(gs_error_rangecheck);
482
88.5k
    } else {
483
88.5k
        ctx->num_pages = (int)floor(d);
484
88.5k
    }
485
486
    /* A simple confidence check in the value of Count. We only do this because
487
     * the OSS-fuzz tool keeps on coming up with files that time out because the
488
     * initial Count is insanely huge, and we spend much time trying to find
489
     * millions of pages which don't exist.
490
     */
491
88.5k
    code = pdfi_dict_knownget_type(ctx, (pdf_dict *)o1, "Kids", PDF_ARRAY, (pdf_obj **)&a);
492
88.5k
    if (code == 0)
493
30
        code = gs_note_error(gs_error_undefined);
494
88.5k
    if (code < 0) {
495
30
        pdfi_countdown(o1);
496
30
        return code;
497
30
    }
498
499
    /* Firstly check if the Kids array has enough nodes, in which case it's
500
     * probably flat (the common case)
501
     */
502
88.5k
    if (a->size != ctx->num_pages) {
503
2.08k
        int i = 0;
504
2.08k
        pdf_obj *p = NULL, *p1 = NULL;
505
2.08k
        pdf_num *c = NULL;
506
507
        /* Either its not a flat tree, or the top node /Count is incorrect.
508
         * Get each entry in the Kids array in turn and total the /Count of
509
         * each node and add any leaf nodes.
510
         */
511
12.9k
        for (i=0;i < a->size; i++) {
512
            /* We must not allow the entry in the array to be replaced, in case it's a circular reference */
513
10.8k
            code = pdfi_array_get_no_store_R(ctx, a, i, &p);
514
10.8k
            if (code < 0)
515
3.59k
                continue;
516
7.29k
            if (pdfi_type_of(p) != PDF_DICT) {
517
1.21k
                pdfi_countdown(p);
518
1.21k
                p = NULL;
519
1.21k
                continue;
520
1.21k
            }
521
            /* Explicit check that the root node Kids array entry is not a self-reference
522
             * back to the root node. We only check one level of the Kids array. so we don't
523
             * need a full loop detection setup here.
524
             */
525
6.08k
            if (p->object_num != 0 && p->object_num == o1->object_num) {
526
8
                pdfi_countdown(p);
527
8
                p = NULL;
528
8
                pdfi_countdown(a);
529
8
                pdfi_countdown(o1);
530
8
                ctx->num_pages = 0;
531
8
                return_error(gs_error_circular_reference);
532
8
            }
533
            /* Now we've checked for circular reference we can replace the entry in the
534
             * array, and add the object to the cache.
535
             * These are optimisations, so we don't especially care whether they succeed
536
             */
537
6.07k
            (void)pdfi_array_put(ctx, a, i, p);
538
6.07k
            (void)replace_cache_entry(ctx, p);
539
6.07k
            code = pdfi_dict_knownget_type(ctx, (pdf_dict *)p, "Type", PDF_NAME, (pdf_obj **)&p1);
540
6.07k
            if (code <= 0) {
541
73
                pdfi_countdown(p);
542
73
                p = NULL;
543
73
                continue;
544
73
            }
545
6.00k
            if (pdfi_name_is((pdf_name *)p1, "Page")) {
546
2.20k
                pagecount++;
547
3.79k
            } else {
548
3.79k
                if (pdfi_name_is((pdf_name *)p1, "Pages")) {
549
3.67k
                    code = pdfi_dict_knownget(ctx, (pdf_dict *)p, "Count", (pdf_obj **)&c);
550
3.67k
                    if (code >= 0) {
551
3.67k
                        if (pdfi_type_of(c) == PDF_INT)
552
3.66k
                            pagecount += c->value.i;
553
3.67k
                        if (pdfi_type_of(c) == PDF_REAL)
554
0
                            pagecount += (int)c->value.d;
555
3.67k
                        pdfi_countdown(c);
556
3.67k
                        c = NULL;
557
3.67k
                    }
558
3.67k
                }
559
3.79k
            }
560
6.00k
            pdfi_countdown(p1);
561
6.00k
            p1 = NULL;
562
6.00k
            pdfi_countdown(p);
563
6.00k
            p = NULL;
564
6.00k
        }
565
2.08k
    } else
566
86.4k
        pagecount = a->size;
567
568
88.5k
    pdfi_countdown(a);
569
570
    /* If the count of the top level of the tree doesn't match the /Count
571
     * of the root node then something is wrong. We could abort right now
572
     * and will if this continues to be a problem, but initially let's assume
573
     * the count of the top level is correct and the root node /Count is wrong.
574
     * This will allow us to recover if only the root /Count gets corrupted.
575
     * In future we could also try validating the entire tree at this point,
576
     * though I suspect that's pointless; if the tree is corrupted we aren't
577
     * likely to get much that's usable from it.
578
     */
579
88.5k
    if (pagecount != ctx->num_pages) {
580
801
        ctx->num_pages = pagecount;
581
801
        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_syntaxerror), NULL, E_PDF_BADPAGECOUNT, "pdfi_read_Pages", NULL)) < 0)
582
0
            return code;
583
801
        code = pdfi_dict_put_int(ctx, (pdf_dict *)o1, "Count", ctx->num_pages);
584
801
        if (code < 0) {
585
0
            pdfi_countdown(o1);
586
0
            return code;
587
0
        }
588
801
    }
589
590
    /* We don't pdfi_countdown(o1) now, because we've transferred our
591
     * reference to the pointer in the pdf_context structure.
592
     */
593
88.5k
    ctx->PagesTree = (pdf_dict *)o1;
594
88.5k
    return 0;
595
88.5k
}
596
597
/* Read optional things in from Root */
598
void pdfi_read_OptionalRoot(pdf_context *ctx)
599
89.0k
{
600
89.0k
    pdf_obj *obj = NULL;
601
89.0k
    int code;
602
89.0k
    bool known;
603
604
89.0k
    if (ctx->args.pdfdebug)
605
0
        outprintf(ctx->memory, "%% Reading other Root contents\n");
606
607
89.0k
    if (ctx->args.pdfdebug)
608
0
        outprintf(ctx->memory, "%% OCProperties\n");
609
89.0k
    code = pdfi_dict_get_type(ctx, ctx->Root, "OCProperties", PDF_DICT, &obj);
610
89.0k
    if (code == 0) {
611
4.73k
        ctx->OCProperties = (pdf_dict *)obj;
612
84.3k
    } else {
613
84.3k
        ctx->OCProperties = NULL;
614
84.3k
        if (ctx->args.pdfdebug)
615
0
            outprintf(ctx->memory, "%% (None)\n");
616
84.3k
    }
617
618
89.0k
    (void)pdfi_dict_known(ctx, ctx->Root, "Collection", &known);
619
620
89.0k
    if (known) {
621
0
        if (ctx->args.pdfdebug)
622
0
            outprintf(ctx->memory, "%% Collection\n");
623
0
        code = pdfi_dict_get(ctx, ctx->Root, "Collection", (pdf_obj **)&ctx->Collection);
624
0
        if (code < 0) {
625
0
            (void)pdfi_set_warning_stop(ctx, 0, NULL, W_PDF_BAD_COLLECTION, "pdfi_read_OptionalRoot", "");
626
0
        }
627
0
    }
628
89.0k
}
629
630
void pdfi_free_OptionalRoot(pdf_context *ctx)
631
110k
{
632
110k
    if (ctx->OCProperties) {
633
4.73k
        pdfi_countdown(ctx->OCProperties);
634
4.73k
        ctx->OCProperties = NULL;
635
4.73k
    }
636
110k
    if (ctx->Collection) {
637
0
        pdfi_countdown(ctx->Collection);
638
0
        ctx->Collection = NULL;
639
0
    }
640
110k
}
641
642
/* Handle child node processing for page_dict */
643
static int pdfi_get_child(pdf_context *ctx, pdf_array *Kids, int i, pdf_dict **pchild)
644
1.05M
{
645
1.05M
    pdf_indirect_ref *node = NULL;
646
1.05M
    pdf_dict *child = NULL;
647
1.05M
    pdf_name *Type = NULL;
648
1.05M
    pdf_dict *leaf_dict = NULL;
649
1.05M
    pdf_name *Key = NULL;
650
1.05M
    int code = 0;
651
652
1.05M
    code = pdfi_array_get_no_deref(ctx, Kids, i, (pdf_obj **)&node);
653
1.05M
    if (code < 0)
654
0
        goto errorExit;
655
656
1.05M
    if (pdfi_type_of(node) != PDF_INDIRECT && pdfi_type_of(node) != PDF_DICT) {
657
141
        code = gs_note_error(gs_error_typecheck);
658
141
        goto errorExit;
659
141
    }
660
661
1.05M
    if (pdfi_type_of(node) == PDF_INDIRECT) {
662
181k
        code = pdfi_dereference(ctx, node->ref_object_num, node->ref_generation_num,
663
181k
                                (pdf_obj **)&child);
664
181k
        if (code < 0) {
665
44.5k
            int code1 = pdfi_repair_file(ctx);
666
44.5k
            if (code1 < 0)
667
44.5k
                goto errorExit;
668
32
            code = pdfi_dereference(ctx, node->ref_object_num,
669
32
                                    node->ref_generation_num, (pdf_obj **)&child);
670
32
            if (code < 0)
671
19
                goto errorExit;
672
32
        }
673
        /* It makes no sense for the Page dictionary to be a stream, but safedocs/DialectDictIsStream.pdf
674
         * has this (stream length is 0, not that it matters) and Acrobat happily opens it....
675
         */
676
136k
        if (pdfi_type_of(child) != PDF_DICT) {
677
1.47k
            pdf_dict *d1 = NULL;
678
679
1.47k
            if (pdfi_type_of(child) != PDF_STREAM) {
680
1.15k
                code = gs_note_error(gs_error_typecheck);
681
1.15k
                goto errorExit;
682
1.15k
            }
683
321
            if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_DICT_IS_STREAM, "pdfi_get_child", NULL)) < 0)
684
0
                goto errorExit;
685
686
321
            code = pdfi_get_stream_dict(ctx, (pdf_stream *)child, &d1);
687
321
            if (code < 0)
688
0
                goto errorExit;
689
321
            pdfi_countdown(child);
690
321
            child = d1;
691
321
            code = replace_cache_entry(ctx, (pdf_obj *)d1);
692
321
            if (code < 0)
693
0
                goto errorExit;
694
321
        }
695
        /* If its an intermediate node, store it in the page_table, if its a leaf node
696
         * then don't store it. Instead we create a special dictionary of our own which
697
         * has a /Type of /PageRef and a /PageRef key which is the indirect reference
698
         * to the page. However in this case we pass on the actual page dictionary to
699
         * the Kids processing below. If we didn't then we'd fall foul of the loop
700
         * detection by dereferencing the same object twice.
701
         * This is tedious, but it means we don't store all the page dictionaries in
702
         * the Pages tree, because page dictionaries can be large and we generally
703
         * only use them once. If processed in order we only dereference each page
704
         * dictionary once, any other order will dereference each page twice. (or more
705
         * if we render the same page multiple times).
706
         */
707
135k
        code = pdfi_dict_get_type(ctx, child, "Type", PDF_NAME, (pdf_obj **)&Type);
708
135k
        if (code < 0)
709
1.70k
            goto errorExit;
710
134k
        if (pdfi_name_is(Type, "Pages")) {
711
917
            code = pdfi_array_put(ctx, Kids, i, (pdf_obj *)child);
712
917
            if (code < 0)
713
0
                goto errorExit;
714
133k
        } else {
715
            /* Bizarrely, one of the QL FTS files (FTS_07_0704.pdf) has a page diciotnary with a /Type of /Template */
716
133k
            if (!pdfi_name_is(Type, "Page"))
717
924
                if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_BADPAGETYPE, "pdfi_get_child", NULL)) < 0)
718
0
                    goto errorExit;
719
            /* Make a 'PageRef' entry (just stores an indirect reference to the actual page)
720
             * and store that in the Kids array for future reference. But pass on the
721
             * dereferenced Page dictionary, in case this is the target page.
722
             */
723
724
133k
            code = pdfi_dict_alloc(ctx, 0, &leaf_dict);
725
133k
            if (code < 0)
726
0
                goto errorExit;
727
133k
            code = pdfi_name_alloc(ctx, (byte *)"PageRef", 7, (pdf_obj **)&Key);
728
133k
            if (code < 0)
729
0
                goto errorExit;
730
133k
            pdfi_countup(Key);
731
732
133k
            code = pdfi_dict_put_obj(ctx, leaf_dict, (pdf_obj *)Key, (pdf_obj *)node, true);
733
133k
            if (code < 0)
734
0
                goto errorExit;
735
133k
            code = pdfi_dict_put(ctx, leaf_dict, "Type", (pdf_obj *)Key);
736
133k
            if (code < 0)
737
0
                goto errorExit;
738
133k
            code = pdfi_array_put(ctx, Kids, i, (pdf_obj *)leaf_dict);
739
133k
            if (code < 0)
740
0
                goto errorExit;
741
133k
            leaf_dict = NULL;
742
133k
        }
743
871k
    } else {
744
871k
        if (ctx->loop_detection != NULL) {
745
871k
            if (node->object_num != 0 && pdfi_loop_detector_check_object(ctx, node->object_num)) {
746
39
                code = gs_note_error(gs_error_circular_reference);
747
39
                goto errorExit;
748
39
            }
749
871k
            if (node->object_num > 0) {
750
66.1k
                code = pdfi_loop_detector_add_object(ctx, node->object_num);
751
66.1k
                if (code < 0)
752
0
                    goto errorExit;
753
66.1k
            }
754
871k
        }
755
871k
        child = (pdf_dict *)node;
756
871k
        pdfi_countup(child);
757
871k
    }
758
759
1.00M
    *pchild = child;
760
1.00M
    child = NULL;
761
762
1.05M
 errorExit:
763
1.05M
    pdfi_free_object((pdf_obj *)leaf_dict);
764
1.05M
    pdfi_countdown(child);
765
1.05M
    pdfi_countdown(node);
766
1.05M
    pdfi_countdown(Type);
767
1.05M
    pdfi_countdown(Key);
768
1.05M
    return code;
769
1.00M
}
770
771
/* Check if key is in the dictionary, and if so, copy it into the inheritable dict.
772
 */
773
static int pdfi_check_inherited_key(pdf_context *ctx, pdf_dict *d, const char *keyname, pdf_dict *inheritable)
774
1.37M
{
775
1.37M
    int code = 0;
776
1.37M
    pdf_obj *object = NULL;
777
1.37M
    bool known;
778
779
    /* Check for inheritable keys, if we find any copy them to the 'inheritable' dictionary at this level */
780
1.37M
    code = pdfi_dict_known(ctx, d, keyname, &known);
781
1.37M
    if (code < 0)
782
0
        goto exit;
783
1.37M
    if (known) {
784
82.6k
        code = pdfi_loop_detector_mark(ctx);
785
82.6k
        if (code < 0){
786
0
            goto exit;
787
0
        }
788
82.6k
        code = pdfi_dict_get(ctx, d, keyname, &object);
789
82.6k
        if (code < 0) {
790
288
            (void)pdfi_loop_detector_cleartomark(ctx);
791
288
            goto exit;
792
288
        }
793
82.3k
        code = pdfi_loop_detector_cleartomark(ctx);
794
82.3k
        if (code < 0) {
795
0
            goto exit;
796
0
        }
797
82.3k
        code = pdfi_dict_put(ctx, inheritable, keyname, object);
798
82.3k
    }
799
800
1.37M
 exit:
801
1.37M
    pdfi_countdown(object);
802
1.37M
    return code;
803
1.37M
}
804
805
int pdfi_get_page_dict(pdf_context *ctx, pdf_dict *d, uint64_t page_num, uint64_t *page_offset,
806
                   pdf_dict **target, pdf_dict *inherited)
807
344k
{
808
344k
    int i, code = 0;
809
344k
    pdf_array *Kids = NULL;
810
344k
    pdf_dict *child = NULL;
811
344k
    pdf_name *Type = NULL;
812
344k
    pdf_dict *inheritable = NULL;
813
344k
    int64_t num;
814
344k
    double dbl;
815
816
344k
    if (ctx->args.pdfdebug)
817
0
        outprintf(ctx->memory, "%% Finding page dictionary for page %"PRIi64"\n", page_num + 1);
818
819
    /* Allocated inheritable dict (it might stay empty) */
820
344k
    code = pdfi_dict_alloc(ctx, 0, &inheritable);
821
344k
    if (code < 0)
822
0
        return code;
823
344k
    pdfi_countup(inheritable);
824
825
344k
    code = pdfi_loop_detector_mark(ctx);
826
344k
    if (code < 0)
827
0
        return code;
828
829
    /* if we are being passed any inherited values from our parent, copy them now */
830
344k
    if (inherited != NULL) {
831
27.3k
        code = pdfi_dict_copy(ctx, inheritable, inherited);
832
27.3k
        if (code < 0)
833
0
            goto exit;
834
27.3k
    }
835
836
344k
    code = pdfi_dict_get_number(ctx, d, "Count", &dbl);
837
344k
    if (code < 0)
838
0
        goto exit;
839
344k
    if (dbl != floor(dbl)) {
840
0
        code = gs_note_error(gs_error_rangecheck);
841
0
        goto exit;
842
0
    }
843
344k
    num = (int)dbl;
844
845
344k
    if (num < 0 || (num + *page_offset) > ctx->num_pages) {
846
0
        code = gs_note_error(gs_error_rangecheck);
847
0
        goto exit;
848
0
    }
849
344k
    if (num + *page_offset < page_num) {
850
0
        *page_offset += num;
851
0
        code = 1;
852
0
        goto exit;
853
0
    }
854
    /* The requested page is a descendant of this node */
855
856
    /* Check for inheritable keys, if we find any copy them to the 'inheritable' dictionary at this level */
857
344k
    code = pdfi_check_inherited_key(ctx, d, "Resources", inheritable);
858
344k
    if (code < 0)
859
288
        goto exit;
860
343k
    code = pdfi_check_inherited_key(ctx, d, "MediaBox", inheritable);
861
343k
    if (code < 0)
862
0
        goto exit;
863
343k
    code = pdfi_check_inherited_key(ctx, d, "CropBox", inheritable);
864
343k
    if (code < 0)
865
0
        goto exit;
866
343k
    code = pdfi_check_inherited_key(ctx, d, "Rotate", inheritable);
867
343k
    if (code < 0) {
868
0
        goto exit;
869
0
    }
870
871
    /* Get the Kids array */
872
343k
    code = pdfi_dict_get_type(ctx, d, "Kids", PDF_ARRAY, (pdf_obj **)&Kids);
873
343k
    if (code < 0) {
874
32
        goto exit;
875
32
    }
876
877
    /* Check each entry in the Kids array */
878
1.05M
    for (i = 0;i < pdfi_array_size(Kids);i++) {
879
1.05M
        pdfi_countdown(child);
880
1.05M
        child = NULL;
881
1.05M
        pdfi_countdown(Type);
882
1.05M
        Type = NULL;
883
884
1.05M
        code = pdfi_get_child(ctx, Kids, i, &child);
885
1.05M
        if (code < 0) {
886
47.6k
            goto exit;
887
47.6k
        }
888
889
        /* Check the type, if its a Pages entry, then recurse. If its a Page entry, is it the one we want */
890
1.00M
        code = pdfi_dict_get_type(ctx, child, "Type", PDF_NAME, (pdf_obj **)&Type);
891
1.00M
        if (code == 0) {
892
1.00M
            if (pdfi_name_is(Type, "Pages")) {
893
44.9k
                code = pdfi_dict_get_number(ctx, child, "Count", &dbl);
894
44.9k
                if (code == 0) {
895
44.9k
                    if (dbl != floor(dbl)) {
896
0
                        code = gs_note_error(gs_error_rangecheck);
897
0
                        goto exit;
898
0
                    }
899
44.9k
                    num = (int)dbl;
900
44.9k
                    if (num < 0 || (num + *page_offset) > ctx->num_pages) {
901
13
                        code = gs_note_error(gs_error_rangecheck);
902
13
                        goto exit;
903
44.8k
                    } else {
904
44.8k
                        if (num + *page_offset <= page_num) {
905
17.5k
                            *page_offset += num;
906
27.3k
                        } else {
907
27.3k
                            code = pdfi_get_page_dict(ctx, child, page_num, page_offset, target, inheritable);
908
27.3k
                            goto exit;
909
27.3k
                        }
910
44.8k
                    }
911
44.9k
                }
912
960k
            } else {
913
960k
                if (pdfi_name_is(Type, "PageRef")) {
914
805k
                    if ((*page_offset) == page_num) {
915
133k
                        pdf_dict *page_dict = NULL;
916
917
133k
                        code = pdfi_dict_get_no_store_R(ctx, child, "PageRef", (pdf_obj **)&page_dict);
918
133k
                        if (code < 0)
919
10
                            goto exit;
920
133k
                        if (pdfi_type_of(page_dict) != PDF_DICT) {
921
1
                            code = gs_note_error(gs_error_typecheck);
922
1
                            goto exit;
923
1
                        }
924
133k
                        code = pdfi_merge_dicts(ctx, page_dict, inheritable);
925
133k
                        *target = page_dict;
926
133k
                        pdfi_countup(*target);
927
133k
                        pdfi_countdown(page_dict);
928
133k
                        goto exit;
929
672k
                    } else {
930
672k
                        *page_offset += 1;
931
672k
                    }
932
805k
                } else {
933
155k
                    if (!pdfi_name_is(Type, "Page")) {
934
1.23k
                        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_typecheck), NULL, E_PDF_BADPAGETYPE, "pdfi_get_page_dict", NULL)) < 0)
935
0
                            goto exit;
936
1.23k
                    }
937
155k
                    if ((*page_offset) == page_num) {
938
135k
                        code = pdfi_merge_dicts(ctx, child, inheritable);
939
135k
                        *target = child;
940
135k
                        pdfi_countup(*target);
941
135k
                        goto exit;
942
135k
                    } else {
943
19.7k
                        *page_offset += 1;
944
19.7k
                    }
945
155k
                }
946
960k
            }
947
1.00M
        }
948
709k
        if (code < 0)
949
203
            goto exit;
950
709k
    }
951
    /* Positive return value indicates we did not find the target below this node, try the next one */
952
27
    code = 1;
953
954
344k
 exit:
955
344k
    pdfi_loop_detector_cleartomark(ctx);
956
344k
    pdfi_countdown(inheritable);
957
344k
    pdfi_countdown(Kids);
958
344k
    pdfi_countdown(child);
959
344k
    pdfi_countdown(Type);
960
344k
    return code;
961
27
}
962
963
int pdfi_doc_page_array_init(pdf_context *ctx)
964
89.0k
{
965
89.0k
    size_t size = ctx->num_pages*sizeof(uint32_t);
966
967
89.0k
    ctx->page_array = (uint32_t *)gs_alloc_bytes(ctx->memory, size,
968
89.0k
                                                 "pdfi_doc_page_array_init(page_array)");
969
89.0k
    if (ctx->page_array == NULL)
970
1
        return_error(gs_error_VMerror);
971
972
89.0k
    memset(ctx->page_array, 0, size);
973
89.0k
    return 0;
974
89.0k
}
975
976
void pdfi_doc_page_array_free(pdf_context *ctx)
977
110k
{
978
110k
    if (!ctx->page_array)
979
21.6k
        return;
980
89.0k
    gs_free_object(ctx->memory, ctx->page_array, "pdfi_doc_page_array_free(page_array)");
981
89.0k
    ctx->page_array = NULL;
982
89.0k
}
983
984
/*
985
 * Checks for both "Resource" and "RD" in the specified dict.
986
 * And then gets the typedict of Type (e.g. Font or XObject).
987
 * Returns 0 if undefined, >0 if found, <0 if error
988
 */
989
static int pdfi_resource_knownget_typedict(pdf_context *ctx, unsigned char *Type,
990
                                           pdf_dict *dict, pdf_dict **typedict)
991
10.1M
{
992
10.1M
    int code;
993
10.1M
    pdf_dict *Resources = NULL;
994
995
10.1M
    code = pdfi_dict_knownget_type(ctx, dict, "Resources", PDF_DICT, (pdf_obj **)&Resources);
996
10.1M
    if (code == 0)
997
4.19M
        code = pdfi_dict_knownget_type(ctx, dict, "DR", PDF_DICT, (pdf_obj **)&Resources);
998
10.1M
    if (code < 0)
999
369k
        goto exit;
1000
9.82M
    if (code > 0)
1001
5.62M
        code = pdfi_dict_knownget_type(ctx, Resources, (const char *)Type, PDF_DICT, (pdf_obj **)typedict);
1002
10.1M
 exit:
1003
10.1M
    pdfi_countdown(Resources);
1004
10.1M
    return code;
1005
9.82M
}
1006
1007
int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name,
1008
                       pdf_dict *dict, pdf_dict *page_dict, pdf_obj **o)
1009
4.60M
{
1010
4.60M
    pdf_dict *typedict = NULL;
1011
4.60M
    pdf_dict *Parent = NULL;
1012
4.60M
    pdf_name *n = NULL;
1013
4.60M
    int code;
1014
4.60M
    bool known = false;
1015
1016
4.60M
    *o = NULL;
1017
1018
    /* Check the provided dict, stream_dict can be NULL if we are trying to find a Default* ColorSpace */
1019
4.60M
    if (dict != NULL) {
1020
4.60M
        bool deref_parent = true, dict_is_XObject = false;
1021
1022
4.60M
        code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict);
1023
4.60M
        if (code < 0)
1024
5.94k
            goto exit;
1025
4.59M
        if (code > 0) {
1026
979k
            code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
1027
979k
            if (code != gs_error_undefined)
1028
776k
                goto exit;
1029
979k
        }
1030
1031
        /* Check the Parents, if any */
1032
        /* If the current dictionary is a Page dictionary, do NOT dereference it's Parent, as that
1033
         * will be the Pages tree, and we will end up with circular references, causing a memory leak.
1034
         */
1035
3.81M
        if (pdfi_dict_knownget_type(ctx, dict, "Type", PDF_NAME, (pdf_obj **)&n) > 0) {
1036
255k
            if (pdfi_name_is(n, "Page"))
1037
7
                deref_parent = false;
1038
255k
            if (pdfi_name_is(n, "XObject"))
1039
194k
                dict_is_XObject = true;
1040
255k
            pdfi_countdown(n);
1041
255k
        }
1042
1043
3.81M
        if (deref_parent) {
1044
3.81M
            code = pdfi_dict_known(ctx, dict, "Parent", &known);
1045
3.81M
            if (code >= 0 && known == true) {
1046
194k
                code = pdfi_dict_get_no_store_R(ctx, dict, "Parent", (pdf_obj **)&Parent);
1047
1048
194k
                if (code >= 0) {
1049
178k
                    if (pdfi_type_of(Parent) != PDF_DICT) {
1050
113
                        if (pdfi_type_of(Parent) == PDF_INDIRECT) {
1051
0
                            pdf_indirect_ref *o = (pdf_indirect_ref *)Parent;
1052
1053
0
                            Parent = NULL;
1054
0
                            code = pdfi_dereference(ctx, o->ref_object_num, o->ref_generation_num, (pdf_obj **)&Parent);
1055
0
                            pdfi_countdown(o);
1056
0
                            if (code >= 0 && pdfi_type_of(Parent) != PDF_DICT) {
1057
0
                                pdfi_countdown(Parent);
1058
0
                                Parent = NULL;
1059
0
                            }
1060
113
                        } else {
1061
113
                            pdfi_countdown(Parent);
1062
113
                            Parent = NULL;
1063
113
                        }
1064
113
                    }
1065
178k
                } else
1066
15.6k
                    Parent = NULL;
1067
194k
            }
1068
1069
3.81M
            if (Parent != NULL) {
1070
178k
                if (ctx->page.CurrentPageDict != NULL && Parent->object_num != ctx->page.CurrentPageDict->object_num) {
1071
178k
                    if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true) {
1072
43.3k
                        code = gs_note_error(gs_error_circular_reference);
1073
43.3k
                        goto exit;
1074
43.3k
                    }
1075
1076
135k
                    code = pdfi_loop_detector_mark(ctx);
1077
135k
                    if (code < 0)
1078
0
                        goto exit;
1079
1080
135k
                    code = pdfi_loop_detector_add_object(ctx, dict->object_num);
1081
135k
                    if (code < 0) {
1082
0
                        (void)pdfi_loop_detector_cleartomark(ctx);
1083
0
                        goto exit;
1084
0
                    }
1085
135k
                    code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o);
1086
135k
                    (void)pdfi_loop_detector_cleartomark(ctx);
1087
135k
                    if (code != gs_error_undefined) {
1088
735
                        if (dict_is_XObject)
1089
643
                            pdfi_set_warning(ctx, 0, NULL, W_PDF_INHERITED_STREAM_RESOURCE, "pdfi_find_resource", (char *)"Couldn't find named resource in supplied dictionary, matching name located in Page Resource");
1090
735
                        goto exit;
1091
735
                    }
1092
135k
                }
1093
178k
            }
1094
3.77M
            code = 0;
1095
3.77M
        }
1096
3.77M
        pdfi_countdown(typedict);
1097
3.77M
        typedict = NULL;
1098
3.77M
    }
1099
1100
    /* Normally page_dict can't be (or shouldn't be) NULL. However, if we are processing
1101
     * a TYpe 3 font, then the 'page dict' is the Resources dictionary of that font. If
1102
     * the font inherits Resources from its page (which it should not) then its possible
1103
     * that the 'page dict' could be NULL here. We need to guard against that. Its possible
1104
     * there may be other, similar, cases (eg Patterns within Patterns). In addition we
1105
     * do need to be able to check the real page dictionary for inhereited resources, and
1106
     * in the case of a type 3 font BuildChar at least there is no easy way to do that.
1107
     * So we'll store the page dictionary for the current page in the context as a
1108
     * last-ditch resource to check.
1109
     */
1110
3.77M
    if (page_dict != NULL) {
1111
3.77M
        code = pdfi_resource_knownget_typedict(ctx, Type, page_dict, &typedict);
1112
3.77M
        if (code < 0)
1113
456k
            goto exit;
1114
1115
3.31M
        if (code > 0) {
1116
3.01M
            code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
1117
3.01M
            if (code != gs_error_undefined)
1118
2.37M
                goto exit;
1119
3.01M
        }
1120
3.31M
    }
1121
1122
943k
    pdfi_countdown(typedict);
1123
943k
    typedict = NULL;
1124
1125
943k
    if (ctx->page.CurrentPageDict != NULL) {
1126
943k
        code = pdfi_resource_knownget_typedict(ctx, Type, ctx->page.CurrentPageDict, &typedict);
1127
943k
        if (code < 0)
1128
248
            goto exit;
1129
1130
943k
        if (code > 0) {
1131
662k
            code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
1132
662k
            if (code != gs_error_undefined)
1133
5.44k
                goto exit;
1134
662k
        }
1135
943k
    }
1136
1137
938k
    pdfi_countdown(typedict);
1138
938k
    typedict = NULL;
1139
1140
938k
    if (ctx->current_stream != NULL) {
1141
548k
        pdf_dict *stream_dict = NULL;
1142
548k
        pdf_stream *stream = ctx->current_stream;
1143
1144
871k
        do {
1145
871k
            code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream, &stream_dict);
1146
871k
            if (code < 0)
1147
0
                goto exit;
1148
871k
            code = pdfi_resource_knownget_typedict(ctx, Type, stream_dict, &typedict);
1149
871k
            if (code < 0)
1150
0
                goto exit;
1151
871k
            if (code > 0) {
1152
324k
                code = pdfi_dict_get_no_store_R_key(ctx, typedict, name, o);
1153
324k
                if (code == 0) {
1154
86
                    pdfi_set_error(ctx, 0, NULL, E_PDF_INHERITED_STREAM_RESOURCE, "pdfi_find_resource", (char *)"Couldn't find named resource in supplied dictionary, or Parents, or Pages, matching name located in earlier stream Resource");
1155
86
                    goto exit;
1156
86
                }
1157
324k
            }
1158
871k
            pdfi_countdown(typedict);
1159
871k
            typedict = NULL;
1160
871k
            stream = pdfi_stream_parent(ctx, stream);
1161
871k
        }while(stream != NULL);
1162
548k
    }
1163
1164
    /* If we got all the way down there, we didn't find it */
1165
938k
    pdfi_set_warning(ctx, 0, NULL, W_PDF_MISSING_NAMED_RESOURCE, "pdfi_find_resource", NULL);
1166
938k
    code = gs_error_undefined;
1167
1168
4.60M
exit:
1169
4.60M
    pdfi_countdown(typedict);
1170
4.60M
    pdfi_countdown(Parent);
1171
4.60M
    return code;
1172
938k
}
1173
1174
/* Mark the actual outline */
1175
static int pdfi_doc_mark_the_outline(pdf_context *ctx, pdf_dict *outline)
1176
858
{
1177
858
    int code = 0;
1178
858
    pdf_dict *tempdict = NULL;
1179
858
    uint64_t dictsize;
1180
858
    uint64_t index;
1181
858
    pdf_name *Key = NULL;
1182
858
    double num = 0;
1183
1184
    /* Basically we only do /Count, /Title, /A, /C, /F
1185
     * The /First, /Last, /Next, /Parent get written magically by pdfwrite
1186
     */
1187
1188
    /* Make a temporary copy of the outline dict */
1189
858
    dictsize = pdfi_dict_entries(outline);
1190
858
    code = pdfi_dict_alloc(ctx, dictsize, &tempdict);
1191
858
    if (code < 0) goto exit;
1192
858
    pdfi_countup(tempdict);
1193
858
    code = pdfi_dict_copy(ctx, tempdict, outline);
1194
858
    if (code < 0) goto exit;
1195
1196
    /* Due to some craziness on the part of Adobe, the /Count in an Outline entry
1197
     * in a PDF file, and the /Count value in an /OUT pdfmark mean different things(!)
1198
     * In a PDF file it is the number of outline entries beneath the current entry
1199
     * (all child descsndants) whereas in a pdfmark it is the number of entries
1200
     * in just the next level. So we cannot use the /Count from the PDF file, we
1201
     * need to go to the /First entry of the next level, and then count all
1202
     * the entries at that level by following each /Next.
1203
     */
1204
858
    code = pdfi_dict_knownget_number(ctx, outline, "Count", &num);
1205
858
    if (code < 0)
1206
0
        goto exit;
1207
1208
    /* We can't rely on Count being present to indicate that the Outline has descendants
1209
     * see bug #707228. Instead, look for the presence of a /First key. If there is no count
1210
     * key, or it is 0, then assume the entry is closed.
1211
     */
1212
858
    {
1213
858
        pdf_dict *current = NULL, *next = NULL;
1214
858
        int count = 0, code1;
1215
1216
858
        code1 = pdfi_dict_knownget_type(ctx, outline, "First", PDF_DICT, (pdf_obj **)&current);
1217
858
        if (code1 > 0) {
1218
100
            if (code <= 0) {
1219
0
                if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_OUTLINECHILD_NO_COUNT, "pdfi_doc_mark_the_outline", NULL)) < 0)
1220
0
                    goto exit;
1221
0
            }
1222
100
            count++;
1223
188
            do {
1224
188
                code1 = pdfi_dict_knownget_type(ctx, current, "Next", PDF_DICT, (pdf_obj **)&next);
1225
188
                if (code1 > 0) {
1226
88
                    pdfi_countdown(current);
1227
88
                    current = next;
1228
88
                    next = NULL;
1229
88
                    count++;
1230
88
                } else
1231
100
                    break;
1232
188
            } while (1);
1233
100
            pdfi_countdown(current);
1234
100
        }
1235
858
        if (num <= 0)
1236
768
            count *= -1;
1237
858
        pdfi_dict_put_int(ctx, tempdict, "Count", count);
1238
858
    }
1239
1240
    /* Go through the dict, removing some keys and doing special handling for others.
1241
     */
1242
0
    code = pdfi_dict_key_first(ctx, outline, (pdf_obj **)&Key, &index);
1243
3.56k
    while (code >= 0) {
1244
3.56k
        if (pdfi_name_is(Key, "Last") || pdfi_name_is(Key, "Next") || pdfi_name_is(Key, "First") ||
1245
3.08k
            pdfi_name_is(Key, "Prev") || pdfi_name_is(Key, "Parent")) {
1246
            /* Delete some keys
1247
             * These are handled in pdfwrite and can lead to circular refs
1248
             */
1249
1.52k
            code = pdfi_dict_delete_pair(ctx, tempdict, Key);
1250
2.04k
        } else if (pdfi_name_is(Key, "SE")) {
1251
            /* TODO: Not sure what to do with SE, delete for now */
1252
            /* Seems to be okay to just delete it, since there should also be a /Dest
1253
             * See sample fts_29_2903.pdf
1254
             * Currently we are same as gs
1255
             */
1256
2
            code = pdfi_dict_delete_pair(ctx, tempdict, Key);
1257
2.04k
        } else if (pdfi_name_is(Key, "A")) {
1258
463
            code = pdfi_pdfmark_modA(ctx, tempdict);
1259
1.57k
        } else if (pdfi_name_is(Key, "Dest")) {
1260
387
            code = pdfi_pdfmark_modDest(ctx, tempdict);
1261
387
        }
1262
3.56k
        if (code < 0)
1263
110
            goto exit;
1264
1265
3.45k
        pdfi_countdown(Key);
1266
3.45k
        Key = NULL;
1267
1268
3.45k
        code = pdfi_dict_key_next(ctx, outline, (pdf_obj **)&Key, &index);
1269
3.45k
        if (code == gs_error_undefined) {
1270
748
            code = 0;
1271
748
            break;
1272
748
        }
1273
3.45k
    }
1274
748
    if (code < 0) goto exit;
1275
1276
    /* Write the pdfmark */
1277
748
    code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "OUT");
1278
748
    if (code < 0)
1279
2
        goto exit;
1280
1281
858
 exit:
1282
858
    pdfi_countdown(tempdict);
1283
858
    pdfi_countdown(Key);
1284
858
    return code;
1285
748
}
1286
1287
/* Do pdfmark on an outline entry (recursive)
1288
 * Note: the logic here is wonky.  It is relying on the behavior of the pdfwrite driver.
1289
 * See pdf_main.ps/writeoutline()
1290
 */
1291
static int pdfi_doc_mark_outline(pdf_context *ctx, pdf_dict *outline)
1292
858
{
1293
858
    int code = 0;
1294
858
    pdf_dict *child = NULL;
1295
858
    pdf_dict *Next = NULL;
1296
1297
858
    if (outline == (pdf_dict *)PDF_NULL_OBJ)
1298
0
        return 0;
1299
1300
    /* Mark the outline */
1301
    /* NOTE: I think the pdfmark for this needs to be written before the children
1302
     * because I think pdfwrite relies on the order of things.
1303
     */
1304
858
    code = pdfi_doc_mark_the_outline(ctx, outline);
1305
858
    if (code < 0)
1306
112
        goto exit1;
1307
1308
    /* Handle the children */
1309
746
    code = pdfi_loop_detector_mark(ctx);
1310
746
    if (code < 0)
1311
0
        goto exit1;
1312
1313
    /* Handle any children (don't deref them, we don't want to leave them hanging around) */
1314
746
    code = pdfi_dict_get_no_store_R(ctx, outline, "First", (pdf_obj **)&child);
1315
746
    if (code < 0 || pdfi_type_of(child) != PDF_DICT) {
1316
        /* TODO: flag a warning? */
1317
663
        code = 0;
1318
663
        goto exit;
1319
663
    }
1320
1321
83
    if (child->object_num != 0) {
1322
83
        code = pdfi_loop_detector_add_object(ctx, child->object_num);
1323
83
        if (code < 0)
1324
0
            goto exit;
1325
83
    }
1326
1327
141
    do {
1328
141
        code = pdfi_doc_mark_outline(ctx, child);
1329
141
        if (code < 0) goto exit;
1330
1331
1332
122
        code = pdfi_dict_get_no_store_R(ctx, child, "Next", (pdf_obj **)&Next);
1333
122
        if (code == gs_error_undefined) {
1334
62
            code = 0;
1335
62
            break;
1336
62
        }
1337
60
        if (code == gs_error_circular_reference) {
1338
0
            code = 0;
1339
0
            goto exit;
1340
0
        }
1341
60
        if (code < 0 || pdfi_type_of(Next) != PDF_DICT)
1342
2
            goto exit;
1343
1344
58
        pdfi_countdown(child);
1345
58
        child = Next;
1346
58
        Next = NULL;
1347
58
    } while (true);
1348
1349
746
 exit:
1350
746
    (void)pdfi_loop_detector_cleartomark(ctx);
1351
858
 exit1:
1352
858
    pdfi_countdown(child);
1353
858
    pdfi_countdown(Next);
1354
858
    return code;
1355
746
}
1356
1357
/* Do pdfmark for Outlines */
1358
static int pdfi_doc_Outlines(pdf_context *ctx)
1359
10.7k
{
1360
10.7k
    int code = 0;
1361
10.7k
    pdf_dict *Outlines = NULL;
1362
10.7k
    pdf_dict *outline = NULL;
1363
10.7k
    pdf_dict *Next = NULL;
1364
1365
10.7k
    if (ctx->args.no_pdfmark_outlines)
1366
0
        goto exit1;
1367
1368
10.7k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "Outlines", PDF_DICT, (pdf_obj **)&Outlines);
1369
10.7k
    if (code <= 0) {
1370
        /* TODO: flag a warning */
1371
10.0k
        code = 0;
1372
10.0k
        goto exit1;
1373
10.0k
    }
1374
1375
691
    code = pdfi_loop_detector_mark(ctx);
1376
691
    if (code < 0)
1377
0
        goto exit1;
1378
1379
    /* Handle any children (don't deref them, we don't want to leave them hanging around) */
1380
691
    code = pdfi_dict_get_no_store_R(ctx, Outlines, "First", (pdf_obj **)&outline);
1381
691
    if (code < 0 || pdfi_type_of(outline) != PDF_DICT) {
1382
        /* TODO: flag a warning? */
1383
170
        code = 0;
1384
170
        goto exit;
1385
170
    }
1386
1387
521
    if (pdfi_type_of(outline) != PDF_DICT)
1388
0
        goto exit; /* Exit with no error? */
1389
1390
521
    if (outline->object_num != 0) {
1391
521
        code = pdfi_loop_detector_add_object(ctx, outline->object_num);
1392
521
        if (code < 0)
1393
0
            goto exit;
1394
521
    }
1395
1396
    /* Loop through all the top-level outline entries
1397
     * First one is in Outlines, and if there are more, they are the Next of the
1398
     * current outline item.  (see spec)
1399
     * (basically we are walking a linked list)
1400
     */
1401
717
    do {
1402
717
        code = pdfi_doc_mark_outline(ctx, outline);
1403
717
        if (code < 0) goto exit;
1404
1405
1406
603
        code = pdfi_dict_get_no_store_R(ctx, outline, "Next", (pdf_obj **)&Next);
1407
603
        if (code == gs_error_undefined) {
1408
403
            code = 0;
1409
403
            break;
1410
403
        }
1411
200
        if (code == gs_error_circular_reference) {
1412
0
            code = 0;
1413
0
            goto exit;
1414
0
        }
1415
200
        if (code < 0 || pdfi_type_of(Next) != PDF_DICT)
1416
4
            goto exit;
1417
1418
196
        pdfi_countdown(outline);
1419
196
        outline = Next;
1420
196
        Next = NULL;
1421
196
    } while (true);
1422
1423
691
 exit:
1424
691
    (void)pdfi_loop_detector_cleartomark(ctx);
1425
10.7k
 exit1:
1426
10.7k
    pdfi_countdown(Outlines);
1427
10.7k
    pdfi_countdown(outline);
1428
10.7k
    pdfi_countdown(Next);
1429
10.7k
    return code;
1430
691
}
1431
1432
/* Do pdfmark for Info */
1433
static int pdfi_doc_Info(pdf_context *ctx)
1434
10.7k
{
1435
10.7k
    int code = 0;
1436
10.7k
    pdf_dict *Info = NULL, *d = NULL;
1437
10.7k
    pdf_dict *tempdict = NULL;
1438
10.7k
    uint64_t dictsize;
1439
10.7k
    uint64_t index;
1440
10.7k
    pdf_name *Key = NULL;
1441
10.7k
    pdf_obj *Value = NULL;
1442
1443
    /* See comment in pdfi_read_Root() for details */
1444
10.7k
    d = ctx->Trailer;
1445
10.7k
    pdfi_countup(d);
1446
10.7k
    code = pdfi_dict_knownget_type(ctx, d, "Info", PDF_DICT, (pdf_obj **)&Info);
1447
10.7k
    pdfi_countdown(d);
1448
10.7k
    if (code <= 0) {
1449
        /* TODO: flag a warning */
1450
7.48k
        goto exit;
1451
7.48k
    }
1452
1453
    /* Make a temporary copy of the Info dict */
1454
3.29k
    dictsize = pdfi_dict_entries(Info);
1455
3.29k
    code = pdfi_dict_alloc(ctx, dictsize, &tempdict);
1456
3.29k
    if (code < 0) goto exit;
1457
3.29k
    pdfi_countup(tempdict);
1458
1459
    /* Copy only certain keys from Info to tempdict
1460
     * NOTE: pdfwrite will set /Producer, /CreationDate and /ModDate
1461
     */
1462
3.29k
    code = pdfi_dict_first(ctx, Info, (pdf_obj **)&Key, &Value, &index);
1463
16.4k
    while (code >= 0) {
1464
16.4k
        if (pdfi_name_is(Key, "Author") || pdfi_name_is(Key, "Creator") ||
1465
12.4k
            pdfi_name_is(Key, "Title") || pdfi_name_is(Key, "Subject") ||
1466
10.7k
            pdfi_name_is(Key, "Keywords")) {
1467
1468
6.22k
            code = pdfi_dict_put_obj(ctx, tempdict, (pdf_obj *)Key, Value, true);
1469
6.22k
            if (code < 0)
1470
0
                goto exit;
1471
6.22k
        }
1472
16.4k
        pdfi_countdown(Key);
1473
16.4k
        Key = NULL;
1474
16.4k
        pdfi_countdown(Value);
1475
16.4k
        Value = NULL;
1476
1477
16.4k
        code = pdfi_dict_next(ctx, Info, (pdf_obj **)&Key, &Value, &index);
1478
16.4k
        if (code == gs_error_undefined) {
1479
3.23k
            code = 0;
1480
3.23k
            break;
1481
3.23k
        }
1482
16.4k
    }
1483
3.29k
    if (code < 0) goto exit;
1484
1485
    /* Write the pdfmark */
1486
3.23k
    code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCINFO");
1487
1488
10.7k
 exit:
1489
10.7k
    pdfi_countdown(Key);
1490
10.7k
    pdfi_countdown(Value);
1491
10.7k
    pdfi_countdown(Info);
1492
10.7k
    pdfi_countdown(tempdict);
1493
10.7k
    return code;
1494
3.23k
}
1495
1496
/* Handle PageLabels for pdfwrite device */
1497
static int pdfi_doc_PageLabels(pdf_context *ctx)
1498
89.0k
{
1499
89.0k
    int code;
1500
89.0k
    pdf_dict *PageLabels = NULL;
1501
1502
89.0k
    if (ctx->loop_detection) {
1503
0
        code = pdfi_loop_detector_mark(ctx);
1504
0
        if (code < 0)
1505
0
            return code;
1506
0
    }
1507
1508
89.0k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "PageLabels", PDF_DICT, (pdf_obj **)&PageLabels);
1509
89.0k
    if (code <= 0) {
1510
85.6k
        if (ctx->loop_detection)
1511
0
            (void)pdfi_loop_detector_cleartomark(ctx);
1512
        /* TODO: flag a warning */
1513
85.6k
        goto exit;
1514
85.6k
    }
1515
1516
3.41k
    if (ctx->loop_detection) {
1517
0
        code = pdfi_loop_detector_cleartomark(ctx);
1518
0
        if (code < 0)
1519
0
            goto exit;
1520
0
    }
1521
1522
3.41k
    if (ctx->device_state.WantsPageLabels) {
1523
        /* This will send the PageLabels object as a 'pdfpagelabels' setdeviceparams */
1524
562
        code = pdfi_pdfmark_object(ctx, (pdf_obj *)PageLabels, "pdfpagelabels");
1525
562
        if (code < 0)
1526
37
            goto exit;
1527
562
    }
1528
1529
89.0k
 exit:
1530
89.0k
    pdfi_countdown(PageLabels);
1531
89.0k
    return code;
1532
3.41k
}
1533
1534
/* Handle OutputIntents stuff
1535
 * (bottom of pdf_main.ps/process_trailer_attrs)
1536
 */
1537
static int pdfi_doc_OutputIntents(pdf_context *ctx)
1538
89.0k
{
1539
89.0k
    int code;
1540
89.0k
    pdf_array *OutputIntents = NULL;
1541
89.0k
    pdf_dict *intent = NULL;
1542
89.0k
    pdf_string *name = NULL;
1543
89.0k
    pdf_stream *DestOutputProfile = NULL;
1544
89.0k
    uint64_t index;
1545
1546
    /* NOTE: subtle difference in error handling -- we are checking for OutputIntents first,
1547
     * so this will just ignore UsePDFX3Profile or UseOutputIntent params without warning,
1548
     * if OutputIntents doesn't exist.  Seems fine to me.
1549
     */
1550
89.0k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "OutputIntents", PDF_ARRAY,
1551
89.0k
                                   (pdf_obj **)&OutputIntents);
1552
89.0k
    if (code <= 0) {
1553
88.5k
        goto exit;
1554
88.5k
    }
1555
1556
    /* TODO: Implement writeoutputintents  if somebody ever complains...
1557
     * See pdf_main.ps/writeoutputintents
1558
     * I am not aware of a device that supports "/OutputIntent" so
1559
     * couldn't figure out what to do for this.
1560
     */
1561
1562
    /* Handle UsePDFX3Profile and UseOutputIntent command line options */
1563
541
    if (ctx->args.UsePDFX3Profile) {
1564
        /* This is an index into the array */
1565
0
        code = pdfi_array_get_type(ctx, OutputIntents, ctx->args.PDFX3Profile_num,
1566
0
                                   PDF_DICT, (pdf_obj **)&intent);
1567
0
        if (code < 0) {
1568
0
            code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_OUTPUTINTENT_INDEX, "pdfi_doc_OutputIntents", "");
1569
0
            goto exit;
1570
0
        }
1571
541
    } else if (ctx->args.UseOutputIntent != NULL) {
1572
        /* This is a name to look up in the array */
1573
0
        for (index=0; index<pdfi_array_size(OutputIntents); index ++) {
1574
0
            code = pdfi_array_get_type(ctx, OutputIntents, index, PDF_DICT, (pdf_obj **)&intent);
1575
0
            if (code < 0) goto exit;
1576
1577
0
            code = pdfi_dict_knownget_type(ctx, intent, "OutputConditionIdentifier", PDF_STRING,
1578
0
                                           (pdf_obj **)&name);
1579
0
            if (code < 0) goto exit;
1580
0
            if (code == 0)
1581
0
                continue;
1582
1583
            /* If the ID is "Custom" then check "Info" instead */
1584
0
            if (pdfi_string_is(name, "Custom")) {
1585
0
                pdfi_countdown(name);
1586
0
                name = NULL;
1587
0
                code = pdfi_dict_knownget_type(ctx, intent, "Info", PDF_STRING, (pdf_obj **)&name);
1588
0
                if (code < 0) goto exit;
1589
0
                if (code == 0)
1590
0
                    continue;
1591
0
            }
1592
1593
            /* Check for a match */
1594
0
            if (pdfi_string_is(name, ctx->args.UseOutputIntent))
1595
0
                break;
1596
1597
0
            pdfi_countdown(intent);
1598
0
            intent = NULL;
1599
0
            pdfi_countdown(name);
1600
0
            name = NULL;
1601
0
        }
1602
0
        code = 0;
1603
541
    } else {
1604
        /* No command line arg was specified, so nothing to do */
1605
541
        code = 0;
1606
541
        goto exit;
1607
541
    }
1608
1609
    /* Now if intent is non-null, we found the selected intent dictionary */
1610
0
    if (intent == NULL)
1611
0
        goto exit;
1612
1613
    /* Load the profile, if it exists */
1614
0
    code = pdfi_dict_knownget_type(ctx, intent, "DestOutputProfile", PDF_STREAM, (pdf_obj **)&DestOutputProfile);
1615
    /* TODO: Flag an error if it doesn't exist?  Only required in some cases */
1616
0
    if (code <= 0) goto exit;
1617
1618
    /* Set the intent to the profile */
1619
0
    code = pdfi_color_setoutputintent(ctx, intent, DestOutputProfile);
1620
1621
89.0k
 exit:
1622
89.0k
    pdfi_countdown(OutputIntents);
1623
89.0k
    pdfi_countdown(intent);
1624
89.0k
    pdfi_countdown(name);
1625
89.0k
    pdfi_countdown(DestOutputProfile);
1626
89.0k
    return code;
1627
0
}
1628
1629
/* Handled an embedded files Names array for pdfwrite device */
1630
static int pdfi_doc_EmbeddedFiles_Names(pdf_context *ctx, pdf_array *names)
1631
44
{
1632
44
    int code;
1633
44
    uint64_t arraysize;
1634
44
    uint64_t index;
1635
44
    pdf_string *name = NULL;
1636
44
    pdf_dict *filespec = NULL;
1637
1638
44
    arraysize = pdfi_array_size(names);
1639
44
    if ((arraysize % 2) != 0) {
1640
1
        code = gs_note_error(gs_error_syntaxerror);
1641
1
        goto exit;
1642
1
    }
1643
1644
    /* This is supposed to be an array of
1645
     * [ (filename1) (filespec1) (filename2) (filespec2) ... ]
1646
     */
1647
74
    for (index = 0; index < arraysize; index += 2) {
1648
43
        code = pdfi_array_get_type(ctx, names, index, PDF_STRING, (pdf_obj **)&name);
1649
43
        if (code < 0) goto exit;
1650
1651
43
        code = pdfi_array_get_type(ctx, names, index+1, PDF_DICT, (pdf_obj **)&filespec);
1652
43
        if (code < 0) goto exit;
1653
1654
37
        code = pdfi_pdfmark_embed_filespec(ctx, name, filespec);
1655
37
        if (code < 0) goto exit;
1656
1657
31
        pdfi_countdown(name);
1658
31
        name = NULL;
1659
31
        pdfi_countdown(filespec);
1660
31
        filespec = NULL;
1661
31
    }
1662
1663
1664
44
 exit:
1665
44
    pdfi_countdown(name);
1666
44
    pdfi_countdown(filespec);
1667
44
    return code;
1668
43
}
1669
1670
/* Handle PageLabels for pdfwrite device */
1671
static int pdfi_doc_EmbeddedFiles(pdf_context *ctx)
1672
10.7k
{
1673
10.7k
    int code;
1674
10.7k
    pdf_dict *Names = NULL;
1675
10.7k
    pdf_dict *EmbeddedFiles = NULL;
1676
10.7k
    pdf_array *Names_array = NULL;
1677
10.7k
    pdf_array *Kids = NULL;
1678
1679
10.7k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "Collection", PDF_DICT, (pdf_obj **)&Names);
1680
10.7k
    if (code < 0) goto exit;
1681
10.7k
    if (code > 0) {
1682
0
        code = 0;
1683
0
        goto exit;
1684
0
    }
1685
1686
10.7k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "Names", PDF_DICT, (pdf_obj **)&Names);
1687
10.7k
    if (code <= 0) goto exit;
1688
1689
979
    code = pdfi_dict_knownget_type(ctx, Names, "EmbeddedFiles", PDF_DICT, (pdf_obj **)&EmbeddedFiles);
1690
979
    if (code <= 0) goto exit;
1691
1692
44
    code = pdfi_dict_knownget_type(ctx, Names, "Kids", PDF_ARRAY, (pdf_obj **)&Kids);
1693
44
    if (code < 0) goto exit;
1694
44
    if (code > 0) {
1695
        /* TODO: Need to implement */
1696
0
        errprintf(ctx->memory, "*** WARNING Kids array in EmbeddedFiles not implemented\n");
1697
0
    }
1698
1699
    /* TODO: This is a name tree.
1700
     * Can contain a Names array, or some complicated Kids.
1701
     * Just handling Names array for now
1702
     */
1703
44
    code = pdfi_dict_knownget_type(ctx, EmbeddedFiles, "Names", PDF_ARRAY, (pdf_obj **)&Names_array);
1704
44
    if (code <= 0) goto exit;
1705
1706
44
    code = pdfi_doc_EmbeddedFiles_Names(ctx, Names_array);
1707
44
    if (code <= 0) goto exit;
1708
1709
10.7k
 exit:
1710
10.7k
    pdfi_countdown(Kids);
1711
10.7k
    pdfi_countdown(Names);
1712
10.7k
    pdfi_countdown(EmbeddedFiles);
1713
10.7k
    pdfi_countdown(Names_array);
1714
10.7k
    return code;
1715
44
}
1716
1717
/* Handle some bookkeeping related to AcroForm (and annotations)
1718
 * See pdf_main.ps/process_trailer_attrs/AcroForm
1719
 *
1720
 * Mainly we preload AcroForm and NeedAppearances in the context
1721
 *
1722
 * TODO: gs code also seems to do something to link up parents in fields/annotations (ParentField)
1723
 * We are going to avoid doing that for now.
1724
 */
1725
static int pdfi_doc_AcroForm(pdf_context *ctx)
1726
89.0k
{
1727
89.0k
    int code = 0;
1728
89.0k
    pdf_dict *AcroForm = NULL;
1729
89.0k
    bool boolval = false;
1730
1731
89.0k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "AcroForm", PDF_DICT, (pdf_obj **)&AcroForm);
1732
89.0k
    if (code <= 0) goto exit;
1733
1734
8.17k
    code = pdfi_dict_get_bool(ctx, AcroForm, "NeedAppearances", &boolval);
1735
8.17k
    if (code < 0) {
1736
7.47k
        if (code == gs_error_undefined) {
1737
7.47k
            boolval = true;
1738
7.47k
            code = 0;
1739
7.47k
        }
1740
4
        else
1741
4
            goto exit;
1742
7.47k
    }
1743
8.16k
    ctx->NeedAppearances = boolval;
1744
1745
    /* Save this for efficiency later */
1746
8.16k
    ctx->AcroForm = AcroForm;
1747
8.16k
    pdfi_countup(AcroForm);
1748
1749
    /* TODO: Link up ParentField (but hopefully we can avoid doing this hacky mess).
1750
     * Also: Something to do with Bug692447.pdf?
1751
     */
1752
1753
1754
89.0k
 exit:
1755
89.0k
    pdfi_countdown(AcroForm);
1756
89.0k
    return code;
1757
8.16k
}
1758
1759
1760
static int pdfi_doc_view(pdf_context *ctx)
1761
10.7k
{
1762
10.7k
    int code = 0;
1763
10.7k
    pdf_dict *tempdict = NULL;
1764
10.7k
    pdf_name *Mode = NULL, *Layout = NULL;
1765
10.7k
    pdf_obj *ActionDest = NULL;
1766
1767
10.7k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "PageMode", PDF_NAME, (pdf_obj **)&Mode);
1768
10.7k
    if (code < 0)
1769
1
        return code;
1770
1771
10.7k
    if (code != 0) {
1772
726
        code = pdfi_dict_alloc(ctx, 1, &tempdict);
1773
726
        if (code < 0)
1774
0
            goto exit;
1775
1776
726
        pdfi_countup(tempdict);
1777
1778
726
        code = pdfi_dict_put(ctx, tempdict, "PageMode", (pdf_obj *)Mode);
1779
726
        if (code < 0)
1780
0
            goto exit;
1781
1782
726
        code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCVIEW");
1783
726
        if (code < 0)
1784
0
            goto exit;
1785
726
        pdfi_countdown(tempdict);
1786
726
        tempdict = NULL;
1787
726
    }
1788
1789
10.7k
    code = pdfi_dict_knownget_type(ctx, ctx->Root, "PageLayout", PDF_NAME, (pdf_obj **)&Layout);
1790
10.7k
    if (code < 0)
1791
0
        goto exit;
1792
1793
10.7k
    if (code != 0) {
1794
628
        code = pdfi_dict_alloc(ctx, 1, &tempdict);
1795
628
        if (code < 0)
1796
0
            goto exit;
1797
1798
628
        pdfi_countup(tempdict);
1799
1800
628
        code = pdfi_dict_put(ctx, tempdict, "PageLayout", (pdf_obj *)Layout);
1801
628
        if (code < 0)
1802
0
            goto exit;
1803
1804
628
        code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCVIEW");
1805
628
        if (code < 0)
1806
0
            goto exit;
1807
628
        pdfi_countdown(tempdict);
1808
628
        tempdict = NULL;
1809
628
    }
1810
1811
10.7k
    code = pdfi_dict_knownget(ctx, ctx->Root, "OpenAction", &ActionDest);
1812
10.7k
    if (code < 0)
1813
34
        goto exit;
1814
1815
10.7k
    if (code != 0) {
1816
599
        if (pdfi_type_of(ActionDest) == PDF_DICT) {
1817
            /* Dictionary means this is an action */
1818
30
            code = pdfi_dict_alloc(ctx, 1, &tempdict);
1819
30
            if (code < 0)
1820
0
                goto exit;
1821
1822
30
            pdfi_countup(tempdict);
1823
1824
30
            code = pdfi_dict_put(ctx, tempdict, "A", (pdf_obj *)ActionDest);
1825
30
            if (code < 0)
1826
0
                goto exit;
1827
1828
30
            code = pdfi_pdfmark_modA(ctx, tempdict);
1829
30
            if (code < 0) goto exit;
1830
1831
29
            code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCVIEW");
1832
569
        } else {
1833
569
            if (pdfi_type_of(ActionDest) == PDF_ARRAY) {
1834
                /* Array means this is a destination */
1835
567
                code = pdfi_dict_alloc(ctx, 1, &tempdict);
1836
567
                if (code < 0)
1837
0
                    goto exit;
1838
1839
567
                pdfi_countup(tempdict);
1840
1841
567
                code = pdfi_dict_put(ctx, tempdict, "Dest", (pdf_obj *)ActionDest);
1842
567
                if (code < 0)
1843
0
                    goto exit;
1844
567
                code = pdfi_pdfmark_modDest(ctx, tempdict);
1845
567
                if (code < 0)
1846
57
                    goto exit;
1847
510
                code = pdfi_pdfmark_from_dict(ctx, tempdict, NULL, "DOCVIEW");
1848
510
                if (code < 0)
1849
0
                    goto exit;
1850
510
            } else {
1851
2
                code = gs_note_error(gs_error_typecheck);
1852
2
                goto exit;
1853
2
            }
1854
569
        }
1855
599
    }
1856
1857
10.7k
exit:
1858
10.7k
    pdfi_countdown(ActionDest);
1859
10.7k
    pdfi_countdown(Layout);
1860
10.7k
    pdfi_countdown(Mode);
1861
10.7k
    pdfi_countdown(tempdict);
1862
10.7k
    return code;
1863
10.7k
}
1864
1865
1866
/* See pdf_main.ps/process_trailer_attrs()
1867
 * Some of this stuff is about pdfmarks, and some of it is just handling
1868
 * random things in the trailer.
1869
 */
1870
int pdfi_doc_trailer(pdf_context *ctx)
1871
89.0k
{
1872
89.0k
    int code = 0;
1873
1874
    /* Can't do this stuff with no Trailer */
1875
89.0k
    if (!ctx->Trailer) {
1876
42.6k
        if ((code = pdfi_set_warning_stop(ctx, gs_note_error(gs_error_undefined), NULL, W_PDF_BAD_TRAILER, "pdfi_doc_trailer", NULL)) < 0)
1877
0
            goto exit;
1878
42.6k
    }
1879
1880
89.0k
    if (ctx->device_state.writepdfmarks) {
1881
        /* Handle Outlines */
1882
10.7k
        code = pdfi_doc_Outlines(ctx);
1883
10.7k
        if (code < 0) {
1884
116
            if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_OUTLINES, "pdfi_doc_trailer", NULL)) < 0)
1885
0
                goto exit;
1886
116
        }
1887
1888
        /* Handle Docview pdfmark stuff */
1889
10.7k
        if (ctx->args.preservedocview) {
1890
10.7k
            code = pdfi_doc_view(ctx);
1891
10.7k
            if (code < 0) {
1892
95
                if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_VIEW, "pdfi_doc_view", NULL)) < 0)
1893
0
                    goto exit;
1894
95
            }
1895
10.7k
        }
1896
1897
        /* Handle Info */
1898
10.7k
        code = pdfi_doc_Info(ctx);
1899
10.7k
        if (code < 0) {
1900
            /* pdfwrite will set a Fatal error when processing the DOCINFO if it has been
1901
             * told to create a PDF/A. the PDFA compatibility is 2, and the file info
1902
             * cannot be handled. In that case, abort immediately.
1903
             */
1904
6.08k
            if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_INFO, "pdfi_doc_trailer", NULL)) < 0)
1905
0
                goto exit;
1906
6.08k
        }
1907
1908
        /* Handle EmbeddedFiles */
1909
        /* TODO: add a configuration option to embed or omit */
1910
10.7k
        if (ctx->args.preserveembeddedfiles) {
1911
10.7k
            code = pdfi_doc_EmbeddedFiles(ctx);
1912
10.7k
            if (code < 0) {
1913
117
                if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_EMBEDDEDFILES, "pdfi_doc_trailer", NULL)) < 0)
1914
0
                    goto exit;
1915
117
            }
1916
10.7k
        }
1917
10.7k
    }
1918
1919
    /* Handle OCProperties */
1920
    /* NOTE: Apparently already handled by pdfi_read_OptionalRoot() */
1921
1922
    /* Handle AcroForm -- this is some bookkeeping once per doc, not rendering them yet */
1923
89.0k
    code = pdfi_doc_AcroForm(ctx);
1924
89.0k
    if (code < 0) {
1925
1.09k
        if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_ACROFORM, "pdfi_doc_trailer", NULL)) < 0)
1926
0
            goto exit;
1927
1.09k
    }
1928
1929
    /* Handle OutputIntent ICC Profile */
1930
89.0k
    code = pdfi_doc_OutputIntents(ctx);
1931
89.0k
    if (code < 0) {
1932
0
        if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_OUTPUTINTENTS, "pdfi_doc_trailer", NULL)) < 0)
1933
0
            goto exit;
1934
0
    }
1935
1936
    /* Handle PageLabels */
1937
89.0k
    code = pdfi_doc_PageLabels(ctx);
1938
89.0k
    if (code < 0) {
1939
157
        if ((code = pdfi_set_warning_stop(ctx, code, NULL, W_PDF_BAD_PAGELABELS, "pdfi_doc_trailer", NULL)) < 0)
1940
0
            goto exit;
1941
157
    }
1942
1943
89.0k
 exit:
1944
89.0k
    return code;
1945
89.0k
}