GodMode9/source/virtual/virtual.c

219 lines
7.6 KiB
C
Raw Normal View History

2016-03-21 18:29:55 +01:00
#include "virtual.h"
#include "vnand.h"
#include "vmem.h"
#include "vgame.h"
2017-02-11 16:52:36 +01:00
#include "vtickdb.h"
2017-01-13 14:20:42 +01:00
#include "vcart.h"
2016-03-21 18:29:55 +01:00
typedef struct {
char drv_letter;
u32 virtual_src;
} __attribute__((packed)) VirtualDrive;
2016-03-21 18:29:55 +01:00
2016-12-20 14:41:03 +01:00
static const VirtualDrive virtualDrives[] = { VRT_DRIVES };
2016-03-21 18:29:55 +01:00
2016-04-09 21:56:42 +02:00
u32 GetVirtualSource(const char* path) {
// check path validity
if ((strnlen(path, 16) < 2) || (path[1] != ':') || ((path[2] != '/') && (path[2] != '\0')))
return 0;
// search for virtual source
for (u32 i = 0; i < (sizeof(virtualDrives) / sizeof(VirtualDrive)); i++)
if (*path == virtualDrives[i].drv_letter) return virtualDrives[i].virtual_src;
return 0;
2016-03-21 18:29:55 +01:00
}
2016-12-20 14:41:03 +01:00
bool InitVirtualImageDrive(void) {
2017-02-11 16:52:36 +01:00
return InitVGameDrive() || InitVTickDbDrive();
2016-12-20 14:41:03 +01:00
}
2016-04-09 21:56:42 +02:00
bool CheckVirtualDrive(const char* path) {
u32 virtual_src = GetVirtualSource(path);
if (virtual_src & (VRT_EMUNAND|VRT_IMGNAND))
return CheckVNandDrive(virtual_src); // check virtual NAND drive for EmuNAND / ImgNAND
else if (virtual_src & VRT_GAME)
return CheckVGameDrive();
2017-02-11 16:52:36 +01:00
else if (virtual_src & VRT_TICKDB)
return CheckVTickDbDrive();
return virtual_src; // this is safe for SysNAND & memory
}
2016-11-28 16:30:49 +01:00
bool ReadVirtualDir(VirtualFile* vfile, VirtualDir* vdir) {
2016-12-21 00:31:21 +01:00
u32 virtual_src = vdir->flags & VRT_SOURCE;
2016-11-28 16:30:49 +01:00
bool ret = false;
2016-12-02 15:42:05 +01:00
if (virtual_src & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD)) {
2016-11-28 16:30:49 +01:00
ret = ReadVNandDir(vfile, vdir);
2016-11-15 23:06:01 +01:00
} else if (virtual_src & VRT_MEMORY) {
2016-11-28 16:30:49 +01:00
ret = ReadVMemDir(vfile, vdir);
} else if (virtual_src & VRT_GAME) {
2016-11-28 16:30:49 +01:00
ret = ReadVGameDir(vfile, vdir);
2017-02-11 16:52:36 +01:00
} else if (virtual_src & VRT_TICKDB) {
ret = ReadVTickDbDir(vfile, vdir);
2017-01-13 14:20:42 +01:00
} else if (virtual_src & VRT_CART) {
ret = ReadVCartDir(vfile, vdir);
2016-11-15 23:06:01 +01:00
}
2016-11-28 16:30:49 +01:00
vfile->flags |= virtual_src; // add source flag
return ret;
}
bool OpenVirtualRoot(VirtualDir* vdir, u32 virtual_src) {
if (virtual_src & VRT_GAME) {
if (!OpenVGameDir(vdir, NULL)) return false;
} else { // generic vdir object
vdir->offset = 0;
vdir->size = 0;
vdir->flags = 0;
}
vdir->index = -1;
vdir->flags |= VFLAG_DIR|virtual_src;
return true;
}
bool OpenVirtualDir(VirtualDir* vdir, VirtualFile* ventry) {
u32 virtual_src = ventry->flags & VRT_SOURCE;
if (ventry->flags & VFLAG_ROOT)
return OpenVirtualRoot(vdir, virtual_src);
2016-12-20 14:41:03 +01:00
if (virtual_src & VRT_GAME) {
if (!OpenVGameDir(vdir, ventry)) return false;
} else {
vdir->index = -1;
vdir->offset = ventry->offset;
vdir->size = ventry->size;
vdir->flags = ventry->flags;
}
2016-11-28 16:30:49 +01:00
vdir->flags |= virtual_src;
return true;
2016-11-15 23:06:01 +01:00
}
2016-11-15 23:34:21 +01:00
bool GetVirtualFile(VirtualFile* vfile, const char* path) {
2016-11-28 16:30:49 +01:00
char lpath[256];
strncpy(lpath, path, 256);
2016-03-21 18:29:55 +01:00
2016-11-28 16:30:49 +01:00
// get virtual source / root dir object
u32 virtual_src = 0;
2016-04-09 21:56:42 +02:00
virtual_src = GetVirtualSource(path);
2016-11-28 16:30:49 +01:00
if (!virtual_src) return false;
2016-03-21 18:29:55 +01:00
2016-11-28 16:30:49 +01:00
// set vfile as root object
memset(vfile, 0, sizeof(VirtualDir));
vfile->flags = VFLAG_ROOT|virtual_src;
if (strnlen(lpath, 256) <= 3) return true;
// tokenize / parse path
char* name;
VirtualDir vdir;
if (!OpenVirtualRoot(&vdir, virtual_src)) return false;
2016-12-21 00:31:21 +01:00
for (name = strtok(lpath + 3, "/"); name && vdir.flags; name = strtok(NULL, "/")) {
2016-12-02 16:42:39 +01:00
if (!(vdir.flags & VFLAG_LV3)) { // standard method
while (true) {
if (!ReadVirtualDir(vfile, &vdir)) return false;
if ((!(vfile->flags & VFLAG_LV3) && (strncasecmp(name, vfile->name, 32) == 0)) ||
((vfile->flags & VFLAG_LV3) && MatchVGameLv3Filename(name, vfile, 256)))
break; // entry found
}
} else { // use lv3 hashes for quicker search
if (!FindVirtualFileInLv3Dir(vfile, &vdir, name))
return false;
2016-11-28 16:30:49 +01:00
}
if (!OpenVirtualDir(&vdir, vfile))
2016-12-21 00:31:21 +01:00
vdir.flags = 0;
2016-11-15 23:06:01 +01:00
}
2016-11-28 16:30:49 +01:00
return (name == NULL); // if name is NULL, this succeeded
}
bool GetVirtualDir(VirtualDir* vdir, const char* path) {
VirtualFile vfile;
return GetVirtualFile(&vfile, path) && OpenVirtualDir(vdir, &vfile);
2016-11-15 23:34:21 +01:00
}
bool GetVirtualDirContents(DirStruct* contents, char* fpath, int fnsize, const char* pattern, bool recursive) {
2016-11-28 16:30:49 +01:00
VirtualDir vdir;
2016-11-15 23:06:01 +01:00
VirtualFile vfile;
char* fname = fpath + strnlen(fpath, fnsize - 1);
(fname++)[0] = '/';
if (!GetVirtualDir(&vdir, fpath))
2016-11-28 16:30:49 +01:00
return false; // get dir reader object
while ((contents->n_entries < MAX_DIR_ENTRIES) && (ReadVirtualDir(&vfile, &vdir))) {
2016-11-15 23:06:01 +01:00
DirEntry* entry = &(contents->entry[contents->n_entries]);
char name[256];
GetVirtualFilename(name, &vfile, 256);
strncpy(fname, name, (fnsize - 1) - (fname - fpath));
if (!pattern || MatchName(pattern, fname)) {
strncpy(entry->path, fpath, 256);
entry->name = entry->path + (fname - fpath);
entry->size = vfile.size;
entry->type = (vfile.flags & VFLAG_DIR) ? T_DIR : T_FILE;
entry->marked = 0;
if (contents->n_entries >= MAX_DIR_ENTRIES)
break; // Too many entries, still okay
if (!recursive || (entry->type != T_DIR))
contents->n_entries++;
2016-11-30 21:01:05 +01:00
}
if (recursive && (vfile.flags & VFLAG_DIR)) {
if (!GetVirtualDirContents(contents, fpath, fnsize, pattern, recursive))
break;
}
2016-11-15 23:06:01 +01:00
}
2016-03-21 18:29:55 +01:00
2016-11-15 23:06:01 +01:00
return true; // not much we can check here
2016-03-21 18:29:55 +01:00
}
bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars) {
2016-12-02 13:26:24 +01:00
if (!(vfile->flags & VFLAG_LV3)) strncpy(name, vfile->name, n_chars);
2017-03-13 20:20:20 +01:00
else if (!GetVGameLv3Filename(name, vfile, n_chars)) return false;
return true;
}
int ReadVirtualFile(const VirtualFile* vfile, u8* buffer, u64 offset, u64 count, u32* bytes_read) {
// basic check of offset / count
if (offset >= vfile->size)
return 0;
else if ((offset + count) > vfile->size)
count = vfile->size - offset;
if (bytes_read) *bytes_read = count;
2016-04-09 21:50:50 +02:00
2016-12-02 15:42:05 +01:00
if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD)) {
return ReadVNandFile(vfile, buffer, offset, count);
} else if (vfile->flags & VRT_MEMORY) {
return ReadVMemFile(vfile, buffer, offset, count);
} else if (vfile->flags & VRT_GAME) {
return ReadVGameFile(vfile, buffer, offset, count);
2017-02-11 16:52:36 +01:00
} else if (vfile->flags & VRT_TICKDB) {
return ReadVTickDbFile(vfile, buffer, offset, count);
2017-01-13 14:20:42 +01:00
} else if (vfile->flags & VRT_CART) {
return ReadVCartFile(vfile, buffer, offset, count);
}
2016-04-09 21:50:50 +02:00
return -1;
2016-03-21 18:29:55 +01:00
}
int WriteVirtualFile(const VirtualFile* vfile, const u8* buffer, u64 offset, u64 count, u32* bytes_written) {
// basic check of offset / count
if (offset >= vfile->size)
return 0;
else if ((offset + count) > vfile->size)
count = vfile->size - offset;
if (bytes_written) *bytes_written = count;
2016-04-09 21:50:50 +02:00
if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) {
return WriteVNandFile(vfile, buffer, offset, count);
} else if (vfile->flags & VRT_MEMORY) {
return WriteVMemFile(vfile, buffer, offset, count);
2017-02-11 16:52:36 +01:00
} // no write support for virtual game / tickdb / cart files
2016-04-09 21:50:50 +02:00
return -1;
2016-03-21 18:29:55 +01:00
}
2017-01-17 23:24:46 +01:00
u64 GetVirtualDriveSize(const char* path) {
u32 virtual_src = GetVirtualSource(path);
if (virtual_src & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND))
return GetVNandDriveSize(virtual_src);
else if (virtual_src & VRT_GAME)
return GetVGameDriveSize();
2017-02-11 16:52:36 +01:00
else if (virtual_src & VRT_TICKDB)
return GetVTickDbDriveSize();
2017-01-17 23:24:46 +01:00
else if (virtual_src & VRT_CART)
return GetVCartDriveSize();
return 0;
}