Random cleanup
This commit is contained in:
parent
320d57599e
commit
9f98190944
@ -1,38 +1,35 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context_initializer.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
context::context() : executer_(this), scheduler_(this), parameters_(this), event_handler_(this)
|
||||
{
|
||||
context_initializer::initialize(this);
|
||||
}
|
||||
|
||||
executer* context::get_executer()
|
||||
{
|
||||
return &this->executer_;
|
||||
}
|
||||
|
||||
scheduler* context::get_scheduler()
|
||||
{
|
||||
return &this->scheduler_;
|
||||
}
|
||||
|
||||
parameters* context::get_parameters()
|
||||
{
|
||||
return &this->parameters_;
|
||||
}
|
||||
|
||||
event_handler* context::get_event_handler()
|
||||
{
|
||||
return &this->event_handler_;
|
||||
}
|
||||
|
||||
chaiscript::ChaiScript* context::get_chai()
|
||||
{
|
||||
return &this->chai_;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "std_include.hpp"
|
||||
#include "context_initializer.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
context::context() : executer_(this), scheduler_(this), parameters_(this), event_handler_(this)
|
||||
{
|
||||
context_initializer::initialize(this);
|
||||
}
|
||||
|
||||
executer* context::get_executer()
|
||||
{
|
||||
return &this->executer_;
|
||||
}
|
||||
|
||||
scheduler* context::get_scheduler()
|
||||
{
|
||||
return &this->scheduler_;
|
||||
}
|
||||
|
||||
parameters* context::get_parameters()
|
||||
{
|
||||
return &this->parameters_;
|
||||
}
|
||||
|
||||
event_handler* context::get_event_handler()
|
||||
{
|
||||
return &this->event_handler_;
|
||||
}
|
||||
|
||||
chaiscript::ChaiScript* context::get_chai()
|
||||
{
|
||||
return &this->chai_;
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,29 @@
|
||||
#pragma once
|
||||
#include "executer.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "parameters.hpp"
|
||||
#include "event_handler.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context final
|
||||
{
|
||||
public:
|
||||
context();
|
||||
|
||||
chaiscript::ChaiScript* get_chai();
|
||||
|
||||
executer* get_executer();
|
||||
scheduler* get_scheduler();
|
||||
parameters* get_parameters();
|
||||
event_handler* get_event_handler();
|
||||
|
||||
private:
|
||||
chaiscript::ChaiScript chai_;
|
||||
|
||||
executer executer_;
|
||||
scheduler scheduler_;
|
||||
parameters parameters_;
|
||||
event_handler event_handler_;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "executer.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "parameters.hpp"
|
||||
#include "event_handler.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context final
|
||||
{
|
||||
public:
|
||||
context();
|
||||
|
||||
chaiscript::ChaiScript* get_chai();
|
||||
|
||||
executer* get_executer();
|
||||
scheduler* get_scheduler();
|
||||
parameters* get_parameters();
|
||||
event_handler* get_event_handler();
|
||||
|
||||
private:
|
||||
chaiscript::ChaiScript chai_;
|
||||
|
||||
executer executer_;
|
||||
scheduler scheduler_;
|
||||
parameters parameters_;
|
||||
event_handler event_handler_;
|
||||
};
|
||||
}
|
||||
|
@ -1,244 +1,238 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context_initializer.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
namespace context_initializer
|
||||
{
|
||||
void initialize_entity(context* context)
|
||||
{
|
||||
const auto chai = context->get_chai();
|
||||
|
||||
chai->add(chaiscript::user_type<entity>(), "_entity");
|
||||
chai->add(chaiscript::constructor<entity()>(), "_entity");
|
||||
chai->add(chaiscript::constructor<entity(const entity&)>(), "_entity");
|
||||
|
||||
chai->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity&
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun(&entity::get), "get");
|
||||
chai->add(chaiscript::fun(&entity::set), "set");
|
||||
|
||||
chai->add(chaiscript::fun(&entity::on_notify), "onNotify");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& event,
|
||||
const std::function<void(
|
||||
std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback)
|
||||
{
|
||||
return ent.on_notify(event, callback, false);
|
||||
}), "onNotify");
|
||||
|
||||
chai->add(chaiscript::fun([context](const std::string& event,
|
||||
const std::function<void(
|
||||
entity, std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback)
|
||||
{
|
||||
generic_event_listener listener;
|
||||
listener.event = event;
|
||||
listener.is_volatile = false;
|
||||
listener.callback = callback;
|
||||
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
chai->add(chaiscript::fun([context](const std::string& event,
|
||||
const std::function<void(
|
||||
entity, std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback, const bool is_volatile)
|
||||
{
|
||||
generic_event_listener listener;
|
||||
listener.event = event;
|
||||
listener.is_volatile = is_volatile;
|
||||
listener.callback = callback;
|
||||
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
// Notification
|
||||
chai->add(chaiscript::fun(&entity::notify), "vectorNotify");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& event)
|
||||
{
|
||||
return ent.notify(event, {});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return ent.notify(event, {a1});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return ent.notify(event, {a1, a2});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3, a4});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3, a4, a5});
|
||||
}), "notify");
|
||||
|
||||
// Instance call
|
||||
chai->add(chaiscript::fun(&entity::call), "vectorCall");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& function)
|
||||
{
|
||||
return ent.call(function, {});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return ent.call(function, {a1});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return ent.call(function, {a1, a2});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3, a4});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3, a4, a5});
|
||||
}), "call");
|
||||
|
||||
// Global call
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, arguments);
|
||||
}), "vectorCall");
|
||||
chai->add(chaiscript::fun([context](const std::string& function)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3, a4});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3, a4, a5});
|
||||
}), "call");
|
||||
}
|
||||
|
||||
void initialize(context* context)
|
||||
{
|
||||
initialize_entity(context);
|
||||
|
||||
const auto chai = context->get_chai();
|
||||
|
||||
chai->add(chaiscript::fun([](const std::string& string)
|
||||
{
|
||||
printf("%s\n", string.data());
|
||||
}), "print");
|
||||
|
||||
chai->add(chaiscript::fun([](const std::string& string)
|
||||
{
|
||||
MessageBoxA(nullptr, string.data(), nullptr, 0);
|
||||
}), "alert");
|
||||
|
||||
const auto level_id = *native::levelEntityId;
|
||||
chai->add_global(chaiscript::var(entity(context, level_id)), "level");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "std_include.hpp"
|
||||
#include "context_initializer.hpp"
|
||||
|
||||
namespace game::scripting::context_initializer
|
||||
{
|
||||
void initialize_entity(context* context)
|
||||
{
|
||||
const auto chai = context->get_chai();
|
||||
|
||||
chai->add(chaiscript::user_type<entity>(), "_entity");
|
||||
chai->add(chaiscript::constructor<entity()>(), "_entity");
|
||||
chai->add(chaiscript::constructor<entity(const entity&)>(), "_entity");
|
||||
|
||||
chai->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity&
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun(&entity::get), "get");
|
||||
chai->add(chaiscript::fun(&entity::set), "set");
|
||||
|
||||
chai->add(chaiscript::fun(&entity::on_notify), "onNotify");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& event,
|
||||
const std::function<void(
|
||||
std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback)
|
||||
{
|
||||
return ent.on_notify(event, callback, false);
|
||||
}), "onNotify");
|
||||
|
||||
chai->add(chaiscript::fun([context](const std::string& event,
|
||||
const std::function<void(
|
||||
entity, std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback)
|
||||
{
|
||||
generic_event_listener listener;
|
||||
listener.event = event;
|
||||
listener.is_volatile = false;
|
||||
listener.callback = callback;
|
||||
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
chai->add(chaiscript::fun([context](const std::string& event,
|
||||
const std::function<void(
|
||||
entity, std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback, const bool is_volatile)
|
||||
{
|
||||
generic_event_listener listener;
|
||||
listener.event = event;
|
||||
listener.is_volatile = is_volatile;
|
||||
listener.callback = callback;
|
||||
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
// Notification
|
||||
chai->add(chaiscript::fun(&entity::notify), "vectorNotify");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& event)
|
||||
{
|
||||
return ent.notify(event, {});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return ent.notify(event, {a1});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return ent.notify(event, {a1, a2});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3, a4});
|
||||
}), "notify");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& event,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return ent.notify(event, {a1, a2, a3, a4, a5});
|
||||
}), "notify");
|
||||
|
||||
// Instance call
|
||||
chai->add(chaiscript::fun(&entity::call), "vectorCall");
|
||||
chai->add(chaiscript::fun([](const entity& ent, const std::string& function)
|
||||
{
|
||||
return ent.call(function, {});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return ent.call(function, {a1});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return ent.call(function, {a1, a2});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3, a4});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](const entity& ent, const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return ent.call(function, {a1, a2, a3, a4, a5});
|
||||
}), "call");
|
||||
|
||||
// Global call
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, arguments);
|
||||
}), "vectorCall");
|
||||
chai->add(chaiscript::fun([context](const std::string& function)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3, a4});
|
||||
}), "call");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[context](const std::string& function,
|
||||
const chaiscript::Boxed_Value& a1,
|
||||
const chaiscript::Boxed_Value& a2,
|
||||
const chaiscript::Boxed_Value& a3,
|
||||
const chaiscript::Boxed_Value& a4,
|
||||
const chaiscript::Boxed_Value& a5)
|
||||
{
|
||||
return context->get_executer()->call(function, 0, {a1, a2, a3, a4, a5});
|
||||
}), "call");
|
||||
}
|
||||
|
||||
void initialize(context* context)
|
||||
{
|
||||
initialize_entity(context);
|
||||
|
||||
const auto chai = context->get_chai();
|
||||
|
||||
chai->add(chaiscript::fun([](const std::string& string)
|
||||
{
|
||||
printf("%s\n", string.data());
|
||||
}), "print");
|
||||
|
||||
chai->add(chaiscript::fun([](const std::string& string)
|
||||
{
|
||||
MessageBoxA(nullptr, string.data(), nullptr, 0);
|
||||
}), "alert");
|
||||
|
||||
const auto level_id = *native::levelEntityId;
|
||||
chai->add_global(chaiscript::var(entity(context, level_id)), "level");
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
#pragma once
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
namespace context_initializer
|
||||
{
|
||||
void initialize(context* context);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game::scripting::context_initializer
|
||||
{
|
||||
void initialize(context* context);
|
||||
}
|
||||
|
@ -1,21 +1,57 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
entity::entity() : entity(nullptr, 0)
|
||||
{
|
||||
entity::entity() : entity(nullptr, 0)
|
||||
}
|
||||
|
||||
entity::entity(const entity& other) : entity(other.context_, other.entity_id_)
|
||||
{
|
||||
}
|
||||
|
||||
entity::entity(entity&& other) noexcept
|
||||
{
|
||||
if (&other == this) return;
|
||||
|
||||
this->context_ = other.context_;
|
||||
this->entity_id_ = other.entity_id_;
|
||||
|
||||
other.context_ = nullptr;
|
||||
other.entity_id_ = 0;
|
||||
}
|
||||
|
||||
entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
entity::~entity()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
entity& entity::operator=(const entity& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
|
||||
this->context_ = other.context_;
|
||||
this->entity_id_ = other.entity_id_;
|
||||
|
||||
this->add();
|
||||
}
|
||||
|
||||
entity::entity(const entity& other) : entity(other.context_, other.entity_id_)
|
||||
{
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
entity::entity(entity&& other) noexcept
|
||||
entity& entity::operator=(entity&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
if (&other == this) return;
|
||||
this->release();
|
||||
|
||||
this->context_ = other.context_;
|
||||
this->entity_id_ = other.entity_id_;
|
||||
@ -24,111 +60,72 @@ namespace game
|
||||
other.entity_id_ = 0;
|
||||
}
|
||||
|
||||
entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id)
|
||||
return *this;
|
||||
}
|
||||
|
||||
event_listener_handle entity::on_notify(const std::string& event,
|
||||
const std::function<void(std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback,
|
||||
const bool is_volatile)
|
||||
const
|
||||
{
|
||||
event_listener listener;
|
||||
listener.event = event;
|
||||
listener.callback = callback;
|
||||
listener.entity_id = this->entity_id_;
|
||||
listener.is_volatile = is_volatile;
|
||||
|
||||
return this->context_->get_event_handler()->add_event_listener(listener);
|
||||
}
|
||||
|
||||
unsigned int entity::get_entity_id() const
|
||||
{
|
||||
return this->entity_id_;
|
||||
}
|
||||
|
||||
native::scr_entref_t entity::get_entity_reference() const
|
||||
{
|
||||
return game::native::Scr_GetEntityIdRef(this->get_entity_id());
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value entity::call(const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::notify(const std::string& event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
this->context_->get_executer()->notify(event, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const
|
||||
{
|
||||
this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value entity::get(const std::string& field) const
|
||||
{
|
||||
return this->context_->get_executer()->get_entity_field(field, this->get_entity_id());
|
||||
}
|
||||
|
||||
void entity::add() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
this->add();
|
||||
native::VariableValue value;
|
||||
value.type = native::SCRIPT_OBJECT;
|
||||
value.u.entityId = this->entity_id_;
|
||||
native::AddRefToValue(&value);
|
||||
}
|
||||
}
|
||||
|
||||
entity::~entity()
|
||||
void entity::release() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
entity& entity::operator=(const entity& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
|
||||
this->context_ = other.context_;
|
||||
this->entity_id_ = other.entity_id_;
|
||||
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
entity& entity::operator=(entity&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
|
||||
this->context_ = other.context_;
|
||||
this->entity_id_ = other.entity_id_;
|
||||
|
||||
other.context_ = nullptr;
|
||||
other.entity_id_ = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
event_listener_handle entity::on_notify(const std::string& event,
|
||||
const std::function<void(std::vector<chaiscript::Boxed_Value>)>&
|
||||
callback,
|
||||
const bool is_volatile)
|
||||
const
|
||||
{
|
||||
event_listener listener;
|
||||
listener.event = event;
|
||||
listener.callback = callback;
|
||||
listener.entity_id = this->entity_id_;
|
||||
listener.is_volatile = is_volatile;
|
||||
|
||||
return this->context_->get_event_handler()->add_event_listener(listener);
|
||||
}
|
||||
|
||||
unsigned int entity::get_entity_id() const
|
||||
{
|
||||
return this->entity_id_;
|
||||
}
|
||||
|
||||
native::scr_entref_t entity::get_entity_reference() const
|
||||
{
|
||||
return game::native::Scr_GetEntityIdRef(this->get_entity_id());
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value entity::call(const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::notify(const std::string& event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const
|
||||
{
|
||||
this->context_->get_executer()->notify(event, this->get_entity_id(), arguments);
|
||||
}
|
||||
|
||||
void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const
|
||||
{
|
||||
this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value entity::get(const std::string& field) const
|
||||
{
|
||||
return this->context_->get_executer()->get_entity_field(field, this->get_entity_id());
|
||||
}
|
||||
|
||||
void entity::add() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
native::VariableValue value;
|
||||
value.type = native::SCRIPT_OBJECT;
|
||||
value.u.entityId = this->entity_id_;
|
||||
native::AddRefToValue(&value);
|
||||
}
|
||||
}
|
||||
|
||||
void entity::release() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
|
||||
}
|
||||
native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,42 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
class event_listener_handle;
|
||||
|
||||
class entity final
|
||||
{
|
||||
public:
|
||||
entity();
|
||||
entity(const entity& other);
|
||||
entity(entity&& other) noexcept;
|
||||
entity(context* context, unsigned int entity_id);
|
||||
~entity();
|
||||
|
||||
entity& operator=(const entity& other);
|
||||
entity& operator=(entity&& other) noexcept;
|
||||
|
||||
event_listener_handle on_notify(const std::string& event,
|
||||
const std::function<void(std::vector<chaiscript::Boxed_Value>)>& callback,
|
||||
bool is_volatile) const;
|
||||
|
||||
unsigned int get_entity_id() const;
|
||||
game::native::scr_entref_t get_entity_reference() const;
|
||||
|
||||
chaiscript::Boxed_Value call(const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const;
|
||||
void notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const;
|
||||
|
||||
void set(const std::string& field, const chaiscript::Boxed_Value& value) const;
|
||||
chaiscript::Boxed_Value get(const std::string& field) const;
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
unsigned int entity_id_;
|
||||
|
||||
void add() const;
|
||||
void release() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context;
|
||||
class event_listener_handle;
|
||||
|
||||
class entity final
|
||||
{
|
||||
public:
|
||||
entity();
|
||||
entity(const entity& other);
|
||||
entity(entity&& other) noexcept;
|
||||
entity(context* context, unsigned int entity_id);
|
||||
~entity();
|
||||
|
||||
entity& operator=(const entity& other);
|
||||
entity& operator=(entity&& other) noexcept;
|
||||
|
||||
event_listener_handle on_notify(const std::string& event,
|
||||
const std::function<void(std::vector<chaiscript::Boxed_Value>)>& callback,
|
||||
bool is_volatile) const;
|
||||
|
||||
unsigned int get_entity_id() const;
|
||||
game::native::scr_entref_t get_entity_reference() const;
|
||||
|
||||
chaiscript::Boxed_Value call(const std::string& function,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments) const;
|
||||
void notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const;
|
||||
|
||||
void set(const std::string& field, const chaiscript::Boxed_Value& value) const;
|
||||
chaiscript::Boxed_Value get(const std::string& field) const;
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
unsigned int entity_id_;
|
||||
|
||||
void add() const;
|
||||
void release() const;
|
||||
};
|
||||
}
|
||||
|
@ -1,16 +1,13 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class event final
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
unsigned int entity_id;
|
||||
std::vector<native::VariableValue> arguments;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class event final
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
unsigned int entity_id;
|
||||
std::vector<native::VariableValue> arguments;
|
||||
};
|
||||
}
|
||||
|
@ -1,123 +1,120 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
event_handler::event_handler(context* context) : context_(context)
|
||||
{
|
||||
event_handler::event_handler(context* context) : context_(context)
|
||||
const auto chai = this->context_->get_chai();
|
||||
|
||||
chai->add(chaiscript::user_type<event_listener_handle>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(),
|
||||
"_event_listener_handle");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle&
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun([this](const event_listener_handle& handle)
|
||||
{
|
||||
const auto chai = this->context_->get_chai();
|
||||
this->remove(handle);
|
||||
}), "clear");
|
||||
}
|
||||
|
||||
chai->add(chaiscript::user_type<event_listener_handle>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(),
|
||||
"_event_listener_handle");
|
||||
void event_handler::dispatch(event* event)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector<chaiscript::Boxed_Value> arguments;
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle&
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun([this](const event_listener_handle& handle)
|
||||
for (auto argument : event->arguments)
|
||||
{
|
||||
this->remove(handle);
|
||||
}), "clear");
|
||||
arguments.push_back(this->context_->get_parameters()->load(argument));
|
||||
}
|
||||
|
||||
this->dispatch_to_specific_listeners(event, arguments);
|
||||
this->dispatch_to_generic_listeners(event, arguments);
|
||||
}
|
||||
|
||||
void event_handler::dispatch(event* event)
|
||||
catch (chaiscript::exception::eval_error& e)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector<chaiscript::Boxed_Value> arguments;
|
||||
throw std::runtime_error(e.pretty_print());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto argument : event->arguments)
|
||||
void event_handler::dispatch_to_specific_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
for (auto listener : this->event_listeners_)
|
||||
{
|
||||
if (listener->event == event->name && listener->entity_id == event->entity_id)
|
||||
{
|
||||
if (listener->is_volatile)
|
||||
{
|
||||
arguments.push_back(this->context_->get_parameters()->load(argument));
|
||||
this->event_listeners_.remove(listener);
|
||||
}
|
||||
|
||||
this->dispatch_to_specific_listeners(event, arguments);
|
||||
this->dispatch_to_generic_listeners(event, arguments);
|
||||
listener->callback(arguments);
|
||||
}
|
||||
catch (chaiscript::exception::eval_error& e)
|
||||
}
|
||||
}
|
||||
|
||||
void event_handler::dispatch_to_generic_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
for (auto listener : this->generic_event_listeners_)
|
||||
{
|
||||
if (listener->event == event->name)
|
||||
{
|
||||
throw std::runtime_error(e.pretty_print());
|
||||
if (listener->is_volatile)
|
||||
{
|
||||
this->generic_event_listeners_.remove(listener);
|
||||
}
|
||||
|
||||
listener->callback(entity(this->context_, event->entity_id), arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event_listener_handle event_handler::add_event_listener(event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->event_listeners_.add(listener);
|
||||
return {listener.id};
|
||||
}
|
||||
|
||||
event_listener_handle event_handler::add_event_listener(generic_event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->generic_event_listeners_.add(listener);
|
||||
return {listener.id};
|
||||
}
|
||||
|
||||
void event_handler::clear()
|
||||
{
|
||||
this->event_listeners_.clear();
|
||||
this->generic_event_listeners_.clear();
|
||||
}
|
||||
|
||||
void event_handler::remove(const event_listener_handle& handle)
|
||||
{
|
||||
for (const auto task : this->event_listeners_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void event_handler::dispatch_to_specific_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
for (const auto task : this->generic_event_listeners_)
|
||||
{
|
||||
for (auto listener : this->event_listeners_)
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
if (listener->event == event->name && listener->entity_id == event->entity_id)
|
||||
{
|
||||
if (listener->is_volatile)
|
||||
{
|
||||
this->event_listeners_.remove(listener);
|
||||
}
|
||||
|
||||
listener->callback(arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void event_handler::dispatch_to_generic_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
for (auto listener : this->generic_event_listeners_)
|
||||
{
|
||||
if (listener->event == event->name)
|
||||
{
|
||||
if (listener->is_volatile)
|
||||
{
|
||||
this->generic_event_listeners_.remove(listener);
|
||||
}
|
||||
|
||||
listener->callback(entity(this->context_, event->entity_id), arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event_listener_handle event_handler::add_event_listener(event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->event_listeners_.add(listener);
|
||||
return {listener.id};
|
||||
}
|
||||
|
||||
event_listener_handle event_handler::add_event_listener(generic_event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->generic_event_listeners_.add(listener);
|
||||
return {listener.id};
|
||||
}
|
||||
|
||||
void event_handler::clear()
|
||||
{
|
||||
this->event_listeners_.clear();
|
||||
this->generic_event_listeners_.clear();
|
||||
}
|
||||
|
||||
void event_handler::remove(const event_listener_handle& handle)
|
||||
{
|
||||
for (const auto task : this->event_listeners_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto task : this->generic_event_listeners_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->generic_event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
this->generic_event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +1,57 @@
|
||||
#pragma once
|
||||
#include "utils/concurrent_list.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class event_listener_handle
|
||||
{
|
||||
public:
|
||||
unsigned long long id = 0;
|
||||
};
|
||||
|
||||
class event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
unsigned int entity_id = 0;
|
||||
std::function<void(std::vector<chaiscript::Boxed_Value>)> callback = {};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class generic_event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
std::function<void(entity, std::vector<chaiscript::Boxed_Value>)> callback = {};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class event_handler final
|
||||
{
|
||||
public:
|
||||
explicit event_handler(context* context);
|
||||
|
||||
void dispatch(event* event);
|
||||
|
||||
event_listener_handle add_event_listener(event_listener listener);
|
||||
event_listener_handle add_event_listener(generic_event_listener listener);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
std::atomic_int64_t current_listener_id_ = 0;
|
||||
|
||||
utils::concurrent_list<event_listener> event_listeners_;
|
||||
utils::concurrent_list<generic_event_listener> generic_event_listeners_;
|
||||
|
||||
void dispatch_to_specific_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
void dispatch_to_generic_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
|
||||
void remove(const event_listener_handle& handle);
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "utils/concurrent_list.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class event_listener_handle
|
||||
{
|
||||
public:
|
||||
unsigned long long id = 0;
|
||||
};
|
||||
|
||||
class event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
unsigned int entity_id = 0;
|
||||
std::function<void(std::vector<chaiscript::Boxed_Value>)> callback = {};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class generic_event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
std::function<void(entity, std::vector<chaiscript::Boxed_Value>)> callback = {};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class event_handler final
|
||||
{
|
||||
public:
|
||||
explicit event_handler(context* context);
|
||||
|
||||
void dispatch(event* event);
|
||||
|
||||
event_listener_handle add_event_listener(event_listener listener);
|
||||
event_listener_handle add_event_listener(generic_event_listener listener);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
std::atomic_int64_t current_listener_id_ = 0;
|
||||
|
||||
utils::concurrent_list<event_listener> event_listeners_;
|
||||
utils::concurrent_list<generic_event_listener> generic_event_listeners_;
|
||||
|
||||
void dispatch_to_specific_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
void dispatch_to_generic_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
|
||||
void remove(const event_listener_handle& handle);
|
||||
};
|
||||
}
|
||||
|
@ -6,167 +6,164 @@
|
||||
#include "safe_executer.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
executer::executer(context* context) : context_(context)
|
||||
{
|
||||
executer::executer(context* context) : context_(context)
|
||||
}
|
||||
|
||||
int executer::get_field_id(const int classnum, const std::string& field) const
|
||||
{
|
||||
const auto field_name = utils::string::to_lower(field);
|
||||
const auto class_id = native::g_classMap[classnum].id;
|
||||
const auto field_str = native::SL_GetString(field_name.data(), 1);
|
||||
const auto _ = gsl::finally([field_str]()
|
||||
{
|
||||
native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)});
|
||||
});
|
||||
|
||||
const auto offset = native::FindVariable(class_id, field_str);
|
||||
if (offset)
|
||||
{
|
||||
const auto index = 4 * (offset + 0xC800 * (class_id & 1));
|
||||
return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index];
|
||||
}
|
||||
|
||||
int executer::get_field_id(const int classnum, const std::string& field) const
|
||||
{
|
||||
const auto field_name = utils::string::to_lower(field);
|
||||
const auto class_id = native::g_classMap[classnum].id;
|
||||
const auto field_str = native::SL_GetString(field_name.data(), 1);
|
||||
const auto _ = gsl::finally([field_str]()
|
||||
{
|
||||
native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)});
|
||||
});
|
||||
return -1;
|
||||
}
|
||||
|
||||
const auto offset = native::FindVariable(class_id, field_str);
|
||||
if (offset)
|
||||
{
|
||||
const auto index = 4 * (offset + 0xC800 * (class_id & 1));
|
||||
return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index];
|
||||
}
|
||||
void executer::set_entity_field(const std::string& field, const unsigned int entity_id,
|
||||
const chaiscript::Boxed_Value& value)
|
||||
{
|
||||
const auto entref = native::Scr_GetEntityIdRef(entity_id);
|
||||
const int id = get_field_id(entref.raw.classnum, field);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void executer::set_entity_field(const std::string& field, const unsigned int entity_id,
|
||||
const chaiscript::Boxed_Value& value)
|
||||
{
|
||||
const auto entref = native::Scr_GetEntityIdRef(entity_id);
|
||||
const int id = get_field_id(entref.raw.classnum, field);
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
this->context_->get_parameters()->push(value);
|
||||
|
||||
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
|
||||
if (!safe_executer::set_entity_field(entref, id))
|
||||
{
|
||||
throw std::runtime_error("Failed to set value for field '" + field + "'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->entity_fields_[entity_id][field] = value;
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id)
|
||||
{
|
||||
const auto entref = native::Scr_GetEntityIdRef(entity_id);
|
||||
const auto id = this->get_field_id(entref.raw.classnum, field);
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
|
||||
native::VariableValue value{};
|
||||
if (!safe_executer::get_entity_field(entref, id, &value))
|
||||
{
|
||||
throw std::runtime_error("Failed to get value for field '" + field + "'");
|
||||
}
|
||||
|
||||
const auto $ = gsl::finally([value]()
|
||||
{
|
||||
native::RemoveRefToValue(value.type, value.u);
|
||||
});
|
||||
|
||||
return this->context_->get_parameters()->load(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& map = this->entity_fields_[entity_id];
|
||||
const auto value = map.find(field);
|
||||
if (value != map.end())
|
||||
{
|
||||
return value->second;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void executer::notify(const std::string& event, const unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
|
||||
std::reverse(arguments.begin(), arguments.end());
|
||||
for (auto argument : arguments)
|
||||
{
|
||||
this->context_->get_parameters()->push(argument);
|
||||
}
|
||||
|
||||
const auto event_id = native::SL_GetString(event.data(), 0);
|
||||
native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const
|
||||
{
|
||||
const auto function_index = find_function_index(function, entity_id == 0);
|
||||
if (function_index < 0)
|
||||
{
|
||||
throw std::runtime_error("No function found for name '" + function + "'");
|
||||
}
|
||||
|
||||
const auto entity = function_index > 0x1C7
|
||||
? native::Scr_GetEntityIdRef(entity_id)
|
||||
: native::scr_entref_t{~0u};
|
||||
|
||||
const auto function_ptr = native::Scr_GetFunc(function_index);
|
||||
|
||||
stack_isolation _;
|
||||
|
||||
std::reverse(arguments.begin(), arguments.end());
|
||||
for (const auto& argument : arguments)
|
||||
{
|
||||
this->context_->get_parameters()->push(argument);
|
||||
}
|
||||
this->context_->get_parameters()->push(value);
|
||||
|
||||
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
|
||||
if (!safe_executer::call(function_ptr, entity))
|
||||
if (!safe_executer::set_entity_field(entref, id))
|
||||
{
|
||||
throw std::runtime_error("Error executing function '" + function + "'");
|
||||
throw std::runtime_error("Failed to set value for field '" + field + "'");
|
||||
}
|
||||
|
||||
return this->context_->get_parameters()->get_return_value();
|
||||
}
|
||||
|
||||
int executer::find_function_index(const std::string& function, const bool prefer_global)
|
||||
else
|
||||
{
|
||||
const auto target = utils::string::to_lower(function);
|
||||
|
||||
const auto primary_map = prefer_global
|
||||
? &global_function_map
|
||||
: &instance_function_map;
|
||||
const auto secondary_map = !prefer_global
|
||||
? &global_function_map
|
||||
: &instance_function_map;
|
||||
|
||||
auto function_entry = primary_map->find(target);
|
||||
if (function_entry != primary_map->end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
function_entry = secondary_map->find(target);
|
||||
if (function_entry != secondary_map->end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
this->entity_fields_[entity_id][field] = value;
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id)
|
||||
{
|
||||
const auto entref = native::Scr_GetEntityIdRef(entity_id);
|
||||
const auto id = this->get_field_id(entref.raw.classnum, field);
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
|
||||
native::VariableValue value{};
|
||||
if (!safe_executer::get_entity_field(entref, id, &value))
|
||||
{
|
||||
throw std::runtime_error("Failed to get value for field '" + field + "'");
|
||||
}
|
||||
|
||||
const auto $ = gsl::finally([value]()
|
||||
{
|
||||
native::RemoveRefToValue(value.type, value.u);
|
||||
});
|
||||
|
||||
return this->context_->get_parameters()->load(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& map = this->entity_fields_[entity_id];
|
||||
const auto value = map.find(field);
|
||||
if (value != map.end())
|
||||
{
|
||||
return value->second;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void executer::notify(const std::string& event, const unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const
|
||||
{
|
||||
stack_isolation _;
|
||||
|
||||
std::reverse(arguments.begin(), arguments.end());
|
||||
for (auto argument : arguments)
|
||||
{
|
||||
this->context_->get_parameters()->push(argument);
|
||||
}
|
||||
|
||||
const auto event_id = native::SL_GetString(event.data(), 0);
|
||||
native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const
|
||||
{
|
||||
const auto function_index = find_function_index(function, entity_id == 0);
|
||||
if (function_index < 0)
|
||||
{
|
||||
throw std::runtime_error("No function found for name '" + function + "'");
|
||||
}
|
||||
|
||||
const auto entity = function_index > 0x1C7
|
||||
? native::Scr_GetEntityIdRef(entity_id)
|
||||
: native::scr_entref_t{~0u};
|
||||
|
||||
const auto function_ptr = native::Scr_GetFunc(function_index);
|
||||
|
||||
stack_isolation _;
|
||||
|
||||
std::reverse(arguments.begin(), arguments.end());
|
||||
for (const auto& argument : arguments)
|
||||
{
|
||||
this->context_->get_parameters()->push(argument);
|
||||
}
|
||||
|
||||
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
|
||||
if (!safe_executer::call(function_ptr, entity))
|
||||
{
|
||||
throw std::runtime_error("Error executing function '" + function + "'");
|
||||
}
|
||||
|
||||
return this->context_->get_parameters()->get_return_value();
|
||||
}
|
||||
|
||||
int executer::find_function_index(const std::string& function, const bool prefer_global)
|
||||
{
|
||||
const auto target = utils::string::to_lower(function);
|
||||
|
||||
const auto primary_map = prefer_global
|
||||
? &global_function_map
|
||||
: &instance_function_map;
|
||||
const auto secondary_map = !prefer_global
|
||||
? &global_function_map
|
||||
: &instance_function_map;
|
||||
|
||||
auto function_entry = primary_map->find(target);
|
||||
if (function_entry != primary_map->end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
function_entry = secondary_map->find(target);
|
||||
if (function_entry != secondary_map->end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class executer final
|
||||
{
|
||||
public:
|
||||
explicit executer(context* context);
|
||||
|
||||
void set_entity_field(const std::string& field, unsigned int entity_id,
|
||||
const chaiscript::Boxed_Value& value);
|
||||
chaiscript::Boxed_Value get_entity_field(const std::string& field, unsigned int entity_id);
|
||||
|
||||
void notify(const std::string& event, unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const;
|
||||
|
||||
chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const;
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
|
||||
std::unordered_map<unsigned int, std::unordered_map<std::string, chaiscript::Boxed_Value>> entity_fields_;
|
||||
|
||||
int get_field_id(int classnum, const std::string& field) const;
|
||||
|
||||
static int find_function_index(const std::string& function, bool prefer_global);
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class executer final
|
||||
{
|
||||
public:
|
||||
explicit executer(context* context);
|
||||
|
||||
void set_entity_field(const std::string& field, unsigned int entity_id,
|
||||
const chaiscript::Boxed_Value& value);
|
||||
chaiscript::Boxed_Value get_entity_field(const std::string& field, unsigned int entity_id);
|
||||
|
||||
void notify(const std::string& event, unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const;
|
||||
|
||||
chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id,
|
||||
std::vector<chaiscript::Boxed_Value> arguments) const;
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
|
||||
std::unordered_map<unsigned int, std::unordered_map<std::string, chaiscript::Boxed_Value>> entity_fields_;
|
||||
|
||||
int get_field_id(int classnum, const std::string& field) const;
|
||||
|
||||
static int find_function_index(const std::string& function, bool prefer_global);
|
||||
};
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
extern std::map<std::string, int> instance_function_map;
|
||||
extern std::map<std::string, int> global_function_map;
|
||||
}
|
||||
extern std::map<std::string, int> instance_function_map;
|
||||
extern std::map<std::string, int> global_function_map;
|
||||
}
|
||||
|
@ -1,153 +1,150 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
parameters::parameters(context* context) : context_(context)
|
||||
{
|
||||
parameters::parameters(context* context) : context_(context)
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const
|
||||
{
|
||||
if (value.type == native::SCRIPT_STRING)
|
||||
{
|
||||
const std::string string = native::SL_ConvertToString(value.u.stringValue);
|
||||
return chaiscript::var(string);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_FLOAT)
|
||||
{
|
||||
return chaiscript::var(value.u.floatValue);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_INTEGER)
|
||||
{
|
||||
return chaiscript::var(value.u.intValue);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_OBJECT)
|
||||
{
|
||||
return chaiscript::var(entity(this->context_, value.u.entityId));
|
||||
}
|
||||
else if (value.type == native::SCRIPT_VECTOR)
|
||||
{
|
||||
std::vector<chaiscript::Boxed_Value> values;
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[0]));
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[1]));
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[2]));
|
||||
|
||||
return chaiscript::var(values);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const
|
||||
return {};
|
||||
}
|
||||
|
||||
void parameters::push(const chaiscript::Boxed_Value& value) const
|
||||
{
|
||||
if (native::scr_VmPub->outparamcount)
|
||||
{
|
||||
if (value.type == native::SCRIPT_STRING)
|
||||
{
|
||||
const std::string string = native::SL_ConvertToString(value.u.stringValue);
|
||||
return chaiscript::var(string);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_FLOAT)
|
||||
{
|
||||
return chaiscript::var(value.u.floatValue);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_INTEGER)
|
||||
{
|
||||
return chaiscript::var(value.u.intValue);
|
||||
}
|
||||
else if (value.type == native::SCRIPT_OBJECT)
|
||||
{
|
||||
return chaiscript::var(entity(this->context_, value.u.entityId));
|
||||
}
|
||||
else if (value.type == native::SCRIPT_VECTOR)
|
||||
{
|
||||
std::vector<chaiscript::Boxed_Value> values;
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[0]));
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[1]));
|
||||
values.push_back(chaiscript::var(value.u.vectorValue[2]));
|
||||
|
||||
return chaiscript::var(values);
|
||||
}
|
||||
|
||||
return {};
|
||||
native::Scr_ClearOutParams();
|
||||
}
|
||||
|
||||
void parameters::push(const chaiscript::Boxed_Value& value) const
|
||||
if (native::scr_VmPub->top == native::scr_VmPub->maxstack)
|
||||
{
|
||||
if (native::scr_VmPub->outparamcount)
|
||||
throw std::runtime_error("Internal script stack overflow");
|
||||
}
|
||||
|
||||
native::VariableValue* value_ptr = ++native::scr_VmPub->top;
|
||||
++native::scr_VmPub->inparamcount;
|
||||
|
||||
value_ptr->type = native::SCRIPT_NONE;
|
||||
value_ptr->u.intValue = 0;
|
||||
|
||||
if (value.get_type_info() == typeid(float))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<float>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<double>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = static_cast<float>(real_value);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<int>(value);
|
||||
value_ptr->type = native::SCRIPT_INTEGER;
|
||||
value_ptr->u.intValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(bool))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<bool>(value);
|
||||
value_ptr->type = native::SCRIPT_INTEGER;
|
||||
value_ptr->u.intValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(entity))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<entity>(value);
|
||||
value_ptr->type = native::SCRIPT_OBJECT;
|
||||
value_ptr->u.entityId = real_value.get_entity_id();
|
||||
|
||||
game::native::AddRefToValue(value_ptr);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(std::string))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::string>(value);
|
||||
value_ptr->type = native::SCRIPT_STRING;
|
||||
value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(std::vector<chaiscript::Boxed_Value>))
|
||||
{
|
||||
float values[3];
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>
|
||||
>(value);
|
||||
if (real_value.size() != 3)
|
||||
{
|
||||
native::Scr_ClearOutParams();
|
||||
throw std::runtime_error("Invalid vector length. Size must be exactly 3");
|
||||
}
|
||||
|
||||
if (native::scr_VmPub->top == native::scr_VmPub->maxstack)
|
||||
const auto unbox_float = [&real_value, this](const size_t index) -> float
|
||||
{
|
||||
throw std::runtime_error("Internal script stack overflow");
|
||||
}
|
||||
|
||||
native::VariableValue* value_ptr = ++native::scr_VmPub->top;
|
||||
++native::scr_VmPub->inparamcount;
|
||||
|
||||
value_ptr->type = native::SCRIPT_NONE;
|
||||
value_ptr->u.intValue = 0;
|
||||
|
||||
if (value.get_type_info() == typeid(float))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<float>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<double>(value);
|
||||
value_ptr->type = native::SCRIPT_FLOAT;
|
||||
value_ptr->u.floatValue = static_cast<float>(real_value);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<int>(value);
|
||||
value_ptr->type = native::SCRIPT_INTEGER;
|
||||
value_ptr->u.intValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(bool))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<bool>(value);
|
||||
value_ptr->type = native::SCRIPT_INTEGER;
|
||||
value_ptr->u.intValue = real_value;
|
||||
}
|
||||
else if (value.get_type_info() == typeid(entity))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<entity>(value);
|
||||
value_ptr->type = native::SCRIPT_OBJECT;
|
||||
value_ptr->u.entityId = real_value.get_entity_id();
|
||||
|
||||
game::native::AddRefToValue(value_ptr);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(std::string))
|
||||
{
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::string>(value);
|
||||
value_ptr->type = native::SCRIPT_STRING;
|
||||
value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0);
|
||||
}
|
||||
else if (value.get_type_info() == typeid(std::vector<chaiscript::Boxed_Value>))
|
||||
{
|
||||
float values[3];
|
||||
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>
|
||||
>(value);
|
||||
if (real_value.size() != 3)
|
||||
const auto value = real_value[index];
|
||||
if (value.get_type_info() == typeid(float))
|
||||
{
|
||||
throw std::runtime_error("Invalid vector length. Size must be exactly 3");
|
||||
return this->context_->get_chai()->boxed_cast<float>(value);
|
||||
}
|
||||
if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<double>(value));
|
||||
}
|
||||
if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<int>(value));
|
||||
}
|
||||
|
||||
const auto unbox_float = [&real_value, this](const size_t index) -> float
|
||||
{
|
||||
const auto value = real_value[index];
|
||||
if (value.get_type_info() == typeid(float))
|
||||
{
|
||||
return this->context_->get_chai()->boxed_cast<float>(value);
|
||||
}
|
||||
if (value.get_type_info() == typeid(double))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<double>(value));
|
||||
}
|
||||
if (value.get_type_info() == typeid(int))
|
||||
{
|
||||
return float(this->context_->get_chai()->boxed_cast<int>(value));
|
||||
}
|
||||
throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number");
|
||||
};
|
||||
|
||||
throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number");
|
||||
};
|
||||
values[0] = unbox_float(0);
|
||||
values[1] = unbox_float(1);
|
||||
values[2] = unbox_float(2);
|
||||
|
||||
values[0] = unbox_float(0);
|
||||
values[1] = unbox_float(1);
|
||||
values[2] = unbox_float(2);
|
||||
|
||||
value_ptr->type = native::SCRIPT_VECTOR;
|
||||
value_ptr->u.vectorValue = native::Scr_AllocVector(values);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'");
|
||||
}
|
||||
value_ptr->type = native::SCRIPT_VECTOR;
|
||||
value_ptr->u.vectorValue = native::Scr_AllocVector(values);
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value parameters::get_return_value() const
|
||||
else
|
||||
{
|
||||
if (native::scr_VmPub->inparamcount == 0) return {};
|
||||
|
||||
native::Scr_ClearOutParams();
|
||||
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
|
||||
return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]);
|
||||
throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::Boxed_Value parameters::get_return_value() const
|
||||
{
|
||||
if (native::scr_VmPub->inparamcount == 0) return {};
|
||||
|
||||
native::Scr_ClearOutParams();
|
||||
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
|
||||
return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,20 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class parameters final
|
||||
{
|
||||
public:
|
||||
explicit parameters(context* context);
|
||||
|
||||
void push(const chaiscript::Boxed_Value& value) const;
|
||||
chaiscript::Boxed_Value load(native::VariableValue value) const;
|
||||
|
||||
chaiscript::Boxed_Value get_return_value() const;
|
||||
private:
|
||||
context* context_;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class parameters final
|
||||
{
|
||||
public:
|
||||
explicit parameters(context* context);
|
||||
|
||||
void push(const chaiscript::Boxed_Value& value) const;
|
||||
chaiscript::Boxed_Value load(native::VariableValue value) const;
|
||||
|
||||
chaiscript::Boxed_Value get_return_value() const;
|
||||
private:
|
||||
context* context_;
|
||||
};
|
||||
}
|
||||
|
@ -1,63 +1,59 @@
|
||||
#include "std_include.hpp"
|
||||
#include "safe_executer.hpp"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4611)
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
namespace safe_executer
|
||||
{
|
||||
static_assert(sizeof(jmp_buf) == 64);
|
||||
|
||||
bool call(const native::scr_call_t function, const native::scr_entref_t entref)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
function(entref.val);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_entity_field(const native::scr_entref_t entref, const int offset)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
native::Scr_SetObjectField(entref.raw.classnum, entref.raw.entnum, offset);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
value->type = native::SCRIPT_NONE;
|
||||
value->u.intValue = 0;
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = native::GetEntityFieldValue(entref.raw.classnum, entref.raw.entnum, offset);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
#include "std_include.hpp"
|
||||
#include "safe_executer.hpp"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4611)
|
||||
|
||||
namespace game::scripting::safe_executer
|
||||
{
|
||||
static_assert(sizeof(jmp_buf) == 64);
|
||||
|
||||
bool call(const native::scr_call_t function, const native::scr_entref_t entref)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
function(entref.val);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_entity_field(const native::scr_entref_t entref, const int offset)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
native::Scr_SetObjectField(entref.raw.classnum, entref.raw.entnum, offset);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value)
|
||||
{
|
||||
*native::g_script_error_level += 1;
|
||||
if (setjmp(native::g_script_error[*native::g_script_error_level]))
|
||||
{
|
||||
value->type = native::SCRIPT_NONE;
|
||||
value->u.intValue = 0;
|
||||
*native::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = native::GetEntityFieldValue(entref.raw.classnum, entref.raw.entnum, offset);
|
||||
|
||||
*native::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
@ -1,15 +1,9 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
namespace safe_executer
|
||||
{
|
||||
bool call(const native::scr_call_t function, const native::scr_entref_t entref);
|
||||
bool set_entity_field(const native::scr_entref_t entref, const int offset);
|
||||
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting::safe_executer
|
||||
{
|
||||
bool call(const native::scr_call_t function, const native::scr_entref_t entref);
|
||||
bool set_entity_field(const native::scr_entref_t entref, const int offset);
|
||||
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value);
|
||||
}
|
||||
|
@ -1,98 +1,95 @@
|
||||
#include "std_include.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace game
|
||||
namespace game::scripting
|
||||
{
|
||||
namespace scripting
|
||||
scheduler::scheduler(context* context) : context_(context)
|
||||
{
|
||||
scheduler::scheduler(context* context) : context_(context)
|
||||
const auto chai = this->context_->get_chai();
|
||||
|
||||
chai->add(chaiscript::user_type<task_handle>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_task_handle");
|
||||
|
||||
chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle&
|
||||
{
|
||||
const auto chai = this->context_->get_chai();
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::user_type<task_handle>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle");
|
||||
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_task_handle");
|
||||
chai->add(chaiscript::fun(
|
||||
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, true);
|
||||
}), "setTimeout");
|
||||
|
||||
chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle&
|
||||
chai->add(chaiscript::fun(
|
||||
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, false);
|
||||
}), "setInterval");
|
||||
|
||||
const auto clear = [this](const task_handle& handle)
|
||||
{
|
||||
this->remove(handle);
|
||||
};
|
||||
|
||||
chai->add(chaiscript::fun(clear), "clear");
|
||||
chai->add(chaiscript::fun(clear), "clearTimeout");
|
||||
chai->add(chaiscript::fun(clear), "clearInterval");
|
||||
}
|
||||
|
||||
void scheduler::run_frame()
|
||||
{
|
||||
for (auto task : this->tasks_)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if ((now - task->last_execution) > task->delay)
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, true);
|
||||
}), "setTimeout");
|
||||
|
||||
chai->add(chaiscript::fun(
|
||||
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
|
||||
{
|
||||
return this->add(callback, milliseconds, false);
|
||||
}), "setInterval");
|
||||
|
||||
const auto clear = [this](const task_handle& handle)
|
||||
{
|
||||
this->remove(handle);
|
||||
};
|
||||
|
||||
chai->add(chaiscript::fun(clear), "clear");
|
||||
chai->add(chaiscript::fun(clear), "clearTimeout");
|
||||
chai->add(chaiscript::fun(clear), "clearInterval");
|
||||
}
|
||||
|
||||
void scheduler::run_frame()
|
||||
{
|
||||
for (auto task : this->tasks_)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if ((now - task->last_execution) > task->delay)
|
||||
{
|
||||
task->last_execution = now;
|
||||
if (task->is_volatile)
|
||||
{
|
||||
this->tasks_.remove(task);
|
||||
}
|
||||
|
||||
task->callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler::clear()
|
||||
{
|
||||
this->tasks_.clear();
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const std::function<void()>& callback, const long long milliseconds,
|
||||
const bool is_volatile)
|
||||
{
|
||||
return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile);
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const std::function<void()>& callback, const std::chrono::milliseconds delay,
|
||||
const bool is_volatile)
|
||||
{
|
||||
task task;
|
||||
task.is_volatile = is_volatile;
|
||||
task.callback = callback;
|
||||
task.delay = delay;
|
||||
task.last_execution = std::chrono::steady_clock::now();
|
||||
task.id = ++this->current_task_id_;
|
||||
|
||||
this->tasks_.add(task);
|
||||
|
||||
return {task.id};
|
||||
}
|
||||
|
||||
void scheduler::remove(const task_handle& handle)
|
||||
{
|
||||
for (auto task : this->tasks_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
task->last_execution = now;
|
||||
if (task->is_volatile)
|
||||
{
|
||||
this->tasks_.remove(task);
|
||||
break;
|
||||
}
|
||||
|
||||
task->callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler::clear()
|
||||
{
|
||||
this->tasks_.clear();
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const std::function<void()>& callback, const long long milliseconds,
|
||||
const bool is_volatile)
|
||||
{
|
||||
return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile);
|
||||
}
|
||||
|
||||
task_handle scheduler::add(const std::function<void()>& callback, const std::chrono::milliseconds delay,
|
||||
const bool is_volatile)
|
||||
{
|
||||
task task;
|
||||
task.is_volatile = is_volatile;
|
||||
task.callback = callback;
|
||||
task.delay = delay;
|
||||
task.last_execution = std::chrono::steady_clock::now();
|
||||
task.id = ++this->current_task_id_;
|
||||
|
||||
this->tasks_.add(task);
|
||||
|
||||
return {task.id};
|
||||
}
|
||||
|
||||
void scheduler::remove(const task_handle& handle)
|
||||
{
|
||||
for (auto task : this->tasks_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->tasks_.remove(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,42 @@
|
||||
#pragma once
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class task_handle
|
||||
{
|
||||
public:
|
||||
unsigned long long id = 0;
|
||||
};
|
||||
|
||||
class task final : public task_handle
|
||||
{
|
||||
public:
|
||||
std::chrono::steady_clock::time_point last_execution{};
|
||||
std::function<void()> callback{};
|
||||
std::chrono::milliseconds delay{};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class scheduler final
|
||||
{
|
||||
public:
|
||||
explicit scheduler(context* context);
|
||||
|
||||
void run_frame();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
|
||||
utils::concurrent_list<task> tasks_;
|
||||
std::atomic_int64_t current_task_id_ = 0;
|
||||
|
||||
task_handle add(const std::function<void()>& callback, long long milliseconds, bool is_volatile);
|
||||
task_handle add(const std::function<void()>& callback, std::chrono::milliseconds delay, bool is_volatile);
|
||||
|
||||
void remove(const task_handle& handle);
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class context;
|
||||
|
||||
class task_handle
|
||||
{
|
||||
public:
|
||||
unsigned long long id = 0;
|
||||
};
|
||||
|
||||
class task final : public task_handle
|
||||
{
|
||||
public:
|
||||
std::chrono::steady_clock::time_point last_execution{};
|
||||
std::function<void()> callback{};
|
||||
std::chrono::milliseconds delay{};
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class scheduler final
|
||||
{
|
||||
public:
|
||||
explicit scheduler(context* context);
|
||||
|
||||
void run_frame();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
|
||||
utils::concurrent_list<task> tasks_;
|
||||
std::atomic_int64_t current_task_id_ = 0;
|
||||
|
||||
task_handle add(const std::function<void()>& callback, long long milliseconds, bool is_volatile);
|
||||
task_handle add(const std::function<void()>& callback, std::chrono::milliseconds delay, bool is_volatile);
|
||||
|
||||
void remove(const task_handle& handle);
|
||||
};
|
||||
}
|
||||
|
@ -1,30 +1,27 @@
|
||||
#include "std_include.hpp"
|
||||
#include "stack_isolation.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
stack_isolation::stack_isolation()
|
||||
{
|
||||
this->in_param_count_ = native::scr_VmPub->inparamcount;
|
||||
this->out_param_count_ = native::scr_VmPub->outparamcount;
|
||||
this->top_ = native::scr_VmPub->top;
|
||||
this->max_stack_ = native::scr_VmPub->maxstack;
|
||||
|
||||
native::scr_VmPub->top = this->stack_;
|
||||
native::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
native::scr_VmPub->outparamcount = 0;
|
||||
}
|
||||
|
||||
stack_isolation::~stack_isolation()
|
||||
{
|
||||
native::Scr_ClearOutParams();
|
||||
native::scr_VmPub->inparamcount = this->in_param_count_;
|
||||
native::scr_VmPub->outparamcount = this->out_param_count_;
|
||||
native::scr_VmPub->top = this->top_;
|
||||
native::scr_VmPub->maxstack = this->max_stack_;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "std_include.hpp"
|
||||
#include "stack_isolation.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
stack_isolation::stack_isolation()
|
||||
{
|
||||
this->in_param_count_ = native::scr_VmPub->inparamcount;
|
||||
this->out_param_count_ = native::scr_VmPub->outparamcount;
|
||||
this->top_ = native::scr_VmPub->top;
|
||||
this->max_stack_ = native::scr_VmPub->maxstack;
|
||||
|
||||
native::scr_VmPub->top = this->stack_;
|
||||
native::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
|
||||
native::scr_VmPub->inparamcount = 0;
|
||||
native::scr_VmPub->outparamcount = 0;
|
||||
}
|
||||
|
||||
stack_isolation::~stack_isolation()
|
||||
{
|
||||
native::Scr_ClearOutParams();
|
||||
native::scr_VmPub->inparamcount = this->in_param_count_;
|
||||
native::scr_VmPub->outparamcount = this->out_param_count_;
|
||||
native::scr_VmPub->top = this->top_;
|
||||
native::scr_VmPub->maxstack = this->max_stack_;
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,20 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class stack_isolation final
|
||||
{
|
||||
public:
|
||||
stack_isolation();
|
||||
~stack_isolation();
|
||||
|
||||
private:
|
||||
native::VariableValue stack_[512]{};
|
||||
|
||||
native::VariableValue* max_stack_;
|
||||
native::VariableValue* top_;
|
||||
unsigned int in_param_count_;
|
||||
unsigned int out_param_count_;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class stack_isolation final
|
||||
{
|
||||
public:
|
||||
stack_isolation();
|
||||
~stack_isolation();
|
||||
|
||||
private:
|
||||
native::VariableValue stack_[512]{};
|
||||
|
||||
native::VariableValue* max_stack_;
|
||||
native::VariableValue* top_;
|
||||
unsigned int in_param_count_;
|
||||
unsigned int out_param_count_;
|
||||
};
|
||||
}
|
||||
|
@ -1,23 +1,20 @@
|
||||
#include "std_include.hpp"
|
||||
#include "variable_value.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
variable_value::variable_value(native::VariableValue value) : value_(value)
|
||||
{
|
||||
native::AddRefToValue(&value);
|
||||
}
|
||||
|
||||
variable_value::~variable_value()
|
||||
{
|
||||
native::RemoveRefToValue(this->value_.type, this->value_.u);
|
||||
}
|
||||
|
||||
variable_value::operator native::VariableValue() const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "std_include.hpp"
|
||||
#include "variable_value.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
variable_value::variable_value(native::VariableValue value) : value_(value)
|
||||
{
|
||||
native::AddRefToValue(&value);
|
||||
}
|
||||
|
||||
variable_value::~variable_value()
|
||||
{
|
||||
native::RemoveRefToValue(this->value_.type, this->value_.u);
|
||||
}
|
||||
|
||||
variable_value::operator native::VariableValue() const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,17 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
namespace scripting
|
||||
{
|
||||
class variable_value final
|
||||
{
|
||||
public:
|
||||
explicit variable_value(native::VariableValue value);
|
||||
~variable_value();
|
||||
|
||||
explicit operator native::VariableValue() const;
|
||||
|
||||
private:
|
||||
native::VariableValue value_;
|
||||
};
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace game::scripting
|
||||
{
|
||||
class variable_value final
|
||||
{
|
||||
public:
|
||||
explicit variable_value(native::VariableValue value);
|
||||
~variable_value();
|
||||
|
||||
explicit operator native::VariableValue() const;
|
||||
|
||||
private:
|
||||
native::VariableValue value_;
|
||||
};
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ namespace demonware
|
||||
auto queue = datagram_packets_.find(s);
|
||||
if (queue != datagram_packets_.end())
|
||||
{
|
||||
const bool blocking = is_blocking_socket(s, UDP_BLOCKING);
|
||||
const auto blocking = is_blocking_socket(s, UDP_BLOCKING);
|
||||
|
||||
lock.unlock();
|
||||
while (blocking && queue->second.empty())
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1>No settings, yet!</h1>
|
||||
<h3>No settings, yet!</h3>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
@ -1,73 +1,70 @@
|
||||
#include <std_include.hpp>
|
||||
#include "memory.hpp"
|
||||
#include "compression.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace compression
|
||||
{
|
||||
std::string zlib::compress(const std::string& data)
|
||||
{
|
||||
memory::allocator allocator;
|
||||
unsigned long length = (data.size() * 2);
|
||||
if (!length) length = 2;
|
||||
|
||||
if (length < 100) length *= 10;
|
||||
|
||||
const auto buffer = allocator.allocate_array<char>(length);
|
||||
if (compress2(reinterpret_cast<Bytef*>(buffer), &length,
|
||||
reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(),
|
||||
Z_BEST_COMPRESSION) != Z_OK)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::string(buffer, length);
|
||||
}
|
||||
|
||||
std::string zlib::decompress(const std::string& data)
|
||||
{
|
||||
z_stream stream;
|
||||
ZeroMemory(&stream, sizeof(stream));
|
||||
std::string buffer;
|
||||
|
||||
if (inflateInit(&stream) != Z_OK)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int ret;
|
||||
memory::allocator allocator;
|
||||
|
||||
const auto dest = allocator.allocate_array<uint8_t>(CHUNK);
|
||||
auto data_ptr = data.data();
|
||||
|
||||
do
|
||||
{
|
||||
stream.avail_in = std::min(static_cast<size_t>(CHUNK), data.size() - (data_ptr - data.data()));
|
||||
stream.next_in = reinterpret_cast<const uint8_t*>(data_ptr);
|
||||
data_ptr += stream.avail_in;
|
||||
|
||||
do
|
||||
{
|
||||
stream.avail_out = CHUNK;
|
||||
stream.next_out = dest;
|
||||
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
return {};
|
||||
}
|
||||
|
||||
buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out);
|
||||
}
|
||||
while (stream.avail_out == 0);
|
||||
}
|
||||
while (ret != Z_STREAM_END);
|
||||
|
||||
inflateEnd(&stream);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include <std_include.hpp>
|
||||
#include "memory.hpp"
|
||||
#include "compression.hpp"
|
||||
|
||||
namespace utils::compression
|
||||
{
|
||||
std::string zlib::compress(const std::string& data)
|
||||
{
|
||||
memory::allocator allocator;
|
||||
unsigned long length = (data.size() * 2);
|
||||
if (!length) length = 2;
|
||||
|
||||
if (length < 100) length *= 10;
|
||||
|
||||
const auto buffer = allocator.allocate_array<char>(length);
|
||||
if (compress2(reinterpret_cast<Bytef*>(buffer), &length,
|
||||
reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(),
|
||||
Z_BEST_COMPRESSION) != Z_OK)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::string(buffer, length);
|
||||
}
|
||||
|
||||
std::string zlib::decompress(const std::string& data)
|
||||
{
|
||||
z_stream stream;
|
||||
ZeroMemory(&stream, sizeof(stream));
|
||||
std::string buffer;
|
||||
|
||||
if (inflateInit(&stream) != Z_OK)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int ret;
|
||||
memory::allocator allocator;
|
||||
|
||||
const auto dest = allocator.allocate_array<uint8_t>(CHUNK);
|
||||
auto data_ptr = data.data();
|
||||
|
||||
do
|
||||
{
|
||||
stream.avail_in = std::min(static_cast<size_t>(CHUNK), data.size() - (data_ptr - data.data()));
|
||||
stream.next_in = reinterpret_cast<const uint8_t*>(data_ptr);
|
||||
data_ptr += stream.avail_in;
|
||||
|
||||
do
|
||||
{
|
||||
stream.avail_out = CHUNK;
|
||||
stream.next_out = dest;
|
||||
|
||||
ret = inflate(&stream, Z_NO_FLUSH);
|
||||
if (ret != Z_OK && ret != Z_STREAM_END)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
return {};
|
||||
}
|
||||
|
||||
buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out);
|
||||
}
|
||||
while (stream.avail_out == 0);
|
||||
}
|
||||
while (ret != Z_STREAM_END);
|
||||
|
||||
inflateEnd(&stream);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#define CHUNK 16384
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace compression
|
||||
{
|
||||
class zlib final
|
||||
{
|
||||
public:
|
||||
static std::string compress(const std::string& data);
|
||||
static std::string decompress(const std::string& data);
|
||||
};
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#define CHUNK 16384
|
||||
|
||||
namespace utils::compression
|
||||
{
|
||||
class zlib final
|
||||
{
|
||||
public:
|
||||
static std::string compress(const std::string& data);
|
||||
static std::string decompress(const std::string& data);
|
||||
};
|
||||
};
|
||||
|
@ -4,323 +4,320 @@
|
||||
|
||||
/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf
|
||||
|
||||
namespace utils
|
||||
namespace utils::cryptography
|
||||
{
|
||||
namespace cryptography
|
||||
ecc::key::key()
|
||||
{
|
||||
ecc::key::key()
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
|
||||
ecc::key::~key()
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
|
||||
bool ecc::key::is_valid() const
|
||||
{
|
||||
return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_)));
|
||||
}
|
||||
|
||||
ecc_key* ecc::key::get()
|
||||
{
|
||||
return &this->key_storage_;
|
||||
}
|
||||
|
||||
std::string ecc::key::get_public_key() const
|
||||
{
|
||||
uint8_t buffer[512] = {0};
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK)
|
||||
{
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
|
||||
ecc::key::~key()
|
||||
{
|
||||
this->free();
|
||||
}
|
||||
|
||||
bool ecc::key::is_valid() const
|
||||
{
|
||||
return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_)));
|
||||
}
|
||||
|
||||
ecc_key* ecc::key::get()
|
||||
{
|
||||
return &this->key_storage_;
|
||||
}
|
||||
|
||||
std::string ecc::key::get_public_key() const
|
||||
{
|
||||
uint8_t buffer[512] = {0};
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK)
|
||||
{
|
||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ecc::key::set(const std::string& pub_key_buffer)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(pub_key_buffer.data()), pub_key_buffer.size(),
|
||||
&this->key_storage_) != CRYPT_OK)
|
||||
{
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
}
|
||||
|
||||
void ecc::key::deserialize(const std::string& key)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_import(reinterpret_cast<const uint8_t*>(key.data()), key.size(), &this->key_storage_) != CRYPT_OK)
|
||||
{
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
}
|
||||
|
||||
std::string ecc::key::serialize(const int type) const
|
||||
{
|
||||
uint8_t buffer[4096] = {0};
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK)
|
||||
{
|
||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void ecc::key::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
ecc_free(&this->key_storage_);
|
||||
}
|
||||
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
|
||||
bool ecc::key::operator==(key& key) const
|
||||
{
|
||||
return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC));
|
||||
}
|
||||
|
||||
ecc::key ecc::generate_key(const int bits)
|
||||
{
|
||||
key key;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_prng(&sprng_desc);
|
||||
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get());
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string ecc::sign_message(key key, const std::string& message)
|
||||
{
|
||||
if (!key.is_valid()) return "";
|
||||
|
||||
uint8_t buffer[512];
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_prng(&sprng_desc);
|
||||
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
|
||||
find_prng("sprng"), key.get());
|
||||
|
||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||
}
|
||||
|
||||
bool ecc::verify_message(key key, const std::string& message, const std::string& signature)
|
||||
return {};
|
||||
}
|
||||
|
||||
void ecc::key::set(const std::string& pub_key_buffer)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(pub_key_buffer.data()), pub_key_buffer.size(),
|
||||
&this->key_storage_) != CRYPT_OK)
|
||||
{
|
||||
if (!key.is_valid()) return false;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
|
||||
auto result = 0;
|
||||
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
|
||||
reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result,
|
||||
key.get()) == CRYPT_OK && result != 0);
|
||||
}
|
||||
|
||||
std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
const auto prng_id = find_prng("yarrow");
|
||||
|
||||
rsa_key new_key;
|
||||
rsa_import(PBYTE(key.data()), key.size(), &new_key);
|
||||
|
||||
prng_state yarrow;
|
||||
rng_make_prng(128, prng_id, &yarrow, nullptr);
|
||||
|
||||
unsigned char buffer[0x80];
|
||||
unsigned long length = sizeof(buffer);
|
||||
|
||||
const auto rsa_result = rsa_encrypt_key( //
|
||||
PBYTE(data.data()), //
|
||||
data.size(), //
|
||||
buffer, //
|
||||
&length, //
|
||||
PBYTE(hash.data()), //
|
||||
hash.size(), //
|
||||
&yarrow, //
|
||||
prng_id, //
|
||||
find_hash("sha1"), //
|
||||
&new_key);
|
||||
|
||||
rsa_free(&new_key);
|
||||
|
||||
if (rsa_result == CRYPT_OK)
|
||||
{
|
||||
return std::string(PCHAR(buffer), length);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void rsa::initialize()
|
||||
{
|
||||
static auto initialized = false;
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_hash(&sha1_desc);
|
||||
register_prng(&yarrow_desc);
|
||||
}
|
||||
|
||||
std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
std::string enc_data;
|
||||
enc_data.resize(data.size());
|
||||
|
||||
symmetric_CBC cbc;
|
||||
const auto des3 = find_cipher("3des");
|
||||
|
||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(enc_data.data())), data.size(), &cbc);
|
||||
cbc_done(&cbc);
|
||||
|
||||
return enc_data;
|
||||
}
|
||||
|
||||
std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
std::string dec_data;
|
||||
dec_data.resize(data.size());
|
||||
|
||||
symmetric_CBC cbc;
|
||||
const auto des3 = find_cipher("3des");
|
||||
|
||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(dec_data.data())), data.size(), &cbc);
|
||||
cbc_done(&cbc);
|
||||
|
||||
return dec_data;
|
||||
}
|
||||
|
||||
void des3::initialize()
|
||||
{
|
||||
static auto initialized = false;
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
register_cipher(&des3_desc);
|
||||
}
|
||||
|
||||
std::string tiger::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[24] = {0};
|
||||
|
||||
hash_state state;
|
||||
tiger_init(&state);
|
||||
tiger_process(&state, data, length);
|
||||
tiger_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha1::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[20] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha1_init(&state);
|
||||
sha1_process(&state, data, length);
|
||||
sha1_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha256::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[32] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha256_init(&state);
|
||||
sha256_process(&state, data, length);
|
||||
sha256_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha512::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha512_init(&state);
|
||||
sha512_process(&state, data, length);
|
||||
sha512_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
unsigned int jenkins_one_at_a_time::compute(const std::string& data)
|
||||
{
|
||||
return compute(data.data(), data.size());
|
||||
}
|
||||
|
||||
unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len)
|
||||
{
|
||||
unsigned int hash, i;
|
||||
for (hash = i = 0; i < len; ++i)
|
||||
{
|
||||
hash += key[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
}
|
||||
|
||||
void ecc::key::deserialize(const std::string& key)
|
||||
{
|
||||
this->free();
|
||||
|
||||
if (ecc_import(reinterpret_cast<const uint8_t*>(key.data()), key.size(), &this->key_storage_) != CRYPT_OK)
|
||||
{
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
}
|
||||
|
||||
std::string ecc::key::serialize(const int type) const
|
||||
{
|
||||
uint8_t buffer[4096] = {0};
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK)
|
||||
{
|
||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void ecc::key::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
ecc_free(&this->key_storage_);
|
||||
}
|
||||
|
||||
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
|
||||
}
|
||||
|
||||
bool ecc::key::operator==(key& key) const
|
||||
{
|
||||
return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC));
|
||||
}
|
||||
|
||||
ecc::key ecc::generate_key(const int bits)
|
||||
{
|
||||
key key;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_prng(&sprng_desc);
|
||||
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get());
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string ecc::sign_message(key key, const std::string& message)
|
||||
{
|
||||
if (!key.is_valid()) return "";
|
||||
|
||||
uint8_t buffer[512];
|
||||
DWORD length = sizeof(buffer);
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_prng(&sprng_desc);
|
||||
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
|
||||
find_prng("sprng"), key.get());
|
||||
|
||||
return std::string(reinterpret_cast<char*>(buffer), length);
|
||||
}
|
||||
|
||||
bool ecc::verify_message(key key, const std::string& message, const std::string& signature)
|
||||
{
|
||||
if (!key.is_valid()) return false;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
|
||||
auto result = 0;
|
||||
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
|
||||
reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result,
|
||||
key.get()) == CRYPT_OK && result != 0);
|
||||
}
|
||||
|
||||
std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
const auto prng_id = find_prng("yarrow");
|
||||
|
||||
rsa_key new_key;
|
||||
rsa_import(PBYTE(key.data()), key.size(), &new_key);
|
||||
|
||||
prng_state yarrow;
|
||||
rng_make_prng(128, prng_id, &yarrow, nullptr);
|
||||
|
||||
unsigned char buffer[0x80];
|
||||
unsigned long length = sizeof(buffer);
|
||||
|
||||
const auto rsa_result = rsa_encrypt_key( //
|
||||
PBYTE(data.data()), //
|
||||
data.size(), //
|
||||
buffer, //
|
||||
&length, //
|
||||
PBYTE(hash.data()), //
|
||||
hash.size(), //
|
||||
&yarrow, //
|
||||
prng_id, //
|
||||
find_hash("sha1"), //
|
||||
&new_key);
|
||||
|
||||
rsa_free(&new_key);
|
||||
|
||||
if (rsa_result == CRYPT_OK)
|
||||
{
|
||||
return std::string(PCHAR(buffer), length);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void rsa::initialize()
|
||||
{
|
||||
static auto initialized = false;
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
ltc_mp = ltm_desc;
|
||||
register_hash(&sha1_desc);
|
||||
register_prng(&yarrow_desc);
|
||||
}
|
||||
|
||||
std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
std::string enc_data;
|
||||
enc_data.resize(data.size());
|
||||
|
||||
symmetric_CBC cbc;
|
||||
const auto des3 = find_cipher("3des");
|
||||
|
||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(enc_data.data())), data.size(), &cbc);
|
||||
cbc_done(&cbc);
|
||||
|
||||
return enc_data;
|
||||
}
|
||||
|
||||
std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key)
|
||||
{
|
||||
initialize();
|
||||
|
||||
std::string dec_data;
|
||||
dec_data.resize(data.size());
|
||||
|
||||
symmetric_CBC cbc;
|
||||
const auto des3 = find_cipher("3des");
|
||||
|
||||
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
|
||||
key.size(), 0, &cbc);
|
||||
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(dec_data.data())), data.size(), &cbc);
|
||||
cbc_done(&cbc);
|
||||
|
||||
return dec_data;
|
||||
}
|
||||
|
||||
void des3::initialize()
|
||||
{
|
||||
static auto initialized = false;
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
register_cipher(&des3_desc);
|
||||
}
|
||||
|
||||
std::string tiger::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[24] = {0};
|
||||
|
||||
hash_state state;
|
||||
tiger_init(&state);
|
||||
tiger_process(&state, data, length);
|
||||
tiger_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha1::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[20] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha1_init(&state);
|
||||
sha1_process(&state, data, length);
|
||||
sha1_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha256::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[32] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha256_init(&state);
|
||||
sha256_process(&state, data, length);
|
||||
sha256_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string sha512::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[64] = {0};
|
||||
|
||||
hash_state state;
|
||||
sha512_init(&state);
|
||||
sha512_process(&state, data, length);
|
||||
sha512_done(&state, buffer);
|
||||
|
||||
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
unsigned int jenkins_one_at_a_time::compute(const std::string& data)
|
||||
{
|
||||
return compute(data.data(), data.size());
|
||||
}
|
||||
|
||||
unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len)
|
||||
{
|
||||
unsigned int hash, i;
|
||||
for (hash = i = 0; i < len; ++i)
|
||||
{
|
||||
hash += key[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
namespace utils::cryptography
|
||||
{
|
||||
namespace cryptography
|
||||
class ecc final
|
||||
{
|
||||
class ecc final
|
||||
public:
|
||||
class key final
|
||||
{
|
||||
public:
|
||||
class key final
|
||||
{
|
||||
public:
|
||||
key();
|
||||
~key();
|
||||
key();
|
||||
~key();
|
||||
|
||||
bool is_valid() const;
|
||||
bool is_valid() const;
|
||||
|
||||
ecc_key* get();
|
||||
ecc_key* get();
|
||||
|
||||
std::string get_public_key() const;
|
||||
std::string get_public_key() const;
|
||||
|
||||
void set(const std::string& pub_key_buffer);
|
||||
void set(const std::string& pub_key_buffer);
|
||||
|
||||
void deserialize(const std::string& key);
|
||||
void deserialize(const std::string& key);
|
||||
|
||||
std::string serialize(int type = PK_PRIVATE) const;
|
||||
std::string serialize(int type = PK_PRIVATE) const;
|
||||
|
||||
void free();
|
||||
void free();
|
||||
|
||||
bool operator==(key& key) const;
|
||||
|
||||
private:
|
||||
ecc_key key_storage_{};
|
||||
};
|
||||
|
||||
static key generate_key(int bits);
|
||||
static std::string sign_message(key key, const std::string& message);
|
||||
static bool verify_message(key key, const std::string& message, const std::string& signature);
|
||||
};
|
||||
|
||||
class rsa final
|
||||
{
|
||||
public:
|
||||
static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key);
|
||||
bool operator==(key& key) const;
|
||||
|
||||
private:
|
||||
static void initialize();
|
||||
ecc_key key_storage_{};
|
||||
};
|
||||
|
||||
class des3 final
|
||||
{
|
||||
public:
|
||||
static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key);
|
||||
static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key);
|
||||
static key generate_key(int bits);
|
||||
static std::string sign_message(key key, const std::string& message);
|
||||
static bool verify_message(key key, const std::string& message, const std::string& signature);
|
||||
};
|
||||
|
||||
private:
|
||||
static void initialize();
|
||||
};
|
||||
class rsa final
|
||||
{
|
||||
public:
|
||||
static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key);
|
||||
|
||||
class tiger final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
private:
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
class sha1 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
class des3 final
|
||||
{
|
||||
public:
|
||||
static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key);
|
||||
static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key);
|
||||
|
||||
class sha256 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
private:
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
class sha512 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
class tiger final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
|
||||
class jenkins_one_at_a_time final
|
||||
{
|
||||
public:
|
||||
static unsigned int compute(const std::string& data);
|
||||
static unsigned int compute(const char* key, size_t len);
|
||||
};
|
||||
}
|
||||
class sha1 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
|
||||
class sha256 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
|
||||
class sha512 final
|
||||
{
|
||||
public:
|
||||
static std::string compute(const std::string& data, bool hex = false);
|
||||
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
};
|
||||
|
||||
class jenkins_one_at_a_time final
|
||||
{
|
||||
public:
|
||||
static unsigned int compute(const std::string& data);
|
||||
static unsigned int compute(const char* key, size_t len);
|
||||
};
|
||||
}
|
||||
|
@ -2,51 +2,48 @@
|
||||
#include "flags.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils
|
||||
namespace utils::flags
|
||||
{
|
||||
namespace flags
|
||||
void parse_flags(std::vector<std::string>& flags)
|
||||
{
|
||||
void parse_flags(std::vector<std::string>& flags)
|
||||
int num_args;
|
||||
const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
||||
|
||||
flags.clear();
|
||||
|
||||
if (argv)
|
||||
{
|
||||
int num_args;
|
||||
const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
|
||||
|
||||
flags.clear();
|
||||
|
||||
if (argv)
|
||||
for (auto i = 0; i < num_args; ++i)
|
||||
{
|
||||
for (auto i = 0; i < num_args; ++i)
|
||||
std::wstring wide_flag(argv[i]);
|
||||
if (wide_flag[0] == L'-')
|
||||
{
|
||||
std::wstring wide_flag(argv[i]);
|
||||
if (wide_flag[0] == L'-')
|
||||
{
|
||||
flags.emplace_back(wide_flag.begin() + 1, wide_flag.end());
|
||||
}
|
||||
}
|
||||
|
||||
LocalFree(argv);
|
||||
}
|
||||
}
|
||||
|
||||
bool has_flag(const std::string& flag)
|
||||
{
|
||||
static auto parsed = false;
|
||||
static std::vector<std::string> enabled_flags;
|
||||
|
||||
if (!parsed)
|
||||
{
|
||||
parse_flags(enabled_flags);
|
||||
}
|
||||
|
||||
for (const auto& entry : enabled_flags)
|
||||
{
|
||||
if (string::to_lower(entry) == string::to_lower(flag))
|
||||
{
|
||||
return true;
|
||||
flags.emplace_back(wide_flag.begin() + 1, wide_flag.end());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
LocalFree(argv);
|
||||
}
|
||||
}
|
||||
|
||||
bool has_flag(const std::string& flag)
|
||||
{
|
||||
static auto parsed = false;
|
||||
static std::vector<std::string> enabled_flags;
|
||||
|
||||
if (!parsed)
|
||||
{
|
||||
parse_flags(enabled_flags);
|
||||
}
|
||||
|
||||
for (const auto& entry : enabled_flags)
|
||||
{
|
||||
if (string::to_lower(entry) == string::to_lower(flag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
namespace utils::flags
|
||||
{
|
||||
namespace flags
|
||||
{
|
||||
bool has_flag(const std::string& flag);
|
||||
}
|
||||
bool has_flag(const std::string& flag);
|
||||
}
|
||||
|
157
src/utils/io.cpp
157
src/utils/io.cpp
@ -1,110 +1,107 @@
|
||||
#include <std_include.hpp>
|
||||
#include "io.hpp"
|
||||
|
||||
namespace utils
|
||||
namespace utils::io
|
||||
{
|
||||
namespace io
|
||||
bool file_exists(const std::string& file)
|
||||
{
|
||||
bool file_exists(const std::string& file)
|
||||
return std::ifstream(file).good();
|
||||
}
|
||||
|
||||
bool write_file(const std::string& file, const std::string& data, const bool append)
|
||||
{
|
||||
const auto pos = file.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
return std::ifstream(file).good();
|
||||
create_directory(file.substr(0, pos));
|
||||
}
|
||||
|
||||
bool write_file(const std::string& file, const std::string& data, const bool append)
|
||||
std::ofstream stream(
|
||||
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out));
|
||||
|
||||
if (stream.is_open())
|
||||
{
|
||||
const auto pos = file.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
create_directory(file.substr(0, pos));
|
||||
}
|
||||
stream.write(data.data(), data.size());
|
||||
stream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ofstream stream(
|
||||
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream.is_open())
|
||||
std::string read_file(const std::string& file)
|
||||
{
|
||||
std::string data;
|
||||
read_file(file, &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool read_file(const std::string& file, std::string* data)
|
||||
{
|
||||
if (!data) return false;
|
||||
data->clear();
|
||||
|
||||
if (file_exists(file))
|
||||
{
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
if (!stream.is_open()) return false;
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const std::streamsize size = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
if (size > -1)
|
||||
{
|
||||
stream.write(data.data(), data.size());
|
||||
data->resize(static_cast<uint32_t>(size));
|
||||
stream.read(const_cast<char*>(data->data()), size);
|
||||
stream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string read_file(const std::string& file)
|
||||
{
|
||||
std::string data;
|
||||
read_file(file, &data);
|
||||
return data;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool read_file(const std::string& file, std::string* data)
|
||||
size_t file_size(const std::string& file)
|
||||
{
|
||||
if (file_exists(file))
|
||||
{
|
||||
if (!data) return false;
|
||||
data->clear();
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
|
||||
if (file_exists(file))
|
||||
if (stream.good())
|
||||
{
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
if (!stream.is_open()) return false;
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const std::streamsize size = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
if (size > -1)
|
||||
{
|
||||
data->resize(static_cast<uint32_t>(size));
|
||||
stream.read(const_cast<char*>(data->data()), size);
|
||||
stream.close();
|
||||
return true;
|
||||
}
|
||||
return static_cast<size_t>(stream.tellg());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t file_size(const std::string& file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool create_directory(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::create_directories(directory);
|
||||
}
|
||||
|
||||
bool directory_exists(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::is_directory(directory);
|
||||
}
|
||||
|
||||
bool directory_is_empty(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::is_empty(directory);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_files(const std::string& directory)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
|
||||
{
|
||||
if (file_exists(file))
|
||||
{
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
|
||||
if (stream.good())
|
||||
{
|
||||
stream.seekg(0, std::ios::end);
|
||||
return static_cast<size_t>(stream.tellg());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
bool create_directory(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::create_directories(directory);
|
||||
}
|
||||
|
||||
bool directory_exists(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::is_directory(directory);
|
||||
}
|
||||
|
||||
bool directory_is_empty(const std::string& directory)
|
||||
{
|
||||
return std::experimental::filesystem::is_empty(directory);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_files(const std::string& directory)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
|
||||
{
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace io
|
||||
{
|
||||
bool file_exists(const std::string& file);
|
||||
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||
bool read_file(const std::string& file, std::string* data);
|
||||
std::string read_file(const std::string& file);
|
||||
size_t file_size(const std::string& file);
|
||||
bool create_directory(const std::string& directory);
|
||||
bool directory_exists(const std::string& directory);
|
||||
bool directory_is_empty(const std::string& directory);
|
||||
std::vector<std::string> list_files(const std::string& directory);
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace utils::io
|
||||
{
|
||||
bool file_exists(const std::string& file);
|
||||
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||
bool read_file(const std::string& file, std::string* data);
|
||||
std::string read_file(const std::string& file);
|
||||
size_t file_size(const std::string& file);
|
||||
bool create_directory(const std::string& directory);
|
||||
bool directory_exists(const std::string& directory);
|
||||
bool directory_is_empty(const std::string& directory);
|
||||
std::vector<std::string> list_files(const std::string& directory);
|
||||
}
|
||||
|
387
src/utils/nt.cpp
387
src/utils/nt.cpp
@ -1,207 +1,204 @@
|
||||
#include <std_include.hpp>
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace utils
|
||||
namespace utils::nt
|
||||
{
|
||||
namespace nt
|
||||
module module::load(const std::string& name)
|
||||
{
|
||||
module module::load(const std::string& name)
|
||||
return module(LoadLibraryA(name.data()));
|
||||
}
|
||||
|
||||
module module::get_by_address(void* address)
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCSTR>(address), &handle);
|
||||
return module(handle);
|
||||
}
|
||||
|
||||
module::module()
|
||||
{
|
||||
this->module_ = GetModuleHandleA(nullptr);
|
||||
}
|
||||
|
||||
module::module(const std::string& name)
|
||||
{
|
||||
this->module_ = GetModuleHandleA(name.data());
|
||||
}
|
||||
|
||||
module::module(const HMODULE handle)
|
||||
{
|
||||
this->module_ = handle;
|
||||
}
|
||||
|
||||
bool module::operator==(const module& obj) const
|
||||
{
|
||||
return this->module_ == obj.module_;
|
||||
}
|
||||
|
||||
module::operator bool() const
|
||||
{
|
||||
return this->is_valid();
|
||||
}
|
||||
|
||||
module::operator HMODULE() const
|
||||
{
|
||||
return this->get_handle();
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS module::get_nt_headers() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
|
||||
}
|
||||
|
||||
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return &this->get_nt_headers()->OptionalHeader;
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> headers;
|
||||
|
||||
auto nt_headers = this->get_nt_headers();
|
||||
auto section = IMAGE_FIRST_SECTION(nt_headers);
|
||||
|
||||
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
return module(LoadLibraryA(name.data()));
|
||||
if (section) headers.push_back(section);
|
||||
else OutputDebugStringA("There was an invalid section :O");
|
||||
}
|
||||
|
||||
module module::get_by_address(void* address)
|
||||
return headers;
|
||||
}
|
||||
|
||||
std::uint8_t* module::get_ptr() const
|
||||
{
|
||||
return reinterpret_cast<std::uint8_t*>(this->module_);
|
||||
}
|
||||
|
||||
void module::unprotect() const
|
||||
{
|
||||
if (!this->is_valid()) return;
|
||||
|
||||
DWORD protection;
|
||||
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
|
||||
&protection);
|
||||
}
|
||||
|
||||
size_t module::get_relative_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return 0;
|
||||
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
|
||||
void* module::get_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return this->get_ptr() + this->get_relative_entry_point();
|
||||
}
|
||||
|
||||
bool module::is_valid() const
|
||||
{
|
||||
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
|
||||
}
|
||||
|
||||
std::string module::get_name() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
auto path = this->get_path();
|
||||
const auto pos = path.find_last_of("/\\");
|
||||
if (pos == std::string::npos) return path;
|
||||
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::string module::get_path() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
char name[MAX_PATH] = {0};
|
||||
GetModuleFileNameA(this->module_, name, sizeof name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void module::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCSTR>(address), &handle);
|
||||
return module(handle);
|
||||
}
|
||||
|
||||
module::module()
|
||||
{
|
||||
this->module_ = GetModuleHandleA(nullptr);
|
||||
}
|
||||
|
||||
module::module(const std::string& name)
|
||||
{
|
||||
this->module_ = GetModuleHandleA(name.data());
|
||||
}
|
||||
|
||||
module::module(const HMODULE handle)
|
||||
{
|
||||
this->module_ = handle;
|
||||
}
|
||||
|
||||
bool module::operator==(const module& obj) const
|
||||
{
|
||||
return this->module_ == obj.module_;
|
||||
}
|
||||
|
||||
module::operator bool() const
|
||||
{
|
||||
return this->is_valid();
|
||||
}
|
||||
|
||||
module::operator HMODULE() const
|
||||
{
|
||||
return this->get_handle();
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS module::get_nt_headers() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
|
||||
}
|
||||
|
||||
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return &this->get_nt_headers()->OptionalHeader;
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> headers;
|
||||
|
||||
auto nt_headers = this->get_nt_headers();
|
||||
auto section = IMAGE_FIRST_SECTION(nt_headers);
|
||||
|
||||
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
if (section) headers.push_back(section);
|
||||
else OutputDebugStringA("There was an invalid section :O");
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
std::uint8_t* module::get_ptr() const
|
||||
{
|
||||
return reinterpret_cast<std::uint8_t*>(this->module_);
|
||||
}
|
||||
|
||||
void module::unprotect() const
|
||||
{
|
||||
if (!this->is_valid()) return;
|
||||
|
||||
DWORD protection;
|
||||
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
|
||||
&protection);
|
||||
}
|
||||
|
||||
size_t module::get_relative_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return 0;
|
||||
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
|
||||
void* module::get_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return this->get_ptr() + this->get_relative_entry_point();
|
||||
}
|
||||
|
||||
bool module::is_valid() const
|
||||
{
|
||||
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
|
||||
}
|
||||
|
||||
std::string module::get_name() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
auto path = this->get_path();
|
||||
const auto pos = path.find_last_of("/\\");
|
||||
if (pos == std::string::npos) return path;
|
||||
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::string module::get_path() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
char name[MAX_PATH] = {0};
|
||||
GetModuleFileNameA(this->module_, name, sizeof name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void module::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
FreeLibrary(this->module_);
|
||||
this->module_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE module::get_handle() const
|
||||
{
|
||||
return this->module_;
|
||||
}
|
||||
|
||||
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
|
||||
const module other_module(module_name);
|
||||
if (!other_module.is_valid()) return nullptr;
|
||||
|
||||
const auto target_function = other_module.get_proc<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
|
||||
OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
|
||||
get_ptr());
|
||||
|
||||
while (original_thunk_data->u1.AddressOfData)
|
||||
{
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number > 0xFFFF) continue;
|
||||
|
||||
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
|
||||
++original_thunk_data;
|
||||
++thunk_data;
|
||||
}
|
||||
|
||||
//break;
|
||||
}
|
||||
|
||||
++import_descriptor;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void raise_hard_exception()
|
||||
{
|
||||
int data = false;
|
||||
const module ntdll("ntdll.dll");
|
||||
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
FreeLibrary(this->module_);
|
||||
this->module_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE module::get_handle() const
|
||||
{
|
||||
return this->module_;
|
||||
}
|
||||
|
||||
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
|
||||
const module other_module(module_name);
|
||||
if (!other_module.is_valid()) return nullptr;
|
||||
|
||||
const auto target_function = other_module.get_proc<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
|
||||
OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
|
||||
get_ptr());
|
||||
|
||||
while (original_thunk_data->u1.AddressOfData)
|
||||
{
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number > 0xFFFF) continue;
|
||||
|
||||
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
|
||||
++original_thunk_data;
|
||||
++thunk_data;
|
||||
}
|
||||
|
||||
//break;
|
||||
}
|
||||
|
||||
++import_descriptor;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void raise_hard_exception()
|
||||
{
|
||||
int data = false;
|
||||
const module ntdll("ntdll.dll");
|
||||
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
}
|
||||
}
|
||||
|
179
src/utils/nt.hpp
179
src/utils/nt.hpp
@ -1,91 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace nt
|
||||
{
|
||||
class module final
|
||||
{
|
||||
public:
|
||||
static module load(const std::string& name);
|
||||
static module get_by_address(void* address);
|
||||
|
||||
module();
|
||||
explicit module(const std::string& name);
|
||||
explicit module(HMODULE handle);
|
||||
|
||||
module(const module& a) : module_(a.module_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator!=(const module& obj) const { return !(*this == obj); };
|
||||
bool operator==(const module& obj) const;
|
||||
|
||||
operator bool() const;
|
||||
operator HMODULE() const;
|
||||
|
||||
void unprotect() const;
|
||||
void* get_entry_point() const;
|
||||
size_t get_relative_entry_point() const;
|
||||
|
||||
bool is_valid() const;
|
||||
std::string get_name() const;
|
||||
std::string get_path() const;
|
||||
std::uint8_t* get_ptr() const;
|
||||
void free();
|
||||
|
||||
HMODULE get_handle() const;
|
||||
|
||||
template <typename T>
|
||||
T get_proc(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) std::function<T>();
|
||||
return reinterpret_cast<T*>(this->get_proc<void*>(process));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__cdecl)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_pascal(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__stdcall)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
|
||||
|
||||
PIMAGE_NT_HEADERS get_nt_headers() const;
|
||||
PIMAGE_DOS_HEADER get_dos_header() const;
|
||||
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
|
||||
|
||||
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
};
|
||||
|
||||
void raise_hard_exception();
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace utils::nt
|
||||
{
|
||||
class module final
|
||||
{
|
||||
public:
|
||||
static module load(const std::string& name);
|
||||
static module get_by_address(void* address);
|
||||
|
||||
module();
|
||||
explicit module(const std::string& name);
|
||||
explicit module(HMODULE handle);
|
||||
|
||||
module(const module& a) : module_(a.module_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator!=(const module& obj) const { return !(*this == obj); };
|
||||
bool operator==(const module& obj) const;
|
||||
|
||||
operator bool() const;
|
||||
operator HMODULE() const;
|
||||
|
||||
void unprotect() const;
|
||||
void* get_entry_point() const;
|
||||
size_t get_relative_entry_point() const;
|
||||
|
||||
bool is_valid() const;
|
||||
std::string get_name() const;
|
||||
std::string get_path() const;
|
||||
std::uint8_t* get_ptr() const;
|
||||
void free();
|
||||
|
||||
HMODULE get_handle() const;
|
||||
|
||||
template <typename T>
|
||||
T get_proc(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) std::function<T>();
|
||||
return reinterpret_cast<T*>(this->get_proc<void*>(process));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__cdecl)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_pascal(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__stdcall)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
|
||||
|
||||
PIMAGE_NT_HEADERS get_nt_headers() const;
|
||||
PIMAGE_DOS_HEADER get_dos_header() const;
|
||||
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
|
||||
|
||||
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
};
|
||||
|
||||
void raise_hard_exception();
|
||||
}
|
||||
|
@ -1,58 +1,55 @@
|
||||
#include <std_include.hpp>
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace string
|
||||
{
|
||||
const char* va(const char* fmt, ...)
|
||||
{
|
||||
static thread_local va_provider<8, 256> provider;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
const char* result = provider.get(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_lower(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(tolower(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string to_upper(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(toupper(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for (unsigned int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
result.append(separator);
|
||||
}
|
||||
|
||||
result.append(va("%02X", data[i] & 0xFF));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#include <std_include.hpp>
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
const char* va(const char* fmt, ...)
|
||||
{
|
||||
static thread_local va_provider<8, 256> provider;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
const char* result = provider.get(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_lower(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(tolower(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string to_upper(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(toupper(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for (unsigned int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
result.append(separator);
|
||||
}
|
||||
|
||||
result.append(va("%02X", data[i] & 0xFF));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +1,81 @@
|
||||
#pragma once
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
namespace string
|
||||
{
|
||||
template <size_t Buffers, size_t MinBufferSize>
|
||||
class va_provider final
|
||||
{
|
||||
public:
|
||||
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||
|
||||
va_provider() : current_buffer_(0)
|
||||
{
|
||||
}
|
||||
|
||||
char* get(const char* format, const va_list ap)
|
||||
{
|
||||
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size || !entry->buffer)
|
||||
{
|
||||
throw std::runtime_error("String pool not initialized");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||
if (res > 0) break; // Success
|
||||
if (res == 0) return nullptr; // Error
|
||||
|
||||
entry->double_size();
|
||||
}
|
||||
|
||||
return entry->buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
class entry final
|
||||
{
|
||||
public:
|
||||
explicit entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||
{
|
||||
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
~entry()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->size = 0;
|
||||
this->buffer = nullptr;
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
||||
}
|
||||
|
||||
void double_size()
|
||||
{
|
||||
this->size *= 2;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
size_t size;
|
||||
char* buffer;
|
||||
};
|
||||
|
||||
size_t current_buffer_;
|
||||
entry string_pool_[Buffers];
|
||||
};
|
||||
|
||||
const char* va(const char* fmt, ...);
|
||||
|
||||
std::string to_lower(std::string text);
|
||||
std::string to_upper(std::string text);
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
template <size_t Buffers, size_t MinBufferSize>
|
||||
class va_provider final
|
||||
{
|
||||
public:
|
||||
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||
|
||||
va_provider() : current_buffer_(0)
|
||||
{
|
||||
}
|
||||
|
||||
char* get(const char* format, const va_list ap)
|
||||
{
|
||||
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size || !entry->buffer)
|
||||
{
|
||||
throw std::runtime_error("String pool not initialized");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||
if (res > 0) break; // Success
|
||||
if (res == 0) return nullptr; // Error
|
||||
|
||||
entry->double_size();
|
||||
}
|
||||
|
||||
return entry->buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
class entry final
|
||||
{
|
||||
public:
|
||||
explicit entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||
{
|
||||
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
~entry()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->size = 0;
|
||||
this->buffer = nullptr;
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
||||
}
|
||||
|
||||
void double_size()
|
||||
{
|
||||
this->size *= 2;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
size_t size;
|
||||
char* buffer;
|
||||
};
|
||||
|
||||
size_t current_buffer_;
|
||||
entry string_pool_[Buffers];
|
||||
};
|
||||
|
||||
const char* va(const char* fmt, ...);
|
||||
|
||||
std::string to_lower(std::string text);
|
||||
std::string to_upper(std::string text);
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user