Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_misc.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* Miscellaneous 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 "gspath.h"             /* For gs_strokepath() */
24
#include "gspaint.h"            /* For gs_erasepage() */
25
#include "gsicc_manage.h"       /* For gsicc_get_default_type() */
26
#include "gsstate.h"            /* for gs_setrenderingintent() */
27
28
/* Get current bbox, possibly from stroking current path (utility function) */
29
int pdfi_get_current_bbox(pdf_context *ctx, gs_rect *bbox, bool stroked)
30
17.1k
{
31
17.1k
    int code, code1;
32
33
17.1k
    if (stroked) {
34
887
        code = pdfi_gsave(ctx);
35
887
        if (code < 0)
36
0
            return code;
37
887
        code = gs_strokepath(ctx->pgs);
38
887
        if (code < 0)
39
0
            goto exit;
40
887
    }
41
17.1k
    code = gs_upathbbox(ctx->pgs, bbox, false);
42
43
17.1k
 exit:
44
17.1k
    if (stroked) {
45
887
        code1 = pdfi_grestore(ctx);
46
887
        if (code == 0)
47
239
            code = code1;
48
887
    }
49
17.1k
    return code;
50
17.1k
}
51
52
/* Get the current color space (the base one) from a color space
53
 */
54
gs_color_space_index pdfi_get_color_space_index(pdf_context *ctx, const gs_color_space *pcs)
55
144k
{
56
144k
    gs_color_space_index csi;
57
58
    /* Get the color space index */
59
144k
    csi = gs_color_space_get_index(pcs);
60
61
    /* If its an Indexed space, then use the base space */
62
144k
    if (csi == gs_color_space_index_Indexed)
63
104
        csi = gs_color_space_get_index(pcs->base_space);
64
65
    /* If its ICC, see if its a substitution for one of the device
66
     * spaces. If so then we will want to behave as if we were using the
67
     * device space.
68
     */
69
144k
    if (csi == gs_color_space_index_ICC && pcs->cmm_icc_profile_data)
70
141k
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
71
72
144k
    return csi;
73
144k
}
74
75
/* Get the current color space (the base one) from current graphics state.
76
 * index -- tells whether to pull from 0 or 1 (probably 0)
77
 */
78
gs_color_space_index pdfi_currentcolorspace(pdf_context *ctx, int index)
79
144k
{
80
144k
    const gs_color_space *pcs;
81
82
144k
    pcs = ctx->pgs->color[index].color_space;
83
84
144k
    return pdfi_get_color_space_index(ctx, pcs);
85
144k
}
86
87
88
int
89
pdfi_name_strcmp(const pdf_name *n, const char *s)
90
33.3k
{
91
33.3k
    int len = strlen(s);
92
33.3k
    if (n->length == len)
93
33.0k
        return memcmp(n->data, s, len);
94
348
    return -1;
95
33.3k
}
96
97
bool
98
pdfi_string_is(const pdf_string *n, const char *s)
99
1
{
100
1
    int len = strlen(s);
101
1
    if (n->length == len)
102
1
        return (memcmp(n->data, s, len) == 0);
103
0
    return false;
104
1
}
105
106
bool
107
pdfi_name_is(const pdf_name *n, const char *s)
108
19.1G
{
109
19.1G
    int len = strlen(s);
110
19.1G
    if (n->length == len)
111
3.09G
        return (memcmp(n->data, s, len) == 0);
112
16.0G
    return false;
113
19.1G
}
114
115
bool
116
pdfi_name_or_string_is(const pdf_obj *n, char *s)
117
0
{
118
0
    if (pdfi_type_of(n) == PDF_NAME)
119
0
        return(pdfi_name_is((const pdf_name *)n, s));
120
0
    if (pdfi_type_of(n) == PDF_STRING)
121
0
        return(pdfi_string_is((const pdf_string *)n, s));
122
0
    return false;
123
0
}
124
125
int
126
pdfi_name_cmp(const pdf_name *n1, const pdf_name *n2)
127
92.5k
{
128
92.5k
    if (n1->length != n2->length)
129
942
        return -1;
130
91.6k
    return memcmp(n1->data, n2->data, n1->length);
131
92.5k
}
132
133
int
134
pdfi_string_cmp(const pdf_string *n1, const pdf_string *n2)
135
0
{
136
0
    if (n1->length != n2->length)
137
0
        return -1;
138
0
    return memcmp(n1->data, n2->data, n1->length);
139
0
}
140
141
/* Set rendering intent, translating from name to number */
142
int pdfi_setrenderingintent(pdf_context *ctx, pdf_name *n)
143
80.1k
{
144
80.1k
    int code = 0;
145
146
80.1k
    if (pdfi_name_is(n, "Perceptual")) {
147
65.0k
        code = gs_setrenderingintent(ctx->pgs, 0);
148
65.0k
    } else if (pdfi_name_is(n, "Saturation")) {
149
0
        code = gs_setrenderingintent(ctx->pgs, 2);
150
15.1k
    } else if (pdfi_name_is(n, "RelativeColorimetric")) {
151
14.4k
        code = gs_setrenderingintent(ctx->pgs, 1);
152
14.4k
    } else if (pdfi_name_is(n, "AbsoluteColorimetric")) {
153
0
        code = gs_setrenderingintent(ctx->pgs, 3);
154
688
    } else {
155
        /* PDF 1.7 Reference, bottom of page 260 if a PDF uses an unknown rendering intent
156
         * then use RelativeColoimetric. But flag a warning.
157
         */
158
688
        pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_RENDERINGINTENT, "pdfi_setrenderingintent", "");
159
688
        code = gs_setrenderingintent(ctx->pgs, 1);
160
688
    }
161
80.1k
    return code;
162
80.1k
}
163
164
int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len)
165
611k
{
166
611k
    if (pdfi_type_of(n) != PDF_NAME)
167
0
        return gs_note_error(gs_error_typecheck);
168
169
611k
    *str = NULL;
170
611k
    *len = 0;
171
172
611k
    *str = (char *)gs_alloc_bytes(ctx->memory, (size_t)n->length + 1, "pdfi_string_from_name");
173
611k
    if (*str == NULL)
174
0
        return gs_note_error(gs_error_VMerror);
175
176
611k
    memcpy(*str, n->data, n->length);
177
611k
    (*str)[n->length] = 0x00;
178
611k
    *len = n->length;
179
180
611k
    return 0;
181
611k
}
182
183
int pdfi_free_string_from_name(pdf_context *ctx, char *str)
184
733k
{
185
733k
    if (str != NULL)
186
611k
        gs_free_object(ctx->memory, str, "pdfi_free_string_from_name");
187
733k
    return 0;
188
733k
}
189
190
void normalize_rectangle(double *d)
191
98.1k
{
192
98.1k
    double d1[4];
193
98.1k
    int i;
194
195
98.1k
    if (d[0] < d[2]) {
196
98.1k
        d1[0] = d[0];
197
98.1k
        d1[2] = d[2];
198
98.1k
    } else {
199
41
        d1[0] = d[2];
200
41
        d1[2] = d[0];
201
41
    }
202
98.1k
    if (d[1] < d[3]) {
203
98.1k
        d1[1] = d[1];
204
98.1k
        d1[3] = d[3];
205
98.1k
    } else {
206
32
        d1[1] = d[3];
207
32
        d1[3] = d[1];
208
32
    }
209
490k
    for (i=0;i<=3;i++){
210
392k
        d[i] = d1[i];
211
392k
    }
212
98.1k
}
213
214
/* Free an array of cstrings, sets the pointer to null */
215
void pdfi_free_cstring_array(pdf_context *ctx, char ***pstrlist)
216
211k
{
217
211k
    char **ptr = *pstrlist;
218
219
211k
    if (ptr == NULL)
220
211k
        return;
221
222
0
    while (*ptr) {
223
0
        gs_free_object(ctx->memory, *ptr, "pdfi_free_cstring_array(item)");
224
0
        ptr ++;
225
0
    }
226
0
    gs_free_object(ctx->memory, *pstrlist, "pdfi_free_cstring_array(array)");
227
0
    *pstrlist = NULL;
228
0
}
229
230
/* Parse an argument string of names into an array of cstrings */
231
/* Format: /Item1,/Item2,/Item3 (no white space) */
232
int pdfi_parse_name_cstring_array(pdf_context *ctx, char *data, uint64_t size, char ***pstrlist)
233
0
{
234
0
    char **strlist = NULL;
235
0
    char **templist = NULL;
236
0
    int numitems = 0, item;
237
0
    int strnum;
238
0
    uint64_t i;
239
0
    char *strptr;
240
0
    int code = 0;
241
242
    /* Free it if it already exists */
243
0
    if (*pstrlist != NULL)
244
0
        pdfi_free_cstring_array(ctx, pstrlist);
245
246
    /* find out how many '/' characters there are -- this is the max possible number
247
     * of items in the list
248
     */
249
0
    for (i=0, strptr = data; i<size; i++,strptr++) {
250
0
        if (*strptr == '/')
251
0
            numitems ++;
252
        /* early exit if we hit a null */
253
0
        if (*strptr == 0)
254
0
            break;
255
0
    }
256
257
    /* Allocate space for the array of char * (plus one extra for null termination) */
258
0
    strlist = (char **)gs_alloc_bytes(ctx->memory, ((size_t)numitems+1)*sizeof(char *),
259
0
                                       "pdfi_parse_cstring_array(strlist)");
260
0
    if (strlist == NULL)
261
0
        return_error(gs_error_VMerror);
262
263
0
    memset(strlist, 0, (numitems+1)*sizeof(char *));
264
265
    /* Allocate a temp array */
266
0
    templist = (char **)gs_alloc_bytes(ctx->memory, ((size_t)numitems+1)*sizeof(char *),
267
0
                                       "pdfi_parse_cstring_array(templist)");
268
0
    if (templist == NULL) {
269
0
        code = gs_note_error(gs_error_VMerror);
270
0
        goto exit;
271
0
    }
272
273
0
    memset(templist, 0, (numitems+1)*sizeof(char *));
274
275
    /* Find start ptr of each string */
276
0
    item = 0;
277
0
    for (i=0, strptr = data; i<size; i++,strptr++) {
278
0
        if (*strptr == '/') {
279
0
            templist[item] = strptr+1;
280
0
            item++;
281
0
        }
282
0
    }
283
284
    /* Find each substring, alloc, copy into string array */
285
0
    strnum = 0;
286
0
    for (i=0; i<numitems; i++) {
287
0
        char *curstr, *nextstr;
288
0
        int length;
289
0
        char *newstr;
290
291
0
        curstr = templist[i];
292
0
        nextstr = templist[i+1];
293
0
        if (!curstr)
294
0
            break;
295
0
        if (*curstr == '/' || *curstr == ',') {
296
            /* Empty string, skip it */
297
0
            continue;
298
0
        }
299
0
        if (nextstr == NULL) {
300
0
            length = size-(curstr-data);
301
0
        } else {
302
0
            length = nextstr - curstr - 1;
303
0
        }
304
0
        if (curstr[length-1] == ',')
305
0
            length --;
306
307
        /* Allocate the string and copy it */
308
0
        newstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)length+1,
309
0
                                       "pdfi_parse_cstring_array(newstr)");
310
0
        if (newstr == NULL) {
311
0
            code = gs_note_error(gs_error_VMerror);
312
0
            goto exit;
313
0
        }
314
0
        memcpy(newstr, curstr, length);
315
0
        newstr[length+1] = 0; /* Null terminate */
316
0
        strlist[strnum] = newstr;
317
0
        strnum ++;
318
0
    }
319
320
0
    *pstrlist = strlist;
321
322
0
 exit:
323
0
    if (code < 0)
324
0
        pdfi_free_cstring_array(ctx, &strlist);
325
0
    if (templist)
326
        gs_free_object(ctx->memory, templist, "pdfi_parse_cstring_array(templist(array))");
327
0
    return code;
328
0
}