1 /* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gsfcmap.c,v 1.27 2004/12/08 21:35:13 stefan Exp $ */
18 /* CMap character decoding */
19 #include <assert.h>
20 #include "memory_.h"
21 #include "string_.h"
22 #include "gx.h"
23 #include "gserrors.h"
24 #include "gsstruct.h"
25 #include "gsutil.h" /* for gs_next_ids */
26 #include "gxfcmap.h"
27
28 typedef struct gs_cmap_identity_s {
29 GS_CMAP_COMMON;
30 int num_bytes;
31 int varying_bytes;
32 int code; /* 0 or num_bytes */
33 } gs_cmap_identity_t;
34
35 /* GC descriptors */
36 public_st_cmap();
37 gs_private_st_suffix_add0_local(st_cmap_identity, gs_cmap_identity_t,
38 "gs_cmap_identity_t", cmap_ptrs, cmap_data,
39 st_cmap);
40
41 /* ---------------- Client procedures ---------------- */
42
43 /* ------ Initialization/creation ------ */
44
45 /*
46 * Create an Identity CMap.
47 */
48 private uint
get_integer_bytes(const byte * src,int count)49 get_integer_bytes(const byte *src, int count)
50 {
51 uint v = 0;
52 int i;
53
54 for (i = 0; i < count; ++i)
55 v = (v << 8) + src[i];
56 return v;
57 }
58 private int
identity_decode_next(const gs_cmap_t * pcmap,const gs_const_string * str,uint * pindex,uint * pfidx,gs_char * pchr,gs_glyph * pglyph)59 identity_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
60 uint *pindex, uint *pfidx,
61 gs_char *pchr, gs_glyph *pglyph)
62 {
63 const gs_cmap_identity_t *const pcimap =
64 (const gs_cmap_identity_t *)pcmap;
65 int num_bytes = pcimap->num_bytes;
66 uint value;
67
68 if (str->size < *pindex + num_bytes) {
69 *pglyph = gs_no_glyph;
70 return (*pindex == str->size ? 2 : -1);
71 }
72 value = get_integer_bytes(str->data + *pindex, num_bytes);
73 *pglyph = gs_min_cid_glyph + value;
74 *pchr = value;
75 *pindex += num_bytes;
76 *pfidx = 0;
77 return pcimap->code;
78 }
79 private int
identity_next_range(gs_cmap_ranges_enum_t * penum)80 identity_next_range(gs_cmap_ranges_enum_t *penum)
81 {
82 if (penum->index == 0) {
83 const gs_cmap_identity_t *const pcimap =
84 (const gs_cmap_identity_t *)penum->cmap;
85
86 memset(penum->range.first, 0, pcimap->num_bytes);
87 memset(penum->range.last, 0xff, pcimap->num_bytes);
88 penum->index = 1;
89 return 0;
90 }
91 return 1;
92 }
93 private const gs_cmap_ranges_enum_procs_t identity_range_procs = {
94 identity_next_range
95 };
96 private void
identity_enum_ranges(const gs_cmap_t * pcmap,gs_cmap_ranges_enum_t * pre)97 identity_enum_ranges(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *pre)
98 {
99 gs_cmap_ranges_enum_setup(pre, pcmap, &identity_range_procs);
100 }
101 private int
identity_next_lookup(gs_cmap_lookups_enum_t * penum)102 identity_next_lookup(gs_cmap_lookups_enum_t *penum)
103 {
104 if (penum->index[0] == 0) {
105 const gs_cmap_identity_t *const pcimap =
106 (const gs_cmap_identity_t *)penum->cmap;
107 int num_bytes = pcimap->num_bytes;
108
109 memset(penum->entry.key[0], 0, num_bytes);
110 memset(penum->entry.key[1], 0xff, num_bytes);
111 memset(penum->entry.key[1], 0, num_bytes - pcimap->varying_bytes);
112 penum->entry.key_size = num_bytes;
113 penum->entry.key_is_range = true;
114 penum->entry.value_type =
115 (pcimap->code ? CODE_VALUE_CHARS : CODE_VALUE_CID);
116 penum->entry.value.size = num_bytes;
117 penum->entry.font_index = 0;
118 penum->index[0] = 1;
119 return 0;
120 }
121 return 1;
122 }
123 private int
no_next_lookup(gs_cmap_lookups_enum_t * penum)124 no_next_lookup(gs_cmap_lookups_enum_t *penum)
125 {
126 return 1;
127 }
128 private int
identity_next_entry(gs_cmap_lookups_enum_t * penum)129 identity_next_entry(gs_cmap_lookups_enum_t *penum)
130 {
131 const gs_cmap_identity_t *const pcimap =
132 (const gs_cmap_identity_t *)penum->cmap;
133 int num_bytes = pcimap->num_bytes;
134 int i = num_bytes - pcimap->varying_bytes;
135
136 memcpy(penum->temp_value, penum->entry.key[0], num_bytes);
137 memcpy(penum->entry.key[0], penum->entry.key[1], i);
138 while (--i >= 0)
139 if (++(penum->entry.key[1][i]) != 0) {
140 penum->entry.value.data = penum->temp_value;
141 return 0;
142 }
143 return 1;
144 }
145
146 private const gs_cmap_lookups_enum_procs_t identity_lookup_procs = {
147 identity_next_lookup, identity_next_entry
148 };
149 const gs_cmap_lookups_enum_procs_t gs_cmap_no_lookups_procs = {
150 no_next_lookup, 0
151 };
152 private void
identity_enum_lookups(const gs_cmap_t * pcmap,int which,gs_cmap_lookups_enum_t * pre)153 identity_enum_lookups(const gs_cmap_t *pcmap, int which,
154 gs_cmap_lookups_enum_t *pre)
155 {
156 gs_cmap_lookups_enum_setup(pre, pcmap,
157 (which ? &gs_cmap_no_lookups_procs :
158 &identity_lookup_procs));
159 }
160 private bool
identity_is_identity(const gs_cmap_t * pcmap,int font_index_only)161 identity_is_identity(const gs_cmap_t *pcmap, int font_index_only)
162 {
163 return true;
164 }
165
166 private const gs_cmap_procs_t identity_procs = {
167 identity_decode_next, identity_enum_ranges, identity_enum_lookups, identity_is_identity
168 };
169
170 private int
gs_cmap_identity_alloc(gs_cmap_t ** ppcmap,int num_bytes,int varying_bytes,int return_code,const char * cmap_name,int wmode,gs_memory_t * mem)171 gs_cmap_identity_alloc(gs_cmap_t **ppcmap, int num_bytes, int varying_bytes,
172 int return_code, const char *cmap_name, int wmode,
173 gs_memory_t *mem)
174 {
175 /*
176 * We could allow any value of num_bytes between 1 and
177 * min(MAX_CMAP_CODE_SIZE, 4), but if num_bytes != 2, we can't name
178 * the result "Identity-[HV]".
179 */
180 static const gs_cid_system_info_t identity_cidsi = {
181 { (const byte *)"Adobe", 5 },
182 { (const byte *)"Identity", 8 },
183 0
184 };
185 int code;
186 gs_cmap_identity_t *pcimap;
187
188 if (num_bytes != 2)
189 return_error(gs_error_rangecheck);
190 code = gs_cmap_alloc(ppcmap, &st_cmap_identity, wmode,
191 (const byte *)cmap_name, strlen(cmap_name),
192 &identity_cidsi, 1, &identity_procs, mem);
193 if (code < 0)
194 return code;
195 pcimap = (gs_cmap_identity_t *)*ppcmap;
196 pcimap->num_bytes = num_bytes;
197 pcimap->varying_bytes = varying_bytes;
198 pcimap->code = return_code;
199 return 0;
200 }
201 int
gs_cmap_create_identity(gs_cmap_t ** ppcmap,int num_bytes,int wmode,gs_memory_t * mem)202 gs_cmap_create_identity(gs_cmap_t **ppcmap, int num_bytes, int wmode,
203 gs_memory_t *mem)
204 {
205 return gs_cmap_identity_alloc(ppcmap, num_bytes, num_bytes, 0,
206 (wmode ? "Identity-V" : "Identity-H"),
207 wmode, mem);
208 }
209 int
gs_cmap_create_char_identity(gs_cmap_t ** ppcmap,int num_bytes,int wmode,gs_memory_t * mem)210 gs_cmap_create_char_identity(gs_cmap_t **ppcmap, int num_bytes, int wmode,
211 gs_memory_t *mem)
212 {
213 return gs_cmap_identity_alloc(ppcmap, num_bytes, 1, num_bytes,
214 (wmode ? "Identity-BF-V" : "Identity-BF-H"),
215 wmode, mem);
216 }
217
218 /* ------ Check identity ------ */
219
220 /*
221 * Check for identity CMap. Uses a fast check for special cases.
222 */
223 int
gs_cmap_is_identity(const gs_cmap_t * pcmap,int font_index_only)224 gs_cmap_is_identity(const gs_cmap_t *pcmap, int font_index_only)
225 {
226 return pcmap->procs->is_identity(pcmap, font_index_only);
227 }
228
229 /* ------ Decoding ------ */
230
231 /*
232 * Decode and map a character from a string using a CMap.
233 * See gsfcmap.h for details.
234 */
235 int
gs_cmap_decode_next(const gs_cmap_t * pcmap,const gs_const_string * str,uint * pindex,uint * pfidx,gs_char * pchr,gs_glyph * pglyph)236 gs_cmap_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
237 uint *pindex, uint *pfidx,
238 gs_char *pchr, gs_glyph *pglyph)
239 {
240 return pcmap->procs->decode_next(pcmap, str, pindex, pfidx, pchr, pglyph);
241 }
242
243 /* ------ Enumeration ------ */
244
245 /*
246 * Initialize the enumeration of the code space ranges, and enumerate
247 * the next range. See gxfcmap.h for details.
248 */
249 void
gs_cmap_ranges_enum_init(const gs_cmap_t * pcmap,gs_cmap_ranges_enum_t * penum)250 gs_cmap_ranges_enum_init(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *penum)
251 {
252 pcmap->procs->enum_ranges(pcmap, penum);
253 }
254 int
gs_cmap_enum_next_range(gs_cmap_ranges_enum_t * penum)255 gs_cmap_enum_next_range(gs_cmap_ranges_enum_t *penum)
256 {
257 return penum->procs->next_range(penum);
258 }
259
260 /*
261 * Initialize the enumeration of the lookups, and enumerate the next
262 * the next lookup or entry. See gxfcmap.h for details.
263 */
264 void
gs_cmap_lookups_enum_init(const gs_cmap_t * pcmap,int which,gs_cmap_lookups_enum_t * penum)265 gs_cmap_lookups_enum_init(const gs_cmap_t *pcmap, int which,
266 gs_cmap_lookups_enum_t *penum)
267 {
268 pcmap->procs->enum_lookups(pcmap, which, penum);
269 }
270 int
gs_cmap_enum_next_lookup(gs_cmap_lookups_enum_t * penum)271 gs_cmap_enum_next_lookup(gs_cmap_lookups_enum_t *penum)
272 {
273 return penum->procs->next_lookup(penum);
274 }
275 int
gs_cmap_enum_next_entry(gs_cmap_lookups_enum_t * penum)276 gs_cmap_enum_next_entry(gs_cmap_lookups_enum_t *penum)
277 {
278 return penum->procs->next_entry(penum);
279 }
280
281 /* ---------------- Implementation procedures ---------------- */
282
283 /* ------ Initialization/creation ------ */
284
285 /*
286 * Initialize a just-allocated CMap, to ensure that all pointers are clean
287 * for the GC. Note that this only initializes the common part.
288 */
289 void
gs_cmap_init(const gs_memory_t * mem,gs_cmap_t * pcmap,int num_fonts)290 gs_cmap_init(const gs_memory_t *mem, gs_cmap_t *pcmap, int num_fonts)
291 {
292 memset(pcmap, 0, sizeof(*pcmap));
293 /* We reserve a range of IDs for pdfwrite needs,
294 to allow an identification of submaps for a particular subfont.
295 */
296 pcmap->id = gs_next_ids(mem, num_fonts);
297 pcmap->num_fonts = num_fonts;
298 uid_set_invalid(&pcmap->uid);
299 }
300
301 /*
302 * Allocate and initialize (the common part of) a CMap.
303 */
304 int
gs_cmap_alloc(gs_cmap_t ** ppcmap,const gs_memory_struct_type_t * pstype,int wmode,const byte * map_name,uint name_size,const gs_cid_system_info_t * pcidsi_in,int num_fonts,const gs_cmap_procs_t * procs,gs_memory_t * mem)305 gs_cmap_alloc(gs_cmap_t **ppcmap, const gs_memory_struct_type_t *pstype,
306 int wmode, const byte *map_name, uint name_size,
307 const gs_cid_system_info_t *pcidsi_in, int num_fonts,
308 const gs_cmap_procs_t *procs, gs_memory_t *mem)
309 {
310 gs_cmap_t *pcmap =
311 gs_alloc_struct(mem, gs_cmap_t, pstype, "gs_cmap_alloc(CMap)");
312 gs_cid_system_info_t *pcidsi =
313 gs_alloc_struct_array(mem, num_fonts, gs_cid_system_info_t,
314 &st_cid_system_info_element,
315 "gs_cmap_alloc(CIDSystemInfo)");
316
317 if (pcmap == 0 || pcidsi == 0) {
318 gs_free_object(mem, pcidsi, "gs_cmap_alloc(CIDSystemInfo)");
319 gs_free_object(mem, pcmap, "gs_cmap_alloc(CMap)");
320 return_error(gs_error_VMerror);
321 }
322 gs_cmap_init(mem, pcmap, num_fonts); /* id, uid, num_fonts */
323 pcmap->CMapType = 1;
324 pcmap->CMapName.data = map_name;
325 pcmap->CMapName.size = name_size;
326 if (pcidsi_in)
327 memcpy(pcidsi, pcidsi_in, sizeof(*pcidsi) * num_fonts);
328 else
329 memset(pcidsi, 0, sizeof(*pcidsi) * num_fonts);
330 pcmap->CIDSystemInfo = pcidsi;
331 pcmap->CMapVersion = 1.0;
332 /* uid = 0, UIDOffset = 0 */
333 pcmap->WMode = wmode;
334 /* from_Unicode = 0 */
335 /* not glyph_name, glyph_name_data */
336 pcmap->procs = procs;
337 *ppcmap = pcmap;
338 return 0;
339 }
340
341 /*
342 * Initialize an enumerator with convenient defaults (index = 0).
343 */
344 void
gs_cmap_ranges_enum_setup(gs_cmap_ranges_enum_t * penum,const gs_cmap_t * pcmap,const gs_cmap_ranges_enum_procs_t * procs)345 gs_cmap_ranges_enum_setup(gs_cmap_ranges_enum_t *penum,
346 const gs_cmap_t *pcmap,
347 const gs_cmap_ranges_enum_procs_t *procs)
348 {
349 penum->cmap = pcmap;
350 penum->procs = procs;
351 penum->index = 0;
352 }
353 void
gs_cmap_lookups_enum_setup(gs_cmap_lookups_enum_t * penum,const gs_cmap_t * pcmap,const gs_cmap_lookups_enum_procs_t * procs)354 gs_cmap_lookups_enum_setup(gs_cmap_lookups_enum_t *penum,
355 const gs_cmap_t *pcmap,
356 const gs_cmap_lookups_enum_procs_t *procs)
357 {
358 penum->cmap = pcmap;
359 penum->procs = procs;
360 penum->index[0] = penum->index[1] = 0;
361 }
362
363 /*
364 * For a random CMap, compute whether it is identity.
365 * It is not applicable to gs_cmap_ToUnicode_t due to
366 * different sizes of domain keys and range values.
367 */
368 bool
gs_cmap_compute_identity(const gs_cmap_t * pcmap,int font_index_only)369 gs_cmap_compute_identity(const gs_cmap_t *pcmap, int font_index_only)
370 {
371 const int which = 0;
372 gs_cmap_lookups_enum_t lenum;
373 int code;
374
375 for (gs_cmap_lookups_enum_init(pcmap, which, &lenum);
376 (code = gs_cmap_enum_next_lookup(&lenum)) == 0; ) {
377 if (font_index_only >= 0 && lenum.entry.font_index != font_index_only)
378 continue;
379 if (font_index_only < 0 && lenum.entry.font_index > 0)
380 return false;
381 while (gs_cmap_enum_next_entry(&lenum) == 0) {
382 switch (lenum.entry.value_type) {
383 case CODE_VALUE_CID:
384 break;
385 case CODE_VALUE_CHARS:
386 return false; /* Not implemented yet. */
387 case CODE_VALUE_GLYPH:
388 return false;
389 default :
390 return false; /* Must not happen. */
391 }
392 if (lenum.entry.key_size != lenum.entry.value.size)
393 return false;
394 if (memcmp(lenum.entry.key[0], lenum.entry.value.data,
395 lenum.entry.key_size))
396 return false;
397 }
398 }
399 return true;
400 }
401
402 /* ================= ToUnicode CMap ========================= */
403
404 /*
405 * This kind of CMaps keeps character a mapping from a random
406 * PS encoding to Unicode, being defined in PDF reference, "ToUnicode CMaps".
407 * It represents ranges in a closure data, without using
408 * gx_cmap_lookup_range_t. A special function gs_cmap_ToUnicode_set
409 * allows to write code pairs into the closure data.
410 */
411
412 private const int gs_cmap_ToUnicode_code_bytes = 2;
413
414 typedef struct gs_cmap_ToUnicode_s {
415 GS_CMAP_COMMON;
416 int num_codes;
417 int key_size;
418 bool is_identity;
419 } gs_cmap_ToUnicode_t;
420
421 gs_private_st_suffix_add0(st_cmap_ToUnicode, gs_cmap_ToUnicode_t,
422 "gs_cmap_ToUnicode_t", cmap_ToUnicode_enum_ptrs, cmap_ToUnicode_reloc_ptrs,
423 st_cmap);
424
425 private int
gs_cmap_ToUnicode_next_range(gs_cmap_ranges_enum_t * penum)426 gs_cmap_ToUnicode_next_range(gs_cmap_ranges_enum_t *penum)
427 { const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
428 if (penum->index == 0) {
429 memset(penum->range.first, 0, cmap->key_size);
430 memset(penum->range.last, 0xff, cmap->key_size);
431 penum->range.size = cmap->key_size;
432 penum->index = 1;
433 return 0;
434 }
435 return 1;
436 }
437
438 private const gs_cmap_ranges_enum_procs_t gs_cmap_ToUnicode_range_procs = {
439 gs_cmap_ToUnicode_next_range
440 };
441
442 private int
gs_cmap_ToUnicode_decode_next(const gs_cmap_t * pcmap,const gs_const_string * str,uint * pindex,uint * pfidx,gs_char * pchr,gs_glyph * pglyph)443 gs_cmap_ToUnicode_decode_next(const gs_cmap_t *pcmap, const gs_const_string *str,
444 uint *pindex, uint *pfidx,
445 gs_char *pchr, gs_glyph *pglyph)
446 {
447 assert(0); /* Unsupported, because never used. */
448 return 0;
449 }
450
451 private void
gs_cmap_ToUnicode_enum_ranges(const gs_cmap_t * pcmap,gs_cmap_ranges_enum_t * pre)452 gs_cmap_ToUnicode_enum_ranges(const gs_cmap_t *pcmap, gs_cmap_ranges_enum_t *pre)
453 {
454 gs_cmap_ranges_enum_setup(pre, pcmap, &gs_cmap_ToUnicode_range_procs);
455 }
456
457 private int
gs_cmap_ToUnicode_next_lookup(gs_cmap_lookups_enum_t * penum)458 gs_cmap_ToUnicode_next_lookup(gs_cmap_lookups_enum_t *penum)
459 { const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
460
461 if (penum->index[0]++ > 0)
462 return 1;
463 penum->entry.value.data = penum->temp_value;
464 penum->entry.value.size = gs_cmap_ToUnicode_code_bytes;
465 penum->index[1] = 0;
466 penum->entry.key_is_range = true;
467 penum->entry.value_type = CODE_VALUE_CHARS;
468 penum->entry.key_size = cmap->key_size;
469 penum->entry.value.size = gs_cmap_ToUnicode_code_bytes;
470 penum->entry.font_index = 0;
471 return 0;
472 }
473
474 private int
gs_cmap_ToUnicode_next_entry(gs_cmap_lookups_enum_t * penum)475 gs_cmap_ToUnicode_next_entry(gs_cmap_lookups_enum_t *penum)
476 { const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)penum->cmap;
477 const uchar *map = cmap->glyph_name_data;
478 const int num_codes = cmap->num_codes;
479 uint index = penum->index[1], i, j;
480 uchar c0, c1, c2;
481
482 /* Warning : this hardcodes gs_cmap_ToUnicode_num_code_bytes = 2 */
483 for (i = index; i < num_codes; i++)
484 if (map[i + i + 0] != 0 || map[i + i + 1] != 0)
485 break;
486 if (i >= num_codes)
487 return 1;
488 c0 = map[i + i + 0];
489 c1 = map[i + i + 1];
490 for (j = i + 1, c2 = c1 + 1; j < num_codes; j++, c2++) {
491 /* Due to PDF spec, *bfrange boundaries may differ
492 in the last byte only. */
493 if (j % 256 == 0)
494 break;
495 if ((uchar)c2 == 0)
496 break;
497 if (map[j + j + 0] != c0 || map[j + j + 1] != c2)
498 break;
499 }
500 penum->index[1] = j;
501 penum->entry.key[0][0] = (uchar)(i >> 8);
502 penum->entry.key[0][cmap->key_size - 1] = (uchar)(i & 0xFF);
503 penum->entry.key[1][0] = (uchar)(j >> 8);
504 penum->entry.key[1][cmap->key_size - 1] = (uchar)((j - 1) & 0xFF);
505 memcpy(penum->temp_value, map + i * gs_cmap_ToUnicode_code_bytes,
506 gs_cmap_ToUnicode_code_bytes);
507 return 0;
508 }
509
510 private const gs_cmap_lookups_enum_procs_t gs_cmap_ToUnicode_lookup_procs = {
511 gs_cmap_ToUnicode_next_lookup, gs_cmap_ToUnicode_next_entry
512 };
513
514 private void
gs_cmap_ToUnicode_enum_lookups(const gs_cmap_t * pcmap,int which,gs_cmap_lookups_enum_t * pre)515 gs_cmap_ToUnicode_enum_lookups(const gs_cmap_t *pcmap, int which,
516 gs_cmap_lookups_enum_t *pre)
517 {
518 gs_cmap_lookups_enum_setup(pre, pcmap,
519 (which ? &gs_cmap_no_lookups_procs : /* fixme */
520 &gs_cmap_ToUnicode_lookup_procs));
521 }
522
523 private bool
gs_cmap_ToUnicode_is_identity(const gs_cmap_t * pcmap,int font_index_only)524 gs_cmap_ToUnicode_is_identity(const gs_cmap_t *pcmap, int font_index_only)
525 { const gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)pcmap;
526 return cmap->is_identity;
527 }
528
529 private const gs_cmap_procs_t gs_cmap_ToUnicode_procs = {
530 gs_cmap_ToUnicode_decode_next,
531 gs_cmap_ToUnicode_enum_ranges,
532 gs_cmap_ToUnicode_enum_lookups,
533 gs_cmap_ToUnicode_is_identity
534 };
535
536 /*
537 * Allocate and initialize a ToUnicode CMap.
538 */
539 int
gs_cmap_ToUnicode_alloc(gs_memory_t * mem,int id,int num_codes,int key_size,gs_cmap_t ** ppcmap)540 gs_cmap_ToUnicode_alloc(gs_memory_t *mem, int id, int num_codes, int key_size, gs_cmap_t **ppcmap)
541 { int code;
542 uchar *map, *cmap_name = NULL;
543 gs_cmap_ToUnicode_t *cmap;
544 int name_len = 0;
545 # if 0
546 /* We don't write a CMap name to ToUnicode CMaps,
547 * becsue (1) there is no conventional method for
548 * generating them, and (2) Acrobat Reader ignores them.
549 * But we'd like to keep this code until beta-testing completes,
550 * and we ensure that other viewers do not need the names.
551 */
552 char sid[10], *pref = "aux-";
553 int sid_len, pref_len = strlen(pref);
554
555 sprintf(sid, "%d", id);
556 sid_len = strlen(sid);
557 name_len = pref_len + sid_len;
558 cmap_name = gs_alloc_string(mem, name_len, "gs_cmap_ToUnicode_alloc");
559 if (cmap_name == 0)
560 return_error(gs_error_VMerror);
561 memcpy(cmap_name, pref, pref_len);
562 memcpy(cmap_name + pref_len, sid, sid_len);
563 # endif
564 code = gs_cmap_alloc(ppcmap, &st_cmap_ToUnicode,
565 0, cmap_name, name_len, NULL, 0, &gs_cmap_ToUnicode_procs, mem);
566 if (code < 0)
567 return code;
568 map = (uchar *)gs_alloc_bytes(mem, num_codes * gs_cmap_ToUnicode_code_bytes,
569 "gs_cmap_ToUnicode_alloc");
570 if (map == NULL)
571 return_error(gs_error_VMerror);
572 memset(map, 0, num_codes * gs_cmap_ToUnicode_code_bytes);
573 cmap = (gs_cmap_ToUnicode_t *)*ppcmap;
574 cmap->glyph_name_data = map;
575 cmap->CMapType = 2;
576 cmap->num_fonts = 1;
577 cmap->key_size = key_size;
578 cmap->num_codes = num_codes;
579 cmap->ToUnicode = true;
580 cmap->is_identity = true;
581 return 0;
582 }
583
584 /*
585 * Write a code pair to ToUnicode CMap.
586 */
587 void
gs_cmap_ToUnicode_add_pair(gs_cmap_t * pcmap,int code0,int code1)588 gs_cmap_ToUnicode_add_pair(gs_cmap_t *pcmap, int code0, int code1)
589 { gs_cmap_ToUnicode_t *cmap = (gs_cmap_ToUnicode_t *)pcmap;
590 uchar *map = pcmap->glyph_name_data;
591 const int num_codes = ((gs_cmap_ToUnicode_t *)pcmap)->num_codes;
592
593 if (code0 >= num_codes)
594 return; /* must not happen. */
595 map[code0 * gs_cmap_ToUnicode_code_bytes + 0] = (uchar)(code1 >> 8);
596 map[code0 * gs_cmap_ToUnicode_code_bytes + 1] = (uchar)(code1 & 0xFF);
597 cmap->is_identity &= (code0 == code1);
598 }
599