Coverage Report

Created: 2026-07-24 07:44

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