Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zfont0.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Composite font creation operator */
18
#include "ghost.h"
19
#include "oper.h"
20
#include "gsstruct.h"
21
/*
22
 * The following lines used to say:
23
 *      #include "gsmatrix.h"
24
 *      #include "gxdevice.h"           /. for gxfont.h ./
25
 * Tony Li says the longer list is necessary to keep the GNU compiler
26
 * happy, but this is pretty hard to understand....
27
 */
28
#include "gxfixed.h"
29
#include "gxmatrix.h"
30
#include "gzstate.h"    /* must precede gxdevice */
31
#include "gxdevice.h"   /* must precede gxfont */
32
#include "gxfcmap.h"
33
#include "gxfont.h"
34
#include "gxfont0.h"
35
#include "bfont.h"
36
#include "ialloc.h"
37
#include "iddict.h"
38
#include "idparam.h"
39
#include "igstate.h"
40
#include "iname.h"
41
#include "store.h"
42
43
/* Imported from zfcmap.c */
44
int ztype0_get_cmap(const gs_cmap_t ** ppcmap, const ref * pfdepvector,
45
                    const ref * op, gs_memory_t *imem);
46
47
/* Forward references */
48
static font_proc_define_font(ztype0_define_font);
49
static font_proc_make_font(ztype0_make_font);
50
static int ensure_char_entry(i_ctx_t *, os_ptr, const char *, byte *, int);
51
52
/* <string|name> <font_dict> .buildfont0 <string|name> <font> */
53
/* Build a type 0 (composite) font. */
54
static int
55
zbuildfont0(i_ctx_t *i_ctx_p)
56
6
{
57
6
    os_ptr op = osp;
58
6
    gs_type0_data data;
59
6
    ref fdepvector;
60
6
    ref *pprefenc;
61
6
    gs_font_type0 *pfont;
62
6
    font_data *pdata;
63
6
    ref save_FID;
64
6
    int i;
65
6
    int code = 0;
66
67
6
    check_op(2);
68
2
    check_type(*op, t_dictionary);
69
1
    {
70
1
        ref *pfmaptype;
71
1
        ref *pfdepvector;
72
73
1
        if (dict_find_string(op, "FMapType", &pfmaptype) <= 0 ||
74
1
            !r_has_type(pfmaptype, t_integer) ||
75
1
            pfmaptype->value.intval < (int)fmap_type_min ||
76
1
            pfmaptype->value.intval > (int)fmap_type_max ||
77
1
            dict_find_string(op, "FDepVector", &pfdepvector) <= 0 ||
78
1
            !r_is_array(pfdepvector)
79
1
            )
80
1
            return_error(gs_error_invalidfont);
81
0
        data.FMapType = (fmap_type) pfmaptype->value.intval;
82
        /*
83
         * Adding elements below could cause the font dictionary to be
84
         * resized, which would invalidate pfdepvector.
85
         */
86
0
        fdepvector = *pfdepvector;
87
0
    }
88
    /* Check that every element of the FDepVector is a font. */
89
0
    data.fdep_size = r_size(&fdepvector);
90
0
    for (i = 0; i < data.fdep_size; i++) {
91
0
        ref fdep;
92
0
        gs_font *psub;
93
94
0
        array_get(imemory, &fdepvector, i, &fdep);
95
0
        if ((code = font_param(&fdep, &psub)) < 0)
96
0
            return code;
97
        /*
98
         * Check the inheritance rules.  Allowed configurations
99
         * (paths from root font) are defined by the regular
100
         * expression:
101
         *      (shift | double_escape escape* | escape*)
102
         *        non_modal* non_composite
103
         */
104
0
        if (psub->FontType == ft_composite) {
105
0
            const gs_font_type0 *const psub0 = (const gs_font_type0 *)psub;
106
0
            fmap_type fmt = psub0->data.FMapType;
107
108
0
            if (fmt == fmap_double_escape ||
109
0
                fmt == fmap_shift ||
110
0
                (fmt == fmap_escape &&
111
0
                 !(data.FMapType == fmap_escape ||
112
0
                   data.FMapType == fmap_double_escape))
113
0
                )
114
0
                return_error(gs_error_invalidfont);
115
0
        }
116
0
    }
117
0
    switch (data.FMapType) {
118
0
        case fmap_escape:
119
0
        case fmap_double_escape:  /* need EscChar */
120
0
            code = ensure_char_entry(i_ctx_p, op, "EscChar", &data.EscChar, 255);
121
0
            break;
122
0
        case fmap_shift:  /* need ShiftIn & ShiftOut */
123
0
            code = ensure_char_entry(i_ctx_p, op, "ShiftIn", &data.ShiftIn, 15);
124
0
            if (code >= 0)
125
0
                code = ensure_char_entry(i_ctx_p, op, "ShiftOut", &data.ShiftOut, 14);
126
0
            break;
127
0
        case fmap_SubsVector: /* need SubsVector */
128
0
            {
129
0
                ref *psubsvector;
130
0
                uint svsize;
131
132
0
                if (dict_find_string(op, "SubsVector", &psubsvector) <= 0 ||
133
0
                    !r_has_type(psubsvector, t_string) ||
134
0
                    (svsize = r_size(psubsvector)) == 0 ||
135
0
                (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 ||
136
0
                    (svsize - 1) % data.subs_width != 0
137
0
                    )
138
0
                    return_error(gs_error_invalidfont);
139
0
                data.subs_size = (svsize - 1) / data.subs_width;
140
0
                data.SubsVector.data = psubsvector->value.bytes + 1;
141
0
                data.SubsVector.size = svsize - 1;
142
0
            } break;
143
0
        case fmap_CMap: /* need CMap */
144
0
            code = ztype0_get_cmap(&data.CMap, (const ref *)&fdepvector,
145
0
                                   (const ref *)op, imemory);
146
0
            break;
147
0
        default:
148
0
            ;
149
0
    }
150
0
    if (code < 0)
151
0
        return code;
152
    /*
153
     * Save the old FID in case we have to back out.
154
     * build_gs_font will return an error if there is a FID entry
155
     * but it doesn't reference a valid font.
156
     */
157
0
    {
158
0
        ref *pfid;
159
160
0
        if (dict_find_string(op, "FID", &pfid) <= 0)
161
0
            make_null(&save_FID);
162
0
        else
163
0
            save_FID = *pfid;
164
0
    }
165
0
    {
166
0
        build_proc_refs build;
167
168
0
        code = build_proc_name_refs(imemory, &build,
169
0
                                    "%Type0BuildChar", "%Type0BuildGlyph");
170
0
        if (code < 0)
171
0
            return code;
172
0
        code = build_gs_font(i_ctx_p, op, (gs_font **) & pfont,
173
0
                             ft_composite, &st_gs_font_type0, &build,
174
0
                             bf_options_none);
175
0
    }
176
0
    if (code != 0)
177
0
        return code;
178
    /* Fill in the rest of the basic font data. */
179
0
    pfont->procs.init_fstack = gs_type0_init_fstack;
180
0
    pfont->procs.define_font = ztype0_define_font;
181
0
    pfont->procs.make_font = ztype0_make_font;
182
0
    pfont->procs.next_char_glyph = gs_type0_next_char_glyph;
183
0
    pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode; /* PDF needs. */
184
0
    if (dict_find_string(op, "PrefEnc", &pprefenc) <= 0) {
185
0
        ref nul;
186
187
0
        make_null_new(&nul);
188
0
        if ((code = idict_put_string(op, "PrefEnc", &nul)) < 0)
189
0
            goto fail;
190
0
    }
191
0
    get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op);
192
    /* Fill in the font data */
193
0
    pdata = pfont_data(pfont);
194
0
    data.encoding_size = r_size(&pdata->Encoding);
195
    /*
196
     * Adobe interpreters apparently require that Encoding.size >= subs_size
197
     * +1 (not sure whether the +1 only applies if the sum of the range
198
     * sizes is less than the size of the code space).  The gs library
199
     * doesn't require this -- it only gives an error if a show operation
200
     * actually would reference beyond the end of the Encoding -- so we
201
     * check this here rather than in the library.
202
     */
203
0
    if (data.FMapType == fmap_SubsVector) {
204
0
        if (data.subs_size >= r_size(&pdata->Encoding)) {
205
0
            code = gs_note_error(gs_error_rangecheck);
206
0
            goto fail;
207
0
        }
208
0
    }
209
0
    data.Encoding =
210
0
        (uint *) ialloc_byte_array(data.encoding_size, sizeof(uint),
211
0
                                   "buildfont0(Encoding)");
212
0
    if (data.Encoding == 0) {
213
0
        code = gs_note_error(gs_error_VMerror);
214
0
        goto fail;
215
0
    }
216
    /* Fill in the encoding vector, checking to make sure that */
217
    /* each element is an integer between 0 and fdep_size-1. */
218
0
    for (i = 0; i < data.encoding_size; i++) {
219
0
        ref enc;
220
221
0
        array_get(imemory, &pdata->Encoding, i, &enc);
222
0
        if (!r_has_type(&enc, t_integer)) {
223
0
            code = gs_note_error(gs_error_typecheck);
224
0
            goto fail;
225
0
        }
226
0
        if ((ulong) enc.value.intval >= data.fdep_size) {
227
0
            code = gs_note_error(gs_error_rangecheck);
228
0
            goto fail;
229
0
        }
230
0
        data.Encoding[i] = (uint) enc.value.intval;
231
0
    }
232
0
    data.FDepVector =
233
0
        ialloc_struct_array(data.fdep_size, gs_font *,
234
0
                            &st_gs_font_ptr_element,
235
0
                            "buildfont0(FDepVector)");
236
0
    if (data.FDepVector == 0) {
237
0
        code = gs_note_error(gs_error_VMerror);
238
0
        goto fail;
239
0
    }
240
0
    for (i = 0; i < data.fdep_size; i++) {
241
0
        ref fdep;
242
0
        ref *pfid;
243
244
0
        array_get(pfont->memory, &fdepvector, i, &fdep);
245
        /* The lookup can't fail, because of the pre-check above. */
246
0
        dict_find_string(&fdep, "FID", &pfid);
247
0
        if (!r_has_type(pfid, t_fontID))
248
0
            return gs_note_error(gs_error_typecheck);
249
250
0
        data.FDepVector[i] = r_ptr(pfid, gs_font);
251
0
    }
252
0
    pfont->data = data;
253
0
    code = define_gs_font(i_ctx_p, (gs_font *) pfont);
254
0
    if (code >= 0)
255
0
        return code;
256
0
fail:
257
        /*
258
         * Undo the insertion of the FID entry in the dictionary.  Note that
259
         * some allocations (Encoding, FDepVector) are not undone.
260
         */
261
0
    if (r_has_type(&save_FID, t_null)) {
262
0
        ref rnfid;
263
264
0
        name_enter_string(pfont->memory, "FID", &rnfid);
265
0
        idict_undef(op, &rnfid);
266
0
    } else
267
0
        idict_put_string(op, "FID", &save_FID);
268
0
    gs_free_object(pfont->memory, pfont, "buildfont0(font)");
269
0
    return code;
270
0
}
271
/* If a newly defined or scaled composite font had to scale */
272
/* any composite sub-fonts, adjust the parent font's FDepVector. */
273
/* This is called only if gs_type0_define/make_font */
274
/* actually changed the FDepVector. */
275
static int
276
ztype0_adjust_FDepVector(gs_font_type0 * pfont)
277
0
{
278
0
    gs_memory_t *mem = pfont->memory;
279
    /* HACK: We know the font was allocated by the interpreter. */
280
0
    gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
281
0
    gs_font **pdep = pfont->data.FDepVector;
282
0
    ref newdep;
283
0
    uint fdep_size = pfont->data.fdep_size;
284
0
    ref *prdep;
285
0
    uint i;
286
0
    int code = gs_alloc_ref_array(imem, &newdep, a_readonly, fdep_size,
287
0
                                  "ztype0_adjust_matrix");
288
289
0
    if (code < 0)
290
0
        return code;
291
0
    for (prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++) {
292
0
        const ref *pdict = pfont_dict(pdep[i]);
293
294
0
        ref_assign(prdep, pdict);
295
0
        r_set_attrs(prdep, imemory_new_mask(imem));
296
0
    }
297
    /*
298
     * The FDepVector is an existing key in the parent's dictionary,
299
     * so it's safe to pass NULL as the dstack pointer to dict_put_string.
300
     */
301
0
    return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep, NULL);
302
0
}
303
static int
304
ztype0_define_font(gs_font_dir * pdir, gs_font * pfont)
305
0
{
306
0
    gs_font_type0 *const pfont0 = (gs_font_type0 *)pfont;
307
0
    gs_font **pdep = pfont0->data.FDepVector;
308
0
    int code = gs_type0_define_font(pdir, pfont);
309
310
0
    if (code < 0 || pfont0->data.FDepVector == pdep)
311
0
        return code;
312
0
    return ztype0_adjust_FDepVector(pfont0);
313
0
}
314
static int
315
ztype0_make_font(gs_font_dir * pdir, const gs_font * pfont,
316
                 const gs_matrix * pmat, gs_font ** ppfont)
317
0
{
318
0
    gs_font_type0 **const ppfont0 = (gs_font_type0 **)ppfont;
319
0
    gs_font **pdep = (*ppfont0)->data.FDepVector;
320
0
    int code;
321
322
0
    code = zdefault_make_font(pdir, pfont, pmat, ppfont);
323
0
    if (code < 0)
324
0
        return code;
325
0
    code = gs_type0_make_font(pdir, pfont, pmat, ppfont);
326
0
    if (code < 0)
327
0
        return code;
328
0
    if ((*ppfont0)->data.FDepVector == pdep)
329
0
        return 0;
330
0
    return ztype0_adjust_FDepVector(*ppfont0);
331
0
}
332
333
/* ------ Internal routines ------ */
334
335
/* Find or add a character entry in a font dictionary. */
336
static int
337
ensure_char_entry(i_ctx_t *i_ctx_p, os_ptr op, const char *kstr,
338
                  byte * pvalue, int default_value)
339
0
{
340
0
    ref *pentry;
341
342
0
    if (dict_find_string(op, kstr, &pentry) <= 0) {
343
0
        ref ent;
344
345
0
        make_int(&ent, default_value);
346
0
        *pvalue = (byte) default_value;
347
0
        return idict_put_string(op, kstr, &ent);
348
0
    } else {
349
0
        check_int_leu_only(*pentry, 255);
350
0
        *pvalue = (byte) pentry->value.intval;
351
0
        return 0;
352
0
    }
353
0
}
354
355
/* ------ Initialization procedure ------ */
356
357
const op_def zfont0_op_defs[] =
358
{
359
    {"2.buildfont0", zbuildfont0},
360
    op_def_end(0)
361
};