Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gsfcmap.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-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
16
17
/* CMap character decoding */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsstruct.h"
23
#include "gsutil.h"   /* for gs_next_ids */
24
#include "gxfcmap.h"
25
26
typedef struct gs_cmap_identity_s {
27
    GS_CMAP_COMMON;
28
    int num_bytes;
29
    int varying_bytes;
30
    int code;     /* 0 or num_bytes */
31
} gs_cmap_identity_t;
32
33
/* GC descriptors */
34
public_st_cmap();
35
gs_public_st_suffix_add0_local(st_cmap_identity, gs_cmap_identity_t,
36
                                "gs_cmap_identity_t", cmap_ptrs, cmap_data,
37
                                st_cmap);
38
39
/* ---------------- Client procedures ---------------- */
40
41
    /* ------ Initialization/creation ------ */
42
43
/*
44
 * Create an Identity CMap.
45
 */
46
static uint
47
get_integer_bytes(const byte *src, int count)
48
0
{
49
0
    uint v = 0;
50
0
    int i;
51
52
0
    for (i = 0; i < count; ++i)
53
0
        v = (v << 8) + src[i];
54
0
    return v;
55
0
}
56
static int
57
identity_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
58
                     uint *pindex, uint *pfidx,
59
                     gs_char *pchr, gs_glyph *pglyph)
60
0
{
61
0
    const gs_cmap_identity_t *const pcimap =
62
0
        (const gs_cmap_identity_t *)pcmap;
63
0
    int num_bytes = pcimap->num_bytes;
64
0
    uint value;
65
66
0
    if (str->size < *pindex + num_bytes) {
67
0
        *pglyph = GS_NO_GLYPH;
68
0
        return (*pindex == str->size ? 2 : -1);
69
0
    }
70
0
    value = get_integer_bytes(str->data + *pindex, num_bytes);
71
0
    *pglyph = GS_MIN_CID_GLYPH + value;
72
0
    *pchr = value;
73
0
    *pindex += num_bytes;
74
0
    *pfidx = 0;
75
0
    return pcimap->code;
76
0
}
77
static int
78
identity_next_range(gs_cmap_ranges_enum_t *penum)
79
0
{
80
0
    if (penum->index == 0) {
81
0
        const gs_cmap_identity_t *const pcimap =
82
0
            (const gs_cmap_identity_t *)penum->cmap;
83
84
0
        memset(penum->range.first, 0, pcimap->num_bytes);
85
0
        memset(penum->range.last, 0xff, pcimap->num_bytes);
86
0
        penum->range.size = pcimap->num_bytes;
87
0
        penum->index = 1;
88
0
        return 0;
89
0
    }
90
0
    return 1;
91
0
}
92
static const gs_cmap_ranges_enum_procs_t identity_range_procs = {
93
    identity_next_range
94
};
95
static void
96
identity_enum_ranges(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *pre)
97
0
{
98
0
    gs_cmap_ranges_enum_setup(pre, pcmap, &identity_range_procs);
99
0
}
100
static int
101
identity_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
102
0
{
103
0
    penum->entry.value.data = 0L;
104
0
    if (penum->index[0] == 0) {
105
0
        const gs_cmap_identity_t *const pcimap =
106
0
            (const gs_cmap_identity_t *)penum->cmap;
107
0
        int num_bytes = pcimap->num_bytes;
108
109
0
        memset(penum->entry.key[0], 0, num_bytes);
110
0
        memset(penum->entry.key[1], 0xff, num_bytes);
111
0
        memset(penum->entry.key[1], 0, num_bytes - pcimap->varying_bytes);
112
0
        penum->entry.key_size = num_bytes;
113
0
        penum->entry.key_is_range = true;
114
0
        penum->entry.value_type =
115
0
            (pcimap->code ? CODE_VALUE_CHARS : CODE_VALUE_CID);
116
0
        penum->entry.value.size = num_bytes;
117
0
        penum->entry.font_index = 0;
118
0
        penum->index[0] = 1;
119
0
        return 0;
120
0
    }
121
0
    return 1;
122
0
}
123
static int
124
no_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
125
2.62k
{
126
2.62k
    penum->entry.value.data = 0L;
127
2.62k
    return 1;
128
2.62k
}
129
static int
130
identity_next_entry(gs_cmap_lookups_enum_t *penum)
131
0
{
132
0
    const gs_cmap_identity_t *const pcimap =
133
0
        (const gs_cmap_identity_t *)penum->cmap;
134
0
    int num_bytes = pcimap->num_bytes;
135
0
    int i = num_bytes - pcimap->varying_bytes;
136
137
0
    memcpy(penum->temp_value, penum->entry.key[0], num_bytes);
138
0
    memcpy(penum->entry.key[0], penum->entry.key[1], i);
139
0
    while (--i >= 0)
140
0
        if (++(penum->entry.key[1][i]) != 0) {
141
0
            penum->entry.value.data = penum->temp_value;
142
0
            return 0;
143
0
        }
144
0
    return 1;
145
0
}
146
147
static const gs_cmap_lookups_enum_procs_t identity_lookup_procs = {
148
    identity_next_lookup, identity_next_entry
149
};
150
const gs_cmap_lookups_enum_procs_t gs_cmap_no_lookups_procs = {
151
    no_next_lookup, 0
152
};
153
static void
154
identity_enum_lookups(const gs_cmap_t *pcmap, int which,
155
                      gs_cmap_lookups_enum_t *pre)
156
0
{
157
0
    gs_cmap_lookups_enum_setup(pre, pcmap,
158
0
                               (which ? &gs_cmap_no_lookups_procs :
159
0
                                &identity_lookup_procs));
160
0
}
161
static bool
162
identity_is_identity(const gs_cmap_t *pcmap, int font_index_only)
163
0
{
164
0
    return true;
165
0
}
166
167
static const gs_cmap_procs_t identity_procs = {
168
    identity_decode_next, identity_enum_ranges, identity_enum_lookups, identity_is_identity
169
};
170
171
static int
172
gs_cmap_identity_alloc(gs_cmap_t **ppcmap, int num_bytes, int varying_bytes,
173
                       int return_code, const char *cmap_name, int wmode,
174
                       gs_memory_t *mem)
175
0
{
176
    /*
177
     * We could allow any value of num_bytes between 1 and
178
     * min(MAX_CMAP_CODE_SIZE, 4), but if num_bytes != 2, we can't name
179
     * the result "Identity-[HV]".
180
     */
181
0
    static const gs_cid_system_info_t identity_cidsi = {
182
0
        { (const byte *)"Adobe", 5 },
183
0
        { (const byte *)"Identity", 8 },
184
0
        0
185
0
    };
186
0
    int code;
187
0
    gs_cmap_identity_t *pcimap;
188
189
0
    if (num_bytes != 2)
190
0
        return_error(gs_error_rangecheck);
191
0
    code = gs_cmap_alloc(ppcmap, &st_cmap_identity, wmode,
192
0
                         (const byte *)cmap_name, strlen(cmap_name),
193
0
                         &identity_cidsi, 1, &identity_procs, mem);
194
0
    if (code < 0)
195
0
        return code;
196
0
    pcimap = (gs_cmap_identity_t *)*ppcmap;
197
0
    pcimap->num_bytes = num_bytes;
198
0
    pcimap->varying_bytes = varying_bytes;
199
0
    pcimap->code = return_code;
200
0
    return 0;
201
0
}
202
int
203
gs_cmap_create_identity(gs_cmap_t **ppcmap, int num_bytes, int wmode,
204
                        gs_memory_t *mem)
205
0
{
206
0
    return gs_cmap_identity_alloc(ppcmap, num_bytes, num_bytes, 0,
207
0
                                  (wmode ? "Identity-V" : "Identity-H"),
208
0
                                  wmode, mem);
209
0
}
210
int
211
gs_cmap_create_char_identity(gs_cmap_t **ppcmap, int num_bytes, int wmode,
212
                             gs_memory_t *mem)
213
0
{
214
0
    return gs_cmap_identity_alloc(ppcmap, num_bytes, 1, num_bytes,
215
0
                                  (wmode ? "Identity-BF-V" : "Identity-BF-H"),
216
0
                                  wmode, mem);
217
0
}
218
219
    /* ------ Check identity ------ */
220
221
/*
222
 * Check for identity CMap. Uses a fast check for special cases.
223
 */
224
bool
225
gs_cmap_is_identity(const gs_cmap_t *pcmap, int font_index_only)
226
32
{
227
32
    return pcmap->procs->is_identity(pcmap, font_index_only);
228
32
}
229
230
    /* ------ Decoding ------ */
231
232
/*
233
 * Decode and map a character from a string using a CMap.
234
 * See gsfcmap.h for details.
235
 */
236
int
237
gs_cmap_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
238
                    uint *pindex, uint *pfidx,
239
                    gs_char *pchr, gs_glyph *pglyph)
240
5.55M
{
241
5.55M
    return pcmap->procs->decode_next(pcmap, str, pindex, pfidx, pchr, pglyph);
242
5.55M
}
243
244
    /* ------ Enumeration ------ */
245
246
/*
247
 * Initialize the enumeration of the code space ranges, and enumerate
248
 * the next range.  See gxfcmap.h for details.
249
 */
250
void
251
gs_cmap_ranges_enum_init(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *penum)
252
2.65k
{
253
2.65k
    pcmap->procs->enum_ranges(pcmap, penum);
254
2.65k
}
255
int
256
gs_cmap_enum_next_range(gs_cmap_ranges_enum_t *penum)
257
5.30k
{
258
5.30k
    return penum->procs->next_range(penum);
259
5.30k
}
260
261
/*
262
 * Initialize the enumeration of the lookups, and enumerate the next
263
 * the next lookup or entry.  See gxfcmap.h for details.
264
 */
265
void
266
gs_cmap_lookups_enum_init(const gs_cmap_t *pcmap, int which,
267
                          gs_cmap_lookups_enum_t *penum)
268
551k
{
269
551k
    pcmap->procs->enum_lookups(pcmap, which, penum);
270
551k
}
271
int
272
gs_cmap_enum_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
273
10.9M
{
274
10.9M
    return penum->procs->next_lookup(mem, penum);
275
10.9M
}
276
int
277
gs_cmap_enum_next_entry(gs_cmap_lookups_enum_t *penum)
278
21.4M
{
279
21.4M
    return penum->procs->next_entry(penum);
280
21.4M
}
281
282
/* ---------------- Implementation procedures ---------------- */
283
284
    /* ------ Initialization/creation ------ */
285
286
/*
287
 * Initialize a just-allocated CMap, to ensure that all pointers are clean
288
 * for the GC.  Note that this only initializes the common part.
289
 */
290
void
291
gs_cmap_init(const gs_memory_t *mem, gs_cmap_t *pcmap, int num_fonts)
292
82.3k
{
293
82.3k
    memset(pcmap, 0, sizeof(*pcmap));
294
    /* We reserve a range of IDs for pdfwrite needs,
295
       to allow an identification of submaps for a particular subfont.
296
     */
297
82.3k
    pcmap->id = gs_next_ids(mem, num_fonts);
298
82.3k
    pcmap->num_fonts = num_fonts;
299
82.3k
    uid_set_invalid(&pcmap->uid);
300
82.3k
}
301
302
/*
303
 * Allocate and initialize (the common part of) a CMap.
304
 */
305
int
306
gs_cmap_alloc(gs_cmap_t **ppcmap, const gs_memory_struct_type_t *pstype,
307
              int wmode, const byte *map_name, uint name_size,
308
              const gs_cid_system_info_t *pcidsi_in, int num_fonts,
309
              const gs_cmap_procs_t *procs, gs_memory_t *mem)
310
82.3k
{
311
82.3k
    gs_cmap_t *pcmap =
312
82.3k
        gs_alloc_struct(mem, gs_cmap_t, pstype, "gs_cmap_alloc(CMap)");
313
82.3k
    gs_cid_system_info_t *pcidsi =
314
82.3k
        gs_alloc_struct_array(mem, num_fonts, gs_cid_system_info_t,
315
82.3k
                              &st_cid_system_info_element,
316
82.3k
                              "gs_cmap_alloc(CIDSystemInfo)");
317
318
82.3k
    if (pcmap == 0 || pcidsi == 0) {
319
0
        gs_free_object(mem, pcidsi, "gs_cmap_alloc(CIDSystemInfo)");
320
0
        gs_free_object(mem, pcmap, "gs_cmap_alloc(CMap)");
321
0
        return_error(gs_error_VMerror);
322
0
    }
323
82.3k
    gs_cmap_init(mem, pcmap, num_fonts);  /* id, uid, num_fonts */
324
82.3k
    pcmap->CMapType = 1;
325
82.3k
    pcmap->CMapName.data = map_name;
326
82.3k
    pcmap->CMapName.size = name_size;
327
82.3k
    if (pcidsi_in)
328
0
        memcpy(pcidsi, pcidsi_in, sizeof(*pcidsi) * num_fonts);
329
82.3k
    else
330
82.3k
        memset(pcidsi, 0, sizeof(*pcidsi) * num_fonts);
331
82.3k
    pcmap->CIDSystemInfo = pcidsi;
332
82.3k
    pcmap->CMapVersion = 1.0;
333
    /* uid = 0, UIDOffset = 0 */
334
82.3k
    pcmap->WMode = wmode;
335
    /* from_Unicode = 0 */
336
    /* not glyph_name, glyph_name_data */
337
82.3k
    pcmap->procs = procs;
338
82.3k
    *ppcmap = pcmap;
339
82.3k
    return 0;
340
82.3k
}
341
342
int gs_cmap_free(gs_cmap_t *pcmap, gs_memory_t *mem)
343
82.3k
{
344
82.3k
    gs_free_object(mem, pcmap->CIDSystemInfo, "gs_cmap_free(CIDSystemInfo)");
345
82.3k
    gs_free_object(mem, pcmap, "gs_cmap_free(CMap)");
346
82.3k
    return 0;
347
82.3k
}
348
349
/*
350
 * Initialize an enumerator with convenient defaults (index = 0).
351
 */
352
void
353
gs_cmap_ranges_enum_setup(gs_cmap_ranges_enum_t *penum,
354
                          const gs_cmap_t *pcmap,
355
                          const gs_cmap_ranges_enum_procs_t *procs)
356
2.65k
{
357
2.65k
    penum->cmap = pcmap;
358
2.65k
    penum->procs = procs;
359
2.65k
    penum->index = 0;
360
2.65k
}
361
void
362
gs_cmap_lookups_enum_setup(gs_cmap_lookups_enum_t *penum,
363
                           const gs_cmap_t *pcmap,
364
                           const gs_cmap_lookups_enum_procs_t *procs)
365
551k
{
366
551k
    penum->cmap = pcmap;
367
551k
    penum->procs = procs;
368
551k
    penum->index[0] = penum->index[1] = 0;
369
551k
}
370
371
/*
372
 * For a random CMap, compute whether it is identity.
373
 * It is not applicable to gs_cmap_ToUnicode_t due to
374
 * different sizes of domain keys and range values.
375
 * Note we reject CMaps with Registry=Artifex
376
 * to force embedding special instandard CMaps,
377
 * which are not commonly in use yet.
378
 */
379
bool
380
gs_cmap_compute_identity(const gs_cmap_t *pcmap, int font_index_only)
381
32
{
382
32
    const int which = 0;
383
32
    gs_cmap_lookups_enum_t lenum;
384
32
    int code;
385
386
32
    if (!bytes_compare(pcmap->CIDSystemInfo->Registry.data, pcmap->CIDSystemInfo->Registry.size,
387
32
                    (const byte *)"Artifex", 7))
388
0
        return false;
389
32
    for (gs_cmap_lookups_enum_init(pcmap, which, &lenum);
390
32
         (code = gs_cmap_enum_next_lookup(NULL, &lenum)) == 0; ) {
391
27
        if (font_index_only >= 0 && lenum.entry.font_index != font_index_only)
392
0
            continue;
393
27
        if (font_index_only < 0 && lenum.entry.font_index > 0)
394
0
            return false;
395
27
        while (gs_cmap_enum_next_entry(&lenum) == 0) {
396
27
            switch (lenum.entry.value_type) {
397
27
            case CODE_VALUE_CID:
398
27
                break;
399
0
            case CODE_VALUE_CHARS:
400
0
                return false; /* Not implemented yet. */
401
0
            case CODE_VALUE_GLYPH:
402
0
                return false;
403
0
            default :
404
0
                return false; /* Must not happen. */
405
27
            }
406
27
            if (lenum.entry.key_size != lenum.entry.value.size)
407
13
                return false;
408
14
            if (memcmp(lenum.entry.key[0], lenum.entry.value.data,
409
14
                lenum.entry.key_size))
410
14
                return false;
411
14
        }
412
27
    }
413
5
    return true;
414
32
}
415
416
/* ================= ToUnicode CMap ========================= */
417
418
/*
419
 * This kind of CMaps keeps character a mapping from a random
420
 * PS encoding to Unicode, being defined in PDF reference, "ToUnicode CMaps".
421
 * It represents ranges in a closure data, without using
422
 * gx_cmap_lookup_range_t. A special function gs_cmap_ToUnicode_set
423
 * allows to write code pairs into the closure data.
424
 */
425
426
static const int gs_cmap_ToUnicode_code_bytes = 2;
427
428
gs_public_st_suffix_add0(st_cmap_ToUnicode, gs_cmap_ToUnicode_t,
429
    "gs_cmap_ToUnicode_t", cmap_ToUnicode_enum_ptrs, cmap_ToUnicode_reloc_ptrs,
430
    st_cmap);
431
432
static int
433
gs_cmap_ToUnicode_next_range(gs_cmap_ranges_enum_t *penum)
434
5.25k
{   const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
435
5.25k
    if (penum->index == 0) {
436
2.62k
        memset(penum->range.first, 0, cmap->key_size);
437
2.62k
        memset(penum->range.last, 0xff, cmap->key_size);
438
2.62k
        penum->range.size = cmap->key_size;
439
2.62k
        penum->index = 1;
440
2.62k
        return 0;
441
2.62k
    }
442
2.62k
    return 1;
443
5.25k
}
444
445
static const gs_cmap_ranges_enum_procs_t gs_cmap_ToUnicode_range_procs = {
446
    gs_cmap_ToUnicode_next_range
447
};
448
449
static int
450
gs_cmap_ToUnicode_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
451
                     uint *pindex, uint *pfidx,
452
                     gs_char *pchr, gs_glyph *pglyph)
453
0
{
454
0
    return_error(gs_error_unregistered);
455
0
}
456
457
static void
458
gs_cmap_ToUnicode_enum_ranges(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *pre)
459
2.62k
{
460
2.62k
    gs_cmap_ranges_enum_setup(pre, pcmap, &gs_cmap_ToUnicode_range_procs);
461
2.62k
}
462
463
static int
464
gs_cmap_ToUnicode_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum)
465
5.25k
{   const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
466
467
5.25k
    if (penum->index[0]++ > 0)
468
2.62k
        return 1;
469
2.62k
    penum->index[1] = 0;
470
2.62k
    penum->entry.key_is_range = true;
471
2.62k
    penum->entry.value_type = CODE_VALUE_CHARS;
472
2.62k
    penum->entry.key_size = cmap->key_size;
473
2.62k
    penum->entry.value.size = gs_cmap_ToUnicode_code_bytes;
474
2.62k
    penum->entry.font_index = 0;
475
2.62k
    penum->entry.value.data = gs_alloc_bytes(mem, cmap->value_size, "working ToUnicode buffer");
476
2.62k
    penum->entry.value.size = cmap->value_size;
477
2.62k
    return 0;
478
5.25k
}
479
480
static int
481
gs_cmap_ToUnicode_next_entry(gs_cmap_lookups_enum_t *penum)
482
106k
{   const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
483
106k
    const uchar *map = cmap->glyph_name_data;
484
106k
    const int num_codes = cmap->num_codes;
485
106k
    uint index = penum->index[1], i, j;
486
106k
    uchar c0, c1, c2;
487
488
14.7M
    for (i = index; i < num_codes; i++)
489
14.7M
        if (map[i * (cmap->value_size + 2)] != 0 || map[i * (cmap->value_size + 2) + 1] != 0)
490
104k
            break;
491
106k
    if (i >= num_codes)
492
2.62k
        return 1;
493
104k
    c0 = map[i * (cmap->value_size + 2) + 2];
494
104k
    if (cmap->value_size > 1)
495
104k
        c1 = map[i * (cmap->value_size + 2) + 3];
496
0
    else
497
0
        c1 = 0;
498
104k
    for (j = i + 1, c2 = c1 + 1; j < num_codes; j++, c2++) {
499
        /* Due to PDF spec, *bfrange boundaries may differ
500
           in the last byte only. */
501
104k
        if (j % 256 == 0)
502
6
            break;
503
104k
        if ((uchar)c2 == 0)
504
0
            break;
505
104k
        if (map[j * (cmap->value_size + 2) + 2] != c0 || map[i * (cmap->value_size + 2) + 3] != c2)
506
104k
            break;
507
104k
    }
508
104k
    penum->index[1] = j;
509
104k
    if (cmap->key_size > 1) {
510
6.54k
        penum->entry.key[0][0] = (uchar)(i >> 8);
511
6.54k
        penum->entry.key[0][cmap->key_size - 1] = (uchar)(i & 0xFF);
512
6.54k
        penum->entry.key[1][0] = (uchar)(j >> 8);
513
6.54k
        penum->entry.key[1][cmap->key_size - 1] = (uchar)((j - 1) & 0xFF);
514
97.6k
    } else {
515
97.6k
        penum->entry.key[0][0] = (uchar)(i);
516
97.6k
        penum->entry.key[1][0] = (uchar)(j - 1);
517
97.6k
    }
518
104k
    c0 = map[i * (cmap->value_size + 2)];
519
104k
    c1 = map[i * (cmap->value_size + 2) + 1];
520
104k
    penum->entry.value.size = (c0 << 8) + c1;
521
104k
    memcpy((void *)penum->entry.value.data, map + (i * (cmap->value_size + 2)) + 2,
522
104k
        penum->entry.value.size);
523
104k
    return 0;
524
106k
}
525
526
static const gs_cmap_lookups_enum_procs_t gs_cmap_ToUnicode_lookup_procs = {
527
    gs_cmap_ToUnicode_next_lookup, gs_cmap_ToUnicode_next_entry
528
};
529
530
static void
531
gs_cmap_ToUnicode_enum_lookups(const gs_cmap_t *pcmap, int which,
532
                      gs_cmap_lookups_enum_t *pre)
533
5.25k
{
534
5.25k
    gs_cmap_lookups_enum_setup(pre, pcmap,
535
5.25k
                               (which ? &gs_cmap_no_lookups_procs : /* fixme */
536
5.25k
                                &gs_cmap_ToUnicode_lookup_procs));
537
5.25k
}
538
539
static bool
540
gs_cmap_ToUnicode_is_identity(const gs_cmap_t *pcmap, int font_index_only)
541
0
{   const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)pcmap;
542
0
    return cmap->is_identity;
543
0
}
544
545
static const gs_cmap_procs_t gs_cmap_ToUnicode_procs = {
546
    gs_cmap_ToUnicode_decode_next,
547
    gs_cmap_ToUnicode_enum_ranges,
548
    gs_cmap_ToUnicode_enum_lookups,
549
    gs_cmap_ToUnicode_is_identity
550
};
551
552
/*
553
 * Allocate and initialize a ToUnicode CMap.
554
 */
555
int
556
gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, int value_size, gs_cmap_t **ppcmap)
557
2.91k
{   int code;
558
2.91k
    uchar *map, *cmap_name = NULL;
559
2.91k
    gs_cmap_ToUnicode_t *cmap;
560
2.91k
    int name_len = 0;
561
#   if 0
562
        /* We don't write a CMap name to ToUnicode CMaps,
563
         * becsue (1) there is no conventional method for
564
         * generating them, and (2) Acrobat Reader ignores them.
565
         * But we'd like to keep this code until beta-testing completes,
566
         * and we ensure that other viewers do not need the names.
567
         */
568
        char sid[10], *pref = "aux-";
569
        int sid_len, pref_len = strlen(pref);
570
571
        gs_snprintf(sid, sizeof(sid), "%d", id);
572
        sid_len = strlen(sid);
573
        name_len = pref_len + sid_len;
574
        cmap_name = gs_alloc_string(mem, name_len, "gs_cmap_ToUnicode_alloc");
575
        if (cmap_name == 0)
576
            return_error(gs_error_VMerror);
577
        memcpy(cmap_name, pref, pref_len);
578
        memcpy(cmap_name + pref_len, sid, sid_len);
579
#   endif
580
2.91k
    code = gs_cmap_alloc(ppcmap, &st_cmap_ToUnicode,
581
2.91k
              0, cmap_name, name_len, NULL, 0, &gs_cmap_ToUnicode_procs, mem);
582
2.91k
    if (code < 0)
583
0
        return code;
584
2.91k
    map = (uchar *)gs_alloc_bytes(mem,
585
2.91k
                                  (size_t)num_codes * (value_size + 2),
586
2.91k
                                  "gs_cmap_ToUnicode_alloc");
587
2.91k
    if (map == NULL) {
588
0
        gs_cmap_free(*ppcmap, mem);
589
0
        *ppcmap = NULL;
590
0
        return_error(gs_error_VMerror);
591
0
    }
592
2.91k
    memset(map, 0, (size_t)num_codes * (value_size + 2));
593
2.91k
    cmap = (gs_cmap_ToUnicode_t *)*ppcmap;
594
2.91k
    cmap->glyph_name_data = map;
595
2.91k
    cmap->CMapType = 2;
596
2.91k
    cmap->num_fonts = 1;
597
2.91k
    cmap->key_size = key_size;
598
2.91k
    cmap->value_size = value_size;
599
2.91k
    cmap->num_codes = num_codes;
600
2.91k
    cmap->ToUnicode = true;
601
2.91k
    cmap->is_identity = true;
602
2.91k
    return 0;
603
2.91k
}
604
605
int gs_cmap_ToUnicode_free(gs_memory_t *mem, gs_cmap_t *pcmap)
606
2.91k
{
607
2.91k
    gs_free_object(mem, pcmap->glyph_name_data, "Free ToUnicode glyph data");
608
2.91k
    gs_cmap_free(pcmap, mem);
609
2.91k
    return 0;
610
2.91k
}
611
612
/* Ths function is called when we discover that the value length we are using to
613
 * store Unicode code points is too small for a new value. It increases
614
 * the size of the map, and of each entry in the map, which is why we have to
615
 * use a for loop rather than a memcpy. Note that when we increase the number
616
 * of bytes used for a map entry, unused bytes are stored at the end, the initial
617
 * 2 bytes are the length (in bytes) actually used by ths entry.
618
 */
619
int
620
gs_cmap_ToUnicode_realloc(gs_memory_t *mem, int new_value_size, gs_cmap_t **ppcmap)
621
40
{
622
40
    gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)*ppcmap;
623
40
    uchar *new_ptr, *new_map, *old_map = cmap->glyph_name_data;
624
40
    int i;
625
626
40
    new_map = (uchar *)gs_alloc_bytes(mem,
627
40
                                      (size_t)cmap->num_codes *
628
40
                                                   (new_value_size + 2),
629
40
                                      "gs_cmap_ToUnicode_alloc");
630
40
    if (new_map == NULL) {
631
0
        return_error(gs_error_VMerror);
632
0
    }
633
40
    new_ptr = new_map;
634
40
    memset(new_map, 0, (size_t)cmap->num_codes * (new_value_size + 2));
635
636
1.25M
    for (i=0;i<cmap->num_codes;i++) {
637
1.25M
        memcpy(new_ptr, old_map, cmap->value_size + 2);
638
1.25M
        old_map += cmap->value_size + 2;
639
1.25M
        new_ptr += new_value_size + 2;
640
1.25M
    }
641
40
    gs_free_object(mem, cmap->glyph_name_data, "Free (realloc) ToUnicode glyph data");
642
40
    cmap->glyph_name_data = new_map;
643
40
    cmap->value_size = new_value_size;
644
40
    return 0;
645
40
}
646
647
int gs_cmap_ToUnicode_check_pair(gs_cmap_t *pcmap, int code0)
648
538k
{
649
538k
    gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)pcmap;
650
538k
    uchar *map = pcmap->glyph_name_data;
651
538k
    const int num_codes = ((gs_cmap_ToUnicode_t *)pcmap)->num_codes;
652
653
538k
    if (code0 >= num_codes)
654
0
        return 0;
655
538k
    if(map[code0 * (cmap->value_size + 2)] == 0 && map[code0 * (cmap->value_size + 2) + 1] == 0)
656
70.6k
        return 0;
657
467k
    return 1;
658
538k
}
659
660
/*
661
 * Write a code pair to ToUnicode CMap.
662
 */
663
void
664
gs_cmap_ToUnicode_add_pair(gs_cmap_t *pcmap, int code0, ushort *u, unsigned int length)
665
126k
{
666
126k
    gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)pcmap;
667
126k
    uchar *map = pcmap->glyph_name_data, *unicode = (uchar *)u;
668
126k
    const int num_codes = ((gs_cmap_ToUnicode_t *)pcmap)->num_codes;
669
126k
    int i, code1 = 0;
670
671
126k
    if (code0 >= num_codes)
672
0
        return; /* must not happen. */
673
126k
    map[code0 * (cmap->value_size + 2)] = (uchar)(length >> 8);
674
126k
    map[code0 * (cmap->value_size + 2) + 1] = (uchar)(length & 0xFF);
675
676
126k
    memcpy(&map[(code0 * (cmap->value_size + 2)) + 2], unicode, length);
677
126k
    if (length <= 4) {
678
380k
        for (i=0;i<length;i++) {
679
253k
            code1 = (code1 << 8) + unicode[i];
680
253k
        }
681
126k
        cmap->is_identity &= (code0 == code1);
682
126k
    }
683
126k
}