- Here is my project / extractor for the .arz files. This will fully extract any .arz database file for Grim Dawn. (Currently only one exists.)
This project is open source released under the GPL v3 license.
Project Home: https://gitlab.com/atom0s/grimarz
Bug Reports: https://gitlab.com/atom0s/grimarz/issues
Pull Requests: https://gitlab.com/atom0s/grimarz/merge_requests
.ARZ File Header
Code: Select all
struct GRIMDAWN_ARZ_V3_HEADER
{
unsigned int Unknown; // Assumed version check.
unsigned int RecordTableStart;
unsigned int RecordTableSize;
unsigned int RecordTableEntryCount;
unsigned int StringTableStart;
unsigned int StringTableSize;
};
The first unknown in this structure seems to be some sort of file check to ensure the file is a proper .arz file. However I did not spend much time on it trying to figure it out. The data for it looks like this:
Code: Select all
v4 = *(_DWORD *)a1;
v5 = (unsigned __int16)*(_DWORD *)a1;
v3 = a1 + 4;
*(_DWORD *)a3 = v4;
if ( v5 < *(_DWORD *)(a2 + 4) || (v7 = *(_DWORD *)(a2 + 32), ((v4 & 0x10000) == 65536) != ((v7 & 0x10000) == 65536)) )
{
result = 0;
}
String Table Format
Code: Select all
0x00000000 unsigned int Number Of Strings In Table
-> unsigned int String Length
-> char[] String
-> unsigned int String Length
-> char[] String
... etc until number of strings is met.
Important: Strings in the table ARE NOT null terminated. They are fixed size strings based on the unsigned int before the start of the string!
Record Table Format
Code: Select all
0x00000000 unsigned int File Path String Id
0x00000004 unsigned int String Length
0x00000008 char[] String (Record Type) [String is not null terminated!]
0x000000?? unsigned int Record Data Position
0x000000?? unsigned int Record Data Length (Compressed)
0x000000?? unsigned int Record Data Length (Decompressed)
0x000000?? unsigned int64 Record File FILETIME
Record Data Format
Before you can read the record data, you must decompress it. Grim Dawn uses LZ4 decompression.
If you need a working library that is tested to work with the Grim Dawn files, you can use:
- C/C++ : http://code.google.com/p/lz4/
- C# : https://lz4net.codeplex.com/
To decompress the data, use the compress and decompressed sizes known from the record table entry for this data object.
Once decompressed, the format is:
Code: Select all
0x00000000 unsigned short Data Type [See Below]
0x00000002 unsigned short Value Count
0x00000004 unsigned int String Key Id
0x00000008 unsigned int Value [To be read as int/float/bool as needed.]
The data type can be one of the following:
Code: Select all
-> 0x0000 == Int32 Value
-> 0x0001 == Float Value
-> 0x0002 == String Value [Value will be index inside of string table of the string.]
-> 0x0003 == Boolean Value
The value is always 4 bytes long regardless of the type read. If the value is a string, it is the index in the string table of the string. Remember, strings are not read based on index / position. So you need to dump the string table (or walk it manually each time) first into a container and index the container for the string being requested.
The rest of the file is 4 DWORDs at the end. I am uncertain what they do. I know where the game references them while loading the database but they are not used in any type of compares or checks. They are simply loaded and moved to a buffer. Afterward they never seem to be touched.
Special thanks to Shalie for his/her notes on some parts of the file I was stuck with.