Coverage Report

Created: 2026-07-24 07:44

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
585
{
94
585
    ref s;
95
585
    int code;
96
97
585
    if (r->error < 0)
98
0
        return;
99
585
    do {
100
585
      r->index++;
101
585
      code = array_get(r->memory, r->sfnts, r->index, &s);
102
585
        if (code < 0) {
103
28
            r->error = code;
104
28
            return;
105
28
        }
106
557
        if (!r_has_type(&s, t_string)) {
107
12
            r->error = gs_note_error(gs_error_typecheck);
108
12
            return;
109
12
        }
110
545
      r->p = s.value.const_bytes;
111
545
      r->length = r_size(&s) & ~(uint) 1; /* See Adobe Technical Note # 5012, section 4.2. */
112
545
    } while (r->length == 0);
113
545
    r->offset = 0;
114
545
}
115
116
static inline byte
117
sfnts_reader_rbyte_inline(sfnts_reader *r)
118
9.28k
{
119
9.28k
    if (r->offset >= r->length)
120
0
        sfnts_next_elem(r);
121
9.28k
    return ((r->error < 0) ? 0 : r->p[r->offset++]);
122
9.28k
}
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
688
#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
344
{
135
344
    ushort retval;
136
137
344
    retval = SFNTS_READER_RBYTE_TO_USHORT(r) << 8;
138
344
    retval += SFNTS_READER_RBYTE_TO_USHORT(r);
139
140
344
    return retval;
141
344
}
142
143
#undef SFNTS_READER_RBYTE_TO_USHORT
144
145
8.60k
#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
2.15k
{
150
2.15k
    ulong retval;
151
2.15k
    retval = SFNTS_READER_RBYTE_TO_ULONG(r) << 24;
152
2.15k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 16;
153
2.15k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r) << 8;
154
2.15k
    retval += SFNTS_READER_RBYTE_TO_ULONG(r);
155
2.15k
    return retval;
156
2.15k
}
157
158
#undef SFNTS_READER_RWORD_TO_LONG
159
160
static int
161
sfnts_reader_rstring(sfnts_reader *r, byte *v, int length)
162
722
{
163
722
    int rlength = length;
164
165
722
    if (length <= 0)
166
0
        return (0);
167
758
    while (r->error >= 0) {
168
742
        int l = min(length, r->length - r->offset);
169
170
742
        memcpy(v, r->p + r->offset, l);
171
742
        length -= l;
172
742
        r->offset += l;
173
742
        if (length <= 0)
174
706
            return (rlength);
175
36
        v += l;
176
36
        sfnts_next_elem(r);
177
36
    }
178
16
    return (rlength - length);
179
722
}
180
181
static void
182
sfnts_reader_seek(sfnts_reader *r, ulong pos)
183
58
{                               /* fixme : optimize */
184
58
    ulong skipped = 0;
185
186
58
    r->index = -1;
187
58
    sfnts_next_elem(r);
188
463
    while (skipped + r->length < pos && r->error >= 0) {
189
405
        skipped += r->length;
190
405
        sfnts_next_elem(r);
191
405
    }
192
58
    r->offset = pos - skipped;
193
58
}
194
195
static void
196
sfnts_reader_init(const gs_memory_t *mem, sfnts_reader *r, ref *pdr)
197
86
{
198
86
    r->memory = mem;
199
86
    r->rbyte = sfnts_reader_rbyte;
200
86
    r->rword = sfnts_reader_rword;
201
86
    r->rlong = sfnts_reader_rlong;
202
86
    r->rstring = sfnts_reader_rstring;
203
86
    r->seek = sfnts_reader_seek;
204
86
    r->index = -1;
205
86
    r->error = 0;
206
86
    if (r_type(pdr) != t_dictionary ||
207
86
        dict_find_string(pdr, "sfnts", &r->sfnts) <= 0)
208
0
        r->error = gs_error_undefined;
209
86
    sfnts_next_elem(r);
210
86
}
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
6
{
228
6
    if (w->buf + w->buf_size < w->p + 1)
229
0
        return;                 /* safety */
230
6
    w->p[0] = v;
231
6
    w->p++;
232
6
}
233
234
static void
235
sfnts_writer_wword(sfnts_writer *w, ushort v)
236
172
{
237
172
    if (w->buf + w->buf_size < w->p + 2)
238
0
        return;                 /* safety */
239
172
    w->p[0] = v / 256;
240
172
    w->p[1] = v % 256;
241
172
    w->p += 2;
242
172
}
243
244
static void
245
sfnts_writer_wlong(sfnts_writer *w, ulong v)
246
817
{
247
817
    if (w->buf + w->buf_size < w->p + 4)
248
0
        return;                 /* safety */
249
817
    w->p[0] = v >> 24;
250
817
    w->p[1] = (v >> 16) & 0xFF;
251
817
    w->p[2] = (v >> 8) & 0xFF;
252
817
    w->p[3] = v & 0xFF;
253
817
    w->p += 4;
254
817
}
255
256
static void
257
sfnts_writer_wstring(sfnts_writer *w, byte *v, int length)
258
292
{
259
292
    if (w->buf + w->buf_size < w->p + length)
260
0
        return;                 /* safety */
261
292
    memcpy(w->p, v, length);
262
292
    w->p += length;
263
292
}
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
1.09k
{
278
1.09k
    return (memcmp(tag, "glyf", 4) && memcmp(tag, "glyx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
279
964
            memcmp(tag, "loca", 4) && memcmp(tag, "locx", 4) && /* Presents in files created by AdobePS5.dll Version 5.1.2 */
280
832
            memcmp(tag, "cmap", 4));
281
1.09k
}
282
283
static void
284
sfnt_copy_table(sfnts_reader *r, sfnts_writer *w, int length)
285
58
{
286
58
    byte buf[1024];
287
288
92
    while (length > 0 && r->error >= 0) {
289
34
        int l = min(length, sizeof(buf));
290
291
34
        (void)r->rstring(r, buf, l);
292
34
        w->wstring(w, buf, l);
293
34
        length -= l;
294
34
    }
295
58
}
296
297
static int
298
sfnts_copy_except_glyf(sfnts_reader *r, sfnts_writer *w)
299
86
{                               /* Note : TTC is not supported and probably is unuseful for Type 42. */
300
    /* This skips glyf, loca and cmap from copying. */
301
86
    struct
302
86
    {
303
86
        byte tag[4];
304
86
        ulong checkSum, offset, offset_new, length;
305
86
    } tables[40];
306
86
    const ushort alignment = 4; /* Not sure, maybe 2 */
307
86
    ulong version = r->rlong(r);
308
86
    ushort num_tables = r->rword(r);
309
86
    ushort i, num_tables_new = 0;
310
86
    ushort searchRange, entrySelector = 0, rangeShift, v;
311
86
    ulong size_new = 12;
312
313
86
    if (num_tables > countof(tables)) {
314
0
        r->error = gs_note_error(gs_error_invalidfont);
315
0
        return r->error;
316
0
    }
317
318
86
    r->rword(r);                /* searchRange */
319
86
    if (r->error < 0)
320
0
        return r->error;
321
322
86
    r->rword(r);                /* entrySelector */
323
86
    if (r->error < 0)
324
0
        return r->error;
325
326
86
    r->rword(r);                /* rangeShift */
327
86
    if (r->error < 0)
328
0
        return r->error;
329
330
774
    for (i = 0; i < num_tables && r->error >= 0; i++) {
331
688
        (void)r->rstring(r, tables[i].tag, 4);
332
688
        if (r->error < 0)
333
0
            continue;
334
688
        tables[i].checkSum = r->rlong(r);
335
688
        tables[i].offset = r->rlong(r);
336
688
        tables[i].length = r->rlong(r);
337
688
        tables[i].offset_new = size_new;
338
688
        if (sfnts_need_copy_table(tables[i].tag)) {
339
516
            num_tables_new++;
340
516
            size_new +=
341
516
                (tables[i].length + alignment - 1) / alignment * alignment;
342
516
        }
343
688
    }
344
86
    if (r->error < 0)
345
0
        return r->error;
346
86
    size_new += num_tables_new * 16;
347
86
    if (w == 0) {
348
43
        return size_new;
349
43
    }
350
43
    searchRange = v = num_tables_new * 16;
351
344
    for (i = 0; v; i++) {
352
301
        v >>= 1;
353
301
        searchRange |= v;
354
301
        entrySelector++;
355
301
    }
356
43
    searchRange -= searchRange >> 1;
357
43
    rangeShift = num_tables_new * 16 - searchRange;
358
359
43
    w->wlong(w, version);
360
43
    w->wword(w, num_tables_new);
361
43
    w->wword(w, searchRange);
362
43
    w->wword(w, entrySelector);
363
43
    w->wword(w, rangeShift);
364
387
    for (i = 0; i < num_tables; i++) {
365
344
        if (sfnts_need_copy_table(tables[i].tag)) {
366
258
            w->wstring(w, tables[i].tag, 4);
367
258
            w->wlong(w, tables[i].checkSum);
368
258
            w->wlong(w, tables[i].offset_new + num_tables_new * 16);
369
258
            w->wlong(w, tables[i].length);
370
258
        }
371
344
    }
372
107
    for (i = 0; i < num_tables && r->error >= 0; i++) {
373
64
        if (sfnts_need_copy_table(tables[i].tag)) {
374
58
            int k = tables[i].length;
375
376
58
            r->seek(r, tables[i].offset);
377
378
58
            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
58
            sfnt_copy_table(r, w, tables[i].length);
383
64
            for (; k & (alignment - 1); k++)
384
6
                w->wbyte(w, 0);
385
58
        }
386
64
    }
387
43
    if (r->error < 0)
388
40
        return r->error;
389
390
3
    return (size_new);
391
43
}
392
393
static int
394
true_type_size(const gs_memory_t *mem, ref *pdr, unsigned long int *length)
395
43
{
396
43
    sfnts_reader r;
397
398
43
    sfnts_reader_init(mem, &r, pdr);
399
43
    *length = sfnts_copy_except_glyf(&r, 0);
400
401
43
    return r.error;
402
43
}
403
404
static int
405
FAPI_FF_serialize_tt_font(gs_fapi_font *ff, void *buf, int buf_size)
406
43
{
407
43
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
408
43
    sfnts_reader r;
409
43
    sfnts_writer w = sfnts_writer_stub;
410
411
43
    w.buf_size = buf_size;
412
43
    w.buf = w.p = buf;
413
43
    sfnts_reader_init(ff->memory, &r, pdr);
414
43
    return sfnts_copy_except_glyf(&r, &w);
415
43
}
416
417
static inline ushort
418
float_to_ushort(float v)
419
2.59M
{
420
2.59M
    return ((ushort) (v * 16)); /* fixme : the scale may depend on renderer */
421
2.59M
}
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.98M
{
431
4.98M
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
432
4.98M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
433
4.98M
    int code = 0;
434
435
4.98M
    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
82.5k
        case gs_fapi_font_feature_FontType:
452
82.5k
            *ret = (pfont->FontType == 2 ? 2 : 1);
453
82.5k
            break;
454
660k
        case gs_fapi_font_feature_FontBBox:
455
660k
            switch (index) {
456
165k
                case 0:
457
165k
                    *ret = ((ushort) pfont->FontBBox.p.x);
458
165k
                    break;
459
165k
                case 1:
460
165k
                    *ret = ((ushort) pfont->FontBBox.p.y);
461
165k
                    break;
462
165k
                case 2:
463
165k
                    *ret = ((ushort) pfont->FontBBox.q.x);
464
165k
                    break;
465
165k
                case 3:
466
165k
                    *ret = ((ushort) pfont->FontBBox.q.y);
467
165k
                    break;
468
0
                default:
469
0
                    code = gs_note_error(gs_error_rangecheck);
470
660k
            }
471
660k
            break;
472
660k
        case gs_fapi_font_feature_BlueValues_count:
473
165k
            *ret = pfont->data.BlueValues.count;
474
165k
            break;
475
1.27M
        case gs_fapi_font_feature_BlueValues:
476
1.27M
            *ret =  (float_to_ushort(pfont->data.BlueValues.values[index]));
477
1.27M
            break;
478
165k
        case gs_fapi_font_feature_OtherBlues_count:
479
165k
            *ret = pfont->data.OtherBlues.count;
480
165k
            break;
481
0
        case gs_fapi_font_feature_OtherBlues:
482
0
            *ret = (float_to_ushort(pfont->data.OtherBlues.values[index]));
483
0
            break;
484
165k
        case gs_fapi_font_feature_FamilyBlues_count:
485
165k
            *ret = pfont->data.FamilyBlues.count;
486
165k
            break;
487
0
        case gs_fapi_font_feature_FamilyBlues:
488
0
            *ret = (float_to_ushort(pfont->data.FamilyBlues.values[index]));
489
0
            break;
490
165k
        case gs_fapi_font_feature_FamilyOtherBlues_count:
491
165k
            *ret = pfont->data.FamilyOtherBlues.count;
492
165k
            break;
493
0
        case gs_fapi_font_feature_FamilyOtherBlues:
494
0
            *ret = (float_to_ushort(pfont->data.FamilyOtherBlues.values[index]));
495
0
            break;
496
165k
        case gs_fapi_font_feature_BlueShift:
497
165k
            *ret = float_to_ushort(pfont->data.BlueShift);
498
165k
            break;
499
165k
        case gs_fapi_font_feature_BlueFuzz:
500
165k
            *ret = float_to_ushort(pfont->data.BlueShift);
501
165k
            break;
502
165k
        case gs_fapi_font_feature_StdHW:
503
165k
            *ret = (pfont->data.StdHW.count == 0 ? 0 : float_to_ushort(pfont->data.StdHW.values[0]));   /* UFST bug ? */
504
165k
            break;
505
165k
        case gs_fapi_font_feature_StdVW:
506
165k
            *ret = (pfont->data.StdVW.count == 0 ? 0 : float_to_ushort(pfont->data.StdVW.values[0]));   /* UFST bug ? */
507
165k
            break;
508
165k
        case gs_fapi_font_feature_StemSnapH_count:
509
165k
            *ret = pfont->data.StemSnapH.count;
510
165k
            break;
511
330k
        case gs_fapi_font_feature_StemSnapH:
512
330k
            *ret = float_to_ushort(pfont->data.StemSnapH.values[index]);
513
330k
            break;
514
165k
        case gs_fapi_font_feature_StemSnapV_count:
515
165k
            *ret = pfont->data.StemSnapV.count;
516
165k
            break;
517
327k
        case gs_fapi_font_feature_StemSnapV:
518
327k
            *ret = float_to_ushort(pfont->data.StemSnapV.values[index]);
519
327k
            break;
520
165k
        case gs_fapi_font_feature_ForceBold:
521
165k
            *ret = pfont->data.ForceBold;
522
165k
            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
165k
        case gs_fapi_font_feature_Subrs_count:
549
165k
            {
550
165k
                ref *Private, *Subrs;
551
552
165k
                if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0) {
553
0
                    *ret = 0;
554
0
                    break;
555
0
                }
556
165k
                if (dict_find_string_with_type(Private, "Subrs", &Subrs, t_array) <= 0) {
557
0
                    *ret = 0;
558
0
                    break;
559
0
                }
560
165k
                *ret = r_size(Subrs);
561
165k
                break;
562
165k
            }
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
165k
            }
573
            /* Multiple Master specific */
574
330k
        case gs_fapi_font_feature_DollarBlend:
575
330k
            {
576
330k
                ref *DBlend;
577
578
330k
                if (dict_find_string(pdr, "$Blend", &DBlend) <= 0)
579
330k
                    *ret = 0;
580
4
                else
581
4
                    *ret = 1;
582
330k
                break;
583
165k
            }
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.98M
    }
1390
4.98M
    return code;
1391
4.98M
}
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
165k
{
1396
165k
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1397
165k
    int code = 0;
1398
1399
165k
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1400
1401
165k
    switch ((int)var_id) {
1402
0
        case gs_fapi_font_feature_UniqueID:
1403
0
            *ret = pfont->UID.id;
1404
0
            break;
1405
165k
        case gs_fapi_font_feature_BlueScale:
1406
165k
            *ret = (ulong) (pfont->data.BlueScale * 65536);
1407
165k
            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
43
        case gs_fapi_font_feature_TT_size:
1432
43
            code = true_type_size(ff->memory, pdr, ret);
1433
43
            break;
1434
165k
    }
1435
165k
    return code;
1436
165k
}
1437
1438
static int
1439
FAPI_FF_get_float(gs_fapi_font *ff, gs_fapi_font_feature var_id, int index, float *ret)
1440
990k
{
1441
990k
    gs_font_type1 *pfont1 = (gs_font_type1 *) ff->client_font_data;
1442
990k
    gs_font_base *pbfont = (gs_font_base *) ff->client_font_data2;
1443
990k
    ref *pdr = pfont_dict(pbfont);
1444
990k
    int code = 0;
1445
990k
    gs_fapi_server *I = pbfont->FAPI;
1446
1447
990k
    switch ((int)var_id) {
1448
990k
        case gs_fapi_font_feature_FontMatrix:
1449
990k
            {
1450
990k
                double FontMatrix_div;
1451
990k
                gs_matrix m, *mptr;
1452
1453
990k
                if (I && I->get_fontmatrix) {
1454
990k
                    FontMatrix_div = 1;
1455
990k
                    mptr = &m;
1456
990k
                    I->get_fontmatrix(I, mptr);
1457
990k
                }
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
990k
                switch (index) {
1465
165k
                    case 0:
1466
165k
                    default:
1467
165k
                        *ret = (mptr->xx / FontMatrix_div);
1468
165k
                        break;
1469
165k
                    case 1:
1470
165k
                        *ret = (mptr->xy / FontMatrix_div);
1471
165k
                        break;
1472
165k
                    case 2:
1473
165k
                        *ret = (mptr->yx / FontMatrix_div);
1474
165k
                        break;
1475
165k
                    case 3:
1476
165k
                        *ret = (mptr->yy / FontMatrix_div);
1477
165k
                        break;
1478
165k
                    case 4:
1479
165k
                        *ret = (mptr->tx / FontMatrix_div);
1480
165k
                        break;
1481
165k
                    case 5:
1482
165k
                        *ret = (mptr->ty / FontMatrix_div);
1483
165k
                        break;
1484
990k
                }
1485
990k
                break;
1486
990k
            }
1487
1488
990k
        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
990k
    }
1595
990k
    return code;
1596
990k
}
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.73M
{
1708
1.73M
    ushort state = 4330;
1709
1710
157M
    for (; l; s++, l--) {
1711
155M
        uchar c = (*s ^ (state >> 8));
1712
1713
155M
        state = (*s + state) * crypt_c1 + crypt_c2;
1714
155M
        if (lenIV > 0)
1715
6.95M
            lenIV--;
1716
148M
        else {
1717
148M
            *p = c;
1718
148M
            p++;
1719
148M
        }
1720
155M
    }
1721
1.73M
}
1722
1723
static int
1724
get_type1_data(gs_fapi_font *ff, const ref *type1string,
1725
               byte *buf, int buf_length)
1726
2.56M
{
1727
2.56M
    gs_font_type1 *pfont = (gs_font_type1 *) ff->client_font_data;
1728
2.56M
    int lenIV = max(pfont->data.lenIV, 0);
1729
2.56M
    int length = r_size(type1string) - (ff->need_decrypt ? lenIV : 0);
1730
1731
2.56M
    if (buf != 0) {
1732
1.73M
        int l = min(length, buf_length);        /*safety */
1733
1734
1.73M
        if (ff->need_decrypt && pfont->data.lenIV >= 0)
1735
1.73M
            decode_bytes(buf, type1string->value.const_bytes, l + lenIV,
1736
1.73M
                         lenIV);
1737
0
        else
1738
0
            memcpy(buf, type1string->value.const_bytes, l);
1739
1.73M
    }
1740
2.56M
    return length;
1741
2.56M
}
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.23M
{
1762
1.23M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
1763
1.23M
    ref *Private, *Subrs, subr;
1764
1765
1.23M
    if (dict_find_string_with_type(pdr, "Private", &Private, t_dictionary) <= 0)
1766
0
        return 0;
1767
1.23M
    if (dict_find_string_with_type(Private, "Subrs", &Subrs, t_array) <= 0)
1768
0
        return 0;
1769
1.23M
    if (array_get_with_type(ff->memory, Subrs, index, &subr, t_string) < 0)
1770
0
        return 0;
1771
1.23M
    return (get_type1_data(ff, &subr, buf, buf_length));
1772
1.23M
}
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.32M
{
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.32M
    ref *pdr = pfont_dict(((gs_font_base *) ff->client_font_data2));
2028
2029
1.32M
    int glyph_length;
2030
1.32M
    i_ctx_t *i_ctx_p = (i_ctx_t *) ff->client_ctx_p;
2031
2032
1.32M
    if (ff->is_type1) {
2033
1.32M
        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.32M
        else {
2043
1.32M
            ref *CharStrings, *CFFCharStrings, char_name, *glyph;
2044
2045
1.32M
            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.32M
                if (name_ref(ff->memory, ff->char_data,
2052
1.32M
                             ff->char_data_len, &char_name, -1) < 0)
2053
0
                    return gs_fapi_glyph_invalid_format;
2054
1.32M
                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.32M
                    ff->char_data = NULL;
2061
1.32M
                }
2062
1.32M
            }
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.32M
            if (dict_find_string_with_type(pdr, "CharStrings", &CharStrings, t_dictionary) <= 0)
2075
0
                return gs_fapi_glyph_invalid_format;
2076
2077
1.32M
            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.32M
            if (r_has_type(glyph, t_array) || r_has_type(glyph, t_mixedarray))
2087
0
                return gs_fapi_glyph_invalid_format;
2088
2089
1.32M
            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.32M
            if (!r_has_type(glyph, t_string))
2103
0
                return 0;
2104
1.32M
            glyph_length = get_type1_data(ff, glyph, buf, buf_length);
2105
1.32M
        }
2106
1.32M
    }
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
                    else
2155
0
                        glyph_length = gs_fapi_glyph_invalid_index;
2156
0
                }
2157
0
                else {
2158
0
                    ulong noffs, endoffs;
2159
                    /* If we haven't got a len_glyphs array, try using the offset of the next glyph offset
2160
                     * to work out the length
2161
                     */
2162
0
                    error = sfnt_get_glyph_offset(pdr, pfont42, char_code + 1, &noffs);
2163
0
                    if (error == 0) {
2164
0
                        glyph_length = noffs - offset0;
2165
0
                        error = sfnt_get_sfnt_length(pdr, &endoffs);
2166
0
                        if (error < 0) {
2167
0
                            glyph_length = gs_fapi_glyph_invalid_index;
2168
0
                        }
2169
0
                        else {
2170
0
                            if (glyph_length + offset0 > endoffs) {
2171
0
                                glyph_length = gs_fapi_glyph_invalid_index;
2172
0
                            }
2173
0
                        }
2174
0
                    }
2175
0
                    else {
2176
                        /* And if we can't get the next glyph offset, use the end of the sfnt data
2177
                         * to work out the length.
2178
                         */
2179
0
                        error = sfnt_get_sfnt_length(pdr, &noffs);
2180
0
                        if (error < 0) {
2181
0
                            glyph_length = gs_fapi_glyph_invalid_index;
2182
0
                        }
2183
0
                        else {
2184
0
                            glyph_length = noffs - offset0;
2185
0
                        }
2186
0
                    }
2187
0
                }
2188
2189
0
                if (buf != 0 && !error) {
2190
0
                    sfnts_reader r;
2191
2192
0
                    sfnts_reader_init(pfont42->memory, &r, pdr);
2193
2194
0
                    r.seek(&r, offset0);
2195
0
                    length_read =
2196
0
                        r.rstring(&r, buf,
2197
0
                                  min(glyph_length,
2198
0
                                      buf_length) /* safety */ );
2199
0
                    if (r.error == 1) {
2200
0
                        glyph_length = gs_fapi_glyph_invalid_index;
2201
0
                    }
2202
                    /* r.error == 2 means a rangecheck, and probably means that the
2203
                     * font is broken, and the final glyph length is longer than the data available for it.
2204
                     * In which case we need to return the number of bytes read.
2205
                     */
2206
0
                    if (r.error == 2) {
2207
0
                        glyph_length = length_read;
2208
0
                    }
2209
0
                }
2210
0
            }
2211
0
        }
2212
0
    }
2213
1.32M
    return glyph_length;
2214
1.32M
}
2215
2216
static int
2217
ps_fapi_get_metrics(gs_fapi_font *ff, gs_string *char_name, gs_glyph cid, double *m, bool vertical)
2218
1.31M
{
2219
1.31M
    ref glyph;
2220
1.31M
    int code;
2221
1.31M
    gs_font_base *pbfont = ((gs_font_base *) ff->client_font_data2);
2222
2223
1.31M
    if (char_name->data != NULL) {
2224
1.31M
        make_string(&glyph, avm_foreign | a_readonly, char_name->size, char_name->data);
2225
1.31M
    }
2226
0
    else {
2227
0
        make_int(&glyph, cid);
2228
0
    }
2229
2230
1.31M
    if (vertical) {
2231
0
        code = zchar_get_metrics2(pbfont, &glyph, m);
2232
0
    }
2233
1.31M
    else {
2234
1.31M
        code = zchar_get_metrics(pbfont, &glyph, m);
2235
1.31M
    }
2236
2237
1.31M
    make_null(&glyph);
2238
2239
1.31M
    return (code);
2240
1.31M
}
2241
2242
2243
/* forward declaration for the ps_ff_stub assignment */
2244
static int ps_get_glyphname_or_cid(gs_text_enum_t *penum,
2245
                                   gs_font_base *pbfont,
2246
                                   gs_string *charstring, gs_string *name,
2247
                                   gs_glyph ccode, gs_string *enc_char_name,
2248
                                   char *font_file_path,
2249
                                   gs_fapi_char_ref *cr, bool bCID);
2250
2251
static int ps_fapi_set_cache(gs_text_enum_t *penum,
2252
                             const gs_font_base *pbfont,
2253
                             const gs_string *char_name, gs_glyph cid,
2254
                             const double pwidth[2], const gs_rect *pbbox,
2255
                             const double Metrics2_sbw_default[4],
2256
                             bool *imagenow);
2257
2258
static const gs_fapi_font ps_ff_stub = {
2259
    0,                          /* server_font_data */
2260
    0,                          /* need_decrypt */
2261
    NULL,                       /* const gs_memory_t */
2262
    0,                          /* font_file_path */
2263
    0,                          /* full_font_buf */
2264
    0,                          /* full_font_buf_len */
2265
    0,                          /* subfont */
2266
    false,                      /* is_type1 */
2267
    false,                      /* is_cid */
2268
    false,                      /* is_outline_font */
2269
    false,                      /* is_mtx_skipped */
2270
    false,                      /* is_vertical */
2271
    false,                      /* metrics_only */
2272
    {{-1, -1}},                 /* ttf_cmap_req */
2273
    {-1, -1},                   /* ttf_cmap_selected */
2274
    0,                          /* client_ctx_p */
2275
    0,                          /* client_font_data */
2276
    0,                          /* client_font_data2 */
2277
    0,                          /* char_data */
2278
    0,                          /* char_data_len */
2279
    0,                          /* embolden */
2280
    FAPI_FF_get_word,
2281
    FAPI_FF_get_long,
2282
    FAPI_FF_get_float,
2283
    FAPI_FF_get_name,
2284
    FAPI_FF_get_proc,
2285
    FAPI_FF_get_gsubr,
2286
    FAPI_FF_get_subr,
2287
    FAPI_FF_get_raw_subr,
2288
    FAPI_FF_get_glyph,
2289
    FAPI_FF_serialize_tt_font,
2290
    NULL,                       /* retrieve_tt_font */
2291
    FAPI_FF_get_charstring,
2292
    FAPI_FF_get_charstring_name,
2293
    ps_get_GlyphDirectory_data_ptr,
2294
    ps_get_glyphname_or_cid,
2295
    ps_fapi_get_metrics,
2296
    ps_fapi_set_cache
2297
};
2298
2299
static int
2300
FAPI_get_xlatmap(i_ctx_t *i_ctx_p, char **xlatmap)
2301
12.2k
{
2302
12.2k
    ref *pref;
2303
12.2k
    int code;
2304
2305
12.2k
    if ((code = dict_find_string(systemdict, ".xlatmap", &pref)) < 0)
2306
0
        return code;
2307
12.2k
    if (code == 0)
2308
0
        return_error(gs_error_undefined);
2309
2310
12.2k
    if (r_type(pref) != t_string)
2311
0
        return_error(gs_error_typecheck);
2312
12.2k
    *xlatmap = (char *)pref->value.bytes;
2313
    /*  Note : this supposes that xlatmap doesn't move in virtual memory.
2314
       Garbager must not be called while plugin executes get_scaled_font, get_decodingID.
2315
       Fix some day with making copy of xlatmap in system memory.
2316
     */
2317
12.2k
    return 0;
2318
12.2k
}
2319
2320
static int
2321
renderer_retcode(gs_memory_t *mem, gs_fapi_server *I, gs_fapi_retcode rc)
2322
0
{
2323
0
    if (rc == 0)
2324
0
        return 0;
2325
0
    emprintf2(mem,
2326
0
              "Error: Font Renderer Plugin ( %s ) return code = %d\n",
2327
0
              I->ig.d->subtype, rc);
2328
0
    return rc < 0 ? rc : gs_error_invalidfont;
2329
0
}
2330
2331
/* <server name>/<null> object .FAPIavailable bool */
2332
static int
2333
zFAPIavailable(i_ctx_t *i_ctx_p)
2334
348k
{
2335
348k
    os_ptr op = osp;
2336
348k
    char *serv_name = NULL;
2337
348k
    ref name_ref;
2338
2339
348k
    check_op(1);
2340
348k
    if (r_has_type(op, t_name)) {
2341
174k
        name_string_ref(imemory, op, &name_ref);
2342
2343
174k
        serv_name =
2344
174k
            (char *) ref_to_string(&name_ref, imemory, "zFAPIavailable");
2345
174k
        if (!serv_name) {
2346
0
            return_error(gs_error_VMerror);
2347
0
        }
2348
174k
    }
2349
2350
348k
    make_bool(op, gs_fapi_available(imemory, serv_name));
2351
2352
348k
    if (serv_name) {
2353
174k
        gs_free_string(imemory, (byte *) serv_name,
2354
174k
                       strlen((char *)serv_name) + 1, "zFAPIavailable");
2355
174k
    }
2356
348k
    return (0);
2357
348k
}
2358
2359
static int
2360
ps_get_server_param(gs_fapi_server *I, const char *subtype, char **server_param, int *server_param_size)
2361
2362
82.5k
{
2363
82.5k
    ref *FAPIconfig, *options, *server_options;
2364
82.5k
    i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
2365
2366
82.5k
    if (dict_find_string(systemdict, ".FAPIconfig", &FAPIconfig) > 0
2367
82.5k
        && r_has_type(FAPIconfig, t_dictionary)) {
2368
82.5k
        if (dict_find_string(FAPIconfig, "ServerOptions", &options) > 0
2369
82.5k
            && r_has_type(options, t_dictionary)) {
2370
82.5k
            if (dict_find_string(options, (char *)subtype, &server_options) >
2371
82.5k
                0 && r_has_type(server_options, t_string)) {
2372
0
                *server_param = (char *) server_options->value.const_bytes;
2373
0
                *server_param_size = r_size(server_options);
2374
0
            }
2375
82.5k
        }
2376
82.5k
    }
2377
82.5k
    return 1;
2378
82.5k
}
2379
2380
static inline int
2381
base_font_param(const ref *pfdict, gs_font **ppfont)
2382
1.15M
{
2383
1.15M
    int code = font_param(pfdict, ppfont);
2384
1.15M
    if (code >= 0 && (*ppfont)->FontType == ft_composite) {
2385
0
        code = gs_note_error(gs_error_invalidfont);
2386
0
    }
2387
1.15M
    return code;
2388
1.15M
}
2389
2390
static int
2391
FAPI_refine_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font *pfont,
2392
                 int subfont, const char *font_file_path)
2393
82.5k
{
2394
82.5k
    ref *pdr = op;              /* font dict */
2395
82.5k
    const char *decodingID = NULL;
2396
82.5k
    char *xlatmap = NULL;
2397
82.5k
    gs_font_base *pbfont = (gs_font_base *)pfont;
2398
82.5k
    gs_fapi_server *I = pbfont->FAPI;
2399
82.5k
    ref *Decoding_old;
2400
82.5k
    int code;
2401
2402
82.5k
    if (font_file_path != NULL && pbfont->FAPI_font_data == NULL)
2403
0
        if ((code = FAPI_get_xlatmap(i_ctx_p, &xlatmap)) < 0)
2404
0
            return code;
2405
2406
82.5k
    gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
2407
2408
82.5k
    code =
2409
82.5k
        gs_fapi_prepare_font(pfont, I, subfont, font_file_path,
2410
82.5k
                             NULL, xlatmap, &decodingID);
2411
82.5k
    if (code < 0)
2412
0
        return code;
2413
2414
82.5k
    if (code > 0) {
2415
        /* save refined FontBBox back to PS world */
2416
0
        ref *v, mat[4], arr;
2417
0
        int attrs;
2418
2419
0
        if (dict_find_string(op, "FontBBox", &v) > 0) {
2420
0
            if (!r_has_type(v, t_array) && !r_has_type(v, t_shortarray)
2421
0
                && !r_has_type(v, t_mixedarray))
2422
0
                return_error(gs_error_invalidfont);
2423
0
            make_real(&mat[0], pbfont->FontBBox.p.x);
2424
0
            make_real(&mat[1], pbfont->FontBBox.p.y);
2425
0
            make_real(&mat[2], pbfont->FontBBox.q.x);
2426
0
            make_real(&mat[3], pbfont->FontBBox.q.y);
2427
0
            if (r_has_type(v, t_shortarray) || r_has_type(v, t_mixedarray)
2428
0
                || r_size(v) < 4) {
2429
                /* Create a new full blown array in case the values are reals */
2430
0
                code = ialloc_ref_array(&arr, a_all, 4, "array");
2431
0
                if (code < 0)
2432
0
                    return code;
2433
0
                v = &arr;
2434
0
                code = idict_put_string(op, "FontBBox", &arr);
2435
0
                if (code < 0)
2436
0
                    return code;
2437
0
                ref_assign_new(v->value.refs + 0, &mat[0]);
2438
0
                ref_assign_new(v->value.refs + 1, &mat[1]);
2439
0
                ref_assign_new(v->value.refs + 2, &mat[2]);
2440
0
                ref_assign_new(v->value.refs + 3, &mat[3]);
2441
0
            }
2442
0
            else {
2443
0
                ref_assign_old(v, v->value.refs + 0, &mat[0],
2444
0
                               "FAPI_refine_font_BBox");
2445
0
                ref_assign_old(v, v->value.refs + 1, &mat[1],
2446
0
                               "FAPI_refine_font_BBox");
2447
0
                ref_assign_old(v, v->value.refs + 2, &mat[2],
2448
0
                               "FAPI_refine_font_BBox");
2449
0
                ref_assign_old(v, v->value.refs + 3, &mat[3],
2450
0
                               "FAPI_refine_font_BBox");
2451
0
            }
2452
0
            attrs = v->tas.type_attrs;
2453
0
            r_clear_attrs(v, a_all);
2454
0
            r_set_attrs(v, attrs | a_execute);
2455
0
        }
2456
0
    }
2457
2458
    /* Assign a Decoding : */
2459
82.5k
    if (decodingID != 0 && *decodingID
2460
0
        && dict_find_string(pdr, "Decoding", &Decoding_old) <= 0) {
2461
0
        ref Decoding;
2462
2463
0
        if (FAPI_ISCIDFONT(pbfont)) {
2464
0
            ref *CIDSystemInfo, *Ordering, SubstNWP;
2465
0
            byte buf[30];
2466
0
            int ordering_length, decodingID_length =
2467
0
                min(strlen(decodingID), sizeof(buf) - 2);
2468
2469
0
            if (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) <= 0
2470
0
                || !r_has_type(CIDSystemInfo, t_dictionary))
2471
0
                return_error(gs_error_invalidfont);
2472
2473
0
            if (dict_find_string(CIDSystemInfo, "Ordering", &Ordering) <= 0
2474
0
                || !r_has_type(Ordering, t_string)) {
2475
0
                return_error(gs_error_invalidfont);
2476
0
            }
2477
2478
0
            ordering_length =
2479
0
                min(r_size(Ordering), sizeof(buf) - 2 - decodingID_length);
2480
0
            memcpy(buf, Ordering->value.const_bytes, ordering_length);
2481
0
            if ((code =
2482
0
                 name_ref(imemory, buf, ordering_length, &SubstNWP, 0)) < 0)
2483
0
                return code;
2484
0
            if ((code =
2485
0
                 dict_put_string(pdr, "SubstNWP", &SubstNWP, NULL)) < 0)
2486
0
                return code;
2487
0
            buf[ordering_length] = '.';
2488
0
            memcpy(buf + ordering_length + 1, decodingID, decodingID_length);
2489
0
            buf[decodingID_length + 1 + ordering_length] = 0;   /* Debug purpose only */
2490
0
            if ((code = name_ref(imemory, buf,
2491
0
                                 decodingID_length + 1 + ordering_length,
2492
0
                                 &Decoding, 0)) < 0)
2493
0
                return code;
2494
0
        }
2495
0
        else if ((code = name_ref(imemory, (const byte *)decodingID,
2496
0
                                  strlen(decodingID), &Decoding, 0)) < 0)
2497
0
            return code;
2498
0
        if ((code = dict_put_string(pdr, "Decoding", &Decoding, NULL)) < 0)
2499
0
            return code;
2500
0
    }
2501
82.5k
    return 0;
2502
82.5k
}
2503
2504
/*  <string|name> <font> <is_disk_font> .rebuildfontFAPI <string|name> <font> */
2505
/*  Rebuild a font for handling it with an external renderer.
2506
2507
    The font was built as a native GS font to allow easy access
2508
    to font features. Then zFAPIrebuildfont sets FAPI entry
2509
    into gx_font_base and replaces BuildGlyph and BuildChar
2510
    to enforce the FAPI handling.
2511
2512
    This operator must not be called with devices which embed fonts.
2513
2514
*/
2515
static int
2516
zFAPIrebuildfont(i_ctx_t *i_ctx_p)
2517
82.5k
{
2518
82.5k
    os_ptr op = osp;
2519
82.5k
    build_proc_refs build;
2520
82.5k
    gs_font *pfont;
2521
82.5k
    int code;
2522
82.5k
    gs_font_base *pbfont;
2523
82.5k
    ref *v;
2524
82.5k
    char *font_file_path = NULL;
2525
82.5k
    char FAPI_ID[20];
2526
82.5k
    const byte *pchars;
2527
82.5k
    uint len;
2528
82.5k
    font_data *pdata;
2529
82.5k
    gs_fapi_server *I;
2530
82.5k
    bool has_buildglyph;
2531
82.5k
    bool has_buildchar;
2532
82.5k
    int subfont;
2533
2534
82.5k
    check_op(3);
2535
82.5k
    code = base_font_param(op - 1, &pfont);
2536
82.5k
    if (code < 0)
2537
0
        return code;
2538
2539
82.5k
    pbfont = (gs_font_base *) pfont;
2540
2541
82.5k
    check_type(*op, t_boolean);
2542
    /* If someone has copied the font dictionary, we may still
2543
     * have the FAPI entry in the dict, but not have the FAPI
2544
     * server assigned in the font object.
2545
     */
2546
82.5k
    if (pbfont->FAPI == NULL) {
2547
70.3k
        if (dict_find_string(op - 1, "FAPI", &v) <= 0
2548
70.3k
            || !r_has_type(v, t_name))
2549
0
            return_error(gs_error_invalidfont);
2550
70.3k
        obj_string_data(imemory, v, &pchars, &len);
2551
70.3k
        len = min(len, sizeof(FAPI_ID) - 1);
2552
70.3k
        strncpy((char *)FAPI_ID, (const char *)pchars, len);
2553
70.3k
        FAPI_ID[len] = 0;
2554
2555
70.3k
        gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
2556
2557
70.3k
        code =
2558
70.3k
            gs_fapi_find_server(imemory, FAPI_ID,
2559
70.3k
                                (gs_fapi_server **) & (pbfont->FAPI), ps_get_server_param);
2560
70.3k
        if (!pbfont->FAPI || code < 0) {
2561
0
            return_error(gs_error_invalidfont);
2562
0
        }
2563
70.3k
    }
2564
2565
82.5k
    pdata = (font_data *) pfont->client_data;
2566
82.5k
    I = pbfont->FAPI;
2567
2568
82.5k
    if (dict_find_string((op - 1), "SubfontId", &v) > 0
2569
0
        && r_has_type(v, t_integer))
2570
0
        subfont = v->value.intval;
2571
82.5k
    else
2572
82.5k
        subfont = 0;
2573
2574
2575
82.5k
    if (r_type(&(pdata->BuildGlyph)) != t_null) {
2576
82.5k
        has_buildglyph = true;
2577
82.5k
    }
2578
0
    else {
2579
0
        has_buildglyph = false;
2580
0
    }
2581
2582
82.5k
    if (r_type(&(pdata->BuildChar)) != t_null) {
2583
82.5k
        has_buildchar = true;
2584
82.5k
    }
2585
1
    else {
2586
1
        has_buildchar = false;
2587
1
    }
2588
2589
    /* This shouldn't happen, but just in case */
2590
82.5k
    if (has_buildglyph == false && has_buildchar == false) {
2591
0
        has_buildglyph = true;
2592
0
    }
2593
2594
82.5k
    if (dict_find_string(op - 1, "Path", &v) <= 0 || !r_has_type(v, t_string)) {
2595
82.5k
        v = NULL;
2596
82.5k
    }
2597
2598
82.5k
    if (pfont->FontType == ft_CID_encrypted && v == NULL) {
2599
1
        if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildGlyph9",
2600
1
                                         ".FAPIBuildGlyph9")) < 0) {
2601
0
            return code;
2602
0
        }
2603
1
    }
2604
82.5k
    else {
2605
82.5k
        if ((code = build_proc_name_refs(imemory, &build, ".FAPIBuildChar",
2606
82.5k
                                         ".FAPIBuildGlyph")) < 0) {
2607
0
            return code;
2608
0
        }
2609
82.5k
    }
2610
2611
82.5k
    if (!
2612
82.5k
        ((r_type(&(pdata->BuildChar)) != t_null
2613
82.5k
          && pdata->BuildChar.value.pname && build.BuildChar.value.pname
2614
82.5k
          && name_index(imemory, &pdata->BuildChar) == name_index(imemory,
2615
82.5k
                                                                  &build.
2616
82.5k
                                                                  BuildChar))
2617
82.5k
         || (r_type(&(pdata->BuildGlyph)) != t_null
2618
82.5k
             && pdata->BuildGlyph.value.pname && build.BuildGlyph.value.pname
2619
82.5k
             && name_index(imemory, &pdata->BuildGlyph) == name_index(imemory,
2620
82.5k
                                                                      &build.
2621
82.5k
                                                                      BuildGlyph))))
2622
82.5k
    {
2623
2624
82.5k
        if (has_buildchar == true) {
2625
82.5k
            ref_assign_new(&pdata->BuildChar, &build.BuildChar);
2626
82.5k
        }
2627
1
        else {
2628
1
            make_null(&pdata->BuildChar);
2629
1
        }
2630
2631
82.5k
        if (has_buildglyph == true) {
2632
82.5k
            ref_assign_new(&pdata->BuildGlyph, &build.BuildGlyph);
2633
82.5k
        }
2634
0
        else {
2635
0
            make_null(&pdata->BuildGlyph);
2636
0
        }
2637
82.5k
        if (v != NULL) {
2638
0
            font_file_path =
2639
0
                ref_to_string(v, imemory_global, "font file path");
2640
0
        }
2641
2642
82.5k
        code =
2643
82.5k
            FAPI_refine_font(i_ctx_p, op - 1, pfont, subfont,
2644
82.5k
                             font_file_path);
2645
2646
82.5k
        memcpy(&I->initial_FontMatrix, &pbfont->FontMatrix,
2647
82.5k
               sizeof(gs_matrix));
2648
2649
82.5k
        if (font_file_path != NULL) {
2650
0
            gs_free_string(imemory_global, (byte *) font_file_path,
2651
0
                           r_size(v) + 1, "font file path");
2652
0
        }
2653
82.5k
    }
2654
82.5k
    pop(1);
2655
82.5k
    return code;
2656
82.5k
}
2657
2658
static ulong
2659
array_find(const gs_memory_t *mem, ref *Encoding, ref *char_name)
2660
0
{
2661
0
    ulong n = r_size(Encoding), i;
2662
0
    ref v;
2663
2664
0
    for (i = 0; i < n; i++)
2665
0
        if (array_get(mem, Encoding, i, &v) < 0)
2666
0
            break;
2667
0
        else if (r_type(char_name) == r_type(&v)
2668
0
                 && char_name->value.const_pname == v.value.const_pname)
2669
0
            return i;
2670
0
    return 0;
2671
0
}
2672
2673
static int
2674
zfapi_finish_render(i_ctx_t *i_ctx_p)
2675
0
{
2676
0
    os_ptr op = osp;
2677
0
    gs_font *pfont;
2678
0
    int code = base_font_param(op - 1, &pfont);
2679
2680
0
    if (code == 0) {
2681
0
        gs_font_base *pbfont = (gs_font_base *) pfont;
2682
0
        gs_fapi_server *I = pbfont->FAPI;
2683
0
        gs_text_enum_t *penum = op_show_find(i_ctx_p);
2684
2685
0
        gs_fapi_set_servers_client_data(imemory, NULL, i_ctx_p);
2686
2687
0
        code = gs_fapi_finish_render(pfont, igs, penum, I);
2688
0
        pop(2);
2689
0
        I->release_char_data(I);
2690
0
    }
2691
0
    return code;
2692
0
}
2693
2694
static int
2695
ps_fapi_set_cache(gs_text_enum_t *penum, const gs_font_base *pbfont,
2696
                  const gs_string *char_name, gs_glyph cid,
2697
                  const double pwidth[2], const gs_rect *pbbox,
2698
                  const double Metrics2_sbw_default[4], bool *imagenow)
2699
1.05M
{
2700
1.05M
    i_ctx_t *i_ctx_p = (i_ctx_t *) pbfont->FAPI->client_ctx_p;
2701
1.05M
    op_proc_t exec_cont = 0;    /* dummy - see below */
2702
1.05M
    int code = 0;
2703
2704
1.05M
    if (cid < GS_MIN_CID_GLYPH) {
2705
1.05M
        ref cname;
2706
2707
1.05M
        make_string(&cname, avm_foreign | a_readonly, char_name->size,
2708
1.05M
                    char_name->data);
2709
1.05M
        code =
2710
1.05M
            zchar_set_cache(i_ctx_p, pbfont, &cname, NULL, pwidth, pbbox,
2711
1.05M
                            zfapi_finish_render, &exec_cont,
2712
1.05M
                            Metrics2_sbw_default);
2713
1.05M
    }
2714
0
    else {
2715
0
        ref cidref;
2716
2717
0
        make_int(&cidref, (cid - GS_MIN_CID_GLYPH));
2718
0
        code = zchar_set_cache(i_ctx_p, pbfont, &cidref, NULL, pwidth, pbbox,
2719
0
                               zfapi_finish_render, &exec_cont,
2720
0
                               Metrics2_sbw_default);
2721
0
    }
2722
2723
1.05M
    if (code >= 0 && exec_cont != NULL) {
2724
1.05M
        *imagenow = true;
2725
1.05M
    }
2726
3.53k
    else {
2727
3.53k
        *imagenow = false;
2728
3.53k
    }
2729
    /* We ignore the value of exec_cont here, and leave it up to
2730
     * gs_fapi_do_char() to do the "right" thing based on the
2731
     * return value
2732
     */
2733
1.05M
    return (code);
2734
1.05M
}
2735
2736
2737
static const byte *
2738
find_substring(const byte *where, int length, const char *what)
2739
0
{
2740
0
    int l = strlen(what);
2741
0
    int n = length - l;
2742
0
    const byte *p = where;
2743
2744
0
    for (; n >= 0; n--, p++)
2745
0
        if (!memcmp(p, what, l))
2746
0
            return p;
2747
0
    return NULL;
2748
0
}
2749
2750
static int
2751
ps_get_glyphname_or_cid(gs_text_enum_t *penum,
2752
                        gs_font_base *pbfont, gs_string *charstring,
2753
                        gs_string *name, gs_glyph ccode,
2754
                        gs_string *enc_char_name, char *font_file_path,
2755
                        gs_fapi_char_ref *cr, bool bCID)
2756
1.31M
{
2757
1.31M
    ref *pdr = pfont_dict(pbfont);
2758
1.31M
    int client_char_code = ccode;
2759
1.31M
    ref char_name, cname_str;
2760
1.31M
    int code = 0;
2761
1.31M
    gs_fapi_server *I = pbfont->FAPI;
2762
1.31M
    bool is_TT_from_type42 = (pbfont->FontType == ft_TrueType && font_file_path == NULL);
2763
1.31M
    bool is_glyph_index = false;
2764
1.31M
    bool is_embedded_type1 =
2765
1.31M
        ((pbfont->FontType == ft_encrypted
2766
1.31M
          || pbfont->FontType == ft_encrypted2) && font_file_path == NULL);
2767
1.31M
    i_ctx_t *i_ctx_p = (i_ctx_t *) I->client_ctx_p;
2768
1.31M
    bool unicode_cp = false;
2769
2770
    /* Obtain the character name : */
2771
1.31M
    if (bCID) {
2772
0
        if (pbfont->FontType == ft_CID_TrueType && font_file_path) {
2773
0
            ref *pdr2, *fidr, *dummy;
2774
0
            pdr2 = pfont_dict(gs_rootfont(igs));
2775
0
            if (dict_find_string_with_type(pdr2, "FontInfo", &fidr, t_dictionary) > 0 &&
2776
0
                dict_find_string(fidr, "GlyphNames2Unicode", &dummy) > 0)
2777
0
            {
2778
0
                unsigned char uc[4] = {0};
2779
0
                unsigned int cc = 0;
2780
0
                int i, l;
2781
0
                if (penum->text.operation & TEXT_FROM_SINGLE_CHAR) {
2782
0
                    cc = penum->text.data.d_char;
2783
0
                } else if (penum->text.operation & TEXT_FROM_SINGLE_GLYPH) {
2784
0
                    cc = penum->text.data.d_glyph - GS_MIN_CID_GLYPH;
2785
0
                }
2786
0
                else {
2787
0
                    byte *c = (byte *)&penum->text.data.bytes[penum->index - penum->bytes_decoded];
2788
0
                    for (i = 0; i < penum->bytes_decoded ; i++) {
2789
0
                      cc |= c[i] << ((penum->bytes_decoded - 1) - i) * 8;
2790
0
                    }
2791
0
                }
2792
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));
2793
0
                if (l > 0 && l < sizeof(uc)) {
2794
0
                    cc = 0;
2795
0
                    for (i = 0; i < l; i++) {
2796
0
                        cc |= uc[l - 1 - i] << (i * 8);
2797
0
                    }
2798
0
                    ccode = cc;
2799
0
                    unicode_cp = true;
2800
0
                }
2801
0
            }
2802
0
        }
2803
0
        client_char_code = ccode;
2804
0
        make_null(&char_name);
2805
0
        enc_char_name->data = NULL;
2806
0
        enc_char_name->size = 0;
2807
0
    }
2808
1.31M
    else {
2809
1.31M
        if (ccode != GS_NO_CHAR) {
2810
            /* Translate from PS encoding to char name : */
2811
1.31M
            ref *Encoding;
2812
2813
1.31M
            client_char_code = ccode;
2814
1.31M
            if (dict_find_string(pdr, "Encoding", &Encoding) > 0 &&
2815
1.31M
                (r_has_type(Encoding, t_array) ||
2816
0
                 r_has_type(Encoding, t_shortarray)
2817
1.31M
                 || r_has_type(Encoding, t_mixedarray))) {
2818
1.31M
                if (array_get(imemory, Encoding, client_char_code, &char_name)
2819
1.31M
                    < 0)
2820
0
                    if ((code =
2821
0
                         name_ref(imemory, (const byte *)".notdef", 7,
2822
0
                                  &char_name, -1)) < 0)
2823
0
                        return code;
2824
1.31M
            }
2825
0
            else {
2826
0
                return_error(gs_error_invalidfont);
2827
0
            }
2828
1.31M
        }
2829
0
        else {
2830
0
            code =
2831
0
                names_ref(imemory->gs_lib_ctx->gs_name_table,
2832
0
                          (const byte *)name->data, name->size, &char_name,
2833
0
                          0);
2834
2835
0
        }
2836
        /* We need to store the name as we get it (from the Encoding array), in case it's
2837
         * had the name extended (with "~GS~xx"), we'll remove the extension before passing
2838
         * it to the renderer for a disk based font. But the metrics dictionary may have
2839
         * been constructed using the extended name....
2840
         */
2841
1.31M
        if (!r_has_type(&char_name, t_name))
2842
0
            return_error(gs_error_invalidfont);
2843
1.31M
        name_string_ref(imemory, &char_name, &cname_str);
2844
1.31M
        enc_char_name->data = cname_str.value.bytes;
2845
1.31M
        enc_char_name->size = r_size(&cname_str);
2846
1.31M
    }
2847
2848
    /* Obtain the character code or glyph index : */
2849
1.31M
    cr->char_codes_count = 1;
2850
1.31M
    if (bCID) {
2851
0
        if (font_file_path != NULL) {
2852
0
            ref *Decoding, *TT_cmap = NULL, *SubstNWP;
2853
0
            ref src_type, dst_type;
2854
0
            uint c = 0;
2855
2856
0
            is_glyph_index = true;
2857
2858
0
            if (dict_find_string(pdr, "Decoding", &Decoding) <= 0
2859
0
                || !r_has_type(Decoding, t_dictionary))
2860
0
                return_error(gs_error_invalidfont);
2861
0
            if (dict_find_string(pdr, "SubstNWP", &SubstNWP) <= 0
2862
0
                || !r_has_type(SubstNWP, t_array))
2863
0
                return_error(gs_error_invalidfont);
2864
0
            if (dict_find_string(pdr, "TT_cmap", &TT_cmap) <= 0
2865
0
                || !r_has_type(TT_cmap, t_dictionary)) {
2866
0
                ref *DecodingArray, char_code, char_code1, ih;
2867
0
                int i = client_char_code % 256, n;
2868
2869
0
                make_int(&ih, client_char_code / 256);
2870
                /* Check the Decoding array for this block of CIDs */
2871
0
                if (dict_find(Decoding, &ih, &DecodingArray) <= 0
2872
0
                    || !r_has_type(DecodingArray, t_array)
2873
0
                    || array_get(imemory, DecodingArray, i, &char_code) < 0) {
2874
0
                    return_error(gs_error_invalidfont);
2875
0
                }
2876
2877
                /* Check the Decoding entry */
2878
0
                if (r_has_type(&char_code, t_integer)) {
2879
0
                    n = 1;
2880
0
                }
2881
0
                else if (r_has_type(&char_code, t_array)) {
2882
0
                    DecodingArray = &char_code;
2883
0
                    i = 0;
2884
0
                    n = r_size(DecodingArray);
2885
0
                }
2886
0
                else {
2887
0
                    return_error(gs_error_invalidfont);
2888
0
                }
2889
2890
0
                for (; n--; i++) {
2891
0
                    if (array_get(imemory, DecodingArray, i, &char_code1) < 0
2892
0
                        || !r_has_type(&char_code1, t_integer)) {
2893
0
                        return_error(gs_error_invalidfont);
2894
0
                    }
2895
2896
0
                    c = char_code1.value.intval;
2897
0
                    I->check_cmap_for_GID(I, &c);
2898
0
                    if (c != 0)
2899
0
                        break;
2900
0
                }
2901
0
            }
2902
0
            else {
2903
0
                ref *CIDSystemInfo;
2904
0
                ref *Ordering;
2905
0
                ref *fdict, *CMapDict, *CMapName, *WMode, CMapNameStr;
2906
0
                char *cmapnm = NULL;
2907
0
                int cmapnmlen = 0;
2908
0
                int wmode = 0;
2909
                /* leave off the -H or -V */
2910
0
                const char * const utfcmap = "Identity-UTF16";
2911
0
                int utfcmaplen = strlen(utfcmap);
2912
2913
0
                fdict = pfont_dict(gs_rootfont(igs));
2914
0
                code = dict_find_string(fdict, "CMap", &CMapDict);
2915
0
                if (code > 0 && r_has_type(CMapDict, t_dictionary)) {
2916
0
                    code = dict_find_string(CMapDict, "WMode", &WMode);
2917
0
                    if (code > 0 && r_has_type(WMode, t_integer)) {
2918
0
                        wmode = WMode->value.intval;
2919
0
                    }
2920
0
                    code = dict_find_string(CMapDict, "CMapName", &CMapName);
2921
0
                    if (code > 0 && r_has_type(CMapName, t_name)) {
2922
0
                        name_string_ref(imemory, CMapName, &CMapNameStr);
2923
0
                        cmapnm = (char *)CMapNameStr.value.bytes;
2924
0
                        cmapnmlen = r_size(&CMapNameStr);
2925
0
                    }
2926
0
                }
2927
                /* We only have to lookup the char code if we're *not* using an identity ordering
2928
                   with the exception of Identity-UTF16 which is a different beast altogether */
2929
0
                if (unicode_cp || (cmapnmlen > 0 && !strncmp(cmapnm, utfcmap, cmapnmlen > utfcmaplen ? utfcmaplen : cmapnmlen))
2930
0
                    || (dict_find_string(pdr, "CIDSystemInfo", &CIDSystemInfo) > 0
2931
0
                    && r_has_type(CIDSystemInfo, t_dictionary)
2932
0
                    && dict_find_string(CIDSystemInfo, "Ordering",
2933
0
                                        &Ordering) > 0
2934
0
                    && r_has_type(Ordering, t_string)
2935
0
                    && strncmp((const char *)Ordering->value.bytes,
2936
0
                               "Identity", 8) != 0)) {
2937
2938
0
                    if ((code =
2939
0
                         cid_to_TT_charcode(imemory, Decoding, TT_cmap,
2940
0
                                            SubstNWP, client_char_code, &c,
2941
0
                                            &src_type, &dst_type)) < 0) {
2942
0
                        return code;
2943
0
                    }
2944
0
                }
2945
0
                else {
2946
0
                    if (pbfont->FontType == ft_CID_TrueType) {
2947
0
                        c = ((gs_font_cid2 *)pbfont)->cidata.CIDMap_proc(((gs_font_cid2 *)pbfont),
2948
0
                                                  client_char_code + GS_MIN_CID_GLYPH);
2949
0
                    }
2950
0
                    else {
2951
0
                        c = client_char_code;
2952
0
                    }
2953
0
                }
2954
0
                if (pbfont->FontType == ft_CID_TrueType)
2955
0
                    c = ((gs_font_cid2 *)pbfont)->data.substitute_glyph_index_vertical((gs_font_type42 *)pbfont, c, wmode, ccode);
2956
0
            }
2957
0
            if (pbfont->FontType == ft_CID_TrueType && c == 0 && TT_cmap) {
2958
0
                ref cc32;
2959
0
                ref *gid;
2960
0
                make_int(&cc32, 32);
2961
0
                if (dict_find(TT_cmap, &cc32, &gid) > 0) {
2962
0
                    if (!r_has_type(gid, t_integer))
2963
0
                        code = gs_note_error(gs_error_typecheck);
2964
0
                    else
2965
0
                        c = gid->value.intval;
2966
0
                }
2967
0
            }
2968
0
            cr->char_codes[0] = c;
2969
            /* fixme : process the narrow/wide/proportional mapping type,
2970
               using src_type, dst_type. Should adjust the 'matrix' above.
2971
               Call get_font_proportional_feature for proper choice.
2972
             */
2973
0
        }
2974
0
        else {
2975
0
            ref *CIDMap;
2976
0
            byte *Map;
2977
0
            int c_code = client_char_code;
2978
0
            int gdb = 2;
2979
0
            int i;
2980
0
            ref *GDBytes = NULL;
2981
2982
0
            if ((dict_find_string(pdr, "GDBytes", &GDBytes) > 0)
2983
0
                && r_has_type(GDBytes, t_integer)) {
2984
0
                gdb = GDBytes->value.intval;
2985
0
            }
2986
2987
            /* The PDF Reference says that we should use a CIDToGIDMap, but the PDF
2988
             * interpreter converts this into a CIDMap (see pdf_font.ps, processCIDToGIDMap)
2989
             */
2990
0
            if (dict_find_string(pdr, "CIDMap", &CIDMap) > 0
2991
0
                && !r_has_type(CIDMap, t_name) && (r_has_type(CIDMap, t_array)
2992
0
                                                   || r_has_type(CIDMap,
2993
0
                                                                 t_string))) {
2994
2995
0
                if (r_has_type(CIDMap, t_array)) {
2996
2997
                    /* Too big for single string, so its an array of 2 strings */
2998
0
                    code = string_array_access_proc(pbfont->memory, CIDMap, 1,
2999
0
                                                    client_char_code * (ulong)gdb,
3000
0
                                                    gdb, NULL, NULL,
3001
0
                                                    (const byte **)&Map);
3002
0
                }
3003
0
                else {
3004
0
                    if (CIDMap->tas.rsize <= c_code * gdb) {
3005
0
                        c_code = 0;
3006
0
                    }
3007
0
                    Map = &CIDMap->value.bytes[c_code * gdb];
3008
                    /* If we don't have enough bytes in CIDMap, ensure we can't enter the loop below setting cr->char_codes[0] */
3009
0
                    if (Map + gdb > CIDMap->value.bytes + CIDMap->tas.rsize)
3010
0
                        code = -1;
3011
0
                }
3012
0
                cr->char_codes[0] = 0;
3013
0
                is_glyph_index = true;
3014
0
                if (code >= 0) {
3015
0
                    for (i = 0; i < gdb; i++) {
3016
0
                        cr->char_codes[0] = (cr->char_codes[0] << 8) + Map[i];
3017
0
                    }
3018
0
                }
3019
0
                else {
3020
0
                    ref *cstr, *refcode;
3021
0
                    code = dict_find_string_with_type(pdr, "CharStrings", &cstr, t_dictionary);
3022
0
                    if (code > 0) {
3023
0
                        code = dict_find_string_with_type(cstr, ".notdef", &refcode, t_integer);
3024
0
                        if (code > 0) {
3025
0
                            cr->char_codes[0] = refcode->value.intval;
3026
0
                        }
3027
0
                    }
3028
0
                }
3029
0
            }
3030
0
            else
3031
0
                cr->char_codes[0] = client_char_code;
3032
0
        }
3033
0
    }
3034
1.31M
    else if (is_TT_from_type42) {
3035
        /* This font must not use 'cmap', so compute glyph index from CharStrings : */
3036
0
        ref *CharStrings, *glyph_index, *cmaptab;
3037
3038
0
        if (dict_find_string(pdr, "TT_cmap", &cmaptab) > 0 &&
3039
0
           r_has_type(cmaptab, t_dictionary)) {
3040
0
           const char *nd = ".notdef";
3041
3042
0
           if (enc_char_name->size >= strlen(nd) &&
3043
0
               enc_char_name->data[0] == nd[0] &&
3044
0
               !memcmp(enc_char_name->data, nd, strlen(nd))) {
3045
0
               ref ccref, *gidref, boolref;
3046
0
               make_int(&ccref, ccode);
3047
0
               if (dict_find(cmaptab, &ccref, &gidref) > 0 &&
3048
0
                   r_has_type(gidref, t_integer) &&
3049
0
                   gidref->value.intval == 0) {
3050
0
                   make_bool(&boolref, true);
3051
0
               }
3052
0
               else {
3053
0
                   make_bool(&boolref, false);
3054
0
               }
3055
0
               dict_put_string(pdr, ".render_notdef", &boolref, NULL);
3056
0
           }
3057
0
        }
3058
3059
0
        if (dict_find_string(pdr, "CharStrings", &CharStrings) <= 0
3060
0
            || !r_has_type(CharStrings, t_dictionary))
3061
0
            return_error(gs_error_invalidfont);
3062
0
        if ((dict_find(CharStrings, &char_name, &glyph_index) <= 0)
3063
0
            || r_has_type(glyph_index, t_null)) {
3064
#ifdef DEBUG
3065
            ref *pvalue;
3066
3067
            if (gs_debug_c('1')
3068
                && (dict_find_string(systemdict, "QUIET", &pvalue)) > 0
3069
                && (r_has_type(pvalue, t_boolean)
3070
                    && pvalue->value.boolval == false)) {
3071
                char *glyphn;
3072
3073
                name_string_ref(imemory, &char_name, &char_name);
3074
3075
                glyphn =
3076
                    ref_to_string(&char_name, imemory,
3077
                                  "ps_get_glyphname_or_cid");
3078
                if (glyphn) {
3079
                    dmprintf2(imemory, " Substituting .notdef for %s in the font %s \n",
3080
                             glyphn, pbfont->font_name.chars);
3081
                    gs_free_string(imemory, (byte *) glyphn,
3082
                                   strlen(glyphn) + 1,
3083
                                   "ps_get_glyphname_or_cid");
3084
                }
3085
            }
3086
#endif
3087
3088
0
            cr->char_codes[0] = 0;      /* .notdef */
3089
0
            if ((code =
3090
0
                 name_ref(imemory, (const byte *)".notdef", 7, &char_name,
3091
0
                          -1)) < 0)
3092
0
                return code;
3093
0
        }
3094
0
        else if (r_has_type(glyph_index, t_integer)) {
3095
0
            cr->char_codes[0] = glyph_index->value.intval;
3096
0
        }
3097
0
        else {
3098
0
#if 1                           /* I can't find this ever being used, no idea what it's for..... */
3099
0
            os_ptr op = osp;
3100
3101
            /* Check execution stack has space for BuldChar proc and finish_render */
3102
0
            check_estack(2);
3103
            /* check space and duplicate the glyph index for BuildChar */
3104
0
            check_op(1);
3105
0
            push(1);
3106
0
            ref_assign_inline(op, op - 1);
3107
            /* Come back to fapi_finish_render after running the BuildChar */
3108
0
            push_op_estack(zfapi_finish_render);
3109
0
            ++esp;
3110
0
            ref_assign(esp, glyph_index);
3111
0
            return o_push_estack;
3112
#else
3113
            return (gs_error_invalidfont);
3114
#endif
3115
0
        }
3116
0
        is_glyph_index = true;
3117
0
    }
3118
1.31M
    else if (is_embedded_type1) {
3119
        /*  Since the client passes charstring by callback using I->ff.char_data,
3120
           the client doesn't need to provide a good cr here.
3121
           Perhaps since UFST uses char codes as glyph cache keys (UFST 4.2 cannot use names),
3122
           we provide font char codes equal to document's char codes.
3123
           This trick assumes that Encoding can't point different glyphs
3124
           for same char code. The last should be true due to
3125
           PLRM3, "5.9.4 Subsetting and Incremental Definition of Glyphs".
3126
         */
3127
1.31M
        if (ccode != GS_NO_CHAR) {
3128
1.31M
            cr->char_codes[0] = client_char_code;
3129
1.31M
        }
3130
0
        else {
3131
            /*
3132
             * Reverse Encoding here, because it can be an incremental one.
3133
             * Note that this can cause problems with UFST (see the comment above),
3134
             * if the encoding doesn't contain the glyph name rendered with glyphshow.
3135
             */
3136
0
            ref *Encoding;
3137
0
            ref glyph;
3138
3139
0
            if ((code = name_ref(pbfont->memory, name->data, name->size, &glyph, false)) < 0)
3140
0
                return code;
3141
3142
0
            if (dict_find_string(osp - 1, "Encoding", &Encoding) > 0) {
3143
0
                cr->char_codes[0] =
3144
0
                    (uint) array_find(imemory, Encoding, &glyph);
3145
0
            }
3146
0
            else
3147
0
                return_error(gs_error_invalidfont);
3148
0
        }
3149
1.31M
    }
3150
0
    else {                      /* a non-embedded font, i.e. a disk font */
3151
0
        bool can_retrieve_char_by_name = false;
3152
0
        const byte *p;
3153
3154
0
        obj_string_data(imemory, &char_name, &cr->char_name,
3155
0
                        &cr->char_name_length);
3156
0
        p = find_substring(cr->char_name, cr->char_name_length,
3157
0
                           gx_extendeg_glyph_name_separator);
3158
0
        if (p != NULL) {
3159
0
            cr->char_name_length = p - cr->char_name;
3160
0
            if ((code = name_ref(pbfont->memory, cr->char_name,
3161
0
                             cr->char_name_length, &char_name, true)) < 0)
3162
0
                return code;
3163
0
        }
3164
0
        if ((code =
3165
0
             renderer_retcode(imemory, I,
3166
0
                              I->can_retrieve_char_by_name(I, &I->ff, cr,
3167
0
                                                           &can_retrieve_char_by_name)))
3168
0
            < 0)
3169
0
            return code;
3170
3171
0
        if (!can_retrieve_char_by_name) {
3172
            /* Translate from char name to encoding used with 3d party font technology : */
3173
0
            ref *Decoding, *char_code;
3174
3175
0
            if (dict_find_string(osp - 1, "Decoding", &Decoding) > 0
3176
0
                && r_has_type(Decoding, t_dictionary)) {
3177
0
                if (dict_find(Decoding, &char_name, &char_code) > 0) {
3178
0
                    code = 0;
3179
0
                    if (r_has_type(char_code, t_integer)) {
3180
0
                        int c_code;
3181
0
                        int_param(char_code, 0xFFFF, &c_code);
3182
0
                        cr->char_codes[0] = (gs_glyph)c_code;
3183
0
                    }
3184
0
                    else if (r_has_type(char_code, t_array)
3185
0
                             || r_has_type(char_code, t_shortarray)) {
3186
0
                        int i;
3187
0
                        ref v;
3188
3189
0
                        cr->char_codes_count = r_size(char_code);
3190
0
                        if (cr->char_codes_count > count_of(cr->char_codes))
3191
0
                            code = gs_note_error(gs_error_rangecheck);
3192
0
                        if (code >= 0) {
3193
0
                            for (i = 0; i < cr->char_codes_count; i++) {
3194
0
                                code = array_get(imemory, char_code, i, &v);
3195
0
                                if (code < 0)
3196
0
                                    break;
3197
0
                                if (!r_has_type(char_code, t_integer)) {
3198
0
                                    code = gs_note_error(gs_error_rangecheck);
3199
0
                                    break;
3200
0
                                }
3201
0
                                cr->char_codes[i] = v.value.intval;
3202
0
                            }
3203
0
                        }
3204
0
                    }
3205
0
                    else {
3206
0
                        code = gs_note_error(gs_error_rangecheck);
3207
0
                    }
3208
0
                    if (code < 0) {
3209
0
                        char buf[16];
3210
0
                        int l = cr->char_name_length;
3211
3212
0
                        if (l > sizeof(buf) - 1) {
3213
0
                            l = sizeof(buf) - 1;
3214
0
                        }
3215
0
                        memcpy(buf, cr->char_name, l);
3216
0
                        buf[l] = 0;
3217
0
                        emprintf1(imemory,
3218
0
                                  "Wrong decoding entry for the character '%s'.\n",
3219
0
                                  buf);
3220
0
                        return_error(gs_error_rangecheck);
3221
0
                    }
3222
0
                }
3223
0
            }
3224
0
        }
3225
0
    }
3226
3227
    /* Provide glyph data for renderer : */
3228
    /* Occasionally, char_name is already a glyph index to pass to the rendering engine
3229
     * so don't treat it as a name object.
3230
     * I believe this will only happen with a TTF/Type42, but checking the object type
3231
     * is cheap, and covers all font type eventualities.
3232
     */
3233
1.31M
    if (!I->ff.is_cid && r_has_type(&char_name, t_name)) {
3234
1.31M
        ref sname;
3235
3236
1.31M
        name_string_ref(imemory, &char_name, &sname);
3237
1.31M
        I->ff.char_data = sname.value.const_bytes;
3238
1.31M
        I->ff.char_data_len = r_size(&sname);
3239
1.31M
    }
3240
0
    else if (I->ff.is_type1) {
3241
0
        I->ff.char_data = charstring;
3242
0
    }
3243
3244
1.31M
    cr->is_glyph_index = is_glyph_index;
3245
1.31M
    cr->client_char_code = client_char_code;
3246
3247
1.31M
    return (code);
3248
1.31M
}
3249
3250
3251
static int
3252
FAPI_char(i_ctx_t *i_ctx_p, bool bBuildGlyph, ref *charstring)
3253
1.05M
{                               /* Stack : <font> <code|name> --> - */
3254
1.05M
    os_ptr op = osp;
3255
1.05M
    ref *pdr = op - 1;
3256
1.05M
    ref *v;
3257
1.05M
    char *font_file_path = NULL;
3258
1.05M
    gs_font *pfont;
3259
1.05M
    int code;
3260
3261
1.05M
    check_op(2);
3262
1.05M
    code = base_font_param(osp - 1, &pfont);
3263
3264
1.05M
    if (code == 0) {
3265
1.05M
        gs_font_base *pbfont = (gs_font_base *) pfont;
3266
1.05M
        bool bCID = (FAPI_ISCIDFONT(pbfont) || charstring != NULL);
3267
1.05M
        int subfont;
3268
1.05M
        gs_fapi_server *I = pbfont->FAPI;
3269
1.05M
        gs_text_enum_t *penum = op_show_find(i_ctx_p);
3270
1.05M
        gs_string char_string, *c_string_p = NULL;
3271
1.05M
        gs_string char_name, *c_name_p = NULL;
3272
1.05M
        gs_glyph cindex = GS_NO_CHAR;
3273
1.05M
        ref gname;
3274
3275
1.05M
        if (I == NULL)
3276
0
            return_error(gs_error_invalidfont);
3277
3278
        /* initialise the FAPI font, this includes language specific stuff */
3279
1.05M
        I->ff = ps_ff_stub;
3280
3281
1.05M
        I->client_ctx_p = i_ctx_p;
3282
3283
1.05M
        if (bBuildGlyph && !bCID) {
3284
0
            if (r_type(op) != t_name) {
3285
0
                name_enter_string(imemory, ".notdef", op);
3286
0
            }
3287
0
            check_type(*op, t_name);
3288
3289
0
            name_string_ref(imemory, op, &gname);
3290
0
            c_name_p = &char_name;
3291
0
            c_name_p->data = gname.value.bytes;
3292
0
            c_name_p->size = r_size(&gname);
3293
3294
0
        }
3295
1.05M
        else {
3296
1.05M
            int chint;
3297
1.05M
            if (bBuildGlyph && pbfont->FontType == ft_CID_TrueType
3298
0
                && r_has_type(op, t_name)) {
3299
0
                ref *chstrs, *chs;
3300
3301
                /* This logic is lifted from %Type11BuildGlyph in gs_cidfn.ps
3302
                 * Note we only have to deal with mistakenly being given a name object
3303
                 * here, the out of range CID is handled later
3304
                 */
3305
0
                if ((dict_find_string_with_type(op - 1, "CharStrings", &chstrs, t_dictionary)) <= 0) {
3306
0
                    return_error(gs_error_undefined);
3307
0
                }
3308
3309
0
                if ((dict_find_string(chstrs, ".notdef", &chs)) <= 0) {
3310
0
                    return_error(gs_error_undefined);
3311
0
                }
3312
0
                ref_assign_inline(op, chs);
3313
0
            }
3314
3315
1.05M
            make_null(&gname);
3316
1.05M
            check_type(*op, t_integer);
3317
1.05M
            int_param(op, 0xFFFF, (int *)&chint);
3318
1.05M
            cindex = chint;
3319
1.05M
        }
3320
3321
1.05M
        if (dict_find_string(pdr, "SubfontId", &v) > 0
3322
0
            && r_has_type(v, t_integer))
3323
0
            subfont = v->value.intval;
3324
1.05M
        else
3325
1.05M
            subfont = 0;
3326
3327
1.05M
        if (dict_find_string(osp - 1, "Path", &v) > 0
3328
0
            && r_has_type(v, t_string)) {
3329
0
            font_file_path = ref_to_string(v, imemory, "font file path");
3330
0
        }
3331
3332
1.05M
        if (charstring) {
3333
0
            c_string_p = &char_string;
3334
0
            c_string_p->data = charstring->value.bytes;
3335
0
            c_string_p->size = r_size(charstring);
3336
0
        }
3337
3338
1.05M
        code =
3339
1.05M
            gs_fapi_do_char(pfont, igs, penum, font_file_path,
3340
1.05M
                            bBuildGlyph, c_string_p, c_name_p, (gs_char)cindex, cindex,
3341
1.05M
                            subfont);
3342
1.05M
        if (font_file_path != NULL) {
3343
0
            gs_free_string(imemory, (byte *) font_file_path, r_size(v) + 1,
3344
0
                           "font file path");
3345
0
        }
3346
        /* This handles the situation where a charstring has been replaced with a PS procedure.
3347
         * against the rules, but not *that* rare.
3348
         * It's also something that GS does internally to simulate font styles.
3349
         */
3350
1.05M
        if (code == gs_error_unregistered) {
3351
0
            os_ptr op = osp;
3352
0
            ref *proc = NULL, gname;
3353
3354
0
            if (I->ff.is_type1
3355
0
                && (get_charstring(&I->ff, cindex, &proc, &gname) >= 0)
3356
0
                && proc != NULL && (r_has_type(proc, t_array)
3357
0
                    || r_has_type(proc, t_mixedarray))) {
3358
0
                push(2);
3359
0
                ref_assign(op - 1, &gname);
3360
0
                ref_assign(op, proc);
3361
0
                return (zchar_exec_char_proc(i_ctx_p));
3362
0
            }
3363
0
            else {
3364
0
                return_error(gs_error_invalidfont);
3365
0
            }
3366
0
        }
3367
1.05M
    }
3368
    /* We've already imaged teh glyph, pop the operands */
3369
1.05M
    if (code == 0)
3370
1.05M
        pop(2);
3371
1.05M
    return code;
3372
1.05M
}
3373
3374
static int
3375
zFAPIBuildGlyph9(i_ctx_t *i_ctx_p)
3376
0
{
3377
    /*  The alghorithm is taken from %Type9BuildGlyph - see gs_cidfn.ps .  */
3378
0
    os_ptr lop, op = osp;
3379
0
    int cid, code;
3380
0
    avm_space s = ialloc_space(idmemory);
3381
0
    ref font9 = *pfont_dict(gs_currentfont(igs));
3382
0
    ref *rFDArray, f;
3383
0
    int font_index;
3384
3385
0
    check_op(2);
3386
0
    check_type(op[0], t_integer);
3387
0
    check_type(op[-1], t_dictionary);
3388
0
    cid = op[0].value.intval;
3389
0
    push(2);
3390
0
    op[-1] = *pfont_dict(gs_currentfont(igs));
3391
0
    op[0] = op[-2];             /* <font0> <cid> <font9> <cid> */
3392
0
    ialloc_set_space(idmemory, (r_is_local(op - 3) ? avm_global : avm_local));  /* for ztype9mapcid */
3393
3394
    /* stack: <font0> <cid> <font9> <cid> */
3395
0
    if ((code = ztype9mapcid(i_ctx_p)) < 0)
3396
0
        return code;            /* <font0> <cid> <charstring> <font_index> */
3397
    /* fixme: what happens if the charstring is absent ?
3398
       Can FDArray contain 'null' (see %Type9BuildGlyph in gs_cidfn.ps)? */
3399
0
    font_index = op[0].value.intval;
3400
0
    if (dict_find_string(&font9, "FDArray", &rFDArray) <= 0
3401
0
        || r_type(rFDArray) != t_array)
3402
0
        return_error(gs_error_invalidfont);
3403
0
    if (array_get(imemory, rFDArray, font_index, &f) < 0
3404
0
        || r_type(&f) != t_dictionary)
3405
0
        return_error(gs_error_invalidfont);
3406
3407
0
    op[0] = op[-2];
3408
0
    op[-2] = op[-1];            /* Keep the charstring on ostack for the garbager. */
3409
0
    op[-1] = f;                 /* <font0> <charstring> <subfont> <cid> */
3410
0
    if ((code = FAPI_char(i_ctx_p, true, op - 2)) < 0)
3411
0
        return code;
3412
    /* stack: <font0> <charstring> */
3413
3414
0
    lop = osp;
3415
0
    if (code == 5) {
3416
0
        int i, ind = (lop - op);
3417
3418
0
        op = osp;
3419
3420
0
        for (i = ind; i >= 0; i--) {
3421
0
            op[-i - 2] = op[-i];
3422
0
        }
3423
0
        pop(2);
3424
0
    }
3425
0
    else if (code < 0) {        /* <font0> <dirty> <dirty> <dirty> */
3426
        /* Adjust ostack for the correct error handling : */
3427
0
        make_int(op - 2, cid);
3428
0
        pop(2);                 /* <font0> <cid> */
3429
0
    }
3430
0
    else if (code != 5) {       /* <font0> <dirty> */
3431
3432
3433
0
        pop(2);                 /* */
3434
        /*  Note that this releases the charstring, and it may be garbage-collected
3435
           before the interpreter calls fapi_finish_render. This requires the server
3436
           to keep glyph raster internally between calls to get_char_raster_metrics
3437
           and get_char_raster. Perhaps UFST cannot provide metrics without
3438
           building a raster, so this constraint actually goes from UFST.
3439
         */
3440
0
    }
3441
0
    ialloc_set_space(idmemory, s);
3442
0
    return code;
3443
0
}
3444
3445
/* <font> <code> .FAPIBuildChar - */
3446
static int
3447
zFAPIBuildChar(i_ctx_t *i_ctx_p)
3448
1.05M
{
3449
1.05M
    return FAPI_char(i_ctx_p, false, NULL);
3450
1.05M
}
3451
3452
/* non-CID : <font> <code> .FAPIBuildGlyph - */
3453
/*     CID : <font> <name> .FAPIBuildGlyph - */
3454
static int
3455
zFAPIBuildGlyph(i_ctx_t *i_ctx_p)
3456
7
{
3457
7
    return FAPI_char(i_ctx_p, true, NULL);
3458
7
}
3459
3460
3461
/* <font_dict> .FAPIpassfont bool <font_dict> */
3462
/* must insert /FAPI to font dictionary */
3463
static int
3464
zFAPIpassfont(i_ctx_t *i_ctx_p)
3465
12.2k
{
3466
12.2k
    os_ptr op = osp;
3467
12.2k
    gs_font *pfont;
3468
12.2k
    int code;
3469
12.2k
    char *font_file_path = NULL;
3470
12.2k
    ref *v;
3471
12.2k
    char *xlatmap = NULL;
3472
12.2k
    char *fapi_request = NULL;
3473
12.2k
    char *fapi_id = NULL;
3474
12.2k
    ref reqstr;
3475
12.2k
    int subfont;
3476
3477
12.2k
    check_op(1);
3478
    /* Normally embedded fonts have no Path, but if a CID font is
3479
     * emulated with a TT font, and it is hooked with FAPI,
3480
     * the path presents and is neccessary to access the full font data.
3481
     */
3482
12.2k
    check_type(*op, t_dictionary);
3483
3484
12.2k
    code = base_font_param(osp, &pfont);
3485
12.2k
    if (code < 0)
3486
0
        return code;
3487
3488
12.2k
    if (dict_find_string(op, "SubfontId", &v) > 0
3489
0
        && r_has_type(v, t_integer))
3490
0
        subfont = v->value.intval;
3491
12.2k
    else
3492
12.2k
        subfont = 0;
3493
3494
12.2k
    code = FAPI_get_xlatmap(i_ctx_p, &xlatmap); /* Useful for emulated fonts hooked with FAPI. */
3495
12.2k
    if (code < 0)
3496
0
        return code;
3497
3498
    /* If the font dictionary contains a FAPIPlugInReq key, the the PS world wants us
3499
     * to try to use a specific FAPI plugin, so find it, and try it....
3500
     */
3501
12.2k
    if (dict_find_string(op, "FAPIPlugInReq", &v) > 0 && r_type(v) == t_name) {
3502
3503
0
        name_string_ref(imemory, v, &reqstr);
3504
3505
0
        fapi_request = ref_to_string(&reqstr, imemory, "zFAPIpassfont");
3506
0
    }
3507
3508
12.2k
    if (dict_find_string(op, "Path", &v) > 0 && r_has_type(v, t_string))
3509
0
        font_file_path = ref_to_string(v, imemory_global, "font file path");
3510
3511
12.2k
    gs_fapi_set_servers_client_data(imemory, &ps_ff_stub, i_ctx_p);
3512
3513
12.2k
    code =
3514
12.2k
        gs_fapi_passfont(pfont, subfont, font_file_path, NULL, fapi_request, xlatmap,
3515
12.2k
                         &fapi_id, NULL, ps_get_server_param);
3516
3517
12.2k
    if (font_file_path != NULL)
3518
0
        gs_free_string(imemory_global, (byte *) font_file_path, r_size(v) + 1,
3519
12.2k
                       "font file path");
3520
3521
12.2k
    if (fapi_request != NULL)
3522
0
        gs_free_string(imemory, (byte *) fapi_request,
3523
12.2k
                       strlen(fapi_request) + 1, "do_FAPIpassfont");
3524
12.2k
    if (code < 0 && code != gs_error_invalidaccess)
3525
20
        return code;
3526
3527
12.1k
    if (code >= 0 && fapi_id != NULL) {
3528
12.1k
        ref FAPI_ID;
3529
3530
12.1k
        if ((code =
3531
12.1k
             name_ref(imemory, (const byte *)fapi_id,
3532
12.1k
                      strlen(fapi_id), &FAPI_ID, false)) < 0)
3533
0
            return code;
3534
12.1k
        if ((code = dict_put_string(op, "FAPI", &FAPI_ID, NULL)) < 0)
3535
0
            return code;        /* Insert FAPI entry to font dictionary. */
3536
12.1k
    }
3537
12.1k
    push(1);
3538
12.1k
    make_bool(op, (fapi_id != NULL));
3539
12.1k
    return 0;
3540
12.1k
}
3541
3542
const op_def zfapi_op_defs[] = {
3543
    {"1.FAPIavailable", zFAPIavailable},
3544
    {"2.FAPIpassfont", zFAPIpassfont},
3545
    {"2.FAPIrebuildfont", zFAPIrebuildfont},
3546
    {"2.FAPIBuildChar", zFAPIBuildChar},
3547
    {"2.FAPIBuildGlyph", zFAPIBuildGlyph},
3548
    {"2.FAPIBuildGlyph9", zFAPIBuildGlyph9},
3549
    op_def_end(0)
3550
};