Coverage Report

Created: 2025-06-10 07:19

/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
1.08M
{
32
1.08M
    ulong v = 0;
33
1.08M
    int i;
34
35
3.24M
    for (i = 0; i < n; ++i)
36
2.15M
        v = (v << 8) + p[i];
37
1.08M
    return v;
38
1.08M
}
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
2.79k
{
103
2.79k
    int i;
104
2.79k
    int len_shortest = MAX_CMAP_CODE_SIZE;
105
2.79k
    uint fidx_shortest = 0; /* font index for this fallback */
106
107
83.4k
    for (i = pcmap->num_lookup - 1; i >= 0; --i) {
108
80.6k
        const gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
109
80.6k
        if ((pclr->key_prefix_size + pclr->key_size) <= len_shortest) {
110
80.6k
           len_shortest = (pclr->key_prefix_size + pclr->key_size);
111
80.6k
           fidx_shortest = pclr->font_index;
112
80.6k
        }
113
80.6k
    }
114
115
2.79k
    *pfidx = fidx_shortest;
116
2.79k
    return len_shortest;
117
2.79k
}
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
361k
{
130
131
361k
    int i;  /* index for current dimension */
132
361k
    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
723k
    for (i = 0; i < key_size; i++)
142
361k
        CID_offset = CID_offset * (key_hi[i] - key_lo[i] + 1) +
143
361k
            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
361k
    return CID_offset;
150
361k
}
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
367k
{
164
367k
    const byte *str = pstr->data + *pindex;
165
367k
    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
367k
    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
367k
    int pm_maxlen = 0;    /* partial match: max length */
181
367k
    int pm_index = *pindex; /* partial match: ptr index (in str) */
182
367k
    uint pm_fidx = *pfidx;  /* partial match: ptr font index */
183
367k
    gs_char pm_chr = *pchr; /* partial match: ptr character */
184
185
367k
    *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
89.9M
    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
89.9M
        const gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
201
89.9M
        int pre_size = pclr->key_prefix_size, key_size = pclr->key_size,
202
89.9M
            chr_size = pre_size + key_size;
203
204
89.9M
        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
89.9M
        if (ssize < chr_size)
210
352k
            continue;
211
212
89.6M
        if (0 < pre_size) {
213
89.6M
            const byte * prefix = pclr->key_prefix;
214
            /* check partial match in prefix */
215
89.9M
            for (j = 0; j < pre_size; j++)
216
89.6M
               if (prefix[j] != str[j])
217
89.2M
                   break;
218
219
89.6M
            if (0 == j)      /* no match, skip to next i */
220
89.2M
                continue;
221
360k
            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
2.61k
                if (pm_maxlen < j) {
230
25
                    pm_maxlen = chr_size;
231
25
                    pm_chr = bytes2int(str, chr_size);
232
25
                    pm_index = (*pindex) + chr_size;
233
25
                    pm_fidx = pclr->font_index;
234
25
                }
235
2.61k
                continue ; /* no need to check key, skip to next i */
236
2.61k
            }
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
89.6M
        } /* if (0 < pre_size) */
245
246
        /* full match in prefix. check key */
247
365k
        {
248
365k
            const byte *key = pclr->keys.data;
249
365k
            int step = key_size;
250
365k
            int k, l;
251
365k
            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
365k
            if (pclr->key_is_range)
260
365k
                step <<=1;   /* step = step * 2; */
261
262
369k
            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
727k
                for (l = 0; l < key_size; l++) {
272
365k
                    byte c = str[l + pre_size];
273
365k
                    if (c < key[l] || c > key[step - key_size + l])
274
3.72k
                        break;
275
365k
                }
276
277
365k
                if (pm_maxlen < pre_size + l) {
278
361k
                    pm_maxlen = chr_size;
279
361k
                    pm_chr = bytes2int(str, chr_size);
280
361k
                    pm_index = (*pindex) + chr_size;
281
361k
                    pm_fidx = pclr->font_index;
282
361k
                }
283
365k
                if (l == key_size)
284
361k
                        break;
285
365k
            }
286
287
            /* all keys are tried, but found no match. */
288
            /* go to next prefix. */
289
365k
            if (k == pclr->num_entries)
290
3.72k
                continue;
291
292
            /* We have a match.  Return the result. */
293
361k
            *pchr = bytes2int(str, chr_size);
294
361k
            *pindex += chr_size;
295
361k
            *pfidx = pclr->font_index;
296
361k
            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
361k
            switch (pclr->value_type) {
307
361k
            case CODE_VALUE_CID:
308
361k
                *pglyph = GS_MIN_CID_GLYPH +
309
361k
                    bytes2int(pvalue, pclr->value_size) +
310
361k
                    gs_multidim_CID_offset(str + pre_size,
311
361k
                        key, key + step - key_size, key_size);
312
361k
                return 0;
313
16
            case CODE_VALUE_NOTDEF:
314
16
                *pglyph = GS_MIN_CID_GLYPH +
315
16
                    bytes2int(pvalue, pclr->value_size);
316
16
                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
361k
            }
329
361k
        }
330
361k
    }
331
    /* No mapping. */
332
5.65k
    *pchr = pm_chr;
333
5.65k
    *pindex = pm_index;
334
5.65k
    *pfidx = pm_fidx;
335
5.65k
    *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
5.65k
    return 0;
346
367k
}
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
364k
{
362
364k
    const gs_cmap_adobe1_t *pcmap = (const gs_cmap_adobe1_t *)pcmap_in;
363
364k
    uint save_index = *pindex;
364
364k
    int code;
365
366
364k
    uint pm_index;
367
364k
    uint pm_fidx;
368
369
    /* For first, check defined map */
370
364k
    if_debug0('J', "[J]GCDN() check def CMap\n");
371
364k
    code =
372
364k
        code_map_decode_next_multidim_regime(&pcmap->def, pstr, pindex, pfidx, pchr, pglyph);
373
374
    /* This is defined character */
375
364k
    if (code != 0 || *pglyph != GS_NO_GLYPH)
376
361k
        return code;
377
378
    /* In here, this is NOT defined character */
379
    /* save partially matched results */
380
2.83k
    pm_index = *pindex;
381
2.83k
    pm_fidx = *pfidx;
382
383
    /* check notdef map. */
384
2.83k
    if_debug0('J', "[J]GCDN() check notdef CMap\n");
385
2.83k
    *pindex = save_index;
386
2.83k
    code =
387
2.83k
        code_map_decode_next_multidim_regime(&pcmap->notdef, pstr, pindex, pfidx, pchr, pglyph);
388
389
    /* This is defined "notdef" character. */
390
2.83k
    if (code != 0 || *pglyph != GS_NO_GLYPH)
391
16
        return code;
392
393
    /*
394
     * This is undefined in def & undef maps,
395
     * use partially matched result with default notdef (CID = 0).
396
     */
397
2.82k
    if (save_index < pm_index) {
398
399
        /* there was some partially matched */
400
401
26
        *pglyph = GS_MIN_CID_GLYPH; /* CID = 0 */
402
26
        *pindex = pm_index;
403
26
        *pfidx = pm_fidx;
404
26
        *pchr = '\0';
405
26
         return 0; /* should return some error for partial matched .notdef? */
406
26
    }
407
2.79k
    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
2.79k
        uint ssize = pstr->size - save_index;
419
2.79k
        int chr_size_shortest =
420
2.79k
                gs_cmap_get_shortest_chr(&pcmap->def, pfidx);
421
422
2.79k
        if (chr_size_shortest <= ssize) {
423
235
            *pglyph = GS_MIN_CID_GLYPH; /* CID = 0, this is CMap fallback */
424
235
            *pindex = save_index + chr_size_shortest;
425
235
            *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
235
            return 0; /* should return some error for fallback .notdef? */
436
235
        }
437
2.55k
        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
2.55k
            *pglyph = GS_NO_GLYPH;
448
2.55k
            *pindex += ssize;
449
2.55k
            return 0;     /* fixme: should return a code != 0 if caller needs to know */
450
2.55k
        }
451
2.79k
    }
452
2.82k
}
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
0
{
464
0
    const gs_cmap_adobe1_t *const pcmap =
465
0
        (const gs_cmap_adobe1_t *)penum->cmap;
466
467
0
    if (penum->index >= pcmap->code_space.num_ranges)
468
0
        return 1;
469
0
    penum->range = pcmap->code_space.ranges[penum->index++];
470
0
    return 0;
471
0
}
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
0
{
478
0
    gs_cmap_ranges_enum_setup(pre, pcmap, &adobe1_range_procs);
479
0
}
480
static int
481
adobe1_next_lookup(gs_cmap_lookups_enum_t *penum, const gx_code_map_t *pcm)
482
187k
{
483
187k
    const gx_cmap_lookup_range_t *lookup = &pcm->lookup[penum->index[0]];
484
485
187k
    penum->entry.value.data = 0L;
486
187k
    if (penum->index[0] >= pcm->num_lookup)
487
907
        return 1;
488
186k
    penum->entry.key_size = lookup->key_prefix_size + lookup->key_size;
489
186k
    penum->entry.key_is_range = lookup->key_is_range;
490
186k
    penum->entry.value_type = lookup->value_type;
491
186k
    penum->entry.value.size = lookup->value_size;
492
186k
    penum->entry.font_index = lookup->font_index;
493
186k
    penum->index[0]++;
494
186k
    penum->index[1] = 0;
495
186k
    return 0;
496
187k
}
497
static int
498
adobe1_next_lookup_def(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
499
187k
{
500
187k
    return adobe1_next_lookup(penum,
501
187k
                        &((const gs_cmap_adobe1_t *)penum->cmap)->def);
502
187k
}
503
static int
504
adobe1_next_lookup_notdef(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
505
0
{
506
0
    return adobe1_next_lookup(penum,
507
0
                        &((const gs_cmap_adobe1_t *)penum->cmap)->notdef);
508
0
}
509
static int
510
adobe1_next_entry(gs_cmap_lookups_enum_t *penum, const gx_code_map_t *pcm)
511
365k
{
512
365k
    const gx_cmap_lookup_range_t *lookup = &pcm->lookup[penum->index[0] - 1];
513
365k
    int psize = lookup->key_prefix_size;
514
365k
    int ksize = lookup->key_size;
515
365k
    const byte *key =
516
365k
        lookup->keys.data + penum->index[1] * ksize *
517
365k
        (lookup->key_is_range ? 2 : 1);
518
365k
    int i;
519
520
365k
    if (penum->index[1] >= lookup->num_entries)
521
178k
        return 1;
522
186k
    if (psize + ksize > MAX_CMAP_CODE_SIZE)
523
112
        return_error(gs_error_rangecheck);
524
558k
    for (i = 0; i < 2; ++i, key += ksize) {
525
372k
        memcpy(penum->entry.key[i], lookup->key_prefix, psize);
526
372k
        memcpy(penum->entry.key[i] + psize, key, ksize);
527
372k
    }
528
186k
    penum->entry.value.data =
529
186k
        lookup->values.data + penum->index[1] * lookup->value_size;
530
186k
    penum->entry.value.size = lookup->value_size;
531
186k
    penum->index[1]++;
532
186k
    return 0;
533
186k
}
534
static int
535
adobe1_next_entry_def(gs_cmap_lookups_enum_t *penum)
536
365k
{
537
365k
    return adobe1_next_entry(penum,
538
365k
                        &((const gs_cmap_adobe1_t *)penum->cmap)->def);
539
365k
}
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
8.57k
{
556
8.57k
    gs_cmap_lookups_enum_setup(pre, pcmap,
557
8.57k
                               (which ? &adobe1_lookup_notdef_procs :
558
8.57k
                                &adobe1_lookup_def_procs));
559
8.57k
}
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
4.30k
{
575
4.30k
    gs_cmap_t *pcmap;
576
4.30k
    gs_cmap_adobe1_t *pcmap1;
577
4.30k
    gx_code_space_range_t *ranges = (gx_code_space_range_t *)
578
4.30k
        gs_alloc_byte_array(mem, num_ranges, sizeof(gx_code_space_range_t),
579
4.30k
                            "gs_cmap_alloc(code space ranges)");
580
4.30k
    gx_cmap_lookup_range_t *lookups =
581
4.30k
        (num_lookups == 0 ? NULL :
582
4.30k
         gs_alloc_struct_array(mem, num_lookups, gx_cmap_lookup_range_t,
583
4.30k
                               &st_cmap_lookup_range,
584
4.30k
                               "gs_cmap_alloc(lookup ranges)"));
585
4.30k
    byte *keys =
586
4.30k
        (keys_size == 0 ? NULL :
587
4.30k
         gs_alloc_string(mem, keys_size, "gs_cmap_alloc(keys)"));
588
4.30k
    byte *values =
589
4.30k
        (values_size == 0 ? NULL :
590
4.30k
         gs_alloc_string(mem, values_size, "gs_cmap_alloc(values)"));
591
4.30k
    int code =
592
4.30k
        gs_cmap_alloc(&pcmap, &st_cmap_adobe1, wmode, map_name, name_size,
593
4.30k
                      pcidsi_in, num_fonts, &cmap_adobe1_procs, mem);
594
4.30k
    uint i;
595
596
4.30k
    if (code < 0 || ranges == 0 || (num_lookups != 0 && lookups == 0) ||
597
4.30k
        (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
4.30k
    *ppcmap = pcmap1 = (gs_cmap_adobe1_t *)pcmap;
605
4.30k
    pcmap1->code_space.ranges = ranges;
606
4.30k
    pcmap1->code_space.num_ranges = num_ranges;
607
4.30k
    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
4.30k
    pcmap1->def.lookup = lookups;
618
4.30k
    pcmap1->def.num_lookup = num_lookups;
619
4.30k
    pcmap1->notdef.lookup = 0;
620
4.30k
    pcmap1->notdef.num_lookup = 0;
621
    /* no mark_glyph, mark_glyph_data, glyph_name, glyph_name_data */
622
4.30k
    return 0;
623
4.30k
}