Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pl/plparams.c
Line
Count
Source
1
/* Copyright (C) 2001-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
17
/* plparams.c -  PJL handling of pdfwrite device parameters */
18
19
#include "std.h"
20
#include "gsmemory.h"
21
#include "gsmatrix.h"           /* for gsdevice.h */
22
#include "gsdevice.h"
23
#include "gsparam.h"
24
#include "gp.h"
25
#include "gserrors.h"
26
#include "string_.h"
27
#include "plparams.h"
28
#include <stdlib.h>
29
30
/*--------------------------------------------- pdfmark -------------------------------------------*/
31
32
/* Add a newly created param_string array to a param list, and then use that
33
 * param list as an argument to put the device parameters.
34
 */
35
static int pdfmark_write_list(gs_memory_t *mem, gx_device *device, gs_param_string_array *array_list)
36
0
{
37
0
    gs_c_param_list list;
38
0
    int code;
39
40
    /* Set the list to writeable, and initialise it */
41
0
    gs_c_param_list_write(&list, mem);
42
    /* We don't want keys to be persistent, as we are going to throw
43
     * away our array, force them to be copied
44
     */
45
0
    gs_param_list_set_persistent_keys((gs_param_list *) &list, false);
46
47
    /* Make really sure the list is writable, but don't initialise it */
48
0
    gs_c_param_list_write_more(&list);
49
50
    /* Add the param string array to the list */
51
0
    code = param_write_string_array((gs_param_list *)&list, "pdfmark", array_list);
52
0
    if (code < 0)
53
0
        return code;
54
55
    /* Set the param list back to readable, so putceviceparams can readit (mad...) */
56
0
    gs_c_param_list_read(&list);
57
58
    /* and set the actual device parameters */
59
0
    code = gs_putdeviceparams(device, (gs_param_list *)&list);
60
61
    /* release the memory allocated for the list parameter */
62
0
    gs_c_param_list_release(&list);
63
64
0
    return code;
65
0
}
66
67
/* pdfmark operations always take an array parameter. Because (see below) we
68
 * know that array valuess must be homogenous types we can treat them all as
69
 * parameter strings.
70
 */
71
static int process_pdfmark(gs_memory_t *mem, gx_device *device, char *pdfmark)
72
0
{
73
0
    char *p, *start, *copy, *stream_data = 0L;
74
0
    int tokens = 0, code = 0;
75
0
    gs_param_string *parray;
76
0
    gs_param_string_array array_list;
77
0
    bool putdict = false;
78
79
    /* Our parsing will alter the string contents, so copy it and perform the parsing on the copy */
80
0
    copy = (char *)gs_alloc_bytes(mem, strlen(pdfmark) + 1, "working buffer for pdfmark processing");
81
0
    if (copy == 0)
82
0
        return -1;
83
0
    strcpy(copy, pdfmark);
84
85
0
    start = copy + 1;
86
0
    if (*pdfmark != '[') {
87
0
        gs_free_object(mem, copy, "working buffer for pdfmark processing");
88
0
        return -1;
89
0
    }
90
91
0
    p = start;
92
0
    while (*p != 0x00){
93
0
        if(*p == '(') {
94
0
            while (*p != ')' && *p != 0x00) {
95
0
                if (*p == '\\')
96
0
                    p++;
97
0
                p++;
98
0
            }
99
0
            if (*p != ')') {
100
0
                gs_free_object(mem, copy, "working buffer for pdfmark processing");
101
0
                return -1;
102
0
            }
103
0
        } else {
104
0
            if (*p == ' ') {
105
0
                tokens++;
106
0
            }
107
0
        }
108
0
        p++;
109
0
    }
110
111
0
    if (*(p-1) != ' ')
112
0
        tokens++;
113
114
    /* We need an extra one for a dummy CTM */
115
0
    tokens++;
116
117
0
    parray = (gs_param_string *)gs_alloc_bytes(mem, (size_t)tokens * sizeof(gs_param_string), "temporary pdfmark array");
118
0
    if (!parray) {
119
0
        gs_free_object(mem, copy, "working buffer for pdfmark processing");
120
0
        return -1;
121
0
    }
122
123
0
    tokens = 0;
124
0
    while (*start == ' ')
125
0
        start++;
126
0
    p = start;
127
128
0
    while (*p != 0x00){
129
0
        if(*p == '(') {
130
0
            while (*p != ')' && *p != 0x00) {
131
0
                if (*p == '\\')
132
0
                    p++;
133
0
                p++;
134
0
            }
135
0
            if (*p != ')') {
136
0
                gs_free_object(mem, copy, "working buffer for pdfmark processing");
137
0
                return -1;
138
0
            }
139
0
        } else {
140
0
            if (*p == ' ') {
141
0
                if (strncmp(start, "<<", 2) == 0) {
142
0
                    putdict = true;
143
0
                } else {
144
0
                    if (strncmp(start, ">>", 2) != 0) {
145
0
                        *p = 0x00;
146
0
                        parray[tokens].data = (const byte *)start;
147
0
                        parray[tokens].size = strlen(start);
148
0
                        parray[tokens++].persistent = false;
149
0
                    }
150
0
                }
151
0
                start = ++p;
152
0
            } else
153
0
                p++;
154
0
        }
155
0
    }
156
0
    if (*(p-1) != ' ') {
157
0
        parray[tokens].data = (const byte *)start;
158
0
        parray[tokens].size = strlen(start);
159
0
        parray[tokens++].persistent = false;
160
0
    }
161
162
    /* Move last entry up one and add a dummy CTM where it used to be */
163
0
    parray[tokens].data = parray[tokens - 1].data;
164
0
    parray[tokens].size = parray[tokens - 1].size;
165
0
    parray[tokens].persistent = parray[tokens - 1].persistent;
166
0
    parray[tokens - 1].data = (const byte *)"[0 0 0 0 0 0]";
167
0
    parray[tokens - 1].size = 13;
168
0
    parray[tokens - 1].persistent = false;
169
170
    /* Features are name objects (ie they start with a '/') but putdeviceparams wants them
171
     * as strings without the '/', so we need to strip that here.
172
     */
173
0
    if (parray[tokens].data[0] != '/') {
174
0
        gs_free_object(mem, copy, "working buffer for pdfmark processing");
175
0
        gs_free_object(mem, parray, "temporary pdfmark array");
176
0
        return -1;
177
0
    } else {
178
0
        parray[tokens].data++;
179
0
        parray[tokens].size--;
180
0
    }
181
182
    /* We need to convert a 'PUT' with a dictonary into a 'PUTDICT', this is normally done
183
     * in PostScript
184
     */
185
0
    if (putdict && strncmp((const char *)(parray[tokens].data), "PUT", 3) == 0) {
186
0
        parray[tokens].data = (const byte *)".PUTDICT";
187
0
        parray[tokens].size = 8;
188
0
        parray[tokens].persistent = false;
189
0
    }
190
    /* We also need some means to handle file data. Normally ths is done by creating a
191
     * PostScript file object and doing a 'PUT', but we can't do that, so we define a
192
     * special variety of 'PUT' called 'PUTFILE' and we handle that here.
193
     */
194
0
    if (strncmp((const char *)(parray[tokens].data), "PUTFILE", 7) == 0) {
195
0
        gp_file *f;
196
0
        char *filename;
197
0
        int bytes;
198
199
0
        if (parray[tokens - 2].data[0] != '(') {
200
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
201
0
            gs_free_object(mem, parray, "temporary pdfmark array");
202
0
            return -1;
203
0
        }
204
0
        filename = (char *)&(parray[tokens - 2].data[1]);
205
0
        filename[strlen(filename) - 1] = 0x00;
206
207
0
        f = gp_fopen(mem, (const char *)filename, "rb");
208
0
        if (!f) {
209
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
210
0
            gs_free_object(mem, parray, "temporary pdfmark array");
211
0
            return -1;
212
0
        }
213
214
0
        if (gp_fseek(f, 0, SEEK_END) != 0) {
215
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
216
0
            gs_free_object(mem, parray, "temporary pdfmark array");
217
0
            gp_fclose(f);
218
0
            return -1;
219
0
        }
220
0
        bytes = gp_ftell(f);
221
0
        if (bytes < 0) {
222
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
223
0
            gs_free_object(mem, parray, "temporary pdfmark array");
224
0
            gp_fclose(f);
225
0
            return -1;
226
0
        }
227
228
0
        parray[tokens - 2].data = (const byte *)gs_alloc_bytes(mem, bytes, "PJL pdfmark, stream");
229
0
        if (!parray[tokens - 2].data) {
230
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
231
0
            gs_free_object(mem, parray, "temporary pdfmark array");
232
0
            gp_fclose(f);
233
0
            return -1;
234
0
        }
235
0
        stream_data = (char *)(parray[tokens - 2].data);
236
237
0
        if (gp_fseek(f, 0, SEEK_SET) != 0) {
238
0
            gs_free_object(mem, stream_data, "PJL pdfmark, stream");
239
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
240
0
            gs_free_object(mem, parray, "temporary pdfmark array");
241
0
            gp_fclose(f);
242
0
            return gs_note_error(gs_error_ioerror);
243
0
        }
244
0
        code = gp_fread(stream_data, 1, bytes, f);
245
0
        if (code != bytes) {
246
0
            gs_free_object(mem, stream_data, "PJL pdfmark, stream");
247
0
            gs_free_object(mem, copy, "working buffer for pdfmark processing");
248
0
            gs_free_object(mem, parray, "temporary pdfmark array");
249
0
            gp_fclose(f);
250
0
            return gs_note_error(gs_error_ioerror);
251
0
        }
252
0
        gp_fclose(f);
253
0
        parray[tokens - 2].size = bytes;
254
255
0
        parray[tokens].data = (const byte *)".PUTSTREAM";
256
0
        parray[tokens].size = 10;
257
0
        parray[tokens].persistent = false;
258
0
    }
259
260
0
    array_list.data = parray;
261
0
    array_list.persistent = 0;
262
0
    array_list.size = ++tokens;
263
264
0
    code = pdfmark_write_list(mem, device, &array_list);
265
266
0
    if (stream_data)
267
0
        gs_free_object(mem, stream_data, "PJL pdfmark, stream");
268
0
    gs_free_object(mem, copy, "working buffer for pdfmark processing");
269
0
    gs_free_object(mem, parray, "temporary pdfmark array");
270
271
0
    return code;
272
0
}
273
274
int pcl_pjl_pdfmark(gs_memory_t *mem, gx_device *device, char *pdfmark)
275
0
{
276
0
    char *pdfmark_start, *token_start, end, *p;
277
0
    int code;
278
279
0
    p = token_start = pdfmark_start = pdfmark + 1;
280
281
0
    do {
282
0
        while (*p != ' ' && *p != '"' && *p != 0x00)
283
0
            p++;
284
0
        if((p - token_start) != 7 || strncmp(token_start, "pdfmark", 7) != 0){
285
0
            if (*p != 0x00)
286
0
                token_start = ++p;
287
0
            else
288
0
                break;
289
0
        } else {
290
0
            token_start--;
291
0
            end = *token_start;
292
0
            *token_start = 0x00;
293
0
            code = process_pdfmark(mem, device, pdfmark_start);
294
0
            if (code < 0)
295
0
                return code;
296
297
0
            *token_start = end;
298
0
            token_start = pdfmark_start = ++p;
299
0
        }
300
0
    } while (*p != 0x00);
301
0
    return 0;
302
0
}
303
304
/*--------------------------------------------- distillerparams -------------------------------------------*/
305
306
int pcl_pjl_setdistillerparams(gs_memory_t *mem, gx_device *device, char *distillerparams)
307
0
{
308
0
    char *p, *start, *copy;
309
0
    int code = 0;
310
0
    gs_c_param_list *plist;
311
312
0
    plist = gs_c_param_list_alloc(mem, "temp C param list for PJL distillerparams");
313
0
    if (plist == NULL)
314
0
        return -1;
315
0
    gs_c_param_list_write(plist, mem);
316
0
    gs_param_list_set_persistent_keys((gs_param_list *) plist, false);
317
0
    gs_c_param_list_write_more(plist);
318
319
    /* Our parsing will alter the string contents, so copy it and perform the parsing on the copy */
320
0
    copy = (char *)gs_alloc_bytes(mem, strlen(distillerparams) + 1, "working buffer for distillerparams processing");
321
0
    if (copy == 0)
322
0
        return -1;
323
0
    strcpy(copy, distillerparams);
324
325
0
    if (*copy == '"') {
326
0
        start = copy + 1;
327
0
        copy[strlen(copy) - 1] = 0x00;
328
0
    }
329
0
    else
330
0
        start = copy;
331
332
0
    if (*start != '<' || start[1] != '<') {
333
0
        gs_free_object(mem, copy, "working buffer for distillerparams processing");
334
0
        return -1;
335
0
    }
336
0
    start += 2;
337
338
0
    if (copy[strlen(copy) - 1] != '>' || copy[strlen(copy) - 2] != '>') {
339
0
        gs_free_object(mem, copy, "working buffer for distillerparams processing");
340
0
        return -1;
341
0
    }
342
0
    copy[strlen(copy) - 2] = 0x00;
343
344
0
    while (*start == ' ')
345
0
        start++;
346
0
    p = start;
347
348
    /* Parse the string, adding what we find to the plist */
349
0
    code = gs_param_list_add_tokens((gs_param_list *)plist, p);
350
0
    if (code < 0) {
351
0
        gs_c_param_list_release(plist);
352
0
        return code;
353
0
    }
354
355
    /* Discard our working copy of the string */
356
0
    gs_free_object(mem, copy, "working buffer for distillerparams processing");
357
358
    /* Set the list to 'read' (bonkers...) */
359
0
    gs_c_param_list_read(plist);
360
361
    /* Actually set the newly created device parameters */
362
0
    code = gs_putdeviceparams(device, (gs_param_list *)plist);
363
364
    /* And throw away the plist, we're done with it */
365
0
    gs_c_param_list_release(plist);
366
0
    return code;
367
0
}