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.
This commit is contained in:
Lily Tsuru 2025-01-12 16:37:44 -05:00
parent dc95b3ba9c
commit 05d4b706b4
4 changed files with 38 additions and 14 deletions

View file

@ -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<T>(toc);
}
template <class T>
[[nodiscard]] T& GetTOCEntry() {
return std::get<T>(toc);
}
std::uint32_t GetCreationUnixTime() const {
std::uint32_t time {};

View file

@ -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<std::size_t>(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<std::size_t>(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<structs::PakHeader_V5::TocEntry_SectorAligned>();
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<std::size_t>(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<std::size_t>(os.tellp()), util::kCDSectorSize), std::istream::beg);
}
sink.OnEvent({ PakProgressReportSink::FileEvent::EventCode::FileWriteEnd,
filename });

View file

@ -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")

View file

@ -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));