support big-endian GSL archives

This commit is contained in:
Martin Michelsen
2022-12-29 15:02:29 -08:00
parent 52db9008a8
commit 68abac4fd4
3 changed files with 24 additions and 13 deletions
+16 -7
View File
@@ -10,20 +10,20 @@ using namespace std;
// TODO: Support big-endian GSLs also (e.g. from PSO GC) template <typename LongT>
struct GSLHeaderEntry { struct GSLHeaderEntry {
ptext<char, 0x20> filename; ptext<char, 0x20> filename;
le_uint32_t offset; // In pages, so actual offset is this * 0x800 LongT offset; // In pages, so actual offset is this * 0x800
le_uint32_t size; LongT size;
uint64_t unused; uint64_t unused;
}; } __attribute__((packed));
GSLArchive::GSLArchive(shared_ptr<const string> data) : data(data) { template <typename LongT>
void GSLArchive::load_t() {
StringReader r(*this->data); StringReader r(*this->data);
uint64_t min_data_offset = 0xFFFFFFFFFFFFFFFF; uint64_t min_data_offset = 0xFFFFFFFFFFFFFFFF;
while (r.where() < min_data_offset) { while (r.where() < min_data_offset) {
const auto& entry = r.get<GSLHeaderEntry>(); const auto& entry = r.get<GSLHeaderEntry<LongT>>();
if (entry.filename.len() == 0) { if (entry.filename.len() == 0) {
break; break;
} }
@@ -35,6 +35,15 @@ GSLArchive::GSLArchive(shared_ptr<const string> data) : data(data) {
} }
} }
GSLArchive::GSLArchive(shared_ptr<const string> data, bool big_endian)
: data(data) {
if (big_endian) {
this->load_t<be_uint32_t>();
} else {
this->load_t<le_uint32_t>();
}
}
const unordered_map<string, GSLArchive::Entry> GSLArchive::all_entries() const { const unordered_map<string, GSLArchive::Entry> GSLArchive::all_entries() const {
return this->entries; return this->entries;
} }
+4 -1
View File
@@ -12,7 +12,7 @@
class GSLArchive { class GSLArchive {
public: public:
GSLArchive(std::shared_ptr<const std::string> data); GSLArchive(std::shared_ptr<const std::string> data, bool big_endian);
~GSLArchive() = default; ~GSLArchive() = default;
struct Entry { struct Entry {
@@ -26,6 +26,9 @@ public:
StringReader get_reader(const std::string& name) const; StringReader get_reader(const std::string& name) const;
private: private:
template <typename LongT>
void load_t();
std::shared_ptr<const std::string> data; std::shared_ptr<const std::string> data;
std::unordered_map<std::string, Entry> entries; std::unordered_map<std::string, Entry> entries;
+4 -5
View File
@@ -364,9 +364,8 @@ The options are:\n\
Extract all files from a GSL archive into the current directory.\n\ Extract all files from a GSL archive into the current directory.\n\
input-filename may be specified. If output-filename is specified, then it\n\ input-filename may be specified. If output-filename is specified, then it\n\
is treated as a prefix which is prepended to the filename of each file\n\ is treated as a prefix which is prepended to the filename of each file\n\
contained in the GSL archive. Importantly, if you want to put the files\n\ contained in the GSL archive. If --big-endian is given, the GSL header is\n\
into a directory, you'll have to create the directory first, and include\n\ read in GameCube format; otherwise it is read in PC/BB format.\n\
a trailing / on output-filename.\n\
\n\ \n\
A few options apply to multiple modes described above:\n\ A few options apply to multiple modes described above:\n\
--parse-data\n\ --parse-data\n\
@@ -825,7 +824,7 @@ int main(int argc, char** argv) {
string data = read_input_data(); string data = read_input_data();
shared_ptr<string> data_shared(new string(move(data))); shared_ptr<string> data_shared(new string(move(data)));
GSLArchive gsl(data_shared); GSLArchive gsl(data_shared, big_endian);
for (const auto& entry_it : gsl.all_entries()) { for (const auto& entry_it : gsl.all_entries()) {
auto e = gsl.get(entry_it.first); auto e = gsl.get(entry_it.first);
save_file(output_filename + entry_it.first, e.first, e.second); save_file(output_filename + entry_it.first, e.first, e.second);
@@ -930,7 +929,7 @@ int main(int argc, char** argv) {
state->bb_patch_file_index.reset(new PatchFileIndex("system/patch-bb")); state->bb_patch_file_index.reset(new PatchFileIndex("system/patch-bb"));
try { try {
auto gsl_file = state->bb_patch_file_index->get("./data/data.gsl"); auto gsl_file = state->bb_patch_file_index->get("./data/data.gsl");
state->bb_data_gsl.reset(new GSLArchive(gsl_file->load_data())); state->bb_data_gsl.reset(new GSLArchive(gsl_file->load_data(), false));
config_log.info("data.gsl found in BB patch files"); config_log.info("data.gsl found in BB patch files");
} catch (const out_of_range&) { } catch (const out_of_range&) {
config_log.info("data.gsl is not present in BB patch files"); config_log.info("data.gsl is not present in BB patch files");