mirror of
https://github.com/rvtr/TDT.git
synced 2025-10-31 13:51:07 -04:00
0.6.8
This commit is contained in:
parent
1491f6b862
commit
c05199c59a
@ -18,13 +18,16 @@ static bool delete(Menu* m);
|
|||||||
|
|
||||||
void backupMenu()
|
void backupMenu()
|
||||||
{
|
{
|
||||||
|
clearScreen(&topScreen);
|
||||||
|
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
setMenuHeader(m, "BACKUP MENU");
|
||||||
generateList(m);
|
generateList(m);
|
||||||
|
|
||||||
//no files found
|
//no files found
|
||||||
if (m->itemCount <= 0)
|
if (m->itemCount <= 0)
|
||||||
{
|
{
|
||||||
messageBox("No backups found.\n");
|
messageBox("\x1B[33mNo backups found.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -77,9 +80,9 @@ static int subMenu()
|
|||||||
|
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
|
||||||
addMenuItem(m, "Restore", NULL);
|
addMenuItem(m, "Restore", NULL, 0);
|
||||||
addMenuItem(m, "Delete", NULL);
|
addMenuItem(m, "Delete", NULL, 0);
|
||||||
addMenuItem(m, "Back - [B]", NULL);
|
addMenuItem(m, "Back - [B]", NULL, 0);
|
||||||
|
|
||||||
printMenu(m);
|
printMenu(m);
|
||||||
|
|
||||||
@ -145,7 +148,7 @@ static void generateList(Menu* m)
|
|||||||
char* path = (char*)malloc(strlen(BACKUP_PATH) + strlen(ent->d_name) + 8);
|
char* path = (char*)malloc(strlen(BACKUP_PATH) + strlen(ent->d_name) + 8);
|
||||||
sprintf(path, "%s/%s", BACKUP_PATH, ent->d_name);
|
sprintf(path, "%s/%s", BACKUP_PATH, ent->d_name);
|
||||||
|
|
||||||
addMenuItem(m, ent->d_name, path);
|
addMenuItem(m, ent->d_name, path, 0);
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
@ -166,7 +169,7 @@ static void generateList(Menu* m)
|
|||||||
|
|
||||||
static void restore(Menu* m)
|
static void restore(Menu* m)
|
||||||
{
|
{
|
||||||
char* fpath = m->items[m->cursor];
|
char* fpath = m->items[m->cursor].value;
|
||||||
|
|
||||||
bool choice = NO;
|
bool choice = NO;
|
||||||
{
|
{
|
||||||
@ -183,7 +186,7 @@ static void restore(Menu* m)
|
|||||||
{
|
{
|
||||||
if (!fpath)
|
if (!fpath)
|
||||||
{
|
{
|
||||||
messageBox("Failed to restore backup.\n");
|
messageBox("\x1B[31mFailed to restore backup.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -191,11 +194,11 @@ static void restore(Menu* m)
|
|||||||
|
|
||||||
if (!copyDir(fpath, "/title"))
|
if (!copyDir(fpath, "/title"))
|
||||||
{
|
{
|
||||||
messagePrint("\nFailed to restore backup.\n");
|
messagePrint("\x1B[31m\nFailed to restore backup.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
messagePrint("\nBackup restored.\n");
|
messagePrint("\x1B[42m\nBackup restored.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +208,7 @@ static bool delete(Menu* m)
|
|||||||
{
|
{
|
||||||
if (!m) return false;
|
if (!m) return false;
|
||||||
|
|
||||||
char* fpath = m->items[m->cursor];
|
char* fpath = m->items[m->cursor].value;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool choice = NO;
|
bool choice = NO;
|
||||||
@ -223,13 +226,13 @@ static bool delete(Menu* m)
|
|||||||
{
|
{
|
||||||
if (!fpath)
|
if (!fpath)
|
||||||
{
|
{
|
||||||
messageBox("Failed to delete backup.\n");
|
messageBox("\x1B[31mFailed to delete backup.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!dirExists(fpath))
|
if (!dirExists(fpath))
|
||||||
{
|
{
|
||||||
messageBox("Failed to delete backup.\n");
|
messageBox("\x1B[31mFailed to delete backup.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -238,11 +241,11 @@ static bool delete(Menu* m)
|
|||||||
if (deleteDir(fpath))
|
if (deleteDir(fpath))
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
messagePrint("\nBackup deleted.\n");
|
messagePrint("\x1B[42m\nBackup deleted.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
messagePrint("\nError deleting backup.\n");
|
messagePrint("\n\x1B[31mError deleting backup.\n\x1B[47m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
#include "install.h"
|
#include "install.h"
|
||||||
#include "fat12.h"
|
#include "sav.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "maketmd.h"
|
#include "maketmd.h"
|
||||||
|
#include "rom.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@ -42,7 +43,9 @@ static bool _patchGameCode(tDSiHeader* h)
|
|||||||
}
|
}
|
||||||
while (_titleIsUsed(h));
|
while (_titleIsUsed(h));
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,26 +59,22 @@ static bool _iqueHack(tDSiHeader* h)
|
|||||||
if (h->ndshdr.reserved1[8] == 0x80)
|
if (h->ndshdr.reserved1[8] == 0x80)
|
||||||
{
|
{
|
||||||
iprintf("iQue Hack...");
|
iprintf("iQue Hack...");
|
||||||
|
|
||||||
h->ndshdr.reserved1[8] = 0x00;
|
h->ndshdr.reserved1[8] = 0x00;
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long long _getSize(FILE* f, tDSiHeader* h)
|
static unsigned long long _getSaveDataSize(tDSiHeader* h)
|
||||||
{
|
{
|
||||||
iprintf("Install Size: ");
|
|
||||||
swiWaitForVBlank();
|
|
||||||
|
|
||||||
unsigned long long size = 0;
|
unsigned long long size = 0;
|
||||||
|
|
||||||
//get app size
|
|
||||||
if (f)
|
|
||||||
size = getFileSize(f);
|
|
||||||
|
|
||||||
//add save file size
|
|
||||||
if (h)
|
if (h)
|
||||||
{
|
{
|
||||||
size += h->public_sav_size;
|
size += h->public_sav_size;
|
||||||
@ -86,9 +85,6 @@ static unsigned long long _getSize(FILE* f, tDSiHeader* h)
|
|||||||
size += 0x4000;
|
size += 0x4000;
|
||||||
}
|
}
|
||||||
|
|
||||||
printBytes(size);
|
|
||||||
iprintf("\n");
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +95,15 @@ static bool _checkSdSpace(unsigned long long size)
|
|||||||
|
|
||||||
if (getSDCardFree() < size)
|
if (getSDCardFree() < size)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("No\n");
|
iprintf("No\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Yes\n");
|
iprintf("Yes\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +114,15 @@ static bool _checkDsiSpace(unsigned long long size)
|
|||||||
|
|
||||||
if (getDsiFree() < size)
|
if (getDsiFree() < size)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("No\n");
|
iprintf("No\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Yes\n");
|
iprintf("Yes\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,26 +133,15 @@ static bool _openMenuSlot()
|
|||||||
|
|
||||||
if (getMenuSlotsFree() <= 0)
|
if (getMenuSlotsFree() <= 0)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("No\n");
|
iprintf("No\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return choicePrint("Try installing anyway?");
|
return choicePrint("Try installing anyway?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Yes\n");
|
iprintf("Yes\n");
|
||||||
return true;
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
|
||||||
|
|
||||||
static bool _isDSiRom(tDSiHeader* h)
|
|
||||||
{
|
|
||||||
//high title id must be one of four
|
|
||||||
if (h->tid_high != 0x00030004 &&
|
|
||||||
h->tid_high != 0x00030005 &&
|
|
||||||
h->tid_high != 0x00030015 &&
|
|
||||||
h->tid_high != 0x00030017)
|
|
||||||
{
|
|
||||||
iprintf("Error: This is not a DSi rom.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +156,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!dataPath)
|
if (!dataPath)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -174,7 +169,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -182,7 +179,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
|
|||||||
fputc(0, f);
|
fputc(0, f);
|
||||||
initFatHeader(f);
|
initFatHeader(f);
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -202,7 +201,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!dataPath)
|
if (!dataPath)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -213,7 +214,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -221,7 +224,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
|
|||||||
fputc(0, f);
|
fputc(0, f);
|
||||||
initFatHeader(f);
|
initFatHeader(f);
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -241,7 +246,9 @@ static void _createBannerSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!dataPath)
|
if (!dataPath)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -252,14 +259,18 @@ static void _createBannerSav(tDSiHeader* h, char* dataPath)
|
|||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fseek(f, 0x4000 - 1, SEEK_SET);
|
fseek(f, 0x4000 - 1, SEEK_SET);
|
||||||
fputc(0, f);
|
fputc(0, f);
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -274,10 +285,14 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
|
|
||||||
//confirmation message
|
//confirmation message
|
||||||
{
|
{
|
||||||
char msg[512];
|
char str[] = "Are you sure you want to install\n";
|
||||||
sprintf(msg, "Are you sure you want to install\n%s\n", fpath);
|
char* msg = (char*)malloc(strlen(str) + strlen(fpath) + 8);
|
||||||
|
sprintf(msg, "%s%s\n", str, fpath);
|
||||||
|
|
||||||
if (choiceBox(msg) == NO)
|
bool choice = choiceBox(msg);
|
||||||
|
free(msg);
|
||||||
|
|
||||||
|
if (choice == NO)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,33 +300,49 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
clearScreen(&bottomScreen);
|
clearScreen(&bottomScreen);
|
||||||
iprintf("Installing %s\n\n", fpath); swiWaitForVBlank();
|
iprintf("Installing %s\n\n", fpath); swiWaitForVBlank();
|
||||||
|
|
||||||
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
FILE* f = fopen(fpath, "rb");
|
|
||||||
|
|
||||||
if (!f)
|
if (!h)
|
||||||
{
|
{
|
||||||
iprintf("Error: could not open file.\n");
|
iprintf("\x1B[31m"); //red
|
||||||
|
iprintf("Error: ");
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
|
iprintf("Could not open file.\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool fixHeader = false;
|
bool fixHeader = false;
|
||||||
|
|
||||||
//read header
|
if (_patchGameCode(h))
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
fread(header, sizeof(tDSiHeader), 1, f);
|
|
||||||
|
|
||||||
if (_patchGameCode(header))
|
|
||||||
fixHeader = true;
|
fixHeader = true;
|
||||||
|
|
||||||
if (!_isDSiRom(header))
|
//title id must be one of these
|
||||||
|
if (h->tid_high == 0x00030004 ||
|
||||||
|
h->tid_high == 0x00030005 ||
|
||||||
|
h->tid_high == 0x00030015 ||
|
||||||
|
h->tid_high == 0x00030017)
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
|
iprintf("Error: ");
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
|
iprintf("This is not a DSi rom.\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long long fileSize = getFileSize(f);
|
//get install size
|
||||||
unsigned long long installSize = _getSize(f, header);
|
iprintf("Install Size: ");
|
||||||
|
swiWaitForVBlank();
|
||||||
|
|
||||||
|
unsigned long long fileSize = getRomSize(fpath);
|
||||||
|
unsigned long long installSize = fileSize + _getSaveDataSize(h);
|
||||||
|
|
||||||
//do not need file opened anymore
|
printBytes(installSize);
|
||||||
fclose(f);
|
iprintf("\n");
|
||||||
|
|
||||||
if (!_checkSdSpace(installSize))
|
if (!_checkSdSpace(installSize))
|
||||||
goto error;
|
goto error;
|
||||||
@ -324,20 +355,22 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
{
|
{
|
||||||
iprintf("System Title Patch...");
|
iprintf("System Title Patch...");
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
header->tid_high = 0x00030015;
|
h->tid_high = 0x00030015;
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
|
||||||
fixHeader = true;
|
fixHeader = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//skip nand check if system title
|
//skip nand check if system title
|
||||||
if (header->tid_high != 0x00030015)
|
if (h->tid_high != 0x00030015)
|
||||||
{
|
{
|
||||||
if (!_checkDsiSpace(installSize))
|
if (!_checkDsiSpace(installSize))
|
||||||
{
|
{
|
||||||
if (choicePrint("Install as system title?"))
|
if (choicePrint("Install as system title?"))
|
||||||
{
|
{
|
||||||
header->tid_high = 0x00030015;
|
h->tid_high = 0x00030015;
|
||||||
fixHeader = true;
|
fixHeader = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -348,22 +381,29 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_iqueHack(header))
|
if (_iqueHack(h))
|
||||||
fixHeader = true;
|
fixHeader = true;
|
||||||
|
|
||||||
//check if title is free
|
|
||||||
if (_titleIsUsed(header))
|
|
||||||
{
|
|
||||||
char msg[512];
|
|
||||||
sprintf(msg, "Title %08x is already used.\nInstall anyway?", (unsigned int)header->tid_low);
|
|
||||||
|
|
||||||
if (choicePrint(msg) == NO)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
//create title directory /title/XXXXXXXX/XXXXXXXX
|
//create title directory /title/XXXXXXXX/XXXXXXXX
|
||||||
char dirPath[32];
|
char dirPath[32];
|
||||||
sprintf(dirPath, "/title/%08x/%08x", (unsigned int)header->tid_high, (unsigned int)header->tid_low);
|
sprintf(dirPath, "/title/%08x/%08x", (unsigned int)h->tid_high, (unsigned int)h->tid_low);
|
||||||
|
|
||||||
|
//check if title is free
|
||||||
|
if (_titleIsUsed(h))
|
||||||
|
{
|
||||||
|
char msg[64];
|
||||||
|
sprintf(msg, "Title %08x is already used.\nInstall anyway?", (unsigned int)h->tid_low);
|
||||||
|
|
||||||
|
if (choicePrint(msg) == NO)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iprintf("\nDeleting:\n");
|
||||||
|
deleteDir(dirPath);
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mkdir(dirPath, 0777);
|
mkdir(dirPath, 0777);
|
||||||
|
|
||||||
@ -384,26 +424,67 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
|
|
||||||
//copy nds file to app
|
//copy nds file to app
|
||||||
{
|
{
|
||||||
if (copyFile(fpath, appPath) == 0)
|
int result = 0;
|
||||||
|
|
||||||
|
if (!romIsCia(fpath))
|
||||||
|
result = copyFile(fpath, appPath);
|
||||||
|
else
|
||||||
|
result = copyFilePart(fpath, 0x3900, fileSize, appPath);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
|
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
iprintf("Empty input path.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
iprintf("Empty output path.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
iprintf("Error opening input file.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
iprintf("Error opening output file.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
//pad out banner if it is the last part of the file
|
//pad out banner if it is the last part of the file
|
||||||
{
|
{
|
||||||
if (header->ndshdr.bannerOffset == fileSize - 0x1C00)
|
if (h->ndshdr.bannerOffset == fileSize - 0x1C00)
|
||||||
{
|
{
|
||||||
iprintf("Padding banner...");
|
iprintf("Padding banner...");
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
|
|
||||||
if (padFile(appPath, 0x7C0) == false)
|
if (padFile(appPath, 0x7C0) == false)
|
||||||
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,25 +496,29 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
|
|
||||||
//fix header checksum
|
//fix header checksum
|
||||||
header->ndshdr.headerCRC16 = swiCRC16(0xFFFF, header, 0x15E);
|
h->ndshdr.headerCRC16 = swiCRC16(0xFFFF, h, 0x15E);
|
||||||
|
|
||||||
//fix RSA signature
|
//fix RSA signature
|
||||||
u8 buffer[20];
|
u8 buffer[20];
|
||||||
swiSHA1Calc(&buffer, header, 0xE00);
|
swiSHA1Calc(&buffer, h, 0xE00);
|
||||||
memcpy(&(header->rsa_signature[0x6C]), buffer, 20);
|
memcpy(&(h->rsa_signature[0x6C]), buffer, 20);
|
||||||
|
|
||||||
f = fopen(appPath, "r+");
|
FILE* f = fopen(appPath, "r+");
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Failed\n");
|
iprintf("Failed\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
fwrite(header, sizeof(tDSiHeader), 1, f);
|
fwrite(h, sizeof(tDSiHeader), 1, f);
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -458,25 +543,27 @@ bool install(char* fpath, bool systemTitle)
|
|||||||
|
|
||||||
mkdir(dataPath, 0777);
|
mkdir(dataPath, 0777);
|
||||||
|
|
||||||
_createPublicSav(header, dataPath);
|
_createPublicSav(h, dataPath);
|
||||||
_createPrivateSav(header, dataPath);
|
_createPrivateSav(h, dataPath);
|
||||||
_createBannerSav(header, dataPath);
|
_createBannerSav(h, dataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
//end
|
//end
|
||||||
result = true;
|
result = true;
|
||||||
iprintf("\nInstallation complete.\nBack - [B]\n");
|
iprintf("\x1B[42m"); //green
|
||||||
keyWait(KEY_A | KEY_B);
|
iprintf("\nInstallation complete.\n");
|
||||||
}
|
iprintf("\x1B[47m"); //white
|
||||||
|
iprintf("Back - [B]\n");
|
||||||
|
keyWait(KEY_A | KEY_B);
|
||||||
|
|
||||||
goto complete;
|
goto complete;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
messagePrint("\nInstallation failed.\n");
|
messagePrint("\x1B[31m\nInstallation failed.\n\x1B[47m");
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
fclose(f);
|
free(h);
|
||||||
free(header);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "app.h"
|
#include "rom.h"
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
@ -13,28 +13,41 @@ enum {
|
|||||||
INSTALL_MENU_BACK
|
INSTALL_MENU_BACK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static char currentDir[512] = "";
|
||||||
|
|
||||||
static void generateList(Menu* m);
|
static void generateList(Menu* m);
|
||||||
static void printItem(Menu* m);
|
static void printItem(Menu* m);
|
||||||
static int subMenu();
|
static int subMenu();
|
||||||
static bool delete(Menu* m);
|
static bool delete(Menu* m);
|
||||||
|
|
||||||
|
static void _setHeader(Menu* m)
|
||||||
|
{
|
||||||
|
if (!m) return;
|
||||||
|
if (currentDir[0] == '\0')
|
||||||
|
setMenuHeader(m, "/");
|
||||||
|
else
|
||||||
|
setMenuHeader(m, currentDir);
|
||||||
|
}
|
||||||
|
|
||||||
void installMenu()
|
void installMenu()
|
||||||
{
|
{
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
_setHeader(m);
|
||||||
generateList(m);
|
generateList(m);
|
||||||
|
|
||||||
//no files found
|
//no files found
|
||||||
if (m->itemCount <= 0)
|
/* if (m->itemCount <= 0)
|
||||||
{
|
{
|
||||||
clearScreen(&bottomScreen);
|
clearScreen(&bottomScreen);
|
||||||
|
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("No files found.\n");
|
iprintf("No files found.\n");
|
||||||
iprintf("Place .nds, .app, or .dsi files in %s\n", ROM_PATH);
|
iprintf("\x1B[47m"); //white
|
||||||
iprintf("\nBack - [B]\n");
|
iprintf("\nBack - [B]\n");
|
||||||
|
|
||||||
keyWait(KEY_B | KEY_A | KEY_START);
|
keyWait(KEY_B | KEY_A | KEY_START);
|
||||||
}
|
}
|
||||||
else
|
else*/
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -51,51 +64,70 @@ void installMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//back
|
//back
|
||||||
if (keysDown() & KEY_B || m->itemCount <= 0)
|
if (keysDown() & KEY_B)
|
||||||
{
|
{
|
||||||
break;
|
char* ptr = strrchr(currentDir, '/');
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
*ptr = '\0';
|
||||||
|
_setHeader(m);
|
||||||
|
resetMenu(m);
|
||||||
|
generateList(m);
|
||||||
|
printMenu(m);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (keysDown() & KEY_X)
|
||||||
|
break;
|
||||||
|
|
||||||
//selection
|
//selection
|
||||||
else if (keysDown() & KEY_A)
|
else if (keysDown() & KEY_A)
|
||||||
{
|
{
|
||||||
switch (subMenu())
|
if (m->itemCount > 0)
|
||||||
{
|
{
|
||||||
case INSTALL_MENU_INSTALL:
|
if (m->items[m->cursor].directory == false)
|
||||||
{
|
{
|
||||||
if (install(m->items[m->cursor], false))
|
//nds file
|
||||||
|
switch (subMenu())
|
||||||
{
|
{
|
||||||
resetMenu(m);
|
case INSTALL_MENU_INSTALL:
|
||||||
generateList(m);
|
install(m->items[m->cursor].value, false);
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
break;
|
case INSTALL_MENU_SYSTEM_TITLE:
|
||||||
|
install(m->items[m->cursor].value, true);
|
||||||
case INSTALL_MENU_SYSTEM_TITLE:
|
break;
|
||||||
{
|
|
||||||
if (install(m->items[m->cursor], true))
|
|
||||||
{
|
|
||||||
resetMenu(m);
|
|
||||||
generateList(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INSTALL_MENU_DELETE:
|
case INSTALL_MENU_DELETE:
|
||||||
{
|
{
|
||||||
if (delete(m))
|
if (delete(m))
|
||||||
{
|
{
|
||||||
resetMenu(m);
|
resetMenu(m);
|
||||||
generateList(m);
|
generateList(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSTALL_MENU_BACK:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
|
{
|
||||||
|
//directory
|
||||||
|
sprintf(currentDir, "%s", m->items[m->cursor].value);
|
||||||
|
_setHeader(m);
|
||||||
|
resetMenu(m);
|
||||||
|
generateList(m);
|
||||||
|
}
|
||||||
|
|
||||||
case INSTALL_MENU_BACK:
|
printMenu(m);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printMenu(m);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +148,7 @@ static void generateList(Menu* m)
|
|||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
struct dirent* ent;
|
struct dirent* ent;
|
||||||
DIR* dir = opendir(ROM_PATH);
|
DIR* dir = opendir(currentDir);
|
||||||
|
|
||||||
if (dir)
|
if (dir)
|
||||||
{
|
{
|
||||||
@ -128,14 +160,35 @@ static void generateList(Menu* m)
|
|||||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ent->d_type != DT_DIR)
|
if (ent->d_type == DT_DIR)
|
||||||
|
{
|
||||||
|
if (count < m->page * ITEMS_PER_PAGE)
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m->itemCount >= ITEMS_PER_PAGE)
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char* fpath = (char*)malloc(strlen(currentDir) + strlen(ent->d_name) + 8);
|
||||||
|
sprintf(fpath, "%s/%s", currentDir, ent->d_name);
|
||||||
|
|
||||||
|
addMenuItem(m, ent->d_name, fpath, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (strstr(ent->d_name, ".nds") != NULL ||
|
if (strstr(ent->d_name, ".nds") != NULL ||
|
||||||
strstr(ent->d_name, ".app") != NULL ||
|
strstr(ent->d_name, ".app") != NULL ||
|
||||||
strstr(ent->d_name, ".dsi") != NULL ||
|
strstr(ent->d_name, ".dsi") != NULL ||
|
||||||
|
strstr(ent->d_name, ".cia") != NULL ||
|
||||||
strstr(ent->d_name, ".NDS") != NULL ||
|
strstr(ent->d_name, ".NDS") != NULL ||
|
||||||
strstr(ent->d_name, ".APP") != NULL ||
|
strstr(ent->d_name, ".APP") != NULL ||
|
||||||
strstr(ent->d_name, ".DSI") != NULL)
|
strstr(ent->d_name, ".DSI") != NULL ||
|
||||||
|
strstr(ent->d_name, ".CIA") != NULL)
|
||||||
{
|
{
|
||||||
if (count < m->page * ITEMS_PER_PAGE)
|
if (count < m->page * ITEMS_PER_PAGE)
|
||||||
count += 1;
|
count += 1;
|
||||||
@ -147,10 +200,10 @@ static void generateList(Menu* m)
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char* fpath = (char*)malloc(strlen(ROM_PATH) + strlen(ent->d_name) + 8);
|
char* fpath = (char*)malloc(strlen(currentDir) + strlen(ent->d_name) + 8);
|
||||||
sprintf(fpath, "%s/%s", ROM_PATH, ent->d_name);
|
sprintf(fpath, "%s/%s", currentDir, ent->d_name);
|
||||||
|
|
||||||
addMenuItem(m, ent->d_name, fpath);
|
addMenuItem(m, ent->d_name, fpath, 0);
|
||||||
|
|
||||||
free(fpath);
|
free(fpath);
|
||||||
}
|
}
|
||||||
@ -174,7 +227,12 @@ static void generateList(Menu* m)
|
|||||||
static void printItem(Menu* m)
|
static void printItem(Menu* m)
|
||||||
{
|
{
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
printAppInfo(m->items[m->cursor]);
|
if (m->itemCount <= 0) return;
|
||||||
|
|
||||||
|
if (m->items[m->cursor].directory)
|
||||||
|
clearScreen(&topScreen);
|
||||||
|
else
|
||||||
|
printRomInfo(m->items[m->cursor].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subMenu()
|
static int subMenu()
|
||||||
@ -183,10 +241,10 @@ static int subMenu()
|
|||||||
|
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
|
||||||
addMenuItem(m, "Install", NULL);
|
addMenuItem(m, "Install", NULL, 0);
|
||||||
addMenuItem(m, "Install as System Title", NULL);
|
addMenuItem(m, "Install as System Title", NULL, 0);
|
||||||
addMenuItem(m, "Delete", NULL);
|
addMenuItem(m, "Delete", NULL, 0);
|
||||||
addMenuItem(m, "Back - [B]", NULL);
|
addMenuItem(m, "Back - [B]", NULL, 0);
|
||||||
|
|
||||||
printMenu(m);
|
printMenu(m);
|
||||||
|
|
||||||
@ -219,7 +277,7 @@ static bool delete(Menu* m)
|
|||||||
{
|
{
|
||||||
if (!m) return false;
|
if (!m) return false;
|
||||||
|
|
||||||
char* fpath = m->items[m->cursor];
|
char* fpath = m->items[m->cursor].value;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool choice = NO;
|
bool choice = NO;
|
||||||
@ -237,18 +295,18 @@ static bool delete(Menu* m)
|
|||||||
{
|
{
|
||||||
if (!fpath)
|
if (!fpath)
|
||||||
{
|
{
|
||||||
messageBox("Could not delete file.");
|
messageBox("\x1B[31mCould not delete file.\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (remove(fpath) == 0)
|
if (remove(fpath) == 0)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
messageBox("File deleted.");
|
messageBox("\x1B[42mFile deleted.\x1B[47m");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
messageBox("Could not delete file.");
|
messageBox("\x1B[31mCould not delete file.\x1B[47m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#define VERSION "0.6.5 beta"
|
#define VERSION "0.6.8"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MAIN_MENU_INSTALL,
|
MAIN_MENU_INSTALL,
|
||||||
@ -43,12 +43,13 @@ static int _mainMenu(int cursor)
|
|||||||
|
|
||||||
//menu
|
//menu
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
setMenuHeader(m, "MAIN MENU");
|
||||||
|
|
||||||
addMenuItem(m, "Install", NULL);
|
addMenuItem(m, "Install", NULL, 0);
|
||||||
addMenuItem(m, "Titles", NULL);
|
addMenuItem(m, "Titles", NULL, 0);
|
||||||
addMenuItem(m, "Restore", NULL);
|
addMenuItem(m, "Restore", NULL, 0);
|
||||||
addMenuItem(m, "Test", NULL);
|
addMenuItem(m, "Test", NULL, 0);
|
||||||
addMenuItem(m, "Shut Down", NULL);
|
addMenuItem(m, "Shut Down", NULL, 0);
|
||||||
|
|
||||||
m->cursor = cursor;
|
m->cursor = cursor;
|
||||||
|
|
||||||
@ -81,14 +82,14 @@ int main(int argc, char **argv)
|
|||||||
//DSi check
|
//DSi check
|
||||||
if (!isDSiMode())
|
if (!isDSiMode())
|
||||||
{
|
{
|
||||||
messageBox("Error: This app is only for the DSi.\n");
|
messageBox("\x1B[31mError:\x1B[33m This app is only for DSi.\x1B[47m");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//setup sd card access
|
//setup sd card access
|
||||||
if (!fatInitDefault())
|
if (!fatInitDefault())
|
||||||
{
|
{
|
||||||
messageBox("fatInitDefault()...Failed\n");
|
messageBox("fatInitDefault()...\x1B[31mFailed\n\x1B[47m");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -141,7 +141,9 @@ int maketmd(char* input, char* tmdPath)
|
|||||||
iprintf("by Przemyslaw Skryjomski\n\t(Tuxality)\n");
|
iprintf("by Przemyslaw Skryjomski\n\t(Tuxality)\n");
|
||||||
|
|
||||||
if(input == NULL || tmdPath == NULL) {
|
if(input == NULL || tmdPath == NULL) {
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
iprintf("\nUsage: %s file.app <file.tmd>\n", "maketmd");
|
iprintf("\nUsage: %s file.app <file.tmd>\n", "maketmd");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +151,9 @@ int maketmd(char* input, char* tmdPath)
|
|||||||
FILE* app = fopen(input, "rb");
|
FILE* app = fopen(input, "rb");
|
||||||
|
|
||||||
if(!app) {
|
if(!app) {
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Error at opening %s for reading.\n", input);
|
iprintf("Error at opening %s for reading.\n", input);
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +163,9 @@ int maketmd(char* input, char* tmdPath)
|
|||||||
if (!tmd)
|
if (!tmd)
|
||||||
{
|
{
|
||||||
fclose(app);
|
fclose(app);
|
||||||
|
iprintf("\x1B[31m"); //white
|
||||||
iprintf("Error at opening %s for writing.\n", tmdPath);
|
iprintf("Error at opening %s for writing.\n", tmdPath);
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,13 @@ Menu* newMenu()
|
|||||||
m->itemCount = 0;
|
m->itemCount = 0;
|
||||||
m->nextPage = false;
|
m->nextPage = false;
|
||||||
m->changePage = 0;
|
m->changePage = 0;
|
||||||
|
m->header[0] = '\0';
|
||||||
|
|
||||||
for (int i = 0; i < ITEMS_PER_PAGE; i++)
|
for (int i = 0; i < ITEMS_PER_PAGE; i++)
|
||||||
{
|
{
|
||||||
m->labels[i] = NULL;
|
m->items[i].directory = false;
|
||||||
m->items[i] = NULL;
|
m->items[i].label = NULL;
|
||||||
|
m->items[i].value = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
@ -30,28 +32,48 @@ void freeMenu(Menu* m)
|
|||||||
m = NULL;
|
m = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMenuItem(Menu* m, char const* label, char const* value)
|
void addMenuItem(Menu* m, char const* label, char const* value, bool directory)
|
||||||
{
|
{
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
|
|
||||||
int i = m->itemCount;
|
int i = m->itemCount;
|
||||||
if (i >= ITEMS_PER_PAGE) return;
|
if (i >= ITEMS_PER_PAGE) return;
|
||||||
|
|
||||||
|
m->items[i].directory = directory;
|
||||||
|
|
||||||
if (label)
|
if (label)
|
||||||
{
|
{
|
||||||
m->labels[i] = (char*)malloc(32);
|
m->items[i].label = (char*)malloc(32);
|
||||||
sprintf(m->labels[i], "%.31s", label);
|
sprintf(m->items[i].label, "%.31s", label);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
m->items[i] = (char*)malloc(strlen(value)+1);
|
m->items[i].value = (char*)malloc(strlen(value)+1);
|
||||||
sprintf(m->items[i], "%s", value);
|
sprintf(m->items[i].value, "%s", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
m->itemCount += 1;
|
m->itemCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMenuHeader(Menu* m, char* str)
|
||||||
|
{
|
||||||
|
if (!m) return;
|
||||||
|
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
m->header[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strPtr = str;
|
||||||
|
|
||||||
|
if (strlen(strPtr) > 30)
|
||||||
|
strPtr = str + (strlen(strPtr) - 30);
|
||||||
|
|
||||||
|
sprintf(m->header, "%.30s", strPtr);
|
||||||
|
}
|
||||||
|
|
||||||
void resetMenu(Menu* m)
|
void resetMenu(Menu* m)
|
||||||
{
|
{
|
||||||
m->cursor = 0;
|
m->cursor = 0;
|
||||||
@ -66,16 +88,16 @@ void clearMenu(Menu* m)
|
|||||||
|
|
||||||
for (int i = 0; i < ITEMS_PER_PAGE; i++)
|
for (int i = 0; i < ITEMS_PER_PAGE; i++)
|
||||||
{
|
{
|
||||||
if (m->labels[i])
|
if (m->items[i].label)
|
||||||
{
|
{
|
||||||
free(m->labels[i]);
|
free(m->items[i].label);
|
||||||
m->labels[i] = NULL;
|
m->items[i].label = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->items[i])
|
if (m->items[i].value)
|
||||||
{
|
{
|
||||||
free(m->items[i]);
|
free(m->items[i].value);
|
||||||
m->items[i] = NULL;
|
m->items[i].value = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,23 +110,40 @@ void printMenu(Menu* m)
|
|||||||
|
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
|
|
||||||
|
//header
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
|
iprintf("%.30s\n\n", m->header);
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
|
|
||||||
|
if (m->itemCount <= 0)
|
||||||
|
{
|
||||||
|
iprintf("Back - [B]\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//items
|
||||||
for (int i = 0; i < m->itemCount; i++)
|
for (int i = 0; i < m->itemCount; i++)
|
||||||
{
|
{
|
||||||
if (m->labels[i])
|
if (m->items[i].label)
|
||||||
iprintf(" %.30s\n", m->labels[i]);
|
{
|
||||||
|
if (m->items[i].directory)
|
||||||
|
iprintf(" [%.28s]\n", m->items[i].label);
|
||||||
|
else
|
||||||
|
iprintf(" %.30s\n", m->items[i].label);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
iprintf(" \n");
|
iprintf(" \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//cursor
|
//cursor
|
||||||
iprintf("\x1b[%d;0H>", m->cursor);
|
iprintf("\x1b[%d;0H>", 2 + m->cursor);
|
||||||
|
|
||||||
//scroll arrows
|
//scroll arrows
|
||||||
if (m->page > 0)
|
if (m->page > 0)
|
||||||
iprintf("\x1b[0;31H^");
|
iprintf("\x1b[2;31H^");
|
||||||
|
|
||||||
if (m->nextPage)
|
if (m->nextPage)
|
||||||
iprintf("\x1b[22;31Hv");
|
iprintf("\x1b[21;31Hv");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _moveCursor(Menu* m, int dir)
|
static void _moveCursor(Menu* m, int dir)
|
||||||
@ -127,7 +166,7 @@ static void _moveCursor(Menu* m, int dir)
|
|||||||
|
|
||||||
else if (m->cursor > m->itemCount-1)
|
else if (m->cursor > m->itemCount-1)
|
||||||
{
|
{
|
||||||
if (m->cursor >= ITEMS_PER_PAGE)
|
if (m->nextPage && m->cursor >= ITEMS_PER_PAGE)
|
||||||
{
|
{
|
||||||
m->changePage = 1;
|
m->changePage = 1;
|
||||||
m->cursor = 0;
|
m->cursor = 0;
|
||||||
|
|||||||
@ -3,7 +3,13 @@
|
|||||||
|
|
||||||
#include <nds/ndstypes.h>
|
#include <nds/ndstypes.h>
|
||||||
|
|
||||||
#define ITEMS_PER_PAGE 23
|
#define ITEMS_PER_PAGE 20
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool directory;
|
||||||
|
char* label;
|
||||||
|
char* value;
|
||||||
|
} Item;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int cursor;
|
int cursor;
|
||||||
@ -11,14 +17,15 @@ typedef struct {
|
|||||||
int itemCount;
|
int itemCount;
|
||||||
bool nextPage;
|
bool nextPage;
|
||||||
int changePage;
|
int changePage;
|
||||||
char* labels[ITEMS_PER_PAGE];
|
char header[32];
|
||||||
char* items[ITEMS_PER_PAGE];
|
Item items[ITEMS_PER_PAGE];
|
||||||
} Menu;
|
} Menu;
|
||||||
|
|
||||||
Menu* newMenu();
|
Menu* newMenu();
|
||||||
void freeMenu(Menu* m);
|
void freeMenu(Menu* m);
|
||||||
|
|
||||||
void addMenuItem(Menu* m, char const* label, char const* value);
|
void addMenuItem(Menu* m, char const* label, char const* value, bool directory);
|
||||||
|
void setMenuHeader(Menu* m, char* str);
|
||||||
|
|
||||||
void resetMenu(Menu* m);
|
void resetMenu(Menu* m);
|
||||||
void clearMenu(Menu* m);
|
void clearMenu(Menu* m);
|
||||||
|
|||||||
@ -20,7 +20,9 @@ bool choiceBox(char* message)
|
|||||||
|
|
||||||
clearScreen(&bottomScreen);
|
clearScreen(&bottomScreen);
|
||||||
|
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
iprintf("%s\n", message);
|
iprintf("%s\n", message);
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
|
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
@ -55,7 +57,9 @@ bool choicePrint(char* message)
|
|||||||
{
|
{
|
||||||
bool choice = NO;
|
bool choice = NO;
|
||||||
|
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
iprintf("\n%s\n", message);
|
iprintf("\n%s\n", message);
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
iprintf("Yes - [A]\nNo - [B]\n");
|
iprintf("Yes - [A]\nNo - [B]\n");
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
|
|||||||
281
arm9/src/rom.c
Normal file
281
arm9/src/rom.c
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
#include "rom.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "storage.h"
|
||||||
|
#include <nds.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
tDSiHeader* getRomHeader(char const* fpath)
|
||||||
|
{
|
||||||
|
if (!fpath) return NULL;
|
||||||
|
|
||||||
|
tDSiHeader* h = NULL;
|
||||||
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
h = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
||||||
|
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
if (romIsCia(fpath))
|
||||||
|
fseek(f, 0x3900, SEEK_SET);
|
||||||
|
else
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
fread(h, sizeof(tDSiHeader), 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
tNDSBanner* getRomBanner(char const* fpath)
|
||||||
|
{
|
||||||
|
if (!fpath) return NULL;
|
||||||
|
|
||||||
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
|
tNDSBanner* b = NULL;
|
||||||
|
|
||||||
|
if (h)
|
||||||
|
{
|
||||||
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
b = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
if (romIsCia(fpath))
|
||||||
|
fseek(f, 0x3900, SEEK_SET);
|
||||||
|
else
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
fseek(f, h->ndshdr.bannerOffset, SEEK_CUR);
|
||||||
|
fread(b, sizeof(tNDSBanner), 1, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(h);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getGameTitle(tNDSBanner* b, char* out, bool full)
|
||||||
|
{
|
||||||
|
if (!b) return false;
|
||||||
|
if (!out) return false;
|
||||||
|
|
||||||
|
//get system language
|
||||||
|
int lang = PersonalData->language;
|
||||||
|
|
||||||
|
//not japanese or chinese
|
||||||
|
if (lang == 0 || lang == 6)
|
||||||
|
lang = 1;
|
||||||
|
|
||||||
|
//read title
|
||||||
|
u16 c;
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
c = b->titles[lang][i];
|
||||||
|
|
||||||
|
//remove accents
|
||||||
|
if (c == 0x00F3)
|
||||||
|
c = 'o';
|
||||||
|
|
||||||
|
if (c == 0x00E1)
|
||||||
|
c = 'a';
|
||||||
|
|
||||||
|
out[i] = (char)c;
|
||||||
|
|
||||||
|
if (!full && out[i] == '\n')
|
||||||
|
{
|
||||||
|
out[i] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out[128] = '\0';
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getGameTitlePath(char const* fpath, char* out, bool full)
|
||||||
|
{
|
||||||
|
if (!fpath) return false;
|
||||||
|
if (!out) return false;
|
||||||
|
|
||||||
|
tNDSBanner* b = getRomBanner(fpath);
|
||||||
|
bool result = getGameTitle(b, out, full);
|
||||||
|
|
||||||
|
free(b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getRomLabel(tDSiHeader* h, char* out)
|
||||||
|
{
|
||||||
|
if (!h) return false;
|
||||||
|
if (!out) return false;
|
||||||
|
|
||||||
|
sprintf(out, "%.12s", h->ndshdr.gameTitle);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getRomCode(tDSiHeader* h, char* out)
|
||||||
|
{
|
||||||
|
if (!h) return false;
|
||||||
|
if (!out) return false;
|
||||||
|
|
||||||
|
sprintf(out, "%.4s", h->ndshdr.gameCode);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getTitleId(tDSiHeader* h, u32* low, u32* high)
|
||||||
|
{
|
||||||
|
if (!h) return false;
|
||||||
|
|
||||||
|
if (low != NULL)
|
||||||
|
*low = h->tid_low;
|
||||||
|
|
||||||
|
if (high != NULL)
|
||||||
|
*high = h->tid_high;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printRomInfo(char const* fpath)
|
||||||
|
{
|
||||||
|
clearScreen(&topScreen);
|
||||||
|
|
||||||
|
if (!fpath) return;
|
||||||
|
|
||||||
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
|
tNDSBanner* b = getRomBanner(fpath);
|
||||||
|
|
||||||
|
if (!isDsiHeader(h))
|
||||||
|
{
|
||||||
|
iprintf("Could not read dsi header.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!b)
|
||||||
|
{
|
||||||
|
iprintf("Could not read banner.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//proper title
|
||||||
|
{
|
||||||
|
char gameTitle[128+1];
|
||||||
|
getGameTitle(b, gameTitle, true);
|
||||||
|
|
||||||
|
iprintf("%s\n\n", gameTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
//file size
|
||||||
|
{
|
||||||
|
iprintf("Size: ");
|
||||||
|
printBytes(getRomSize(fpath));
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("Label: %.12s\n", h->ndshdr.gameTitle);
|
||||||
|
iprintf("Game Code: %.4s\n", h->ndshdr.gameCode);
|
||||||
|
|
||||||
|
//system type
|
||||||
|
{
|
||||||
|
iprintf("Unit Code: ");
|
||||||
|
|
||||||
|
switch (h->ndshdr.unitCode)
|
||||||
|
{
|
||||||
|
case 0: iprintf("NDS"); break;
|
||||||
|
case 2: iprintf("NDS+DSi"); break;
|
||||||
|
case 3: iprintf("DSi"); break;
|
||||||
|
default: iprintf("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//application type
|
||||||
|
{
|
||||||
|
iprintf("Program Type: ");
|
||||||
|
|
||||||
|
switch (h->ndshdr.reserved1[7])
|
||||||
|
{
|
||||||
|
case 0x3: iprintf("Normal"); break;
|
||||||
|
case 0xB: iprintf("Sys"); break;
|
||||||
|
case 0xF: iprintf("Debug/Sys"); break;
|
||||||
|
default: iprintf("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//DSi title ids
|
||||||
|
{
|
||||||
|
if (h->tid_high == 0x00030004 ||
|
||||||
|
h->tid_high == 0x00030005 ||
|
||||||
|
h->tid_high == 0x00030015 ||
|
||||||
|
h->tid_high == 0x00030017 ||
|
||||||
|
h->tid_high == 0x00030000)
|
||||||
|
{
|
||||||
|
iprintf("Title ID: %08x %08x\n", (unsigned int)h->tid_high, (unsigned int)h->tid_low);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//print full file path
|
||||||
|
iprintf("\n%s\n", fpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(b);
|
||||||
|
free(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long getRomSize(char const* fpath)
|
||||||
|
{
|
||||||
|
if (!fpath) return 0;
|
||||||
|
|
||||||
|
unsigned long long size = 0;
|
||||||
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
//cia
|
||||||
|
if (romIsCia(fpath))
|
||||||
|
{
|
||||||
|
unsigned char bytes[4] = { 0 };
|
||||||
|
fseek(f, 0x38D0, SEEK_SET);
|
||||||
|
fread(bytes, 4, 1, f);
|
||||||
|
size = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
size = ftell(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool romIsCia(char const* fpath)
|
||||||
|
{
|
||||||
|
if (!fpath) return false;
|
||||||
|
return (strstr(fpath, ".cia") != NULL || strstr(fpath, ".CIA") != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDsiHeader(tDSiHeader* h)
|
||||||
|
{
|
||||||
|
if (!h) return false;
|
||||||
|
|
||||||
|
return ( h->tid_low == (unsigned int)((h->ndshdr.gameCode[0] << 24) | (h->ndshdr.gameCode[1] << 16) | (h->ndshdr.gameCode[2] << 8) | h->ndshdr.gameCode[3]) );
|
||||||
|
}
|
||||||
24
arm9/src/rom.h
Normal file
24
arm9/src/rom.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef ROM_H
|
||||||
|
#define ROM_H
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <nds/memory.h>
|
||||||
|
|
||||||
|
tDSiHeader* getRomHeader(char const* fpath);
|
||||||
|
tNDSBanner* getRomBanner(char const* fpath);
|
||||||
|
|
||||||
|
bool getGameTitle(tNDSBanner* b, char* out, bool full);
|
||||||
|
bool getGameTitlePath(char const* fpath, char* out, bool full);
|
||||||
|
|
||||||
|
bool getRomLabel(tDSiHeader* h, char* out);
|
||||||
|
bool getRomCode(tDSiHeader* h, char* out);
|
||||||
|
bool getTitleId(tDSiHeader* h, u32* low, u32* high);
|
||||||
|
|
||||||
|
void printRomInfo(char const* fpath);
|
||||||
|
|
||||||
|
unsigned long long getRomSize(char const* fpath);
|
||||||
|
|
||||||
|
bool romIsCia(char const* fpath);
|
||||||
|
bool isDsiHeader(tDSiHeader* h);
|
||||||
|
|
||||||
|
#endif
|
||||||
123
arm9/src/sav.c
Normal file
123
arm9/src/sav.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "sav.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
static u32 _getClusterSize(u32 sizebytes)
|
||||||
|
{
|
||||||
|
if (sizebytes < 573440)
|
||||||
|
return 512;
|
||||||
|
|
||||||
|
else if (sizebytes < 5472256)
|
||||||
|
return 2048;
|
||||||
|
|
||||||
|
else if (sizebytes < 17301504)
|
||||||
|
return 4096;
|
||||||
|
|
||||||
|
else
|
||||||
|
return 2048;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16 _getMaxFiles(u32 sizebytes)
|
||||||
|
{
|
||||||
|
if (sizebytes < 573440)
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
else
|
||||||
|
return 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wip
|
||||||
|
static u16 _getFatz(u32 sizebytes)
|
||||||
|
{
|
||||||
|
if (sizebytes <= 0x4000) //16 kb
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
else if (sizebytes <= 0x200000) //2 mb
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
else
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wip
|
||||||
|
static u16 _getTotSec16(u32 sizebytes, u16 bytesPerSec)
|
||||||
|
{
|
||||||
|
if (sizebytes == 0x4000) //16 kb
|
||||||
|
return 27;
|
||||||
|
|
||||||
|
return sizebytes / bytesPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initFatHeader(FILE* f)
|
||||||
|
{
|
||||||
|
if (!f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//get size
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
u32 size = ftell(f);
|
||||||
|
|
||||||
|
FATHeader* h = (FATHeader*)malloc(sizeof(FATHeader));
|
||||||
|
|
||||||
|
h->BS_JmpBoot[0] = 0xE9;
|
||||||
|
h->BS_JmpBoot[1] = 0;
|
||||||
|
h->BS_JmpBoot[2] = 0;
|
||||||
|
|
||||||
|
h->BS_OEMName[0] = 'M';
|
||||||
|
h->BS_OEMName[1] = 'S';
|
||||||
|
h->BS_OEMName[2] = 'W';
|
||||||
|
h->BS_OEMName[3] = 'I';
|
||||||
|
h->BS_OEMName[4] = 'N';
|
||||||
|
h->BS_OEMName[5] = '4';
|
||||||
|
h->BS_OEMName[6] = '.';
|
||||||
|
h->BS_OEMName[7] = '1';
|
||||||
|
|
||||||
|
h->BPB_BytesPerSec = 512;
|
||||||
|
h->BPB_SecPerClus = _getClusterSize(size) / h->BPB_BytesPerSec;
|
||||||
|
h->BPB_RsvdSecCnt = 1;
|
||||||
|
h->BPB_NumFATs = 2;
|
||||||
|
h->BPB_RootEntCnt = _getMaxFiles(size) * 2;
|
||||||
|
h->BPB_TotSec16 = _getTotSec16(size, h->BPB_BytesPerSec); //
|
||||||
|
h->BPB_Media = 0xF8;
|
||||||
|
h->BPB_FATSz16 = _getFatz(size); //
|
||||||
|
h->BPB_SecPerTrk = 0;
|
||||||
|
h->BPB_NumHeads = 0;
|
||||||
|
h->BPB_HiddSec = 0;
|
||||||
|
h->BPB_TotSec32 = 0;
|
||||||
|
h->BS_DrvNum = 0x07;
|
||||||
|
h->BS_Reserved1 = 0;
|
||||||
|
h->BS_BootSig = 0x29;
|
||||||
|
h->BS_VolID = 305419896;
|
||||||
|
|
||||||
|
h->BS_VolLab[0] = 'V';
|
||||||
|
h->BS_VolLab[1] = 'O';
|
||||||
|
h->BS_VolLab[2] = 'L';
|
||||||
|
h->BS_VolLab[3] = 'U';
|
||||||
|
h->BS_VolLab[4] = 'M';
|
||||||
|
h->BS_VolLab[5] = 'E';
|
||||||
|
h->BS_VolLab[6] = 'L';
|
||||||
|
h->BS_VolLab[7] = 'A';
|
||||||
|
h->BS_VolLab[8] = 'B';
|
||||||
|
h->BS_VolLab[9] = 'E';
|
||||||
|
h->BS_VolLab[10] = 'L';
|
||||||
|
|
||||||
|
h->BS_FilSysType[0] = 'F';
|
||||||
|
h->BS_FilSysType[1] = 'A';
|
||||||
|
h->BS_FilSysType[2] = 'T';
|
||||||
|
h->BS_FilSysType[3] = '1';
|
||||||
|
h->BS_FilSysType[4] = '2';
|
||||||
|
h->BS_FilSysType[5] = ' ';
|
||||||
|
h->BS_FilSysType[6] = ' ';
|
||||||
|
h->BS_FilSysType[7] = ' ';
|
||||||
|
|
||||||
|
memset(h->BS_BootCode, 0, 448);
|
||||||
|
|
||||||
|
h->BS_BootSign = 0xAA55;
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fwrite(h, sizeof(FATHeader), 1, f);
|
||||||
|
|
||||||
|
free(h);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
38
arm9/src/sav.h
Normal file
38
arm9/src/sav.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef SAV_H
|
||||||
|
#define SAV_H
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
//http://elm-chan.org/docs/fat_e.html
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 BS_JmpBoot[3]; //0x0000
|
||||||
|
u8 BS_OEMName[8]; //0x0003
|
||||||
|
u16 BPB_BytesPerSec; //0x000B
|
||||||
|
u8 BPB_SecPerClus; //0x000D
|
||||||
|
u16 BPB_RsvdSecCnt; //0x000E
|
||||||
|
u8 BPB_NumFATs;
|
||||||
|
u16 BPB_RootEntCnt;
|
||||||
|
u16 BPB_TotSec16;
|
||||||
|
u8 BPB_Media;
|
||||||
|
u16 BPB_FATSz16;
|
||||||
|
u16 BPB_SecPerTrk;
|
||||||
|
u16 BPB_NumHeads;
|
||||||
|
u32 BPB_HiddSec;
|
||||||
|
u32 BPB_TotSec32;
|
||||||
|
u8 BS_DrvNum;
|
||||||
|
u8 BS_Reserved1;
|
||||||
|
u8 BS_BootSig;
|
||||||
|
u32 BS_VolID;
|
||||||
|
u8 BS_VolLab[11];
|
||||||
|
u8 BS_FilSysType[8];
|
||||||
|
u8 BS_BootCode[448];
|
||||||
|
u16 BS_BootSign;
|
||||||
|
} FATHeader;
|
||||||
|
#pragma pack(push, 0)
|
||||||
|
|
||||||
|
bool initFatHeader(FILE* f);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -36,6 +36,8 @@ void printProgressBar(float percent)
|
|||||||
{
|
{
|
||||||
consoleSelect(&topScreen);
|
consoleSelect(&topScreen);
|
||||||
|
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
|
|
||||||
//Print frame
|
//Print frame
|
||||||
if (lastBars <= 0)
|
if (lastBars <= 0)
|
||||||
{
|
{
|
||||||
@ -45,12 +47,14 @@ void printProgressBar(float percent)
|
|||||||
|
|
||||||
//Print bars
|
//Print bars
|
||||||
if (bars > 0)
|
if (bars > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < bars; i++)
|
for (int i = 0; i < bars; i++)
|
||||||
iprintf("\x1b[23;%dH|", 1 + i);
|
iprintf("\x1b[23;%dH|", 1 + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBars = bars;
|
lastBars = bars;
|
||||||
|
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,52 +78,75 @@ bool fileExists(char const* path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copyFile(char const* in, char const* out)
|
int copyFile(char const* src, char const* dst)
|
||||||
{
|
{
|
||||||
if (!in || !out) return false;
|
if (!src) return 1;
|
||||||
|
|
||||||
FILE* fin = fopen(in, "rb");
|
unsigned long long size = getFileSizePath(src);
|
||||||
FILE* fout = fopen(out, "wb");
|
return copyFilePart(src, 0, size, dst);
|
||||||
|
}
|
||||||
|
|
||||||
if (!fin || !fout)
|
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst)
|
||||||
|
{
|
||||||
|
if (!src) return 1;
|
||||||
|
if (!dst) return 2;
|
||||||
|
|
||||||
|
FILE* fin = fopen(src, "rb");
|
||||||
|
|
||||||
|
if (!fin)
|
||||||
{
|
{
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
fclose(fout);
|
return 3;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
consoleSelect(&topScreen);
|
FILE* fout = fopen(dst, "wb");
|
||||||
|
|
||||||
int bytesRead;
|
if (!fout)
|
||||||
int totalBytesRead = 0;
|
|
||||||
int fileSize = getFileSize(fin);
|
|
||||||
|
|
||||||
#define BUFF_SIZE 128 //Arbitrary. A value too large freezes the ds.
|
|
||||||
char* buffer = (char*)malloc(BUFF_SIZE);
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
bytesRead = fread(buffer, 1, BUFF_SIZE, fin);
|
fclose(fin);
|
||||||
fwrite(buffer, bytesRead, 1, fout);
|
fclose(fout);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(fin, offset, SEEK_SET);
|
||||||
|
|
||||||
totalBytesRead += bytesRead;
|
consoleSelect(&topScreen);
|
||||||
printProgressBar( ((float)totalBytesRead / (float)fileSize) );
|
|
||||||
|
|
||||||
if (bytesRead != BUFF_SIZE)
|
int bytesRead;
|
||||||
break;
|
unsigned int totalBytesRead = 0;
|
||||||
|
|
||||||
|
#define BUFF_SIZE 128 //Arbitrary. A value too large freezes the ds.
|
||||||
|
char* buffer = (char*)malloc(BUFF_SIZE);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
unsigned int toRead = BUFF_SIZE;
|
||||||
|
if (size - totalBytesRead < BUFF_SIZE)
|
||||||
|
toRead = size - totalBytesRead;
|
||||||
|
|
||||||
|
bytesRead = fread(buffer, 1, toRead, fin);
|
||||||
|
fwrite(buffer, bytesRead, 1, fout);
|
||||||
|
|
||||||
|
totalBytesRead += bytesRead;
|
||||||
|
printProgressBar( ((float)totalBytesRead / (float)size) );
|
||||||
|
|
||||||
|
if (bytesRead != BUFF_SIZE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearProgressBar();
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearProgressBar();
|
fclose(fout);
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
fclose(fout);
|
return 0;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long getFileSize(FILE* f)
|
unsigned long long getFileSize(FILE* f)
|
||||||
@ -224,14 +251,42 @@ bool copyDir(char const* src, char const* dst)
|
|||||||
|
|
||||||
// iprintf("%s\n%s\n\n", fsrc, fdst);
|
// iprintf("%s\n%s\n\n", fsrc, fdst);
|
||||||
iprintf("%s...", fdst);
|
iprintf("%s...", fdst);
|
||||||
if(!copyFile(fsrc, fdst))
|
|
||||||
|
int ret = copyFile(fsrc, fdst);
|
||||||
|
|
||||||
|
if(ret != 0)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m"); //red
|
||||||
iprintf("Fail\n");
|
iprintf("Fail\n");
|
||||||
|
iprintf("\x1B[33m"); //yellow
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
iprintf("Empty input path.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
iprintf("Empty output path.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
iprintf("Error opening input file.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
iprintf("Error opening output file.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[42m"); //green
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m"); //white
|
||||||
}
|
}
|
||||||
|
|
||||||
free(fdst);
|
free(fdst);
|
||||||
@ -288,12 +343,16 @@ bool deleteDir(char const* path)
|
|||||||
iprintf("%s...", fpath);
|
iprintf("%s...", fpath);
|
||||||
if (remove(fpath) != 0)
|
if (remove(fpath) != 0)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m");
|
||||||
iprintf("Fail\n");
|
iprintf("Fail\n");
|
||||||
|
iprintf("\x1B[47m");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[42m");
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,12 +363,16 @@ bool deleteDir(char const* path)
|
|||||||
iprintf("%s...", path);
|
iprintf("%s...", path);
|
||||||
if (remove(path) != 0)
|
if (remove(path) != 0)
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[31m");
|
||||||
iprintf("Fail\n");
|
iprintf("Fail\n");
|
||||||
|
iprintf("\x1B[47m");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
iprintf("\x1B[42m");
|
||||||
iprintf("Done\n");
|
iprintf("Done\n");
|
||||||
|
iprintf("\x1B[47m");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -333,14 +396,14 @@ unsigned long long getDirSize(const char* path)
|
|||||||
if (ent->d_type == DT_DIR)
|
if (ent->d_type == DT_DIR)
|
||||||
{
|
{
|
||||||
char fullpath[512];
|
char fullpath[512];
|
||||||
sprintf(fullpath, "%s%s/", path, ent->d_name);
|
sprintf(fullpath, "%s/%s", path, ent->d_name);
|
||||||
|
|
||||||
size += getDirSize(fullpath);
|
size += getDirSize(fullpath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char fullpath[256];
|
char fullpath[260];
|
||||||
sprintf(fullpath, "%s%s", path, ent->d_name);
|
sprintf(fullpath, "%s/%s", path, ent->d_name);
|
||||||
|
|
||||||
size += getFileSizePath(fullpath);
|
size += getFileSizePath(fullpath);
|
||||||
}
|
}
|
||||||
@ -432,32 +495,36 @@ unsigned long long getSDCardFree()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//internal storage
|
//internal storage
|
||||||
int getDsiSize()
|
unsigned long long getDsiSize()
|
||||||
{
|
{
|
||||||
//The DSi has 256MB of internal storage. Some is unavailable and used by other things.
|
//The DSi has 256MB of internal storage. Some is unavailable and used by other things.
|
||||||
//Find a better way to do this
|
//Find a better way to do this
|
||||||
return 240 * 1024 * 1024;
|
return 240 * 1024 * 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDsiFree()
|
unsigned long long getDsiFree()
|
||||||
{
|
{
|
||||||
//Get free space by subtracting file sizes in emulated nand folders
|
//Get free space by subtracting file sizes in emulated nand folders
|
||||||
//Find a better way to do this
|
//Find a better way to do this
|
||||||
int size = getDsiSize();
|
long long size = getDsiSize();
|
||||||
|
|
||||||
size -= getDirSize("/sys/");
|
size -= getDirSize("/sys");
|
||||||
size -= getDirSize("/title/");
|
size -= getDirSize("/title/0003000f");
|
||||||
size -= getDirSize("/ticket/");
|
size -= getDirSize("/title/00030004");
|
||||||
size -= getDirSize("/shared1/");
|
size -= getDirSize("/title/00030005");
|
||||||
size -= getDirSize("/shared2/");
|
size -= getDirSize("/title/00030017");
|
||||||
size -= getDirSize("/import/");
|
size -= getDirSize("/ticket");
|
||||||
size -= getDirSize("/tmp/");
|
size -= getDirSize("/shared1");
|
||||||
size -= getDirSize("/progress/");
|
size -= getDirSize("/shared2");
|
||||||
|
size -= getDirSize("/import");
|
||||||
|
size -= getDirSize("/tmp");
|
||||||
|
size -= getDirSize("/progress");
|
||||||
|
|
||||||
size -= getDirSize("/photo/");
|
size -= getDirSize("/photo");
|
||||||
size -= getDirSize("/private/");
|
size -= getDirSize("/private");
|
||||||
|
|
||||||
size += getDirSize("/title/00030015/");
|
if (size < 0)
|
||||||
|
return 0;
|
||||||
return size;
|
|
||||||
|
return (unsigned long long)size;
|
||||||
}
|
}
|
||||||
@ -5,7 +5,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define BACKUP_PATH "/titlebackup"
|
#define BACKUP_PATH "/titlebackup"
|
||||||
#define ROM_PATH "/dsi"
|
|
||||||
#define BYTES_PER_BLOCK (1024*128)
|
#define BYTES_PER_BLOCK (1024*128)
|
||||||
|
|
||||||
//printing
|
//printing
|
||||||
@ -17,7 +16,8 @@ void clearProgressBar();
|
|||||||
|
|
||||||
//Files
|
//Files
|
||||||
bool fileExists(char const* path);
|
bool fileExists(char const* path);
|
||||||
bool copyFile(char const* src, char const* dst);
|
int copyFile(char const* src, char const* dst);
|
||||||
|
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst);
|
||||||
unsigned long long getFileSize(FILE* f);
|
unsigned long long getFileSize(FILE* f);
|
||||||
unsigned long long getFileSizePath(char const* path);
|
unsigned long long getFileSizePath(char const* path);
|
||||||
bool padFile(char const* path, int size);
|
bool padFile(char const* path, int size);
|
||||||
@ -40,8 +40,8 @@ unsigned long long getSDCardFree();
|
|||||||
#define getSDCardUsedSpace() (getSDCardSize() - getSDCardFree())
|
#define getSDCardUsedSpace() (getSDCardSize() - getSDCardFree())
|
||||||
|
|
||||||
//internal storage
|
//internal storage
|
||||||
int getDsiSize();
|
unsigned long long getDsiSize();
|
||||||
int getDsiFree();
|
unsigned long long getDsiFree();
|
||||||
#define getDsiUsed() (getDSIStorageSize() - getDSIStorageFree())
|
#define getDsiUsed() (getDSIStorageSize() - getDSIStorageFree())
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "app.h"
|
#include "rom.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
@ -20,6 +20,7 @@ static bool delete(Menu* m);
|
|||||||
void titleMenu()
|
void titleMenu()
|
||||||
{
|
{
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
setMenuHeader(m, "INSTALLED TITLES");
|
||||||
generateList(m);
|
generateList(m);
|
||||||
|
|
||||||
//no titles
|
//no titles
|
||||||
@ -146,9 +147,9 @@ static void generateList(Menu* m)
|
|||||||
sprintf(path, "%s/%s", contentPath, subent->d_name);
|
sprintf(path, "%s/%s", contentPath, subent->d_name);
|
||||||
|
|
||||||
char title[128];
|
char title[128];
|
||||||
getAppTitle(path, title);
|
getGameTitlePath(path, title, false);
|
||||||
|
|
||||||
addMenuItem(m, title, path);
|
addMenuItem(m, title, path, 0);
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
@ -180,7 +181,7 @@ static void generateList(Menu* m)
|
|||||||
static void printItem(Menu* m)
|
static void printItem(Menu* m)
|
||||||
{
|
{
|
||||||
if (!m) return;
|
if (!m) return;
|
||||||
printAppInfo(m->items[m->cursor]);
|
printRomInfo(m->items[m->cursor].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int subMenu()
|
static int subMenu()
|
||||||
@ -189,9 +190,9 @@ static int subMenu()
|
|||||||
|
|
||||||
Menu* m = newMenu();
|
Menu* m = newMenu();
|
||||||
|
|
||||||
addMenuItem(m, "Backup", NULL);
|
addMenuItem(m, "Backup", NULL, 0);
|
||||||
addMenuItem(m, "Delete", NULL);
|
addMenuItem(m, "Delete", NULL, 0);
|
||||||
addMenuItem(m, "Back - [B]", NULL);
|
addMenuItem(m, "Back - [B]", NULL, 0);
|
||||||
|
|
||||||
printMenu(m);
|
printMenu(m);
|
||||||
|
|
||||||
@ -219,16 +220,18 @@ static int subMenu()
|
|||||||
|
|
||||||
static void backup(Menu* m)
|
static void backup(Menu* m)
|
||||||
{
|
{
|
||||||
char* fpath = m->items[m->cursor];
|
char* fpath = m->items[m->cursor].value;
|
||||||
char* backname = NULL;
|
char* backname = NULL;
|
||||||
|
|
||||||
|
tDSiHeader* h = getRomHeader(fpath);
|
||||||
|
|
||||||
{
|
{
|
||||||
//make backup folder name
|
//make backup folder name
|
||||||
char label[16];
|
char label[16];
|
||||||
getAppLabel(fpath, label);
|
getRomLabel(h, label);
|
||||||
|
|
||||||
char gamecode[5];
|
char gamecode[5];
|
||||||
getGameCode(fpath, gamecode);
|
getRomCode(h, gamecode);
|
||||||
|
|
||||||
backname = (char*)malloc(strlen(label) + strlen(gamecode) + 16);
|
backname = (char*)malloc(strlen(label) + strlen(gamecode) + 16);
|
||||||
sprintf(backname, "%s-%s", label, gamecode);
|
sprintf(backname, "%s-%s", label, gamecode);
|
||||||
@ -263,7 +266,7 @@ static void backup(Menu* m)
|
|||||||
{
|
{
|
||||||
u32 tid_low = 1;
|
u32 tid_low = 1;
|
||||||
u32 tid_high = 1;
|
u32 tid_high = 1;
|
||||||
getTid(fpath, &tid_low, &tid_high);
|
getTitleId(h, &tid_low, &tid_high);
|
||||||
|
|
||||||
char* srcpath = (char*)malloc(strlen("/title/") + 32);
|
char* srcpath = (char*)malloc(strlen("/title/") + 32);
|
||||||
sprintf(srcpath, "/title/%08x/%08x", (unsigned int)tid_high, (unsigned int)tid_low);
|
sprintf(srcpath, "/title/%08x/%08x", (unsigned int)tid_high, (unsigned int)tid_low);
|
||||||
@ -310,20 +313,21 @@ static void backup(Menu* m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(backname);
|
free(backname);
|
||||||
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool delete(Menu* m)
|
static bool delete(Menu* m)
|
||||||
{
|
{
|
||||||
if (!m) return false;
|
if (!m) return false;
|
||||||
|
|
||||||
char* fpath = m->items[m->cursor];
|
char* fpath = m->items[m->cursor].value;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool choice = NO;
|
bool choice = NO;
|
||||||
{
|
{
|
||||||
//get app title
|
//get app title
|
||||||
char title[128];
|
char title[128];
|
||||||
getAppTitle(m->items[m->cursor], title);
|
getGameTitlePath(m->items[m->cursor].value, title, false);
|
||||||
|
|
||||||
char str[] = "Are you sure you want to delete\n";
|
char str[] = "Are you sure you want to delete\n";
|
||||||
char* msg = (char*)malloc(strlen(str) + strlen(title) + 8);
|
char* msg = (char*)malloc(strlen(str) + strlen(title) + 8);
|
||||||
@ -343,7 +347,7 @@ static bool delete(Menu* m)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char dirPath[64];
|
char dirPath[64];
|
||||||
sprintf(dirPath, "%.25s", fpath);
|
sprintf(dirPath, "%.24s", fpath);
|
||||||
|
|
||||||
if (!dirExists(dirPath))
|
if (!dirExists(dirPath))
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user