Coverage Report

Created: 2025-11-16 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_array.c
Line
Count
Source
1
/* Copyright (C) 2018-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
/* array handling for the PDF interpreter */
17
18
#include "ghostpdf.h"
19
#include "pdf_types.h"
20
#include "pdf_stack.h"
21
#include "pdf_deref.h"
22
#include "pdf_array.h"
23
#include "pdf_loop_detect.h"
24
25
/* NOTE: I think this should take a pdf_context param, but it's not available where it's
26
 * called, would require some surgery.
27
 */
28
void pdfi_free_array(pdf_obj *o)
29
20.5M
{
30
20.5M
    pdf_array *a = (pdf_array *)o;
31
20.5M
    int i;
32
33
224M
    for (i=0;i < a->size;i++) {
34
203M
        if (a->values[i] != NULL)
35
203M
            pdfi_countdown(a->values[i]);
36
203M
    }
37
20.5M
    gs_free_object(OBJ_MEMORY(a), a->values, "pdf interpreter free array contents");
38
20.5M
    gs_free_object(OBJ_MEMORY(a), a, "pdf interpreter free array");
39
20.5M
}
40
41
int pdfi_array_alloc(pdf_context *ctx, uint64_t size, pdf_array **a)
42
20.4M
{
43
20.4M
    int code, i;
44
45
20.4M
    *a = NULL;
46
20.4M
    code = pdfi_object_alloc(ctx, PDF_ARRAY, size, (pdf_obj **)a);
47
20.4M
    if (code < 0)
48
0
        return code;
49
50
20.4M
    (*a)->size = size;
51
52
20.4M
    if (size > 0) {
53
        /* Start all the array entries pointing to null.
54
         * array_put will replace tehm. This ensures we always have a valid
55
         * object for every entry. pdfi_array_from_stack() doesn't do this
56
         * initialisation because we know how many obejcts there are in the array
57
         * and we have valid objects for each entry on the stack already created.
58
         */
59
218M
        for (i=0;i<size;i++){
60
199M
            (*a)->values[i] = PDF_NULL_OBJ;
61
199M
        }
62
19.2M
    }
63
20.4M
    return 0;
64
20.4M
}
65
66
/* This was defined in pdf_int.c until we moved the equivalent pdfi_dict_from_stack() into
67
 * pdf_dict.c, because we needed to be able to create dictionaries for images. We don't have
68
 * that need, but its less confusing to have the array_from_stack function defined in
69
 * here, similarly to the dictionary routine.
70
 */
71
int pdfi_array_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen)
72
20.4M
{
73
20.4M
    uint64_t index = 0;
74
20.4M
    pdf_array *a = NULL;
75
20.4M
    pdf_obj *o;
76
20.4M
    int code;
77
78
20.4M
    code = pdfi_count_to_mark(ctx, &index);
79
20.4M
    if (code < 0)
80
279k
        return code;
81
82
20.2M
    code = pdfi_array_alloc(ctx, index, &a);
83
20.2M
    if (code < 0)
84
0
        return code;
85
86
167M
    while (index) {
87
147M
        o = ctx->stack_top[-1];
88
147M
        code = pdfi_array_put(ctx, a, --index, o);
89
147M
        if (code < 0) {
90
0
            (void)pdfi_clear_to_mark(ctx);
91
0
            return code;
92
0
        }
93
147M
        pdfi_pop(ctx, 1);
94
147M
    }
95
96
20.2M
    code = pdfi_clear_to_mark(ctx);
97
20.2M
    if (code < 0)
98
0
        return code;
99
100
20.2M
    if (ctx->args.pdfdebug)
101
0
        outprintf (ctx->memory, " ]\n");
102
103
20.2M
    a->indirect_num = indirect_num;
104
20.2M
    a->indirect_gen = indirect_gen;
105
106
20.2M
    code = pdfi_push(ctx, (pdf_obj *)a);
107
20.2M
    if (code < 0)
108
0
        pdfi_free_array((pdf_obj *)a);
109
110
20.2M
    return code;
111
20.2M
}
112
113
int pdfi_array_fetch_recursing(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache)
114
961k
{
115
961k
    int code;
116
961k
    pdf_obj *obj;
117
118
961k
    *o = NULL;
119
120
961k
    if (pdfi_type_of(a) != PDF_ARRAY)
121
0
        return_error(gs_error_typecheck);
122
123
961k
    if (index >= a->size)
124
0
        return_error(gs_error_rangecheck);
125
961k
    obj = a->values[index];
126
127
961k
    if (pdfi_type_of(obj) == PDF_INDIRECT) {
128
2.04k
        pdf_obj *o1 = NULL;
129
2.04k
        pdf_indirect_ref *r = (pdf_indirect_ref *)obj;
130
131
2.04k
        if (r->ref_object_num == a->object_num)
132
10
            return_error(gs_error_circular_reference);
133
134
2.03k
        if (cache)
135
2.03k
            code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, &o1);
136
0
        else
137
0
            code = pdfi_deref_loop_detect_nocache(ctx, r->ref_object_num, r->ref_generation_num, &o1);
138
2.03k
        if (code < 0)
139
389
            return code;
140
141
1.64k
        if (setref)
142
1.64k
            (void)pdfi_array_put(ctx, a, index, o1);
143
1.64k
        obj = o1;
144
959k
    } else {
145
959k
        if (ctx->loop_detection != NULL && (uintptr_t)obj > TOKEN__LAST_KEY && obj->object_num != 0)
146
995
            if (pdfi_loop_detector_check_object(ctx, obj->object_num))
147
2
                return gs_note_error(gs_error_circular_reference);
148
959k
        pdfi_countup(obj);
149
959k
    }
150
151
961k
    *o = obj;
152
961k
    return 0;
153
961k
}
154
155
/* Fetch object from array, resolving indirect reference if needed
156
 * setref -- indicates whether to replace indirect ref with the object
157
 */
158
int pdfi_array_fetch(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o, bool setref, bool cache)
159
475M
{
160
475M
    int code;
161
475M
    pdf_obj *obj;
162
163
475M
    *o = NULL;
164
165
475M
    if (pdfi_type_of(a) != PDF_ARRAY)
166
2.87k
        return_error(gs_error_typecheck);
167
168
475M
    if (index >= a->size)
169
15.0k
        return_error(gs_error_rangecheck);
170
475M
    obj = a->values[index];
171
172
475M
    if (pdfi_type_of(obj) == PDF_INDIRECT) {
173
1.57M
        pdf_obj *o1 = NULL;
174
1.57M
        pdf_indirect_ref *r = (pdf_indirect_ref *)obj;
175
176
1.57M
        if (r->ref_object_num == a->object_num)
177
172
            return_error(gs_error_circular_reference);
178
179
1.57M
        if (cache)
180
1.51M
            code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, &o1);
181
65.2k
        else
182
65.2k
            code = pdfi_deref_loop_detect_nocache(ctx, r->ref_object_num, r->ref_generation_num, &o1);
183
1.57M
        if (code < 0)
184
658k
            return code;
185
186
917k
        if (setref)
187
903k
            (void)pdfi_array_put(ctx, a, index, o1);
188
917k
        obj = o1;
189
473M
    } else {
190
473M
        pdfi_countup(obj);
191
473M
    }
192
193
474M
    *o = obj;
194
474M
    return 0;
195
475M
}
196
197
/* Get element from array without resolving PDF_INDIRECT dereferences.
198
 * It looks to me like some usages need to do the checking themselves to
199
 * avoid circular references?  Can remove this if not really needed.
200
 */
201
int pdfi_array_get_no_deref(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
202
1.87M
{
203
1.87M
    if (pdfi_type_of(a) != PDF_ARRAY)
204
0
        return_error(gs_error_typecheck);
205
206
1.87M
    if (index >= a->size)
207
0
        return_error(gs_error_rangecheck);
208
209
1.87M
    *o = a->values[index];
210
1.87M
    pdfi_countup(*o);
211
1.87M
    return 0;
212
1.87M
}
213
214
/* Same as pdfi_array_get() but doesn't replace indirect ref with a new object.
215
 */
216
int pdfi_array_get_no_store_R(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj **o)
217
1.23M
{
218
1.23M
    int code;
219
220
1.23M
    code = pdfi_array_fetch(ctx, a, index, o, false, false);
221
1.23M
    if (code < 0) return code;
222
223
1.23M
    return 0;
224
1.23M
}
225
226
/* Get value from pdfi_array.
227
 * Handles type-checking and resolving indirect references.
228
 */
229
int pdfi_array_get_type(pdf_context *ctx, pdf_array *a, uint64_t index,
230
                    pdf_obj_type type, pdf_obj **o)
231
135M
{
232
135M
    int code;
233
234
135M
    code = pdfi_array_get(ctx, a, index, o);
235
135M
    if (code < 0)
236
280k
        return code;
237
238
134M
    if (pdfi_type_of(*o) != type) {
239
31.6k
        pdfi_countdown(*o);
240
31.6k
        *o = NULL;
241
31.6k
        return_error(gs_error_typecheck);
242
31.6k
    }
243
134M
    return 0;
244
134M
}
245
246
int pdfi_array_get_int(pdf_context *ctx, pdf_array *a, uint64_t index, int64_t *i)
247
96.2k
{
248
96.2k
    int code;
249
96.2k
    pdf_obj *n;
250
251
96.2k
    code = pdfi_array_get(ctx, a, index, &n);
252
96.2k
    if (code < 0)
253
80
        return code;
254
96.1k
    code = pdfi_obj_to_int(ctx, n, i);
255
96.1k
    pdfi_countdown(n);
256
96.1k
    return code;
257
96.2k
}
258
259
int pdfi_array_get_number(pdf_context *ctx, pdf_array *a, uint64_t index, double *d)
260
30.4M
{
261
30.4M
    int code;
262
30.4M
    pdf_obj *n;
263
264
30.4M
    code = pdfi_array_get(ctx, a, index, &n);
265
30.4M
    if (code < 0)
266
76
        return code;
267
268
30.4M
    code = pdfi_obj_to_real(ctx, n, d);
269
30.4M
    pdfi_countdown(n);
270
271
30.4M
    return code;
272
30.4M
}
273
274
/* Check whether a particular object is in an array.
275
 * If index is not NULL, fill it in with the index of the object.
276
 * Note that this will resolve indirect references if needed.
277
 */
278
bool pdfi_array_known(pdf_context *ctx, pdf_array *a, pdf_obj *o, int *index)
279
84.6k
{
280
84.6k
    int i;
281
282
84.6k
    if (pdfi_type_of(a) != PDF_ARRAY)
283
0
        return_error(gs_error_typecheck);
284
285
37.5M
    for (i=0; i < a->size; i++) {
286
37.5M
        pdf_obj *val;
287
37.5M
        int code;
288
289
37.5M
        code = pdfi_array_fetch(ctx, a, i, &val, true, true);
290
37.5M
        if (code < 0)
291
346k
            continue;
292
37.1M
        if (pdf_object_num(val) == pdf_object_num(o)) {
293
81.7k
            if (index != NULL) *index = i;
294
81.7k
            pdfi_countdown(val);
295
81.7k
            return true;
296
81.7k
        }
297
37.1M
        pdfi_countdown(val);
298
37.1M
    }
299
2.86k
    return false;
300
84.6k
}
301
302
int pdfi_array_put(pdf_context *ctx, pdf_array *a, uint64_t index, pdf_obj *o)
303
207M
{
304
207M
    if (pdfi_type_of(a) != PDF_ARRAY)
305
0
        return_error(gs_error_typecheck);
306
307
207M
    if (index >= a->size)
308
0
        return_error(gs_error_rangecheck);
309
310
207M
    pdfi_countdown(a->values[index]);
311
207M
    a->values[index] = o;
312
207M
    pdfi_countup(o);
313
207M
    return 0;
314
207M
}
315
316
int pdfi_array_put_int(pdf_context *ctx, pdf_array *a, uint64_t index, int64_t val)
317
12
{
318
12
    int code;
319
12
    pdf_num *obj;
320
321
12
    if (pdfi_type_of(a) != PDF_ARRAY)
322
0
        return_error(gs_error_typecheck);
323
324
12
    code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&obj);
325
12
    if (code < 0)
326
0
        return code;
327
12
    obj->value.i = val;
328
329
12
    return pdfi_array_put(ctx, a, index, (pdf_obj *)obj);
330
12
}
331
332
int pdfi_array_put_real(pdf_context *ctx, pdf_array *a, uint64_t index, double val)
333
14.4k
{
334
14.4k
    int code;
335
14.4k
    pdf_num *obj;
336
337
14.4k
    if (pdfi_type_of(a) != PDF_ARRAY)
338
0
        return_error(gs_error_typecheck);
339
340
14.4k
    code = pdfi_object_alloc(ctx, PDF_REAL, 0, (pdf_obj **)&obj);
341
14.4k
    if (code < 0)
342
0
        return code;
343
14.4k
    obj->value.d = val;
344
345
14.4k
    return pdfi_array_put(ctx, a, index, (pdf_obj *)obj);
346
14.4k
}
347
348
/* Strictly speaking the normalize_rect isn't really part of the PDF array
349
 * processing, but its very likely that any time we want to use it, the
350
 * rectangle will have come from a PDF array in a PDF file so it makes
351
 * sense to have it here.
352
 */
353
354
/* Normalize rectangle */
355
void pdfi_normalize_rect(pdf_context *ctx, gs_rect *rect)
356
394k
{
357
394k
    double temp;
358
359
    /* Normalize the rectangle */
360
394k
    if (rect->p.x > rect->q.x) {
361
1.92k
        temp = rect->p.x;
362
1.92k
        rect->p.x = rect->q.x;
363
1.92k
        rect->q.x = temp;
364
1.92k
    }
365
394k
    if (rect->p.y > rect->q.y) {
366
369
        temp = rect->p.y;
367
369
        rect->p.y = rect->q.y;
368
369
        rect->q.y = temp;
369
369
    }
370
394k
}
371
372
/*
373
 * Turn an Array into a gs_rect.  If Array is NULL, makes a tiny rect
374
 */
375
int pdfi_array_to_gs_rect(pdf_context *ctx, pdf_array *array, gs_rect *rect)
376
1.00M
{
377
1.00M
    double number;
378
1.00M
    int code = 0;
379
380
    /* Init to tiny rect to allow sane continuation on errors */
381
1.00M
    rect->p.x = 0.0;
382
1.00M
    rect->p.y = 0.0;
383
1.00M
    rect->q.x = 1.0;
384
1.00M
    rect->q.y = 1.0;
385
386
    /* Identity matrix if no array */
387
1.00M
    if (array == NULL || pdfi_type_of(array) != PDF_ARRAY) {
388
5.23k
        return 0;
389
5.23k
    }
390
995k
    if (pdfi_array_size(array) != 4) {
391
487
        return_error(gs_error_rangecheck);
392
487
    }
393
994k
    code = pdfi_array_get_number(ctx, array, 0, &number);
394
994k
    if (code < 0) goto errorExit;
395
994k
    rect->p.x = (float)number;
396
994k
    code = pdfi_array_get_number(ctx, array, 1, &number);
397
994k
    if (code < 0) goto errorExit;
398
994k
    rect->p.y = (float)number;
399
994k
    code = pdfi_array_get_number(ctx, array, 2, &number);
400
994k
    if (code < 0) goto errorExit;
401
994k
    rect->q.x = (float)number;
402
994k
    code = pdfi_array_get_number(ctx, array, 3, &number);
403
994k
    if (code < 0) goto errorExit;
404
994k
    rect->q.y = (float)number;
405
406
994k
    return 0;
407
408
130
 errorExit:
409
130
    return code;
410
994k
}
411
412
/* Create a new PDF array object with 4 entires, and store the values from a
413
 * gs_rect to it.
414
 */
415
int pdfi_gs_rect_to_array(pdf_context *ctx, gs_rect *rect, pdf_array **new_array)
416
9.70k
{
417
9.70k
    pdf_num *num = NULL;
418
9.70k
    int code = 0;
419
420
9.70k
    code = pdfi_array_alloc(ctx, 4, new_array);
421
9.70k
    if (code < 0)
422
0
        return code;
423
424
9.70k
    pdfi_countup(*new_array);
425
426
9.70k
    code = pdfi_num_alloc(ctx, rect->p.x, &num);
427
9.70k
    if (code < 0)
428
0
        goto error;
429
430
9.70k
    code = pdfi_array_put(ctx, *new_array, 0, (pdf_obj *)num);
431
9.70k
    if (code < 0)
432
0
        goto error;
433
434
9.70k
    code = pdfi_num_alloc(ctx, rect->p.y, &num);
435
9.70k
    if (code < 0)
436
0
        goto error;
437
438
9.70k
    code = pdfi_array_put(ctx, *new_array, 1, (pdf_obj *)num);
439
9.70k
    if (code < 0)
440
0
        goto error;
441
442
9.70k
    code = pdfi_num_alloc(ctx, rect->q.x, &num);
443
9.70k
    if (code < 0)
444
0
        goto error;
445
446
9.70k
    code = pdfi_array_put(ctx, *new_array, 2, (pdf_obj *)num);
447
9.70k
    if (code < 0)
448
0
        goto error;
449
450
9.70k
    code = pdfi_num_alloc(ctx, rect->q.y, &num);
451
9.70k
    if (code < 0)
452
0
        goto error;
453
454
9.70k
    code = pdfi_array_put(ctx, *new_array, 3, (pdf_obj *)num);
455
9.70k
    if (code < 0)
456
0
        goto error;
457
458
9.70k
    return 0;
459
460
0
error:
461
0
    pdfi_countdown(new_array);
462
0
    return code;
463
9.70k
}
464
465
/* Turn a /Matrix Array into a gs_matrix.  If Array is NULL, makes an identity matrix */
466
int pdfi_array_to_gs_matrix(pdf_context *ctx, pdf_array *array, gs_matrix *mat)
467
628k
{
468
628k
    double number;
469
628k
    int code = 0;
470
471
    /* Init to identity matrix to allow sane continuation on errors */
472
628k
    mat->xx = 1.0;
473
628k
    mat->xy = 0.0;
474
628k
    mat->yx = 0.0;
475
628k
    mat->yy = 1.0;
476
628k
    mat->tx = 0.0;
477
628k
    mat->ty = 0.0;
478
479
    /* Identity matrix if no array */
480
628k
    if (array == NULL || pdfi_type_of(array) != PDF_ARRAY) {
481
407k
        return 0;
482
407k
    }
483
220k
    if (pdfi_array_size(array) != 6) {
484
231
        return_error(gs_error_rangecheck);
485
231
    }
486
220k
    code = pdfi_array_get_number(ctx, array, 0, &number);
487
220k
    if (code < 0) goto errorExit;
488
220k
    mat->xx = (float)number;
489
220k
    code = pdfi_array_get_number(ctx, array, 1, &number);
490
220k
    if (code < 0) goto errorExit;
491
220k
    mat->xy = (float)number;
492
220k
    code = pdfi_array_get_number(ctx, array, 2, &number);
493
220k
    if (code < 0) goto errorExit;
494
220k
    mat->yx = (float)number;
495
220k
    code = pdfi_array_get_number(ctx, array, 3, &number);
496
220k
    if (code < 0) goto errorExit;
497
220k
    mat->yy = (float)number;
498
220k
    code = pdfi_array_get_number(ctx, array, 4, &number);
499
220k
    if (code < 0) goto errorExit;
500
220k
    mat->tx = (float)number;
501
220k
    code = pdfi_array_get_number(ctx, array, 5, &number);
502
220k
    if (code < 0) goto errorExit;
503
220k
    mat->ty = (float)number;
504
220k
    return 0;
505
506
42
 errorExit:
507
42
    return code;
508
220k
}
509
510
/* Turn a pdf_array into a double array of specified size */
511
int pdfi_array_to_num_array(pdf_context *ctx, pdf_array *array, double *out, int offset, int size)
512
22.7k
{
513
22.7k
    int i;
514
22.7k
    int code;
515
22.7k
    double num;
516
517
160k
    for (i=0; i<size; i++) {
518
138k
        code = pdfi_array_get_number(ctx, array, offset+i, &num);
519
138k
        if (code < 0)
520
109
            return code;
521
137k
        out[i] = num;
522
137k
    }
523
22.6k
    return 0;
524
22.7k
}
525
526
/* Transform a BBox by a matrix (from zmatrix.c/zbbox_transform())*/
527
void
528
pdfi_bbox_transform(pdf_context *ctx, gs_rect *bbox, gs_matrix *matrix)
529
235k
{
530
235k
    gs_point aa, az, za, zz;
531
235k
    double temp;
532
533
235k
    gs_point_transform(bbox->p.x, bbox->p.y, matrix, &aa);
534
235k
    gs_point_transform(bbox->p.x, bbox->q.y, matrix, &az);
535
235k
    gs_point_transform(bbox->q.x, bbox->p.y, matrix, &za);
536
235k
    gs_point_transform(bbox->q.x, bbox->q.y, matrix, &zz);
537
538
235k
    if ( aa.x > az.x)
539
1.63k
        temp = aa.x, aa.x = az.x, az.x = temp;
540
235k
    if ( za.x > zz.x)
541
1.63k
        temp = za.x, za.x = zz.x, zz.x = temp;
542
235k
    if ( za.x < aa.x)
543
81
        aa.x = za.x;  /* min */
544
235k
    if ( az.x > zz.x)
545
81
        zz.x = az.x;  /* max */
546
547
235k
    if ( aa.y > az.y)
548
4.96k
        temp = aa.y, aa.y = az.y, az.y = temp;
549
235k
    if ( za.y > zz.y)
550
4.96k
        temp = za.y, za.y = zz.y, zz.y = temp;
551
235k
    if ( za.y < aa.y)
552
95
        aa.y = za.y;  /* min */
553
235k
    if ( az.y > zz.y)
554
95
        zz.y = az.y;  /* max */
555
556
235k
    bbox->p.x = aa.x;
557
235k
    bbox->p.y = aa.y;
558
235k
    bbox->q.x = zz.x;
559
235k
    bbox->q.y = zz.y;
560
235k
}