Make-Forwarder-Dsi/arm9/source/main.cpp
2019-02-13 20:18:36 +01:00

273 lines
7.3 KiB
C++

/*---------------------------------------------------------------------------------
Basic template code for starting a DS app
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <cstdio>
#include <fstream>
#include <vector>
#include <unistd.h>
#include <fat.h>
#include "file_browse.h"
#include "headers.h"
#include "utils.h"
#include "menu.h"
#include "inifile.h"
#include "apppatch.h"
CIniFile bootsrtapconfig;
CIniFile bootstrap_template;
PrintConsole upperScreen;
PrintConsole lowerScreen;
void WriteMessage(std::string text, bool clear = false, PrintConsole* screen = nullptr) {
if(screen)
consoleSelect(screen);
if(clear)
consoleClear();
if(text.size() <= DISPLAY_COLUMNS) {
iprintf(text.c_str());
return;
}
std::vector<std::string> words;
std::string temp;
for(int i = 0; i < (int)text.size(); i++) {
if(text[i] == ' ' || text[i] == '\n') {
words.push_back(temp);
temp.clear();
if(text[i] == '\n')
words.push_back("\n");
} else
temp += text[i];
}
if(temp.size())
words.push_back(temp);
int column = 0;
for(auto word : words) {
if(word.size() == 1 && word[0] == '\n') {
if(column != DISPLAY_COLUMNS)
iprintf("\n");
column = 0;
return;
}
int chkval = column + (int)word.size();
if(column)
chkval++;
if(chkval <= DISPLAY_COLUMNS) {
if(column) {
iprintf(" ");
column++;
}
iprintf(word.c_str());
column += (int)word.size();
} else {
if(column != DISPLAY_COLUMNS)
iprintf("\n");
column = (int)word.size();
iprintf(word.c_str());
}
}
}
menu yesno;
void displayInit() {
lowerScreen = *consoleDemoInit();
videoSetMode(MODE_0_2D);
vramSetBankA(VRAM_A_MAIN_BG);
consoleInit(&upperScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
}
bool fileExists(const std::string& file) {
struct stat buf;
return (stat(file.c_str(), &buf) == 0);
}
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
void stop (void) {
//---------------------------------------------------------------------------------
while (1) {
swiWaitForVBlank();
}
}
void wait (void) {
//---------------------------------------------------------------------------------
while (1) {
swiWaitForVBlank();
scanKeys();
int pressed = keysDown();
if(pressed & KEY_A) break;
}
}
const char* GetErrorString(int code) {
switch(code){
case 1:
return "fatInitDefault failed!";
case 2:
return "The MakeForwarder folder is missing!";
case 3:
return "Template.nds is missing from the MakeForwarder folder!";
case 4:
return "Error when reading the template.nds file, make sure to have the correct one!";
case 5:
return "Couldn't open the target rom, or the rom is not a valid target!";
default:
return "";
}
}
void PrintError(int errorcode, bool halt = false) {
consoleSetWindow(&upperScreen, 0, 3, DISPLAY_COLUMNS, 23);
consoleSelect(&upperScreen);
WriteMessage(GetErrorString(errorcode), true);
if (halt)
stop();
else {
WriteMessage("Press A to continue", false);
wait();
consoleClear();
}
}
std::string GetHexid(std::string file, int* chk) {
std::ifstream infile(file, std::ifstream::binary);
infile.seekg(0xc);
if(infile.tellg()!=0xc) {
*chk = 1;
return "";
}
std::string gameid;
gameid.resize(4);
infile.read(&gameid[0], 4);
infile.close();
return string_to_hex(gameid);
}
void CreateForwarder() {
std::vector<std::string> extensionList={".nds"};
WriteMessage("Select the target rom", true, &upperScreen);
consoleSelect(&lowerScreen);
std::string file = browseForFile(extensionList);
chdir("sd:/");
int chk = 0;
std::string gameidhex = GetHexid(file, &chk);
if (chk){
PrintError(5);
return;
}
std::string folderpath("sd:/title/00030004/" + gameidhex);
if(fileExists(folderpath + "/content/00000000.app")) {
WriteMessage("A DsiWare with the same id already exists, do you want to overwrite it?", true, &upperScreen);
int ret = yesno.DoMenu(&lowerScreen);
consoleSelect(&upperScreen);
consoleClear();
if(ret)
return;
}
WriteMessage("Creating forwarder", true, &lowerScreen);
ReplaceBanner("sd:/MakeForwarder/template.nds", file, "sd:/MakeForwarder/banner.nds");
Patch("sd:/MakeForwarder/banner.nds", false);
MakeTmd("sd:/MakeForwarder/banner.nds", "sd:/MakeForwarder/title.tmd");
chk = PathStringReplace("title/00030004/" + gameidhex + "/data/");
if(chk) {
PrintError(chk);
remove("sd:/MakeForwarder/banner.nds");
remove("sd:/MakeForwarder/title.tmd");
return;
}
if(CreatePath("title/00030004/" + gameidhex + "/data", "sd:/") && CreatePath("title/00030004/" + gameidhex + "/content", "sd:/")) {
Movefile("sd:/MakeForwarder/banner.nds", folderpath + "/content/00000000.app");
Movefile("sd:/MakeForwarder/title.tmd", folderpath + "/content/title.tmd");
if(bootstrap_template.HasFileHandle()) {
bootsrtapconfig.SaveIniFile((folderpath + "/data/config.ini").c_str());
bootstrap_template.SetString( "NDS-BOOTSTRAP", "NDS_PATH", file.c_str());
std::string savePath = ReplaceAll(file, ".nds", ".sav");
bootstrap_template.SetString( "NDS-BOOTSTRAP", "SAV_PATH", savePath.c_str());
bootstrap_template.SaveIniFile((folderpath + "/data/bootstrap.ini").c_str());
}
}
}
void SetBootstrap() {
std::vector<std::string> extensionList={".nds"};
WriteMessage("Select the target bootstrap file to be used", true, &upperScreen);
consoleSelect(&lowerScreen);
std::string file = browseForFile(extensionList);
chdir("sd:/");
size_t found = file.find_last_of("/");
std::string bootstrappath=file.substr(0,found+1);
std::string bootstrapversion=file.substr(found+1);
bootsrtapconfig.SetString( "NDS-FORWARDER", "BOOTSTRAP_PATH", bootstrappath.c_str());
bootsrtapconfig.SetString( "NDS-FORWARDER", "BOOTSTRAP_VERSION", bootstrapversion.c_str());
bootstrap_template.LoadIniFile((bootstrappath+"nds-bootstrap.ini").c_str());
}
void CheckResources() {
if (!fileExists("sd:/MakeForwarder"))
PrintError(2, true);
if (!fileExists("sd:/MakeForwarder/template.nds"))
PrintError(3, true);
std::ifstream ndstemplate("sd:/MakeForwarder/template.nds", std::ifstream::binary);
std::string str((std::istreambuf_iterator<char>(ndstemplate)),
std::istreambuf_iterator<char>());
std::size_t found = str.find("sd:/kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk");
if(found == std::string::npos)
PrintError(4, true);
}
int main() {
displayInit();
consoleSetWindow(&upperScreen, 0, 0, DISPLAY_COLUMNS, 3);
WriteMessage("Forwarder maker by edo9300 v1.0", true, &upperScreen);
consoleSetWindow(&upperScreen, 0, 3, DISPLAY_COLUMNS, 23);
if (!fatInitDefault())
PrintError(1, true);
CheckResources();
menu mainmenu;
mainmenu.AddOption("Create Forwarder");
mainmenu.AddOption("Set target bootstrap");
yesno.AddOption("Yes");
yesno.AddOption("No");
while(1){
swiWaitForVBlank();
WriteMessage("Use the option \"Set target bootstrap\" to avoid configuring the created forwarders at startup", true, &upperScreen);
int ret = mainmenu.DoMenu(&lowerScreen);
if (ret==0)
CreateForwarder();
else if (ret==1)
SetBootstrap();
else
break;
}
stop();
return 0;
}