add AR code file parser and shit
This commit is contained in:
parent
28b8f614ee
commit
4cefff2528
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
Copyright 2016-2020 Arisotura
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ARCodeFile.h"
|
||||
#include "Platform.h"
|
||||
|
||||
|
||||
// TODO: import codes from other sources (usrcheat.dat, ...)
|
||||
// TODO: more user-friendly error reporting
|
||||
|
||||
|
||||
ARCodeFile::ARCodeFile(const char* filename)
|
||||
{
|
||||
memset(Filename, 0, sizeof(Filename));
|
||||
strncpy(Filename, filename, 1023);
|
||||
|
||||
Error = false;
|
||||
|
||||
Categories.clear();
|
||||
|
||||
FILE* f = Platform::OpenFile(Filename, "r");
|
||||
if (!f) return;
|
||||
|
||||
bool isincat = false;
|
||||
ARCodeCat curcat;
|
||||
|
||||
bool isincode = false;
|
||||
ARCode curcode;
|
||||
|
||||
char linebuf[1024];
|
||||
while (!feof(f))
|
||||
{
|
||||
fgets(linebuf, 1024, f);
|
||||
linebuf[1023] = '\0';
|
||||
|
||||
char* start = linebuf;
|
||||
while (start[0]==' ' || start[0]=='\t')
|
||||
start++;
|
||||
|
||||
if (start[0]=='#' || start[0]=='\r' || start[0]=='\n' || start[0]=='\0')
|
||||
continue;
|
||||
|
||||
if (!strncasecmp(start, "CAT", 3))
|
||||
{
|
||||
char catname[128];
|
||||
int ret = sscanf(start, "CAT %127[^\n]", catname);
|
||||
catname[127] = '\0';
|
||||
|
||||
if (ret < 1)
|
||||
{
|
||||
printf("AR: malformed CAT line: %s\n", start);
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isincode) curcat.Codes.push_back(curcode);
|
||||
isincode = false;
|
||||
|
||||
if (isincat) Categories.push_back(curcat);
|
||||
isincat = true;
|
||||
|
||||
memcpy(curcat.Name, catname, 128);
|
||||
curcat.Codes.clear();
|
||||
}
|
||||
else if (!strncasecmp(start, "CODE", 4))
|
||||
{
|
||||
int enable;
|
||||
char codename[128];
|
||||
int ret = sscanf(start, "CODE %d %127[^\n]", &enable, codename);
|
||||
codename[127] = '\0';
|
||||
|
||||
if (ret < 2)
|
||||
{
|
||||
printf("AR: malformed CODE line: %s\n", start);
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isincat)
|
||||
{
|
||||
printf("AR: encountered CODE line with no category started\n");
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isincode) curcat.Codes.push_back(curcode);
|
||||
isincode = true;
|
||||
|
||||
memcpy(curcode.Name, codename, 128);
|
||||
curcode.Enabled = enable!=0;
|
||||
curcode.CodeLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 c0, c1;
|
||||
int ret = sscanf(start, "%08X %08X", &c0, &c1);
|
||||
|
||||
if (ret < 2)
|
||||
{
|
||||
printf("AR: malformed data line: %s\n", start);
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isincode)
|
||||
{
|
||||
printf("AR: encountered data line with no code started\n");
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (curcode.CodeLen >= 2*64)
|
||||
{
|
||||
printf("AR: code too long!\n");
|
||||
fclose(f);
|
||||
Error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
u32 idx = curcode.CodeLen;
|
||||
curcode.Code[idx+0] = c0;
|
||||
curcode.Code[idx+1] = c1;
|
||||
curcode.CodeLen += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (isincode) curcat.Codes.push_back(curcode);
|
||||
if (isincat) Categories.push_back(curcat);
|
||||
|
||||
fclose(f);
|
||||
|
||||
printf("PARSED OUTPUT\n");
|
||||
for (ARCodeCatList::iterator it = Categories.begin(); it != Categories.end(); it++)
|
||||
{
|
||||
ARCodeCat& cat = *it;
|
||||
printf("CAT %s\n", cat.Name);
|
||||
|
||||
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
|
||||
{
|
||||
ARCode& code = *jt;
|
||||
printf("CODE %d %s\n", code.Enabled, code.Name);
|
||||
|
||||
for (u32 i = 0; i < code.CodeLen; i+=2)
|
||||
{
|
||||
printf("%08X %08X\n", code.Code[i], code.Code[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ARCodeFile::~ARCodeFile()
|
||||
{
|
||||
//
|
||||
}
|
|
@ -16,18 +16,48 @@
|
|||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#ifndef ARCODELIST_H
|
||||
#define ARCODELIST_H
|
||||
#ifndef ARCODEFILE_H
|
||||
#define ARCODEFILE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define ARCL_MAJOR 1
|
||||
#define ARCL_MINOR 1
|
||||
typedef struct
|
||||
{
|
||||
char Name[128];
|
||||
bool Enabled;
|
||||
u32 CodeLen;
|
||||
u32 Code[2*64];
|
||||
|
||||
class ARCodeList
|
||||
} ARCode;
|
||||
|
||||
typedef std::vector<ARCode> ARCodeList;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char Name[128];
|
||||
ARCodeList Codes;
|
||||
|
||||
} ARCodeCat;
|
||||
|
||||
typedef std::vector<ARCodeCat> ARCodeCatList;
|
||||
|
||||
|
||||
class ARCodeFile
|
||||
{
|
||||
public:
|
||||
//
|
||||
ARCodeFile(const char* filename);
|
||||
~ARCodeFile();
|
||||
|
||||
bool Error;
|
||||
|
||||
bool Save();
|
||||
|
||||
ARCodeCatList Categories;
|
||||
|
||||
private:
|
||||
char Filename[1024];
|
||||
};
|
||||
|
||||
#endif // ARCODELIST_H
|
||||
#endif // ARCODEFILE_H
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
Copyright 2016-2020 Arisotura
|
||||
|
||||
This file is part of melonDS.
|
||||
|
||||
melonDS is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ARCodeList.h"
|
||||
|
||||
/*
|
||||
Action Replay code list format
|
||||
|
||||
header:
|
||||
00 - magic MLAR
|
||||
04 - version major
|
||||
06 - version minor
|
||||
08 - length
|
||||
0C - number of codes
|
||||
|
||||
code header:
|
||||
00 - magic MLCD
|
||||
04 - name length
|
||||
08 - code length
|
||||
0C - enable flag
|
||||
10 - code data (UTF8 name then actual code)
|
||||
*/
|
135
src/AREngine.cpp
135
src/AREngine.cpp
|
@ -25,119 +25,30 @@
|
|||
namespace AREngine
|
||||
{
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 Code[2 * 64]; // TODO: more sensible size for this? allocate on demand?
|
||||
bool Enabled;
|
||||
|
||||
} CheatEntry;
|
||||
|
||||
// TODO: more sensible size for this? allocate on demand?
|
||||
CheatEntry CheatCodes[64];
|
||||
u32 NumCheatCodes;
|
||||
|
||||
|
||||
void ParseTextCode(char* text, int tlen, u32* code, int clen) // or whatever this should be named?
|
||||
{
|
||||
u32 cur_word = 0;
|
||||
u32 ndigits = 0;
|
||||
u32 nin = 0;
|
||||
u32 nout = 0;
|
||||
|
||||
char c;
|
||||
while ((c = *text++) != '\0')
|
||||
{
|
||||
u32 val;
|
||||
if (c >= '0' && c <= '9')
|
||||
val = c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
val = c - 'a' + 0xA;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
val = c - 'A' + 0xA;
|
||||
else
|
||||
continue;
|
||||
|
||||
cur_word <<= 4;
|
||||
cur_word |= val;
|
||||
|
||||
ndigits++;
|
||||
if (ndigits >= 8)
|
||||
{
|
||||
if (nout >= clen)
|
||||
{
|
||||
printf("AR: code too long!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
*code++ = cur_word;
|
||||
nout++;
|
||||
|
||||
ndigits = 0;
|
||||
cur_word = 0;
|
||||
}
|
||||
|
||||
nin++;
|
||||
if (nin >= tlen) break;
|
||||
}
|
||||
|
||||
if (nout & 1)
|
||||
{
|
||||
printf("AR: code was missing one word\n");
|
||||
if (nout >= clen)
|
||||
{
|
||||
printf("AR: code too long!\n");
|
||||
return;
|
||||
}
|
||||
*code++ = 0;
|
||||
}
|
||||
}
|
||||
// AR code file - frontend is responsible for managing this
|
||||
ARCodeFile* CodeFile;
|
||||
|
||||
|
||||
bool Init()
|
||||
{
|
||||
CodeFile = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
memset(CheatCodes, 0, sizeof(CheatCodes));
|
||||
NumCheatCodes = 0;
|
||||
CodeFile = nullptr;
|
||||
}
|
||||
|
||||
// TODO: acquire codes from a sensible source!
|
||||
CheatEntry* entry = &CheatCodes[0];
|
||||
u32* ptr = &entry->Code[0];
|
||||
|
||||
/*char* test = R"(9209D09A 00000000
|
||||
6209B468 00000000
|
||||
B209B468 00000000
|
||||
10000672 000003FF
|
||||
D2000000 00000000
|
||||
9209D09A 00000000
|
||||
94000130 FCBF0000
|
||||
6209B468 00000000
|
||||
B209B468 00000000
|
||||
200006B3 00000001
|
||||
200006B4 00000001
|
||||
D2000000 00000000
|
||||
9209D09A 00000000
|
||||
94000130 FC7F0000
|
||||
6209B468 00000000
|
||||
B209B468 00000000
|
||||
10000672 00000000
|
||||
D2000000 00000000)";
|
||||
ParseTextCode(test, entry->Code, 2*64);
|
||||
printf("PARSED CODE:\n");
|
||||
for (int i = 0; i < 2*64; i+=2)
|
||||
{
|
||||
printf("%08X %08X\n", entry->Code[i], entry->Code[i+1]);
|
||||
}
|
||||
entry->Enabled = true;
|
||||
NumCheatCodes++;*/
|
||||
void SetCodeFile(ARCodeFile* file)
|
||||
{
|
||||
CodeFile = file;
|
||||
}
|
||||
|
||||
|
||||
|
@ -147,9 +58,9 @@ D2000000 00000000)";
|
|||
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
|
||||
case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F)
|
||||
|
||||
void RunCheat(CheatEntry* entry)
|
||||
void RunCheat(ARCode& arcode)
|
||||
{
|
||||
u32* code = &entry->Code[0];
|
||||
u32* code = &arcode.Code[0];
|
||||
|
||||
u32 offset = 0;
|
||||
u32 datareg = 0;
|
||||
|
@ -166,9 +77,11 @@ void RunCheat(CheatEntry* entry)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
if (code >= &arcode.Code[arcode.CodeLen])
|
||||
break;
|
||||
|
||||
u32 a = *code++;
|
||||
u32 b = *code++;
|
||||
if ((a|b) == 0) break;
|
||||
|
||||
u8 op = a >> 24;
|
||||
|
||||
|
@ -179,7 +92,7 @@ void RunCheat(CheatEntry* entry)
|
|||
if ((op & 0xF0) == 0xE0)
|
||||
{
|
||||
for (u32 i = 0; i < b; i += 8)
|
||||
*code += 2;
|
||||
code += 2;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -428,7 +341,7 @@ void RunCheat(CheatEntry* entry)
|
|||
if (bytesleft > 0)
|
||||
{
|
||||
u8* leftover = (u8*)code;
|
||||
*code += 2;
|
||||
code += 2;
|
||||
if (bytesleft >= 4)
|
||||
{
|
||||
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
|
||||
|
@ -477,13 +390,19 @@ void RunCheat(CheatEntry* entry)
|
|||
|
||||
void RunCheats()
|
||||
{
|
||||
// TODO: make it disableable in general
|
||||
if (!CodeFile) return;
|
||||
|
||||
for (u32 i = 0; i < NumCheatCodes; i++)
|
||||
for (ARCodeCatList::iterator i = CodeFile->Categories.begin(); i != CodeFile->Categories.end(); i++)
|
||||
{
|
||||
CheatEntry* entry = &CheatCodes[i];
|
||||
if (entry->Enabled)
|
||||
RunCheat(entry);
|
||||
ARCodeCat& cat = *i;
|
||||
|
||||
for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++)
|
||||
{
|
||||
ARCode& code = *j;
|
||||
|
||||
if (code.Enabled)
|
||||
RunCheat(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef ARENGINE_H
|
||||
#define ARENGINE_H
|
||||
|
||||
#include "ARCodeFile.h"
|
||||
|
||||
namespace AREngine
|
||||
{
|
||||
|
||||
|
@ -26,6 +28,8 @@ bool Init();
|
|||
void DeInit();
|
||||
void Reset();
|
||||
|
||||
void SetCodeFile(ARCodeFile* file);
|
||||
|
||||
void RunCheats();
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ project(core)
|
|||
set (CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_library(core STATIC
|
||||
ARCodeList.cpp
|
||||
ARCodeFile.cpp
|
||||
AREngine.cpp
|
||||
ARM.cpp
|
||||
ARM_InstrTable.h
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
Loading…
Reference in New Issue