Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/pdf/pdf_misc.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-2023 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
23.6k
{
31
23.6k
    int code, code1;
32
33
23.6k
    if (stroked) {
34
1.72k
        code = pdfi_gsave(ctx);
35
1.72k
        if (code < 0)
36
0
            return code;
37
1.72k
        code = gs_strokepath(ctx->pgs);
38
1.72k
        if (code < 0)
39
0
            goto exit;
40
1.72k
    }
41
23.6k
    code = gs_upathbbox(ctx->pgs, bbox, false);
42
43
23.6k
 exit:
44
23.6k
    if (stroked) {
45
1.72k
        code1 = pdfi_grestore(ctx);
46
1.72k
        if (code == 0)
47
528
            code = code1;
48
1.72k
    }
49
23.6k
    return code;
50
23.6k
}
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
235k
{
56
235k
    gs_color_space_index csi;
57
58
    /* Get the color space index */
59
235k
    csi = gs_color_space_get_index(pcs);
60
61
    /* If its an Indexed space, then use the base space */
62
235k
    if (csi == gs_color_space_index_Indexed)
63
197
        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
235k
    if (csi == gs_color_space_index_ICC && pcs->cmm_icc_profile_data)
70
230k
        csi = gsicc_get_default_type(pcs->cmm_icc_profile_data);
71
72
235k
    return csi;
73
235k
}
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
235k
{
80
235k
    const gs_color_space *pcs;
81
82
235k
    pcs = ctx->pgs->color[index].color_space;
83
84
235k
    return pdfi_get_color_space_index(ctx, pcs);
85
235k
}
86
87
88
int
89
pdfi_name_strcmp(const pdf_name *n, const char *s)
90
35.6k
{
91
35.6k
    int len = strlen(s);
92
35.6k
    if (n->length == len)
93
35.3k
        return memcmp(n->data, s, len);
94
351
    return -1;
95
35.6k
}
96
97
bool
98
pdfi_string_is(const pdf_string *n, const char *s)
99
0
{
100
0
    int len = strlen(s);
101
0
    if (n->length == len)
102
0
        return (memcmp(n->data, s, len) == 0);
103
0
    return false;
104
0
}
105
106
bool
107
pdfi_name_is(const pdf_name *n, const char *s)
108
20.2G
{
109
20.2G
    int len = strlen(s);
110
20.2G
    if (n->length == len)
111
3.12G
        return (memcmp(n->data, s, len) == 0);
112
17.0G
    return false;
113
20.2G
}
114
115
int
116
pdfi_name_cmp(const pdf_name *n1, const pdf_name *n2)
117
164k
{
118
164k
    if (n1->length != n2->length)
119
784
        return -1;
120
163k
    return memcmp(n1->data, n2->data, n1->length);
121
164k
}
122
123
int
124
pdfi_string_cmp(const pdf_string *n1, const pdf_string *n2)
125
0
{
126
0
    if (n1->length != n2->length)
127
0
        return -1;
128
0
    return memcmp(n1->data, n2->data, n1->length);
129
0
}
130
131
/* Set rendering intent, translating from name to number */
132
int pdfi_setrenderingintent(pdf_context *ctx, pdf_name *n)
133
147k
{
134
147k
    int code = 0;
135
136
147k
    if (pdfi_name_is(n, "Perceptual")) {
137
128k
        code = gs_setrenderingintent(ctx->pgs, 0);
138
128k
    } else if (pdfi_name_is(n, "Saturation")) {
139
0
        code = gs_setrenderingintent(ctx->pgs, 2);
140
19.2k
    } else if (pdfi_name_is(n, "RelativeColorimetric")) {
141
18.1k
        code = gs_setrenderingintent(ctx->pgs, 1);
142
18.1k
    } else if (pdfi_name_is(n, "AbsoluteColorimetric")) {
143
0
        code = gs_setrenderingintent(ctx->pgs, 3);
144
1.14k
    } else {
145
        /* PDF 1.7 Reference, bottom of page 260 if a PDF uses an unknown rendering intent
146
         * then use RelativeColoimetric. But flag a warning.
147
         */
148
1.14k
        pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_RENDERINGINTENT, "pdfi_setrenderingintent", "");
149
1.14k
        code = gs_setrenderingintent(ctx->pgs, 1);
150
1.14k
    }
151
147k
    return code;
152
147k
}
153
154
int pdfi_string_from_name(pdf_context *ctx, pdf_name *n, char **str, int *len)
155
638k
{
156
638k
    if (pdfi_type_of(n) != PDF_NAME)
157
0
        return gs_note_error(gs_error_typecheck);
158
159
638k
    *str = NULL;
160
638k
    *len = 0;
161
162
638k
    *str = (char *)gs_alloc_bytes(ctx->memory, n->length + 1, "pdfi_string_from_name");
163
638k
    if (*str == NULL)
164
0
        return gs_note_error(gs_error_VMerror);
165
166
638k
    memcpy(*str, n->data, n->length);
167
638k
    (*str)[n->length] = 0x00;
168
638k
    *len = n->length;
169
170
638k
    return 0;
171
638k
}
172
173
int pdfi_free_string_from_name(pdf_context *ctx, char *str)
174
767k
{
175
767k
    if (str != NULL)
176
638k
        gs_free_object(ctx->memory, str, "pdfi_free_string_from_name");
177
767k
    return 0;
178
767k
}
179
180
void normalize_rectangle(double *d)
181
103k
{
182
103k
    double d1[4];
183
103k
    int i;
184
185
103k
    if (d[0] < d[2]) {
186
103k
        d1[0] = d[0];
187
103k
        d1[2] = d[2];
188
103k
    } else {
189
46
        d1[0] = d[2];
190
46
        d1[2] = d[0];
191
46
    }
192
103k
    if (d[1] < d[3]) {
193
103k
        d1[1] = d[1];
194
103k
        d1[3] = d[3];
195
103k
    } else {
196
39
        d1[1] = d[3];
197
39
        d1[3] = d[1];
198
39
    }
199
519k
    for (i=0;i<=3;i++){
200
415k
        d[i] = d1[i];
201
415k
    }
202
103k
}
203
204
/* Free an array of cstrings, sets the pointer to null */
205
void pdfi_free_cstring_array(pdf_context *ctx, char ***pstrlist)
206
189k
{
207
189k
    char **ptr = *pstrlist;
208
209
189k
    if (ptr == NULL)
210
189k
        return;
211
212
0
    while (*ptr) {
213
0
        gs_free_object(ctx->memory, *ptr, "pdfi_free_cstring_array(item)");
214
0
        ptr ++;
215
0
    }
216
0
    gs_free_object(ctx->memory, *pstrlist, "pdfi_free_cstring_array(array)");
217
0
    *pstrlist = NULL;
218
0
}
219
220
/* Parse an argument string of names into an array of cstrings */
221
/* Format: /Item1,/Item2,/Item3 (no white space) */
222
int pdfi_parse_name_cstring_array(pdf_context *ctx, char *data, uint64_t size, char ***pstrlist)
223
0
{
224
0
    char **strlist = NULL;
225
0
    char **templist = NULL;
226
0
    int numitems = 0, item;
227
0
    int strnum;
228
0
    uint64_t i;
229
0
    char *strptr;
230
0
    int code = 0;
231
232
    /* Free it if it already exists */
233
0
    if (*pstrlist != NULL)
234
0
        pdfi_free_cstring_array(ctx, pstrlist);
235
236
    /* find out how many '/' characters there are -- this is the max possible number
237
     * of items in the list
238
     */
239
0
    for (i=0, strptr = data; i<size; i++,strptr++) {
240
0
        if (*strptr == '/')
241
0
            numitems ++;
242
        /* early exit if we hit a null */
243
0
        if (*strptr == 0)
244
0
            break;
245
0
    }
246
247
    /* Allocate space for the array of char * (plus one extra for null termination) */
248
0
    strlist = (char **)gs_alloc_bytes(ctx->memory, (numitems+1)*sizeof(char *),
249
0
                                       "pdfi_parse_cstring_array(strlist)");
250
0
    if (strlist == NULL)
251
0
        return_error(gs_error_VMerror);
252
253
0
    memset(strlist, 0, (numitems+1)*sizeof(char *));
254
255
    /* Allocate a temp array */
256
0
    templist = (char **)gs_alloc_bytes(ctx->memory, (numitems+1)*sizeof(char *),
257
0
                                       "pdfi_parse_cstring_array(templist)");
258
0
    if (templist == NULL) {
259
0
        code = gs_note_error(gs_error_VMerror);
260
0
        goto exit;
261
0
    }
262
263
0
    memset(templist, 0, (numitems+1)*sizeof(char *));
264
265
    /* Find start ptr of each string */
266
0
    item = 0;
267
0
    for (i=0, strptr = data; i<size; i++,strptr++) {
268
0
        if (*strptr == '/') {
269
0
            templist[item] = strptr+1;
270
0
            item++;
271
0
        }
272
0
    }
273
274
    /* Find each substring, alloc, copy into string array */
275
0
    strnum = 0;
276
0
    for (i=0; i<numitems; i++) {
277
0
        char *curstr, *nextstr;
278
0
        int length;
279
0
        char *newstr;
280
281
0
        curstr = templist[i];
282
0
        nextstr = templist[i+1];
283
0
        if (!curstr)
284
0
            break;
285
0
        if (*curstr == '/' || *curstr == ',') {
286
            /* Empty string, skip it */
287
0
            continue;
288
0
        }
289
0
        if (nextstr == NULL) {
290
0
            length = size-(curstr-data);
291
0
        } else {
292
0
            length = nextstr - curstr - 1;
293
0
        }
294
0
        if (curstr[length-1] == ',')
295
0
            length --;
296
297
        /* Allocate the string and copy it */
298
0
        newstr = (char *)gs_alloc_bytes(ctx->memory, length+1,
299
0
                                       "pdfi_parse_cstring_array(newstr)");
300
0
        if (newstr == NULL) {
301
0
            code = gs_note_error(gs_error_VMerror);
302
0
            goto exit;
303
0
        }
304
0
        memcpy(newstr, curstr, length);
305
0
        newstr[length+1] = 0; /* Null terminate */
306
0
        strlist[strnum] = newstr;
307
0
        strnum ++;
308
0
    }
309
310
0
    *pstrlist = strlist;
311
312
0
 exit:
313
0
    if (code < 0)
314
0
        pdfi_free_cstring_array(ctx, &strlist);
315
0
    if (templist)
316
0
        gs_free_object(ctx->memory, templist, "pdfi_parse_cstring_array(templist(array))");
317
0
    return code;
318
0
}