mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-28 07:47:02 -05:00
* patterns/uf2: add family ID enum * patterns/uf2: Fix enum spacing * patterns: add missing description pragmas and README entries, etc. * patterns/uf2: add reference for Family ID enum
160 lines
3.8 KiB
Rust
160 lines
3.8 KiB
Rust
#pragma author LolHacksRule
|
|
#pragma description Exient XGS Engine Pak files
|
|
|
|
import std.mem;
|
|
import std.core;
|
|
import type.time;
|
|
import type.magic;
|
|
|
|
//By LolHacksRule
|
|
|
|
/*
|
|
XGSPAK VX only works with games using XGS Engine VX (I think First Touch Games use multiple?), using different versions with them is likely a bad idea as devs can only use one of the three.
|
|
XGSPAKV1 can be used with ZLib or Raw content.
|
|
Works nearly perfectly on PAKs WITH and WITHOUT folders.
|
|
*/
|
|
|
|
/*
|
|
TODO:
|
|
Double check XGSPAKV0 from NFS Wii, it's probably similar?
|
|
Fix FTG V1 PAK if possible, uses V0 layout
|
|
*/
|
|
|
|
/*
|
|
Format info I used:
|
|
https://aluigi.altervista.org/bms/angry_birds_go.bms
|
|
https://aluigi.altervista.org/bms/angry_birds_starwars.bms
|
|
https://aluigi.altervista.org/bms/xpk2.bms
|
|
https://aluigi.altervista.org/bms/dls20.bms
|
|
*/
|
|
|
|
enum PakVersion : u8
|
|
{
|
|
Version0, //NFS Wii/Trilogy 3DS/DLS
|
|
Version1, //ABGO V1/ABTF, AB Console Ports
|
|
Version2 //ABGO V2+
|
|
};
|
|
|
|
enum CompressionType : u32
|
|
{
|
|
Raw, //NFS Wii/Trilogy 3DS/DLS
|
|
Zlib, //ABGO V1/ABTF, AB Console Ports
|
|
LZ4 //ABGO V2+
|
|
};
|
|
|
|
struct XGSPakHeader
|
|
{
|
|
if (std::mem::read_unsigned($, 1) > 2) //Assume BE
|
|
{
|
|
std::core::set_endian(std::mem::Endian::Big);
|
|
char magic[3];
|
|
PakVersion ver;
|
|
}
|
|
else
|
|
{
|
|
PakVersion ver;
|
|
char magic[3];
|
|
}
|
|
u32 folders;
|
|
u32 files; //-1 bcz init folder
|
|
u32 fileContentTableSize;
|
|
if (ver == PakVersion::Version2)
|
|
{
|
|
CompressionType compressionType;
|
|
}
|
|
};
|
|
|
|
struct XGSPakFolderBase
|
|
{
|
|
if (Head.ver == PakVersion::Version0)
|
|
{
|
|
char *name[] : u32[[pointer_base("offToStringTable")]];
|
|
u32 filesInFolder;
|
|
u32 subfolders;
|
|
u32 filesPos;
|
|
u32 foldersPos;
|
|
}
|
|
else
|
|
{
|
|
if (Head.magic == "XPK")
|
|
{
|
|
u32 dummy;
|
|
char *name[] : u32 [[pointer_base("offToStringTable")]];
|
|
u32 dummy2;
|
|
u32 filesPos;
|
|
u32 dummy3;
|
|
u32 foldersPos;
|
|
u32 filesInFolder;
|
|
u32 subfolders;
|
|
}
|
|
else
|
|
{
|
|
//u64 name;
|
|
char *name[] : u64 [[pointer_base("offToStringTable")]];
|
|
u64 filesPos;
|
|
u64 foldersPos;
|
|
u32 filesInFolder;
|
|
u32 subfolders;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct XGSPakContentMeta
|
|
{
|
|
if (Head.ver == PakVersion::Version0)
|
|
{
|
|
char *name[] : u32 [[pointer_base("offToStringTable")]];
|
|
u32 decompFileSize;
|
|
u32 fileOff;
|
|
u32 compressed;
|
|
type::time32_t timestamp;
|
|
u32 compFileSize;
|
|
}
|
|
else
|
|
{
|
|
if (Head.magic == "XPK")
|
|
{
|
|
u32 dummy;
|
|
char *name[] : u32 [[pointer_base("offToStringTable")]];
|
|
u32 decompFileSize;
|
|
u32 fileOff;
|
|
u32 compressed;
|
|
type::time32_t timestamp;
|
|
u32 compFileSize;
|
|
u32 dummy2;
|
|
}
|
|
else
|
|
{
|
|
//u64 name;
|
|
char *name[] : u64 [[pointer_base("offToStringTable")]];
|
|
u32 decompFileSize;
|
|
u32 fileOff;
|
|
u32 compressed;
|
|
type::time32_t timestamp;
|
|
u64 compFileSize;
|
|
}
|
|
}
|
|
if (compressed)
|
|
{
|
|
u8 compressedFile[compFileSize] @ fileOff;
|
|
}
|
|
else
|
|
{
|
|
u8 file[decompFileSize] @ fileOff;
|
|
}
|
|
};
|
|
|
|
|
|
XGSPakHeader Head @ $;
|
|
//u32 offToStringTable_old = ((0x20*Head.folders)+(0x20*Head.files))+sizeof (Head); //Finicky but it works
|
|
|
|
fn offToStringTable(u128 offset) {
|
|
match (Head.ver)
|
|
{
|
|
(PakVersion::Version0): return ((0x14*Head.folders)+(0x18*Head.files))+sizeof (Head);
|
|
(PakVersion::Version1 | PakVersion::Version2): return ((0x20*Head.folders)+(0x20*Head.files))+sizeof (Head);
|
|
}
|
|
};
|
|
|
|
XGSPakFolderBase FolderBase[Head.folders] @ $;
|
|
XGSPakContentMeta ContentMeta[Head.files] @ $; |