add decoder for Ep3 trial download quests

This commit is contained in:
Martin Michelsen
2023-09-26 12:12:41 -07:00
parent a4961ad69d
commit 63f6aff4ed
3 changed files with 53 additions and 32 deletions
+19 -3
View File
@@ -165,8 +165,7 @@ string find_seed_and_decrypt_download_quest_data_section(
string result; string result;
uint64_t result_seed = parallel_range<uint64_t>([&](uint64_t seed, size_t) { uint64_t result_seed = parallel_range<uint64_t>([&](uint64_t seed, size_t) {
try { try {
string ret = decrypt_download_quest_data_section<IsBigEndian>( string ret = decrypt_download_quest_data_section<IsBigEndian>(data_section, size, seed);
data_section, size, seed);
lock_guard<mutex> g(result_lock); lock_guard<mutex> g(result_lock);
result = std::move(ret); result = std::move(ret);
return true; return true;
@@ -522,7 +521,23 @@ string Quest::decode_gci_file(
return compressed_data; return compressed_data;
} }
} else if (header.game_id[2] == 'S') { // Episode 3 } else if (header.is_ep3()) {
if (header.is_trial()) {
if (known_seed >= 0) {
return decrypt_download_quest_data_section<true>(
r.getv(header.data_size), header.data_size, known_seed);
} else {
if (find_seed_num_threads < 0) {
throw runtime_error("file is encrypted");
}
if (find_seed_num_threads == 0) {
find_seed_num_threads = thread::hardware_concurrency();
}
return find_seed_and_decrypt_download_quest_data_section<true>(
r.getv(header.data_size), header.data_size, find_seed_num_threads);
}
} else {
// The first 0x10 bytes in the data segment appear to be unused. In most // The first 0x10 bytes in the data segment appear to be unused. In most
// files I've seen, the last half of it (8 bytes) are duplicates of the // files I've seen, the last half of it (8 bytes) are duplicates of the
// first 8 bytes of the unscrambled, compressed data, though this is the // first 8 bytes of the unscrambled, compressed data, though this is the
@@ -552,6 +567,7 @@ string Quest::decode_gci_file(
decompressed_size, sizeof(Episode3::MapDefinition))); decompressed_size, sizeof(Episode3::MapDefinition)));
} }
return data; return data;
}
} else { } else {
throw runtime_error("unknown game name in GCI header"); throw runtime_error("unknown game name in GCI header");
+5 -1
View File
@@ -87,7 +87,7 @@ void PSOGCIFileHeader::check() const {
if (this->developer_id[0] != '8' || this->developer_id[1] != 'P') { if (this->developer_id[0] != '8' || this->developer_id[1] != 'P') {
throw runtime_error("GCI file is not for a Sega game"); throw runtime_error("GCI file is not for a Sega game");
} }
if (this->game_id[0] != 'G') { if ((this->game_id[0] != 'G') && (this->game_id[0] != 'D')) {
throw runtime_error("GCI file is not for a GameCube game"); throw runtime_error("GCI file is not for a GameCube game");
} }
if (this->game_id[1] != 'P') { if (this->game_id[1] != 'P') {
@@ -106,6 +106,10 @@ bool PSOGCIFileHeader::is_ep3() const {
return (this->game_id[2] == 'S'); return (this->game_id[2] == 'S');
} }
bool PSOGCIFileHeader::is_trial() const {
return (this->game_id[0] == 'D');
}
uint32_t compute_psogc_timestamp( uint32_t compute_psogc_timestamp(
uint16_t year, uint16_t year,
uint8_t month, uint8_t month,
+1
View File
@@ -86,6 +86,7 @@ struct PSOGCIFileHeader {
bool is_ep12() const; bool is_ep12() const;
bool is_ep3() const; bool is_ep3() const;
bool is_trial() const;
} __attribute__((packed)); } __attribute__((packed));
struct PSOGCSystemFile { struct PSOGCSystemFile {