Coverage Report

Created: 2025-04-22 06:20

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