1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: zfont.c 9043 2008-08-28 22:48:19Z giles $ */
15 /* Generic font operators */
16 #include "ghost.h"
17 #include "oper.h"
18 #include "gsstruct.h" /* for registering root */
19 #include "gzstate.h" /* must precede gxdevice */
20 #include "gxdevice.h" /* must precede gxfont */
21 #include "gxfont.h"
22 #include "gxfcache.h"
23 #include "bfont.h"
24 #include "ialloc.h"
25 #include "iddict.h"
26 #include "igstate.h"
27 #include "iname.h" /* for name_mark_index */
28 #include "isave.h"
29 #include "store.h"
30 #include "ivmspace.h"
31 #include "gscencs.h"
32
33 /* Forward references */
34 static int make_font(i_ctx_t *, const gs_matrix *);
35 static void make_uint_array(os_ptr, const uint *, int);
36 static int setup_unicode_decoder(i_ctx_t *i_ctx_p, ref *Decoding);
37
38 /* The (global) font directory */
39 gs_font_dir *ifont_dir = 0; /* needed for buildfont */
40
41 /* Mark a glyph as a PostScript name (if it isn't a CID). */
42 bool
zfont_mark_glyph_name(const gs_memory_t * mem,gs_glyph glyph,void * ignore_data)43 zfont_mark_glyph_name(const gs_memory_t *mem, gs_glyph glyph, void *ignore_data)
44 {
45 return (glyph >= gs_c_min_std_encoding_glyph || glyph == gs_no_glyph ? false :
46 name_mark_index(mem, (uint) glyph));
47 }
48
49 /* Get a global glyph code. */
50 static int
zfont_global_glyph_code(const gs_memory_t * mem,gs_const_string * gstr,gs_glyph * pglyph)51 zfont_global_glyph_code(const gs_memory_t *mem, gs_const_string *gstr, gs_glyph *pglyph)
52 {
53 ref v;
54 int code = name_ref(mem, gstr->data, gstr->size, &v, 0);
55
56 if (code < 0)
57 return code;
58 *pglyph = (gs_glyph)name_index(mem, &v);
59 return 0;
60 }
61
62 /* Initialize the font operators */
63 static int
zfont_init(i_ctx_t * i_ctx_p)64 zfont_init(i_ctx_t *i_ctx_p)
65 {
66 ifont_dir = gs_font_dir_alloc2(imemory, imemory->non_gc_memory);
67 ifont_dir->ccache.mark_glyph = zfont_mark_glyph_name;
68 ifont_dir->global_glyph_code = zfont_global_glyph_code;
69 return gs_register_struct_root(imemory, NULL, (void **)&ifont_dir,
70 "ifont_dir");
71 }
72
73 /* <font> <scale> scalefont <new_font> */
74 static int
zscalefont(i_ctx_t * i_ctx_p)75 zscalefont(i_ctx_t *i_ctx_p)
76 {
77 os_ptr op = osp;
78 int code;
79 double scale;
80 gs_matrix mat;
81
82 if ((code = real_param(op, &scale)) < 0)
83 return code;
84 if ((code = gs_make_scaling(scale, scale, &mat)) < 0)
85 return code;
86 return make_font(i_ctx_p, &mat);
87 }
88
89 /* <font> <matrix> makefont <new_font> */
90 static int
zmakefont(i_ctx_t * i_ctx_p)91 zmakefont(i_ctx_t *i_ctx_p)
92 {
93 os_ptr op = osp;
94 int code;
95 gs_matrix mat;
96
97 if ((code = read_matrix(imemory, op, &mat)) < 0)
98 return code;
99 return make_font(i_ctx_p, &mat);
100 }
101
102 /* <font> setfont - */
103 int
zsetfont(i_ctx_t * i_ctx_p)104 zsetfont(i_ctx_t *i_ctx_p)
105 {
106 os_ptr op = osp;
107 gs_font *pfont;
108 int code = font_param(op, &pfont);
109
110 if (code < 0 || (code = gs_setfont(igs, pfont)) < 0)
111 return code;
112 pop(1);
113 return code;
114 }
115
116 /* - currentfont <font> */
117 static int
zcurrentfont(i_ctx_t * i_ctx_p)118 zcurrentfont(i_ctx_t *i_ctx_p)
119 {
120 os_ptr op = osp;
121
122 push(1);
123 *op = *pfont_dict(gs_currentfont(igs));
124 return 0;
125 }
126
127 /* - cachestatus <mark> <bsize> <bmax> <msize> <mmax> <csize> <cmax> <blimit> */
128 static int
zcachestatus(i_ctx_t * i_ctx_p)129 zcachestatus(i_ctx_t *i_ctx_p)
130 {
131 os_ptr op = osp;
132 uint status[7];
133
134 gs_cachestatus(ifont_dir, status);
135 push(7);
136 make_uint_array(op - 6, status, 7);
137 return 0;
138 }
139
140 /* <blimit> setcachelimit - */
141 static int
zsetcachelimit(i_ctx_t * i_ctx_p)142 zsetcachelimit(i_ctx_t *i_ctx_p)
143 {
144 os_ptr op = osp;
145
146 check_int_leu(*op, max_uint);
147 gs_setcachelimit(ifont_dir, (uint) op->value.intval);
148 pop(1);
149 return 0;
150 }
151
152 /* <mark> <size> <lower> <upper> setcacheparams - */
153 static int
zsetcacheparams(i_ctx_t * i_ctx_p)154 zsetcacheparams(i_ctx_t *i_ctx_p)
155 {
156 os_ptr op = osp;
157 uint params[3];
158 int i, code;
159 os_ptr opp = op;
160
161 for (i = 0; i < 3 && !r_has_type(opp, t_mark); i++, opp--) {
162 check_int_leu(*opp, max_uint);
163 params[i] = opp->value.intval;
164 }
165 switch (i) {
166 case 3:
167 if ((code = gs_setcachesize(ifont_dir, params[2])) < 0)
168 return code;
169 case 2:
170 if ((code = gs_setcachelower(ifont_dir, params[1])) < 0)
171 return code;
172 case 1:
173 if ((code = gs_setcacheupper(ifont_dir, params[0])) < 0)
174 return code;
175 case 0:;
176 }
177 return zcleartomark(i_ctx_p);
178 }
179
180 /* - currentcacheparams <mark> <size> <lower> <upper> */
181 static int
zcurrentcacheparams(i_ctx_t * i_ctx_p)182 zcurrentcacheparams(i_ctx_t *i_ctx_p)
183 {
184 os_ptr op = osp;
185 uint params[3];
186
187 params[0] = gs_currentcachesize(ifont_dir);
188 params[1] = gs_currentcachelower(ifont_dir);
189 params[2] = gs_currentcacheupper(ifont_dir);
190 push(4);
191 make_mark(op - 3);
192 make_uint_array(op - 2, params, 3);
193 return 0;
194 }
195
196 /* <font> .registerfont - */
197 static int
zregisterfont(i_ctx_t * i_ctx_p)198 zregisterfont(i_ctx_t *i_ctx_p)
199 {
200 os_ptr op = osp;
201 gs_font *pfont;
202 int code = font_param(op, &pfont);
203
204 if (code < 0)
205 return code;
206 pfont->is_resource = true;
207 pop(1);
208 return 0;
209 }
210
211
212 /* <Decoding> .setupUnicodeDecoder - */
213 static int
zsetupUnicodeDecoder(i_ctx_t * i_ctx_p)214 zsetupUnicodeDecoder(i_ctx_t *i_ctx_p)
215 { /* The allocation mode must be global. */
216 os_ptr op = osp;
217 int code;
218
219 check_type(*op, t_dictionary);
220 code = setup_unicode_decoder(i_ctx_p, op);
221 if (code < 0)
222 return code;
223 pop(1);
224 return 0;
225 }
226
227 /* ------ Initialization procedure ------ */
228
229 const op_def zfont_op_defs[] =
230 {
231 {"0currentfont", zcurrentfont},
232 {"2makefont", zmakefont},
233 {"2scalefont", zscalefont},
234 {"1setfont", zsetfont},
235 {"0cachestatus", zcachestatus},
236 {"1setcachelimit", zsetcachelimit},
237 {"1setcacheparams", zsetcacheparams},
238 {"0currentcacheparams", zcurrentcacheparams},
239 {"1.registerfont", zregisterfont},
240 {"1.setupUnicodeDecoder", zsetupUnicodeDecoder},
241 op_def_end(zfont_init)
242 };
243
244 /* ------ Subroutines ------ */
245
246 /* Validate a font parameter. */
247 int
font_param(const ref * pfdict,gs_font ** ppfont)248 font_param(const ref * pfdict, gs_font ** ppfont)
249 { /*
250 * Check that pfdict is a read-only dictionary, that it has a FID
251 * entry whose value is a fontID, and that the fontID points to a
252 * gs_font structure whose associated PostScript dictionary is
253 * pfdict.
254 */
255 ref *pid;
256 gs_font *pfont;
257 const font_data *pdata;
258
259 check_type(*pfdict, t_dictionary);
260 if (dict_find_string(pfdict, "FID", &pid) <= 0 ||
261 !r_has_type(pid, t_fontID)
262 )
263 return_error(e_invalidfont);
264 pfont = r_ptr(pid, gs_font);
265 if (pfont == 0)
266 return_error(e_invalidfont); /* unregistered font */
267 pdata = pfont->client_data;
268 if (!obj_eq(pfont->memory, &pdata->dict, pfdict))
269 return_error(e_invalidfont);
270 *ppfont = pfont;
271 return 0;
272 }
273
274 /* Add the FID entry to a font dictionary. */
275 /* Note that i_ctx_p may be NULL. */
276 int
add_FID(i_ctx_t * i_ctx_p,ref * fp,gs_font * pfont,gs_ref_memory_t * imem)277 add_FID(i_ctx_t *i_ctx_p, ref * fp /* t_dictionary */ , gs_font * pfont,
278 gs_ref_memory_t *imem)
279 {
280 ref fid;
281
282 make_tav(&fid, t_fontID,
283 a_readonly | imemory_space(imem) | imemory_new_mask(imem),
284 pstruct, (void *)pfont);
285 return (i_ctx_p ? idict_put_string(fp, "FID", &fid) :
286 dict_put_string(fp, "FID", &fid, NULL));
287 }
288
289 /* Make a transformed font (common code for makefont/scalefont). */
290 static int
make_font(i_ctx_t * i_ctx_p,const gs_matrix * pmat)291 make_font(i_ctx_t *i_ctx_p, const gs_matrix * pmat)
292 {
293 os_ptr op = osp;
294 os_ptr fp = op - 1;
295 gs_font *oldfont, *newfont;
296 int code;
297 ref *pencoding = 0;
298
299 code = font_param(fp, &oldfont);
300 if (code < 0)
301 return code;
302 {
303 uint space = ialloc_space(idmemory);
304
305 ialloc_set_space(idmemory, r_space(fp));
306 if (dict_find_string(fp, "Encoding", &pencoding) > 0 &&
307 !r_is_array(pencoding)
308 )
309 code = gs_note_error(e_invalidfont);
310 else {
311 /*
312 * Temporarily substitute the new dictionary
313 * for the old one, in case the Encoding changed.
314 */
315 ref olddict;
316
317 olddict = *pfont_dict(oldfont);
318 *pfont_dict(oldfont) = *fp;
319 code = gs_makefont(ifont_dir, oldfont, pmat, &newfont);
320 *pfont_dict(oldfont) = olddict;
321 }
322 ialloc_set_space(idmemory, space);
323 }
324 if (code < 0)
325 return code;
326 /*
327 * We have to allow for the possibility that the font's Encoding
328 * is different from that of the base font. Note that the
329 * font_data of the new font was simply copied from the old one.
330 */
331 if (pencoding != 0 &&
332 !obj_eq(imemory, pencoding, &pfont_data(newfont)->Encoding)
333 ) {
334 if (newfont->FontType == ft_composite)
335 return_error(e_rangecheck);
336 /* We should really do validity checking here.... */
337 ref_assign(&pfont_data(newfont)->Encoding, pencoding);
338 lookup_gs_simple_font_encoding((gs_font_base *) newfont);
339 }
340 *fp = *pfont_dict(newfont);
341 pop(1);
342 return 0;
343 }
344 /* Create the transformed font dictionary. */
345 /* This is the make_font completion procedure for all non-composite fonts */
346 /* created at the interpreter level (see build_gs_simple_font in zbfont.c.) */
347 int
zbase_make_font(gs_font_dir * pdir,const gs_font * oldfont,const gs_matrix * pmat,gs_font ** ppfont)348 zbase_make_font(gs_font_dir * pdir, const gs_font * oldfont,
349 const gs_matrix * pmat, gs_font ** ppfont)
350 {
351 /*
352 * We must call gs_base_make_font so that the XUID gets copied
353 * if necessary.
354 */
355 int code = gs_base_make_font(pdir, oldfont, pmat, ppfont);
356
357 if (code < 0)
358 return code;
359 return zdefault_make_font(pdir, oldfont, pmat, ppfont);
360 }
361 int
zdefault_make_font(gs_font_dir * pdir,const gs_font * oldfont,const gs_matrix * pmat,gs_font ** ppfont)362 zdefault_make_font(gs_font_dir * pdir, const gs_font * oldfont,
363 const gs_matrix * pmat, gs_font ** ppfont)
364 {
365 gs_font *newfont = *ppfont;
366 gs_memory_t *mem = newfont->memory;
367 /* HACK: we know this font was allocated by the interpreter. */
368 gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
369 ref *fp = pfont_dict(oldfont);
370 font_data *pdata;
371 ref newdict, newmat, scalemat;
372 uint dlen = dict_maxlength(fp);
373 uint mlen = dict_length(fp) + 3; /* FontID, OrigFont, ScaleMatrix */
374 int code;
375
376 if (dlen < mlen)
377 dlen = mlen;
378 if ((pdata = gs_alloc_struct(mem, font_data, &st_font_data,
379 "make_font(font_data)")) == 0
380 )
381 return_error(e_VMerror);
382 /*
383 * This dictionary is newly created: it's safe to pass NULL as the
384 * dstack pointer to dict_copy and dict_put_string.
385 */
386 if ((code = dict_alloc(imem, dlen, &newdict)) < 0 ||
387 (code = dict_copy(fp, &newdict, NULL)) < 0 ||
388 (code = gs_alloc_ref_array(imem, &newmat, a_all, 12,
389 "make_font(matrices)")) < 0
390 )
391 return code;
392 refset_null_new(newmat.value.refs, 12, imemory_new_mask(imem));
393 ref_assign(&scalemat, &newmat);
394 r_set_size(&scalemat, 6);
395 scalemat.value.refs += 6;
396 /*
397 * Create the scaling matrix. We could do this several different
398 * ways: by "dividing" the new FontMatrix by the base FontMatrix, by
399 * multiplying the current scaling matrix by a ScaleMatrix kept in
400 * the gs_font, or by multiplying the current scaling matrix by the
401 * ScaleMatrix from the font dictionary. We opt for the last of
402 * these.
403 */
404 {
405 gs_matrix scale, prev_scale;
406 ref *ppsm;
407
408 if (!(dict_find_string(fp, "ScaleMatrix", &ppsm) > 0 &&
409 read_matrix(mem, ppsm, &prev_scale) >= 0 &&
410 gs_matrix_multiply(pmat, &prev_scale, &scale) >= 0)
411 )
412 scale = *pmat;
413 write_matrix_new(&scalemat, &scale, imem);
414 }
415 r_clear_attrs(&scalemat, a_write);
416 r_set_size(&newmat, 6);
417 write_matrix_new(&newmat, &newfont->FontMatrix, imem);
418 r_clear_attrs(&newmat, a_write);
419 if ((code = dict_put_string(&newdict, "FontMatrix", &newmat, NULL)) < 0 ||
420 (code = dict_put_string(&newdict, "OrigFont", pfont_dict(oldfont->base), NULL)) < 0 ||
421 (code = dict_put_string(&newdict, "ScaleMatrix", &scalemat, NULL)) < 0 ||
422 (code = add_FID(NULL, &newdict, newfont, imem)) < 0
423 )
424 return code;
425 newfont->client_data = pdata;
426 *pdata = *pfont_data(oldfont);
427 pdata->dict = newdict;
428 r_clear_attrs(dict_access_ref(&newdict), a_write);
429 return 0;
430 }
431
432 /* Convert an array of (unsigned) integers to stack form. */
433 static void
make_uint_array(register os_ptr op,const uint * intp,int count)434 make_uint_array(register os_ptr op, const uint * intp, int count)
435 {
436 int i;
437
438 for (i = 0; i < count; i++, op++, intp++)
439 make_int(op, *intp);
440 }
441
442 /* Remove scaled font and character cache entries that would be */
443 /* invalidated by a restore. */
444 static bool
purge_if_name_removed(const gs_memory_t * mem,cached_char * cc,void * vsave)445 purge_if_name_removed(const gs_memory_t *mem, cached_char * cc, void *vsave)
446 {
447 return alloc_name_index_is_since_save(mem, cc->code, vsave);
448 }
449
450 /* Remove entries from font and character caches. */
451 int
font_restore(const alloc_save_t * save)452 font_restore(const alloc_save_t * save)
453 {
454 gs_font_dir *pdir = ifont_dir;
455 const gs_memory_t *mem = 0;
456 int code;
457
458 if (pdir == 0) /* not initialized yet */
459 return 0;
460
461 /* Purge original (unscaled) fonts. */
462
463 {
464 gs_font *pfont;
465
466 otop:
467 for (pfont = pdir->orig_fonts; pfont != 0;
468 pfont = pfont->next
469 ) {
470 mem = pfont->memory;
471 if (alloc_is_since_save((char *)pfont, save)) {
472 code = gs_purge_font(pfont);
473 if (code < 0)
474 return code;
475 goto otop;
476 }
477 }
478 }
479
480 /* Purge cached scaled fonts. */
481
482 {
483 gs_font *pfont;
484
485 top:
486 for (pfont = pdir->scaled_fonts; pfont != 0;
487 pfont = pfont->next
488 ) {
489 if (alloc_is_since_save((char *)pfont, save)) {
490 code = gs_purge_font(pfont);
491 if (code < 0)
492 return code;
493 goto top;
494 }
495 }
496 }
497
498 /* Purge xfonts and uncached scaled fonts. */
499
500 {
501 cached_fm_pair *pair;
502 uint n;
503
504 for (pair = pdir->fmcache.mdata, n = pdir->fmcache.mmax;
505 n > 0; pair++, n--
506 )
507 if (!fm_pair_is_free(pair)) {
508 #if 0
509 /* We disabled this code portion because
510 gx_add_fm_pair now copied xvalues
511 into a stable memory.
512 */
513 if ((uid_is_XUID(&pair->UID) &&
514 alloc_is_since_save((char *)pair->UID.xvalues,
515 save))
516 ) {
517 code = gs_purge_fm_pair(pdir, pair, 0);
518 if (code < 0)
519 return code;
520 continue;
521 }
522 #endif
523 if (pair->font != 0 &&
524 alloc_is_since_save((char *)pair->font, save)
525 ) {
526 if (!uid_is_valid(&pair->UID))
527 gs_clean_fm_pair(pdir, pair);
528 /* Don't discard pairs with a surviving UID. */
529 pair->font = 0;
530 }
531 if (pair->xfont != 0 &&
532 alloc_is_since_save((char *)pair->xfont, save)
533 ) {
534 code = gs_purge_fm_pair(pdir, pair, 1);
535 if (code < 0)
536 return code;
537 }
538 }
539 }
540
541 /* Purge characters with names about to be removed. */
542 /* We only need to do this if any new names have been created */
543 /* since the save. */
544
545 if (alloc_any_names_since_save(save))
546 gx_purge_selected_cached_chars(pdir, purge_if_name_removed,
547 (void *)save);
548 return 0;
549 }
550
551 /* ------ Font procedures for PostScript fonts ------ */
552
553 /* font_info procedure */
554 static bool
zfont_info_has(const ref * pfidict,const char * key,gs_const_string * pmember)555 zfont_info_has(const ref *pfidict, const char *key, gs_const_string *pmember)
556 {
557 ref *pvalue;
558
559 if (dict_find_string(pfidict, key, &pvalue) > 0 &&
560 r_has_type(pvalue, t_string)
561 ) {
562 pmember->data = pvalue->value.const_bytes;
563 pmember->size = r_size(pvalue);
564 return true;
565 }
566 return false;
567 }
568 int
zfont_info(gs_font * font,const gs_point * pscale,int members,gs_font_info_t * info)569 zfont_info(gs_font *font, const gs_point *pscale, int members,
570 gs_font_info_t *info)
571 {
572 int code = gs_default_font_info(font, pscale, members &
573 ~(FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE |
574 FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME),
575 info);
576 const ref *pfdict;
577 ref *pfontinfo, *pvalue;
578
579 if (code < 0)
580 return code;
581 pfdict = &pfont_data(font)->dict;
582 if (dict_find_string(pfdict, "FontInfo", &pfontinfo) <= 0 ||
583 !r_has_type(pfontinfo, t_dictionary))
584 return 0;
585 if ((members & FONT_INFO_COPYRIGHT) &&
586 zfont_info_has(pfontinfo, "Copyright", &info->Copyright))
587 info->members |= FONT_INFO_COPYRIGHT;
588 if ((members & FONT_INFO_NOTICE) &&
589 zfont_info_has(pfontinfo, "Notice", &info->Notice))
590 info->members |= FONT_INFO_NOTICE;
591 if ((members & FONT_INFO_FAMILY_NAME) &&
592 zfont_info_has(pfontinfo, "FamilyName", &info->FamilyName))
593 info->members |= FONT_INFO_FAMILY_NAME;
594 if ((members & FONT_INFO_FULL_NAME) &&
595 zfont_info_has(pfontinfo, "FullName", &info->FullName))
596 info->members |= FONT_INFO_FULL_NAME;
597 if ((members & FONT_INFO_EMBEDDING_RIGHTS)
598 && (dict_find_string(pfontinfo, "FSType", &pvalue) > 0)) {
599 info->EmbeddingRights = pvalue->value.intval;
600 info->members |= FONT_INFO_EMBEDDING_RIGHTS;
601 }
602 return code;
603 }
604
605 /* -------------------- Utilities --------------*/
606
607 typedef struct gs_unicode_decoder_s {
608 ref data;
609 } gs_unicode_decoder;
610
611 /* GC procedures */
612 static
CLEAR_MARKS_PROC(unicode_decoder_clear_marks)613 CLEAR_MARKS_PROC(unicode_decoder_clear_marks)
614 { gs_unicode_decoder *const pptr = vptr;
615
616 r_clear_attrs(&pptr->data, l_mark);
617 }
618 static
619 ENUM_PTRS_WITH(unicode_decoder_enum_ptrs, gs_unicode_decoder *pptr) return 0;
620 case 0:
621 ENUM_RETURN_REF(&pptr->data);
622 ENUM_PTRS_END
623 static RELOC_PTRS_WITH(unicode_decoder_reloc_ptrs, gs_unicode_decoder *pptr);
624 RELOC_REF_VAR(pptr->data);
625 r_clear_attrs(&pptr->data, l_mark);
626 RELOC_PTRS_END
627
628 gs_private_st_complex_only(st_unicode_decoder, gs_unicode_decoder,\
629 "unicode_decoder", unicode_decoder_clear_marks, unicode_decoder_enum_ptrs,
630 unicode_decoder_reloc_ptrs, 0);
631
632 /* Get the Unicode value for a glyph. */
633 const ref *
zfont_get_to_unicode_map(gs_font_dir * dir)634 zfont_get_to_unicode_map(gs_font_dir *dir)
635 {
636 const gs_unicode_decoder *pud = (gs_unicode_decoder *)dir->glyph_to_unicode_table;
637
638 return (pud == NULL ? NULL : &pud->data);
639 }
640
641 static int
setup_unicode_decoder(i_ctx_t * i_ctx_p,ref * Decoding)642 setup_unicode_decoder(i_ctx_t *i_ctx_p, ref *Decoding)
643 {
644 gs_unicode_decoder *pud = gs_alloc_struct(imemory, gs_unicode_decoder,
645 &st_unicode_decoder, "setup_unicode_decoder");
646 if (pud == NULL)
647 return_error(e_VMerror);
648 ref_assign_new(&pud->data, Decoding);
649 ifont_dir->glyph_to_unicode_table = pud;
650 return 0;
651 }
652