Coverage Report

Created: 2026-09-14 07:34

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-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
/* 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
808
{
53
808
    const pl_symbol_map_t **ppsm = pl_built_in_symbol_maps;
54
55
10.3k
    while (*ppsm != 0 && pl_get_uint16((*ppsm)->id) != symbol_set)
56
9.53k
        ++ppsm;
57
808
    return (*ppsm ? *ppsm : NULL);
58
808
}
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
808
{
64
808
    px_gstate_t *pxgs = pxs->pxgs;
65
66
808
    uint symbol_set = pxgs->symbol_set;
67
68
808
    pxgs->symbol_map = pxl_find_symbol_map(symbol_set);
69
808
}
70
71
static int
72
px_set_char_matrix(px_state_t * pxs)
73
784
{
74
784
    px_gstate_t *pxgs = pxs->pxgs;
75
76
784
    px_font_t *pxfont = pxgs->base_font;
77
78
784
    gs_matrix mat;
79
80
784
    if (pxfont == 0)
81
0
        return_error(errorNoCurrentFont);
82
784
    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
18
        if (pxgs->char_angle != 0 ||
91
18
            pxgs->char_shear.x != 0 || pxgs->char_shear.y != 0 ||
92
18
            pxgs->char_scale.x != 1 || pxgs->char_scale.y != 1)
93
0
            return_error(errorIllegalFontData);
94
95
        /* remove negative scale component */
96
18
        gs_make_scaling(pxs->units_per_measure.x / pxfont->resolution.x,
97
18
                        pxs->units_per_measure.y / pxfont->resolution.y,
98
18
                        &mat);
99
100
        /*
101
         * Rotate the bitmap to undo the effect of its built-in
102
         * orientation.
103
         */
104
18
        gs_matrix_rotate(&mat, 90.0 * pxfont->header[1], &mat);
105
766
    } else {
106
766
        float char_size = pxgs->char_size;
107
108
766
        int i;
109
110
766
        gs_make_identity(&mat);
111
        /* H-P and Microsoft have Y coordinates running opposite ways. */
112
766
        gs_matrix_scale(&mat, char_size, -char_size, &mat);
113
        /* Apply the character transformations in the reverse order. */
114
3.06k
        for (i = 0; i < 3; ++i)
115
2.29k
            switch (pxgs->char_transforms[i]) {
116
766
                case pxct_rotate:
117
766
                    if (pxgs->char_angle != 0)
118
17
                        gs_matrix_rotate(&mat, pxgs->char_angle, &mat);
119
766
                    break;
120
766
                case pxct_shear:
121
766
                    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
766
                    break;
130
766
                case pxct_scale:
131
766
                    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
766
                    break;
135
2.29k
            }
136
766
    }
137
784
    pxgs->char_matrix = mat;
138
784
    pxgs->char_matrix_set = true;
139
784
    return 0;
140
784
}
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
15.6k
{
151
15.6k
    gs_memory_t *mem = pxs->memory;
152
153
15.6k
    uint num_chars;
154
155
15.6k
    int code = 0;
156
157
    /* Check for a valid font. */
158
15.6k
    if (size < 8 /* header */  + 6 /* 1 required segment */  +
159
15.6k
        6                       /* NULL segment */
160
15.6k
        )
161
0
        return_error(errorIllegalFontData);
162
15.6k
    if (header[0] != 0 /* format */  ||
163
15.6k
        header[5] != 0          /* variety */
164
15.6k
        )
165
0
        return_error(errorIllegalFontHeaderFields);
166
167
15.6k
    pxfont->header = (byte *) header;   /* remove const cast */
168
15.6k
    pxfont->header_size = size;
169
15.6k
    {
170
15.6k
        static const pl_font_offset_errors_t errors = {
171
15.6k
            errorIllegalFontData,
172
15.6k
            errorIllegalFontSegment,
173
15.6k
            errorIllegalFontHeaderFields,
174
15.6k
            errorIllegalNullSegmentSize,
175
15.6k
            errorMissingRequiredSegment,
176
15.6k
            errorIllegalGlobalTrueTypeSegment,
177
15.6k
            errorIllegalGalleyCharacterSegment,
178
15.6k
            errorIllegalVerticalTxSegment,
179
15.6k
            errorIllegalBitmapResolutionSegment
180
15.6k
        };
181
15.6k
        int code =
182
15.6k
            pl_font_scan_segments(mem, pxfont, 4, 8, size, true, &errors);
183
184
15.6k
        if (code < 0)
185
5
            return code;
186
15.6k
    }
187
15.6k
    num_chars = pl_get_uint16(header + 6);
188
    /* Allocate the character table. */
189
15.6k
    {                           /* Some fonts ask for unreasonably large tables.... */
190
15.6k
        int code = pl_font_alloc_glyph_table(pxfont, min(num_chars, 300),
191
15.6k
                                             mem, "px_define_font(glyphs)");
192
193
15.6k
        if (code < 0)
194
0
            return code;
195
15.6k
    }
196
    /* Now construct a gs_font. */
197
15.6k
    if (pxfont->scaling_technology == plfst_bitmap) {   /* Bitmap font. */
198
15.6k
        gs_font_base *pfont =
199
15.6k
            gs_alloc_struct(mem, gs_font_base, &st_gs_font_base,
200
15.6k
                            "px_define_font(gs_font_base)");
201
202
15.6k
        int code;
203
204
15.6k
        if (pfont == 0)
205
0
            return_error(errorInsufficientMemory);
206
15.6k
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
207
15.6k
        if (code < 0)
208
0
            return code;
209
15.6k
        pl_fill_in_bitmap_font(pfont, id);
210
15.6k
    } else {                    /* TrueType font. */
211
94
        gs_font_type42 *pfont =
212
94
            gs_alloc_struct(mem, gs_font_type42, &st_gs_font_type42,
213
94
                            "px_define_font(gs_font_type42)");
214
215
94
        int code;
216
217
94
        if (pfont == 0)
218
0
            return_error(errorInsufficientMemory);
219
        /* Some fonts ask for unreasonably large tables.... */
220
94
        code = pl_tt_alloc_char_glyphs(pxfont, min(num_chars, 300), mem,
221
94
                                       "px_define_font(char_glyphs)");
222
94
        if (code < 0)
223
0
            return code;
224
225
94
        code = px_fill_in_font((gs_font *) pfont, pxfont, pxs);
226
94
        if (code < 0)
227
0
            return code;
228
94
        {
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
94
            static const byte version1_0[4] = { 0, 1, 0, 0 };
237
            /* offset to the sfnt version.   */
238
94
            uint offs = pxfont->offsets.GT + (pxfont->large_sizes ? 6 : 4);
239
240
94
            if (gs_object_size(mem, header) >= offs + sizeof(version1_0))
241
94
                memcpy(header + offs, version1_0, sizeof(version1_0));
242
94
        }
243
94
        code = pl_fill_in_tt_font(pfont, NULL, id);
244
94
        if (code < 0)
245
15
            return code;
246
94
    }
247
15.6k
    pxfont->params.symbol_set = pl_get_uint16(header + 2);
248
249
15.6k
    if (header[4] == plfst_TrueType) {
250
79
        pxfont->is_xl_format = true;
251
79
        pl_prepend_xl_dummy_header(mem, &header); /* lgtm [cpp/useless-expression] */
252
79
        pxfont->header = header;
253
79
        pxfont->header_size = gs_object_size(mem, header);
254
15.6k
    } else {
255
15.6k
        pxfont->is_xl_format = false;
256
15.6k
    }
257
258
15.6k
    if ((code = gs_definefont(pxs->font_dir, pxfont->pfont)) < 0) {
259
0
        return (code);
260
0
    }
261
262
15.6k
    if (pxfont->scaling_technology == plfst_TrueType) {
263
79
        code = pl_fapi_passfont(pxfont, 0, NULL, NULL, NULL, 0);
264
79
    }
265
266
15.6k
    return (code);
267
15.6k
}
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
54
{
273
54
    char *mptr = message + strlen(message);
274
275
54
    uint fnsize = pfnv->value.array.size;
276
277
54
    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
881
        if ((*mptr = (byte) integer_elt(pfnv, i)) < 32)
285
15
            *mptr = '?';
286
54
    *mptr = 0;
287
54
}
288
289
static inline bool
290
px_downloaded_and_bound(pl_font_t * plfont)
291
3.41k
{
292
3.41k
    return (plfont->storage != pxfsInternal && pl_font_is_bound(plfont));
293
3.41k
}
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.41k
{
301
3.41k
    const px_value_t *pstr = par->pv[0];
302
3.41k
    const unsigned char *str = (const unsigned char *)pstr->value.array.data;
303
3.41k
    uint len = pstr->value.array.size;
304
3.41k
    int i;
305
3.41k
    gs_char chr;
306
3.41k
    const pl_symbol_map_t *psm = pxs->pxgs->symbol_map;
307
3.41k
    bool db = px_downloaded_and_bound(pxs->pxgs->base_font);
308
309
214k
    for (i = 0; i < len; i++) {
310
210k
        if (pstr->type & pxd_ubyte) {
311
210k
            chr = str[i];
312
210k
        } else {
313
0
            chr = uint16at(&str[i << 1], (pstr->type & pxd_big_endian));
314
0
        }
315
210k
        pchr[i] = pl_map_symbol((db ? NULL : psm), chr,
316
210k
                                pxs->pxgs->base_font->storage == pxfsInternal,
317
210k
                                false /* pxl does not support MSL */ ,
318
210k
                                pxs->memory);
319
210k
    }
320
3.41k
}
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.41k
{
329
3.41k
    gs_text_params_t text;
330
3.41k
    int code;
331
332
3.41k
    text.operation =
333
3.41k
        TEXT_FROM_CHARS | TEXT_REPLACE_WIDTHS | TEXT_RETURN_WIDTH;
334
3.41k
    if (to_path)
335
0
        text.operation |= TEXT_DO_TRUE_CHARPATH;
336
3.41k
    else
337
3.41k
        text.operation |= TEXT_DO_DRAW;
338
3.41k
    text.operation |= can_cache ? 0 : TEXT_NO_CACHE;
339
3.41k
    text.data.chars = str;
340
3.41k
    text.size = size;
341
3.41k
    text.x_widths = x_widths;
342
3.41k
    text.y_widths = y_widths;
343
3.41k
    text.widths_size = widths_size;
344
3.41k
    code = gs_text_begin(pgs, &text, mem, ppte);
345
3.41k
    if (code < 0)
346
0
        return code;
347
348
3.41k
    return code;
349
3.41k
}
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.41k
{
358
3.41k
    gs_memory_t *mem = pxs->memory;
359
3.41k
    gs_gstate *pgs = pxs->pgs;
360
3.41k
    px_gstate_t *pxgs = pxs->pxgs;
361
3.41k
    gs_text_enum_t *penum;
362
3.41k
    const px_value_t *pstr = par->pv[0];
363
3.41k
    uint len = pstr->value.array.size;
364
3.41k
    const px_value_t *pxdata = par->pv[1];
365
3.41k
    const px_value_t *pydata = par->pv[2];
366
3.41k
    gs_font *pfont = gs_currentfont(pgs);
367
3.41k
    int code = 0;
368
3.41k
    gs_char *pchr = 0;
369
3.41k
    pl_font_t *plfont;
370
371
3.41k
    if (pfont == 0)
372
0
        return_error(errorNoCurrentFont);
373
374
3.41k
    plfont = (pl_font_t *) pfont->client_data;
375
3.41k
    if ((pxdata != 0 && pxdata->value.array.size != len) ||
376
3.41k
        (pydata != 0 && pydata->value.array.size != len)
377
3.41k
        )
378
2
        return_error(errorIllegalArraySize);
379
3.41k
    if (!pxgs->base_font)
380
0
        return_error(errorNoCurrentFont);
381
3.41k
    if (!pxgs->char_matrix_set) {
382
784
        gs_matrix *cm = &pxgs->char_matrix;
383
384
784
        float det;
385
386
784
        code = px_set_char_matrix(pxs);
387
784
        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
784
        det = (float)(cm->xx * cm->yy) - (float)(cm->xy * cm->yx);
393
784
        if (det == 0)
394
0
            return 0;
395
784
    }
396
397
3.41k
    {
398
3.41k
        gs_matrix cmat;
399
400
3.41k
        gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
401
3.41k
                           &cmat);
402
3.41k
        gs_setcharmatrix(pgs, &cmat);
403
3.41k
    }
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.41k
    gs_matrix_multiply(&pfont->orig_FontMatrix, &pxgs->char_matrix,
409
3.41k
                       &pfont->FontMatrix);
410
    /* we don't need to consider the vertical mess for resident fonts */
411
3.41k
    if (plfont->storage != pxfsDownLoaded) {
412
3.36k
        pfont->WMode = 0;       /* horizontal */
413
3.36k
        plfont->allow_vertical_substitutes = false;
414
3.36k
    } else {                    /* downloaded */
415
53
        pfont->WMode = pxgs->writing_mode;
416
        /* allow vertical substitutes for non-bitmap characters if requested. */
417
53
        if (pxgs->char_sub_mode == eVerticalSubstitution &&
418
0
            plfont->scaling_technology != plfst_bitmap)
419
0
            plfont->allow_vertical_substitutes = true;
420
53
        else
421
53
            plfont->allow_vertical_substitutes = false;
422
53
    }
423
424
    /* set bold fraction - charpaths are not algorithmically boldened */
425
3.41k
    if (to_path == false)
426
3.41k
        plfont->bold_fraction = pxgs->char_bold_value;
427
428
3.41k
    pchr = (gs_char *) gs_alloc_byte_array(mem, len, sizeof(gs_char),
429
3.41k
                                           "px_text gs_char[]");
430
3.41k
    if (pchr == 0)
431
0
        return_error(errorInsufficientMemory);
432
433
3.41k
    px_str_to_gschars(par, pxs, pchr);
434
435
3.41k
    {
436
3.41k
        uint i;
437
3.41k
        float *fxvals = 0;
438
3.41k
        float *fyvals = 0;
439
440
3.41k
        if (len > 0) {
441
3.41k
            fxvals =
442
3.41k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float),
443
3.41k
                                             "px_text fxvals");
444
3.41k
            fyvals =
445
3.41k
                (float *)gs_alloc_byte_array(mem, len + 1, sizeof(float) * 2,
446
3.41k
                                             "px_text fyals");
447
3.41k
            if (fxvals == 0 || fyvals == 0)
448
0
                return_error(errorInsufficientMemory);
449
3.41k
        }
450
214k
        for (i = 0; i < len; i++) {
451
210k
            fxvals[i] = pxdata ? real_elt(pxdata, i) : 0.0;
452
210k
            fyvals[i] = pydata ? real_elt(pydata, i) : 0.0;
453
210k
        }
454
455
3.41k
        code = px_text_setup(pgs, pchr, len, fxvals, fyvals,
456
3.41k
                             len, mem, &penum, to_path,
457
3.41k
                             pxgs->char_bold_value == 0 &&
458
3.41k
                             plfont->allow_vertical_substitutes == 0);
459
460
3.41k
        if (code >= 0) {
461
3.41k
            code = gs_text_process(penum);
462
3.41k
            gs_text_release(pgs, penum, "pxtext");
463
3.41k
        }
464
3.41k
        if (fxvals)
465
3.41k
            gs_free_object(mem, fxvals, "px_text fvals");
466
3.41k
        if (fyvals)
467
3.41k
            gs_free_object(mem, fyvals, "py_text fvals");
468
3.41k
    }
469
470
3.41k
    gs_free_object(mem, pchr, "px_text gs_char");
471
3.41k
    return (code == gs_error_invalidfont ?
472
3.41k
            gs_note_error(errorBadFontData) : code);
473
3.41k
}
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
815
{
483
815
    px_gstate_t *pxgs = pxs->pxgs;
484
815
    px_font_t *pxfont;
485
815
    px_value_t *pfnv;
486
815
    uint symbol_set;
487
815
    int code;
488
489
815
    if (!par->pv[3]) {
490
815
         if (!par->pv[0] || !par->pv[1] || !par->pv[2])
491
7
             return gs_note_error(errorMissingAttribute);
492
808
        pfnv = par->pv[0];
493
        /* force "find_font" to fail if the symbol set is not
494
           specified */
495
808
        symbol_set = (par->pv[2] ? par->pv[2]->value.i : (uint)-1);
496
808
        code = px_find_font(pfnv, symbol_set, &pxfont, pxs);
497
808
        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
808
        code = gs_setfont(pxs->pgs, pxfont->pfont);
525
808
        if (code < 0)
526
0
            return code;
527
808
        pxgs->char_size = real_value(par->pv[1], 0);
528
808
        pxgs->symbol_set = symbol_set;
529
808
        pxgs->base_font = pxfont;
530
808
        px_set_symbol_map(pxs, pxfont->font_type == plft_16bit);
531
808
        pxgs->char_matrix_set = false;
532
808
    } else {                    /* PCLSelectFont */
533
0
        code = pxpcl_selectfont(par, pxs);
534
0
        if (code < 0)
535
0
            return code;
536
0
    }
537
808
    return 0;
538
815
}
539
540
const byte apxBeginFontHeader[] = {
541
    pxaFontName, pxaFontFormat, 0, 0
542
};
543
int
544
pxBeginFontHeader(px_args_t * par, px_state_t * pxs)
545
312
{
546
312
    px_value_t *pfnv = par->pv[0];
547
312
    gs_memory_t *mem = pxs->memory;
548
312
    px_font_t *pxfont;
549
312
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
550
551
312
    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
312
    pxfont = pl_alloc_font(mem, "pxBeginFontHeader(pxfont)");
558
312
    if (pxfont == 0)
559
0
        return_error(errorInsufficientMemory);
560
312
    pxfont->storage = pxfsDownLoaded;
561
312
    pxfont->data_are_permanent = false;
562
312
    code = px_dict_put(&pxs->font_dict, par->pv[0], pxfont);
563
312
    if (code < 0) {
564
0
        gs_free_object(mem, pxfont, "pxBeginFontHeader(pxfont)");
565
0
        return code;
566
0
    }
567
312
    pxs->download_font = pxfont;
568
312
    pxs->download_bytes.data = 0;
569
312
    pxs->download_bytes.size = 0;
570
312
    return 0;
571
312
}
572
573
const byte apxReadFontHeader[] = {
574
    pxaFontHeaderLength, 0, 0
575
};
576
int
577
pxReadFontHeader(px_args_t * par, px_state_t * pxs)
578
1.53k
{
579
1.53k
    ulong len = par->pv[0]->value.i;
580
1.53k
    ulong left = len - par->source.position;
581
1.53k
    int code = pxNeedData;
582
583
1.53k
    if (left > 0) {
584
1.53k
        ulong pos;
585
586
1.53k
        if (par->source.position == 0) {        /* (Re-)allocate the downloaded data. */
587
1.53k
            void *new_data;
588
589
1.53k
            if (par->source.available == 0)
590
772
                return code;
591
760
            new_data =
592
760
                (pxs->download_bytes.size == 0 ?
593
304
                 gs_alloc_bytes(pxs->memory, len, "pxReadFontHeader") :
594
760
                 gs_resize_object(pxs->memory, pxs->download_bytes.data,
595
760
                                  pxs->download_bytes.size + len,
596
760
                                  "pxReadFontHeader"));
597
760
            if (new_data == 0)
598
0
                return_error(errorInsufficientMemory);
599
760
            pxs->download_bytes.data = new_data;
600
760
            pxs->download_bytes.size += len;
601
760
        }
602
760
        if (left > par->source.available)
603
14
            left = par->source.available;
604
746
        else
605
746
            code = 0;
606
760
        pos = pxs->download_bytes.size - len + par->source.position;
607
760
        memcpy(pxs->download_bytes.data + pos, par->source.data, left);
608
760
        par->source.position += left;
609
760
        par->source.data += left;
610
760
        par->source.available -= left;
611
760
        if (pos < 8 && pos + left >= 8) {       /* Check the font header fields now. */
612
303
            const byte *data = pxs->download_bytes.data;
613
614
303
            if (data[0] | data[5])
615
1
                return_error(errorIllegalFontHeaderFields);
616
302
            switch (data[4]) {
617
105
                case plfst_TrueType:
618
105
                    if (data[1])
619
0
                        return_error(errorIllegalFontHeaderFields);
620
105
                    break;
621
194
                case plfst_bitmap:
622
194
                    if (data[1] & ~3)
623
1
                        return_error(errorIllegalFontHeaderFields);
624
193
                    break;
625
193
                default:
626
3
                    return_error(errorIllegalFontHeaderFields);
627
302
            }
628
302
        }
629
760
    }
630
755
    return code;
631
1.53k
}
632
633
const byte apxEndFontHeader[] = { 0, 0 };
634
int
635
pxEndFontHeader(px_args_t * par, px_state_t * pxs)
636
264
{
637
264
    px_font_t *pxfont = pxs->download_font;
638
264
    int code = px_define_font(pxfont, pxs->download_bytes.data,
639
264
                              (ulong) pxs->download_bytes.size,
640
264
                              gs_next_ids(pxs->memory, 1), pxs);
641
642
        /****** HOW TO DETERMINE FONT TYPE? ******/
643
264
    pxfont->font_type = plft_16bit;
644
    /* Clear pointers for GC */
645
264
    pxs->download_font = 0;
646
264
    pxs->download_bytes.data = 0;
647
264
    return code;
648
264
}
649
650
const byte apxBeginChar[] = {
651
    pxaFontName, 0, 0
652
};
653
int
654
pxBeginChar(px_args_t * par, px_state_t * pxs)
655
235
{
656
235
    px_value_t *pfnv = par->pv[0];
657
235
    px_font_t *pxfont;
658
235
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
659
660
235
    if (code >= 0 && pxfont == 0)
661
0
        code = gs_note_error(errorFontUndefined);
662
235
    if (code < 0) {
663
18
        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
18
        return code;
668
18
    }
669
217
    if (pxfont->storage != pxfsDownLoaded)
670
0
        return_error(errorCannotReplaceCharacter);
671
217
    pxs->download_font = pxfont;
672
217
    return 0;
673
217
}
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.00k
{
681
2.00k
    uint char_code = par->pv[0]->value.i;
682
2.00k
    uint size = par->pv[1]->value.i;
683
2.00k
    uint pos = par->source.position;
684
685
2.00k
    if (pos == 0) {
686
        /* We're starting a character definition. */
687
1.92k
        byte *def;
688
689
1.92k
        if (size < 2)
690
0
            return_error(errorIllegalCharacterData);
691
1.92k
        if (par->source.available == 0)
692
965
            return pxNeedData;
693
962
        def = gs_alloc_bytes(pxs->memory, size, "pxReadChar");
694
962
        if (def == 0)
695
0
            return_error(errorInsufficientMemory);
696
962
        pxs->download_bytes.data = def;
697
962
        pxs->download_bytes.size = size;
698
962
    }
699
2.08k
    while (pos < size) {
700
1.16k
        uint copy = min(par->source.available, size - pos);
701
702
1.16k
        if (copy == 0)
703
119
            return pxNeedData;
704
1.04k
        memcpy(pxs->download_bytes.data + pos, par->source.data, copy);
705
1.04k
        par->source.data += copy;
706
1.04k
        par->source.available -= copy;
707
1.04k
        par->source.position = pos += copy;
708
1.04k
    }
709
    /* We have the complete character. */
710
    /* Do error checks before installing. */
711
922
    {
712
922
        byte *data = pxs->download_bytes.data;
713
714
922
        int code = 0;
715
716
922
        switch (data[0]) {
717
529
            case 0:            /* bitmap */
718
529
                if (false /* NB FIXME header[4] != plfst_bitmap */ )
719
0
                    code = gs_note_error(errorFSTMismatch);
720
529
                else if (data[1] != 0)
721
1
                    code = gs_note_error(errorUnsupportedCharacterClass);
722
528
                else if (size < 10)
723
0
                    code = gs_note_error(errorIllegalCharacterData);
724
528
                else {
725
528
                    int loff = pl_get_int16(data + 2);
726
528
                    int toff = pl_get_int16(data + 4);
727
528
                    uint width = pl_get_uint16(data + 6);
728
528
                    uint height = pl_get_uint16(data + 8);
729
528
                    uint bmp_size = ((width + 7) >> 3) * height;
730
528
                    uint bmp_offset = round_up(10, ARCH_ALIGN_PTR_MOD);
731
732
528
                    if (size != 10 + ((width + 7) >> 3) * height)
733
6
                        code = gs_note_error(errorIllegalCharacterData);
734
522
                    else if ((-16384 > toff) || (toff > 16384))
735
0
                        code = gs_note_error(errorIllegalCharacterData);
736
522
                    else if ((-16384 > loff) || (loff > 16384))
737
1
                        code = gs_note_error(errorIllegalCharacterData);
738
521
                    else if ((1 > height) || (height > 16384))
739
0
                        code = gs_note_error(errorIllegalCharacterData);
740
521
                    else if ((1 > width) || (width > 16384))
741
0
                        code = gs_note_error(errorIllegalCharacterData);
742
743
528
                    if (code >= 0) {
744
                        /* try to get the bitmap aligned */
745
521
                        data =
746
521
                            gs_resize_object(pxs->memory, data,
747
521
                                             bmp_offset + bmp_size,
748
521
                                             "pxReadChar");
749
521
                        if (data) {
750
521
                            memmove(data + bmp_offset, data + 10, bmp_size);
751
521
                            pxs->download_bytes.data = data;
752
521
                        }
753
0
                        else
754
0
                            code = gs_note_error(errorInsufficientMemory);
755
521
                    }
756
528
                }
757
529
                break;
758
389
            case 1:            /* TrueType outline */
759
389
                if (false /* NB FIXME header[4] != plfst_TrueType */ )
760
0
                    code = gs_note_error(errorFSTMismatch);
761
389
                else if (data[1] != 0 && data[1] != 1 && data[1] != 2)
762
1
                    code = gs_note_error(errorUnsupportedCharacterClass);
763
388
                else if (size < 6 || size != 2 + pl_get_uint16(data + 2))
764
1
                    code = gs_note_error(errorIllegalCharacterData);
765
389
                break;
766
4
            default:
767
4
                code = gs_note_error(errorUnsupportedCharacterFormat);
768
922
        }
769
922
        if (code >= 0) {
770
908
            code = pl_font_add_glyph(pxs->download_font, char_code,
771
908
                                    (byte *) data, pxs->download_bytes.size);     /* const cast */
772
908
            if (code < 0)
773
0
                code = gs_note_error(errorInternalOverflow);
774
908
        }
775
776
922
        if (code < 0)
777
14
            gs_free_object(pxs->memory, pxs->download_bytes.data,
778
922
                           "pxReadChar");
779
922
        pxs->download_bytes.data = 0;
780
922
        return code;
781
922
    }
782
922
}
783
784
const byte apxEndChar[] = { 0, 0 };
785
int
786
pxEndChar(px_args_t * par, px_state_t * pxs)
787
45
{
788
45
    return 0;
789
45
}
790
791
const byte apxRemoveFont[] = {
792
    pxaFontName, 0, 0
793
};
794
int
795
pxRemoveFont(px_args_t * par, px_state_t * pxs)
796
0
{
797
0
    px_value_t *pfnv = par->pv[0];
798
0
    px_font_t *pxfont;
799
0
    int code = px_find_existing_font(pfnv, &pxfont, pxs);
800
0
    const char *error = 0;
801
802
0
    if (code < 0)
803
0
        error = "UndefinedFontNotRemoved - ";
804
0
    else if (pxfont == 0)       /* built-in font, assume internal */
805
0
        error = "InternalFontNotRemoved - ";
806
0
    else
807
0
        switch (pxfont->storage) {
808
0
            case pxfsInternal:
809
0
                error = "InternalFontNotRemoved - ";
810
0
                break;
811
0
            case pxfsMassStorage:
812
0
                error = "MassStorageFontNotRemoved - ";
813
0
                break;
814
0
            default:           /* downloaded */
815
0
                ;
816
0
        }
817
818
0
    if (error) {                /* Construct a warning message including the font name. */
819
0
        char message[px_max_error_line + 1];
820
821
0
        strcpy(message, error);
822
0
        px_concat_font_name(message, px_max_error_line, pfnv);
823
0
        code = px_record_warning(message, false, pxs);
824
0
    }
825
826
0
    if (error == NULL && pxfont != NULL) {
827
        /*
828
         * If we're deleting the current font we have to update the
829
         * graphics state.
830
         */
831
0
        if (pxfont->pfont == gs_currentfont(pxs->pgs))
832
0
            gs_setfont(pxs->pgs, NULL);
833
834
0
        px_dict_undef(&pxs->font_dict, par->pv[0]);
835
0
    }
836
837
0
    return code;
838
0
}