Danmakufu 0.12m .dat archive format


The Danmakufu 0.12m file format looks roughly like this. All values are little endian, and there is no padding.

struct thdnh_012m_header {
  char magic[10]; // Always "PACK_FILE\0"
  uint32_t file_count; // Number of files in the archive.
  thdnh_012m_entry entries[file_count]; // Entries are dynamically sized
}

struct thdnh_012m_entry {
  uint32_t name_length; // Length of the file name
  char name[name_length]; // File name, encoded as a zero terminated string.
  uint32_t file_offset; // Offset of the file data in the archive
  uint32_t file_length; // Length of the full file data
}

The file data is handled somewhat specially. If the file data begins with "COMPRESS_ZIP\0", it is parsed as the following structure. Otherwise, the whole file is treated as uncompressed data.

struct thdnh_012m_compressed {
  char magic[13]; // Always "COMPRESS_ZIP\0"
  uint32_t uncompressed_size; // Size of the uncompressed data.
  char data[]; // The file data, compressed with zlib. Fills the rest of the file data. 
}

Danmakufu ph3 .dat archive format


Danmakufu ph3 adds support for directories. Same as with 0.12m, all values are little endian and there is no padding.

struct thdnh_ph3_header {
  char magic[11]; // Always "ArchiveFile"
  uint32_t file_count; // Number of files in the archive.
  bool is_compressed; // true if the file list is compressed, false otherwise.
  uint32_t file_list_size; // Compressed size of the file list. Ignored if is_compressed is false.
  char file_list[]; // If is_compressed is true, a zlib compressed that is file_list_size bytes uncompressed.
                    // If is_compressed is false, file_list_size is ignored, and the entries directly follow.
                    // Regardless, the data is a sequential list of file_count thdnh_ph3_file_entrys.
}

struct thdnh_ph3_file_entry {
  uint32_t entry_size; // The size of the file entry, *not* including this field.
  uint32_t dir_name_length; // The length of the directory name in characters.
  wchar_t dir_name[dir_name_length]; // The directory name in UTF-16. Not zero terminated.
  uint32_t file_name_length; // The length of the file name in characters.
  wchar_t file_name[file_name_length]; // The file name in UTF-16. Not zero terminated.
  uint32_t is_compressed; // Whether the file data is zlib compressed.
  uint32_t uncompressed_len; // The uncompressed length of the file.
  uint32_t compressed_len; // The compressed length of the file. Ignored if is_compressed is false.
  uint32_t offset; // Offset of the file data in the archive
}

The file data is a plain zlib stream if is_compressed is true, and a plain uncompressed stream if it is false.