Implement bootstrapping (#73)

This commit is contained in:
Void 2020-10-26 22:38:21 -05:00 committed by GitHub
parent 581e0545a0
commit 44f3a0ccb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 494 additions and 18 deletions

View File

@ -12,7 +12,7 @@ struct ClipboardFile {
int drive; // 0 == SD card, 1 == Flashcard, 2 == RAMdrive 1, 3 == RAMdrive 2
bool nitro;
ClipboardFile(std::string path, std::string name, bool folder, int drive, bool nitro) : path(path), name(name), folder(folder), drive(drive), nitro(nitro) {}
ClipboardFile(std::string path, std::string name, bool folder, int drive, bool nitro) : path(std::move(path)), name(std::move(name)), folder(folder), drive(drive), nitro(nitro) {}
};
extern std::vector<ClipboardFile> clipboard;

View File

@ -39,6 +39,8 @@
#include "driveOperations.h"
#include "dumpOperations.h"
#include "nitrofs.h"
#include "inifile.h"
#include "nds_loader_arm9.h"
#define SCREEN_COLS 22
#define ENTRIES_PER_SCREEN 23
@ -105,7 +107,7 @@ void getDirectoryContents (std::vector<DirEntry>& dirContents) {
if (!dirEntry.isDirectory) {
dirEntry.size = getFileSize(dirEntry.name.c_str());
}
if (extension(dirEntry.name, {"nds", "argv", "dsi", "ids", "app"})) {
if (extension(dirEntry.name, {"nds", "argv", "dsi", "ids", "app", "srl"})) {
dirEntry.isApp = ((currentDrive == 0 && sdMounted) || (currentDrive == 1 && flashcardMounted));
} else if (extension(dirEntry.name, {"firm"})) {
dirEntry.isApp = (isDSiMode() && is3DS && sdMounted);
@ -208,40 +210,35 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
iprintf ("\x1b[%d;0H", cursorScreenPos + OPTIONS_ENTRIES_START_ROW);
if (!entry->isDirectory) {
if (entry->isApp) {
maxCursors++;
assignedOp[maxCursors] = FileOperation::bootFile;
printf(" Boot file\n");
assignedOp[++maxCursors] = FileOperation::bootstrapFile;
printf(" Bootstrap file\n");
assignedOp[++maxCursors] = FileOperation::bootFile;
printf(" Boot file (Direct)\n");
}
if(extension(entry->name, {"nds", "dsi", "ids", "app"}))
{
maxCursors++;
assignedOp[maxCursors] = FileOperation::mountNitroFS;
assignedOp[++maxCursors] = FileOperation::mountNitroFS;
printf(" Mount NitroFS\n");
}
else if(extension(entry->name, {"sav"}))
{
maxCursors++;
assignedOp[maxCursors] = FileOperation::restoreSave;
assignedOp[++maxCursors] = FileOperation::restoreSave;
printf(" Restore save\n");
}
else if(extension(entry->name, {"img", "sd"}))
{
maxCursors++;
assignedOp[maxCursors] = FileOperation::mountImg;
assignedOp[++maxCursors] = FileOperation::mountImg;
printf(" Mount as FAT image\n");
}
}
maxCursors++;
assignedOp[maxCursors] = FileOperation::showInfo;
assignedOp[++maxCursors] = FileOperation::showInfo;
printf(entry->isDirectory ? " Show directory info\n" : " Show file info\n");
if (sdMounted && (strcmp(path, "sd:/gm9i/out/") != 0)) {
maxCursors++;
assignedOp[maxCursors] = FileOperation::copySdOut;
assignedOp[++maxCursors] = FileOperation::copySdOut;
printf(" Copy to sd:/gm9i/out\n");
}
if (flashcardMounted && (strcmp(path, "fat:/gm9i/out/") != 0)) {
maxCursors++;
assignedOp[maxCursors] = FileOperation::copyFatOut;
assignedOp[++maxCursors] = FileOperation::copyFatOut;
printf(" Copy to fat:/gm9i/out\n");
}
printf("\n");
@ -287,6 +284,24 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
iprintf ("\x1b[%d;3H", optionOffset + OPTIONS_ENTRIES_START_ROW+cursorScreenPos);
printf("Now loading...");
break;
} case FileOperation::bootstrapFile: {
char baseFile[256], savePath[PATH_MAX]; //, bootstrapConfigPath[32];
//snprintf(bootstrapConfigPath, 32, "%s:/_nds/nds-bootstrap.ini", isDSiMode() ? "sd" : "fat");
strncpy(baseFile, entry->name.c_str(), 256);
*strrchr(baseFile, '.') = 0;
snprintf(savePath, PATH_MAX, "%s%s%s.sav", path, !access("saves", F_OK) ? "saves/" : "", baseFile);
CIniFile bootstrapConfig("/_nds/nds-bootstrap.ini");
bootstrapConfig.SetString("NDS-BOOTSTRAP", "NDS_PATH", fullPath);
bootstrapConfig.SetString("NDS-BOOTSTRAP", "SAV_PATH", savePath);
bootstrapConfig.SetInt("NDS-BOOTSTRAP", "DSI_MODE", 0);
bootstrapConfig.SaveIniFile("/_nds/nds-bootstrap.ini");
// TODO Something less hacky lol
chdir("/_nds");
// TODO Read header and check for homebrew flag, based on that runNdsFile nds-bootstrap(-hb)-release
entry->name = "nds-bootstrap-release.nds";
applaunch = true;
return FileOperation::bootFile;
break;
} case FileOperation::restoreSave: {
ndsCardSaveRestore(entry->name.c_str());
break;

View File

@ -35,6 +35,7 @@ struct DirEntry {
enum class FileOperation {
none,
bootFile,
bootstrapFile,
mountNitroFS,
mountImg,
restoreSave,

393
arm9/source/inifile.cpp Normal file
View File

@ -0,0 +1,393 @@
/*
inifile.cpp
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdio>
#include <cstdlib>
#include "inifile.h"
static bool freadLine(FILE* f,std::string& str)
{
str.clear();
__read:
char p=0;
size_t readed=fread(&p,1,1,f);
if(0==readed)
{
str="";
return false;
}
if('\n'==p||'\r'==p)
{
str="";
return true;
}
while(p!='\n'&&p!='\r'&&readed)
{
str+=p;
readed=fread(&p,1,1,f);
}
if(str.empty()||""==str)
{
goto __read;
}
return true;
}
static void trimString(std::string& str)
{
size_t first=str.find_first_not_of(" \t"),last;
if(first==str.npos)
{
str="";
}
else
{
last=str.find_last_not_of(" \t");
if(first>0||(last+1)<str.length()) str=str.substr(first,last-first+1);
}
}
CIniFile::CIniFile()
{
m_bLastResult=false;
m_bModified=false;
m_bReadOnly=false;
}
CIniFile::CIniFile(const std::string& filename)
{
m_sFileName=filename;
m_bLastResult=false;
m_bModified=false;
m_bReadOnly=false;
LoadIniFile(m_sFileName);
}
CIniFile::~CIniFile()
{
if(m_FileContainer.size()>0)
{
m_FileContainer.clear();
}
}
void CIniFile::SetString(const std::string& Section,const std::string& Item,const std::string& Value)
{
if(GetFileString(Section,Item)!=Value)
{
SetFileString(Section,Item,Value);
m_bModified=true;
}
}
void CIniFile::SetInt(const std::string& Section,const std::string& Item,int Value)
{
char buf[16];
snprintf(buf, sizeof(buf), "%d", Value);
std::string strtemp(buf);
if(GetFileString(Section,Item)!=strtemp)
{
SetFileString(Section,Item,strtemp);
m_bModified=true;
}
}
std::string CIniFile::GetString(const std::string& Section,const std::string& Item)
{
return GetFileString(Section,Item);
}
std::string CIniFile::GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue)
{
std::string temp=GetString(Section,Item);
if(!m_bLastResult)
{
SetString(Section,Item,DefaultValue);
temp=DefaultValue;
}
return temp;
}
void CIniFile::GetStringVector(const std::string& Section,const std::string& Item,std::vector< std::string >& strings,char delimiter)
{
std::string strValue=GetFileString(Section,Item);
strings.clear();
size_t pos;
while((pos=strValue.find(delimiter),strValue.npos!=pos))
{
const std::string string=strValue.substr(0,pos);
if(string.length())
{
strings.push_back(string);
}
strValue=strValue.substr(pos+1,strValue.npos);
}
if(strValue.length())
{
strings.push_back(strValue);
}
}
void CIniFile::SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter)
{
std::string strValue;
for(size_t ii=0;ii<strings.size();++ii)
{
if(ii) strValue+=delimiter;
strValue+=strings[ii];
}
SetString(Section,Item,strValue);
}
int CIniFile::GetInt(const std::string& Section,const std::string& Item)
{
std::string value=GetFileString(Section,Item);
if(value.size()>2&&'0'==value[0]&&('x'==value[1]||'X'==value[1]))
return strtol(value.c_str(),NULL,16);
else
return strtol(value.c_str(),NULL,10);
}
int CIniFile::GetInt(const std::string& Section,const std::string& Item,int DefaultValue)
{
int temp;
temp=GetInt(Section,Item);
if(!m_bLastResult)
{
SetInt(Section,Item,DefaultValue);
temp=DefaultValue;
}
return temp;
}
bool CIniFile::LoadIniFile(const std::string& FileName)
{
//dbg_printf("load %s\n",FileName.c_str());
if(FileName!="") m_sFileName=FileName;
FILE* f=fopen(FileName.c_str(),"rb");
if(NULL==f) return false;
//check for utf8 bom.
char bom[3];
if(fread(bom,3,1,f)==1&&bom[0]==0xef&&bom[1]==0xbb&&bom[2]==0xbf) ;
else fseek(f,0,SEEK_SET);
std::string strline("");
m_FileContainer.clear();
while(freadLine(f,strline))
{
trimString(strline);
if(strline!=""&&';'!=strline[0]&&'/'!=strline[0]&&'!'!=strline[0]) m_FileContainer.push_back(strline);
}
fclose(f);
m_bLastResult=false;
m_bModified=false;
return true;
}
bool CIniFile::SaveIniFileModified(const std::string& FileName)
{
if(m_bModified==true)
{
return SaveIniFile(FileName);
}
return true;
}
bool CIniFile::SaveIniFile(const std::string& FileName)
{
if(FileName!="")
m_sFileName=FileName;
FILE* f=fopen(m_sFileName.c_str(),"wb");
if(NULL==f)
{
return false;
}
for(size_t ii=0;ii<m_FileContainer.size();ii++)
{
std::string& strline=m_FileContainer[ii];
size_t notSpace=strline.find_first_not_of(' ');
strline=strline.substr(notSpace);
if(strline.find('[')==0&&ii>0)
{
if(!m_FileContainer[ii-1].empty()&&m_FileContainer[ii-1]!="")
fwrite("\r\n",1,2,f);
}
if(!strline.empty()&&strline!="")
{
fwrite(strline.c_str(),1,strline.length(),f);
fwrite("\r\n",1,2,f);
}
}
fclose(f);
m_bModified=false;
return true;
}
std::string CIniFile::GetFileString(const std::string& Section,const std::string& Item)
{
std::string strline;
std::string strSection;
std::string strItem;
std::string strValue;
size_t ii=0;
size_t iFileLines=m_FileContainer.size();
if(m_bReadOnly)
{
cSectionCache::iterator it=m_Cache.find(Section);
if((it!=m_Cache.end())) ii=it->second;
}
m_bLastResult=false;
if(iFileLines>0)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t rBracketPos=0;
if('['==strline[0]) rBracketPos=strline.find(']');
if(rBracketPos>0&&rBracketPos!=std::string::npos)
{
strSection=strline.substr(1,rBracketPos-1);
if(m_bReadOnly) m_Cache.insert(std::make_pair(strSection,ii-1));
if(strSection==Section)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t equalsignPos=strline.find('=');
if(equalsignPos!=strline.npos)
{
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
if(last==strline.npos) strItem="";
else strItem=strline.substr(0,last+1);
if(strItem==Item)
{
size_t first=strline.find_first_not_of(" \t",equalsignPos+1);
if(first==strline.npos) strValue="";
else strValue=strline.substr(first);
m_bLastResult=true;
return strValue;
}
}
else if('['==strline[0])
{
break;
}
}
break;
}
}
}
}
return std::string("");
}
void CIniFile::SetFileString(const std::string& Section,const std::string& Item,const std::string& Value)
{
std::string strline;
std::string strSection;
std::string strItem;
if(m_bReadOnly) return;
size_t ii=0;
size_t iFileLines=m_FileContainer.size();
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t rBracketPos=0;
if('['==strline[0]) rBracketPos=strline.find(']');
if(rBracketPos>0&&rBracketPos!=std::string::npos)
{
strSection=strline.substr(1,rBracketPos-1);
if(strSection==Section)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t equalsignPos=strline.find('=');
if(equalsignPos!=strline.npos)
{
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
if(last==strline.npos) strItem="";
else strItem=strline.substr(0,last+1);
if(Item==strItem)
{
ReplaceLine(ii-1,Item+" = "+Value);
return;
}
}
else if('['==strline[0])
{
InsertLine(ii-1,Item+" = "+Value);
return;
}
}
InsertLine(ii,Item+" = "+Value);
return;
}
}
}
InsertLine(ii,"["+Section+"]");
InsertLine(ii+1,Item+" = "+Value);
return;
}
bool CIniFile::InsertLine(size_t line,const std::string& str)
{
m_FileContainer.insert(m_FileContainer.begin()+line,str);
return true;
}
bool CIniFile::ReplaceLine(size_t line,const std::string& str)
{
m_FileContainer[line]=str;
return true;
}

67
arm9/source/inifile.h Normal file
View File

@ -0,0 +1,67 @@
/*
inifile.h
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009-2010 yellow wood goblin
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INIFILE_H_
#define _INIFILE_H_
#include <string>
#include <vector>
#include <map>
class CIniFile
{
public:
CIniFile();
explicit CIniFile(const std::string& filename);
virtual ~CIniFile();
public:
bool LoadIniFile(const std::string& FileName);
bool SaveIniFile(const std::string& FileName);
bool SaveIniFileModified(const std::string& FileName);
std::string GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue);
void SetString(const std::string& Section,const std::string& Item,const std::string& Value);
int GetInt(const std::string& Section,const std::string& Item,int DefaultValue);
void SetInt(const std::string& Section,const std::string& Item,int Value);
void GetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
void SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
protected:
std::string m_sFileName;
typedef std::vector<std::string> cStringArray;
cStringArray m_FileContainer;
bool m_bLastResult;
bool m_bModified;
bool m_bReadOnly;
typedef std::map<std::string,size_t> cSectionCache;
cSectionCache m_Cache;
bool InsertLine(size_t line,const std::string& str);
bool ReplaceLine(size_t line,const std::string& str);
void SetFileString(const std::string& Section,const std::string& Item,const std::string& Value);
std::string GetFileString(const std::string& Section,const std::string& Item);
std::string GetString(const std::string& Section,const std::string& Item);
int GetInt(const std::string& Section,const std::string& Item);
};
#endif // _INIFILE_H_

View File

@ -295,7 +295,7 @@ int main(int argc, char **argv) {
argarray.push_back(strdup(filename.c_str()));
}
if (extension(filename, {"nds", "dsi", "ids", "app"})) {
if (extension(filename, {"nds", "dsi", "ids", "app", "srl"})) {
char *name = argarray.at(0);
strcpy (filePath + pathLen, name);
free(argarray.at(0));