xref: /plan9/sys/src/cmd/gs/src/zfcmap.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 1998, 1999, 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: zfcmap.c,v 1.17 2005/10/04 06:30:02 ray Exp $ */
18 /* CMap creation operator */
19 #include "memory_.h"
20 #include "ghost.h"
21 #include "oper.h"
22 #include "gsmatrix.h"		/* for gxfont.h */
23 #include "gsstruct.h"
24 #include "gsutil.h"		/* for bytes_compare */
25 #include "gxfcmap1.h"
26 #include "gxfont.h"
27 #include "ialloc.h"
28 #include "icid.h"
29 #include "iddict.h"
30 #include "idparam.h"
31 #include "ifont.h"		/* for zfont_mark_glyph_name */
32 #include "iname.h"
33 #include "store.h"
34 
35 /* Exported for zfont0.c */
36 int ztype0_get_cmap(const gs_cmap_t ** ppcmap, const ref * pfdepvector,
37 		    const ref * op, gs_memory_t *imem);
38 
39 /*
40  * Define whether to check the compatibility of CIDSystemInfo between the
41  * CMap and the composite font.  PLRM2 says compatibility is required, but
42  * PLRM3 says the interpreter doesn't check it.
43  */
44 /*#define CHECK_CID_SYSTEM_INFO_COMPATIBILITY*/
45 
46 /* ---------------- Internal procedures ---------------- */
47 
48 /* Free a code map in case of VMerror. */
49 private void
free_code_map(gx_code_map_t * pcmap,gs_memory_t * mem)50 free_code_map(gx_code_map_t * pcmap, gs_memory_t * mem)
51 {
52     if (pcmap->lookup) {
53 	int i;
54 
55 	for (i = 0; i < pcmap->num_lookup; ++i) {
56 	    gx_cmap_lookup_range_t *pclr = &pcmap->lookup[i];
57 
58 	    if (pclr->value_type == CODE_VALUE_GLYPH)
59 		gs_free_string(mem, pclr->values.data, pclr->values.size,
60 			       "free_code_map(values)");
61 	}
62 	gs_free_object(mem, pcmap->lookup, "free_code_map(map)");
63     }
64 }
65 
66 /* Convert code ranges to internal form. */
67 private int
acquire_code_ranges(gs_cmap_adobe1_t * cmap,const ref * pref,gs_memory_t * mem)68 acquire_code_ranges(gs_cmap_adobe1_t *cmap, const ref *pref, gs_memory_t *mem)
69 {
70     uint num_ranges = 0;
71     gx_code_space_range_t *ranges;
72     uint i, j, elem_sz;
73     ref elem;
74 
75     if (!r_is_array(pref))
76 	return_error(e_rangecheck);
77     for (i=0; i < r_size(pref); i++) {
78         int code = array_get(mem, pref, i, &elem);
79         if (code < 0)
80             return code;
81         elem_sz = r_size(&elem);
82         if (elem_sz & 1)
83 	    return_error(e_rangecheck);
84         num_ranges += elem_sz;
85     }
86     if (num_ranges == 0)
87 	return_error(e_rangecheck);
88     num_ranges >>= 1;
89 
90     ranges = (gx_code_space_range_t *)
91 	gs_alloc_byte_array(mem, num_ranges, sizeof(gx_code_space_range_t),
92 			    "acquire_code_ranges");
93     if (ranges == 0)
94 	return_error(e_VMerror);
95     cmap->code_space.ranges = ranges;
96     cmap->code_space.num_ranges = num_ranges;
97 
98     for (i = 0; i < r_size(pref); i++) {
99         array_get(mem, pref, i, &elem);
100         elem_sz = r_size(&elem);
101         for (j = 0; j < elem_sz; j += 2) {
102 	ref rfirst, rlast;
103 	int size;
104 
105 	    array_get(mem, &elem, j, &rfirst);
106 	    array_get(mem, &elem, j + 1, &rlast);
107 	if (!r_has_type(&rfirst, t_string) ||
108 	    !r_has_type(&rlast, t_string) ||
109 	    (size = r_size(&rfirst)) == 0 || size > MAX_CMAP_CODE_SIZE ||
110 	    r_size(&rlast) != size ||
111 	    memcmp(rfirst.value.bytes, rlast.value.bytes, size) > 0)
112 	    return_error(e_rangecheck);
113 	memcpy(ranges->first, rfirst.value.bytes, size);
114 	memcpy(ranges->last, rlast.value.bytes, size);
115 	ranges->size = size;
116             ++ranges;
117         }
118     }
119     return 0;
120 }
121 
122 /* Convert a code map to internal form. */
123 private int
acquire_code_map(gx_code_map_t * pcmap,const ref * pref,gs_cmap_adobe1_t * root,gs_memory_t * mem)124 acquire_code_map(gx_code_map_t *pcmap, const ref *pref, gs_cmap_adobe1_t *root,
125 		 gs_memory_t *mem)
126 {
127     uint num_lookup = 0;
128     gx_cmap_lookup_range_t *pclr;
129     long i;
130     ref elem;
131     uint elem_sz;
132 
133     if (!r_is_array(pref))
134 	return_error(e_rangecheck);
135     for (i=0; i < r_size(pref); i++) {
136         int code = array_get(mem, pref, i, &elem);
137         if (code < 0)
138             return code;
139         elem_sz = r_size(&elem);
140         if (elem_sz % 5 != 0)
141 	return_error(e_rangecheck);
142         num_lookup += elem_sz;
143     }
144     num_lookup /= 5;
145     pclr = gs_alloc_struct_array(mem, num_lookup, gx_cmap_lookup_range_t,
146 				 &st_cmap_lookup_range_element,
147 				 "acquire_code_map(lookup ranges)");
148     if (pclr == 0)
149 	return_error(e_VMerror);
150     memset(pclr, 0, sizeof(*pclr) * num_lookup);
151     pcmap->lookup = pclr;
152     pcmap->num_lookup = num_lookup;
153 
154 
155     for (i = 0; i < r_size(pref); i++) {
156         uint j;
157         array_get(mem, pref, i, &elem);
158         elem_sz = r_size(&elem);
159         for (j = 0; j < elem_sz; j += 5) {
160 	ref rprefix, rmisc, rkeys, rvalues, rfxs;
161 
162 	    array_get(mem, &elem, j, &rprefix);
163 	    array_get(mem, &elem, j + 1, &rmisc);
164 	    array_get(mem, &elem, j + 2, &rkeys);
165 	    array_get(mem, &elem, j + 3, &rvalues);
166 	    array_get(mem, &elem, j + 4, &rfxs);
167 
168 	if (!r_has_type(&rprefix, t_string) ||
169 	    !r_has_type(&rmisc, t_string) ||
170 	    !r_has_type(&rkeys, t_string) ||
171 	    !(r_has_type(&rvalues, t_string) || r_is_array(&rvalues)) ||
172 	    !r_has_type(&rfxs, t_integer)
173 	    )
174 	    return_error(e_typecheck);
175 	if (r_size(&rmisc) != 4 ||
176 	    rmisc.value.bytes[0] > MAX_CMAP_CODE_SIZE - r_size(&rprefix) ||
177 	    rmisc.value.bytes[1] > 1 ||
178 	    rmisc.value.bytes[2] > CODE_VALUE_MAX ||
179 	    rmisc.value.bytes[3] == 0)
180 	    return_error(e_rangecheck);
181 	pclr->cmap = root;
182 	pclr->key_size = rmisc.value.bytes[0];
183 	pclr->key_prefix_size = r_size(&rprefix);
184 	memcpy(pclr->key_prefix, rprefix.value.bytes, pclr->key_prefix_size);
185 	pclr->key_is_range = rmisc.value.bytes[1];
186 	if (pclr->key_size == 0) {
187 	    /* This is a single entry consisting only of the prefix. */
188 	    if (r_size(&rkeys) != 0)
189 		return_error(e_rangecheck);
190 	    pclr->num_entries = 1;
191 	} else {
192 	    int step = pclr->key_size * (pclr->key_is_range ? 2 : 1);
193 
194 	    if (r_size(&rkeys) % step != 0)
195 		return_error(e_rangecheck);
196 	    pclr->num_entries = r_size(&rkeys) / step;
197 	}
198 	pclr->keys.data = rkeys.value.bytes,
199 	    pclr->keys.size = r_size(&rkeys);
200 	pclr->value_type = rmisc.value.bytes[2];
201 	pclr->value_size = rmisc.value.bytes[3];
202 	if (r_has_type(&rvalues, t_string)) {
203 	    if (pclr->value_type == CODE_VALUE_GLYPH)
204 		return_error(e_rangecheck);
205 	    if (r_size(&rvalues) % pclr->num_entries != 0 ||
206 		r_size(&rvalues) / pclr->num_entries != pclr->value_size)
207 		return_error(e_rangecheck);
208 	    pclr->values.data = rvalues.value.bytes,
209 		pclr->values.size = r_size(&rvalues);
210 	} else {
211 	    uint values_size = pclr->num_entries * pclr->value_size;
212 	    long k;
213 	    byte *pvalue;
214 
215 	    if (pclr->value_type != CODE_VALUE_GLYPH ||
216 		r_size(&rvalues) != pclr->num_entries ||
217 		pclr->value_size > sizeof(gs_glyph))
218 		return_error(e_rangecheck);
219 	    pclr->values.data = gs_alloc_string(mem, values_size,
220 						"acquire_code_map(values)");
221 	    if (pclr->values.data == 0)
222 		return_error(e_VMerror);
223 	    pclr->values.size = values_size;
224 	    pvalue = pclr->values.data;
225 	    for (k = 0; k < pclr->num_entries; ++k) {
226 		ref rvalue;
227 		gs_glyph value;
228 		int i;
229 
230 		array_get(mem, &rvalues, k, &rvalue);
231 		if (!r_has_type(&rvalue, t_name))
232 		    return_error(e_rangecheck);
233 		value = name_index(mem, &rvalue);
234 		/*
235 		 * We need a special check here because some CPUs cannot
236 		 * shift by the full size of an int or long.
237 		 */
238 		if (pclr->value_size < sizeof(value) &&
239 		    (value >> (pclr->value_size * 8)) != 0
240 		    )
241 		    return_error(e_rangecheck);
242 		for (i = pclr->value_size; --i >= 0; )
243 		    *pvalue++ = (byte)(value >> (i * 8));
244 	    }
245 	}
246 	check_int_leu_only(rfxs, 0xff);
247 	pclr->font_index = (int)rfxs.value.intval;
248             ++pclr;
249         }
250     }
251     return 0;
252 }
253 
254 /*
255  * Acquire the CIDSystemInfo array from a dictionary.  If missing, fabricate
256  * a 0-element array and return 1.
257  */
258 private int
acquire_cid_system_info(ref * psia,const ref * op)259 acquire_cid_system_info(ref *psia, const ref *op)
260 {
261     ref *prcidsi;
262 
263     if (dict_find_string(op, "CIDSystemInfo", &prcidsi) <= 0) {
264 	make_empty_array(psia, a_readonly);
265 	return 1;
266     }
267     if (r_has_type(prcidsi, t_dictionary)) {
268 	make_array(psia, a_readonly, 1, prcidsi);
269 	return 0;
270     }
271     if (!r_is_array(prcidsi))
272 	return_error(e_typecheck);
273     *psia = *prcidsi;
274     return 0;
275 }
276 
277 /*
278  * Get one element of a CIDSystemInfo array.  If the element is missing or
279  * null, return 1.
280  */
281 private int
get_cid_system_info(const gs_memory_t * mem,gs_cid_system_info_t * pcidsi,const ref * psia,uint index)282 get_cid_system_info(const gs_memory_t *mem, gs_cid_system_info_t *pcidsi, const ref *psia, uint index)
283 {
284     ref rcidsi;
285     int code = array_get(mem, psia, (long)index, &rcidsi);
286 
287     if (code < 0 || r_has_type(&rcidsi, t_null)) {
288 	cid_system_info_set_null(pcidsi);
289 	return 1;
290     }
291     return cid_system_info_param(pcidsi, &rcidsi);
292 }
293 
294 #ifdef CHECK_CID_SYSTEM_INFO_COMPATIBILITY
295 
296 /* Check compatibility of CIDSystemInfo. */
297 private bool
bytes_eq(const gs_const_string * pcs1,const gs_const_string * pcs2)298 bytes_eq(const gs_const_string *pcs1, const gs_const_string *pcs2)
299 {
300     return !bytes_compare(pcs1->data, pcs1->size,
301 			  pcs2->data, pcs2->size);
302 }
303 private bool
cid_system_info_compatible(const gs_cid_system_info_t * psi1,const gs_cid_system_info_t * psi2)304 cid_system_info_compatible(const gs_cid_system_info_t * psi1,
305 			   const gs_cid_system_info_t * psi2)
306 {
307     return bytes_eq(&psi1->Registry, &psi2->Registry) &&
308 	bytes_eq(&psi1->Ordering, &psi2->Ordering);
309 }
310 
311 #endif /* CHECK_CID_SYSTEM_INFO_COMPATIBILITY */
312 
313 /* ---------------- (Semi-)public procedures ---------------- */
314 
315 /* Get the CodeMap from a Type 0 font, and check the CIDSystemInfo of */
316 /* its subsidiary fonts. */
317 int
ztype0_get_cmap(const gs_cmap_t ** ppcmap,const ref * pfdepvector,const ref * op,gs_memory_t * imem)318 ztype0_get_cmap(const gs_cmap_t **ppcmap, const ref *pfdepvector,
319 		const ref *op, gs_memory_t *imem)
320 {
321     ref *prcmap;
322     ref *pcodemap;
323     const gs_cmap_t *pcmap;
324     int code;
325     uint num_fonts;
326     uint i;
327 
328     /*
329      * We have no way of checking whether the CodeMap is a concrete
330      * subclass of gs_cmap_t, so we just check that it is in fact a
331      * t_struct and is large enough.
332      */
333     if (dict_find_string(op, "CMap", &prcmap) <= 0 ||
334 	!r_has_type(prcmap, t_dictionary) ||
335 	dict_find_string(prcmap, "CodeMap", &pcodemap) <= 0 ||
336 	!r_is_struct(pcodemap) ||
337 	gs_object_size(imem, r_ptr(pcodemap, gs_cmap_t)) < sizeof(gs_cmap_t)
338 	)
339 	return_error(e_invalidfont);
340     pcmap = r_ptr(pcodemap, gs_cmap_t);
341     num_fonts = r_size(pfdepvector);
342     for (i = 0; i < num_fonts; ++i) {
343 	ref rfdep, rfsi;
344 
345 	array_get(imem, pfdepvector, (long)i, &rfdep);
346 	code = acquire_cid_system_info(&rfsi, &rfdep);
347 	if (code < 0)
348 	    return code;
349 	if (code == 0) {
350 	    if (r_size(&rfsi) != 1)
351 		return_error(e_rangecheck);
352 #ifdef CHECK_CID_SYSTEM_INFO_COMPATIBILITY
353 	    {
354 		gs_cid_system_info_t cidsi;
355 
356 		get_cid_system_info(&cidsi, &rfsi, 0);
357 		if (!cid_system_info_is_null(&cidsi) &&
358 		    !cid_system_info_compatible(&cidsi,
359 						pcmap->CIDSystemInfo + i))
360 		    return_error(e_rangecheck);
361 	    }
362 #endif
363 	}
364     }
365     *ppcmap = pcmap;
366     return 0;
367 }
368 
369 /* ---------------- Operators ---------------- */
370 
371 /* <CMap> .buildcmap <CMap> */
372 /*
373  * Create the internal form of a CMap.  The initial CMap must be read-write
374  * and have an entry with key = CodeMap and value = null; the result is
375  * read-only and has a real CodeMap.
376  *
377  * This operator reads the CMapType, CMapName, CIDSystemInfo, CMapVersion,
378  * UIDOffset, XUID, WMode, and .CodeMapData elements of the CMap dictionary.
379  * For details, see lib/gs_cmap.ps and the Adobe documentation.
380  */
381 private int
zfcmap_glyph_name(const gs_memory_t * mem,gs_glyph glyph,gs_const_string * pstr,void * proc_data)382 zfcmap_glyph_name(const gs_memory_t *mem,
383 		  gs_glyph glyph, gs_const_string *pstr, void *proc_data)
384 {
385     ref nref, nsref;
386     int code = 0;
387 
388     /*code = */name_index_ref(mem, (uint)glyph, &nref);
389     if (code < 0)
390 	return code;
391     name_string_ref(mem, &nref, &nsref);
392     pstr->data = nsref.value.const_bytes;
393     pstr->size = r_size(&nsref);
394     return 0;
395 }
396 private int
zbuildcmap(i_ctx_t * i_ctx_p)397 zbuildcmap(i_ctx_t *i_ctx_p)
398 {
399     os_ptr op = osp;
400     int code;
401     ref *pcmapname;
402     ref *puidoffset;
403     ref *pcodemapdata;
404     ref *pcodemap;
405     ref rname, rcidsi, rcoderanges, rdefs, rnotdefs;
406     gs_cmap_adobe1_t *pcmap = 0;
407     ref rcmap;
408     uint i;
409 
410     check_type(*op, t_dictionary);
411     check_dict_write(*op);
412     if ((code = dict_find_string(op, "CMapName", &pcmapname)) <= 0) {
413 	code = gs_note_error(e_rangecheck);
414 	goto fail;
415     }
416     if (!r_has_type(pcmapname, t_name)) {
417 	code = gs_note_error(e_typecheck);
418 	goto fail;
419     }
420     name_string_ref(imemory, pcmapname, &rname);
421     if (dict_find_string(op, ".CodeMapData", &pcodemapdata) <= 0 ||
422 	!r_has_type(pcodemapdata, t_array) ||
423 	r_size(pcodemapdata) != 3 ||
424 	dict_find_string(op, "CodeMap", &pcodemap) <= 0 ||
425 	!r_has_type(pcodemap, t_null)
426 	) {
427 	code = gs_note_error(e_rangecheck);
428 	goto fail;
429     }
430     if ((code = acquire_cid_system_info(&rcidsi, op)) < 0)
431 	goto fail;
432     if ((code = gs_cmap_adobe1_alloc(&pcmap, 0, rname.value.const_bytes,
433 				     r_size(&rname), r_size(&rcidsi),
434 				     0, 0, 0, 0, 0, imemory)) < 0)
435 	goto fail;
436     if ((code = dict_int_param(op, "CMapType", 0, 1, 0, &pcmap->CMapType)) < 0 ||
437 	(code = dict_float_param(op, "CMapVersion", 0.0, &pcmap->CMapVersion)) < 0 ||
438 	(code = dict_uid_param(op, &pcmap->uid, 0, imemory, i_ctx_p)) < 0 ||
439 	(code = dict_int_param(op, "WMode", 0, 1, 0, &pcmap->WMode)) < 0
440 	)
441 	goto fail;
442     if (dict_find_string(op, "UIDOffset", &puidoffset) > 0) {
443 	if (!r_has_type(puidoffset, t_integer)) {
444 	    code = gs_note_error(e_typecheck);
445 	    goto fail;
446 	}
447 	pcmap->UIDOffset = puidoffset->value.intval; /* long, not int */
448     }
449     for (i = 0; i < r_size(&rcidsi); ++i) {
450         code = get_cid_system_info(imemory, pcmap->CIDSystemInfo + i, &rcidsi, i);
451 	if (code < 0)
452 	    goto fail;
453     }
454     array_get(imemory, pcodemapdata, 0L, &rcoderanges);
455     array_get(imemory, pcodemapdata, 1L, &rdefs);
456     array_get(imemory, pcodemapdata, 2L, &rnotdefs);
457     if ((code = acquire_code_ranges(pcmap, &rcoderanges, imemory)) < 0)
458 	goto fail;
459     if ((code = acquire_code_map(&pcmap->def, &rdefs, pcmap, imemory)) < 0)
460 	goto fail;
461     if ((code = acquire_code_map(&pcmap->notdef, &rnotdefs, pcmap, imemory)) < 0)
462 	goto fail;
463     pcmap->mark_glyph = zfont_mark_glyph_name;
464     pcmap->mark_glyph_data = 0;
465     pcmap->glyph_name = zfcmap_glyph_name;
466     pcmap->glyph_name_data = 0;
467     make_istruct_new(&rcmap, a_readonly, pcmap);
468     code = idict_put_string(op, "CodeMap", &rcmap);
469     if (code < 0)
470 	goto fail;
471     return zreadonly(i_ctx_p);
472 fail:
473     if (pcmap) {
474 	free_code_map(&pcmap->notdef, imemory);
475 	free_code_map(&pcmap->def, imemory);
476 	ifree_object(pcmap->CIDSystemInfo, "zbuildcmap(CIDSystemInfo)");
477 	ifree_object(pcmap, "zbuildcmap(cmap)");
478     }
479     return code;
480 }
481 
482 /* ------ Initialization procedure ------ */
483 
484 const op_def zfcmap_op_defs[] =
485 {
486     {"1.buildcmap", zbuildcmap},
487     op_def_end(0)
488 };
489