Ejemplo n.º 1
0
/* Make a reusable file stream. */
static int
make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length)
{
    uint save_space = icurrent_space;
    uint stream_space = imemory_space((const gs_ref_memory_t *)fs->memory);
    gs_const_string fname;
    gs_parsed_file_name_t pname;
    stream *s;
    int code;

    if (sfilename(fs, &fname) < 0)
        return_error(e_ioerror);
    code = gs_parse_file_name(&pname, (const char *)fname.data, fname.size,
                              imemory);
    if (code < 0)
        return code;
    if (pname.len == 0)		/* %stdin% etc. won't have a filename */
        return_error(e_invalidfileaccess); /* can't reopen */
    if (pname.iodev == NULL)
        pname.iodev = iodev_default(imemory);
    /* Open the file again, to be independent of the source. */
    ialloc_set_space(idmemory, stream_space);
    code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
    ialloc_set_space(idmemory, save_space);
    if (code < 0)
        return code;
    if (sread_subfile(s, offset, length) < 0) {
        sclose(s);
        return_error(e_ioerror);
    }
    s->close_at_eod = false;
    make_stream_file(op, s, "r");
    return 0;
}
Ejemplo n.º 2
0
/* The caller guarantees that *op is a dictionary. */
int
build_gs_sub_font(i_ctx_t *i_ctx_p, const ref *op, gs_font **ppfont,
                  font_type ftype, gs_memory_type_ptr_t pstype,
                  const build_proc_refs * pbuild, const ref *pencoding,
                  ref *fid_op)
{
    gs_matrix mat, omat;
    ref fname;			/* t_string */
    gs_font *pfont;
    font_data *pdata;
    /*
     * Make sure that we allocate the font data
     * in the same VM as the font dictionary.
     */
    uint space = ialloc_space(idmemory);
    int code = sub_font_params(imemory, op, &mat, &omat, &fname);

    if (code < 0)
        return code;
    ialloc_set_space(idmemory, r_space(op));
    pfont = gs_font_alloc(imemory, pstype, &gs_font_procs_default, NULL,
                          "buildfont(font)");
    pdata = ialloc_struct(font_data, &st_font_data,
                          "buildfont(data)");
    if (pfont == 0 || pdata == 0)
        code = gs_note_error(e_VMerror);
    else if (fid_op)
        code = add_FID(i_ctx_p, fid_op, pfont, iimemory);
    if (code < 0) {
        ifree_object(pdata, "buildfont(data)");
        ifree_object(pfont, "buildfont(font)");
        ialloc_set_space(idmemory, space);
        return code;
    }
    refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref));
    ref_assign_new(&pdata->dict, op);
    ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar);
    ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph);
    if (pencoding)
        ref_assign_new(&pdata->Encoding, pencoding);
    pfont->client_data = pdata;
    pfont->FontType = ftype;
    pfont->FontMatrix = mat;
    pfont->orig_FontMatrix = omat;
    pfont->BitmapWidths = false;
    pfont->ExactSize = fbit_use_bitmaps;
    pfont->InBetweenSize = fbit_use_outlines;
    pfont->TransformedChar = fbit_use_outlines;
    pfont->WMode = 0;
    pfont->procs.encode_char = zfont_encode_char;
    pfont->procs.glyph_name = zfont_glyph_name;
    ialloc_set_space(idmemory, space);
    copy_font_name(&pfont->font_name, &fname);
    *ppfont = pfont;
    return 0;
}
Ejemplo n.º 3
0
/* Make a transformed font (common code for makefont/scalefont). */
static int
make_font(i_ctx_t *i_ctx_p, const gs_matrix * pmat)
{
    os_ptr op = osp;
    os_ptr fp = op - 1;
    gs_font *oldfont, *newfont;
    int code;
    ref *pencoding = 0;

    code = font_param(fp, &oldfont);
    if (code < 0)
        return code;
    {
        uint space = ialloc_space(idmemory);

        ialloc_set_space(idmemory, r_space(fp));
        if (dict_find_string(fp, "Encoding", &pencoding) > 0 &&
            !r_is_array(pencoding)
            )
            code = gs_note_error(e_invalidfont);
        else {
                /*
                 * Temporarily substitute the new dictionary
                 * for the old one, in case the Encoding changed.
                 */
            ref olddict;

            olddict = *pfont_dict(oldfont);
            *pfont_dict(oldfont) = *fp;
            code = gs_makefont(ifont_dir, oldfont, pmat, &newfont);
            *pfont_dict(oldfont) = olddict;
        }
        ialloc_set_space(idmemory, space);
    }
    if (code < 0)
        return code;
    /*
     * We have to allow for the possibility that the font's Encoding
     * is different from that of the base font.  Note that the
     * font_data of the new font was simply copied from the old one.
     */
    if (pencoding != 0 &&
        !obj_eq(imemory, pencoding, &pfont_data(newfont)->Encoding)
        ) {
        if (newfont->FontType == ft_composite)
            return_error(e_rangecheck);
        /* We should really do validity checking here.... */
        ref_assign(&pfont_data(newfont)->Encoding, pencoding);
        lookup_gs_simple_font_encoding((gs_font_base *) newfont);
    }
    *fp = *pfont_dict(newfont);
    pop(1);
    return 0;
}
Ejemplo n.º 4
0
/* Execute an operator with a specific VM selected as current VM. */
static int
specific_vm_op(i_ctx_t *i_ctx_p, op_proc_t opproc, uint space)
{
    uint save_space = icurrent_space;
    int code;

    ialloc_set_space(idmemory, space);
    code = opproc(i_ctx_p);
    ialloc_set_space(idmemory, save_space);
    return code;
}
Ejemplo n.º 5
0
/* <bool> .setglobal - */
private int
zsetglobal(register os_ptr op)
{	check_type(*op, t_boolean);
	ialloc_set_space(idmemory,
			 (op->value.boolval ? avm_global : avm_local));
	pop(1);
	return 0;
}
Ejemplo n.º 6
0
/* <save> .forgetsave - */
static int
zforgetsave(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    alloc_save_t *asave;
    vm_save_t *vmsave;
    int code = restore_check_operand(op, &asave, idmemory);

    if (code < 0)
        return 0;
    vmsave = alloc_save_client_data(asave);
    /* Reset l_new in all stack entries if the new save level is zero. */
    restore_fix_stack(&o_stack, asave, false);
    restore_fix_stack(&e_stack, asave, false);
    restore_fix_stack(&d_stack, asave, false);
    /*
     * Forget the gsaves, by deleting the bottom gstate on
     * the current stack and the top one on the saved stack and then
     * concatenating the stacks together.
     */
    {
        gs_state *pgs = igs;
        gs_state *last;

        while (gs_state_saved(last = gs_state_saved(pgs)) != 0)
            pgs = last;
        gs_state_swap_saved(last, vmsave->gsave);
        gs_grestore(last);
        gs_grestore(last);
    }
    /* Forget the save in the memory manager. */
    code = alloc_forget_save_in(idmemory, asave);
    if (code < 0)
        return code;
    {
        uint space = icurrent_space;

        ialloc_set_space(idmemory, avm_local);
        /* See above for why we clear the gsave pointer here. */
        vmsave->gsave = 0;
        ifree_object(vmsave, "zrestore");
        ialloc_set_space(idmemory, space);
    }
    pop(1);
    return 0;
}
Ejemplo n.º 7
0
/* The caller guarantees that *op is a dictionary. */
int
build_gs_simple_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                     font_type ftype, gs_memory_type_ptr_t pstype,
                     const build_proc_refs * pbuild,
                     build_font_options_t options)
{
    double bbox[4];
    gs_uid uid;
    int code;
    gs_font_base *pfont;
    uint space = ialloc_space(idmemory);

    code = font_bbox_param(imemory, op, bbox);
    if (code < 0)
        return code;
    /*
     * Make sure that we allocate uid
     * in the same VM as the font dictionary
     * (see build_gs_sub_font).
     */
    ialloc_set_space(idmemory, r_space(op));
    code = dict_uid_param(op, &uid, 0, imemory, i_ctx_p);
    ialloc_set_space(idmemory, space);
    if (code < 0)
        return code;
    if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid))
        uid_set_invalid(&uid);
    code = build_gs_font(i_ctx_p, op, (gs_font **) ppfont, ftype, pstype,
                         pbuild, options);
    if (code != 0)		/* invalid or scaled font */
        return code;
    pfont = *ppfont;
    pfont->procs.init_fstack = gs_default_init_fstack;
    pfont->procs.define_font = gs_no_define_font;
    pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode;
    pfont->procs.make_font = zbase_make_font;
    pfont->procs.next_char_glyph = gs_default_next_char_glyph;
    pfont->FAPI = 0;
    pfont->FAPI_font_data = 0;
    init_gs_simple_font(pfont, bbox, &uid);
    lookup_gs_simple_font_encoding(pfont);
    get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op);
    return 0;
}
Ejemplo n.º 8
0
/* Make a reusable string stream. */
int
make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size,
         uint string_space, long offset, long length, bool is_bytestring)
{
    uint save_space = icurrent_space;
    stream *s;
    long left = min(length, size - offset);

    ialloc_set_space(idmemory, string_space);
    s = file_alloc_stream(imemory, "make_rss");
    ialloc_set_space(idmemory, save_space);
    if (s == 0)
        return_error(e_VMerror);
    sread_string_reusable(s, data + offset, max(left, 0));
    if (is_bytestring)
        s->cbuf_string.data = 0;	/* byte array, not string */
    make_stream_file(op, s, "r");
    return 0;
}
Ejemplo n.º 9
0
/* <bool> .setglobal - */
private int
zsetglobal(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    check_type(*op, t_boolean);
    ialloc_set_space(idmemory,
		     (op->value.boolval ? avm_global : avm_local));
    pop(1);
    return 0;
}
Ejemplo n.º 10
0
/* Initialize the allocator */
int
ialloc_init(gs_dual_memory_t *dmem, gs_memory_t * rmem, uint chunk_size,
	    bool level2)
{
    gs_ref_memory_t *ilmem = ialloc_alloc_state(rmem, chunk_size);
    gs_ref_memory_t *ilmem_stable = ialloc_alloc_state(rmem, chunk_size);
    gs_ref_memory_t *igmem = 0;
    gs_ref_memory_t *igmem_stable = 0;
    gs_ref_memory_t *ismem = ialloc_alloc_state(rmem, chunk_size);
    int i;

    if (ilmem == 0 || ilmem_stable == 0 || ismem == 0)
	goto fail;
    ilmem->stable_memory = (gs_memory_t *)ilmem_stable;
    if (level2) {
	igmem = ialloc_alloc_state(rmem, chunk_size);
	igmem_stable = ialloc_alloc_state(rmem, chunk_size);
	if (igmem == 0 || igmem_stable == 0)
	    goto fail;
	igmem->stable_memory = (gs_memory_t *)igmem_stable;
    } else
	igmem = ilmem, igmem_stable = ilmem_stable;
    for (i = 0; i < countof(dmem->spaces_indexed); i++)
	dmem->spaces_indexed[i] = 0;
    dmem->space_local = ilmem;
    dmem->space_global = igmem;
    dmem->space_system = ismem;
    dmem->spaces.vm_reclaim = gs_gc_reclaim; /* real GC */
    dmem->reclaim = 0;		/* no interpreter GC yet */
    /* Level 1 systems have only local VM. */
    igmem->space = avm_global;
    igmem_stable->space = avm_global;
    ilmem->space = avm_local;	/* overrides if ilmem == igmem */
    ilmem_stable->space = avm_local; /* ditto */
    ismem->space = avm_system;
#   if IGC_PTR_STABILITY_CHECK
    igmem->space_id = (i_vm_global << 1) + 1;
    igmem_stable->space_id = i_vm_global << 1;
    ilmem->space_id = (i_vm_local << 1) + 1;	/* overrides if ilmem == igmem */
    ilmem_stable->space_id = i_vm_local << 1; /* ditto */
    ismem->space_id = (i_vm_system << 1);
#   endif
    ialloc_set_space(dmem, avm_global);
    return 0;
 fail:
    gs_free_object(rmem, igmem_stable, "ialloc_init failure");
    gs_free_object(rmem, igmem, "ialloc_init failure");
    gs_free_object(rmem, ismem, "ialloc_init failure");
    gs_free_object(rmem, ilmem_stable, "ialloc_init failure");
    gs_free_object(rmem, ilmem, "ialloc_init failure");
    return_error(e_VMerror);
}
Ejemplo n.º 11
0
/* - save <save> */
int
zsave(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    uint space = icurrent_space;
    vm_save_t *vmsave;
    ulong sid;
    int code;
    gs_state *prev;

    if (I_VALIDATE_BEFORE_SAVE)
        ivalidate_clean_spaces(i_ctx_p);
    ialloc_set_space(idmemory, avm_local);
    vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
    ialloc_set_space(idmemory, space);
    if (vmsave == 0)
        return_error(e_VMerror);
    code = alloc_save_state(idmemory, vmsave, &sid);
    if (code < 0)
        return code;
    if (sid == 0) {
        ifree_object(vmsave, "zsave");
        return_error(e_VMerror);
    }
    if_debug2('u', "[u]vmsave 0x%lx, id = %lu\n",
              (ulong) vmsave, (ulong) sid);
    code = gs_gsave_for_save(igs, &prev);
    if (code < 0)
        return code;
    code = gs_gsave(igs);
    if (code < 0)
        return code;
    vmsave->gsave = prev;
    push(1);
    make_tav(op, t_save, 0, saveid, sid);
    if (I_VALIDATE_AFTER_SAVE)
        ivalidate_clean_spaces(i_ctx_p);
    return 0;
}
Ejemplo n.º 12
0
/* Create an op_array table. */
static int
alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
                     op_array_table *opt)
{
    uint save_space = ialloc_space(idmemory);
    int code;

    ialloc_set_space(idmemory, space);
    code = ialloc_ref_array(&opt->table, a_readonly, size,
                            "op_array table");
    ialloc_set_space(idmemory, save_space);
    if (code < 0)
        return code;
    refset_null(opt->table.value.refs, size);
    opt->nx_table =
        (ushort *) ialloc_byte_array(size, sizeof(ushort),
                                     "op_array nx_table");
    if (opt->nx_table == 0)
        return_error(e_VMerror);
    opt->count = 0;
    opt->attrs = space | a_executable;
    return 0;
}
Ejemplo n.º 13
0
/* Initialize the allocator */
void
ialloc_init(gs_memory_t *mem, uint chunk_size, bool level2)
{	gs_ref_memory_t *ilmem = ialloc_alloc_state(mem, chunk_size);
	gs_ref_memory_t *igmem =
		(level2 ?
		 ialloc_alloc_state(mem, chunk_size) :
		 ilmem);
	gs_ref_memory_t *ismem = ialloc_alloc_state(mem, chunk_size);
	int i;

	for ( i = 0; i < countof(gs_imemory.spaces.indexed); i++ )
	  gs_imemory.spaces.indexed[i] = 0;
	gs_imemory.space_local = ilmem;
	gs_imemory.space_global = igmem;
	gs_imemory.space_system = ismem;
	gs_imemory.reclaim = 0;
	/* Level 1 systems have only local VM. */
	igmem->space = avm_global;
	ilmem->space = avm_local;	/* overrides if ilmem == igmem */
	igmem->global = ilmem->global = igmem;
	ismem->space = avm_system;
	ialloc_set_space(&gs_imemory, avm_global);
}
Ejemplo n.º 14
0
int
zrestore(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    alloc_save_t *asave;
    bool last;
    vm_save_t *vmsave;
    int code = restore_check_operand(op, &asave, idmemory);

    if (code < 0)
        return code;
    if_debug2('u', "[u]vmrestore 0x%lx, id = %lu\n",
              (ulong) alloc_save_client_data(asave),
              (ulong) op->value.saveid);
    if (I_VALIDATE_BEFORE_RESTORE)
        ivalidate_clean_spaces(i_ctx_p);
    /* Check the contents of the stacks. */
    osp--;
    {
        int code;

        if ((code = restore_check_stack(i_ctx_p, &o_stack, asave, false)) < 0 ||
                (code = restore_check_stack(i_ctx_p, &e_stack, asave, true)) < 0 ||
                (code = restore_check_stack(i_ctx_p, &d_stack, asave, false)) < 0
           ) {
            osp++;
            return code;
        }
    }
    /* Reset l_new in all stack entries if the new save level is zero. */
    /* Also do some special fixing on the e-stack. */
    restore_fix_stack(&o_stack, asave, false);
    restore_fix_stack(&e_stack, asave, true);
    restore_fix_stack(&d_stack, asave, false);
    /* Iteratively restore the state of memory, */
    /* also doing a grestoreall at each step. */
    do {
        vmsave = alloc_save_client_data(alloc_save_current(idmemory));
        /* Restore the graphics state. */
        gs_grestoreall_for_restore(igs, vmsave->gsave);
        /*
         * If alloc_save_space decided to do a second save, the vmsave
         * object was allocated one save level less deep than the
         * current level, so ifree_object won't actually free it;
         * however, it points to a gsave object that definitely
         * *has* been freed.  In order not to trip up the garbage
         * collector, we clear the gsave pointer now.
         */
        vmsave->gsave = 0;
        /* Now it's safe to restore the state of memory. */
        code = alloc_restore_step_in(idmemory, asave);
        if (code < 0)
            return code;
        last = code;
    }
    while (!last);
    {
        uint space = icurrent_space;

        ialloc_set_space(idmemory, avm_local);
        ifree_object(vmsave, "zrestore");
        ialloc_set_space(idmemory, space);
    }
    dict_set_top();		/* reload dict stack cache */
    if (I_VALIDATE_AFTER_RESTORE)
        ivalidate_clean_spaces(i_ctx_p);
    /* If the i_ctx_p LockFilePermissions is true, but the userparams */
    /* we just restored is false, we need to make sure that we do not */
    /* cause an 'invalidaccess' in setuserparams. Temporarily set     */
    /* LockFilePermissions false until the gs_lev2.ps can do a        */
    /* setuserparams from the restored userparam dictionary.          */
    i_ctx_p->LockFilePermissions = false;
    return 0;
}
Ejemplo n.º 15
0
/* or a negative error code. */
int
build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype,
              gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild,
              build_font_options_t options)
{
    ref kname;			/* t_string */
    ref *pftype;
    ref *pencoding = 0;
    bool bitmapwidths;
    int exactsize, inbetweensize, transformedchar;
    int wmode;
    int code;
    gs_font *pfont;
    ref *pfid;
    ref *aop = dict_access_ref(op);
    bool cpsi_mode = gs_currentcpsimode(imemory);

    get_font_name(imemory, &kname, op - 1);
    if (dict_find_string(op, "FontType", &pftype) <= 0 ||
        !r_has_type(pftype, t_integer) ||
        pftype->value.intval != (int)ftype
        )
        return_error(e_invalidfont);
    if (dict_find_string(op, "Encoding", &pencoding) <= 0) {
        if (!(options & bf_Encoding_optional))
            return_error(e_invalidfont);
        pencoding = 0;
    } else {
        if (!r_is_array(pencoding))
            return_error(e_invalidfont);
    }
    if (pencoding) {   /* observed Adobe behavior */
        int count = r_size(pencoding);
        int type = ftype ? t_name : t_integer;
        bool fixit = false;

        while (count--) {
           ref r;
           if ((code = array_get(imemory, pencoding, count, &r)) < 0 ||
             !(r_has_type(&r, type) || r_has_type(&r, t_null))) {
               if (!cpsi_mode && ftype == ft_user_defined) {
                   if (code < 0 || r_has_type(&r, t_null)) {
                       return_error(e_typecheck);
                   }
                   fixit = true;
                   break;
               }
               else {
                   return_error(e_typecheck);
               }
           }
        }

        /* For at least Type 3 fonts, Adobe Distiller will "fix" an Encoding array, as in, for example
         * Bug 692681 where the arrays contain integers rather than names. Once the font is instantiated
         * the integers have been converted to names.
         * It is preferable to to this manipulation here, rather than in Postscript, because we are less
         * restricted by read-only attributes and VM save levels.
         */
        if (fixit) {
            ref penc;
            uint size = 0;
            char buf[32], *bptr;
            avm_space curglob = ialloc_space(idmemory);
            avm_space useglob = r_is_local(pencoding) ? avm_local : avm_global;

            ialloc_set_space(idmemory, useglob);
            
            count = r_size(pencoding);
            if ((code = ialloc_ref_array(&penc, (r_type_attrs(pencoding) & a_readonly), count, "build_gs_font")) < 0)
                 return code;
            
            while (count--) {
               ref r;
               if (array_get(imemory, pencoding, count, &r) < 0){
                   return_error(e_typecheck);
               }
               /* For type 3, we know the Encoding entries must be names */
               if (r_has_type(&r, t_name)){
                   ref_assign(&(penc.value.refs[count]), &r);
               }
               else {
               
                   if ((code = obj_cvs(imemory, &r, (byte *)buf, 32, &size, (const byte **)(&bptr))) < 0) {
                       return(code);
                   }
                   if ((code = name_ref(imemory, (const byte *)bptr, size, &r, true)) < 0)
                        return code;
                   ref_assign(&(penc.value.refs[count]), &r);
               }
            }
            
            if ((code = dict_put_string(osp, "Encoding", &penc, NULL)) < 0)
               return code;
            ialloc_set_space(idmemory, curglob);
        }
    }
    if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 ||
        (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 ||
        (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 ||
        (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 ||
        (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0
        )
        return code;
    code = dict_find_string(op, "FID", &pfid);
    if (code > 0 && r_has_type(pfid, t_fontID)) { /* silently ignore invalid FID per CET 13-05.ps */
        /*
         * If this font has a FID entry already, it might be a scaled font
         * made by makefont or scalefont; in a Level 2 environment, it might
         * be an existing font being registered under a second name, or a
         * re-encoded font (which was invalid in Level 1, but dvips did it
         * anyway).
         */
        pfont = r_ptr(pfid, gs_font);
        /*
         * If the following condition is false this is a re-encoded font,
         * or some other questionable situation in which the FID
         * was preserved.  Pretend the FID wasn't there.
         */
        if (obj_eq(pfont->memory, pfont_dict(pfont), op)) {
            if (pfont->base == pfont) {	/* original font */
                if (!level2_enabled)
                    return_error(e_invalidfont);
                *ppfont = pfont;
                return 1;
            } else {		/* This was made by makefont or scalefont. */
                /* Just insert the new name. */
                gs_matrix mat;
                ref fname;			/* t_string */

                code = sub_font_params(imemory, op, &mat, NULL, &fname);
                if (code < 0)
                    return code;
                code = 1;
                copy_font_name(&pfont->font_name, &fname);
                goto set_name;
            }
        }
    }
    /* This is a new font. */
    if (!r_has_attr(aop, a_write))
        return_error(e_invalidaccess);
    {
        ref encoding;

        /*
         * Since add_FID may resize the dictionary and cause
         * pencoding to become invalid, save the Encoding.
         */
        if (pencoding) {
            encoding = *pencoding;
            pencoding = &encoding;
        }
        code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype,
                                 pbuild, pencoding, op);
        if (code < 0)
            return code;
    }
    pfont->BitmapWidths = bitmapwidths;
    pfont->ExactSize = (fbit_type)exactsize;
    pfont->InBetweenSize = (fbit_type)inbetweensize;
    pfont->TransformedChar = (fbit_type)transformedchar;
    pfont->WMode = wmode;
    pfont->procs.font_info = zfont_info;
    code = 0;
set_name:
    copy_font_name(&pfont->key_name, &kname);
    *ppfont = pfont;
    return code;
}