mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Improved virtual directory handling
This commit is contained in:
parent
525b5b8810
commit
924dd8216e
58
source/dir.c
Normal file
58
source/dir.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "dir.h"
|
||||||
|
|
||||||
|
void DirEntryCpy(DirEntry* dest, const DirEntry* orig) {
|
||||||
|
memcpy(dest, orig, sizeof(DirEntry));
|
||||||
|
dest->name = dest->path + (orig->name - orig->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortDirStruct(DirStruct* contents) {
|
||||||
|
for (u32 s = 0; s < contents->n_entries; s++) {
|
||||||
|
DirEntry* cmp0 = &(contents->entry[s]);
|
||||||
|
DirEntry* min0 = cmp0;
|
||||||
|
if (cmp0->type == T_DOTDOT) continue;
|
||||||
|
for (u32 c = s + 1; c < contents->n_entries; c++) {
|
||||||
|
DirEntry* cmp1 = &(contents->entry[c]);
|
||||||
|
if (min0->type != cmp1->type) {
|
||||||
|
if (min0->type > cmp1->type)
|
||||||
|
min0 = cmp1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncasecmp(min0->name, cmp1->name, 256) > 0)
|
||||||
|
min0 = cmp1;
|
||||||
|
}
|
||||||
|
if (min0 != cmp0) {
|
||||||
|
DirEntry swap; // swap entries and fix names
|
||||||
|
DirEntryCpy(&swap, cmp0);
|
||||||
|
DirEntryCpy(cmp0, min0);
|
||||||
|
DirEntryCpy(min0, &swap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
|
||||||
|
bool MatchName(const char *pattern, const char *path) {
|
||||||
|
// handling non asterisk chars
|
||||||
|
for (; *pattern != '*'; pattern++, path++) {
|
||||||
|
if ((*pattern == '\0') && (*path == '\0')) {
|
||||||
|
return true; // end reached simultaneously, match found
|
||||||
|
} else if ((*pattern == '\0') || (*path == '\0')) {
|
||||||
|
return false; // end reached on only one, failure
|
||||||
|
} else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path))) {
|
||||||
|
return false; // chars don't match, failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handling the asterisk (matches one or more chars in path)
|
||||||
|
if ((*(pattern+1) == '?') || (*(pattern+1) == '*')) {
|
||||||
|
return false; // stupid user shenanigans, failure
|
||||||
|
} else if (*path == '\0') {
|
||||||
|
return false; // asterisk, but end reached on path, failure
|
||||||
|
} else if (*(pattern+1) == '\0') {
|
||||||
|
return true; // nothing after the asterisk, match found
|
||||||
|
} else { // we couldn't really go without recursion here
|
||||||
|
for (path++; *path != '\0'; path++) {
|
||||||
|
if (MatchName(pattern + 1, path)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
29
source/dir.h
Normal file
29
source/dir.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define MAX_DIR_ENTRIES 1024
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
T_ROOT,
|
||||||
|
T_DIR,
|
||||||
|
T_FILE,
|
||||||
|
T_DOTDOT
|
||||||
|
} EntryType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* name; // should point to the correct portion of the path
|
||||||
|
char path[256];
|
||||||
|
u64 size;
|
||||||
|
EntryType type;
|
||||||
|
u8 marked;
|
||||||
|
} DirEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 n_entries;
|
||||||
|
DirEntry entry[MAX_DIR_ENTRIES];
|
||||||
|
} DirStruct;
|
||||||
|
|
||||||
|
void DirEntryCpy(DirEntry* dest, const DirEntry* orig);
|
||||||
|
void SortDirStruct(DirStruct* contents);
|
||||||
|
bool MatchName(const char *pattern, const char *path);
|
81
source/fs.c
81
source/fs.c
@ -1029,63 +1029,6 @@ void CreateScreenshot() {
|
|||||||
FileSetData(filename, MAIN_BUFFER, 54 + (400 * 240 * 3 * 2), 0, true);
|
FileSetData(filename, MAIN_BUFFER, 54 + (400 * 240 * 3 * 2), 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirEntryCpy(DirEntry* dest, const DirEntry* orig) {
|
|
||||||
memcpy(dest, orig, sizeof(DirEntry));
|
|
||||||
dest->name = dest->path + (orig->name - orig->path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortDirStruct(DirStruct* contents) {
|
|
||||||
for (u32 s = 0; s < contents->n_entries; s++) {
|
|
||||||
DirEntry* cmp0 = &(contents->entry[s]);
|
|
||||||
DirEntry* min0 = cmp0;
|
|
||||||
if (cmp0->type == T_DOTDOT) continue;
|
|
||||||
for (u32 c = s + 1; c < contents->n_entries; c++) {
|
|
||||||
DirEntry* cmp1 = &(contents->entry[c]);
|
|
||||||
if (min0->type != cmp1->type) {
|
|
||||||
if (min0->type > cmp1->type)
|
|
||||||
min0 = cmp1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (strncasecmp(min0->name, cmp1->name, 256) > 0)
|
|
||||||
min0 = cmp1;
|
|
||||||
}
|
|
||||||
if (min0 != cmp0) {
|
|
||||||
DirEntry swap; // swap entries and fix names
|
|
||||||
DirEntryCpy(&swap, cmp0);
|
|
||||||
DirEntryCpy(cmp0, min0);
|
|
||||||
DirEntryCpy(min0, &swap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
|
|
||||||
bool MatchName(const char *pattern, const char *path) {
|
|
||||||
// handling non asterisk chars
|
|
||||||
for (; *pattern != '*'; pattern++, path++) {
|
|
||||||
if ((*pattern == '\0') && (*path == '\0')) {
|
|
||||||
return true; // end reached simultaneously, match found
|
|
||||||
} else if ((*pattern == '\0') || (*path == '\0')) {
|
|
||||||
return false; // end reached on only one, failure
|
|
||||||
} else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path))) {
|
|
||||||
return false; // chars don't match, failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// handling the asterisk (matches one or more chars in path)
|
|
||||||
if ((*(pattern+1) == '?') || (*(pattern+1) == '*')) {
|
|
||||||
return false; // stupid user shenanigans, failure
|
|
||||||
} else if (*path == '\0') {
|
|
||||||
return false; // asterisk, but end reached on path, failure
|
|
||||||
} else if (*(pattern+1) == '\0') {
|
|
||||||
return true; // nothing after the asterisk, match found
|
|
||||||
} else { // we couldn't really go without recursion here
|
|
||||||
for (path++; *path != '\0'; path++) {
|
|
||||||
if (MatchName(pattern + 1, path)) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetRootDirContentsWorker(DirStruct* contents) {
|
bool GetRootDirContentsWorker(DirStruct* contents) {
|
||||||
static const char* drvname[] = {
|
static const char* drvname[] = {
|
||||||
"SDCARD",
|
"SDCARD",
|
||||||
@ -1103,7 +1046,7 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
|
|||||||
u32 n_entries = 0;
|
u32 n_entries = 0;
|
||||||
|
|
||||||
// virtual root objects hacked in
|
// virtual root objects hacked in
|
||||||
for (u32 pdrv = 0; (pdrv < NORM_FS+VIRT_FS) && (n_entries < MAX_ENTRIES); pdrv++) {
|
for (u32 pdrv = 0; (pdrv < NORM_FS+VIRT_FS) && (n_entries < MAX_DIR_ENTRIES); pdrv++) {
|
||||||
DirEntry* entry = &(contents->entry[n_entries]);
|
DirEntry* entry = &(contents->entry[n_entries]);
|
||||||
if (!DriveType(drvnum[pdrv])) continue; // drive not available
|
if (!DriveType(drvnum[pdrv])) continue; // drive not available
|
||||||
memset(entry->path, 0x00, 64);
|
memset(entry->path, 0x00, 64);
|
||||||
@ -1124,24 +1067,6 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
|
|||||||
return contents->n_entries;
|
return contents->n_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetVirtualDirContentsWorker(DirStruct* contents, const char* path, const char* pattern) {
|
|
||||||
if (strchr(path, '/')) return false; // only top level paths
|
|
||||||
for (u32 n = 0; (n < virtualFileList_size) && (contents->n_entries < MAX_ENTRIES); n++) {
|
|
||||||
VirtualFile vfile;
|
|
||||||
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
|
||||||
if (pattern && !MatchName(pattern, virtualFileList[n])) continue;
|
|
||||||
snprintf(entry->path, 256, "%s/%s", path, virtualFileList[n]);
|
|
||||||
if (!FindVirtualFile(&vfile, entry->path, 0)) continue;
|
|
||||||
entry->name = entry->path + strnlen(path, 256) + 1;
|
|
||||||
entry->size = vfile.size;
|
|
||||||
entry->type = T_FILE;
|
|
||||||
entry->marked = 0;
|
|
||||||
contents->n_entries++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // not much we can check here
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive) {
|
bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive) {
|
||||||
DIR pdir;
|
DIR pdir;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
@ -1171,7 +1096,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch
|
|||||||
entry->size = fno.fsize;
|
entry->size = fno.fsize;
|
||||||
}
|
}
|
||||||
entry->marked = 0;
|
entry->marked = 0;
|
||||||
if (contents->n_entries >= MAX_ENTRIES) {
|
if (contents->n_entries >= MAX_DIR_ENTRIES) {
|
||||||
ret = true; // Too many entries, still okay
|
ret = true; // Too many entries, still okay
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1201,7 +1126,7 @@ void SearchDirContents(DirStruct* contents, const char* path, const char* patter
|
|||||||
contents->entry->size = 0;
|
contents->entry->size = 0;
|
||||||
contents->n_entries = 1;
|
contents->n_entries = 1;
|
||||||
if (DriveType(path) & DRV_VIRTUAL) {
|
if (DriveType(path) & DRV_VIRTUAL) {
|
||||||
if (!GetVirtualDirContentsWorker(contents, path, pattern))
|
if (!GetVirtualDirContents(contents, path, pattern))
|
||||||
contents->n_entries = 0;
|
contents->n_entries = 0;
|
||||||
} else {
|
} else {
|
||||||
char fpath[256]; // 256 is the maximum length of a full path
|
char fpath[256]; // 256 is the maximum length of a full path
|
||||||
|
28
source/fs.h
28
source/fs.h
@ -1,15 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "dir.h"
|
||||||
typedef enum {
|
|
||||||
T_ROOT,
|
|
||||||
T_DIR,
|
|
||||||
T_FILE,
|
|
||||||
T_DOTDOT
|
|
||||||
} EntryType;
|
|
||||||
|
|
||||||
#define MAX_ENTRIES 1024
|
|
||||||
|
|
||||||
// primary drive types
|
// primary drive types
|
||||||
#define DRV_UNKNOWN (0<<0)
|
#define DRV_UNKNOWN (0<<0)
|
||||||
@ -43,19 +35,6 @@ typedef enum {
|
|||||||
#define SKIP_ALL (1<<1)
|
#define SKIP_ALL (1<<1)
|
||||||
#define OVERWRITE_ALL (1<<2)
|
#define OVERWRITE_ALL (1<<2)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* name; // should point to the correct portion of the path
|
|
||||||
char path[256];
|
|
||||||
u64 size;
|
|
||||||
EntryType type;
|
|
||||||
u8 marked;
|
|
||||||
} DirEntry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u32 n_entries;
|
|
||||||
DirEntry entry[MAX_ENTRIES];
|
|
||||||
} DirStruct;
|
|
||||||
|
|
||||||
bool InitSDCardFS();
|
bool InitSDCardFS();
|
||||||
bool InitExtFS();
|
bool InitExtFS();
|
||||||
void DeinitExtFS();
|
void DeinitExtFS();
|
||||||
@ -133,8 +112,5 @@ uint64_t GetPartitionOffsetSector(const char* path);
|
|||||||
/** Function to identify the type of a drive **/
|
/** Function to identify the type of a drive **/
|
||||||
int DriveType(const char* path);
|
int DriveType(const char* path);
|
||||||
|
|
||||||
/** Check for soecial search drive **/
|
/** Check for special search drive **/
|
||||||
bool IsSearchDrive(const char* path);
|
bool IsSearchDrive(const char* path);
|
||||||
|
|
||||||
/** Helper function for copying DirEntry structs */
|
|
||||||
void DirEntryCpy(DirEntry* dest, const DirEntry* orig);
|
|
||||||
|
@ -26,8 +26,16 @@ bool CheckVirtualDrive(const char* path) {
|
|||||||
return virtual_src; // this is safe for SysNAND & memory
|
return virtual_src; // this is safe for SysNAND & memory
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size)
|
bool ReadVirtualDir(VirtualFile* vfile, u32 virtual_src) {
|
||||||
{
|
if (virtual_src & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) {
|
||||||
|
return ReadVNandDir(vfile, virtual_src);
|
||||||
|
} else if (virtual_src & VRT_MEMORY) {
|
||||||
|
return ReadVMemDir(vfile);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size) {
|
||||||
// get / fix the name
|
// get / fix the name
|
||||||
char* fname = strchr(path, '/');
|
char* fname = strchr(path, '/');
|
||||||
if (!fname) return false;
|
if (!fname) return false;
|
||||||
@ -39,17 +47,38 @@ bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size)
|
|||||||
if (!virtual_src || (fname - path != 3))
|
if (!virtual_src || (fname - path != 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// get virtual file struct from appropriate function
|
// read virtual dir, match the path / size
|
||||||
if (virtual_src & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) {
|
ReadVirtualDir(NULL, virtual_src); // reset dir reader
|
||||||
if (!FindVNandFile(vfile, virtual_src, fname, size)) return false;
|
while (ReadVirtualDir(vfile, virtual_src)) {
|
||||||
} else if (virtual_src & VRT_MEMORY) {
|
vfile->flags |= virtual_src; // add source flag
|
||||||
if (!FindVMemFile(vfile, fname, size)) return false;
|
if (((strncasecmp(fname, vfile->name, 32) == 0) ||
|
||||||
} else return false;
|
(size && (vfile->size == size)))) // search by size should be a last resort solution
|
||||||
|
return true; // file found
|
||||||
|
}
|
||||||
|
|
||||||
// add the virtual source to the virtual file flags
|
// failed if arriving
|
||||||
vfile->flags |= virtual_src;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetVirtualDirContents(DirStruct* contents, const char* path, const char* pattern) {
|
||||||
|
u32 virtual_src = GetVirtualSource(path);
|
||||||
|
if (!virtual_src) return false; // not a virtual path
|
||||||
|
if (strchr(path, '/')) return false; // only top level paths
|
||||||
|
|
||||||
return true;
|
VirtualFile vfile;
|
||||||
|
ReadVirtualDir(NULL, virtual_src); // reset dir reader
|
||||||
|
while ((contents->n_entries < MAX_DIR_ENTRIES) && (ReadVirtualDir(&vfile, virtual_src))) {
|
||||||
|
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
||||||
|
if (pattern && !MatchName(pattern, vfile.name)) continue;
|
||||||
|
snprintf(entry->path, 256, "%s/%s", path, vfile.name);
|
||||||
|
entry->name = entry->path + strnlen(path, 256) + 1;
|
||||||
|
entry->size = vfile.size;
|
||||||
|
entry->type = T_FILE;
|
||||||
|
entry->marked = 0;
|
||||||
|
contents->n_entries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // not much we can check here
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read)
|
int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "dir.h"
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
|
|
||||||
#define VRT_SYSNAND NAND_SYSNAND
|
#define VRT_SYSNAND NAND_SYSNAND
|
||||||
@ -10,14 +11,6 @@
|
|||||||
|
|
||||||
#define VFLAG_A9LH_AREA (1<<20)
|
#define VFLAG_A9LH_AREA (1<<20)
|
||||||
|
|
||||||
static const char* virtualFileList[] = { // must have a match in virtualFileTemplates[]
|
|
||||||
"twln.bin", "twlp.bin", "agbsave.bin", "firm0.bin", "firm1.bin", "ctrnand_fat.bin",
|
|
||||||
"ctrnand_full.bin", "nand.bin", "nand_minsize.bin", "nand_hdr.bin", "twlmbr.bin", "sector0x96.bin",
|
|
||||||
"itcm.mem", "arm9.mem", "arm9ext.mem", "vram.mem", "dsp.mem", "axiwram.mem",
|
|
||||||
"fcram.mem", "fcramext.mem", "dtcm.mem", "bootrom_unp.mem"
|
|
||||||
};
|
|
||||||
static const u32 virtualFileList_size = sizeof(virtualFileList) / sizeof(char*);
|
|
||||||
|
|
||||||
// virtual file flag (subject to change):
|
// virtual file flag (subject to change):
|
||||||
// bits 0...9 : reserved for NAND virtual sources and info
|
// bits 0...9 : reserved for NAND virtual sources and info
|
||||||
// bits 10...19: reserved for other virtual sources
|
// bits 10...19: reserved for other virtual sources
|
||||||
@ -34,5 +27,6 @@ typedef struct {
|
|||||||
u32 GetVirtualSource(const char* path);
|
u32 GetVirtualSource(const char* path);
|
||||||
bool CheckVirtualDrive(const char* path);
|
bool CheckVirtualDrive(const char* path);
|
||||||
bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size);
|
bool FindVirtualFile(VirtualFile* vfile, const char* path, u32 size);
|
||||||
|
bool GetVirtualDirContents(DirStruct* contents, const char* path, const char* pattern);
|
||||||
int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read);
|
int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count, u32* bytes_read);
|
||||||
int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written);
|
int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count, u32* bytes_written);
|
||||||
|
@ -19,27 +19,30 @@ static const VirtualFile vMemFileTemplates[] = {
|
|||||||
{ "bootrom_unp.mem" , 0xFFFF0000, 0x00008000, 0xFF, 0 }
|
{ "bootrom_unp.mem" , 0xFFFF0000, 0x00008000, 0xFF, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FindVMemFile(VirtualFile* vfile, const char* name, u32 size) {
|
bool ReadVMemDir(VirtualFile* vfile) {
|
||||||
// parse the template list, get the correct one
|
static int num = -1;
|
||||||
u32 n_templates = sizeof(vMemFileTemplates) / sizeof(VirtualFile);
|
int n_templates = sizeof(vMemFileTemplates) / sizeof(VirtualFile);
|
||||||
const VirtualFile* curr_template = NULL;
|
const VirtualFile* templates = vMemFileTemplates;
|
||||||
for (u32 i = 0; i < n_templates; i++) {
|
|
||||||
curr_template = &vMemFileTemplates[i];
|
if (!vfile) { // NULL pointer -> reset dir reader / internal number
|
||||||
if (((strncasecmp(name, curr_template->name, 32) == 0) ||
|
num = -1;
|
||||||
(size && (curr_template->size == size)))) // search by size should be a last resort solution
|
return true;
|
||||||
break;
|
|
||||||
curr_template = NULL;
|
|
||||||
}
|
}
|
||||||
if (!curr_template) return false;
|
|
||||||
|
|
||||||
// copy current template to vfile
|
while (++num < n_templates) {
|
||||||
memcpy(vfile, curr_template, sizeof(VirtualFile));
|
// copy current template to vfile
|
||||||
|
memcpy(vfile, templates + num, sizeof(VirtualFile));
|
||||||
|
|
||||||
|
// process special flag
|
||||||
|
if ((vfile->flags & VFLAG_N3DS_ONLY) && (GetUnitPlatform() != PLATFORM_N3DS))
|
||||||
|
return false; // this is not on O3DS consoles
|
||||||
|
|
||||||
|
// found if arriving here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (num >= n_templates) return false;
|
||||||
|
|
||||||
// process special flag
|
return false;
|
||||||
if ((vfile->flags & VFLAG_N3DS_ONLY) && (GetUnitPlatform() != PLATFORM_N3DS))
|
|
||||||
return false; // this is not on O3DS consoles
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
|
int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "virtual.h"
|
#include "virtual.h"
|
||||||
|
|
||||||
bool FindVMemFile(VirtualFile* vfile, const char* name, u32 size);
|
bool ReadVMemDir(VirtualFile* vfile);
|
||||||
int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count);
|
int ReadVMemFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count);
|
||||||
int WriteVMemFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);
|
int WriteVMemFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);
|
||||||
|
@ -34,41 +34,46 @@ bool CheckVNandDrive(u32 nand_src) {
|
|||||||
return GetNandSizeSectors(nand_src);
|
return GetNandSizeSectors(nand_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindVNandFile(VirtualFile* vfile, u32 nand_src, const char* name, u32 size) {
|
bool ReadVNandDir(VirtualFile* vfile, u32 nand_src) {
|
||||||
// get virtual type (O3DS/N3DS/NO3DS)
|
static int num = -1;
|
||||||
u32 virtual_type = CheckNandType(nand_src);
|
int n_templates = sizeof(vNandFileTemplates) / sizeof(VirtualFile);
|
||||||
// workaround if CheckNandType() comes up with no result (empty EmuNAND)
|
const VirtualFile* templates = vNandFileTemplates;
|
||||||
if (!virtual_type) virtual_type = (GetUnitPlatform() == PLATFORM_3DS) ? NAND_TYPE_O3DS : NAND_TYPE_N3DS;
|
|
||||||
|
|
||||||
// parse the template list, get the correct one
|
if (!vfile) { // NULL pointer -> reset dir reader / internal number
|
||||||
u32 n_templates = sizeof(vNandFileTemplates) / sizeof(VirtualFile);
|
num = -1;
|
||||||
const VirtualFile* curr_template = NULL;
|
return true;
|
||||||
for (u32 i = 0; i < n_templates; i++) {
|
|
||||||
curr_template = &vNandFileTemplates[i];
|
|
||||||
if ((curr_template->flags & virtual_type) && ((strncasecmp(name, curr_template->name, 32) == 0) ||
|
|
||||||
(size && (curr_template->size == size)))) // search by size should be a last resort solution
|
|
||||||
break;
|
|
||||||
curr_template = NULL;
|
|
||||||
}
|
|
||||||
if (!curr_template) return false;
|
|
||||||
|
|
||||||
// copy current template to vfile
|
|
||||||
memcpy(vfile, curr_template, sizeof(VirtualFile));
|
|
||||||
|
|
||||||
// process special flags
|
|
||||||
if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto())
|
|
||||||
return false; // keyslot 0x05 not properly set up
|
|
||||||
if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto())
|
|
||||||
return false; // sector 0x96 crypto not set up
|
|
||||||
if (!(nand_src & VRT_SYSNAND) || (*(vu32*) 0x101401C0))
|
|
||||||
vfile->flags &= ~VFLAG_A9LH_AREA; // flag is meaningless outside of A9LH / SysNAND
|
|
||||||
if (vfile->flags & VFLAG_NAND_SIZE) {
|
|
||||||
if ((nand_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src)))
|
|
||||||
return false; // EmuNAND/ImgNAND is too small
|
|
||||||
vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
while (++num < n_templates) {
|
||||||
|
// get NAND type (O3DS/N3DS/NO3DS), workaround for empty EmuNAND
|
||||||
|
u32 nand_type = CheckNandType(nand_src);
|
||||||
|
if (!nand_type) nand_type = (GetUnitPlatform() == PLATFORM_3DS) ? NAND_TYPE_O3DS : NAND_TYPE_N3DS;
|
||||||
|
|
||||||
|
// copy current template to vfile
|
||||||
|
memcpy(vfile, templates + num, sizeof(VirtualFile));
|
||||||
|
|
||||||
|
// process / check special flags
|
||||||
|
if (!(vfile->flags & nand_type))
|
||||||
|
continue; // virtual file has wrong NAND type
|
||||||
|
if ((vfile->keyslot == 0x05) && !CheckSlot0x05Crypto())
|
||||||
|
continue; // keyslot 0x05 not properly set up
|
||||||
|
if ((vfile->flags & VFLAG_NEEDS_OTP) && !CheckSector0x96Crypto())
|
||||||
|
return false; // sector 0x96 crypto not set up
|
||||||
|
if (!(nand_src & VRT_SYSNAND) || (*(vu32*) 0x101401C0))
|
||||||
|
vfile->flags &= ~VFLAG_A9LH_AREA; // flag is meaningless outside of A9LH / SysNAND
|
||||||
|
if (vfile->flags & VFLAG_NAND_SIZE) {
|
||||||
|
if ((nand_src != NAND_SYSNAND) && (GetNandSizeSectors(NAND_SYSNAND) != GetNandSizeSectors(nand_src)))
|
||||||
|
continue; // EmuNAND/ImgNAND is too small
|
||||||
|
vfile->size = GetNandSizeSectors(NAND_SYSNAND) * 0x200;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found if arriving here
|
||||||
|
vfile->flags |= nand_src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (num >= n_templates) return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
|
int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
#include "virtual.h"
|
#include "virtual.h"
|
||||||
|
|
||||||
bool CheckVNandDrive(u32 nand_src);
|
bool CheckVNandDrive(u32 nand_src);
|
||||||
bool FindVNandFile(VirtualFile* vfile, u32 nand_src, const char* name, u32 size);
|
bool ReadVNandDir(VirtualFile* vfile, u32 nand_src);
|
||||||
int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count);
|
int ReadVNandFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count);
|
||||||
int WriteVNandFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);
|
int WriteVNandFile(const VirtualFile* vfile, const u8* buffer, u32 offset, u32 count);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user