Coverage Report

Created: 2022-10-31 07:00

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