xref: /plan9/sys/src/cmd/gs/src/iccfont.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992-2004 artofcode LLC.  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: iccfont.c,v 1.11 2004/10/26 02:50:56 giles Exp $ */
18 /* Initialization support for compiled fonts */
19 
20 #include "string_.h"
21 #include "ghost.h"
22 #include "gsstruct.h"		/* for iscan.h */
23 #include "gscencs.h"
24 #include "gsmatrix.h"
25 #include "gxfont.h"		/* for ifont.h */
26 #include "ccfont.h"
27 #include "ierrors.h"
28 #include "ialloc.h"
29 #include "idict.h"
30 #include "ifont.h"
31 #include "iname.h"
32 #include "isave.h"		/* for ialloc_ref_array */
33 #include "iutil.h"
34 #include "oper.h"
35 #include "ostack.h"		/* for iscan.h */
36 #include "store.h"
37 #include "stream.h"		/* for iscan.h */
38 #include "strimpl.h"		/* for sfilter.h for picky compilers */
39 #include "sfilter.h"		/* for iscan.h */
40 #include "iscan.h"
41 
42 /* ------ Private code ------ */
43 
44 /* Forward references */
45 private int cfont_ref_from_string(i_ctx_t *, ref *, const char *, uint);
46 
47 typedef struct {
48     i_ctx_t *i_ctx_p;
49     const char *str_array;
50     ref next;
51 } str_enum;
52 
53 inline private void
init_str_enum(str_enum * pse,i_ctx_t * i_ctx_p,const char * ksa)54 init_str_enum(str_enum *pse, i_ctx_t *i_ctx_p, const char *ksa)
55 {
56     pse->i_ctx_p = i_ctx_p;
57     pse->str_array = ksa;
58 }
59 
60 typedef struct {
61     cfont_dict_keys keys;
62     str_enum strings;
63 } key_enum;
64 
65 inline private void
init_key_enum(key_enum * pke,i_ctx_t * i_ctx_p,const cfont_dict_keys * pkeys,const char * ksa)66 init_key_enum(key_enum *pke, i_ctx_t *i_ctx_p, const cfont_dict_keys *pkeys,
67 	      const char *ksa)
68 {
69     pke->keys = *pkeys;
70     init_str_enum(&pke->strings, i_ctx_p, ksa);
71 }
72 
73 /* Check for reaching the end of the keys. */
74 inline private bool
more_keys(const key_enum * pke)75 more_keys(const key_enum *pke)
76 {
77     return (pke->keys.num_enc_keys | pke->keys.num_str_keys);
78 }
79 
80 /* Get the next string from a string array. */
81 /* Return 1 if it was a string, 0 if it was something else, */
82 /* or an error code. */
83 private int
cfont_next_string(str_enum * pse)84 cfont_next_string(str_enum * pse)
85 {
86     const byte *str = (const byte *)pse->str_array;
87     uint len = (str[0] << 8) + str[1];
88 
89     if (len == 0xffff) {
90 	make_null(&pse->next);
91 	pse->str_array += 2;
92 	return 0;
93     } else if (len >= 0xff00) {
94 	int code;
95 
96 	len = ((len & 0xff) << 8) + str[2];
97 	code = cfont_ref_from_string(pse->i_ctx_p, &pse->next,
98 				     pse->str_array + 3, len);
99 	if (code < 0)
100 	    return code;
101 	pse->str_array += 3 + len;
102 	return 0;
103     }
104     make_const_string(&pse->next, avm_foreign, len, str + 2);
105     pse->str_array += 2 + len;
106     return 1;
107 }
108 
109 /* Put the next entry into a dictionary. */
110 /* We know that more_keys(kp) is true. */
111 private int
cfont_put_next(ref * pdict,key_enum * kep,const ref * pvalue)112 cfont_put_next(ref * pdict, key_enum * kep, const ref * pvalue)
113 {
114     i_ctx_t *i_ctx_p = kep->strings.i_ctx_p;
115     cfont_dict_keys * const kp = &kep->keys;
116     ref kname;
117     int code;
118 
119     if (pdict->value.pdict == 0) {
120 	/* First time, create the dictionary. */
121 	code = dict_create(kp->num_enc_keys + kp->num_str_keys +
122 			   kp->extra_slots, pdict);
123 	if (code < 0)
124 	    return code;
125     }
126     if (kp->num_enc_keys) {
127 	const charindex *skp = kp->enc_keys++;
128 	gs_glyph glyph = gs_c_known_encode((gs_char)skp->charx, skp->encx);
129 	gs_const_string gstr;
130 
131 	if (glyph == GS_NO_GLYPH)
132 	    code = gs_note_error(e_undefined);
133 	else if ((code = gs_c_glyph_name(glyph, &gstr)) >= 0)
134 	    code = name_ref(imemory, gstr.data, gstr.size, &kname, 0);
135 	kp->num_enc_keys--;
136     } else {			/* must have kp->num_str_keys != 0 */
137 	code = cfont_next_string(&kep->strings);
138 	if (code != 1)
139 	    return (code < 0 ? code : gs_note_error(e_Fatal));
140 	code = name_ref(imemory, kep->strings.next.value.const_bytes,
141 			r_size(&kep->strings.next), &kname, 0);
142 	kp->num_str_keys--;
143     }
144     if (code < 0)
145 	return code;
146     return dict_put(pdict, &kname, pvalue, &i_ctx_p->dict_stack);
147 }
148 
149 /* ------ Routines called from compiled font initialization ------ */
150 
151 /* Create a dictionary with general ref values. */
152 private int
cfont_ref_dict_create(i_ctx_t * i_ctx_p,ref * pdict,const cfont_dict_keys * kp,cfont_string_array ksa,const ref * values)153 cfont_ref_dict_create(i_ctx_t *i_ctx_p, ref *pdict,
154 		      const cfont_dict_keys *kp, cfont_string_array ksa,
155 		      const ref *values)
156 {
157     key_enum kenum;
158     const ref *vp = values;
159 
160     init_key_enum(&kenum, i_ctx_p, kp, ksa);
161     pdict->value.pdict = 0;
162     while (more_keys(&kenum)) {
163 	const ref *pvalue = vp++;
164 	int code = cfont_put_next(pdict, &kenum, pvalue);
165 
166 	if (code < 0)
167 	    return code;
168     }
169     r_store_attrs(dict_access_ref(pdict), a_all, kp->dict_attrs);
170     return 0;
171 }
172 
173 /* Create a dictionary with string/null values. */
174 private int
cfont_string_dict_create(i_ctx_t * i_ctx_p,ref * pdict,const cfont_dict_keys * kp,cfont_string_array ksa,cfont_string_array kva)175 cfont_string_dict_create(i_ctx_t *i_ctx_p, ref *pdict,
176 			 const cfont_dict_keys *kp, cfont_string_array ksa,
177 			 cfont_string_array kva)
178 {
179     key_enum kenum;
180     str_enum senum;
181     uint attrs = kp->value_attrs;
182 
183     init_key_enum(&kenum, i_ctx_p, kp, ksa);
184     init_str_enum(&senum, i_ctx_p, kva);
185     pdict->value.pdict = 0;
186     while (more_keys(&kenum)) {
187 	int code = cfont_next_string(&senum);
188 
189 	switch (code) {
190 	    default:		/* error */
191 		return code;
192 	    case 1:		/* string */
193 		r_set_attrs(&senum.next, attrs);
194 	    case 0:		/* other */
195 		;
196 	}
197 	code = cfont_put_next(pdict, &kenum, &senum.next);
198 	if (code < 0)
199 	    return code;
200     }
201     r_store_attrs(dict_access_ref(pdict), a_all, kp->dict_attrs);
202     return 0;
203 }
204 
205 /* Create a dictionary with number values. */
206 private int
cfont_num_dict_create(i_ctx_t * i_ctx_p,ref * pdict,const cfont_dict_keys * kp,cfont_string_array ksa,const ref * values,const char * lengths)207 cfont_num_dict_create(i_ctx_t *i_ctx_p, ref * pdict,
208 		      const cfont_dict_keys * kp, cfont_string_array ksa,
209 		      const ref * values, const char *lengths)
210 {
211     key_enum kenum;
212     const ref *vp = values;
213     const char *lp = lengths;
214     ref vnum;
215 
216     init_key_enum(&kenum, i_ctx_p, kp, ksa);
217     pdict->value.pdict = 0;
218     while (more_keys(&kenum)) {
219 	int len = (lp == 0 ? 0 : *lp++);
220 	int code;
221 
222 	if (len == 0)
223 	    vnum = *vp++;
224 	else {
225 	    --len;
226 	    make_const_array(&vnum, avm_foreign | a_readonly, len, vp);
227 	    vp += len;
228 	}
229 	code = cfont_put_next(pdict, &kenum, &vnum);
230 	if (code < 0)
231 	    return code;
232     }
233     r_store_attrs(dict_access_ref(pdict), a_all, kp->dict_attrs);
234     return 0;
235 }
236 
237 /* Create an array with name values. */
238 private int
cfont_name_array_create(i_ctx_t * i_ctx_p,ref * parray,cfont_string_array ksa,int size)239 cfont_name_array_create(i_ctx_t *i_ctx_p, ref * parray, cfont_string_array ksa,
240 			int size)
241 {
242     int code = ialloc_ref_array(parray, a_readonly, size,
243 				"cfont_name_array_create");
244     ref *aptr = parray->value.refs;
245     int i;
246     str_enum senum;
247 
248     if (code < 0)
249 	return code;
250     init_str_enum(&senum, i_ctx_p, ksa);
251     for (i = 0; i < size; i++, aptr++) {
252 	ref nref;
253 	int code = cfont_next_string(&senum);
254 
255 	if (code != 1)
256 	    return (code < 0 ? code : gs_note_error(e_Fatal));
257 	code = name_ref(imemory, senum.next.value.const_bytes,
258 			r_size(&senum.next), &nref, 0);
259 	if (code < 0)
260 	    return code;
261 	ref_assign_new(aptr, &nref);
262     }
263     return 0;
264 }
265 
266 /* Create an array with string/null values. */
267 private int
cfont_string_array_create(i_ctx_t * i_ctx_p,ref * parray,cfont_string_array ksa,int size,uint attrs)268 cfont_string_array_create(i_ctx_t *i_ctx_p, ref * parray,
269 			  cfont_string_array ksa, int size, uint attrs)
270 {
271     int code = ialloc_ref_array(parray, a_readonly, size,
272 				"cfont_string_array_create");
273     ref *aptr = parray->value.refs;
274     int i;
275     str_enum senum;
276 
277     if (code < 0)
278 	return code;
279     init_str_enum(&senum, i_ctx_p, ksa);
280     for (i = 0; i < size; i++, aptr++) {
281 	int code = cfont_next_string(&senum);
282 
283 	switch (code) {
284 	    default:		/* error */
285 		return code;
286 	    case 1:		/* string */
287 		r_set_attrs(&senum.next, attrs);
288 	    case 0:		/* other */
289 		;
290 	}
291 	ref_mark_new(&senum.next);
292 	*aptr = senum.next;
293     }
294     return 0;
295 }
296 
297 /* Create an array with scalar values. */
298 private int
cfont_scalar_array_create(i_ctx_t * i_ctx_p,ref * parray,const ref * va,int size,uint attrs)299 cfont_scalar_array_create(i_ctx_t *i_ctx_p, ref * parray,
300 			  const ref *va, int size, uint attrs)
301 {
302     int code = ialloc_ref_array(parray, attrs, size,
303 				"cfont_scalar_array_create");
304     ref *aptr = parray->value.refs;
305     uint elt_attrs = attrs | ialloc_new_mask;
306     int i;
307 
308     if (code < 0)
309 	return code;
310     memcpy(aptr, va, size * sizeof(ref));
311     for (i = 0; i < size; i++, aptr++)
312 	r_set_attrs(aptr, elt_attrs);
313     return 0;
314 }
315 
316 /* Create a name. */
317 private int
cfont_name_create(i_ctx_t * i_ctx_p,ref * pnref,const char * str)318 cfont_name_create(i_ctx_t *i_ctx_p, ref * pnref, const char *str)
319 {
320     return name_ref(imemory, (const byte *)str, strlen(str), pnref, 0);
321 }
322 
323 /* Create an object by parsing a string. */
324 private int
cfont_ref_from_string(i_ctx_t * i_ctx_p,ref * pref,const char * str,uint len)325 cfont_ref_from_string(i_ctx_t *i_ctx_p, ref * pref, const char *str, uint len)
326 {
327     scanner_state sstate;
328     stream s;
329     int code;
330 
331     scanner_state_init(&sstate, false);
332     s_init(&s, imemory);
333     sread_string(&s, (const byte *)str, len);
334     code = scan_token(i_ctx_p, &s, pref, &sstate);
335     return (code <= 0 ? code : gs_note_error(e_Fatal));
336 }
337 
338 /* ------ Initialization ------ */
339 
340 /* Procedure vector passed to font initialization procedures. */
341 private const cfont_procs ccfont_procs = {
342     cfont_ref_dict_create,
343     cfont_string_dict_create,
344     cfont_num_dict_create,
345     cfont_name_array_create,
346     cfont_string_array_create,
347     cfont_scalar_array_create,
348     cfont_name_create,
349     cfont_ref_from_string
350 };
351 
352 /* null    .getccfont    <number-of-fonts> */
353 /* <int>   .getccfont    <font-object> */
354 private int
zgetccfont(i_ctx_t * i_ctx_p)355 zgetccfont(i_ctx_t *i_ctx_p)
356 {
357     os_ptr op = osp;
358     int code;
359     const ccfont_fproc *fprocs;
360     int nfonts;
361     int index;
362 
363     code = ccfont_fprocs(&nfonts, &fprocs);
364     if (code != ccfont_version)
365 	return_error(e_invalidfont);
366 
367     if (r_has_type(op, t_null)) {
368 	make_int(op, nfonts);
369 	return 0;
370     }
371     check_type(*op, t_integer);
372     index = op->value.intval;
373     if (index < 0 || index >= nfonts)
374 	return_error(e_rangecheck);
375 
376     return (*fprocs[index]) (i_ctx_p, &ccfont_procs, op);
377 }
378 
379 /* Operator table initialization */
380 
381 const op_def ccfonts_op_defs[] =
382 {
383     {"0.getccfont", zgetccfont},
384     op_def_end(0)
385 };
386