Coverage Report

Created: 2026-08-08 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pcuptrn.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
17
/* pcuptrn.c - code for PCL and GL/2 user defined patterns */
18
19
#include "string_.h"
20
#include "gx.h"
21
#include "gsuid.h"
22
#include "gscsel.h"
23
#include "gsdevice.h"
24
#include "gxdevice.h"
25
#include "gscspace.h"
26
#include "gxdcolor.h"
27
#include "gxcolor2.h"
28
#include "gxpcolor.h"
29
#include "pldict.h"
30
#include "pcindxed.h"
31
#include "pcpatrn.h"
32
#include "pcbiptrn.h"
33
#include "pcuptrn.h"
34
35
gs_private_st_simple(st_pattern_data_t, pcl_pattern_data_t,
36
                     "PCL/GL pattern data");
37
gs_private_st_simple(st_pattern_t, pcl_pattern_t, "PCL/GL pattern");
38
39
/*
40
 * Free routine for pattern data structure.
41
 */
42
static void
43
free_pattern_data(gs_memory_t * pmem, void *pvpat_data, client_name_t cname)
44
9.59k
{
45
9.59k
    pcl_pattern_data_t *ppat_data = (pcl_pattern_data_t *) pvpat_data;
46
47
9.59k
    if ((ppat_data->storage != pcds_internal)
48
8.10k
        && (ppat_data->pixinfo.data != 0))
49
8.10k
        gs_free_object(pmem, ppat_data->pixinfo.data, cname);
50
9.59k
    gs_free_object(pmem, pvpat_data, cname);
51
9.59k
}
52
53
/*
54
 * Build a pattern data structure. This routine is static as pattern
55
 * data structures may only be built as part of a pattern.
56
 *
57
 * All pattern data structure are built as "temporary". Routines that build
58
 * internal patterns should modify this as soon as the pattern is built.
59
 *
60
 * Returns 0 on success, < 0 in the event of an error. In the latter case,
61
 * *pppat_data will be set to NULL.
62
 */
63
static int
64
build_pattern_data(pcl_pattern_data_t ** pppat_data,
65
                   const gs_depth_bitmap * ppixinfo,
66
                   pcl_pattern_type_t type,
67
                   int xres, int yres, gs_memory_t * pmem)
68
9.59k
{
69
9.59k
    pcl_pattern_data_t *ppat_data = 0;
70
71
9.59k
    *pppat_data = 0;
72
9.59k
    rc_alloc_struct_1(ppat_data,
73
9.59k
                      pcl_pattern_data_t,
74
9.59k
                      &st_pattern_data_t,
75
9.59k
                      pmem, return e_Memory, "allocate PCL pattern data");
76
9.59k
    ppat_data->rc.free = free_pattern_data;
77
78
9.59k
    ppat_data->pixinfo = *ppixinfo;
79
9.59k
    ppat_data->storage = pcds_temporary;
80
9.59k
    ppat_data->type = type;
81
9.59k
    ppat_data->xres = xres;
82
9.59k
    ppat_data->yres = yres;
83
84
9.59k
    *pppat_data = ppat_data;
85
9.59k
    return 0;
86
9.59k
}
87
88
/*
89
 * Free the rendered portion of a pattern.
90
 */
91
static void
92
free_pattern_rendering(const gs_memory_t * mem, pcl_pattern_t * pptrn)
93
9.59k
{
94
9.59k
    if (pptrn->pcol_ccolor != 0) {
95
2.83k
        pcl_ccolor_release(pptrn->pcol_ccolor);
96
2.83k
        pptrn->pcol_ccolor = 0;
97
2.83k
    }
98
9.59k
    if (pptrn->pmask_ccolor != 0) {
99
1.93k
        pcl_ccolor_release(pptrn->pmask_ccolor);
100
1.93k
        pptrn->pmask_ccolor = 0;
101
1.93k
    }
102
9.59k
}
103
104
/*
105
 * Free routine for patterns. This is exported for the benefit of the code
106
 * that handles PCL built-in patterns.
107
 */
108
void
109
pcl_pattern_free_pattern(gs_memory_t * pmem,
110
                         void *pvptrn, client_name_t cname)
111
234k
{
112
234k
    pcl_pattern_t *pptrn = (pcl_pattern_t *) pvptrn;
113
114
234k
    if (pptrn == NULL)
115
224k
        return;
116
9.59k
    free_pattern_rendering(pmem, pptrn);
117
9.59k
    if (pptrn->ppat_data != 0)
118
9.59k
        pcl_pattern_data_release(pptrn->ppat_data);
119
9.59k
    gs_free_object(pmem, pvptrn, cname);
120
9.59k
}
121
122
/*
123
 * Build a PCL pattern.
124
 *
125
 * This is expoorted for use by the routines that create the "built in"
126
 * patterns.
127
 *
128
 * Returns 0 if successful, < 0 in the event of an error. In the latter case,
129
 * *ppptrn will be set to null.
130
 */
131
int
132
pcl_pattern_build_pattern(pcl_pattern_t ** ppptrn,
133
                          const gs_depth_bitmap * ppixinfo,
134
                          pcl_pattern_type_t type,
135
                          int xres, int yres, gs_memory_t * pmem)
136
9.59k
{
137
9.59k
    pcl_pattern_t *pptrn = 0;
138
9.59k
    int code = 0;
139
140
9.59k
    *ppptrn = 0;
141
9.59k
    pptrn = gs_alloc_struct(pmem,
142
9.59k
                            pcl_pattern_t,
143
9.59k
                            &st_pattern_t, "create PCL pattern");
144
9.59k
    if (pptrn == 0)
145
0
        return e_Memory;
146
147
9.59k
    pptrn->pcol_ccolor = 0;
148
9.59k
    pptrn->pmask_ccolor = 0;
149
9.59k
    pptrn->orient = 0;
150
    /* provide a sentinel to guarantee the initial pattern is
151
       rendered */
152
9.59k
    pptrn->ref_pt.x = pptrn->ref_pt.y = -1.0;
153
9.59k
    code = build_pattern_data(&(pptrn->ppat_data),
154
9.59k
                              ppixinfo, type, xres, yres, pmem);
155
9.59k
    if (code < 0) {
156
0
        pcl_pattern_free_pattern(pmem, pptrn, "create PCL pattern");
157
0
        return code;
158
0
    }
159
160
9.59k
    *ppptrn = pptrn;
161
9.59k
    return 0;
162
9.59k
}
163
164
/*
165
 * Get a PCL user-defined pattern. A null return indicates the pattern is
166
 * not defined.
167
 */
168
pcl_pattern_t *
169
pcl_pattern_get_pcl_uptrn(pcl_state_t * pcs, int id)
170
73
{
171
73
    if (pcs->last_pcl_uptrn_id != id) {
172
71
        pcl_id_t key;
173
174
71
        pcs->last_pcl_uptrn_id = id;
175
71
        id_set_value(key, id);
176
71
        if (!pl_dict_lookup(&pcs->pcl_patterns,
177
71
                            id_key(key),
178
71
                            2, (void **)&pcs->plast_pcl_uptrn, false, NULL))
179
71
            pcs->plast_pcl_uptrn = 0;
180
71
    }
181
182
73
    return pcs->plast_pcl_uptrn;
183
73
}
184
185
/*
186
 * Define a PCL user-defined pattern. This procedure updates the cached
187
 * information, hence it should be used for all definitions. To undefine
188
 * an entry, set the second operard to null.
189
 *
190
 * Returns 0 on success, < 0 in the event of an error.
191
 */
192
static int
193
define_pcl_ptrn(pcl_state_t * pcs, int id, pcl_pattern_t * pptrn, bool gl2)
194
1.84k
{
195
1.84k
    pcl_id_t key;
196
1.84k
    pl_dict_t *pd = (gl2 ? &pcs->gl_patterns : &pcs->pcl_patterns);
197
198
1.84k
    id_set_value(key, id);
199
1.84k
    if (pptrn == 0)
200
1.84k
        pl_dict_undef(pd, id_key(key), 2);
201
0
    else if (pl_dict_put(pd, id_key(key), 2, pptrn) < 0) {
202
        /* on error, pl_dict_put consumes pptrn */
203
0
        return e_Memory;
204
0
    }
205
206
1.84k
    if (gl2) {
207
1.84k
        if (pcs->last_gl2_RF_indx == id)
208
223
            pcs->plast_gl2_uptrn = pptrn;
209
1.84k
    } else {                    /* pcl pattern */
210
0
        if (pcs->last_pcl_uptrn_id == id)
211
0
            pcs->plast_pcl_uptrn = pptrn;
212
0
    }
213
1.84k
    return 0;
214
1.84k
}
215
216
/*
217
 * Delete all temporary patterns or all patterns, based on the value of
218
 * the operand.
219
 */
220
static int
221
delete_all_pcl_ptrns(bool renderings, bool tmp_only, pcl_state_t * pcs)
222
33.3k
{
223
33.3k
    pcl_pattern_t *pptrn;
224
33.3k
    pl_dict_enum_t denum;
225
33.3k
    gs_const_string plkey;
226
33.3k
    pl_dict_t *pdict[2];
227
33.3k
    int code = 0;
228
33.3k
    int i;
229
230
33.3k
    pdict[0] = &pcs->pcl_patterns;
231
33.3k
    pdict[1] = &pcs->gl_patterns;
232
233
100k
    for (i = 0; i < 2; i++) {
234
66.7k
        pl_dict_enum_begin(pdict[i], &denum);
235
68.6k
        while (pl_dict_enum_next(&denum, &plkey, (void **)&pptrn)) {
236
1.84k
            if (!tmp_only || (pptrn->ppat_data->storage == pcds_temporary)) {
237
1.84k
                short idx = (plkey.data[0] << 8) + plkey.data[1];
238
239
1.84k
                code = define_pcl_ptrn(pcs, idx, NULL,
240
1.84k
                                (pdict[i] == &pcs->gl_patterns));
241
1.84k
                if (code < 0)
242
0
                    return code;
243
                /* NB this should be checked - if instead of
244
                   else-if? */
245
1.84k
            } else if (renderings)
246
0
                free_pattern_rendering(pcs->memory, pptrn);
247
1.84k
        }
248
66.7k
    }
249
33.3k
    return code;
250
33.3k
}
251
252
/*
253
 * Get a GL/2 user defined pattern. A null return indicates there is no pattern
254
 * defined for the index.
255
 */
256
pcl_pattern_t *
257
pcl_pattern_get_gl_uptrn(pcl_state_t * pcs, int indx)
258
32.4k
{
259
32.4k
    if (pcs->last_gl2_RF_indx != indx) {
260
5.94k
        pcl_id_t key;
261
262
5.94k
        pcs->last_gl2_RF_indx = indx;
263
5.94k
        id_set_value(key, indx);
264
5.94k
        if (!pl_dict_lookup(&pcs->gl_patterns,
265
5.94k
                            id_key(key),
266
5.94k
                            2, (void **)(&pcs->plast_gl2_uptrn), false, NULL))
267
847
            pcs->plast_gl2_uptrn = 0;
268
5.94k
    }
269
270
32.4k
    return pcs->plast_gl2_uptrn;
271
32.4k
}
272
273
/*
274
 * Create and define a GL/2 user-define pattern. This is the only pattern-
275
 * control like facility provided for GL/2. To undefine patterns, use null
276
 * as the second operand. See pcpatrn.h for further information.
277
 *
278
 * Note that RF patterns may be either colored or uncolored. At the GL/2 level
279
 * the determination is made based on whether or not they contain pen indices
280
 * other than 0 or 1. At this level the determination is based on the depth
281
 * of the data pixmap: 1 for uncolored, 8 for colored.
282
 *
283
 * Returns 0 on success, < 0 in the event of an error.
284
 */
285
int
286
pcl_pattern_RF(int indx, const gs_depth_bitmap * ppixmap, pcl_state_t * pcs)
287
885k
{
288
885k
    pcl_id_t key;
289
885k
    pcl_pattern_t *pptrn = 0;
290
291
885k
    id_set_value(key, indx);
292
293
885k
    if (ppixmap != 0) {
294
8.10k
        pcl_pattern_type_t type = (ppixmap->pix_depth == 1
295
8.10k
                                   ? pcl_pattern_uncolored
296
8.10k
                                   : pcl_pattern_colored);
297
        /* RF appears to use the resolution of the device contrary to
298
           what the pcl documentation implies */
299
8.10k
        gx_device *pdev = gs_currentdevice(pcs->pgs);
300
8.10k
        int code = pcl_pattern_build_pattern(&pptrn,
301
8.10k
                                             ppixmap,
302
8.10k
                                             type,
303
8.10k
                                             (int)pdev->HWResolution[0],
304
8.10k
                                             (int)pdev->HWResolution[1],
305
8.10k
                                             pcs->memory);
306
307
8.10k
        if (code < 0) {
308
0
            gs_free_object(pcs->memory, ppixmap->data, "pcl_pattern_RF");
309
0
            return code;
310
0
        }
311
312
8.10k
        if (pl_dict_put(&pcs->gl_patterns, id_key(key), 2, pptrn) < 0) {
313
0
            return e_Memory;
314
0
        }
315
316
8.10k
    } else
317
877k
        pl_dict_undef(&pcs->gl_patterns, id_key(key), 2);
318
319
885k
    if (pcs->last_gl2_RF_indx == indx)
320
55.5k
        pcs->plast_gl2_uptrn = pptrn;
321
322
885k
    return 0;
323
885k
}
324
325
/*
326
 * The PCL user-define pattern type. For memory management reasons, this has
327
 * a transitory existence.
328
 *
329
 * This object comes in two forms, with and without resolution. Which form
330
 * applies is determined based on the size of the received data array as
331
 * compared to that indicated by the height, width, and depth fields
332
 *
333
 * Note: These structures are defined by HP.
334
 */
335
typedef struct pcl_upattern0_s
336
{
337
    byte format;                /* actually pcl_pattern_type_t */
338
    byte cont;                  /* continuation; currently unused */
339
    byte depth;                 /* bits per pixel; 1 or 8 */
340
    byte dummy;                 /* reserved - currently unused */
341
    byte height[2];             /* height in pixels */
342
    byte width[2];              /* width in pixels */
343
    byte data[1];               /* actual size derived from hgiht, width, and bits */
344
} pcl_upattern0_t;
345
346
typedef struct pcl_upattern1_s
347
{
348
    byte format;                /* actually pcl_pattern_type_t */
349
    byte cont;                  /* continuation; currently unused */
350
    byte depth;                 /* bits per pixel; 1 or 8 */
351
    byte dummy;                 /* reserved - currently unused */
352
    byte height[2];             /* height in pixels */
353
    byte width[2];              /* width in pixels */
354
    byte xres[2];               /* width resolution */
355
    byte yres[2];               /* height resolution */
356
    byte data[1];               /* actual size derived from hgiht, width, and bits */
357
} pcl_upattern1_t;
358
359
/*
360
 * ESC * c # W
361
 *
362
 * Download Pattern
363
 */
364
static int
365
download_pcl_pattern(pcl_args_t * pargs, pcl_state_t * pcs)
366
66
{
367
66
    uint count = arg_data_size(pargs);
368
66
    const pcl_upattern0_t *puptrn0 = (pcl_upattern0_t *) arg_data(pargs);
369
66
    uint format, depth, ndsize, dsize;
370
66
    size_t rsize;
371
66
    gs_depth_bitmap pixinfo;
372
66
    int xres = 300, yres = 300;
373
66
    pcl_pattern_t *pptrn = 0;
374
66
    int code = 0;
375
376
#ifdef DEBUG
377
    if (gs_debug_c('i')) {
378
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
379
    }
380
#endif
381
382
66
    format = puptrn0->format;
383
66
    if (format == 20) {
384
0
        if (count < 12)
385
0
            return e_Range;
386
        /* non data size - the size of the parameters that describe the data */
387
0
        ndsize = sizeof(pcl_upattern1_t) - 1;
388
66
    } else {
389
66
        if (count < 8)
390
9
            return e_Range;
391
        /* non data size - the size of the parameters that describe the data */
392
57
        ndsize = sizeof(pcl_upattern0_t) - 1;
393
57
    }
394
57
    pixinfo.num_comps = 1;
395
57
    pixinfo.size.x = (((uint) puptrn0->width[0]) << 8) + puptrn0->width[1];
396
57
    pixinfo.size.y = (((uint) puptrn0->height[0]) << 8) + puptrn0->height[1];
397
57
    depth = puptrn0->depth & 0xf;
398
57
    pixinfo.pix_depth = depth;
399
57
    pixinfo.raster = (pixinfo.size.x * depth + 7) / 8;
400
57
    pixinfo.id = gx_no_bitmap_id;
401
57
    rsize = pixinfo.raster * pixinfo.size.y;
402
57
    dsize = min(count - ndsize, rsize);
403
404
    /* check for legitimate format */
405
57
    if ((format == 0) || (format == 20)) {
406
3
        if (depth != 1)
407
3
            return e_Range;
408
54
    } else if ((format != 1) ||
409
0
               ((depth != 1) && (depth != 8)) ||
410
0
               (pixinfo.size.x == 0) || (pixinfo.size.y == 0))
411
54
        return e_Range;
412
413
0
    if (rsize == 0)
414
0
        return e_Range;
415
416
    /* allocate space for the array */
417
0
    pixinfo.data = gs_alloc_bytes(pcs->memory, rsize, "download PCL pattern");
418
419
0
    if (pixinfo.data == 0)
420
0
        return e_Memory;
421
422
0
    if (format == 20) {
423
0
        pcl_upattern1_t *puptrn1 = (pcl_upattern1_t *) puptrn0;
424
425
0
        xres = (((uint) puptrn1->xres[0]) << 8) + puptrn1->xres[1];
426
0
        yres = (((uint) puptrn1->yres[0]) << 8) + puptrn1->yres[1];
427
0
        memcpy(pixinfo.data, puptrn1->data, dsize);
428
0
    } else {
429
0
        memcpy(pixinfo.data, puptrn0->data, dsize);
430
0
    }
431
0
    if (dsize < rsize)
432
0
        memset(pixinfo.data + dsize, 0, rsize - dsize);
433
434
    /* build the pattern */
435
0
    code = pcl_pattern_build_pattern(&(pptrn),
436
0
                                     &pixinfo,
437
0
                                     (format == 1 ? pcl_pattern_colored
438
0
                                      : pcl_pattern_uncolored),
439
0
                                     xres, yres, pcs->memory);
440
441
    /* place the pattern into the pattern dictionary */
442
0
    if ((code < 0) ||
443
0
        ((code = define_pcl_ptrn(pcs, pcs->pattern_id, pptrn, false)) < 0)) {
444
0
        if (pptrn == NULL)
445
0
            gs_free_object(pcs->memory,
446
0
                           (void *)pixinfo.data, "download PCL pattern");
447
0
    }
448
449
0
    return code;
450
0
}
451
452
/*
453
 * ESC * c # Q
454
 *
455
 * Pattern contorl.
456
 */
457
static int
458
pattern_control(pcl_args_t * pargs, pcl_state_t * pcs)
459
60
{
460
60
    pcl_pattern_t *pptrn = 0;
461
60
    int code = 0;
462
463
60
    switch (int_arg(pargs)) {
464
465
            /* delete all patterns */
466
50
        case 0:
467
50
            code = delete_all_pcl_ptrns(false, false, pcs);
468
50
            break;
469
470
            /* delete all temporary patterns */
471
0
        case 1:
472
0
            code = delete_all_pcl_ptrns(false, true, pcs);
473
0
            break;
474
475
            /* delete last specified pattern */
476
0
        case 2:
477
0
            define_pcl_ptrn(pcs, pcs->pattern_id, NULL, false);
478
479
            /* make last specified pattern temporary */
480
0
        case 4:
481
0
            pptrn = pcl_pattern_get_pcl_uptrn(pcs, pcs->pattern_id);
482
0
            if (pptrn != 0)
483
0
                pptrn->ppat_data->storage = pcds_temporary;
484
0
            break;
485
486
            /* make last specified pattern permanent */
487
0
        case 5:
488
0
            pptrn = pcl_pattern_get_pcl_uptrn(pcs, pcs->pattern_id);
489
0
            if (pptrn != 0)
490
0
                pptrn->ppat_data->storage = pcds_permanent;
491
0
            break;
492
493
10
        default:
494
10
            break;
495
60
    }
496
497
60
    return code;
498
60
}
499
500
static int
501
upattern_do_copy(pcl_state_t * psaved, const pcl_state_t * pcs,
502
                 pcl_copy_operation_t operation)
503
0
{
504
0
    int i;
505
506
    /* copy back any patterns created during macro invocation. */
507
0
    if ((operation & pcl_copy_after) != 0) {
508
0
        for (i = 0; i < countof(pcs->bi_pattern_array); i++)
509
0
            psaved->bi_pattern_array[i] = pcs->bi_pattern_array[i];
510
0
        psaved->gl_patterns = pcs->gl_patterns;
511
0
        psaved->pcl_patterns = pcs->pcl_patterns;
512
0
        psaved->last_pcl_uptrn_id = pcs->last_pcl_uptrn_id;
513
0
        psaved->plast_pcl_uptrn = pcs->plast_pcl_uptrn;
514
0
        psaved->last_gl2_RF_indx = pcs->last_gl2_RF_indx;
515
0
        psaved->plast_gl2_uptrn = pcs->plast_gl2_uptrn;
516
0
        psaved->punsolid_pattern = pcs->punsolid_pattern;
517
0
        psaved->psolid_pattern = pcs->psolid_pattern;
518
0
    }
519
0
    return 0;
520
0
}
521
522
/*
523
 * Initialization and reset routines.
524
 */
525
static int
526
upattern_do_registration(pcl_parser_state_t * pcl_parser_state,
527
                         gs_memory_t * pmem)
528
16.1k
{
529
16.1k
    DEFINE_CLASS('*') {
530
16.1k
        'c', 'W',
531
16.1k
            PCL_COMMAND("Download Pattern", download_pcl_pattern,
532
16.1k
                        pca_bytes | pca_in_rtl)
533
16.1k
    }, {
534
16.1k
        'c', 'Q',
535
16.1k
            PCL_COMMAND("Pattern Control",
536
16.1k
                        pattern_control,
537
16.1k
                        pca_neg_ignore | pca_big_ignore | pca_in_rtl)
538
16.1k
    }, END_CLASS return 0;
539
16.1k
}
540
541
static int
542
upattern_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
543
49.4k
{
544
49.4k
    int code = 0;
545
546
49.4k
    if ((type & pcl_reset_initial) != 0) {
547
16.1k
        pl_dict_init(&pcs->pcl_patterns, pcs->memory,
548
16.1k
                     pcl_pattern_free_pattern);
549
16.1k
        pl_dict_init(&pcs->gl_patterns, pcs->memory,
550
16.1k
                     pcl_pattern_free_pattern);
551
16.1k
        pcs->last_pcl_uptrn_id = -1;
552
16.1k
        pcs->plast_pcl_uptrn = 0;
553
16.1k
        pcs->last_gl2_RF_indx = -1;
554
16.1k
        pcs->plast_gl2_uptrn = 0;
555
556
16.1k
    } else
557
33.3k
        if ((type &
558
33.3k
             (pcl_reset_cold | pcl_reset_printer | pcl_reset_permanent)) !=
559
33.3k
            0) {
560
33.3k
        code = delete_all_pcl_ptrns(true, !(type & pcl_reset_permanent), pcs);
561
33.3k
        pcl_pattern_clear_bi_patterns(pcs);
562
        /* GL's IN command takes care of the GL patterns */
563
33.3k
    }
564
565
49.4k
    return code;
566
49.4k
}
567
568
const pcl_init_t pcl_upattern_init =
569
    { upattern_do_registration, upattern_do_reset, upattern_do_copy };