Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pcsfont.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
/* pcsfont.c */
18
/* PCL5 soft font creation commands */
19
#include "memory_.h"
20
#include "stdio_.h"             /* needed for pl_load_tt_font */
21
#include "math_.h"
22
#include "gdebug.h"
23
#include "pcommand.h"
24
#include "pcfont.h"
25
#include "pcursor.h"
26
#include "pcpage.h"
27
#include "pcstate.h"
28
#include "pcfsel.h"
29
#include "pcparse.h"
30
#include "pjparse.h"
31
#include "pldict.h"
32
#include "plvalue.h"
33
#include "plmain.h"             /* for high_level_device...
34
                                   hopefully this will go away soon */
35
#include "plfapi.h"
36
37
#include "gsbitops.h"
38
#include "gsccode.h"
39
#include "gsmatrix.h"
40
#include "gsutil.h"
41
#include "gxfont.h"
42
#include "gxfont42.h"
43
44
#define IGNORE_BAD_HEADER_FORMAT_SPECIFIER
45
46
/* Emulate bug in HP printer where component metrics are ignored. */
47
#define DISABLE_USE_MY_METRICS
48
49
/* Define the downloaded character data formats. */
50
typedef enum
51
{
52
    pccd_bitmap = 4,
53
    pccd_intellifont = 10,
54
    pccd_truetype = 15
55
} pcl_character_format;
56
57
/* ------ Internal procedures ------ */
58
59
/* Delete a soft font.  If it is the currently selected font, or the */
60
/* current primary or secondary font, cause a new one to be chosen. */
61
static int
62
pcl_delete_soft_font(pcl_state_t * pcs, const byte * key, uint ksize,
63
                     void *value)
64
123
{
65
123
    if (value == NULL) {
66
106
        if (!pl_dict_find_no_stack(&pcs->soft_fonts, key, ksize, &value))
67
94
            return 0;             /* not a defined font */
68
106
    }
69
29
    {
70
29
        pl_font_t *plfontp = (pl_font_t *) value;
71
72
29
        if (pcs->font_selection[0].font == plfontp)
73
0
            pcs->font_selection[0].font = 0;
74
29
        if (pcs->font_selection[1].font == plfontp)
75
0
            pcs->font_selection[1].font = 0;
76
        /* if this is permanent font we need to tell PJL we are
77
           removing it */
78
29
        if (plfontp->storage & pcds_permanent)
79
0
            if (pjl_proc_register_permanent_soft_font_deletion(pcs->pjls,
80
0
                                                               plfontp->
81
0
                                                               params.
82
0
                                                               pjl_font_number)
83
0
                > 0) {
84
0
                int code = pcl_set_current_font_environment(pcs);
85
86
0
                if (code < 0)
87
0
                    return code;
88
0
            }
89
29
        pcs->font = pcs->font_selection[pcs->font_selected].font;
90
29
        pl_dict_undef_purge_synonyms(&pcs->soft_fonts, key, ksize);
91
29
    }
92
0
    return 0;
93
29
}
94
95
/* ------ Commands ------ */
96
97
static int                      /* ESC * c <id> D */
98
pcl_assign_font_id(pcl_args_t * pargs, pcl_state_t * pcs)
99
469
{
100
469
    uint id = uint_arg(pargs);
101
102
469
    id_set_value(pcs->font_id, id);
103
    /* set state to use id's not strings */
104
469
    pcs->font_id_type = numeric_id;
105
469
    return 0;
106
469
}
107
108
/* Supports copy or assignment of resident fonts.  Copying a soft font
109
   involves a deep copy and a new font.  Copying a resident font
110
   creates a link to the original (source) font */
111
112
static int
113
pcl_make_resident_font_copy(pcl_state_t * pcs)
114
0
{
115
0
    pl_dict_enum_t dictp;
116
0
    gs_const_string key;
117
0
    void *value;
118
0
    bool found = false;
119
120
    /* first check for a duplicate key, if found remove it */
121
0
    if (pl_dict_lookup
122
0
        (&pcs->built_in_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, &value,
123
0
         false, (pl_dict_t **) 0))
124
0
        if (pl_dict_undef
125
0
            (&pcs->built_in_fonts, CURRENT_FONT_ID,
126
0
             CURRENT_FONT_ID_SIZE) == false)
127
            /* shouldn't fail */
128
0
            return -1;
129
130
    /* now search for the value */
131
0
    pl_dict_enum_begin(&pcs->built_in_fonts, &dictp);
132
0
    while (pl_dict_enum_next(&dictp, &key, &value))
133
0
        if ((void *)(pcs->font) == value) {
134
0
            found = true;
135
0
            break;
136
0
        }
137
0
    if (found == false)
138
0
        return -1;
139
0
    return pl_dict_put_synonym(&pcs->built_in_fonts, key.data,
140
0
                        key.size, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE);
141
0
}
142
143
static int                      /* ESC * c <fc_enum> F */
144
pcl_font_control(pcl_args_t * pargs, pcl_state_t * pcs)
145
33.1k
{
146
33.1k
    int code = 0;
147
33.1k
    gs_const_string key;
148
33.1k
    void *value;
149
33.1k
    pl_dict_enum_t denum;
150
151
33.1k
    switch (uint_arg(pargs)) {
152
321
        case 0:
153
            /* Delete all soft fonts. */
154
321
            pcs->font = pcs->font_selection[pcs->font_selected].font;
155
321
            pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false);
156
324
            while (pl_dict_enum_next(&denum, &key, &value)) {
157
3
                code = pcl_delete_soft_font(pcs, key.data, key.size, value);
158
3
                if (code < 0)
159
0
                    return code;
160
                /* when deleting fonts we must restart the enumeration
161
                   each time because the last deleted font may have had
162
                   deleted synonyms which are not properly registered in
163
                   the enumeration structure.  NB A similar change should
164
                   be made for deleting all temporary fonts. */
165
3
                pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false);
166
3
            }
167
321
            pl_dict_release(&pcs->soft_fonts);
168
321
            break;
169
32.8k
        case 1:
170
            /* Delete all temporary soft fonts. */
171
32.8k
            pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false);
172
32.8k
            while (pl_dict_enum_next(&denum, &key, &value))
173
14
                if (((pl_font_t *) value)->storage == pcds_temporary) {
174
14
                    code = pcl_delete_soft_font(pcs, key.data, key.size, value);
175
14
                    if (code < 0)
176
0
                        return code;
177
                    /* Since deleting the softfont also deletes any "synonyms" in
178
                       the dictionary, it means the dictionary contents can change
179
                       under our feet.
180
                       The simplest solution is to start the enumeration with
181
                       a clean slate. This isn't used often enough for the
182
                       efficiency to be a worry.
183
                     */
184
14
                    pl_dict_enum_stack_begin(&pcs->soft_fonts, &denum, false);
185
14
                }
186
32.8k
            break;
187
32.8k
        case 2:
188
            /* Delete soft font <font_id>. */
189
1
            code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE,
190
1
                                 NULL);
191
            /* decache the currently selected font in case we deleted it. */
192
1
            pcl_decache_font(pcs, -1, true);
193
194
1
            break;
195
3
        case 3:
196
            /* Delete character <font_id, character_code>. */
197
3
            if (pl_dict_find_no_stack
198
3
                (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE,
199
3
                 &value))
200
0
                pl_font_remove_glyph((pl_font_t *) value,
201
0
                                     pcs->character_code);
202
3
            return 0;
203
204
0
            break;
205
1
        case 4:
206
            /* Make soft font <font_id> temporary. */
207
1
            if (pl_dict_find_no_stack
208
1
                (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE,
209
1
                 &value))
210
0
                ((pl_font_t *) value)->storage = pcds_temporary;
211
212
1
            break;
213
0
        case 5:
214
            /* Make soft font <font_id> permanent. */
215
0
            if (pl_dict_find_no_stack
216
0
                (&pcs->soft_fonts, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE,
217
0
                 &value)) {
218
0
                ((pl_font_t *) value)->storage = pcds_permanent;
219
0
                ((pl_font_t *) value)->params.pjl_font_number =
220
0
                    pjl_proc_register_permanent_soft_font_addition(pcs->pjls);
221
0
            }
222
0
            break;
223
0
        case 6:
224
0
            {
225
0
                if (pcs->font == 0) {
226
0
                    code = pcl_recompute_font(pcs, false);
227
0
                    if (code < 0)
228
0
                        return code;
229
0
                }
230
0
                if (pcs->font->storage == pcds_internal) {
231
0
                    return pcl_make_resident_font_copy(pcs);
232
0
                } else {
233
0
                    pl_font_t *plfont = pl_clone_font(pcs->font,
234
0
                                                      pcs->memory,
235
0
                                                      "pcl_font_control()");
236
237
0
                    if (plfont == 0) {
238
0
                        dmprintf(pcs->memory, "pcsfont.c clone font FIXME\n");
239
0
                        return 0;
240
0
                    }
241
0
                    code = gs_definefont(pcs->font_dir, plfont->pfont);
242
0
                    if (code < 0)
243
0
                        return code;
244
0
                    if (plfont->scaling_technology == plfst_TrueType)
245
0
                        code = pl_fapi_passfont(plfont, 0, NULL, NULL, NULL, 0);
246
0
                    if (code < 0)
247
0
                        return code;
248
249
0
                    code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID,
250
0
                                         CURRENT_FONT_ID_SIZE, NULL);
251
0
                    if (code < 0)
252
0
                        return code;
253
0
                    plfont->storage = pcds_temporary;
254
0
                    plfont->data_are_permanent = false;
255
0
                    code = pl_dict_put(&pcs->soft_fonts, CURRENT_FONT_ID,
256
0
                                CURRENT_FONT_ID_SIZE, plfont);
257
0
                }
258
0
            }
259
0
            break;
260
52
        default:
261
52
            return 0;
262
33.1k
    }
263
33.1k
    return code;
264
33.1k
}
265
266
#ifdef DEBUG
267
static void
268
dump_dl_font_header(const gs_memory_t * mem, const pcl_font_header_t *pfh)
269
{
270
    const char *header_format;
271
    int i;
272
273
    dmprintf1(mem, "FontDescriptorSize:%d\n", pl_get_uint16(pfh->FontDescriptorSize));
274
275
    switch (pfh->HeaderFormat) {
276
    case pcfh_bitmap:
277
        header_format = "bitmap";
278
        break;
279
    case pcfh_resolution_bitmap:
280
        header_format = "resolution bitmap";
281
        break;
282
    case pcfh_intellifont_bound:
283
        header_format = "bound intellifont";
284
        break;
285
    case pcfh_intellifont_unbound:
286
        header_format = "unbound intellifont";
287
        break;
288
    case pcfh_truetype:
289
        header_format = "truetype";
290
        break;
291
    case pcfh_truetype_large:
292
        header_format = "truetype large";
293
        break;
294
    default:
295
        header_format = "unknown";
296
    }
297
    dmprintf1(mem, "Header Format:%s\n", header_format);
298
    dmprintf1(mem, "Font Type:%d\n", (pl_font_type_t) pfh->FontType);
299
    dmprintf1(mem, "Style:%d\n", (pfh->StyleMSB << 8) + pfh->StyleLSB);
300
    dmprintf1(mem, "BaseLinePostion:%d\n", pl_get_uint16(pfh->BaselinePosition));
301
    dmprintf1(mem, "Reserved (should be 0):%d\n", pfh->Reserved);
302
    dmprintf1(mem, "CellWidth:%d\n", pl_get_uint16(pfh->CellWidth));
303
    dmprintf1(mem, "CellHeight:%d\n", pl_get_uint16(pfh->CellHeight));
304
    dmprintf1(mem, "Orientation:%d\n", pfh->Orientation);
305
    dmprintf1(mem, "Spacing:%d\n", pfh->Spacing);
306
    dmprintf1(mem, "SymbolSet:%d\n", pl_get_uint16(pfh->SymbolSet));
307
    dmprintf1(mem, "Pitch:%d\n", pl_get_uint16(pfh->Pitch));
308
    dmprintf1(mem, "Height:%d\n", pl_get_uint16(pfh->Height));
309
    dmprintf1(mem, "xHeight:%d\n", pl_get_uint16(pfh->xHeight));
310
    dmprintf1(mem, "WidthType:%d\n", pfh->WidthType);
311
    dmprintf1(mem, "StrokeWeight:%d\n", pfh->StrokeWeight);
312
    dmprintf1(mem, "TypeFace:%d\n", (pfh->TypefaceMSB << 8) + pfh->TypefaceLSB);
313
    dmprintf1(mem, "SerifStyle:%d\n", pfh->SerifStyle);
314
    dmprintf1(mem, "Quality:%d\n", pfh->Quality);
315
    dmprintf1(mem, "Placement:%d\n", pfh->Placement);
316
    dmprintf1(mem, "UnderlinePosition:%d\n", pfh->UnderlinePosition);
317
    dmprintf1(mem, "UnderlineThickness:%d\n", pfh->UnderlineThickness);
318
    dmprintf1(mem, "TextHeight:%d\n", pl_get_uint16(pfh->TextHeight));
319
    dmprintf1(mem, "TextWidth:%d\n", pl_get_uint16(pfh->TextWidth));
320
    dmprintf1(mem, "FirstCode:%d\n", pl_get_uint16(pfh->FirstCode));
321
    dmprintf1(mem, "LastCode:%d\n", pl_get_uint16(pfh->LastCode));
322
323
    dmprintf1(mem, "PitchExtended:%d\n", pfh->PitchExtended);
324
    dmprintf1(mem, "HeightExtended:%d\n", pfh->HeightExtended);
325
    dmprintf1(mem, "CapHeight:%d\n", pl_get_uint16(pfh->CapHeight));
326
    dmprintf4(mem, "FontNumber:%d %d %d %d\n", pfh->FontNumber[0],
327
              pfh->FontNumber[1], pfh->FontNumber[2], pfh->FontNumber[3]);
328
    dmprintf(mem, "FontName:");
329
    for (i = 0; i < sizeof(pfh->FontName); i++) {
330
        unsigned char c = pfh->FontName[i];
331
        if (c < 32 || c == 127)
332
            dmprintf1(mem, "<%02x>", c);
333
        else
334
            dmprintf1(mem, "%c", c);
335
    }
336
    dmprintf(mem, "\n");
337
    if (pfh->HeaderFormat == pcfh_resolution_bitmap) {
338
#define pfhx ((const pcl_resolution_bitmap_header_t *)pfh)
339
        dmprintf1(mem, "XResolution:%d\n", pl_get_uint16(pfhx->XResolution));
340
        dmprintf1(mem, "YResolution:%d\n", pl_get_uint16(pfhx->YResolution));
341
#undef pfhx
342
    }
343
344
    return;
345
}
346
#endif
347
static int                      /* ESC ) s <count> W */
348
pcl_font_header(pcl_args_t * pargs, pcl_state_t * pcs)
349
113
{
350
113
    uint count = uint_arg(pargs);
351
113
    const byte *data = arg_data(pargs);
352
113
    pcl_font_header_t *pfh = (pcl_font_header_t *) data;
353
113
    uint desc_size;
354
113
    pl_font_scaling_technology_t fst;
355
113
    gs_memory_t *mem = pcs->memory;
356
113
    pl_font_t *plfont;
357
113
    byte *header;
358
113
    int code;
359
113
    bool has_checksum;
360
361
#ifdef DEBUG
362
    if (gs_debug_c('i')) {
363
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
364
    }
365
#endif
366
367
113
    if (count < 64 && pfh->HeaderFormat != pcfh_bitmap)
368
8
        return e_Range;         /* pcfh_bitmap defaults short headers to 0 except underline position = 5; */
369
#ifdef DEBUG
370
    if (gs_debug_c('=')) {
371
        dump_dl_font_header(pcs->memory, pfh);
372
    }
373
#endif
374
105
    desc_size =
375
105
        (pfh->FontDescriptorSize[0] << 8) + pfh->FontDescriptorSize[1];
376
    /* Dispatch on the header format. */
377
105
    switch (pfh->HeaderFormat) {
378
105
        case pcfh_bitmap:
379
105
        case pcfh_resolution_bitmap:
380
105
            fst = plfst_bitmap;
381
105
            has_checksum = false;
382
105
            break;
383
0
        case pcfh_intellifont_bound:
384
0
        case pcfh_intellifont_unbound:
385
0
            fst = plfst_Intellifont;
386
            /* intellifonts do have a checksum but we have seen
387
               several fonts in tests that don't follow the
388
               documentation.  It is possible intellifonts use a
389
               different offset than truetype to begin the summation.
390
               We have not investigated. */
391
0
            has_checksum = false;
392
0
            break;
393
0
        case pcfh_truetype:
394
0
        case pcfh_truetype_large:
395
0
            fst = plfst_TrueType;
396
0
            has_checksum = true;
397
0
            break;
398
0
        default:
399
0
#ifdef IGNORE_BAD_HEADER_FORMAT_SPECIFIER
400
0
            return 0;
401
#else
402
            return_error(gs_error_invalidfont);
403
#endif
404
405
105
    }
406
407
    /* Fonts should include a final byte that makes the sum of the
408
       bytes in the font 0 (mod 256).  The hp documentation says
409
       byte 64 and up should contribute to the checksum.  All
410
       known examples indicate byte 64 (index 63 of the array
411
       below) is not included. */
412
105
    if (has_checksum) {
413
0
        ulong sum = 0;
414
0
        int i;
415
416
0
        for (i = count - 1; i >= 64; i--) {
417
0
            sum += data[i];
418
0
            sum %= 256;
419
0
        }
420
421
0
        if (sum != 0) {
422
0
            dmprintf1(pcs->memory, "corrupt font sum=%ld\n", sum);
423
0
            return_error(gs_error_invalidfont);
424
0
        }
425
0
    }
426
    /* Delete any previous font with this ID. */
427
105
    code = pcl_delete_soft_font(pcs, CURRENT_FONT_ID, CURRENT_FONT_ID_SIZE, NULL);
428
105
    if (code < 0)
429
0
        return code;
430
    /* Create the generic font information. */
431
105
    plfont = pl_alloc_font(mem, "pcl_font_header(pl_font_t)");
432
#ifdef DEBUG
433
    {
434
        int i;
435
        for (i = 0; i < sizeof(pfh->FontName); i++)
436
            plfont->FontName[i] = pfh->FontName[i];
437
    }
438
#endif
439
105
    header = gs_alloc_bytes(mem, count, "pcl_font_header(header)");
440
105
    if (plfont == NULL || header == NULL) {
441
0
        gs_free_object(mem, header, "pcl_font_header(header)");
442
0
        gs_free_object(mem, plfont, "pcl_font_header(pl_font_t)");
443
0
        return_error(e_Memory);
444
0
    }
445
105
    memcpy(header, data, count);
446
105
    plfont->storage = pcds_temporary;
447
105
    plfont->data_are_permanent = false;
448
105
    if (fst == plfst_Intellifont) {
449
0
        if (pfh->HeaderFormat != pcfh_intellifont_bound) {
450
            /* copy in the compliment while we are here. */
451
0
            memcpy(plfont->character_complement, &data[78], 8);
452
0
        }
453
0
    }
454
105
    plfont->header = header;
455
105
    plfont->header_size = count;
456
105
    plfont->is_xl_format = false;
457
105
    plfont->scaling_technology = fst;
458
105
    plfont->font_type = (pl_font_type_t) pfh->FontType;
459
105
    plfont->font_file = (char *)0;
460
105
    code = pl_font_alloc_glyph_table(plfont, 256, mem,
461
105
                                     "pcl_font_header(char table)");
462
105
    if (code < 0)
463
0
        goto fail;
464
    /* Create the actual font. */
465
105
    switch (fst) {
466
105
        case plfst_bitmap:
467
105
            {
468
105
                gs_font_base *pfont;
469
470
105
              bitmap:pfont = gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
471
105
                                        "pcl_font_header(bitmap font)");
472
473
105
                if (pfont == NULL) {
474
0
                    code = e_Memory;
475
0
                    goto fail;
476
0
                }
477
105
                code =
478
105
                    pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir,
479
105
                                    mem, "nameless_font");
480
105
                if (code < 0)
481
0
                    goto fail;
482
105
                pl_fill_in_bitmap_font(pfont, gs_next_ids(mem, 1));
483
                /* Extract parameters from the font header. */
484
105
                if (pfh->HeaderFormat == pcfh_resolution_bitmap) {
485
0
#define pfhx ((const pcl_resolution_bitmap_header_t *)pfh)
486
0
                    plfont->resolution.x = pl_get_uint16(pfhx->XResolution);
487
0
                    plfont->resolution.y = pl_get_uint16(pfhx->YResolution);
488
0
#undef pfhx
489
0
                }
490
                /* note that we jump to the bitmap label for type 16 - so
491
                   called truetype large which can also be bitmap but its
492
                   resolution field is filled in when scanning the
493
                   segments (see pl_font_scan_segments() the resolution
494
                   does not show up in the font header. */
495
105
                else if (pfh->HeaderFormat == pcfh_bitmap)
496
105
                    plfont->resolution.x = plfont->resolution.y = 300;
497
105
                {
498
105
                    ulong pitch_1024th_dots =
499
105
                        ((ulong) pl_get_uint16(pfh->Pitch) << 8) +
500
105
                        pfh->PitchExtended;
501
105
                    double pitch_cp = (double)
502
105
                        (pitch_1024th_dots / 1024.0     /* dots */
503
105
                         / plfont->resolution.x /* => inches */
504
105
                         * 7200.0);
505
506
105
                    pl_fp_set_pitch_cp(&plfont->params, pitch_cp);
507
105
                }
508
105
                {
509
105
                    uint height_quarter_dots = pl_get_uint16(pfh->Height);
510
511
105
                    plfont->params.height_4ths =
512
105
                        (uint) (floor((double)height_quarter_dots * 72.0 /
513
105
                                      (double)(plfont->resolution.x) + 0.5));
514
105
                }
515
105
                break;
516
105
            }
517
0
        case plfst_TrueType:
518
0
            {
519
520
0
                gs_font_type42 *pfont;
521
522
0
                {
523
0
                    static const pl_font_offset_errors_t errors = {
524
0
                        gs_error_invalidfont, 0
525
0
                    };
526
0
                    code =
527
0
                        pl_font_scan_segments(mem, plfont, 70, desc_size,
528
0
                                              (ulong) count - 2,
529
0
                                              pfh->HeaderFormat ==
530
0
                                              pcfh_truetype_large, &errors);
531
0
                    if (code < 0)
532
0
                        goto fail;
533
                    /* truetype large format 16 can be truetype or bitmap -
534
                       absurd */
535
0
                    if ((pfh->HeaderFormat == pcfh_truetype_large) &&
536
0
                        (plfont->scaling_technology == plfst_bitmap))
537
0
                        goto bitmap;
538
539
0
                }
540
0
                pfont =
541
0
                    gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42,
542
0
                                    "pcl_font_header(truetype font)");
543
0
                if (pfont == NULL) {
544
0
                    code = e_Memory;
545
0
                    goto fail;
546
0
                }
547
548
0
                code =
549
0
                    pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir,
550
0
                                    mem, "nameless_font");
551
0
                if (code < 0)
552
0
                    goto fail;
553
554
0
                {
555
0
                    uint num_chars = pl_get_uint16(pfh->LastCode);
556
557
0
                    if (num_chars < 20)
558
0
                        num_chars = 20;
559
0
                    else if (num_chars > 300)
560
0
                        num_chars = 300;
561
0
                    code = pl_tt_alloc_char_glyphs(plfont, num_chars, mem,
562
0
                                                   "pcl_font_header(char_glyphs)");
563
0
                    if (code < 0)
564
0
                        goto fail;
565
0
                }
566
0
                code = pl_fill_in_tt_font(pfont, NULL, gs_next_ids(mem, 1));
567
0
                if (code < 0)
568
0
                    goto fail;
569
0
                {
570
0
                    uint pitch_cp =
571
0
                        (uint) (pl_get_uint16(pfh->Pitch) * 1000.0 /
572
0
                                pfont->data.unitsPerEm);
573
0
                    pl_fp_set_pitch_cp(&plfont->params, pitch_cp);
574
0
                }
575
0
            }
576
0
            break;
577
0
        case plfst_Intellifont:
578
0
            {
579
0
                gs_font_base *pfont =
580
0
                    gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
581
0
                                    "pcl_font_header(bitmap font)");
582
583
0
                if (pfont == NULL) {
584
0
                    code = e_Memory;
585
0
                    goto fail;
586
0
                }
587
0
                code =
588
0
                    pl_fill_in_font((gs_font *) pfont, plfont, pcs->font_dir,
589
0
                                    mem, "nameless_font");
590
0
                if (code < 0)
591
0
                    goto fail;
592
0
                pl_fill_in_intelli_font(pfont, gs_next_ids(mem, 1));
593
0
                {
594
0
                    uint pitch_cp =
595
0
                        (uint) (pl_get_uint16(pfh->Pitch) * 1000.0 / 8782.0);
596
0
                    pl_fp_set_pitch_cp(&plfont->params, pitch_cp);
597
0
                }
598
0
                break;
599
0
            }
600
0
        default:
601
0
            code = gs_error_invalidfont; /* can't happen */
602
0
            goto fail;
603
105
    }
604
    /* Extract common parameters from the font header. */
605
105
    plfont->params.symbol_set = pl_get_uint16(pfh->SymbolSet);
606
105
    if (pfh->Spacing > 1) {
607
8
        code = e_Range;
608
8
        goto fail;
609
8
    }
610
97
    plfont->params.proportional_spacing = pfh->Spacing;
611
97
    plfont->params.style = (pfh->StyleMSB << 8) + pfh->StyleLSB;
612
97
    plfont->params.stroke_weight =      /* signed byte */
613
97
        (int)(pfh->StrokeWeight ^ 0x80) - 0x80;
614
97
    plfont->params.typeface_family =
615
97
        (pfh->TypefaceMSB << 8) + pfh->TypefaceLSB;
616
97
    plfont->params.pjl_font_number = pcs->pjl_dlfont_number++;
617
618
97
    code = pl_dict_put(&pcs->soft_fonts, CURRENT_FONT_ID,
619
97
                CURRENT_FONT_ID_SIZE, plfont);
620
97
    if (code < 0) {
621
        /* on error, pl_dict_put consumes plfont */
622
0
        return code;
623
0
    }
624
97
    plfont->pfont->procs.define_font = gs_no_define_font;
625
626
97
    if ((code = gs_definefont(pcs->font_dir, plfont->pfont)) != 0) {
627
0
        goto fail;
628
0
    }
629
630
97
    if (plfont->scaling_technology == plfst_TrueType)
631
0
        code = pl_fapi_passfont(plfont, 0, NULL, NULL, NULL, 0);
632
633
97
    return code;
634
635
8
fail:
636
8
    if (code < 0)
637
0
        pl_free_font(mem, plfont, "pcl_font_header(pl_font_t)");
638
639
8
    return (code);
640
97
}
641
642
static int                      /* ESC * c <char_code> E */
643
pcl_character_code(pcl_args_t * pargs, pcl_state_t * pcs)
644
1.67k
{
645
1.67k
    pcs->character_code = uint_arg(pargs);
646
1.67k
    return 0;
647
1.67k
}
648
649
static int                      /* ESC ( s <count> W */
650
pcl_character_data(pcl_args_t * pargs, pcl_state_t * pcs)
651
1.37k
{
652
1.37k
    uint count = uint_arg(pargs);
653
1.37k
    uint font_data_size = count;
654
1.37k
    const byte *data = arg_data(pargs);
655
1.37k
    void *value;
656
1.37k
    pl_font_t *plfont;
657
1.37k
    pcl_font_header_format_t format;
658
1.37k
    byte *char_data = 0;
659
1.37k
    int code;
660
661
#ifdef DEBUG
662
    if (gs_debug_c('i')) {
663
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
664
    }
665
#endif
666
667
1.37k
    if (!pl_dict_find_no_stack(&pcs->soft_fonts, CURRENT_FONT_ID,
668
1.37k
                               CURRENT_FONT_ID_SIZE, &value))
669
465
        return 0;               /* font not found */
670
671
913
    plfont = ((pl_font_t *) value);
672
673
913
    if (count < 4 || data[2] > count - 2)
674
2
        goto fail_range;
675
911
    if (data[1]) {              /* continuation */
676
        /* Check that we are continuing data - we know this is the
677
           case if the previous download character command byte count
678
           is smaller than the data indicated calculating the space
679
           for the glyph */
680
0
        if ((pcs->soft_font_char_data == 0))
681
0
            goto fail_range;
682
        /* NB we only enable this for uncompressed bitmap
683
           characters for now, since we don't have real world
684
           examples for the other font file formats.  */
685
0
        if (data[0] != pccd_bitmap && data[3] != 1) {
686
0
            dmprintf(pcs->memory,
687
0
                     "continuation not implemented for this font type\n");
688
0
            return e_Unimplemented;
689
0
        }
690
        /* check for buffer overrun */
691
0
        if (pcs->soft_font_count + count - 2 > gs_object_size(pcs->memory, pcs->soft_font_char_data))
692
0
            goto fail_range;
693
694
        /* append the new data to the new object */
695
0
        memcpy(pcs->soft_font_char_data + pcs->soft_font_count, data + 2,
696
0
               count - 2);
697
        /* update the continuation count */
698
0
        pcs->soft_font_count += (count - 2);
699
0
        return 0;
700
911
    } else {
701
911
        pcs->soft_font_count = 0;
702
911
        pcs->soft_font_char_data = 0;
703
911
    }
704
911
    format = (pcl_font_header_format_t)
705
911
        ((const pcl_font_header_t *)plfont->header)->HeaderFormat;
706
911
    switch (data[0]) {
707
908
        case pccd_bitmap:
708
908
            {
709
908
                uint width, height;
710
711
908
                if (data[2] != 14 ||
712
907
                    (format != pcfh_bitmap &&
713
0
                     format != pcfh_resolution_bitmap &&
714
0
                     format != pcfh_truetype_large)
715
908
                    )
716
1
                    goto fail_range;
717
718
907
                width = pl_get_uint16(data + 10);
719
907
                if (width < 1 || width > 16384)
720
2
                    goto fail_range;
721
905
                height = pl_get_uint16(data + 12);
722
905
                if (height < 1 || height > 16384)
723
23
                    goto fail_range;
724
                /* more error checking of offsets, delta, width and height. */
725
882
                {
726
882
                    int toff, loff;
727
882
                    int deltax;
728
729
882
                    loff = pl_get_int16(data + 6);
730
882
                    if ((-16384 > loff) || (loff > 16384))
731
1
                        goto fail_range;
732
881
                    toff = pl_get_int16(data + 8);
733
881
                    if ((-16384 > toff) || (toff > 16384))
734
0
                        goto fail_range;
735
881
                    deltax = pl_get_int16(data + 14);
736
881
                    if ((-32768 > deltax) || (deltax > 32767))
737
0
                        goto fail_range;
738
                    /* also reject if width * height larger than 1MByte */
739
881
                    if ((width * height / 8) > 1024 * 1024)
740
3
                        goto fail_range;
741
881
                }
742
743
878
                switch (data[3]) {
744
876
                    case 1:    /* uncompressed bitmap */
745
876
                        font_data_size = 16 + (((width + 7) >> 3) * height);
746
876
                        break;
747
0
                    case 2:    /* compressed bitmap */
748
0
                        {
749
0
                            uint y = 0;
750
0
                            const byte *src = data + 16;
751
0
                            const byte *end = data + count;
752
0
                            uint width_bytes = (width + 7) >> 3;
753
0
                            byte *row;
754
755
0
                            font_data_size = 16 + width_bytes * height;
756
757
0
                            char_data =
758
0
                                gs_alloc_bytes(pcs->memory,
759
0
                                               font_data_size,
760
0
                                               "pcl_character_data(compressed bitmap)");
761
0
                            if (char_data == 0)
762
0
                                return_error(e_Memory);
763
0
                            memcpy(char_data, data, 16);
764
0
                            memset(char_data + 16, 0, (size_t)width_bytes * height);
765
0
                            row = char_data + 16;
766
0
                            while (src < end && y < height) {   /* Read the next compressed row. */
767
0
                                uint x;
768
0
                                int color = 0;
769
0
                                uint reps = *src++;
770
771
0
                                for (x = 0; src < end && x < width; color ^= 1) {       /* Read the next run. */
772
0
                                    uint rlen = *src++;
773
774
0
                                    if (rlen > width - x)
775
0
                                        goto fail_range; /* row overrun */
776
0
                                    if (color) {        /* Set the run to black. */
777
0
                                        char *data = (char *)row;
778
779
0
                                        while (rlen--) {
780
0
                                            data[x >> 3] |= (128 >> (x & 7));
781
0
                                            x++;
782
0
                                        }
783
0
                                    } else
784
0
                                        x += rlen;
785
0
                                }
786
0
                                row += width_bytes;
787
0
                                ++y;
788
                                /* Replicate the row if needed. */
789
0
                                for (; reps > 0 && y < height;
790
0
                                     --reps, ++y, row += width_bytes)
791
0
                                    memcpy(row, row - width_bytes,
792
0
                                           width_bytes);
793
0
                            }
794
0
                        }
795
0
                        break;
796
2
                    default:
797
2
                        goto fail_range;
798
878
                }
799
878
            }
800
876
            break;
801
876
        case pccd_intellifont:
802
0
            if (data[2] != 2 ||
803
0
                (format != pcfh_intellifont_bound &&
804
0
                 format != pcfh_intellifont_unbound)
805
0
                )
806
0
                goto fail_range;
807
0
            switch (data[3]) {
808
0
                case 3:        /* non-compound character */
809
                    /* See TRM Table 11-41 (p. 11-60) for the following. */
810
0
                    if (count < 14)
811
0
                        goto fail_range;
812
0
                    {
813
0
                        uint data_size = pl_get_uint16(data + 4);
814
815
                        /* The contour data excludes 4 initial bytes of header */
816
                        /* and 2 final bytes of padding/checksum. */
817
0
                        if (data_size != count - 6)
818
0
                            goto fail_range;
819
0
                    }
820
0
                    break;
821
0
                case 4:        /* compound character */
822
                    /* See TRM Figure 11-42 and 11-43 (p. 11-61) */
823
                    /* for the following. */
824
0
                    if (count < 8)
825
0
                        goto fail_range;
826
0
                    {
827
0
                        uint num_components = data[6];
828
829
0
                        if (count != 8 + num_components * 6 + 2)
830
0
                            goto fail_range;
831
0
                    }
832
0
                    break;
833
0
                default:
834
0
                    goto fail_range;
835
0
            }
836
0
            break;
837
0
        case pccd_truetype:
838
0
            if (format != pcfh_truetype && format != pcfh_truetype_large)
839
0
                goto fail_range;
840
0
            break;
841
3
        default:
842
3
            goto fail_range;
843
911
    }
844
    /* Register the character. */
845
    /**** FREE PREVIOUS DEFINITION ****/
846
    /* Compressed bitmaps have already allocated and filled in */
847
    /* the character data structure. */
848
876
    if (char_data == 0) {
849
876
        char_data = gs_alloc_bytes(pcs->memory, font_data_size,
850
876
                                   "pcl_character_data");
851
876
        if (char_data == 0)
852
0
            return_error(e_Memory);
853
876
        memset(char_data, 0, font_data_size);
854
        /* if count > font_data_size extra data is ignored */
855
876
        memcpy(char_data, data, min(count, font_data_size));
856
        /* NB we only handle continuation for uncompressed bitmap characters */
857
876
        if (data[0] == pccd_bitmap && data[3] == 1 && font_data_size > count    /* expecting continuation */
858
876
            ) {
859
9
            pcs->soft_font_char_data = char_data;
860
9
            pcs->soft_font_count = count;
861
867
        } else {
862
867
            pcs->soft_font_char_data = 0;
863
867
            pcs->soft_font_count = 0;
864
867
        }
865
876
    }
866
    /* get and set the orientation field */
867
876
    {
868
876
        pcl_font_header_t *header = (pcl_font_header_t *) plfont->header;
869
870
876
        plfont->orient = header->Orientation;
871
876
    }
872
876
    code = pl_font_add_glyph(plfont, pcs->character_code, char_data, font_data_size);
873
876
    if (code < 0) {
874
0
        gs_free_object(pcs->memory, char_data, "pcl_character_data");
875
0
        return code;
876
0
    }
877
876
#ifdef DISABLE_USE_MY_METRICS
878
876
    if (data[0] == pccd_truetype)
879
0
        code = pl_font_disable_composite_metrics(plfont, pcs->character_code);
880
876
#endif /* DISABLE_USE_MY_METRICS */
881
876
    return code;
882
0
#undef plfont
883
884
37
    fail_range:
885
37
    gs_free_object(pcs->memory, char_data, "pcl_character_data");
886
37
    return e_Range;
887
876
}
888
889
/* template for casting data to command */
890
typedef struct alphanumeric_data_s
891
{
892
    byte operation;
893
    byte string_id[512];
894
} alphanumeric_data_t;
895
896
typedef enum resource_type_enum
897
{
898
    macro_resource,
899
    font_resource
900
} resource_type_t;
901
902
/*
903
 * Search the PJL file system for a macro or font resource and
904
 * associate it's name with the current font or macro id
905
 */
906
static int
907
pcl_find_resource(pcl_state_t * pcs,
908
                  const byte sid[],
909
                  int sid_size, resource_type_t resource_type)
910
0
{
911
912
0
    void *value = NULL;
913
0
    char alphaname[512 + 1];
914
0
    long int size;
915
0
    int c;
916
0
    int code = 0;
917
918
    /* a null terminated string is needed for the PJL resource call */
919
0
    for (c = 0; c < sid_size && c < 512; c++)
920
0
        alphaname[c] = sid[c];
921
0
    alphaname[c] = '\0';
922
923
0
    size = pjl_proc_get_named_resource_size(pcs->pjls, alphaname);
924
    /* resource not found */
925
0
    if (size <= 0)
926
0
        return 0;
927
928
    /* for a macro we need enough room for the macro header plus the
929
       macro itself, fonts are handled differently, see below */
930
0
    value = gs_alloc_bytes(pcs->memory,
931
0
                           size +
932
0
                           (resource_type == macro_resource ?
933
0
                            sizeof(pcl_macro_t) : 0),
934
0
                           "resource");
935
936
0
    if (value == NULL)
937
0
        return_error(gs_error_Fatal);
938
939
940
0
    if (pjl_proc_get_named_resource(pcs->pjls, alphaname,
941
0
                                        (byte *) value +
942
0
                                        (resource_type == macro_resource ?
943
0
                                         sizeof(pcl_macro_t) : 0), size) < 0) {
944
0
        gs_free_object(pcs->memory, value, "resource");
945
0
        return_error(gs_error_Fatal);
946
0
    }
947
948
    /* if this is a font we have to recursively invoke the PCL
949
       interpreter to process the data and create the downloaded
950
       font. */
951
0
    if (resource_type == font_resource) {
952
0
        stream_cursor_read r;
953
0
        pcl_parser_state_t state;
954
955
0
        r.ptr = (byte *)value - 1;
956
0
        r.limit = r.ptr + size;
957
0
        state.definitions = pcs->pcl_commands;
958
0
        code = pcl_process_init(&state, pcs);
959
0
        if (code < 0 || (code = pcl_process(&state, pcs, &r) < 0)) {
960
0
            gs_free_object(pcs->memory, value, "resource");
961
0
            return_error(code);
962
0
        }
963
0
    }
964
965
    /* The font resource was added to the dictionary when the font was
966
       downloaded in the recursive interpreter invocation above, so we
967
       don't need to add (put) it in the dictionary. */
968
0
    if (resource_type == macro_resource) {
969
0
        code = pl_dict_put(&pcs->macros, CURRENT_MACRO_ID, CURRENT_MACRO_ID_SIZE, value);
970
0
        if (code < 0) {
971
0
            gs_free_object(pcs->memory, value, "resource");
972
0
            return code;
973
0
        }
974
0
        code = pl_dict_put_synonym(&pcs->macros, CURRENT_MACRO_ID,
975
0
                                       CURRENT_MACRO_ID_SIZE, sid, sid_size);
976
0
        if (code < 0) {
977
0
            pl_dict_undef_purge_synonyms(&pcs->macros, CURRENT_MACRO_ID, CURRENT_MACRO_ID_SIZE);
978
0
            return code;
979
0
        }
980
0
    } else {
981
0
        code = pl_dict_put_synonym(&pcs->soft_fonts, CURRENT_FONT_ID,
982
0
                                   CURRENT_FONT_ID_SIZE, sid, sid_size);
983
        /* font was constructed separately, don't need the
984
           original PCL commands from which the font was
985
           constructed. */
986
0
        gs_free_object(pcs->memory, value, "resource");
987
0
        if (code < 0)
988
0
            return_error(code);
989
0
    }
990
0
    return code;
991
0
}
992
993
static int                      /* ESC & n <count> W [operation][string ID] */
994
pcl_alphanumeric_id_data(pcl_args_t * pargs, pcl_state_t * pcs)
995
0
{
996
0
    uint count = uint_arg(pargs);
997
998
0
    const alphanumeric_data_t *alpha_data =
999
0
        (const alphanumeric_data_t *)arg_data(pargs);
1000
1001
0
    int string_id_size = (count - 1);   /* size of id data size - operation size */
1002
1003
#ifdef DEBUG
1004
    if (gs_debug_c('i')) {
1005
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
1006
    }
1007
#endif
1008
1009
0
    if (count == 0)
1010
0
        return 0;
1011
0
    if (count < 1 || count > 512)
1012
0
        return e_Range;
1013
0
    switch (alpha_data->operation) {
1014
0
        case 0:
1015
            /* Set the current font id to the given string id. */
1016
0
            {
1017
0
                char *new_id =
1018
0
                    (char *)gs_alloc_bytes(pcs->memory, string_id_size,
1019
0
                                           "pcl_alphanumeric_id_data");
1020
1021
0
                if (new_id == 0)
1022
0
                    return_error(e_Memory);
1023
                /* release the previous id, if necessary */
1024
0
                if (pcs->alpha_font_id.id)
1025
0
                    gs_free_object(pcs->memory,
1026
0
                                   pcs->alpha_font_id.id,
1027
0
                                   "pcl_free_string_id");
1028
                /* copy in the new id from the data */
1029
0
                memcpy(new_id, alpha_data->string_id, string_id_size);
1030
                /* set new id and size */
1031
0
                pcs->alpha_font_id.id = (byte *) new_id;
1032
0
                pcs->alpha_font_id.size = string_id_size;
1033
                /* now set up the state to use string id's */
1034
0
                pcs->font_id_type = string_id;
1035
0
            }
1036
0
            break;
1037
0
        case 1:
1038
0
            {
1039
                /* Associates the current font's font id to the font
1040
                   with the string id. */
1041
0
                void *value;
1042
                /* simple case the font is in the dictionary */
1043
0
                if (pl_dict_find_no_stack(&pcs->soft_fonts, alpha_data->string_id, string_id_size, &value)) {
1044
0
                    (void)pl_dict_put_synonym(&pcs->soft_fonts, alpha_data->string_id,
1045
0
                                               string_id_size, CURRENT_FONT_ID,
1046
0
                                               CURRENT_FONT_ID_SIZE);
1047
0
                    return 0;
1048
0
                } else {
1049
                    /* search the PJL file system for a font resource */
1050
0
                    return pcl_find_resource(pcs, alpha_data->string_id,
1051
0
                                             string_id_size, font_resource);
1052
0
                }
1053
0
            }
1054
0
            break;
1055
0
        case 2:
1056
0
            {
1057
                /* Select the fonts referred to by the String ID as
1058
                   primary.  Same as font id selection but uses the
1059
                   string key instead of a numerical key */
1060
0
                void *value;
1061
0
                pcl_font_selection_t *pfs = &pcs->font_selection[primary];
1062
1063
0
                if (!pl_dict_find_no_stack(&pcs->soft_fonts,
1064
0
                                           alpha_data->string_id,
1065
0
                                           string_id_size, &value))
1066
0
                    return 1;
1067
                /* NB wrong */
1068
0
                pcl_set_id_parameters(pcs, pfs, (pl_font_t *) value, 0);
1069
0
                pcl_decache_font(pcs, -1, true);
1070
0
            }
1071
0
            break;
1072
0
        case 3:
1073
0
            {
1074
                /* same as case 2 but sets secondary font */
1075
0
                void *value;
1076
0
                pcl_font_selection_t *pfs = &pcs->font_selection[secondary];
1077
1078
0
                if (!pl_dict_find_no_stack(&pcs->soft_fonts,
1079
0
                                           alpha_data->string_id,
1080
0
                                           string_id_size, &value))
1081
0
                    return 1;
1082
                /* NB wrong */
1083
0
                pcl_set_id_parameters(pcs, pfs, (pl_font_t *) value, 0);
1084
0
                pcl_decache_font(pcs, -1, true);
1085
0
            }
1086
0
            break;
1087
0
        case 4:
1088
0
            {
1089
                /* sets the current macro id to the string id */
1090
0
                char *new_id =
1091
0
                    (char *)gs_alloc_bytes(pcs->memory, string_id_size,
1092
0
                                           "pcl_alphanumeric_id_data");
1093
1094
0
                if (new_id == 0)
1095
0
                    return_error(e_Memory);
1096
                /* release the previous id, if necessary */
1097
0
                if (pcs->alpha_macro_id.id)
1098
0
                    gs_free_object(pcs->memory,
1099
0
                                   pcs->alpha_macro_id.id,
1100
0
                                   "pcl_free_string_id");
1101
                /* copy in the new id from the data */
1102
0
                memcpy(new_id, alpha_data->string_id, string_id_size);
1103
                /* set new id and size */
1104
0
                pcs->alpha_macro_id.id = (byte *) new_id;
1105
0
                pcs->alpha_macro_id.size = string_id_size;
1106
                /* now set up the state to use string id's */
1107
0
                pcs->macro_id_type = string_id;
1108
0
            }
1109
0
            break;
1110
0
        case 5:
1111
0
            {
1112
                /* Associates the current macro's id with the string id. */
1113
0
                void *value;
1114
                /* simple case - the macro is in the dictionary */
1115
0
                if (pl_dict_find_no_stack(&pcs->macros, alpha_data->string_id, string_id_size, &value)) {
1116
0
                    (void)pl_dict_put_synonym(&pcs->macros, alpha_data->string_id,
1117
0
                                               string_id_size, CURRENT_MACRO_ID,
1118
0
                                               CURRENT_MACRO_ID_SIZE);
1119
0
                    return 0;
1120
0
                } else {
1121
                    /* search the PJL file system for a macro resource */
1122
0
                    return pcl_find_resource(pcs, alpha_data->string_id,
1123
0
                                             string_id_size, macro_resource);
1124
0
                }
1125
0
            }
1126
0
            break;
1127
0
        case 20:
1128
            /* deletes the font association named by the current Font ID */
1129
0
            if (pcs->font_id_type == string_id)
1130
0
                return pcl_delete_soft_font(pcs, CURRENT_FONT_STRING_ID,
1131
0
                                         CURRENT_FONT_STRING_ID_SIZE, NULL);
1132
0
            break;
1133
0
        case 21:
1134
            /* deletes the macro association named the the current macro id */
1135
0
            if (pcs->macro_id_type == string_id)
1136
0
                pl_dict_undef(&pcs->macros, CURRENT_MACRO_STRING_ID,
1137
0
                              CURRENT_MACRO_STRING_ID_SIZE);
1138
0
            break;
1139
0
        case 100:
1140
            /* media select */
1141
1142
            /* this is not sufficiently specified in the PCL
1143
               comparison guide and interacts with the control panel
1144
               so we do not implement it completely.  We have verified
1145
               the following occurs: */
1146
0
            {
1147
0
                int code = pcl_end_page_if_marked(pcs);
1148
0
                if (code < 0)
1149
0
                    return code;
1150
0
                return pcl_home_cursor(pcs);
1151
0
            }
1152
0
            break;
1153
0
        default:
1154
0
            return e_Range;
1155
0
    }
1156
0
    return 0;
1157
0
}
1158
1159
/* Initialization */
1160
static int
1161
pcsfont_do_registration(pcl_parser_state_t * pcl_parser_state,
1162
                        gs_memory_t * mem)
1163
16.1k
{                               /* Register commands */
1164
16.1k
    DEFINE_CLASS('*') {
1165
16.1k
    'c', 'D',
1166
16.1k
            PCL_COMMAND("Assign Font ID", pcl_assign_font_id,
1167
16.1k
                            pca_neg_error | pca_big_error)}, {
1168
16.1k
    'c', 'F',
1169
16.1k
            PCL_COMMAND("Font Control", pcl_font_control,
1170
16.1k
                            pca_neg_error | pca_big_error)},
1171
16.1k
        END_CLASS
1172
16.1k
        DEFINE_CLASS_COMMAND_ARGS(')', 's', 'W', "Font Header",
1173
16.1k
                                  pcl_font_header, pca_bytes)
1174
16.1k
        DEFINE_CLASS_COMMAND_ARGS('*', 'c', 'E', "Character Code",
1175
16.1k
                                  pcl_character_code,
1176
16.1k
                                  pca_neg_error | pca_big_ok)
1177
16.1k
        DEFINE_CLASS_COMMAND_ARGS('(', 's', 'W', "Character Data",
1178
16.1k
                                  pcl_character_data, pca_bytes)
1179
16.1k
        DEFINE_CLASS_COMMAND_ARGS('&', 'n', 'W', "Alphanumeric ID Data",
1180
16.1k
                                  pcl_alphanumeric_id_data, pca_bytes)
1181
16.1k
        return 0;
1182
16.1k
}
1183
static int
1184
pcsfont_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
1185
48.9k
{
1186
48.9k
    if (type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay)) {
1187
48.9k
        pcs->soft_font_char_data = 0;
1188
48.9k
        pcs->soft_font_count = 0;
1189
48.9k
        id_set_value(pcs->font_id, 0);
1190
48.9k
        pcs->character_code = 0;
1191
48.9k
        pcs->font_id_type = numeric_id;
1192
48.9k
        if ((type & pcl_reset_printer) != 0) {
1193
32.7k
            int code = 0;
1194
32.7k
            pcl_args_t args;
1195
1196
32.7k
            arg_set_uint(&args, 1);     /* delete temporary fonts */
1197
32.7k
            code = pcl_font_control(&args, pcs);
1198
32.7k
            if (pcs->alpha_font_id.id != 0)
1199
0
                gs_free_object(pcs->memory,
1200
32.7k
                               pcs->alpha_font_id.id, "pcsfont_do_reset");
1201
32.7k
            if (code < 0)
1202
0
                return code;
1203
32.7k
        }
1204
48.9k
        pcs->alpha_font_id.id = 0;
1205
48.9k
    }
1206
48.9k
    return 0;
1207
48.9k
}
1208
static int
1209
pcsfont_do_copy(pcl_state_t * psaved, const pcl_state_t * pcs,
1210
                pcl_copy_operation_t operation)
1211
0
{
1212
0
    if (operation & pcl_copy_after) {   /* Don't restore the soft font set. */
1213
0
        psaved->soft_fonts = pcs->soft_fonts;
1214
0
        psaved->built_in_fonts = pcs->built_in_fonts;
1215
0
    }
1216
0
    return 0;
1217
0
}
1218
const pcl_init_t pcsfont_init = {
1219
    pcsfont_do_registration, pcsfont_do_reset, pcsfont_do_copy
1220
};