Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/base/gsfcmap1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
16
17
/* Adobe-based CMap character decoding */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "stdint_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gsstruct.h"
24
#include "gsutil.h"   /* for gs_next_ids */
25
#include "gxfcmap1.h"
26
#include "gp.h"
27
28
/* Get a big-endian integer. */
29
static inline ulong
30
bytes2int(const byte *p, int n)
31
16.4M
{
32
16.4M
    ulong v = 0;
33
16.4M
    int i;
34
35
48.8M
    for (i = 0; i < n; ++i)
36
32.3M
        v = (v << 8) + p[i];
37
16.4M
    return v;
38
16.4M
}
39
40
/* ---------------- GC descriptors ---------------- */
41
42
public_st_cmap_adobe1();
43
/* Because lookup ranges can be elements of arrays, */
44
/* their enum_ptrs procedure must never return 0 prematurely. */
45
static
46
0
ENUM_PTRS_WITH(cmap_lookup_range_enum_ptrs,
47
0
               gx_cmap_lookup_range_t *pclr) return 0;
48
0
case 0:
49
0
    if (pclr->value_type == CODE_VALUE_GLYPH) {
50
0
        const byte *pv = pclr->values.data;
51
0
        int gsize = pclr->value_size;
52
0
        int k;
53
54
0
        for (k = 0; k < pclr->num_entries; ++k, pv += gsize) {
55
0
            gs_glyph glyph = bytes2int(pv, gsize);
56
57
0
            pclr->cmap->mark_glyph(mem, glyph, pclr->cmap->mark_glyph_data);
58
0
        }
59
0
    }
60
0
    return ENUM_OBJ(pclr->cmap);
61
0
case 1: return ENUM_STRING(&pclr->keys);
62
0
case 2: return ENUM_STRING(&pclr->values);
63
0
ENUM_PTRS_END
64
static
65
0
RELOC_PTRS_WITH(cmap_lookup_range_reloc_ptrs, gx_cmap_lookup_range_t *pclr)
66
0
    RELOC_VAR(pclr->cmap);
67
0
    RELOC_STRING_VAR(pclr->keys);
68
0
    RELOC_STRING_VAR(pclr->values);
69
0
RELOC_PTRS_END
70
public_st_cmap_lookup_range();
71
public_st_cmap_lookup_range_element();
72
73
/* ---------------- Procedures ---------------- */
74
75
    /* ------ Decoding ------ */
76
77
/*
78
 * multi-dimensional range comparator
79
 */
80
81
#ifdef DEBUG
82
static void
83
print_msg_str_in_range(const byte *str,
84
                       const byte *key_lo, const byte *key_hi,
85
                       int key_size)
86
{
87
    gs_memory_t *mem = gp_get_debug_mem_ptr();
88
89
    if (mem == NULL)
90
        return;
91
    debug_print_string_hex(mem, str, key_size);
92
    dmlprintf(mem, " in ");
93
    debug_print_string_hex(mem, key_lo, key_size);
94
    dmlprintf(mem, " - ");
95
    debug_print_string_hex(mem, key_hi, key_size);
96
    dmlprintf(mem, "\n");
97
}
98
#endif
99
100
static int
101
gs_cmap_get_shortest_chr(const gx_code_map_t * pcmap, uint *pfidx)
102
48.0k
{
103
48.0k
    int i;
104
48.0k
    int len_shortest = MAX_CMAP_CODE_SIZE;
105
48.0k
    uint fidx_shortest = 0; /* font index for this fallback */
106
107
1.18M
    for (i = pcmap->num_lookup - 1; i >= 0; --i) {
108
1.13M
        const gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
109
1.13M
        if ((pclr->key_prefix_size + pclr->key_size) <= len_shortest) {
110
1.13M
           len_shortest = (pclr->key_prefix_size + pclr->key_size);
111
1.13M
           fidx_shortest = pclr->font_index;
112
1.13M
        }
113
1.13M
    }
114
115
48.0k
    *pfidx = fidx_shortest;
116
48.0k
    return len_shortest;
117
48.0k
}
118
119
/*
120
 * multi-dimensional relative position calculator
121
 *
122
 * Returns offset of the given CID, considering CID range
123
 * as array of CIDs (the last index changes fastest).
124
 */
125
static int
126
gs_multidim_CID_offset(const byte *key_str,
127
                        const byte *key_lo, const byte *key_hi,
128
                        int key_size)
129
5.48M
{
130
131
5.48M
    int i;  /* index for current dimension */
132
5.48M
    int CID_offset = 0;
133
134
#ifdef DEBUG
135
    if (gs_debug_c('J')) {
136
        dlprintf("[J]gmCo()         calc CID_offset for 0x");
137
        print_msg_str_in_range(key_str, key_lo, key_hi, key_size);
138
    }
139
#endif
140
141
10.9M
    for (i = 0; i < key_size; i++)
142
5.48M
        CID_offset = CID_offset * (key_hi[i] - key_lo[i] + 1) +
143
5.48M
            key_str[i] - key_lo[i];
144
145
#ifdef DEBUG
146
    if_debug1('J', "[J]gmCo()         CID_offset = %d\n", CID_offset);
147
#endif
148
149
5.48M
    return CID_offset;
150
5.48M
}
151
152
/*
153
 * Decode a character from a string using a code map, updating the index.
154
 * Return 0 for a CID or name, N > 0 for a character code where N is the
155
 * number of bytes in the code, or an error.  Store the decoded bytes in
156
 * *pchr.  For undefined characters, set *pglyph = GS_NO_GLYPH and return 0.
157
 */
158
static int
159
code_map_decode_next_multidim_regime(const gx_code_map_t * pcmap,
160
                     const gs_const_string * pstr,
161
                     uint * pindex, uint * pfidx,
162
                     gs_char * pchr, gs_glyph * pglyph)
163
5.58M
{
164
5.58M
    const byte *str = pstr->data + *pindex;
165
5.58M
    uint ssize = pstr->size - *pindex;
166
    /*
167
     * The keys are not sorted due to 'usecmap'.  Possible optimization :
168
     * merge and sort keys in 'zbuildcmap', then use binary search here.
169
     * This would be valuable for UniJIS-UTF8-H, which contains about 7000
170
     * keys.
171
     */
172
5.58M
    int i;
173
174
    /*
175
     * In the fallback of CMap decoding procedure, there is "partial matching".
176
     * For detail, refer PostScript Ref. Manual v3 at the end of Fonts chapter.
177
     */
178
179
    /* "pm" stands for partial match (not pointer), temporal use. */
180
5.58M
    int pm_maxlen = 0;    /* partial match: max length */
181
5.58M
    int pm_index = *pindex; /* partial match: ptr index (in str) */
182
5.58M
    uint pm_fidx = *pfidx;  /* partial match: ptr font index */
183
5.58M
    gs_char pm_chr = *pchr; /* partial match: ptr character */
184
185
5.58M
    *pchr = '\0';
186
187
#ifdef DEBUG
188
    if (gs_debug_c('J')) {
189
        dlprintf("[J]CMDNmr() is called: str=(");
190
        debug_print_string_hex_nomem(str, ssize);
191
        dlprintf3(") @ "PRI_INTPTR" ssize=%d, %d ranges to check\n",
192
                  (intptr_t)str, ssize, pcmap->num_lookup);
193
    }
194
#endif
195
196
1.31G
    for (i = pcmap->num_lookup - 1; i >= 0; --i) {
197
        /* main loop - scan the map passed via pcmap */
198
        /* reverse scan order due to 'usecmap' */
199
200
1.31G
        const gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
201
1.31G
        int pre_size = pclr->key_prefix_size, key_size = pclr->key_size,
202
1.31G
            chr_size = pre_size + key_size;
203
204
1.31G
        int j = 0;
205
        /* length of the given byte stream is shorter than
206
         * chr-length of current range, no need for further check,
207
         * skip to the next range.
208
         */
209
1.31G
        if (ssize < chr_size)
210
3.71M
            continue;
211
212
1.31G
        if (0 < pre_size) {
213
1.31G
            const byte * prefix = pclr->key_prefix;
214
            /* check partial match in prefix */
215
1.31G
            for (j = 0; j < pre_size; j++)
216
1.31G
               if (prefix[j] != str[j])
217
1.30G
                   break;
218
219
1.31G
            if (0 == j)      /* no match, skip to next i */
220
1.30G
                continue;
221
5.32M
            else if (j < pre_size) { /* not exact, partial match */
222
#ifdef DEBUG
223
                if (gs_debug_c('J')) {
224
                    dlprintf("[J]CMDNmr() partial match with prefix:");
225
                    print_msg_str_in_range(str, prefix,
226
                                                prefix, pre_size);
227
                }
228
#endif
229
38.2k
                if (pm_maxlen < j) {
230
706
                    pm_maxlen = chr_size;
231
706
                    pm_chr = bytes2int(str, chr_size);
232
706
                    pm_index = (*pindex) + chr_size;
233
706
                    pm_fidx = pclr->font_index;
234
706
                }
235
38.2k
                continue ; /* no need to check key, skip to next i */
236
38.2k
            }
237
238
#ifdef DEBUG
239
            if (gs_debug_c('J')) {
240
                dlprintf("[J]CMDNmr()   full match with prefix:");
241
                print_msg_str_in_range(str, prefix, prefix, pre_size);
242
            }
243
#endif
244
1.31G
        } /* if (0 < pre_size) */
245
246
        /* full match in prefix. check key */
247
5.56M
        {
248
5.56M
            const byte *key = pclr->keys.data;
249
5.56M
            int step = key_size;
250
5.56M
            int k, l;
251
5.56M
            const byte *pvalue = NULL;
252
253
            /* when range is "range", 2 keys for lo-end and hi-end
254
             * are stacked. So twice the step. current "key" points
255
             * lo-end of current range, and the pointer for hi-end
256
             * is calculated by (key + step - key_size).
257
             */
258
259
5.56M
            if (pclr->key_is_range)
260
5.56M
                step <<=1;   /* step = step * 2; */
261
262
5.64M
            for (k = 0; k < pclr->num_entries; ++k, key += step) {
263
264
#ifdef DEBUG
265
                if_debug0('j', "[j]CMDNmr()     check key:");
266
                if (gs_debug_c('j'))
267
                    print_msg_str_in_range(str + pre_size,
268
                        key, key + step - key_size, key_size) ;
269
#endif
270
271
11.0M
                for (l = 0; l < key_size; l++) {
272
5.56M
                    byte c = str[l + pre_size];
273
5.56M
                    if (c < key[l] || c > key[step - key_size + l])
274
78.0k
                        break;
275
5.56M
                }
276
277
5.56M
                if (pm_maxlen < pre_size + l) {
278
5.48M
                    pm_maxlen = chr_size;
279
5.48M
                    pm_chr = bytes2int(str, chr_size);
280
5.48M
                    pm_index = (*pindex) + chr_size;
281
5.48M
                    pm_fidx = pclr->font_index;
282
5.48M
                }
283
5.56M
                if (l == key_size)
284
5.48M
                        break;
285
5.56M
            }
286
287
            /* all keys are tried, but found no match. */
288
            /* go to next prefix. */
289
5.56M
            if (k == pclr->num_entries)
290
78.0k
                continue;
291
292
            /* We have a match.  Return the result. */
293
5.48M
            *pchr = bytes2int(str, chr_size);
294
5.48M
            *pindex += chr_size;
295
5.48M
            *pfidx = pclr->font_index;
296
5.48M
            pvalue = pclr->values.data + k * pclr->value_size;
297
298
#ifdef DEBUG
299
            if (gs_debug_c('J')) {
300
                dlprintf("[J]CMDNmr()     full matched pvalue=(");
301
                debug_print_string_hex_nomem(pvalue, pclr->value_size);
302
                dlprintf(")\n");
303
            }
304
#endif
305
306
5.48M
            switch (pclr->value_type) {
307
5.48M
            case CODE_VALUE_CID:
308
5.48M
                *pglyph = GS_MIN_CID_GLYPH +
309
5.48M
                    bytes2int(pvalue, pclr->value_size) +
310
5.48M
                    gs_multidim_CID_offset(str + pre_size,
311
5.48M
                        key, key + step - key_size, key_size);
312
5.48M
                return 0;
313
228
            case CODE_VALUE_NOTDEF:
314
228
                *pglyph = GS_MIN_CID_GLYPH +
315
228
                    bytes2int(pvalue, pclr->value_size);
316
228
                return 0;
317
0
            case CODE_VALUE_GLYPH:
318
0
                *pglyph = bytes2int(pvalue, pclr->value_size);
319
0
                return 0;
320
0
            case CODE_VALUE_CHARS:
321
0
                *pglyph =
322
0
                    bytes2int(pvalue, pclr->value_size) +
323
0
                    bytes2int(str + pre_size, key_size) -
324
0
                    bytes2int(key, key_size);
325
0
                return pclr->value_size;
326
0
            default:            /* shouldn't happen */
327
0
                return_error(gs_error_rangecheck);
328
5.48M
            }
329
5.48M
        }
330
5.48M
    }
331
    /* No mapping. */
332
97.5k
    *pchr = pm_chr;
333
97.5k
    *pindex = pm_index;
334
97.5k
    *pfidx = pm_fidx;
335
97.5k
    *pglyph = GS_NO_GLYPH;
336
337
#ifdef DEBUG
338
    if (gs_debug_c('J')) {
339
        dlprintf("[J]CMDNmr()     no full match, use partial match for (");
340
        debug_print_string_hex_nomem(str, pm_maxlen);
341
        dlprintf(")\n");
342
    }
343
#endif
344
345
97.5k
    return 0;
346
5.58M
}
347
348
/*
349
 * Decode a character from a string using a CMap.
350
 * Return like code_map_decode_next.
351
 * At present, the range specification by (begin|end)codespacerange
352
 * is not used in this function. Therefore, this function accepts
353
 * some invalid CMap which def & undef maps exceed the codespacerange.
354
 * It should be checked in this function, or some procedure in gs_cmap.ps.
355
 */
356
static int
357
gs_cmap_adobe1_decode_next(const gs_cmap_t * pcmap_in,
358
                           const gs_const_string * pstr,
359
                           uint * pindex, uint * pfidx,
360
                           gs_char * pchr, gs_glyph * pglyph)
361
5.53M
{
362
5.53M
    const gs_cmap_adobe1_t *pcmap = (const gs_cmap_adobe1_t *)pcmap_in;
363
5.53M
    uint save_index = *pindex;
364
5.53M
    int code;
365
366
5.53M
    uint pm_index;
367
5.53M
    uint pm_fidx;
368
369
    /* For first, check defined map */
370
5.53M
    if_debug0('J', "[J]GCDN() check def CMap\n");
371
5.53M
    code =
372
5.53M
        code_map_decode_next_multidim_regime(&pcmap->def, pstr, pindex, pfidx, pchr, pglyph);
373
374
    /* This is defined character */
375
5.53M
    if (code != 0 || *pglyph != GS_NO_GLYPH)
376
5.48M
        return code;
377
378
    /* In here, this is NOT defined character */
379
    /* save partially matched results */
380
48.8k
    pm_index = *pindex;
381
48.8k
    pm_fidx = *pfidx;
382
383
    /* check notdef map. */
384
48.8k
    if_debug0('J', "[J]GCDN() check notdef CMap\n");
385
48.8k
    *pindex = save_index;
386
48.8k
    code =
387
48.8k
        code_map_decode_next_multidim_regime(&pcmap->notdef, pstr, pindex, pfidx, pchr, pglyph);
388
389
    /* This is defined "notdef" character. */
390
48.8k
    if (code != 0 || *pglyph != GS_NO_GLYPH)
391
228
        return code;
392
393
    /*
394
     * This is undefined in def & undef maps,
395
     * use partially matched result with default notdef (CID = 0).
396
     */
397
48.6k
    if (save_index < pm_index) {
398
399
        /* there was some partially matched */
400
401
619
        *pglyph = GS_MIN_CID_GLYPH; /* CID = 0 */
402
619
        *pindex = pm_index;
403
619
        *pfidx = pm_fidx;
404
619
        *pchr = '\0';
405
619
         return 0; /* should return some error for partial matched .notdef? */
406
619
    }
407
48.0k
    else {
408
        /* no match */
409
410
        /* Even partial match is failed.
411
         * Getting the shortest length from defined characters,
412
         * and take the leading bytes (with same length of the shortest
413
         * defined chr) as an unidentified character: CID = 0.
414
         * Also this procedure is specified in PS Ref. Manual v3,
415
         * at the end of Fonts chapter.
416
         */
417
418
48.0k
        uint ssize = pstr->size - save_index;
419
48.0k
        int chr_size_shortest =
420
48.0k
                gs_cmap_get_shortest_chr(&pcmap->def, pfidx);
421
422
48.0k
        if (chr_size_shortest <= ssize) {
423
4.06k
            *pglyph = GS_MIN_CID_GLYPH; /* CID = 0, this is CMap fallback */
424
4.06k
            *pindex = save_index + chr_size_shortest;
425
4.06k
            *pchr = '\0';
426
#ifdef DEBUG
427
            if (gs_debug_c('J')) {
428
                const byte *str = pstr->data + save_index;
429
                dlprintf1("[J]GCDN() no partial match, skip %d byte (",
430
                                               chr_size_shortest);
431
                debug_print_string_hex_nomem(str, chr_size_shortest);
432
                dlprintf(")\n");
433
            }
434
#endif
435
4.06k
            return 0; /* should return some error for fallback .notdef? */
436
4.06k
        }
437
43.9k
        else {
438
            /* Undecodable string is shorter than the shortest character,
439
             * return 'GS_NO_GLYPH' and update index to end-of-string
440
             */
441
#ifdef DEBUG
442
            if (gs_debug_c('J')) {
443
                dlprintf2("[J]GCDN() left data in buffer (%d) is shorter than shortest defined character (%d)\n",
444
                  ssize, chr_size_shortest);
445
            }
446
#endif
447
43.9k
            *pglyph = GS_NO_GLYPH;
448
43.9k
            *pindex += ssize;
449
43.9k
            return 0;     /* fixme: should return a code != 0 if caller needs to know */
450
43.9k
        }
451
48.0k
    }
452
48.6k
}
453
454
    /* ------ Initialization/creation ------ */
455
456
/*
457
 * Allocate and initialize an Adobe1 CMap.  The caller must still fill in
458
 * the code space ranges, lookup tables, keys, and values.
459
 */
460
461
static int
462
adobe1_next_range(gs_cmap_ranges_enum_t *penum)
463
126
{
464
126
    const gs_cmap_adobe1_t *const pcmap =
465
126
        (const gs_cmap_adobe1_t *)penum->cmap;
466
467
126
    if (penum->index >= pcmap->code_space.num_ranges)
468
60
        return 1;
469
66
    penum->range = pcmap->code_space.ranges[penum->index++];
470
66
    return 0;
471
126
}
472
static const gs_cmap_ranges_enum_procs_t adobe1_range_procs = {
473
    adobe1_next_range
474
};
475
static void
476
gs_cmap_adobe1_enum_ranges(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *pre)
477
60
{
478
60
    gs_cmap_ranges_enum_setup(pre, pcmap, &adobe1_range_procs);
479
60
}
480
static int
481
adobe1_next_lookup(gs_cmap_lookups_enum_t *penum, const gx_code_map_t *pcm)
482
12.8M
{
483
12.8M
    const gx_cmap_lookup_range_t *lookup = &pcm->lookup[penum->index[0]];
484
485
12.8M
    penum->entry.value.data = 0L;
486
12.8M
    if (penum->index[0] >= pcm->num_lookup)
487
73.2k
        return 1;
488
12.7M
    penum->entry.key_size = lookup->key_prefix_size + lookup->key_size;
489
12.7M
    penum->entry.key_is_range = lookup->key_is_range;
490
12.7M
    penum->entry.value_type = lookup->value_type;
491
12.7M
    penum->entry.value.size = lookup->value_size;
492
12.7M
    penum->entry.font_index = lookup->font_index;
493
12.7M
    penum->index[0]++;
494
12.7M
    penum->index[1] = 0;
495
12.7M
    return 0;
496
12.8M
}
497
static int
498
adobe1_next_lookup_def(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
499
12.8M
{
500
12.8M
    return adobe1_next_lookup(penum,
501
12.8M
                        &((const gs_cmap_adobe1_t *)penum->cmap)->def);
502
12.8M
}
503
static int
504
adobe1_next_lookup_notdef(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
505
60
{
506
60
    return adobe1_next_lookup(penum,
507
60
                        &((const gs_cmap_adobe1_t *)penum->cmap)->notdef);
508
60
}
509
static int
510
adobe1_next_entry(gs_cmap_lookups_enum_t *penum, const gx_code_map_t *pcm)
511
24.7M
{
512
24.7M
    const gx_cmap_lookup_range_t *lookup = &pcm->lookup[penum->index[0] - 1];
513
24.7M
    int psize = lookup->key_prefix_size;
514
24.7M
    int ksize = lookup->key_size;
515
24.7M
    const byte *key =
516
24.7M
        lookup->keys.data + penum->index[1] * ksize *
517
24.7M
        (lookup->key_is_range ? 2 : 1);
518
24.7M
    int i;
519
520
24.7M
    if (penum->index[1] >= lookup->num_entries)
521
11.9M
        return 1;
522
12.7M
    if (psize + ksize > MAX_CMAP_CODE_SIZE)
523
172
        return_error(gs_error_rangecheck);
524
38.3M
    for (i = 0; i < 2; ++i, key += ksize) {
525
25.5M
        memcpy(penum->entry.key[i], lookup->key_prefix, psize);
526
25.5M
        memcpy(penum->entry.key[i] + psize, key, ksize);
527
25.5M
    }
528
12.7M
    penum->entry.value.data =
529
12.7M
        lookup->values.data + penum->index[1] * lookup->value_size;
530
12.7M
    penum->entry.value.size = lookup->value_size;
531
12.7M
    penum->index[1]++;
532
12.7M
    return 0;
533
12.7M
}
534
static int
535
adobe1_next_entry_def(gs_cmap_lookups_enum_t *penum)
536
24.7M
{
537
24.7M
    return adobe1_next_entry(penum,
538
24.7M
                        &((const gs_cmap_adobe1_t *)penum->cmap)->def);
539
24.7M
}
540
static int
541
adobe1_next_entry_notdef(gs_cmap_lookups_enum_t *penum)
542
0
{
543
0
    return adobe1_next_entry(penum,
544
0
                        &((const gs_cmap_adobe1_t *)penum->cmap)->notdef);
545
0
}
546
static const gs_cmap_lookups_enum_procs_t adobe1_lookup_def_procs = {
547
    adobe1_next_lookup_def, adobe1_next_entry_def
548
};
549
static const gs_cmap_lookups_enum_procs_t adobe1_lookup_notdef_procs = {
550
    adobe1_next_lookup_notdef, adobe1_next_entry_notdef
551
};
552
static void
553
gs_cmap_adobe1_enum_lookups(const gs_cmap_t *pcmap, int which,
554
                            gs_cmap_lookups_enum_t *pre)
555
856k
{
556
856k
    gs_cmap_lookups_enum_setup(pre, pcmap,
557
856k
                               (which ? &adobe1_lookup_notdef_procs :
558
856k
                                &adobe1_lookup_def_procs));
559
856k
}
560
561
static const gs_cmap_procs_t cmap_adobe1_procs = {
562
    gs_cmap_adobe1_decode_next,
563
    gs_cmap_adobe1_enum_ranges,
564
    gs_cmap_adobe1_enum_lookups,
565
    gs_cmap_compute_identity
566
};
567
568
int
569
gs_cmap_adobe1_alloc(gs_cmap_adobe1_t **ppcmap, int wmode,
570
                     const byte *map_name, uint name_size,
571
                     uint num_fonts, uint num_ranges, uint num_lookups,
572
                     uint keys_size, uint values_size,
573
                     const gs_cid_system_info_t *pcidsi_in, gs_memory_t *mem)
574
78.5k
{
575
78.5k
    gs_cmap_t *pcmap;
576
78.5k
    gs_cmap_adobe1_t *pcmap1;
577
78.5k
    gx_code_space_range_t *ranges = (gx_code_space_range_t *)
578
78.5k
        gs_alloc_byte_array(mem, num_ranges, sizeof(gx_code_space_range_t),
579
78.5k
                            "gs_cmap_alloc(code space ranges)");
580
78.5k
    gx_cmap_lookup_range_t *lookups =
581
78.5k
        (num_lookups == 0 ? NULL :
582
78.5k
         gs_alloc_struct_array(mem, num_lookups, gx_cmap_lookup_range_t,
583
78.5k
                               &st_cmap_lookup_range,
584
78.5k
                               "gs_cmap_alloc(lookup ranges)"));
585
78.5k
    byte *keys =
586
78.5k
        (keys_size == 0 ? NULL :
587
78.5k
         gs_alloc_string(mem, keys_size, "gs_cmap_alloc(keys)"));
588
78.5k
    byte *values =
589
78.5k
        (values_size == 0 ? NULL :
590
78.5k
         gs_alloc_string(mem, values_size, "gs_cmap_alloc(values)"));
591
78.5k
    int code =
592
78.5k
        gs_cmap_alloc(&pcmap, &st_cmap_adobe1, wmode, map_name, name_size,
593
78.5k
                      pcidsi_in, num_fonts, &cmap_adobe1_procs, mem);
594
78.5k
    uint i;
595
596
78.5k
    if (code < 0 || ranges == 0 || (num_lookups != 0 && lookups == 0) ||
597
78.5k
        (keys_size != 0 && keys == 0) || (values_size != 0 && values == 0)) {
598
0
        gs_free_string(mem, values, values_size, "gs_cmap_alloc(values)");
599
0
        gs_free_string(mem, keys, keys_size, "gs_cmap_alloc(keys)");
600
0
        gs_free_object(mem, lookups, "gs_cmap_alloc(lookup ranges)");
601
0
        gs_free_object(mem, ranges, "gs_cmap_alloc(code space ranges)");
602
0
        return_error(gs_error_VMerror);
603
0
    }
604
78.5k
    *ppcmap = pcmap1 = (gs_cmap_adobe1_t *)pcmap;
605
78.5k
    pcmap1->code_space.ranges = ranges;
606
78.5k
    pcmap1->code_space.num_ranges = num_ranges;
607
78.5k
    if (num_lookups > 0) {
608
0
        for (i = 0; i < num_lookups; ++i) {
609
0
            memset(&lookups[i], 0, sizeof(*lookups));
610
0
            lookups[i].cmap = pcmap1;
611
0
        }
612
0
        lookups[0].keys.data = keys;
613
0
        lookups[0].keys.size = keys_size;
614
0
        lookups[0].values.data = values;
615
0
        lookups[0].values.size = values_size;
616
0
    }
617
78.5k
    pcmap1->def.lookup = lookups;
618
78.5k
    pcmap1->def.num_lookup = num_lookups;
619
78.5k
    pcmap1->notdef.lookup = 0;
620
78.5k
    pcmap1->notdef.num_lookup = 0;
621
    /* no mark_glyph, mark_glyph_data, glyph_name, glyph_name_data */
622
78.5k
    return 0;
623
78.5k
}