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( 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","); 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) // 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; 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, // 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, // 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. // the input string is written unmodified.

View File

@ -34,44 +34,45 @@ wxString strgametitle;
struct PatchTextTable struct PatchTextTable
{ {
wxString text; int code;
int code; const wxChar* text;
PATCHTABLEFUNC func; PATCHTABLEFUNC* func;
}; };
static const PatchTextTable commands[] = static const PatchTextTable commands[] =
{ {
{ L"comment", 1, PatchFunc::comment }, { 1, L"comment", PatchFunc::comment },
{ L"gametitle", 2, PatchFunc::gametitle }, { 2, L"gametitle", PatchFunc::gametitle },
{ L"patch", 3, PatchFunc::patch }, { 3, L"patch", PatchFunc::patch },
{ L"fastmemory", 4, NULL }, // enable for faster but bugger mem (mvc2 is faster) { 4, L"fastmemory", NULL }, // enable for faster but bugger mem (mvc2 is faster)
{ L"roundmode", 5, PatchFunc::roundmode }, // changes rounding mode for floating point { 5, L"roundmode", PatchFunc::roundmode }, // changes rounding mode for floating point
// syntax: roundmode=X,Y // syntax: roundmode=X,Y
// possible values for X,Y: NEAR, DOWN, UP, CHOP // possible values for X,Y: NEAR, DOWN, UP, CHOP
// X - EE rounding mode (default is NEAR) // X - EE rounding mode (default is NEAR)
// Y - VU rounding mode (default is CHOP) // Y - VU rounding mode (default is CHOP)
{ L"zerogs", 6, PatchFunc::zerogs }, // zerogs=hex { 6, L"zerogs", PatchFunc::zerogs }, // zerogs=hex
{ L"vunanmode",8, NULL }, { 7, L"vunanmode", NULL },
{ L"ffxhack",9, NULL}, { 8, L"ffxhack", NULL}, // *obsolete*
{ L"xkickdelay",10, NULL}, { 9, L"xkickdelay", NULL},
{ wxEmptyString, 0, NULL }
{ 0, wxEmptyString, NULL } // Array Terminator
}; };
static const PatchTextTable dataType[] = static const PatchTextTable dataType[] =
{ {
{ L"byte", 1, NULL }, { 1, L"byte", NULL },
{ L"short", 2, NULL }, { 2, L"short", NULL },
{ L"word", 3, NULL }, { 3, L"word", NULL },
{ L"double", 4, NULL }, { 4, L"double", NULL },
{ L"extended", 5, NULL }, { 5, L"extended", NULL },
{ wxEmptyString, 0, NULL } { 0, wxEmptyString, NULL }
}; };
static const PatchTextTable cpuCore[] = static const PatchTextTable cpuCore[] =
{ {
{ L"EE", 1, NULL }, { 1, L"EE", NULL },
{ L"IOP", 2, NULL }, { 2, L"IOP", NULL },
{ wxEmptyString, 0, NULL } { 0, wxEmptyString, NULL }
}; };
void writeCheat() void writeCheat()
@ -367,13 +368,9 @@ void handle_extended_t( IniPatch *p)
// IniFile Functions. // 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 ) void inifile_trim( wxString& buffer )
{ {
buffer.Trim( false ); // trims left side. buffer.Trim(false); // trims left side.
if( buffer.Length() <= 1 ) // this I'm not sure about... - air if( buffer.Length() <= 1 ) // this I'm not sure about... - air
{ {
@ -390,15 +387,15 @@ void inifile_trim( wxString& buffer )
buffer.Trim(true); // trims right side. 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; int i = 0;
while (Table[i].text[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; break;
} }
i++; 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. // 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; // Is this really what we want to be doing here? Seems like just leaving it empty/blank
wxString parameter; // would make more sense... --air
if (set.rvalue.IsEmpty()) set.rvalue = set.lvalue;
// extract param part (after '=') int code = PatchTableExecute( set, commands );
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 );
} }
// This routine recieves a file from inifile_read, trims it, // 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, // This routine creates a pnach filename from the games crc,
// loads it, trims the commands, and sends them to be parsed. // loads it, trims the commands, and sends them to be parsed.
void inifile_read(wxString name ) void inifile_read(const wxString& name )
{ {
wxTextFile f1; wxTextFile f1;
wxString buffer; wxString buffer;
patchnumber = 0; 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"); buffer = Path::Combine(L"patches", name + L".pnach");
if(!f1.Open(buffer) && wxFileName::IsCaseSensitive()) if(!f1.Open(buffer) && wxFileName::IsCaseSensitive())
{ {
name.MakeUpper(); f1.Open( Path::Combine(L"patches", name.Upper() + L".pnach") );
f1.Open( Path::Combine(L"patches", name + L".pnach") );
} }
if(!f1.IsOpened()) if(!f1.IsOpened())
@ -533,7 +522,7 @@ void ApplyPatch(int place)
} }
} }
void InitPatch(wxString crc) void InitPatch(const wxString& crc)
{ {
inifile_read(crc); inifile_read(crc);
Console.WriteLn("patchnumber: %d", patchnumber); Console.WriteLn("patchnumber: %d", patchnumber);
@ -573,36 +562,37 @@ void PrintPatch(int i)
switch(Patch[i].cpu) switch(Patch[i].cpu)
{ {
case CPU_EE: Console.WriteLn("Cpu: EE"); break; case CPU_EE: Console.WriteLn("Cpu: EE"); break;
case CPU_IOP: Console.WriteLn("Cpu: IOP"); break; case CPU_IOP: Console.WriteLn("Cpu: IOP"); break;
default: Console.WriteLn("Cpu: None"); break; default: Console.WriteLn("Cpu: None"); break;
} }
Console.WriteLn("Address: %X", Patch[i].addr); Console.WriteLn("Address: %X", Patch[i].addr);
switch (Patch[i].type) switch (Patch[i].type)
{ {
case BYTE_T: Console.WriteLn("Type: Byte"); break; case BYTE_T: Console.WriteLn("Type: Byte"); break;
case SHORT_T: Console.WriteLn("Type: Short"); break; case SHORT_T: Console.WriteLn("Type: Short"); break;
case WORD_T: Console.WriteLn("Type: Word"); break; case WORD_T: Console.WriteLn("Type: Word"); break;
case DOUBLE_T: Console.WriteLn("Type: Double"); break; case DOUBLE_T: Console.WriteLn("Type: Double"); break;
case EXTENDED_T: Console.WriteLn("Type: Extended"); break; case EXTENDED_T: Console.WriteLn("Type: Extended"); break;
default: Console.WriteLn("Type: None"); break;
default: Console.WriteLn("Type: None"); break;
} }
Console.WriteLn("Data: %I64X", Patch[i].data); 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; unsigned long l;
str.ToULong(&l, base); str.ToULong(&l, base);
return l; 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); str.ToULongLong(&l, base);
return l; return l;
} }
@ -610,77 +600,78 @@ u64 StrToU64(wxString str, int base = 10)
// PatchFunc Functions. // PatchFunc Functions.
namespace PatchFunc namespace PatchFunc
{ {
void comment( wxString text1, wxString text2 ) void comment( const wxString& text1, const wxString& text2 )
{ {
Console.WriteLn( L"comment: " + 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 ); Console.WriteLn( L"gametitle: " + text2 );
strgametitle = text2; strgametitle = text2;
Console.SetTitle( strgametitle ); Console.SetTitle( strgametitle );
} }
void patch( wxString cmd, wxString param ) struct PatchPieces
{ {
wxArrayString m_pieces;
PatchPieces( const wxString& param )
{
SplitString( m_pieces, param, L"," );
if( m_pieces.Count() < 5 )
throw wxsFormat( L"Expected 5 data parameters; only found %d", m_pieces.Count() );
}
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]; }
};
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.
DevCon.WriteLn(cmd + L" " + param); DevCon.WriteLn(cmd + L" " + param);
wxString pText;
if ( patchnumber >= MAX_PATCH ) try
{ {
// TODO : Use wxLogError for this, once we have full unicode compliance on cmd/params vars. if ( patchnumber >= MAX_PATCH )
//wxLogError( L"Patch ERROR: Maximum number of patches reached: %s=%s", cmd, param ); throw wxString( L"Maximum number of patches reached" );
Console.Error( L"Patch ERROR: Maximum number of patches reached: " + cmd +L"=" + param );
return; Patch[patchnumber].enabled = 0;
} PatchPieces pieces( param );
// I've just sort of hacked this in place for the moment. Patch[patchnumber].placetopatch = StrToU32(pieces.PlaceToPatch(), 10);
// Using SafeList is probably better, but I'll leave that to Air... Patch[patchnumber].cpu = (patch_cpu_type)PatchTableExecute( pieces.CpuType(), cpuCore );
//SafeList<wxString> pieces; Patch[patchnumber].addr = StrToU32(pieces.MemAddr(), 16);
//SplitString( pieces, param, L"," ); Patch[patchnumber].type = (patch_data_type)PatchTableExecute( pieces.OperandSize(), dataType );
Patch[patchnumber].data = StrToU64( pieces.WriteValue(), 16 );
Patch[patchnumber].placetopatch = StrToU32(param.BeforeFirst(L','), 10); if (Patch[patchnumber].cpu == 0)
param = param.AfterFirst(L','); throw wxsFormat( L"Unrecognized CPU Target: '%s'", pieces.CpuType().c_str() );
pText = param.BeforeFirst(L',');
inifile_trim( pText ); if (Patch[patchnumber].type == 0)
Patch[patchnumber].cpu = (patch_cpu_type)PatchTableExecute( pText, wxEmptyString, cpuCore ); throw wxsFormat( L"Unrecognized Operand Size: '%s'", pieces.OperandSize().c_str() );
if (Patch[patchnumber].cpu == 0) Patch[patchnumber].enabled = 1; // omg success!!
{
Console.Error( L"Unrecognized patch '" + cmd + L"'" );
return;
}
param = param.AfterFirst(L','); //PrintPatch(patchnumber);
pText = param.BeforeFirst(L','); patchnumber++;
inifile_trim( pText ); }
Patch[patchnumber].addr = StrToU32(pText, 16); catch( wxString& exmsg )
{
param = param.AfterFirst(L','); Console.Error( L"(Patch) Error Parsing: %s=%s", cmd.c_str(), param.c_str() );
pText = param.BeforeFirst(L','); Console.Error( L"\t" + exmsg );
inifile_trim( pText ); }
Patch[patchnumber].type = (patch_data_type)PatchTableExecute( pText, wxEmptyString, dataType );
if ( Patch[patchnumber].type == 0 )
{
Console.Error( L"Unrecognized patch '" + cmd + L"'" );
return;
}
param = param.AfterFirst(L',');
pText = param.BeforeFirst(L',');
inifile_trim( pText );
Patch[patchnumber].data = StrToU64(pText, 16);
Patch[patchnumber].enabled = 1;
//PrintPatch(patchnumber);
patchnumber++;
} }
void roundmode( wxString cmd, wxString param ) void roundmode( const wxString& cmd, const wxString& param )
{ {
DevCon.WriteLn(cmd + L" " + param); DevCon.WriteLn(cmd + L" " + param);
@ -691,8 +682,7 @@ namespace PatchFunc
SSE_RoundMode vutype = EmuConfig.Cpu.sseVUMXCSR.GetRoundMode(); SSE_RoundMode vutype = EmuConfig.Cpu.sseVUMXCSR.GetRoundMode();
index = 0; index = 0;
param.MakeLower(); pText = param.Lower().BeforeFirst(L',');
pText = param.BeforeFirst(L',');
while(pText != wxEmptyString) while(pText != wxEmptyString)
{ {
SSE_RoundMode type; SSE_RoundMode type;
@ -726,7 +716,7 @@ namespace PatchFunc
SetRoundMode(eetype,vutype); SetRoundMode(eetype,vutype);
} }
void zerogs(wxString cmd, wxString param) void zerogs(const wxString& cmd, const wxString& param)
{ {
DevCon.WriteLn( cmd + L" " + param); DevCon.WriteLn( cmd + L" " + param);
g_ZeroGSOptions = StrToU32(param, 16); g_ZeroGSOptions = StrToU32(param, 16);

View File

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

View File

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

View File

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