Coverage Report

Created: 2025-11-16 07:40

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