Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/pdf/pdf_optcontent.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-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
/* Optional Content routines */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "pdf_misc.h"
21
#include "pdf_font_types.h"
22
#include "pdf_gstate.h"
23
#include "pdf_dict.h"
24
#include "pdf_array.h"
25
#include "pdf_doc.h"
26
#include "pdf_mark.h"
27
#include "pdf_optcontent.h"
28
29
30
/* Find the default value for an ocdict, based on contents of OCProperties */
31
/* NOTE: the spec says that if BaseState is present, it won't be set to "OFF",
32
 * but this doesn't seem to be the case (Bug 691491).  Also, the spec
33
 * says the ON and OFF arrays are redundant in certain cases.  We just
34
 * look at everything anyway.
35
 * Default is going to be visible unless anything here indicates that it
36
 * should be turned off.
37
 */
38
static bool
39
pdfi_get_default_OCG_val(pdf_context *ctx, pdf_dict *ocdict)
40
19.7k
{
41
19.7k
    bool is_visible = true;
42
19.7k
    pdf_dict *D = NULL;
43
19.7k
    pdf_obj *BaseState = NULL;
44
19.7k
    pdf_array *OFF = NULL;
45
19.7k
    pdf_array *ON = NULL;
46
19.7k
    int code;
47
48
19.7k
    if (ctx->OCProperties == NULL)
49
700
        return is_visible;
50
51
19.0k
    code = pdfi_dict_knownget_type(ctx, ctx->OCProperties, "D", PDF_DICT, (pdf_obj **)&D);
52
19.0k
    if (code <= 0)
53
2
        goto cleanup;
54
55
19.0k
    code = pdfi_dict_knownget_type(ctx, D, "BaseState", PDF_NAME, &BaseState);
56
19.0k
    if (code < 0) {
57
0
        goto cleanup;
58
0
    }
59
19.0k
    if (code > 0) {
60
0
        if (pdfi_name_is((pdf_name *)BaseState, "OFF")) {
61
0
            is_visible = false;
62
0
        }
63
0
    }
64
65
19.0k
    if (!is_visible) {
66
0
        code = pdfi_dict_knownget_type(ctx, D, "ON", PDF_ARRAY, (pdf_obj **)&ON);
67
0
        if (code < 0)
68
0
            goto cleanup;
69
0
        if (code > 0) {
70
0
            if (pdfi_array_known(ctx, ON, (pdf_obj *)ocdict, NULL))
71
0
                is_visible = true;
72
0
        }
73
0
    }
74
75
19.0k
    if (is_visible) {
76
19.0k
        code = pdfi_dict_knownget_type(ctx, D, "OFF", PDF_ARRAY, (pdf_obj **)&OFF);
77
19.0k
        if (code < 0)
78
2.73k
            goto cleanup;
79
16.3k
        if (code > 0) {
80
16.0k
            if (pdfi_array_known(ctx, OFF, (pdf_obj *)ocdict, NULL))
81
15.7k
                is_visible = false;
82
16.0k
        }
83
16.3k
    }
84
85
86
19.0k
 cleanup:
87
19.0k
    pdfi_countdown(BaseState);
88
19.0k
    pdfi_countdown(D);
89
19.0k
    pdfi_countdown(OFF);
90
19.0k
    pdfi_countdown(ON);
91
19.0k
    return is_visible;
92
19.0k
}
93
94
/* Check Usage for an OCG */
95
static bool
96
pdfi_oc_check_OCG_usage(pdf_context *ctx, pdf_dict *ocdict)
97
817
{
98
817
    bool is_visible = true;
99
817
    int code;
100
817
    pdf_dict *Usage = NULL;
101
817
    pdf_dict *dict = NULL;
102
817
    pdf_obj *name = NULL;
103
104
    /* Check Usage to see if it has additional info */
105
817
    code = pdfi_dict_knownget_type(ctx, ocdict, "Usage", PDF_DICT, (pdf_obj **)&Usage);
106
817
    if (code <= 0) {
107
        /* No Usage, so we're done */
108
502
        goto cleanup;
109
502
    }
110
111
315
    if (ctx->args.printed) {
112
315
        code = pdfi_dict_knownget_type(ctx, ocdict, "Print", PDF_DICT, (pdf_obj **)&dict);
113
315
        if (code <= 0)
114
315
            goto cleanup;
115
0
        code = pdfi_dict_knownget_type(ctx, dict, "PrintState", PDF_NAME, &name);
116
0
        if (code <= 0)
117
0
            goto cleanup;
118
0
    } else {
119
0
        code = pdfi_dict_knownget_type(ctx, ocdict, "View", PDF_DICT, (pdf_obj **)&dict);
120
0
        if (code <= 0)
121
0
            goto cleanup;
122
0
        code = pdfi_dict_knownget_type(ctx, dict, "ViewState", PDF_NAME, &name);
123
0
        if (code <= 0)
124
0
            goto cleanup;
125
0
    }
126
0
    if (pdfi_name_strcmp((pdf_name *)name, "OFF")) {
127
0
        is_visible = false;
128
0
    }
129
130
817
 cleanup:
131
817
    pdfi_countdown(Usage);
132
817
    pdfi_countdown(dict);
133
817
    pdfi_countdown(name);
134
135
817
    return is_visible;
136
0
}
137
138
typedef enum {
139
    P_AnyOn,
140
    P_AllOn,
141
    P_AllOff,
142
    P_AnyOff
143
} ocmd_p_type;
144
145
static bool
146
pdfi_oc_check_OCMD_array(pdf_context *ctx, pdf_array *array, ocmd_p_type type)
147
19.6k
{
148
19.6k
    bool is_visible;
149
19.6k
    uint64_t i;
150
19.6k
    int code;
151
19.6k
    pdf_obj *val = NULL;
152
153
    /* Setup default */
154
19.6k
    switch (type) {
155
19.6k
    case P_AnyOn:
156
19.6k
    case P_AnyOff:
157
19.6k
        is_visible = false;
158
19.6k
        break;
159
0
    case P_AllOn:
160
0
    case P_AllOff:
161
0
        is_visible = true;
162
0
        break;
163
19.6k
    }
164
165
36.1k
    for (i=0; i<pdfi_array_size(array); i++) {
166
19.6k
        bool vis;
167
168
19.6k
        code = pdfi_array_get(ctx, array, i, &val);
169
19.6k
        if (code < 0) continue;
170
18.9k
        if (pdfi_type_of(val) != PDF_DICT) {
171
0
            dmprintf1(ctx->memory, "WARNING: OCMD array contains item type %d, expected PDF_DICT or PDF_NULL\n", pdfi_type_of(val));
172
0
            pdfi_countdown(val);
173
0
            val = NULL;
174
0
            continue;
175
0
        }
176
177
18.9k
        vis = pdfi_get_default_OCG_val(ctx, (pdf_dict *)val);
178
18.9k
        switch (type) {
179
18.9k
        case P_AnyOn:
180
            /* visible if any is on */
181
18.9k
            if (vis) {
182
3.16k
                is_visible = true;
183
3.16k
                goto cleanup;
184
3.16k
            }
185
15.7k
            break;
186
15.7k
        case P_AllOn:
187
            /* visible if all on */
188
0
            if (!vis) {
189
0
                is_visible = false;
190
0
                goto cleanup;
191
0
            }
192
0
            break;
193
0
        case P_AllOff:
194
            /* visible if all are off */
195
0
            if (vis) {
196
0
                is_visible = false;
197
0
                goto cleanup;
198
0
            }
199
0
            break;
200
0
        case P_AnyOff:
201
            /* visible if any is off */
202
0
            if (!vis) {
203
0
                is_visible = true;
204
0
                goto cleanup;
205
0
            }
206
0
            break;
207
18.9k
        }
208
15.7k
        pdfi_countdown(val);
209
15.7k
        val = NULL;
210
15.7k
    }
211
212
19.6k
 cleanup:
213
19.6k
    pdfi_countdown(val);
214
19.6k
    return is_visible;
215
19.6k
}
216
217
static bool
218
pdfi_oc_check_OCMD(pdf_context *ctx, pdf_dict *ocdict)
219
19.7k
{
220
19.7k
    bool is_visible = true;
221
19.7k
    int code;
222
19.7k
    pdf_obj *VE = NULL;
223
19.7k
    pdf_obj *obj = NULL;
224
19.7k
    pdf_obj *Pname = NULL;
225
19.7k
    pdf_dict *OCGs_dict = NULL; /* alias, don't need to free */
226
19.7k
    pdf_array *OCGs_array = NULL; /* alias, don't need to free */
227
19.7k
    ocmd_p_type Ptype = P_AnyOn;
228
229
    /* TODO: We don't support this, so log a warning and ignore */
230
19.7k
    code = pdfi_dict_knownget_type(ctx, ocdict, "VE", PDF_ARRAY, &VE);
231
19.7k
    if (code > 0) {
232
90
        dmprintf(ctx->memory, "WARNING: OCMD contains VE, which is not supported (ignoring)\n");
233
90
    }
234
235
19.7k
    code = pdfi_dict_knownget(ctx, ocdict, "OCGs", &obj);
236
19.7k
    if (code <= 0)
237
91
        goto cleanup;
238
19.6k
    if (pdfi_type_of(obj) == PDF_ARRAY) {
239
19.6k
        OCGs_array = (pdf_array *)obj;
240
19.6k
    } else if (pdfi_type_of(obj) == PDF_DICT) {
241
30
        OCGs_dict = (pdf_dict *)obj;
242
30
    } else {
243
0
        goto cleanup;
244
0
    }
245
246
19.6k
    code = pdfi_dict_knownget_type(ctx, ocdict, "P", PDF_NAME, &Pname);
247
19.6k
    if (code < 0)
248
0
        goto cleanup;
249
19.6k
    if (code == 0 || pdfi_name_is((pdf_name *)Pname, "AnyOn")) {
250
19.6k
        Ptype = P_AnyOn;
251
19.6k
    } else if (pdfi_name_is((pdf_name *)Pname, "AllOn")) {
252
0
        Ptype = P_AllOn;
253
0
    } else if (pdfi_name_is((pdf_name *)Pname, "AnyOff")) {
254
0
        Ptype = P_AnyOff;
255
0
    } else if (pdfi_name_is((pdf_name *)Pname, "AllOff")) {
256
0
        Ptype = P_AllOff;
257
0
    } else {
258
0
        Ptype = P_AnyOn;
259
0
    }
260
261
19.6k
    if (OCGs_dict) {
262
30
        switch (Ptype) {
263
30
        case P_AnyOn:
264
30
        case P_AllOn:
265
30
            is_visible = pdfi_get_default_OCG_val(ctx, OCGs_dict);
266
30
            break;
267
0
        case P_AllOff:
268
0
        case P_AnyOff:
269
0
            is_visible = !pdfi_get_default_OCG_val(ctx, OCGs_dict);
270
0
            break;
271
30
        }
272
19.6k
    } else {
273
19.6k
        is_visible = pdfi_oc_check_OCMD_array(ctx, OCGs_array, Ptype);
274
19.6k
    }
275
276
19.7k
 cleanup:
277
19.7k
    pdfi_countdown(VE);
278
19.7k
    pdfi_countdown(obj);
279
19.7k
    pdfi_countdown(Pname);
280
281
19.7k
    return is_visible;
282
19.6k
}
283
284
/* Check if an OCG or OCMD is visible, passing in OC dict */
285
bool
286
pdfi_oc_is_ocg_visible(pdf_context *ctx, pdf_dict *ocdict)
287
20.6k
{
288
20.6k
    pdf_name *type = NULL;
289
20.6k
    bool is_visible = true;
290
20.6k
    int code;
291
292
    /* Type can be either OCMD or OCG.
293
     */
294
20.6k
    code = pdfi_dict_knownget_type(ctx, ocdict, "Type", PDF_NAME, (pdf_obj **)&type);
295
20.6k
    if (code <= 0)
296
5
        goto cleanup;
297
298
20.6k
    if (pdfi_name_is(type, "OCMD")) {
299
19.7k
        is_visible = pdfi_oc_check_OCMD(ctx, ocdict);
300
19.7k
    } else if (pdfi_name_is(type, "OCG")) {
301
841
        is_visible = pdfi_get_default_OCG_val(ctx, ocdict);
302
841
        if (is_visible)
303
817
            is_visible = pdfi_oc_check_OCG_usage(ctx, ocdict);
304
841
    } else {
305
26
        char str[100];
306
26
        memcpy(str, (const char *)type->data, type->length < 100 ? type->length : 99);
307
26
        str[type->length < 100 ? type->length : 99] = '\0';
308
26
        dmprintf1(ctx->memory, "WARNING: OC dict type is %s, expected OCG or OCMD\n", str);
309
26
    }
310
311
20.6k
 cleanup:
312
20.6k
    pdfi_countdown(type);
313
314
20.6k
    if (ctx->args.pdfdebug) {
315
0
        dmprintf2(ctx->memory, "OCG: OC Dict %d %s visible\n", ocdict->object_num,
316
0
                  is_visible ? "IS" : "IS NOT");
317
0
    }
318
20.6k
    return is_visible;
319
20.6k
}
320
321
86.7k
#define NUM_CONTENT_LEVELS 100
322
typedef struct {
323
    byte *flags;
324
    uint64_t num_off;
325
    uint64_t max_flags;
326
} pdfi_oc_levels_t;
327
328
static int pdfi_oc_levels_init(pdf_context *ctx, pdfi_oc_levels_t **levels)
329
43.3k
{
330
43.3k
    byte *data;
331
43.3k
    pdfi_oc_levels_t *new;
332
333
43.3k
    *levels = NULL;
334
335
43.3k
    new = (pdfi_oc_levels_t *)gs_alloc_bytes(ctx->memory, sizeof(pdfi_oc_levels_t),
336
43.3k
                                             "pdfi_oc_levels_init (levels)");
337
43.3k
    if (!new)
338
0
        return_error(gs_error_VMerror);
339
340
43.3k
    data = (byte *)gs_alloc_bytes(ctx->memory, NUM_CONTENT_LEVELS, "pdfi_oc_levels_init (data)");
341
43.3k
    if (!data) {
342
0
        gs_free_object(ctx->memory, new, "pdfi_oc_levels_init (levels (error))");
343
0
        return_error(gs_error_VMerror);
344
0
    }
345
43.3k
    memset(data, 0, NUM_CONTENT_LEVELS);
346
347
43.3k
    new->flags = data;
348
43.3k
    new->num_off = 0;
349
43.3k
    new->max_flags = NUM_CONTENT_LEVELS;
350
43.3k
    *levels = new;
351
352
43.3k
    return 0;
353
43.3k
}
354
355
static int pdfi_oc_levels_free(pdf_context *ctx, pdfi_oc_levels_t *levels)
356
59.7k
{
357
59.7k
    if (!levels)
358
16.3k
        return 0;
359
43.3k
    gs_free_object(ctx->memory, levels->flags, "pdfi_oc_levels_free (flags)");
360
43.3k
    gs_free_object(ctx->memory, levels, "pdfi_oc_levels_free (levels)");
361
362
43.3k
    return 0;
363
59.7k
}
364
365
static int pdfi_oc_levels_set(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64_t index)
366
16.5k
{
367
16.5k
    byte *new = NULL;
368
16.5k
    uint64_t newmax;
369
370
16.5k
    if (index > levels->max_flags - 1) {
371
        /* Expand the flags buffer */
372
0
        newmax = levels->max_flags + NUM_CONTENT_LEVELS;
373
0
        if (index > newmax)
374
0
            return_error(gs_error_Fatal); /* shouldn't happen */
375
0
        new = gs_alloc_bytes(ctx->memory, newmax, "pdfi_oc_levels_set (new data)");
376
0
        if (!new)
377
0
            return_error(gs_error_VMerror);
378
0
        memset(new, 0, newmax);
379
0
        memcpy(new, levels->flags, levels->max_flags);
380
0
        gs_free_object(ctx->memory, levels->flags, "pdfi_oc_levels_set (old data)");
381
0
        levels->flags = new;
382
0
        levels->max_flags += NUM_CONTENT_LEVELS;
383
0
    }
384
385
16.5k
    if (levels->flags[index] == 0)
386
16.5k
        levels->num_off ++;
387
16.5k
    levels->flags[index] = 1;
388
16.5k
    return 0;
389
16.5k
}
390
391
static int pdfi_oc_levels_clear(pdf_context *ctx, pdfi_oc_levels_t *levels, uint64_t index)
392
114k
{
393
114k
    if (index > levels->max_flags - 1)
394
0
        return -1;
395
114k
    if (levels->flags[index] != 0)
396
16.4k
        levels->num_off --;
397
114k
    levels->flags[index] = 0;
398
114k
    return 0;
399
114k
}
400
401
402
/* Test if content is turned off for this element.
403
 */
404
bool pdfi_oc_is_off(pdf_context *ctx)
405
4.54M
{
406
4.54M
    pdfi_oc_levels_t *levels = (pdfi_oc_levels_t *)ctx->OFFlevels;
407
4.54M
    uint64_t num_off = levels->num_off;
408
409
4.54M
    return (num_off != 0);
410
4.54M
}
411
412
int pdfi_oc_init(pdf_context *ctx)
413
43.3k
{
414
43.3k
    int code;
415
416
43.3k
    ctx->BMClevel = 0;
417
43.3k
    if (ctx->OFFlevels) {
418
18.9k
        pdfi_oc_levels_free(ctx, ctx->OFFlevels);
419
18.9k
        ctx->OFFlevels = NULL;
420
18.9k
    }
421
43.3k
    code = pdfi_oc_levels_init(ctx, (pdfi_oc_levels_t **)&ctx->OFFlevels);
422
43.3k
    if (code < 0)
423
0
        return code;
424
425
43.3k
    return 0;
426
43.3k
}
427
428
int pdfi_oc_free(pdf_context *ctx)
429
40.8k
{
430
40.8k
    int code;
431
432
40.8k
    code = pdfi_oc_levels_free(ctx, (pdfi_oc_levels_t *)ctx->OFFlevels);
433
40.8k
    ctx->OFFlevels = NULL;
434
40.8k
    return code;
435
40.8k
}
436
437
int pdfi_op_MP(pdf_context *ctx)
438
921
{
439
921
    pdf_obj *o = NULL;
440
921
    int code = 0;
441
442
921
    if (pdfi_count_stack(ctx) < 1)
443
32
        return_error(gs_error_stackunderflow);
444
445
889
    if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent)
446
889
        goto exit;
447
448
0
    o = ctx->stack_top[-1];
449
0
    pdfi_countup(o);
450
0
    pdfi_pop(ctx, 1);
451
452
0
    if (pdfi_type_of(o) != PDF_NAME) {
453
0
        code = gs_note_error(gs_error_typecheck);
454
0
        goto exit;
455
0
    }
456
457
0
    code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "MP");
458
0
    ctx->BMClevel ++;
459
460
889
exit:
461
889
    pdfi_countdown(o);
462
889
    return code;
463
0
}
464
465
int pdfi_op_DP(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
466
754
{
467
754
    pdf_name *properties = NULL;
468
754
    int code = 0;
469
754
    pdf_obj **objarray = NULL, *o = NULL;
470
471
754
    if (pdfi_count_stack(ctx) < 2) {
472
0
        pdfi_clearstack(ctx);
473
0
        return gs_note_error(gs_error_stackunderflow);
474
0
    }
475
476
754
    if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) {
477
754
        pdfi_pop(ctx, 2); /* pop args */
478
754
        goto exit;
479
754
    }
480
481
0
    if (pdfi_type_of(ctx->stack_top[-2]) != PDF_NAME) {
482
0
        pdfi_pop(ctx, 2); /* pop args */
483
0
        code = gs_note_error(gs_error_typecheck);
484
0
        goto exit;
485
0
    }
486
487
0
    objarray = (pdf_obj **)gs_alloc_bytes(ctx->memory, 2 * sizeof(pdf_obj *), "pdfi_op_DP");
488
0
    if (objarray == NULL) {
489
0
        code = gs_note_error(gs_error_VMerror);
490
0
        goto exit;
491
0
    }
492
493
0
    objarray[0] = ctx->stack_top[-2];
494
0
    pdfi_countup(objarray[0]);
495
0
    o = ctx->stack_top[-2];
496
0
    pdfi_countup(o);
497
0
    pdfi_pop(ctx, 2); /* pop args */
498
499
0
    switch (pdfi_type_of(o)) {
500
0
        case PDF_NAME:
501
0
            code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)o, stream_dict, page_dict, (pdf_obj **)&properties);
502
0
            if(code < 0)
503
0
                goto exit;
504
0
            if (pdfi_type_of(properties) != PDF_DICT) {
505
0
                code = gs_note_error(gs_error_typecheck);
506
0
                goto exit;
507
0
            }
508
0
            objarray[1] = (pdf_obj *)properties;
509
0
            break;
510
0
        case PDF_DICT:
511
0
            objarray[1] = o;
512
0
            break;
513
0
        default:
514
0
            code = gs_note_error(gs_error_VMerror);
515
0
            goto exit;
516
0
    }
517
518
0
    code = pdfi_pdfmark_from_objarray(ctx, objarray, 2, NULL, "DP");
519
520
754
 exit:
521
754
    if (objarray != NULL) {
522
0
        pdfi_countdown(objarray[0]);
523
0
        gs_free_object(ctx->memory, objarray, "free pdfi_op_DP");
524
0
    }
525
754
    pdfi_countdown(o);
526
754
    pdfi_countdown(properties);
527
754
    return code;
528
0
}
529
530
/* begin marked content sequence */
531
int pdfi_op_BMC(pdf_context *ctx)
532
6.37k
{
533
6.37k
    pdf_obj *o = NULL;
534
6.37k
    int code = 0;
535
536
    /* This will also prevent us writing out an EMC if the BMC is in any way invalid */
537
6.37k
    ctx->BDCWasOC = true;
538
539
6.37k
    if (pdfi_count_stack(ctx) < 1)
540
0
        return_error(gs_error_stackunderflow);
541
542
6.37k
    if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent) {
543
6.37k
        pdfi_pop(ctx, 1);
544
6.37k
        goto exit;
545
6.37k
    }
546
547
0
    o = ctx->stack_top[-1];
548
0
    pdfi_countup(o);
549
0
    pdfi_pop(ctx, 1);
550
551
0
    if (pdfi_type_of(o) != PDF_NAME) {
552
0
        code = gs_note_error(gs_error_typecheck);
553
0
        goto exit;
554
0
    }
555
556
0
    ctx->BDCWasOC = false;
557
0
    code = pdfi_pdfmark_from_objarray(ctx, &o, 1, NULL, "BMC");
558
0
    ctx->BMClevel ++;
559
560
6.37k
exit:
561
6.37k
    pdfi_countdown(o);
562
6.37k
    return code;
563
0
}
564
565
/* begin marked content sequence with property list */
566
int pdfi_op_BDC(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *page_dict)
567
109k
{
568
109k
    pdf_name *tag = NULL;
569
109k
    pdf_name *properties = NULL;
570
109k
    pdf_dict *oc_dict = NULL;
571
109k
    int code = 0;
572
109k
    bool ocg_is_visible;
573
109k
    pdf_obj **objarray = NULL, *o = NULL;;
574
575
    /* This will also prevent us writing out an EMC if the BDC is in any way invalid */
576
109k
    ctx->BDCWasOC = true;
577
578
109k
    if (pdfi_count_stack(ctx) < 2) {
579
422
        pdfi_clearstack(ctx);
580
422
        return gs_note_error(gs_error_stackunderflow);
581
422
    }
582
583
108k
    ctx->BMClevel ++;
584
585
108k
    tag = (pdf_name *)ctx->stack_top[-2];
586
108k
    pdfi_countup(tag);
587
108k
    o = ctx->stack_top[-1];
588
108k
    pdfi_countup(o);
589
108k
    pdfi_pop(ctx, 2);
590
591
108k
    if (pdfi_type_of(tag) != PDF_NAME)
592
541
        goto exit;
593
594
108k
    if (!pdfi_name_is(tag, "OC")) {
595
63.9k
        ctx->BDCWasOC = false;
596
63.9k
        if (!ctx->device_state.writepdfmarks || !ctx->args.preservemarkedcontent)
597
63.9k
            goto exit;
598
599
0
        objarray = (pdf_obj **)gs_alloc_bytes(ctx->memory, 2 * sizeof(pdf_obj *), "pdfi_op_BDC");
600
0
        if (objarray == NULL) {
601
0
            code = gs_note_error(gs_error_VMerror);
602
0
            goto exit;
603
0
        }
604
605
0
        objarray[0] = (pdf_obj *)tag;
606
607
0
        switch (pdfi_type_of(o)) {
608
0
            case PDF_NAME:
609
0
                code = pdfi_find_resource(ctx, (unsigned char *)"Properties", (pdf_name *)o, stream_dict, page_dict, (pdf_obj **)&oc_dict);
610
0
                if(code < 0)
611
0
                    goto exit;
612
0
                if (pdfi_type_of(oc_dict) != PDF_DICT) {
613
0
                    code = gs_note_error(gs_error_typecheck);
614
0
                    goto exit;
615
0
                }
616
0
                objarray[1] = (pdf_obj *)oc_dict;
617
0
                break;
618
0
            case PDF_DICT:
619
0
                objarray[1] = o;
620
0
                break;
621
0
            default:
622
0
                code = gs_note_error(gs_error_VMerror);
623
0
                goto exit;
624
0
        }
625
626
0
        code = pdfi_pdfmark_from_objarray(ctx, objarray, 2, NULL, "BDC");
627
0
        goto exit;
628
0
    }
629
630
    /* Check if first arg is a name and handle it if so */
631
    /* TODO: spec says it could also be an inline dict that we should be able to handle,
632
     * but I am just matching what gs does for now, and it doesn't handle that case.
633
     */
634
44.4k
    properties = (pdf_name *)o;
635
44.4k
    if (pdfi_type_of(properties) != PDF_NAME)
636
3
        goto exit;
637
638
    /* If it's a name, look it up in Properties */
639
44.4k
    code = pdfi_find_resource(ctx, (unsigned char *)"Properties", properties,
640
44.4k
                              (pdf_dict *)stream_dict, page_dict, (pdf_obj **)&oc_dict);
641
44.4k
    if (code != 0)
642
23.4k
        goto exit;
643
20.9k
    if (pdfi_type_of(oc_dict) != PDF_DICT)
644
283
        goto exit;
645
646
    /* Now we have an OC dict, see if it's visible */
647
20.6k
    ocg_is_visible = pdfi_oc_is_ocg_visible(ctx, oc_dict);
648
20.6k
    if (!ocg_is_visible)
649
16.5k
        code = pdfi_oc_levels_set(ctx, ctx->OFFlevels, ctx->BMClevel);
650
651
108k
 exit:
652
108k
    if (objarray != NULL)
653
0
        gs_free_object(ctx->memory, objarray, "free pdfi_op_BDC");
654
108k
    pdfi_countdown(o);
655
108k
    pdfi_countdown(tag);
656
108k
    pdfi_countdown(oc_dict);
657
108k
    return code;
658
20.6k
}
659
660
/* end marked content sequence */
661
int pdfi_op_EMC(pdf_context *ctx)
662
114k
{
663
114k
    int code, code1 = 0;
664
665
114k
    if (ctx->device_state.writepdfmarks && ctx->args.preservemarkedcontent && !ctx->BDCWasOC)
666
0
        code1 = pdfi_pdfmark_from_objarray(ctx, NULL, 0, NULL, "EMC");
667
668
114k
    code = pdfi_oc_levels_clear(ctx, ctx->OFFlevels, ctx->BMClevel);
669
114k
    if (code == 0)
670
114k
        code = code1;
671
672
    /* TODO: Should we flag error on too many EMC? */
673
114k
    if (ctx->BMClevel > 0)
674
107k
        ctx->BMClevel --;
675
114k
    return code;
676
114k
}