mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 22:22:21 -04:00
support unpacking iso files in the extractor (#1300)
This commit is contained in:
@@ -34,6 +34,7 @@ add_library(common
|
||||
util/diff.cpp
|
||||
util/FileUtil.cpp
|
||||
util/json_util.cpp
|
||||
util/read_iso_file.cpp
|
||||
util/Timer.cpp
|
||||
util/os.cpp
|
||||
util/print_float.cpp
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "read_iso_file.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
IsoFile::IsoFile() {
|
||||
root.is_dir = true;
|
||||
}
|
||||
|
||||
std::string IsoFile::print() const {
|
||||
std::string result;
|
||||
root.print(&result, "");
|
||||
return result;
|
||||
}
|
||||
|
||||
void IsoFile::Entry::print(std::string* result, const std::string& prefix) const {
|
||||
if (is_dir) {
|
||||
std::string child_prefix = prefix + "/" + name;
|
||||
for (const auto& child : children) {
|
||||
child.print(result, child_prefix);
|
||||
}
|
||||
} else {
|
||||
result->append(prefix);
|
||||
result->push_back('/');
|
||||
result->append(name);
|
||||
result->push_back('\n');
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr int SECTOR_SIZE = 0x800;
|
||||
|
||||
template <typename T>
|
||||
T read_file(FILE* fp, u32 sector, u32 offset_in_sector) {
|
||||
T result;
|
||||
if (fseek(fp, sector * SECTOR_SIZE + offset_in_sector, SEEK_SET)) {
|
||||
ASSERT_MSG(false, "Failed to fseek iso");
|
||||
}
|
||||
if (fread(&result, sizeof(T), 1, fp) != 1) {
|
||||
ASSERT_MSG(false, "Failed to fread iso");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void add_from_dir(FILE* fp, u32 sector, u32 size, IsoFile::Entry* parent) {
|
||||
u32 offset = 0;
|
||||
while (offset < size) {
|
||||
if (!read_file<u8>(fp, sector, offset)) {
|
||||
offset = (offset & ~(SECTOR_SIZE - 1)) + SECTOR_SIZE;
|
||||
continue;
|
||||
}
|
||||
u8 record_size = read_file<u8>(fp, sector, offset);
|
||||
u8 kind = read_file<u8>(fp, sector, offset + 0x21);
|
||||
if ((kind != 0) && (kind != 1)) {
|
||||
auto& entry = parent->children.emplace_back();
|
||||
u32 extent = read_file<u32>(fp, sector, offset + 2);
|
||||
u32 dir_or_file_size = read_file<u32>(fp, sector, offset + 10);
|
||||
u32 name_len = read_file<u8>(fp, sector, offset + 32);
|
||||
u8 c0 = read_file<u8>(fp, sector, offset + name_len + 0x1f);
|
||||
u8 c1 = read_file<u8>(fp, sector, offset + name_len + 0x20);
|
||||
for (u32 i = 0; i < name_len; i++) {
|
||||
entry.name.push_back(read_file<char>(fp, sector, offset + 0x21 + i));
|
||||
}
|
||||
entry.is_dir = (c0 != ';' || c1 != '1');
|
||||
if (entry.is_dir) {
|
||||
add_from_dir(fp, extent, dir_or_file_size, &entry);
|
||||
} else {
|
||||
entry.name.pop_back();
|
||||
entry.name.pop_back();
|
||||
entry.offset_in_file = SECTOR_SIZE * extent;
|
||||
entry.size = dir_or_file_size;
|
||||
}
|
||||
}
|
||||
offset += record_size;
|
||||
}
|
||||
}
|
||||
|
||||
void unpack_entry(FILE* fp, const IsoFile::Entry& entry, const std::filesystem::path& dest) {
|
||||
std::filesystem::path path_to_entry = dest / entry.name;
|
||||
if (entry.is_dir) {
|
||||
std::filesystem::create_directory(path_to_entry);
|
||||
for (const auto& child : entry.children) {
|
||||
unpack_entry(fp, child, path_to_entry);
|
||||
}
|
||||
} else {
|
||||
std::vector<u8> buffer(entry.size);
|
||||
if (fseek(fp, entry.offset_in_file, SEEK_SET)) {
|
||||
ASSERT_MSG(false, "Failed to fseek iso when unpacking");
|
||||
}
|
||||
if (fread(buffer.data(), buffer.size(), 1, fp) != 1) {
|
||||
ASSERT_MSG(false, "Failed to fread iso when unpacking");
|
||||
}
|
||||
file_util::write_binary_file(path_to_entry.string(), buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
IsoFile find_files_in_iso(FILE* fp) {
|
||||
IsoFile result;
|
||||
u32 path_table_sector = read_file<u32>(fp, 0x10, 0x8c);
|
||||
u32 path_table_extent = read_file<u32>(fp, path_table_sector, 2);
|
||||
u32 dir_size = read_file<u32>(fp, path_table_extent, 10);
|
||||
add_from_dir(fp, path_table_extent, dir_size, &result.root);
|
||||
return result;
|
||||
}
|
||||
|
||||
void unpack_iso_files(FILE* fp, const IsoFile& layout, const std::filesystem::path& dest) {
|
||||
unpack_entry(fp, layout.root, dest);
|
||||
}
|
||||
|
||||
void unpack_iso_files(FILE* fp, const std::filesystem::path& dest) {
|
||||
unpack_iso_files(fp, find_files_in_iso(fp), dest);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
struct IsoFile {
|
||||
struct Entry {
|
||||
bool is_dir = false;
|
||||
std::string name;
|
||||
|
||||
// if file
|
||||
size_t offset_in_file = 0;
|
||||
size_t size = 0;
|
||||
|
||||
// if dir
|
||||
std::vector<Entry> children;
|
||||
void print(std::string* result, const std::string& prefix) const;
|
||||
};
|
||||
|
||||
std::string print() const;
|
||||
|
||||
Entry root;
|
||||
|
||||
IsoFile();
|
||||
};
|
||||
|
||||
IsoFile find_files_in_iso(FILE* fp);
|
||||
void unpack_iso_files(FILE* fp, const IsoFile& layout, const std::filesystem::path& dest);
|
||||
void unpack_iso_files(FILE* fp, const std::filesystem::path& dest);
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "decompiler/level_extractor/extract_level.h"
|
||||
#include "decompiler/config.h"
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "common/util/read_iso_file.h"
|
||||
|
||||
void setup_global_decompiler_stuff() {
|
||||
file_util::init_crc();
|
||||
@@ -31,8 +32,15 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (!std::filesystem::is_directory(jak1_input_files)) {
|
||||
fmt::print("Error: input folder {} is not a folder.\n", jak1_input_files.string());
|
||||
return 1;
|
||||
fmt::print("Note: input isn't a folder, assuming it's an ISO file...\n");
|
||||
auto path_to_iso_files = file_util::get_jak_project_dir() / "extracted_iso";
|
||||
std::filesystem::create_directories(path_to_iso_files);
|
||||
|
||||
auto fp = fopen(jak1_input_files.string().c_str(), "rb");
|
||||
ASSERT_MSG(fp, "failed to open input ISO file\n");
|
||||
unpack_iso_files(fp, path_to_iso_files);
|
||||
fclose(fp);
|
||||
jak1_input_files = path_to_iso_files;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(jak1_input_files / "DGO")) {
|
||||
|
||||
Reference in New Issue
Block a user