mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Rename cxx directory to cpp
Also update the crate name and references to it. This helps distinguish the C++ wrapper that's built using CXX from CXX itself.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
|
||||
|
||||
#include "loot/api.h"
|
||||
|
||||
#include "api/game.h"
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
extern "C" {
|
||||
extern const unsigned int LIBLOOT_VERSION_MAJOR;
|
||||
|
||||
extern const unsigned int LIBLOOT_VERSION_MINOR;
|
||||
|
||||
extern const unsigned int LIBLOOT_VERSION_PATCH;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_TRACE;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_DEBUG;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_INFO;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_WARNING;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_ERROR;
|
||||
|
||||
extern const uint8_t LIBLOOT_LOG_LEVEL_FATAL;
|
||||
|
||||
void libloot_set_logging_callback(void (*callback)(uint8_t, const char*, void*),
|
||||
void* context);
|
||||
}
|
||||
|
||||
namespace {
|
||||
using loot::LogLevel;
|
||||
|
||||
typedef std::function<void(LogLevel, std::string_view)> Callback;
|
||||
|
||||
static Callback STORED_CALLBACK;
|
||||
|
||||
LogLevel convert(uint8_t level) {
|
||||
if (level == LIBLOOT_LOG_LEVEL_TRACE) {
|
||||
return LogLevel::trace;
|
||||
} else if (level == LIBLOOT_LOG_LEVEL_DEBUG) {
|
||||
return LogLevel::debug;
|
||||
} else if (level == LIBLOOT_LOG_LEVEL_INFO) {
|
||||
return LogLevel::info;
|
||||
} else if (level == LIBLOOT_LOG_LEVEL_WARNING) {
|
||||
return LogLevel::warning;
|
||||
} else if (level == LIBLOOT_LOG_LEVEL_ERROR) {
|
||||
return LogLevel::error;
|
||||
} else {
|
||||
return LogLevel::fatal;
|
||||
}
|
||||
}
|
||||
|
||||
loot::rust::LogLevel convert(LogLevel level) {
|
||||
switch (level) {
|
||||
case LogLevel::trace:
|
||||
return loot::rust::LogLevel::Trace;
|
||||
case LogLevel::debug:
|
||||
return loot::rust::LogLevel::Debug;
|
||||
case LogLevel::info:
|
||||
return loot::rust::LogLevel::Info;
|
||||
case LogLevel::warning:
|
||||
return loot::rust::LogLevel::Warning;
|
||||
case LogLevel::error:
|
||||
return loot::rust::LogLevel::Error;
|
||||
case LogLevel::fatal:
|
||||
return loot::rust::LogLevel::Fatal;
|
||||
default:
|
||||
return loot::rust::LogLevel::Trace;
|
||||
}
|
||||
}
|
||||
|
||||
void logging_callback(uint8_t level, const char* message, void* context) {
|
||||
auto& callback = *static_cast<Callback*>(context);
|
||||
|
||||
callback(convert(level), message);
|
||||
}
|
||||
}
|
||||
|
||||
namespace loot {
|
||||
LOOT_API void SetLoggingCallback(Callback callback) {
|
||||
STORED_CALLBACK = callback;
|
||||
libloot_set_logging_callback(logging_callback, &STORED_CALLBACK);
|
||||
}
|
||||
|
||||
LOOT_API void SetLogLevel(LogLevel level) {
|
||||
loot::rust::set_log_level(convert(level));
|
||||
}
|
||||
|
||||
LOOT_API bool IsCompatible(const unsigned int versionMajor,
|
||||
const unsigned int versionMinor,
|
||||
const unsigned int versionPatch) {
|
||||
return loot::rust::is_compatible(versionMajor, versionMinor, versionPatch);
|
||||
}
|
||||
|
||||
LOOT_API std::unique_ptr<GameInterface> CreateGameHandle(
|
||||
const GameType game,
|
||||
const std::filesystem::path& gamePath,
|
||||
const std::filesystem::path& gameLocalPath) {
|
||||
return std::make_unique<Game>(game, gamePath, gameLocalPath);
|
||||
}
|
||||
|
||||
LOOT_API std::string GetLiblootVersion() {
|
||||
return std::string(loot::rust::libloot_version());
|
||||
}
|
||||
|
||||
LOOT_API std::string GetLiblootRevision() {
|
||||
return std::string(loot::rust::libloot_revision());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
#include "api/convert.h"
|
||||
|
||||
#include "api/exception.h"
|
||||
|
||||
namespace loot {
|
||||
// To public types
|
||||
/////////////////////
|
||||
|
||||
std::string convert(const ::rust::String& string) {
|
||||
return std::string(string);
|
||||
}
|
||||
|
||||
// Although there's an explicit conversion operator declared, it seems that
|
||||
// building the CXX wrapper with MSVC doesn't set __cplusplus correctly as using
|
||||
// the operator causes a linker error, so this just reimpls it as a function.
|
||||
std::string_view convert(::rust::Str str) {
|
||||
return std::string_view(str.data(), str.length());
|
||||
}
|
||||
|
||||
loot::Group convert(const loot::rust::Group& group) {
|
||||
return loot::Group(convert(group.name()),
|
||||
convert<std::string>(group.after_groups()),
|
||||
convert(group.description()));
|
||||
}
|
||||
|
||||
loot::File convert(const loot::rust::File& file) {
|
||||
return loot::File(convert(file.filename().as_str()),
|
||||
convert(file.display_name()),
|
||||
convert(file.condition()),
|
||||
convert<loot::MessageContent>(file.detail()),
|
||||
convert(file.constraint()));
|
||||
}
|
||||
|
||||
loot::MessageType convert(loot::rust::MessageType messageType) {
|
||||
switch (messageType) {
|
||||
case loot::rust::MessageType::Say:
|
||||
return loot::MessageType::say;
|
||||
case loot::rust::MessageType::Warn:
|
||||
return loot::MessageType::warn;
|
||||
case loot::rust::MessageType::Error:
|
||||
return loot::MessageType::error;
|
||||
default:
|
||||
throw std::logic_error("Unsupported MessageType value");
|
||||
}
|
||||
}
|
||||
|
||||
loot::MessageContent convert(const loot::rust::MessageContent& content) {
|
||||
return loot::MessageContent(convert(content.text()),
|
||||
convert(content.language()));
|
||||
}
|
||||
|
||||
loot::Message convert(const loot::rust::Message& message) {
|
||||
return loot::Message(convert(message.message_type()),
|
||||
convert<loot::MessageContent>(message.content()),
|
||||
convert(message.condition()));
|
||||
}
|
||||
|
||||
loot::Tag convert(const loot::rust::Tag& tag) {
|
||||
return loot::Tag(
|
||||
convert(tag.name()), tag.is_addition(), convert(tag.condition()));
|
||||
}
|
||||
|
||||
loot::PluginCleaningData convert(const loot::rust::PluginCleaningData& data) {
|
||||
return loot::PluginCleaningData(data.crc(),
|
||||
convert(data.cleaning_utility()),
|
||||
convert<loot::MessageContent>(data.detail()),
|
||||
data.itm_count(),
|
||||
data.deleted_reference_count(),
|
||||
data.deleted_navmesh_count());
|
||||
}
|
||||
|
||||
loot::Location convert(const loot::rust::Location& location) {
|
||||
return loot::Location(convert(location.url()), convert(location.name()));
|
||||
}
|
||||
|
||||
loot::PluginMetadata convert(const loot::rust::PluginMetadata& metadata) {
|
||||
auto output = loot::PluginMetadata(convert(metadata.name()));
|
||||
|
||||
if (!metadata.group().empty()) {
|
||||
output.SetGroup(convert(metadata.group()));
|
||||
}
|
||||
|
||||
output.SetLoadAfterFiles(convert<loot::File>(metadata.load_after_files()));
|
||||
output.SetRequirements(convert<loot::File>(metadata.requirements()));
|
||||
output.SetIncompatibilities(
|
||||
convert<loot::File>(metadata.incompatibilities()));
|
||||
output.SetMessages(convert<loot::Message>(metadata.messages()));
|
||||
output.SetTags(convert<loot::Tag>(metadata.tags()));
|
||||
output.SetDirtyInfo(convert<loot::PluginCleaningData>(metadata.dirty_info()));
|
||||
output.SetCleanInfo(convert<loot::PluginCleaningData>(metadata.clean_info()));
|
||||
output.SetLocations(convert<loot::Location>(metadata.locations()));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::optional<loot::EdgeType> convert(uint8_t edgeType) {
|
||||
switch (edgeType) {
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::Hardcoded):
|
||||
return loot::EdgeType::hardcoded;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::MasterFlag):
|
||||
return loot::EdgeType::masterFlag;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::Master):
|
||||
return loot::EdgeType::master;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::MasterlistRequirement):
|
||||
return loot::EdgeType::masterlistRequirement;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::UserRequirement):
|
||||
return loot::EdgeType::userRequirement;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::MasterlistLoadAfter):
|
||||
return loot::EdgeType::masterlistLoadAfter;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::UserLoadAfter):
|
||||
return loot::EdgeType::userLoadAfter;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::MasterlistGroup):
|
||||
return loot::EdgeType::masterlistGroup;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::UserGroup):
|
||||
return loot::EdgeType::userGroup;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::RecordOverlap):
|
||||
return loot::EdgeType::recordOverlap;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::AssetOverlap):
|
||||
return loot::EdgeType::assetOverlap;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::TieBreak):
|
||||
return loot::EdgeType::tieBreak;
|
||||
case static_cast<uint8_t>(loot::rust::EdgeType::BlueprintMaster):
|
||||
return loot::EdgeType::blueprintMaster;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
loot::Vertex convert(const loot::rust::Vertex& vertex) {
|
||||
try {
|
||||
const auto outEdgeType = convert(vertex.out_edge_type());
|
||||
if (outEdgeType.has_value()) {
|
||||
return loot::Vertex(convert(vertex.name()), outEdgeType.value());
|
||||
} else {
|
||||
return loot::Vertex(convert(vertex.name()));
|
||||
}
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
// From public types
|
||||
///////////////////////
|
||||
|
||||
::rust::Str convert(std::string_view view) {
|
||||
return ::rust::Str(view.data(), view.length());
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::Group> convert(const loot::Group& group) {
|
||||
return loot::rust::new_group(
|
||||
group.GetName(), group.GetDescription(), convert(group.GetAfterGroups()));
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::File> convert(const loot::File& file) {
|
||||
try {
|
||||
return loot::rust::new_file(
|
||||
std::string(file.GetName()),
|
||||
file.GetDisplayName(),
|
||||
file.GetCondition(),
|
||||
::rust::Slice(convert<loot::rust::MessageContent>(file.GetDetail())),
|
||||
file.GetConstraint());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
loot::rust::MessageType convert(loot::MessageType messageType) {
|
||||
switch (messageType) {
|
||||
case loot::MessageType::say:
|
||||
return loot::rust::MessageType::Say;
|
||||
case loot::MessageType::warn:
|
||||
return loot::rust::MessageType::Warn;
|
||||
case loot::MessageType::error:
|
||||
return loot::rust::MessageType::Error;
|
||||
default:
|
||||
throw std::logic_error("Unsupported MessageType value");
|
||||
}
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::MessageContent> convert(
|
||||
const loot::MessageContent& content) {
|
||||
return loot::rust::new_message_content(content.GetText(),
|
||||
content.GetLanguage());
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::Message> convert(const loot::Message& message) {
|
||||
try {
|
||||
return loot::rust::multilingual_message(
|
||||
convert(message.GetType()),
|
||||
::rust::Slice(
|
||||
convert<loot::rust::MessageContent>(message.GetContent())),
|
||||
message.GetCondition());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::Tag> convert(const loot::Tag& tag) {
|
||||
try {
|
||||
const auto suggestion = tag.IsAddition()
|
||||
? loot::rust::TagSuggestion::Addition
|
||||
: loot::rust::TagSuggestion::Removal;
|
||||
return loot::rust::new_tag(tag.GetName(), suggestion, tag.GetCondition());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::PluginCleaningData> convert(
|
||||
const loot::PluginCleaningData& data) {
|
||||
try {
|
||||
return loot::rust::new_plugin_cleaning_data(
|
||||
data.GetCRC(),
|
||||
data.GetCleaningUtility(),
|
||||
::rust::Slice(convert<loot::rust::MessageContent>(data.GetDetail())),
|
||||
data.GetITMCount(),
|
||||
data.GetDeletedReferenceCount(),
|
||||
data.GetDeletedNavmeshCount());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::Location> convert(const loot::Location& location) {
|
||||
return loot::rust::new_location(location.GetURL(), location.GetName());
|
||||
}
|
||||
|
||||
::rust::Box<loot::rust::PluginMetadata> convert(
|
||||
const loot::PluginMetadata& metadata) {
|
||||
try {
|
||||
auto output = loot::rust::new_plugin_metadata(metadata.GetName());
|
||||
|
||||
if (metadata.GetGroup().has_value()) {
|
||||
output->set_group(metadata.GetGroup().value());
|
||||
}
|
||||
|
||||
output->set_load_after_files(
|
||||
::rust::Slice(convert<loot::rust::File>(metadata.GetLoadAfterFiles())));
|
||||
output->set_requirements(
|
||||
::rust::Slice(convert<loot::rust::File>(metadata.GetRequirements())));
|
||||
output->set_incompatibilities(::rust::Slice(
|
||||
convert<loot::rust::File>(metadata.GetIncompatibilities())));
|
||||
output->set_messages(
|
||||
::rust::Slice(convert<loot::rust::Message>(metadata.GetMessages())));
|
||||
output->set_tags(
|
||||
::rust::Slice(convert<loot::rust::Tag>(metadata.GetTags())));
|
||||
output->set_dirty_info(::rust::Slice(
|
||||
convert<loot::rust::PluginCleaningData>(metadata.GetDirtyInfo())));
|
||||
output->set_clean_info(::rust::Slice(
|
||||
convert<loot::rust::PluginCleaningData>(metadata.GetCleanInfo())));
|
||||
output->set_locations(
|
||||
::rust::Slice(convert<loot::rust::Location>(metadata.GetLocations())));
|
||||
|
||||
return output;
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
// Between containers
|
||||
////////////////////////
|
||||
|
||||
::rust::Vec<::rust::String> convert(const std::vector<std::string>& vector) {
|
||||
::rust::Vec<::rust::String> strings;
|
||||
for (const auto& str : vector) {
|
||||
strings.push_back(str);
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef LOOT_API_CONVERT
|
||||
#define LOOT_API_CONVERT
|
||||
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
#include "loot/metadata/group.h"
|
||||
#include "loot/metadata/plugin_metadata.h"
|
||||
#include "loot/vertex.h"
|
||||
|
||||
namespace loot {
|
||||
// To public types
|
||||
/////////////////////
|
||||
|
||||
std::string convert(const ::rust::String& string);
|
||||
|
||||
std::string_view convert(::rust::Str string);
|
||||
|
||||
loot::Group convert(const loot::rust::Group& group);
|
||||
|
||||
loot::File convert(const loot::rust::File& file);
|
||||
|
||||
loot::MessageType convert(loot::rust::MessageType messageType);
|
||||
|
||||
loot::MessageContent convert(const loot::rust::MessageContent& content);
|
||||
|
||||
loot::Message convert(const loot::rust::Message& message);
|
||||
|
||||
loot::Tag convert(const loot::rust::Tag& tag);
|
||||
|
||||
loot::PluginCleaningData convert(const loot::rust::PluginCleaningData& data);
|
||||
|
||||
loot::Location convert(const loot::rust::Location& location);
|
||||
|
||||
loot::PluginMetadata convert(const loot::rust::PluginMetadata& metadata);
|
||||
|
||||
std::optional<loot::EdgeType> convert(uint8_t edgeType);
|
||||
|
||||
loot::Vertex convert(const loot::rust::Vertex& vertex);
|
||||
|
||||
// From public types
|
||||
///////////////////////
|
||||
|
||||
::rust::Str convert(std::string_view view);
|
||||
|
||||
::rust::Box<loot::rust::Group> convert(const loot::Group& group);
|
||||
|
||||
::rust::Box<loot::rust::File> convert(const loot::File& file);
|
||||
|
||||
loot::rust::MessageType convert(loot::MessageType messageType);
|
||||
|
||||
::rust::Box<loot::rust::MessageContent> convert(
|
||||
const loot::MessageContent& content);
|
||||
|
||||
::rust::Box<loot::rust::Message> convert(const loot::Message& message);
|
||||
|
||||
::rust::Box<loot::rust::Tag> convert(const loot::Tag& tag);
|
||||
|
||||
::rust::Box<loot::rust::PluginCleaningData> convert(
|
||||
const loot::PluginCleaningData& data);
|
||||
|
||||
::rust::Box<loot::rust::Location> convert(const loot::Location& location);
|
||||
|
||||
::rust::Box<loot::rust::PluginMetadata> convert(
|
||||
const loot::PluginMetadata& metadata);
|
||||
|
||||
// Between containers
|
||||
////////////////////////
|
||||
|
||||
::rust::Vec<::rust::String> convert(const std::vector<std::string>& vector);
|
||||
|
||||
template<typename T, typename U>
|
||||
std::vector<T> convert(const ::rust::Slice<const U>& slice) {
|
||||
std::vector<T> output;
|
||||
for (const auto& element : slice) {
|
||||
output.push_back(convert(element));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
std::vector<T> convert(const ::rust::Vec<U>& vec) {
|
||||
return convert<T, U>(::rust::Slice(vec));
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
const std::vector<::rust::Box<T>> convert(const std::vector<U>& vec) {
|
||||
return convert<::rust::Box<T>, U>(::rust::Slice(vec));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
|
||||
#include "api/database.h"
|
||||
|
||||
#include "api/convert.h"
|
||||
#include "api/exception.h"
|
||||
|
||||
namespace loot {
|
||||
Database::Database(::rust::Box<loot::rust::Database>&& database) :
|
||||
database_(std::move(database)) {}
|
||||
|
||||
void Database::LoadMasterlist(const std::filesystem::path& masterlistPath) {
|
||||
try {
|
||||
database_->load_masterlist(masterlistPath.u8string());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::LoadMasterlistWithPrelude(
|
||||
const std::filesystem::path& masterlistPath,
|
||||
const std::filesystem::path& masterlistPreludePath) {
|
||||
try {
|
||||
database_->load_masterlist_with_prelude(masterlistPath.u8string(),
|
||||
masterlistPreludePath.u8string());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::LoadUserlist(const std::filesystem::path& userlistPath) {
|
||||
try {
|
||||
database_->load_userlist(userlistPath.u8string());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::WriteUserMetadata(const std::filesystem::path& outputFile,
|
||||
const bool overwrite) const {
|
||||
try {
|
||||
database_->write_user_metadata(outputFile.u8string(), overwrite);
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
bool Database::Evaluate(const std::string& condition) const {
|
||||
try {
|
||||
return database_->evaluate(condition);
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Database::GetKnownBashTags() const {
|
||||
try {
|
||||
return convert<std::string>(database_->known_bash_tags());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Message> Database::GetGeneralMessages(
|
||||
bool evaluateConditions) const {
|
||||
try {
|
||||
return convert<Message>(database_->general_messages(evaluateConditions));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Group> Database::GetGroups(bool includeUserMetadata) const {
|
||||
try {
|
||||
return convert<Group>(database_->groups(includeUserMetadata));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Group> Database::GetUserGroups() const {
|
||||
try {
|
||||
return convert<Group>(database_->user_groups());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::SetUserGroups(const std::vector<Group>& groups) {
|
||||
try {
|
||||
database_->set_user_groups(
|
||||
::rust::Slice(convert<loot::rust::Group>(groups)));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vertex> Database::GetGroupsPath(
|
||||
std::string_view fromGroupName,
|
||||
std::string_view toGroupName) const {
|
||||
try {
|
||||
return convert<Vertex>(
|
||||
database_->groups_path(convert(fromGroupName), convert(toGroupName)));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<PluginMetadata> Database::GetPluginMetadata(
|
||||
std::string_view plugin,
|
||||
bool includeUserMetadata,
|
||||
bool evaluateConditions) const {
|
||||
try {
|
||||
const auto metadata = database_->plugin_metadata(
|
||||
convert(plugin), includeUserMetadata, evaluateConditions);
|
||||
if (metadata->is_some()) {
|
||||
return convert(metadata->as_ref());
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<PluginMetadata> Database::GetPluginUserMetadata(
|
||||
std::string_view plugin,
|
||||
bool evaluateConditions) const {
|
||||
try {
|
||||
const auto metadata =
|
||||
database_->plugin_user_metadata(convert(plugin), evaluateConditions);
|
||||
if (metadata->is_some()) {
|
||||
return convert(metadata->as_ref());
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::SetPluginUserMetadata(const PluginMetadata& pluginMetadata) {
|
||||
try {
|
||||
database_->set_plugin_user_metadata(convert(pluginMetadata));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::DiscardPluginUserMetadata(std::string_view plugin) {
|
||||
try {
|
||||
database_->discard_plugin_user_metadata(convert(plugin));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::DiscardAllUserMetadata() {
|
||||
try {
|
||||
database_->discard_all_user_metadata();
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::WriteMinimalList(const std::filesystem::path& outputFile,
|
||||
const bool overwrite) const {
|
||||
try {
|
||||
database_->write_minimal_list(outputFile.u8string(), overwrite);
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifndef LOOT_API_DATABASE
|
||||
#define LOOT_API_DATABASE
|
||||
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
#include "loot/database_interface.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace loot {
|
||||
class Database final : public DatabaseInterface {
|
||||
public:
|
||||
explicit Database(::rust::Box<loot::rust::Database>&& database);
|
||||
|
||||
void LoadMasterlist(const std::filesystem::path& masterlist_path) override;
|
||||
|
||||
void LoadMasterlistWithPrelude(
|
||||
const std::filesystem::path& masterlist_path,
|
||||
const std::filesystem::path& masterlist_prelude_path) override;
|
||||
|
||||
void LoadUserlist(const std::filesystem::path& userlist_path) override;
|
||||
|
||||
void WriteUserMetadata(const std::filesystem::path& outputFile,
|
||||
const bool overwrite) const override;
|
||||
|
||||
void WriteMinimalList(const std::filesystem::path& outputFile,
|
||||
const bool overwrite) const override;
|
||||
|
||||
bool Evaluate(const std::string& condition) const override;
|
||||
|
||||
std::vector<std::string> GetKnownBashTags() const override;
|
||||
|
||||
std::vector<Message> GetGeneralMessages(
|
||||
bool evaluateConditions = false) const override;
|
||||
|
||||
std::vector<Group> GetGroups(bool includeUserMetadata = true) const override;
|
||||
std::vector<Group> GetUserGroups() const override;
|
||||
void SetUserGroups(const std::vector<Group>& groups) override;
|
||||
std::vector<Vertex> GetGroupsPath(
|
||||
std::string_view fromGroupName,
|
||||
std::string_view toGroupName) const override;
|
||||
|
||||
std::optional<PluginMetadata> GetPluginMetadata(
|
||||
std::string_view plugin,
|
||||
bool includeUserMetadata = true,
|
||||
bool evaluateConditions = false) const override;
|
||||
|
||||
std::optional<PluginMetadata> GetPluginUserMetadata(
|
||||
std::string_view plugin,
|
||||
bool evaluateConditions = false) const override;
|
||||
|
||||
void SetPluginUserMetadata(const PluginMetadata& pluginMetadata) override;
|
||||
|
||||
void DiscardPluginUserMetadata(std::string_view plugin) override;
|
||||
|
||||
void DiscardAllUserMetadata() override;
|
||||
|
||||
private:
|
||||
::rust::Box<loot::rust::Database> database_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/exception/error_categories.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace loot {
|
||||
namespace detail {
|
||||
class esplugin_category : public std::error_category {
|
||||
const char* name() const noexcept override { return "esplugin"; }
|
||||
|
||||
std::string message(int) const override { return "esplugin error"; }
|
||||
|
||||
bool equivalent(const std::error_code& code, int) const noexcept override {
|
||||
return code.category().name() == name();
|
||||
}
|
||||
};
|
||||
|
||||
class libloadorder_category : public std::error_category {
|
||||
const char* name() const noexcept override { return "libloadorder"; }
|
||||
|
||||
std::string message(int) const override { return "Libloadorder error"; }
|
||||
|
||||
bool equivalent(const std::error_code& code, int) const noexcept override {
|
||||
return code.category().name() == name();
|
||||
}
|
||||
};
|
||||
|
||||
class loot_condition_interpreter_category : public std::error_category {
|
||||
const char* name() const noexcept override {
|
||||
return "loot condition interpreter";
|
||||
}
|
||||
|
||||
std::string message(int) const override {
|
||||
return "loot condition interpreter error";
|
||||
}
|
||||
|
||||
bool equivalent(const std::error_code& code, int) const noexcept override {
|
||||
return code.category().name() == name();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LOOT_API const std::error_category& esplugin_category() {
|
||||
static detail::esplugin_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
LOOT_API const std::error_category& libloadorder_category() {
|
||||
static detail::libloadorder_category instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
LOOT_API const std::error_category& loot_condition_interpreter_category() {
|
||||
static detail::loot_condition_interpreter_category instance;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#include "api/exception.h"
|
||||
|
||||
#include <charconv>
|
||||
|
||||
#include "loot/exception/condition_syntax_error.h"
|
||||
#include "loot/exception/cyclic_interaction_error.h"
|
||||
#include "loot/exception/error_categories.h"
|
||||
#include "loot/exception/file_access_error.h"
|
||||
#include "loot/exception/undefined_group_error.h"
|
||||
#include "loot/vertex.h"
|
||||
|
||||
namespace {
|
||||
using std::string_view_literals::operator""sv;
|
||||
using loot::EdgeType;
|
||||
using loot::Vertex;
|
||||
|
||||
constexpr std::string_view CYCLIC_ERROR_PREFIX = "CyclicInteractionError: "sv;
|
||||
constexpr std::string_view UNDEFINED_GROUP_ERROR_PREFIX =
|
||||
"UndefinedGroupError: "sv;
|
||||
constexpr std::string_view ESPLUGIN_ERROR_PREFIX = "EspluginError: "sv;
|
||||
constexpr std::string_view LIBLOADORDER_ERROR_PREFIX = "LibloadorderError: "sv;
|
||||
constexpr std::string_view LCI_ERROR_PREFIX = "LciError: "sv;
|
||||
constexpr std::string_view FILE_ACCESS_ERROR_PREFIX = "FileAccessError: "sv;
|
||||
constexpr std::string_view INVALID_ARGUMENT_PREFIX = "InvalidArgument: "sv;
|
||||
|
||||
bool startsWith(std::string_view str, std::string_view prefix) {
|
||||
if (str.size() < prefix.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return str.substr(0, prefix.size()) == prefix;
|
||||
}
|
||||
|
||||
std::string replace(std::string_view str,
|
||||
std::string_view from,
|
||||
std::string_view to) {
|
||||
std::string out;
|
||||
out.reserve(str.size());
|
||||
|
||||
size_t i = 0;
|
||||
while (i < str.size()) {
|
||||
if (i + from.size() <= str.size() && str.substr(i, from.size()) == from) {
|
||||
out.append(to);
|
||||
i += from.size();
|
||||
} else {
|
||||
out.push_back(str[i]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
EdgeType toEdgeType(std::string_view edgeTypeDisplay) {
|
||||
if (edgeTypeDisplay == "Hardcoded") {
|
||||
return EdgeType::hardcoded;
|
||||
} else if (edgeTypeDisplay == "Master Flag") {
|
||||
return EdgeType::masterFlag;
|
||||
} else if (edgeTypeDisplay == "Master") {
|
||||
return EdgeType::master;
|
||||
} else if (edgeTypeDisplay == "Masterlist Requirement") {
|
||||
return EdgeType::masterlistRequirement;
|
||||
} else if (edgeTypeDisplay == "User Requirement") {
|
||||
return EdgeType::userRequirement;
|
||||
} else if (edgeTypeDisplay == "Masterlist Load After") {
|
||||
return EdgeType::masterlistLoadAfter;
|
||||
} else if (edgeTypeDisplay == "User Load After") {
|
||||
return EdgeType::userLoadAfter;
|
||||
} else if (edgeTypeDisplay == "Masterlist Group") {
|
||||
return EdgeType::masterlistGroup;
|
||||
} else if (edgeTypeDisplay == "User Group") {
|
||||
return EdgeType::userGroup;
|
||||
} else if (edgeTypeDisplay == "Record Overlap") {
|
||||
return EdgeType::recordOverlap;
|
||||
} else if (edgeTypeDisplay == "Asset Overlap") {
|
||||
return EdgeType::assetOverlap;
|
||||
} else if (edgeTypeDisplay == "Tie Break") {
|
||||
return EdgeType::tieBreak;
|
||||
} else if (edgeTypeDisplay == "Blueprint Master") {
|
||||
return EdgeType::blueprintMaster;
|
||||
} else {
|
||||
std::string what("Unrecognised edge type: ");
|
||||
what += edgeTypeDisplay;
|
||||
throw std::logic_error(what);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Vertex> parseCyclicError(std::string_view what) {
|
||||
const auto suffix = what.substr(0, CYCLIC_ERROR_PREFIX.size());
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
size_t pos = 0;
|
||||
while (pos < suffix.size()) {
|
||||
const auto sepPos = suffix.find("--", pos);
|
||||
const auto escapedName = suffix.substr(pos, sepPos);
|
||||
const auto name = replace(replace(escapedName, "\\-", "-"), "\\\\", "\\");
|
||||
|
||||
if (sepPos != std::string::npos) {
|
||||
const auto secondSepPos = suffix.find("--", sepPos + 2);
|
||||
const auto escapedEdgeName =
|
||||
suffix.substr(sepPos + 2, secondSepPos - (sepPos + 2));
|
||||
|
||||
vertices.push_back(Vertex(name, toEdgeType(escapedEdgeName)));
|
||||
|
||||
pos = secondSepPos + 2;
|
||||
} else {
|
||||
vertices.push_back(Vertex(name));
|
||||
pos = suffix.size();
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
std::string getErrorSuffix(std::string_view what) {
|
||||
const auto sepPos = what.find(": ");
|
||||
|
||||
return std::string(what.substr(sepPos + 2));
|
||||
}
|
||||
|
||||
std::pair<int, std::string> parseSystemError(std::string_view whatSuffix) {
|
||||
const auto sepPos = whatSuffix.find(": ");
|
||||
int code;
|
||||
const auto result =
|
||||
std::from_chars(whatSuffix.data(), whatSuffix.data() + sepPos, code);
|
||||
if (result.ec != std::errc{}) {
|
||||
std::string err = "Could not parse error code from string: ";
|
||||
err += whatSuffix;
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
return std::make_pair(code, std::string(whatSuffix.substr(sepPos + 2)));
|
||||
}
|
||||
}
|
||||
|
||||
namespace loot {
|
||||
std::exception_ptr mapError(const ::rust::Error& error) {
|
||||
if (startsWith(error.what(), CYCLIC_ERROR_PREFIX)) {
|
||||
return std::make_exception_ptr(
|
||||
CyclicInteractionError(parseCyclicError(error.what())));
|
||||
} else if (startsWith(error.what(), UNDEFINED_GROUP_ERROR_PREFIX)) {
|
||||
return std::make_exception_ptr(
|
||||
UndefinedGroupError(getErrorSuffix(error.what())));
|
||||
} else if (startsWith(error.what(), ESPLUGIN_ERROR_PREFIX)) {
|
||||
const auto [code, details] = parseSystemError(
|
||||
std::string_view(error.what()).substr(ESPLUGIN_ERROR_PREFIX.size()));
|
||||
|
||||
return std::make_exception_ptr(
|
||||
std::system_error(code, esplugin_category(), details));
|
||||
|
||||
} else if (startsWith(error.what(), LIBLOADORDER_ERROR_PREFIX)) {
|
||||
const auto [code, details] =
|
||||
parseSystemError(std::string_view(error.what())
|
||||
.substr(LIBLOADORDER_ERROR_PREFIX.size()));
|
||||
|
||||
return std::make_exception_ptr(
|
||||
std::system_error(code, libloadorder_category(), details));
|
||||
} else if (startsWith(error.what(), LCI_ERROR_PREFIX)) {
|
||||
const auto [code, details] = parseSystemError(
|
||||
std::string_view(error.what()).substr(LCI_ERROR_PREFIX.size()));
|
||||
|
||||
return std::make_exception_ptr(ConditionSyntaxError(
|
||||
code, loot_condition_interpreter_category(), details));
|
||||
} else if (startsWith(error.what(), FILE_ACCESS_ERROR_PREFIX)) {
|
||||
return std::make_exception_ptr(
|
||||
FileAccessError(getErrorSuffix(error.what())));
|
||||
} else if (startsWith(error.what(), FILE_ACCESS_ERROR_PREFIX)) {
|
||||
return std::make_exception_ptr(
|
||||
FileAccessError(getErrorSuffix(error.what())));
|
||||
} else if (startsWith(error.what(), INVALID_ARGUMENT_PREFIX)) {
|
||||
return std::make_exception_ptr(
|
||||
std::invalid_argument(getErrorSuffix(error.what())));
|
||||
} else {
|
||||
return std::make_exception_ptr(std::runtime_error(error.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef LOOT_API_EXCEPTION
|
||||
#define LOOT_API_EXCEPTION
|
||||
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace loot {
|
||||
std::exception_ptr mapError(const ::rust::Error& error);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,248 @@
|
||||
|
||||
#include "api/game.h"
|
||||
|
||||
#include "api/convert.h"
|
||||
#include "api/exception.h"
|
||||
|
||||
namespace {
|
||||
loot::GameType convert(loot::rust::GameType gameType) {
|
||||
switch (gameType) {
|
||||
case loot::rust::GameType::Morrowind:
|
||||
return loot::GameType::tes3;
|
||||
case loot::rust::GameType::Oblivion:
|
||||
return loot::GameType::tes4;
|
||||
case loot::rust::GameType::Skyrim:
|
||||
return loot::GameType::tes5;
|
||||
case loot::rust::GameType::SkyrimSE:
|
||||
return loot::GameType::tes5se;
|
||||
case loot::rust::GameType::SkyrimVR:
|
||||
return loot::GameType::tes5vr;
|
||||
case loot::rust::GameType::Fallout3:
|
||||
return loot::GameType::fo3;
|
||||
case loot::rust::GameType::FalloutNV:
|
||||
return loot::GameType::fonv;
|
||||
case loot::rust::GameType::Fallout4:
|
||||
return loot::GameType::fo4;
|
||||
case loot::rust::GameType::Fallout4VR:
|
||||
return loot::GameType::fo4vr;
|
||||
case loot::rust::GameType::Starfield:
|
||||
return loot::GameType::starfield;
|
||||
case loot::rust::GameType::OpenMW:
|
||||
return loot::GameType::openmw;
|
||||
default:
|
||||
throw std::logic_error("Unsupported GameType value");
|
||||
}
|
||||
}
|
||||
|
||||
loot::rust::GameType convert(loot::GameType gameType) {
|
||||
switch (gameType) {
|
||||
case loot::GameType::tes3:
|
||||
return loot::rust::GameType::Morrowind;
|
||||
case loot::GameType::tes4:
|
||||
return loot::rust::GameType::Oblivion;
|
||||
case loot::GameType::tes5:
|
||||
return loot::rust::GameType::Skyrim;
|
||||
case loot::GameType::tes5se:
|
||||
return loot::rust::GameType::SkyrimSE;
|
||||
case loot::GameType::tes5vr:
|
||||
return loot::rust::GameType::SkyrimVR;
|
||||
case loot::GameType::fo3:
|
||||
return loot::rust::GameType::Fallout3;
|
||||
case loot::GameType::fonv:
|
||||
return loot::rust::GameType::FalloutNV;
|
||||
case loot::GameType::fo4:
|
||||
return loot::rust::GameType::Fallout4;
|
||||
case loot::GameType::fo4vr:
|
||||
return loot::rust::GameType::Fallout4VR;
|
||||
case loot::GameType::starfield:
|
||||
return loot::rust::GameType::Starfield;
|
||||
case loot::GameType::openmw:
|
||||
return loot::rust::GameType::OpenMW;
|
||||
default:
|
||||
throw std::logic_error("Unsupported GameType value");
|
||||
}
|
||||
}
|
||||
|
||||
rust::Box<loot::rust::Game> constructGame(
|
||||
const loot::GameType gameType,
|
||||
const std::filesystem::path& gamePath,
|
||||
const std::filesystem::path& localDataPath) {
|
||||
try {
|
||||
if (localDataPath.empty()) {
|
||||
return loot::rust::new_game(convert(gameType), gamePath.u8string());
|
||||
} else {
|
||||
return loot::rust::new_game_with_local_path(
|
||||
convert(gameType), gamePath.u8string(), localDataPath.u8string());
|
||||
}
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(loot::mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<::rust::Str> as_str_refs(const std::vector<std::string>& vector) {
|
||||
std::vector<::rust::Str> strings;
|
||||
for (const auto& str : vector) {
|
||||
strings.push_back(str);
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
|
||||
namespace loot {
|
||||
Game::Game(const GameType gameType,
|
||||
const std::filesystem::path& gamePath,
|
||||
const std::filesystem::path& localDataPath) :
|
||||
game_(constructGame(gameType, gamePath, localDataPath)),
|
||||
database_(game_->database()) {}
|
||||
|
||||
GameType Game::GetType() const {
|
||||
try {
|
||||
return ::convert(game_->game_type());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
const DatabaseInterface& Game::GetDatabase() const { return database_; }
|
||||
|
||||
DatabaseInterface& Game::GetDatabase() { return database_; }
|
||||
|
||||
std::vector<std::filesystem::path> Game::GetAdditionalDataPaths() const {
|
||||
try {
|
||||
std::vector<std::filesystem::path> paths;
|
||||
for (const auto& path_str : game_->additional_data_paths()) {
|
||||
paths.push_back(
|
||||
std::filesystem::u8path(path_str.begin(), path_str.end()));
|
||||
}
|
||||
|
||||
return paths;
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Game::SetAdditionalDataPaths(
|
||||
const std::vector<std::filesystem::path>& additionalDataPaths) {
|
||||
std::vector<::rust::String> path_strings;
|
||||
std::vector<::rust::Str> path_strs;
|
||||
for (const auto& path : additionalDataPaths) {
|
||||
path_strings.push_back(path.u8string());
|
||||
path_strs.push_back(path_strings.back());
|
||||
}
|
||||
try {
|
||||
game_->set_additional_data_paths(
|
||||
::rust::Slice<const ::rust::Str>(path_strs));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
bool Game::IsValidPlugin(const std::filesystem::path& pluginPath) const {
|
||||
return game_->is_valid_plugin(pluginPath.u8string());
|
||||
}
|
||||
|
||||
void Game::LoadPlugins(const std::vector<std::filesystem::path>& pluginPaths,
|
||||
bool loadHeadersOnly) {
|
||||
std::vector<::rust::String> path_strings;
|
||||
std::vector<::rust::Str> path_strs;
|
||||
for (const auto& path : pluginPaths) {
|
||||
path_strings.push_back(path.u8string());
|
||||
path_strs.push_back(path_strings.back());
|
||||
}
|
||||
|
||||
try {
|
||||
if (loadHeadersOnly) {
|
||||
game_->load_plugin_headers(::rust::Slice<const ::rust::Str>(path_strs));
|
||||
} else {
|
||||
game_->load_plugins(::rust::Slice<const ::rust::Str>(path_strs));
|
||||
}
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Game::ClearLoadedPlugins() { game_->clear_loaded_plugins(); }
|
||||
|
||||
std::shared_ptr<const PluginInterface> Game::GetPlugin(
|
||||
std::string_view pluginName) const {
|
||||
const auto pluginOpt = game_->plugin(convert(pluginName));
|
||||
if (!pluginOpt->is_some()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
return std::make_shared<Plugin>(
|
||||
std::move(pluginOpt->as_ref().boxed_clone()));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const PluginInterface>> Game::GetLoadedPlugins()
|
||||
const {
|
||||
std::vector<std::shared_ptr<const PluginInterface>> plugins;
|
||||
for (const auto& pluginRef : game_->loaded_plugins()) {
|
||||
plugins.push_back(
|
||||
std::make_shared<Plugin>(std::move(pluginRef.boxed_clone())));
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
std::vector<std::string> Game::SortPlugins(
|
||||
const std::vector<std::string>& pluginFilenames) {
|
||||
const auto strs = as_str_refs(pluginFilenames);
|
||||
|
||||
try {
|
||||
const auto results = game_->sort_plugins(::rust::Slice(strs));
|
||||
|
||||
return convert<std::string>(results);
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
void Game::LoadCurrentLoadOrderState() {
|
||||
try {
|
||||
game_->load_current_load_order_state();
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
bool Game::IsLoadOrderAmbiguous() const {
|
||||
try {
|
||||
return game_->is_load_order_ambiguous();
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path Game::GetActivePluginsFilePath() const {
|
||||
try {
|
||||
const auto path_string = game_->active_plugins_file_path();
|
||||
return std::filesystem::u8path(path_string.begin(), path_string.end());
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
|
||||
bool Game::IsPluginActive(const std::string& pluginName) const {
|
||||
return game_->is_plugin_active(pluginName);
|
||||
}
|
||||
|
||||
std::vector<std::string> Game::GetLoadOrder() const {
|
||||
return convert<std::string>(game_->load_order());
|
||||
}
|
||||
|
||||
void Game::SetLoadOrder(const std::vector<std::string>& loadOrder) {
|
||||
const auto strs = as_str_refs(loadOrder);
|
||||
|
||||
try {
|
||||
game_->set_load_order(::rust::Slice(strs));
|
||||
} catch (const ::rust::Error& e) {
|
||||
std::rethrow_exception(mapError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef LOOT_API_GAME
|
||||
#define LOOT_API_GAME
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "api/database.h"
|
||||
#include "api/plugin.h"
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
#include "loot/game_interface.h"
|
||||
#include "loot/metadata/filename.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace loot {
|
||||
class Game final : public GameInterface {
|
||||
public:
|
||||
explicit Game(const GameType gameType,
|
||||
const std::filesystem::path& gamePath,
|
||||
const std::filesystem::path& gameLocalDataPath = "");
|
||||
|
||||
// Game Interface Methods //
|
||||
////////////////////////////
|
||||
|
||||
GameType GetType() const override;
|
||||
|
||||
std::vector<std::filesystem::path> GetAdditionalDataPaths() const;
|
||||
|
||||
void SetAdditionalDataPaths(
|
||||
const std::vector<std::filesystem::path>& additionalDataPaths) override;
|
||||
|
||||
DatabaseInterface& GetDatabase() override;
|
||||
const DatabaseInterface& GetDatabase() const override;
|
||||
|
||||
bool IsValidPlugin(const std::filesystem::path& pluginPath) const override;
|
||||
|
||||
void LoadPlugins(const std::vector<std::filesystem::path>& pluginPaths,
|
||||
bool loadHeadersOnly) override;
|
||||
|
||||
void ClearLoadedPlugins() override;
|
||||
|
||||
std::shared_ptr<const PluginInterface> GetPlugin(
|
||||
std::string_view pluginName) const override;
|
||||
|
||||
std::vector<std::shared_ptr<const PluginInterface>> GetLoadedPlugins()
|
||||
const override;
|
||||
|
||||
std::vector<std::string> SortPlugins(
|
||||
const std::vector<std::string>& pluginFilenames) override;
|
||||
|
||||
void LoadCurrentLoadOrderState() override;
|
||||
|
||||
bool IsLoadOrderAmbiguous() const override;
|
||||
|
||||
std::filesystem::path GetActivePluginsFilePath() const override;
|
||||
|
||||
bool IsPluginActive(const std::string& pluginName) const override;
|
||||
|
||||
std::vector<std::string> GetLoadOrder() const override;
|
||||
|
||||
void SetLoadOrder(const std::vector<std::string>& loadOrder) override;
|
||||
|
||||
private:
|
||||
::rust::Box<loot::rust::Game> game_;
|
||||
Database database_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/conditional_metadata.h"
|
||||
|
||||
namespace loot {
|
||||
ConditionalMetadata::ConditionalMetadata(std::string_view condition) :
|
||||
condition_(condition) {}
|
||||
|
||||
bool ConditionalMetadata::IsConditional() const { return !condition_.empty(); }
|
||||
|
||||
std::string ConditionalMetadata::GetCondition() const { return condition_; }
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/file.h"
|
||||
|
||||
namespace loot {
|
||||
File::File(std::string_view name,
|
||||
std::string_view display,
|
||||
std::string_view condition,
|
||||
const std::vector<MessageContent>& detail,
|
||||
std::string_view constraint) :
|
||||
ConditionalMetadata(condition),
|
||||
name_(Filename(name)),
|
||||
display_(display),
|
||||
detail_(detail),
|
||||
constraint_(constraint) {}
|
||||
|
||||
Filename File::GetName() const { return name_; }
|
||||
|
||||
std::string File::GetDisplayName() const { return display_; }
|
||||
|
||||
std::vector<MessageContent> File::GetDetail() const { return detail_; }
|
||||
|
||||
std::string File::GetConstraint() const { return constraint_; }
|
||||
|
||||
bool operator==(const File& lhs, const File& rhs) {
|
||||
return lhs.GetDisplayName() == rhs.GetDisplayName() &&
|
||||
lhs.GetCondition() == rhs.GetCondition() &&
|
||||
lhs.GetConstraint() == rhs.GetConstraint() &&
|
||||
lhs.GetName() == rhs.GetName() && lhs.GetDetail() == rhs.GetDetail();
|
||||
}
|
||||
|
||||
bool operator!=(const File& lhs, const File& rhs) { return !(lhs == rhs); }
|
||||
|
||||
bool operator<(const File& lhs, const File& rhs) {
|
||||
if (lhs.GetDisplayName() < rhs.GetDisplayName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetDisplayName() < lhs.GetDisplayName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetCondition() < rhs.GetCondition()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetCondition() < lhs.GetCondition()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetConstraint() < rhs.GetConstraint()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetConstraint() < lhs.GetConstraint()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetName() < rhs.GetName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetName() < lhs.GetName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetDetail() < rhs.GetDetail();
|
||||
}
|
||||
|
||||
bool operator>(const File& lhs, const File& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const File& lhs, const File& rhs) { return !(lhs > rhs); }
|
||||
|
||||
bool operator>=(const File& lhs, const File& rhs) { return !(lhs < rhs); }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/filename.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
// #include "api/helpers/text.h"
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
|
||||
namespace loot {
|
||||
Filename::Filename(std::string_view filename) : filename_(filename) {}
|
||||
|
||||
Filename::operator std::string() const { return filename_; }
|
||||
|
||||
bool operator==(const Filename& lhs, const Filename& rhs) {
|
||||
return loot::rust::compare_filenames(std::string(lhs), std::string(rhs)) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const Filename& lhs, const Filename& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const Filename& lhs, const Filename& rhs) {
|
||||
return loot::rust::compare_filenames(std::string(lhs), std::string(rhs)) < 0;
|
||||
}
|
||||
|
||||
bool operator>(const Filename& lhs, const Filename& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const Filename& lhs, const Filename& rhs) {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
bool operator>=(const Filename& lhs, const Filename& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2018 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/group.h"
|
||||
|
||||
namespace loot {
|
||||
Group::Group(std::string_view name,
|
||||
const std::vector<std::string>& afterGroups,
|
||||
std::string_view description) :
|
||||
name_(name), description_(description), afterGroups_(afterGroups) {}
|
||||
|
||||
std::string Group::GetName() const { return name_; }
|
||||
|
||||
std::string Group::GetDescription() const { return description_; }
|
||||
|
||||
std::vector<std::string> Group::GetAfterGroups() const { return afterGroups_; }
|
||||
|
||||
bool operator==(const Group& lhs, const Group& rhs) {
|
||||
return lhs.GetName() == rhs.GetName() &&
|
||||
lhs.GetDescription() == rhs.GetDescription() &&
|
||||
lhs.GetAfterGroups() == rhs.GetAfterGroups();
|
||||
}
|
||||
|
||||
bool operator!=(const Group& lhs, const Group& rhs) { return !(lhs == rhs); }
|
||||
|
||||
bool operator<(const Group& lhs, const Group& rhs) {
|
||||
if (lhs.GetName() < rhs.GetName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetName() < lhs.GetName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetDescription() < rhs.GetDescription()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetDescription() < lhs.GetDescription()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetAfterGroups() < rhs.GetAfterGroups();
|
||||
}
|
||||
|
||||
bool operator>(const Group& lhs, const Group& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const Group& lhs, const Group& rhs) { return !(lhs > rhs); }
|
||||
|
||||
bool operator>=(const Group& lhs, const Group& rhs) { return !(lhs < rhs); }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/location.h"
|
||||
|
||||
namespace loot {
|
||||
Location::Location(std::string_view url, std::string_view name) :
|
||||
url_(url), name_(name) {}
|
||||
|
||||
std::string Location::GetURL() const { return url_; }
|
||||
|
||||
std::string Location::GetName() const { return name_; }
|
||||
|
||||
bool operator==(const Location& lhs, const Location& rhs) {
|
||||
return lhs.GetURL() == rhs.GetURL() && lhs.GetName() == rhs.GetName();
|
||||
}
|
||||
|
||||
bool operator!=(const Location& lhs, const Location& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const Location& lhs, const Location& rhs) {
|
||||
if (lhs.GetURL() < rhs.GetURL()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetURL() < lhs.GetURL()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetName() < rhs.GetName();
|
||||
}
|
||||
|
||||
bool operator>(const Location& lhs, const Location& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const Location& lhs, const Location& rhs) {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
bool operator>=(const Location& lhs, const Location& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/message.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace loot {
|
||||
Message::Message(const MessageType type,
|
||||
std::string_view content,
|
||||
std::string_view condition) :
|
||||
ConditionalMetadata(condition),
|
||||
type_(type),
|
||||
content_({MessageContent(content)}) {}
|
||||
|
||||
Message::Message(const MessageType type,
|
||||
const std::vector<MessageContent>& content,
|
||||
std::string_view condition) :
|
||||
ConditionalMetadata(condition), type_(type), content_(content) {
|
||||
if (content.size() > 1) {
|
||||
bool englishStringExists = false;
|
||||
for (const auto& mc : content) {
|
||||
if (mc.GetLanguage() == MessageContent::DEFAULT_LANGUAGE)
|
||||
englishStringExists = true;
|
||||
}
|
||||
if (!englishStringExists)
|
||||
throw std::invalid_argument(
|
||||
"bad conversion: multilingual messages must contain an English "
|
||||
"content string");
|
||||
}
|
||||
}
|
||||
|
||||
MessageType Message::GetType() const { return type_; }
|
||||
|
||||
std::vector<MessageContent> Message::GetContent() const { return content_; }
|
||||
|
||||
bool operator==(const Message& lhs, const Message& rhs) {
|
||||
return lhs.GetType() == rhs.GetType() &&
|
||||
lhs.GetCondition() == rhs.GetCondition() &&
|
||||
lhs.GetContent() == rhs.GetContent();
|
||||
}
|
||||
|
||||
bool operator!=(const Message& lhs, const Message& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const Message& lhs, const Message& rhs) {
|
||||
if (lhs.GetType() < rhs.GetType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetType() < lhs.GetType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetCondition() < rhs.GetCondition()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetCondition() < lhs.GetCondition()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetContent() < rhs.GetContent();
|
||||
}
|
||||
|
||||
bool operator>(const Message& lhs, const Message& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const Message& lhs, const Message& rhs) { return !(lhs > rhs); }
|
||||
|
||||
bool operator>=(const Message& lhs, const Message& rhs) { return !(lhs < rhs); }
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/message_content.h"
|
||||
|
||||
namespace loot {
|
||||
MessageContent::MessageContent(std::string_view text,
|
||||
std::string_view language) :
|
||||
text_(text), language_(language) {}
|
||||
|
||||
std::string MessageContent::GetText() const { return text_; }
|
||||
|
||||
std::string MessageContent::GetLanguage() const { return language_; }
|
||||
|
||||
bool operator==(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
return lhs.GetText() == rhs.GetText() &&
|
||||
lhs.GetLanguage() == rhs.GetLanguage();
|
||||
}
|
||||
|
||||
bool operator!=(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
if (lhs.GetText() < rhs.GetText()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetText() < lhs.GetText()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetLanguage() < rhs.GetLanguage();
|
||||
}
|
||||
|
||||
bool operator>(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
bool operator<=(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
bool operator>=(const MessageContent& lhs, const MessageContent& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
std::optional<MessageContent> SelectMessageContent(
|
||||
const std::vector<MessageContent> content,
|
||||
std::string_view language) {
|
||||
if (content.empty())
|
||||
return std::nullopt;
|
||||
else if (content.size() == 1)
|
||||
return content.at(0);
|
||||
else {
|
||||
auto languageCode = language.substr(0, language.find("_"));
|
||||
const auto isCountryCodeGiven = languageCode.length() != language.length();
|
||||
|
||||
std::optional<MessageContent> matchedLanguage;
|
||||
std::optional<MessageContent> english;
|
||||
for (const auto& mc : content) {
|
||||
auto contentLanguage = mc.GetLanguage();
|
||||
|
||||
if (contentLanguage == language) {
|
||||
return mc;
|
||||
} else if (!matchedLanguage.has_value()) {
|
||||
if (isCountryCodeGiven && contentLanguage == languageCode) {
|
||||
matchedLanguage = mc;
|
||||
} else if (!isCountryCodeGiven) {
|
||||
const auto underscorePos = contentLanguage.find("_");
|
||||
if (underscorePos != std::string::npos) {
|
||||
auto contentLanguageCode = contentLanguage.substr(0, underscorePos);
|
||||
if (contentLanguageCode == language) {
|
||||
matchedLanguage = mc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contentLanguage == MessageContent::DEFAULT_LANGUAGE) {
|
||||
english = mc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedLanguage.has_value()) {
|
||||
return matchedLanguage;
|
||||
}
|
||||
|
||||
if (english.has_value()) {
|
||||
return english;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/plugin_cleaning_data.h"
|
||||
|
||||
namespace loot {
|
||||
PluginCleaningData::PluginCleaningData(uint32_t crc, std::string_view utility) :
|
||||
crc_(crc), utility_(utility) {}
|
||||
|
||||
PluginCleaningData::PluginCleaningData(
|
||||
uint32_t crc,
|
||||
std::string_view utility,
|
||||
const std::vector<MessageContent>& detail,
|
||||
unsigned int itm,
|
||||
unsigned int ref,
|
||||
unsigned int nav) :
|
||||
crc_(crc),
|
||||
itm_(itm),
|
||||
ref_(ref),
|
||||
nav_(nav),
|
||||
utility_(utility),
|
||||
detail_(detail) {}
|
||||
|
||||
uint32_t PluginCleaningData::GetCRC() const { return crc_; }
|
||||
|
||||
unsigned int PluginCleaningData::GetITMCount() const { return itm_; }
|
||||
|
||||
unsigned int PluginCleaningData::GetDeletedReferenceCount() const {
|
||||
return ref_;
|
||||
}
|
||||
|
||||
unsigned int PluginCleaningData::GetDeletedNavmeshCount() const { return nav_; }
|
||||
|
||||
std::string PluginCleaningData::GetCleaningUtility() const { return utility_; }
|
||||
|
||||
std::vector<MessageContent> PluginCleaningData::GetDetail() const {
|
||||
return detail_;
|
||||
}
|
||||
|
||||
bool operator==(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
return lhs.GetCRC() == rhs.GetCRC() &&
|
||||
lhs.GetITMCount() == rhs.GetITMCount() &&
|
||||
lhs.GetDeletedReferenceCount() == rhs.GetDeletedReferenceCount() &&
|
||||
lhs.GetDeletedNavmeshCount() == rhs.GetDeletedNavmeshCount() &&
|
||||
lhs.GetCleaningUtility() == rhs.GetCleaningUtility() &&
|
||||
lhs.GetDetail() == rhs.GetDetail();
|
||||
}
|
||||
|
||||
bool operator!=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
if (lhs.GetCRC() < rhs.GetCRC()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetCRC() < lhs.GetCRC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetCleaningUtility() < rhs.GetCleaningUtility()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetCleaningUtility() < lhs.GetCleaningUtility()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetITMCount() < rhs.GetITMCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetITMCount() < lhs.GetITMCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetDeletedReferenceCount() < rhs.GetDeletedReferenceCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetDeletedReferenceCount() < lhs.GetDeletedReferenceCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.GetDeletedNavmeshCount() < rhs.GetDeletedNavmeshCount()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetDeletedNavmeshCount() < lhs.GetDeletedNavmeshCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetDetail() < rhs.GetDetail();
|
||||
}
|
||||
|
||||
bool operator>(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
bool operator<=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
bool operator>=(const PluginCleaningData& lhs, const PluginCleaningData& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/plugin_metadata.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "api/convert.h"
|
||||
#include "libloot-cpp/src/lib.rs.h"
|
||||
|
||||
namespace {
|
||||
// Append second to first, skipping any elements that are already present in
|
||||
// first. Although this is O(U * M), both input vectors are expected to be
|
||||
// small (with tens of elements being an unusually large number).
|
||||
template<typename T>
|
||||
std::vector<T> mergeVectors(std::vector<T> first,
|
||||
const std::vector<T>& second) {
|
||||
const auto initialSizeOfFirst = first.size();
|
||||
for (const auto& element : second) {
|
||||
const auto end = first.cbegin() + initialSizeOfFirst;
|
||||
|
||||
if (std::find(first.cbegin(), end, element) == end) {
|
||||
first.push_back(element);
|
||||
}
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
std::string TrimDotGhostExtension(std::string&& filename) {
|
||||
using std::string_view_literals::operator""sv;
|
||||
// If the name passed ends in '.ghost', that should be trimmed.
|
||||
constexpr std::string_view GHOST_FILE_EXTENSION = ".ghost"sv;
|
||||
|
||||
if (filename.length() < GHOST_FILE_EXTENSION.length()) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
auto view = std::string_view(filename);
|
||||
view.remove_prefix(filename.length() - GHOST_FILE_EXTENSION.length());
|
||||
|
||||
bool areEqual = std::equal(
|
||||
view.begin(),
|
||||
view.end(),
|
||||
GHOST_FILE_EXTENSION.begin(),
|
||||
[](unsigned char a, unsigned char b) { return std::tolower(a) == b; });
|
||||
|
||||
if (areEqual) {
|
||||
return filename.substr(0,
|
||||
filename.length() - GHOST_FILE_EXTENSION.length());
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
namespace loot {
|
||||
// If the name passed ends in '.ghost', that should be trimmed.
|
||||
PluginMetadata::PluginMetadata(std::string_view n) :
|
||||
name_(TrimDotGhostExtension(std::string(n))) {
|
||||
if (IsRegexPlugin()) {
|
||||
nameRegex_ = std::regex(name_, std::regex::ECMAScript | std::regex::icase);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginMetadata::MergeMetadata(const PluginMetadata& plugin) {
|
||||
if (plugin.HasNameOnly())
|
||||
return;
|
||||
|
||||
if (!group_.has_value() && plugin.GetGroup()) {
|
||||
group_ = plugin.GetGroup();
|
||||
}
|
||||
|
||||
loadAfter_ = mergeVectors(loadAfter_, plugin.loadAfter_);
|
||||
requirements_ = mergeVectors(requirements_, plugin.requirements_);
|
||||
incompatibilities_ =
|
||||
mergeVectors(incompatibilities_, plugin.incompatibilities_);
|
||||
|
||||
tags_ = mergeVectors(tags_, plugin.tags_);
|
||||
|
||||
// Messages are in an ordered list, and should be fully merged.
|
||||
messages_.insert(
|
||||
end(messages_), begin(plugin.messages_), end(plugin.messages_));
|
||||
|
||||
dirtyInfo_ = mergeVectors(dirtyInfo_, plugin.dirtyInfo_);
|
||||
cleanInfo_ = mergeVectors(cleanInfo_, plugin.cleanInfo_);
|
||||
locations_ = mergeVectors(locations_, plugin.locations_);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string PluginMetadata::GetName() const { return name_; }
|
||||
|
||||
std::optional<std::string> PluginMetadata::GetGroup() const { return group_; }
|
||||
|
||||
std::vector<File> PluginMetadata::GetLoadAfterFiles() const {
|
||||
return loadAfter_;
|
||||
}
|
||||
|
||||
std::vector<File> PluginMetadata::GetRequirements() const {
|
||||
return requirements_;
|
||||
}
|
||||
|
||||
std::vector<File> PluginMetadata::GetIncompatibilities() const {
|
||||
return incompatibilities_;
|
||||
}
|
||||
|
||||
std::vector<Message> PluginMetadata::GetMessages() const { return messages_; }
|
||||
|
||||
std::vector<Tag> PluginMetadata::GetTags() const { return tags_; }
|
||||
|
||||
std::vector<PluginCleaningData> PluginMetadata::GetDirtyInfo() const {
|
||||
return dirtyInfo_;
|
||||
}
|
||||
|
||||
std::vector<PluginCleaningData> PluginMetadata::GetCleanInfo() const {
|
||||
return cleanInfo_;
|
||||
}
|
||||
|
||||
std::vector<Location> PluginMetadata::GetLocations() const {
|
||||
return locations_;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetGroup(std::string_view group) { group_ = group; }
|
||||
|
||||
void PluginMetadata::UnsetGroup() { group_ = std::nullopt; }
|
||||
|
||||
void PluginMetadata::SetLoadAfterFiles(const std::vector<File>& l) {
|
||||
loadAfter_ = l;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetRequirements(const std::vector<File>& r) {
|
||||
requirements_ = r;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetIncompatibilities(const std::vector<File>& i) {
|
||||
incompatibilities_ = i;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetMessages(const std::vector<Message>& m) {
|
||||
messages_ = m;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetTags(const std::vector<Tag>& t) { tags_ = t; }
|
||||
|
||||
void PluginMetadata::SetDirtyInfo(
|
||||
const std::vector<PluginCleaningData>& dirtyInfo) {
|
||||
dirtyInfo_ = dirtyInfo;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetCleanInfo(const std::vector<PluginCleaningData>& info) {
|
||||
cleanInfo_ = info;
|
||||
}
|
||||
|
||||
void PluginMetadata::SetLocations(const std::vector<Location>& locations) {
|
||||
locations_ = locations;
|
||||
}
|
||||
|
||||
bool PluginMetadata::HasNameOnly() const {
|
||||
return !group_.has_value() && loadAfter_.empty() && requirements_.empty() &&
|
||||
incompatibilities_.empty() && messages_.empty() && tags_.empty() &&
|
||||
dirtyInfo_.empty() && cleanInfo_.empty() && locations_.empty();
|
||||
}
|
||||
|
||||
bool PluginMetadata::IsRegexPlugin() const {
|
||||
// Treat as regex if the plugin filename contains any of ":\*?|" as
|
||||
// they are not valid Windows filename characters, but have meaning
|
||||
// in regexes.
|
||||
return strpbrk(name_.c_str(), ":\\*?|") != nullptr;
|
||||
}
|
||||
|
||||
bool PluginMetadata::NameMatches(std::string_view pluginName) const {
|
||||
if (IsRegexPlugin()) {
|
||||
if (!nameRegex_.has_value()) {
|
||||
throw std::runtime_error("Regex plugin does not have regex object");
|
||||
}
|
||||
|
||||
return std::regex_match(
|
||||
pluginName.begin(), pluginName.end(), nameRegex_.value());
|
||||
}
|
||||
|
||||
return loot::rust::compare_filenames(name_, convert(pluginName)) == 0;
|
||||
}
|
||||
|
||||
std::string PluginMetadata::AsYaml() const {
|
||||
const auto metadata = convert(*this);
|
||||
return std::string(metadata->as_yaml());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2016 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT 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.
|
||||
|
||||
LOOT 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 LOOT. If not, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loot/metadata/tag.h"
|
||||
|
||||
namespace loot {
|
||||
Tag::Tag(std::string_view tag,
|
||||
const bool isAddition,
|
||||
std::string_view condition) :
|
||||
ConditionalMetadata(condition), name_(tag), addTag_(isAddition) {}
|
||||
|
||||
bool Tag::IsAddition() const { return addTag_; }
|
||||
|
||||
std::string Tag::GetName() const { return name_; }
|
||||
|
||||
bool operator==(const Tag& lhs, const Tag& rhs) {
|
||||
return lhs.IsAddition() == rhs.IsAddition() &&
|
||||
lhs.GetName() == rhs.GetName() &&
|
||||
lhs.GetCondition() == rhs.GetCondition();
|
||||
}
|
||||
|
||||
bool operator!=(const Tag& lhs, const Tag& rhs) { return !(lhs == rhs); }
|
||||
|
||||
bool operator<(const Tag& lhs, const Tag& rhs) {
|
||||
if (lhs.IsAddition() != rhs.IsAddition()) {
|
||||
return lhs.IsAddition() && !rhs.IsAddition();
|
||||
}
|
||||
|
||||
if (lhs.GetName() < rhs.GetName()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rhs.GetName() < lhs.GetName()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.GetCondition() < rhs.GetCondition();
|
||||
}
|
||||
|
||||
bool operator>(const Tag& lhs, const Tag& rhs) { return rhs < lhs; }
|
||||
|
||||
bool operator<=(const Tag& lhs, const Tag& rhs) { return !(lhs > rhs); }
|
||||
|
||||
bool operator>=(const Tag& lhs, const Tag& rhs) { return !(lhs < rhs); }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user