2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-05-17 07:21:43 +00:00

feat: add support for extracting ipaks to ImageConverter

This commit is contained in:
Jan Laupetin
2026-05-11 21:58:25 +02:00
parent a2ab44da39
commit 36b4ec7781
6 changed files with 98 additions and 60 deletions
+79 -27
View File
@@ -8,8 +8,8 @@
#include "Image/IwiWriter27.h"
#include "Image/IwiWriter6.h"
#include "Image/IwiWriter8.h"
#include "Image/Texture.h"
#include "ImageConverterArgs.h"
#include "ObjContainer/IPak/IPak.h"
#include "Utils/Logging/Log.h"
#include "Utils/StringUtils.h"
@@ -27,36 +27,17 @@ namespace
{
constexpr auto EXTENSION_IWI = ".iwi";
constexpr auto EXTENSION_DDS = ".dds";
constexpr auto EXTENSION_IPAK = ".ipak";
class ImageConverterImpl final : public ImageConverter
class ImageConverter
{
public:
ImageConverterImpl()
: m_game_to_convert_to(std::nullopt)
explicit ImageConverter(const ImageConverterArgs& args)
: m_game_to_convert_to(args.m_game_to_convert_to)
{
}
bool Start(const int argc, const char** argv) override
{
con::init();
auto shouldContinue = true;
if (!m_args.ParseArgs(argc, argv, shouldContinue))
return false;
if (!shouldContinue)
return true;
m_game_to_convert_to = m_args.m_game_to_convert_to;
for (const auto& file : m_args.m_files_to_convert)
Convert(file);
return true;
}
private:
void Convert(const std::string& file)
void HandleFile(const std::string& file)
{
const fs::path filePath(file);
auto extension = filePath.extension().string();
@@ -66,10 +47,13 @@ namespace
ConvertIwi(filePath);
else if (extension == EXTENSION_DDS)
ConvertDds(filePath);
else if (extension == EXTENSION_IPAK)
ExtractIpak(filePath);
else
con::error("Unsupported extension {}", extension);
}
private:
bool ConvertIwi(const fs::path& iwiPath)
{
std::ifstream file(iwiPath, std::ios::in | std::ios::binary);
@@ -195,6 +179,60 @@ namespace
return true;
}
bool ExtractIpak(const fs::path& ipakPath)
{
auto file = std::make_unique<std::ifstream>(ipakPath, std::ios::in | std::ios::binary);
if (!file->is_open())
{
con::error("Failed to open ipak {}", ipakPath.string());
return false;
}
auto ipak = IIPak::Create(ipakPath.string(), std::move(file));
if (!ipak->Initialize())
{
con::error("Failed to read ipak {}", ipakPath.string());
return false;
}
const auto outDir = fs::absolute(ipakPath).parent_path() / ipakPath.filename().replace_extension();
fs::create_directories(outDir);
for (const auto& indexEntry : ipak->GetIndexEntries())
{
const auto fileName = std::format("{:6x}_{:6x}.iwi", indexEntry.key.dataHash, indexEntry.key.nameHash);
std::ofstream outFile(outDir / fileName, std::ios::out | std::ios::binary);
if (!outFile.is_open())
{
con::error("Failed to open ipak file {}", fileName);
return false;
}
auto entryStream = ipak->GetEntryStream(indexEntry.key.nameHash, indexEntry.key.dataHash);
if (!entryStream)
{
con::error("Failed to open entry stream for {}", fileName);
return false;
}
char buffer[0x2000];
entryStream->read(buffer, 0x2000);
auto readCount = entryStream->gcount();
while (readCount > 0)
{
outFile.write(buffer, readCount);
entryStream->read(buffer, 0x2000);
readCount = entryStream->gcount();
}
entryStream->close();
outFile.close();
}
return true;
}
ImageConverterArgs m_args;
std::optional<GameId> m_game_to_convert_to;
DdsWriter m_dds_writer;
@@ -202,7 +240,21 @@ namespace
};
} // namespace
std::unique_ptr<ImageConverter> ImageConverter::Create()
bool RunImageConverter(const int argc, const char** argv)
{
return std::make_unique<ImageConverterImpl>();
con::init();
auto shouldContinue = true;
ImageConverterArgs args;
if (!args.ParseArgs(argc, argv, shouldContinue))
return false;
if (!shouldContinue)
return true;
ImageConverter imageConverter(args);
for (const auto& file : args.m_files_to_convert)
imageConverter.HandleFile(file);
return true;
}