From 05d4b706b46c010df06f075d90c4127944cef8cf Mon Sep 17 00:00:00 2001 From: modeco80 Date: Sun, 12 Jan 2025 16:37:44 -0500 Subject: [PATCH] libeuropa/io: Refactor PakWriter for pakv5 sector alignment support This really could be classed a "fix", since adding support for it when reading broke writing. Now we do the right thing. This makes sector-alignment a no-op when writing other archive versions. I might make it an error to specify -s with a non-JSF package version. --- include/europa/io/PakFile.hpp | 12 ++++++++-- src/libeuropa/io/PakWriter.cpp | 36 ++++++++++++++++++++-------- src/tools/eupak/main.cpp | 2 +- src/tools/eupak/tasks/CreateTask.cpp | 2 +- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/include/europa/io/PakFile.hpp b/include/europa/io/PakFile.hpp index 361b772..ef8c012 100644 --- a/include/europa/io/PakFile.hpp +++ b/include/europa/io/PakFile.hpp @@ -93,7 +93,7 @@ namespace europa::io { toc = value; } - void InitAs(structs::PakVersion version) { + void InitAs(structs::PakVersion version, bool aligned) { switch(version) { case structs::PakVersion::Ver3: toc = structs::PakHeader_V3::TocEntry {}; @@ -102,7 +102,10 @@ namespace europa::io { toc = structs::PakHeader_V4::TocEntry {}; break; case structs::PakVersion::Ver5: - toc = structs::PakHeader_V5::TocEntry {}; + if(aligned) + toc = structs::PakHeader_V5::TocEntry_SectorAligned {}; + else + toc = structs::PakHeader_V5::TocEntry {}; break; default: throw std::invalid_argument("Invalid PAK version to initalize TOC entry"); @@ -147,6 +150,11 @@ namespace europa::io { return std::get(toc); } + template + [[nodiscard]] T& GetTOCEntry() { + return std::get(toc); + } + std::uint32_t GetCreationUnixTime() const { std::uint32_t time {}; diff --git a/src/libeuropa/io/PakWriter.cpp b/src/libeuropa/io/PakWriter.cpp index cb5e57d..384d28f 100644 --- a/src/libeuropa/io/PakWriter.cpp +++ b/src/libeuropa/io/PakWriter.cpp @@ -64,15 +64,21 @@ namespace europa::io { // Leave space for the header os.seekp(sizeof(THeader), std::ostream::beg); - // Version 5 paks seem to have an additional bit of reserved data - // (which is all zeros.) - if(THeader::VERSION == structs::PakVersion::Ver5) { - os.seekp(6, std::ostream::cur); + if constexpr(THeader::VERSION == structs::PakVersion::Ver5) { + if(sectorAlignment == SectorAlignment::Align) { + pakHeader.sectorAlignment = util::kCDSectorSize; + pakHeader.sectorAlignedFlag = 1; + } else { + pakHeader.sectorAlignment = 0; + pakHeader.sectorAlignedFlag = 0; + } } - // Align the first file to start on the next sector boundary. - if(sectorAlignment == SectorAlignment::Align) - os.seekp(util::AlignBy(static_cast(os.tellp()), util::kCDSectorSize), std::istream::beg); + if constexpr(THeader::VERSION == structs::PakVersion::Ver5) { + // Align the first file to start on the next sector boundary. + if(sectorAlignment == SectorAlignment::Align) + os.seekp(util::AlignBy(static_cast(os.tellp()), util::kCDSectorSize), std::istream::beg); + } // Write all the file data for(auto& [filename, file] : sortedFiles) { @@ -84,6 +90,14 @@ namespace europa::io { tocEntry.offset = os.tellp(); }); + // For sector alignment. + if constexpr(THeader::VERSION == structs::PakVersion::Ver5) { + if(sectorAlignment == SectorAlignment::Align) { + auto& toc = file.GetTOCEntry(); + toc.startLBA = (os.tellp() / util::kCDSectorSize); + } + } + auto& fileData = file.GetData(); // Visit the file data sum type and do the right operation @@ -109,9 +123,11 @@ namespace europa::io { }); // clang-format on - // Align to the next sector boundary. - if(sectorAlignment == SectorAlignment::Align) - os.seekp(util::AlignBy(static_cast(os.tellp()), util::kCDSectorSize), std::istream::beg); + if constexpr(THeader::VERSION == structs::PakVersion::Ver5) { + // Align to the next sector boundary. + if(sectorAlignment == SectorAlignment::Align) + os.seekp(util::AlignBy(static_cast(os.tellp()), util::kCDSectorSize), std::istream::beg); + } sink.OnEvent({ PakProgressReportSink::FileEvent::EventCode::FileWriteEnd, filename }); diff --git a/src/tools/eupak/main.cpp b/src/tools/eupak/main.cpp index 4b4d877..9a36aba 100644 --- a/src/tools/eupak/main.cpp +++ b/src/tools/eupak/main.cpp @@ -61,7 +61,7 @@ int main(int argc, char** argv) { .metavar("VERSION"); createParser.add_argument("-s", "--sector-aligned") - .help(R"(Aligns all files in this new package to CD-ROM sector boundaries.)") + .help(R"(Aligns all files in this new package to CD-ROM sector boundaries. Only valid for -V jedistarfighter.)") .flag(); createParser.add_argument("output") diff --git a/src/tools/eupak/tasks/CreateTask.cpp b/src/tools/eupak/tasks/CreateTask.cpp index 8f33f89..37b4dd1 100644 --- a/src/tools/eupak/tasks/CreateTask.cpp +++ b/src/tools/eupak/tasks/CreateTask.cpp @@ -130,7 +130,7 @@ namespace eupak::tasks { eio::PakFile file; eio::PakFile::DataType pakData = eio::PakFileData::InitAsPath(ent.path()); - file.InitAs(args.pakVersion); + file.InitAs(args.pakVersion, args.sectorAligned); // Add data file.SetData(std::move(pakData));