feat(tools): Add tool to create RIM archives from folders
This commit is contained in:
parent
9ac90910ac
commit
be572da467
11 changed files with 208 additions and 16 deletions
|
@ -108,6 +108,7 @@ set(RESOURCE_HEADERS
|
|||
src/resource/format/lytreader.h
|
||||
src/resource/format/pereader.h
|
||||
src/resource/format/rimreader.h
|
||||
src/resource/format/rimwriter.h
|
||||
src/resource/format/ssfreader.h
|
||||
src/resource/format/tlkreader.h
|
||||
src/resource/format/visreader.h
|
||||
|
@ -135,6 +136,7 @@ set(RESOURCE_SOURCES
|
|||
src/resource/format/lytreader.cpp
|
||||
src/resource/format/pereader.cpp
|
||||
src/resource/format/rimreader.cpp
|
||||
src/resource/format/rimwriter.cpp
|
||||
src/resource/format/ssfreader.cpp
|
||||
src/resource/format/tlkreader.cpp
|
||||
src/resource/format/visreader.cpp
|
||||
|
|
|
@ -68,6 +68,11 @@ void StreamWriter::putBytes(const ByteArray &bytes) {
|
|||
_stream->write(&bytes[0], bytes.size());
|
||||
}
|
||||
|
||||
void StreamWriter::putBytes(int count, uint8_t val) {
|
||||
ByteArray data(count, val);
|
||||
_stream->write(&data[0], count);
|
||||
}
|
||||
|
||||
size_t StreamWriter::tell() const {
|
||||
return _stream->tellp();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
void putString(const std::string &str);
|
||||
void putCString(const std::string &str);
|
||||
void putBytes(const ByteArray &bytes);
|
||||
void putBytes(int count, uint8_t val = 0);
|
||||
|
||||
size_t tell() const;
|
||||
|
||||
|
|
76
src/resource/format/rimwriter.cpp
Normal file
76
src/resource/format/rimwriter.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rimwriter.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "../../common/streamwriter.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace resource {
|
||||
|
||||
void RimWriter::add(Resource &&res) {
|
||||
_resources.push_back(res);
|
||||
}
|
||||
|
||||
void RimWriter::save(const fs::path &path) {
|
||||
auto rim = make_shared<fs::ofstream>(path, ios::binary);
|
||||
StreamWriter writer(rim);
|
||||
uint32_t numResources = static_cast<uint32_t>(_resources.size());
|
||||
|
||||
writer.putString("RIM V1.0");
|
||||
writer.putUint32(0); // reserved
|
||||
writer.putUint32(numResources);
|
||||
writer.putUint32(0x78); // offset to resource headers
|
||||
writer.putBytes(100); // reserved
|
||||
|
||||
uint32_t id = 0;
|
||||
uint32_t offset = 0x78 + numResources * 32;
|
||||
|
||||
// Write resource headers
|
||||
for (auto &res : _resources) {
|
||||
auto size = static_cast<uint32_t>(res.data.size());
|
||||
|
||||
string resRef(res.resRef);
|
||||
resRef.resize(16);
|
||||
writer.putString(resRef);
|
||||
|
||||
writer.putUint32(static_cast<uint32_t>(res.resType));
|
||||
writer.putUint32(id++);
|
||||
writer.putUint32(offset);
|
||||
writer.putUint32(size);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
// Write resources data
|
||||
for (auto &res : _resources) {
|
||||
writer.putBytes(res.data);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace resource
|
||||
|
||||
} // namespace reone
|
50
src/resource/format/rimwriter.h
Normal file
50
src/resource/format/rimwriter.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021 The reone project contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "../../common/types.h"
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
namespace reone {
|
||||
|
||||
namespace resource {
|
||||
|
||||
class RimWriter {
|
||||
public:
|
||||
struct Resource {
|
||||
std::string resRef;
|
||||
ResourceType resType { ResourceType::Invalid };
|
||||
ByteArray data;
|
||||
};
|
||||
|
||||
void add(Resource &&res);
|
||||
void save(const boost::filesystem::path &path);
|
||||
|
||||
private:
|
||||
std::vector<Resource> _resources;
|
||||
};
|
||||
|
||||
} // namespace resource
|
||||
|
||||
} // namespace reone
|
|
@ -97,7 +97,7 @@ const string &getExtByResType(ResourceType type) {
|
|||
return g_extByType[type];
|
||||
}
|
||||
|
||||
ResourceType getResTypeByExt(const string &ext) {
|
||||
ResourceType getResTypeByExt(const string &ext, bool logNotFound) {
|
||||
if (!g_typeByExtInited) {
|
||||
for (auto &entry : g_extByType) {
|
||||
g_typeByExt.insert(make_pair(entry.second, entry.first));
|
||||
|
@ -106,7 +106,9 @@ ResourceType getResTypeByExt(const string &ext) {
|
|||
}
|
||||
auto it = g_typeByExt.find(ext);
|
||||
if (it == g_typeByExt.end()) {
|
||||
warn("Resource type not found by extension: " + ext);
|
||||
if (logNotFound) {
|
||||
warn("Resource type not found by extension: " + ext);
|
||||
}
|
||||
return ResourceType::Invalid;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace reone {
|
|||
namespace resource {
|
||||
|
||||
const std::string &getExtByResType(ResourceType type);
|
||||
ResourceType getResTypeByExt(const std::string &ext);
|
||||
ResourceType getResTypeByExt(const std::string &ext, bool logNotFound = true);
|
||||
|
||||
} // namespace resource
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ static const unordered_map<string, Operation> g_operations {
|
|||
{ "to-json", Operation::ToJSON },
|
||||
{ "to-tga", Operation::ToTGA },
|
||||
{ "to-2da", Operation::To2DA },
|
||||
{ "to-gff", Operation::ToGFF }
|
||||
{ "to-gff", Operation::ToGFF },
|
||||
{ "to-rim", Operation::ToRIM },
|
||||
};
|
||||
|
||||
Program::Program(int argc, char **argv) : _argc(argc), _argv(argv) {
|
||||
|
@ -93,6 +94,7 @@ void Program::initOptions() {
|
|||
("to-tga", "convert TPC image to TGA")
|
||||
("to-2da", "convert JSON to 2DA")
|
||||
("to-gff", "convert JSON to GFF")
|
||||
("to-rim", "create RIM archive from directory")
|
||||
("target", po::value<string>(), "target name or path to input file");
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "../src/resource/format/rimwriter.h"
|
||||
#include "../src/resource/typeutil.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -32,13 +33,23 @@ namespace reone {
|
|||
namespace tools {
|
||||
|
||||
void RimTool::invoke(Operation operation, const fs::path &target, const fs::path &gamePath, const fs::path &destPath) {
|
||||
RimReader rim;
|
||||
rim.load(target);
|
||||
|
||||
if (operation == Operation::List) {
|
||||
list(rim);
|
||||
} else if (operation == Operation::Extract) {
|
||||
extract(rim, destPath);
|
||||
switch (operation) {
|
||||
case Operation::List:
|
||||
case Operation::Extract: {
|
||||
RimReader rim;
|
||||
rim.load(target);
|
||||
if (operation == Operation::List) {
|
||||
list(rim);
|
||||
} else if (operation == Operation::Extract) {
|
||||
extract(rim, destPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Operation::ToRIM:
|
||||
toRIM(target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,11 +76,52 @@ void RimTool::extract(RimReader &rim, const fs::path &destPath) {
|
|||
}
|
||||
}
|
||||
|
||||
void RimTool::toRIM(const fs::path &target) {
|
||||
RimWriter rim;
|
||||
|
||||
for (auto &entry : fs::directory_iterator(target)) {
|
||||
fs::path path(entry);
|
||||
if (fs::is_directory(path)) continue;
|
||||
|
||||
string ext(path.extension().string());
|
||||
ext.erase(0, 1);
|
||||
|
||||
ResourceType resType = getResTypeByExt(ext, false);
|
||||
if (resType == ResourceType::Invalid) continue;
|
||||
|
||||
fs::ifstream in(path, ios::binary);
|
||||
in.seekg(0, ios::end);
|
||||
size_t size = in.tellg();
|
||||
ByteArray data(size);
|
||||
in.seekg(0);
|
||||
in.read(&data[0], size);
|
||||
|
||||
fs::path resRef(path.filename());
|
||||
resRef.replace_extension("");
|
||||
|
||||
RimWriter::Resource res;
|
||||
res.resRef = resRef.string();
|
||||
res.resType = resType;
|
||||
res.data = move(data);
|
||||
|
||||
rim.add(move(res));
|
||||
}
|
||||
|
||||
fs::path rimPath(target.parent_path());
|
||||
rimPath.append(target.filename().string() + ".rim");
|
||||
rim.save(rimPath);
|
||||
}
|
||||
|
||||
bool RimTool::supports(Operation operation, const fs::path &target) const {
|
||||
return
|
||||
!fs::is_directory(target) &&
|
||||
target.extension() == ".rim" &&
|
||||
(operation == Operation::List || operation == Operation::Extract);
|
||||
switch (operation) {
|
||||
case Operation::List:
|
||||
case Operation::Extract:
|
||||
return !fs::is_directory(target) && target.extension() == ".rim";
|
||||
case Operation::ToRIM:
|
||||
return fs::is_directory(target);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
private:
|
||||
void list(const resource::RimReader &rim);
|
||||
void extract(resource::RimReader &rim, const boost::filesystem::path &destPath);
|
||||
void toRIM(const boost::filesystem::path &target);
|
||||
};
|
||||
|
||||
class TwoDaTool : public ITool {
|
||||
|
|
|
@ -28,7 +28,8 @@ enum class Operation {
|
|||
ToJSON,
|
||||
ToTGA,
|
||||
To2DA,
|
||||
ToGFF
|
||||
ToGFF,
|
||||
ToRIM
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
|
Loading…
Reference in a new issue