blob: a7c45dd680b4021c5b7d7f776316500f4846d82d [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#ifdef UNIX
#ifndef HAVE_POSIX_TERMIOS
#include <sys/ioctl.h>
#include <termio.h>
#else
#ifndef HAVE_TCGETATTR
#define HAVE_TCGETATTR
#endif /* HAVE_TCGETATTR */
#ifndef HAVE_TCSETATTR
#define HAVE_TCSETATTR
#endif /* HAVE_TCSETATTR */
#include <termios.h>
#endif /* HAVE_POSIX_TERMIOS */
#endif
/* Define the `getch()' function. On Unix systems, it is an alias */
/* for `getchar()', and the debugger front end must ensure that the */
/* `stdin' file descriptor is not in line-by-line input mode. */
#ifndef UNIX
#include <conio.h>
#else
#define getch getchar
#endif
#include <freetype/freetype.h>
#include "ttobjs.h"
#include "ttdriver.h"
#include "ttinterp.h"
FT_Library library; /* root library object */
FT_Memory memory; /* system object */
FT_Driver driver; /* truetype driver */
TT_Face face; /* truetype face */
TT_Size size; /* truetype size */
TT_GlyphSlot glyph; /* truetype glyph slot */
TT_ExecContext exec; /* truetype execution context */
TT_Error error;
TT_CodeRange_Tag debug_coderange = tt_coderange_glyph;
typedef FT_Byte ByteStr[2];
typedef FT_Byte WordStr[4];
typedef FT_Byte LongStr[8];
typedef FT_Byte DebugStr[128];
static DebugStr tempStr;
#undef PACK
#define PACK( x, y ) ((x << 4) | y)
static const TT_Byte Pop_Push_Count[256] =
{
/* opcodes are gathered in groups of 16 */
/* please keep the spaces as they are */
/* SVTCA y */ PACK( 0, 0 ),
/* SVTCA x */ PACK( 0, 0 ),
/* SPvTCA y */ PACK( 0, 0 ),
/* SPvTCA x */ PACK( 0, 0 ),
/* SFvTCA y */ PACK( 0, 0 ),
/* SFvTCA x */ PACK( 0, 0 ),
/* SPvTL // */ PACK( 2, 0 ),
/* SPvTL + */ PACK( 2, 0 ),
/* SFvTL // */ PACK( 2, 0 ),
/* SFvTL + */ PACK( 2, 0 ),
/* SPvFS */ PACK( 2, 0 ),
/* SFvFS */ PACK( 2, 0 ),
/* GPV */ PACK( 0, 2 ),
/* GFV */ PACK( 0, 2 ),
/* SFvTPv */ PACK( 0, 0 ),
/* ISECT */ PACK( 5, 0 ),
/* SRP0 */ PACK( 1, 0 ),
/* SRP1 */ PACK( 1, 0 ),
/* SRP2 */ PACK( 1, 0 ),
/* SZP0 */ PACK( 1, 0 ),
/* SZP1 */ PACK( 1, 0 ),
/* SZP2 */ PACK( 1, 0 ),
/* SZPS */ PACK( 1, 0 ),
/* SLOOP */ PACK( 1, 0 ),
/* RTG */ PACK( 0, 0 ),
/* RTHG */ PACK( 0, 0 ),
/* SMD */ PACK( 1, 0 ),
/* ELSE */ PACK( 0, 0 ),
/* JMPR */ PACK( 1, 0 ),
/* SCvTCi */ PACK( 1, 0 ),
/* SSwCi */ PACK( 1, 0 ),
/* SSW */ PACK( 1, 0 ),
/* DUP */ PACK( 1, 2 ),
/* POP */ PACK( 1, 0 ),
/* CLEAR */ PACK( 0, 0 ),
/* SWAP */ PACK( 2, 2 ),
/* DEPTH */ PACK( 0, 1 ),
/* CINDEX */ PACK( 1, 1 ),
/* MINDEX */ PACK( 1, 0 ),
/* AlignPTS */ PACK( 2, 0 ),
/* INS_$28 */ PACK( 0, 0 ),
/* UTP */ PACK( 1, 0 ),
/* LOOPCALL */ PACK( 2, 0 ),
/* CALL */ PACK( 1, 0 ),
/* FDEF */ PACK( 1, 0 ),
/* ENDF */ PACK( 0, 0 ),
/* MDAP[0] */ PACK( 1, 0 ),
/* MDAP[1] */ PACK( 1, 0 ),
/* IUP[0] */ PACK( 0, 0 ),
/* IUP[1] */ PACK( 0, 0 ),
/* SHP[0] */ PACK( 0, 0 ),
/* SHP[1] */ PACK( 0, 0 ),
/* SHC[0] */ PACK( 1, 0 ),
/* SHC[1] */ PACK( 1, 0 ),
/* SHZ[0] */ PACK( 1, 0 ),
/* SHZ[1] */ PACK( 1, 0 ),
/* SHPIX */ PACK( 1, 0 ),
/* IP */ PACK( 0, 0 ),
/* MSIRP[0] */ PACK( 2, 0 ),
/* MSIRP[1] */ PACK( 2, 0 ),
/* AlignRP */ PACK( 0, 0 ),
/* RTDG */ PACK( 0, 0 ),
/* MIAP[0] */ PACK( 2, 0 ),
/* MIAP[1] */ PACK( 2, 0 ),
/* NPushB */ PACK( 0, 0 ),
/* NPushW */ PACK( 0, 0 ),
/* WS */ PACK( 2, 0 ),
/* RS */ PACK( 1, 1 ),
/* WCvtP */ PACK( 2, 0 ),
/* RCvt */ PACK( 1, 1 ),
/* GC[0] */ PACK( 1, 1 ),
/* GC[1] */ PACK( 1, 1 ),
/* SCFS */ PACK( 2, 0 ),
/* MD[0] */ PACK( 2, 1 ),
/* MD[1] */ PACK( 2, 1 ),
/* MPPEM */ PACK( 0, 1 ),
/* MPS */ PACK( 0, 1 ),
/* FlipON */ PACK( 0, 0 ),
/* FlipOFF */ PACK( 0, 0 ),
/* DEBUG */ PACK( 1, 0 ),
/* LT */ PACK( 2, 1 ),
/* LTEQ */ PACK( 2, 1 ),
/* GT */ PACK( 2, 1 ),
/* GTEQ */ PACK( 2, 1 ),
/* EQ */ PACK( 2, 1 ),
/* NEQ */ PACK( 2, 1 ),
/* ODD */ PACK( 1, 1 ),
/* EVEN */ PACK( 1, 1 ),
/* IF */ PACK( 1, 0 ),
/* EIF */ PACK( 0, 0 ),
/* AND */ PACK( 2, 1 ),
/* OR */ PACK( 2, 1 ),
/* NOT */ PACK( 1, 1 ),
/* DeltaP1 */ PACK( 1, 0 ),
/* SDB */ PACK( 1, 0 ),
/* SDS */ PACK( 1, 0 ),
/* ADD */ PACK( 2, 1 ),
/* SUB */ PACK( 2, 1 ),
/* DIV */ PACK( 2, 1 ),
/* MUL */ PACK( 2, 1 ),
/* ABS */ PACK( 1, 1 ),
/* NEG */ PACK( 1, 1 ),
/* FLOOR */ PACK( 1, 1 ),
/* CEILING */ PACK( 1, 1 ),
/* ROUND[0] */ PACK( 1, 1 ),
/* ROUND[1] */ PACK( 1, 1 ),
/* ROUND[2] */ PACK( 1, 1 ),
/* ROUND[3] */ PACK( 1, 1 ),
/* NROUND[0] */ PACK( 1, 1 ),
/* NROUND[1] */ PACK( 1, 1 ),
/* NROUND[2] */ PACK( 1, 1 ),
/* NROUND[3] */ PACK( 1, 1 ),
/* WCvtF */ PACK( 2, 0 ),
/* DeltaP2 */ PACK( 1, 0 ),
/* DeltaP3 */ PACK( 1, 0 ),
/* DeltaCn[0] */ PACK( 1, 0 ),
/* DeltaCn[1] */ PACK( 1, 0 ),
/* DeltaCn[2] */ PACK( 1, 0 ),
/* SROUND */ PACK( 1, 0 ),
/* S45Round */ PACK( 1, 0 ),
/* JROT */ PACK( 2, 0 ),
/* JROF */ PACK( 2, 0 ),
/* ROFF */ PACK( 0, 0 ),
/* INS_$7B */ PACK( 0, 0 ),
/* RUTG */ PACK( 0, 0 ),
/* RDTG */ PACK( 0, 0 ),
/* SANGW */ PACK( 1, 0 ),
/* AA */ PACK( 1, 0 ),
/* FlipPT */ PACK( 0, 0 ),
/* FlipRgON */ PACK( 2, 0 ),
/* FlipRgOFF */ PACK( 2, 0 ),
/* INS_$83 */ PACK( 0, 0 ),
/* INS_$84 */ PACK( 0, 0 ),
/* ScanCTRL */ PACK( 1, 0 ),
/* SDVPTL[0] */ PACK( 2, 0 ),
/* SDVPTL[1] */ PACK( 2, 0 ),
/* GetINFO */ PACK( 1, 1 ),
/* IDEF */ PACK( 1, 0 ),
/* ROLL */ PACK( 3, 3 ),
/* MAX */ PACK( 2, 1 ),
/* MIN */ PACK( 2, 1 ),
/* ScanTYPE */ PACK( 1, 0 ),
/* InstCTRL */ PACK( 2, 0 ),
/* INS_$8F */ PACK( 0, 0 ),
/* INS_$90 */ PACK( 0, 0 ),
/* INS_$91 */ PACK( 0, 0 ),
/* INS_$92 */ PACK( 0, 0 ),
/* INS_$93 */ PACK( 0, 0 ),
/* INS_$94 */ PACK( 0, 0 ),
/* INS_$95 */ PACK( 0, 0 ),
/* INS_$96 */ PACK( 0, 0 ),
/* INS_$97 */ PACK( 0, 0 ),
/* INS_$98 */ PACK( 0, 0 ),
/* INS_$99 */ PACK( 0, 0 ),
/* INS_$9A */ PACK( 0, 0 ),
/* INS_$9B */ PACK( 0, 0 ),
/* INS_$9C */ PACK( 0, 0 ),
/* INS_$9D */ PACK( 0, 0 ),
/* INS_$9E */ PACK( 0, 0 ),
/* INS_$9F */ PACK( 0, 0 ),
/* INS_$A0 */ PACK( 0, 0 ),
/* INS_$A1 */ PACK( 0, 0 ),
/* INS_$A2 */ PACK( 0, 0 ),
/* INS_$A3 */ PACK( 0, 0 ),
/* INS_$A4 */ PACK( 0, 0 ),
/* INS_$A5 */ PACK( 0, 0 ),
/* INS_$A6 */ PACK( 0, 0 ),
/* INS_$A7 */ PACK( 0, 0 ),
/* INS_$A8 */ PACK( 0, 0 ),
/* INS_$A9 */ PACK( 0, 0 ),
/* INS_$AA */ PACK( 0, 0 ),
/* INS_$AB */ PACK( 0, 0 ),
/* INS_$AC */ PACK( 0, 0 ),
/* INS_$AD */ PACK( 0, 0 ),
/* INS_$AE */ PACK( 0, 0 ),
/* INS_$AF */ PACK( 0, 0 ),
/* PushB[0] */ PACK( 0, 1 ),
/* PushB[1] */ PACK( 0, 2 ),
/* PushB[2] */ PACK( 0, 3 ),
/* PushB[3] */ PACK( 0, 4 ),
/* PushB[4] */ PACK( 0, 5 ),
/* PushB[5] */ PACK( 0, 6 ),
/* PushB[6] */ PACK( 0, 7 ),
/* PushB[7] */ PACK( 0, 8 ),
/* PushW[0] */ PACK( 0, 1 ),
/* PushW[1] */ PACK( 0, 2 ),
/* PushW[2] */ PACK( 0, 3 ),
/* PushW[3] */ PACK( 0, 4 ),
/* PushW[4] */ PACK( 0, 5 ),
/* PushW[5] */ PACK( 0, 6 ),
/* PushW[6] */ PACK( 0, 7 ),
/* PushW[7] */ PACK( 0, 8 ),
/* MDRP[00] */ PACK( 1, 0 ),
/* MDRP[01] */ PACK( 1, 0 ),
/* MDRP[02] */ PACK( 1, 0 ),
/* MDRP[03] */ PACK( 1, 0 ),
/* MDRP[04] */ PACK( 1, 0 ),
/* MDRP[05] */ PACK( 1, 0 ),
/* MDRP[06] */ PACK( 1, 0 ),
/* MDRP[07] */ PACK( 1, 0 ),
/* MDRP[08] */ PACK( 1, 0 ),
/* MDRP[09] */ PACK( 1, 0 ),
/* MDRP[10] */ PACK( 1, 0 ),
/* MDRP[11] */ PACK( 1, 0 ),
/* MDRP[12] */ PACK( 1, 0 ),
/* MDRP[13] */ PACK( 1, 0 ),
/* MDRP[14] */ PACK( 1, 0 ),
/* MDRP[15] */ PACK( 1, 0 ),
/* MDRP[16] */ PACK( 1, 0 ),
/* MDRP[17] */ PACK( 1, 0 ),
/* MDRP[18] */ PACK( 1, 0 ),
/* MDRP[19] */ PACK( 1, 0 ),
/* MDRP[20] */ PACK( 1, 0 ),
/* MDRP[21] */ PACK( 1, 0 ),
/* MDRP[22] */ PACK( 1, 0 ),
/* MDRP[23] */ PACK( 1, 0 ),
/* MDRP[24] */ PACK( 1, 0 ),
/* MDRP[25] */ PACK( 1, 0 ),
/* MDRP[26] */ PACK( 1, 0 ),
/* MDRP[27] */ PACK( 1, 0 ),
/* MDRP[28] */ PACK( 1, 0 ),
/* MDRP[29] */ PACK( 1, 0 ),
/* MDRP[30] */ PACK( 1, 0 ),
/* MDRP[31] */ PACK( 1, 0 ),
/* MIRP[00] */ PACK( 2, 0 ),
/* MIRP[01] */ PACK( 2, 0 ),
/* MIRP[02] */ PACK( 2, 0 ),
/* MIRP[03] */ PACK( 2, 0 ),
/* MIRP[04] */ PACK( 2, 0 ),
/* MIRP[05] */ PACK( 2, 0 ),
/* MIRP[06] */ PACK( 2, 0 ),
/* MIRP[07] */ PACK( 2, 0 ),
/* MIRP[08] */ PACK( 2, 0 ),
/* MIRP[09] */ PACK( 2, 0 ),
/* MIRP[10] */ PACK( 2, 0 ),
/* MIRP[11] */ PACK( 2, 0 ),
/* MIRP[12] */ PACK( 2, 0 ),
/* MIRP[13] */ PACK( 2, 0 ),
/* MIRP[14] */ PACK( 2, 0 ),
/* MIRP[15] */ PACK( 2, 0 ),
/* MIRP[16] */ PACK( 2, 0 ),
/* MIRP[17] */ PACK( 2, 0 ),
/* MIRP[18] */ PACK( 2, 0 ),
/* MIRP[19] */ PACK( 2, 0 ),
/* MIRP[20] */ PACK( 2, 0 ),
/* MIRP[21] */ PACK( 2, 0 ),
/* MIRP[22] */ PACK( 2, 0 ),
/* MIRP[23] */ PACK( 2, 0 ),
/* MIRP[24] */ PACK( 2, 0 ),
/* MIRP[25] */ PACK( 2, 0 ),
/* MIRP[26] */ PACK( 2, 0 ),
/* MIRP[27] */ PACK( 2, 0 ),
/* MIRP[28] */ PACK( 2, 0 ),
/* MIRP[29] */ PACK( 2, 0 ),
/* MIRP[30] */ PACK( 2, 0 ),
/* MIRP[31] */ PACK( 2, 0 )
};
static const FT_String* OpStr[256] = {
"SVTCA y", /* Set vectors to coordinate axis y */
"SVTCA x", /* Set vectors to coordinate axis x */
"SPvTCA y", /* Set Proj. vec. to coord. axis y */
"SPvTCA x", /* Set Proj. vec. to coord. axis x */
"SFvTCA y", /* Set Free. vec. to coord. axis y */
"SFvTCA x", /* Set Free. vec. to coord. axis x */
"SPvTL //", /* Set Proj. vec. parallel to segment */
"SPvTL +", /* Set Proj. vec. normal to segment */
"SFvTL //", /* Set Free. vec. parallel to segment */
"SFvTL +", /* Set Free. vec. normal to segment */
"SPvFS", /* Set Proj. vec. from stack */
"SFvFS", /* Set Free. vec. from stack */
"GPV", /* Get projection vector */
"GFV", /* Get freedom vector */
"SFvTPv", /* Set free. vec. to proj. vec. */
"ISECT", /* compute intersection */
"SRP0", /* Set reference point 0 */
"SRP1", /* Set reference point 1 */
"SRP2", /* Set reference point 2 */
"SZP0", /* Set Zone Pointer 0 */
"SZP1", /* Set Zone Pointer 1 */
"SZP2", /* Set Zone Pointer 2 */
"SZPS", /* Set all zone pointers */
"SLOOP", /* Set loop counter */
"RTG", /* Round to Grid */
"RTHG", /* Round to Half-Grid */
"SMD", /* Set Minimum Distance */
"ELSE", /* Else */
"JMPR", /* Jump Relative */
"SCvTCi", /* Set CVT */
"SSwCi", /* */
"SSW", /* */
"DUP",
"POP",
"CLEAR",
"SWAP",
"DEPTH",
"CINDEX",
"MINDEX",
"AlignPTS",
"INS_$28",
"UTP",
"LOOPCALL",
"CALL",
"FDEF",
"ENDF",
"MDAP[-]",
"MDAP[r]",
"IUP[y]",
"IUP[x]",
"SHP[0]",
"SHP[1]",
"SHC[0]",
"SHC[1]",
"SHZ[0]",
"SHZ[1]",
"SHPIX",
"IP",
"MSIRP[0]",
"MSIRP[1]",
"AlignRP",
"RTDG",
"MIAP[-]",
"MIAP[r]",
"NPushB",
"NPushW",
"WS",
"RS",
"WCvtP",
"RCvt",
"GC[0]",
"GC[1]",
"SCFS",
"MD[0]",
"MD[1]",
"MPPEM",
"MPS",
"FlipON",
"FlipOFF",
"DEBUG",
"LT",
"LTEQ",
"GT",
"GTEQ",
"EQ",
"NEQ",
"ODD",
"EVEN",
"IF",
"EIF",
"AND",
"OR",
"NOT",
"DeltaP1",
"SDB",
"SDS",
"ADD",
"SUB",
"DIV",
"MUL",
"ABS",
"NEG",
"FLOOR",
"CEILING",
"ROUND[G]",
"ROUND[B]",
"ROUND[W]",
"ROUND[?]",
"NROUND[G]",
"NROUND[B]",
"NROUND[W]",
"NROUND[?]",
"WCvtF",
"DeltaP2",
"DeltaP3",
"DeltaC1",
"DeltaC2",
"DeltaC3",
"SROUND",
"S45Round",
"JROT",
"JROF",
"ROFF",
"INS_$7B",
"RUTG",
"RDTG",
"SANGW",
"AA",
"FlipPT",
"FlipRgON",
"FlipRgOFF",
"INS_$83",
"INS_$84",
"ScanCTRL",
"SDPVTL[0]",
"SDPVTL[1]",
"GetINFO",
"IDEF",
"ROLL",
"MAX",
"MIN",
"ScanTYPE",
"IntCTRL",
"INS_$8F",
"INS_$90",
"INS_$91",
"INS_$92",
"INS_$93",
"INS_$94",
"INS_$95",
"INS_$96",
"INS_$97",
"INS_$98",
"INS_$99",
"INS_$9A",
"INS_$9B",
"INS_$9C",
"INS_$9D",
"INS_$9E",
"INS_$9F",
"INS_$A0",
"INS_$A1",
"INS_$A2",
"INS_$A3",
"INS_$A4",
"INS_$A5",
"INS_$A6",
"INS_$A7",
"INS_$A8",
"INS_$A9",
"INS_$AA",
"INS_$AB",
"INS_$AC",
"INS_$AD",
"INS_$AE",
"INS_$AF",
"PushB[0]",
"PushB[1]",
"PushB[2]",
"PushB[3]",
"PushB[4]",
"PushB[5]",
"PushB[6]",
"PushB[7]",
"PushW[0]",
"PushW[1]",
"PushW[2]",
"PushW[3]",
"PushW[4]",
"PushW[5]",
"PushW[6]",
"PushW[7]",
"MDRP[G]",
"MDRP[B]",
"MDRP[W]",
"MDRP[?]",
"MDRP[rG]",
"MDRP[rB]",
"MDRP[rW]",
"MDRP[r?]",
"MDRP[mG]",
"MDRP[mB]",
"MDRP[mW]",
"MDRP[m?]",
"MDRP[mrG]",
"MDRP[mrB]",
"MDRP[mrW]",
"MDRP[mr?]",
"MDRP[pG]",
"MDRP[pB]",
"MDRP[pW]",
"MDRP[p?]",
"MDRP[prG]",
"MDRP[prB]",
"MDRP[prW]",
"MDRP[pr?]",
"MDRP[pmG]",
"MDRP[pmB]",
"MDRP[pmW]",
"MDRP[pm?]",
"MDRP[pmrG]",
"MDRP[pmrB]",
"MDRP[pmrW]",
"MDRP[pmr?]",
"MIRP[G]",
"MIRP[B]",
"MIRP[W]",
"MIRP[?]",
"MIRP[rG]",
"MIRP[rB]",
"MIRP[rW]",
"MIRP[r?]",
"MIRP[mG]",
"MIRP[mB]",
"MIRP[mW]",
"MIRP[m?]",
"MIRP[mrG]",
"MIRP[mrB]",
"MIRP[mrW]",
"MIRP[mr?]",
"MIRP[pG]",
"MIRP[pB]",
"MIRP[pW]",
"MIRP[p?]",
"MIRP[prG]",
"MIRP[prB]",
"MIRP[prW]",
"MIRP[pr?]",
"MIRP[pmG]",
"MIRP[pmB]",
"MIRP[pmW]",
"MIRP[pm?]",
"MIRP[pmrG]",
"MIRP[pmrB]",
"MIRP[pmrW]",
"MIRP[pmr?]"
};
/*********************************************************************
*
* Init_Keyboard : set the input file descriptor to char-by-char
* mode on Unix..
*
*********************************************************************/
#ifdef UNIX
struct termios old_termio;
static
void Init_Keyboard( void )
{
struct termios termio;
#ifndef HAVE_TCGETATTR
ioctl( 0, TCGETS, &old_termio );
#else
tcgetattr( 0, &old_termio );
#endif
termio = old_termio;
/* termio.c_lflag &= ~(ICANON+ECHO+ECHOE+ECHOK+ECHONL+ECHOKE); */
termio.c_lflag &= ~(ICANON+ECHO+ECHOE+ECHOK+ECHONL);
#ifndef HAVE_TCSETATTR
ioctl( 0, TCSETS, &termio );
#else
tcsetattr( 0, TCSANOW, &termio );
#endif
}
static
void Reset_Keyboard( void )
{
#ifndef HAVE_TCSETATTR
ioctl( 0, TCSETS, &old_termio );
#else
tcsetattr( 0, TCSANOW, &old_termio );
#endif
}
#else
static
void Init_Keyboard( void )
{
}
static
void Reset_Keyboard( void )
{
}
#endif
void Panic( const char* message )
{
fprintf( stderr, "%s\n error code = 0x%04x\n", message, error );
Reset_Keyboard();
exit(1);
}
/******************************************************************
*
* Function : Calc_Length
*
* Description : Computes the length in bytes of current opcode.
*
*****************************************************************/
#define CUR (*exc)
static void Calc_Length( TT_ExecContext exc )
{
CUR.opcode = CUR.code[CUR.IP];
switch ( CUR.opcode )
{
case 0x40:
if ( CUR.IP + 1 >= CUR.codeSize )
Panic( "code range overflow !!" );
CUR.length = CUR.code[CUR.IP + 1] + 2;
break;
case 0x41:
if ( CUR.IP + 1 >= CUR.codeSize )
Panic( "code range overflow !!" );
CUR.length = CUR.code[CUR.IP + 1] * 2 + 2;
break;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
CUR.length = CUR.opcode - 0xB0 + 2;
break;
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF:
CUR.length = (CUR.opcode - 0xB8) * 2 + 3;
break;
default:
CUR.length = 1;
break;
}
/* make sure result is in range */
if ( CUR.IP + CUR.length > CUR.codeSize )
Panic( "code range overflow !!" );
}
/* Disassemble the current line */
/* */
const FT_String* Cur_U_Line( TT_ExecContext exec )
{
FT_String s[32];
FT_Int op, i, n;
op = exec->code[ exec->IP ];
sprintf( tempStr, "%04lx: %02hx %s", exec->IP, op, OpStr[op] );
if ( op == 0x40 )
{
n = exec->code[ exec->IP+1 ];
sprintf( s, "(%d)", n );
strncat( tempStr, s, 8 );
if ( n > 20 ) n = 20; /* limit output */
for ( i = 0; i < n; i++ )
{
sprintf( s, " $%02hx", exec->code[ exec->IP+i+2 ] );
strncat( tempStr, s, 8 );
}
}
else if ( op == 0x41 )
{
n = exec->code[ exec->IP+1 ];
sprintf( s, "(%d)", n );
strncat( tempStr, s, 8 );
if (n > 20) n = 20; /* limit output */
for ( i = 0; i < n; i++ )
{
sprintf( s, " $%02hx%02hx", exec->code[ exec->IP+i*2+2 ],
exec->code[ exec->IP+i*2+3 ] );
strncat( tempStr, s, 8 );
}
}
else if ( (op & 0xF8) == 0xB0 )
{
n = op-0xB0;
for ( i=0; i <= n; i++ )
{
sprintf( s, " $%02hx", exec->code[ exec->IP+i+1 ] );
strncat( tempStr, s, 8 );
}
}
else if ( (op & 0xF8) == 0xB8 )
{
n = op-0xB8;
for ( i = 0; i <= n; i++ )
{
sprintf( s, " $%02hx%02hx", exec->code[ exec->IP+i*2+1 ],
exec->code[ exec->IP+i*2+2 ] );
strncat( tempStr, s, 8 );
}
}
return (FT_String*)tempStr;
}
static
TT_Error RunIns( TT_ExecContext exc )
{
FT_Int A, diff, key;
FT_Long next_IP;
FT_Char ch, oldch = '\0', *temp;
TT_Error error = 0;
FT_GlyphZone save;
FT_GlyphZone pts;
const FT_String* round_str[8] =
{
"to half-grid",
"to grid",
"to double grid",
"down to grid",
"up to grid",
"off",
"super",
"super 45"
};
/* only debug the requested code range */
if (exc->curRange != (TT_Int)debug_coderange)
return TT_RunIns(exc);
exc->pts.n_points = exc->zp0.n_points;
exc->pts.n_contours = exc->zp0.n_contours;
pts = exc->pts;
save.n_points = pts.n_points;
save.n_contours = pts.n_contours;
save.org = (TT_Vector*)malloc( 2 * sizeof( TT_F26Dot6 ) *
save.n_points );
save.cur = (TT_Vector*)malloc( 2 * sizeof( TT_F26Dot6 ) *
save.n_points );
save.tags = (TT_Byte*)malloc( save.n_points );
exc->instruction_trap = 1;
do
{
if ( CUR.IP < CUR.codeSize )
{
Calc_Length( exc );
CUR.args = CUR.top - (Pop_Push_Count[CUR.opcode] >> 4);
/* `args' is the top of the stack once arguments have been popped. */
/* One can also interpret it as the index of the last argument. */
/* Print the current line. We use a 80-columns console with the */
/* following formatting: */
/* */
/* [loc]:[addr] [opcode] [disassemby] [a][b]|[c][d] */
/* */
{
char temp[80];
int n, col, pop;
int args = CUR.args;
sprintf( temp, "%78c\n", ' ' );
/* first letter of location */
switch ( CUR.curRange )
{
case tt_coderange_glyph:
temp[0] = 'g';
break;
case tt_coderange_cvt:
temp[0] = 'c';
break;
default:
temp[0] = 'f';
}
/* current IP */
sprintf( temp+1, "%04lx: %02x %-36.36s",
CUR.IP,
CUR.opcode,
Cur_U_Line(&CUR) );
strncpy( temp+46, " (", 2 );
args = CUR.top - 1;
pop = Pop_Push_Count[CUR.opcode] >> 4;
col = 48;
for ( n = 6; n > 0; n-- )
{
if ( pop == 0 )
temp[col-1] = (temp[col-1] == '(' ? ' ' : ')' );
if ( args < CUR.top && args >= 0 )
sprintf( temp+col, "%04lx", CUR.stack[args] );
else
sprintf( temp+col, " " );
temp[col+4] = ' ';
col += 5;
pop--;
args--;
}
temp[78] = '\n';
temp[79] = '\0';
printf( "%s", temp );
}
/* First, check for empty stack and overflow */
if ( CUR.args < 0 )
{
printf( "ERROR : Too Few Arguments\n" );
CUR.error = TT_Err_Too_Few_Arguments;
goto LErrorLabel_;
}
CUR.new_top = CUR.args + (Pop_Push_Count[CUR.opcode] & 15);
/* new_top is the new top of the stack, after the instruction's */
/* execution. top will be set to new_top after the 'case' */
if ( CUR.new_top > CUR.stackSize )
{
printf( "ERROR : Stack overflow\n" );
CUR.error = TT_Err_Stack_Overflow;
goto LErrorLabel_;
}
}
else
printf( "End of program reached.\n" );
key = 0;
do
{
/* read keyboard */
ch = getch();
switch ( ch )
{
/* Help - show keybindings */
case '?':
printf( "TTDebug Help\n\n" );
printf( "? Show this page\n" );
printf( "q Quit debugger\n" );
printf( "n Skip to next instruction\n" );
printf( "s Step into\n" );
printf( "v Show vector info\n" );
printf( "g Show graphics state\n" );
printf( "p Show points zone\n\n" );
break;
/* Show vectors */
case 'v':
printf( "freedom (%04hx,%04hx)\n", exc->GS.freeVector.x,
exc->GS.freeVector.y );
printf( "projection (%04hx,%04hx)\n", exc->GS.projVector.x,
exc->GS.projVector.y );
printf( "dual (%04hx,%04hx)\n\n", exc->GS.dualVector.x,
exc->GS.dualVector.y );
break;
/* Show graphics state */
case 'g':
printf( "rounding %s\n", round_str[exc->GS.round_state] );
printf( "min dist %04lx\n", exc->GS.minimum_distance );
printf( "cvt_cutin %04lx\n", exc->GS.control_value_cutin );
break;
/* Show points table */
case 'p':
for ( A = 0; A < exc->pts.n_points; A++ )
{
printf( "%02hx ", A );
printf( "%08lx,%08lx - ", pts.org[A].x, pts.org[A].y );
printf( "%08lx,%08lx\n", pts.cur[A].x, pts.cur[A].y );
}
printf(( "\n" ));
break;
default:
key = 1;
}
} while ( !key );
MEM_Copy( save.org, pts.org, pts.n_points * sizeof ( TT_Vector ) );
MEM_Copy( save.cur, pts.cur, pts.n_points * sizeof ( TT_Vector ) );
MEM_Copy( save.tags, pts.tags, pts.n_points );
/* a return indicate the last command */
if (ch == '\r')
ch = oldch;
switch ( ch )
{
/* Quit debugger */
case 'q':
goto LErrorLabel_;
/* Step over */
case 'n':
if ( exc->IP < exc->codeSize )
{
/* `step over' is equivalent to `step into' except if */
/* the current opcode is a CALL or LOOPCALL */
if ( CUR.opcode != 0x2a && CUR.opcode != 0x2b )
goto Step_into;
/* otherwise, loop execution until we reach the next opcode */
next_IP = CUR.IP + CUR.length;
while ( exc->IP != next_IP )
{
if ( ( error = TT_RunIns( exc ) ) )
goto LErrorLabel_;
}
}
oldch = ch;
break;
/* Step into */
case 's':
if ( exc->IP < exc->codeSize )
Step_into:
if ( ( error = TT_RunIns( exc ) ) )
goto LErrorLabel_;
oldch = ch;
break;
default:
printf( "unknown command. Press ? for help\n" );
oldch = '\0';
}
for ( A = 0; A < pts.n_points; A++ )
{
diff = 0;
if ( save.org[A].x != pts.org[A].x ) diff |= 1;
if ( save.org[A].y != pts.org[A].y ) diff |= 2;
if ( save.cur[A].x != pts.cur[A].x ) diff |= 4;
if ( save.cur[A].y != pts.cur[A].y ) diff |= 8;
if ( save.tags[A] != pts.tags[A] ) diff |= 16;
if ( diff )
{
printf( "%02hx ", A );
if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
printf( temp, save.tags[A] & 7 );
if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
printf( temp, save.org[A].x );
if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
printf( temp, save.org[A].y );
if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
printf( temp, save.cur[A].x );
if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
printf( temp, save.cur[A].y );
printf( "\n" );
printf( "%02hx ", A );
if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
printf( temp, pts.tags[A] & 7 );
if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
printf( temp, pts.org[A].x );
if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
printf( temp, pts.org[A].y );
if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
printf( temp, pts.cur[A].x );
if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
printf( temp, pts.cur[A].y );
printf( "\n\n" );
}
}
} while ( TRUE );
LErrorLabel_:
if (error)
Panic( "error during execution" );
return error;
}
static
void Usage()
{
fprintf( stderr, "ttdebug - a simply TrueType font debugger\n" );
fprintf( stderr, "(c) The FreeType project - www.freetype.org\n" );
fprintf( stderr, "-------------------------------------------\n\n" );
fprintf( stderr, "usage : ttdebug [options] glyph size fontfile[.ttf]\n\n" );
fprintf( stderr, " glyph - glyph index within the font file. Can be negative to query \n" );
fprintf( stderr, " the debugging of the font 'cvt' program\n\n" );
fprintf( stderr, " size - size of glyph in pixels\n\n" );
fprintf( stderr, " fontfile - a valid TrueType file.\n\n" );
fprintf( stderr, " valid options are:\n\n" );
fprintf( stderr, " -d : Dump mode. Shows the glyph program and exit immediately\n" );
fprintf( stderr, " -n : Non-interactive mode. Dumps the execution trace and exit\n" );
exit(1);
}
int dump_mode;
int non_interactive_mode;
char* file_name;
int glyph_index;
int glyph_size;
int main( int argc, char** argv )
{
char valid;
/* Check number of arguments */
if ( argc < 4 ) Usage();
/* Check options */
dump_mode = 0;
non_interactive_mode = 0;
argv++;
while (argv[0][0] == '-')
{
valid = 0;
switch (argv[0][1])
{
case 'd':
dump_mode = 1;
valid = 1;
break;
case 'n':
non_interactive_mode = 1;
valid = 1;
break;
default:
;
}
if (valid)
{
argv++;
argc--;
if (argc < 4) Usage();
}
else
break;
}
/* Get Glyph index */
if ( sscanf( argv[0], "%d", &glyph_index ) != 1 )
{
printf( "invalid glyph index = %s\n", argv[1] );
Usage();
}
/* Get Glyph size */
if ( sscanf( argv[1], "%d", &glyph_size ) != 1 )
{
printf( "invalid glyph size = %s\n", argv[1] );
Usage();
}
/* Get file name */
file_name = argv[2];
Init_Keyboard();
/* Init library, read face object, get driver, create size */
error = FT_Init_FreeType( &library );
if (error) Panic( "could not initialise FreeType library" );
memory = library->memory;
driver = FT_Get_Driver( library, "truetype" );
if (!driver) Panic( "could not find the TrueType driver in FreeType 2\n" );
FT_Set_Debug_Hook( library,
FT_DEBUG_HOOK_TRUETYPE,
(FT_DebugHook_Func)RunIns );
error = FT_New_Face( library, file_name, 0, (FT_Face*)&face );
if (error) Panic( "could not open font resource" );
/* find driver and check format */
if ( face->root.driver != driver )
{
error = FT_Err_Invalid_File_Format;
Panic( "This is not a TrueType font" );
}
size = (TT_Size)face->root.size;
if (glyph_index < 0)
{
exec = TT_New_Context( face );
size->debug = 1;
size->context = exec;
error = FT_Set_Char_Size( (FT_Face)face, glyph_size << 6, glyph_size << 6, 72, 72 );
if (error) Panic( "could not set character sizes" );
}
else
{
error = FT_Set_Char_Size( (FT_Face)face, glyph_size << 6, glyph_size << 6, 72, 72 );
if (error) Panic( "could not set character sizes" );
glyph = (TT_GlyphSlot)face->root.glyph;
/* Now load glyph */
error = FT_Load_Glyph( (FT_Face)face, glyph_index, FT_LOAD_DEFAULT );
if (error) Panic( "could not load glyph" );
}
Reset_Keyboard();
return 0;
}