Exetools  

Go Back   Exetools > General > Source Code

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 01-16-2015, 14:05
atom0s's Avatar
atom0s atom0s is offline
Family
 
Join Date: Jan 2015
Location: 127.0.0.1
Posts: 286
Rept. Given: 25
Rept. Rcvd 103 Times in 49 Posts
Thanks Given: 47
Thanks Rcvd at 483 Times in 196 Posts
atom0s Reputation: 100-199 atom0s Reputation: 100-199
[C++] Grim Dawn Archive File Extractor (.arc)

This is another project of mine for a game called Grim Dawn. This tool will extract the game data that is packed in the games custom .arc format. Again, not something I think many will be interested in as a whole, but the project is open source so sharing it in case someone finds any parts of it useful.

grimarc - Grim Dawn Archive File Extractor (.arc)
  • 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://github.com/atom0s/grimarc
    Bug Reports: https://github.com/atom0s/grimarc/issues
    Pull Requests: https://github.com/atom0s/grimarc/pulls

Download Latest Version:
https://github.com/atom0s/grimarc/releases/latest

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:
file
{
    header
    file_data
    file_record_table
    file_table_of_contents
}
ARC File Header (v3)
Code:
/**
 * @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:
/**
 * @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:
/**
 * @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/windows/desktop/ms724320(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.
Reply With Quote
The Following 2 Users Gave Reputation+1 to atom0s For This Useful Post:
Loki (01-16-2015), p4r4d0x (01-21-2015)
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On


Similar Threads
Thread Thread Starter Forum Replies Last Post
Woodmann Archive bolzano_1989 General Discussion 13 12-16-2016 04:51
[C++] Grim Dawn Database File Extractor (.arz) atom0s Source Code 0 01-16-2015 14:06


All times are GMT +8. The time now is 07:59.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX
( 1998 - 2020 )