Coverage Report

Created: 2025-12-31 07:31

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