mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-25 20:56:53 +01:00
Added stuff to make it even more noob-proof.
Made function to check if a game has save data on the Wii nand. This can be used to allow/not allow booting certain alt dols. So far it is only called before 1 game, and it seems to work fine without issue.
This commit is contained in:
parent
9393c7f87e
commit
ef30d9c6d9
File diff suppressed because one or more lines are too long
@ -698,7 +698,7 @@ int MenuDiscList() {
|
||||
mainWindow->Append(&w);
|
||||
|
||||
ResumeGui();
|
||||
|
||||
|
||||
while (menu == MENU_NONE) {
|
||||
|
||||
if (idiotFlag==1) {
|
||||
|
@ -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) {
|
||||
|
494
source/wad/isfs.c
Normal file
494
source/wad/isfs.c
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
|
||||
libisfs -- a NAND filesystem devoptab library for the Wii
|
||||
|
||||
Copyright (C) 2008 Joseph Jordan <joe.ftpii@psychlaw.com.au>
|
||||
Copyright (C) 2009 Waninkoko <waninkoko@gmail.com>
|
||||
|
||||
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 <errno.h>
|
||||
#include <ogc/isfs.h>
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
#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;
|
||||
}
|
37
source/wad/isfs.h
Normal file
37
source/wad/isfs.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
|
||||
libisfs -- a NAND filesystem devoptab library for the Wii
|
||||
|
||||
Copyright (C) 2008 Joseph Jordan <joe.ftpii@psychlaw.com.au>
|
||||
|
||||
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 <ogc/isfs.h>
|
||||
|
||||
#define ISFS_MAXPATHLEN (ISFS_MAXPATH + 1)
|
||||
|
||||
bool ISFS_Mount();
|
||||
bool ISFS_Unmount();
|
||||
|
||||
#endif /* _LIBISFS_H_ */
|
||||
|
@ -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;cnt<saveCnt;cnt++)
|
||||
{
|
||||
struct savegame *save = &saveList[cnt];
|
||||
if (strcmp(gameID,titleText((u32)(save->tid >> 32),(u32)(save->tid & 0xFFFFFFFF)))==0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------
|
||||
from any title deleter
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user