mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-21 05:09:46 -06:00
add AR code file parser and shit
This commit is contained in:
176
src/ARCodeFile.cpp
Normal file
176
src/ARCodeFile.cpp
Normal file
@ -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/.
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ARCODELIST_H
|
#ifndef ARCODEFILE_H
|
||||||
#define ARCODELIST_H
|
#define ARCODEFILE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define ARCL_MAJOR 1
|
typedef struct
|
||||||
#define ARCL_MINOR 1
|
{
|
||||||
|
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:
|
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
|
namespace AREngine
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef struct
|
// AR code file - frontend is responsible for managing this
|
||||||
{
|
ARCodeFile* CodeFile;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
bool Init()
|
||||||
{
|
{
|
||||||
|
CodeFile = nullptr;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
memset(CheatCodes, 0, sizeof(CheatCodes));
|
CodeFile = nullptr;
|
||||||
NumCheatCodes = 0;
|
}
|
||||||
|
|
||||||
// TODO: acquire codes from a sensible source!
|
|
||||||
CheatEntry* entry = &CheatCodes[0];
|
|
||||||
u32* ptr = &entry->Code[0];
|
|
||||||
|
|
||||||
/*char* test = R"(9209D09A 00000000
|
void SetCodeFile(ARCodeFile* file)
|
||||||
6209B468 00000000
|
{
|
||||||
B209B468 00000000
|
CodeFile = file;
|
||||||
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++;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -147,9 +58,9 @@ D2000000 00000000)";
|
|||||||
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
|
case ((x)+0x08): case ((x)+0x09): case ((x)+0x0A): case ((x)+0x0B): \
|
||||||
case ((x)+0x0C): case ((x)+0x0D): case ((x)+0x0E): case ((x)+0x0F)
|
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 offset = 0;
|
||||||
u32 datareg = 0;
|
u32 datareg = 0;
|
||||||
@ -166,9 +77,11 @@ void RunCheat(CheatEntry* entry)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
if (code >= &arcode.Code[arcode.CodeLen])
|
||||||
|
break;
|
||||||
|
|
||||||
u32 a = *code++;
|
u32 a = *code++;
|
||||||
u32 b = *code++;
|
u32 b = *code++;
|
||||||
if ((a|b) == 0) break;
|
|
||||||
|
|
||||||
u8 op = a >> 24;
|
u8 op = a >> 24;
|
||||||
|
|
||||||
@ -179,7 +92,7 @@ void RunCheat(CheatEntry* entry)
|
|||||||
if ((op & 0xF0) == 0xE0)
|
if ((op & 0xF0) == 0xE0)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < b; i += 8)
|
for (u32 i = 0; i < b; i += 8)
|
||||||
*code += 2;
|
code += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -428,7 +341,7 @@ void RunCheat(CheatEntry* entry)
|
|||||||
if (bytesleft > 0)
|
if (bytesleft > 0)
|
||||||
{
|
{
|
||||||
u8* leftover = (u8*)code;
|
u8* leftover = (u8*)code;
|
||||||
*code += 2;
|
code += 2;
|
||||||
if (bytesleft >= 4)
|
if (bytesleft >= 4)
|
||||||
{
|
{
|
||||||
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
|
NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
|
||||||
@ -477,13 +390,19 @@ void RunCheat(CheatEntry* entry)
|
|||||||
|
|
||||||
void RunCheats()
|
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];
|
ARCodeCat& cat = *i;
|
||||||
if (entry->Enabled)
|
|
||||||
RunCheat(entry);
|
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
|
#ifndef ARENGINE_H
|
||||||
#define ARENGINE_H
|
#define ARENGINE_H
|
||||||
|
|
||||||
|
#include "ARCodeFile.h"
|
||||||
|
|
||||||
namespace AREngine
|
namespace AREngine
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -26,6 +28,8 @@ bool Init();
|
|||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void SetCodeFile(ARCodeFile* file);
|
||||||
|
|
||||||
void RunCheats();
|
void RunCheats();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ project(core)
|
|||||||
set (CMAKE_CXX_STANDARD 14)
|
set (CMAKE_CXX_STANDARD 14)
|
||||||
|
|
||||||
add_library(core STATIC
|
add_library(core STATIC
|
||||||
ARCodeList.cpp
|
ARCodeFile.cpp
|
||||||
AREngine.cpp
|
AREngine.cpp
|
||||||
ARM.cpp
|
ARM.cpp
|
||||||
ARM_InstrTable.h
|
ARM_InstrTable.h
|
||||||
|
@ -74,6 +74,9 @@
|
|||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
Reference in New Issue
Block a user