Coverage Report

Created: 2026-08-08 08:00

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