Add files via upload

This commit is contained in:
JeffRuLz 2018-09-25 15:06:12 -05:00 committed by GitHub
parent 14dcd71e33
commit eb16d0581a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1032 additions and 889 deletions

BIN
icon.bmp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -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);
}

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "menus.h"
#include "main.h"
#include "menu.h"
#include "storage.h"
void testMenu()

View File

@ -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
View 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
View 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