Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pxl/pxfont.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
/* pxfont.c */
18
/* PCL XL font operators */
19
20
#include "math_.h"
21
#include "stdio_.h"
22
#include "string_.h"
23
#include "gdebug.h"
24
#include "plvalue.h"
25
#include "pxoper.h"
26
#include "pxstate.h"
27
#include "pxfont.h"
28
#include "gserrors.h"
29
#include "gsstruct.h"
30
#include "gschar.h"
31
#include "gspaint.h"
32
#include "gspath.h"
33
#include "gsstate.h"
34
#include "gscoord.h"
35
#include "gsimage.h"
36
#include "gsutil.h"             /* for string_match */
37
#include "gxfont.h"
38
#include "gxfont42.h"
39
#include "gxfixed.h"
40
#include "gxchar.h"
41
#include "gxpath.h"
42
#include "gzstate.h"
43
#include "pxptable.h"
44
#include "pxpthr.h"
45
46
#include "plfapi.h"
47
48
/* ---------------- Operator utilities ---------------- */
49
50
static const pl_symbol_map_t *
51
pxl_find_symbol_map(uint symbol_set)
52
639
{
53
639
    const pl_symbol_map_t **ppsm = pl_built_in_symbol_maps;
54
55
8.02k
    while (*ppsm != 0 && pl_get_uint16((*ppsm)->id) != symbol_set)
56
7.38k
        ++ppsm;
57
639
    return (*ppsm ? *ppsm : NULL);
58
639
}
59
60
/* Compute the symbol map from the font and symbol set. */
61
void
62
px_set_symbol_map(px_state_t * pxs, bool wide16)
63
639
{
64
639
    px_gstate_t *pxgs = pxs->pxgs;
65
66
639
    uint symbol_set = pxgs->symbol_set;
67
68
639
    pxgs->symbol_map = pxl_find_symbol_map(symbol_set);
69
639
}
70
71
static int
72
px_set_char_matrix(px_state_t * pxs)
73
626
{
74
626
    px_gstate_t *pxgs = pxs->pxgs;
75
76
626
    px_font_t *pxfont = pxgs->base_font;
77
78
626
    gs_matrix mat;
79
80
626
    if (pxfont == 0)
81
0
        return_error(errorNoCurrentFont);
82
626
    if (pxfont->scaling_technology == plfst_bitmap) {
83
        /*
84
         * Bitmaps don't scale, shear, or rotate; however, we have to
85
         * scale them to make the resolution match that of the device.
86
         * Note that we disregard the character size, and, in px_text,
87
         * all but the translation and orientation components of the
88
         * CTM.
89
         */
90
20
        if (pxgs->char_angle != 0 ||
91
20
            pxgs->char_shear.x != 0 || pxgs->char_shear.y != 0 ||
92
20
            pxgs->char_scale.x != 1 || pxgs->char_scale.y != 1)
93
0
            return_error(errorIllegalFontData);
94
95
        /* remove negative scale component */
96
20
        gs_make_scaling(pxs->units_per_measure.x / pxfont->resolution.x,
97
20
                        pxs->units_per_measure.y / pxfont->resolution.y,
98
20
                        &mat);
99
100
        /*
101
         * Rotate the bitmap to undo the effect of its built-in
102
         * orientation.
103
         */
104
20
        gs_matrix_rotate(&mat, 90.0 * pxfont->header[1], &mat);
105
606
    } else {
106
606
        float char_size = pxgs->char_size;
107
108
606
        int i;
109
110
606
        gs_make_identity(&mat);
111
        /* H-P and Microsoft have Y coordinates running opposite ways. */
112
606
        gs_matrix_scale(&mat, char_size, -char_size, &mat);
113
        /* Apply the character transformations in the reverse order. */
114
2.42k
        for (i = 0; i < 3; ++i)
115
1.81k
            switch (pxgs->char_transforms[i]) {
116
606
                case pxct_rotate:
117
606
                    if (pxgs->char_angle != 0)
118
7
                        gs_matrix_rotate(&mat, pxgs->char_angle, &mat);
119
606
                    break;
120
606
                case pxct_shear:
121
606
                    if (pxgs->char_shear.x != 0 || pxgs->char_shear.y != 0) {
122
0
                        gs_matrix smat;
123
124
0
                        gs_make_identity(&smat);
125
0
                        smat.yx = pxgs->char_shear.x;
126
0
                        smat.xy = pxgs->char_shear.y;
127
0
                        gs_matrix_multiply(&smat, &mat, &mat);
128
0
                    }
129
606
                    break;
130
606
                case pxct_scale:
131
606
                    if (pxgs->char_scale.x != 1 || pxgs->char_scale.y != 1)
132
0
                        gs_matrix_scale(&mat, pxgs->char_scale.x,
133
0
                                        pxgs->char_scale.y, &mat);
134
606
                    break;
135
1.81k
            }
136
606
    }
137
626
    pxgs->char_matrix = mat;
138
626
    pxgs->char_matrix_set = true;
139
626
    return 0;
140
626
}
141
142
/* ---------------- Operator implementations ---------------- */
143
144
/* Define a font.  The caller must fill in pxfont->storage and ->font_type. */
145
/* This procedure implements FontHeader loading; it is exported for */
146
/* initializing the error page font. */
147
int
148
px_define_font(px_font_t * pxfont, byte * header, ulong size, gs_id id,
149
               px_state_t * pxs)
150
12.2k
{
151
12.2k
    gs_memory_t *mem = pxs->memory;
152
153
12.2k
    uint num_chars;
154
155
12.2k
    int code = 0;
156
157
    /* Check for a valid font. */
158
12.2k
    if (size < 8 /* header */  + 6 /* 1 required segment */  +
159
12.2k
        6                       /* NULL segment */
160
12.2k
        )
161
0
        return_error(errorIllegalFontData);
162
12.2k
    if (header[0] != 0 /* format */  ||
163
12.2k
        header[5] != 0          /* variety */
164
12.2k
        )
165
0
        return_error(errorIllegalFontHeaderFields);
166
167
12.2k
    pxfont->header = (byte *) header;   /* remove const cast */
168
12.2k
    pxfont->header_size = size;
169
12.2k
    {
170
12.2k
        static const pl_font_offset_errors_t errors = {
171
12.2k
            errorIllegalFontData,
172
12.2k
            errorIllegalFontSegment,
173
12.2k
            errorIllegalFontHeaderFields,
174
12.2k
            errorIllegalNullSegmentSize,
175
12.2k
            errorMissingRequiredSegment,
176
12.2k
            errorIllegalGlobalTrueTypeSegment,
177
12.2k
            errorIllegalGalleyCharacterSegment,
178
12.2k
            errorIllegalVerticalTxSegment,
179
12.2k
            errorIllegalBitmapResolutionSegment
180
12.2k
        };
181
12.2k
        int code =
182
12.2k
            pl_font_scan_segments(mem, pxfont, 4, 8, size, true, &errors);
183
184
12.2k
        if (code < 0)
185
5
            return code;
186
12.2k
    }
187
12.2k
    num_chars = pl_get_uint16(header + 6);
188
    /* Allocate the character table. */
189
12.2k
    {                           /* Some fonts ask for unreasonably large tables.... */
190
12.2k
        int code = pl_font_alloc_glyph_table(pxfont, min(num_chars, 300),
191
12.2k
                                             mem, "px_define_font(glyphs)");
192
193
12.2k
        if (code < 0)
194
0
            return code;
195
12.2k
    }
196
    /* Now construct a gs_font. */
197
12.2k
    if (pxfont->scaling_technology == plfst_bitmap) {   /* Bitmap font. */
198
12.2k
        gs_font_base *pfont =
199
12.2k
            gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
200
12.2k
                            "px_define_font(gs_font_base)");
201
202
12.2k
        int code;
203
204
12.2k
        if (pfont == 0)
205
0
            return_error(errorInsufficientMemory);
206
12.2k
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
207
12.2k
        if (code < 0)
208
0
            return code;
209
12.2k
        pl_fill_in_bitmap_font(pfont, id);
210
12.2k
    } else {                    /* TrueType font. */
211
62
        gs_font_type42 *pfont =
212
62
            gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42,
213
62
                            "px_define_font(gs_font_type42)");
214
215
62
        int code;
216
217
62
        if (pfont == 0)
218
0
            return_error(errorInsufficientMemory);
219
        /* Some fonts ask for unreasonably large tables.... */
220
62
        code = pl_tt_alloc_char_glyphs(pxfont, min(num_chars, 300), mem,
221
62
                                       "px_define_font(char_glyphs)");
222
62
        if (code < 0)
223
0
            return code;
224
225
62
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
226
62
        if (code < 0)
227
0
            return code;
228
62
        {
229
            /* some pcl xl drivers generate an incorrect sfnt
230
               version, in particular they will use a true type
231
               collection header where truetype was intended.  The
232
               hp printer does not detect this problem.  Brutishly,
233
               we write in what the driver writers intended here
234
               and bypass and avoid later failures that would
235
               result from an incorrect header. */
236
62
            static const byte version1_0[4] = { 0, 1, 0, 0 };
237
            /* offset to the sfnt version.   */
238
62
            uint offs = pxfont->offsets.GT + (pxfont->large_sizes ? 6 : 4);
239
240
62
            if (gs_object_size(mem, header) >= offs + sizeof(version1_0))
241
62
                memcpy(header + offs, version1_0, sizeof(version1_0));
242
62
        }
243
62
        code = pl_fill_in_tt_font(pfont, NULL, id);
244
62
        if (code < 0)
245
3
            return code;
246
62
    }
247
12.2k
    pxfont->params.symbol_set = pl_get_uint16(header + 2);
248
249
12.2k
    if (header[4] == plfst_TrueType) {
250
59
        pxfont->is_xl_format = true;
251
59
        pl_prepend_xl_dummy_header(mem, &header); /* lgtm [cpp/useless-expression] */
252
59
        pxfont->header = header;
253
59
        pxfont->header_size = gs_object_size(mem, header);
254
12.2k
    } else {
255
12.2k
        pxfont->is_xl_format = false;
256
12.2k
    }
257
258
12.2k
    if ((code = gs_definefont(pxs->font_dir, pxfont->pfont)) < 0) {
259
0
        return (code);
260
0
    }
261
262
12.2k
    if (pxfont->scaling_technology == plfst_TrueType) {
263
59
        code = pl_fapi_passfont(pxfont, 0, NULL, NULL, NULL, 0);
264
59
    }
265
266
12.2k
    return (code);
267
12.2k
}
268
269
/* Concatenate a widened (16-bit) font name onto an error message string. */
270
void
271
px_concat_font_name(char *message, uint max_message, const px_value_t * pfnv)
272
52
{
273
52
    char *mptr = message + strlen(message);
274
275
52
    uint fnsize = pfnv->value.array.size;
276
277
52
    uint i;
278
279
    /*
280
     **** We truncate 16-bit font name chars to 8 bits
281
     **** for the message.
282
     */
283
935
    for (i = 0; i < fnsize && mptr - message < max_message; ++mptr, ++i)
284
883
        if ((*mptr = (byte) integer_elt(pfnv, i)) < 32)
285
17
            *mptr = '?';
286
52
    *mptr = 0;
287
52
}
288
289
static inline bool
290
px_downloaded_and_bound(pl_font_t * plfont)
291
3.16k
{
292
3.16k
    return (plfont->storage != pxfsInternal && pl_font_is_bound(plfont));
293
3.16k
}
294
295
/** Convert pxl text arguments into an array of gs_chars
296
 * caller must allocate the correct size array pchar and free it later
297
 */
298
static void
299
px_str_to_gschars(px_args_t * par, px_state_t * pxs, gs_char * pchr)
300
3.16k
{
301
3.16k
    const px_value_t *pstr = par->pv[0];
302
3.16k
    const unsigned char *str = (const unsigned char *)pstr->value.array.data;
303
3.16k
    uint len = pstr->value.array.size;
304
3.16k
    int i;
305
3.16k
    gs_char chr;
306
3.16k
    const pl_symbol_map_t *psm = pxs->pxgs->symbol_map;
307
3.16k
    bool db = px_downloaded_and_bound(pxs->pxgs->base_font);
308
309
189k
    for (i = 0; i < len; i++) {
310
186k
        if (pstr->type & pxd_ubyte) {
311
186k
            chr = str[i];
312
186k
        } else {
313
0
            chr = uint16at(&str[i << 1], (pstr->type & pxd_big_endian));
314
0
        }
315
186k
        pchr[i] = pl_map_symbol((db ? NULL : psm), chr,
316
186k
                                pxs->pxgs->base_font->storage == pxfsInternal,
317
186k
                                false /* pxl does not support MSL */ ,
318
186k
                                pxs->memory);
319
186k
    }
320
3.16k
}
321
322
/* startup for the processing text */
323
static int
324
px_text_setup(gs_gstate * pgs, const gs_char * str, uint size,
325
              const float *x_widths, const float *y_widths,
326
              uint widths_size, gs_memory_t * mem, gs_text_enum_t ** ppte,
327
              bool to_path, bool can_cache)
328
3.16k
{
329
3.16k
    gs_text_params_t text;
330
3.16k
    int code;
331
332
3.16k
    text.operation =
333
3.16k
        TEXT_FROM_CHARS | TEXT_REPLACE_WIDTHS | TEXT_RETURN_WIDTH;
334
3.16k
    if (to_path)
335
0
        text.operation |= TEXT_DO_TRUE_CHARPATH;
336
3.16k
    else
337
3.16k
        text.operation |= TEXT_DO_DRAW;
338
3.16k
    text.operation |= can_cache ? 0 : TEXT_NO_CACHE;
339
3.16k
    text.data.chars = str;
340
3.16k
    text.size = size;
341
3.16k
    text.x_widths = x_widths;
342
3.16k
    text.y_widths = y_widths;
343
3.16k
    text.widths_size = widths_size;
344
3.16k
    code = gs_text_begin(pgs, &text, mem, ppte);
345
3.16k
    if (code < 0)
346
0
        return code;
347
348
3.16k
    return code;
349
3.16k
}
350
351
/* Paint text or add it to the path. */
352
/* This procedure implements the Text and TextPath operators. */
353
/* Attributes: pxaTextData, pxaXSpacingData, pxaYSpacingData. */
354
355
int
356
px_text(px_args_t * par, px_state_t * pxs, bool to_path)
357
3.16k
{
358
3.16k
    gs_memory_t *mem = pxs->memory;
359
3.16k
    gs_gstate *pgs = pxs->pgs;
360
3.16k
    px_gstate_t *pxgs = pxs->pxgs;
361
3.16k
    gs_text_enum_t *penum;
362
3.16k
    const px_value_t *pstr = par->pv[0];
363
3.16k
    uint len = pstr->value.array.size;
364
3.16k
    const px_value_t *pxdata = par->pv[1];
365
3.16k
    const px_value_t *pydata = par->pv[2];
366
3.16k
    gs_font *pfont = gs_currentfont(pgs);
367
3.16k
    int code = 0;
368
3.16k
    gs_char *pchr = 0;
369
3.16k
    pl_font_t *plfont;
370
371
3.16k
    if (pfont == 0)
372
1
        return_error(errorNoCurrentFont);
373
374
3.16k
    plfont = (pl_font_t *) pfont->client_data;
375
3.16k
    if ((pxdata != 0 && pxdata->value.array.size != len) ||
376
3.16k
        (pydata != 0 && pydata->value.array.size != len)
377
3.16k
        )
378
1
        return_error(errorIllegalArraySize);
379
3.16k
    if (!pxgs->base_font)
380
0
        return_error(errorNoCurrentFont);
381
3.16k
    if (!pxgs->char_matrix_set) {
382
626
        gs_matrix *cm = &pxgs->char_matrix;
383
384
626
        float det;
385
386
626
        code = px_set_char_matrix(pxs);
387
626
        if (code < 0)
388
0
            return code;
389
        /* check for a singular matrix - this does not generate an
390
           interpreter error on hp.  Casts prevent double precision
391
           temporary variables, as in gsmatrix.c. */
392
626
        det = (float)(cm->xx * cm->yy) - (float)(cm->xy * cm->yx);
393
626
        if (det == 0)
394
0
            return 0;
395
626
    }
396
397
3.16k
    {
398
3.16k
        gs_matrix cmat;
399
400
3.16k
        gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
401
3.16k
                           &cmat);
402
3.16k
        gs_setcharmatrix(pgs, &cmat);
403
3.16k
    }
404
405
    /* The character matrix is not visible to devices.  High level
406
       devices get character scaling information from the font's
407
       matrix (FontMatrix).  */
408
3.16k
    gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
409
3.16k
                       &pfont->FontMatrix);
410
    /* we don't need to consider the vertical mess for resident fonts */
411
3.16k
    if (plfont->storage != pxfsDownLoaded) {
412
3.11k
        pfont->WMode = 0;       /* horizontal */
413
3.11k
        plfont->allow_vertical_substitutes = false;
414
3.11k
    } else {                    /* downloaded */
415
52
        pfont->WMode = pxgs->writing_mode;
416
        /* allow vertical substitutes for non-bitmap characters if requested. */
417
52
        if (pxgs->char_sub_mode == eVerticalSubstitution &&
418
0
            plfont->scaling_technology != plfst_bitmap)
419
0
            plfont->allow_vertical_substitutes = true;
420
52
        else
421
52
            plfont->allow_vertical_substitutes = false;
422
52
    }
423
424
    /* set bold fraction - charpaths are not algorithmically boldened */
425
3.16k
    if (to_path == false)
426
3.16k
        plfont->bold_fraction = pxgs->char_bold_value;
427
428
3.16k
    pchr = (gs_char *) gs_alloc_byte_array(mem, len, sizeof(gs_char),
429
3.16k
                                           "px_text gs_char[]");
430
3.16k
    if (pchr == 0)
431
0
        return_error(errorInsufficientMemory);
432
433
3.16k
    px_str_to_gschars(par, pxs, pchr);
434
435
3.16k
    {
436
3.16k
        uint i;
437
3.16k
        float *fxvals = 0;
438
3.16k
        float *fyvals = 0;
439
440
3.16k
        if (len > 0) {
441
3.16k
            fxvals =
442
3.16k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float),
443
3.16k
                                             "px_text fxvals");
444
3.16k
            fyvals =
445
3.16k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float) * 2,
446
3.16k
                                             "px_text fyals");
447
3.16k
            if (fxvals == 0 || fyvals == 0)
448
0
                return_error(errorInsufficientMemory);
449
3.16k
        }
450
189k
        for (i = 0; i < len; i++) {
451
186k
            fxvals[i] = pxdata ? real_elt(pxdata, i) : 0.0;
452
186k
            fyvals[i] = pydata ? real_elt(pydata, i) : 0.0;
453
186k
        }
454
455
3.16k
        code = px_text_setup(pgs, pchr, len, fxvals, fyvals,
456
3.16k
                             len, mem, &penum, to_path,
457
3.16k
                             pxgs->char_bold_value == 0 &&
458
3.16k
                             plfont->allow_vertical_substitutes == 0);
459
460
3.16k
        if (code >= 0) {
461
3.16k
            code = gs_text_process(penum);
462
3.16k
            gs_text_release(pgs, penum, "pxtext");
463
3.16k
        }
464
3.16k
        if (fxvals)
465
3.16k
            gs_free_object(mem, fxvals, "px_text fvals");
466
3.16k
        if (fyvals)
467
3.16k
            gs_free_object(mem, fyvals, "py_text fvals");
468
3.16k
    }
469
470
3.16k
    gs_free_object(mem, pchr, "px_text gs_char");
471
3.16k
    return (code == gs_error_invalidfont ?
472
3.16k
            gs_note_error(errorBadFontData) : code);
473
3.16k
}
474
475
/* ---------------- Operators ---------------- */
476
477
const byte apxSetFont[] = {
478
    0, pxaFontName, pxaCharSize, pxaSymbolSet, pxaPCLSelectFont, 0
479
};
480
int
481
pxSetFont(px_args_t * par, px_state_t * pxs)
482
645
{
483
645
    px_gstate_t *pxgs = pxs->pxgs;
484
645
    px_font_t *pxfont;
485
645
    px_value_t *pfnv;
486
645
    uint symbol_set;
487
645
    int code;
488
489
645
    if (!par->pv[3]) {
490
645
         if (!par->pv[0] || !par->pv[1] || !par->pv[2])
491
6
             return gs_note_error(errorMissingAttribute);
492
639
        pfnv = par->pv[0];
493
        /* force "find_font" to fail if the symbol set is not
494
           specified */
495
639
        symbol_set = (par->pv[2] ? par->pv[2]->value.i : (uint)-1);
496
639
        code = px_find_font(pfnv, symbol_set, &pxfont, pxs);
497
639
        if (code < 0) {
498
0
            switch (code) {
499
0
                case errorFontUndefined:
500
0
                    strcpy(pxs->error_line, "FontUndefined - ");
501
0
                    goto undef;
502
0
                case errorFontUndefinedNoSubstituteFound:
503
0
                    strcpy(pxs->error_line,
504
0
                           "FontUndefinedNoSubstituteFound - ");
505
0
                  undef:px_concat_font_name(pxs->error_line, px_max_error_line,
506
0
                                        pfnv);
507
0
                    break;
508
0
                case errorSymbolSetRemapUndefined:
509
0
                    strcpy(pxs->error_line, "SymbolSetRemapUndefined - ");
510
0
                    px_concat_font_name(pxs->error_line, px_max_error_line,
511
0
                                        pfnv);
512
0
                    {
513
0
                        char setstr[26];        /* 64-bit value plus message */
514
515
0
                        gs_snprintf(setstr, sizeof(setstr), " : %d", symbol_set);
516
0
                        strncat(pxs->error_line, setstr,
517
0
                                px_max_error_line - strlen(pxs->error_line));
518
0
                        pxs->error_line[px_max_error_line] = 0;
519
0
                    }
520
0
                    break;
521
0
            }
522
0
            return code;
523
0
        }
524
639
        code = gs_setfont(pxs->pgs, pxfont->pfont);
525
639
        if (code < 0)
526
0
            return code;
527
639
        pxgs->char_size = real_value(par->pv[1], 0);
528
639
        pxgs->symbol_set = symbol_set;
529
639
        pxgs->base_font = pxfont;
530
639
        px_set_symbol_map(pxs, pxfont->font_type == plft_16bit);
531
639
        pxgs->char_matrix_set = false;
532
639
    } else {                    /* PCLSelectFont */
533
0
        code = pxpcl_selectfont(par, pxs);
534
0
        if (code < 0)
535
0
            return code;
536
0
    }
537
639
    return 0;
538
645
}
539
540
const byte apxBeginFontHeader[] = {
541
    pxaFontName, pxaFontFormat, 0, 0
542
};
543
int
544
pxBeginFontHeader(px_args_t * par, px_state_t * pxs)
545
288
{
546
288
    px_value_t *pfnv = par->pv[0];
547
288
    gs_memory_t *mem = pxs->memory;
548
288
    px_font_t *pxfont;
549
288
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
550
551
288
    if (code >= 0) {
552
0
        strcpy(pxs->error_line, "FontNameAlreadyExists - ");
553
0
        px_concat_font_name(pxs->error_line, px_max_error_line, pfnv);
554
0
        return_error(errorFontNameAlreadyExists);
555
0
    }
556
    /* Make a partially filled-in dictionary entry. */
557
288
    pxfont = pl_alloc_font(mem, "pxBeginFontHeader(pxfont)");
558
288
    if (pxfont == 0)
559
0
        return_error(errorInsufficientMemory);
560
288
    pxfont->storage = pxfsDownLoaded;
561
288
    pxfont->data_are_permanent = false;
562
288
    code = px_dict_put(&pxs->font_dict, par->pv[0], pxfont);
563
288
    if (code < 0) {
564
0
        gs_free_object(mem, pxfont, "pxBeginFontHeader(pxfont)");
565
0
        return code;
566
0
    }
567
288
    pxs->download_font = pxfont;
568
288
    pxs->download_bytes.data = 0;
569
288
    pxs->download_bytes.size = 0;
570
288
    return 0;
571
288
}
572
573
const byte apxReadFontHeader[] = {
574
    pxaFontHeaderLength, 0, 0
575
};
576
int
577
pxReadFontHeader(px_args_t * par, px_state_t * pxs)
578
1.51k
{
579
1.51k
    ulong len = par->pv[0]->value.i;
580
1.51k
    ulong left = len - par->source.position;
581
1.51k
    int code = pxNeedData;
582
583
1.51k
    if (left > 0) {
584
1.51k
        ulong pos;
585
586
1.51k
        if (par->source.position == 0) {        /* (Re-)allocate the downloaded data. */
587
1.51k
            void *new_data;
588
589
1.51k
            if (par->source.available == 0)
590
759
                return code;
591
752
            new_data =
592
752
                (pxs->download_bytes.size == 0 ?
593
283
                 gs_alloc_bytes(pxs->memory, len, "pxReadFontHeader") :
594
752
                 gs_resize_object(pxs->memory, pxs->download_bytes.data,
595
752
                                  pxs->download_bytes.size + len,
596
752
                                  "pxReadFontHeader"));
597
752
            if (new_data == 0)
598
0
                return_error(errorInsufficientMemory);
599
752
            pxs->download_bytes.data = new_data;
600
752
            pxs->download_bytes.size += len;
601
752
        }
602
752
        if (left > par->source.available)
603
2
            left = par->source.available;
604
750
        else
605
750
            code = 0;
606
752
        pos = pxs->download_bytes.size - len + par->source.position;
607
752
        memcpy(pxs->download_bytes.data + pos, par->source.data, left);
608
752
        par->source.position += left;
609
752
        par->source.data += left;
610
752
        par->source.available -= left;
611
752
        if (pos < 8 && pos + left >= 8) {       /* Check the font header fields now. */
612
283
            const byte *data = pxs->download_bytes.data;
613
614
283
            if (data[0] | data[5])
615
1
                return_error(errorIllegalFontHeaderFields);
616
282
            switch (data[4]) {
617
69
                case plfst_TrueType:
618
69
                    if (data[1])
619
0
                        return_error(errorIllegalFontHeaderFields);
620
69
                    break;
621
211
                case plfst_bitmap:
622
211
                    if (data[1] & ~3)
623
1
                        return_error(errorIllegalFontHeaderFields);
624
210
                    break;
625
210
                default:
626
2
                    return_error(errorIllegalFontHeaderFields);
627
282
            }
628
282
        }
629
752
    }
630
748
    return code;
631
1.51k
}
632
633
const byte apxEndFontHeader[] = { 0, 0 };
634
int
635
pxEndFontHeader(px_args_t * par, px_state_t * pxs)
636
262
{
637
262
    px_font_t *pxfont = pxs->download_font;
638
262
    int code = px_define_font(pxfont, pxs->download_bytes.data,
639
262
                              (ulong) pxs->download_bytes.size,
640
262
                              gs_next_ids(pxs->memory, 1), pxs);
641
642
        /****** HOW TO DETERMINE FONT TYPE? ******/
643
262
    pxfont->font_type = plft_16bit;
644
    /* Clear pointers for GC */
645
262
    pxs->download_font = 0;
646
262
    pxs->download_bytes.data = 0;
647
262
    return code;
648
262
}
649
650
const byte apxBeginChar[] = {
651
    pxaFontName, 0, 0
652
};
653
int
654
pxBeginChar(px_args_t * par, px_state_t * pxs)
655
244
{
656
244
    px_value_t *pfnv = par->pv[0];
657
244
    px_font_t *pxfont;
658
244
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
659
660
244
    if (code >= 0 && pxfont == 0)
661
0
        code = gs_note_error(errorFontUndefined);
662
244
    if (code < 0) {
663
22
        if (code == errorFontUndefined) {
664
0
            strcpy(pxs->error_line, "FontUndefined - ");
665
0
            px_concat_font_name(pxs->error_line, px_max_error_line, pfnv);
666
0
        }
667
22
        return code;
668
22
    }
669
222
    if (pxfont->storage != pxfsDownLoaded)
670
0
        return_error(errorCannotReplaceCharacter);
671
222
    pxs->download_font = pxfont;
672
222
    return 0;
673
222
}
674
675
const byte apxReadChar[] = {
676
    pxaCharCode, pxaCharDataSize, 0, 0
677
};
678
int
679
pxReadChar(px_args_t * par, px_state_t * pxs)
680
2.09k
{
681
2.09k
    uint char_code = par->pv[0]->value.i;
682
2.09k
    uint size = par->pv[1]->value.i;
683
2.09k
    uint pos = par->source.position;
684
685
2.09k
    if (pos == 0) {
686
        /* We're starting a character definition. */
687
2.00k
        byte *def;
688
689
2.00k
        if (size < 2)
690
0
            return_error(errorIllegalCharacterData);
691
2.00k
        if (par->source.available == 0)
692
1.00k
            return pxNeedData;
693
1.00k
        def = gs_alloc_bytes(pxs->memory, size, "pxReadChar");
694
1.00k
        if (def == 0)
695
0
            return_error(errorInsufficientMemory);
696
1.00k
        pxs->download_bytes.data = def;
697
1.00k
        pxs->download_bytes.size = size;
698
1.00k
    }
699
2.18k
    while (pos < size) {
700
1.21k
        uint copy = min(par->source.available, size - pos);
701
702
1.21k
        if (copy == 0)
703
118
            return pxNeedData;
704
1.09k
        memcpy(pxs->download_bytes.data + pos, par->source.data, copy);
705
1.09k
        par->source.data += copy;
706
1.09k
        par->source.available -= copy;
707
1.09k
        par->source.position = pos += copy;
708
1.09k
    }
709
    /* We have the complete character. */
710
    /* Do error checks before installing. */
711
976
    {
712
976
        byte *data = pxs->download_bytes.data;
713
714
976
        int code = 0;
715
716
976
        switch (data[0]) {
717
624
            case 0:            /* bitmap */
718
624
                if (false /* NB FIXME header[4] != plfst_bitmap */ )
719
0
                    code = gs_note_error(errorFSTMismatch);
720
624
                else if (data[1] != 0)
721
3
                    code = gs_note_error(errorUnsupportedCharacterClass);
722
621
                else if (size < 10)
723
0
                    code = gs_note_error(errorIllegalCharacterData);
724
621
                else {
725
621
                    int loff = pl_get_int16(data + 2);
726
621
                    int toff = pl_get_int16(data + 4);
727
621
                    uint width = pl_get_uint16(data + 6);
728
621
                    uint height = pl_get_uint16(data + 8);
729
621
                    uint bmp_size = ((width + 7) >> 3) * height;
730
621
                    uint bmp_offset = round_up(10, ARCH_ALIGN_PTR_MOD);
731
732
621
                    if (size != 10 + ((width + 7) >> 3) * height)
733
11
                        code = gs_note_error(errorIllegalCharacterData);
734
610
                    else if ((-16384 > toff) || (toff > 16384))
735
0
                        code = gs_note_error(errorIllegalCharacterData);
736
610
                    else if ((-16384 > loff) || (loff > 16384))
737
0
                        code = gs_note_error(errorIllegalCharacterData);
738
610
                    else if ((1 > height) || (height > 16384))
739
0
                        code = gs_note_error(errorIllegalCharacterData);
740
610
                    else if ((1 > width) || (width > 16384))
741
0
                        code = gs_note_error(errorIllegalCharacterData);
742
743
621
                    if (code >= 0) {
744
                        /* try to get the bitmap aligned */
745
610
                        data =
746
610
                            gs_resize_object(pxs->memory, data,
747
610
                                             bmp_offset + bmp_size,
748
610
                                             "pxReadChar");
749
610
                        if (data)
750
610
                            memmove(data + bmp_offset, data + 10, bmp_size);
751
0
                        else
752
0
                            code = gs_note_error(errorInsufficientMemory);
753
610
                    }
754
621
                }
755
624
                break;
756
346
            case 1:            /* TrueType outline */
757
346
                if (false /* NB FIXME header[4] != plfst_TrueType */ )
758
0
                    code = gs_note_error(errorFSTMismatch);
759
346
                else if (data[1] != 0 && data[1] != 1 && data[1] != 2)
760
0
                    code = gs_note_error(errorUnsupportedCharacterClass);
761
346
                else if (size < 6 || size != 2 + pl_get_uint16(data + 2))
762
1
                    code = gs_note_error(errorIllegalCharacterData);
763
346
                break;
764
6
            default:
765
6
                code = gs_note_error(errorUnsupportedCharacterFormat);
766
976
        }
767
976
        if (code >= 0) {
768
955
            code = pl_font_add_glyph(pxs->download_font, char_code,
769
955
                                    (byte *) data, pxs->download_bytes.size);     /* const cast */
770
955
            if (code < 0)
771
0
                code = gs_note_error(errorInternalOverflow);
772
955
        }
773
774
976
        if (code < 0)
775
21
            gs_free_object(pxs->memory, pxs->download_bytes.data,
776
976
                           "pxReadChar");
777
976
        pxs->download_bytes.data = 0;
778
976
        return code;
779
976
    }
780
976
}
781
782
const byte apxEndChar[] = { 0, 0 };
783
int
784
pxEndChar(px_args_t * par, px_state_t * pxs)
785
42
{
786
42
    return 0;
787
42
}
788
789
const byte apxRemoveFont[] = {
790
    pxaFontName, 0, 0
791
};
792
int
793
pxRemoveFont(px_args_t * par, px_state_t * pxs)
794
0
{
795
0
    px_value_t *pfnv = par->pv[0];
796
0
    px_font_t *pxfont;
797
0
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
798
0
    const char *error = 0;
799
800
0
    if (code < 0)
801
0
        error = "UndefinedFontNotRemoved - ";
802
0
    else if (pxfont == 0)       /* built-in font, assume internal */
803
0
        error = "InternalFontNotRemoved - ";
804
0
    else
805
0
        switch (pxfont->storage) {
806
0
            case pxfsInternal:
807
0
                error = "InternalFontNotRemoved - ";
808
0
                break;
809
0
            case pxfsMassStorage:
810
0
                error = "MassStorageFontNotRemoved - ";
811
0
                break;
812
0
            default:           /* downloaded */
813
0
                ;
814
0
        }
815
816
0
    if (error) {                /* Construct a warning message including the font name. */
817
0
        char message[px_max_error_line + 1];
818
819
0
        strcpy(message, error);
820
0
        px_concat_font_name(message, px_max_error_line, pfnv);
821
0
        code = px_record_warning(message, false, pxs);
822
0
    }
823
824
0
    if (error == NULL && pxfont != NULL) {
825
        /*
826
         * If we're deleting the current font we have to update the
827
         * graphics state.
828
         */
829
0
        if (pxfont->pfont == gs_currentfont(pxs->pgs))
830
0
            gs_setfont(pxs->pgs, NULL);
831
832
0
        px_dict_undef(&pxs->font_dict, par->pv[0]);
833
0
    }
834
835
0
    return code;
836
0
}