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 "titles.h"
|
||||
#include "maketmd.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 {
|
||||
INSTALL_MENU_INSTALL,
|
||||
@ -282,154 +12,305 @@ enum {
|
||||
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;
|
||||
subCursor = 0;
|
||||
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||
|
||||
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)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
if (printMenu == true)
|
||||
if (moveCursor(m))
|
||||
{
|
||||
printMenu = false;
|
||||
printItem(m);
|
||||
printMenu(m);
|
||||
}
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
if (keysDown() & KEY_B)
|
||||
break;
|
||||
|
||||
iprintf("\tInstall\n");
|
||||
iprintf("\tDelete\n");
|
||||
iprintf("\tBack - B\n");
|
||||
//Selection
|
||||
else if (keysDown() & KEY_A)
|
||||
{
|
||||
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
|
||||
iprintf("\x1b[%d;0H ", subCursor);
|
||||
free(m);
|
||||
}
|
||||
|
||||
//Move cursor
|
||||
if (keysDown() & KEY_DOWN)
|
||||
//mode = 0: add items to menu
|
||||
//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)
|
||||
subCursor++;
|
||||
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 || 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)
|
||||
{
|
||||
if (subCursor > 0)
|
||||
subCursor--;
|
||||
}
|
||||
endloop:
|
||||
closedir(dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Reprint cursor
|
||||
iprintf("\x1b[%d;0H>", subCursor);
|
||||
void generateList(Menu* m)
|
||||
{
|
||||
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)
|
||||
break;
|
||||
|
||||
else if (keysDown() & KEY_A)
|
||||
{
|
||||
if (subCursor == INSTALL_MENU_INSTALL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
result = m->cursor;
|
||||
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);
|
||||
consoleClear();
|
||||
|
||||
iprintf("Installing %s\n", fpath); swiWaitForVBlank();
|
||||
|
||||
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
||||
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||
|
||||
FILE* f = fopen(fpath, "rb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
iprintf("Error: could not open file.\n\nPress B to exit.\n");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
iprintf("Error: could not open file.\n");
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Load header
|
||||
tDSiHeader header;
|
||||
tNDSBanner banner;
|
||||
bool patchHeader = false;
|
||||
|
||||
//Read header and 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);
|
||||
fread(header, sizeof(tDSiHeader), 1, f);
|
||||
|
||||
fseek(f, header->ndshdr.bannerOffset, SEEK_SET);
|
||||
fread(banner, sizeof(tNDSBanner), 1, f);
|
||||
}
|
||||
/*
|
||||
//Check header size
|
||||
if (header.ndshdr.headerSize != 0x4000)
|
||||
|
||||
//Patch homebrew roms if gameCode is #### or null
|
||||
if ((strcmp(header->ndshdr.gameCode, "####") == 0 && header->tid_low == 0x23232323) ||
|
||||
(!*header->ndshdr.gameCode && header->tid_low == 0))
|
||||
{
|
||||
iprintf("Error: no DSi header.");
|
||||
goto error;
|
||||
iprintf("Patching header...");
|
||||
|
||||
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
|
||||
if (header.tid_high != 0x00030004 &&
|
||||
header.tid_high != 0x00030005 &&
|
||||
header.tid_high != 0x00030015)
|
||||
|
||||
//Must be DSi rom
|
||||
//High title id must be one of three
|
||||
{
|
||||
iprintf("This file cannot be installed.\nInvalid title ID.");
|
||||
goto error;
|
||||
if (header->tid_high != 0x00030004 &&
|
||||
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
|
||||
int fileSize = -1;
|
||||
int fileSize = -1;
|
||||
|
||||
{
|
||||
iprintf("File Size: "); swiWaitForVBlank();
|
||||
iprintf("File Size: ");
|
||||
|
||||
fileSize = getFileSize(f);
|
||||
|
||||
@ -437,12 +318,12 @@ void install(char* fpath)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//Do not want file opened anymore
|
||||
//Do not need file opened anymore
|
||||
fclose(f);
|
||||
|
||||
//SD card check
|
||||
{
|
||||
iprintf("Enough room on SD card?..."); swiWaitForVBlank();
|
||||
iprintf("Enough room on SD card?...");
|
||||
|
||||
if (getSDCardFree() < fileSize)
|
||||
{
|
||||
@ -455,28 +336,28 @@ void install(char* fpath)
|
||||
|
||||
//DSi storage check
|
||||
{
|
||||
iprintf("Enough room on DSi?..."); swiWaitForVBlank();
|
||||
iprintf("Enough room on DSi?...");
|
||||
|
||||
if (getDsiFree() < fileSize)
|
||||
{
|
||||
iprintf("No\n"); swiWaitForVBlank();
|
||||
iprintf("No\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Yes\n"); swiWaitForVBlank();
|
||||
iprintf("Yes\n");
|
||||
}
|
||||
|
||||
//Menu slot check
|
||||
{
|
||||
iprintf("Open DSi menu slot?..."); swiWaitForVBlank();
|
||||
iprintf("Open DSi menu slot?...");
|
||||
|
||||
if (getMenuSlotsFree() <= 0)
|
||||
{
|
||||
iprintf("No\n"); swiWaitForVBlank();
|
||||
iprintf("No\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Yes\n"); swiWaitForVBlank();
|
||||
iprintf("Yes\n");
|
||||
}
|
||||
|
||||
//Create title directory
|
||||
@ -484,10 +365,8 @@ void install(char* fpath)
|
||||
char dirPath[256];
|
||||
|
||||
{
|
||||
sprintf(titleID, "%08x", (unsigned int)header.tid_low);
|
||||
sprintf(dirPath, "/title/%08x/%s", (unsigned int)header.tid_high, titleID);
|
||||
|
||||
//iprintf("Creating dir\n%s\n", dirPath); swiWaitForVBlank();
|
||||
sprintf(titleID, "%08x", (unsigned int)header->tid_low);
|
||||
sprintf(dirPath, "/title/%08x/%s", (unsigned int)header->tid_high, titleID);
|
||||
}
|
||||
|
||||
//Check if title is already installed
|
||||
@ -523,24 +402,46 @@ void install(char* fpath)
|
||||
char contentPath[256];
|
||||
sprintf(contentPath, "%s/content", dirPath);
|
||||
|
||||
//iprintf("Creating dir\n%s\n", contentPath); swiWaitForVBlank();
|
||||
mkdir(contentPath, 0777);
|
||||
|
||||
//Create 0000000.app
|
||||
//Does 00000000 always work?
|
||||
{
|
||||
char appPath[256];
|
||||
sprintf(appPath, "%s/00000000.app", contentPath);
|
||||
|
||||
iprintf("Creating 00000000.app..."); swiWaitForVBlank();
|
||||
|
||||
if (copyFile(fpath, appPath) == 0)
|
||||
//Copy nds file to app
|
||||
{
|
||||
iprintf("Failed\n");
|
||||
goto error;
|
||||
iprintf("Creating 00000000.app...");
|
||||
|
||||
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
|
||||
{
|
||||
@ -558,101 +459,140 @@ void install(char* fpath)
|
||||
char dataPath[256];
|
||||
sprintf(dataPath, "%s/data", dirPath);
|
||||
|
||||
//iprintf("Creating dir\n%s\n", dataPath); swiWaitForVBlank();
|
||||
mkdir(dataPath, 0777);
|
||||
|
||||
//If needed, create public.sav
|
||||
if (header.public_sav_size > 0)
|
||||
if (header->public_sav_size > 0)
|
||||
{
|
||||
char publicPath[512];
|
||||
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)
|
||||
fwrite(&num, 1, 1, f);
|
||||
FILE* file = fopen(publicPath, "wb");
|
||||
|
||||
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 (header.private_sav_size > 0)
|
||||
if (header->private_sav_size > 0)
|
||||
{
|
||||
char privatePath[512];
|
||||
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)
|
||||
fwrite(&num, 1, 1, f);
|
||||
FILE* file = fopen(privatePath, "wb");
|
||||
|
||||
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 (header.appflags & 0x4)
|
||||
if (header->appflags & 0x4)
|
||||
{
|
||||
char bannerPath[512];
|
||||
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?
|
||||
fwrite(&num, 1, 1, f);
|
||||
FILE* file = fopen(bannerPath, "wb");
|
||||
|
||||
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");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
keyWait(KEY_A | KEY_B);
|
||||
}
|
||||
|
||||
complete:
|
||||
fclose(f);
|
||||
return;
|
||||
goto complete;
|
||||
|
||||
error:
|
||||
fclose(f);
|
||||
|
||||
iprintf("\nInstallation failed.\n\nPress B to exit.\n");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
|
||||
complete:
|
||||
free(banner);
|
||||
free(header);
|
||||
|
||||
fclose(f);
|
||||
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 "menus.h"
|
||||
#include "menu.h"
|
||||
#include <time.h>
|
||||
|
||||
#define VERSION "0.4"
|
||||
#define VERSION "0.5"
|
||||
|
||||
enum {
|
||||
MAIN_MENU_INSTALL,
|
||||
@ -15,6 +16,8 @@ static int mainMenu();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
srand(time(0));
|
||||
|
||||
videoSetMode(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(&bottomScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true);
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
if (!fatInitDefault())
|
||||
{
|
||||
consoleSelect(&bottomScreen);
|
||||
@ -64,9 +70,7 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cursor = 0;
|
||||
|
||||
int mainMenu()
|
||||
static int mainMenu()
|
||||
{
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
@ -75,59 +79,30 @@ int mainMenu()
|
||||
iprintf("\nversion %s\n", VERSION);
|
||||
iprintf("\x1b[23;0HJeff - 2018");
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||
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)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
//Clear cursor
|
||||
iprintf("\x1b[%d;0H ", cursor);
|
||||
|
||||
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 (moveCursor(m) == 1)
|
||||
printMenu(m);
|
||||
|
||||
if (keysDown() & KEY_A)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int cursor = m->cursor;
|
||||
free(m);
|
||||
|
||||
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)
|
||||
{
|
||||
tDSiHeader header;
|
||||
tNDSBanner banner;
|
||||
if (path == NULL) return;
|
||||
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
|
||||
tDSiHeader* header = (tDSiHeader*)malloc(sizeof(tDSiHeader));
|
||||
tNDSBanner* banner = (tNDSBanner*)malloc(sizeof(tNDSBanner));
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
else
|
||||
@ -51,7 +56,7 @@ void printFileInfo(const char* path)
|
||||
|
||||
//Convert 2 byte characters to 1 byte
|
||||
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);
|
||||
}
|
||||
@ -63,14 +68,14 @@ void printFileInfo(const char* path)
|
||||
iprintf("\n");
|
||||
}
|
||||
|
||||
iprintf("Label: %.12s\n", header.ndshdr.gameTitle);
|
||||
iprintf("Game Code: %.4s\n", header.ndshdr.gameCode);
|
||||
iprintf("Label: %.12s\n", header->ndshdr.gameTitle);
|
||||
iprintf("Game Code: %.4s\n", header->ndshdr.gameCode);
|
||||
|
||||
//System type
|
||||
{
|
||||
iprintf("Unit Code: ");
|
||||
|
||||
switch (header.ndshdr.unitCode)
|
||||
switch (header->ndshdr.unitCode)
|
||||
{
|
||||
case 0: iprintf("NDS"); break;
|
||||
case 2: iprintf("NDS+DSi"); break;
|
||||
@ -85,19 +90,27 @@ void printFileInfo(const char* path)
|
||||
{
|
||||
iprintf("Program Type: ");
|
||||
|
||||
switch (header.ndshdr.reserved1[7])
|
||||
switch (header->ndshdr.reserved1[7])
|
||||
{
|
||||
case 0x3: iprintf("Normal"); break;
|
||||
case 0xB: iprintf("Sys"); break;
|
||||
case 0xF: iprintf("Debug/Sys"); break;
|
||||
default: iprintf("unknown");
|
||||
default: iprintf("unknown");
|
||||
}
|
||||
|
||||
iprintf("\n");
|
||||
}
|
||||
|
||||
iprintf("Title ID: %08x %08x\n", (unsigned int)header.tid_high,
|
||||
(unsigned int)header.tid_low);
|
||||
//DSi data
|
||||
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
|
||||
iprintf("\n%s\n", path);
|
||||
@ -106,6 +119,9 @@ void printFileInfo(const char* path)
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
free(banner);
|
||||
free(header);
|
||||
}
|
||||
|
||||
//Progress bar
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "menus.h"
|
||||
#include "main.h"
|
||||
#include "menu.h"
|
||||
#include "storage.h"
|
||||
|
||||
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 <dirent.h>
|
||||
|
||||
#define NUM_OF_DIRECTORIES 3
|
||||
static const char* directories[] = {
|
||||
"00030004",
|
||||
"00030005",
|
||||
"00030015"
|
||||
static void generateList(Menu* m);
|
||||
static void printItem(Menu* m);
|
||||
|
||||
static int subMenu();
|
||||
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()
|
||||
{
|
||||
cursor = 0;
|
||||
scrolly = 0;
|
||||
numberOfTitles = getNumberOfTitles();
|
||||
Menu* m = (Menu*)malloc(sizeof(Menu));
|
||||
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
consoleClear();
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
generateList(m);
|
||||
|
||||
//No titles error
|
||||
if (numberOfTitles <= 0)
|
||||
if (getNumberOfMenuItems(m) <= 0)
|
||||
{
|
||||
consoleClear();
|
||||
|
||||
iprintf("No titles found.\n");
|
||||
iprintf("Back - B\n");
|
||||
|
||||
@ -46,188 +46,70 @@ void titleMenu()
|
||||
}
|
||||
|
||||
//Print data
|
||||
consoleSelect(&topScreen);
|
||||
printTitleInfo(cursor);
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
printList();
|
||||
printItem(m);
|
||||
printMenu(m);
|
||||
|
||||
while (1)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
int thisScrolly = scrolly;
|
||||
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)
|
||||
if (moveCursor(m))
|
||||
{
|
||||
repeat (10)
|
||||
moveCursor(1);
|
||||
printItem(m);
|
||||
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)
|
||||
break;
|
||||
|
||||
else if (keysDown() & KEY_A)
|
||||
{
|
||||
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 )
|
||||
switch (subMenu())
|
||||
{
|
||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||
continue;
|
||||
case TITLE_MENU_DUMP:
|
||||
dump(m);
|
||||
break;
|
||||
|
||||
if (ent->d_type == DT_DIR)
|
||||
{
|
||||
//Search for an .app file
|
||||
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);
|
||||
}
|
||||
case TITLE_MENU_DELETE:
|
||||
delete(m);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//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;
|
||||
struct dirent* ent;
|
||||
struct dirent* ent;
|
||||
|
||||
char dirPath[256];
|
||||
sprintf(dirPath, "/title/%s", directories[i]);
|
||||
@ -236,7 +118,7 @@ int getTitle(int num, char* title, char* path)
|
||||
|
||||
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)
|
||||
continue;
|
||||
@ -254,7 +136,7 @@ int getTitle(int num, char* title, char* path)
|
||||
|
||||
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)
|
||||
continue;
|
||||
@ -263,61 +145,57 @@ int getTitle(int num, char* title, char* path)
|
||||
{
|
||||
if (strstr(subent->d_name, ".app") != NULL)
|
||||
{
|
||||
if (count < num)
|
||||
count++;
|
||||
//Found requested title
|
||||
char path[384];
|
||||
sprintf(path, "%s/%s", contentPath, subent->d_name);
|
||||
|
||||
else
|
||||
//Generate list
|
||||
if (mode == 0)
|
||||
{
|
||||
//Found requested title
|
||||
char filepath[384];
|
||||
sprintf(filepath, "%s/%s", contentPath, subent->d_name);
|
||||
FILE* f = fopen(path, "rb");
|
||||
|
||||
//Output title
|
||||
if (title != NULL)
|
||||
if (f)
|
||||
{
|
||||
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, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
tNDSHeader header;
|
||||
tNDSBanner banner;
|
||||
char c = banner->titles[1][i];
|
||||
|
||||
//Replace new line with space
|
||||
if (c == '\n')
|
||||
c = ' ';
|
||||
|
||||
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++)
|
||||
{
|
||||
char c = banner.titles[1][i];
|
||||
|
||||
if (c == '\n')
|
||||
c = ' ';
|
||||
|
||||
tstr[i] = c;
|
||||
}
|
||||
|
||||
sprintf(title, "%s", tstr);
|
||||
tstr[i] = c;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
free(banner);
|
||||
free(header);
|
||||
|
||||
addMenuItem(m, tstr);
|
||||
}
|
||||
|
||||
//Output path
|
||||
if (path != NULL)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
//Get item file name
|
||||
else if (mode == 1)
|
||||
{
|
||||
if (count < m->cursor)
|
||||
count++;
|
||||
else
|
||||
{
|
||||
sprintf(path, "%s", filepath);
|
||||
}
|
||||
|
||||
//Exit this mess
|
||||
result = 1;
|
||||
break;
|
||||
sprintf(out, "%s", path);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,173 +213,228 @@ int getTitle(int num, char* title, char* path)
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
static int subCursor = 0;
|
||||
|
||||
enum {
|
||||
// TITLE_MENU_BACKUP,
|
||||
TITLE_MENU_DUMP,
|
||||
TITLE_MENU_DELETE,
|
||||
TITLE_MENU_BACK
|
||||
};
|
||||
|
||||
void subMenu()
|
||||
void generateList(Menu* m)
|
||||
{
|
||||
subCursor = 0;
|
||||
|
||||
if (m == NULL) return;
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
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("\tDump\n");
|
||||
iprintf("\tDelete\n");
|
||||
iprintf("\tBack\n");
|
||||
addMenuItem(m, "Dump");
|
||||
// addMenuItem(m, "Backup Saved Data");
|
||||
// addMenuItem(m, "Restore Saved Data");
|
||||
addMenuItem(m, "Delete");
|
||||
addMenuItem(m, "Back");
|
||||
|
||||
printMenu(m);
|
||||
|
||||
while (1)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
//Clear cursor
|
||||
iprintf("\x1b[%d;0H ", subCursor);
|
||||
if (moveCursor(m))
|
||||
printMenu(m);
|
||||
|
||||
//Move cursor
|
||||
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)
|
||||
if (keysDown() & KEY_B)
|
||||
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