114 lines
3.3 KiB
C++
114 lines
3.3 KiB
C++
#include <XCEngine/Core/Asset/ArtifactContainer.h>
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
namespace fs = std::filesystem;
|
|
using namespace XCEngine::Resources;
|
|
|
|
namespace {
|
|
|
|
void PrintUsage() {
|
|
std::cout
|
|
<< "Usage:\n"
|
|
<< " artifact_inspect <artifact-path>\n"
|
|
<< " artifact_inspect <artifact-path> --extract <entry-name> <output-path>\n";
|
|
}
|
|
|
|
bool WritePayloadToFile(const fs::path& outputPath,
|
|
const XCEngine::Containers::Array<XCEngine::Core::uint8>& payload) {
|
|
std::error_code ec;
|
|
const fs::path parent = outputPath.parent_path();
|
|
if (!parent.empty()) {
|
|
fs::create_directories(parent, ec);
|
|
if (ec) {
|
|
std::cerr << "Failed to create output directory: " << parent.string() << "\n";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::ofstream output(outputPath, std::ios::binary | std::ios::trunc);
|
|
if (!output.is_open()) {
|
|
std::cerr << "Failed to open output file: " << outputPath.string() << "\n";
|
|
return false;
|
|
}
|
|
|
|
if (!payload.Empty()) {
|
|
output.write(reinterpret_cast<const char*>(payload.Data()),
|
|
static_cast<std::streamsize>(payload.Size()));
|
|
}
|
|
|
|
if (!output) {
|
|
std::cerr << "Failed to write output file: " << outputPath.string() << "\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void PrintEntry(const ArtifactContainerEntryView& entry) {
|
|
std::cout
|
|
<< "- name: " << entry.name.CStr()
|
|
<< ", type: " << GetResourceTypeName(entry.resourceType)
|
|
<< ", localID: " << entry.localID
|
|
<< ", size: " << entry.payloadSize
|
|
<< "\n";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 2 && argc != 5) {
|
|
PrintUsage();
|
|
return 1;
|
|
}
|
|
|
|
const XCEngine::Containers::String artifactPath(argv[1] == nullptr ? "" : argv[1]);
|
|
|
|
ArtifactContainerReader reader;
|
|
XCEngine::Containers::String errorMessage;
|
|
if (!reader.Open(artifactPath, &errorMessage)) {
|
|
std::cerr
|
|
<< "Failed to open artifact container: "
|
|
<< (errorMessage.Empty() ? artifactPath.CStr() : errorMessage.CStr())
|
|
<< "\n";
|
|
return 2;
|
|
}
|
|
|
|
std::cout << "Artifact: " << reader.GetPath().CStr() << "\n";
|
|
std::cout << "Entries: " << reader.GetEntryCount() << "\n";
|
|
for (const ArtifactContainerEntryView& entry : reader.GetEntries()) {
|
|
PrintEntry(entry);
|
|
}
|
|
|
|
if (argc == 5) {
|
|
const std::string mode = argv[2] == nullptr ? std::string() : std::string(argv[2]);
|
|
if (mode != "--extract") {
|
|
PrintUsage();
|
|
return 1;
|
|
}
|
|
|
|
const XCEngine::Containers::String entryName(argv[3] == nullptr ? "" : argv[3]);
|
|
XCEngine::Containers::Array<XCEngine::Core::uint8> payload;
|
|
if (!reader.ReadEntryPayload(entryName, payload, &errorMessage)) {
|
|
std::cerr
|
|
<< "Failed to read entry payload: "
|
|
<< (errorMessage.Empty() ? entryName.CStr() : errorMessage.CStr())
|
|
<< "\n";
|
|
return 3;
|
|
}
|
|
|
|
const fs::path outputPath(argv[4] == nullptr ? "" : argv[4]);
|
|
if (!WritePayloadToFile(outputPath, payload)) {
|
|
return 4;
|
|
}
|
|
|
|
std::cout
|
|
<< "Extracted entry '" << entryName.CStr() << "' to " << outputPath.string() << "\n";
|
|
}
|
|
|
|
return 0;
|
|
}
|