Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/vpkpp/format/PAK.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ constexpr auto PAK_SIGNATURE = sourcepp::parser::binary::makeFourCC("PACK");
constexpr uint8_t PAK_SIN_FILENAME_MAX_SIZE = 120;
constexpr auto PAK_SIN_SIGNATURE = sourcepp::parser::binary::makeFourCC("SPAK");

constexpr auto PAK_SIN_RELOADED_SIGNATURE = sourcepp::parser::binary::makeFourCC("SRPK");

constexpr uint8_t PAK_HROT_FILENAME_MAX_SIZE = 120;
constexpr auto PAK_HROT_SIGNATURE = sourcepp::parser::binary::makeFourCC("HROT");

Expand All @@ -25,6 +27,7 @@ class PAK : public PackFile {
enum class Type {
PAK,
SIN,
SIN_RELOADED,
HROT,
};

Expand Down
139 changes: 112 additions & 27 deletions src/vpkpp/format/PAK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ std::unique_ptr<PackFile> PAK::create(const std::string& path, Type type) {
case Type::SIN:
stream << PAK_SIN_SIGNATURE;
break;
case Type::SIN_RELOADED:
stream << PAK_SIN_RELOADED_SIGNATURE;
break;
case Type::HROT:
stream << PAK_HROT_SIGNATURE;
break;
Expand Down Expand Up @@ -46,30 +49,66 @@ std::unique_ptr<PackFile> PAK::open(const std::string& path, const EntryCallback
pak->type = Type::PAK;
} else if (signature == PAK_SIN_SIGNATURE) {
pak->type = Type::SIN;
} else if (signature == PAK_SIN_RELOADED_SIGNATURE) {
pak->type = Type::SIN_RELOADED;
} else if (signature == PAK_HROT_SIGNATURE) {
pak->type = Type::HROT;
} else {
// File is not a PAK
return nullptr;
}

const auto directoryOffset = reader.read<uint32_t>();
// Directory size / file entry size
const auto fileCount = reader.read<uint32_t>() / (sizeof(uint32_t) * 2 + pak->getFilenameLength());
if (pak->type == Type::SIN_RELOADED) {
const auto reserved = reader.read<int32_t>();
const auto directoryOffset = reader.read<uint64_t>();
const auto namesOffset = reader.read<uint64_t>();
const auto fileCount = reader.read<uint32_t>();
const auto namesLength = reader.read<uint32_t>();

// read names buffer
std::string namesBuffer;
reader.seek_in(namesOffset);
reader.read(namesBuffer, namesLength, false);

reader.seek_in(directoryOffset);
for (uint32_t i = 0; i < fileCount; i++) {
Entry entry = createNewEntry();
// read directory
reader.seek_in(directoryOffset);
for (uint32_t i = 0; i < fileCount; i++) {
Entry entry = createNewEntry();

auto entryPath = pak->cleanEntryPath(reader.read_string(pak->getFilenameLength()));
const auto filePos = reader.read<uint64_t>();
const auto fileLen = reader.read<uint32_t>();
const auto nameOfs = reader.read<uint32_t>();

entry.offset = reader.read<uint32_t>();
entry.length = reader.read<uint32_t>();
auto entryPath = pak->cleanEntryPath(namesBuffer.c_str() + nameOfs);

pak->entries.emplace(entryPath, entry);
entry.offset = filePos;
entry.length = fileLen;

if (callback) {
callback(entryPath, entry);
pak->entries.emplace(entryPath, entry);

if (callback) {
callback(entryPath, entry);
}
}
} else {
const auto directoryOffset = reader.read<uint32_t>();
// Directory size / file entry size
const auto fileCount = reader.read<uint32_t>() / (sizeof(uint32_t) * 2 + pak->getFilenameLength());

reader.seek_in(directoryOffset);
for (uint32_t i = 0; i < fileCount; i++) {
Entry entry = createNewEntry();

auto entryPath = pak->cleanEntryPath(reader.read_string(pak->getFilenameLength()));

entry.offset = reader.read<uint32_t>();
entry.length = reader.read<uint32_t>();

pak->entries.emplace(entryPath, entry);

if (callback) {
callback(entryPath, entry);
}
}
}

Expand Down Expand Up @@ -115,11 +154,16 @@ bool PAK::bake(const std::string& outputDir_, BakeOptions options, const EntryCa

// Read data before overwriting, we don't know if we're writing to ourself
std::vector<std::byte> fileData;
std::vector<std::byte> nameData;
for (auto& [path, entry] : entriesToBake) {
if (auto binData = this->readEntry(path)) {
entry->offset = fileData.size();

fileData.insert(fileData.end(), binData->begin(), binData->end());

size_t oldSize = nameData.size();
nameData.resize(oldSize + path.size() + 1);
memcpy(&nameData[oldSize], path.data(), path.size());
} else {
entry->offset = 0;
entry->length = 0;
Expand All @@ -133,24 +177,63 @@ bool PAK::bake(const std::string& outputDir_, BakeOptions options, const EntryCa
// Signature
stream.write<uint32_t>(this->getSignature());

// Offset and size of directory
static constexpr auto HEADER_OFFSET = sizeof(uint32_t) * 3;
stream
.write<uint32_t>(HEADER_OFFSET + fileData.size())
.write<uint32_t>(entriesToBake.size() * (sizeof(uint32_t) * 2 + this->getFilenameLength()));
// Header
if (this->type == Type::SIN_RELOADED) {
// Reserved value
// Basically a version identifier, but not used...?
stream.write<int32_t>(0);

// File data
stream.write(fileData);
// Offset of directory
static constexpr auto HEADER_OFFSET = sizeof(uint32_t) * 3 + sizeof(uint64_t) * 2;
stream.write<uint64_t>(HEADER_OFFSET + fileData.size());

// Directory
for (const auto& [path, entry] : entriesToBake) {
stream
.write(path, true, this->getFilenameLength())
.write<uint32_t>(entry->offset + HEADER_OFFSET)
.write<uint32_t>(entry->length);
// Offset of names
uint32_t numFiles = entriesToBake.size();
uint64_t directorySize = (sizeof(uint64_t) + (sizeof(uint32_t) * 2)) * numFiles;
stream.write<uint64_t>(HEADER_OFFSET + fileData.size() + directorySize);

if (callback) {
callback(path, *entry);
// Number of files
stream.write<uint32_t>(numFiles);

// Size of names
stream.write<uint32_t>(nameData.size());

// File data
stream.write(fileData);

// Directory
for (const auto& [path, entry] : entriesToBake) {
stream
.write<uint64_t>(entry->offset + HEADER_OFFSET)
.write<uint32_t>(entry->length);

if (callback) {
callback(path, *entry);
}
}

// Names
stream.write(nameData);
} else {
// Offset and size of directory
static constexpr auto HEADER_OFFSET = sizeof(uint32_t) * 3;
stream
.write<uint32_t>(HEADER_OFFSET + fileData.size())
.write<uint32_t>(entriesToBake.size() * (sizeof(uint32_t) * 2 + this->getFilenameLength()));

// File data
stream.write(fileData);

// Directory
for (const auto& [path, entry] : entriesToBake) {
stream
.write(path, true, this->getFilenameLength())
.write<uint32_t>(entry->offset + HEADER_OFFSET)
.write<uint32_t>(entry->length);

if (callback) {
callback(path, *entry);
}
}
}
}
Expand Down Expand Up @@ -180,6 +263,8 @@ uint32_t PAK::getSignature() const {
return PAK_SIGNATURE;
case Type::SIN:
return PAK_SIN_SIGNATURE;
case Type::SIN_RELOADED:
return PAK_SIN_RELOADED_SIGNATURE;
case Type::HROT:
return PAK_HROT_SIGNATURE;
}
Expand Down
Loading