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
e6291362f3
commit
e0f2505016
140
Makefile
Normal file
140
Makefile
Normal file
@ -0,0 +1,140 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
# MAXMOD_SOUNDBANK contains a directory of music and sound effect files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(shell basename $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := src
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
GAME_TITLE := TMFH
|
||||
GAME_SUBTITLE1 := Title Manager for HiyaCFW
|
||||
GAME_SUBTITLE2 := JeffRuLz
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s
|
||||
|
||||
CFLAGS := -g -Wall -O2\
|
||||
-fomit-frame-pointer\
|
||||
-ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM9
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with the project (order is important)
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -lfat -lnds9
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(LIBNDS)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
icons := $(wildcard *.bmp)
|
||||
|
||||
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
|
||||
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
|
||||
else
|
||||
ifneq (,$(findstring icon.bmp,$(icons)))
|
||||
export GAME_ICON := $(CURDIR)/icon.bmp
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).nds : $(OUTPUT).elf
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
$(bin2o)
|
||||
|
||||
-include $(DEPSDIR)/*.d
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
642
src/installmenu.c
Normal file
642
src/installmenu.c
Normal file
@ -0,0 +1,642 @@
|
||||
#include "menus.h"
|
||||
#include "storage.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,
|
||||
INSTALL_MENU_DELETE,
|
||||
INSTALL_MENU_BACK
|
||||
};
|
||||
|
||||
void subMenu()
|
||||
{
|
||||
bool printMenu = true;
|
||||
subCursor = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
if (printMenu == true)
|
||||
{
|
||||
printMenu = false;
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("\tInstall\n");
|
||||
iprintf("\tDelete\n");
|
||||
iprintf("\tBack - B\n");
|
||||
}
|
||||
|
||||
//Clear cursor
|
||||
iprintf("\x1b[%d;0H ", subCursor);
|
||||
|
||||
//Move cursor
|
||||
if (keysDown() & KEY_DOWN)
|
||||
{
|
||||
if (subCursor < INSTALL_MENU_BACK)
|
||||
subCursor++;
|
||||
}
|
||||
|
||||
if (keysDown() & KEY_UP)
|
||||
{
|
||||
if (subCursor > 0)
|
||||
subCursor--;
|
||||
}
|
||||
|
||||
//Reprint cursor
|
||||
iprintf("\x1b[%d;0H>", subCursor);
|
||||
|
||||
//
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void install(char* fpath)
|
||||
{
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("Installing %s\n", fpath); swiWaitForVBlank();
|
||||
|
||||
FILE* f = fopen(fpath, "rb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
iprintf("Error: could not open file.\nPress B to exit.\n");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Load header
|
||||
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);
|
||||
}
|
||||
|
||||
//Print file size
|
||||
int fileSize = -1;
|
||||
|
||||
{
|
||||
iprintf("File Size: "); swiWaitForVBlank();
|
||||
|
||||
fileSize = getFileSize(f);
|
||||
|
||||
printBytes(fileSize);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//Do not want file opened anymore
|
||||
fclose(f);
|
||||
|
||||
//SD card check
|
||||
{
|
||||
iprintf("Enough room on SD card?..."); swiWaitForVBlank();
|
||||
|
||||
if (getSDCardFree() < fileSize)
|
||||
{
|
||||
iprintf("No\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Yes\n");
|
||||
}
|
||||
|
||||
//DSi storage check
|
||||
{
|
||||
iprintf("Enough room on DSi?..."); swiWaitForVBlank();
|
||||
|
||||
if (getDsiFree() < fileSize)
|
||||
{
|
||||
iprintf("No\n"); swiWaitForVBlank();
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Yes\n"); swiWaitForVBlank();
|
||||
}
|
||||
|
||||
//Menu slot check
|
||||
{
|
||||
iprintf("Open DSi menu slot?..."); swiWaitForVBlank();
|
||||
|
||||
if (getMenuSlotsFree() <= 0)
|
||||
{
|
||||
iprintf("No\n"); swiWaitForVBlank();
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Yes\n"); swiWaitForVBlank();
|
||||
}
|
||||
|
||||
//Create title directory
|
||||
char titleID[8+1];
|
||||
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();
|
||||
}
|
||||
|
||||
//Check if title is already installed
|
||||
{
|
||||
DIR* dir = opendir(dirPath);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
closedir(dir);
|
||||
|
||||
iprintf("Title %s is already used.\nInstall anyway?\n", titleID);
|
||||
iprintf("Yes - A\nNo - B\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
if (keysDown() & KEY_A)
|
||||
break;
|
||||
|
||||
if (keysDown() & KEY_B)
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
mkdir(dirPath, 0777);
|
||||
|
||||
//Content folder
|
||||
{
|
||||
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)
|
||||
{
|
||||
iprintf("Failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
iprintf("Done\n");
|
||||
|
||||
//Make TMD
|
||||
{
|
||||
char tmdPath[256];
|
||||
sprintf(tmdPath, "%s/title.tmd", contentPath);
|
||||
|
||||
if (maketmd(appPath, tmdPath) != 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Data folder
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
repeat (header.public_sav_size)
|
||||
fwrite(&num, 1, 1, f);
|
||||
|
||||
iprintf("Done\n");
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
//If needed, create private.sav
|
||||
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;
|
||||
|
||||
repeat (header.private_sav_size)
|
||||
fwrite(&num, 1, 1, f);
|
||||
|
||||
iprintf("Done\n");
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
//If needed, create banner.sav
|
||||
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;
|
||||
|
||||
repeat (1024*16) //Is banner.sav always 16kb?
|
||||
fwrite(&num, 1, 1, f);
|
||||
|
||||
iprintf("Done\n");
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
iprintf("\nInstallation complete.\nPress B to exit.\n");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
}
|
||||
|
||||
complete:
|
||||
fclose(f);
|
||||
return;
|
||||
|
||||
error:
|
||||
fclose(f);
|
||||
|
||||
iprintf("\nInstallation failed.\nPress B to exit.\n");
|
||||
keyWait(KEY_A | KEY_B);
|
||||
|
||||
return;
|
||||
}
|
||||
133
src/main.c
Normal file
133
src/main.c
Normal file
@ -0,0 +1,133 @@
|
||||
#include "main.h"
|
||||
#include "menus.h"
|
||||
|
||||
#define VERSION "0.4"
|
||||
|
||||
enum {
|
||||
MAIN_MENU_INSTALL,
|
||||
MAIN_MENU_TITLES,
|
||||
// MAIN_MENU_RESTORE,
|
||||
MAIN_MENU_TEST,
|
||||
MAIN_MENU_EXIT
|
||||
};
|
||||
|
||||
static int mainMenu();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
videoSetMode(MODE_0_2D);
|
||||
videoSetModeSub(MODE_0_2D);
|
||||
|
||||
vramSetBankA(VRAM_A_MAIN_BG);
|
||||
vramSetBankC(VRAM_C_SUB_BG);
|
||||
|
||||
consoleInit(&topScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
|
||||
consoleInit(&bottomScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, false, true);
|
||||
|
||||
if (!fatInitDefault())
|
||||
{
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("fatInitDefault...Failed\n");
|
||||
iprintf("\nPress B to exit.\n");
|
||||
|
||||
keyWait(KEY_B | KEY_A | KEY_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool programEnd = false;
|
||||
|
||||
while (!programEnd)
|
||||
{
|
||||
switch (mainMenu())
|
||||
{
|
||||
case MAIN_MENU_INSTALL:
|
||||
installMenu();
|
||||
break;
|
||||
|
||||
case MAIN_MENU_TITLES:
|
||||
titleMenu();
|
||||
break;
|
||||
|
||||
case MAIN_MENU_TEST:
|
||||
testMenu();
|
||||
break;
|
||||
|
||||
case MAIN_MENU_EXIT:
|
||||
programEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cursor = 0;
|
||||
|
||||
int mainMenu()
|
||||
{
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("\tTitle Manager for HiyaCFW\n");
|
||||
iprintf("\nversion %s\n", VERSION);
|
||||
iprintf("\x1b[23;0HJeff - 2018");
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
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 (keysDown() & KEY_A)
|
||||
break;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
15
src/main.h
Normal file
15
src/main.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <nds.h>
|
||||
#include <fat.h>
|
||||
#include <stdio.h>
|
||||
|
||||
PrintConsole topScreen;
|
||||
PrintConsole bottomScreen;
|
||||
|
||||
#define abs(X) ( (X) < 0 ? -(X): (X) )
|
||||
#define sign(X) ( ((X) > 0) - ((X) < 0) )
|
||||
#define repeat(X) for (int _I_ = 0; _I_ < (X); _I_++)
|
||||
|
||||
#endif
|
||||
173
src/maketmd.c
Normal file
173
src/maketmd.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------
|
||||
|
||||
maketmd.cpp -- TMD Creator for DSiWare Homebrew
|
||||
|
||||
Copyright (C) 2018
|
||||
Przemyslaw Skryjomski (Tuxality)
|
||||
|
||||
Big thanks to:
|
||||
Apache Thunder
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
---------------------------------------------------------------------------------*/
|
||||
|
||||
/* September 2018 - Jeff - Translated from C++ to C and uses libnds instead of openssl
|
||||
Original: github.com/Tuxality/maketmd
|
||||
*/
|
||||
|
||||
#include "maketmd.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <nds/sha1.h>
|
||||
#include <nds/ndstypes.h>
|
||||
#include <machine/endian.h>
|
||||
|
||||
//#define TMD_CREATOR_VER "0.2"
|
||||
|
||||
#define TMD_SIZE 0x208
|
||||
#define SHA_BUFFER_SIZE 0x200
|
||||
#define SHA_DIGEST_LENGTH 0x14
|
||||
|
||||
void tmd_create(uint8_t* tmd, FILE* app)
|
||||
{
|
||||
// Phase 1 - offset 0x18C (Title ID, first part)
|
||||
{
|
||||
fseek(app, 0x234, SEEK_SET);
|
||||
|
||||
uint32_t value;
|
||||
fread(&value, 4, 1, app);
|
||||
value = __bswap32(value);
|
||||
|
||||
memcpy(tmd + 0x18c, &value, 4);
|
||||
}
|
||||
|
||||
// Phase 2 - offset 0x190 (Title ID, second part)
|
||||
{
|
||||
// We can take this also from 0x230, but reversed
|
||||
fseek(app, 0x0C, SEEK_SET);
|
||||
fread((char*)&tmd[0x190], 4, 1, app);
|
||||
}
|
||||
|
||||
// Phase 3 - offset 0x198 (Group ID = '01')
|
||||
{
|
||||
fseek(app, 0x10, SEEK_SET);
|
||||
fread((char*)&tmd[0x198], 2, 1, app);
|
||||
}
|
||||
|
||||
// Phase 4 - offset 0x1AA (fill-in 0x80 value, 0x10 times)
|
||||
{
|
||||
for(size_t i = 0; i<0x10; i++) {
|
||||
tmd[0x1AA + i] = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 5 - offset 0x1DE (number of contents = 1)
|
||||
{
|
||||
tmd[0x1DE] = 0x00;
|
||||
tmd[0x1DF] = 0x01;
|
||||
}
|
||||
|
||||
// Phase 6 - offset 0x1EA (type of content = 1)
|
||||
{
|
||||
tmd[0x1EA] = 0x00;
|
||||
tmd[0x1EB] = 0x01;
|
||||
}
|
||||
|
||||
// Phase 7 - offset, 0x1EC (file size, 8B)
|
||||
{
|
||||
fseek(app, 0, SEEK_END);
|
||||
uint32_t size = ftell(app);
|
||||
size = __bswap32(size);
|
||||
|
||||
// We only use 4B for size as for now
|
||||
memcpy((tmd + 0x1F0), &size, sizeof(u32));
|
||||
}
|
||||
|
||||
// Phase 8 - offset, 0x1F4 (SHA1 sum, 20B)
|
||||
{
|
||||
// Makes use of libnds
|
||||
fseek(app, 0, SEEK_SET);
|
||||
|
||||
uint8_t buffer[SHA_BUFFER_SIZE] = { 0 };
|
||||
uint32_t buffer_read = 0;
|
||||
|
||||
swiSHA1context_t ctx;
|
||||
swiSHA1Init(&ctx);
|
||||
|
||||
do {
|
||||
buffer_read = fread((char*)&buffer[0], 1, SHA_BUFFER_SIZE, app);
|
||||
|
||||
swiSHA1Update(&ctx, buffer, buffer_read);
|
||||
} while(buffer_read == SHA_BUFFER_SIZE);
|
||||
|
||||
swiSHA1Final(buffer, &ctx);
|
||||
|
||||
//Store SHA1 sum
|
||||
memcpy((tmd + 0x1F4), buffer, SHA_DIGEST_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
int maketmd(char* input, char* tmdPath)
|
||||
{
|
||||
iprintf("MakeTMD for DSiWare Homebrew\n");
|
||||
iprintf("by Przemyslaw Skryjomski\n\t(Tuxality)\n");
|
||||
|
||||
if(input == NULL || tmdPath == NULL) {
|
||||
iprintf("\nUsage: %s file.app <file.tmd>\n", "maketmd");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// APP file (input)
|
||||
FILE* app = fopen(input, "rb");
|
||||
|
||||
if(!app) {
|
||||
iprintf("Error at opening %s for reading.\n", input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TMD file (output)
|
||||
FILE* tmd = fopen(tmdPath, "wb");
|
||||
|
||||
if (!tmd)
|
||||
{
|
||||
fclose(app);
|
||||
iprintf("Error at opening %s for writing.\n", tmdPath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate memory for TMD
|
||||
uint8_t* tmd_template = (uint8_t*)malloc(sizeof(uint8_t) * TMD_SIZE);
|
||||
memset(tmd_template, 0, sizeof(uint8_t) * TMD_SIZE); // zeroed
|
||||
|
||||
// Prepare TMD template then write to file
|
||||
tmd_create(tmd_template, app);
|
||||
fwrite((const char*)(&tmd_template[0]), TMD_SIZE, 1, tmd);
|
||||
|
||||
// Free allocated memory for TMD
|
||||
free(tmd_template);
|
||||
|
||||
// This is done in dtor, but we additionally flush tmd.
|
||||
fclose(app);
|
||||
fclose(tmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
src/maketmd.h
Normal file
6
src/maketmd.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef MAKETMD_H
|
||||
#define MAKETMD_H
|
||||
|
||||
int maketmd(char* input, char* tmdPath);
|
||||
|
||||
#endif
|
||||
72
src/menus.c
Normal file
72
src/menus.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include "menus.h"
|
||||
|
||||
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();
|
||||
}
|
||||
19
src/menus.h
Normal file
19
src/menus.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef MENUS_H
|
||||
#define MENUS_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
//Text box choices
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
void titleMenu();
|
||||
void installMenu();
|
||||
void testMenu();
|
||||
|
||||
void keyWait(u32 key);
|
||||
|
||||
int choiceBox(char* message);
|
||||
void messageBox(char* message);
|
||||
|
||||
#endif
|
||||
493
src/storage.c
Normal file
493
src/storage.c
Normal file
@ -0,0 +1,493 @@
|
||||
#include "storage.h"
|
||||
#include "main.h"
|
||||
#include <nds.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
//#include <nds/arm7/sdmmc.h>
|
||||
|
||||
#define TITLE_LIMIT 39
|
||||
|
||||
//Printing
|
||||
void printBytes(int bytes)
|
||||
{
|
||||
if (abs(bytes) < 1024)
|
||||
iprintf("%dB", bytes);
|
||||
|
||||
else if (abs(bytes) < 1024 * 1024)
|
||||
printf("%.2fKB", (float)bytes / 1024);
|
||||
|
||||
else if (abs(bytes) < 1024 * 1024 * 1024)
|
||||
printf("%.2fMB", (float)bytes / 1024 / 1024);
|
||||
|
||||
else
|
||||
printf("%.2fGB", (float)bytes / 1024 / 1024 / 1024);
|
||||
}
|
||||
|
||||
void printFileInfo(const char* path)
|
||||
{
|
||||
tDSiHeader header;
|
||||
tNDSBanner banner;
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
if (fread(&header, sizeof(tDSiHeader), 1, f) != 1)
|
||||
iprintf("Could not read dsi header.\n");
|
||||
|
||||
else
|
||||
{
|
||||
fseek(f, header.ndshdr.bannerOffset, SEEK_SET);
|
||||
|
||||
if (fread(&banner, sizeof(tNDSBanner), 1, f) != 1)
|
||||
iprintf("Could not read banner.\n");
|
||||
|
||||
else
|
||||
{
|
||||
//Proper title
|
||||
{
|
||||
char gameTitle[128+1];
|
||||
gameTitle[128] = '\0';
|
||||
|
||||
//Convert 2 byte characters to 1 byte
|
||||
for (int i = 0; i < 128; i++)
|
||||
gameTitle[i] = (char)banner.titles[1][i];
|
||||
|
||||
iprintf("%s\n\n", gameTitle);
|
||||
}
|
||||
|
||||
//File size
|
||||
{
|
||||
iprintf("Size: ");
|
||||
printBytes(getFileSize(f));
|
||||
iprintf("\n");
|
||||
}
|
||||
|
||||
iprintf("Label: %.12s\n", header.ndshdr.gameTitle);
|
||||
iprintf("Game Code: %.4s\n", header.ndshdr.gameCode);
|
||||
|
||||
//System type
|
||||
{
|
||||
iprintf("Unit Code: ");
|
||||
|
||||
switch (header.ndshdr.unitCode)
|
||||
{
|
||||
case 0: iprintf("NDS"); break;
|
||||
case 2: iprintf("NDS+DSi"); break;
|
||||
case 3: iprintf("DSi"); break;
|
||||
default: iprintf("unknown");
|
||||
}
|
||||
|
||||
iprintf("\n");
|
||||
}
|
||||
|
||||
//Application type
|
||||
{
|
||||
iprintf("Program Type: ");
|
||||
|
||||
switch (header.ndshdr.reserved1[7])
|
||||
{
|
||||
case 0x3: iprintf("Normal"); break;
|
||||
case 0xB: iprintf("Sys"); break;
|
||||
case 0xF: iprintf("Debug/Sys"); break;
|
||||
default: iprintf("unknown");
|
||||
}
|
||||
|
||||
iprintf("\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
//Progress bar
|
||||
void printProgressBar(int progress, int total)
|
||||
{
|
||||
iprintf("\x1b[23;0H[");
|
||||
iprintf("\x1b[23;31H]");
|
||||
|
||||
float bar = ((float)progress / (float)total) * 30.f;
|
||||
|
||||
for (int i = 0; i < bar; i++)
|
||||
iprintf("\x1b[23;%dH|", 1 + i);
|
||||
}
|
||||
|
||||
void clearProgressBar()
|
||||
{
|
||||
iprintf("\x1b[23;0H ");
|
||||
}
|
||||
|
||||
//Files
|
||||
int copyFile(const char* in, char* out)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (in == NULL || out == NULL)
|
||||
return 0;
|
||||
|
||||
FILE* fin = fopen(in, "rb");
|
||||
FILE* fout = fopen(out, "wb");
|
||||
|
||||
if (fin == NULL || fout == NULL)
|
||||
{
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
consoleSelect(&topScreen);
|
||||
|
||||
int fileSize = getFileSize(fin);
|
||||
int totalBytesRead = 0;
|
||||
int progressTimer = 100;
|
||||
|
||||
const int buffSize = 1024*32; //Arbitrary. A value too large freezes the system.
|
||||
unsigned char* buffer = (unsigned char*)malloc(sizeof(unsigned char) * buffSize);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int bytesRead = fread(buffer, 1, buffSize, fin);
|
||||
fwrite(buffer, 1, bytesRead, fout);
|
||||
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
//Re-print progress bar every so often, but not every time
|
||||
if ((progressTimer += 1) >= 25)
|
||||
{
|
||||
progressTimer = 0;
|
||||
printProgressBar(totalBytesRead, fileSize);
|
||||
}
|
||||
|
||||
if (feof(fin))
|
||||
{
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ferror(fin))
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
clearProgressBar();
|
||||
consoleSelect(&bottomScreen);
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
fclose(fout);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getFileSize(FILE* f)
|
||||
{
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int getFileSizePath(const char* path)
|
||||
{
|
||||
if (path == NULL)
|
||||
return -1;
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
int size = getFileSize(f);
|
||||
fclose(f);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
//Directories
|
||||
int dirExists(const char* path)
|
||||
{
|
||||
if (path == NULL)
|
||||
return 0;
|
||||
|
||||
DIR* dir = opendir(path);
|
||||
|
||||
if (dir)
|
||||
{
|
||||
closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Incomplete
|
||||
int copyDir(char* in, char* out)
|
||||
{
|
||||
if (in == NULL || out == NULL)
|
||||
return 0;
|
||||
|
||||
DIR* dir;
|
||||
struct dirent *ent;
|
||||
|
||||
dir = opendir(in);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mkdir(out, 0777);
|
||||
|
||||
while ( (ent = readdir(dir)) != NULL )
|
||||
{
|
||||
if(strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||
continue;
|
||||
|
||||
if (ent->d_type == DT_DIR)
|
||||
{
|
||||
char inPath[512];
|
||||
char outPath[512];
|
||||
|
||||
sprintf(inPath, "%s%s/", in, ent->d_name);
|
||||
sprintf(outPath, "%s%s/", out, ent->d_name);
|
||||
|
||||
copyDir(inPath, outPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
char inPath[512];
|
||||
char outPath[512];
|
||||
|
||||
sprintf(inPath, "%s%s", in, ent->d_name);
|
||||
sprintf(outPath, "%s%s", out, ent->d_name);
|
||||
|
||||
copyFile(inPath, outPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
int deleteDir(const char* path)
|
||||
{
|
||||
if (strcmp("/", path) == 0)
|
||||
{
|
||||
//Oh fuck no
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR* dir;
|
||||
struct dirent *ent;
|
||||
|
||||
dir = opendir(path);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( (ent = readdir(dir)) != NULL )
|
||||
{
|
||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||
continue;
|
||||
|
||||
if (ent->d_type == DT_DIR)
|
||||
{
|
||||
//Delete directory
|
||||
char subpath[512];
|
||||
sprintf(subpath, "%s%s/", path, ent->d_name);
|
||||
|
||||
deleteDir(subpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Delete file
|
||||
char fpath[512];
|
||||
sprintf(fpath, "%s%s", path, ent->d_name);
|
||||
|
||||
remove(fpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
rmdir(path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getDirSize(const char* path)
|
||||
{
|
||||
if (path == NULL)
|
||||
return 0;
|
||||
|
||||
int size = 0;
|
||||
|
||||
DIR* dir;
|
||||
struct dirent *ent;
|
||||
|
||||
dir = opendir(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)
|
||||
{
|
||||
char fullpath[512];
|
||||
sprintf(fullpath, "%s%s/", path, ent->d_name);
|
||||
|
||||
size += getDirSize(fullpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
char fullpath[256];
|
||||
sprintf(fullpath, "%s%s", path, ent->d_name);
|
||||
|
||||
size += getFileSizePath(fullpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
//Home menu
|
||||
int getMenuSlots()
|
||||
{
|
||||
//Assume the home menu has a hard limit on slots
|
||||
//Find a better way to do this
|
||||
return TITLE_LIMIT;
|
||||
}
|
||||
|
||||
#define NUM_OF_DIRECTORIES 3
|
||||
static const char* directories[] = {
|
||||
"00030004",
|
||||
"00030005",
|
||||
"00030015"
|
||||
};
|
||||
|
||||
int getMenuSlotsFree()
|
||||
{
|
||||
//Get number of open menu slots by subtracting the number of directories in the title folders
|
||||
//Find a better way to do this
|
||||
|
||||
int freeSlots = TITLE_LIMIT;
|
||||
|
||||
DIR* dir;
|
||||
struct dirent* ent;
|
||||
|
||||
for (int i = 0; i < NUM_OF_DIRECTORIES; i++)
|
||||
{
|
||||
char path[256];
|
||||
sprintf(path, "/title/%s", directories[i]);
|
||||
|
||||
dir = opendir(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)
|
||||
freeSlots -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return freeSlots;
|
||||
}
|
||||
|
||||
//SD Card
|
||||
int sdIsInserted()
|
||||
{
|
||||
// Undefined reference
|
||||
// return sdmmc_cardinserted();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getSDCardSize()
|
||||
{
|
||||
if (sdIsInserted())
|
||||
{
|
||||
struct statvfs st;
|
||||
if (statvfs("/", &st) == 0)
|
||||
return st.f_bsize * st.f_blocks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getSDCardFree()
|
||||
{
|
||||
if (sdIsInserted())
|
||||
{
|
||||
struct statvfs st;
|
||||
if (statvfs("/", &st) == 0)
|
||||
return st.f_bsize * st.f_bavail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Internal storage
|
||||
int getDsiSize()
|
||||
{
|
||||
//The DSi has 256MB of internal storage. Some is unavailable and used by other things.
|
||||
//Find a better way to do this
|
||||
// return 240 * 1024 * 1024;
|
||||
return 248 * 1024 * 1024;
|
||||
}
|
||||
|
||||
int getDsiFree()
|
||||
{
|
||||
//Get free space by subtracting file sizes in emulated nand folders
|
||||
//Find a better way to do this
|
||||
int size = getDsiSize();
|
||||
|
||||
size -= getDirSize("/sys/");
|
||||
size -= getDirSize("/title/");
|
||||
size -= getDirSize("/ticket/");
|
||||
size -= getDirSize("/shared1/");
|
||||
size -= getDirSize("/shared2/");
|
||||
size -= getDirSize("/import/");
|
||||
size -= getDirSize("/tmp/");
|
||||
size -= getDirSize("/progress/");
|
||||
|
||||
size -= getDirSize("/photo/");
|
||||
size -= getDirSize("/private/");
|
||||
|
||||
return size;
|
||||
}
|
||||
47
src/storage.h
Normal file
47
src/storage.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef STORAGE_H
|
||||
#define STORAGE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define BACKUP_PATH "/titlebackup/"
|
||||
#define ROM_PATH "/dsi/"
|
||||
|
||||
#define BYTES_PER_BLOCK (1024*128)
|
||||
|
||||
//Printing
|
||||
void printBytes(int bytes);
|
||||
void printFileInfo(const char* path);
|
||||
|
||||
//Progress bar
|
||||
void printProgressBar(int progress, int total);
|
||||
void clearProgressBar();
|
||||
|
||||
//Files
|
||||
int copyFile(const char* in, char* out);
|
||||
int getFileSize(FILE* f);
|
||||
int getFileSizePath(const char* path);
|
||||
|
||||
//Directories
|
||||
int dirExists(const char* path);
|
||||
//int copyDir(const char* in, char* out);
|
||||
int deleteDir(const char* path);
|
||||
int getDirSize(const char* path);
|
||||
|
||||
//Home menu
|
||||
int getMenuSlots();
|
||||
int getMenuSlotsFree();
|
||||
#define getMenuSlotsUsed() (getMenuSlots() - getMenuSlotsFree())
|
||||
|
||||
//SD Card
|
||||
int sdIsInserted();
|
||||
|
||||
int getSDCardSize();
|
||||
int getSDCardFree();
|
||||
#define getSDCardUsedSpace() (getSDCardSize() - getSDCardFree())
|
||||
|
||||
//Internal storage
|
||||
int getDsiSize();
|
||||
int getDsiFree();
|
||||
#define getDsiUsed() (getDSIStorageSize() - getDSIStorageFree())
|
||||
|
||||
#endif
|
||||
63
src/testmenu.c
Normal file
63
src/testmenu.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "menus.h"
|
||||
#include "storage.h"
|
||||
|
||||
void testMenu()
|
||||
{
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
|
||||
iprintf("Storage Check Test\n\n");
|
||||
iprintf("Verify these are accurate and\nreport if they're not.\n");
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
int free = -1;
|
||||
int size = -1;
|
||||
|
||||
//Home menu slots
|
||||
{
|
||||
iprintf("Free Home Menu Slots:\n"); swiWaitForVBlank();
|
||||
|
||||
free = getMenuSlotsFree();
|
||||
iprintf("\t%d / ", free); swiWaitForVBlank();
|
||||
|
||||
size = getMenuSlots();
|
||||
iprintf("%d\n", size); swiWaitForVBlank();
|
||||
}
|
||||
|
||||
//SD Card
|
||||
{
|
||||
iprintf("\nFree SD Space:\n\t"); swiWaitForVBlank();
|
||||
|
||||
free = getSDCardFree();
|
||||
printBytes(free);
|
||||
iprintf(" / "); swiWaitForVBlank();
|
||||
|
||||
size = getSDCardSize();
|
||||
printBytes(size);
|
||||
iprintf("\n"); swiWaitForVBlank();
|
||||
|
||||
printf("\t%.0f / %.0f blocks\n", (float)free / BYTES_PER_BLOCK, (float)size / BYTES_PER_BLOCK);
|
||||
}
|
||||
|
||||
//Emunand
|
||||
{
|
||||
iprintf("\nFree DSi Space:\n\t"); swiWaitForVBlank();
|
||||
|
||||
free = getDsiFree();
|
||||
printBytes(free);
|
||||
iprintf(" / "); swiWaitForVBlank();
|
||||
|
||||
size = getDsiSize();
|
||||
printBytes(size);
|
||||
iprintf("\n"); swiWaitForVBlank();
|
||||
|
||||
printf("\t%.0f / %.0f blocks\n", (float)free / BYTES_PER_BLOCK, (float)size / BYTES_PER_BLOCK);
|
||||
}
|
||||
|
||||
//
|
||||
iprintf("\nBack - B\n");
|
||||
|
||||
keyWait(KEY_B);
|
||||
}
|
||||
497
src/titlemenu.c
Normal file
497
src/titlemenu.c
Normal file
@ -0,0 +1,497 @@
|
||||
#include "menus.h"
|
||||
#include "storage.h"
|
||||
#include <dirent.h>
|
||||
|
||||
#define NUM_OF_DIRECTORIES 3
|
||||
static const char* directories[] = {
|
||||
"00030004",
|
||||
"00030005",
|
||||
"00030015"
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
consoleSelect(&topScreen);
|
||||
consoleClear();
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
//No titles error
|
||||
if (numberOfTitles <= 0)
|
||||
{
|
||||
iprintf("No titles found.\n");
|
||||
iprintf("Back - B\n");
|
||||
|
||||
keyWait(KEY_B | KEY_A | KEY_START);
|
||||
return;
|
||||
}
|
||||
|
||||
//Print data
|
||||
consoleSelect(&topScreen);
|
||||
printTitleInfo(cursor);
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
printList();
|
||||
|
||||
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)
|
||||
{
|
||||
repeat (10)
|
||||
moveCursor(1);
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int getTitle(int num, char* title, char* path)
|
||||
{
|
||||
int result = 0;
|
||||
int count = 0;
|
||||
|
||||
//Scan choice title directories
|
||||
for (int i = 0; i < NUM_OF_DIRECTORIES && result == 0; 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 && result == 0)
|
||||
{
|
||||
if (strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0)
|
||||
continue;
|
||||
|
||||
if (ent->d_type == DT_DIR)
|
||||
{
|
||||
//Scan content folder
|
||||
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 && result == 0)
|
||||
{
|
||||
if (strcmp(".", subent->d_name) == 0 || strcmp("..", subent->d_name) == 0)
|
||||
continue;
|
||||
|
||||
if (subent->d_type != DT_DIR)
|
||||
{
|
||||
if (strstr(subent->d_name, ".app") != NULL)
|
||||
{
|
||||
if (count < num)
|
||||
count++;
|
||||
|
||||
else
|
||||
{
|
||||
//Found requested title
|
||||
char filepath[384];
|
||||
sprintf(filepath, "%s/%s", contentPath, subent->d_name);
|
||||
|
||||
//Output title
|
||||
if (title != NULL)
|
||||
{
|
||||
FILE* f = fopen(filepath, "rb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
sprintf(title, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
tNDSHeader header;
|
||||
tNDSBanner banner;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
//Output path
|
||||
if (path != NULL)
|
||||
{
|
||||
sprintf(path, "%s", filepath);
|
||||
}
|
||||
|
||||
//Exit this mess
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(subdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
static int subCursor = 0;
|
||||
|
||||
enum {
|
||||
// TITLE_MENU_BACKUP,
|
||||
TITLE_MENU_DUMP,
|
||||
TITLE_MENU_DELETE,
|
||||
TITLE_MENU_BACK
|
||||
};
|
||||
|
||||
void subMenu()
|
||||
{
|
||||
subCursor = 0;
|
||||
|
||||
consoleSelect(&bottomScreen);
|
||||
consoleClear();
|
||||
|
||||
// iprintf("\tBackup\n");
|
||||
iprintf("\tDump\n");
|
||||
iprintf("\tDelete\n");
|
||||
iprintf("\tBack\n");
|
||||
|
||||
while (1)
|
||||
{
|
||||
swiWaitForVBlank();
|
||||
scanKeys();
|
||||
|
||||
//Clear cursor
|
||||
iprintf("\x1b[%d;0H ", subCursor);
|
||||
|
||||
//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
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user