mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
parent
cfa26c2a2d
commit
fdcc9059e2
@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
#define CRC16_TABVAL 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
#define CRC16_TABVAL 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
|
||||||
|
|
||||||
|
#define FNT_ENTRY_ISDIR(e) ((bool)((*(u8*)(e))&0x80))
|
||||||
|
#define FNT_ENTRY_FNLEN(e) ((*(u8*)(e))&~0x80)
|
||||||
|
#define FNT_ENTRY_LEN(e) (1 + FNT_ENTRY_FNLEN(e) + (FNT_ENTRY_ISDIR(e)?2:0))
|
||||||
|
#define FNT_ENTRY_NEXT(e) (((u8*)(e)) + FNT_ENTRY_LEN(e))
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 subtable_offset;
|
u32 subtable_offset;
|
||||||
@ -89,47 +94,62 @@ u32 GetTwlIcon(u8* icon, const TwlIconData* twl_icon) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ReadNitroRomDir(u32 dirid, u64* offset, u64* size, bool* is_dir, u8** fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat) {
|
u32 FindNitroRomDir(u32 dirid, u32* fileid, u8** fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat) {
|
||||||
static u32 fileid = 0;
|
|
||||||
static u8* subtbl_end = NULL;
|
|
||||||
NitroFntBaseEntry* fnt_base = (NitroFntBaseEntry*) fnt;
|
NitroFntBaseEntry* fnt_base = (NitroFntBaseEntry*) fnt;
|
||||||
NitroFntBaseEntry* fnt_dir = &((NitroFntBaseEntry*) fnt)[dirid];
|
NitroFntBaseEntry* fnt_dir = &((NitroFntBaseEntry*) fnt)[dirid];
|
||||||
NitroFatEntry* fat_lut = (NitroFatEntry*) fat;
|
NitroFatEntry* fat_lut = (NitroFatEntry*) fat;
|
||||||
|
|
||||||
if (dirid >= fnt_base->parent_id) return 1; // dir ID out of bounds
|
// base sanity checks
|
||||||
if (*fnt_entry && (*fnt_entry - fnt >= (int) hdr->fnt_size)) return 1; // FNT entry out of bounds
|
|
||||||
if (fnt_base->parent_id*sizeof(NitroFntBaseEntry) > fnt_base->subtable_offset) return 1; // invalid FNT
|
if (fnt_base->parent_id*sizeof(NitroFntBaseEntry) > fnt_base->subtable_offset) return 1; // invalid FNT
|
||||||
|
if (dirid >= fnt_base->parent_id) return 1; // dir ID out of bounds
|
||||||
|
|
||||||
if (!*fnt_entry) { // if *fnt_entry is NULL: reset file id and start with first entry
|
// set first FNT entry / fileid
|
||||||
*fnt_entry = fnt + fnt_dir->subtable_offset;
|
*fnt_entry = fnt + fnt_dir->subtable_offset;
|
||||||
fileid = fnt_dir->file0_id;
|
*fileid = fnt_dir->file0_id;
|
||||||
|
|
||||||
|
// check subtable / directory validity
|
||||||
|
if (*fnt_entry >= fnt + hdr->fnt_size) return 1;
|
||||||
|
u8* subtbl_end = NULL;
|
||||||
|
u32 fid = *fileid;
|
||||||
for (subtbl_end = *fnt_entry; *subtbl_end && (subtbl_end < fnt + hdr->fnt_size); subtbl_end++);
|
for (subtbl_end = *fnt_entry; *subtbl_end && (subtbl_end < fnt + hdr->fnt_size); subtbl_end++);
|
||||||
} else { // advance to next entry
|
for (u8* entry = *fnt_entry; *entry; entry = FNT_ENTRY_NEXT(entry)) {
|
||||||
u32 pfnlen = **fnt_entry & ~0x80;
|
if (entry > subtbl_end) return 1; // corrupt subtable
|
||||||
bool was_dir = **fnt_entry & 0x80;
|
if (fat_lut[fid].start_address > fat_lut[fid].end_address) return 1; // corrupt fat
|
||||||
*fnt_entry += 1 + pfnlen + (was_dir?2:0);
|
if (!FNT_ENTRY_ISDIR(entry)) fid++;
|
||||||
if (!was_dir) fileid++;
|
|
||||||
}
|
}
|
||||||
|
if (fid*sizeof(NitroFatEntry) > hdr->fat_size) return 1; // corrupt fnt / fat
|
||||||
|
|
||||||
// check for trouble
|
|
||||||
if (*fnt_entry > subtbl_end)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// check for end of subtable
|
|
||||||
if (!**fnt_entry) { // end of subtable reached
|
|
||||||
*fnt_entry = NULL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*is_dir = **fnt_entry & 0x80;
|
u32 NextNitroRomEntry(u32* fileid, u8** fnt_entry) {
|
||||||
|
// check for end of subtable
|
||||||
|
if (!*fnt_entry || !**fnt_entry) return 1;
|
||||||
|
|
||||||
|
// advance to next entry
|
||||||
|
if (!FNT_ENTRY_ISDIR(*fnt_entry)) (*fileid)++;
|
||||||
|
*fnt_entry += FNT_ENTRY_LEN(*fnt_entry);
|
||||||
|
|
||||||
|
// check for end of subtable
|
||||||
|
if (!**fnt_entry) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ReadNitroRomEntry(u64* offset, u64* size, bool* is_dir, u32 fileid, u8* fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat) {
|
||||||
|
// check for end of subtable
|
||||||
|
if (!fnt_entry || !*fnt_entry) return 1;
|
||||||
|
|
||||||
|
// decipher FNT entry
|
||||||
|
*is_dir = FNT_ENTRY_ISDIR(fnt_entry);
|
||||||
if (!(*is_dir)) { // for files
|
if (!(*is_dir)) { // for files
|
||||||
if (fileid*sizeof(NitroFatEntry) > hdr->fat_size) return 1; // corrupt fnt / fat
|
NitroFatEntry* fat_lut = (NitroFatEntry*) fat;
|
||||||
if (fat_lut[fileid].start_address > fat_lut[fileid].end_address) return 1; // corrupt fat
|
|
||||||
*offset = fat_lut[fileid].start_address;
|
*offset = fat_lut[fileid].start_address;
|
||||||
*size = fat_lut[fileid].end_address - fat_lut[fileid].start_address;
|
*size = fat_lut[fileid].end_address - fat_lut[fileid].start_address;
|
||||||
} else { // for dirs
|
} else { // for dirs
|
||||||
u32 fnlen = **fnt_entry & ~0x80;
|
u32 fnlen = FNT_ENTRY_FNLEN(fnt_entry);
|
||||||
*offset = (u64) ((*fnt_entry)[1+fnlen]|((*fnt_entry)[1+fnlen+1]<<8)) & 0xFFF; // dir ID goes in offset
|
*offset = (u64) (fnt_entry[1+fnlen]|(fnt_entry[1+fnlen+1]<<8)) & 0xFFF; // dir ID goes in offset
|
||||||
*size = 0;
|
*size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,4 +127,7 @@ u32 ValidateTwlHeader(TwlHeader* twl);
|
|||||||
u32 LoadTwlMetaData(const char* path, TwlHeader* hdr, TwlIconData* icon);
|
u32 LoadTwlMetaData(const char* path, TwlHeader* hdr, TwlIconData* icon);
|
||||||
u32 GetTwlTitle(char* desc, const TwlIconData* twl_icon);
|
u32 GetTwlTitle(char* desc, const TwlIconData* twl_icon);
|
||||||
u32 GetTwlIcon(u8* icon, const TwlIconData* twl_icon);
|
u32 GetTwlIcon(u8* icon, const TwlIconData* twl_icon);
|
||||||
u32 ReadNitroRomDir(u32 dirid, u64* offset, u64* size, bool* is_dir, u8** fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat);
|
|
||||||
|
u32 FindNitroRomDir(u32 dirid, u32* fileid, u8** fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat);
|
||||||
|
u32 NextNitroRomEntry(u32* fileid, u8** fnt_entry);
|
||||||
|
u32 ReadNitroRomEntry(u64* offset, u64* size, bool* is_dir, u32 fileid, u8* fnt_entry, TwlHeader* hdr, u8* fnt, u8* fat);
|
||||||
|
@ -797,33 +797,41 @@ bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ReadVGameDirNitro(VirtualFile* vfile, VirtualDir* vdir) {
|
bool ReadVGameDirNitro(VirtualFile* vfile, VirtualDir* vdir) {
|
||||||
static u8* fnt_entry = NULL;
|
u8* fnt = nitrofs;
|
||||||
|
u8* fat = nitrofs + twl->fat_offset - twl->fnt_offset;
|
||||||
|
|
||||||
vfile->name[0] = '\0';
|
vfile->name[0] = '\0';
|
||||||
vfile->flags = VFLAG_NITRO;
|
vfile->flags = VFLAG_NITRO;
|
||||||
vfile->keyslot = 0;
|
vfile->keyslot = 0;
|
||||||
|
|
||||||
// start from parent dir object
|
// start from parent dir object
|
||||||
if (vdir->index == -1) {
|
if (vdir->index == -1) {
|
||||||
fnt_entry = NULL;
|
u8* fnt_entry = NULL;
|
||||||
vdir->index = 0;
|
u32 dirid = vdir->offset & 0xFFF;
|
||||||
|
u32 fileid = 0;
|
||||||
|
if (FindNitroRomDir(dirid, &fileid, &fnt_entry, twl, fnt, fat) == 0) {
|
||||||
|
vdir->index = fileid; // store fileid in index
|
||||||
|
vdir->offset = (vdir->offset&0xFFFFFFFF) | (((u64)(fnt_entry - fnt)) << 32); // store offsets in offset
|
||||||
|
} else vdir->index = -3; // error
|
||||||
}
|
}
|
||||||
|
|
||||||
// read directory entries until done
|
// read directory entries until done
|
||||||
if (vdir->index == 0) {
|
if (vdir->index >= 0) {
|
||||||
u8* fnt = nitrofs;
|
u8* fnt_entry = fnt + (vdir->offset >> 32);
|
||||||
u8* fat = nitrofs + twl->fat_offset - twl->fnt_offset;
|
u32 fileid = vdir->index;
|
||||||
u32 dirid = vdir->offset & 0xFFF;
|
|
||||||
bool is_dir;
|
bool is_dir;
|
||||||
if (ReadNitroRomDir(dirid, &(vfile->offset), &(vfile->size), &is_dir, &fnt_entry, twl, fnt, fat) != 0)
|
if (ReadNitroRomEntry(&(vfile->offset), &(vfile->size), &is_dir, fileid, fnt_entry, twl, fnt, fat) == 0) {
|
||||||
vdir->index = 2; // error reading dir
|
|
||||||
if (fnt_entry) {
|
|
||||||
if (!is_dir) vfile->offset += offset_nds;
|
if (!is_dir) vfile->offset += offset_nds;
|
||||||
vfile->offset |= ((u64)(fnt_entry - fnt)) << 32;
|
vfile->offset |= ((u64)(fnt_entry - fnt)) << 32;
|
||||||
if (is_dir) vfile->flags |= VFLAG_DIR;
|
if (is_dir) vfile->flags |= VFLAG_DIR;
|
||||||
} else vdir->index = 1; // end of dir
|
// advance to next entry
|
||||||
|
NextNitroRomEntry(&fileid, &fnt_entry);
|
||||||
|
vdir->index = fileid;
|
||||||
|
vdir->offset = (vdir->offset&0xFFFFFFFF) | (((u64)(fnt_entry - fnt)) << 32);
|
||||||
|
} else vdir->index = -2; // end of dir
|
||||||
}
|
}
|
||||||
|
|
||||||
return (vdir->index == 0);
|
return (vdir->index >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadVGameDir(VirtualFile* vfile, VirtualDir* vdir) {
|
bool ReadVGameDir(VirtualFile* vfile, VirtualDir* vdir) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user