- Here is my project / extractor for the .arc files. This will fully extract any archive (.arc) file you give it.
This project is open source released under the GPL v3 license.
Project Home: https://gitlab.com/atom0s/grimarc
Bug Reports: https://gitlab.com/atom0s/grimarc/issues
Pull Requests: https://gitlab.com/atom0s/grimarc/merge_requests
File Format Information
Please note this data and format is subject to change. Grim Dawn is still in alpha testing and is not completed.
The developers may change the formats at random causing this information to become invalid.
At the time of this post, the game is currently at build: B23
To start, the .arc files are broken into four sections.
Code: Select all
file
{
header
file_data
file_record_table
file_table_of_contents
}
ARC File Header (v3)
Code: Select all
/**
* @brief ARC File Header (v3)
*/
struct ARC_V3_HEADER
{
unsigned int Magic; // ARC
unsigned int Version;
unsigned int NumberOfFileEntries;
unsigned int NumberOfDataRecords; // (NumberOfDataRecords * 12) = RecordTableSize
unsigned int RecordTableSize;
unsigned int StringTableSize;
unsigned int RecordTableOffset;
};
- NumberOfFileEntries is the total number of files this .arc contains.
- NumberOfDataRecords is the total number of file parts within the second part of this .arc file.
- RecordTableSize is the total size of the record parts table. (Each entry is 12 bytes long.)
- StringTableSize is the total size of the string table.
- RecordTableOffset is the offset to the file parts table.
Next, after the header is the file data parts. This chunk is handled by the next two parts of the file. So the next part we have the record table. The record table defines the file parts in the chunk of data before it. The format is:
Code: Select all
/**
* @brief ARC File Part Entry (v3)
*/
struct ARC_V3_FILE_PART
{
unsigned int PartOffset;
unsigned int CompressedSize;
unsigned int DecompressedSize;
};
Each entry points to a part of a file. (Or a whole file if its not parted.) If the compressed size matches the decompressed size, the part is not considered compressed and can be dumped as-is. These file parts are compressed using LZ4 compression.
Following this table, is the string table. Each string is the name of a file within the archive. The string table is just a block of strings, null terminated in a row. The position of the string is the index of the file within the archive. So the first entry in the ToC table uses the first string in the string table, the second uses the second and so on. There is no string lookup in .arc files like there is in .arz files!
The last block of data in the file is the files table of contents. This is the major part of the file that is used to read and understand the rest of the file. The ToC attaches to the record table to know which blocks of data to read. The ToC is formatted like this:
Code: Select all
/**
* @brief ARC File Table Of Contents Entry (v3)
*/
#pragma pack(1)
struct ARC_V3_FILE_TOC_ENTRY
{
unsigned int EntryType;
unsigned int FileOffset;
unsigned int CompressedSize;
unsigned int DecompressedSize;
unsigned int Unknown0001; // Possible timestamp?
unsigned __int64 FileTime;
unsigned int FileParts;
unsigned int FirstPartIndex;
unsigned int StringEntryLength;
unsigned int StringEntryOffset;
};
#pragma pop
- EntryType determines how the entry is stored. Apparently if this is set to 1 the entry is not compressed at all. I do not believe this is used anymore and every entry I have seen has always been 3.
- FileOffset is the offset to the first part of this file.
- CompressedSize is the total compressed size of this file.
- DecompressedSize is the total decompressed size of this file.
- Unknown0001 is unknown. I think this may be some sort of timestamp.
- FileTime is the file time of the file. (See http://msdn.microsoft.com/en-us/library ... 20(v=vs.85).aspx)
- FileParts is the number of parts this file is broken into.
- FirstPartIndex is the first index inside of the record table to start using as parts of this file.
- StringEntryLength is the length of the string in the string table.
- StringEntryOffset is the offset in the string table for this string.