Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zcid.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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 and CID-keyed font services */
18
#include "ghost.h"
19
#include "ierrors.h"
20
#include "gxcid.h"
21
#include "icid.h"   /* for checking prototype */
22
#include "idict.h"
23
#include "idparam.h"
24
#include "store.h"
25
#include "oper.h"
26
#include "gserrors.h"
27
28
/* Get the information from a CIDSystemInfo dictionary. */
29
int
30
cid_system_info_param(gs_cid_system_info_t *pcidsi, const ref *prcidsi)
31
2
{
32
2
    ref *pregistry;
33
2
    ref *pordering;
34
2
    int code;
35
36
2
    if (!r_has_type(prcidsi, t_dictionary))
37
0
        return_error(gs_error_typecheck);
38
2
    if (dict_find_string(prcidsi, "Registry", &pregistry) <= 0 ||
39
2
        dict_find_string(prcidsi, "Ordering", &pordering) <= 0
40
2
        )
41
0
        return_error(gs_error_rangecheck);
42
2
    check_read_type_only(*pregistry, t_string);
43
2
    check_read_type_only(*pordering, t_string);
44
2
    pcidsi->Registry.data = pregistry->value.const_bytes;
45
2
    pcidsi->Registry.size = r_size(pregistry);
46
2
    pcidsi->Ordering.data = pordering->value.const_bytes;
47
2
    pcidsi->Ordering.size = r_size(pordering);
48
2
    code = dict_int_param(prcidsi, "Supplement", 0, max_int, -1,
49
2
                          &pcidsi->Supplement);
50
2
    return (code < 0 ? code : 0);
51
2
}
52
53
/* Convert a CID into TT char code or to TT glyph index. */
54
static bool
55
TT_char_code_from_CID_no_subst(const gs_memory_t *mem,
56
                               const ref *Decoding, const ref *TT_cmap, uint nCID, uint *c)
57
0
{   ref *DecodingArray, char_code, char_code1, ih, *glyph_index;
58
0
    bool found = false;
59
0
    int i = nCID % 256, n;
60
61
0
    make_int(&ih, nCID / 256);
62
0
    if (dict_find(Decoding, &ih, &DecodingArray) <= 0 ||
63
0
            !r_has_type(DecodingArray, t_array) ||
64
0
            array_get(mem, DecodingArray, i, &char_code) < 0)
65
0
        return false;
66
0
    if (r_has_type(&char_code, t_integer))
67
0
        n = 1;
68
0
    else if (r_has_type(&char_code, t_array)) {
69
0
        DecodingArray = &char_code;
70
0
        i = 0;
71
0
        n = r_size(DecodingArray);
72
0
    } else
73
0
        return false; /* Must not happen. */
74
0
    for (;n--; i++) {
75
0
        int code;
76
77
0
        if (array_get(mem, DecodingArray, i, &char_code1) < 0 ||
78
0
            !r_has_type(&char_code1, t_integer))
79
0
            return false; /* Must not happen. */
80
0
        code = dict_find(TT_cmap, &char_code1, &glyph_index);
81
0
        if (code > 0 && r_has_type(glyph_index, t_integer)) {
82
0
            *c = glyph_index->value.intval;
83
0
            found = true;
84
0
            if (*c != 0)
85
0
                return true;
86
0
        }
87
0
    }
88
0
    return found;
89
0
}
90
91
/* Convert a CID into a TT char code or into a TT glyph index, using SubstNWP. */
92
/* Returns 1 if a glyph presents, 0 if not, <0 if error. */
93
int
94
cid_to_TT_charcode(const gs_memory_t *mem,
95
                   const ref *Decoding, const ref *TT_cmap, const ref *SubstNWP,
96
                   uint nCID, uint *c, ref *src_type, ref *dst_type)
97
0
{
98
0
    int SubstNWP_length = r_size(SubstNWP), i, code;
99
100
0
    if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, nCID, c)) {
101
0
        make_null(src_type);
102
        /* Leaving dst_type uninitialized. */
103
0
        return 1;
104
0
    }
105
0
    for (i = 0; i < SubstNWP_length; i += 5) {
106
0
        ref rb, re, rs;
107
0
        int nb, ne, ns;
108
109
0
        if ((code = array_get(mem, SubstNWP, i + 1, &rb)) < 0)
110
0
            return code;
111
0
        if ((code = array_get(mem, SubstNWP, i + 2, &re)) < 0)
112
0
            return code;
113
0
        if ((code = array_get(mem, SubstNWP, i + 3, &rs)) < 0)
114
0
            return code;
115
0
        if (!r_has_type(&rb, t_integer) || !r_has_type(&re, t_integer) || !r_has_type(&rs, t_integer))
116
0
            return_error(gs_error_typecheck);
117
0
        nb = rb.value.intval;
118
0
        ne = re.value.intval;
119
0
        ns = rs.value.intval;
120
0
        if (nCID >= nb && nCID <= ne)
121
0
            if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, ns + (nCID - nb), c)) {
122
0
                if ((code = array_get(mem, SubstNWP, i + 0, src_type)) < 0)
123
0
                    return code;
124
0
                if ((code = array_get(mem, SubstNWP, i + 4, dst_type)) < 0)
125
0
                    return code;
126
0
                return 1;
127
0
            }
128
0
        if (nCID >= ns && nCID <= ns + (ne - nb))
129
0
            if (TT_char_code_from_CID_no_subst(mem, Decoding, TT_cmap, nb + (nCID - ns), c)) {
130
0
                if ((code = array_get(mem, SubstNWP, i + 0, dst_type)) < 0)
131
0
                    return code;
132
0
                if ((code = array_get(mem, SubstNWP, i + 4, src_type)) < 0)
133
0
                    return code;
134
0
                return 1;
135
0
            }
136
0
    }
137
0
    *c = 0;
138
0
    return 0;
139
0
}
140
141
/* Set a CIDMap element. */
142
static int
143
set_CIDMap_element(const gs_memory_t *mem, ref *CIDMap, uint cid, uint glyph_index)
144
0
{   /* Assuming the CIDMap is already type-checked. */
145
    /* Assuming GDBytes == 2. */
146
0
    uint offset = cid * 2;
147
0
    uint count = r_size(CIDMap), size, i;
148
0
    ref s;
149
0
    uchar *c;
150
151
0
    if (glyph_index >= 65536 || cid > max_uint / 2)
152
0
        return_error(gs_error_rangecheck); /* Can't store with GDBytes == 2. */
153
0
    for (i = 0; i < count; i++) {
154
0
        array_get(mem, CIDMap, i, &s);
155
0
        if (!r_has_type(&s, t_string))
156
0
            return 0;
157
0
        size = r_size(&s) & ~1;
158
0
        if (offset < size) {
159
0
            c = s.value.bytes + offset;
160
0
            c[0] = (uchar)(glyph_index >> 8);
161
0
            c[1] = (uchar)(glyph_index & 255);
162
0
            break;
163
0
        }
164
0
        offset -= size;
165
0
    }
166
    /* We ignore the substitution if it goes out the CIDMap range.
167
       It must not happen, except for empty Decoding elements */
168
0
    return 0;
169
0
}
170
171
/* Create a CIDMap from a True Type cmap array, Decoding and SubstNWP. */
172
int
173
cid_fill_CIDMap(const gs_memory_t *mem,
174
                const ref *Decoding, const ref *TT_cmap, const ref *SubstNWP, int GDBytes,
175
                ref *CIDMap)
176
0
{   int dict_enum;
177
0
    ref el[2];
178
0
    int count, i;
179
180
0
    if (GDBytes != 2)
181
0
        return_error(gs_error_unregistered); /* Unimplemented. */
182
0
    if (r_type(CIDMap) != t_array)
183
0
        return_error(gs_error_unregistered); /* Unimplemented. It could be a single string. */
184
0
    count = r_size(CIDMap);
185
    /* Checking the CIDMap structure correctness : */
186
0
    for (i = 0; i < count; i++) {
187
0
        ref s;
188
0
        int code = array_get(mem, CIDMap, i, &s);
189
190
0
        if (code < 0)
191
0
            return code;
192
0
        check_type(s, t_string); /* fixme : optimize with moving to TT_char_code_from_CID. */
193
0
    }
194
    /* Compute the CIDMap : */
195
0
    dict_enum = dict_first(Decoding);
196
0
    for (;;) {
197
0
        int index, count, i;
198
199
0
        if ((dict_enum = dict_next(Decoding, dict_enum, el)) == -1)
200
0
            break;
201
0
        if (!r_has_type(&el[0], t_integer))
202
0
            continue;
203
0
        if (!r_has_type(&el[1], t_array))
204
0
            return_error(gs_error_typecheck);
205
0
        index = el[0].value.intval;
206
0
        count = r_size(&el[1]);
207
0
        for (i = 0; i < count; i++) {
208
0
            uint cid = index * 256 + i, glyph_index;
209
0
            ref src_type, dst_type;
210
0
            int code = cid_to_TT_charcode(mem, Decoding, TT_cmap, SubstNWP,
211
0
                                cid, &glyph_index, &src_type, &dst_type);
212
213
0
            if (code < 0)
214
0
                return code;
215
0
            if (code > 0) {
216
0
                code = set_CIDMap_element(mem, CIDMap, cid, glyph_index);
217
0
                if (code < 0)
218
0
                    return code;
219
0
            }
220
0
        }
221
0
    }
222
0
    return 0;
223
0
}
224
225
int
226
cid_fill_Identity_CIDMap(const gs_memory_t *mem,
227
                ref *CIDMap)
228
0
{   int count, i;
229
230
0
    count = r_size(CIDMap);
231
0
    if (count != 3)
232
0
        return_error(gs_error_rangecheck);
233
234
    /* Checking the CIDMap structure correctness : */
235
0
    for (i = 0; i < count; i++) {
236
0
        ref s;
237
0
        int code = array_get(mem, CIDMap, i, &s);
238
239
0
        if (code < 0)
240
0
            return code;
241
0
        check_type(s, t_string); /* fixme : optimize with moving to TT_char_code_from_CID. */
242
0
    }
243
0
    for (i=0; i < 255*255; i++) {
244
0
        int code;
245
246
0
        code = set_CIDMap_element(mem, CIDMap, i, i);
247
0
        if (code < 0)
248
0
            return code;
249
0
    }
250
0
    return 0;
251
0
}