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