Files
jak-project/common/util/read_iso_file.cpp
T
ManDude 7d5045ab3f PAL & NTSC-J support + updates (#1490)
* PAL dumps files

* alrighty then

* make PAL warning slightly more specific

* PAL patches for `title-obs`

* Update all-types.gc

* PAL patch `beach-obs`

* `process-taskable` PAL patch

* `ambient` PAL patch

* `yakow` PAL patch

* `village-obs` PAL patch

* `sparticle-launcher` patch

* `swamp-obs` PAL patch

* `sequence-a-village1` PAL patch

* typo

* errors

* `powerups` PAL patch

* `ogreboss` PAL patch

* jak 1 v2 encoding

* `load-boundary` PAL patch

* `flying-lurker` PAL patch

* `mayor` PAL patch

* update game encoding to PAL (v2) encoding

* `cam-debug` and `cam-update` PAL patch

* `fisher` PAL patch

* `target` PAL patch

* `target2` PAL patch and fix text compiling

* `target-death` PAL patch

* `target-racer-h` PAL patch

* `logic-target` PAL patch

* `main` PAL patch

* `snow-flutflut-obs` PAL patch

* `rolling-obs` PAL patch

* `gsound` PAL patch

* update refs

* `progress` and `progress-draw` PAL patches

* clang

* wrong.

* complain

* clang

* fix test

* fix blurry jp text

* fix weird interrupt lag from setting window size

* patch more text lines, special handling for credits

* Update FontUtils.cpp

* Add xdelta3 and file patching interface

* add window lock toggle and update settings ver

* better particle hacks

* add PAL support to extractor

* Fix credits

* also NTSC-J support

* make xdelta3 a separate library

* address feedback

Co-authored-by: water <awaterford111445@gmail.com>
2022-06-22 05:16:34 +01:00

136 lines
4.2 KiB
C++

#include "read_iso_file.h"
#include "common/log/log.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,
IsoFile& iso,
const IsoFile::Entry& entry,
const std::filesystem::path& dest,
bool print_progress) {
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, iso, child, path_to_entry, print_progress);
}
} else {
if (print_progress) {
lg::info("Extracting {}...", entry.name);
}
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());
iso.files_extracted++;
if (iso.shouldHash) {
xxh::hash_t<64> hash = xxh::xxhash<64>(buffer);
iso.hashes.push_back(hash);
}
}
}
} // 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,
IsoFile& layout,
const std::filesystem::path& dest,
bool print_progress) {
unpack_entry(fp, layout, layout.root, dest, print_progress);
}
IsoFile unpack_iso_files(FILE* fp,
const std::filesystem::path& dest,
bool print_progress,
const bool hashFiles) {
auto file = find_files_in_iso(fp);
file.shouldHash = hashFiles;
unpack_iso_files(fp, file, dest, print_progress);
return file;
}