Coverage Report

Created: 2026-04-09 07:06

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
41.2k
{
54
41.2k
    int code = 0;
55
41.2k
    stream *s;
56
41.2k
    char fname[gp_file_name_sizeof];
57
41.2k
    const char *path_pfx = "Init/";
58
41.2k
    const char *poststring = "\nendstream";
59
41.2k
    const int poststringlen = strlen(poststring);
60
41.2k
    fname[0] = '\0';
61
62
41.2k
    if (strlen(path_pfx) + strlen(mapfilename) + 1 > gp_file_name_sizeof)
63
0
        return_error(gs_error_invalidfileaccess);
64
65
41.2k
    code = pdfi_open_resource_file(ctx, mapfilename, strlen(mapfilename), &s);
66
41.2k
    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
41.2k
    if (code >= 0) {
73
41.2k
        int i;
74
41.2k
        int64_t file_size;
75
76
41.2k
        sfseek(s, 0, SEEK_END);
77
41.2k
        file_size = sftell(s);
78
41.2k
        sfseek(s, 0, SEEK_SET);
79
41.2k
        if (file_size < 0 || file_size > max_int - poststringlen) {
80
0
            code = gs_note_error(gs_error_ioerror);
81
41.2k
        } else {
82
41.2k
            byte *dbuf;
83
41.2k
            *buflen = (int)file_size;
84
85
41.2k
            (*buf) = gs_alloc_bytes(ctx->memory, (size_t)*buflen + poststringlen, "pdf_cmap_open_file(buf)");
86
41.2k
            if (*buf != NULL) {
87
41.2k
                sfread((*buf), 1, *buflen, s);
88
41.2k
                memcpy((*buf) + *buflen, poststring, poststringlen);
89
41.2k
                *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
131M
                for (i = 0, dbuf = *buf; i < *buflen - 1; i++, dbuf++) {
96
131M
                    if (*dbuf == ';') {
97
3.55M
                        *dbuf = ' ';
98
3.55M
                    }
99
131M
                    if (memcmp(dbuf, "cvn ", 4) == 0) {
100
0
                        dbuf[0] = dbuf[1] = dbuf[2] = 0x20;
101
0
                    }
102
131M
                }
103
41.2k
            }
104
0
            else {
105
0
                code = gs_note_error(gs_error_VMerror);
106
0
            }
107
41.2k
        }
108
41.2k
        sfclose(s);
109
41.2k
    }
110
41.2k
    return code;
111
41.2k
}
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
41.2k
{
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
41.2k
    return 0;
237
41.2k
}
238
239
static int
240
pdf_make_fontmap(pdf_context *ctx, const char *default_fmapname, int cidfmap)
241
41.2k
{
242
41.2k
    byte *fmapbuf = NULL;
243
41.2k
    int code, fmapbuflen;
244
41.2k
    pdf_c_stream *fmapstr = NULL;
245
41.2k
    pdf_stream fakedict = {0};
246
41.2k
    pdfi_custom_fmap_entry *pcfe = pdfi_custom_fmap_entries;
247
41.2k
    int i, j = 0;
248
41.2k
    char fmapname[gp_file_name_sizeof];
249
41.2k
    pdf_c_stream fakemainstream = {0};
250
41.2k
    int stacksize = pdfi_count_stack(ctx);
251
252
41.2k
    strncpy(fmapname, default_fmapname, strlen(default_fmapname) + 1);
253
254
41.2k
    code = pdfi_mark_stack(ctx, PDF_DICT_MARK);
255
41.2k
    if (code < 0)
256
0
        goto done;
257
258
41.2k
    do {
259
41.2k
        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
41.2k
        code = pdfi_fontmap_open_file(ctx, (const char *)fmapname, &fmapbuf, &fmapbuflen);
265
41.2k
        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
41.2k
        else {
278
41.2k
            code = pdfi_open_memory_stream_from_memory(ctx, fmapbuflen, fmapbuf, &fmapstr, true);
279
41.2k
            if (code >= 0) {
280
281
41.2k
                if (ctx->main_stream == NULL) {
282
0
                    ctx->main_stream = &fakemainstream;
283
0
                }
284
285
41.2k
                if (fmapbuflen > 0)
286
41.2k
                    code = pdfi_interpret_content_stream(ctx, fmapstr, &fakedict, NULL);
287
0
                else
288
0
                    code = 0;
289
290
41.2k
                if (ctx->main_stream == &fakemainstream) {
291
0
                    ctx->main_stream = NULL;
292
0
                }
293
41.2k
                gs_free_object(ctx->memory, fmapbuf, "pdf_make_fontmap(fmapbuf)");
294
41.2k
            }
295
41.2k
        }
296
41.2k
        j++;
297
41.2k
    } while(j < ctx->num_fontmapfiles && cidfmap == false && code >= 0);
298
299
41.2k
    if (code >= 0) {
300
41.2k
        if (pdfi_count_stack(ctx) > stacksize) {
301
41.2k
            code = pdfi_dict_from_stack(ctx, 0, 0, true);
302
41.2k
            if (code < 0)
303
0
                goto done;
304
305
41.2k
            if (cidfmap == true) {
306
5.36k
                ctx->pdfcidfmap = (pdf_dict *)ctx->stack_top[-1];
307
5.36k
                pdfi_countup(ctx->pdfcidfmap);
308
5.36k
            }
309
35.8k
            else {
310
35.8k
                ctx->pdffontmap = (pdf_dict *)ctx->stack_top[-1];
311
35.8k
                pdfi_countup(ctx->pdffontmap);
312
35.8k
            }
313
41.2k
            pdfi_pop(ctx, 1);
314
41.2k
            code = 0;
315
316
            /* Add our internal aliases to the fontmap. */
317
41.2k
            if (cidfmap == false) {
318
71.7k
                for (i = 0; pcfe[i].keyname != NULL; i++) {
319
35.8k
                    pdf_obj *value;
320
35.8k
                    bool k;
321
322
                    /* We don't want to *replace* entries */
323
35.8k
                    if (pdfi_dict_known(ctx, ctx->pdffontmap, pcfe[i].keyname, &k) >= 0
324
35.8k
                        && k != true) {
325
35.8k
                        code = pdfi_name_alloc(ctx, (byte *)pcfe[i].mappedname, strlen(pcfe[i].mappedname), &value);
326
35.8k
                        if (code < 0)
327
0
                            continue;
328
35.8k
                        pdfi_countup(value);
329
                        /* If dict_put throws an error, we just carry on - hence the (void) */
330
35.8k
                        (void)pdfi_dict_put(ctx,  ctx->pdffontmap, pcfe[i].keyname, value);
331
35.8k
                        pdfi_countdown(value);
332
35.8k
                    }
333
35.8k
                }
334
35.8k
            }
335
41.2k
        }
336
0
        else {
337
0
            code = gs_note_error(gs_error_syntaxerror);
338
0
        }
339
41.2k
    }
340
41.2k
done:
341
    /* We always want to leave here with a valid map dictionary
342
       even if it's empty
343
     */
344
41.2k
    if (cidfmap == true) {
345
5.36k
        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
5.36k
    }
351
35.8k
    else {
352
35.8k
        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
35.8k
    }
358
41.2k
    if (code >= 0) {
359
41.2k
        code = pdfi_populate_ufst_fontmap(ctx);
360
41.2k
    }
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
41.2k
    pdfi_clearstack(ctx);
430
41.2k
    return code;
431
41.2k
}
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
1.99M
{
938
1.99M
    void *enum_state = NULL;
939
1.99M
    int code = 0;
940
1.99M
    char *fontname, *path;
941
1.99M
    char *working = NULL;
942
943
1.99M
    working = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_platform_fontmap");
944
1.99M
    if (working == NULL) {
945
0
        code = gs_note_error(gs_error_VMerror);
946
0
        goto done;
947
0
    }
948
949
1.99M
    enum_state = gp_enumerate_fonts_init(ctx->memory);
950
1.99M
    if (enum_state == NULL) {
951
1.99M
        code = gs_note_error(gs_error_VMerror);
952
1.99M
        goto done;
953
1.99M
    }
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
1.99M
done:
967
1.99M
    gp_enumerate_fonts_free(enum_state);
968
1.99M
    gs_free_object(ctx->memory, working, "pdfi_generate_platform_fontmap");
969
1.99M
    return code;
970
0
}
971
972
static int pdfi_generate_native_fontmap(pdf_context *ctx)
973
1.99M
{
974
1.99M
    file_enum *fe;
975
1.99M
    int i;
976
1.99M
    char *patrn= NULL;
977
1.99M
    char *result = NULL;
978
1.99M
    char *working = NULL;
979
1.99M
    int code = 0, l;
980
981
1.99M
    if (ctx->pdfnativefontmap != NULL) /* Only run this once */
982
0
        return 0;
983
1.99M
    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
1.99M
    (void)pdfi_generate_platform_fontmap(ctx);
993
994
1.99M
    patrn = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
995
1.99M
    result = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
996
1.99M
    working = (char *)gs_alloc_bytes(ctx->memory, gp_file_name_sizeof, "pdfi_generate_native_fontmap");
997
1.99M
    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
1.99M
    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
1.99M
    gs_free_object(ctx->memory, patrn, "pdfi_generate_native_fontmap");
1096
1.99M
    gs_free_object(ctx->memory, result, "pdfi_generate_native_fontmap");
1097
1.99M
    gs_free_object(ctx->memory, working, "pdfi_generate_native_fontmap");
1098
1.99M
    return 0;
1099
1.99M
}
1100
1101
int
1102
pdfi_fontmap_lookup_font(pdf_context *ctx, pdf_dict *font_dict, pdf_name *fname, pdf_obj **mapname, int *findex)
1103
1.99M
{
1104
1.99M
    int code;
1105
1.99M
    pdf_obj *mname;
1106
1107
1.99M
    *findex = 0;
1108
1109
1.99M
    if (ctx->pdffontmap == NULL) {
1110
35.8k
        const char *fmap_default = "Fontmap.GS";
1111
35.8k
        char *fmapname = (char *)fmap_default;
1112
35.8k
        code = pdf_make_fontmap(ctx, fmapname, false);
1113
35.8k
        if (code < 0) {
1114
0
            return code;
1115
0
        }
1116
35.8k
    }
1117
1.99M
    if (ctx->pdfnativefontmap == NULL) {
1118
1.99M
        code = pdfi_generate_native_fontmap(ctx);
1119
1.99M
        if (code < 0)
1120
0
            return code;
1121
1.99M
    }
1122
1.99M
    code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, fname, &mname);
1123
1.99M
    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
432k
         while(pdfi_type_of(mname) != PDF_FONT) {
1132
432k
             pdf_obj *mname2;
1133
432k
             code = pdfi_dict_get_by_key(ctx, ctx->pdffontmap, (pdf_name *)mname, &mname2);
1134
432k
             if (code < 0) {
1135
432k
                 code = 0;
1136
432k
                 break;
1137
432k
             }
1138
301
             pdfi_countdown(mname);
1139
301
             mname = mname2;
1140
301
         }
1141
432k
    }
1142
1143
1.99M
    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
1.99M
    else {
1168
1.99M
        code = gs_error_undefined;
1169
1.99M
    }
1170
1171
1.99M
    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
1.99M
    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
432k
        *mapname = mname;
1178
432k
        code = 0;
1179
432k
    }
1180
1.56M
    else {
1181
1.56M
        pdfi_countdown(mname);
1182
1.56M
        code = gs_note_error(gs_error_undefined);
1183
1.56M
    }
1184
1.99M
    return code;
1185
1.99M
}
1186
1187
int
1188
pdfi_fontmap_lookup_cidfont(pdf_context *ctx, pdf_dict *font_dict, pdf_name *name, pdf_obj **mapname, int *findex)
1189
49.6k
{
1190
49.6k
    int code = 0;
1191
49.6k
    pdf_obj *cidname = NULL;
1192
49.6k
    pdf_obj *mname;
1193
1194
49.6k
    *findex = 0;
1195
1196
49.6k
    if (ctx->pdfcidfmap == NULL) {
1197
5.36k
        const char *cidfmap_default = "cidfmap";
1198
5.36k
        char *cidfmapname = (char *)cidfmap_default;
1199
5.36k
        code = pdf_make_fontmap(ctx, cidfmapname, true);
1200
5.36k
        if (code < 0) {
1201
0
            return code;
1202
0
        }
1203
5.36k
    }
1204
49.6k
    if (name == NULL || pdfi_type_of(name) != PDF_NAME) {
1205
26.0k
        code = pdfi_dict_get(ctx, font_dict, "BaseFont", &cidname);
1206
26.0k
        if (code < 0 || pdfi_type_of(cidname) != PDF_NAME) {
1207
330
            pdfi_countdown(cidname);
1208
330
            return_error(gs_error_undefined);
1209
330
        }
1210
1211
26.0k
    }
1212
23.5k
    else {
1213
23.5k
        cidname = (pdf_obj *)name;
1214
23.5k
        pdfi_countup(cidname);
1215
23.5k
    }
1216
1217
49.3k
    code = pdfi_dict_get_by_key(ctx, ctx->pdfcidfmap, (pdf_name *)cidname, &mname);
1218
49.3k
    pdfi_countdown(cidname);
1219
49.3k
    if (code < 0)
1220
49.3k
        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
}