mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
499 lines
15 KiB
C++
499 lines
15 KiB
C++
/*
|
|
History
|
|
=======
|
|
2005/12/07 MuadDib: Added "Recompile required" to Bad version reports.
|
|
|
|
Notes
|
|
=======
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "../clib/stl_inc.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "../clib/strutil.h"
|
|
|
|
#include "filefmt.h"
|
|
|
|
#include "eprog.h"
|
|
#include "escriptv.h"
|
|
#include "options.h"
|
|
#include "executor.h"
|
|
#include "objmethods.h"
|
|
|
|
int EScriptProgram::read(const char *fname)
|
|
{
|
|
FILE* fp = NULL;
|
|
|
|
try
|
|
{
|
|
name = fname;
|
|
|
|
fp = fopen(fname, "rb");
|
|
if (!fp)
|
|
throw runtime_error( string("Unable to open ") + fname + " for reading." );
|
|
|
|
BSCRIPT_FILE_HDR hdr;
|
|
if (fread( &hdr, sizeof hdr, 1, fp ) != 1)
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": error reading header" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (hdr.magic2[0] != BSCRIPT_FILE_MAGIC0 ||
|
|
hdr.magic2[1] != BSCRIPT_FILE_MAGIC1)
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": bad magic value '" << hdr.magic2[0] << hdr.magic2[1] << "'" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
// auto-check for latest version (see filefmt.h for setting)
|
|
if (hdr.version != ESCRIPT_FILE_VER_CURRENT)
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": Recompile required. Bad version number " << hdr.version << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
version = hdr.version;
|
|
nglobals = hdr.globals;
|
|
BSCRIPT_SECTION_HDR sechdr;
|
|
while (fread( &sechdr, sizeof sechdr, 1, fp ) == 1)
|
|
{
|
|
switch( sechdr.type )
|
|
{
|
|
case BSCRIPT_SECTION_PROGDEF:
|
|
if (read_progdef_hdr(fp))
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": error reading progdef section" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case BSCRIPT_SECTION_MODULE:
|
|
if (read_module(fp))
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": error reading module section" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
break;
|
|
case BSCRIPT_SECTION_CODE:
|
|
tokens.read(fp);
|
|
break;
|
|
case BSCRIPT_SECTION_SYMBOLS:
|
|
symbols.read(fp);
|
|
break;
|
|
case BSCRIPT_SECTION_GLOBALVARNAMES:
|
|
if (read_globalvarnames(fp))
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": error reading global variable name section" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
break;
|
|
case BSCRIPT_SECTION_EXPORTED_FUNCTIONS:
|
|
if (read_exported_functions(fp, &sechdr))
|
|
{
|
|
cerr << "Error loading script " << fname
|
|
<< ": error reading exported functions section" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
cerr << "Error loading script " << fname
|
|
<< ": unknown section type " << int(sechdr.type) << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
|
|
return create_instructions();
|
|
}
|
|
catch( std::exception& ex )
|
|
{
|
|
cerr << "Exception caught while loading script " << fname << ": " << ex.what() << endl;
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
#ifndef WIN32
|
|
catch(...)
|
|
{
|
|
cerr << "Exception caught while loading script " << fname << endl;
|
|
if (fp != NULL)
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
int EScriptProgram::create_instructions()
|
|
{
|
|
int nLines = tokens.length() / sizeof(StoredToken);
|
|
instr.resize( nLines ); // = new Instruction[ nLines ];
|
|
|
|
for( int i = 0; i < nLines; i++ )
|
|
{
|
|
Instruction& ins = instr[i];
|
|
if (_readToken( ins.token, i ))
|
|
return -1;
|
|
|
|
// executor only:
|
|
ins.func = Executor::GetInstrFunc( ins.token );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int EScriptProgram::read_progdef_hdr( FILE *fp )
|
|
{
|
|
BSCRIPT_PROGDEF_HDR hdr;
|
|
if (fread( &hdr, sizeof hdr, 1, fp ) != 1)
|
|
return -1;
|
|
|
|
haveProgram = true;
|
|
expectedArgs = hdr.expectedArgs;
|
|
return 0;
|
|
}
|
|
|
|
int EScriptProgram::read_module( FILE *fp )
|
|
{
|
|
BSCRIPT_MODULE_HDR hdr;
|
|
if (fread( &hdr, sizeof hdr, 1, fp ) != 1)
|
|
return -1;
|
|
FunctionalityModule *fm = new FunctionalityModule( hdr.modulename );
|
|
for( unsigned i = 0; i < hdr.nfuncs; i++ )
|
|
{
|
|
BSCRIPT_MODULE_FUNCTION func;
|
|
if (fread( &func, sizeof func, 1, fp ) != 1)
|
|
{
|
|
delete fm;
|
|
return -1;
|
|
}
|
|
fm->addFunction( func.funcname, func.nargs );
|
|
}
|
|
modules.push_back( fm );
|
|
return 0;
|
|
}
|
|
|
|
/* Note: This function is ONLY used from Executor::read(). */
|
|
int EScriptProgram::_readToken(Token& token, unsigned position) const
|
|
{
|
|
StoredToken st;
|
|
tokens.atGet1( position, st );
|
|
// StoredToken& st = tokens[position];
|
|
|
|
token.module = (ModuleID) st.module;
|
|
token.id = static_cast<BTokenId>(st.id);
|
|
token.type = static_cast<BTokenType>(st.type);
|
|
token.lval = st.offset;
|
|
|
|
token.nulStr();
|
|
|
|
// FIXME: USED to set lval to 0 for TYP_FUNC. Not sure if needed anymore.
|
|
// FIXME: Doesn't seem to be, but must be sure before removal
|
|
switch( st.id )
|
|
{
|
|
case INS_CASEJMP:
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
}
|
|
token.dataptr = reinterpret_cast<const unsigned char*>(symbols.array()+st.offset);
|
|
return 0;
|
|
case TOK_LONG:
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
}
|
|
token.lval = * (int *) (symbols.array()+st.offset);
|
|
return 0;
|
|
case TOK_DOUBLE:
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
}
|
|
token.dval = * (double *) (symbols.array()+st.offset);
|
|
return 0;
|
|
|
|
case CTRL_STATEMENTBEGIN:
|
|
if (st.offset)
|
|
{
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
return -1;
|
|
}
|
|
DebugToken *dt = (DebugToken *) (symbols.array()+st.offset);
|
|
token.sourceFile = dt->sourceFile;
|
|
token.lval = dt->offset;
|
|
|
|
if (dt->strOffset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(dt->strOffset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
return -1;
|
|
}
|
|
if (dt->strOffset) token.setStr(symbols.array() + dt->strOffset);
|
|
}
|
|
return 0;
|
|
|
|
case INS_INITFOREACH:
|
|
case INS_STEPFOREACH:
|
|
case INS_INITFOR:
|
|
case INS_NEXTFOR:
|
|
case TOK_GLOBALVAR:
|
|
case TOK_LOCALVAR:
|
|
case CTRL_JSR_USERFUNC:
|
|
case CTRL_LEAVE_BLOCK:
|
|
case TOK_ARRAY_SUBSCRIPT:
|
|
case RSV_JMPIFFALSE:
|
|
case RSV_JMPIFTRUE:
|
|
case RSV_GOTO:
|
|
case RSV_LOCAL:
|
|
case RSV_GLOBAL:
|
|
case INS_ASSIGN_GLOBALVAR:
|
|
case INS_ASSIGN_LOCALVAR:
|
|
case INS_GET_MEMBER_ID:
|
|
case INS_SET_MEMBER_ID:
|
|
case INS_SET_MEMBER_ID_CONSUME:
|
|
case INS_CALL_METHOD_ID:
|
|
token.lval = st.offset;
|
|
return 0;
|
|
|
|
case INS_CALL_METHOD:
|
|
case TOK_FUNC:
|
|
case TOK_USERFUNC:
|
|
token.lval = st.type;
|
|
token.type = (st.id == TOK_FUNC) ? TYP_FUNC : TYP_USERFUNC;
|
|
if (st.offset)
|
|
{
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
}
|
|
token.setStr(symbols.array()+st.offset);
|
|
}
|
|
else if (token.type == TYP_FUNC)
|
|
{
|
|
FunctionalityModule* modl = modules[token.module];
|
|
const ModuleFunction* modfunc;
|
|
|
|
// executor only:
|
|
modfunc = modl->functions.at( token.lval );
|
|
|
|
token.setStr( modfunc->name.c_str() );
|
|
}
|
|
return 0;
|
|
|
|
default:
|
|
if (st.offset)
|
|
{
|
|
if (st.offset >= symbols.length())
|
|
{
|
|
throw runtime_error( "Symbol offset of " + decint(st.offset) + " exceeds symbol store length of " + decint(symbols.length()) + " at PC=" + decint(position));
|
|
}
|
|
token.setStr(symbols.array()+st.offset);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int EScriptProgram::read_globalvarnames( FILE* fp )
|
|
{
|
|
BSCRIPT_GLOBALVARNAMES_HDR hdr;
|
|
if (fread( &hdr, sizeof hdr, 1, fp ) != 1)
|
|
return -1;
|
|
int res = 0;
|
|
unsigned bufalloc = 20;
|
|
char* buffer = new char[bufalloc];
|
|
for( unsigned idx = 0; idx < hdr.nGlobalVars; ++idx )
|
|
{
|
|
BSCRIPT_GLOBALVARNAME_HDR ghdr;
|
|
if (fread( &ghdr, sizeof ghdr, 1, fp ) != 1)
|
|
{
|
|
res = -1;
|
|
break;
|
|
}
|
|
if (ghdr.namelen >= bufalloc)
|
|
{
|
|
bufalloc = ghdr.namelen + 5;
|
|
delete[] buffer;
|
|
buffer = new char[bufalloc];
|
|
}
|
|
if (fread( buffer, ghdr.namelen+1, 1, fp ) != 1)
|
|
{
|
|
res = -1;
|
|
break;
|
|
}
|
|
globalvarnames.push_back( string(buffer) );
|
|
}
|
|
delete[] buffer;
|
|
buffer = NULL;
|
|
return res;
|
|
}
|
|
|
|
int EScriptProgram::read_exported_functions( FILE* fp, BSCRIPT_SECTION_HDR* hdr )
|
|
{
|
|
BSCRIPT_EXPORTED_FUNCTION bef;
|
|
ObjMethod* mth;
|
|
|
|
unsigned nexports = hdr->length / sizeof bef;
|
|
while (nexports--)
|
|
{
|
|
if (fread( &bef, sizeof bef, 1, fp ) != 1)
|
|
return -1;
|
|
EPExportedFunction ef;
|
|
ef.name = bef.funcname;
|
|
ef.nargs = bef.nargs;
|
|
ef.PC = bef.PC;
|
|
exported_functions.push_back( ef );
|
|
if( (mth = getKnownObjMethod(ef.name.c_str())) != NULL )
|
|
mth->overridden = true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int EScriptProgram::read_dbg_file()
|
|
{
|
|
if (debug_loaded)
|
|
return 0;
|
|
|
|
string mname = name;
|
|
mname.replace( mname.size()-3, 3, "dbg" );
|
|
FILE* fp = fopen( mname.c_str(), "rb" );
|
|
if (!fp)
|
|
{
|
|
cerr << "Unable to open " << mname << endl;
|
|
return -1;
|
|
}
|
|
|
|
u32 version;
|
|
fread( &version, sizeof version, 1, fp );
|
|
if (version != 2 && version != 3)
|
|
{
|
|
cerr << "Recompile required. Bad version " << version << " in " << mname << ", expected version 2" << endl;
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
unsigned bufalloc = 20;
|
|
char* buffer = new char[bufalloc];
|
|
int res = 0;
|
|
|
|
u32 count;
|
|
fread( &count, sizeof count, 1, fp );
|
|
dbg_filenames.resize( count );
|
|
for( unsigned i = 0; i < dbg_filenames.size(); ++i )
|
|
{
|
|
fread( &count, sizeof count, 1, fp );
|
|
if (count >= bufalloc)
|
|
{
|
|
delete[] buffer;
|
|
bufalloc = count*2;
|
|
buffer = new char[bufalloc];
|
|
}
|
|
fread( buffer, count, 1, fp );
|
|
dbg_filenames[i] = buffer;
|
|
}
|
|
|
|
fread( &count, sizeof count, 1, fp );
|
|
globalvarnames.resize( count );
|
|
for( unsigned i = 0; i < globalvarnames.size(); ++i )
|
|
{
|
|
fread( &count, sizeof count, 1, fp );
|
|
if (count >= bufalloc)
|
|
{
|
|
delete[] buffer;
|
|
bufalloc = count*2;
|
|
buffer = new char[bufalloc];
|
|
}
|
|
fread( buffer, count, 1, fp );
|
|
globalvarnames[i] = buffer;
|
|
}
|
|
|
|
fread( &count, sizeof count, 1, fp );
|
|
dbg_filenum.resize( count );
|
|
dbg_linenum.resize( count );
|
|
dbg_ins_blocks.resize( count );
|
|
dbg_ins_statementbegin.resize( count );
|
|
for( unsigned i = 0; i < tokens.count(); ++i )
|
|
{
|
|
BSCRIPT_DBG_INSTRUCTION ins;
|
|
fread( &ins, sizeof ins, 1, fp );
|
|
dbg_filenum[i] = ins.filenum;
|
|
dbg_linenum[i] = ins.linenum;
|
|
dbg_ins_blocks[i] = ins.blocknum;
|
|
dbg_ins_statementbegin[i] = ins.statementbegin?true:false;
|
|
}
|
|
fread( &count, sizeof count, 1, fp );
|
|
blocks.resize( count );
|
|
for( unsigned i = 0; i < blocks.size(); ++i )
|
|
{
|
|
EPDbgBlock& block = blocks[i];
|
|
u32 tmp;
|
|
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
block.parentblockidx = tmp;
|
|
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
block.parentvariables = tmp;
|
|
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
block.localvarnames.resize( tmp );
|
|
|
|
for( unsigned j = 0; j < block.localvarnames.size(); ++j )
|
|
{
|
|
fread( &count, sizeof count, 1, fp );
|
|
if (count >= bufalloc)
|
|
{
|
|
delete[] buffer;
|
|
bufalloc = count*2;
|
|
buffer = new char[bufalloc];
|
|
}
|
|
fread( buffer, count, 1, fp );
|
|
block.localvarnames[j] = buffer;
|
|
}
|
|
}
|
|
if (version >= 3)
|
|
{
|
|
fread( &count, sizeof count, 1, fp );
|
|
dbg_functions.resize( count );
|
|
for( unsigned i = 0; i < dbg_functions.size(); ++i )
|
|
{
|
|
EPDbgFunction& func = dbg_functions[i];
|
|
u32 tmp;
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
if (tmp >= bufalloc)
|
|
{
|
|
delete[] buffer;
|
|
bufalloc = tmp*2;
|
|
buffer = new char[bufalloc];
|
|
}
|
|
fread( buffer, tmp, 1, fp );
|
|
func.name = buffer;
|
|
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
func.firstPC = tmp;
|
|
fread( &tmp, sizeof tmp, 1, fp );
|
|
func.lastPC = tmp;
|
|
}
|
|
}
|
|
|
|
delete[] buffer;
|
|
buffer = NULL;
|
|
|
|
fclose(fp);
|
|
debug_loaded = true;
|
|
|
|
return res;
|
|
}
|