I got my hands on the game yesterday morning, a bit late to the party (as I've forgot about the release till I was reminded) and after a few hours of poking around (and criticizing the bad format), I've got the game data extracted without a hitch or any particular issues.
Here's a quick breakdown of the badly defined archive format used for Tokyo Xanadu eX+, it's not perfect but you probably also could write a packer with this:
Code: Select all
// File Header Section (0x10)
string headerTag; // Constant: PDA (Null Terminated)
uint32 compressionType; // Presumed to be this. Value is constant 2
uint32 fileEntryOffset; // Offset relative to start of file to the end of compressed file data after the header.
uint32 fileCount; // File count
// Raw Data Section (Variable Length), Files consist of a 0x10 header & raw compressed data.
uint32 uncompressedSize; // Size expected after decompression.
uint32 compressedSize; // Size of compressed data after this header.
byte[8] unknown; // Sometimes 0, not a pointer/offset.
byte[x] compressedData; // Raw compressed data. Compression type is deflate. (Might be deflate64, I didn't verify, works under both).
// File entry section (immediately succeeding compressed data), variable length, repeated fileCount times..
time_t archiveTime; // C Time format. Appears to be the time the file was last packed/modified in the archive. Archive appears to be one of type that is built from scratch but files are simply updated and pushed in, potential for lots of unused goodies.
uint32 unknown; // The purpose is unknown.
uint32 compressedSize; // Same as in the file entry, except including 0x10 header.
uint32 uncompressedSize; // Same as in file entry, size post decompression.
uint16 fileNameLength; // Length of file name, including junk terminators.
uint16 fileFlags; // ? Seem to be flags, cannot tell as of yet, proper investigation was not made.
uint32 fileOffset; // Offset to the Raw Data Section for this file, relative to start of file.
string fileName; // Name of the file, lesser or equal to the fileNameLength field.
byte[1-3] shitPadding; // Literally what the name implies and the awful part of this format. Rather than null terminating strings and having the length correctly explicitly defined, the format pads the end of the file name with random junk data (which changes every time file name length changes) until the combined length of both the name and the junk is integer divisible by 4.
Notably some filenames for old and marked as unused files are also badly defined and would not extract to storage (I've seen 3 instances of this), the exporter sanitizes all file name outputs such that these files could also be extracted.
Usage:
Code: Select all
dotnet Xanadu-BRA-Decompress.dll <BRA Archive> -t
Source: https://github.com/sewer56lol/Xanadu-BRA-Decompress
Download (Binary):
The application is a .NET Core 2.0 program, you might require the runtime: https://www.microsoft.com/net/download/windows