/src/ghostpdl/base/gsfcid2.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 | | /* Create a CIDFontType 2 font from a Type 42 font. */ |
18 | | #include "memory_.h" |
19 | | #include "gx.h" |
20 | | #include "gserrors.h" |
21 | | #include "gsstruct.h" |
22 | | #include "gsutil.h" |
23 | | #include "gxfont.h" |
24 | | #include "gxfcid.h" |
25 | | #include "gxfcmap.h" |
26 | | #include "gxfont0c.h" |
27 | | |
28 | | /* |
29 | | * Create a Type 2 CIDFont from a Type 42 font. |
30 | | */ |
31 | | static int |
32 | | identity_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph) |
33 | 0 | { |
34 | 0 | ulong cid = glyph - GS_MIN_CID_GLYPH; |
35 | |
|
36 | 0 | if (cid >= pfont->cidata.common.CIDCount) |
37 | 0 | return_error(gs_error_rangecheck); |
38 | 0 | return (int)cid; |
39 | 0 | } |
40 | | int |
41 | | gs_font_cid2_from_type42(gs_font_cid2 **ppfcid, gs_font_type42 *pfont42, |
42 | | int wmode, gs_memory_t *mem) |
43 | 0 | { |
44 | 0 | gs_font_cid2 *pfcid = |
45 | 0 | gs_alloc_struct(mem, gs_font_cid2, &st_gs_font_cid2, |
46 | 0 | "gs_font_cid2_from_type42"); |
47 | |
|
48 | 0 | if (pfcid == 0) |
49 | 0 | return_error(gs_error_VMerror); |
50 | | |
51 | | /* CIDFontType 2 is a subclass (extension) of FontType 42. */ |
52 | 0 | memcpy(pfcid, pfont42, sizeof(*pfont42)); |
53 | 0 | pfcid->memory = mem; |
54 | 0 | pfcid->next = pfcid->prev = 0; /* probably not necessary */ |
55 | 0 | pfcid->is_resource = 0; |
56 | 0 | gs_font_notify_init((gs_font *)pfcid); |
57 | 0 | pfcid->id = gs_next_ids(mem, 1); |
58 | 0 | pfcid->base = (gs_font *)pfcid; |
59 | 0 | pfcid->FontType = ft_CID_TrueType; |
60 | | /* Fill in the rest of the CIDFont data. */ |
61 | 0 | cid_system_info_set_null(&pfcid->cidata.common.CIDSystemInfo); |
62 | 0 | pfcid->cidata.common.CIDCount = pfont42->data.numGlyphs; |
63 | 0 | pfcid->cidata.common.GDBytes = 2; /* not used */ |
64 | 0 | pfcid->cidata.MetricsCount = 0; |
65 | 0 | pfcid->cidata.CIDMap_proc = identity_CIDMap_proc; |
66 | | /* Since MetricsCount == 0, don't need orig_procs. */ |
67 | |
|
68 | 0 | *ppfcid = pfcid; |
69 | 0 | return 0; |
70 | 0 | } |
71 | | |
72 | 0 | #define U16(p) (((uint)((p)[0]) << 8) + (p)[1]) |
73 | 0 | #define U32(p) get_u32_msb(p) |
74 | | #define PUT16(p, v)\ |
75 | 0 | BEGIN (p)[0] = (byte)((v) >> 8); (p)[1] = (byte)(v); END |
76 | | |
77 | | /* |
78 | | * Define a subclass of gs_cmap_t that accesses the most common type of |
79 | | * TrueType cmap (Platform 3, Encoding 1, Format 4) directly. |
80 | | */ |
81 | | typedef struct gs_cmap_tt_16bit_format4_s { |
82 | | GS_CMAP_COMMON; |
83 | | gs_font_type42 *font; |
84 | | uint segCount2; |
85 | | ulong endCount, startCount, idDelta, idRangeOffset, glyphIdArray; |
86 | | } gs_cmap_tt_16bit_format4_t; |
87 | | gs_public_st_suffix_add1(st_cmap_tt_16bit_format4, gs_cmap_tt_16bit_format4_t, |
88 | | "gs_cmap_tt_16bit_format4_t", |
89 | | cmap_tt_16bit_format4_enum_ptrs, cmap_tt_16bit_format4_reloc_ptrs, |
90 | | st_cmap, font); |
91 | | |
92 | | static int |
93 | | tt_16bit_format4_decode_next(const gs_cmap_t * pcmap_in, |
94 | | const gs_const_string * pstr, |
95 | | uint * pindex, uint * pfidx, |
96 | | gs_char * pchr, gs_glyph * pglyph) |
97 | 0 | { |
98 | 0 | const gs_cmap_tt_16bit_format4_t *pcmap = |
99 | 0 | (const gs_cmap_tt_16bit_format4_t *)pcmap_in; |
100 | 0 | gs_font_type42 *pfont = pcmap->font; |
101 | 0 | byte ttdata[2]; |
102 | 0 | int code; |
103 | 0 | uint chr, value = 0; |
104 | 0 | uint segment2; |
105 | |
|
106 | 0 | if (pstr->size < *pindex + 2) { |
107 | 0 | *pglyph = GS_NO_GLYPH; |
108 | 0 | return (*pindex == pstr->size ? 2 : -1); |
109 | 0 | } |
110 | 0 | chr = U16(pstr->data + *pindex); |
111 | | /* The table is sorted, but we use linear search for simplicity. */ |
112 | 0 | for (segment2 = 0; segment2 < pcmap->segCount2; segment2 += 2) { |
113 | 0 | uint start, delta, roff; |
114 | |
|
115 | 0 | READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata); |
116 | 0 | if (chr > U16(ttdata)) |
117 | 0 | continue; |
118 | 0 | READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata); |
119 | 0 | start = U16(ttdata); |
120 | 0 | if (chr < start) |
121 | 0 | continue; |
122 | 0 | READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata); |
123 | 0 | delta = U16(ttdata); |
124 | 0 | READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata); |
125 | 0 | roff = U16(ttdata); |
126 | 0 | if (roff) { |
127 | 0 | ulong gidoff = pcmap->idRangeOffset + segment2 + roff + |
128 | 0 | (chr - start) * 2; |
129 | |
|
130 | 0 | READ_SFNTS(pfont, gidoff, 2, ttdata); |
131 | 0 | value = U16(ttdata); |
132 | 0 | if (value != 0) |
133 | 0 | value += delta; |
134 | 0 | } else |
135 | 0 | value = chr + delta; |
136 | 0 | break; |
137 | 0 | } |
138 | 0 | *pglyph = GS_MIN_CID_GLYPH + (value & 0xffff); |
139 | 0 | *pchr = chr; |
140 | 0 | *pindex += 2; |
141 | 0 | *pfidx = 0; |
142 | 0 | return 0; |
143 | 0 | } |
144 | | static int |
145 | | tt_16bit_format4_next_range(gs_cmap_ranges_enum_t *penum) |
146 | 0 | { |
147 | | /* There is just a single 2-byte range. */ |
148 | 0 | if (penum->index == 0) { |
149 | 0 | penum->range.first[0] = penum->range.first[1] = 0; |
150 | 0 | penum->range.last[0] = penum->range.last[1] = 0xff; |
151 | 0 | penum->range.size = 2; |
152 | 0 | penum->index = 1; |
153 | 0 | return 0; |
154 | 0 | } |
155 | 0 | return 1; |
156 | 0 | } |
157 | | static const gs_cmap_ranges_enum_procs_t tt_16bit_format4_range_procs = { |
158 | | tt_16bit_format4_next_range |
159 | | }; |
160 | | static void |
161 | | tt_16bit_format4_enum_ranges(const gs_cmap_t *pcmap, |
162 | | gs_cmap_ranges_enum_t *pre) |
163 | 0 | { |
164 | 0 | gs_cmap_ranges_enum_setup(pre, pcmap, &tt_16bit_format4_range_procs); |
165 | 0 | } |
166 | | static int |
167 | | tt_16bit_format4_next_lookup(gs_memory_t *mem, gs_cmap_lookups_enum_t *penum) |
168 | 0 | { |
169 | 0 | penum->entry.value.data = 0L; |
170 | 0 | if (penum->index[0] == 0) { |
171 | 0 | penum->entry.key_size = 2; |
172 | 0 | penum->entry.key_is_range = true; |
173 | 0 | penum->entry.value_type = CODE_VALUE_CID; |
174 | 0 | penum->entry.value.size = 2; |
175 | 0 | penum->entry.font_index = 0; |
176 | 0 | penum->index[0] = 1; |
177 | 0 | return 0; |
178 | 0 | } |
179 | 0 | return 1; |
180 | 0 | } |
181 | | static int |
182 | | tt_16bit_format4_next_entry(gs_cmap_lookups_enum_t *penum) |
183 | 0 | { |
184 | | /* index[1] is segment # << 17 + first code. */ |
185 | 0 | uint segment2 = penum->index[1] >> 16; |
186 | 0 | uint next = penum->index[1] & 0xffff; |
187 | 0 | const gs_cmap_tt_16bit_format4_t *pcmap = |
188 | 0 | (const gs_cmap_tt_16bit_format4_t *)penum->cmap; |
189 | 0 | gs_font_type42 *pfont = pcmap->font; |
190 | 0 | byte ttdata[2]; |
191 | 0 | int code; |
192 | 0 | uint start, end, delta, roff; |
193 | 0 | uint value; |
194 | |
|
195 | 0 | top: |
196 | 0 | if (segment2 >= pcmap->segCount2) |
197 | 0 | return 1; |
198 | 0 | READ_SFNTS(pfont, pcmap->endCount + segment2, 2, ttdata); |
199 | 0 | end = U16(ttdata); |
200 | 0 | if (next > end) { |
201 | 0 | segment2 += 2; |
202 | 0 | goto top; |
203 | 0 | } |
204 | 0 | READ_SFNTS(pfont, pcmap->startCount + segment2, 2, ttdata); |
205 | 0 | start = U16(ttdata); |
206 | 0 | if (next < start) |
207 | 0 | next = start; |
208 | 0 | PUT16(penum->entry.key[0], next); |
209 | 0 | READ_SFNTS(pfont, pcmap->idDelta + segment2, 2, ttdata); |
210 | 0 | delta = U16(ttdata); |
211 | 0 | READ_SFNTS(pfont, pcmap->idRangeOffset + segment2, 2, ttdata); |
212 | 0 | roff = U16(ttdata); |
213 | 0 | if (roff) { |
214 | | /* Non-zero offset, table lookup. */ |
215 | 0 | ulong gidoff = pcmap->idRangeOffset + segment2 + roff; |
216 | |
|
217 | 0 | READ_SFNTS(pfont, gidoff, 2, ttdata); |
218 | 0 | value = U16(ttdata); |
219 | 0 | if (value != 0) |
220 | 0 | value += delta; |
221 | 0 | ++next; |
222 | 0 | } else { |
223 | | /* Zero offset, account for high-order byte changes. */ |
224 | 0 | value = next + delta; |
225 | 0 | next = min(end, (next | 0xff)) + 1; |
226 | 0 | } |
227 | 0 | PUT16(penum->entry.key[1], next - 1); |
228 | 0 | PUT16(penum->temp_value, value); |
229 | 0 | penum->entry.value.data = penum->temp_value; |
230 | 0 | penum->entry.value.size = 2; |
231 | 0 | penum->index[1] = (segment2 << 16) + next; |
232 | 0 | return 0; |
233 | 0 | } |
234 | | static const gs_cmap_lookups_enum_procs_t tt_16bit_format4_lookup_procs = { |
235 | | tt_16bit_format4_next_lookup, tt_16bit_format4_next_entry |
236 | | }; |
237 | | static void |
238 | | tt_16bit_format4_enum_lookups(const gs_cmap_t *pcmap, int which, |
239 | | gs_cmap_lookups_enum_t *pre) |
240 | 0 | { |
241 | 0 | gs_cmap_lookups_enum_setup(pre, pcmap, |
242 | 0 | (which ? &gs_cmap_no_lookups_procs : |
243 | 0 | &tt_16bit_format4_lookup_procs)); |
244 | 0 | } |
245 | | |
246 | | static const gs_cmap_procs_t tt_16bit_format4_procs = { |
247 | | tt_16bit_format4_decode_next, |
248 | | tt_16bit_format4_enum_ranges, |
249 | | tt_16bit_format4_enum_lookups, |
250 | | gs_cmap_compute_identity |
251 | | }; |
252 | | |
253 | | /* |
254 | | * Create a CMap from a TrueType Platform 3, Encoding 1, Format 4 cmap. |
255 | | */ |
256 | | int |
257 | | gs_cmap_from_type42_cmap(gs_cmap_t **ppcmap, gs_font_type42 *pfont, |
258 | | int wmode, gs_memory_t *mem) |
259 | 0 | { |
260 | 0 | ulong origin = pfont->data.cmap; |
261 | 0 | gs_cmap_tt_16bit_format4_t *pcmap; |
262 | 0 | int code; |
263 | 0 | byte ttdata[8]; |
264 | 0 | ulong offset = origin; |
265 | 0 | uint segCount2; |
266 | |
|
267 | 0 | if (origin == 0) |
268 | 0 | return_error(gs_error_invalidfont); |
269 | | |
270 | | /* |
271 | | * Find the desired cmap sub-table, if any. |
272 | | */ |
273 | 0 | { |
274 | 0 | uint cmap_count; |
275 | 0 | uint i; |
276 | |
|
277 | 0 | READ_SFNTS(pfont, origin + 2, 2, ttdata); |
278 | 0 | cmap_count = U16(ttdata); |
279 | 0 | for (i = 0; i < cmap_count; ++i) { |
280 | 0 | READ_SFNTS(pfont, origin + 4 + i * 8, 8, ttdata); |
281 | 0 | if (U16(ttdata) != 3 || /* platform ID */ |
282 | 0 | U16(ttdata + 2) != 1 /* encoding ID */ |
283 | 0 | ) |
284 | 0 | continue; |
285 | 0 | offset = origin + U32(ttdata + 4); |
286 | 0 | READ_SFNTS(pfont, offset, 2, ttdata); |
287 | 0 | if (U16(ttdata) != 4 /* format */) |
288 | 0 | continue; |
289 | 0 | break; |
290 | 0 | } |
291 | 0 | if (i >= cmap_count) /* not found */ |
292 | 0 | return_error(gs_error_invalidfont); |
293 | 0 | READ_SFNTS(pfont, offset + 6, 2, ttdata); |
294 | 0 | segCount2 = U16(ttdata); |
295 | 0 | } |
296 | | |
297 | | /* Allocate the CMap. */ |
298 | 0 | { |
299 | 0 | static const gs_cid_system_info_t null_cidsi = { |
300 | 0 | { (const byte*) "none", 4 }, |
301 | 0 | { (const byte*) "none", 4 }, |
302 | 0 | 0 |
303 | 0 | }; |
304 | 0 | code = gs_cmap_alloc(ppcmap, &st_cmap_tt_16bit_format4, wmode, |
305 | 0 | (const byte *)"none", 4, &null_cidsi, 1, |
306 | 0 | &tt_16bit_format4_procs, mem); |
307 | 0 | if (code < 0) |
308 | 0 | return code; |
309 | 0 | } |
310 | 0 | pcmap = (gs_cmap_tt_16bit_format4_t *)*ppcmap; |
311 | 0 | pcmap->from_Unicode = true; |
312 | 0 | pcmap->font = pfont; |
313 | 0 | pcmap->segCount2 = segCount2; |
314 | 0 | pcmap->endCount = offset + 14; |
315 | 0 | pcmap->startCount = pcmap->endCount + segCount2 + 2; |
316 | 0 | pcmap->idDelta = pcmap->startCount + segCount2; |
317 | 0 | pcmap->idRangeOffset = pcmap->idDelta + segCount2; |
318 | 0 | pcmap->glyphIdArray = pcmap->idRangeOffset + segCount2; |
319 | 0 | return 0; |
320 | 0 | } |