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 {
  // Always "PACK_FILE\0"
  char magic[10];
  // Number of files in the archive.
  uint32_t file_count;
  // Entries are dynamically sized
  thdnh_012m_entry entries[file_count];
}

struct thdnh_012m_entry {
  // Length of the file name
  uint32_t name_length;
  // File name, encoded as a zero terminated string.
  char name[name_length]; 

  // Offset of the file data in the archive
  uint32_t file_offset;
  // Length of the full file data
  uint32_t file_length;
}

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 {
  // Always "COMPRESS_ZIP\0"
  char magic[13];
  // Size of the uncompressed data.
  uint32_t uncompressed_size;
  // The file data, compressed with zlib. Fills the rest of the file data. 
  char 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 {
  // Always "ArchiveFile"
  char magic[11];

  // Number of files in the archive.
  uint32_t file_count; 
  // true if the file list is compressed, false otherwise.
  bool is_compressed; 
  // Compressed size of the file list. Ignored if is_compressed is false.
  uint32_t file_list_size;

  // If is_compressed is true, a zlib compressed list of thdnh_ph3_file_entrys.
  // If is_compressed is false, an uncompressed thdnh_ph3_file_entrys.
  char file_list[]; 
}

struct thdnh_ph3_file_entry {
  // The size of the file entry, *not* including this field.
  uint32_t entry_size;

  // The length of the directory name in characters.
  uint32_t dir_name_length;
  // The directory name in UTF-16. Not zero terminated.
  wchar_t dir_name[dir_name_length];

  // The length of the file name in characters.
  uint32_t file_name_length;
  // The file name in UTF-16. Not zero terminated.
  wchar_t file_name[file_name_length];

  // Whether the file data is zlib compressed.
  uint32_t is_compressed;
  // The uncompressed length of the file.
  uint32_t uncompressed_len;
  // The compressed length of the file. Ignored if is_compressed is false.
  uint32_t compressed_len;

  // Offset of the file data in the archive
  uint32_t offset;
}

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