forked from Mirror/GodMode9
implement vdisadiff
This commit is contained in:
parent
1026a60597
commit
f8b9332728
@ -13,7 +13,7 @@
|
||||
u64 IdentifyFileType(const char* path) {
|
||||
const u8 romfs_magic[] = { ROMFS_MAGIC };
|
||||
const u8 diff_magic[] = { DIFF_MAGIC };
|
||||
// const u8 disa_magic[] = { DISA_MAGIC };
|
||||
const u8 disa_magic[] = { DISA_MAGIC };
|
||||
const u8 tickdb_magic[] = { TICKDB_MAGIC };
|
||||
const u8 smdh_magic[] = { SMDH_MAGIC };
|
||||
const u8 threedsx_magic[] = { THREEDSX_EXT_MAGIC };
|
||||
@ -98,6 +98,8 @@ u64 IdentifyFileType(const char* path) {
|
||||
if (memcmp(header + 0x100, tickdb_magic, sizeof(tickdb_magic)) == 0) // ticket.db file
|
||||
return SYS_DIFF | SYS_TICKDB; // ticket.db
|
||||
return SYS_DIFF;
|
||||
} else if (memcmp(header + 0x100, disa_magic, sizeof(disa_magic)) == 0) { // DISA file
|
||||
return SYS_DISA;
|
||||
} else if (memcmp(header, smdh_magic, sizeof(smdh_magic)) == 0) {
|
||||
return GAME_SMDH; // SMDH file
|
||||
} else if (ValidateTwlHeader((TwlHeader*) data) == 0) {
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define GAME_TAD (1ULL<<16)
|
||||
#define SYS_FIRM (1ULL<<17)
|
||||
#define SYS_DIFF (1ULL<<18)
|
||||
#define SYS_DISA (1ULL<<19) // not yet used
|
||||
#define SYS_DISA (1ULL<<19)
|
||||
#define SYS_AGBSAVE (1ULL<<20)
|
||||
#define SYS_TICKDB (1ULL<<21)
|
||||
#define BIN_NCCHNFO (1ULL<<22)
|
||||
@ -44,7 +44,7 @@
|
||||
#define FLAG_NUSCDN (1ULL<<62)
|
||||
#define FLAG_CXI (1ULL<<63)
|
||||
|
||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|GAME_NDS|GAME_TAD|SYS_FIRM|SYS_TICKDB|BIN_KEYDB))
|
||||
#define FTYPE_MOUNTABLE(tp) (tp&(IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|GAME_NDS|GAME_TAD|SYS_FIRM|SYS_DIFF|SYS_DISA|SYS_TICKDB|BIN_KEYDB))
|
||||
#define FTYPE_VERIFICABLE(tp) (tp&(IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|GAME_BOSS|SYS_FIRM))
|
||||
#define FTYPE_DECRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|GAME_NUSCDN|SYS_FIRM|BIN_KEYDB))
|
||||
#define FTYPE_ENCRYPTABLE(tp) (tp&(GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_BOSS|BIN_KEYDB))
|
||||
|
@ -46,7 +46,7 @@ int DriveType(const char* path) {
|
||||
type = DRV_VIRTUAL | DRV_SYSNAND;
|
||||
} else if (vsrc == VRT_EMUNAND) {
|
||||
type = DRV_VIRTUAL | DRV_EMUNAND;
|
||||
} else if (vsrc == VRT_IMGNAND) {
|
||||
} else if ((vsrc == VRT_IMGNAND) || (vsrc == VRT_DISADIFF)) {
|
||||
type = DRV_VIRTUAL | DRV_IMAGE;
|
||||
} else if (vsrc == VRT_XORPAD) {
|
||||
type = DRV_VIRTUAL | DRV_XORPAD;
|
||||
|
@ -37,13 +37,13 @@
|
||||
"EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "EMUNAND SD", "EMUNAND VIRTUAL", \
|
||||
"IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", "IMGNAND VIRTUAL", \
|
||||
"GAMECART", \
|
||||
"GAME IMAGE", "AESKEYDB IMAGE", "TICKET.DB IMAGE", \
|
||||
"GAME IMAGE", "AESKEYDB IMAGE", "TICKET.DB IMAGE", "DISA/DIFF IMAGE", \
|
||||
"MEMORY VIRTUAL", \
|
||||
"VRAM VIRTUAL", \
|
||||
"LAST SEARCH" \
|
||||
|
||||
#define FS_DRVNUM \
|
||||
"0:", "1:", "2:", "3:", "A:", "S:", "4:", "5:", "6:", "B:", "E:", "7:", "8:", "9:", "I:", "C:", "G:", "K:", "T:", "M:", "V:", "Z:"
|
||||
"0:", "1:", "2:", "3:", "A:", "S:", "4:", "5:", "6:", "B:", "E:", "7:", "8:", "9:", "I:", "C:", "G:", "K:", "T:", "D:", "M:", "V:", "Z:"
|
||||
|
||||
/** Function to identify the type of a drive **/
|
||||
int DriveType(const char* path);
|
||||
|
@ -47,6 +47,8 @@ bool InitImgFS(const char* path) {
|
||||
snprintf(fsname, 7, "%lu:", drv_i);
|
||||
if (!(DriveType(fsname)&DRV_IMAGE)) break;
|
||||
}
|
||||
// deinit virtual filesystem
|
||||
DeinitVirtualImageDrive();
|
||||
// deinit image filesystem
|
||||
DismountDriveType(DRV_IMAGE);
|
||||
// (re)mount image, done if path == NULL
|
||||
|
@ -1103,7 +1103,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
bool transferable = (FTYPE_TRANSFERABLE(filetype) && IS_UNLOCKED && (drvtype & DRV_FAT));
|
||||
bool hsinjectable = (FTYPE_HASCODE(filetype));
|
||||
bool extrcodeable = (FTYPE_HASCODE(filetype));
|
||||
bool extrdiffable = (FTYPE_ISDISADIFF(filetype));
|
||||
bool restorable = (FTYPE_RESTORABLE(filetype) && IS_UNLOCKED && !(drvtype & DRV_SYSNAND));
|
||||
bool ebackupable = (FTYPE_EBACKUP(filetype));
|
||||
bool ncsdfixable = (FTYPE_NCSDFIXABLE(filetype));
|
||||
@ -1128,7 +1127,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
extrcodeable = (FTYPE_HASCODE(filetype_cxi));
|
||||
}
|
||||
|
||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || extrdiffable || keyinitable || keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || agbimportable;
|
||||
bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || agbimportable;
|
||||
|
||||
char pathstr[32+1];
|
||||
TruncateString(pathstr, file_path, 32, 8);
|
||||
@ -1173,7 +1172,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
(filetype & SYS_FIRM ) ? "FIRM image options..." :
|
||||
(filetype & SYS_AGBSAVE)? (agbimportable) ? "AGBSAVE options..." : "Dump GBA VC save" :
|
||||
(filetype & SYS_TICKDB) ? "Ticket.db options..." :
|
||||
(filetype & SYS_DIFF) ? "Extract DIFF data" :
|
||||
(filetype & SYS_DIFF) ? "Mount as DIFF image" :
|
||||
(filetype & SYS_DISA) ? "Mount as DISA image" :
|
||||
(filetype & BIN_TIKDB) ? "Titlekey options..." :
|
||||
(filetype & BIN_KEYDB) ? "AESkeydb options..." :
|
||||
(filetype & BIN_LEGKEY) ? "Build " KEYDB_NAME :
|
||||
@ -1316,7 +1316,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
int ctrtransfer = (transferable) ? ++n_opt : -1;
|
||||
int hsinject = (hsinjectable) ? ++n_opt : -1;
|
||||
int extrcode = (extrcodeable) ? ++n_opt : -1;
|
||||
int extrdiff = (extrdiffable) ? ++n_opt : -1;
|
||||
int trim = (trimable) ? ++n_opt : -1;
|
||||
int rename = (renamable) ? ++n_opt : -1;
|
||||
int xorpad = (xorpadable) ? ++n_opt : -1;
|
||||
@ -1353,7 +1352,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)";
|
||||
if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)";
|
||||
if (extrcode > 0) optionstr[extrcode-1] = "Extract " EXEFS_CODE_NAME;
|
||||
if (extrdiff > 0) optionstr[extrdiff-1] = "Extract DIFF data";
|
||||
if (keyinit > 0) optionstr[keyinit-1] = "Init " KEYDB_NAME;
|
||||
if (keyinstall > 0) optionstr[keyinstall-1] = "Install " KEYDB_NAME;
|
||||
if (install > 0) optionstr[install-1] = "Install FIRM";
|
||||
@ -1369,7 +1367,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
user_select = (n_opt <= 1) ? n_opt : (int) ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ?
|
||||
"%s\n%(%lu files selected)" : "%s", pathstr, n_marked);
|
||||
if (user_select == mount) { // -> mount file as image
|
||||
const char* mnt_drv_paths[] = { "7:", "G:", "K:", "T:", "I:" }; // maybe move that to fsdrive.h
|
||||
const char* mnt_drv_paths[] = { "7:", "G:", "K:", "T:", "I:", "D:" }; // maybe move that to fsdrive.h
|
||||
if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE))
|
||||
clipboard->n_entries = 0; // remove last mounted image clipboard entries
|
||||
InitImgFS((filetype & GAME_TMD) ? cxi_path : file_path);
|
||||
@ -1741,7 +1739,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if ((user_select == extrcode) || (user_select == extrdiff)) { // -> Extract .code or DIFF partition
|
||||
else if (user_select == extrcode) { // -> Extract .code
|
||||
if ((n_marked > 1) && ShowPrompt(true, "Try to extract all %lu selected files?", n_marked)) {
|
||||
u32 n_success = 0;
|
||||
u32 n_other = 0;
|
||||
@ -1756,10 +1754,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
continue;
|
||||
}
|
||||
DrawDirContents(current_dir, (*cursor = i), scroll);
|
||||
if (filetype & SYS_DIFF) {
|
||||
if (ExtractDataFromDisaDiff(path) == 0) n_success++;
|
||||
else continue;
|
||||
} else if (filetype & GAME_TMD) {
|
||||
if (filetype & GAME_TMD) {
|
||||
char cxi_pathl[256] = { 0 };
|
||||
if ((GetTmdContentPath(cxi_pathl, path) == 0) && PathExist(cxi_pathl) &&
|
||||
(ExtractCodeFromCxiFile(cxi_pathl, NULL, NULL) == 0)) {
|
||||
@ -1774,11 +1769,6 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
|
||||
if (n_other) ShowPrompt(false, "%lu/%lu files extracted ok\n%lu/%lu not of same type",
|
||||
n_success, n_marked, n_other, n_marked);
|
||||
else ShowPrompt(false, "%lu/%lu files extracted ok", n_success, n_marked);
|
||||
} else if (filetype & SYS_DIFF) {
|
||||
ShowString("%s\nExtracting data, please wait...", pathstr);
|
||||
if (ExtractDataFromDisaDiff(file_path) == 0) {
|
||||
ShowPrompt(false, "%s\ndata extracted to " OUTPUT_PATH, pathstr);
|
||||
} else ShowPrompt(false, "%s\ndata extract failed", pathstr);
|
||||
} else {
|
||||
char extstr[8] = { 0 };
|
||||
ShowString("%s\nExtracting .code, please wait...", pathstr);
|
||||
|
@ -1825,66 +1825,6 @@ u32 CompressCode(const char* path, const char* path_out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 ExtractDataFromDisaDiff(const char* path) {
|
||||
char dest[256];
|
||||
u32 ret = 0;
|
||||
|
||||
// build output name
|
||||
char* name = strrchr(path, '/');
|
||||
if (!name) return 1;
|
||||
snprintf(dest, 256, "%s/%s", OUTPUT_PATH, ++name);
|
||||
|
||||
// replace extension
|
||||
char* dot = strrchr(dest, '.');
|
||||
if (!dot || (dot < strrchr(dest, '/')))
|
||||
dot = dest + strnlen(dest, 256);
|
||||
snprintf(dot, 16, ".%s", "bin");
|
||||
|
||||
if (!CheckWritePermissions(dest)) return 1;
|
||||
|
||||
// prepare DISA / DIFF read
|
||||
DisaDiffRWInfo info;
|
||||
u8* lvl2_cache = NULL;
|
||||
if ((GetDisaDiffRWInfo(path, &info, false) != 0) ||
|
||||
!(lvl2_cache = (u8*) malloc(info.size_dpfs_lvl2)) ||
|
||||
(BuildDisaDiffDpfsLvl2Cache(path, &info, lvl2_cache, info.size_dpfs_lvl2) != 0)) {
|
||||
if (lvl2_cache) free(lvl2_cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// prepare buffer
|
||||
u8* buffer = (u8*) malloc(STD_BUFFER_SIZE);
|
||||
if (!buffer) {
|
||||
free(lvl2_cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// open output file
|
||||
FIL file;
|
||||
if (fvx_open(&file, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||
free(buffer);
|
||||
free(lvl2_cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// actually extract the partition
|
||||
u32 total_size = 0;
|
||||
for (u32 i = 0; ret == 0; i += STD_BUFFER_SIZE) {
|
||||
UINT btr;
|
||||
u32 add_size = ReadDisaDiffIvfcLvl4(path, &info, i, STD_BUFFER_SIZE, buffer);
|
||||
if (!add_size) break;
|
||||
if ((fvx_write(&file, buffer, add_size, &btr) != FR_OK) || (btr != add_size)) ret = 1;
|
||||
total_size += add_size;
|
||||
}
|
||||
|
||||
// wrap it up
|
||||
if (!total_size) ret = 1;
|
||||
free(buffer);
|
||||
free(lvl2_cache);
|
||||
fvx_close(&file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 GetGameFileTrimmedSize(const char* path) {
|
||||
u64 filetype = IdentifyFileType(path);
|
||||
u64 trimsize = 0;
|
||||
|
@ -9,7 +9,6 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit);
|
||||
u32 DumpCxiSrlFromTmdFile(const char* path);
|
||||
u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr);
|
||||
u32 CompressCode(const char* path, const char* path_out);
|
||||
u32 ExtractDataFromDisaDiff(const char* path);
|
||||
u64 GetGameFileTrimmedSize(const char* path);
|
||||
u32 TrimGameFile(const char* path);
|
||||
u32 ShowGameFileTitleInfo(const char* path);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "vkeydb.h"
|
||||
#include "vcart.h"
|
||||
#include "vvram.h"
|
||||
#include "vdisadiff.h"
|
||||
|
||||
typedef struct {
|
||||
char drv_letter;
|
||||
@ -24,11 +25,16 @@ u32 GetVirtualSource(const char* path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InitVirtualImageDrive(void) {
|
||||
void DeinitVirtualImageDrive(void) {
|
||||
DeinitVGameDrive();
|
||||
DeinitVTickDbDrive();
|
||||
DeinitVKeyDbDrive();
|
||||
return InitVGameDrive() || InitVTickDbDrive() || InitVKeyDbDrive();
|
||||
DeinitVDisaDiffDrive();
|
||||
}
|
||||
|
||||
bool InitVirtualImageDrive(void) {
|
||||
DeinitVirtualImageDrive();
|
||||
return InitVGameDrive() || InitVDisaDiffDrive() || InitVKeyDbDrive();
|
||||
}
|
||||
|
||||
bool CheckVirtualDrive(const char* path) {
|
||||
@ -43,6 +49,8 @@ bool CheckVirtualDrive(const char* path) {
|
||||
return CheckVTickDbDrive();
|
||||
else if (virtual_src & VRT_KEYDB)
|
||||
return CheckVKeyDbDrive();
|
||||
else if (virtual_src & VRT_DISADIFF)
|
||||
return CheckVDisaDiffDrive();
|
||||
return virtual_src; // this is safe for SysNAND & memory
|
||||
}
|
||||
|
||||
@ -63,6 +71,8 @@ bool ReadVirtualDir(VirtualFile* vfile, VirtualDir* vdir) {
|
||||
ret = ReadVCartDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_VRAM) {
|
||||
ret = ReadVVramDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_DISADIFF) {
|
||||
ret = ReadVDisaDiffDir(vfile, vdir);
|
||||
}
|
||||
vfile->flags |= virtual_src; // add source flag
|
||||
return ret;
|
||||
@ -171,6 +181,8 @@ int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 coun
|
||||
return ReadVCartFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_VRAM) {
|
||||
return ReadVVramFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_DISADIFF) {
|
||||
return ReadVDisaDiffFile(vfile, buffer, offset, count);
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -190,6 +202,8 @@ int WriteVirtualFile(const VirtualFile* vfile, const void* buffer, u64 offset, u
|
||||
return WriteVNandFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_MEMORY) {
|
||||
return WriteVMemFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_DISADIFF) {
|
||||
return WriteVDisaDiffFile(vfile, buffer, offset, count);
|
||||
} // no write support for virtual game / tickdb / keydb / cart / vram files
|
||||
|
||||
return -1;
|
||||
|
@ -3,33 +3,34 @@
|
||||
#include "common.h"
|
||||
#include "nand.h"
|
||||
|
||||
#define VRT_SYSNAND NAND_SYSNAND
|
||||
#define VRT_EMUNAND NAND_EMUNAND
|
||||
#define VRT_IMGNAND NAND_IMGNAND
|
||||
#define VRT_XORPAD NAND_ZERONAND
|
||||
#define VRT_MEMORY (1UL<<4)
|
||||
#define VRT_GAME (1UL<<5)
|
||||
#define VRT_TICKDB (1UL<<6)
|
||||
#define VRT_KEYDB (1UL<<7)
|
||||
#define VRT_CART (1UL<<8)
|
||||
#define VRT_VRAM (1UL<<9)
|
||||
#define VRT_SYSNAND NAND_SYSNAND
|
||||
#define VRT_EMUNAND NAND_EMUNAND
|
||||
#define VRT_IMGNAND NAND_IMGNAND
|
||||
#define VRT_XORPAD NAND_ZERONAND
|
||||
#define VRT_MEMORY (1UL<<4)
|
||||
#define VRT_GAME (1UL<<5)
|
||||
#define VRT_TICKDB (1UL<<6)
|
||||
#define VRT_KEYDB (1UL<<7)
|
||||
#define VRT_CART (1UL<<8)
|
||||
#define VRT_VRAM (1UL<<9)
|
||||
#define VRT_DISADIFF (1UL<<10)
|
||||
|
||||
#define VRT_SOURCE (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD|VRT_MEMORY|VRT_GAME|VRT_TICKDB|VRT_KEYDB|VRT_CART|VRT_VRAM)
|
||||
#define VRT_SOURCE (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD|VRT_MEMORY|VRT_GAME|VRT_TICKDB|VRT_KEYDB|VRT_CART|VRT_VRAM|VRT_DISADIFF)
|
||||
|
||||
#define VFLAG_DIR (1UL<<10)
|
||||
#define VFLAG_ROOT (1UL<<11)
|
||||
#define VFLAG_READONLY (1UL<<12)
|
||||
#define VFLAG_DELETABLE (1UL<<13)
|
||||
#define VFLAG_LV3 (1UL<<14)
|
||||
#define VFLAG_DIR (1UL<<11)
|
||||
#define VFLAG_ROOT (1UL<<12)
|
||||
#define VFLAG_READONLY (1UL<<13)
|
||||
#define VFLAG_DELETABLE (1UL<<14)
|
||||
#define VFLAG_LV3 (1UL<<15)
|
||||
|
||||
|
||||
#define VRT_DRIVES {'S', VRT_SYSNAND}, {'E', VRT_EMUNAND}, {'I', VRT_IMGNAND}, {'X', VRT_XORPAD }, \
|
||||
{'M', VRT_MEMORY}, {'G', VRT_GAME}, {'K', VRT_KEYDB}, {'T', VRT_TICKDB}, {'C', VRT_CART}, {'V', VRT_VRAM}
|
||||
{'M', VRT_MEMORY}, {'G', VRT_GAME}, {'K', VRT_KEYDB}, {'T', VRT_TICKDB}, {'C', VRT_CART}, {'V', VRT_VRAM}, {'D', VRT_DISADIFF}
|
||||
|
||||
// virtual file flag (subject to change):
|
||||
// bits 0...3 : reserved for NAND virtual sources and info
|
||||
// bits 4...9 : reserved for other virtual sources
|
||||
// bits 10...15: reserved for external flags
|
||||
// bits 4...10 : reserved for other virtual sources
|
||||
// bits 11...15: reserved for external flags
|
||||
// bits 16...31: reserved for internal flags (different per source, see vgame.c)
|
||||
typedef struct {
|
||||
char name[32];
|
||||
@ -48,6 +49,7 @@ typedef struct {
|
||||
} VirtualDir;
|
||||
|
||||
u32 GetVirtualSource(const char* path);
|
||||
void DeinitVirtualImageDrive(void);
|
||||
bool InitVirtualImageDrive(void);
|
||||
bool CheckVirtualDrive(const char* path);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user