/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 | } |