Beispiel #1
0
static void gx_ttfReader__Reset(gx_ttfReader *self)
{
    if (self->extra_glyph_index != -1) {
        self->extra_glyph_index = -1;
        gs_glyph_data_free(&self->glyph_data, "gx_ttfReader__Reset");
    }
    self->error = false;
    self->pos = 0;
}
Beispiel #2
0
static void gx_ttfReader__ReleaseGlyph(ttfReader *self, int glyph_index)
{
    gx_ttfReader *r = (gx_ttfReader *)self;

    if (r->extra_glyph_index != glyph_index)
        return;
    r->extra_glyph_index = -1;
    gs_glyph_data_free(&r->glyph_data, "gx_ttfReader__ReleaseExtraGlyph");
}
Beispiel #3
0
/* Get the outline of a CIDFontType 0 glyph. */
static int
z9_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat,
                 gx_path *ppath, double sbw[4])
{
    gs_font_cid0 *const pfcid = (gs_font_cid0 *)font;
    ref gref;
    gs_glyph_data_t gdata;
    int code, fidx, ocode;

    gdata.memory = font->memory;
    code = pfcid->cidata.glyph_data((gs_font_base *)pfcid, glyph, &gdata,
                                    &fidx);
    if (code < 0)
        return code;
    glyph_ref(font->memory, glyph, &gref);
    ocode = zcharstring_outline(pfcid->cidata.FDArray[fidx], WMode, &gref, &gdata,
                                pmat, ppath, sbw);
    gs_glyph_data_free(&gdata, "z9_glyph_outline");
    return ocode;
}
Beispiel #4
0
/* Note that pgd may be NULL. */
static int
z9_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_glyph_data_t *pgd,
              int *pfidx)
{
    gs_font_cid0 *pfont = (gs_font_cid0 *)pbfont;
    const font_data *pfdata = pfont_data(pfont);
    long glyph_index = (long)(glyph - gs_min_cid_glyph);
    gs_glyph_data_t gdata;
    ulong fidx;
    int code;

    gdata.memory = pfont->memory;
    if (!r_has_type(&pfdata->u.cid0.GlyphDirectory, t_null)) {
        code = font_gdir_get_outline(pfont->memory,
                                     &pfdata->u.cid0.GlyphDirectory,
                                     glyph_index, &gdata);
        if (code < 0)
            return code;
        /* Get the definition from GlyphDirectory. */
        if (!gdata.bits.data)
            return_error(e_rangecheck);
        code = get_index(&gdata, pfont->cidata.FDBytes, &fidx);
        if (code < 0)
            return code;
        if (fidx >= pfont->cidata.FDArray_size)
            return_error(e_rangecheck);
        if (pgd)
            *pgd = gdata;
        *pfidx = (int)fidx;
        return code;
    }
    /* Get the definition from the binary data (GlyphData or DataSource). */
    if (glyph_index < 0 || glyph_index >= pfont->cidata.common.CIDCount) {
        *pfidx = 0;
        if (pgd)
            gs_glyph_data_from_null(pgd);
        return_error(e_rangecheck);
    }
    {
        byte fd_gd[(MAX_FDBytes + MAX_GDBytes) * 2];
        uint num_bytes = pfont->cidata.FDBytes + pfont->cidata.common.GDBytes;
        ulong base = pfont->cidata.CIDMapOffset + glyph_index * num_bytes;
        ulong gidx, fidx_next, gidx_next;
        int rcode = cid0_read_bytes(pfont, base, (ulong)(num_bytes * 2), fd_gd,
                                    &gdata);
        gs_glyph_data_t orig_data;

        if (rcode < 0)
            return rcode;
        orig_data = gdata;
        if ((code = get_index(&gdata, pfont->cidata.FDBytes, &fidx)) < 0 ||
            (code = get_index(&gdata, pfont->cidata.common.GDBytes, &gidx)) < 0 ||
            (code = get_index(&gdata, pfont->cidata.FDBytes, &fidx_next)) < 0 ||
            (code = get_index(&gdata, pfont->cidata.common.GDBytes, &gidx_next)) < 0
            )
            DO_NOTHING;
        gs_glyph_data_free(&orig_data, "z9_glyph_data");
        if (code < 0)
            return code;
        /*
         * Some CID fonts (from Adobe!) have invalid font indexes for
         * missing glyphs.  Handle this now.
         */
        if (gidx_next <= gidx) { /* missing glyph */
            *pfidx = 0;
            if (pgd)
                gs_glyph_data_from_null(pgd);
            return_error(e_undefined);
        }
        if (fidx >= pfont->cidata.FDArray_size)
            return_error(e_rangecheck);
        *pfidx = (int)fidx;
        if (pgd == 0)
            return 0;
        return cid0_read_bytes(pfont, gidx, gidx_next - gidx, NULL, pgd);
    }
}
/*
 * Write the Private dictionary.  This is a separate procedure only for
 * readability.  write_CharString is a parameter so that we can encrypt
 * Subrs and CharStrings when the font's lenIV == -1 but we are writing
 * the font with lenIV = 0.
 */
static int
write_Private(stream *s, gs_font_type1 *pfont,
	      gs_glyph *subset_glyphs, uint subset_size,
	      gs_glyph notdef, int lenIV,
	      int (*write_CharString)(stream *, const void *, uint),
	      const param_printer_params_t *ppp)
{
    const gs_type1_data *const pdata = &pfont->data;
    printer_param_list_t rlist;
    gs_param_list *const plist = (gs_param_list *)&rlist;
    int code = s_init_param_printer(&rlist, ppp, s);

    if (code < 0)
	return 0;
    stream_puts(s, "dup /Private 17 dict dup begin\n");
    stream_puts(s, "/-|{string currentfile exch readstring pop}executeonly def\n");
    stream_puts(s, "/|-{noaccess def}executeonly def\n");
    stream_puts(s, "/|{noaccess put}executeonly def\n");
    {
	static const gs_param_item_t private_items[] = {
	    {"BlueFuzz", gs_param_type_int,
	     offset_of(gs_type1_data, BlueFuzz)},
	    {"BlueScale", gs_param_type_float,
	     offset_of(gs_type1_data, BlueScale)},
	    {"BlueShift", gs_param_type_float,
	     offset_of(gs_type1_data, BlueShift)},
	    {"ExpansionFactor", gs_param_type_float,
	     offset_of(gs_type1_data, ExpansionFactor)},
	    {"ForceBold", gs_param_type_bool,
	     offset_of(gs_type1_data, ForceBold)},
	    {"LanguageGroup", gs_param_type_int,
	     offset_of(gs_type1_data, LanguageGroup)},
	    {"RndStemUp", gs_param_type_bool,
	     offset_of(gs_type1_data, RndStemUp)},
	    gs_param_item_end
	};
	gs_type1_data defaults;

	defaults.BlueFuzz = 1;
	defaults.BlueScale = (float)0.039625;
	defaults.BlueShift = 7.0;
	defaults.ExpansionFactor = (float)0.06;
	defaults.ForceBold = false;
	defaults.LanguageGroup = 0;
	defaults.RndStemUp = true;
	code = gs_param_write_items(plist, pdata, &defaults, private_items);
	if (code < 0)
	    return code;
	if (lenIV != 4) {
	    code = param_write_int(plist, "lenIV", &lenIV);
	    if (code < 0)
		return code;
	}
	write_float_array(plist, "BlueValues", pdata->BlueValues.values,
			  pdata->BlueValues.count);
	write_float_array(plist, "OtherBlues", pdata->OtherBlues.values,
			  pdata->OtherBlues.count);
	write_float_array(plist, "FamilyBlues", pdata->FamilyBlues.values,
			  pdata->FamilyBlues.count);
	write_float_array(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values,
			  pdata->FamilyOtherBlues.count);
	write_float_array(plist, "StdHW", pdata->StdHW.values,
			  pdata->StdHW.count);
	write_float_array(plist, "StdVW", pdata->StdVW.values,
			  pdata->StdVW.count);
	write_float_array(plist, "StemSnapH", pdata->StemSnapH.values,
			  pdata->StemSnapH.count);
	write_float_array(plist, "StemSnapV", pdata->StemSnapV.values,
			  pdata->StemSnapV.count);
    }
    write_uid(s, &pfont->UID);
    stream_puts(s, "/MinFeature{16 16} def\n");
    stream_puts(s, "/password 5839 def\n");

    /*
     * Write the Subrs.  We always write them all, even for subsets.
     * (We will fix this someday.)
     */

    {
	int n, i;
	gs_glyph_data_t gdata;
	int code;

	gdata.memory = pfont->memory;
	for (n = 0;
	     (code = pdata->procs.subr_data(pfont, n, false, &gdata)) !=
		 gs_error_rangecheck;
	     ) {
	    ++n;
	    if (code >= 0)
		gs_glyph_data_free(&gdata, "write_Private(Subrs)");
	}
	pprintd1(s, "/Subrs %d array\n", n);
	for (i = 0; i < n; ++i)
	    if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) {
		char buf[50];

		if (gdata.bits.size) {
		    sprintf(buf, "dup %d %u -| ", i, gdata.bits.size);
		    stream_puts(s, buf);
		    write_CharString(s, gdata.bits.data, gdata.bits.size);
		    stream_puts(s, " |\n");
		}
		gs_glyph_data_free(&gdata, "write_Private(Subrs)");
	    }
	stream_puts(s, "|-\n");
    }

    /* We don't write OtherSubrs -- there had better not be any! */

    /* Write the CharStrings. */

    {
	int num_chars = 0;
	gs_glyph glyph;
	psf_glyph_enum_t genum;
	gs_glyph_data_t gdata;
	int code;

	gdata.memory = pfont->memory;
	psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs,
				    (subset_glyphs ? subset_size : 0),
				    GLYPH_SPACE_NAME);
	for (glyph = gs_no_glyph;
	     (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
	     )
	    if (code == 0 &&
		(code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
		) {
		++num_chars;
		gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
	    }
	pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars);
	psf_enumerate_glyphs_reset(&genum);
	for (glyph = gs_no_glyph;
	     (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
	    )
	    if (code == 0 &&
		(code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
		) {
		gs_const_string gstr;
		int code;

		code = pfont->procs.glyph_name((gs_font *)pfont, glyph, &gstr);
		if (code < 0)
		    return code;
		stream_puts(s, "/");
		stream_write(s, gstr.data, gstr.size);
		pprintd1(s, " %d -| ", gdata.bits.size);
		write_CharString(s, gdata.bits.data, gdata.bits.size);
		stream_puts(s, " |-\n");
		gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
	    }
    }

    /* Wrap up. */

    stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n");
    s_release_param_printer(&rlist);
    return 0;
}
Beispiel #6
0
int
gs_type1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat,
		    int members, gs_glyph_info_t *info)
{
    gs_font_type1 *const pfont = (gs_font_type1 *)font;
    gs_type1_data *const pdata = &pfont->data;
    int wmode = ((members & GLYPH_INFO_WIDTH1) != 0);
    int piece_members = members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES);
    int width_members = (members & ((GLYPH_INFO_WIDTH0 << wmode) | (GLYPH_INFO_VVECTOR0 << wmode)));
    int default_members = members & ~(piece_members | GLYPH_INFO_WIDTHS |
				     GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1 |
				     GLYPH_INFO_OUTLINE_WIDTHS);
    int code = 0;
    gs_glyph_data_t gdata;

    if (default_members) {
	code = gs_default_glyph_info(font, glyph, pmat, default_members, info);

	if (code < 0)
	    return code;
    } else
	info->members = 0;

    if (default_members == members)
	return code;		/* all done */

    gdata.memory = pfont->memory;
    if ((code = pdata->procs.glyph_data(pfont, glyph, &gdata)) < 0)
	return code;		/* non-existent glyph */

    if (piece_members) {
	code = gs_type1_glyph_pieces(pfont, &gdata, members, info);
	if (code < 0)
	    return code;
	info->members |= piece_members;
    }

    if (width_members) {
	gx_path path;
	/*
	 * Interpret the CharString until we get to the [h]sbw.
	 */
	gs_imager_state gis;
	gs_type1_state cis;
	int value;

	/* Initialize just enough of the imager state. */
	if (pmat)
	    gs_matrix_fixed_from_matrix(&gis.ctm, pmat);
	else {
	    gs_matrix imat;

	    gs_make_identity(&imat);
	    gs_matrix_fixed_from_matrix(&gis.ctm, &imat);
	}
	gis.flatness = 0;
	code = gs_type1_interp_init(&cis, &gis, NULL /* no path needed */,
				    NULL, NULL, true, 0, pfont);
	if (code < 0)
	    return code;
	cis.no_grid_fitting = true;
	gx_path_init_bbox_accumulator(&path);
	cis.path = &path;
	code = pdata->interpret(&cis, &gdata, &value);
	switch (code) {
	case 0:		/* done with no [h]sbw, error */
	                /* Adobe interpreters ignore the error! */
	    info->width[wmode].x = 0;
	    info->width[wmode].y = 0;
	    info->v.x = 0;
	    info->v.y = 0;
	    break;
	default:		/* code < 0, error */
	    return code;
	case type1_result_callothersubr:	/* unknown OtherSubr */
	    return_error(gs_error_rangecheck); /* can't handle it */
	case type1_result_sbw:
	    info->width[wmode].x = fixed2float(cis.width.x);
	    info->width[wmode].y = fixed2float(cis.width.y);
	    info->v.x = fixed2float(cis.lsb.x);
	    info->v.y = fixed2float(cis.lsb.y);
	    break;
	}
	info->members |= width_members | (GLYPH_INFO_VVECTOR0 << wmode);
    }

    gs_glyph_data_free(&gdata, "gs_type1_glyph_info");
    return code;
}
Beispiel #7
0
/*
 * If a Type 1 character is defined with 'seac', store the character codes
 * in chars[0] and chars[1] and return 1; otherwise, return 0 or <0.
 * This is exported only for the benefit of font copying.
 */
int
gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont,
		     const gs_glyph_data_t *pgd, gs_char *chars)
{
    gs_type1_data *const pdata = &pfont->data;
    /*
     * Decode the CharString looking for seac.  We have to process
     * callsubr, callothersubr, and return operators, but if we see
     * any other operators other than [h]sbw, pop, hint operators,
     * or endchar, we can return immediately.  We have to include
     * endchar because it is an (undocumented) equivalent for seac
     * in Type 2 CharStrings: see the cx_endchar case in
     * gs_type2_interpret in gstype2.c.
     *
     * It's really unfortunate that we have to duplicate so much parsing
     * code, but factoring out the parser from the interpreter would
     * involve more restructuring than we're prepared to do right now.
     */
    bool encrypted = pdata->lenIV >= 0;
    fixed cstack[ostack_size];
    fixed *csp;
    ip_state_t ipstack[ipstack_size + 1];
    ip_state_t *ipsp = &ipstack[0];
    const byte *cip;
    crypt_state state;
    int c;
    int code;
    
    CLEAR_CSTACK(cstack, csp);
    cip = pgd->bits.data;
 call:
    state = crypt_charstring_seed;
    if (encrypted) {
	int skip = pdata->lenIV;

	/* Skip initial random bytes */
	for (; skip > 0; ++cip, --skip)
	    decrypt_skip_next(*cip, state);
    }
 top:
    for (;;) {
	uint c0 = *cip++;

	charstring_next(c0, state, c, encrypted);
	if (c >= c_num1) {
	    /* This is a number, decode it and push it on the stack. */
	    if (c < c_pos2_0) {	/* 1-byte number */
		decode_push_num1(csp, cstack, c);
	    } else if (c < cx_num4) {	/* 2-byte number */
		decode_push_num2(csp, cstack, c, cip, state, encrypted);
	    } else if (c == cx_num4) {	/* 4-byte number */
		long lw;

		decode_num4(lw, cip, state, encrypted);
		CS_CHECK_PUSH(csp, cstack);
		*++csp = int2fixed(lw);
	    } else		/* not possible */
		return_error(gs_error_invalidfont);
	    continue;
	}
#define cnext CLEAR_CSTACK(cstack, csp); goto top
	switch ((char_command) c) {
	default:
	    goto out;
	case c_callsubr:
	    c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
	    code = pdata->procs.subr_data
		(pfont, c, false, &ipsp[1].cs_data);
	    if (code < 0)
		return_error(code);
	    --csp;
	    ipsp->ip = cip, ipsp->dstate = state;
	    ++ipsp;
	    cip = ipsp->cs_data.bits.data;
	    goto call;
	case c_return:
	    gs_glyph_data_free(&ipsp->cs_data, "gs_type1_piece_codes");
	    --ipsp;
	    cip = ipsp->ip, state = ipsp->dstate;
	    goto top;
	case cx_hstem:
	case cx_vstem:
	case c1_hsbw:
	    cnext;
	case cx_endchar:
	    if (csp < cstack + 3)
		goto out;	/* not seac */
	do_seac:
	    /* This is the payoff for all this code! */
	    chars[0] = fixed2int(csp[-1]);
	    chars[1] = fixed2int(csp[0]);
	    return 1;
	case cx_escape:
	    charstring_next(*cip, state, c, encrypted);
	    ++cip;
	    switch ((char1_extended_command) c) {
	    default:
		goto out;
	    case ce1_vstem3:
	    case ce1_hstem3:
	    case ce1_sbw:
		cnext;
	    case ce1_pop:
		/*
		 * pop must do nothing, since it is used after
		 * subr# 1 3 callothersubr.
		 */
		goto top;
	    case ce1_seac:
		goto do_seac;
	    case ce1_callothersubr:
		switch (fixed2int_var(*csp)) {
		default:
		    goto out;
		case 3:
		    csp -= 2;
		    goto top;
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		    cnext;
		}
	    }
	}
#undef cnext
    }
 out:
    return 0;
}
Beispiel #8
0
/*
 * Continue interpreting a Type 1 charstring.  If str != 0, it is taken as
 * the byte string to interpret.  Return 0 on successful completion, <0 on
 * error, or >0 when client intervention is required (or allowed).  The int*
 * argument is where the othersubr # is stored for callothersubr.
 */
int
gs_type1_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
		   int *pindex)
{
    gs_font_type1 *pfont = pcis->pfont;
    gs_type1_data *pdata = &pfont->data;
    t1_hinter *h = &pcis->h;
    bool encrypted = pdata->lenIV >= 0;
    fixed cstack[ostack_size];

#define cs0 cstack[0]
#define ics0 fixed2int_var(cs0)
#define cs1 cstack[1]
#define ics1 fixed2int_var(cs1)
#define cs2 cstack[2]
#define ics2 fixed2int_var(cs2)
#define cs3 cstack[3]
#define ics3 fixed2int_var(cs3)
#define cs4 cstack[4]
#define ics4 fixed2int_var(cs4)
#define cs5 cstack[5]
#define ics5 fixed2int_var(cs5)
    cs_ptr csp;
#define clear CLEAR_CSTACK(cstack, csp)
    ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
    register const byte *cip;
    register crypt_state state;
    register int c;
    int code = 0;
    fixed ftx = pcis->origin.x, fty = pcis->origin.y;

    switch (pcis->init_done) {
	case -1:
	    t1_hinter__init(h, pcis->path);
	    break;
	case 0:
	    gs_type1_finish_init(pcis);	/* sets origin */
	    ftx = pcis->origin.x, fty = pcis->origin.y;
            code = t1_hinter__set_mapping(h, &pcis->pis->ctm,
			    &pfont->FontMatrix, &pfont->base->FontMatrix,
			    pcis->scale.x.log2_unit, pcis->scale.x.log2_unit,
			    pcis->scale.x.log2_unit - pcis->log2_subpixels.x,
			    pcis->scale.y.log2_unit - pcis->log2_subpixels.y,
			    pcis->origin.x, pcis->origin.y, 
			    gs_currentaligntopixels(pfont->dir));
	    if (code < 0)
	    	return code;
	    code = t1_hinter__set_font_data(h, 1, pdata, pcis->no_grid_fitting);
	    if (code < 0)
	    	return code;
	    break;
	default /*case 1 */ :
	    break;
    }
    INIT_CSTACK(cstack, csp, pcis);

    if (pgd == 0)
	goto cont;
    ipsp->cs_data = *pgd;
    cip = pgd->bits.data;
  call:state = crypt_charstring_seed;
    if (encrypted) {
	int skip = pdata->lenIV;

	/* Skip initial random bytes */
	for (; skip > 0; ++cip, --skip)
	    decrypt_skip_next(*cip, state);
    }
    goto top;
  cont:cip = ipsp->ip;
    state = ipsp->dstate;
  top:for (;;) {
	uint c0 = *cip++;

	charstring_next(c0, state, c, encrypted);
	if (c >= c_num1) {
	    /* This is a number, decode it and push it on the stack. */

	    if (c < c_pos2_0) {	/* 1-byte number */
		decode_push_num1(csp, cstack, c);
	    } else if (c < cx_num4) {	/* 2-byte number */
		decode_push_num2(csp, cstack, c, cip, state, encrypted);
	    } else if (c == cx_num4) {	/* 4-byte number */
		long lw;

		decode_num4(lw, cip, state, encrypted);
		CS_CHECK_PUSH(csp, cstack);
		*++csp = int2fixed(lw);
		if (lw != fixed2long(*csp)) {
		    /*
		     * We handle the only case we've ever seen that
		     * actually uses such large numbers specially.
		     */
		    long denom;

		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c < c_num1)
			return_error(gs_error_rangecheck);
		    if (c < c_pos2_0)
			decode_num1(denom, c);
		    else if (c < cx_num4)
			decode_num2(denom, c, cip, state, encrypted);
		    else if (c == cx_num4)
			decode_num4(denom, cip, state, encrypted);
		    else
			return_error(gs_error_invalidfont);
		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c != cx_escape)
			return_error(gs_error_rangecheck);
		    c0 = *cip++;
		    charstring_next(c0, state, c, encrypted);
		    if (c != ce1_div)
			return_error(gs_error_rangecheck);
		    *csp = float2fixed((double)lw / denom);
		}
	    } else		/* not possible */
		return_error(gs_error_invalidfont);
	  pushed:if_debug3('1', "[1]%d: (%d) %f\n",
		      (int)(csp - cstack), c, fixed2float(*csp));
	    continue;
	}
#ifdef DEBUG
	if (gs_debug['1']) {
	    static const char *const c1names[] =
	    {char1_command_names};

	    if (c1names[c] == 0)
		dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
	    else
		dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
			  c1names[c]);
	}
#endif
	switch ((char_command) c) {
#define cnext clear; goto top
#define inext goto top

		/* Commands with identical functions in Type 1 and Type 2, */
		/* except for 'escape'. */

	    case c_undef0:
	    case c_undef2:
	    case c_undef17:
		return_error(gs_error_invalidfont);
	    case c_callsubr:
		c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
		code = pdata->procs.subr_data
		    (pfont, c, false, &ipsp[1].cs_data);
		if (code < 0)
		    return_error(code);
		--csp;
		ipsp->ip = cip, ipsp->dstate = state;
		++ipsp;
		cip = ipsp->cs_data.bits.data;
		goto call;
	    case c_return:
		gs_glyph_data_free(&ipsp->cs_data, "gs_type1_interpret");
		--ipsp;
		goto cont;
	    case c_undoc15:
		/* See gstype1.h for information on this opcode. */
		cnext;

		/* Commands with similar but not identical functions */
		/* in Type 1 and Type 2 charstrings. */

	    case cx_hstem:
                code = t1_hinter__hstem(h, cs0, cs1);
		if (code < 0)
		    return code;
		cnext;
	    case cx_vstem:
                code = t1_hinter__vstem(h, cs0, cs1);
		if (code < 0)
		    return code;
		cnext;
	    case cx_vmoveto:
		cs1 = cs0;
		cs0 = 0;
	      move:		/* cs0 = dx, cs1 = dy for hint checking. */
                code = t1_hinter__rmoveto(h, cs0, cs1);
		goto cc;
	    case cx_rlineto:
	      line:		/* cs0 = dx, cs1 = dy for hint checking. */
                code = t1_hinter__rlineto(h, cs0, cs1);
	      cc:if (code < 0)
		    return code;
		cnext;
	    case cx_hlineto:
		cs1 = 0;
		goto line;
	    case cx_vlineto:
		cs1 = cs0;
		cs0 = 0;
		goto line;
	    case cx_rrcurveto:
                code = t1_hinter__rcurveto(h, cs0, cs1, cs2, cs3, cs4, cs5);
		goto cc;
	    case cx_endchar:
                code = t1_hinter__endchar(h, (pcis->seac_accent >= 0));
		if (code < 0)
		    return code;
                if (pcis->seac_accent < 0) {
                    code = t1_hinter__endglyph(h);
		    if (code < 0)
			return code;
		    code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path);
		    if (code < 0)
			return code;
		}
		code = gs_type1_endchar(pcis);
		if (code == 1) {
		    /* do accent of seac */
		    ipsp = &pcis->ipstack[pcis->ips_count - 1];
		    cip = ipsp->cs_data.bits.data;
		    goto call;
		}
		return code;
	    case cx_rmoveto:
		goto move;
	    case cx_hmoveto:
		cs1 = 0;
		goto move;
	    case cx_vhcurveto:
                code = t1_hinter__rcurveto(h, 0, cs0, cs1, cs2, cs3, 0);
		goto cc;
	    case cx_hvcurveto:
                code = t1_hinter__rcurveto(h, cs0, 0, cs1, cs2, 0, cs3);
		goto cc;

		/* Commands only recognized in Type 1 charstrings, */
		/* plus 'escape'. */

	    case c1_closepath:
                code = t1_hinter__closepath(h);
		goto cc;
	    case c1_hsbw:
                if (!h->seac_flag) {
		    fixed sbx = cs0, sby = fixed_0, wx = cs1, wy = fixed_0;

		    if (pcis->sb_set) {
			sbx = pcis->lsb.x;
			sby = pcis->lsb.y;
		    }
		    if (pcis->width_set) {
			wx = pcis->width.x;
			wy = pcis->width.y;
		    }
		    code = t1_hinter__sbw(h, sbx, sby, wx, wy);
                } else
                    code = t1_hinter__sbw_seac(h, pcis->adxy.x, pcis->adxy.y);
		if (code < 0)
		    return code;
		gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0);
		cs1 = fixed_0;
rsbw:		/* Give the caller the opportunity to intervene. */
		pcis->os_count = 0;	/* clear */
		ipsp->ip = cip, ipsp->dstate = state;
		pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
		/* If we aren't in a seac, do nothing else now; */
		/* finish_init will take care of the rest. */
		if (pcis->init_done < 0) {
		    /* Finish init when we return. */
		    pcis->init_done = 0;
		} else {
		    /*
		     * Accumulate the side bearing now, but don't do it
		     * a second time for the base character of a seac.
		     */
		    if (pcis->seac_accent >= 0) {
			/*
			 * As a special hack to work around a bug in
			 * Fontographer, we deal with the (illegal)
			 * situation in which the side bearing of the
			 * accented character (save_lsbx) is different from
			 * the side bearing of the base character (cs0/cs1).
			 */
			fixed dsbx = cs0 - pcis->save_lsb.x;
			fixed dsby = cs1 - pcis->save_lsb.y;

			if (dsbx | dsby) {
			    pcis->lsb.x += dsbx;
			    pcis->lsb.y += dsby;
			    pcis->save_adxy.x -= dsbx;
			    pcis->save_adxy.y -= dsby;
			}
		    }
		}
		return type1_result_sbw;
	    case cx_escape:
		charstring_next(*cip, state, c, encrypted);
		++cip;
#ifdef DEBUG
		if (gs_debug['1'] && c < char1_extended_command_count) {
		    static const char *const ce1names[] =
		    {char1_extended_command_names};

		    if (ce1names[c] == 0)
			dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
		    else
			dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
				  ce1names[c]);
		}
#endif
		switch ((char1_extended_command) c) {
		    case ce1_dotsection:
                        code = t1_hinter__dotsection(h);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_vstem3:
                        code = t1_hinter__vstem3(h, cs0, cs1, cs2, cs3, cs4, cs5);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_hstem3:
                        code = t1_hinter__hstem3(h, cs0, cs1, cs2, cs3, cs4, cs5);
			if (code < 0)
			    return code;
			cnext;
		    case ce1_seac:
			code = gs_type1_seac(pcis, cstack + 1, cstack[0],
					     ipsp);
			if (code != 0) {
			    *pindex = ics3;
			    return code;
			}
			clear;
			cip = ipsp->cs_data.bits.data;
			goto call;
		    case ce1_sbw:
                        if (!h->seac_flag)
                            code = t1_hinter__sbw(h, cs0, cs1, cs2, cs3);
                        else
                            code = t1_hinter__sbw_seac(h, cs0 + pcis->adxy.x , cs1 + pcis->adxy.y);
			if (code < 0)
			    return code;
			gs_type1_sbw(pcis, cs0, cs1, cs2, cs3);
			goto rsbw;
		    case ce1_div:
			csp[-1] = float2fixed((double)csp[-1] / (double)*csp);
			--csp;
			goto pushed;
		    case ce1_undoc15:
			/* See gstype1.h for information on this opcode. */
			cnext;
		    case ce1_callothersubr:
			{
			    int num_results;
			    /* We must remember to pop both the othersubr # */
			    /* and the argument count off the stack. */
			    switch (*pindex = fixed2int_var(*csp)) {
				case 0:
				    {	
					fixed fheight = csp[-4];
					/* Assume the next two opcodes */
					/* are `pop' `pop'.  Unfortunately, some */
					/* Monotype fonts put these in a Subr, */
					/* so we can't just look ahead in the */
					/* opcode stream. */
					pcis->ignore_pops = 2;
					csp[-4] = csp[-3] - pcis->asb_diff;
					csp[-3] = csp[-2];
					csp -= 3;
					code = t1_hinter__flex_end(h, fheight);
				    }
				    if (code < 0)
					return code;
				    pcis->flex_count = flex_max;	/* not inside flex */
				    inext;
				case 1:
				    code = t1_hinter__flex_beg(h);
				    if (code < 0)
					return code;
				    pcis->flex_count = 1;
				    csp -= 2;
				    inext;
				case 2:
				    if (pcis->flex_count >= flex_max)
					return_error(gs_error_invalidfont);
				    code = t1_hinter__flex_point(h);
				    if (code < 0)
					return code;
				    csp -= 2;
				    inext;
				case 3:
				    /* Assume the next opcode is a `pop'. */
				    /* See above as to why we don't just */
				    /* look ahead in the opcode stream. */
				    pcis->ignore_pops = 1;
                                    code = t1_hinter__drop_hints(h);
				    if (code < 0)
					return code;
				    csp -= 2;
				    inext;
				case 12:
				case 13:
				    /* Counter control isn't implemented. */
				    cnext;
				case 14:
				    num_results = 1;
				  blend:
				    code = gs_type1_blend(pcis, csp,
							  num_results);
				    if (code < 0)
					return code;
				    csp -= code;
				    inext;
				case 15:
				    num_results = 2;
				    goto blend;
				case 16:
				    num_results = 3;
				    goto blend;
				case 17:
				    num_results = 4;
				    goto blend;
				case 18:
				    num_results = 6;
				    goto blend;
			    }
			}
			/* Not a recognized othersubr, */
			/* let the client handle it. */
			{
			    int scount = csp - cstack;
			    int n;

			    /* Copy the arguments to the caller's stack. */
			    if (scount < 1 || csp[-1] < 0 ||
				csp[-1] > int2fixed(scount - 1)
				)
				return_error(gs_error_invalidfont);
			    n = fixed2int_var(csp[-1]);
			    code = (*pdata->procs.push_values)
				(pcis->callback_data, csp - (n + 1), n);
			    if (code < 0)
				return_error(code);
			    scount -= n + 1;
			    /* Exit to caller */
			    ipsp->ip = cip, ipsp->dstate = state;
			    pcis->os_count = scount;
			    pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
			    if (scount)
				memcpy(pcis->ostack, cstack, scount * sizeof(fixed));
			    return type1_result_callothersubr;
			}
		    case ce1_pop:
			/* Check whether we're ignoring the pops after */
			/* a known othersubr. */
			if (pcis->ignore_pops != 0) {
			    pcis->ignore_pops--;
			    inext;
			}
			CS_CHECK_PUSH(csp, cstack);
			++csp;
			code = (*pdata->procs.pop_value)
			    (pcis->callback_data, csp);
			if (code < 0)
			    return_error(code);
			goto pushed;
		    case ce1_setcurrentpoint:
			t1_hinter__setcurrentpoint(h, cs0, cs1);
			cs0 += pcis->adxy.x;
			cs1 += pcis->adxy.y;
			cnext;
		    default:
			return_error(gs_error_invalidfont);
		}
		/*NOTREACHED */

		/* Fill up the dispatch up to 32. */

	      case_c1_undefs:
	    default:		/* pacify compiler */
		return_error(gs_error_invalidfont);
	}
    }
}
Beispiel #9
0
/*
 * Continue interpreting a Type 2 charstring.  If str != 0, it is taken as
 * the byte string to interpret.  Return 0 on successful completion, <0 on
 * error, or >0 when client intervention is required (or allowed).  The int*
 * argument is only for compatibility with the Type 1 charstring interpreter.
 */
int
gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd,
                   int *ignore_pindex)
{
    gs_font_type1 *pfont = pcis->pfont;
    gs_type1_data *pdata = &pfont->data;
    t1_hinter *h = &pcis->h;
    bool encrypted = pdata->lenIV >= 0;
    fixed cstack[ostack_size];
    cs_ptr csp;
#define clear CLEAR_CSTACK(cstack, csp)
    ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1];
    register const byte *cip;
    register crypt_state state;
    register int c;
    cs_ptr ap;
    bool vertical;
    int code = 0;

/****** FAKE THE REGISTRY ******/
    struct {
        float *values;
        uint size;
    } Registry[1];

    Registry[0].values = pcis->pfont->data.WeightVector.values;

    switch (pcis->init_done) {
        case -1:
            t1_hinter__init(h, pcis->path);
            break;
        case 0:
            gs_type1_finish_init(pcis);	/* sets origin */
            code = t1_hinter__set_mapping(h, &pcis->pis->ctm,
                            &pfont->FontMatrix, &pfont->base->FontMatrix,
                            pcis->scale.x.log2_unit, pcis->scale.x.log2_unit,
                            pcis->scale.x.log2_unit - pcis->log2_subpixels.x,
                            pcis->scale.y.log2_unit - pcis->log2_subpixels.y,
                            pcis->origin.x, pcis->origin.y,
                            gs_currentaligntopixels(pfont->dir));
            if (code < 0)
                return code;
            code = t1_hinter__set_font_data(h, 2, pdata, pcis->no_grid_fitting,
                            pcis->pfont->is_resource);
            if (code < 0)
                return code;
            break;
        default /*case 1 */ :
            break;
    }
    INIT_CSTACK(cstack, csp, pcis);

    if (pgd == 0)
        goto cont;
    ipsp->cs_data = *pgd;
    cip = pgd->bits.data;
    if (cip == 0)
        return (gs_note_error(gs_error_invalidfont));
  call:state = crypt_charstring_seed;
    if (encrypted) {
        int skip = pdata->lenIV;

        /* Skip initial random bytes */
        for (; skip > 0; ++cip, --skip)
            decrypt_skip_next(*cip, state);
    }
    goto top;
  cont:if (ipsp < pcis->ipstack || ipsp->ip == 0)
        return (gs_note_error(gs_error_invalidfont));
    cip = ipsp->ip;
    state = ipsp->dstate;
  top:for (;;) {
        uint c0 = *cip++;

        charstring_next(c0, state, c, encrypted);
        if (c >= c_num1) {
            /* This is a number, decode it and push it on the stack. */

            if (c < c_pos2_0) {	/* 1-byte number */
                decode_push_num1(csp, cstack, c);
            } else if (c < cx_num4) {	/* 2-byte number */
                decode_push_num2(csp, cstack, c, cip, state, encrypted);
            } else if (c == cx_num4) {	/* 4-byte number */
                long lw;

                decode_num4(lw, cip, state, encrypted);
                /* 32-bit numbers are 16:16. */
                CS_CHECK_PUSH(csp, cstack);
                *++csp = arith_rshift(lw, 16 - _fixed_shift);
            } else		/* not possible */
                return_error(gs_error_invalidfont);
          pushed:if_debug3('1', "[1]%d: (%d) %f\n",
                      (int)(csp - cstack), c, fixed2float(*csp));
            continue;
        }
#ifdef DEBUG
        if (gs_debug['1']) {
            static const char *const c2names[] =
            {char2_command_names};

            if (c2names[c] == 0)
                dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
            else
                dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
                          c2names[c]);
        }
#endif
        switch ((char_command) c) {
#define cnext clear; goto top

                /* Commands with identical functions in Type 1 and Type 2, */
                /* except for 'escape'. */

            case c_undef0:
            case c_undef2:
            case c_undef17:
                return_error(gs_error_invalidfont);
            case c_callsubr:
                c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
                code = pdata->procs.subr_data
                    (pfont, c, false, &ipsp[1].cs_data);
              subr:if (code < 0) {
                    /* Calling a Subr with an out-of-range index is clearly a error:
                     * the Adobe documentation says the results of doing this are
                     * undefined. However, we have seen a PDF file produced by Adobe
                     * PDF Library 4.16 that included a Type 2 font that called an
                     * out-of-range Subr, and Acrobat Reader did not signal an error.
                     * Therefore, we ignore such calls.
                     */
                    cip++;
                    goto top;
                }
                --csp;
                ipsp->ip = cip, ipsp->dstate = state;
                ++ipsp;
                cip = ipsp->cs_data.bits.data;
                goto call;
            case c_return:
                gs_glyph_data_free(&ipsp->cs_data, "gs_type2_interpret");
                --ipsp;
                goto cont;
            case c_undoc15:
                /* See gstype1.h for information on this opcode. */
                cnext;

                /* Commands with similar but not identical functions */
                /* in Type 1 and Type 2 charstrings. */

            case cx_hstem:
                goto hstem;
            case cx_vstem:
                goto vstem;
            case cx_vmoveto:
                check_first_operator(csp > cstack);
                code = t1_hinter__rmoveto(h, 0, *csp);
              move:
              cc:
                if (code < 0)
                    return code;
                goto pp;
            case cx_rlineto:
                for (ap = cstack; ap + 1 <= csp; ap += 2) {
                    code = t1_hinter__rlineto(h, ap[0], ap[1]);
                    if (code < 0)
                        return code;
                }
              pp:
                cnext;
            case cx_hlineto:
                vertical = false;
                goto hvl;
            case cx_vlineto:
                vertical = true;
              hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) {
                    if (vertical) {
                        code = t1_hinter__rlineto(h, 0, ap[0]);
                    } else {
                        code = t1_hinter__rlineto(h, ap[0], 0);
                    }
                    if (code < 0)
                        return code;
                }
                goto pp;
            case cx_rrcurveto:
                for (ap = cstack; ap + 5 <= csp; ap += 6) {
                    code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2],
                                            ap[3], ap[4], ap[5]);
                    if (code < 0)
                        return code;
                }
                goto pp;
            case cx_endchar:
                /*
                 * It is a feature of Type 2 CharStrings that if endchar is
                 * invoked with 4 or 5 operands, it is equivalent to the
                 * Type 1 seac operator. In this case, the asb operand of
                 * seac is missing: we assume it is the same as the
                 * l.s.b. of the accented character.  This feature was
                 * undocumented until the 16 March 2000 version of the Type
                 * 2 Charstring Format specification, but, thankfully, is
                 * described in that revision.
                 */
                if (csp >= cstack + 3) {
                    check_first_operator(csp > cstack + 3);
                    code = gs_type1_seac(pcis, cstack, 0, ipsp);
                    if (code < 0)
                        return code;
                    clear;
                    cip = ipsp->cs_data.bits.data;
                    goto call;
                }
                /*
                 * This might be the only operator in the charstring.
                 * In this case, there might be a width on the stack.
                 */
                check_first_operator(csp >= cstack);
                if (pcis->seac_accent < 0) {
                    code = t1_hinter__endglyph(h);
                    if (code < 0)
                        return code;
                    code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path);
                    if (code < 0)
                        return code;
                } else {
                    t1_hinter__setcurrentpoint(h, pcis->save_adxy.x + pcis->origin_offset.x,
                                                  pcis->save_adxy.y + pcis->origin_offset.y);
                    code = t1_hinter__end_subglyph(h);
                    if (code < 0)
                        return code;
                }
                code = gs_type1_endchar(pcis);
                if (code == 1) {
                    /*
                     * Reset the total hint count so that hintmask will
                     * parse its following data correctly.
                     * (gs_type1_endchar already reset the actual hint
                     * tables.)
                     */
                    pcis->num_hints = 0;
                    /* do accent of seac */
                    ipsp = &pcis->ipstack[pcis->ips_count - 1];
                    cip = ipsp->cs_data.bits.data;
                    goto call;
                }
                return code;
            case cx_rmoveto:
                /* See vmoveto above re closing the subpath. */
                check_first_operator(!((csp - cstack) & 1));
                if (csp > cstack + 1) {
                  /* Some Type 2 charstrings omit the vstemhm operator before rmoveto,
                     even though this is only allowed before hintmask and cntrmask.
                     Thanks to Felix Pahl.
                   */
                  type2_vstem(pcis, csp - 2, cstack);
                  cstack [0] = csp [-1];
                  cstack [1] = csp [ 0];
                  csp = cstack + 1;
                }
                code = t1_hinter__rmoveto(h, csp[-1], *csp);
                goto move;
            case cx_hmoveto:
                /* See vmoveto above re closing the subpath. */
                check_first_operator(csp > cstack);
                code = t1_hinter__rmoveto(h, *csp, 0);
                goto move;
            case cx_vhcurveto:
                vertical = true;
                goto hvc;
            case cx_hvcurveto:
                vertical = false;
              hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) {
                    gs_fixed_point pt[2] = {{0, 0}, {0, 0}};
                    if (vertical) {
                        pt[0].y = ap[0];
                        pt[1].x = ap[3];
                        if (ap + 4 == csp)
                            pt[1].y = ap[4];
                    } else {
                        pt[0].x = ap[0];
                        if (ap + 4 == csp)
                            pt[1].x = ap[4];
                        pt[1].y = ap[3];
                    }
                    code = t1_hinter__rcurveto(h, pt[0].x, pt[0].y, ap[1], ap[2], pt[1].x, pt[1].y);
                    if (code < 0)
                        return code;
                }
                goto pp;

                        /***********************
                         * New Type 2 commands *
                         ***********************/

            case c2_blend:
                {
                    int n = fixed2int_var(*csp);
                    int num_values = csp - cstack;
                    gs_font_type1 *pfont = pcis->pfont;
                    int k = pfont->data.WeightVector.count;
                    int i, j;
                    cs_ptr base, deltas;

                    base = csp - 1 - num_values;
                    deltas = base + n - 1;
                    for (j = 0; j < n; j++, base++, deltas += k - 1)
                        for (i = 1; i < k; i++)
                            *base += (fixed)(deltas[i] *
                                pfont->data.WeightVector.values[i]);
                }
                cnext;
            case c2_hstemhm:
              hstem:check_first_operator(!((csp - cstack) & 1));
                {
                    fixed x = 0;

                    for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2) {
                            code = t1_hinter__hstem(h, x += ap[0], ap[1]);
                            if (code < 0)
                                return code;
                    }
                }
                pcis->num_hints += (csp + 1 - cstack) >> 1;
                cnext;
            case c2_hintmask:
                /*
                 * A hintmask at the beginning of the CharString is
                 * equivalent to vstemhm + hintmask.  For simplicity, we use
                 * this interpretation everywhere.
                 */
            case c2_cntrmask:
                check_first_operator(!((csp - cstack) & 1));
                type2_vstem(pcis, csp, cstack);
                /*
                 * We should clear the stack here only if this is the
                 * initial mask operator that includes the implicit
                 * vstemhm, but currently this is too much trouble to
                 * detect.
                 */
                clear;
                {
                    byte mask[max_total_stem_hints / 8];
                    int i;

                    for (i = 0; i < pcis->num_hints; ++cip, i += 8) {
                        charstring_next(*cip, state, mask[i >> 3], encrypted);
                        if_debug1('1', " 0x%02x", mask[i >> 3]);
                    }
                    if_debug0('1', "\n");
                    ipsp->ip = cip;
                    ipsp->dstate = state;
                    if (c == c2_cntrmask) {
                        /****** NYI ******/
                    } else {	/* hintmask or equivalent */
                        if_debug0('1', "[1]hstem hints:\n");
                        if_debug0('1', "[1]vstem hints:\n");
                        code = t1_hinter__hint_mask(h, mask);
                        if (code < 0)
                            return code;
                    }
                }
                break;
            case c2_vstemhm:
              vstem:check_first_operator(!((csp - cstack) & 1));
                type2_vstem(pcis, csp, cstack);
                cnext;
            case c2_rcurveline:
                for (ap = cstack; ap + 5 <= csp; ap += 6) {
                    code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3],
                                            ap[4], ap[5]);
                    if (code < 0)
                        return code;
                }
                code = t1_hinter__rlineto(h, ap[0], ap[1]);
                goto cc;
            case c2_rlinecurve:
                for (ap = cstack; ap + 7 <= csp; ap += 2) {
                    code = t1_hinter__rlineto(h, ap[0], ap[1]);
                    if (code < 0)
                        return code;
                }
                code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3],
                                        ap[4], ap[5]);
                goto cc;
            case c2_vvcurveto:
                ap = cstack;
                {
                    int n = csp + 1 - cstack;
                    fixed dxa = (n & 1 ? *ap++ : 0);

                    for (; ap + 3 <= csp; ap += 4) {
                        code = t1_hinter__rcurveto(h, dxa, ap[0], ap[1], ap[2],
                                                fixed_0, ap[3]);
                        if (code < 0)
                            return code;
                        dxa = 0;
                    }
                }
                goto pp;
            case c2_hhcurveto:
                ap = cstack;
                {
                    int n = csp + 1 - cstack;
                    fixed dya = (n & 1 ? *ap++ : 0);

                    for (; ap + 3 <= csp; ap += 4) {
                        code = t1_hinter__rcurveto(h, ap[0], dya, ap[1], ap[2],
                                                ap[3], fixed_0);
                        if (code < 0)
                            return code;
                        dya = 0;
                    }
                }
                goto pp;
            case c2_shortint:
                {
                    int c1, c2;

                    charstring_next(*cip, state, c1, encrypted);
                    ++cip;
                    charstring_next(*cip, state, c2, encrypted);
                    ++cip;
                    CS_CHECK_PUSH(csp, cstack);
                    *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2);
                }
                goto pushed;
            case c2_callgsubr:
                c = fixed2int_var(*csp) + pdata->gsubrNumberBias;
                code = pdata->procs.subr_data
                    (pfont, c, true, &ipsp[1].cs_data);
                goto subr;
            case cx_escape:
                charstring_next(*cip, state, c, encrypted);
                ++cip;
#ifdef DEBUG
                if (gs_debug['1'] && c < char2_extended_command_count) {
                    static const char *const ce2names[] =
                    {char2_extended_command_names};

                    if (ce2names[c] == 0)
                        dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c);
                    else
                        dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c,
                                  ce2names[c]);
                }
#endif
                switch ((char2_extended_command) c) {
                    case ce2_and:
                        csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0);
                        --csp;
                        break;
                    case ce2_or:
                        csp[-1] = (csp[-1] | *csp ? fixed_1 : 0);
                        --csp;
                        break;
                    case ce2_not:
                        *csp = (*csp ? 0 : fixed_1);
                        break;
                    case ce2_store:
                        {
                            int i, n = fixed2int_var(*csp);
                            float *to = Registry[fixed2int_var(csp[-3])].values +
                            fixed2int_var(csp[-2]);
                            const fixed *from =
                            pcis->transient_array + fixed2int_var(csp[-1]);

                            for (i = 0; i < n; ++i)
                                to[i] = fixed2float(from[i]);
                        }
                        csp -= 4;
                        break;
                    case ce2_abs:
                        if (*csp < 0)
                            *csp = -*csp;
                        break;
                    case ce2_add:
                        csp[-1] += *csp;
                        --csp;
                        break;
                    case ce2_sub:
                        csp[-1] -= *csp;
                        --csp;
                        break;
                    case ce2_div:
                        csp[-1] = float2fixed((double)csp[-1] / *csp);
                        --csp;
                        break;
                    case ce2_load:
                        /* The specification says there is no j (starting index */
                        /* in registry array) argument.... */
                        {
                            int i, n = fixed2int_var(*csp);
                            const float *from = Registry[fixed2int_var(csp[-2])].values;
                            fixed *to =
                            pcis->transient_array + fixed2int_var(csp[-1]);

                            for (i = 0; i < n; ++i)
                                to[i] = float2fixed(from[i]);
                        }
                        csp -= 3;
                        break;
                    case ce2_neg:
                        *csp = -*csp;
                        break;
                    case ce2_eq:
                        csp[-1] = (csp[-1] == *csp ? fixed_1 : 0);
                        --csp;
                        break;
                    case ce2_drop:
                        --csp;
                        break;
                    case ce2_put:
                        pcis->transient_array[fixed2int_var(*csp)] = csp[-1];
                        csp -= 2;
                        break;
                    case ce2_get:
                        *csp = pcis->transient_array[fixed2int_var(*csp)];
                        break;
                    case ce2_ifelse:
                        if (csp[-1] > *csp)
                            csp[-3] = csp[-2];
                        csp -= 3;
                        break;
                    case ce2_random:
                        CS_CHECK_PUSH(csp, cstack);
                        ++csp;
                        /****** NYI ******/
                        break;
                    case ce2_mul:
                        {
                            double prod = fixed2float(csp[-1]) * *csp;

                            csp[-1] =
                                (prod > max_fixed ? max_fixed :
                                 prod < min_fixed ? min_fixed : (fixed)prod);
                        }
                        --csp;
                        break;
                    case ce2_sqrt:
                        if (*csp >= 0)
                            *csp = float2fixed(sqrt(fixed2float(*csp)));
                        break;
                    case ce2_dup:
                        CS_CHECK_PUSH(csp, cstack);
                        csp[1] = *csp;
                        ++csp;
                        break;
                    case ce2_exch:
                        {
                            fixed top = *csp;

                            *csp = csp[-1], csp[-1] = top;
                        }
                        break;
                    case ce2_index:
                        *csp =
                            (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]);
                        break;
                    case ce2_roll:
                        {
                            int distance = fixed2int_var(*csp);
                            int count = fixed2int_var(csp[-1]);
                            cs_ptr bot;

                            csp -= 2;
                            if (count < 0 || count > csp + 1 - cstack)
                                return_error(gs_error_invalidfont);
                            if (count == 0)
                                break;
                            if (distance < 0)
                                distance = count - (-distance % count);
                            bot = csp + 1 - count;
                            while (--distance >= 0) {
                                fixed top = *csp;

                                memmove(bot + 1, bot,
                                        (count - 1) * sizeof(fixed));
                                *bot = top;
                            }
                        }
                        break;
                    case ce2_hflex:
                        csp[6] = fixed_half;	/* fd/100 */
                        csp[4] = *csp, csp[5] = 0;	/* dx6, dy6 */
                        csp[2] = csp[-1], csp[3] = -csp[-4];	/* dx5, dy5 */
                        *csp = csp[-2], csp[1] = 0;	/* dx4, dy4 */
                        csp[-2] = csp[-3], csp[-1] = 0;		/* dx3, dy3 */
                        csp[-3] = csp[-4], csp[-4] = csp[-5];	/* dx2, dy2 */
                        csp[-5] = 0;	/* dy1 */
                        csp += 6;
                        goto flex;
                    case ce2_flex:
                        *csp /= 100;	/* fd/100 */
flex:			{
                            fixed x_join = csp[-12] + csp[-10] + csp[-8];
                            fixed y_join = csp[-11] + csp[-9] + csp[-7];
                            fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2];
                            fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1];
                            gs_point join, end;
                            double flex_depth;

                            if ((code =
                                 gs_distance_transform(fixed2float(x_join),
                                                       fixed2float(y_join),
                                                       &ctm_only(pcis->pis),
                                                       &join)) < 0 ||
                                (code =
                                 gs_distance_transform(fixed2float(x_end),
                                                       fixed2float(y_end),
                                                       &ctm_only(pcis->pis),
                                                       &end)) < 0
                                )
                                return code;
                            /*
                             * Use the X or Y distance depending on whether
                             * the curve is more horizontal or more
                             * vertical.
                             */
                            if (any_abs(end.y) > any_abs(end.x))
                                flex_depth = join.x;
                            else
                                flex_depth = join.y;
                            if (fabs(flex_depth) < fixed2float(*csp)) {
                                /* Do flex as line. */
                                code = t1_hinter__rlineto(h, x_end, y_end);
                            } else {
                                /*
                                 * Do flex as curve.  We can't jump to rrc,
                                 * because the flex operators don't clear
                                 * the stack (!).
                                 */
                                code = t1_hinter__rcurveto(h,
                                        csp[-12], csp[-11], csp[-10],
                                        csp[-9], csp[-8], csp[-7]);
                                if (code < 0)
                                    return code;
                                code = t1_hinter__rcurveto(h,
                                        csp[-6], csp[-5], csp[-4],
                                        csp[-3], csp[-2], csp[-1]);
                            }
                            if (code < 0)
                                return code;
                            csp -= 13;
                        }
                        cnext;
                    case ce2_hflex1:
                        csp[4] = fixed_half;	/* fd/100 */
                        csp[2] = *csp;          /* dx6 */
                        csp[3] = -(csp[-7] + csp[-5] + csp[-1]);	/* dy6 */
                        *csp = csp[-2], csp[1] = csp[-1];	/* dx5, dy5 */
                        csp[-2] = csp[-3], csp[-1] = 0;		/* dx4, dy4 */
                        csp[-3] = 0;	/* dy3 */
                        csp += 4;
                        goto flex;
                    case ce2_flex1:
                        {
                            fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2];
                            fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1];

                            if (any_abs(dx) > any_abs(dy))
                                csp[1] = -dy;	/* d6 is dx6 */
                            else
                                csp[1] = *csp, *csp = -dx;	/* d6 is dy6 */
                        }
                        csp[2] = fixed_half;	/* fd/100 */
                        csp += 2;
                        goto flex;
                }
                break;

                /* Fill up the dispatch up to 32. */

              case_c2_undefs:
            default:		/* pacify compiler */
                return_error(gs_error_invalidfont);
        }
    }
}