Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pcsymbol.c
Line
Count
Source
1
/* Copyright (C) 2001-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
17
/* pcsymbol.c */
18
/* PCL5 user-defined symbol set commands */
19
#include "stdio_.h"             /* std.h + NULL */
20
#include "plvalue.h"
21
#include "pcommand.h"
22
#include "pcstate.h"
23
#include "pcfont.h"
24
#include "pcsymbol.h"
25
26
/* HP printers will not convert MSL coded symbol table to unicode.  An
27
   MSL based font must be used with an MSL symbol set.  We think this
28
   is a bug.  The following definition can be uncommented to support
29
   the feature anyway */
30
31
/* #define SUPPORT_MSL_TO_UNICODE */
32
33
static int                      /* ESC * c <id> R */
34
pcl_symbol_set_id_code(pcl_args_t * pargs, pcl_state_t * pcs)
35
129
{
36
129
    uint id = uint_arg(pargs);
37
38
129
    id_set_value(pcs->symbol_set_id, id);
39
129
    return 0;
40
129
}
41
42
#ifdef DEBUG
43
static void
44
dump_dl_symbol_set(const gs_memory_t * mem, const pl_symbol_map_t * psm)
45
{
46
    dmprintf6(mem,
47
              "header size:%d id:%d format:%s type:%d first code:%d last code:%d\n",
48
              pl_get_uint16(psm->header_size), pl_get_uint16(psm->id),
49
              (psm->format ==
50
               1 ? "MSL" : (psm->format == 3 ? "Unicode" : "Unknown")),
51
              psm->type, pl_get_uint16(psm->first_code),
52
              pl_get_uint16(psm->last_code));
53
    {
54
        int i;
55
        int num_codes =
56
            pl_get_uint16(psm->last_code) - pl_get_uint16(psm->first_code) +
57
            1;
58
        for (i = 0; i < num_codes; i++) {
59
            dmprintf2(mem, "index=%d, code:%d\n", i, psm->codes[i]);
60
        }
61
    }
62
}
63
#endif
64
65
static int                      /* ESC ( f <count> W */
66
pcl_define_symbol_set(pcl_args_t * pargs, pcl_state_t * pcs)
67
0
{
68
0
    uint count = uint_arg(pargs);
69
0
    const pl_symbol_map_t *psm = (pl_symbol_map_t *) arg_data(pargs);
70
0
    uint header_size;
71
0
    uint first_code, last_code;
72
0
    gs_memory_t *mem = pcs->memory;
73
0
    pl_symbol_map_t *header;
74
0
    pcl_symbol_set_t *symsetp;
75
0
    pl_glyph_vocabulary_t gv;
76
77
#ifdef DEBUG
78
    if (gs_debug_c('i')) {
79
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
80
    }
81
#endif
82
83
0
#define psm_header_size 18
84
0
    if (count < psm_header_size)
85
0
        return e_Range;
86
0
    header_size = pl_get_uint16(psm->header_size);
87
0
    if (header_size < psm_header_size ||
88
0
        psm->id[0] != id_key(pcs->symbol_set_id)[0] ||
89
0
        psm->id[1] != id_key(pcs->symbol_set_id)[1] || psm->type > 2)
90
0
        return e_Range;
91
0
    switch (psm->format) {
92
0
        case 1:
93
0
            gv = plgv_MSL;
94
0
            break;
95
0
        case 3:
96
0
            gv = plgv_Unicode;
97
0
            break;
98
0
        default:
99
0
            return e_Range;
100
0
    }
101
0
    first_code = pl_get_uint16(psm->first_code);
102
0
    last_code = pl_get_uint16(psm->last_code);
103
104
0
    if (last_code > 255 || first_code > last_code)
105
0
        return e_Range;
106
107
0
    {
108
0
        int num_codes = last_code - first_code + 1;  /* must be in [0,256] now. */
109
0
        int i;
110
111
0
        if (num_codes == 0 || (count != psm_header_size + num_codes * 2))
112
0
            return e_Range;
113
114
0
        header =
115
0
            (pl_symbol_map_t *) gs_alloc_bytes(mem,
116
0
                                               sizeof(pl_symbol_map_t),
117
0
                                               "pcl_font_header(header)");
118
0
        if (header == 0)
119
0
            return_error(e_Memory);
120
0
        memcpy((void *)header, (void *)psm, psm_header_size);
121
        /* allow mapping to and from msl and unicode */
122
0
        if (psm->format == 1)
123
#ifdef SUPPORT_MSL_TO_UNICODE
124
            header->mapping_type = PLGV_M2U_MAPPING;
125
#else
126
0
            header->mapping_type = PLGV_NO_MAPPING;
127
0
#endif
128
0
        else
129
0
            header->mapping_type = PLGV_U2M_MAPPING;
130
131
        /*
132
         * Byte swap the codes now, so that we don't have to byte swap
133
         * them every time we access them.
134
         */
135
0
        for (i = 0; i < num_codes; i++)
136
0
            header->codes[i] =
137
0
                pl_get_uint16((byte *) psm + psm_header_size + i * 2);
138
0
    }
139
0
#undef psm_header_size
140
141
#ifdef DEBUG
142
    if (gs_debug_c('='))
143
        dump_dl_symbol_set(mem, psm);
144
#endif
145
146
    /* Symbol set may already exist; if so, we may be replacing one of
147
     * its existing maps or adding one for a new glyph vocabulary. */
148
0
    if (pl_dict_find(&pcs->soft_symbol_sets, id_key(pcs->symbol_set_id),
149
0
                     2, (void **)&symsetp)) {
150
0
        if (symsetp->maps[gv] != NULL)
151
0
            gs_free_object(mem, symsetp->maps[gv], "symset map");
152
0
    } else {
153
0
        int code = 0;
154
0
        pl_glyph_vocabulary_t gx;
155
156
0
        symsetp = (pcl_symbol_set_t *) gs_alloc_bytes(mem,
157
0
                                                      sizeof
158
0
                                                      (pcl_symbol_set_t),
159
0
                                                      "symset dict value");
160
0
        if (!symsetp) {
161
0
            gs_free_object(mem, header, "pcl_font_header(header)");
162
0
            return_error(e_Memory);
163
0
        }
164
0
        for (gx = plgv_MSL; gx < plgv_next; gx++)
165
0
            symsetp->maps[gx] = NULL;
166
0
        symsetp->storage = pcds_temporary;
167
0
        code = pl_dict_put(&pcs->soft_symbol_sets, id_key(pcs->symbol_set_id),
168
0
                    2, symsetp);
169
0
        if (code < 0) {
170
0
            gs_free_object(mem, header, "pcl_font_header(header)");
171
0
            return code;
172
0
        }
173
0
    }
174
0
    symsetp->maps[gv] = header;
175
176
0
    return 0;
177
0
}
178
179
static int                      /* ESC * c <ssc_enum> S */
180
pcl_symbol_set_control(pcl_args_t * pargs, pcl_state_t * pcs)
181
26.4k
{
182
26.4k
    gs_const_string key;
183
26.4k
    void *value;
184
26.4k
    pl_dict_enum_t denum;
185
186
26.4k
    switch (int_arg(pargs)) {
187
51
        case 0:
188
51
            {
189
                /* Delete all user-defined symbol sets. */
190
                /* Note: When deleting symbol set(s), it is easier
191
                 * (safer?)  to decache and reselect fonts
192
                 * unconditionally.  (Consider, for example, deleting
193
                 * a downloaded overload of a built-in which might be
194
                 * the default ID.)
195
                 */
196
51
                pl_dict_release(&pcs->soft_symbol_sets);
197
51
                pcl_decache_font(pcs, -1, true);
198
51
            }
199
51
            return 0;
200
26.3k
        case 1:
201
26.3k
            {
202
                /* Delete all temporary symbol sets. */
203
26.3k
                pl_dict_enum_stack_begin(&pcs->soft_symbol_sets, &denum,
204
26.3k
                                         false);
205
26.3k
                while (pl_dict_enum_next(&denum, &key, &value))
206
0
                    if (((pcl_symbol_set_t *) value)->storage ==
207
0
                        pcds_temporary)
208
0
                        pl_dict_undef(&pcs->soft_symbol_sets, key.data,
209
0
                                      key.size);
210
26.3k
                pcl_decache_font(pcs, -1, true);
211
26.3k
            }
212
26.3k
            return 0;
213
0
        case 2:
214
0
            {
215
                /* Delete symbol set <symbol_set_id>. */
216
0
                pl_dict_undef(&pcs->soft_symbol_sets,
217
0
                              id_key(pcs->symbol_set_id), 2);
218
0
                pcl_decache_font(pcs, -1, true);
219
0
            }
220
0
            return 0;
221
0
        case 4:
222
0
            {
223
                /* Make <symbol_set_id> temporary. */
224
0
                if (pl_dict_find(&pcs->soft_symbol_sets,
225
0
                                 id_key(pcs->symbol_set_id), 2, &value))
226
0
                    ((pcl_symbol_set_t *) value)->storage = pcds_temporary;
227
0
            }
228
0
            return 0;
229
0
        case 5:
230
0
            {
231
                /* Make <symbol_set_id> permanent. */
232
0
                if (pl_dict_find(&pcs->soft_symbol_sets,
233
0
                                 id_key(pcs->symbol_set_id), 2, &value))
234
0
                    ((pcl_symbol_set_t *) value)->storage = pcds_permanent;
235
0
            }
236
0
            return 0;
237
23
        default:
238
23
            return 0;
239
26.4k
    }
240
26.4k
}
241
242
static void                     /* free any symbol maps as well as dict value entry */
243
pcsymbol_dict_value_free(gs_memory_t * mem, void *value, client_name_t cname)
244
484k
{
245
484k
    pcl_symbol_set_t *ssp = (pcl_symbol_set_t *) value;
246
484k
    pl_glyph_vocabulary_t gx;
247
248
484k
    if (ssp->storage != pcds_internal) {
249
0
        for (gx = plgv_MSL; gx < plgv_next; gx++) {
250
0
            if (ssp->maps[gx] != NULL)
251
0
                gs_free_object(mem, (void *)ssp->maps[gx], cname);
252
0
        }
253
0
    }
254
484k
    gs_free_object(mem, value, cname);
255
484k
}
256
257
static int
258
pcl_load_built_in_symbol_sets(pcl_state_t * pcs)
259
8.97k
{
260
8.97k
    const pl_symbol_map_t **maplp;
261
8.97k
    pcl_symbol_set_t *symsetp;
262
8.97k
    pl_glyph_vocabulary_t gv;
263
264
502k
    for (maplp = &pl_built_in_symbol_maps[0]; *maplp; maplp++) {
265
493k
        const pl_symbol_map_t *mapp = *maplp;
266
267
        /* Create entry for symbol set if this is the first map for
268
         * that set. */
269
493k
        if (!pl_dict_find(&pcs->built_in_symbol_sets, mapp->id, 2,
270
493k
                          (void **)&symsetp)) {
271
484k
            pl_glyph_vocabulary_t gx;
272
273
484k
            symsetp = (pcl_symbol_set_t *) gs_alloc_bytes(pcs->memory,
274
484k
                                                          sizeof
275
484k
                                                          (pcl_symbol_set_t),
276
484k
                                                          "symset init dict value");
277
484k
            if (!symsetp)
278
0
                return_error(e_Memory);
279
1.45M
            for (gx = plgv_MSL; gx < plgv_next; gx++)
280
969k
                symsetp->maps[gx] = NULL;
281
484k
            symsetp->storage = pcds_internal;
282
283
484k
            if (pl_dict_put(&pcs->built_in_symbol_sets, mapp->id, 2, symsetp) < 0) {
284
                /* on error, pl_dict_put consumes symsetp */
285
0
                return_error(gs_error_VMerror);
286
0
            }
287
484k
        }
288
493k
        gv = (mapp->character_requirements[7] & 07) == 1 ?
289
457k
            plgv_Unicode : plgv_MSL;
290
493k
        symsetp->maps[gv] = (pl_symbol_map_t *) mapp;
291
493k
    }
292
8.97k
    return 0;
293
8.97k
}
294
295
bool
296
pcl_check_symbol_support(const byte * symset_req, const byte * font_sup)
297
18.8M
{
298
18.8M
    int i;
299
300
    /* if glyph vocabularies match, following will work on the
301
     * last 3 bits of last byte.  Note that the font-support bits
302
     * are inverted (0 means available).
303
     */
304
149M
    for (i = 0; i < 7; i++)
305
131M
        if (symset_req[i] & font_sup[i])
306
268k
            return false;       /* something needed, not present */
307
    /* check the last byte but not the glyph vocabularies. */
308
18.5M
    if ((symset_req[7] >> 3) & (font_sup[7] >> 3))
309
0
        return false;
310
311
18.5M
    return true;
312
18.5M
}
313
314
/* Find the symbol map for a particular symbol set and glyph vocabulary,
315
 * if it exists.
316
 * There are two dictionaries--one for soft (downloaded) symbol sets and
317
 * one for built-ins.  These are searched separately.  The actual maps
318
 * present for a symbol set may overlap between soft and built-in. */
319
pl_symbol_map_t *
320
pcl_find_symbol_map(const pcl_state_t * pcs, const byte * id,
321
                    pl_glyph_vocabulary_t gv, bool wide16)
322
37.3M
{
323
37.3M
    pcl_symbol_set_t *setp;
324
325
37.3M
    if (pl_dict_find((pl_dict_t *) & pcs->soft_symbol_sets,
326
37.3M
                     id, 2, (void **)&setp) ||
327
37.3M
        pl_dict_find((pl_dict_t *) & pcs->built_in_symbol_sets,
328
37.3M
                     id, 2, (void **)&setp)) {
329
330
        /* 16 bit sets are not supported, they aren't strictly
331
           necessary, yet. */
332
30.4M
        if (wide16)
333
0
            return NULL;
334
        /* simple case we found a matching symbol set */
335
30.4M
        if (setp->maps[gv] != NULL)
336
30.4M
            return setp->maps[gv];
337
        /* we requested a unicode symbol set and found an msl
338
           symbol set that can be mapped to unicode */
339
204
        if ((gv == plgv_Unicode) &&
340
204
            (setp->maps[plgv_MSL]) &&
341
204
            ((setp->maps[plgv_MSL])->mapping_type == PLGV_M2U_MAPPING))
342
0
            return setp->maps[plgv_MSL];
343
        /* we requested an msl symbol set and found a unicode
344
           symbol set that can be mapped to msl */
345
204
        if ((gv == plgv_MSL) &&
346
0
            (setp->maps[plgv_Unicode]) &&
347
0
            ((setp->maps[plgv_Unicode])->mapping_type == PLGV_U2M_MAPPING))
348
0
            return setp->maps[plgv_Unicode];
349
204
    }
350
6.89M
    return NULL;
351
37.3M
}
352
353
/* Initialization */
354
static int
355
pcsymbol_do_registration(pcl_parser_state_t * pcl_parser_state,
356
                         gs_memory_t * mem)
357
8.97k
{                               /* Register commands */
358
8.97k
    DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'R', "Symbol Set ID Code",
359
8.97k
                              pcl_symbol_set_id_code,
360
8.97k
                              pca_neg_error | pca_big_error)
361
8.97k
        DEFINE_CLASS_COMMAND_ARGS('(', 'f', 'W', "Define Symbol Set",
362
8.97k
                                  pcl_define_symbol_set,
363
8.97k
                                  pca_byte_data | pca_neg_error |
364
8.97k
                                  pca_big_clamp)
365
8.97k
        DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'S', "Symbol Set Control",
366
8.97k
                                  pcl_symbol_set_control,
367
8.97k
                                  pca_neg_ignore | pca_big_ignore)
368
8.97k
        return 0;
369
8.97k
}
370
371
static int
372
pcsymbol_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
373
35.3k
{
374
35.3k
    int code;
375
376
35.3k
    if (type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay)) {
377
35.3k
        id_set_value(pcs->symbol_set_id, 0);
378
35.3k
        if (type & pcl_reset_initial) {
379
            /* Don't set a parent relationship from soft to built-in
380
             * symbol sets.  Although it is arguably useful, it's
381
             * better to avoid it and keep anyone who's looking at the
382
             * soft symbol sets from mucking up the permanent ones. */
383
8.97k
            pl_dict_init(&pcs->soft_symbol_sets, pcs->memory,
384
8.97k
                         pcsymbol_dict_value_free);
385
8.97k
            pl_dict_init(&pcs->built_in_symbol_sets, pcs->memory,
386
8.97k
                         pcsymbol_dict_value_free);
387
            /* NB.  Symbol sets are require for RTL/HPGL/2 mode for
388
             * stickfonts but we shouldn't load all of them. */
389
8.97k
            if (pcl_load_built_in_symbol_sets(pcs) < 0)
390
8.97k
                dmprintf(pcs->memory, "Internal error, no symbol sets found");
391
26.3k
        } else if (type & pcl_reset_printer) {
392
26.3k
            pcl_args_t args;
393
394
26.3k
            arg_set_uint(&args, 1);     /* delete temporary symbol sets */
395
26.3k
            code = pcl_symbol_set_control(&args, pcs);
396
26.3k
            if (code < 0)
397
0
                return code;
398
26.3k
        }
399
35.3k
    }
400
35.3k
    if (type & pcl_reset_permanent) {
401
0
        pl_dict_release(&pcs->soft_symbol_sets);
402
0
        pl_dict_release(&pcs->built_in_symbol_sets);
403
0
    }
404
35.3k
    return 0;
405
35.3k
}
406
407
static int
408
pcsymbol_do_copy(pcl_state_t * psaved, const pcl_state_t * pcs,
409
                 pcl_copy_operation_t operation)
410
0
{
411
0
    if (operation & pcl_copy_after) {
412
        /* Don't restore the downloaded symbol set dictionary. */
413
0
        psaved->built_in_symbol_sets = pcs->built_in_symbol_sets;
414
0
    }
415
0
    return 0;
416
0
}
417
418
const pcl_init_t pcsymbol_init = {
419
    pcsymbol_do_registration, pcsymbol_do_reset, pcsymbol_do_copy
420
};