Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_fmap.c
Line
Count
Source
1
/* Copyright (C) 2020-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
/* Font re-mapping */
16
17
#include "strmio.h"
18
#include "stream.h"
19
#include "scanchar.h"
20
#include "gsstrl.h"
21
22
#include "pdf_int.h"
23
#include "pdf_types.h"
24
#include "pdf_font_types.h"
25
#include "pdf_array.h"
26
#include "pdf_dict.h"
27
#include "pdf_stack.h"
28
#include "pdf_file.h"
29
#include "pdf_misc.h"
30
#include "pdf_font.h"
31
#include "pdf_fontmt.h"
32
#include "pdf_fmap.h"
33
34
typedef struct
35
{
36
    const char *keyname;
37
    const char *mappedname;
38
} pdfi_custom_fmap_entry;
39
40
pdfi_custom_fmap_entry pdfi_custom_fmap_entries[] =
41
{
42
  {"Helv", "Helvetica"},
43
  {NULL, NULL}
44
};
45
46
static inline bool pdfi_fmap_file_exists(pdf_context *ctx, pdf_string *fname)
47
0
{
48
0
    return pdfi_font_file_exists(ctx, (const char *)fname->data, fname->length);
49
0
}
50
51
static int
52
pdfi_fontmap_open_file(pdf_context *ctx, const char *mapfilename, byte **buf, int *buflen)
53
48.7k
{
54
48.7k
    int code = 0;
55
48.7k
    stream *s;
56
48.7k
    char fname[gp_file_name_sizeof];
57
48.7k
    const char *path_pfx = "Init/";
58
48.7k
    const char *poststring = "\nendstream";
59
48.7k
    const int poststringlen = strlen(poststring);
60
48.7k
    fname[0] = '\0';
61
62
48.7k
    if (strlen(path_pfx) + strlen(mapfilename) + 1 > gp_file_name_sizeof)
63
0
        return_error(gs_error_invalidfileaccess);
64
65
48.7k
    code = pdfi_open_resource_file(ctx, mapfilename, strlen(mapfilename), &s);
66
48.7k
    if (code < 0) {
67
0
        strncat(fname, path_pfx, strlen(path_pfx));
68
0
        strncat(fname, (char *)mapfilename, strlen(mapfilename));
69
0
        code = pdfi_open_resource_file(ctx, fname, strlen(fname), &s);
70
0
    }
71
72
48.7k
    if (code >= 0) {
73
48.7k
        int i;
74
48.7k
        int64_t file_size;
75
76
48.7k
        sfseek(s, 0, SEEK_END);
77
48.7k
        file_size = sftell(s);
78
48.7k
        sfseek(s, 0, SEEK_SET);
79
48.7k
        if (file_size < 0 || file_size > max_int - poststringlen) {
80
0
            code = gs_note_error(gs_error_ioerror);
81
48.7k
        } else {
82
48.7k
            byte *dbuf;
83
48.7k
            *buflen = (int)file_size;
84
85
48.7k
            (*buf) = gs_alloc_bytes(ctx->memory, (size_t)*buflen + poststringlen, "pdf_cmap_open_file(buf)");
86
48.7k
            if (*buf != NULL) {
87
48.7k
                sfread((*buf), 1, *buflen, s);
88
48.7k
                memcpy((*buf) + *buflen, poststring, poststringlen);
89
48.7k
                *buflen += poststringlen;
90
                /* This is naff, but works for now
91
                   When parsing Fontmap in PS, ";" is defined as "def"
92
                   Also some people use "cvn" to convert a string to a name.
93
                   We don't need either, because the dictionary is built from the stack.
94
                 */
95
155M
                for (i = 0, dbuf = *buf; i < *buflen - 1; i++, dbuf++) {
96
155M
                    if (*dbuf == ';') {
97
4.18M
                        *dbuf = ' ';
98
4.18M
                    }
99
155M
                    if (memcmp(dbuf, "cvn ", 4) == 0) {
100
0
                        dbuf[0] = dbuf[1] = dbuf[2] = 0x20;
101
0
                    }
102
155M
                }
103
48.7k
            }
104
0
            else {
105
0
                code = gs_note_error(gs_error_VMerror);
106
0
            }
107
48.7k
        }
108
48.7k
        sfclose(s);
109
48.7k
    }
110
48.7k
    return code;
111
48.7k
}
112
113
#ifdef UFST_BRIDGE
114
/* we know fco_path is null terminated */
115
static pdf_string *pdfi_make_fco_path_string(pdf_context *ctx, char *fco_path)
116
{
117
    pdf_string *fp;
118
    int code = pdfi_object_alloc(ctx, PDF_STRING, strlen(fco_path), (pdf_obj **)&fp);
119
    if (code < 0)
120
        return NULL;
121
    pdfi_countup(fp);
122
    memcpy(fp->data, fco_path, strlen(fco_path));
123
124
    return fp;
125
}
126
#endif /* UFST_BRIDGE */
127
128
static inline int pdfi_populate_ufst_fontmap(pdf_context *ctx)
129
48.7k
{
130
#ifdef UFST_BRIDGE
131
    int status = 0;
132
    int bSize, i;
133
    char pthnm[gp_file_name_sizeof];
134
    char *ufst_root_dir;
135
    char *fco;
136
    char *fco_start, *fco_lim;
137
    size_t ufst_root_dir_len;
138
139
    if (pdfi_fapi_ufst_available(ctx->memory) == false) {
140
        return (0);
141
    }
142
143
    ufst_root_dir = (char *)pdfi_fapi_ufst_get_font_dir(ctx->memory);
144
    ufst_root_dir_len = strlen(ufst_root_dir);
145
    if (ufst_root_dir_len >= gp_file_name_sizeof) {
146
        return gs_error_Fatal;
147
    }
148
    fco_start = fco = (char *)pdfi_fapi_ufst_get_fco_list(ctx->memory);
149
    fco_lim = fco_start + strlen(fco_start) + 1;
150
    while (fco < fco_lim && status == 0) {
151
        pdf_string *fco_str;
152
        status = 0;
153
        /* build and open (get handle) for the k'th fco file name */
154
        gs_strlcpy((char *)pthnm, ufst_root_dir, sizeof pthnm);
155
156
        for (i = 2; fco[i] != gp_file_name_list_separator && (&fco[i]) < fco_lim - 1; i++)
157
            ;
158
159
        if (i + ufst_root_dir_len >= gp_file_name_sizeof) {
160
            return gs_error_Fatal;
161
        }
162
        strncat(pthnm, fco, i);
163
        fco += (i + 1);
164
        fco_str = pdfi_make_fco_path_string(ctx, pthnm);
165
        if (fco_str == NULL) {
166
            return gs_error_Fatal;
167
        }
168
169
        /* enumerate the files in this fco */
170
        for (i = 0; status == 0; i++) {
171
            char *pname = NULL;
172
            pdf_font_microtype *pdffont = NULL;
173
            int font_number = 0;
174
175
            status = pdfi_alloc_mt_font(ctx, fco_str, i, &pdffont);
176
            if (status < 0)
177
                break;
178
            status = pdfi_fapi_passfont((pdf_font *)pdffont, i, (char *)"UFST", pthnm, NULL, 0);
179
            if (status < 0){
180
#ifdef DEBUG
181
                outprintf(ctx->memory, "CGIFfco_Access error %d\n", status);
182
#endif
183
                pdfi_countdown(pdffont);
184
                break;
185
            }
186
187
            /* For Microtype fonts, once we get here, these
188
             * pl_fapi_get*() calls cannot fail, so we can
189
             * safely ignore the return value
190
             */
191
            (void)pdfi_fapi_get_mtype_font_name((gs_font *)pdffont->pfont, NULL, &bSize);
192
193
            pname = (char *)gs_alloc_bytes(ctx->memory, bSize, "pdfi: mt font name buffer");
194
            if (!pname) {
195
                pdfi_countdown(pdffont);
196
                (void)pdfi_set_warning_stop(ctx, gs_note_error(gs_error_VMerror), NULL, W_PDF_VMERROR_BUILTIN_FONT, "pdfi_populate_ufst_fontmap", "");
197
                outprintf(ctx->memory, "VM Error for built-in font %d", i);
198
                continue;
199
            }
200
201
            (void)pdfi_fapi_get_mtype_font_name((gs_font *)pdffont->pfont, (byte *) pname, &bSize);
202
            (void)pdfi_fapi_get_mtype_font_number((gs_font *)pdffont->pfont, &font_number);
203
204
            if (bSize < gs_font_name_max) {
205
                memcpy(pdffont->pfont->key_name.chars, pname, bSize);
206
                pdffont->pfont->key_name.chars[bSize] = 0;
207
                pdffont->pfont->key_name.size = bSize;
208
                memcpy(pdffont->pfont->font_name.chars, pname, bSize);
209
                pdffont->pfont->font_name.chars[bSize] = 0;
210
                pdffont->pfont->font_name.size = bSize;
211
            }
212
            status = gs_definefont(ctx->font_dir, (gs_font *) pdffont->pfont);
213
            if (status < 0) {
214
                pdfi_countdown(pdffont);
215
                status = 0;
216
                continue;
217
            }
218
            gs_notify_release(&pdffont->pfont->notify_list);
219
            status = pdfi_fapi_passfont((pdf_font *)pdffont, i, (char *)"UFST", pthnm, NULL, 0);
220
            if (status < 0) {
221
                pdfi_countdown(pdffont);
222
                status = 0;
223
                continue;
224
            }
225
            status = pdfi_dict_put(ctx, ctx->pdffontmap, pname, (pdf_obj *)pdffont);
226
            pdfi_countdown(pdffont);
227
            if (status < 0) {
228
                status = 0;
229
                continue;
230
            }
231
            gs_free_object(ctx->memory, pname, "pdfi_populate_ufst_fontmap");
232
        }
233
        pdfi_countdown(fco_str);
234
    }
235
#endif /* UFST_BRIDGE */
236
48.7k
    return 0;
237
48.7k
}
238
239
static int
240
pdf_make_fontmap(pdf_context *ctx, const char *default_fmapname, int cidfmap)
241
48.7k
{
242
48.7k
    byte *fmapbuf = NULL;
243
48.7k
    int code, fmapbuflen;
244
48.7k
    pdf_c_stream *fmapstr = NULL;
245
48.7k
    pdf_stream fakedict = {0};
246
48.7k
    pdfi_custom_fmap_entry *pcfe = pdfi_custom_fmap_entries;
247
48.7k
    int i, j = 0;
248
48.7k
    char fmapname[gp_file_name_sizeof];
249
48.7k
    pdf_c_stream fakemainstream = {0};
250
48.7k
    int stacksize = pdfi_count_stack(ctx);
251
252
48.7k
    strncpy(fmapname, default_fmapname, strlen(default_fmapname) + 1);
253
254
48.7k
    code = pdfi_mark_stack(ctx, PDF_DICT_MARK);
255
48.7k
    if (code < 0)
256
0
        goto done;
257
258
48.7k
    do {
259
48.7k
        if (j < ctx->num_fontmapfiles && cidfmap == false) {
260
0
            memcpy(fmapname, ctx->fontmapfiles[j].data, ctx->fontmapfiles[j].size);
261
0
            fmapname[ctx->fontmapfiles[j].size] = '\0';
262
0
        }
263
264
48.7k
        code = pdfi_fontmap_open_file(ctx, (const char *)fmapname, &fmapbuf, &fmapbuflen);
265
48.7k
        if (code < 0) {
266
0
            if (ctx->args.QUIET != true) {
267
0
                (void)outwrite(ctx->memory, "Warning: ", 9);
268
0
                if (cidfmap)
269
0
                    (void)outwrite(ctx->memory, "cidfmap file ", 13);
270
0
                else
271
0
                    (void)outwrite(ctx->memory, "Fontmap file \"", 14);
272
0
                (void)outwrite(ctx->memory, fmapname, strlen(fmapname));
273
0
                (void)outwrite(ctx->memory, "\" not found.\n", 13);
274
0
                code = 0;
275
0
            }
276
0
        }
277
48.7k
        else {
278
48.7k
            code = pdfi_open_memory_stream_from_memory(ctx, fmapbuflen, fmapbuf, &fmapstr, true);
279
48.7k
            if (code >= 0) {
280
281
48.7k
                if (ctx->main_stream == NULL) {
282
0
                    ctx->main_stream = &fakemainstream;
283
0
                }
284
285
48.7k
                if (fmapbuflen > 0)
286
48.7k
                    code = pdfi_interpret_content_stream(ctx, fmapstr, &fakedict, NULL);
287
0
                else
288
0
                    code = 0;
289
290
48.7k
                if (ctx->main_stream == &fakemainstream) {
291
0
                    ctx->main_stream = NULL;
292
0
                }
293
48.7k
                gs_free_object(ctx->memory, fmapbuf, "pdf_make_fontmap(fmapbuf)");
294
48.7k
            }
295
48.7k
        }
296
48.7k
        j++;
297
48.7k
    } while(j < ctx->num_fontmapfiles && cidfmap == false && code >= 0);
298
299
48.7k
    if (code >= 0) {
300
48.7k
        if (pdfi_count_stack(ctx) > stacksize) {
301
48.7k
            code = pdfi_dict_from_stack(ctx, 0, 0, true);
302
48.7k
            if (code < 0)
303
0
                goto done;
304
305
48.7k
            if (cidfmap == true) {
306
6.48k
                ctx->pdfcidfmap = (pdf_dict *)ctx->stack_top[-1];
307
6.48k
                pdfi_countup(ctx->pdfcidfmap);
308
6.48k
            }
309
42.2k
            else {
310
42.2k
                ctx->pdffontmap = (pdf_dict *)ctx->stack_top[-1];
311
42.2k
                pdfi_countup(ctx->pdffontmap);
312
42.2k
            }
313
48.7k
            pdfi_pop(ctx, 1);
314
48.7k
            code = 0;
315
316
            /* Add our internal aliases to the fontmap. */
317
48.7k
            if (cidfmap == false) {
318
84.4k
                for (i = 0; pcfe[i].keyname != NULL; i++) {
319
42.2k
                    pdf_obj *value;
320
42.2k
                    bool k;
321
322
                    /* We don't want to *replace* entries */
323
42.2k
                    if (pdfi_dict_known(ctx, ctx->pdffontmap, pcfe[i].keyname, &k) >= 0
324
42.2k
                        && k != true) {
325
42.2k
                        code = pdfi_name_alloc(ctx, (byte *)pcfe[i].mappedname, strlen(pcfe[i].mappedname), &value);
326
42.2k
                        if (code < 0)
327
0
                            continue;
328
42.2k
                        pdfi_countup(value);
329
                        /* If dict_put throws an error, we just carry on - hence the (void) */
330
42.2k
                        (void)pdfi_dict_put(ctx,  ctx->pdffontmap, pcfe[i].keyname, value);
331
42.2k
                        pdfi_countdown(value);
332
42.2k
                    }
333
42.2k
                }
334
42.2k
            }
335
48.7k
        }
336
0
        else {
337
0
            code = gs_note_error(gs_error_syntaxerror);
338
0
        }
339
48.7k
    }
340
48.7k
done:
341
    /* We always want to leave here with a valid map dictionary
342
       even if it's empty
343
     */
344
48.7k
    if (cidfmap == true) {
345
6.48k
        if (ctx->pdfcidfmap == NULL) {
346
0
            code = pdfi_dict_alloc(ctx, 0, &ctx->pdfcidfmap);
347
0
            if (code >= 0)
348
0
                pdfi_countup(ctx->pdfcidfmap);
349
0
        }
350
6.48k
    }
351
42.2k
    else {
352
42.2k
        if (ctx->pdffontmap == NULL) {
353
0
            code = pdfi_dict_alloc(ctx, 0, &ctx->pdffontmap);
354
0
            if (code >= 0)
355
0
                pdfi_countup(ctx->pdffontmap);
356
0
        }
357
42.2k
    }
358
48.7k
    if (code >= 0) {
359
48.7k
        code = pdfi_populate_ufst_fontmap(ctx);
360
48.7k
    }
361
#ifdef DUMP_FONTMAP
362
    if (ctx->pdffontmap != NULL) {
363
        uint64_t ind;
364
        int find = -1;
365
        pdf_name *key = NULL;
366
        pdf_obj *v = NULL;
367
        pdf_string *val = NULL;
368
        (void)pdfi_dict_key_first(ctx, ctx->pdffontmap, (pdf_obj **) &key, &ind);
369
        (void)pdfi_dict_get_by_key(ctx, ctx->pdffontmap, key, (pdf_obj **)&v);
370
        for (j = 0; j < key->length; j++)
371
            dprintf1("%c", key->data[j]);
372
        if (pdfi_type_of(v) == PDF_DICT) {
373
            pdf_num *n;
374
            pdf_string *val2;
375
            code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
376
            if (code >= 0 && pdfi_type_of(n) == PDF_INT)
377
                find = n->value.i;
378
            else
379
                code = 0;
380
            (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
381
            val = val2;
382
        }
383
        else {
384
            val = (pdf_string *)v;
385
        }
386
        dprintf(" ");
387
        for (j = 0; j < val->length; j++)
388
            dprintf1("%c", val->data[j]);
389
        if (find != -1) {
390
            dprintf1("  Index = %d", find);
391
            find = -1;
392
        }
393
394
        dprintf("\n");
395
        pdfi_countdown(key);
396
        pdfi_countdown(val);
397
398
        while (pdfi_dict_key_next(ctx, ctx->pdffontmap, (pdf_obj **) &key, &ind) >= 0 && ind > 0) {
399
            (void)pdfi_dict_get_by_key(ctx, ctx->pdffontmap, key, (pdf_obj **)&v);
400
            for (j = 0; j < key->length; j++)
401
                dprintf1("%c", key->data[j]);
402
            if (pdfi_type_of(v) == PDF_DICT) {
403
                pdf_num *n;
404
                pdf_string *val2;
405
                code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
406
                if (code >= 0 && pdfi_type_of(n) == PDF_INT)
407
                    find = n->value.i;
408
                else
409
                    code = 0;
410
                (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
411
                val = val2;
412
            }
413
            else {
414
                val = (pdf_string *)v;
415
            }
416
            dprintf("       ");
417
            for (j = 0; j < val->length; j++)
418
                dprintf1("%c", val->data[j]);
419
            if (find != -1) {
420
                dprintf1("  Index = %d", find);
421
                find = -1;
422
            }
423
            pdfi_countdown(key);
424
            pdfi_countdown(val);
425
            dprintf("\n");
426
        }
427
    }
428
#endif
429
48.7k
    pdfi_clearstack(ctx);
430
48.7k
    return code;
431
48.7k
}
432
433
enum {
434
  no_type_font = -1,
435
  type0_font = 0,
436
  type1_font = 1,
437
  cff_font = 2,
438
  type3_font = 3,
439
  tt_font = 42
440
};
441
442
/* For font file scanning we want to treat OTTO as TTF (rather than, for "normal"
443
   font loading, treat OTTO as CFF, hence we need a different type picker.
444
 */
445
static int pdfi_font_scan_type_picker(byte *buf, int64_t buflen)
446
0
{
447
0
#define MAKEMAGIC(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
448
449
0
    if (buflen >= 4) {
450
0
        if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC(0, 1, 0, 0)
451
0
            || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 'r', 'u', 'e')
452
0
            || MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('t', 't', 'c', 'f')) {
453
0
            return tt_font;
454
0
        }
455
0
        else if (MAKEMAGIC(buf[0], buf[1], buf[2], buf[3]) == MAKEMAGIC('O', 'T', 'T', 'O')) {
456
0
            return tt_font;
457
0
        }
458
0
        else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC('%', '!', 'P', 0)) {
459
0
            return type1_font; /* pfa */
460
0
        }
461
0
        else if (MAKEMAGIC(buf[0], buf[1], buf[2], 0) == MAKEMAGIC(1, 0, 4, 0)) {
462
0
            return cff_font; /* 1C/CFF */
463
0
        }
464
0
        else if (MAKEMAGIC(buf[0], buf[1], 0, 0) == MAKEMAGIC(128, 1, 0, 0)) {
465
0
            return type1_font; /* pfb */
466
0
        }
467
0
    }
468
0
    return no_type_font;
469
0
#undef MAKEMAGIC
470
0
}
471
472
static int pdfi_add__to_native_fontmap(pdf_context *ctx, const char *fontname, const char *filepath, const int index)
473
0
{
474
0
    int code;
475
0
    pdf_string *fpstr;
476
477
0
    if (ctx->pdfnativefontmap == NULL) {
478
        /* 32 is just an arbitrary starting point */
479
0
        code = pdfi_dict_alloc(ctx, 32, &ctx->pdfnativefontmap);
480
0
        if (code < 0)
481
0
            return code;
482
0
        pdfi_countup(ctx->pdfnativefontmap);
483
0
    }
484
    /* index == -1 is a file with a single font in it */
485
0
    if (index == -1) {
486
0
        code = pdfi_object_alloc(ctx, PDF_STRING, strlen(filepath), (pdf_obj **)&fpstr);
487
0
        if (code < 0)
488
0
            return code;
489
0
        pdfi_countup(fpstr);
490
0
        memcpy(fpstr->data, filepath, fpstr->length);
491
0
        code = pdfi_dict_put(ctx, ctx->pdfnativefontmap, fontname, (pdf_obj *)fpstr);
492
0
        pdfi_countdown(fpstr);
493
0
    }
494
0
    else {
495
0
        pdf_dict *recdict;
496
0
        pdf_num *ind;
497
498
0
        code = pdfi_object_alloc(ctx, PDF_DICT, 2, (pdf_obj **)&recdict);
499
0
        if (code < 0)
500
0
            return code;
501
0
        pdfi_countup(recdict);
502
503
0
        code = pdfi_object_alloc(ctx, PDF_STRING, strlen(filepath), (pdf_obj **)&fpstr);
504
0
        if (code < 0) {
505
0
            pdfi_countdown(recdict);
506
0
            return code;
507
0
        }
508
0
        pdfi_countup(fpstr);
509
0
        memcpy(fpstr->data, filepath, fpstr->length);
510
0
        code = pdfi_dict_put(ctx, recdict, "Path", (pdf_obj *)fpstr);
511
0
        pdfi_countdown(fpstr);
512
0
        if (code < 0) {
513
0
            pdfi_countdown(recdict);
514
0
            return code;
515
0
        }
516
517
0
        code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&ind);
518
0
        if (code < 0) {
519
0
            pdfi_countdown(recdict);
520
0
            return code;
521
0
        }
522
0
        ind->value.i = index;
523
0
        pdfi_countup(ind);
524
0
        code = pdfi_dict_put(ctx, recdict, "Index", (pdf_obj *)ind);
525
0
        pdfi_countdown(ind);
526
0
        if (code < 0) {
527
0
            pdfi_countdown(recdict);
528
0
            return code;
529
0
        }
530
0
        code = pdfi_dict_put(ctx, ctx->pdfnativefontmap, fontname, (pdf_obj *)recdict);
531
0
        pdfi_countdown(recdict);
532
0
    }
533
534
0
    return code;
535
0
}
536
537
static inline int
538
pdfi_end_ps_token(int c)
539
0
{
540
0
    return (c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA) || (c == '/')  || (c == '\0');
541
0
}
542
543
/* Naive way to find a Type 1 /FontName key */
544
static int pdfi_type1_add_to_native_map(pdf_context *ctx, stream *f, char *fname, char *pname, int pname_size)
545
0
{
546
0
    gs_string buf;
547
0
    uint count = 0;
548
0
    int code = gs_error_undefined;
549
0
    char *namestr = NULL, *enamestr;
550
0
    char *typestr;
551
0
    bool pin_eol = false; /* initialised just to placate coverity */
552
0
    int type = -1;
553
0
    int lines = 0;
554
0
    buf.data = (byte *)pname;
555
0
    buf.size = pname_size;
556
557
    /* It's not an absolute requirement, but it is a de facto standard that
558
       /FontType and /FontName keys start in column 0 of their lines
559
     */
560
0
    while ((code = sreadline(f, NULL, NULL, NULL, &buf, NULL, &count, &pin_eol, NULL)) >= 0) {
561
0
        lines++;
562
0
        if (lines > 100 || (buf.size >= 17 && memcmp(buf.data, "currentfile eexec", 17) == 0))
563
0
            break;
564
0
        else if (buf.size > 9 && memcmp(buf.data, "/FontName", 9) == 0) {
565
0
            namestr = (char *)buf.data + 9;
566
0
            while (pdfi_end_ps_token(*namestr))
567
0
                namestr++;
568
0
            if (*namestr != '\0') {
569
0
                while(*namestr == 0x20 || *namestr == 0x9)
570
0
                    namestr++;
571
0
                if (*namestr == '/')
572
0
                    namestr++;
573
0
                enamestr = namestr;
574
0
                while(!pdfi_end_ps_token((int)*enamestr))
575
0
                    enamestr++;
576
0
                count = enamestr - namestr > pname_size - 1 ? pname_size - 1 : enamestr - namestr;
577
0
                memmove(pname, namestr, count);
578
0
                pname[count] = '\0';
579
0
                buf.data += count + 1;
580
0
                buf.size -= count + 1;
581
0
                if (type == 1)
582
0
                    break;
583
0
            }
584
0
        }
585
0
        else if (buf.size > 9 && memcmp(buf.data, "/FontType", 9) == 0) {
586
0
            typestr = (char *)buf.data + 9;
587
0
            while (pdfi_end_ps_token(*typestr))
588
0
                typestr++;
589
0
            if (*typestr != '\0') {
590
0
                while(*typestr == 0x20 || *typestr == 0x9)
591
0
                    namestr++;
592
0
                if (*typestr == '/')
593
0
                    typestr++;
594
0
                enamestr = typestr;
595
0
                while(!pdfi_end_ps_token((int)*enamestr))
596
0
                    enamestr++;
597
0
                count = enamestr - typestr > pname_size - 1 ? pname_size - 1 : enamestr - typestr;
598
0
                if (count == 1 && *typestr == '1') {
599
0
                    type = 1;
600
0
                    if (namestr != NULL)
601
0
                        break;
602
0
                }
603
0
            }
604
0
        }
605
0
        count = 0;
606
0
    }
607
0
    if (type == 1 && namestr != NULL) {
608
0
        code = pdfi_add__to_native_fontmap(ctx, (const char *)pname, (const char *)fname, -1);
609
0
    }
610
0
    return code < 0 ? code : gs_error_handled;
611
0
}
612
613
static inline int
614
u16(const byte *p)
615
0
{
616
0
    return (p[0] << 8) | p[1];
617
0
}
618
619
static inline int
620
sru16(stream *s)
621
0
{
622
0
    byte p[2];
623
0
    int code = sfread(p, 1, 2, s);
624
625
0
    if (code < 0)
626
0
        return 0;
627
628
0
    return u16(p);
629
0
}
630
631
static inline int
632
u32(const byte *p)
633
0
{
634
0
    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
635
0
}
636
637
static inline int
638
sru32(stream *s)
639
0
{
640
0
    byte p[4];
641
0
    int code = sfread(p, 1, 4, s);
642
0
    if (code < 0)
643
0
        return 0;
644
645
0
    return u32(p);
646
0
}
647
648
static int pdfi_ttf_add_to_native_map(pdf_context *ctx, stream *f, byte magic[4], char *fname, char *pname, int pname_size)
649
0
{
650
0
    int ntables, i, j, k, code2, code = gs_error_undefined;
651
0
    char table[4];
652
0
    int nte, storageOffset;
653
0
    bool include_index = false;
654
0
    uint32_t nfonts = 1, tableoffs;
655
0
    int findex;
656
0
    gs_offset_t l;
657
658
0
    code2 = sfseek(f, 0, SEEK_END);
659
0
    if (code2 < 0)
660
0
        return code;
661
0
    l = stell(f);
662
    /* 4 to skip the magic number */
663
0
    code2 = sfseek(f, 4, SEEK_SET);
664
0
    if (code2 < 0)
665
0
        return code;
666
667
0
    if (memcmp(magic, "ttcf", 4) == 0) {
668
0
        uint32_t ver;
669
0
        include_index = true;
670
0
        ver = sru32(f);
671
0
        if (ver != 0x00010000 && ver !=0x00020000) {
672
0
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_invalidaccess), NULL, E_PDF_BAD_TTC_VERSION, "pdfi_ttf_add_to_native_map", NULL);
673
0
            outprintf(ctx->memory, "Unknown TTC header version %08X.\n", ver);
674
0
            return code;
675
0
        }
676
0
        nfonts = sru32(f);
677
        /* There isn't a specific limit on the number of fonts,
678
           freetype limits to 255, so we'll do the same here
679
         */
680
0
        if (nfonts > 255)
681
0
            return_error(gs_error_invalidfont);
682
0
    }
683
684
0
    for (findex = 0; findex < nfonts; findex++) {
685
0
        if (include_index == true ) {
686
0
            if (findex * 4 > l)
687
0
                break;
688
0
            code2 = sfseek(f, findex * 4, SEEK_CUR);
689
0
            if (code2 < 0)
690
0
                return code2;
691
692
0
            tableoffs = sru32(f);
693
0
            if (tableoffs + 4 > l)
694
0
                break;
695
0
            code2 = sfseek(f, tableoffs + 4, SEEK_SET);
696
0
            if (code2 < 0)
697
0
                return code2;
698
0
        }
699
700
0
        ntables = sru16(f);
701
        /* Similar to above - no spec limit, but we do the same
702
           as freetype
703
         */
704
0
        if (ntables > 255)
705
0
            continue;
706
707
        /* Skip the remainder of the invariant header bytes */
708
0
        (void)sru16(f);
709
0
        (void)sru32(f);
710
711
0
        for (i = 0, code2 = 0; i < ntables && code2 >= 0; i++) {
712
0
            if (stell(f) + 4 > l) {
713
0
                code2 = gs_error_ioerror;
714
0
                continue;
715
0
            }
716
0
            code2 = sfread(table, 1, 4, f);
717
0
            if (code2 < 0)
718
0
                return code2;
719
0
            if (!memcmp(table, "name", 4)) {
720
0
                uint table_pos, table_len;
721
0
                byte *namet;
722
0
                (void)sru32(f); /* skip checksum */
723
724
0
                table_pos = sru32(f);
725
0
                table_len = sru32(f);
726
0
                if (table_pos + table_len > l) {
727
0
                    code2 = gs_error_ioerror;
728
0
                    continue;
729
0
                }
730
731
0
                code2 = sfseek(f, table_pos, SEEK_SET);
732
0
                if (code2 < 0)
733
0
                    continue;
734
735
0
                namet = (byte *)gs_alloc_bytes(ctx->memory, table_len, "pdfi_ttf_add_to_native_map");
736
0
                if (namet == NULL)
737
0
                    return_error(gs_error_VMerror);
738
0
                code2 = sfread(namet, 1, table_len, f);
739
0
                if (code2 < 0) {
740
0
                    gs_free_object(ctx->memory, namet,"pdfi_ttf_add_to_native_map");
741
0
                    continue;
742
0
                }
743
0
                nte = u16(namet + 2);
744
                /* Again, arbitrary limit... */
745
0
                if (nte > 255) {
746
0
                    gs_free_object(ctx->memory, namet,"pdfi_ttf_add_to_native_map");
747
0
                    continue;
748
0
                }
749
0
                storageOffset = u16(namet + 4);
750
751
0
                for (j = 0; j < nte; j++) {
752
0
                    byte *rec = namet + 6 + j * 12;
753
0
                    if (u16(rec + 6) == 6) {
754
0
                        int pid = u16(rec);
755
0
                        int eid = u16(rec + 2);
756
0
                        int nl = u16(rec + 8);
757
0
                        int noffs = u16(rec + 10);
758
759
0
                        if (nl + noffs + storageOffset > table_len || nl >= pname_size) {
760
0
                            break;
761
0
                        }
762
0
                        memcpy(pname, namet + storageOffset + noffs, nl);
763
0
                        pname[nl] = '\0';
764
0
                        if ((pid == 0 || (pid == 2 && eid == 1) || (pid == 3 && eid == 1)) && (nl % 2) == 0) {
765
0
                            for (k = 0; k < nl; k += 2) {
766
0
                                if (pname[k] != '\0')
767
0
                                    break;
768
0
                            }
769
0
                            if (k == nl) {
770
0
                                int k1, k2;
771
0
                                for (k1 = 0, k2 = 1; k2 < nl; k1++, k2 += 2) {
772
0
                                    pname[k1] = pname[k2];
773
0
                                }
774
0
                                nl = nl >> 1;
775
0
                                pname[nl] = '\0';
776
0
                            }
777
0
                        }
778
779
0
                        for (k = 0; k < nl; k++)
780
0
                            if (pname[k] < 32 || pname[k] > 126) /* is it a valid PS name? */
781
0
                                break;
782
0
                        if (k == nl) {
783
0
                            code = 0;
784
0
                            break;
785
0
                       }
786
0
                    }
787
0
                }
788
0
                if (code == gs_error_undefined) {
789
0
                    for (j = 0; j < nte; j++) {
790
0
                        byte *rec = namet + 6 + j * 12;
791
0
                        if (u16(rec + 6) == 4) {
792
0
                            int pid = u16(rec);
793
0
                            int eid = u16(rec + 2);
794
0
                            int nl = u16(rec + 8);
795
0
                            int noffs = u16(rec + 10);
796
797
0
                            if (nl + noffs + storageOffset > table_len || nl >= pname_size) {
798
0
                                break;
799
0
                            }
800
0
                            memcpy(pname, namet + storageOffset + noffs, nl);
801
0
                            pname[nl] = '\0';
802
0
                            if ((pid == 0 || (pid == 2 && eid == 1) || (pid == 3 && eid == 1)) && (nl % 2) == 0) {
803
0
                                for (k = 0; k < nl; k += 2) {
804
0
                                    if (pname[k] != '\0')
805
0
                                        break;
806
0
                                }
807
0
                                if (k == nl) {
808
0
                                    int k1, k2;
809
0
                                    for (k1 = 0, k2 = 1; k2 < nl; k1++, k2 += 2) {
810
0
                                        pname[k1] = pname[k2];
811
0
                                    }
812
0
                                    nl = nl >> 1;
813
0
                                    pname[nl] = '\0';
814
0
                                }
815
0
                            }
816
0
                            for (k = 0; k < nl; k++)
817
0
                                if (pname[k] < 32 || pname[k] > 126) /* is it a valid PS name? */
818
0
                                    break;
819
0
                            if (k == nl)
820
0
                                code = 0;
821
0
                            break;
822
0
                        }
823
0
                    }
824
0
                }
825
0
                gs_free_object(ctx->memory, namet, "pdfi_ttf_add_to_native_map");
826
0
                break;
827
0
            }
828
0
            else {
829
0
                sfseek(f, 12, SEEK_CUR);
830
0
            }
831
0
        }
832
0
        if (code >= 0)
833
0
            code = pdfi_add__to_native_fontmap(ctx, (const char *)pname, (const char *)fname, (include_index == true ? findex : -1));
834
0
    }
835
0
    return code;
836
0
}
837
838
static const char *font_scan_skip_list[] = {
839
  ".afm",
840
  ".bat",
841
  ".c",
842
  ".cmd",
843
  ".com",
844
  ".dir",
845
  ".dll",
846
  ".doc",
847
  ".drv",
848
  ".exe",
849
  ".fon",
850
  ".fot",
851
  ".h",
852
  ".o",
853
  ".obj",
854
  ".pfm",
855
  ".pss",
856
  ".txt",
857
  ".gz",
858
  ".pcf"
859
};
860
861
static bool font_scan_skip_file(const char *fname)
862
0
{
863
0
    size_t l2, l = strlen(fname);
864
0
    bool skip = false;
865
0
    int i;
866
867
0
    for (i = 0; i < (sizeof(font_scan_skip_list)/sizeof(*font_scan_skip_list)); i++) {
868
0
        l2 = strlen(font_scan_skip_list[i]);
869
0
        if (memcmp(font_scan_skip_list[i], fname + l - l2, l2) == 0) {
870
0
            skip = true;
871
0
            break;
872
0
        }
873
0
    }
874
0
    return skip;
875
0
}
876
877
static int pdfi_add_font_to_native_map(pdf_context *ctx, const char *fp, char *working)
878
0
{
879
0
    stream *sf;
880
0
    int code = 0;
881
0
    uint nread;
882
0
    byte magic[4]; /* We only (currently) use up to 4 bytes for type guessing */
883
0
    int type;
884
885
0
    if (font_scan_skip_file(fp))
886
0
        return 0;
887
888
0
    sf = sfopen(fp, "r", ctx->memory);
889
0
    if (sf == NULL)
890
0
        return 0;
891
0
    code = sgets(sf, magic, 4, &nread);
892
0
    if (code < 0 || nread < 4) {
893
0
        code = 0;
894
0
        sfclose(sf);
895
0
        return 0;
896
0
    }
897
898
0
    code = sfseek(sf, 0, SEEK_SET);
899
0
    if (code < 0) {
900
0
        code = 0;
901
0
        sfclose(sf);
902
0
        return 0;
903
0
    }
904
    /* Slightly naff: in this one case, we want to treat OTTO fonts
905
       as Truetype, so we lookup the TTF 'name' table - it's more efficient
906
       than decoding the CFF, and probably will give more expected results
907
     */
908
0
    if (memcmp(magic, "OTTO", 4) == 0 || memcmp(magic, "ttcf", 4) == 0) {
909
0
        type = tt_font;
910
0
    }
911
0
    else {
912
0
        type = pdfi_font_scan_type_picker((byte *)magic, 4);
913
0
    }
914
0
    switch(type) {
915
0
        case tt_font:
916
0
          code = pdfi_ttf_add_to_native_map(ctx, sf, magic, (char *)fp, working, gp_file_name_sizeof);
917
0
          break;
918
0
        case cff_font:
919
0
              code = gs_error_undefined;
920
0
          break;
921
0
        case type1_font:
922
0
          code = pdfi_type1_add_to_native_map(ctx, sf, (char *)fp, working, gp_file_name_sizeof);
923
0
          break;
924
0
        default:
925
0
          break;
926
0
    }
927
0
    sfclose(sf);
928
    /* We ignore most errors, on the basis it probably means it wasn't a valid font file */
929
0
    if (code != gs_error_VMerror)
930
0
        code = 0;
931
932
0
    return code;
933
0
}
934
935
/* still writes into pdfnativefontmap dictionary */
936
static int pdfi_generate_platform_fontmap(pdf_context *ctx)
937
2.22M
{
938
2.22M
    void *enum_state = NULL;
939
2.22M
    int code = 0;
940
2.22M
    char *fontname, *path;
941
2.22M
    char *working = NULL;
942
943
2.22M
    working = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_platform_fontmap");
944
2.22M
    if (working == NULL) {
945
0
        code = gs_note_error(gs_error_VMerror);
946
0
        goto done;
947
0
    }
948
949
2.22M
    enum_state = gp_enumerate_fonts_init(ctx->memory);
950
2.22M
    if (enum_state == NULL) {
951
2.22M
        code = gs_note_error(gs_error_VMerror);
952
2.22M
        goto done;
953
2.22M
    }
954
955
0
    while((code = gp_enumerate_fonts_next(enum_state, &fontname, &path )) > 0) {
956
0
        if (fontname == NULL || path == NULL) {
957
0
            continue;
958
0
        }
959
0
        code = pdfi_add_font_to_native_map(ctx, path, working);
960
961
        /* We ignore most errors, on the basis it probably means it wasn't a valid font file */
962
0
        if (code == gs_error_VMerror)
963
0
            break;
964
0
        code = 0;
965
0
    }
966
2.22M
done:
967
2.22M
    gp_enumerate_fonts_free(enum_state);
968
2.22M
    gs_free_object(ctx->memory, working, "pdfi_generate_platform_fontmap");
969
2.22M
    return code;
970
0
}
971
972
static int pdfi_generate_native_fontmap(pdf_context *ctx)
973
2.22M
{
974
2.22M
    file_enum *fe;
975
2.22M
    int i;
976
2.22M
    char *patrn= NULL;
977
2.22M
    char *result = NULL;
978
2.22M
    char *working = NULL;
979
2.22M
    int code = 0, l;
980
981
2.22M
    if (ctx->pdfnativefontmap != NULL) /* Only run this once */
982
0
        return 0;
983
2.22M
    if (ctx->args.nonativefontmap == true) {
984
        /* Basically create an empty dictionary */
985
0
        code = pdfi_dict_alloc(ctx, 1, &ctx->pdfnativefontmap);
986
0
        if (code < 0)
987
0
            return code;
988
0
        pdfi_countup(ctx->pdfnativefontmap);
989
0
        return 0;
990
0
    }
991
992
2.22M
    (void)pdfi_generate_platform_fontmap(ctx);
993
994
2.22M
    patrn = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
995
2.22M
    result = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
996
2.22M
    working = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
997
2.22M
    if (patrn == NULL || result == NULL || working == NULL) {
998
0
        gs_free_object(ctx->memory, patrn, "pdfi_generate_native_fontmap");
999
0
        gs_free_object(ctx->memory, result, "pdfi_generate_native_fontmap");
1000
0
        gs_free_object(ctx->memory, working, "pdfi_generate_native_fontmap");
1001
0
        return_error(gs_error_VMerror);
1002
0
    }
1003
1004
2.22M
    for (i = 0; i < ctx->search_paths.num_font_paths; i++) {
1005
1006
0
        memcpy(patrn, ctx->search_paths.font_paths[i].data, ctx->search_paths.font_paths[i].size);
1007
0
        memcpy(patrn + ctx->search_paths.font_paths[i].size, "/*", 2);
1008
0
        patrn[ctx->search_paths.font_paths[i].size + 2] = '\0';
1009
1010
0
        fe = gp_enumerate_files_init(ctx->memory, (const char *)patrn, strlen(patrn));
1011
0
        while ((l = gp_enumerate_files_next(ctx->memory, fe, result, gp_file_name_sizeof - 1)) != ~(uint) 0) {
1012
0
            result[l] = '\0';
1013
1014
0
            code = pdfi_add_font_to_native_map(ctx, result, working);
1015
1016
            /* We ignore most errors, on the basis it probably means it wasn't a valid font file */
1017
0
            if (code == gs_error_VMerror)
1018
0
                break;
1019
0
            code = 0;
1020
0
        }
1021
        /* We only need to explicitly destroy the enumerator if we exit before enumeration is complete */
1022
0
        if (code < 0)
1023
0
            gp_enumerate_files_close(ctx->memory, fe);
1024
0
    }
1025
1026
#ifdef DUMP_NATIVE_FONTMAP
1027
    if (ctx->pdfnativefontmap != NULL) {
1028
        uint64_t ind;
1029
        int find = -1;
1030
        pdf_name *key = NULL;
1031
        pdf_obj *v = NULL;
1032
        pdf_string *val = NULL;
1033
        (void)pdfi_dict_key_first(ctx, ctx->pdfnativefontmap, (pdf_obj **) &key, &ind);
1034
        (void)pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, key, (pdf_obj **)&v);
1035
        for (j = 0; j < key->length; j++)
1036
            dprintf1("%c", key->data[j]);
1037
        if (pdfi_type_of(v) == PDF_DICT) {
1038
            pdf_num *n;
1039
            pdf_string *val2;
1040
            code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
1041
            if (code >= 0 && pdfi_type_of(n) == PDF_INT)
1042
                find = n->value.i;
1043
            else
1044
                code = 0;
1045
            (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
1046
            val = val2;
1047
        }
1048
        else {
1049
            val = (pdf_string *)v;
1050
        }
1051
        dprintf(" ");
1052
        for (j = 0; j < val->length; j++)
1053
            dprintf1("%c", val->data[j]);
1054
        if (find != -1) {
1055
            dprintf1("  Index = %d", find);
1056
            find = -1;
1057
        }
1058
1059
        dprintf("\n");
1060
        pdfi_countdown(key);
1061
        pdfi_countdown(val);
1062
1063
        while (pdfi_dict_key_next(ctx, ctx->pdfnativefontmap, (pdf_obj **) &key, &ind) >= 0 && ind > 0) {
1064
            (void)pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, key, (pdf_obj **)&v);
1065
            for (j = 0; j < key->length; j++)
1066
                dprintf1("%c", key->data[j]);
1067
            if (pdfi_type_of(v) == PDF_DICT) {
1068
                pdf_num *n;
1069
                pdf_string *val2;
1070
                code = pdfi_dict_get(ctx, (pdf_dict *)v, "Index", (pdf_obj **)&n);
1071
                if (code >= 0 && pdfi_type_of(n) == PDF_INT)
1072
                    find = n->value.i;
1073
                else
1074
                    code = 0;
1075
                (void)pdfi_dict_get(ctx, (pdf_dict *)v, "Path", (pdf_obj **)&val2);
1076
                val = val2;
1077
            }
1078
            else {
1079
                val = (pdf_string *)v;
1080
            }
1081
            dprintf("       ");
1082
            for (j = 0; j < val->length; j++)
1083
                dprintf1("%c", val->data[j]);
1084
            if (find != -1) {
1085
                dprintf1("  Index = %d", find);
1086
                find = -1;
1087
            }
1088
            pdfi_countdown(key);
1089
            pdfi_countdown(val);
1090
            dprintf("\n");
1091
        }
1092
    }
1093
#endif
1094
1095
2.22M
    gs_free_object(ctx->memory, patrn, "pdfi_generate_native_fontmap");
1096
2.22M
    gs_free_object(ctx->memory, result, "pdfi_generate_native_fontmap");
1097
2.22M
    gs_free_object(ctx->memory, working, "pdfi_generate_native_fontmap");
1098
2.22M
    return 0;
1099
2.22M
}
1100
1101
int
1102
pdfi_fontmap_lookup_font(pdf_context *ctx, pdf_dict *font_dict, pdf_name *fname, pdf_obj **mapname, int *findex)
1103
2.22M
{
1104
2.22M
    int code;
1105
2.22M
    pdf_obj *mname;
1106
1107
2.22M
    *findex = 0;
1108
1109
2.22M
    if (ctx->pdffontmap == NULL) {
1110
42.2k
        const char *fmap_default = "Fontmap.GS";
1111
42.2k
        char *fmapname = (char *)fmap_default;
1112
42.2k
        code = pdf_make_fontmap(ctx, fmapname, false);
1113
42.2k
        if (code < 0) {
1114
0
            return code;
1115
0
        }
1116
42.2k
    }
1117
2.22M
    if (ctx->pdfnativefontmap == NULL) {
1118
2.22M
        code = pdfi_generate_native_fontmap(ctx);
1119
2.22M
        if (code < 0)
1120
0
            return code;
1121
2.22M
    }
1122
2.22M
    code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, fname, &mname);
1123
2.22M
    if (code >= 0) {
1124
        /* Fontmap can map in multiple "jump" i.e.
1125
           name -> substitute name
1126
           subsitute name -> file name
1127
           So we want to loop until we no more hits.
1128
           With "predefined fonts" in the fontmap, as in with UFST, we can
1129
           have a an actual font, as well as a name or string (file name).
1130
         */
1131
484k
         while(pdfi_type_of(mname) != PDF_FONT) {
1132
484k
             pdf_obj *mname2;
1133
484k
             code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, (pdf_name *)mname, &mname2);
1134
484k
             if (code < 0) {
1135
483k
                 code = 0;
1136
483k
                 break;
1137
483k
             }
1138
357
             pdfi_countdown(mname);
1139
357
             mname = mname2;
1140
357
         }
1141
483k
    }
1142
1143
2.22M
    if (code < 0 && ctx->pdfnativefontmap != NULL) {
1144
0
        pdf_obj *record;
1145
0
        code = pdfi_dict_get_by_key(ctx, ctx->pdfnativefontmap, fname, &record);
1146
0
        if (code >= 0) {
1147
0
            if (pdfi_type_of(record) == PDF_STRING) {
1148
0
                mname = record;
1149
0
            }
1150
0
            else if (pdfi_type_of(record) == PDF_DICT) {
1151
0
                int64_t i64;
1152
0
                code = pdfi_dict_get(ctx, (pdf_dict *)record, "Path", &mname);
1153
0
                if (code >= 0)
1154
0
                    code = pdfi_dict_get_int(ctx, (pdf_dict *)record, "Index", &i64);
1155
0
                if (code < 0) {
1156
0
                    pdfi_countdown(record);
1157
0
                    return code;
1158
0
                }
1159
0
                *findex = (int)i64; /* Rangecheck? */
1160
0
            }
1161
0
            else {
1162
0
                pdfi_countdown(record);
1163
0
                code = gs_error_undefined;
1164
0
            }
1165
0
        }
1166
0
    }
1167
2.22M
    else {
1168
2.22M
        code = gs_error_undefined;
1169
2.22M
    }
1170
1171
2.22M
    if (mname != NULL && pdfi_type_of(mname) == PDF_STRING && pdfi_fmap_file_exists(ctx, (pdf_string *)mname)) {
1172
0
        *mapname = mname;
1173
0
        (void)pdfi_dict_put(ctx, font_dict, ".Path", mname);
1174
0
        code = 0;
1175
0
    }
1176
2.22M
    else if (mname != NULL && (pdfi_type_of(mname) == PDF_NAME || pdfi_type_of(mname) == PDF_FONT)) { /* If we map to a name, we assume (for now) we have the font as a "built-in" */
1177
483k
        *mapname = mname;
1178
483k
        code = 0;
1179
483k
    }
1180
1.74M
    else {
1181
1.74M
        pdfi_countdown(mname);
1182
1.74M
        code = gs_note_error(gs_error_undefined);
1183
1.74M
    }
1184
2.22M
    return code;
1185
2.22M
}
1186
1187
int
1188
pdfi_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name, pdf_obj **mapname, int *findex)
1189
58.7k
{
1190
58.7k
    int code = 0;
1191
58.7k
    pdf_obj *cidname = NULL;
1192
58.7k
    pdf_obj *mname;
1193
1194
58.7k
    *findex = 0;
1195
1196
58.7k
    if (ctx->pdfcidfmap == NULL) {
1197
6.48k
        const char *cidfmap_default = "cidfmap";
1198
6.48k
        char *cidfmapname = (char *)cidfmap_default;
1199
6.48k
        code = pdf_make_fontmap(ctx, cidfmapname, true);
1200
6.48k
        if (code < 0) {
1201
0
            return code;
1202
0
        }
1203
6.48k
    }
1204
58.7k
    if (name == NULL || pdfi_type_of(name) != PDF_NAME) {
1205
30.8k
        code = pdfi_dict_get(ctx, font_dict, "BaseFont", &cidname);
1206
30.8k
        if (code < 0 || pdfi_type_of(cidname) != PDF_NAME) {
1207
564
            pdfi_countdown(cidname);
1208
564
            return_error(gs_error_undefined);
1209
564
        }
1210
1211
30.8k
    }
1212
27.8k
    else {
1213
27.8k
        cidname = (pdf_obj *)name;
1214
27.8k
        pdfi_countup(cidname);
1215
27.8k
    }
1216
1217
58.2k
    code = pdfi_dict_get_by_key(ctx, ctx->pdfcidfmap, (pdf_name *)cidname, &mname);
1218
58.2k
    pdfi_countdown(cidname);
1219
58.2k
    if (code < 0)
1220
58.2k
        return code;
1221
    /* As above cidfmap can map in multiple "jump" i.e.
1222
       name -> substitute name
1223
       subsitute name -> "record"
1224
       So we want to loop until we no more hits.
1225
     */
1226
0
    while(1) {
1227
0
        pdf_obj *mname2;
1228
0
        code = pdfi_dict_get_by_key(ctx, ctx->pdfcidfmap, (pdf_name *)mname, &mname2);
1229
0
        if (code < 0) break;
1230
0
        pdfi_countdown(mname);
1231
0
        mname = mname2;
1232
0
    }
1233
0
    if (pdfi_type_of(mname) == PDF_DICT) {
1234
0
        pdf_dict *rec = (pdf_dict *)mname;
1235
0
        pdf_name *filetype;
1236
0
        pdf_name *path = NULL;
1237
0
        int64_t i64;
1238
1239
0
        code = pdfi_dict_get(ctx, rec, "FileType", (pdf_obj **)&filetype);
1240
        /* We only handle TTF files, just now */
1241
0
        if (code < 0 || pdfi_type_of(filetype) != PDF_NAME || filetype->length != 8 || memcmp(filetype->data, "TrueType", 8) != 0) {
1242
0
            pdfi_countdown(filetype);
1243
0
            pdfi_countdown(rec);
1244
0
            return_error(gs_error_undefined);
1245
0
        }
1246
0
        pdfi_countdown(filetype);
1247
1248
0
        code = pdfi_dict_get(ctx, rec, "Path", (pdf_obj **)&path);
1249
0
        if (code < 0 || pdfi_type_of(path) != PDF_STRING || !pdfi_fmap_file_exists(ctx, (pdf_string *)path)) {
1250
0
            pdfi_countdown(rec);
1251
0
            return_error(gs_error_undefined);
1252
0
        }
1253
1254
0
        *mapname = (pdf_obj *)path;
1255
0
        (void)pdfi_dict_put(ctx, font_dict, ".Path", (pdf_obj *)path);
1256
0
        code = pdfi_dict_get_int(ctx, rec, "SubfontID", &i64);
1257
0
        *findex = (code < 0) ? 0 : (int)i64; /* rangecheck? */
1258
0
        code = 0;
1259
1260
0
    }
1261
0
    else {
1262
0
        *mapname = (pdf_obj *)mname;
1263
0
        code = 0;
1264
0
    }
1265
1266
0
    return code;
1267
0
}