Some updates

This commit is contained in:
WolverinDEV 2020-04-28 18:27:46 +02:00
parent 56e4ca45a9
commit ee4c7540f0
3 changed files with 137 additions and 84 deletions

View File

@ -196,12 +196,4 @@ ErrorType ts::findError(std::string key){
for(auto elm : avariableErrors)
if(elm.name == key) return elm;
return ErrorType{1, key, "undefined"};
}
CommandResult CommandResult::Success = {avariableErrors[0], ""};
CommandResult CommandResult::NotImplemented = {avariableErrors[2], ""};
CommandResultPermissionError::CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg) : CommandResult(findError(0x0A08), "") {
this->extraProperties["failed_permid"] = std::to_string((int16_t) error);
this->_type = PERM_ERROR;
}

View File

@ -184,15 +184,22 @@ namespace ts {
std::map<std::string, std::string> extra_properties;
};
enum struct command_result_type {
detailed = 0b00,
error = 0b10,
bulked = 0b11
};
/*
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
* return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no destructor!)
* return command_result{error::vs_critical, "unknown error"}; => To a lot of code
*/
struct command_result_bulk;
struct command_result { /* fixed size of 8 (64 bits) */
static constexpr uint64_t MASK_ERROR = ~((uint64_t) 1 << (sizeof(error::type) * 8));
static constexpr uint64_t MASK_PERMISSION = ~((uint64_t) 1 << (sizeof(permission::PermissionType) * 8));
static constexpr uint64_t MASK_PTR = ~((uint64_t) 0b111U);
static constexpr uint8_t OFFSET_ERROR = (8 - sizeof(error::type)) * 8;
static constexpr uint8_t OFFSET_PERMISSION = (8 - sizeof(permission::PermissionType) - sizeof(error::type)) * 8;
@ -205,44 +212,108 @@ namespace ts {
* bits [64 - sizeof(error::type);64] => error type | Usually evaluates to [48;64]
* bits [64 - sizeof(error::type) - sizeof(permission::PermissionType);64 - sizeof(error::type)] => permission id | Usually evaluates to [32;48]
*/
uint64_t data = 0;
uint64_t data{0};
/* Test for mode 1 as described before */
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62);
static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 60);
[[nodiscard]] inline command_result_type type() const {
return (command_result_type) (this->data & 0b11U);
}
[[nodiscard]] inline bool has_error() const {
switch (this->type()) {
case command_result_type::bulked:
return false;
case command_result_type::error:
return this->error_code() != error::ok;
case command_result_type::detailed:
return this->details()->error_id != error::ok;
default:
assert(false);
return false;
}
}
/* only valid for command_result_type::error */
[[nodiscard]] inline error::type error_code() const {
if(this->is_detailed()) return this->details()->error_id;
assert(this->type() == command_result_type::error);
return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR);
}
/* only valid for command_result_type::error */
[[nodiscard]] inline bool is_permission_error() const {
assert(this->type() == command_result_type::error);
return this->error_code() == error::server_insufficeient_permissions;
}
/* only valid for command_result_type::error */
[[nodiscard]] inline permission::PermissionType permission_id() const {
if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */
assert(this->type() == command_result_type::error);
return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION);
}
[[nodiscard]] inline const detailed_command_result* details() const { return (detailed_command_result*) this->data; }
[[nodiscard]] inline detailed_command_result* details() { return (detailed_command_result*) this->data; }
[[nodiscard]] inline bool is_detailed() const {
return (this->data & 0x1UL) == 0;
/* only valid for command_result_type::detailed */
[[nodiscard]] inline const detailed_command_result* details() const {
assert(this->type() == command_result_type::detailed);
return (detailed_command_result*) (this->data & MASK_PTR);
}
inline std::unique_ptr<detailed_command_result> release_details() {
if(!this->is_detailed()) return nullptr;
/* only valid for command_result_type::detailed */
[[nodiscard]] inline detailed_command_result* details() {
assert(this->type() == command_result_type::detailed);
return (detailed_command_result*) (this->data & MASK_PTR);
}
#if 0 // Dont use release_details. Use release_data instead
[[nodiscard]] inline std::unique_ptr<detailed_command_result> release_details() {
auto type = this->type();
if(type != command_result_type::detailed) return nullptr;
auto result = this->details();
this->data = 0;
return std::unique_ptr<detailed_command_result>{result};
}
#endif
/* Attention: Releases the internal detailed pointer! */
inline CommandResult as_command_result();
/* only valid for command_result_type::bulked */
[[nodiscard]] inline const std::vector<command_result>* bulks() const {
assert(this->type() == command_result_type::bulked);
return (std::vector<command_result>*) (this->data & MASK_PTR);
}
/* only valid for command_result_type::bulked */
[[nodiscard]] inline std::vector<command_result>* bulks() {
assert(this->type() == command_result_type::bulked);
return (std::vector<command_result>*) (this->data & MASK_PTR);
}
#if 0 // Dont use release_bulks. Use release_data instead
[[nodiscard]] inline std::vector<command_result> release_bulks() {
auto type = this->type();
if(type != command_result_type::bulked) return {};
std::vector<command_result> result{};
auto bulks = reinterpret_cast<std::vector<command_result>*>(this->data);
result.swap(*bulks);
delete bulks;
this->data = 0;
return result;
}
#endif
inline void release_data() {
auto type = this->type();
if(type == command_result_type::bulked) {
auto bulks = this->bulks();
delete bulks;
} else if(type == command_result_type::detailed) {
auto details = this->details();
delete details;
}
this->data = 0;
}
#ifndef _NDEBUG /* We dont need to secure that because gcc deduct us to an uint64_t and the only advantage is the mem leak test which is deactivated anyways */
command_result(command_result&) = delete;
@ -255,7 +326,7 @@ namespace ts {
command_result() = default;
explicit command_result(permission::PermissionType permission) {
this->data = 0x01; /* the the type to 1 */
this->data = (uint64_t) command_result_type::error;
this->data |= (uint64_t) error::server_insufficeient_permissions << OFFSET_ERROR;
this->data |= (uint64_t) permission << OFFSET_PERMISSION;
@ -263,7 +334,7 @@ namespace ts {
explicit command_result(error::type error) {
this->data = 0x01; /* the the type to 1 */
this->data = (uint64_t) command_result_type::error;
this->data |= (uint64_t) error << (8 - sizeof(error::type)) * 8;
}
@ -273,16 +344,19 @@ namespace ts {
assert(((uintptr_t) details_ptr & 0x03U) == 0); // must be aligned!
this->data = (uintptr_t) details_ptr;
this->data |= (uint64_t) command_result_type::detailed;
details_ptr->error_id = error;
details_ptr->extra_properties["extra_msg"] = message;
}
command_result(error::type error, const std::map<std::string, std::string>& properties) : command_result{error, std::string{""}} {
assert(this->is_detailed());
assert(this->type() == command_result_type::detailed);
this->details()->extra_properties = properties;
}
explicit command_result(command_result_bulk&&);
#ifndef _NDEBUG
/* if we're not using any debug we dont have to use a deconstructor. A deconstructor prevent a direct uint64_t return as described above */
~command_result() {
@ -295,6 +369,50 @@ namespace ts {
};
static_assert(sizeof(command_result) == 8);
struct command_result_bulk {
friend struct command_result;
public:
command_result_bulk() = default;
command_result_bulk(command_result&& result) { this->results.push_back(std::forward<command_result>(result)); }
~command_result_bulk() {
for(auto& result : this->results)
result.release_data();
}
inline void reserve(size_t length) {
this->results.reserve(length);
}
inline void emplace_result(permission::PermissionType permission) {
this->results.emplace_back(permission);
}
inline void emplace_result(error::type error) {
this->results.emplace_back(error);
}
inline void emplace_result(error::type error, const std::string& message) {
this->results.emplace_back(error, message);
}
[[nodiscard]] inline auto begin() { return this->results.begin(); }
[[nodiscard]] inline auto end() { return this->results.end(); }
[[nodiscard]] inline auto cbegin() const { return this->results.cbegin(); }
[[nodiscard]] inline auto cend() const { return this->results.cend(); }
private:
std::vector<command_result> results{};
};
inline command_result::command_result(ts::command_result_bulk &&bulk) {
auto bulks = new std::vector<command_result>{};
assert(((uintptr_t) bulks & 0x03U) == 0); // must be aligned!
this->data = (uintptr_t) bulks;
this->data |= (uint64_t) command_result_type::bulked;
bulks->swap(bulk.results);
}
struct ErrorType {
public:
static ErrorType Success;
@ -334,63 +452,6 @@ namespace ts {
extern const std::vector<ErrorType> avariableErrors;
extern ErrorType findError(uint16_t errorId);
extern ErrorType findError(std::string key);
enum CommandResultType {
GENERAL,
PERM_ERROR
};
struct CommandResult {
public:
static CommandResult Success;
static CommandResult NotImplemented;
CommandResult(const CommandResult& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
CommandResult(CommandResult&& ref) : _type(ref._type), error(ref.error), extraProperties(ref.extraProperties) {}
CommandResult(ErrorType error, const std::string &extraMsg = "") : error(std::move(error)) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
CommandResult(std::string error, const std::string &extraMsg = "") : error(findError(std::move(error))) { if(extraMsg.empty()) return; /*extraProperties["extramsg"] = extraMsg; */extraProperties["extra_msg"] = extraMsg; }
CommandResult() : CommandResult(ErrorType::Success, ""){}
CommandResult(ErrorType error, std::map<std::string, std::string> details) : error(error), extraProperties(std::move(details)) {}
bool operator==(const CommandResult& ref){
return this->error == ref.error && ref.extraProperties == this->extraProperties;
}
CommandResult& operator=(const CommandResult& ref)= default;
/**
* @return true if fail
*/
bool operator!() const {
return this->error != ErrorType::Success;
}
virtual CommandResultType type(){ return _type; }
ErrorType error;
std::map<std::string, std::string> extraProperties;
CommandResultType _type = CommandResultType::GENERAL;
};
struct CommandResultPermissionError : public CommandResult {
public:
CommandResultPermissionError(permission::PermissionType error, const std::string &extraMsg = "");
};
CommandResult command_result::as_command_result() {
if(this->is_detailed()) {
const auto details = this->details();
auto result = CommandResult{findError(details->error_id), details->extra_properties};
this->release_details();
return result;
} else {
const auto code = this->error_code();
auto error = findError(this->error_code());
if(code == error::server_insufficeient_permissions)
return CommandResultPermissionError{(permission::PermissionType) this->permission_id()};
else
return CommandResult{error};
}
}
}
#undef _NDEBUG

View File

@ -61,7 +61,7 @@ command_result test3() {
void eval_test(command_result x) {
if(x.is_detailed()) {
cout << "Detailed!" << endl;
x.release_details();
x.release_data();
} else {
auto a = x.permission_id();
auto b = x.error_code();