This commit is contained in:
JeffRuLz 2019-06-20 14:24:53 -05:00 committed by GitHub
parent 1491f6b862
commit c05199c59a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 985 additions and 243 deletions

View File

@ -18,13 +18,16 @@ static bool delete(Menu* m);
void backupMenu()
{
clearScreen(&topScreen);
Menu* m = newMenu();
setMenuHeader(m, "BACKUP MENU");
generateList(m);
//no files found
if (m->itemCount <= 0)
{
messageBox("No backups found.\n");
messageBox("\x1B[33mNo backups found.\n\x1B[47m");
}
else
{
@ -77,9 +80,9 @@ static int subMenu()
Menu* m = newMenu();
addMenuItem(m, "Restore", NULL);
addMenuItem(m, "Delete", NULL);
addMenuItem(m, "Back - [B]", NULL);
addMenuItem(m, "Restore", NULL, 0);
addMenuItem(m, "Delete", NULL, 0);
addMenuItem(m, "Back - [B]", NULL, 0);
printMenu(m);
@ -145,7 +148,7 @@ static void generateList(Menu* m)
char* path = (char*)malloc(strlen(BACKUP_PATH) + strlen(ent->d_name) + 8);
sprintf(path, "%s/%s", BACKUP_PATH, ent->d_name);
addMenuItem(m, ent->d_name, path);
addMenuItem(m, ent->d_name, path, 0);
free(path);
}
@ -166,7 +169,7 @@ static void generateList(Menu* m)
static void restore(Menu* m)
{
char* fpath = m->items[m->cursor];
char* fpath = m->items[m->cursor].value;
bool choice = NO;
{
@ -183,7 +186,7 @@ static void restore(Menu* m)
{
if (!fpath)
{
messageBox("Failed to restore backup.\n");
messageBox("\x1B[31mFailed to restore backup.\n\x1B[47m");
}
else
{
@ -191,11 +194,11 @@ static void restore(Menu* m)
if (!copyDir(fpath, "/title"))
{
messagePrint("\nFailed to restore backup.\n");
messagePrint("\x1B[31m\nFailed to restore backup.\n\x1B[47m");
}
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;
char* fpath = m->items[m->cursor];
char* fpath = m->items[m->cursor].value;
bool result = false;
bool choice = NO;
@ -223,13 +226,13 @@ static bool delete(Menu* m)
{
if (!fpath)
{
messageBox("Failed to delete backup.\n");
messageBox("\x1B[31mFailed to delete backup.\n\x1B[47m");
}
else
{
if (!dirExists(fpath))
{
messageBox("Failed to delete backup.\n");
messageBox("\x1B[31mFailed to delete backup.\n\x1B[47m");
}
else
{
@ -238,11 +241,11 @@ static bool delete(Menu* m)
if (deleteDir(fpath))
{
result = true;
messagePrint("\nBackup deleted.\n");
messagePrint("\x1B[42m\nBackup deleted.\n\x1B[47m");
}
else
{
messagePrint("\nError deleting backup.\n");
messagePrint("\n\x1B[31mError deleting backup.\n\x1B[47m");
}
}
}

View File

@ -1,8 +1,9 @@
#include "install.h"
#include "fat12.h"
#include "sav.h"
#include "main.h"
#include "message.h"
#include "maketmd.h"
#include "rom.h"
#include "storage.h"
#include <sys/stat.h>
@ -42,7 +43,9 @@ static bool _patchGameCode(tDSiHeader* h)
}
while (_titleIsUsed(h));
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
return true;
}
@ -56,26 +59,22 @@ static bool _iqueHack(tDSiHeader* h)
if (h->ndshdr.reserved1[8] == 0x80)
{
iprintf("iQue Hack...");
h->ndshdr.reserved1[8] = 0x00;
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
return true;
}
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;
//get app size
if (f)
size = getFileSize(f);
//add save file size
if (h)
{
size += h->public_sav_size;
@ -86,9 +85,6 @@ static unsigned long long _getSize(FILE* f, tDSiHeader* h)
size += 0x4000;
}
printBytes(size);
iprintf("\n");
return size;
}
@ -99,11 +95,15 @@ static bool _checkSdSpace(unsigned long long size)
if (getSDCardFree() < size)
{
iprintf("\x1B[31m"); //red
iprintf("No\n");
iprintf("\x1B[47m"); //white
return false;
}
iprintf("\x1B[42m"); //green
iprintf("Yes\n");
iprintf("\x1B[47m"); //white
return true;
}
@ -114,11 +114,15 @@ static bool _checkDsiSpace(unsigned long long size)
if (getDsiFree() < size)
{
iprintf("\x1B[31m"); //red
iprintf("No\n");
iprintf("\x1B[47m"); //white
return false;
}
iprintf("\x1B[42m"); //green
iprintf("Yes\n");
iprintf("\x1B[47m"); //white
return true;
}
@ -129,26 +133,15 @@ static bool _openMenuSlot()
if (getMenuSlotsFree() <= 0)
{
iprintf("\x1B[31m"); //red
iprintf("No\n");
iprintf("\x1B[47m"); //white
return choicePrint("Try installing anyway?");
}
iprintf("\x1B[42m"); //green
iprintf("Yes\n");
return true;
}
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;
}
iprintf("\x1B[47m"); //white
return true;
}
@ -163,7 +156,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
if (!dataPath)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
@ -174,7 +169,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
if (!f)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
@ -182,7 +179,9 @@ static void _createPublicSav(tDSiHeader* h, char* dataPath)
fputc(0, f);
initFatHeader(f);
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
fclose(f);
@ -202,7 +201,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
if (!dataPath)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
@ -213,7 +214,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
if (!f)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
@ -221,7 +224,9 @@ static void _createPrivateSav(tDSiHeader* h, char* dataPath)
fputc(0, f);
initFatHeader(f);
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
fclose(f);
@ -241,7 +246,9 @@ static void _createBannerSav(tDSiHeader* h, char* dataPath)
if (!dataPath)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
@ -252,14 +259,18 @@ static void _createBannerSav(tDSiHeader* h, char* dataPath)
if (!f)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
fseek(f, 0x4000 - 1, SEEK_SET);
fputc(0, f);
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
fclose(f);
@ -274,10 +285,14 @@ bool install(char* fpath, bool systemTitle)
//confirmation message
{
char msg[512];
sprintf(msg, "Are you sure you want to install\n%s\n", fpath);
char str[] = "Are you sure you want to install\n";
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;
}
@ -285,33 +300,49 @@ bool install(char* fpath, bool systemTitle)
clearScreen(&bottomScreen);
iprintf("Installing %s\n\n", fpath); swiWaitForVBlank();
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
FILE* f = fopen(fpath, "rb");
tDSiHeader* h = getRomHeader(fpath);
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;
}
else
{
bool fixHeader = false;
//read header
fseek(f, 0, SEEK_SET);
fread(header, sizeof(tDSiHeader), 1, f);
if (_patchGameCode(header))
if (_patchGameCode(h))
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;
}
unsigned long long fileSize = getFileSize(f);
unsigned long long installSize = _getSize(f, header);
//get install size
iprintf("Install Size: ");
swiWaitForVBlank();
unsigned long long fileSize = getRomSize(fpath);
unsigned long long installSize = fileSize + _getSaveDataSize(h);
//do not need file opened anymore
fclose(f);
printBytes(installSize);
iprintf("\n");
if (!_checkSdSpace(installSize))
goto error;
@ -324,20 +355,22 @@ bool install(char* fpath, bool systemTitle)
{
iprintf("System Title Patch...");
swiWaitForVBlank();
header->tid_high = 0x00030015;
h->tid_high = 0x00030015;
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
fixHeader = true;
}
//skip nand check if system title
if (header->tid_high != 0x00030015)
if (h->tid_high != 0x00030015)
{
if (!_checkDsiSpace(installSize))
{
if (choicePrint("Install as system title?"))
{
header->tid_high = 0x00030015;
h->tid_high = 0x00030015;
fixHeader = true;
}
else
@ -348,22 +381,29 @@ bool install(char* fpath, bool systemTitle)
}
}
if (_iqueHack(header))
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;
}
if (_iqueHack(h))
fixHeader = true;
//create title directory /title/XXXXXXXX/XXXXXXXX
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);
@ -384,26 +424,67 @@ bool install(char* fpath, bool systemTitle)
//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("\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;
}
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
//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...");
swiWaitForVBlank();
if (padFile(appPath, 0x7C0) == false)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
}
}
@ -415,25 +496,29 @@ bool install(char* fpath, bool systemTitle)
swiWaitForVBlank();
//fix header checksum
header->ndshdr.headerCRC16 = swiCRC16(0xFFFF, header, 0x15E);
h->ndshdr.headerCRC16 = swiCRC16(0xFFFF, h, 0x15E);
//fix RSA signature
u8 buffer[20];
swiSHA1Calc(&buffer, header, 0xE00);
memcpy(&(header->rsa_signature[0x6C]), buffer, 20);
swiSHA1Calc(&buffer, h, 0xE00);
memcpy(&(h->rsa_signature[0x6C]), buffer, 20);
f = fopen(appPath, "r+");
FILE* f = fopen(appPath, "r+");
if (!f)
{
iprintf("\x1B[31m"); //red
iprintf("Failed\n");
iprintf("\x1B[47m"); //white
}
else
{
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("\x1B[47m"); //white
}
fclose(f);
@ -458,25 +543,27 @@ bool install(char* fpath, bool systemTitle)
mkdir(dataPath, 0777);
_createPublicSav(header, dataPath);
_createPrivateSav(header, dataPath);
_createBannerSav(header, dataPath);
_createPublicSav(h, dataPath);
_createPrivateSav(h, dataPath);
_createBannerSav(h, dataPath);
}
//end
result = true;
iprintf("\nInstallation complete.\nBack - [B]\n");
keyWait(KEY_A | KEY_B);
}
iprintf("\x1B[42m"); //green
iprintf("\nInstallation complete.\n");
iprintf("\x1B[47m"); //white
iprintf("Back - [B]\n");
keyWait(KEY_A | KEY_B);
goto complete;
goto complete;
}
error:
messagePrint("\nInstallation failed.\n");
messagePrint("\x1B[31m\nInstallation failed.\n\x1B[47m");
complete:
fclose(f);
free(header);
free(h);
return result;
}

View File

@ -1,5 +1,5 @@
#include "main.h"
#include "app.h"
#include "rom.h"
#include "install.h"
#include "menu.h"
#include "storage.h"
@ -13,28 +13,41 @@ enum {
INSTALL_MENU_BACK
};
static char currentDir[512] = "";
static void generateList(Menu* m);
static void printItem(Menu* m);
static int subMenu();
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()
{
Menu* m = newMenu();
_setHeader(m);
generateList(m);
//no files found
if (m->itemCount <= 0)
/* if (m->itemCount <= 0)
{
clearScreen(&bottomScreen);
iprintf("\x1B[31m"); //red
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");
keyWait(KEY_B | KEY_A | KEY_START);
}
else
else*/
{
while (1)
{
@ -51,51 +64,70 @@ void installMenu()
}
//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
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);
generateList(m);
}
}
break;
case INSTALL_MENU_SYSTEM_TITLE:
{
if (install(m->items[m->cursor], true))
{
resetMenu(m);
generateList(m);
}
}
break;
case INSTALL_MENU_INSTALL:
install(m->items[m->cursor].value, false);
break;
case INSTALL_MENU_SYSTEM_TITLE:
install(m->items[m->cursor].value, true);
break;
case INSTALL_MENU_DELETE:
{
if (delete(m))
{
resetMenu(m);
generateList(m);
case INSTALL_MENU_DELETE:
{
if (delete(m))
{
resetMenu(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:
break;
printMenu(m);
}
printMenu(m);
}
}
}
@ -116,7 +148,7 @@ static void generateList(Menu* m)
bool done = false;
struct dirent* ent;
DIR* dir = opendir(ROM_PATH);
DIR* dir = opendir(currentDir);
if (dir)
{
@ -128,14 +160,35 @@ static void generateList(Menu* m)
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
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 ||
strstr(ent->d_name, ".app") != NULL ||
strstr(ent->d_name, ".dsi") != NULL ||
strstr(ent->d_name, ".cia") != NULL ||
strstr(ent->d_name, ".NDS") != 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)
count += 1;
@ -147,10 +200,10 @@ static void generateList(Menu* m)
else
{
char* fpath = (char*)malloc(strlen(ROM_PATH) + strlen(ent->d_name) + 8);
sprintf(fpath, "%s/%s", ROM_PATH, ent->d_name);
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);
addMenuItem(m, ent->d_name, fpath, 0);
free(fpath);
}
@ -174,7 +227,12 @@ static void generateList(Menu* m)
static void printItem(Menu* m)
{
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()
@ -183,10 +241,10 @@ static int subMenu()
Menu* m = newMenu();
addMenuItem(m, "Install", NULL);
addMenuItem(m, "Install as System Title", NULL);
addMenuItem(m, "Delete", NULL);
addMenuItem(m, "Back - [B]", NULL);
addMenuItem(m, "Install", NULL, 0);
addMenuItem(m, "Install as System Title", NULL, 0);
addMenuItem(m, "Delete", NULL, 0);
addMenuItem(m, "Back - [B]", NULL, 0);
printMenu(m);
@ -219,7 +277,7 @@ static bool delete(Menu* m)
{
if (!m) return false;
char* fpath = m->items[m->cursor];
char* fpath = m->items[m->cursor].value;
bool result = false;
bool choice = NO;
@ -237,18 +295,18 @@ static bool delete(Menu* m)
{
if (!fpath)
{
messageBox("Could not delete file.");
messageBox("\x1B[31mCould not delete file.\x1B[47m");
}
else
{
if (remove(fpath) == 0)
{
result = true;
messageBox("File deleted.");
messageBox("\x1B[42mFile deleted.\x1B[47m");
}
else
{
messageBox("Could not delete file.");
messageBox("\x1B[31mCould not delete file.\x1B[47m");
}
}
}

View File

@ -3,7 +3,7 @@
#include "message.h"
#include <time.h>
#define VERSION "0.6.5 beta"
#define VERSION "0.6.8"
enum {
MAIN_MENU_INSTALL,
@ -43,12 +43,13 @@ static int _mainMenu(int cursor)
//menu
Menu* m = newMenu();
setMenuHeader(m, "MAIN MENU");
addMenuItem(m, "Install", NULL);
addMenuItem(m, "Titles", NULL);
addMenuItem(m, "Restore", NULL);
addMenuItem(m, "Test", NULL);
addMenuItem(m, "Shut Down", NULL);
addMenuItem(m, "Install", NULL, 0);
addMenuItem(m, "Titles", NULL, 0);
addMenuItem(m, "Restore", NULL, 0);
addMenuItem(m, "Test", NULL, 0);
addMenuItem(m, "Shut Down", NULL, 0);
m->cursor = cursor;
@ -81,14 +82,14 @@ int main(int argc, char **argv)
//DSi check
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;
}
//setup sd card access
if (!fatInitDefault())
{
messageBox("fatInitDefault()...Failed\n");
messageBox("fatInitDefault()...\x1B[31mFailed\n\x1B[47m");
return 0;
}

View File

@ -141,7 +141,9 @@ int maketmd(char* input, char* tmdPath)
iprintf("by Przemyslaw Skryjomski\n\t(Tuxality)\n");
if(input == NULL || tmdPath == NULL) {
iprintf("\x1B[33m"); //yellow
iprintf("\nUsage: %s file.app <file.tmd>\n", "maketmd");
iprintf("\x1B[47m"); //white
return 1;
}
@ -149,7 +151,9 @@ int maketmd(char* input, char* tmdPath)
FILE* app = fopen(input, "rb");
if(!app) {
iprintf("\x1B[31m"); //red
iprintf("Error at opening %s for reading.\n", input);
iprintf("\x1B[47m"); //white
return 1;
}
@ -159,7 +163,9 @@ int maketmd(char* input, char* tmdPath)
if (!tmd)
{
fclose(app);
iprintf("\x1B[31m"); //white
iprintf("Error at opening %s for writing.\n", tmdPath);
iprintf("\x1B[47m"); //white
return 1;
}

View File

@ -10,11 +10,13 @@ Menu* newMenu()
m->itemCount = 0;
m->nextPage = false;
m->changePage = 0;
m->header[0] = '\0';
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
m->labels[i] = NULL;
m->items[i] = NULL;
m->items[i].directory = false;
m->items[i].label = NULL;
m->items[i].value = NULL;
}
return m;
@ -30,28 +32,48 @@ void freeMenu(Menu* m)
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;
int i = m->itemCount;
if (i >= ITEMS_PER_PAGE) return;
m->items[i].directory = directory;
if (label)
{
m->labels[i] = (char*)malloc(32);
sprintf(m->labels[i], "%.31s", label);
m->items[i].label = (char*)malloc(32);
sprintf(m->items[i].label, "%.31s", label);
}
if (value)
{
m->items[i] = (char*)malloc(strlen(value)+1);
sprintf(m->items[i], "%s", value);
m->items[i].value = (char*)malloc(strlen(value)+1);
sprintf(m->items[i].value, "%s", value);
}
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)
{
m->cursor = 0;
@ -66,16 +88,16 @@ void clearMenu(Menu* m)
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
if (m->labels[i])
if (m->items[i].label)
{
free(m->labels[i]);
m->labels[i] = NULL;
free(m->items[i].label);
m->items[i].label = NULL;
}
if (m->items[i])
if (m->items[i].value)
{
free(m->items[i]);
m->items[i] = NULL;
free(m->items[i].value);
m->items[i].value = NULL;
}
}
@ -88,23 +110,40 @@ void printMenu(Menu* m)
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++)
{
if (m->labels[i])
iprintf(" %.30s\n", m->labels[i]);
if (m->items[i].label)
{
if (m->items[i].directory)
iprintf(" [%.28s]\n", m->items[i].label);
else
iprintf(" %.30s\n", m->items[i].label);
}
else
iprintf(" \n");
}
//cursor
iprintf("\x1b[%d;0H>", m->cursor);
//cursor
iprintf("\x1b[%d;0H>", 2 + m->cursor);
//scroll arrows
if (m->page > 0)
iprintf("\x1b[0;31H^");
iprintf("\x1b[2;31H^");
if (m->nextPage)
iprintf("\x1b[22;31Hv");
iprintf("\x1b[21;31Hv");
}
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)
{
if (m->cursor >= ITEMS_PER_PAGE)
if (m->nextPage && m->cursor >= ITEMS_PER_PAGE)
{
m->changePage = 1;
m->cursor = 0;

View File

@ -3,7 +3,13 @@
#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 {
int cursor;
@ -11,14 +17,15 @@ typedef struct {
int itemCount;
bool nextPage;
int changePage;
char* labels[ITEMS_PER_PAGE];
char* items[ITEMS_PER_PAGE];
char header[32];
Item items[ITEMS_PER_PAGE];
} Menu;
Menu* newMenu();
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 clearMenu(Menu* m);

View File

@ -20,7 +20,9 @@ bool choiceBox(char* message)
clearScreen(&bottomScreen);
iprintf("\x1B[33m"); //yellow
iprintf("%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
while (1)
@ -55,7 +57,9 @@ bool choicePrint(char* message)
{
bool choice = NO;
iprintf("\x1B[33m"); //yellow
iprintf("\n%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("Yes - [A]\nNo - [B]\n");
while (1)

281
arm9/src/rom.c Normal file
View 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
View 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
View 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
View 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

View File

@ -36,6 +36,8 @@ void printProgressBar(float percent)
{
consoleSelect(&topScreen);
iprintf("\x1B[42m"); //green
//Print frame
if (lastBars <= 0)
{
@ -45,12 +47,14 @@ void printProgressBar(float percent)
//Print bars
if (bars > 0)
{
{
for (int i = 0; i < bars; i++)
iprintf("\x1b[23;%dH|", 1 + i);
iprintf("\x1b[23;%dH|", 1 + i);
}
lastBars = bars;
iprintf("\x1B[47m"); //white
}
}
@ -74,52 +78,75 @@ bool fileExists(char const* path)
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");
FILE* fout = fopen(out, "wb");
unsigned long long size = getFileSizePath(src);
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(fout);
return false;
return 3;
}
else
{
consoleSelect(&topScreen);
FILE* fout = fopen(dst, "wb");
int bytesRead;
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)
if (!fout)
{
bytesRead = fread(buffer, 1, BUFF_SIZE, fin);
fwrite(buffer, bytesRead, 1, fout);
fclose(fin);
fclose(fout);
return 4;
}
else
{
fseek(fin, offset, SEEK_SET);
totalBytesRead += bytesRead;
printProgressBar( ((float)totalBytesRead / (float)fileSize) );
consoleSelect(&topScreen);
if (bytesRead != BUFF_SIZE)
break;
int bytesRead;
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();
consoleSelect(&bottomScreen);
free(buffer);
fclose(fout);
}
fclose(fin);
fclose(fout);
return true;
return 0;
}
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...", fdst);
if(!copyFile(fsrc, fdst))
int ret = copyFile(fsrc, fdst);
if(ret != 0)
{
iprintf("\x1B[31m"); //red
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;
}
else
{
iprintf("\x1B[42m"); //green
iprintf("Done\n");
iprintf("\x1B[47m"); //white
}
free(fdst);
@ -288,12 +343,16 @@ bool deleteDir(char const* path)
iprintf("%s...", fpath);
if (remove(fpath) != 0)
{
iprintf("\x1B[31m");
iprintf("Fail\n");
iprintf("\x1B[47m");
result = false;
}
else
{
iprintf("\x1B[42m");
iprintf("Done\n");
iprintf("\x1B[47m");
}
}
}
@ -304,12 +363,16 @@ bool deleteDir(char const* path)
iprintf("%s...", path);
if (remove(path) != 0)
{
iprintf("\x1B[31m");
iprintf("Fail\n");
iprintf("\x1B[47m");
result = false;
}
else
{
iprintf("\x1B[42m");
iprintf("Done\n");
iprintf("\x1B[47m");
}
return result;
@ -333,14 +396,14 @@ unsigned long long getDirSize(const char* path)
if (ent->d_type == DT_DIR)
{
char fullpath[512];
sprintf(fullpath, "%s%s/", path, ent->d_name);
sprintf(fullpath, "%s/%s", path, ent->d_name);
size += getDirSize(fullpath);
}
else
{
char fullpath[256];
sprintf(fullpath, "%s%s", path, ent->d_name);
char fullpath[260];
sprintf(fullpath, "%s/%s", path, ent->d_name);
size += getFileSizePath(fullpath);
}
@ -432,32 +495,36 @@ unsigned long long getSDCardFree()
}
//internal storage
int getDsiSize()
unsigned long long getDsiSize()
{
//The DSi has 256MB of internal storage. Some is unavailable and used by other things.
//Find a better way to do this
return 240 * 1024 * 1024;
}
int getDsiFree()
unsigned long long getDsiFree()
{
//Get free space by subtracting file sizes in emulated nand folders
//Find a better way to do this
int size = getDsiSize();
long long size = getDsiSize();
size -= getDirSize("/sys/");
size -= getDirSize("/title/");
size -= getDirSize("/ticket/");
size -= getDirSize("/shared1/");
size -= getDirSize("/shared2/");
size -= getDirSize("/import/");
size -= getDirSize("/tmp/");
size -= getDirSize("/progress/");
size -= getDirSize("/sys");
size -= getDirSize("/title/0003000f");
size -= getDirSize("/title/00030004");
size -= getDirSize("/title/00030005");
size -= getDirSize("/title/00030017");
size -= getDirSize("/ticket");
size -= getDirSize("/shared1");
size -= getDirSize("/shared2");
size -= getDirSize("/import");
size -= getDirSize("/tmp");
size -= getDirSize("/progress");
size -= getDirSize("/photo/");
size -= getDirSize("/private/");
size -= getDirSize("/photo");
size -= getDirSize("/private");
size += getDirSize("/title/00030015/");
return size;
if (size < 0)
return 0;
return (unsigned long long)size;
}

View File

@ -5,7 +5,6 @@
#include <stdio.h>
#define BACKUP_PATH "/titlebackup"
#define ROM_PATH "/dsi"
#define BYTES_PER_BLOCK (1024*128)
//printing
@ -17,7 +16,8 @@ void clearProgressBar();
//Files
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 getFileSizePath(char const* path);
bool padFile(char const* path, int size);
@ -40,8 +40,8 @@ unsigned long long getSDCardFree();
#define getSDCardUsedSpace() (getSDCardSize() - getSDCardFree())
//internal storage
int getDsiSize();
int getDsiFree();
unsigned long long getDsiSize();
unsigned long long getDsiFree();
#define getDsiUsed() (getDSIStorageSize() - getDSIStorageFree())
#endif

View File

@ -1,5 +1,5 @@
#include "main.h"
#include "app.h"
#include "rom.h"
#include "menu.h"
#include "message.h"
#include "storage.h"
@ -20,6 +20,7 @@ static bool delete(Menu* m);
void titleMenu()
{
Menu* m = newMenu();
setMenuHeader(m, "INSTALLED TITLES");
generateList(m);
//no titles
@ -146,9 +147,9 @@ static void generateList(Menu* m)
sprintf(path, "%s/%s", contentPath, subent->d_name);
char title[128];
getAppTitle(path, title);
getGameTitlePath(path, title, false);
addMenuItem(m, title, path);
addMenuItem(m, title, path, 0);
free(path);
}
@ -180,7 +181,7 @@ static void generateList(Menu* m)
static void printItem(Menu* m)
{
if (!m) return;
printAppInfo(m->items[m->cursor]);
printRomInfo(m->items[m->cursor].value);
}
static int subMenu()
@ -189,9 +190,9 @@ static int subMenu()
Menu* m = newMenu();
addMenuItem(m, "Backup", NULL);
addMenuItem(m, "Delete", NULL);
addMenuItem(m, "Back - [B]", NULL);
addMenuItem(m, "Backup", NULL, 0);
addMenuItem(m, "Delete", NULL, 0);
addMenuItem(m, "Back - [B]", NULL, 0);
printMenu(m);
@ -219,16 +220,18 @@ static int subMenu()
static void backup(Menu* m)
{
char* fpath = m->items[m->cursor];
char* fpath = m->items[m->cursor].value;
char* backname = NULL;
tDSiHeader* h = getRomHeader(fpath);
{
//make backup folder name
char label[16];
getAppLabel(fpath, label);
getRomLabel(h, label);
char gamecode[5];
getGameCode(fpath, gamecode);
getRomCode(h, gamecode);
backname = (char*)malloc(strlen(label) + strlen(gamecode) + 16);
sprintf(backname, "%s-%s", label, gamecode);
@ -263,7 +266,7 @@ static void backup(Menu* m)
{
u32 tid_low = 1;
u32 tid_high = 1;
getTid(fpath, &tid_low, &tid_high);
getTitleId(h, &tid_low, &tid_high);
char* srcpath = (char*)malloc(strlen("/title/") + 32);
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(h);
}
static bool delete(Menu* m)
{
if (!m) return false;
char* fpath = m->items[m->cursor];
char* fpath = m->items[m->cursor].value;
bool result = false;
bool choice = NO;
{
//get app title
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* msg = (char*)malloc(strlen(str) + strlen(title) + 8);
@ -343,7 +347,7 @@ static bool delete(Menu* m)
else
{
char dirPath[64];
sprintf(dirPath, "%.25s", fpath);
sprintf(dirPath, "%.24s", fpath);
if (!dirExists(dirPath))
{