mirror of
https://github.com/rvtr/TDT.git
synced 2025-10-31 13:51:07 -04:00
Add files via upload
This commit is contained in:
parent
14dcd71e33
commit
eb16d0581a
BIN
icon.bmp
BIN
icon.bmp
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@ -1,280 +1,10 @@
|
|||||||
#include "menus.h"
|
#include "menu.h"
|
||||||
|
#include "main.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
#include "titles.h"
|
||||||
#include "maketmd.h"
|
#include "maketmd.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
static int cursor = 0;
|
|
||||||
static int scrolly = 0;
|
|
||||||
static int numberOfTitles = 0;
|
|
||||||
|
|
||||||
static void moveCursor(int dir);
|
|
||||||
|
|
||||||
static void printList();
|
|
||||||
static void printFileInfoNum(int num);
|
|
||||||
|
|
||||||
static int getNumberOfTitles();
|
|
||||||
//static void getGameTitle(char* title, FILE* f);
|
|
||||||
static int getFile(char* dest, int num, int fullpath);
|
|
||||||
|
|
||||||
static void subMenu();
|
|
||||||
static void install(char* fpath);
|
|
||||||
|
|
||||||
void installMenu()
|
|
||||||
{
|
|
||||||
cursor = 0;
|
|
||||||
scrolly = 0;
|
|
||||||
numberOfTitles = getNumberOfTitles();
|
|
||||||
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
//No titles error
|
|
||||||
if (numberOfTitles == 0)
|
|
||||||
{
|
|
||||||
iprintf("No files found.\n");
|
|
||||||
iprintf("Place .nds(dsi) or .app files in %s\n", ROM_PATH);
|
|
||||||
iprintf("\nBack - B\n");
|
|
||||||
|
|
||||||
keyWait(KEY_B | KEY_A | KEY_START);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print data
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
printFileInfoNum(cursor);
|
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
printList();
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
swiWaitForVBlank();
|
|
||||||
scanKeys();
|
|
||||||
|
|
||||||
int thisCursor = cursor;
|
|
||||||
int thisscrolly = scrolly;
|
|
||||||
|
|
||||||
//Clear cursor
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
iprintf("\x1b[%d;0H ", cursor - scrolly);
|
|
||||||
|
|
||||||
//Move cursor
|
|
||||||
if (keysDown() & KEY_DOWN)
|
|
||||||
moveCursor(1);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_UP)
|
|
||||||
moveCursor(-1);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_RIGHT)
|
|
||||||
{
|
|
||||||
repeat (10)
|
|
||||||
moveCursor(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysDown() & KEY_LEFT)
|
|
||||||
{
|
|
||||||
repeat (10)
|
|
||||||
moveCursor(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Refresh screens
|
|
||||||
if (thisCursor != cursor)
|
|
||||||
{
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
printFileInfoNum(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thisscrolly != scrolly)
|
|
||||||
{
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
printList();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print cursor
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
iprintf("\x1b[%d;0H>", cursor - scrolly);
|
|
||||||
|
|
||||||
//
|
|
||||||
if (keysDown() & KEY_B)
|
|
||||||
break;
|
|
||||||
else if (keysDown() & KEY_A)
|
|
||||||
{
|
|
||||||
subMenu();
|
|
||||||
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
printFileInfoNum(cursor);
|
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
printList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveCursor(int dir)
|
|
||||||
{
|
|
||||||
cursor += sign(dir);
|
|
||||||
|
|
||||||
if (cursor < 0)
|
|
||||||
cursor = 0;
|
|
||||||
|
|
||||||
if (cursor >= numberOfTitles - 1)
|
|
||||||
cursor = numberOfTitles - 1;
|
|
||||||
|
|
||||||
if (cursor - scrolly >= 23)
|
|
||||||
scrolly += 1;
|
|
||||||
|
|
||||||
if (cursor - scrolly < 0)
|
|
||||||
scrolly -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printList()
|
|
||||||
{
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
for (int i = scrolly; i < scrolly + 23; i++)
|
|
||||||
{
|
|
||||||
char str[256];
|
|
||||||
if (getFile(str, i, 0) == 1)
|
|
||||||
iprintf(" %.30s\n", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Scroll arrows
|
|
||||||
if (scrolly > 0)
|
|
||||||
iprintf("\x1b[0;31H^");
|
|
||||||
|
|
||||||
if (scrolly < numberOfTitles - 23)
|
|
||||||
iprintf("\x1b[22;31Hv");
|
|
||||||
}
|
|
||||||
|
|
||||||
void printFileInfoNum(int num)
|
|
||||||
{
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
char path[256];
|
|
||||||
if (getFile(path, num, 1) == 1)
|
|
||||||
printFileInfo(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getNumberOfTitles()
|
|
||||||
{
|
|
||||||
DIR* dir;
|
|
||||||
struct dirent* ent;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
dir = opendir(ROM_PATH);
|
|
||||||
|
|
||||||
if (dir)
|
|
||||||
{
|
|
||||||
while ( (ent = readdir(dir)) != NULL )
|
|
||||||
{
|
|
||||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ent->d_type != DT_DIR)
|
|
||||||
{
|
|
||||||
if (strstr(ent->d_name, ".nds") != NULL || strstr(ent->d_name, ".app") != NULL)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
void getGameTitle(char* title, FILE* f)
|
|
||||||
{
|
|
||||||
tDSiHeader header;
|
|
||||||
tNDSBanner banner;
|
|
||||||
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
fread(&header, sizeof(tDSiHeader), 1, f);
|
|
||||||
fseek(f, header.ndshdr.bannerOffset, SEEK_SET);
|
|
||||||
fread(&banner, sizeof(tNDSBanner), 1, f);
|
|
||||||
|
|
||||||
// iprintf("\t%s\n", header.ndshdr.gameTitle);
|
|
||||||
// iprintf("\t%s\n", (char*)banner.titles[0]);
|
|
||||||
|
|
||||||
int line = 0;
|
|
||||||
for (int i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
char c = banner.titles[0][i];
|
|
||||||
|
|
||||||
if (c == '\n')
|
|
||||||
{
|
|
||||||
if (line == 0)
|
|
||||||
{
|
|
||||||
title[i] = ' ';
|
|
||||||
line = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
title[i] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
title[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
title[64] = '\0';
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int getFile(char* dest, int num, int fullpath)
|
|
||||||
{
|
|
||||||
DIR* dir;
|
|
||||||
struct dirent* ent;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
dir = opendir(ROM_PATH);
|
|
||||||
|
|
||||||
if (dir)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while ( (ent = readdir(dir)) != NULL )
|
|
||||||
{
|
|
||||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ent->d_type != DT_DIR)
|
|
||||||
{
|
|
||||||
if(strstr(ent->d_name, ".nds") != NULL || strstr(ent->d_name, ".app") != NULL)
|
|
||||||
{
|
|
||||||
if (count < num)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fullpath == 0)
|
|
||||||
sprintf(dest, "%s", ent->d_name);
|
|
||||||
else
|
|
||||||
sprintf(dest, "%s%s", ROM_PATH, ent->d_name);
|
|
||||||
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
static int subCursor = 0;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
INSTALL_MENU_INSTALL,
|
INSTALL_MENU_INSTALL,
|
||||||
@ -282,154 +12,305 @@ enum {
|
|||||||
INSTALL_MENU_BACK
|
INSTALL_MENU_BACK
|
||||||
};
|
};
|
||||||
|
|
||||||
void subMenu()
|
static void generateList(Menu* m);
|
||||||
|
static void printItem(Menu* m);
|
||||||
|
|
||||||
|
static int subMenu();
|
||||||
|
static void install(Menu* m);
|
||||||
|
static void delete(Menu* m);
|
||||||
|
|
||||||
|
|
||||||
|
void installMenu()
|
||||||
{
|
{
|
||||||
bool printMenu = true;
|
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||||
subCursor = 0;
|
|
||||||
|
clearMenu(m);
|
||||||
|
generateList(m);
|
||||||
|
|
||||||
|
//No files found
|
||||||
|
if (getNumberOfMenuItems(m) <= 0)
|
||||||
|
{
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
iprintf("No files found.\n");
|
||||||
|
iprintf("Place .nds, .app, or .dsi files in %s\n", ROM_PATH);
|
||||||
|
iprintf("\nBack - B\n");
|
||||||
|
|
||||||
|
keyWait(KEY_B | KEY_A | KEY_START);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Print data
|
||||||
|
printItem(m);
|
||||||
|
printMenu(m);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
scanKeys();
|
scanKeys();
|
||||||
|
|
||||||
if (printMenu == true)
|
if (moveCursor(m))
|
||||||
{
|
{
|
||||||
printMenu = false;
|
printItem(m);
|
||||||
|
printMenu(m);
|
||||||
|
}
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
if (keysDown() & KEY_B)
|
||||||
consoleClear();
|
break;
|
||||||
|
|
||||||
iprintf("\tInstall\n");
|
//Selection
|
||||||
iprintf("\tDelete\n");
|
else if (keysDown() & KEY_A)
|
||||||
iprintf("\tBack - B\n");
|
{
|
||||||
|
switch (subMenu())
|
||||||
|
{
|
||||||
|
case INSTALL_MENU_INSTALL:
|
||||||
|
install(m);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSTALL_MENU_DELETE:
|
||||||
|
delete(m);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSTALL_MENU_BACK:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Clear cursor
|
free(m);
|
||||||
iprintf("\x1b[%d;0H ", subCursor);
|
}
|
||||||
|
|
||||||
//Move cursor
|
//mode = 0: add items to menu
|
||||||
if (keysDown() & KEY_DOWN)
|
//mode = 1: return full path of item num to out
|
||||||
|
static bool _walkList(Menu* m, int mode, char* out)
|
||||||
|
{
|
||||||
|
//Skip if no menu
|
||||||
|
if (m == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//Reset menu
|
||||||
|
if (mode == 0)
|
||||||
|
clearMenu(m);
|
||||||
|
|
||||||
|
//
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* ent;
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
dir = opendir(ROM_PATH);
|
||||||
|
|
||||||
|
if (dir)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
//Scan /dsi/
|
||||||
|
while ( (ent = readdir(dir)) != NULL )
|
||||||
{
|
{
|
||||||
if (subCursor < INSTALL_MENU_BACK)
|
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||||
subCursor++;
|
continue;
|
||||||
|
|
||||||
|
if (ent->d_type != DT_DIR)
|
||||||
|
{
|
||||||
|
if (strstr(ent->d_name, ".nds") != NULL || strstr(ent->d_name, ".app") != NULL || strstr(ent->d_name, ".dsi") != NULL ||
|
||||||
|
strstr(ent->d_name, ".NDS") != NULL || strstr(ent->d_name, ".APP") != NULL || strstr(ent->d_name, ".DSI") != NULL)
|
||||||
|
{
|
||||||
|
//Generate list
|
||||||
|
if (mode == 0)
|
||||||
|
{
|
||||||
|
char name[128];
|
||||||
|
sprintf(name, "%s", ent->d_name);
|
||||||
|
|
||||||
|
addMenuItem(m, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get item file name
|
||||||
|
else if (mode == 1)
|
||||||
|
{
|
||||||
|
if (count < m->cursor)
|
||||||
|
count++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf(out, "%s%s", ROM_PATH, ent->d_name);
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
goto endloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keysDown() & KEY_UP)
|
endloop:
|
||||||
{
|
closedir(dir);
|
||||||
if (subCursor > 0)
|
return result;
|
||||||
subCursor--;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//Reprint cursor
|
void generateList(Menu* m)
|
||||||
iprintf("\x1b[%d;0H>", subCursor);
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
iprintf("Gathering files...\n");
|
||||||
|
|
||||||
|
_walkList(m, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printItem(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
char path[256];
|
||||||
|
if (_walkList(m, 1, path) == true)
|
||||||
|
printFileInfo(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
int subMenu()
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||||
|
clearMenu(m);
|
||||||
|
|
||||||
|
addMenuItem(m, "Install");
|
||||||
|
addMenuItem(m, "Delete");
|
||||||
|
addMenuItem(m, "Back - B");
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
|
||||||
|
if (moveCursor(m))
|
||||||
|
printMenu(m);
|
||||||
|
|
||||||
//
|
|
||||||
if (keysDown() & KEY_B)
|
if (keysDown() & KEY_B)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
else if (keysDown() & KEY_A)
|
else if (keysDown() & KEY_A)
|
||||||
{
|
{
|
||||||
if (subCursor == INSTALL_MENU_INSTALL)
|
result = m->cursor;
|
||||||
{
|
break;
|
||||||
char fpath[256];
|
|
||||||
getFile(fpath, cursor, 1);
|
|
||||||
|
|
||||||
char msg[512+1];
|
|
||||||
msg[512] = '\0';
|
|
||||||
sprintf(msg, "Are you sure you want to install\n%s\n", fpath);
|
|
||||||
|
|
||||||
if (choiceBox(msg) == YES)
|
|
||||||
install(fpath);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (subCursor == INSTALL_MENU_DELETE)
|
|
||||||
{
|
|
||||||
char fpath[256];
|
|
||||||
getFile(fpath, cursor, 1);
|
|
||||||
|
|
||||||
char msg[512+1];
|
|
||||||
msg[512] = '\0';
|
|
||||||
sprintf(msg, "Are you sure you want to delete\n%s\n", fpath);
|
|
||||||
|
|
||||||
if (choiceBox(msg) == YES)
|
|
||||||
{
|
|
||||||
if (remove(fpath) != 0)
|
|
||||||
messageBox("File could not be deleted.");
|
|
||||||
|
|
||||||
else
|
|
||||||
messageBox("File deleted.");
|
|
||||||
|
|
||||||
//Reset
|
|
||||||
cursor = 0;
|
|
||||||
scrolly = 0;
|
|
||||||
numberOfTitles = getNumberOfTitles();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printMenu = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (subCursor == INSTALL_MENU_BACK)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(m);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void install(char* fpath)
|
void install(Menu* m)
|
||||||
{
|
{
|
||||||
|
char fpath[256];
|
||||||
|
|
||||||
|
//Confirmation message
|
||||||
|
{
|
||||||
|
int choice = NO;
|
||||||
|
|
||||||
|
if (_walkList(m, 1, fpath) == true)
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
sprintf(msg, "Are you sure you want to install\n%s\n", fpath);
|
||||||
|
choice = choiceBox(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice == NO)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start installation
|
||||||
consoleSelect(&bottomScreen);
|
consoleSelect(&bottomScreen);
|
||||||
consoleClear();
|
consoleClear();
|
||||||
|
|
||||||
iprintf("Installing %s\n", fpath); swiWaitForVBlank();
|
iprintf("Installing %s\n", fpath); swiWaitForVBlank();
|
||||||
|
|
||||||
|
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
||||||
|
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
FILE* f = fopen(fpath, "rb");
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
iprintf("Error: could not open file.\n\nPress B to exit.\n");
|
iprintf("Error: could not open file.\n");
|
||||||
keyWait(KEY_A | KEY_B);
|
goto error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Load header
|
bool patchHeader = false;
|
||||||
tDSiHeader header;
|
|
||||||
tNDSBanner banner;
|
|
||||||
|
|
||||||
|
//Read header and banner
|
||||||
{
|
{
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
fread(&header, sizeof(tDSiHeader), 1, f);
|
fread(header, sizeof(tDSiHeader), 1, f);
|
||||||
fseek(f, header.ndshdr.bannerOffset, SEEK_SET);
|
|
||||||
fread(&banner, sizeof(tNDSBanner), 1, f);
|
fseek(f, header->ndshdr.bannerOffset, SEEK_SET);
|
||||||
|
fread(banner, sizeof(tNDSBanner), 1, f);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
//Check header size
|
//Patch homebrew roms if gameCode is #### or null
|
||||||
if (header.ndshdr.headerSize != 0x4000)
|
if ((strcmp(header->ndshdr.gameCode, "####") == 0 && header->tid_low == 0x23232323) ||
|
||||||
|
(!*header->ndshdr.gameCode && header->tid_low == 0))
|
||||||
{
|
{
|
||||||
iprintf("Error: no DSi header.");
|
iprintf("Patching header...");
|
||||||
goto error;
|
|
||||||
|
patchHeader = true;
|
||||||
|
|
||||||
|
//Set as standard app
|
||||||
|
header->tid_high = 0x00030004;
|
||||||
|
|
||||||
|
//Give it a random game code
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//First letter shouldn't be A
|
||||||
|
do
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
header->ndshdr.gameCode[i] = 0x41 + (rand() % (26));
|
||||||
|
}
|
||||||
|
while (header->ndshdr.gameCode[0] == 'A');
|
||||||
|
|
||||||
|
//Correct title id
|
||||||
|
header->tid_low = gameCodeToTitleID(header->ndshdr.gameCode);
|
||||||
|
}
|
||||||
|
while (titleIsUsed(header->tid_low, header->tid_high) == true);
|
||||||
|
|
||||||
|
//Fix header checksum
|
||||||
|
header->ndshdr.headerCRC16 = swiCRC16(0xFFFF, header, 0x15E);
|
||||||
|
|
||||||
|
//Fix RSA signature
|
||||||
|
u8 buffer[20];
|
||||||
|
swiSHA1Calc(&buffer, header, 0xE00);
|
||||||
|
memcpy(&(header->rsa_signature[0x6C]), buffer, 20);
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
//Check high title id
|
//Must be DSi rom
|
||||||
if (header.tid_high != 0x00030004 &&
|
//High title id must be one of three
|
||||||
header.tid_high != 0x00030005 &&
|
|
||||||
header.tid_high != 0x00030015)
|
|
||||||
{
|
{
|
||||||
iprintf("This file cannot be installed.\nInvalid title ID.");
|
if (header->tid_high != 0x00030004 &&
|
||||||
goto error;
|
header->tid_high != 0x00030005 &&
|
||||||
|
header->tid_high != 0x00030015 &&
|
||||||
|
header->tid_high != 0x00030017)
|
||||||
|
{
|
||||||
|
iprintf("Error: This is not a DSi rom.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Print file size
|
//Print file size
|
||||||
int fileSize = -1;
|
int fileSize = -1;
|
||||||
|
|
||||||
{
|
{
|
||||||
iprintf("File Size: "); swiWaitForVBlank();
|
iprintf("File Size: ");
|
||||||
|
|
||||||
fileSize = getFileSize(f);
|
fileSize = getFileSize(f);
|
||||||
|
|
||||||
@ -437,12 +318,12 @@ void install(char* fpath)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Do not want file opened anymore
|
//Do not need file opened anymore
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
//SD card check
|
//SD card check
|
||||||
{
|
{
|
||||||
iprintf("Enough room on SD card?..."); swiWaitForVBlank();
|
iprintf("Enough room on SD card?...");
|
||||||
|
|
||||||
if (getSDCardFree() < fileSize)
|
if (getSDCardFree() < fileSize)
|
||||||
{
|
{
|
||||||
@ -455,28 +336,28 @@ void install(char* fpath)
|
|||||||
|
|
||||||
//DSi storage check
|
//DSi storage check
|
||||||
{
|
{
|
||||||
iprintf("Enough room on DSi?..."); swiWaitForVBlank();
|
iprintf("Enough room on DSi?...");
|
||||||
|
|
||||||
if (getDsiFree() < fileSize)
|
if (getDsiFree() < fileSize)
|
||||||
{
|
{
|
||||||
iprintf("No\n"); swiWaitForVBlank();
|
iprintf("No\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("Yes\n"); swiWaitForVBlank();
|
iprintf("Yes\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Menu slot check
|
//Menu slot check
|
||||||
{
|
{
|
||||||
iprintf("Open DSi menu slot?..."); swiWaitForVBlank();
|
iprintf("Open DSi menu slot?...");
|
||||||
|
|
||||||
if (getMenuSlotsFree() <= 0)
|
if (getMenuSlotsFree() <= 0)
|
||||||
{
|
{
|
||||||
iprintf("No\n"); swiWaitForVBlank();
|
iprintf("No\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("Yes\n"); swiWaitForVBlank();
|
iprintf("Yes\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create title directory
|
//Create title directory
|
||||||
@ -484,10 +365,8 @@ void install(char* fpath)
|
|||||||
char dirPath[256];
|
char dirPath[256];
|
||||||
|
|
||||||
{
|
{
|
||||||
sprintf(titleID, "%08x", (unsigned int)header.tid_low);
|
sprintf(titleID, "%08x", (unsigned int)header->tid_low);
|
||||||
sprintf(dirPath, "/title/%08x/%s", (unsigned int)header.tid_high, titleID);
|
sprintf(dirPath, "/title/%08x/%s", (unsigned int)header->tid_high, titleID);
|
||||||
|
|
||||||
//iprintf("Creating dir\n%s\n", dirPath); swiWaitForVBlank();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if title is already installed
|
//Check if title is already installed
|
||||||
@ -523,24 +402,46 @@ void install(char* fpath)
|
|||||||
char contentPath[256];
|
char contentPath[256];
|
||||||
sprintf(contentPath, "%s/content", dirPath);
|
sprintf(contentPath, "%s/content", dirPath);
|
||||||
|
|
||||||
//iprintf("Creating dir\n%s\n", contentPath); swiWaitForVBlank();
|
|
||||||
mkdir(contentPath, 0777);
|
mkdir(contentPath, 0777);
|
||||||
|
|
||||||
//Create 0000000.app
|
//Create 0000000.app
|
||||||
//Does 00000000 always work?
|
|
||||||
{
|
{
|
||||||
char appPath[256];
|
char appPath[256];
|
||||||
sprintf(appPath, "%s/00000000.app", contentPath);
|
sprintf(appPath, "%s/00000000.app", contentPath);
|
||||||
|
|
||||||
iprintf("Creating 00000000.app..."); swiWaitForVBlank();
|
//Copy nds file to app
|
||||||
|
|
||||||
if (copyFile(fpath, appPath) == 0)
|
|
||||||
{
|
{
|
||||||
iprintf("Failed\n");
|
iprintf("Creating 00000000.app...");
|
||||||
goto error;
|
|
||||||
|
if (copyFile(fpath, appPath) == 0)
|
||||||
|
{
|
||||||
|
iprintf("Failed\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("Done\n");
|
//Write new patched header
|
||||||
|
if (patchHeader == true)
|
||||||
|
{
|
||||||
|
iprintf("Writing header...");
|
||||||
|
|
||||||
|
FILE* f = fopen(appPath, "r+");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
iprintf("Failed\n");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fwrite(header, sizeof(tDSiHeader), 1, f);
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
//Make TMD
|
//Make TMD
|
||||||
{
|
{
|
||||||
@ -558,101 +459,140 @@ void install(char* fpath)
|
|||||||
char dataPath[256];
|
char dataPath[256];
|
||||||
sprintf(dataPath, "%s/data", dirPath);
|
sprintf(dataPath, "%s/data", dirPath);
|
||||||
|
|
||||||
//iprintf("Creating dir\n%s\n", dataPath); swiWaitForVBlank();
|
|
||||||
mkdir(dataPath, 0777);
|
mkdir(dataPath, 0777);
|
||||||
|
|
||||||
//If needed, create public.sav
|
//If needed, create public.sav
|
||||||
if (header.public_sav_size > 0)
|
if (header->public_sav_size > 0)
|
||||||
{
|
{
|
||||||
char publicPath[512];
|
char publicPath[512];
|
||||||
sprintf(publicPath, "%s/public.sav", dataPath);
|
sprintf(publicPath, "%s/public.sav", dataPath);
|
||||||
|
|
||||||
iprintf("Creating public.sav..."); swiWaitForVBlank();
|
|
||||||
|
|
||||||
FILE* file = fopen(publicPath, "wb");
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
iprintf("Failed\n");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
char num = 0;
|
iprintf("Creating public.sav...");
|
||||||
|
|
||||||
repeat (header.public_sav_size)
|
FILE* file = fopen(publicPath, "wb");
|
||||||
fwrite(&num, 1, 1, f);
|
|
||||||
|
|
||||||
iprintf("Done\n");
|
if (!file)
|
||||||
|
iprintf("Failed\n");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char num = 0;
|
||||||
|
|
||||||
|
repeat (header->public_sav_size)
|
||||||
|
fwrite(&num, 1, 1, f);
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If needed, create private.sav
|
//If needed, create private.sav
|
||||||
if (header.private_sav_size > 0)
|
if (header->private_sav_size > 0)
|
||||||
{
|
{
|
||||||
char privatePath[512];
|
char privatePath[512];
|
||||||
sprintf(privatePath, "%s/private.sav", dataPath);
|
sprintf(privatePath, "%s/private.sav", dataPath);
|
||||||
|
|
||||||
iprintf("Creating private.sav..."); swiWaitForVBlank();
|
|
||||||
|
|
||||||
FILE* file = fopen(privatePath, "wb");
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
iprintf("Failed\n");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
char num = 0;
|
iprintf("Creating private.sav...");
|
||||||
|
|
||||||
repeat (header.private_sav_size)
|
FILE* file = fopen(privatePath, "wb");
|
||||||
fwrite(&num, 1, 1, f);
|
|
||||||
|
|
||||||
iprintf("Done\n");
|
if (!file)
|
||||||
|
iprintf("Failed\n");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char num = 0;
|
||||||
|
|
||||||
|
repeat (header->private_sav_size)
|
||||||
|
fwrite(&num, 1, 1, f);
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//If needed, create banner.sav
|
//If needed, create banner.sav
|
||||||
if (header.appflags & 0x4)
|
if (header->appflags & 0x4)
|
||||||
{
|
{
|
||||||
char bannerPath[512];
|
char bannerPath[512];
|
||||||
sprintf(bannerPath, "%s/banner.sav", dataPath);
|
sprintf(bannerPath, "%s/banner.sav", dataPath);
|
||||||
|
|
||||||
iprintf("Creating banner.sav..."); swiWaitForVBlank();
|
|
||||||
|
|
||||||
FILE* file = fopen(bannerPath, "wb");
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
iprintf("Failed\n");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
char num = 0;
|
iprintf("Creating banner.sav...");
|
||||||
|
|
||||||
repeat (1024*16) //Is banner.sav always 16kb?
|
FILE* file = fopen(bannerPath, "wb");
|
||||||
fwrite(&num, 1, 1, f);
|
|
||||||
|
|
||||||
iprintf("Done\n");
|
if (!file)
|
||||||
|
iprintf("Failed\n");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char num = 0;
|
||||||
|
|
||||||
|
repeat (0x4000)
|
||||||
|
fwrite(&num, 1, 1, f);
|
||||||
|
|
||||||
|
iprintf("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
iprintf("\nInstallation complete.\nPress B to exit.\n");
|
iprintf("\nInstallation complete.\nPress B to exit.\n");
|
||||||
keyWait(KEY_A | KEY_B);
|
keyWait(KEY_A | KEY_B);
|
||||||
}
|
}
|
||||||
|
|
||||||
complete:
|
goto complete;
|
||||||
fclose(f);
|
|
||||||
return;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
iprintf("\nInstallation failed.\n\nPress B to exit.\n");
|
iprintf("\nInstallation failed.\n\nPress B to exit.\n");
|
||||||
keyWait(KEY_A | KEY_B);
|
keyWait(KEY_A | KEY_B);
|
||||||
|
|
||||||
|
complete:
|
||||||
|
free(banner);
|
||||||
|
free(header);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(Menu* m)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
int choice = NO;
|
||||||
|
|
||||||
|
if (_walkList(m, 1, path) == true)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
sprintf(msg, "Are you sure you want to delete\n%s\n", path);
|
||||||
|
choice = choiceBox(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice == YES)
|
||||||
|
{
|
||||||
|
if (remove(path) != 0)
|
||||||
|
{
|
||||||
|
messageBox("File could not be deleted.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageBox("File deleted.");
|
||||||
|
|
||||||
|
generateList(m);
|
||||||
|
printItem(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
}
|
}
|
||||||
77
src/main.c
77
src/main.c
@ -1,7 +1,8 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "menus.h"
|
#include "menu.h"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#define VERSION "0.4"
|
#define VERSION "0.5"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MAIN_MENU_INSTALL,
|
MAIN_MENU_INSTALL,
|
||||||
@ -15,6 +16,8 @@ static int mainMenu();
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
srand(time(0));
|
||||||
|
|
||||||
videoSetMode(MODE_0_2D);
|
videoSetMode(MODE_0_2D);
|
||||||
videoSetModeSub(MODE_0_2D);
|
videoSetModeSub(MODE_0_2D);
|
||||||
|
|
||||||
@ -24,6 +27,9 @@ int main(int argc, char **argv)
|
|||||||
consoleInit(&topScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
|
consoleInit(&topScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
|
||||||
consoleInit(&bottomScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true);
|
consoleInit(&bottomScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true);
|
||||||
|
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
if (!fatInitDefault())
|
if (!fatInitDefault())
|
||||||
{
|
{
|
||||||
consoleSelect(&bottomScreen);
|
consoleSelect(&bottomScreen);
|
||||||
@ -64,9 +70,7 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cursor = 0;
|
static int mainMenu()
|
||||||
|
|
||||||
int mainMenu()
|
|
||||||
{
|
{
|
||||||
consoleSelect(&topScreen);
|
consoleSelect(&topScreen);
|
||||||
consoleClear();
|
consoleClear();
|
||||||
@ -75,59 +79,30 @@ int mainMenu()
|
|||||||
iprintf("\nversion %s\n", VERSION);
|
iprintf("\nversion %s\n", VERSION);
|
||||||
iprintf("\x1b[23;0HJeff - 2018");
|
iprintf("\x1b[23;0HJeff - 2018");
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||||
consoleClear();
|
clearMenu(m);
|
||||||
|
|
||||||
|
addMenuItem(m, "Install");
|
||||||
|
addMenuItem(m, "Titles");
|
||||||
|
addMenuItem(m, "Test");
|
||||||
|
addMenuItem(m, "Exit");
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
|
|
||||||
iprintf("\tInstall\n");
|
|
||||||
iprintf("\tTitles\n");
|
|
||||||
// iprintf("\tRestore\n");
|
|
||||||
iprintf("\tTest\n");
|
|
||||||
iprintf("\tExit");
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
scanKeys();
|
scanKeys();
|
||||||
|
|
||||||
//Clear cursor
|
if (moveCursor(m) == 1)
|
||||||
iprintf("\x1b[%d;0H ", cursor);
|
printMenu(m);
|
||||||
|
|
||||||
if (keysDown() & KEY_DOWN)
|
|
||||||
{
|
|
||||||
if ( (cursor += 1) > MAIN_MENU_EXIT )
|
|
||||||
cursor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysDown() & KEY_RIGHT)
|
|
||||||
{
|
|
||||||
repeat (10)
|
|
||||||
{
|
|
||||||
if ( (cursor += 1) > MAIN_MENU_EXIT )
|
|
||||||
cursor = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysDown() & KEY_UP)
|
|
||||||
{
|
|
||||||
if ( (cursor -= 1) < 0 )
|
|
||||||
cursor = MAIN_MENU_EXIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysDown() & KEY_LEFT)
|
|
||||||
{
|
|
||||||
repeat (10)
|
|
||||||
{
|
|
||||||
if ( (cursor -= 1) < 0 )
|
|
||||||
cursor = MAIN_MENU_EXIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//print cursor
|
|
||||||
iprintf("\x1b[%d;0H>", cursor);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_A)
|
if (keysDown() & KEY_A)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cursor = m->cursor;
|
||||||
|
free(m);
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
191
src/menu.c
Normal file
191
src/menu.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "menu.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include <nds.h>
|
||||||
|
|
||||||
|
#define SCREEN_ROWS 23
|
||||||
|
|
||||||
|
void clearMenu(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
m->numberOfItems = 0;
|
||||||
|
m->cursor = 0;
|
||||||
|
m->scrolly = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _printMenuItem(Menu* m, int item)
|
||||||
|
{
|
||||||
|
if (item < 0 || item > m->numberOfItems) return;
|
||||||
|
|
||||||
|
iprintf(" %.30s", m->items[item].label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printMenu(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
swiWaitForVBlank();
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
int i = m->scrolly;
|
||||||
|
while (i < m->scrolly + SCREEN_ROWS && i < m->numberOfItems)
|
||||||
|
{
|
||||||
|
_printMenuItem(m, i);
|
||||||
|
iprintf("\n");
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cursor
|
||||||
|
iprintf("\x1b[%d;0H>", m->cursor - m->scrolly);
|
||||||
|
|
||||||
|
//Scroll arrows
|
||||||
|
if (m->scrolly > 0)
|
||||||
|
iprintf("\x1b[0;31H^");
|
||||||
|
|
||||||
|
if (m->scrolly < m->numberOfItems - SCREEN_ROWS)
|
||||||
|
iprintf("\x1b[22;31Hv");
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMenuCursor(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return -1;
|
||||||
|
return m->cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumberOfMenuItems(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return -1;
|
||||||
|
return m->numberOfItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _moveCursor(Menu* m, int dir)
|
||||||
|
{
|
||||||
|
m->cursor += sign(dir);
|
||||||
|
|
||||||
|
if (m->cursor < 0)
|
||||||
|
m->cursor = 0;
|
||||||
|
|
||||||
|
if (m->cursor >= m->numberOfItems - 1)
|
||||||
|
m->cursor = m->numberOfItems - 1;
|
||||||
|
|
||||||
|
if (m->cursor - m->scrolly >= SCREEN_ROWS)
|
||||||
|
m->scrolly += 1;
|
||||||
|
|
||||||
|
if (m->cursor - m->scrolly < 0)
|
||||||
|
m->scrolly -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int moveCursor(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int lastCursor = m->cursor;
|
||||||
|
|
||||||
|
if (keysDown() & KEY_DOWN)
|
||||||
|
_moveCursor(m, 1);
|
||||||
|
|
||||||
|
if (keysDown() & KEY_UP)
|
||||||
|
_moveCursor(m, -1);
|
||||||
|
|
||||||
|
if (keysDown() & KEY_RIGHT)
|
||||||
|
{
|
||||||
|
repeat (10)
|
||||||
|
_moveCursor(m, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keysDown() & KEY_LEFT)
|
||||||
|
{
|
||||||
|
repeat (10)
|
||||||
|
_moveCursor(m, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(lastCursor == m->cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMenuItem(Menu* m, char* label)
|
||||||
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
if (label != NULL)
|
||||||
|
sprintf(m->items[m->numberOfItems].label, "%.32s", label);
|
||||||
|
|
||||||
|
m->numberOfItems += 1;
|
||||||
|
|
||||||
|
m->cursor = 0;
|
||||||
|
m->scrolly = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void keyWait(u32 key)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
|
||||||
|
if (keysDown() & key)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int choiceBox(char* message)
|
||||||
|
{
|
||||||
|
const int choiceRow = 10;
|
||||||
|
int cursor = 0;
|
||||||
|
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
iprintf("%s\n", message);
|
||||||
|
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
|
||||||
|
//Clear cursor
|
||||||
|
iprintf("\x1b[%d;0H ", choiceRow + cursor);
|
||||||
|
|
||||||
|
if (keysDown() & (KEY_UP | KEY_DOWN))
|
||||||
|
cursor = !cursor;
|
||||||
|
|
||||||
|
//Print cursor
|
||||||
|
iprintf("\x1b[%d;0H>", choiceRow + cursor);
|
||||||
|
|
||||||
|
if (keysDown() & (KEY_A | KEY_START))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (keysDown() & KEY_B)
|
||||||
|
{
|
||||||
|
cursor = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scanKeys();
|
||||||
|
return (cursor == 0)? YES: NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void messageBox(char* message)
|
||||||
|
{
|
||||||
|
consoleSelect(&bottomScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
iprintf("%s\n", message);
|
||||||
|
iprintf("\nOkay - A\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
swiWaitForVBlank();
|
||||||
|
scanKeys();
|
||||||
|
|
||||||
|
if (keysDown() & (KEY_A | KEY_START))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scanKeys();
|
||||||
|
}
|
||||||
40
src/menu.h
Normal file
40
src/menu.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef MENU_H
|
||||||
|
#define MENU_H
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
|
||||||
|
void titleMenu();
|
||||||
|
void installMenu();
|
||||||
|
void testMenu();
|
||||||
|
|
||||||
|
#define NUM_OF_ITEMS 100
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char label[32+1];
|
||||||
|
} MenuItem;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int cursor;
|
||||||
|
int scrolly;
|
||||||
|
int numberOfItems;
|
||||||
|
MenuItem items[NUM_OF_ITEMS];
|
||||||
|
} Menu;
|
||||||
|
|
||||||
|
void clearMenu(Menu* m);
|
||||||
|
void printMenu(Menu* m);
|
||||||
|
|
||||||
|
int getMenuCursor(Menu* m);
|
||||||
|
int getNumberOfMenuItems(Menu* m);
|
||||||
|
int moveCursor(Menu* m);
|
||||||
|
|
||||||
|
void addMenuItem(Menu* m, char* label);
|
||||||
|
|
||||||
|
|
||||||
|
#define YES 1
|
||||||
|
#define NO 0
|
||||||
|
|
||||||
|
void keyWait(u32 key);
|
||||||
|
int choiceBox(char* message);
|
||||||
|
void messageBox(char* message);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -25,21 +25,26 @@ void printBytes(int bytes)
|
|||||||
|
|
||||||
void printFileInfo(const char* path)
|
void printFileInfo(const char* path)
|
||||||
{
|
{
|
||||||
tDSiHeader header;
|
if (path == NULL) return;
|
||||||
tNDSBanner banner;
|
|
||||||
|
consoleSelect(&topScreen);
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
|
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
||||||
|
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
FILE* f = fopen(path, "rb");
|
FILE* f = fopen(path, "rb");
|
||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
if (fread(&header, sizeof(tDSiHeader), 1, f) != 1)
|
if (fread(header, sizeof(tDSiHeader), 1, f) != 1)
|
||||||
iprintf("Could not read dsi header.\n");
|
iprintf("Could not read dsi header.\n");
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fseek(f, header.ndshdr.bannerOffset, SEEK_SET);
|
fseek(f, header->ndshdr.bannerOffset, SEEK_SET);
|
||||||
|
|
||||||
if (fread(&banner, sizeof(tNDSBanner), 1, f) != 1)
|
if (fread(banner, sizeof(tNDSBanner), 1, f) != 1)
|
||||||
iprintf("Could not read banner.\n");
|
iprintf("Could not read banner.\n");
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -51,7 +56,7 @@ void printFileInfo(const char* path)
|
|||||||
|
|
||||||
//Convert 2 byte characters to 1 byte
|
//Convert 2 byte characters to 1 byte
|
||||||
for (int i = 0; i < 128; i++)
|
for (int i = 0; i < 128; i++)
|
||||||
gameTitle[i] = (char)banner.titles[1][i];
|
gameTitle[i] = (char)banner->titles[1][i];
|
||||||
|
|
||||||
iprintf("%s\n\n", gameTitle);
|
iprintf("%s\n\n", gameTitle);
|
||||||
}
|
}
|
||||||
@ -63,14 +68,14 @@ void printFileInfo(const char* path)
|
|||||||
iprintf("\n");
|
iprintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("Label: %.12s\n", header.ndshdr.gameTitle);
|
iprintf("Label: %.12s\n", header->ndshdr.gameTitle);
|
||||||
iprintf("Game Code: %.4s\n", header.ndshdr.gameCode);
|
iprintf("Game Code: %.4s\n", header->ndshdr.gameCode);
|
||||||
|
|
||||||
//System type
|
//System type
|
||||||
{
|
{
|
||||||
iprintf("Unit Code: ");
|
iprintf("Unit Code: ");
|
||||||
|
|
||||||
switch (header.ndshdr.unitCode)
|
switch (header->ndshdr.unitCode)
|
||||||
{
|
{
|
||||||
case 0: iprintf("NDS"); break;
|
case 0: iprintf("NDS"); break;
|
||||||
case 2: iprintf("NDS+DSi"); break;
|
case 2: iprintf("NDS+DSi"); break;
|
||||||
@ -85,19 +90,27 @@ void printFileInfo(const char* path)
|
|||||||
{
|
{
|
||||||
iprintf("Program Type: ");
|
iprintf("Program Type: ");
|
||||||
|
|
||||||
switch (header.ndshdr.reserved1[7])
|
switch (header->ndshdr.reserved1[7])
|
||||||
{
|
{
|
||||||
case 0x3: iprintf("Normal"); break;
|
case 0x3: iprintf("Normal"); break;
|
||||||
case 0xB: iprintf("Sys"); break;
|
case 0xB: iprintf("Sys"); break;
|
||||||
case 0xF: iprintf("Debug/Sys"); break;
|
case 0xF: iprintf("Debug/Sys"); break;
|
||||||
default: iprintf("unknown");
|
default: iprintf("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("\n");
|
iprintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
iprintf("Title ID: %08x %08x\n", (unsigned int)header.tid_high,
|
//DSi data
|
||||||
(unsigned int)header.tid_low);
|
if (header->tid_high == 0x00030004 ||
|
||||||
|
header->tid_high == 0x00030005 ||
|
||||||
|
header->tid_high == 0x00030015 ||
|
||||||
|
header->tid_high == 0x00030017 ||
|
||||||
|
header->tid_high == 0x00030000)
|
||||||
|
{
|
||||||
|
iprintf("Title ID: %08x %08x\n", (unsigned int)header->tid_high,
|
||||||
|
(unsigned int)header->tid_low);
|
||||||
|
}
|
||||||
|
|
||||||
//Print full file path
|
//Print full file path
|
||||||
iprintf("\n%s\n", path);
|
iprintf("\n%s\n", path);
|
||||||
@ -106,6 +119,9 @@ void printFileInfo(const char* path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
free(banner);
|
||||||
|
free(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Progress bar
|
//Progress bar
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "menus.h"
|
#include "main.h"
|
||||||
|
#include "menu.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
void testMenu()
|
void testMenu()
|
||||||
|
|||||||
695
src/titlemenu.c
695
src/titlemenu.c
@ -1,43 +1,43 @@
|
|||||||
#include "menus.h"
|
#include "menu.h"
|
||||||
|
#include "main.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#define NUM_OF_DIRECTORIES 3
|
static void generateList(Menu* m);
|
||||||
static const char* directories[] = {
|
static void printItem(Menu* m);
|
||||||
"00030004",
|
|
||||||
"00030005",
|
static int subMenu();
|
||||||
"00030015"
|
static void dump(Menu* m);
|
||||||
|
static void delete(Menu* m);
|
||||||
|
//static void backupData(Menu* m);
|
||||||
|
//static void restoreData(Menu* m);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
// TITLE_MENU_BACKUP,
|
||||||
|
TITLE_MENU_DUMP,
|
||||||
|
// TITLE_MENU_BACKUP_DATA,
|
||||||
|
// TITLE_MENU_RESTORE_DATA,
|
||||||
|
TITLE_MENU_DELETE,
|
||||||
|
TITLE_MENU_BACK
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cursor = 0;
|
|
||||||
static int scrolly = 0;
|
|
||||||
static int numberOfTitles = 0;
|
|
||||||
|
|
||||||
static void moveCursor(int dir);
|
|
||||||
|
|
||||||
static void printList();
|
|
||||||
static void printTitleInfo(int num);
|
|
||||||
|
|
||||||
static int getNumberOfTitles();
|
|
||||||
static int getTitle(int num, char* title, char* path);
|
|
||||||
|
|
||||||
static void subMenu();
|
|
||||||
|
|
||||||
void titleMenu()
|
void titleMenu()
|
||||||
{
|
{
|
||||||
cursor = 0;
|
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||||
scrolly = 0;
|
|
||||||
numberOfTitles = getNumberOfTitles();
|
|
||||||
|
|
||||||
consoleSelect(&topScreen);
|
consoleSelect(&topScreen);
|
||||||
consoleClear();
|
consoleClear();
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
consoleSelect(&bottomScreen);
|
||||||
consoleClear();
|
consoleClear();
|
||||||
|
|
||||||
|
generateList(m);
|
||||||
|
|
||||||
//No titles error
|
//No titles error
|
||||||
if (numberOfTitles <= 0)
|
if (getNumberOfMenuItems(m) <= 0)
|
||||||
{
|
{
|
||||||
|
consoleClear();
|
||||||
|
|
||||||
iprintf("No titles found.\n");
|
iprintf("No titles found.\n");
|
||||||
iprintf("Back - B\n");
|
iprintf("Back - B\n");
|
||||||
|
|
||||||
@ -46,188 +46,70 @@ void titleMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Print data
|
//Print data
|
||||||
consoleSelect(&topScreen);
|
printItem(m);
|
||||||
printTitleInfo(cursor);
|
printMenu(m);
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
printList();
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
scanKeys();
|
scanKeys();
|
||||||
|
|
||||||
int thisScrolly = scrolly;
|
if (moveCursor(m))
|
||||||
int thisCursor = cursor;
|
|
||||||
|
|
||||||
//Clear cursor
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
iprintf("\x1b[%d;0H ", cursor - scrolly);
|
|
||||||
|
|
||||||
//Move cursor
|
|
||||||
if (keysDown() & KEY_DOWN)
|
|
||||||
moveCursor(1);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_UP)
|
|
||||||
moveCursor(-1);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_RIGHT)
|
|
||||||
{
|
{
|
||||||
repeat (10)
|
printItem(m);
|
||||||
moveCursor(1);
|
printMenu(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keysDown() & KEY_LEFT)
|
|
||||||
{
|
|
||||||
repeat (10)
|
|
||||||
moveCursor(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Re-print list
|
|
||||||
if (thisCursor != cursor)
|
|
||||||
{
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
printTitleInfo(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thisScrolly != scrolly)
|
|
||||||
{
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
printList();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print cursor
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
iprintf("\x1b[%d;0H>", cursor - scrolly);
|
|
||||||
|
|
||||||
//
|
|
||||||
if (keysDown() & KEY_B)
|
if (keysDown() & KEY_B)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
else if (keysDown() & KEY_A)
|
else if (keysDown() & KEY_A)
|
||||||
{
|
{
|
||||||
subMenu();
|
switch (subMenu())
|
||||||
|
|
||||||
consoleSelect(&topScreen);
|
|
||||||
printTitleInfo(cursor);
|
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
|
||||||
printList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveCursor(int dir)
|
|
||||||
{
|
|
||||||
cursor += sign(dir);
|
|
||||||
|
|
||||||
if (cursor < 0)
|
|
||||||
cursor = 0;
|
|
||||||
|
|
||||||
if (cursor >= numberOfTitles - 1)
|
|
||||||
cursor = numberOfTitles - 1;
|
|
||||||
|
|
||||||
if (cursor - scrolly >= 23)
|
|
||||||
scrolly += 1;
|
|
||||||
|
|
||||||
if (cursor - scrolly < 0)
|
|
||||||
scrolly -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printList()
|
|
||||||
{
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
for (int i = scrolly; i < scrolly + 23; i++)
|
|
||||||
{
|
|
||||||
char title[256];
|
|
||||||
if (getTitle(i, title, NULL) == 1)
|
|
||||||
iprintf(" %.30s\n", title);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Scroll arrows
|
|
||||||
if (scrolly > 0)
|
|
||||||
iprintf("\x1b[0;31H^");
|
|
||||||
|
|
||||||
if (scrolly < numberOfTitles - 23)
|
|
||||||
iprintf("\x1b[22;31Hv");
|
|
||||||
}
|
|
||||||
|
|
||||||
void printTitleInfo(int num)
|
|
||||||
{
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
char path[256];
|
|
||||||
if (getTitle(num, NULL, path) == 1)
|
|
||||||
printFileInfo(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getNumberOfTitles()
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
//Scan choice title directories
|
|
||||||
for (int i = 0; i < NUM_OF_DIRECTORIES; i++)
|
|
||||||
{
|
|
||||||
DIR* dir;
|
|
||||||
struct dirent* ent;
|
|
||||||
|
|
||||||
char dirPath[256];
|
|
||||||
sprintf(dirPath, "/title/%s", directories[i]);
|
|
||||||
|
|
||||||
dir = opendir(dirPath);
|
|
||||||
|
|
||||||
if (dir)
|
|
||||||
{
|
|
||||||
while ( (ent = readdir(dir)) != NULL )
|
|
||||||
{
|
{
|
||||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
case TITLE_MENU_DUMP:
|
||||||
continue;
|
dump(m);
|
||||||
|
break;
|
||||||
|
|
||||||
if (ent->d_type == DT_DIR)
|
case TITLE_MENU_DELETE:
|
||||||
{
|
delete(m);
|
||||||
//Search for an .app file
|
break;
|
||||||
char contentPath[384];
|
|
||||||
sprintf(contentPath, "%s/%s/content", dirPath, ent->d_name);
|
|
||||||
|
|
||||||
DIR* subdir;
|
|
||||||
struct dirent* subent;
|
|
||||||
|
|
||||||
subdir = opendir(contentPath);
|
|
||||||
|
|
||||||
if (subdir)
|
|
||||||
{
|
|
||||||
while ( (subent = readdir(subdir)) != NULL )
|
|
||||||
{
|
|
||||||
if (strcmp(".", subent->d_name) == 0 || strcmp("..", subent->d_name) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//Found a title
|
|
||||||
if (strstr(subent->d_name, ".app") != NULL)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(subdir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
free(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTitle(int num, char* title, char* path)
|
#define NUM_OF_DIRECTORIES 3
|
||||||
|
static const char* directories[] = {
|
||||||
|
"00030004",
|
||||||
|
"00030005",
|
||||||
|
"00030015"
|
||||||
|
};
|
||||||
|
|
||||||
|
//mode = 0: add items to menu
|
||||||
|
//mode = 1: return full path of menu item
|
||||||
|
static bool _walkList(Menu* m, int mode, char* out)
|
||||||
{
|
{
|
||||||
int result = 0;
|
//Skip if no menu
|
||||||
|
if (m == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//Reset menu
|
||||||
|
if (mode == 0)
|
||||||
|
clearMenu(m);
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
//Scan choice title directories
|
//Scan choice title directories
|
||||||
for (int i = 0; i < NUM_OF_DIRECTORIES && result == 0; i++)
|
for (int i = 0; i < NUM_OF_DIRECTORIES && result == false; i++)
|
||||||
{
|
{
|
||||||
DIR* dir;
|
DIR* dir;
|
||||||
struct dirent* ent;
|
struct dirent* ent;
|
||||||
|
|
||||||
char dirPath[256];
|
char dirPath[256];
|
||||||
sprintf(dirPath, "/title/%s", directories[i]);
|
sprintf(dirPath, "/title/%s", directories[i]);
|
||||||
@ -236,7 +118,7 @@ int getTitle(int num, char* title, char* path)
|
|||||||
|
|
||||||
if (dir)
|
if (dir)
|
||||||
{
|
{
|
||||||
while ( (ent = readdir(dir)) != NULL && result == 0)
|
while ( (ent = readdir(dir)) != NULL && result == false)
|
||||||
{
|
{
|
||||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -254,7 +136,7 @@ int getTitle(int num, char* title, char* path)
|
|||||||
|
|
||||||
if (subdir)
|
if (subdir)
|
||||||
{
|
{
|
||||||
while ( (subent = readdir(subdir)) != NULL && result == 0)
|
while ( (subent = readdir(subdir)) != NULL && result == false)
|
||||||
{
|
{
|
||||||
if (strcmp(".", subent->d_name) == 0 || strcmp("..", subent->d_name) == 0)
|
if (strcmp(".", subent->d_name) == 0 || strcmp("..", subent->d_name) == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -263,61 +145,57 @@ int getTitle(int num, char* title, char* path)
|
|||||||
{
|
{
|
||||||
if (strstr(subent->d_name, ".app") != NULL)
|
if (strstr(subent->d_name, ".app") != NULL)
|
||||||
{
|
{
|
||||||
if (count < num)
|
//Found requested title
|
||||||
count++;
|
char path[384];
|
||||||
|
sprintf(path, "%s/%s", contentPath, subent->d_name);
|
||||||
|
|
||||||
else
|
//Generate list
|
||||||
|
if (mode == 0)
|
||||||
{
|
{
|
||||||
//Found requested title
|
FILE* f = fopen(path, "rb");
|
||||||
char filepath[384];
|
|
||||||
sprintf(filepath, "%s/%s", contentPath, subent->d_name);
|
|
||||||
|
|
||||||
//Output title
|
if (f)
|
||||||
if (title != NULL)
|
|
||||||
{
|
{
|
||||||
FILE* f = fopen(filepath, "rb");
|
tNDSHeader* header = (tNDSHeader*)malloc(sizeof(tNDSHeader));
|
||||||
|
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
if (!f)
|
fread(header, sizeof(tNDSHeader), 1, f);
|
||||||
|
fseek(f, header->bannerOffset, SEEK_SET);
|
||||||
|
fread(banner, sizeof(tNDSBanner), 1, f);
|
||||||
|
|
||||||
|
char tstr[128+1];
|
||||||
|
tstr[128] = '\0';
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
{
|
{
|
||||||
sprintf(title, " ");
|
char c = banner->titles[1][i];
|
||||||
}
|
|
||||||
else
|
//Replace new line with space
|
||||||
{
|
if (c == '\n')
|
||||||
tNDSHeader header;
|
c = ' ';
|
||||||
tNDSBanner banner;
|
|
||||||
|
|
||||||
fread(&header, sizeof(tNDSHeader), 1, f);
|
tstr[i] = c;
|
||||||
fseek(f, header.bannerOffset, SEEK_SET);
|
|
||||||
fread(&banner, sizeof(tNDSBanner), 1, f);
|
|
||||||
|
|
||||||
char tstr[128+1];
|
|
||||||
tstr[128] = '\0';
|
|
||||||
|
|
||||||
for (int i = 0; i < 128; i++)
|
|
||||||
{
|
|
||||||
char c = banner.titles[1][i];
|
|
||||||
|
|
||||||
if (c == '\n')
|
|
||||||
c = ' ';
|
|
||||||
|
|
||||||
tstr[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(title, "%s", tstr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
free(banner);
|
||||||
|
free(header);
|
||||||
|
|
||||||
|
addMenuItem(m, tstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Output path
|
fclose(f);
|
||||||
if (path != NULL)
|
}
|
||||||
|
|
||||||
|
//Get item file name
|
||||||
|
else if (mode == 1)
|
||||||
|
{
|
||||||
|
if (count < m->cursor)
|
||||||
|
count++;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
sprintf(path, "%s", filepath);
|
sprintf(out, "%s", path);
|
||||||
}
|
result = true;
|
||||||
|
}
|
||||||
//Exit this mess
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,173 +213,228 @@ int getTitle(int num, char* title, char* path)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
void generateList(Menu* m)
|
||||||
static int subCursor = 0;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
// TITLE_MENU_BACKUP,
|
|
||||||
TITLE_MENU_DUMP,
|
|
||||||
TITLE_MENU_DELETE,
|
|
||||||
TITLE_MENU_BACK
|
|
||||||
};
|
|
||||||
|
|
||||||
void subMenu()
|
|
||||||
{
|
{
|
||||||
subCursor = 0;
|
if (m == NULL) return;
|
||||||
|
|
||||||
consoleSelect(&bottomScreen);
|
consoleSelect(&bottomScreen);
|
||||||
consoleClear();
|
consoleClear();
|
||||||
|
|
||||||
|
iprintf("Gathering files...\n"); swiWaitForVBlank();
|
||||||
|
|
||||||
|
clearMenu(m);
|
||||||
|
_walkList(m, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printItem(Menu* m)
|
||||||
|
{
|
||||||
|
if (m == NULL) return;
|
||||||
|
|
||||||
|
char path[256];
|
||||||
|
if (_walkList(m, 1, path) == true)
|
||||||
|
printFileInfo(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
int subMenu()
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||||
|
clearMenu(m);
|
||||||
|
|
||||||
// iprintf("\tBackup\n");
|
// iprintf("\tBackup\n");
|
||||||
iprintf("\tDump\n");
|
addMenuItem(m, "Dump");
|
||||||
iprintf("\tDelete\n");
|
// addMenuItem(m, "Backup Saved Data");
|
||||||
iprintf("\tBack\n");
|
// addMenuItem(m, "Restore Saved Data");
|
||||||
|
addMenuItem(m, "Delete");
|
||||||
|
addMenuItem(m, "Back");
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
scanKeys();
|
scanKeys();
|
||||||
|
|
||||||
//Clear cursor
|
if (moveCursor(m))
|
||||||
iprintf("\x1b[%d;0H ", subCursor);
|
printMenu(m);
|
||||||
|
|
||||||
//Move cursor
|
if (keysDown() & KEY_B)
|
||||||
if (keysDown() & KEY_DOWN)
|
|
||||||
{
|
|
||||||
if (subCursor < TITLE_MENU_BACK)
|
|
||||||
subCursor += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keysDown() & KEY_UP)
|
|
||||||
{
|
|
||||||
if (subCursor > 0)
|
|
||||||
subCursor -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Print cursor
|
|
||||||
iprintf("\x1b[%d;0H>", subCursor);
|
|
||||||
|
|
||||||
if (keysDown() & KEY_A)
|
|
||||||
{
|
|
||||||
char title[256];
|
|
||||||
char path[256];
|
|
||||||
getTitle(cursor, title, path);
|
|
||||||
|
|
||||||
//Only get first line of title
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
if (title[i] == '\n')
|
|
||||||
{
|
|
||||||
title[i] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* //
|
|
||||||
if (subCursor == TITLE_MENU_BACKUP)
|
|
||||||
{
|
|
||||||
char dir[256];
|
|
||||||
sprintf(dir, "%.24s", path);
|
|
||||||
|
|
||||||
char msg[512];
|
|
||||||
sprintf(msg, "Are you sure you want to backup\n%s", dir);
|
|
||||||
|
|
||||||
if (choiceBox(msg) == YES)
|
|
||||||
{
|
|
||||||
if (getDirSize(dir) > getSDCardFree())
|
|
||||||
messageBox("Error, not enough space on SD card.\nTitle backup failed.");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (copyDir(dir, BACKUP_PATH) == 1)
|
|
||||||
messageBox("Title was backed up.");
|
|
||||||
else
|
|
||||||
messageBox("Title backup failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (subCursor == TITLE_MENU_DUMP)
|
|
||||||
{
|
|
||||||
char fpath[256];
|
|
||||||
if (getTitle(cursor, NULL, fpath) == 1)
|
|
||||||
{
|
|
||||||
FILE* f = fopen(fpath, "rb");
|
|
||||||
|
|
||||||
if (!f)
|
|
||||||
messageBox("Can not dump title.\n");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int fsize = getFileSize(f);
|
|
||||||
|
|
||||||
if (fsize > getSDCardFree())
|
|
||||||
messageBox("Not enough free space on SD card.\n");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tNDSHeader header;
|
|
||||||
tNDSBanner banner;
|
|
||||||
|
|
||||||
fread(&header, sizeof(tNDSHeader), 1, f);
|
|
||||||
fseek(f, header.bannerOffset, SEEK_SET);
|
|
||||||
fread(&banner, sizeof(tNDSBanner), 1, f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
char outpath[256];
|
|
||||||
sprintf(outpath, "%s%.12s - %.4s.nds", ROM_PATH, header.gameTitle, header.gameCode);
|
|
||||||
|
|
||||||
char msg[512];
|
|
||||||
sprintf(msg, "Dump title to\n%s\n", outpath);
|
|
||||||
|
|
||||||
if (choiceBox(msg) == YES)
|
|
||||||
{
|
|
||||||
if (copyFile(fpath, outpath) == 1)
|
|
||||||
messageBox("Title saved.\n");
|
|
||||||
else
|
|
||||||
messageBox("Title dump failed.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (subCursor == TITLE_MENU_DELETE)
|
|
||||||
{
|
|
||||||
char msg[512];
|
|
||||||
sprintf(msg, "Are you sure you want to delete\n%s", title);
|
|
||||||
|
|
||||||
if (choiceBox(msg) == YES)
|
|
||||||
{
|
|
||||||
char dirPath[256];
|
|
||||||
sprintf(dirPath, "%.25s", path);
|
|
||||||
|
|
||||||
if (deleteDir(dirPath) == 1)
|
|
||||||
messageBox("Title deleted.\n");
|
|
||||||
else
|
|
||||||
messageBox("Title could not be deleted.\n");
|
|
||||||
|
|
||||||
//Reset main menu
|
|
||||||
cursor = 0;
|
|
||||||
scrolly = 0;
|
|
||||||
numberOfTitles = getNumberOfTitles();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (subCursor == TITLE_MENU_BACK)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (keysDown() & KEY_B)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
else if (keysDown() & KEY_A)
|
||||||
|
{
|
||||||
|
result = m->cursor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
free(m);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dump(Menu* m)
|
||||||
|
{
|
||||||
|
char fpath[256];
|
||||||
|
|
||||||
|
if (_walkList(m, 1, fpath) == false)
|
||||||
|
{
|
||||||
|
messageBox("Failed to dump title.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
messageBox("Can not dump title.\n");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int fsize = getFileSize(f);
|
||||||
|
|
||||||
|
if (fsize > getSDCardFree())
|
||||||
|
{
|
||||||
|
messageBox("Not enough free space on SD card.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tNDSHeader* header = (tNDSHeader*)malloc(sizeof(tNDSHeader));
|
||||||
|
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
|
fread(header, sizeof(tNDSHeader), 1, f);
|
||||||
|
fseek(f, header->bannerOffset, SEEK_SET);
|
||||||
|
fread(banner, sizeof(tNDSBanner), 1, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
char outpath[256];
|
||||||
|
sprintf(outpath, "%s%.12s - %.4s.nds", ROM_PATH, header->gameTitle, header->gameCode);
|
||||||
|
|
||||||
|
int choice = NO;
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
sprintf(msg, "Dump title to\n%s\n", outpath);
|
||||||
|
choice = choiceBox(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice == YES)
|
||||||
|
{
|
||||||
|
if (copyFile(fpath, outpath) == 1)
|
||||||
|
messageBox("Title saved.\n");
|
||||||
|
else
|
||||||
|
messageBox("Title dump failed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(banner);
|
||||||
|
free(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete(Menu* m)
|
||||||
|
{
|
||||||
|
char fpath[256];
|
||||||
|
|
||||||
|
if (_walkList(m, 1, fpath) == false)
|
||||||
|
{
|
||||||
|
messageBox("Failed to delete title.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int choice = NO;
|
||||||
|
|
||||||
|
{
|
||||||
|
//Get title name
|
||||||
|
char title[128+1];
|
||||||
|
title[128] = '\0';
|
||||||
|
|
||||||
|
FILE* f = fopen(fpath, "rb");
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
{
|
||||||
|
messageBox("Failed to delete title.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tNDSHeader* header = (tNDSHeader*)malloc(sizeof(tNDSHeader));
|
||||||
|
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fread(header, sizeof(tNDSHeader), 1, f);
|
||||||
|
fseek(f, header->bannerOffset, SEEK_SET);
|
||||||
|
fread(banner, sizeof(tNDSBanner), 1, f);
|
||||||
|
|
||||||
|
for (int i = 0; i < 128; i++)
|
||||||
|
title[i] = (char)banner->titles[1][i];
|
||||||
|
|
||||||
|
free(banner);
|
||||||
|
free(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
char msg[512];
|
||||||
|
sprintf(msg, "Are you sure you want to delete\n%s", title);
|
||||||
|
choice = choiceBox(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choice == YES)
|
||||||
|
{
|
||||||
|
char dirpath[256];
|
||||||
|
sprintf(dirpath, "%.25s", fpath);
|
||||||
|
|
||||||
|
if (deleteDir(dirpath) == 1)
|
||||||
|
messageBox("Title deleted.\n");
|
||||||
|
else
|
||||||
|
messageBox("Title could not be deleted.\n");
|
||||||
|
|
||||||
|
generateList(m);
|
||||||
|
printItem(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printMenu(m);
|
||||||
|
}
|
||||||
|
/* Incomplete
|
||||||
|
static void backupData(Menu* m)
|
||||||
|
{
|
||||||
|
char msg[512];
|
||||||
|
char dirPath[256];
|
||||||
|
sprintf(dirPath, "/dsisave/%s", title);
|
||||||
|
sprintf(msg, "Backup data to\n%s", dirPath);
|
||||||
|
|
||||||
|
if (choiceBox(msg) == YES)
|
||||||
|
{
|
||||||
|
mkdir(dirPath, 0777);
|
||||||
|
|
||||||
|
FILE* f = fopen(path, "rb");
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
tDSiHeader header;
|
||||||
|
fread(&header, sizeof(tDSiHeader), 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
char titleID[8+1];
|
||||||
|
sprintf(titleID, "%08x", (unsigned int)header.tid_low);
|
||||||
|
|
||||||
|
DIR* dir;
|
||||||
|
struct dirent* ent;
|
||||||
|
|
||||||
|
dir = opendir(ROM_PATH);
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restoreData(Menu* m)
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
37
src/titles.c
Normal file
37
src/titles.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "titles.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
bool titleIsUsed(u32 tidlow, u32 tidhigh)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
char path[256];
|
||||||
|
sprintf(path, "/title/%08x/%08x/", (unsigned int)tidhigh, (unsigned int)tidlow);
|
||||||
|
|
||||||
|
DIR* dir = opendir(path);
|
||||||
|
struct dirent* ent;
|
||||||
|
|
||||||
|
if (dir)
|
||||||
|
{
|
||||||
|
while ( (ent = readdir(dir)) != NULL )
|
||||||
|
{
|
||||||
|
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ent->d_type != DT_DIR)
|
||||||
|
{
|
||||||
|
if (strstr(ent->d_name, ".app") != NULL)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
10
src/titles.h
Normal file
10
src/titles.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef TITLES_H
|
||||||
|
#define TITLES_H
|
||||||
|
|
||||||
|
#include <nds/ndstypes.h>
|
||||||
|
|
||||||
|
#define gameCodeToTitleID(X) ( (X[0] << 24) | (X[1] << 16) | (X[2] << 8) | X[3] )
|
||||||
|
|
||||||
|
bool titleIsUsed(u32 tidlow, u32 tidhigh);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user