Patch parsing code cleanups, using some parser helper classes and properly const-qualified wxString parameters; also improved error handling slightly.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2163 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-11-08 17:18:34 +00:00
parent 921f91d826
commit d92f756cdf
6 changed files with 154 additions and 124 deletions

View File

@ -46,6 +46,29 @@ extern bool TryParse( wxPoint& dest, const wxString& src, const wxPoint& defval=
extern bool TryParse( wxSize& dest, const wxString& src, const wxSize& defval=wxDefaultSize, const wxString& separators=L",");
extern bool TryParse( wxRect& dest, const wxString& src, const wxRect& defval=wxDefaultRect, const wxString& separators=L",");
// --------------------------------------------------------------------------------------
// ParsedAssignmentString
// --------------------------------------------------------------------------------------
// This class is a simple helper for parsing INI-style assignments, in the typical form of:
// variable = value
// filename = SomeString.txt
// integer = 15
//
// This parser supports both '//' and ';' at the head of a line as indicators of a commented
// line, and such a line will return empty strings for l- and r-value.
//
// No type handling is performed -- the user must manually parse strings into integers, etc.
// For advanced "fully functional" ini file parsing, consider using wxFileConfig instead.
//
struct ParsedAssignmentString
{
wxString lvalue;
wxString rvalue;
bool IsComment;
ParsedAssignmentString( const wxString& src );
};
//////////////////////////////////////////////////////////////////////////////////////////
// Custom internal sprintf functions, which are ASCII only (even in UNICODE builds)

View File

@ -172,6 +172,19 @@ bool TryParse( wxRect& dest, const wxString& src, const wxRect& defval, const wx
return true;
}
ParsedAssignmentString::ParsedAssignmentString( const wxString& src )
{
IsComment = false;
if( src.StartsWith( L"//" ) || src.StartsWith( L";" ) )
{
IsComment = true;
return;
}
lvalue = src.BeforeFirst(L'=').Trim(true).Trim(false);
rvalue = src.AfterFirst(L'=').Trim(true).Trim(false);
}
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
// so that Notepad won't throw a fit and Rama can read the logs again! On Unix and Mac platforms,
// the input string is written unmodified.

View File

@ -34,44 +34,45 @@ wxString strgametitle;
struct PatchTextTable
{
wxString text;
int code;
PATCHTABLEFUNC func;
const wxChar* text;
PATCHTABLEFUNC* func;
};
static const PatchTextTable commands[] =
{
{ L"comment", 1, PatchFunc::comment },
{ L"gametitle", 2, PatchFunc::gametitle },
{ L"patch", 3, PatchFunc::patch },
{ L"fastmemory", 4, NULL }, // enable for faster but bugger mem (mvc2 is faster)
{ L"roundmode", 5, PatchFunc::roundmode }, // changes rounding mode for floating point
{ 1, L"comment", PatchFunc::comment },
{ 2, L"gametitle", PatchFunc::gametitle },
{ 3, L"patch", PatchFunc::patch },
{ 4, L"fastmemory", NULL }, // enable for faster but bugger mem (mvc2 is faster)
{ 5, L"roundmode", PatchFunc::roundmode }, // changes rounding mode for floating point
// syntax: roundmode=X,Y
// possible values for X,Y: NEAR, DOWN, UP, CHOP
// X - EE rounding mode (default is NEAR)
// Y - VU rounding mode (default is CHOP)
{ L"zerogs", 6, PatchFunc::zerogs }, // zerogs=hex
{ L"vunanmode",8, NULL },
{ L"ffxhack",9, NULL},
{ L"xkickdelay",10, NULL},
{ wxEmptyString, 0, NULL }
{ 6, L"zerogs", PatchFunc::zerogs }, // zerogs=hex
{ 7, L"vunanmode", NULL },
{ 8, L"ffxhack", NULL}, // *obsolete*
{ 9, L"xkickdelay", NULL},
{ 0, wxEmptyString, NULL } // Array Terminator
};
static const PatchTextTable dataType[] =
{
{ L"byte", 1, NULL },
{ L"short", 2, NULL },
{ L"word", 3, NULL },
{ L"double", 4, NULL },
{ L"extended", 5, NULL },
{ wxEmptyString, 0, NULL }
{ 1, L"byte", NULL },
{ 2, L"short", NULL },
{ 3, L"word", NULL },
{ 4, L"double", NULL },
{ 5, L"extended", NULL },
{ 0, wxEmptyString, NULL }
};
static const PatchTextTable cpuCore[] =
{
{ L"EE", 1, NULL },
{ L"IOP", 2, NULL },
{ wxEmptyString, 0, NULL }
{ 1, L"EE", NULL },
{ 2, L"IOP", NULL },
{ 0, wxEmptyString, NULL }
};
void writeCheat()
@ -367,10 +368,6 @@ void handle_extended_t( IniPatch *p)
// IniFile Functions.
// New version of trim (untested), which I coded but can't use yet because the
// rest of Patch needs to be more wxString-involved first. --Air
// And now it is... --Arcum42
void inifile_trim( wxString& buffer )
{
buffer.Trim(false); // trims left side.
@ -390,15 +387,15 @@ void inifile_trim( wxString& buffer )
buffer.Trim(true); // trims right side.
}
static int PatchTableExecute( wxString text1, wxString text2, const PatchTextTable * Table )
static int PatchTableExecute( const ParsedAssignmentString& set, const PatchTextTable * Table )
{
int i = 0;
while (Table[i].text[0])
{
if (!text1.Cmp(Table[i].text))
if (!set.lvalue.Cmp(Table[i].text))
{
if (Table[i].func) Table[i].func(text1, text2);
if (Table[i].func) Table[i].func(set.lvalue, set.rvalue);
break;
}
i++;
@ -408,24 +405,15 @@ static int PatchTableExecute( wxString text1, wxString text2, const PatchTextTab
}
// This routine is for executing the commands of the ini file.
void inifile_command( wxString cmd )
void inifile_command( const wxString& cmd )
{
int code;
ParsedAssignmentString set( cmd );
wxString command;
wxString parameter;
// Is this really what we want to be doing here? Seems like just leaving it empty/blank
// would make more sense... --air
if (set.rvalue.IsEmpty()) set.rvalue = set.lvalue;
// extract param part (after '=')
wxString pEqual = cmd.AfterFirst(L'=');
if (pEqual.IsEmpty()) pEqual = cmd;
command = cmd.BeforeFirst(L'=');
parameter = pEqual;
inifile_trim( command );
inifile_trim( parameter );
code = PatchTableExecute( command, parameter, commands );
int code = PatchTableExecute( set, commands );
}
// This routine recieves a file from inifile_read, trims it,
@ -442,19 +430,20 @@ void inifile_process(wxTextFile &f1 )
// This routine creates a pnach filename from the games crc,
// loads it, trims the commands, and sends them to be parsed.
void inifile_read(wxString name )
void inifile_read(const wxString& name )
{
wxTextFile f1;
wxString buffer;
patchnumber = 0;
// FIXME : We need to add a 'patches' folder to the AppConfig, and use that instead. --air
buffer = Path::Combine(L"patches", name + L".pnach");
if(!f1.Open(buffer) && wxFileName::IsCaseSensitive())
{
name.MakeUpper();
f1.Open( Path::Combine(L"patches", name + L".pnach") );
f1.Open( Path::Combine(L"patches", name.Upper() + L".pnach") );
}
if(!f1.IsOpened())
@ -533,7 +522,7 @@ void ApplyPatch(int place)
}
}
void InitPatch(wxString crc)
void InitPatch(const wxString& crc)
{
inifile_read(crc);
Console.WriteLn("patchnumber: %d", patchnumber);
@ -587,22 +576,23 @@ void PrintPatch(int i)
case WORD_T: Console.WriteLn("Type: Word"); break;
case DOUBLE_T: Console.WriteLn("Type: Double"); break;
case EXTENDED_T: Console.WriteLn("Type: Extended"); break;
default: Console.WriteLn("Type: None"); break;
}
Console.WriteLn("Data: %I64X", Patch[i].data);
}
u32 StrToU32(wxString str, int base = 10)
static u32 StrToU32(const wxString& str, int base = 10)
{
unsigned long l;
str.ToULong(&l, base);
return l;
}
u64 StrToU64(wxString str, int base = 10)
static u64 StrToU64(const wxString& str, int base = 10)
{
unsigned long long l;
wxULongLong_t l;
str.ToULongLong(&l, base);
return l;
}
@ -610,77 +600,78 @@ u64 StrToU64(wxString str, int base = 10)
// PatchFunc Functions.
namespace PatchFunc
{
void comment( wxString text1, wxString text2 )
void comment( const wxString& text1, const wxString& text2 )
{
Console.WriteLn( L"comment: " + text2 );
}
void gametitle( wxString text1, wxString text2 )
void gametitle( const wxString& text1, const wxString& text2 )
{
Console.WriteLn( L"gametitle: " + text2 );
strgametitle = text2;
Console.SetTitle( strgametitle );
}
void patch( wxString cmd, wxString param )
struct PatchPieces
{
DevCon.WriteLn(cmd + L" " + param);
wxString pText;
wxArrayString m_pieces;
if ( patchnumber >= MAX_PATCH )
PatchPieces( const wxString& param )
{
// TODO : Use wxLogError for this, once we have full unicode compliance on cmd/params vars.
//wxLogError( L"Patch ERROR: Maximum number of patches reached: %s=%s", cmd, param );
Console.Error( L"Patch ERROR: Maximum number of patches reached: " + cmd +L"=" + param );
return;
SplitString( m_pieces, param, L"," );
if( m_pieces.Count() < 5 )
throw wxsFormat( L"Expected 5 data parameters; only found %d", m_pieces.Count() );
}
// I've just sort of hacked this in place for the moment.
// Using SafeList is probably better, but I'll leave that to Air...
//SafeList<wxString> pieces;
//SplitString( pieces, param, L"," );
const wxString& PlaceToPatch() const { return m_pieces[0]; }
const wxString& CpuType() const { return m_pieces[1]; }
const wxString& MemAddr() const { return m_pieces[2]; }
const wxString& OperandSize() const { return m_pieces[3]; }
const wxString& WriteValue() const { return m_pieces[4]; }
};
Patch[patchnumber].placetopatch = StrToU32(param.BeforeFirst(L','), 10);
param = param.AfterFirst(L',');
pText = param.BeforeFirst(L',');
void patch( const wxString& cmd, const wxString& param )
{
// Error Handling Note: I just throw simple wxStrings here, and then catch them below and
// format them into more detailed cmd+data+error printouts. If we want to add user-friendly
// (translated) messages for display in a popup window then we'll have to upgrade the
// exception a little bit.
inifile_trim( pText );
Patch[patchnumber].cpu = (patch_cpu_type)PatchTableExecute( pText, wxEmptyString, cpuCore );
DevCon.WriteLn(cmd + L" " + param);
try
{
if ( patchnumber >= MAX_PATCH )
throw wxString( L"Maximum number of patches reached" );
Patch[patchnumber].enabled = 0;
PatchPieces pieces( param );
Patch[patchnumber].placetopatch = StrToU32(pieces.PlaceToPatch(), 10);
Patch[patchnumber].cpu = (patch_cpu_type)PatchTableExecute( pieces.CpuType(), cpuCore );
Patch[patchnumber].addr = StrToU32(pieces.MemAddr(), 16);
Patch[patchnumber].type = (patch_data_type)PatchTableExecute( pieces.OperandSize(), dataType );
Patch[patchnumber].data = StrToU64( pieces.WriteValue(), 16 );
if (Patch[patchnumber].cpu == 0)
{
Console.Error( L"Unrecognized patch '" + cmd + L"'" );
return;
}
param = param.AfterFirst(L',');
pText = param.BeforeFirst(L',');
inifile_trim( pText );
Patch[patchnumber].addr = StrToU32(pText, 16);
param = param.AfterFirst(L',');
pText = param.BeforeFirst(L',');
inifile_trim( pText );
Patch[patchnumber].type = (patch_data_type)PatchTableExecute( pText, wxEmptyString, dataType );
throw wxsFormat( L"Unrecognized CPU Target: '%s'", pieces.CpuType().c_str() );
if (Patch[patchnumber].type == 0)
{
Console.Error( L"Unrecognized patch '" + cmd + L"'" );
return;
}
throw wxsFormat( L"Unrecognized Operand Size: '%s'", pieces.OperandSize().c_str() );
param = param.AfterFirst(L',');
pText = param.BeforeFirst(L',');
inifile_trim( pText );
Patch[patchnumber].data = StrToU64(pText, 16);
Patch[patchnumber].enabled = 1;
Patch[patchnumber].enabled = 1; // omg success!!
//PrintPatch(patchnumber);
patchnumber++;
}
catch( wxString& exmsg )
{
Console.Error( L"(Patch) Error Parsing: %s=%s", cmd.c_str(), param.c_str() );
Console.Error( L"\t" + exmsg );
}
}
void roundmode( wxString cmd, wxString param )
void roundmode( const wxString& cmd, const wxString& param )
{
DevCon.WriteLn(cmd + L" " + param);
@ -691,8 +682,7 @@ namespace PatchFunc
SSE_RoundMode vutype = EmuConfig.Cpu.sseVUMXCSR.GetRoundMode();
index = 0;
param.MakeLower();
pText = param.BeforeFirst(L',');
pText = param.Lower().BeforeFirst(L',');
while(pText != wxEmptyString)
{
SSE_RoundMode type;
@ -726,7 +716,7 @@ namespace PatchFunc
SetRoundMode(eetype,vutype);
}
void zerogs(wxString cmd, wxString param)
void zerogs(const wxString& cmd, const wxString& param)
{
DevCon.WriteLn( cmd + L" " + param);
g_ZeroGSOptions = StrToU32(param, 16);

View File

@ -34,7 +34,7 @@ enum patch_data_type {
EXTENDED_T
};
typedef void (*PATCHTABLEFUNC)( wxString text1, wxString text2 );
typedef void PATCHTABLEFUNC( const wxString& text1, const wxString& text2 );
struct IniPatch
{
@ -49,15 +49,15 @@ struct IniPatch
namespace PatchFunc
{
void comment( wxString text1, wxString text2 );
void gametitle( wxString text1, wxString text2 );
void patch( wxString text1, wxString text2 );
void roundmode( wxString text1, wxString text2 );
void zerogs( wxString text1, wxString text2 );
PATCHTABLEFUNC comment;
PATCHTABLEFUNC gametitle;
PATCHTABLEFUNC patch;
PATCHTABLEFUNC roundmode;
PATCHTABLEFUNC zerogs;
}
void inifile_read( wxString name );
void inifile_command( wxString cmd );
void inifile_read( const wxString& name );
void inifile_command( const wxString& cmd );
void inifile_trim( wxString& buffer );
int AddPatch(int Mode, int Place, int Address, int Size, u64 data);

View File

@ -39,5 +39,5 @@ public:
{
Write( fmt, strlen( fmt ) );
}
};

View File

@ -1763,6 +1763,10 @@
<Filter
Name="IsoFS"
>
<File
RelativePath="..\..\CDVD\IsoFS\IsoDirectory.h"
>
</File>
<File
RelativePath="..\..\CDVD\IsoFS\IsoFile.cpp"
>