diff --git a/gui.pnproj b/gui.pnproj
index 9c8c1fea..4ff60c09 100644
--- a/gui.pnproj
+++ b/gui.pnproj
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/source/menu.cpp b/source/menu.cpp
index 1ac93f72..f61607e9 100644
--- a/source/menu.cpp
+++ b/source/menu.cpp
@@ -698,7 +698,7 @@ int MenuDiscList() {
mainWindow->Append(&w);
ResumeGui();
-
+
while (menu == MENU_NONE) {
if (idiotFlag==1) {
diff --git a/source/prompts/DiscBrowser.cpp b/source/prompts/DiscBrowser.cpp
index 11e231bc..02aa8c83 100644
--- a/source/prompts/DiscBrowser.cpp
+++ b/source/prompts/DiscBrowser.cpp
@@ -17,6 +17,7 @@
#include "sys.h"
#include "settings/cfg.h"
#include "memory.h"
+#include "../wad/title.h"
/*** Extern functions ***/
extern void ResumeGui();
@@ -316,6 +317,15 @@ int autoSelectDol(const char *id, bool force) {
int autoSelectDolMenu(const char *id) {
//Metroid Prime Trilogy
+ //don't let the game start without a save game in the nand
+ char id4[10];
+ sprintf(id4,"%c%c%c%c",id[0],id[1],id[2],id[3]);
+
+ if (CheckForSave(id4)==0)
+ {
+ WindowPrompt(0,"You need to play the game one time to create a save file. Then exit and start it again using the dol of the game you want to use.",tr("Ok"));
+ return -1;
+ }
if (strcmp(id,"R3ME01") == 0) {
int choice = WindowPrompt(tr("Select a DOL"), 0, "Metroid Prime", "Metroid Prime 2", "Metroid Prime 3", tr("Default"));
switch (choice) {
diff --git a/source/wad/isfs.c b/source/wad/isfs.c
new file mode 100644
index 00000000..abbea717
--- /dev/null
+++ b/source/wad/isfs.c
@@ -0,0 +1,494 @@
+/*
+
+libisfs -- a NAND filesystem devoptab library for the Wii
+
+Copyright (C) 2008 Joseph Jordan
+Copyright (C) 2009 Waninkoko
+
+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.
+
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "isfs.h"
+
+#define DEVICE_NAME "isfs"
+
+#define FLAG_DIR 1
+#define DIR_SEPARATOR '/'
+#define SECTOR_SIZE 0x800
+#define BUFFER_SIZE 0x8000
+
+typedef struct DIR_ENTRY_STRUCT {
+ char *name;
+ char *abspath;
+ u32 size;
+ u8 flags;
+ u32 fileCount;
+ struct DIR_ENTRY_STRUCT *children;
+} DIR_ENTRY;
+
+typedef struct {
+ DIR_ENTRY *entry;
+ s32 isfs_fd;
+ bool inUse;
+} FILE_STRUCT;
+
+typedef struct {
+ DIR_ENTRY *entry;
+ u32 index;
+ bool inUse;
+} DIR_STATE_STRUCT;
+
+static char rw_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
+
+static DIR_ENTRY *root = NULL;
+static DIR_ENTRY *current = NULL;
+static s32 dotab_device = -1;
+
+static bool is_dir(DIR_ENTRY *entry) {
+ return entry->flags & FLAG_DIR;
+}
+
+static bool invalid_drive_specifier(const char *path) {
+ if (strchr(path, ':') == NULL) return false;
+ int namelen = strlen(DEVICE_NAME);
+ if (!strncmp(DEVICE_NAME, path, namelen) && path[namelen] == ':') return false;
+ return true;
+}
+
+static DIR_ENTRY *entry_from_path(const char *path) {
+ if (invalid_drive_specifier(path)) return NULL;
+ if (strchr(path, ':') != NULL) path = strchr(path, ':') + 1;
+ DIR_ENTRY *entry;
+ bool found = false;
+ bool notFound = false;
+ const char *pathPosition = path;
+ const char *pathEnd = strchr(path, '\0');
+ if (pathPosition[0] == DIR_SEPARATOR) {
+ entry = root;
+ while (pathPosition[0] == DIR_SEPARATOR) pathPosition++;
+ if (pathPosition >= pathEnd) found = true;
+ } else {
+ entry = current;
+ }
+ if (entry == root && !strcmp(".", pathPosition)) found = true;
+ DIR_ENTRY *dir = entry;
+ while (!found && !notFound) {
+ const char *nextPathPosition = strchr(pathPosition, DIR_SEPARATOR);
+ size_t dirnameLength;
+ if (nextPathPosition != NULL) dirnameLength = nextPathPosition - pathPosition;
+ else dirnameLength = strlen(pathPosition);
+ if (dirnameLength >= ISFS_MAXPATHLEN) return NULL;
+
+ u32 fileIndex = 0;
+ while (fileIndex < dir->fileCount && !found && !notFound) {
+ entry = &dir->children[fileIndex];
+ if (dirnameLength == strnlen(entry->name, ISFS_MAXPATHLEN - 1) && !strncasecmp(pathPosition, entry->name, dirnameLength)) found = true;
+ if (found && !is_dir(entry) && nextPathPosition) found = false;
+ if (!found) fileIndex++;
+ }
+
+ if (fileIndex >= dir->fileCount) {
+ notFound = true;
+ found = false;
+ } else if (!nextPathPosition || nextPathPosition >= pathEnd) {
+ found = true;
+ } else if (is_dir(entry)) {
+ dir = entry;
+ pathPosition = nextPathPosition;
+ while (pathPosition[0] == DIR_SEPARATOR) pathPosition++;
+ if (pathPosition >= pathEnd) found = true;
+ else found = false;
+ }
+ }
+
+ if (found && !notFound) return entry;
+ return NULL;
+}
+
+static int _ISFS_open_r(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fileStruct;
+ DIR_ENTRY *entry = entry_from_path(path);
+ if (!entry) {
+ r->_errno = ENOENT;
+ return -1;
+ } else if (is_dir(entry)) {
+ r->_errno = EISDIR;
+ return -1;
+ }
+
+ int omode = 0;
+
+ if (mode & O_RDONLY)
+ omode |= ISFS_OPEN_READ;
+ if (mode & O_WRONLY)
+ omode |= ISFS_OPEN_WRITE;
+ if (mode & O_RDWR)
+ omode |= ISFS_OPEN_RW;
+
+ if (mode & O_CREAT) {
+ int user = 0;
+ int group = 0;
+ int other = 0;
+
+ if (flags & S_IRUSR)
+ user |= ISFS_OPEN_READ;
+ if (flags & S_IWUSR)
+ user |= ISFS_OPEN_WRITE;
+ if (flags & S_IRGRP)
+ group |= ISFS_OPEN_READ;
+ if (flags & S_IWGRP)
+ group |= ISFS_OPEN_WRITE;
+ if (flags & S_IROTH)
+ other |= ISFS_OPEN_READ;
+ if (flags & S_IWOTH)
+ other |= ISFS_OPEN_WRITE;
+
+ ISFS_CreateFile(entry->abspath, 0, user, group, other);
+ }
+
+ file->entry = entry;
+ file->inUse = true;
+ file->isfs_fd = ISFS_Open(entry->abspath, omode);
+ if (file->isfs_fd < 0) {
+ r->_errno = -file->isfs_fd;
+ return -1;
+ }
+
+ return (int)file;
+}
+
+static int _ISFS_close_r(struct _reent *r, int fd) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fd;
+ if (!file->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ file->inUse = false;
+
+ s32 ret = ISFS_Close(file->isfs_fd);
+ if (ret < 0) {
+ r->_errno = -ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _ISFS_write_r(struct _reent *r, int fd, const char *ptr, size_t len) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fd;
+ if (!file->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ if (len <= 0) {
+ return 0;
+ }
+
+ memcpy(rw_buffer, ptr, len);
+
+ s32 ret = ISFS_Write(file->isfs_fd, rw_buffer, len);
+ if (ret < 0) {
+ r->_errno = -ret;
+ return -1;
+ } else if (ret < len) {
+ r->_errno = EOVERFLOW;
+ }
+
+ return ret;
+}
+
+static int _ISFS_read_r(struct _reent *r, int fd, char *ptr, size_t len) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fd;
+ if (!file->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ if (len <= 0) {
+ return 0;
+ }
+
+ s32 ret = ISFS_Read(file->isfs_fd, rw_buffer, len);
+ if (ret < 0) {
+ r->_errno = -ret;
+ return -1;
+ } else if (ret < len) {
+ r->_errno = EOVERFLOW;
+ }
+
+ memcpy(ptr, rw_buffer, ret);
+ return ret;
+}
+
+static off_t _ISFS_seek_r(struct _reent *r, int fd, off_t pos, int dir) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fd;
+ if (!file->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+
+ s32 ret = ISFS_Seek(file->isfs_fd, pos, dir);
+ if (ret < 0) {
+ r->_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+static void stat_entry(DIR_ENTRY *entry, struct stat *st) {
+ st->st_dev = 0x4957;
+ st->st_ino = 0;
+ st->st_mode = ((is_dir(entry)) ? S_IFDIR : S_IFREG) | (S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_nlink = 1;
+ st->st_uid = 1;
+ st->st_gid = 2;
+ st->st_rdev = st->st_dev;
+ st->st_size = entry->size;
+ st->st_atime = 0;
+ st->st_spare1 = 0;
+ st->st_mtime = 0;
+ st->st_spare2 = 0;
+ st->st_ctime = 0;
+ st->st_spare3 = 0;
+ st->st_blksize = SECTOR_SIZE;
+ st->st_blocks = (entry->size + SECTOR_SIZE - 1) / SECTOR_SIZE;
+ st->st_spare4[0] = 0;
+ st->st_spare4[1] = 0;
+}
+
+static int _ISFS_fstat_r(struct _reent *r, int fd, struct stat *st) {
+ FILE_STRUCT *file = (FILE_STRUCT *)fd;
+ if (!file->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ stat_entry(file->entry, st);
+ return 0;
+}
+
+static int _ISFS_stat_r(struct _reent *r, const char *path, struct stat *st) {
+ DIR_ENTRY *entry = entry_from_path(path);
+ if (!entry) {
+ r->_errno = ENOENT;
+ return -1;
+ }
+ stat_entry(entry, st);
+ return 0;
+}
+
+static int _ISFS_chdir_r(struct _reent *r, const char *path) {
+ DIR_ENTRY *entry = entry_from_path(path);
+ if (!entry) {
+ r->_errno = ENOENT;
+ return -1;
+ } else if (!is_dir(entry)) {
+ r->_errno = ENOTDIR;
+ return -1;
+ }
+ return 0;
+}
+
+static int _ISFS_mkdir_r(struct _reent *r, const char *path, int mode) {
+ DIR_ENTRY *entry = entry_from_path(path);
+ if (entry) {
+ r->_errno = ENOENT;
+ return -1;
+ }
+
+ int other = (mode % 10);
+ int group = (mode / 10) % 10;
+ int user = (mode / 100) % 10;
+
+ s32 ret = ISFS_CreateDir(path, 0, user >> 1, group >> 1, other >> 1);
+ if (ret < 0) {
+ r->_errno = -ret;
+ return -1;
+ }
+ return 0;
+}
+
+static DIR_ITER *_ISFS_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path) {
+ DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT *)(dirState->dirStruct);
+ state->entry = entry_from_path(path);
+ if (!state->entry) {
+ r->_errno = ENOENT;
+ return NULL;
+ } else if (!is_dir(state->entry)) {
+ r->_errno = ENOTDIR;
+ return NULL;
+ }
+ state->index = 0;
+ state->inUse = true;
+ return dirState;
+}
+
+static int _ISFS_dirreset_r(struct _reent *r, DIR_ITER *dirState) {
+ DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT *)(dirState->dirStruct);
+ if (!state->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ state->index = 0;
+ return 0;
+}
+
+static int _ISFS_dirnext_r(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) {
+ DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT *)(dirState->dirStruct);
+ if (!state->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ if (state->index >= state->entry->fileCount) {
+ r->_errno = ENOENT;
+ return -1;
+ }
+ DIR_ENTRY *entry = &state->entry->children[state->index++];
+ strncpy(filename, entry->name, ISFS_MAXPATHLEN - 1);
+ stat_entry(entry, st);
+ return 0;
+}
+
+static int _ISFS_dirclose_r(struct _reent *r, DIR_ITER *dirState) {
+ DIR_STATE_STRUCT *state = (DIR_STATE_STRUCT *)(dirState->dirStruct);
+ if (!state->inUse) {
+ r->_errno = EBADF;
+ return -1;
+ }
+ state->inUse = false;
+ return 0;
+}
+
+static const devoptab_t dotab_isfs = {
+ DEVICE_NAME,
+ sizeof(FILE_STRUCT),
+ _ISFS_open_r,
+ _ISFS_close_r,
+ _ISFS_write_r,
+ _ISFS_read_r,
+ _ISFS_seek_r,
+ _ISFS_fstat_r,
+ _ISFS_stat_r,
+ NULL,
+ NULL,
+ _ISFS_chdir_r,
+ NULL,
+ _ISFS_mkdir_r,
+ sizeof(DIR_STATE_STRUCT),
+ _ISFS_diropen_r,
+ _ISFS_dirreset_r,
+ _ISFS_dirnext_r,
+ _ISFS_dirclose_r,
+ NULL
+};
+
+static DIR_ENTRY *add_child_entry(DIR_ENTRY *dir, const char *name) {
+ DIR_ENTRY *newChildren = realloc(dir->children, (dir->fileCount + 1) * sizeof(DIR_ENTRY));
+ if (!newChildren) return NULL;
+ bzero(newChildren + dir->fileCount, sizeof(DIR_ENTRY));
+ dir->children = newChildren;
+ DIR_ENTRY *child = &dir->children[dir->fileCount++];
+ child->name = strdup(name);
+ if (!child->name) return NULL;
+ child->abspath = malloc(strlen(dir->abspath) + (dir != root) + strlen(name) + 1);
+ if (!child->abspath) return NULL;
+ sprintf(child->abspath, "%s/%s", dir == root ? "" : dir->abspath, name);
+ return child;
+}
+
+static bool read_recursive(DIR_ENTRY *parent) {
+ u32 fileCount;
+ s32 ret = ISFS_ReadDir(parent->abspath, NULL, &fileCount);
+ if (ret != ISFS_OK) {
+ s32 fd = ISFS_Open(parent->abspath, ISFS_OPEN_READ);
+ if (fd >= 0) {
+ static fstats st __attribute__((aligned(32)));
+ if (ISFS_GetFileStats(fd, &st) == ISFS_OK) parent->size = st.file_length;
+ ISFS_Close(fd);
+ }
+ return true;
+ }
+ parent->flags = FLAG_DIR;
+ if (fileCount > 0) {
+ if ((ISFS_MAXPATHLEN * fileCount) > BUFFER_SIZE) return false;
+ ret = ISFS_ReadDir(parent->abspath, rw_buffer, &fileCount);
+ if (ret != ISFS_OK) return false;
+ u32 fileNum;
+ char *name = rw_buffer;
+ for (fileNum = 0; fileNum < fileCount; fileNum++) {
+ DIR_ENTRY *child = add_child_entry(parent, name);
+ if (!child) return false;
+ name += strlen(name) + 1;
+ }
+ for (fileNum = 0; fileNum < fileCount; fileNum++)
+ if (!read_recursive(parent->children + fileNum))
+ return false;
+ }
+ return true;
+}
+
+static bool read_isfs() {
+ root = malloc(sizeof(DIR_ENTRY));
+ if (!root) return false;
+ bzero(root, sizeof(DIR_ENTRY));
+ current = root;
+ root->name = strdup("/");
+ if (!root->name) return false;
+ root->abspath = strdup("/");
+ if (!root->abspath) return false;
+ return read_recursive(root);
+}
+
+static void cleanup_recursive(DIR_ENTRY *entry) {
+ u32 i;
+ for (i = 0; i < entry->fileCount; i++) cleanup_recursive(&entry->children[i]);
+ if (entry->children) free(entry->children);
+ if (entry->name) free(entry->name);
+ if (entry->abspath) free(entry->abspath);
+}
+
+bool ISFS_Mount() {
+ ISFS_Unmount();
+ bool success = read_isfs() && (dotab_device = AddDevice(&dotab_isfs)) >= 0;
+ if (!success) ISFS_Unmount();
+ return success;
+}
+
+bool ISFS_Unmount() {
+ if (root) {
+ cleanup_recursive(root);
+ free(root);
+ root = NULL;
+ }
+ current = root;
+ if (dotab_device >= 0) {
+ dotab_device = -1;
+ return !RemoveDevice(DEVICE_NAME ":");
+ }
+ return true;
+}
diff --git a/source/wad/isfs.h b/source/wad/isfs.h
new file mode 100644
index 00000000..2a509197
--- /dev/null
+++ b/source/wad/isfs.h
@@ -0,0 +1,37 @@
+/*
+
+libisfs -- a NAND filesystem devoptab library for the Wii
+
+Copyright (C) 2008 Joseph Jordan
+
+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.
+
+*/
+#ifndef _LIBISFS_H
+#define _LIBISFS_H
+
+#include
+
+#define ISFS_MAXPATHLEN (ISFS_MAXPATH + 1)
+
+bool ISFS_Mount();
+bool ISFS_Unmount();
+
+#endif /* _LIBISFS_H_ */
+
diff --git a/source/wad/title.c b/source/wad/title.c
index 8db49eb6..85870135 100644
--- a/source/wad/title.c
+++ b/source/wad/title.c
@@ -9,6 +9,7 @@
#include "../settings/cfg.h"
#include "fatmounter.h"
#include "id.h"
+#include "isfs.h"
#define MAX_TITLES 256
@@ -169,6 +170,8 @@ s32 Title_GetSysVersion(u64 tid, u64 *outbuf) {
return 0;
}
+
+
s32 Title_GetSize(u64 tid, u32 *outbuf) {
signed_blob *p_tmd = NULL;
tmd *tmd_data = NULL;
@@ -317,6 +320,127 @@ s32 Uninstall_DeleteTicket(u32 title_u, u32 title_l) {
return ret;
}
+
+//////savegame shit, from waninkoko. modified for use in this project
+/* Savegame structure */
+struct savegame {
+ /* Title name */
+ char name[65];
+
+ /* Title ID */
+ u64 tid;
+};
+
+s32 Savegame_CheckTitle(const char *path)
+{
+ FILE *fp = NULL;
+
+ char filepath[128];
+
+ /* Generate filepath */
+ sprintf(filepath, "%s/banner.bin", path);
+
+ /* Try to open banner */
+ fp = fopen(filepath, "rb");
+ if (!fp)
+ return -1;
+
+ /* Close file */
+ fclose(fp);
+
+ return 0;
+}
+
+s32 Savegame_GetNandPath(u64 tid, char *outbuf)
+{
+ s32 ret;
+ char buffer[1024] ATTRIBUTE_ALIGN(32);
+
+ /* Get data directory */
+ ret = ES_GetDataDir(tid, buffer);
+ if (ret < 0)
+ return ret;
+
+ /* Generate NAND directory */
+ sprintf(outbuf, "isfs:%s", buffer);
+
+ return 0;
+}
+
+s32 __Menu_GetNandSaves(struct savegame **outbuf, u32 *outlen)
+{
+ struct savegame *buffer = NULL;
+
+ u64 *titleList = NULL;
+ u32 titleCnt;
+
+ u32 cnt, idx;
+ s32 ret;
+
+ /* Get title list */
+ ret = Title_GetList(&titleList, &titleCnt);
+ if (ret < 0)
+ return ret;
+
+ /* Allocate memory */
+ buffer = malloc(sizeof(struct savegame) * titleCnt);
+ if (!buffer) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Copy titles */
+ for (cnt = idx = 0; idx < titleCnt; idx++) {
+ u64 tid = titleList[idx];
+ char savepath[128];
+
+ /* Generate dirpath */
+ Savegame_GetNandPath(tid, savepath);
+
+ /* Check for title savegame */
+ ret = Savegame_CheckTitle(savepath);
+ if (!ret) {
+ struct savegame *save = &buffer[cnt++];
+
+ /* Set title ID */
+ save->tid = tid;
+ }
+ }
+
+ /* Set values */
+ *outbuf = buffer;
+ *outlen = cnt;
+
+ /* Success */
+ ret = 0;
+
+out:
+ /* Free memory */
+ if (titleList)
+ free(titleList);
+
+ return ret;
+}
+
+s32 __Menu_EntryCmp(const void *p1, const void *p2)
+{
+ struct savegame *s1 = (struct savegame *)p1;
+ struct savegame *s2 = (struct savegame *)p2;
+
+ /* Compare entries */
+ return strcmp(s1->name, s2->name);
+}
+
+s32 __Menu_RetrieveList(struct savegame **outbuf, u32 *outlen)
+{
+ s32 ret;
+ ret = __Menu_GetNandSaves(outbuf, outlen);
+ if (ret >= 0)
+ qsort(*outbuf, *outlen, sizeof(struct savegame), __Menu_EntryCmp);
+
+ return ret;
+}
+
//carefull when using this function
//it will force remove stuff even if something fails
s32 Uninstall_FromTitle(const u64 tid) {
@@ -586,6 +710,35 @@ char *titleText(u32 kind, u32 title) {
return text;
}
+//giantpune's magic function to check for game saves
+//give a ID4 of a game and returns 1 if the game has save data, 0 if not, or <0 for errors
+int CheckForSave(const char *gameID)
+{
+
+ if (ISFS_Initialize()<0)
+ return -1;
+
+ if (!ISFS_Mount())
+ return -2;
+
+ struct savegame *saveList = NULL;
+ u32 saveCnt;
+ u32 cnt;
+
+
+ if (__Menu_RetrieveList(&saveList, &saveCnt)<0)
+ return -3;
+
+ for (cnt=0;cnttid >> 32),(u32)(save->tid & 0xFFFFFFFF)))==0)
+ return 1;
+ }
+ return 0;
+
+}
+
/*-------------------------------------------------------------
from any title deleter
diff --git a/source/wad/title.h b/source/wad/title.h
index 03a48198..a7ab8073 100644
--- a/source/wad/title.h
+++ b/source/wad/title.h
@@ -60,6 +60,9 @@ extern "C" {
char *__getTitleName(u64 titleid, int language);
s32 Uninstall_FromTitle(const u64 tid);
+
+//check for a game save present on nand based on game ID
+int CheckForSave(const char *gameID);
#ifdef __cplusplus
}