Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zfapi.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
/* Font API client */
18
19
#include "stdlib.h"             /* abs() */
20
21
#include "memory_.h"
22
#include "math_.h"
23
#include "stat_.h"              /* include before definition of esp macro, bug 691123 */
24
#include "string_.h"
25
#include "ghost.h"
26
#include "gp.h"
27
#include "oper.h"
28
#include "gxdevice.h"
29
#include "gxfont.h"
30
#include "gxfont1.h"
31
#include "gxchar.h"
32
#include "gzpath.h"
33
#include "gxpath.h"
34
#include "gxfcache.h"
35
#include "gxchrout.h"
36
#include "gximask.h"
37
#include "gscoord.h"
38
#include "gspaint.h"
39
#include "gsfont.h"
40
#include "gspath.h"
41
#include "bfont.h"
42
#include "dstack.h"
43
#include "estack.h"
44
#include "ichar.h"
45
#include "idict.h"
46
#include "iname.h"
47
#include "ifont.h"
48
#include "icid.h"
49
#include "igstate.h"
50
#include "icharout.h"
51
52
#include "ifapi.h"
53
#include "iplugin.h"
54
#include "store.h"
55
#include "gzstate.h"
56
/* #include "gdevpsf.h" */
57
#include "stream.h"             /* for files.h */
58
#include "gscrypt1.h"
59
#include "gxfcid.h"
60
#include "gsstype.h"
61
#include "gxchar.h"             /* for st_gs_show_enum */
62
#include "ipacked.h"            /* for packed_next */
63
#include "iddict.h"
64
#include "ifont42.h"            /* for string_array_access_proc */
65
#include "gdebug.h"
66
#include "gsimage.h"
67
#include "gxcldev.h"
68
#include "gxdevmem.h"
69
70
#include "gxfapi.h"
71
72
/* -------------------------------------------------------- */
73
74
typedef struct sfnts_reader_s sfnts_reader;
75
struct sfnts_reader_s
76
{
77
    ref *sfnts;
78
    const gs_memory_t *memory;
79
    const byte *p;
80
    long index;
81
    uint offset;
82
    uint length;
83
    int error;
84
         byte(*rbyte) (sfnts_reader *r);
85
         ushort(*rword) (sfnts_reader *r);
86
         ulong(*rlong) (sfnts_reader *r);
87
    int (*rstring) (sfnts_reader *r, byte *v, int length);
88
    void (*seek) (sfnts_reader *r, ulong pos);
89
};
90
91
static void
92
sfnts_next_elem(sfnts_reader *r)
93
402
{
94
402
    ref s;
95
402
    int code;
96
97
402
    if (r->error < 0)
98
0
        return;
99
402
    do {
100
402
      r->index++;
101
402
      code = array_get(r->memory, r->sfnts, r->index, &s);
102
402
        if (code < 0) {
103
20
            r->error = code;
104
20
            return;
105
20
        }
106
382
        if (!r_has_type(&s, t_string)) {
107
8
            r->error = gs_note_error(gs_error_typecheck);
108
8
            return;
109
8
        }
110
374
      r->p = s.value.const_bytes;
111
374
      r->length = r_size(&s) & ~(uint) 1; /* See Adobe Technical Note # 5012, section 4.2. */
112
374
    } while (r->length == 0);
113
374
    r->offset = 0;
114
374
}
115
116
static inline byte
117
sfnts_reader_rbyte_inline(sfnts_reader *r)
118
6.48k
{
119
6.48k
    if (r->offset >= r->length)
120
0
        sfnts_next_elem(r);
121
6.48k
    return ((r->error < 0) ? 0 : r->p[r->offset++]);
122
6.48k
}
123
124
static byte
125
sfnts_reader_rbyte(sfnts_reader *r)
126
0
{                               /* old compiler compatibility */
127
0
    return (sfnts_reader_rbyte_inline(r));
128
0
}
129
130
480
#define SFNTS_READER_RBYTE_TO_USHORT(r) ((ulong)sfnts_reader_rbyte_inline(r))
131
132
static ushort
133
sfnts_reader_rword(sfnts_reader *r)
134
240
{
135
240
    ushort retval;
136
137
240
    retval = SFNTS_READER_RBYTE_TO_USHORT(r) << 8;
138
240
    retval += SFNTS_READER_RBYTE_TO_USHORT(r);
139
140
240
    return retval;
141
240
}
142
143
#undef SFNTS_READER_RBYTE_TO_USHORT
144
145
6.00k
#define SFNTS_READER_RBYTE_TO_ULONG(r) ((ulong)sfnts_reader_rbyte_inline(r))
146
147
static ulong
148
sfnts_reader_rlong(sfnts_reader *r)
149
1.50k
{
150
1.50k
    ulong retval;
151
1.50k
    retval = SFNTS_READER_RBYTE_TO_ULONG(r) << 24;
152
1.50k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 16;
153
1.50k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 8;
154
1.50k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r);
155
1.50k
    return retval;
156
1.50k
}
157
158
#undef SFNTS_READER_RWORD_TO_LONG
159
160
static int
161
sfnts_reader_rstring(sfnts_reader *r, byte *v, int length)
162
504
{
163
504
    int rlength = length;
164
165
504
    if (length <= 0)
166
0
        return (0);
167
528
    while (r->error >= 0) {
168
516
        int l = min(length, r->length - r->offset);
169
170
516
        memcpy(v, r->p + r->offset, l);
171
516
        length -= l;
172
516
        r->offset += l;
173
516
        if (length <= 0)
174
492
            return (rlength);
175
24
        v += l;
176
24
        sfnts_next_elem(r);
177
24
    }
178
12
    return (rlength - length);
179
504
}
180
181
static void
182
sfnts_reader_seek(sfnts_reader *r, ulong pos)
183
40
{                               /* fixme : optimize */
184
40
    ulong skipped = 0;
185
186
40
    r->index = -1;
187
40
    sfnts_next_elem(r);
188
318
    while (skipped + r->length < pos && r->error >= 0) {
189
278
        skipped += r->length;
190
278
        sfnts_next_elem(r);
191
278
    }
192
40
    r->offset = pos - skipped;
193
40
}
194
195
static void
196
sfnts_reader_init(const gs_memory_t *mem, sfnts_reader *r, ref *pdr)
197
60
{
198
60
    r->memory = mem;
199
60
    r->rbyte = sfnts_reader_rbyte;
200
60
    r->rword = sfnts_reader_rword;
201
60
    r->rlong = sfnts_reader_rlong;
202
60
    r->rstring = sfnts_reader_rstring;
203
60
    r->seek = sfnts_reader_seek;
204
60
    r->index = -1;
205
60
    r->error = 0;
206
60
    if (r_type(pdr) != t_dictionary ||
207
60
        dict_find_string(pdr, "sfnts", &r->sfnts) <= 0)
208
0
        r->error = gs_error_undefined;
209
60
    sfnts_next_elem(r);
210
60
}
211
212
/* -------------------------------------------------------- */
213
214
typedef struct sfnts_writer_s sfnts_writer;
215
struct sfnts_writer_s
216
{
217
    byte *buf, *p;
218
    int buf_size;
219
    void (*wbyte) (sfnts_writer *w, byte v);
220
    void (*wword) (sfnts_writer *w, ushort v);
221
    void (*wlong) (sfnts_writer *w, ulong v);
222
    void (*wstring) (sfnts_writer *w, byte *v, int length);
223
};
224
225
static void
226
sfnts_writer_wbyte(sfnts_writer *w, byte v)
227
4
{
228
4
    if (w->buf + w->buf_size < w->p + 1)
229
0
        return;                 /* safety */
230
4
    w->p[0] = v;
231
4
    w->p++;
232
4
}
233
234
static void
235
sfnts_writer_wword(sfnts_writer *w, ushort v)
236
120
{
237
120
    if (w->buf + w->buf_size < w->p + 2)
238
0
        return;                 /* safety */
239
120
    w->p[0] = v / 256;
240
120
    w->p[1] = v % 256;
241
120
    w->p += 2;
242
120
}
243
244
static void
245
sfnts_writer_wlong(sfnts_writer *w, ulong v)
246
570
{
247
570
    if (w->buf + w->buf_size < w->p + 4)
248
0
        return;                 /* safety */
249
570
    w->p[0] = v >> 24;
250
570
    w->p[1] = (v >> 16) & 0xFF;
251
570
    w->p[2] = (v >> 8) & 0xFF;
252
570
    w->p[3] = v & 0xFF;
253
570
    w->p += 4;
254
570
}
255
256
static void
257
sfnts_writer_wstring(sfnts_writer *w, byte *v, int length)
258
204
{
259
204
    if (w->buf + w->buf_size < w->p + length)
260
0
        return;                 /* safety */
261
204
    memcpy(w->p, v, length);
262
204
    w->p += length;
263
204
}
264
265
static const sfnts_writer sfnts_writer_stub = {
266
    0, 0, 0,
267
    sfnts_writer_wbyte,
268
    sfnts_writer_wword,
269
    sfnts_writer_wlong,
270
    sfnts_writer_wstring
271
};
272
273
/* -------------------------------------------------------- */
274
275
static inline bool
276
sfnts_need_copy_table(byte *tag)
277
764
{
278
764
    return (memcmp(tag, "glyf", 4) && memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
279
672
            memcmp(tag, "loca", 4) && memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
280
580
            memcmp(tag, "cmap", 4));
281
764
}
282
283
static void
284
sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length)
285
40
{
286
40
    byte buf[1024];
287
288
64
    while (length > 0 && r->error >= 0) {
289
24
        int l = min(length, sizeof(buf));
290
291
24
        (void)r->rstring(r, buf, l);
292
24
        w->wstring(w, buf, l);
293
24
        length -= l;
294
24
    }
295
40
}
296
297
static int
298
sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w)
299
60
{                               /* Note : TTC is not supported and probably is unuseful for Type 42. */
300
    /* This skips glyf, loca and cmap from copying. */
301
60
    struct
302
60
    {
303
60
        byte tag[4];
304
60
        ulong checkSum, offset, offset_new, length;
305
60
    } tables[40];
306
60
    const ushort alignment = 4; /* Not sure, maybe 2 */
307
60
    ulong version = r->rlong(r);
308
60
    ushort num_tables = r->rword(r);
309
60
    ushort i, num_tables_new = 0;
310
60
    ushort searchRange, entrySelector = 0, rangeShift, v;
311
60
    ulong size_new = 12;
312
313
60
    if (num_tables > countof(tables)) {
314
0
        r->error = gs_note_error(gs_error_invalidfont);
315
0
        return r->error;
316
0
    }
317
318
60
    r->rword(r);                /* searchRange */
319
60
    if (r->error < 0)
320
0
        return r->error;
321
322
60
    r->rword(r);                /* entrySelector */
323
60
    if (r->error < 0)
324
0
        return r->error;
325
326
60
    r->rword(r);                /* rangeShift */
327
60
    if (r->error < 0)
328
0
        return r->error;
329
330
540
    for (i = 0; i < num_tables && r->error >= 0; i++) {
331
480
        (void)r->rstring(r, tables[i].tag, 4);
332
480
        if (r->error < 0)
333
0
            continue;
334
480
        tables[i].checkSum = r->rlong(r);
335
480
        tables[i].offset = r->rlong(r);
336
480
        tables[i].length = r->rlong(r);
337
480
        tables[i].offset_new = size_new;
338
480
        if (sfnts_need_copy_table(tables[i].tag)) {
339
360
            num_tables_new++;
340
360
            size_new +=
341
360
                (tables[i].length + alignment - 1) / alignment * alignment;
342
360
        }
343
480
    }
344
60
    if (r->error < 0)
345
0
        return r->error;
346
60
    size_new += num_tables_new * 16;
347
60
    if (w == 0) {
348
30
        return size_new;
349
30
    }
350
30
    searchRange = v = num_tables_new * 16;
351
240
    for (i = 0; v; i++) {
352
210
        v >>= 1;
353
210
        searchRange |= v;
354
210
        entrySelector++;
355
210
    }
356
30
    searchRange -= searchRange >> 1;
357
30
    rangeShift = num_tables_new * 16 - searchRange;
358
359
30
    w->wlong(w, version);
360
30
    w->wword(w, num_tables_new);
361
30
    w->wword(w, searchRange);
362
30
    w->wword(w, entrySelector);
363
30
    w->wword(w, rangeShift);
364
270
    for (i = 0; i < num_tables; i++) {
365
240
        if (sfnts_need_copy_table(tables[i].tag)) {
366
180
            w->wstring(w, tables[i].tag, 4);
367
180
            w->wlong(w, tables[i].checkSum);
368
180
            w->wlong(w, tables[i].offset_new + num_tables_new * 16);
369
180
            w->wlong(w, tables[i].length);
370
180
        }
371
240
    }
372
74
    for (i = 0; i < num_tables && r->error >= 0; i++) {
373
44
        if (sfnts_need_copy_table(tables[i].tag)) {
374
40
            int k = tables[i].length;
375
376
40
            r->seek(r, tables[i].offset);
377
378
40
            if (w->p - w->buf != tables[i].offset_new + num_tables_new * 16) {
379
0
                r->error = gs_error_invalidfont;       /* the algorithm consistency check */
380
0
                continue;
381
0
            }
382
40
            sfnt_copy_table(r, w, tables[i].length);
383
44
            for (; k & (alignment - 1); k++)
384
4
                w->wbyte(w, 0);
385
40
        }
386
44
    }
387
30
    if (r->error < 0)
388
28
        return r->error;
389
390
2
    return (size_new);
391
30
}
392
393
static int
394
true_type_size(const gs_memory_t *mem, ref *pdr, unsigned long int *length)
395
30
{
396
30
    sfnts_reader r;
397
398
30
    sfnts_reader_init(mem, &r, pdr);
399
30
    *length = sfnts_copy_except_glyf(&r, 0);
400
401
30
    return r.error;
402
30
}
403
404
static int
405
FAPI_FF_serialize_tt_font(gs_fapi_font *ff, void *buf, int buf_size)
406
30
{
407
30
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
408
30
    sfnts_reader r;
409
30
    sfnts_writer w = sfnts_writer_stub;
410
411
30
    w.buf_size = buf_size;
412
30
    w.buf = w.p = buf;
413
30
    sfnts_reader_init(ff->memory, &r, pdr);
414
30
    return sfnts_copy_except_glyf(&r, &w);
415
30
}
416
417
static inline ushort
418
float_to_ushort(float v)
419
2.09M
{
420
2.09M
    return ((ushort) (v * 16)); /* fixme : the scale may depend on renderer */
421
2.09M
}
422
423
/* In general, we assumed that the entries we use below have been validated (at least for type)
424
 * at definefont time. This means validating each entry only once, rather than on every read
425
 * here. Better, for example, for BlendDesignMap which is an array, of arrays, of arrays of
426
 * numbers.
427
 */
428
static int
429
FAPI_FF_get_word(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, unsigned short *ret)
430
4.03M
{
431
4.03M
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
432
4.03M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
433
4.03M
    int code = 0;
434
435
4.03M
    switch ((int)var_id) {
436
0
        case gs_fapi_font_feature_Weight:
437
0
            *ret = 0;           /* wrong */
438
0
            break;
439
0
        case gs_fapi_font_feature_ItalicAngle:
440
0
            *ret = 0;           /* wrong */
441
0
            break;
442
0
        case gs_fapi_font_feature_IsFixedPitch:
443
0
            *ret = 0;           /* wrong */
444
0
            break;
445
0
        case gs_fapi_font_feature_UnderLinePosition:
446
0
            *ret = 0;           /* wrong */
447
0
            break;
448
0
        case gs_fapi_font_feature_UnderlineThickness:
449
0
            *ret = 0;           /* wrong */
450
0
            break;
451
66.9k
        case gs_fapi_font_feature_FontType:
452
66.9k
            *ret = (pfont->FontType == 2 ? 2 : 1);
453
66.9k
            break;
454
535k
        case gs_fapi_font_feature_FontBBox:
455
535k
            switch (index) {
456
133k
                case 0:
457
133k
                    *ret = ((ushort) pfont->FontBBox.p.x);
458
133k
                    break;
459
133k
                case 1:
460
133k
                    *ret = ((ushort) pfont->FontBBox.p.y);
461
133k
                    break;
462
133k
                case 2:
463
133k
                    *ret = ((ushort) pfont->FontBBox.q.x);
464
133k
                    break;
465
133k
                case 3:
466
133k
                    *ret = ((ushort) pfont->FontBBox.q.y);
467
133k
                    break;
468
0
                default:
469
0
                    code = gs_note_error(gs_error_rangecheck);
470
535k
            }
471
535k
            break;
472
535k
        case gs_fapi_font_feature_BlueValues_count:
473
133k
            *ret = pfont->data.BlueValues.count;
474
133k
            break;
475
1.02M
        case gs_fapi_font_feature_BlueValues:
476
1.02M
            *ret =  (float_to_ushort(pfont->data.BlueValues.values[index]));
477
1.02M
            break;
478
133k
        case gs_fapi_font_feature_OtherBlues_count:
479
133k
            *ret = pfont->data.OtherBlues.count;
480
133k
            break;
481
0
        case gs_fapi_font_feature_OtherBlues:
482
0
            *ret = (float_to_ushort(pfont->data.OtherBlues.values[index]));
483
0
            break;
484
133k
        case gs_fapi_font_feature_FamilyBlues_count:
485
133k
            *ret = pfont->data.FamilyBlues.count;
486
133k
            break;
487
0
        case gs_fapi_font_feature_FamilyBlues:
488
0
            *ret = (float_to_ushort(pfont->data.FamilyBlues.values[index]));
489
0
            break;
490
133k
        case gs_fapi_font_feature_FamilyOtherBlues_count:
491
133k
            *ret = pfont->data.FamilyOtherBlues.count;
492
133k
            break;
493
0
        case gs_fapi_font_feature_FamilyOtherBlues:
494
0
            *ret = (float_to_ushort(pfont->data.FamilyOtherBlues.values[index]));
495
0
            break;
496
133k
        case gs_fapi_font_feature_BlueShift:
497
133k
            *ret = float_to_ushort(pfont->data.BlueShift);
498
133k
            break;
499
133k
        case gs_fapi_font_feature_BlueFuzz:
500
133k
            *ret = float_to_ushort(pfont->data.BlueShift);
501
133k
            break;
502
133k
        case gs_fapi_font_feature_StdHW:
503
133k
            *ret = (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0]));   /* UFST bug ? */
504
133k
            break;
505
133k
        case gs_fapi_font_feature_StdVW:
506
133k
            *ret = (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0]));   /* UFST bug ? */
507
133k
            break;
508
133k
        case gs_fapi_font_feature_StemSnapH_count:
509
133k
            *ret = pfont->data.StemSnapH.count;
510
133k
            break;
511
267k
        case gs_fapi_font_feature_StemSnapH:
512
267k
            *ret = float_to_ushort(pfont->data.StemSnapH.values[index]);
513
267k
            break;
514
133k
        case gs_fapi_font_feature_StemSnapV_count:
515
133k
            *ret = pfont->data.StemSnapV.count;
516
133k
            break;
517
264k
        case gs_fapi_font_feature_StemSnapV:
518
264k
            *ret = float_to_ushort(pfont->data.StemSnapV.values[index]);
519
264k
            break;
520
133k
        case gs_fapi_font_feature_ForceBold:
521
133k
            *ret = pfont->data.ForceBold;
522
133k
            break;
523
0
        case gs_fapi_font_feature_LanguageGroup:
524
0
            *ret = pfont->data.LanguageGroup;
525
0
            break;
526
0
        case gs_fapi_font_feature_lenIV:
527
0
            *ret = ff->need_decrypt ? 0 : pfont->data.lenIV;
528
0
            break;
529
0
        case gs_fapi_font_feature_GlobalSubrs_count:
530
0
            {
531
0
                ref *Private, *GlobalSubrs;
532
533
0
                if (pfont->FontType == ft_encrypted2) {
534
0
                    if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0) {
535
0
                        *ret = 0;
536
0
                        break;
537
0
                    }
538
0
                    if (dict_find_string(Private, "GlobalSubrs", &GlobalSubrs) <= 0) {
539
0
                        *ret = 0;
540
0
                        break;
541
0
                    }
542
0
                    *ret = r_size(GlobalSubrs);
543
0
                    break;
544
0
                }
545
0
                *ret = 0;
546
0
                break;
547
0
            }
548
133k
        case gs_fapi_font_feature_Subrs_count:
549
133k
            {
550
133k
                ref *Private, *Subrs;
551
552
133k
                if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0) {
553
0
                    *ret = 0;
554
0
                    break;
555
0
                }
556
133k
                if (dict_find_string_with_type(Private, "Subrs", &Subrs, t_array) <= 0) {
557
0
                    *ret = 0;
558
0
                    break;
559
0
                }
560
133k
                *ret = r_size(Subrs);
561
133k
                break;
562
133k
            }
563
0
        case gs_fapi_font_feature_CharStrings_count:
564
0
            {
565
0
                ref *CharStrings;
566
567
0
                if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0)
568
0
                    *ret = 0;
569
0
                else
570
0
                    *ret = dict_maxlength(CharStrings);
571
0
                break;
572
133k
            }
573
            /* Multiple Master specific */
574
267k
        case gs_fapi_font_feature_DollarBlend:
575
267k
            {
576
267k
                ref *DBlend;
577
578
267k
                if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
579
267k
                    *ret = 0;
580
4
                else
581
4
                    *ret = 1;
582
267k
                break;
583
133k
            }
584
6
        case gs_fapi_font_feature_BlendAxisTypes_count:
585
6
            {
586
6
                ref *Info, *Axes;
587
588
6
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
589
0
                    *ret = 0;
590
0
                    break;
591
0
                }
592
6
                if (dict_find_string_with_type(Info, "BlendAxisTypes", &Axes, t_array) <= 0) {
593
0
                    *ret = 0;
594
0
                    break;
595
0
                }
596
6
                *ret = r_size(Axes);
597
6
                break;
598
6
            }
599
0
        case gs_fapi_font_feature_BlendFontInfo_count:
600
0
            {
601
0
                ref *Info, *FontInfo;
602
603
0
                if (dict_find_string_with_type(pdr, "Blend", &Info, t_dictionary) <= 0) {
604
0
                    *ret = 0;
605
0
                    break;
606
0
                }
607
0
                if (dict_find_string_with_type(Info, "FontInfo", &FontInfo, t_dictionary) <= 0) {
608
0
                    *ret = 0;
609
0
                    break;
610
0
                }
611
0
                *ret = dict_length(FontInfo);
612
0
                break;
613
0
            }
614
0
        case gs_fapi_font_feature_BlendPrivate_count:
615
0
            {
616
0
                ref *Info, *Private;
617
618
0
                if (dict_find_string_with_type(pdr, "Blend", &Info, t_dictionary) <= 0) {
619
0
                    *ret = 0;
620
0
                    break;
621
0
                }
622
0
                if (dict_find_string_with_type(Info, "Private", &Private, t_dictionary) <= 0) {
623
0
                    *ret = 0;
624
0
                    break;
625
0
                }
626
0
                *ret = dict_length(Private);
627
0
                break;
628
0
            }
629
2
        case gs_fapi_font_feature_WeightVector_count:
630
2
            {
631
2
                *ret = pfont->data.WeightVector.count;
632
2
                break;
633
0
            }
634
4
        case gs_fapi_font_feature_BlendDesignPositionsArrays_count:
635
4
            {
636
4
                ref *Info, *Array;
637
638
4
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
639
0
                    *ret = 0;
640
0
                    break;
641
0
                }
642
4
                if (dict_find_string_with_type(Info, "BlendDesignPositions", &Array, t_array) <= 0) {
643
0
                    *ret = 0;
644
0
                    break;
645
0
                }
646
4
                *ret = r_size(Array);
647
4
                break;
648
4
            }
649
4
        case gs_fapi_font_feature_BlendDesignMapArrays_count:
650
4
            {
651
4
                ref *Info, *Array;
652
653
4
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
654
0
                    *ret = 0;
655
0
                    break;
656
0
                }
657
4
                if (dict_find_string_with_type(Info, "BlendDesignMap", &Array, t_array) <= 0) {
658
0
                    *ret = 0;
659
0
                    break;
660
0
                }
661
4
                *ret = r_size(Array);
662
4
                break;
663
4
            }
664
2
        case gs_fapi_font_feature_BlendDesignMapSubArrays_count:
665
2
            {
666
2
                ref *Info, *Array, SubArray;
667
668
2
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
669
0
                    *ret = 0;
670
0
                    break;
671
0
                }
672
2
                if (dict_find_string_with_type(Info, "BlendDesignMap", &Array, t_array) <= 0) {
673
0
                    *ret = 0;
674
0
                    break;
675
0
                }
676
2
                if (array_get_with_type(ff->memory, Array, index, &SubArray, t_array) < 0) {
677
0
                    *ret = 0;
678
0
                    break;
679
0
                }
680
2
                *ret = r_size(&SubArray);
681
2
                break;
682
2
            }
683
2
        case gs_fapi_font_feature_DollarBlend_length:
684
2
            {
685
2
                ref *DBlend, Element, string;
686
2
                int i, length = 0;
687
2
                char Buffer[32];
688
689
2
                if (dict_find_string(pdr, "$Blend", &DBlend) <= 0) {
690
0
                    *ret = 0;
691
0
                    break;
692
0
                }
693
8
                for (i = 0; i < r_size(DBlend); i++) {
694
                    /* When reading the real proc, we add a space between each entry */
695
6
                    length++;
696
6
                    if (array_get(ff->memory, DBlend, i, &Element) < 0) {
697
0
                        length = 0;
698
0
                        break;
699
0
                    }
700
6
                    switch (r_btype(&Element)) {
701
0
                        case t_name:
702
0
                            name_string_ref(ff->memory, &Element, &string);
703
0
                            length += r_size(&string);
704
0
                            break;
705
2
                        case t_real:
706
2
                            gs_snprintf(Buffer, sizeof(Buffer), "%f", Element.value.realval);
707
2
                            length += strlen(Buffer);
708
2
                            break;
709
0
                        case t_integer:
710
0
                            gs_snprintf(Buffer, sizeof(Buffer), "%"PRIpsint, Element.value.intval);
711
0
                            length += strlen(Buffer);
712
0
                            break;
713
4
                        case t_operator:
714
4
                            {
715
4
                                op_def const *op;
716
717
4
                                op = op_index_def(r_size(&Element));
718
4
                                length += strlen(op->oname + 1);
719
4
                            }
720
4
                            break;
721
0
                        default:
722
0
                            break;
723
6
                    }
724
725
6
                    if (length > max_ushort) {
726
0
                        length = 0;
727
0
                        break;
728
0
                    }
729
6
                 }
730
2
                *ret = length;
731
2
                break;
732
2
            }
733
2
        case gs_fapi_font_feature_BlendFontBBox_length:
734
2
            {
735
2
                ref *Blend, *bfbbox, bfbbox0;
736
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
737
0
                    *ret = 0;
738
0
                    break;
739
0
                }
740
741
2
                if (dict_find_string_with_type(Blend, "FontBBox", &bfbbox, t_array) <= 0) {
742
0
                    *ret = 0;
743
0
                    break;
744
0
                }
745
2
                if (array_get_with_type(ff->memory, bfbbox, 0, &bfbbox0, t_array) < 0) {
746
0
                    *ret = 0;
747
0
                    break;
748
0
                }
749
2
                *ret = (ushort)r_size(&bfbbox0);
750
2
                break;
751
2
            }
752
16
        case gs_fapi_font_feature_BlendFontBBox:
753
16
            {
754
16
                ref *Blend, *bfbbox, subbfbbox, val;
755
16
                int aind, ind;
756
16
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
757
0
                    *ret = 0;
758
0
                    break;
759
0
                }
760
16
                if (dict_find_string_with_type(Blend, "FontBBox", &bfbbox, t_array) <= 0) {
761
0
                    *ret = 0;
762
0
                    break;
763
0
                }
764
16
                ind = index % 4;
765
16
                aind = (index - ind) /4;
766
16
                if (array_get_with_type(ff->memory, bfbbox, aind, &subbfbbox, t_array) < 0) {
767
0
                    *ret = 0;
768
0
                    break;
769
0
                }
770
16
                if (array_get_with_type(ff->memory, &subbfbbox, ind, &val, t_integer) < 0) {
771
0
                    *ret = 0;
772
0
                    break;
773
0
                }
774
775
16
                *ret = (ushort)val.value.intval;
776
16
                break;
777
16
            }
778
2
        case gs_fapi_font_feature_BlendBlueValues_length:
779
2
            {
780
2
                ref *Priv, *Blend, *bbv;
781
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
782
0
                    *ret = 0;
783
0
                    break;
784
0
                }
785
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
786
0
                    *ret = 0;
787
0
                    break;
788
0
                }
789
2
                if (dict_find_string_with_type(Priv, "BlueValues", &bbv, t_array) <= 0) {
790
2
                    *ret = 0;
791
2
                    break;
792
2
                }
793
0
                *ret = (ushort)r_size(bbv);
794
0
                break;
795
2
            }
796
0
        case gs_fapi_font_feature_BlendBlueValues_count:
797
0
            {
798
0
                ref *Priv, *Blend, *bbv, sub;
799
800
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
801
0
                    *ret = 0;
802
0
                    break;
803
0
                }
804
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
805
0
                    *ret = 0;
806
0
                    break;
807
0
                }
808
0
                if (dict_find_string_with_type(Priv, "BlueValues", &bbv, t_array) <= 0) {
809
0
                    *ret = 0;
810
0
                    break;
811
0
                }
812
0
                if (array_get_with_type(ff->memory, bbv, index, &sub, t_array) < 0) {
813
0
                    *ret = 0;
814
0
                    break;
815
0
                }
816
0
                *ret = (ushort)r_size(&sub);
817
0
                break;
818
0
            }
819
0
        case gs_fapi_font_feature_BlendBlueValues:
820
0
            {
821
0
                ref *Priv, *Blend, *bbv, sub, r;
822
0
                int aind = 0;
823
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
824
0
                    *ret = 0;
825
0
                    break;
826
0
                }
827
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
828
0
                    *ret = 0;
829
0
                    break;
830
0
                }
831
0
                if (dict_find_string_with_type(Priv, "BlueValues", &bbv, t_array) <= 0) {
832
0
                    *ret = 0;
833
0
                    break;
834
0
                }
835
836
0
                while (1) {
837
0
                    if ((code = array_get_with_type(ff->memory, bbv, aind++, &sub, t_array)) < 0) {
838
0
                        *ret = 0;
839
0
                        break;
840
0
                    }
841
0
                    if (index - (int)r_size(&sub) < 0) {
842
0
                        break;
843
0
                    }
844
0
                    index -= r_size(&sub);
845
0
                }
846
0
                if (code < 0)
847
0
                    break;
848
849
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_integer) < 0) {
850
0
                    *ret = 0;
851
0
                    break;
852
0
                }
853
854
0
                *ret = (ushort)r.value.intval;
855
0
                break;
856
0
            }
857
2
        case gs_fapi_font_feature_BlendOtherBlues_length:
858
2
            {
859
2
                ref *Priv, *Blend, *bob;
860
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
861
0
                    *ret = 0;
862
0
                    break;
863
0
                }
864
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
865
0
                    *ret = 0;
866
0
                    break;
867
0
                }
868
2
                if (dict_find_string_with_type(Priv, "OtherBlues", &bob, t_array) <= 0) {
869
2
                    *ret = 0;
870
2
                    break;
871
2
                }
872
0
                *ret = (ushort)r_size(bob);
873
0
                break;
874
2
            }
875
0
        case gs_fapi_font_feature_BlendOtherBlues_count:
876
0
            {
877
0
                ref *Priv, *Blend, *bob, sub;
878
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
879
0
                    *ret = 0;
880
0
                    break;
881
0
                }
882
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
883
0
                    *ret = 0;
884
0
                    break;
885
0
                }
886
0
                if (dict_find_string_with_type(Priv, "OtherBlues", &bob, t_array) <= 0) {
887
0
                    *ret = 0;
888
0
                    break;
889
0
                }
890
891
0
                 if (array_get_with_type(ff->memory, bob, index, &sub, t_array) < 0) {
892
0
                    *ret = 0;
893
0
                    break;
894
0
                }
895
0
                *ret = (ushort)r_size(&sub);
896
0
                break;
897
0
            }
898
0
        case gs_fapi_font_feature_BlendOtherBlues:
899
0
            {
900
0
                ref *Priv, *Blend, *bob, sub, r;
901
0
                int aind = 0;
902
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
903
0
                    *ret = 0;
904
0
                    break;
905
0
                }
906
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
907
0
                    *ret = 0;
908
0
                    break;
909
0
                }
910
0
                if (dict_find_string_with_type(Priv, "OtherBlues", &bob, t_array) <= 0) {
911
0
                    *ret = 0;
912
0
                    break;
913
0
                }
914
915
0
                while (1) {
916
0
                    if ((code = array_get_with_type(ff->memory, bob, aind++, &sub, t_array)) < 0)
917
0
                        break;
918
0
                    if (index - (int)r_size(&sub) < 0) {
919
0
                        break;
920
0
                    }
921
0
                    index -= r_size(&sub);
922
0
                }
923
0
                if (code < 0) {
924
0
                    *ret = 0;
925
0
                    break;
926
0
                }
927
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_integer) < 0) {
928
0
                    *ret = 0;
929
0
                    break;
930
0
                }
931
932
0
                *ret = (ushort)r.value.intval;
933
0
                break;
934
0
            }
935
2
        case gs_fapi_font_feature_BlendBlueScale_count:
936
2
            {
937
2
                ref *Priv, *Blend, *bbs;
938
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
939
0
                    *ret = 0;
940
0
                    break;
941
0
                }
942
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
943
0
                    *ret = 0;
944
0
                    break;
945
0
                }
946
2
                if (dict_find_string_with_type(Priv, "BlueScale", &bbs, t_array) <= 0) {
947
2
                    *ret = 0;
948
2
                    break;
949
2
                }
950
0
                *ret = (ushort)r_size(bbs);
951
0
                break;
952
2
            }
953
2
        case gs_fapi_font_feature_BlendBlueShift_count:
954
2
            {
955
2
                ref *Priv, *Blend, *bbs;
956
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
957
0
                    *ret = 0;
958
0
                    break;
959
0
                }
960
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
961
0
                    *ret = 0;
962
0
                    break;
963
0
                }
964
2
                if (dict_find_string_with_type(Priv, "BlueShift", &bbs, t_array) <= 0) {
965
2
                    *ret = 0;
966
2
                    break;
967
2
                }
968
0
                *ret = (ushort)r_size(bbs);
969
0
                break;
970
2
            }
971
0
        case gs_fapi_font_feature_BlendBlueShift:
972
0
            {
973
0
                ref *Priv, *Blend, *bbs, r;
974
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
975
0
                    *ret = 0;
976
0
                    break;
977
0
                }
978
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
979
0
                    *ret = 0;
980
0
                    break;
981
0
                }
982
0
                if (dict_find_string_with_type(Priv, "BlueShift", &bbs, t_array) <= 0) {
983
0
                    *ret = 0;
984
0
                    break;
985
0
                }
986
0
                if (array_get_with_type(ff->memory, bbs, index, &r, t_integer) < 0) {
987
0
                    *ret = 0;
988
0
                    break;
989
0
                }
990
991
0
                *ret = (ushort)r.value.intval;
992
0
                break;
993
0
            }
994
2
        case gs_fapi_font_feature_BlendBlueFuzz_count:
995
2
            {
996
2
                ref *Priv, *Blend, *bbf;
997
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
998
0
                    *ret = 0;
999
0
                    break;
1000
0
                }
1001
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1002
0
                    *ret = 0;
1003
0
                    break;
1004
0
                }
1005
2
                if (dict_find_string_with_type(Priv, "BlueFuzz", &bbf, t_array) <= 0) {
1006
2
                    *ret = 0;
1007
2
                    break;
1008
2
                }
1009
0
                *ret = (ushort)r_size(bbf);
1010
0
                break;
1011
2
            }
1012
0
        case gs_fapi_font_feature_BlendBlueFuzz:
1013
0
            {
1014
0
                ref *Priv, *Blend, *bbf, r;
1015
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1016
0
                    *ret = 0;
1017
0
                    break;
1018
0
                }
1019
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1020
0
                    *ret = 0;
1021
0
                    break;
1022
0
                }
1023
0
                if (dict_find_string_with_type(Priv, "BlueFuzz", &bbf, t_array) <= 0) {
1024
0
                    *ret = 0;
1025
0
                    break;
1026
0
                }
1027
0
                if (array_get_with_type(ff->memory, bbf, index, &r, t_integer) < 0) {
1028
0
                    *ret = 0;
1029
0
                    break;
1030
0
                }
1031
1032
0
                *ret = (ushort)r.value.intval;
1033
0
                break;
1034
0
            }
1035
2
        case gs_fapi_font_feature_BlendForceBold_count:
1036
2
            {
1037
2
                ref *Priv, *Blend, *bfb;
1038
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1039
0
                    *ret = 0;
1040
0
                    break;
1041
0
                }
1042
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1043
0
                    *ret = 0;
1044
0
                    break;
1045
0
                }
1046
2
                if (dict_find_string_with_type(Priv, "ForceBold", &bfb, t_array) <= 0) {
1047
2
                    *ret = 0;
1048
2
                    break;
1049
2
                }
1050
0
                *ret = (ushort)r_size(bfb);
1051
0
                break;
1052
2
            }
1053
0
        case gs_fapi_font_feature_BlendForceBold:
1054
0
            {
1055
0
                ref *Priv, *Blend, *bfb, r;
1056
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1057
0
                    *ret = 0;
1058
0
                    break;
1059
0
                }
1060
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1061
0
                    *ret = 0;
1062
0
                    break;
1063
0
                }
1064
0
                if (dict_find_string_with_type(Priv, "ForceBold", &bfb, t_array) <= 0) {
1065
0
                    *ret = 0;
1066
0
                    break;
1067
0
                }
1068
0
                if (array_get_with_type(ff->memory, bfb, index, &r, t_boolean) < 0) {
1069
0
                    *ret = 0;
1070
0
                    break;
1071
0
                }
1072
1073
0
                *ret = (ushort)r.value.boolval;
1074
0
            }
1075
2
        case gs_fapi_font_feature_BlendStdHW_length:
1076
2
            {
1077
2
                ref *Priv, *Blend, *stdhw;
1078
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1079
0
                    *ret = 0;
1080
0
                    break;
1081
0
                }
1082
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1083
0
                    *ret = 0;
1084
0
                    break;
1085
0
                }
1086
2
                if (dict_find_string_with_type(Priv, "StdHW", &stdhw, t_array) <= 0) {
1087
2
                    *ret = 0;
1088
2
                    break;
1089
2
                }
1090
0
                *ret = (ushort)r_size(stdhw);
1091
0
                break;
1092
2
            }
1093
0
        case gs_fapi_font_feature_BlendStdHW_count:
1094
0
            {
1095
0
                ref *Priv, *Blend, *stdhw, sub;
1096
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1097
0
                    *ret = 0;
1098
0
                    break;
1099
0
                }
1100
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1101
0
                    *ret = 0;
1102
0
                    break;
1103
0
                }
1104
0
                if (dict_find_string_with_type(Priv, "StdHW", &stdhw, t_array) <= 0) {
1105
0
                    *ret = 0;
1106
0
                    break;
1107
0
                }
1108
1109
0
                if (array_get_with_type(ff->memory, stdhw, index, &sub, t_array) < 0) {
1110
0
                    *ret = 0;
1111
0
                    break;
1112
0
                }
1113
0
                *ret = (ushort)r_size(&sub);
1114
0
                break;
1115
0
            }
1116
0
        case gs_fapi_font_feature_BlendStdHW:
1117
0
            {
1118
0
                ref *Priv, *Blend, *stdhw, sub, r;
1119
0
                int aind = 0;
1120
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1121
0
                    *ret = 0;
1122
0
                    break;
1123
0
                }
1124
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1125
0
                    *ret = 0;
1126
0
                    break;
1127
0
                }
1128
0
                if (dict_find_string_with_type(Priv, "StdHW", &stdhw, t_array) <= 0) {
1129
0
                    *ret = 0;
1130
0
                    break;
1131
0
                }
1132
1133
0
                while (1) {
1134
0
                    if ((code = array_get_with_type(ff->memory, stdhw, aind++, &sub, t_array)) < 0)
1135
0
                        break;
1136
0
                    if (index - (int)r_size(&sub) < 0) {
1137
0
                        break;
1138
0
                    }
1139
0
                    index -= r_size(&sub);
1140
0
                }
1141
0
                if (code < 0) {
1142
0
                    *ret = 0;
1143
0
                    break;
1144
0
                }
1145
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_integer) < 0) {
1146
0
                    *ret = 0;
1147
0
                    break;
1148
0
                }
1149
1150
0
                *ret = (ushort)r.value.intval;
1151
0
                break;
1152
0
            }
1153
2
        case gs_fapi_font_feature_BlendStdVW_length:
1154
2
            {
1155
2
                ref *Priv, *Blend, *stdvw;
1156
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1157
0
                    *ret = 0;
1158
0
                    break;
1159
0
                }
1160
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1161
0
                    *ret = 0;
1162
0
                    break;
1163
0
                }
1164
2
                if (dict_find_string_with_type(Priv, "StdVW", &stdvw, t_array) <= 0) {
1165
2
                    *ret = 0;
1166
2
                    break;
1167
2
                }
1168
0
                *ret = (ushort)r_size(stdvw);
1169
0
                break;
1170
2
            }
1171
0
        case gs_fapi_font_feature_BlendStdVW_count:
1172
0
            {
1173
0
                ref *Priv, *Blend, *stdvw, sub;
1174
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1175
0
                    *ret = 0;
1176
0
                    break;
1177
0
                }
1178
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1179
0
                    *ret = 0;
1180
0
                    break;
1181
0
                }
1182
0
                if (dict_find_string_with_type(Priv, "StdVW", &stdvw, t_array) <= 0) {
1183
0
                    *ret = 0;
1184
0
                    break;
1185
0
                }
1186
1187
0
                if (array_get_with_type(ff->memory, stdvw, index, &sub, t_array) < 0) {
1188
0
                    *ret = 0;
1189
0
                    break;
1190
0
                }
1191
0
                *ret = (ushort)r_size(&sub);
1192
0
                break;
1193
0
            }
1194
0
        case gs_fapi_font_feature_BlendStdVW:
1195
0
            {
1196
0
                ref *Priv, *Blend, *stdvw, sub, r;
1197
0
                int aind = 0;
1198
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1199
0
                    *ret = 0;
1200
0
                    break;
1201
0
                }
1202
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1203
0
                    *ret = 0;
1204
0
                    break;
1205
0
                }
1206
0
                if (dict_find_string_with_type(Priv, "StdVW", &stdvw, t_array) <= 0) {
1207
0
                    *ret = 0;
1208
0
                    break;
1209
0
                }
1210
1211
0
                while (1) {
1212
0
                    if ((code = array_get_with_type(ff->memory, stdvw, aind++, &sub, t_array)) < 0)
1213
0
                        break;
1214
0
                    if (index - (int)r_size(&sub) < 0) {
1215
0
                        break;
1216
0
                    }
1217
0
                    index -= r_size(&sub);
1218
0
                }
1219
0
                if (code < 0) {
1220
0
                    *ret = 0;
1221
0
                    break;
1222
0
                }
1223
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_integer) < 0) {
1224
0
                    *ret = 0;
1225
0
                    break;
1226
0
                }
1227
1228
0
                *ret = (ushort)r.value.intval;
1229
0
                break;
1230
0
            }
1231
2
        case gs_fapi_font_feature_BlendStemSnapH_length:
1232
2
            {
1233
2
                ref *Priv, *Blend, *ssh;
1234
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1235
0
                    *ret = 0;
1236
0
                    break;
1237
0
                }
1238
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1239
0
                    *ret = 0;
1240
0
                    break;
1241
0
                }
1242
2
                if (dict_find_string(Priv, "StemSnapH", &ssh) <= 0) {
1243
2
                    *ret = 0;
1244
2
                    break;
1245
2
                }
1246
0
                *ret = (ushort)r_size(ssh);
1247
0
                break;
1248
2
            }
1249
0
        case gs_fapi_font_feature_BlendStemSnapH_count:
1250
0
            {
1251
0
                ref *Priv, *Blend, *bssh, sub;
1252
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1253
0
                    *ret = 0;
1254
0
                    break;
1255
0
                }
1256
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1257
0
                    *ret = 0;
1258
0
                    break;
1259
0
                }
1260
0
                if (dict_find_string_with_type(Priv, "StemSnapH", &bssh, t_array) <= 0) {
1261
0
                    *ret = 0;
1262
0
                    break;
1263
0
                }
1264
1265
0
                if (array_get_with_type(ff->memory, bssh, index, &sub, t_array) < 0) {
1266
0
                    *ret = 0;
1267
0
                    break;
1268
0
                }
1269
0
                *ret = (ushort)r_size(&sub);
1270
0
                break;
1271
0
            }
1272
0
        case gs_fapi_font_feature_BlendStemSnapH:
1273
0
            {
1274
0
                ref *Priv, *Blend, *bssh, sub, r;
1275
0
                int aind = 0;
1276
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1277
0
                    *ret = 0;
1278
0
                    break;
1279
0
                }
1280
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1281
0
                    *ret = 0;
1282
0
                    break;
1283
0
                }
1284
0
                if (dict_find_string_with_type(Priv, "StemSnapH", &bssh, t_array) <= 0) {
1285
0
                    *ret = 0;
1286
0
                    break;
1287
0
                }
1288
1289
0
                while (1) {
1290
0
                    if ((code = array_get_with_type(ff->memory, bssh, aind++, &sub, t_array)) < 0)
1291
0
                        break;
1292
0
                    if (index - (int)r_size(&sub) < 0) {
1293
0
                        break;
1294
0
                    }
1295
0
                    index -= r_size(&sub);
1296
0
                }
1297
0
                if (code < 0) {
1298
0
                    *ret = 0;
1299
0
                    break;
1300
0
                }
1301
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_integer) < 0) {
1302
0
                    *ret = 0;
1303
0
                    break;
1304
0
                }
1305
1306
0
                *ret = (ushort)r.value.intval;
1307
0
                break;
1308
0
            }
1309
2
        case gs_fapi_font_feature_BlendStemSnapV_length:
1310
2
            {
1311
2
                ref *Priv, *Blend, *ssv;
1312
2
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1313
0
                    *ret = 0;
1314
0
                    break;
1315
0
                }
1316
2
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1317
0
                    *ret = 0;
1318
0
                    break;
1319
0
                }
1320
2
                if (dict_find_string_with_type(Priv, "StemSnapV", &ssv, t_array) <= 0) {
1321
2
                    *ret = 0;
1322
2
                    break;
1323
2
                }
1324
0
                *ret = (ushort)r_size(ssv);
1325
0
                break;
1326
2
            }
1327
0
        case gs_fapi_font_feature_BlendStemSnapV_count:
1328
0
            {
1329
0
                ref *Priv, *Blend, *bssv, sub;
1330
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1331
0
                    *ret = 0;
1332
0
                    break;
1333
0
                }
1334
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1335
0
                    *ret = 0;
1336
0
                    break;
1337
0
                }
1338
0
                if (dict_find_string_with_type(Priv, "StemSnapV", &bssv, t_array) <= 0) {
1339
0
                    *ret = 0;
1340
0
                    break;
1341
0
                }
1342
1343
0
                if (array_get_with_type(ff->memory, bssv, index, &sub, t_array) < 0) {
1344
0
                    *ret = 0;
1345
0
                    break;
1346
0
                }
1347
0
                *ret = (ushort)r_size(&sub);
1348
0
                break;
1349
0
            }
1350
0
        case gs_fapi_font_feature_BlendStemSnapV:
1351
0
            {
1352
0
                ref *Priv, *Blend, *bssv, sub, r;
1353
0
                int aind = 0;
1354
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1355
0
                    *ret = 0;
1356
0
                    break;
1357
0
                }
1358
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1359
0
                    *ret = 0;
1360
0
                    break;
1361
0
                }
1362
0
                if (dict_find_string_with_type(Priv, "StemSnapV", &bssv, t_array) <= 0) {
1363
0
                    *ret = 0;
1364
0
                    break;
1365
0
                }
1366
1367
0
                while (1) {
1368
0
                    if ((code = array_get_with_type(ff->memory, bssv, aind++, &sub, t_array)) < 0)
1369
0
                        break;
1370
0
                    if (index - (int)r_size(&sub) < 0) {
1371
0
                        break;
1372
0
                    }
1373
0
                    index -= r_size(&sub);
1374
0
                }
1375
0
                if (code < 0) {
1376
0
                    *ret = 0;
1377
0
                    break;
1378
0
                }
1379
0
                if (array_get_with_type(ff->memory, &sub, index, &r, t_array) < 0) {
1380
0
                    *ret = 0;
1381
0
                    break;
1382
0
                }
1383
1384
0
                *ret = (ushort)r.value.intval;
1385
0
                break;
1386
0
            }
1387
1388
            /* End MM specifics */
1389
4.03M
    }
1390
4.03M
    return code;
1391
4.03M
}
1392
1393
static int
1394
FAPI_FF_get_long(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, unsigned long *ret)
1395
133k
{
1396
133k
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1397
133k
    int code = 0;
1398
1399
133k
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1400
1401
133k
    switch ((int)var_id) {
1402
0
        case gs_fapi_font_feature_UniqueID:
1403
0
            *ret = pfont->UID.id;
1404
0
            break;
1405
133k
        case gs_fapi_font_feature_BlueScale:
1406
133k
            *ret = (ulong) (pfont->data.BlueScale * 65536);
1407
133k
            break;
1408
0
        case gs_fapi_font_feature_Subrs_total_size:
1409
0
            {
1410
0
                ref *Private, *Subrs, v;
1411
0
                int lenIV = max(pfont->data.lenIV, 0), k;
1412
0
                ulong size = 0;
1413
0
                long i;
1414
0
                const char *name[2] = { "Subrs", "GlobalSubrs" };
1415
0
                if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0) {
1416
0
                    *ret = 0;
1417
0
                    break;
1418
0
                }
1419
0
                for (k = 0; k < 2; k++) {
1420
0
                    if (dict_find_string_with_type(Private, name[k], &Subrs, t_array) > 0)
1421
0
                        for (i = r_size(Subrs) - 1; i >= 0; i--) {
1422
0
                            array_get(pfont->memory, Subrs, i, &v);
1423
0
                            if (r_type(&v) == t_string) {
1424
0
                                size += r_size(&v) - (ff->need_decrypt ? 0 : lenIV);
1425
0
                            }
1426
0
                        }
1427
0
                }
1428
0
                *ret = size;
1429
0
            }
1430
0
            break;
1431
30
        case gs_fapi_font_feature_TT_size:
1432
30
            code = true_type_size(ff->memory, pdr, ret);
1433
30
            break;
1434
133k
    }
1435
133k
    return code;
1436
133k
}
1437
1438
static int
1439
FAPI_FF_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, float *ret)
1440
803k
{
1441
803k
    gs_font_type1 *pfont1 = (gs_font_type1 *) ff->client_font_data;
1442
803k
    gs_font_base *pbfont = (gs_font_base *) ff->client_font_data2;
1443
803k
    ref *pdr = pfont_dict(pbfont);
1444
803k
    int code = 0;
1445
803k
    gs_fapi_server *I = pbfont->FAPI;
1446
1447
803k
    switch ((int)var_id) {
1448
803k
        case gs_fapi_font_feature_FontMatrix:
1449
803k
            {
1450
803k
                double FontMatrix_div;
1451
803k
                gs_matrix m, *mptr;
1452
1453
803k
                if (I && I->get_fontmatrix) {
1454
803k
                    FontMatrix_div = 1;
1455
803k
                    mptr = &m;
1456
803k
                    I->get_fontmatrix(I, mptr);
1457
803k
                }
1458
0
                else {
1459
0
                    FontMatrix_div =
1460
0
                        ((ff->is_cid
1461
0
                          && (!FAPI_ISCIDFONT(pbfont))) ? 1000 : 1);
1462
0
                    mptr = &(pbfont->base->FontMatrix);
1463
0
                }
1464
803k
                switch (index) {
1465
133k
                    case 0:
1466
133k
                    default:
1467
133k
                        *ret = (mptr->xx / FontMatrix_div);
1468
133k
                        break;
1469
133k
                    case 1:
1470
133k
                        *ret = (mptr->xy / FontMatrix_div);
1471
133k
                        break;
1472
133k
                    case 2:
1473
133k
                        *ret = (mptr->yx / FontMatrix_div);
1474
133k
                        break;
1475
133k
                    case 3:
1476
133k
                        *ret = (mptr->yy / FontMatrix_div);
1477
133k
                        break;
1478
133k
                    case 4:
1479
133k
                        *ret = (mptr->tx / FontMatrix_div);
1480
133k
                        break;
1481
133k
                    case 5:
1482
133k
                        *ret = (mptr->ty / FontMatrix_div);
1483
133k
                        break;
1484
803k
                }
1485
803k
                break;
1486
803k
            }
1487
1488
803k
        case gs_fapi_font_feature_WeightVector:
1489
4
            {
1490
4
                if (index < pfont1->data.WeightVector.count) {
1491
4
                    *ret = pfont1->data.WeightVector.values[index];
1492
4
                }
1493
0
                else {
1494
0
                    *ret = 0;
1495
0
                }
1496
4
            }
1497
4
            break;
1498
12
        case gs_fapi_font_feature_BlendDesignPositionsArrayValue:
1499
12
            {
1500
12
                ref *Info, *Array, SubArray, value;
1501
12
                int array_index = index / 8;
1502
1503
12
                index %= 8;
1504
12
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
1505
0
                    *ret = 0;
1506
0
                    break;
1507
0
                }
1508
12
                if (dict_find_string_with_type(Info, "BlendDesignPositions", &Array, t_array) <= 0) {
1509
0
                    *ret = 0;
1510
0
                    break;
1511
0
                }
1512
12
                if (array_get_with_type(ff->memory, Array, array_index, &SubArray, t_array) < 0) {
1513
4
                    *ret = 0;
1514
4
                    break;
1515
4
                }
1516
8
                if (array_get(ff->memory, &SubArray, index, &value) < 0)
1517
2
                    return 0;
1518
6
                if (!r_has_type(&value, t_integer)) {
1519
0
                    if (r_has_type(&value, t_real)) {
1520
0
                        *ret = value.value.realval;
1521
0
                    }
1522
0
                    else
1523
0
                        *ret = 0;
1524
0
                }
1525
6
                else
1526
6
                    *ret = ((float)value.value.intval);
1527
6
            }
1528
0
            break;
1529
0
        case gs_fapi_font_feature_BlendDesignMapArrayValue:
1530
0
            {
1531
0
                ref *Info, *Array, SubArray, SubSubArray, value;
1532
0
                int array_index = index / 64;
1533
1534
0
                index %= 8;
1535
0
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
1536
0
                    *ret = 0;
1537
0
                    break;
1538
0
                 }
1539
0
                if (dict_find_string_with_type(Info, "BlendDesignMap", &Array, t_dictionary) <= 0) {
1540
0
                    *ret = 0;
1541
0
                    break;
1542
0
                }
1543
0
                if (array_get_with_type(ff->memory, Array, array_index, &SubArray, t_array) < 0) {
1544
0
                    *ret = 0;
1545
0
                    break;
1546
0
                }
1547
0
                if (array_get_with_type(ff->memory, &SubArray, index, &SubSubArray, t_array) < 0) {
1548
0
                    *ret = 0;
1549
0
                    break;
1550
0
                }
1551
0
                if (array_get(ff->memory, &SubSubArray, index, &value) < 0) {
1552
0
                    *ret = 0;
1553
0
                    break;
1554
0
                }
1555
0
                if (!r_has_type(&value, t_integer)) {
1556
0
                    if (r_has_type(&value, t_real)) {
1557
0
                        *ret = (value.value.realval);
1558
0
                    }
1559
0
                    else
1560
0
                        *ret = 0;
1561
0
                }
1562
0
                else
1563
0
                    *ret = ((float)value.value.intval);
1564
0
            }
1565
0
            break;
1566
0
        case gs_fapi_font_feature_BlendBlueScale:
1567
0
            {
1568
0
                ref *Priv, *Blend, *bbs, r;
1569
1570
0
                if (dict_find_string_with_type(pdr, "Blend", &Blend, t_dictionary) <= 0) {
1571
0
                    *ret = 0;
1572
0
                    break;
1573
0
                }
1574
0
                if (dict_find_string_with_type(Blend, "Private", &Priv, t_dictionary) <= 0) {
1575
0
                    *ret = 0;
1576
0
                    break;
1577
0
                }
1578
0
                if (dict_find_string_with_type(Priv, "BlueScale", &bbs, t_array) <= 0) {
1579
0
                    *ret = 0;
1580
0
                    break;
1581
0
                }
1582
0
                if (array_get(ff->memory, bbs, index, &r) < 0) {
1583
0
                    *ret = 0;
1584
0
                    break;
1585
0
                }
1586
0
               if (r_has_type(&r, t_real))
1587
0
                   *ret = r.value.realval;
1588
0
               else if (r_has_type(&r, t_integer))
1589
0
                   *ret = (float)r.value.intval;
1590
0
               else
1591
0
                   code = gs_note_error(gs_error_typecheck);
1592
0
            }
1593
0
            break;
1594
803k
    }
1595
803k
    return code;
1596
803k
}
1597
1598
static int
1599
FAPI_FF_get_name(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index,
1600
                 char *Buffer, int len)
1601
2
{
1602
2
    ref name, string;
1603
2
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1604
2
    int code = 0;
1605
1606
2
    switch ((int)var_id) {
1607
2
        case gs_fapi_font_feature_BlendAxisTypes:
1608
2
            {
1609
2
                ref *Info, *Axes;
1610
1611
2
                if (dict_find_string_with_type(pdr, "FontInfo", &Info, t_dictionary) <= 0) {
1612
0
                    code = gs_note_error(gs_error_undefined);
1613
0
                    break;
1614
0
                }
1615
2
                if (dict_find_string_with_type(Info, "BlendAxisTypes", &Axes, t_array) <= 0) {
1616
0
                    code = gs_note_error(gs_error_undefined);
1617
0
                    break;
1618
0
                }
1619
2
                if (array_get_with_type(ff->memory, Axes, index, &name, t_name) < 0) {
1620
0
                    code = gs_note_error(gs_error_undefined);
1621
0
                    break;
1622
0
                }
1623
2
            }
1624
2
    }
1625
2
    if (code >= 0) {
1626
2
        name_string_ref(ff->memory, &name, &string);
1627
2
        if (r_size(&string) < len) {
1628
2
            memcpy(Buffer, string.value.const_bytes, r_size(&string));
1629
2
            Buffer[r_size(&string)] = 0x00;
1630
2
        }
1631
0
        else {
1632
0
            code = gs_note_error(gs_error_unknownerror);
1633
0
        }
1634
2
    }
1635
2
    return code;
1636
2
}
1637
1638
/* NOTE: we checked the type of $Blend at definefont time, so we know it is a
1639
 * procedure and don't need to check it again here
1640
 */
1641
static int
1642
FAPI_FF_get_proc(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index,
1643
                 char *Buffer)
1644
2
{
1645
2
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1646
2
    char *ptr = Buffer;
1647
2
    int code = 0;
1648
1649
2
    if (!Buffer)
1650
1
        return_error(gs_error_unknownerror);
1651
1652
1
    switch ((int)var_id) {
1653
1
        case gs_fapi_font_feature_DollarBlend:
1654
1
            {
1655
1
                ref *DBlend, Element, string;
1656
1
                int i;
1657
1
                char Buf[32];
1658
1659
1
                if (dict_find_string(pdr, "$Blend", &DBlend) <= 0) {
1660
0
                    code = gs_note_error(gs_error_undefined);
1661
0
                    break;
1662
0
                }
1663
4
                for (i = 0; i < r_size(DBlend); i++) {
1664
3
                    *ptr++ = 0x20;
1665
3
                    if (array_get(ff->memory, DBlend, i, &Element) < 0) {
1666
0
                        code = gs_note_error(gs_error_undefined);
1667
0
                        break;
1668
0
                    }
1669
3
                    switch (r_btype(&Element)) {
1670
0
                        case t_name:
1671
0
                            name_string_ref(ff->memory, &Element, &string);
1672
1673
0
                            strncpy(ptr, (char *)string.value.const_bytes,
1674
0
                                    r_size(&string));
1675
0
                            ptr += r_size(&string);
1676
0
                            break;
1677
1
                        case t_real:
1678
1
                            gs_snprintf(Buf, sizeof(Buf), "%f", Element.value.realval);
1679
1
                            strcpy(ptr, Buf);
1680
1
                            ptr += strlen(Buf);
1681
1
                            break;
1682
0
                        case t_integer:
1683
0
                            gs_snprintf(Buf, sizeof(Buf), "%"PRIpsint, Element.value.intval);
1684
0
                            strcpy(ptr, Buf);
1685
0
                            ptr += strlen(Buf);
1686
0
                            break;
1687
2
                        case t_operator:
1688
2
                            {
1689
2
                                op_def const *op;
1690
1691
2
                                op = op_index_def(r_size(&Element));
1692
2
                                strcpy(ptr, op->oname + 1);
1693
2
                                ptr += strlen(op->oname + 1);
1694
2
                            }
1695
2
                            break;
1696
0
                        default:
1697
0
                            break;
1698
3
                    }
1699
3
                }
1700
1
            }
1701
1
    }
1702
1
    return code < 0 ? code : (ptr - Buffer);
1703
1
}
1704
1705
static inline void
1706
decode_bytes(byte *p, const byte *s, int l, int lenIV)
1707
1.67M
{
1708
1.67M
    ushort state = 4330;
1709
1710
158M
    for (; l; s++, l--) {
1711
156M
        uchar c = (*s ^ (state >> 8));
1712
1713
156M
        state = (*s + state) * crypt_c1 + crypt_c2;
1714
156M
        if (lenIV > 0)
1715
6.69M
            lenIV--;
1716
150M
        else {
1717
150M
            *p = c;
1718
150M
            p++;
1719
150M
        }
1720
156M
    }
1721
1.67M
}
1722
1723
static int
1724
get_type1_data(gs_fapi_font *ff, const ref *type1string,
1725
               byte *buf, int buf_length)
1726
2.34M
{
1727
2.34M
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1728
2.34M
    int lenIV = max(pfont->data.lenIV, 0);
1729
2.34M
    int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0);
1730
1731
2.34M
    if (buf != 0) {
1732
1.67M
        int l = min(length, buf_length);        /*safety */
1733
1734
1.67M
        if (ff->need_decrypt && pfont->data.lenIV >= 0)
1735
1.67M
            decode_bytes(buf, type1string->value.const_bytes, l + lenIV,
1736
1.67M
                         lenIV);
1737
0
        else
1738
0
            memcpy(buf, type1string->value.const_bytes, l);
1739
1.67M
    }
1740
2.34M
    return length;
1741
2.34M
}
1742
1743
static int
1744
FAPI_FF_get_gsubr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
1745
0
{
1746
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1747
0
    ref *Private, *GlobalSubrs, subr;
1748
1749
0
    if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0)
1750
0
        return 0;
1751
0
    if (dict_find_string_with_type(Private, "GlobalSubrs", &GlobalSubrs, t_array) <= 0)
1752
0
        return 0;
1753
0
    if (array_get_with_type(ff->memory,
1754
0
                  GlobalSubrs, index, &subr, t_string) < 0)
1755
0
        return 0;
1756
0
    return (get_type1_data(ff, &subr, buf, buf_length));
1757
0
}
1758
1759
static int
1760
FAPI_FF_get_subr(gs_fapi_font *ff, int index, byte *buf, int buf_length)
1761
1.00M
{
1762
1.00M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1763
1.00M
    ref *Private, *Subrs, subr;
1764
1765
1.00M
    if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0)
1766
0
        return 0;
1767
1.00M
    if (dict_find_string_with_type(Private, "Subrs", &Subrs, t_array) <= 0)
1768
0
        return 0;
1769
1.00M
    if (array_get_with_type(ff->memory, Subrs, index, &subr, t_string) < 0)
1770
0
        return 0;
1771
1.00M
    return (get_type1_data(ff, &subr, buf, buf_length));
1772
1.00M
}
1773
1774
static int
1775
FAPI_FF_get_raw_subr(gs_fapi_font *ff, int index, byte *buf,
1776
                     int buf_length)
1777
0
{
1778
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1779
0
    ref *Private, *Subrs, subr;
1780
0
    int code = 0;
1781
1782
0
    do {
1783
0
        if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0) {
1784
0
            code = gs_note_error(gs_error_undefined);
1785
0
            break;
1786
0
        }
1787
0
        if (dict_find_string_with_type(Private, "Subrs", &Subrs, t_array) <= 0) {
1788
0
            code = gs_note_error(gs_error_undefined);
1789
0
            break;
1790
0
        }
1791
0
        if (array_get_with_type(ff->memory, Subrs, index, &subr, t_string) < 0) {
1792
0
            code = gs_note_error(gs_error_undefined);
1793
0
            break;
1794
0
        }
1795
0
        if (buf && buf_length && buf_length >= r_size(&subr)) {
1796
0
            memcpy(buf, subr.value.const_bytes, r_size(&subr));
1797
0
        }
1798
0
    } while(0);
1799
1800
0
    return code < 0 ? code : r_size(&subr);
1801
0
}
1802
1803
/* FAPI_FF_get_charstring_name() and FAPI_FF_get_charstring()
1804
 *
1805
 * Generally we'd want to use the dictionary content
1806
 * enumeration API rather than dict_index_entry(), but
1807
 * the FAPI interface doesn't enforce sequential accessing
1808
 * of the indices.
1809
 * Setting up enumeration and enumerating through the entries
1810
 * until we reach the requested valid index is a performance
1811
 * hit we don't want to pay.
1812
 *
1813
 * Luckily, the checks we need for invalid CharString contents
1814
 * also handle empty "slots" in the dictionary.
1815
 */
1816
1817
static int
1818
FAPI_FF_get_charstring_name(gs_fapi_font *ff, int index, byte *buf,
1819
                            ushort buf_length)
1820
0
{
1821
0
    int code = 0;
1822
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1823
0
    ref *CharStrings, eltp[2], string;
1824
1825
0
    do {
1826
0
        if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0) {
1827
0
            code = gs_note_error(gs_error_undefined);
1828
0
            break;
1829
0
        }
1830
0
        if (dict_index_entry(CharStrings, index, eltp) < 0) {
1831
0
            code = gs_note_error(gs_error_undefined);
1832
0
            break;
1833
0
        }
1834
0
        if (r_type(&eltp[0]) != t_name) {
1835
0
            code = gs_note_error(gs_error_undefined);
1836
0
            break;
1837
0
        }
1838
0
        name_string_ref(ff->memory, &eltp[0], &string);
1839
0
        if (r_size(&string) <= buf_length) {
1840
0
            memcpy(buf, string.value.const_bytes, r_size(&string));
1841
0
            buf[r_size(&string)] = 0x00;
1842
0
        }
1843
0
    } while(0);
1844
0
    return code < 0 ? code : r_size(&string);
1845
0
}
1846
1847
static int
1848
FAPI_FF_get_charstring(gs_fapi_font *ff, int index, byte *buf,
1849
                       ushort buf_length)
1850
0
{
1851
0
    int code = 0;
1852
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1853
0
    ref *CharStrings, eltp[2];
1854
1855
0
    do {
1856
0
        if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0) {
1857
0
            code = gs_note_error(gs_error_undefined);
1858
0
            break;
1859
0
        }
1860
0
        if (dict_index_entry(CharStrings, index, eltp) < 0) {
1861
0
            code = gs_note_error(gs_error_undefined);
1862
0
            break;
1863
0
        }
1864
0
        if (r_type(&eltp[1]) != t_string) {
1865
0
            code = gs_note_error(gs_error_typecheck);
1866
0
            break;
1867
0
        }
1868
0
        if (buf && buf_length && buf_length >= r_size(&eltp[1])) {
1869
0
            memcpy(buf, eltp[1].value.const_bytes, r_size(&eltp[1]));
1870
0
        }
1871
0
    } while(0);
1872
1873
0
    return code < 0 ? code : r_size(&eltp[1]);
1874
0
}
1875
1876
static int
1877
sfnt_get_sfnt_length(ref *pdr, ulong *len)
1878
0
{
1879
0
    int code = 0;
1880
0
    ref *sfnts, sfnt_elem;
1881
0
    const gs_memory_t *mem = dict_mem(pdr->value.pdict);
1882
1883
0
    *len = 0;
1884
0
    if (r_type(pdr) != t_dictionary ||
1885
0
        dict_find_string(pdr, "sfnts", &sfnts) <= 0) {
1886
0
        code = gs_error_invalidfont;
1887
0
    }
1888
0
    else {
1889
0
        if (r_type(sfnts) != t_array && r_type(sfnts) != t_string) {
1890
0
            code = gs_error_invalidfont;
1891
0
        }
1892
0
        else {
1893
0
            if (r_type(sfnts) == t_string) {
1894
0
                *len = r_size(sfnts);
1895
0
            }
1896
0
            else {
1897
0
                int i;
1898
0
                for (i = 0; i < r_size(sfnts); i++) {
1899
0
                    code = array_get(mem, sfnts, i, &sfnt_elem);
1900
0
                    if (code < 0) break;
1901
0
                    if (!r_has_type(&sfnt_elem, t_string)) {
1902
0
                        code = gs_note_error(gs_error_typecheck);
1903
0
                        break;
1904
0
                    }
1905
0
                    *len += r_size(&sfnt_elem);
1906
0
                }
1907
0
            }
1908
0
        }
1909
0
    }
1910
0
    return code;
1911
0
}
1912
1913
static int
1914
sfnt_get_glyph_offset(ref *pdr, gs_font_type42 *pfont42, int index,
1915
                      ulong *offset0)
1916
0
{                               /* Note : TTC is not supported and probably is unuseful for Type 42. */
1917
0
    sfnts_reader r;
1918
0
    int glyf_elem_size = (pfont42->data.indexToLocFormat) ? 4 : 2;
1919
0
    ulong fullsize;
1920
1921
0
    if (index < pfont42->data.trueNumGlyphs) {
1922
0
        sfnts_reader_init(pfont42->memory, &r, pdr);
1923
0
        r.seek(&r, pfont42->data.loca + index * (ulong)glyf_elem_size);
1924
0
        *offset0 =
1925
0
            pfont42->data.glyf + (glyf_elem_size ==
1926
0
                              2 ? r.rword(&r) * 2 : r.rlong(&r));
1927
0
        r.error = sfnt_get_sfnt_length(pdr, &fullsize);
1928
0
        if (r.error < 0 || *offset0 > fullsize) {
1929
0
            r.error = gs_note_error(gs_error_invalidaccess);
1930
0
        }
1931
0
    }
1932
0
    else {
1933
0
        r.error = gs_note_error(gs_error_rangecheck);
1934
0
    }
1935
0
    return (r.error);
1936
0
}
1937
1938
static int
1939
ps_get_GlyphDirectory_data_ptr(gs_fapi_font *ff, int char_code,
1940
                               const byte **ptr)
1941
0
{
1942
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1943
0
    ref *GlyphDirectory, glyph0, *glyph = &glyph0, glyph_index;
1944
1945
0
    if (dict_find_string(pdr, "GlyphDirectory", &GlyphDirectory) > 0) {
1946
0
        if (((r_type(GlyphDirectory) == t_dictionary &&
1947
0
              (make_int(&glyph_index, char_code),
1948
0
               dict_find(GlyphDirectory, &glyph_index, &glyph) > 0)) ||
1949
0
             (r_type(GlyphDirectory) == t_array &&
1950
0
              array_get(ff->memory, GlyphDirectory, char_code, &glyph0) >= 0)
1951
0
            )
1952
0
            && r_type(glyph) == t_string) {
1953
0
            *ptr = glyph->value.const_bytes;
1954
0
            return (r_size(glyph));
1955
0
        }
1956
0
        else
1957
            /* We have a GlyphDirectory, but couldn't find the glyph. If we
1958
             * return -1 then we will attempt to use glyf and loca which
1959
             * will fail. Instead return 0, so we execute an 'empty' glyph.
1960
             */
1961
0
            return 0;
1962
0
    }
1963
0
    return -1;
1964
0
}
1965
1966
static int
1967
get_charstring(gs_fapi_font *ff, int char_code, ref **proc, ref *char_name)
1968
0
{
1969
0
    ref *CharStrings;
1970
0
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1971
1972
0
    if (ff->is_type1) {
1973
0
        if (ff->is_cid)
1974
0
            return -1;
1975
0
        if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0)
1976
0
            return -1;
1977
1978
0
        if (ff->char_data != NULL) {
1979
            /*
1980
             * Can't use char_code in this case because hooked Type 1 fonts
1981
             * with 'glyphshow' may render a character which has no
1982
             * Encoding entry.
1983
             */
1984
0
            if (name_ref
1985
0
                (ff->memory, ff->char_data, ff->char_data_len, char_name,
1986
0
                 -1) < 0)
1987
0
                return -1;
1988
0
        }
1989
0
        else {                  /* seac */
1990
0
            i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p;
1991
0
            ref *StandardEncoding;
1992
1993
0
            if (dict_find_string
1994
0
                (systemdict, "StandardEncoding", &StandardEncoding) <= 0
1995
0
                || array_get(ff->memory, StandardEncoding, char_code,
1996
0
                             char_name) < 0) {
1997
0
                if (name_ref
1998
0
                    (ff->memory, (const byte *)".notdef", 7, char_name,
1999
0
                     -1) < 0)
2000
0
                    return -1;
2001
0
            }
2002
0
        }
2003
0
        if (dict_find(CharStrings, char_name, (ref **) proc) <= 0)
2004
0
            return -1;
2005
0
    }
2006
0
    return 0;
2007
0
}
2008
2009
static int
2010
FAPI_FF_get_glyph(gs_fapi_font *ff, gs_glyph char_code, byte *buf, int buf_length)
2011
1.34M
{
2012
    /*
2013
     * We assume that renderer requests glyph data with multiple
2014
     * consecutive calls to this function.
2015
     *
2016
     * For a simple glyph it calls this function exactly twice: first
2017
     * with buf == NULL for requesting the necessary buffer length, and
2018
     * second with buf != NULL for requesting the data (the second call
2019
     * may be skipped if the renderer discontinues the rendering).
2020
     *
2021
     * For a composite glyph it calls this function 2 * (N + 1)
2022
     * times: 2 calls for the main glyph (same as above) followed with
2023
     * 2 * N calls for subglyphs, where N is less or equal to the number
2024
     * of subglyphs (N may be less if the renderer caches glyph data,
2025
     * or discontinues rendering on an exception).
2026
     */
2027
1.34M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
2028
2029
1.34M
    int glyph_length;
2030
1.34M
    i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p;
2031
2032
1.34M
    if (ff->is_type1) {
2033
1.34M
        if (ff->is_cid) {
2034
0
            const gs_string *char_str = (const gs_string *)ff->char_data;
2035
0
            ref glyph;
2036
2037
0
            make_string(&glyph, avm_foreign | a_readonly, char_str->size,
2038
0
                        char_str->data);
2039
2040
0
            glyph_length = get_type1_data(ff, &glyph, buf, buf_length);
2041
0
        }
2042
1.34M
        else {
2043
1.34M
            ref *CharStrings, *CFFCharStrings, char_name, *glyph;
2044
2045
1.34M
            if (ff->char_data != NULL) {
2046
                /*
2047
                 * Can't use char_code in this case because hooked Type 1 fonts
2048
                 * with 'glyphshow' may render a character which has no
2049
                 * Encoding entry.
2050
                 */
2051
1.34M
                if (name_ref(ff->memory, ff->char_data,
2052
1.34M
                             ff->char_data_len, &char_name, -1) < 0)
2053
0
                    return gs_fapi_glyph_invalid_format;
2054
1.34M
                if (buf != NULL) {
2055
                    /*
2056
                     * Trigger the next call to the 'seac' case below.
2057
                     * Here we use the assumption about call sequence
2058
                     * being documented above.
2059
                     */
2060
1.33M
                    ff->char_data = NULL;
2061
1.33M
                }
2062
1.34M
            }
2063
0
            else {              /* seac */
2064
0
                ref *StandardEncoding;
2065
2066
0
                if (dict_find_string
2067
0
                    (systemdict, "StandardEncoding", &StandardEncoding) <= 0
2068
0
                    || array_get(ff->memory, StandardEncoding, char_code,
2069
0
                                 &char_name) < 0)
2070
0
                    if (name_ref
2071
0
                        (ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0)
2072
0
                        return gs_fapi_glyph_invalid_format;
2073
0
            }
2074
1.34M
            if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0)
2075
0
                return gs_fapi_glyph_invalid_format;
2076
2077
1.34M
            if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
2078
0
                if (name_ref
2079
0
                    (ff->memory, (const byte *)".notdef", 7, &char_name, -1) < 0) {
2080
0
                    return gs_fapi_glyph_invalid_format;
2081
0
                }
2082
0
                if (dict_find(CharStrings, &char_name, &glyph) <= 0) {
2083
0
                    return gs_fapi_glyph_invalid_format;
2084
0
                }
2085
0
            }
2086
1.34M
            if (r_has_type(glyph, t_array) || r_has_type(glyph, t_mixedarray))
2087
0
                return gs_fapi_glyph_invalid_format;
2088
2089
1.34M
            if (r_has_type(glyph, t_integer)
2090
0
                && dict_find_string_with_type(pdr, "CFFCharStrings", &CFFCharStrings, t_dictionary) > 0 && r_has_type(CFFCharStrings, t_dictionary)) {
2091
0
                ref *g2;
2092
0
                if (dict_find(CFFCharStrings, glyph, &g2) <= 0) {
2093
0
                    ref nd;
2094
0
                    make_int(&nd, 0);
2095
0
                    if (dict_find(CFFCharStrings, &nd, &g2) <= 0) {
2096
0
                        return gs_fapi_glyph_invalid_format;
2097
0
                    }
2098
0
                }
2099
0
                glyph = g2;
2100
0
            }
2101
2102
1.34M
            if (!r_has_type(glyph, t_string))
2103
0
                return 0;
2104
1.34M
            glyph_length = get_type1_data(ff, glyph, buf, buf_length);
2105
1.34M
        }
2106
1.34M
    }
2107
0
    else {                      /* type 42 */
2108
0
        const byte *data_ptr;
2109
0
        int l = ff->get_glyphdirectory_data(ff, char_code, &data_ptr);
2110
0
        ref *render_notdef_ref;
2111
0
        bool render_notdef = true;
2112
2113
0
        if (dict_find_string(pdr, ".render_notdef", &render_notdef_ref) > 0
2114
0
            && r_has_type(render_notdef_ref, t_boolean)) {
2115
0
            render_notdef = render_notdef_ref->value.boolval;
2116
0
        }
2117
0
        else {
2118
0
            render_notdef = i_ctx_p->RenderTTNotdef;
2119
0
        }
2120
2121
        /* We should only render the TT notdef if we've been told to - logic lifted from zchar42.c */
2122
0
        if (!render_notdef
2123
0
            &&
2124
0
            ((ff->char_data_len == 7
2125
0
              && strncmp((const char *)ff->char_data, ".notdef", 7) == 0)
2126
0
             || (ff->char_data_len > 9
2127
0
                 && strncmp((const char *)ff->char_data, ".notdef~GS",
2128
0
                            10) == 0))) {
2129
0
            glyph_length = 0;
2130
0
        }
2131
0
        else {
2132
0
            if (l >= 0) {
2133
0
                int MetricsCount = gs_fapi_get_metrics_count(ff), mc =
2134
0
                    MetricsCount << 1;
2135
2136
0
                glyph_length = max((l - mc), 0);
2137
0
                if (glyph_length > 65535) /* We want limit this to a short int value */
2138
0
                    glyph_length = 0;
2139
0
                if (buf != 0 && glyph_length > 0)
2140
0
                    memcpy(buf, data_ptr + mc,
2141
0
                           min(glyph_length, buf_length) /* safety */ );
2142
0
            }
2143
0
            else {
2144
0
                gs_font_type42 *pfont42 = (gs_font_type42 *) ff->client_font_data;
2145
0
                ulong offset0, length_read;
2146
0
                int error = sfnt_get_glyph_offset(pdr, pfont42, char_code, &offset0);
2147
2148
0
                if (error < 0) {
2149
0
                    glyph_length = gs_fapi_glyph_invalid_index;
2150
0
                }
2151
0
                else if (pfont42->data.len_glyphs) {
2152
0
                    if (char_code <= pfont42->data.numGlyphs) {
2153
0
                        glyph_length = pfont42->data.len_glyphs[char_code];
2154
0
                        if (glyph_length > 0) {
2155
0
                            ulong endoffs0;
2156
2157
0
                            if (glyph_length > 65535
2158
0
                                || sfnt_get_sfnt_length(pdr, &endoffs0) < 0
2159
0
                                || offset0 > endoffs0
2160
0
                                || (ulong)glyph_length > endoffs0 - offset0)
2161
0
                                glyph_length = gs_fapi_glyph_invalid_index;
2162
0
                        }
2163
0
                    }
2164
0
                    else
2165
0
                        glyph_length = gs_fapi_glyph_invalid_index;
2166
0
                }
2167
0
                else {
2168
0
                    ulong noffs, endoffs;
2169
                    /* If we haven't got a len_glyphs array, try using the offset of the next glyph offset
2170
                     * to work out the length
2171
                     */
2172
0
                    error = sfnt_get_glyph_offset(pdr, pfont42, char_code + 1, &noffs);
2173
0
                    if (error == 0) {
2174
0
                        glyph_length = noffs - offset0;
2175
0
                        error = sfnt_get_sfnt_length(pdr, &endoffs);
2176
0
                        if (error < 0) {
2177
0
                            glyph_length = gs_fapi_glyph_invalid_index;
2178
0
                        }
2179
0
                        else {
2180
0
                            if (glyph_length + offset0 > endoffs) {
2181
0
                                glyph_length = gs_fapi_glyph_invalid_index;
2182
0
                            }
2183
0
                        }
2184
0
                    }
2185
0
                    else {
2186
                        /* And if we can't get the next glyph offset, use the end of the sfnt data
2187
                         * to work out the length.
2188
                         */
2189
0
                        error = sfnt_get_sfnt_length(pdr, &noffs);
2190
0
                        if (error < 0) {
2191
0
                            glyph_length = gs_fapi_glyph_invalid_index;
2192
0
                        }
2193
0
                        else {
2194
0
                            glyph_length = noffs - offset0;
2195
0
                        }
2196
0
                    }
2197
0
                }
2198
2199
0
                if (buf != 0 && !error) {
2200
0
                    sfnts_reader r;
2201
2202
0
                    sfnts_reader_init(pfont42->memory, &r, pdr);
2203
2204
0
                    r.seek(&r, offset0);
2205
0
                    length_read =
2206
0
                        r.rstring(&r, buf,
2207
0
                                  min(glyph_length,
2208
0
                                      buf_length) /* safety */ );
2209
0
                    if (glyph_length > 0
2210
0
                        && (r.error < 0
2211
0
                            || length_read <
2212
0
                                   (ulong)min(glyph_length, buf_length)))
2213
0
                        glyph_length = (int)length_read;
2214
0
                }
2215
0
            }
2216
0
        }
2217
0
    }
2218
    /* Avoid passing uninitialised or left over byte values to the fapi server */
2219
1.34M
    if (buf != NULL && glyph_length < buf_length) {
2220
1.29M
        size_t n = glyph_length < 0 ? 0 : glyph_length;
2221
1.29M
        memset(buf + n, 0x00, buf_length - n);
2222
1.29M
    }
2223
1.34M
    return glyph_length;
2224
1.34M
}
2225
2226
static int
2227
ps_fapi_get_metrics(gs_fapi_font *ff, gs_string *char_name, gs_glyph cid, double *m, bool vertical)
2228
1.33M
{
2229
1.33M
    ref glyph;
2230
1.33M
    int code;
2231
1.33M
    gs_font_base *pbfont = ((gs_font_base *) ff->client_font_data2);
2232
2233
1.33M
    if (char_name->data != NULL) {
2234
1.33M
        make_string(&glyph, avm_foreign | a_readonly, char_name->size, char_name->data);
2235
1.33M
    }
2236
0
    else {
2237
0
        make_int(&glyph, cid);
2238
0
    }
2239
2240
1.33M
    if (vertical) {
2241
0
        code = zchar_get_metrics2(pbfont, &glyph, m);
2242
0
    }
2243
1.33M
    else {
2244
1.33M
        code = zchar_get_metrics(pbfont, &glyph, m);
2245
1.33M
    }
2246
2247
1.33M
    make_null(&glyph);
2248
2249
1.33M
    return (code);
2250
1.33M
}
2251
2252
2253
/* forward declaration for the ps_ff_stub assignment */
2254
static int ps_get_glyphname_or_cid(gs_text_enum_t *penum,
2255
                                   gs_font_base *pbfont,
2256
                                   gs_string *charstring, gs_string *name,
2257
                                   gs_glyph ccode, gs_string *enc_char_name,
2258
                                   char *font_file_path,
2259
                                   gs_fapi_char_ref *cr, bool bCID);
2260
2261
static int ps_fapi_set_cache(gs_text_enum_t *penum,
2262
                             const gs_font_base *pbfont,
2263
                             const gs_string *char_name, gs_glyph cid,
2264
                             const double pwidth[2], const gs_rect *pbbox,
2265
                             const double Metrics2_sbw_default[4],
2266
                             bool *imagenow);
2267
2268
static const gs_fapi_font ps_ff_stub = {
2269
    0,                          /* server_font_data */
2270
    0,                          /* need_decrypt */
2271
    NULL,                       /* const gs_memory_t */
2272
    0,                          /* font_file_path */
2273
    0,                          /* full_font_buf */
2274
    0,                          /* full_font_buf_len */
2275
    0,                          /* subfont */
2276
    false,                      /* is_type1 */
2277
    false,                      /* is_cid */
2278
    false,                      /* is_outline_font */
2279
    false,                      /* is_mtx_skipped */
2280
    false,                      /* is_vertical */
2281
    false,                      /* metrics_only */
2282
    {{-1, -1}},                 /* ttf_cmap_req */
2283
    {-1, -1},                   /* ttf_cmap_selected */
2284
    0,                          /* client_ctx_p */
2285
    0,                          /* client_font_data */
2286
    0,                          /* client_font_data2 */
2287
    0,                          /* char_data */
2288
    0,                          /* char_data_len */
2289
    0,                          /* embolden */
2290
    FAPI_FF_get_word,
2291
    FAPI_FF_get_long,
2292
    FAPI_FF_get_float,
2293
    FAPI_FF_get_name,
2294
    FAPI_FF_get_proc,
2295
    FAPI_FF_get_gsubr,
2296
    FAPI_FF_get_subr,
2297
    FAPI_FF_get_raw_subr,
2298
    FAPI_FF_get_glyph,
2299
    FAPI_FF_serialize_tt_font,
2300
    NULL,                       /* retrieve_tt_font */
2301
    FAPI_FF_get_charstring,
2302
    FAPI_FF_get_charstring_name,
2303
    ps_get_GlyphDirectory_data_ptr,
2304
    ps_get_glyphname_or_cid,
2305
    ps_fapi_get_metrics,
2306
    ps_fapi_set_cache
2307
};
2308
2309
static int
2310
FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap)
2311
10.1k
{
2312
10.1k
    ref *pref;
2313
10.1k
    int code;
2314
2315
10.1k
    if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0)
2316
0
        return code;
2317
10.1k
    if (code == 0)
2318
0
        return_error(gs_error_undefined);
2319
2320
10.1k
    if (r_type(pref) != t_string)
2321
0
        return_error(gs_error_typecheck);
2322
10.1k
    *xlatmap = (char *)pref->value.bytes;
2323
    /*  Note : this supposes that xlatmap doesn't move in virtual memory.
2324
       Garbager must not be called while plugin executes get_scaled_font, get_decodingID.
2325
       Fix some day with making copy of xlatmap in system memory.
2326
     */
2327
10.1k
    return 0;
2328
10.1k
}
2329
2330
static int
2331
renderer_retcode(gs_memory_t *mem, gs_fapi_server *I, gs_fapi_retcode rc)
2332
0
{
2333
0
    if (rc == 0)
2334
0
        return 0;
2335
0
    emprintf2(mem,
2336
0
              "Error: Font Renderer Plugin ( %s ) return code = %d\n",
2337
0
              I->ig.d->subtype, rc);
2338
0
    return rc < 0 ? rc : gs_error_invalidfont;
2339
0
}
2340
2341
/* <server name>/<null> object .FAPIavailable bool */
2342
static int
2343
zFAPIavailable(i_ctx_t *i_ctx_p)
2344
324k
{
2345
324k
    os_ptr op = osp;
2346
324k
    char *serv_name = NULL;
2347
324k
    ref name_ref;
2348
2349
324k
    check_op(1);
2350
324k
    if (r_has_type(op, t_name)) {
2351
162k
        name_string_ref(imemory, op, &name_ref);
2352
2353
162k
        serv_name =
2354
162k
            (char *) ref_to_string(&name_ref, imemory, "zFAPIavailable");
2355
162k
        if (!serv_name) {
2356
0
            return_error(gs_error_VMerror);
2357
0
        }
2358
162k
    }
2359
2360
324k
    make_bool(op, gs_fapi_available(imemory, serv_name));
2361
2362
324k
    if (serv_name) {
2363
162k
        gs_free_string(imemory, (byte *) serv_name,
2364
162k
                       strlen((char *)serv_name) + 1, "zFAPIavailable");
2365
162k
    }
2366
324k
    return (0);
2367
324k
}
2368
2369
static int
2370
ps_get_server_param(gs_fapi_server *I, const char *subtype, char **server_param, int *server_param_size)
2371
2372
66.9k
{
2373
66.9k
    ref *FAPIconfig, *options, *server_options;
2374
66.9k
    i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
2375
2376
66.9k
    if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0
2377
66.9k
        && r_has_type(FAPIconfig, t_dictionary)) {
2378
66.9k
        if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0
2379
66.9k
            && r_has_type(options, t_dictionary)) {
2380
66.9k
            if (dict_find_string(options, (char *)subtype, &server_options) >
2381
66.9k
                0 && r_has_type(server_options, t_string)) {
2382
0
                *server_param = (char *) server_options->value.const_bytes;
2383
0
                *server_param_size = r_size(server_options);
2384
0
            }
2385
66.9k
        }
2386
66.9k
    }
2387
66.9k
    return 1;
2388
66.9k
}
2389
2390
static inline int
2391
base_font_param(const ref *pfdict, gs_font **ppfont)
2392
1.14M
{
2393
1.14M
    int code = font_param(pfdict, ppfont);
2394
1.14M
    if (code >= 0 && (*ppfont)->FontType == ft_composite) {
2395
0
        code = gs_note_error(gs_error_invalidfont);
2396
0
    }
2397
1.14M
    return code;
2398
1.14M
}
2399
2400
static int
2401
FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font *pfont,
2402
                 int subfont, const char *font_file_path)
2403
66.9k
{
2404
66.9k
    ref *pdr = op;              /* font dict */
2405
66.9k
    const char *decodingID = NULL;
2406
66.9k
    char *xlatmap = NULL;
2407
66.9k
    gs_font_base *pbfont = (gs_font_base *)pfont;
2408
66.9k
    gs_fapi_server *I = pbfont->FAPI;
2409
66.9k
    ref *Decoding_old;
2410
66.9k
    int code;
2411
2412
66.9k
    if (font_file_path != NULL && pbfont->FAPI_font_data == NULL)
2413
0
        if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0)
2414
0
            return code;
2415
2416
66.9k
    gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
2417
2418
66.9k
    code =
2419
66.9k
        gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
2420
66.9k
                             NULL, xlatmap, &decodingID);
2421
66.9k
    if (code < 0)
2422
0
        return code;
2423
2424
66.9k
    if (code > 0) {
2425
        /* save refined FontBBox back to PS world */
2426
0
        ref *v, mat[4], arr;
2427
0
        int attrs;
2428
2429
0
        if (dict_find_string(op, "FontBBox", &v) > 0) {
2430
0
            if (!r_has_type(v, t_array) && !r_has_type(v, t_shortarray)
2431
0
                && !r_has_type(v, t_mixedarray))
2432
0
                return_error(gs_error_invalidfont);
2433
0
            make_real(&mat[0], pbfont->FontBBox.p.x);
2434
0
            make_real(&mat[1], pbfont->FontBBox.p.y);
2435
0
            make_real(&mat[2], pbfont->FontBBox.q.x);
2436
0
            make_real(&mat[3], pbfont->FontBBox.q.y);
2437
0
            if (r_has_type(v, t_shortarray) || r_has_type(v, t_mixedarray)
2438
0
                || r_size(v) < 4) {
2439
                /* Create a new full blown array in case the values are reals */
2440
0
                code = ialloc_ref_array(&arr, a_all, 4, "array");
2441
0
                if (code < 0)
2442
0
                    return code;
2443
0
                v = &arr;
2444
0
                code = idict_put_string(op, "FontBBox", &arr);
2445
0
                if (code < 0)
2446
0
                    return code;
2447
0
                ref_assign_new(v->value.refs + 0, &mat[0]);
2448
0
                ref_assign_new(v->value.refs + 1, &mat[1]);
2449
0
                ref_assign_new(v->value.refs + 2, &mat[2]);
2450
0
                ref_assign_new(v->value.refs + 3, &mat[3]);
2451
0
            }
2452
0
            else {
2453
0
                ref_assign_old(v, v->value.refs + 0, &mat[0],
2454
0
                               "FAPI_refine_font_BBox");
2455
0
                ref_assign_old(v, v->value.refs + 1, &mat[1],
2456
0
                               "FAPI_refine_font_BBox");
2457
0
                ref_assign_old(v, v->value.refs + 2, &mat[2],
2458
0
                               "FAPI_refine_font_BBox");
2459
0
                ref_assign_old(v, v->value.refs + 3, &mat[3],
2460
0
                               "FAPI_refine_font_BBox");
2461
0
            }
2462
0
            attrs = v->tas.type_attrs;
2463
0
            r_clear_attrs(v, a_all);
2464
0
            r_set_attrs(v, attrs | a_execute);
2465
0
        }
2466
0
    }
2467
2468
    /* Assign a Decoding : */
2469
66.9k
    if (decodingID != 0 && *decodingID
2470
0
        && dict_find_string(pdr, "Decoding", &Decoding_old) <= 0) {
2471
0
        ref Decoding;
2472
2473
0
        if (FAPI_ISCIDFONT(pbfont)) {
2474
0
            ref *CIDSystemInfo, *Ordering, SubstNWP;
2475
0
            byte buf[30];
2476
0
            int ordering_length, decodingID_length =
2477
0
                min(strlen(decodingID), sizeof(buf) - 2);
2478
2479
0
            if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0
2480
0
                || !r_has_type(CIDSystemInfo, t_dictionary))
2481
0
                return_error(gs_error_invalidfont);
2482
2483
0
            if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0
2484
0
                || !r_has_type(Ordering, t_string)) {
2485
0
                return_error(gs_error_invalidfont);
2486
0
            }
2487
2488
0
            ordering_length =
2489
0
                min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length);
2490
0
            memcpy(buf, Ordering->value.const_bytes, ordering_length);
2491
0
            if ((code =
2492
0
                 name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0)
2493
0
                return code;
2494
0
            if ((code =
2495
0
                 dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0)
2496
0
                return code;
2497
0
            buf[ordering_length] = '.';
2498
0
            memcpy(buf + ordering_length + 1, decodingID, decodingID_length);
2499
0
            buf[decodingID_length + 1 + ordering_length] = 0;   /* Debug purpose only */
2500
0
            if ((code = name_ref(imemory, buf,
2501
0
                                 decodingID_length + 1 + ordering_length,
2502
0
                                 &Decoding, 0)) < 0)
2503
0
                return code;
2504
0
        }
2505
0
        else if ((code = name_ref(imemory, (const byte *)decodingID,
2506
0
                                  strlen(decodingID), &Decoding, 0)) < 0)
2507
0
            return code;
2508
0
        if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0)
2509
0
            return code;
2510
0
    }
2511
66.9k
    return 0;
2512
66.9k
}
2513
2514
/*  <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */
2515
/*  Rebuild a font for handling it with an external renderer.
2516
2517
    The font was built as a native GS font to allow easy access
2518
    to font features. Then zFAPIrebuildfont sets FAPI entry
2519
    into gx_font_base and replaces BuildGlyph and BuildChar
2520
    to enforce the FAPI handling.
2521
2522
    This operator must not be called with devices which embed fonts.
2523
2524
*/
2525
static int
2526
zFAPIrebuildfont(i_ctx_t *i_ctx_p)
2527
66.9k
{
2528
66.9k
    os_ptr op = osp;
2529
66.9k
    build_proc_refs build;
2530
66.9k
    gs_font *pfont;
2531
66.9k
    int code;
2532
66.9k
    gs_font_base *pbfont;
2533
66.9k
    ref *v;
2534
66.9k
    char *font_file_path = NULL;
2535
66.9k
    char FAPI_ID[20];
2536
66.9k
    const byte *pchars;
2537
66.9k
    uint len;
2538
66.9k
    font_data *pdata;
2539
66.9k
    gs_fapi_server *I;
2540
66.9k
    bool has_buildglyph;
2541
66.9k
    bool has_buildchar;
2542
66.9k
    int subfont;
2543
2544
66.9k
    check_op(3);
2545
66.9k
    code = base_font_param(op - 1, &pfont);
2546
66.9k
    if (code < 0)
2547
0
        return code;
2548
2549
66.9k
    pbfont = (gs_font_base *) pfont;
2550
2551
66.9k
    check_type(*op, t_boolean);
2552
    /* If someone has copied the font dictionary, we may still
2553
     * have the FAPI entry in the dict, but not have the FAPI
2554
     * server assigned in the font object.
2555
     */
2556
66.9k
    if (pbfont->FAPI == NULL) {
2557
56.8k
        if (dict_find_string(op - 1, "FAPI", &v) <= 0
2558
56.8k
            || !r_has_type(v, t_name))
2559
0
            return_error(gs_error_invalidfont);
2560
56.8k
        obj_string_data(imemory, v, &pchars, &len);
2561
56.8k
        len = min(len, sizeof(FAPI_ID) - 1);
2562
56.8k
        strncpy((char *)FAPI_ID, (const char *)pchars, len);
2563
56.8k
        FAPI_ID[len] = 0;
2564
2565
56.8k
        gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
2566
2567
56.8k
        code =
2568
56.8k
            gs_fapi_find_server(imemory, FAPI_ID,
2569
56.8k
                                (gs_fapi_server **) & (pbfont->FAPI), ps_get_server_param);
2570
56.8k
        if (!pbfont->FAPI || code < 0) {
2571
0
            return_error(gs_error_invalidfont);
2572
0
        }
2573
56.8k
    }
2574
2575
66.9k
    pdata = (font_data *) pfont->client_data;
2576
66.9k
    I = pbfont->FAPI;
2577
2578
66.9k
    if (dict_find_string((op - 1), "SubfontId", &v) > 0
2579
0
        && r_has_type(v, t_integer))
2580
0
        subfont = v->value.intval;
2581
66.9k
    else
2582
66.9k
        subfont = 0;
2583
2584
2585
66.9k
    if (r_type(&(pdata->BuildGlyph)) != t_null) {
2586
66.9k
        has_buildglyph = true;
2587
66.9k
    }
2588
0
    else {
2589
0
        has_buildglyph = false;
2590
0
    }
2591
2592
66.9k
    if (r_type(&(pdata->BuildChar)) != t_null) {
2593
66.9k
        has_buildchar = true;
2594
66.9k
    }
2595
1
    else {
2596
1
        has_buildchar = false;
2597
1
    }
2598
2599
    /* This shouldn't happen, but just in case */
2600
66.9k
    if (has_buildglyph == false && has_buildchar == false) {
2601
0
        has_buildglyph = true;
2602
0
    }
2603
2604
66.9k
    if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string)) {
2605
66.9k
        v = NULL;
2606
66.9k
    }
2607
2608
66.9k
    if (pfont->FontType == ft_CID_encrypted && v == NULL) {
2609
1
        if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9",
2610
1
                                         ".FAPIBuildGlyph9")) < 0) {
2611
0
            return code;
2612
0
        }
2613
1
    }
2614
66.9k
    else {
2615
66.9k
        if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar",
2616
66.9k
                                         ".FAPIBuildGlyph")) < 0) {
2617
0
            return code;
2618
0
        }
2619
66.9k
    }
2620
2621
66.9k
    if (!
2622
66.9k
        ((r_type(&(pdata->BuildChar)) != t_null
2623
66.9k
          && pdata->BuildChar.value.pname && build.BuildChar.value.pname
2624
66.9k
          && name_index(imemory, &pdata->BuildChar) == name_index(imemory,
2625
66.9k
                                                                  &build.
2626
66.9k
                                                                  BuildChar))
2627
66.9k
         || (r_type(&(pdata->BuildGlyph)) != t_null
2628
66.9k
             && pdata->BuildGlyph.value.pname && build.BuildGlyph.value.pname
2629
66.9k
             && name_index(imemory, &pdata->BuildGlyph) == name_index(imemory,
2630
66.9k
                                                                      &build.
2631
66.9k
                                                                      BuildGlyph))))
2632
66.9k
    {
2633
2634
66.9k
        if (has_buildchar == true) {
2635
66.9k
            ref_assign_new(&pdata->BuildChar, &build.BuildChar);
2636
66.9k
        }
2637
1
        else {
2638
1
            make_null(&pdata->BuildChar);
2639
1
        }
2640
2641
66.9k
        if (has_buildglyph == true) {
2642
66.9k
            ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph);
2643
66.9k
        }
2644
0
        else {
2645
0
            make_null(&pdata->BuildGlyph);
2646
0
        }
2647
66.9k
        if (v != NULL) {
2648
0
            font_file_path =
2649
0
                ref_to_string(v, imemory_global, "font file path");
2650
0
        }
2651
2652
66.9k
        code =
2653
66.9k
            FAPI_refine_font(i_ctx_p, op - 1, pfont, subfont,
2654
66.9k
                             font_file_path);
2655
2656
66.9k
        memcpy(&I->initial_FontMatrix, &pbfont->FontMatrix,
2657
66.9k
               sizeof(gs_matrix));
2658
2659
66.9k
        if (font_file_path != NULL) {
2660
0
            gs_free_string(imemory_global, (byte *) font_file_path,
2661
0
                           r_size(v) + 1, "font file path");
2662
0
        }
2663
66.9k
    }
2664
66.9k
    pop(1);
2665
66.9k
    return code;
2666
66.9k
}
2667
2668
static ulong
2669
array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name)
2670
0
{
2671
0
    ulong n = r_size(Encoding), i;
2672
0
    ref v;
2673
2674
0
    for (i = 0; i < n; i++)
2675
0
        if (array_get(mem, Encoding, i, &v) < 0)
2676
0
            break;
2677
0
        else if (r_type(char_name) == r_type(&v)
2678
0
                 && char_name->value.const_pname == v.value.const_pname)
2679
0
            return i;
2680
0
    return 0;
2681
0
}
2682
2683
static int
2684
zfapi_finish_render(i_ctx_t *i_ctx_p)
2685
0
{
2686
0
    os_ptr op = osp;
2687
0
    gs_font *pfont;
2688
0
    int code = base_font_param(op - 1, &pfont);
2689
2690
0
    if (code == 0) {
2691
0
        gs_font_base *pbfont = (gs_font_base *) pfont;
2692
0
        gs_fapi_server *I = pbfont->FAPI;
2693
0
        gs_text_enum_t *penum = op_show_find(i_ctx_p);
2694
2695
0
        gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
2696
2697
0
        code = gs_fapi_finish_render(pfont, igs, penum, I);
2698
0
        pop(2);
2699
0
        I->release_char_data(I);
2700
0
    }
2701
0
    return code;
2702
0
}
2703
2704
static int
2705
ps_fapi_set_cache(gs_text_enum_t *penum, const gs_font_base *pbfont,
2706
                  const gs_string *char_name, gs_glyph cid,
2707
                  const double pwidth[2], const gs_rect *pbbox,
2708
                  const double Metrics2_sbw_default[4], bool *imagenow)
2709
1.06M
{
2710
1.06M
    i_ctx_t *i_ctx_p = (i_ctx_t *) pbfont->FAPI->client_ctx_p;
2711
1.06M
    op_proc_t exec_cont = 0;    /* dummy - see below */
2712
1.06M
    int code = 0;
2713
2714
1.06M
    if (cid < GS_MIN_CID_GLYPH) {
2715
1.06M
        ref cname;
2716
2717
1.06M
        make_string(&cname, avm_foreign | a_readonly, char_name->size,
2718
1.06M
                    char_name->data);
2719
1.06M
        code =
2720
1.06M
            zchar_set_cache(i_ctx_p, pbfont, &cname, NULL, pwidth, pbbox,
2721
1.06M
                            zfapi_finish_render, &exec_cont,
2722
1.06M
                            Metrics2_sbw_default);
2723
1.06M
    }
2724
0
    else {
2725
0
        ref cidref;
2726
2727
0
        make_int(&cidref, (cid - GS_MIN_CID_GLYPH));
2728
0
        code = zchar_set_cache(i_ctx_p, pbfont, &cidref, NULL, pwidth, pbbox,
2729
0
                               zfapi_finish_render, &exec_cont,
2730
0
                               Metrics2_sbw_default);
2731
0
    }
2732
2733
1.06M
    if (code >= 0 && exec_cont != NULL) {
2734
1.06M
        *imagenow = true;
2735
1.06M
    }
2736
3.36k
    else {
2737
3.36k
        *imagenow = false;
2738
3.36k
    }
2739
    /* We ignore the value of exec_cont here, and leave it up to
2740
     * gs_fapi_do_char() to do the "right" thing based on the
2741
     * return value
2742
     */
2743
1.06M
    return (code);
2744
1.06M
}
2745
2746
2747
static const byte *
2748
find_substring(const byte *where, int length, const char *what)
2749
0
{
2750
0
    int l = strlen(what);
2751
0
    int n = length - l;
2752
0
    const byte *p = where;
2753
2754
0
    for (; n >= 0; n--, p++)
2755
0
        if (!memcmp(p, what, l))
2756
0
            return p;
2757
0
    return NULL;
2758
0
}
2759
2760
static int
2761
ps_get_glyphname_or_cid(gs_text_enum_t *penum,
2762
                        gs_font_base *pbfont, gs_string *charstring,
2763
                        gs_string *name, gs_glyph ccode,
2764
                        gs_string *enc_char_name, char *font_file_path,
2765
                        gs_fapi_char_ref *cr, bool bCID)
2766
1.33M
{
2767
1.33M
    ref *pdr = pfont_dict(pbfont);
2768
1.33M
    int client_char_code = ccode;
2769
1.33M
    ref char_name, cname_str;
2770
1.33M
    int code = 0;
2771
1.33M
    gs_fapi_server *I = pbfont->FAPI;
2772
1.33M
    bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL);
2773
1.33M
    bool is_glyph_index = false;
2774
1.33M
    bool is_embedded_type1 =
2775
1.33M
        ((pbfont->FontType == ft_encrypted
2776
1.33M
          || pbfont->FontType == ft_encrypted2) && font_file_path == NULL);
2777
1.33M
    i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
2778
1.33M
    bool unicode_cp = false;
2779
2780
    /* Obtain the character name : */
2781
1.33M
    if (bCID) {
2782
0
        if (pbfont->FontType == ft_CID_TrueType && font_file_path) {
2783
0
            ref *pdr2, *fidr, *dummy;
2784
0
            pdr2 = pfont_dict(gs_rootfont(igs));
2785
0
            if (dict_find_string_with_type(pdr2, "FontInfo", &fidr, t_dictionary) > 0 &&
2786
0
                dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0)
2787
0
            {
2788
0
                unsigned char uc[4] = {0};
2789
0
                unsigned int cc = 0;
2790
0
                int i, l;
2791
0
                if (penum->text.operation & TEXT_FROM_SINGLE_CHAR) {
2792
0
                    cc = penum->text.data.d_char;
2793
0
                } else if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) {
2794
0
                    cc = penum->text.data.d_glyph - GS_MIN_CID_GLYPH;
2795
0
                }
2796
0
                else {
2797
0
                    byte *c = (byte *)&penum->text.data.bytes[penum->index - penum->bytes_decoded];
2798
0
                    for (i = 0; i < penum->bytes_decoded ; i++) {
2799
0
                      cc |= c[i] << ((penum->bytes_decoded - 1) - i) * 8;
2800
0
                    }
2801
0
                }
2802
0
                l = ((gs_font_base *)gs_rootfont(igs))->procs.decode_glyph(gs_rootfont(igs), cc + GS_MIN_CID_GLYPH, ccode, (unsigned short *)uc, sizeof(uc));
2803
0
                if (l > 0 && l < sizeof(uc)) {
2804
0
                    cc = 0;
2805
0
                    for (i = 0; i < l; i++) {
2806
0
                        cc |= uc[l - 1 - i] << (i * 8);
2807
0
                    }
2808
0
                    ccode = cc;
2809
0
                    unicode_cp = true;
2810
0
                }
2811
0
            }
2812
0
        }
2813
0
        client_char_code = ccode;
2814
0
        make_null(&char_name);
2815
0
        enc_char_name->data = NULL;
2816
0
        enc_char_name->size = 0;
2817
0
    }
2818
1.33M
    else {
2819
1.33M
        if (ccode != GS_NO_CHAR) {
2820
            /* Translate from PS encoding to char name : */
2821
1.33M
            ref *Encoding;
2822
2823
1.33M
            client_char_code = ccode;
2824
1.33M
            if (dict_find_string(pdr, "Encoding", &Encoding) > 0 &&
2825
1.33M
                (r_has_type(Encoding, t_array) ||
2826
0
                 r_has_type(Encoding, t_shortarray)
2827
1.33M
                 || r_has_type(Encoding, t_mixedarray))) {
2828
1.33M
                if (array_get(imemory, Encoding, client_char_code, &char_name)
2829
1.33M
                    < 0)
2830
0
                    if ((code =
2831
0
                         name_ref(imemory, (const byte *)".notdef", 7,
2832
0
                                  &char_name, -1)) < 0)
2833
0
                        return code;
2834
1.33M
            }
2835
0
            else {
2836
0
                return_error(gs_error_invalidfont);
2837
0
            }
2838
1.33M
        }
2839
0
        else {
2840
0
            code =
2841
0
                names_ref(imemory->gs_lib_ctx->gs_name_table,
2842
0
                          (const byte *)name->data, name->size, &char_name,
2843
0
                          0);
2844
2845
0
        }
2846
        /* We need to store the name as we get it (from the Encoding array), in case it's
2847
         * had the name extended (with "~GS~xx"), we'll remove the extension before passing
2848
         * it to the renderer for a disk based font. But the metrics dictionary may have
2849
         * been constructed using the extended name....
2850
         */
2851
1.33M
        if (!r_has_type(&char_name, t_name))
2852
0
            return_error(gs_error_invalidfont);
2853
1.33M
        name_string_ref(imemory, &char_name, &cname_str);
2854
1.33M
        enc_char_name->data = cname_str.value.bytes;
2855
1.33M
        enc_char_name->size = r_size(&cname_str);
2856
1.33M
    }
2857
2858
    /* Obtain the character code or glyph index : */
2859
1.33M
    cr->char_codes_count = 1;
2860
1.33M
    if (bCID) {
2861
0
        if (font_file_path != NULL) {
2862
0
            ref *Decoding, *TT_cmap = NULL, *SubstNWP;
2863
0
            ref src_type, dst_type;
2864
0
            uint c = 0;
2865
2866
0
            is_glyph_index = true;
2867
2868
0
            if (dict_find_string(pdr, "Decoding", &Decoding) <= 0
2869
0
                || !r_has_type(Decoding, t_dictionary))
2870
0
                return_error(gs_error_invalidfont);
2871
0
            if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0
2872
0
                || !r_has_type(SubstNWP, t_array))
2873
0
                return_error(gs_error_invalidfont);
2874
0
            if (dict_find_string(pdr, "TT_cmap", &TT_cmap) <= 0
2875
0
                || !r_has_type(TT_cmap, t_dictionary)) {
2876
0
                ref *DecodingArray, char_code, char_code1, ih;
2877
0
                int i = client_char_code % 256, n;
2878
2879
0
                make_int(&ih, client_char_code / 256);
2880
                /* Check the Decoding array for this block of CIDs */
2881
0
                if (dict_find(Decoding, &ih, &DecodingArray) <= 0
2882
0
                    || !r_has_type(DecodingArray, t_array)
2883
0
                    || array_get(imemory, DecodingArray, i, &char_code) < 0) {
2884
0
                    return_error(gs_error_invalidfont);
2885
0
                }
2886
2887
                /* Check the Decoding entry */
2888
0
                if (r_has_type(&char_code, t_integer)) {
2889
0
                    n = 1;
2890
0
                }
2891
0
                else if (r_has_type(&char_code, t_array)) {
2892
0
                    DecodingArray = &char_code;
2893
0
                    i = 0;
2894
0
                    n = r_size(DecodingArray);
2895
0
                }
2896
0
                else {
2897
0
                    return_error(gs_error_invalidfont);
2898
0
                }
2899
2900
0
                for (; n--; i++) {
2901
0
                    if (array_get(imemory, DecodingArray, i, &char_code1) < 0
2902
0
                        || !r_has_type(&char_code1, t_integer)) {
2903
0
                        return_error(gs_error_invalidfont);
2904
0
                    }
2905
2906
0
                    c = char_code1.value.intval;
2907
0
                    I->check_cmap_for_GID(I, &c);
2908
0
                    if (c != 0)
2909
0
                        break;
2910
0
                }
2911
0
            }
2912
0
            else {
2913
0
                ref *CIDSystemInfo;
2914
0
                ref *Ordering;
2915
0
                ref *fdict, *CMapDict, *CMapName, *WMode, CMapNameStr;
2916
0
                char *cmapnm = NULL;
2917
0
                int cmapnmlen = 0;
2918
0
                int wmode = 0;
2919
                /* leave off the -H or -V */
2920
0
                const char * const utfcmap = "Identity-UTF16";
2921
0
                int utfcmaplen = strlen(utfcmap);
2922
2923
0
                fdict = pfont_dict(gs_rootfont(igs));
2924
0
                code = dict_find_string(fdict, "CMap", &CMapDict);
2925
0
                if (code > 0 && r_has_type(CMapDict, t_dictionary)) {
2926
0
                    code = dict_find_string(CMapDict, "WMode", &WMode);
2927
0
                    if (code > 0 && r_has_type(WMode, t_integer)) {
2928
0
                        wmode = WMode->value.intval;
2929
0
                    }
2930
0
                    code = dict_find_string(CMapDict, "CMapName", &CMapName);
2931
0
                    if (code > 0 && r_has_type(CMapName, t_name)) {
2932
0
                        name_string_ref(imemory, CMapName, &CMapNameStr);
2933
0
                        cmapnm = (char *)CMapNameStr.value.bytes;
2934
0
                        cmapnmlen = r_size(&CMapNameStr);
2935
0
                    }
2936
0
                }
2937
                /* We only have to lookup the char code if we're *not* using an identity ordering
2938
                   with the exception of Identity-UTF16 which is a different beast altogether */
2939
0
                if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen))
2940
0
                    || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0
2941
0
                    && r_has_type(CIDSystemInfo, t_dictionary)
2942
0
                    && dict_find_string(CIDSystemInfo, "Ordering",
2943
0
                                        &Ordering) > 0
2944
0
                    && r_has_type(Ordering, t_string)
2945
0
                    && strncmp((const char *)Ordering->value.bytes,
2946
0
                               "Identity", 8) != 0)) {
2947
2948
0
                    if ((code =
2949
0
                         cid_to_TT_charcode(imemory, Decoding, TT_cmap,
2950
0
                                            SubstNWP, client_char_code, &c,
2951
0
                                            &src_type, &dst_type)) < 0) {
2952
0
                        return code;
2953
0
                    }
2954
0
                }
2955
0
                else {
2956
0
                    if (pbfont->FontType == ft_CID_TrueType) {
2957
0
                        c = ((gs_font_cid2 *)pbfont)->cidata.CIDMap_proc(((gs_font_cid2 *)pbfont),
2958
0
                                                  client_char_code + GS_MIN_CID_GLYPH);
2959
0
                    }
2960
0
                    else {
2961
0
                        c = client_char_code;
2962
0
                    }
2963
0
                }
2964
0
                if (pbfont->FontType == ft_CID_TrueType)
2965
0
                    c = ((gs_font_cid2 *)pbfont)->data.substitute_glyph_index_vertical((gs_font_type42 *)pbfont, c, wmode, ccode);
2966
0
            }
2967
0
            if (pbfont->FontType == ft_CID_TrueType && c == 0 && TT_cmap) {
2968
0
                ref cc32;
2969
0
                ref *gid;
2970
0
                make_int(&cc32, 32);
2971
0
                if (dict_find(TT_cmap, &cc32, &gid) > 0) {
2972
0
                    if (!r_has_type(gid, t_integer))
2973
0
                        code = gs_note_error(gs_error_typecheck);
2974
0
                    else
2975
0
                        c = gid->value.intval;
2976
0
                }
2977
0
            }
2978
0
            cr->char_codes[0] = c;
2979
            /* fixme : process the narrow/wide/proportional mapping type,
2980
               using src_type, dst_type. Should adjust the 'matrix' above.
2981
               Call get_font_proportional_feature for proper choice.
2982
             */
2983
0
        }
2984
0
        else {
2985
0
            ref *CIDMap;
2986
0
            byte *Map;
2987
0
            int c_code = client_char_code;
2988
0
            int gdb = 2;
2989
0
            int i;
2990
0
            ref *GDBytes = NULL;
2991
2992
0
            if ((dict_find_string(pdr, "GDBytes", &GDBytes) > 0)
2993
0
                && r_has_type(GDBytes, t_integer)) {
2994
0
                gdb = GDBytes->value.intval;
2995
0
            }
2996
2997
            /* The PDF Reference says that we should use a CIDToGIDMap, but the PDF
2998
             * interpreter converts this into a CIDMap (see pdf_font.ps, processCIDToGIDMap)
2999
             */
3000
0
            if (dict_find_string(pdr, "CIDMap", &CIDMap) > 0
3001
0
                && !r_has_type(CIDMap, t_name) && (r_has_type(CIDMap, t_array)
3002
0
                                                   || r_has_type(CIDMap,
3003
0
                                                                 t_string))) {
3004
3005
0
                if (r_has_type(CIDMap, t_array)) {
3006
3007
                    /* Too big for single string, so its an array of 2 strings */
3008
0
                    code = string_array_access_proc(pbfont->memory, CIDMap, 1,
3009
0
                                                    client_char_code * (ulong)gdb,
3010
0
                                                    gdb, NULL, NULL,
3011
0
                                                    (const byte **)&Map);
3012
0
                }
3013
0
                else {
3014
0
                    if (CIDMap->tas.rsize <= c_code * gdb) {
3015
0
                        c_code = 0;
3016
0
                    }
3017
0
                    Map = &CIDMap->value.bytes[c_code * gdb];
3018
                    /* If we don't have enough bytes in CIDMap, ensure we can't enter the loop below setting cr->char_codes[0] */
3019
0
                    if (Map + gdb > CIDMap->value.bytes + CIDMap->tas.rsize)
3020
0
                        code = -1;
3021
0
                }
3022
0
                cr->char_codes[0] = 0;
3023
0
                is_glyph_index = true;
3024
0
                if (code >= 0) {
3025
0
                    for (i = 0; i < gdb; i++) {
3026
0
                        cr->char_codes[0] = (cr->char_codes[0] << 8) + Map[i];
3027
0
                    }
3028
0
                }
3029
0
                else {
3030
0
                    ref *cstr, *refcode;
3031
0
                    code = dict_find_string_with_type(pdr, "CharStrings", &cstr, t_dictionary);
3032
0
                    if (code > 0) {
3033
0
                        code = dict_find_string_with_type(cstr, ".notdef", &refcode, t_integer);
3034
0
                        if (code > 0) {
3035
0
                            cr->char_codes[0] = refcode->value.intval;
3036
0
                        }
3037
0
                    }
3038
0
                }
3039
0
            }
3040
0
            else
3041
0
                cr->char_codes[0] = client_char_code;
3042
0
        }
3043
0
    }
3044
1.33M
    else if (is_TT_from_type42) {
3045
        /* This font must not use 'cmap', so compute glyph index from CharStrings : */
3046
0
        ref *CharStrings, *glyph_index, *cmaptab;
3047
3048
0
        if (dict_find_string(pdr, "TT_cmap", &cmaptab) > 0 &&
3049
0
           r_has_type(cmaptab, t_dictionary)) {
3050
0
           const char *nd = ".notdef";
3051
3052
0
           if (enc_char_name->size >= strlen(nd) &&
3053
0
               enc_char_name->data[0] == nd[0] &&
3054
0
               !memcmp(enc_char_name->data, nd, strlen(nd))) {
3055
0
               ref ccref, *gidref, boolref;
3056
0
               make_int(&ccref, ccode);
3057
0
               if (dict_find(cmaptab, &ccref, &gidref) > 0 &&
3058
0
                   r_has_type(gidref, t_integer) &&
3059
0
                   gidref->value.intval == 0) {
3060
0
                   make_bool(&boolref, true);
3061
0
               }
3062
0
               else {
3063
0
                   make_bool(&boolref, false);
3064
0
               }
3065
0
               dict_put_string(pdr, ".render_notdef", &boolref, NULL);
3066
0
           }
3067
0
        }
3068
3069
0
        if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0
3070
0
            || !r_has_type(CharStrings, t_dictionary))
3071
0
            return_error(gs_error_invalidfont);
3072
0
        if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0)
3073
0
            || r_has_type(glyph_index, t_null)) {
3074
#ifdef DEBUG
3075
            ref *pvalue;
3076
3077
            if (gs_debug_c('1')
3078
                && (dict_find_string(systemdict, "QUIET", &pvalue)) > 0
3079
                && (r_has_type(pvalue, t_boolean)
3080
                    && pvalue->value.boolval == false)) {
3081
                char *glyphn;
3082
3083
                name_string_ref(imemory, &char_name, &char_name);
3084
3085
                glyphn =
3086
                    ref_to_string(&char_name, imemory,
3087
                                  "ps_get_glyphname_or_cid");
3088
                if (glyphn) {
3089
                    dmprintf2(imemory, " Substituting .notdef for %s in the font %s \n",
3090
                             glyphn, pbfont->font_name.chars);
3091
                    gs_free_string(imemory, (byte *) glyphn,
3092
                                   strlen(glyphn) + 1,
3093
                                   "ps_get_glyphname_or_cid");
3094
                }
3095
            }
3096
#endif
3097
3098
0
            cr->char_codes[0] = 0;      /* .notdef */
3099
0
            if ((code =
3100
0
                 name_ref(imemory, (const byte *)".notdef", 7, &char_name,
3101
0
                          -1)) < 0)
3102
0
                return code;
3103
0
        }
3104
0
        else if (r_has_type(glyph_index, t_integer)) {
3105
0
            cr->char_codes[0] = glyph_index->value.intval;
3106
0
        }
3107
0
        else {
3108
0
#if 1                           /* I can't find this ever being used, no idea what it's for..... */
3109
0
            os_ptr op = osp;
3110
3111
            /* Check execution stack has space for BuldChar proc and finish_render */
3112
0
            check_estack(2);
3113
            /* check space and duplicate the glyph index for BuildChar */
3114
0
            check_op(1);
3115
0
            push(1);
3116
0
            ref_assign_inline(op, op - 1);
3117
            /* Come back to fapi_finish_render after running the BuildChar */
3118
0
            push_op_estack(zfapi_finish_render);
3119
0
            ++esp;
3120
0
            ref_assign(esp, glyph_index);
3121
0
            return o_push_estack;
3122
#else
3123
            return (gs_error_invalidfont);
3124
#endif
3125
0
        }
3126
0
        is_glyph_index = true;
3127
0
    }
3128
1.33M
    else if (is_embedded_type1) {
3129
        /*  Since the client passes charstring by callback using I->ff.char_data,
3130
           the client doesn't need to provide a good cr here.
3131
           Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names),
3132
           we provide font char codes equal to document's char codes.
3133
           This trick assumes that Encoding can't point different glyphs
3134
           for same char code. The last should be true due to
3135
           PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs".
3136
         */
3137
1.33M
        if (ccode != GS_NO_CHAR) {
3138
1.33M
            cr->char_codes[0] = client_char_code;
3139
1.33M
        }
3140
0
        else {
3141
            /*
3142
             * Reverse Encoding here, because it can be an incremental one.
3143
             * Note that this can cause problems with UFST (see the comment above),
3144
             * if the encoding doesn't contain the glyph name rendered with glyphshow.
3145
             */
3146
0
            ref *Encoding;
3147
0
            ref glyph;
3148
3149
0
            if ((code = name_ref(pbfont->memory, name->data, name->size, &glyph, false)) < 0)
3150
0
                return code;
3151
3152
0
            if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0) {
3153
0
                cr->char_codes[0] =
3154
0
                    (uint) array_find(imemory, Encoding, &glyph);
3155
0
            }
3156
0
            else
3157
0
                return_error(gs_error_invalidfont);
3158
0
        }
3159
1.33M
    }
3160
0
    else {                      /* a non-embedded font, i.e. a disk font */
3161
0
        bool can_retrieve_char_by_name = false;
3162
0
        const byte *p;
3163
3164
0
        obj_string_data(imemory, &char_name, &cr->char_name,
3165
0
                        &cr->char_name_length);
3166
0
        p = find_substring(cr->char_name, cr->char_name_length,
3167
0
                           gx_extendeg_glyph_name_separator);
3168
0
        if (p != NULL) {
3169
0
            cr->char_name_length = p - cr->char_name;
3170
0
            if ((code = name_ref(pbfont->memory, cr->char_name,
3171
0
                             cr->char_name_length, &char_name, true)) < 0)
3172
0
                return code;
3173
0
        }
3174
0
        if ((code =
3175
0
             renderer_retcode(imemory, I,
3176
0
                              I->can_retrieve_char_by_name(I, &I->ff, cr,
3177
0
                                                           &can_retrieve_char_by_name)))
3178
0
            < 0)
3179
0
            return code;
3180
3181
0
        if (!can_retrieve_char_by_name) {
3182
            /* Translate from char name to encoding used with 3d party font technology : */
3183
0
            ref *Decoding, *char_code;
3184
3185
0
            if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0
3186
0
                && r_has_type(Decoding, t_dictionary)) {
3187
0
                if (dict_find(Decoding, &char_name, &char_code) > 0) {
3188
0
                    code = 0;
3189
0
                    if (r_has_type(char_code, t_integer)) {
3190
0
                        int c_code;
3191
0
                        int_param(char_code, 0xFFFF, &c_code);
3192
0
                        cr->char_codes[0] = (gs_glyph)c_code;
3193
0
                    }
3194
0
                    else if (r_has_type(char_code, t_array)
3195
0
                             || r_has_type(char_code, t_shortarray)) {
3196
0
                        int i;
3197
0
                        ref v;
3198
3199
0
                        cr->char_codes_count = r_size(char_code);
3200
0
                        if (cr->char_codes_count > count_of(cr->char_codes))
3201
0
                            code = gs_note_error(gs_error_rangecheck);
3202
0
                        if (code >= 0) {
3203
0
                            for (i = 0; i < cr->char_codes_count; i++) {
3204
0
                                code = array_get(imemory, char_code, i, &v);
3205
0
                                if (code < 0)
3206
0
                                    break;
3207
0
                                if (!r_has_type(char_code, t_integer)) {
3208
0
                                    code = gs_note_error(gs_error_rangecheck);
3209
0
                                    break;
3210
0
                                }
3211
0
                                cr->char_codes[i] = v.value.intval;
3212
0
                            }
3213
0
                        }
3214
0
                    }
3215
0
                    else {
3216
0
                        code = gs_note_error(gs_error_rangecheck);
3217
0
                    }
3218
0
                    if (code < 0) {
3219
0
                        char buf[16];
3220
0
                        int l = cr->char_name_length;
3221
3222
0
                        if (l > sizeof(buf) - 1) {
3223
0
                            l = sizeof(buf) - 1;
3224
0
                        }
3225
0
                        memcpy(buf, cr->char_name, l);
3226
0
                        buf[l] = 0;
3227
0
                        emprintf1(imemory,
3228
0
                                  "Wrong decoding entry for the character '%s'.\n",
3229
0
                                  buf);
3230
0
                        return_error(gs_error_rangecheck);
3231
0
                    }
3232
0
                }
3233
0
            }
3234
0
        }
3235
0
    }
3236
3237
    /* Provide glyph data for renderer : */
3238
    /* Occasionally, char_name is already a glyph index to pass to the rendering engine
3239
     * so don't treat it as a name object.
3240
     * I believe this will only happen with a TTF/Type42, but checking the object type
3241
     * is cheap, and covers all font type eventualities.
3242
     */
3243
1.33M
    if (!I->ff.is_cid && r_has_type(&char_name, t_name)) {
3244
1.33M
        ref sname;
3245
3246
1.33M
        name_string_ref(imemory, &char_name, &sname);
3247
1.33M
        I->ff.char_data = sname.value.const_bytes;
3248
1.33M
        I->ff.char_data_len = r_size(&sname);
3249
1.33M
    }
3250
0
    else if (I->ff.is_type1) {
3251
0
        I->ff.char_data = charstring;
3252
0
    }
3253
3254
1.33M
    cr->is_glyph_index = is_glyph_index;
3255
1.33M
    cr->client_char_code = client_char_code;
3256
3257
1.33M
    return (code);
3258
1.33M
}
3259
3260
3261
static int
3262
FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring)
3263
1.06M
{                               /* Stack : <font> <code|name> --> - */
3264
1.06M
    os_ptr op = osp;
3265
1.06M
    ref *pdr = op - 1;
3266
1.06M
    ref *v;
3267
1.06M
    char *font_file_path = NULL;
3268
1.06M
    gs_font *pfont;
3269
1.06M
    int code;
3270
3271
1.06M
    check_op(2);
3272
1.06M
    code = base_font_param(osp - 1, &pfont);
3273
3274
1.06M
    if (code == 0) {
3275
1.06M
        gs_font_base *pbfont = (gs_font_base *) pfont;
3276
1.06M
        bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
3277
1.06M
        int subfont;
3278
1.06M
        gs_fapi_server *I = pbfont->FAPI;
3279
1.06M
        gs_text_enum_t *penum = op_show_find(i_ctx_p);
3280
1.06M
        gs_string char_string, *c_string_p = NULL;
3281
1.06M
        gs_string char_name, *c_name_p = NULL;
3282
1.06M
        gs_glyph cindex = GS_NO_CHAR;
3283
1.06M
        ref gname;
3284
3285
1.06M
        if (I == NULL)
3286
0
            return_error(gs_error_invalidfont);
3287
3288
        /* initialise the FAPI font, this includes language specific stuff */
3289
1.06M
        I->ff = ps_ff_stub;
3290
3291
1.06M
        I->client_ctx_p = i_ctx_p;
3292
3293
1.06M
        if (bBuildGlyph && !bCID) {
3294
0
            if (r_type(op) != t_name) {
3295
0
                name_enter_string(imemory, ".notdef", op);
3296
0
            }
3297
0
            check_type(*op, t_name);
3298
3299
0
            name_string_ref(imemory, op, &gname);
3300
0
            c_name_p = &char_name;
3301
0
            c_name_p->data = gname.value.bytes;
3302
0
            c_name_p->size = r_size(&gname);
3303
3304
0
        }
3305
1.06M
        else {
3306
1.06M
            int chint;
3307
1.06M
            if (bBuildGlyph && pbfont->FontType == ft_CID_TrueType
3308
0
                && r_has_type(op, t_name)) {
3309
0
                ref *chstrs, *chs;
3310
3311
                /* This logic is lifted from %Type11BuildGlyph in gs_cidfn.ps
3312
                 * Note we only have to deal with mistakenly being given a name object
3313
                 * here, the out of range CID is handled later
3314
                 */
3315
0
                if ((dict_find_string_with_type(op - 1, "CharStrings", &chstrs, t_dictionary)) <= 0) {
3316
0
                    return_error(gs_error_undefined);
3317
0
                }
3318
3319
0
                if ((dict_find_string(chstrs, ".notdef", &chs)) <= 0) {
3320
0
                    return_error(gs_error_undefined);
3321
0
                }
3322
0
                ref_assign_inline(op, chs);
3323
0
            }
3324
3325
1.06M
            make_null(&gname);
3326
1.06M
            check_type(*op, t_integer);
3327
1.06M
            int_param(op, 0xFFFF, (int *)&chint);
3328
1.06M
            cindex = chint;
3329
1.06M
        }
3330
3331
1.06M
        if (dict_find_string(pdr, "SubfontId", &v) > 0
3332
0
            && r_has_type(v, t_integer))
3333
0
            subfont = v->value.intval;
3334
1.06M
        else
3335
1.06M
            subfont = 0;
3336
3337
1.06M
        if (dict_find_string(osp - 1, "Path", &v) > 0
3338
0
            && r_has_type(v, t_string)) {
3339
0
            font_file_path = ref_to_string(v, imemory, "font file path");
3340
0
        }
3341
3342
1.06M
        if (charstring) {
3343
0
            c_string_p = &char_string;
3344
0
            c_string_p->data = charstring->value.bytes;
3345
0
            c_string_p->size = r_size(charstring);
3346
0
        }
3347
3348
1.06M
        code =
3349
1.06M
            gs_fapi_do_char(pfont, igs, penum, font_file_path,
3350
1.06M
                            bBuildGlyph, c_string_p, c_name_p, (gs_char)cindex, cindex,
3351
1.06M
                            subfont);
3352
1.06M
        if (font_file_path != NULL) {
3353
0
            gs_free_string(imemory, (byte *) font_file_path, r_size(v) + 1,
3354
0
                           "font file path");
3355
0
        }
3356
        /* This handles the situation where a charstring has been replaced with a PS procedure.
3357
         * against the rules, but not *that* rare.
3358
         * It's also something that GS does internally to simulate font styles.
3359
         */
3360
1.06M
        if (code == gs_error_unregistered) {
3361
0
            os_ptr op = osp;
3362
0
            ref *proc = NULL, gname;
3363
3364
0
            if (I->ff.is_type1
3365
0
                && (get_charstring(&I->ff, cindex, &proc, &gname) >= 0)
3366
0
                && proc != NULL && (r_has_type(proc, t_array)
3367
0
                    || r_has_type(proc, t_mixedarray))) {
3368
0
                push(2);
3369
0
                ref_assign(op - 1, &gname);
3370
0
                ref_assign(op, proc);
3371
0
                return (zchar_exec_char_proc(i_ctx_p));
3372
0
            }
3373
0
            else {
3374
0
                return_error(gs_error_invalidfont);
3375
0
            }
3376
0
        }
3377
1.06M
    }
3378
    /* We've already imaged teh glyph, pop the operands */
3379
1.06M
    if (code == 0)
3380
1.06M
        pop(2);
3381
1.06M
    return code;
3382
1.06M
}
3383
3384
static int
3385
zFAPIBuildGlyph9(i_ctx_t *i_ctx_p)
3386
0
{
3387
    /*  The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps .  */
3388
0
    os_ptr lop, op = osp;
3389
0
    int cid, code;
3390
0
    avm_space s = ialloc_space(idmemory);
3391
0
    ref font9 = *pfont_dict(gs_currentfont(igs));
3392
0
    ref *rFDArray, f;
3393
0
    int font_index;
3394
3395
0
    check_op(2);
3396
0
    check_type(op[0], t_integer);
3397
0
    check_type(op[-1], t_dictionary);
3398
0
    cid = op[0].value.intval;
3399
0
    push(2);
3400
0
    op[-1] = *pfont_dict(gs_currentfont(igs));
3401
0
    op[0] = op[-2];             /* <font0> <cid> <font9> <cid> */
3402
0
    ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local));  /* for ztype9mapcid */
3403
3404
    /* stack: <font0> <cid> <font9> <cid> */
3405
0
    if ((code = ztype9mapcid(i_ctx_p)) < 0)
3406
0
        return code;            /* <font0> <cid> <charstring> <font_index> */
3407
    /* fixme: what happens if the charstring is absent ?
3408
       Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */
3409
0
    font_index = op[0].value.intval;
3410
0
    if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0
3411
0
        || r_type(rFDArray) != t_array)
3412
0
        return_error(gs_error_invalidfont);
3413
0
    if (array_get(imemory, rFDArray, font_index, &f) < 0
3414
0
        || r_type(&f) != t_dictionary)
3415
0
        return_error(gs_error_invalidfont);
3416
3417
0
    op[0] = op[-2];
3418
0
    op[-2] = op[-1];            /* Keep the charstring on ostack for the garbager. */
3419
0
    op[-1] = f;                 /* <font0> <charstring> <subfont> <cid> */
3420
0
    if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0)
3421
0
        return code;
3422
    /* stack: <font0> <charstring> */
3423
3424
0
    lop = osp;
3425
0
    if (code == 5) {
3426
0
        int i, ind = (lop - op);
3427
3428
0
        op = osp;
3429
3430
0
        for (i = ind; i >= 0; i--) {
3431
0
            op[-i - 2] = op[-i];
3432
0
        }
3433
0
        pop(2);
3434
0
    }
3435
0
    else if (code < 0) {        /* <font0> <dirty> <dirty> <dirty> */
3436
        /* Adjust ostack for the correct error handling : */
3437
0
        make_int(op - 2, cid);
3438
0
        pop(2);                 /* <font0> <cid> */
3439
0
    }
3440
0
    else if (code != 5) {       /* <font0> <dirty> */
3441
3442
3443
0
        pop(2);                 /* */
3444
        /*  Note that this releases the charstring, and it may be garbage-collected
3445
           before the interpreter calls fapi_finish_render. This requires the server
3446
           to keep glyph raster internally between calls to get_char_raster_metrics
3447
           and get_char_raster. Perhaps UFST cannot provide metrics without
3448
           building a raster, so this constraint actually goes from UFST.
3449
         */
3450
0
    }
3451
0
    ialloc_set_space(idmemory, s);
3452
0
    return code;
3453
0
}
3454
3455
/* <font> <code> .FAPIBuildChar - */
3456
static int
3457
zFAPIBuildChar(i_ctx_t *i_ctx_p)
3458
1.06M
{
3459
1.06M
    return FAPI_char(i_ctx_p, false, NULL);
3460
1.06M
}
3461
3462
/* non-CID : <font> <code> .FAPIBuildGlyph - */
3463
/*     CID : <font> <name> .FAPIBuildGlyph - */
3464
static int
3465
zFAPIBuildGlyph(i_ctx_t *i_ctx_p)
3466
6
{
3467
6
    return FAPI_char(i_ctx_p, true, NULL);
3468
6
}
3469
3470
3471
/* <font_dict> .FAPIpassfont bool <font_dict> */
3472
/* must insert /FAPI to font dictionary */
3473
static int
3474
zFAPIpassfont(i_ctx_t *i_ctx_p)
3475
10.1k
{
3476
10.1k
    os_ptr op = osp;
3477
10.1k
    gs_font *pfont;
3478
10.1k
    int code;
3479
10.1k
    char *font_file_path = NULL;
3480
10.1k
    ref *v;
3481
10.1k
    char *xlatmap = NULL;
3482
10.1k
    char *fapi_request = NULL;
3483
10.1k
    char *fapi_id = NULL;
3484
10.1k
    ref reqstr;
3485
10.1k
    int subfont;
3486
3487
10.1k
    check_op(1);
3488
    /* Normally embedded fonts have no Path, but if a CID font is
3489
     * emulated with a TT font, and it is hooked with FAPI,
3490
     * the path presents and is neccessary to access the full font data.
3491
     */
3492
10.1k
    check_type(*op, t_dictionary);
3493
3494
10.1k
    code = base_font_param(osp, &pfont);
3495
10.1k
    if (code < 0)
3496
0
        return code;
3497
3498
10.1k
    if (dict_find_string(op, "SubfontId", &v) > 0
3499
0
        && r_has_type(v, t_integer))
3500
0
        subfont = v->value.intval;
3501
10.1k
    else
3502
10.1k
        subfont = 0;
3503
3504
10.1k
    code = FAPI_get_xlatmap(i_ctx_p, &xlatmap); /* Useful for emulated fonts hooked with FAPI. */
3505
10.1k
    if (code < 0)
3506
0
        return code;
3507
3508
    /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us
3509
     * to try to use a specific FAPI plugin, so find it, and try it....
3510
     */
3511
10.1k
    if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) {
3512
3513
0
        name_string_ref(imemory, v, &reqstr);
3514
3515
0
        fapi_request = ref_to_string(&reqstr, imemory, "zFAPIpassfont");
3516
0
    }
3517
3518
10.1k
    if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string))
3519
0
        font_file_path = ref_to_string(v, imemory_global, "font file path");
3520
3521
10.1k
    gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
3522
3523
10.1k
    code =
3524
10.1k
        gs_fapi_passfont(pfont, subfont, font_file_path, NULL, fapi_request, xlatmap,
3525
10.1k
                         &fapi_id, NULL, ps_get_server_param);
3526
3527
10.1k
    if (font_file_path != NULL)
3528
0
        gs_free_string(imemory_global, (byte *) font_file_path, r_size(v) + 1,
3529
10.1k
                       "font file path");
3530
3531
10.1k
    if (fapi_request != NULL)
3532
0
        gs_free_string(imemory, (byte *) fapi_request,
3533
10.1k
                       strlen(fapi_request) + 1, "do_FAPIpassfont");
3534
10.1k
    if (code < 0 && code != gs_error_invalidaccess)
3535
14
        return code;
3536
3537
10.1k
    if (code >= 0 && fapi_id != NULL) {
3538
10.1k
        ref FAPI_ID;
3539
3540
10.1k
        if ((code =
3541
10.1k
             name_ref(imemory, (const byte *)fapi_id,
3542
10.1k
                      strlen(fapi_id), &FAPI_ID, false)) < 0)
3543
0
            return code;
3544
10.1k
        if ((code = dict_put_string(op, "FAPI", &FAPI_ID, NULL)) < 0)
3545
0
            return code;        /* Insert FAPI entry to font dictionary. */
3546
10.1k
    }
3547
10.1k
    push(1);
3548
10.1k
    make_bool(op, (fapi_id != NULL));
3549
10.1k
    return 0;
3550
10.1k
}
3551
3552
const op_def zfapi_op_defs[] = {
3553
    {"1.FAPIavailable", zFAPIavailable},
3554
    {"2.FAPIpassfont", zFAPIpassfont},
3555
    {"2.FAPIrebuildfont", zFAPIrebuildfont},
3556
    {"2.FAPIBuildChar", zFAPIBuildChar},
3557
    {"2.FAPIBuildGlyph", zFAPIBuildGlyph},
3558
    {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9},
3559
    op_def_end(0)
3560
};