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