Some updates
This commit is contained in:
parent
56e4ca45a9
commit
ee4c7540f0
@ -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;
|
||||
}
|
211
src/Error.h
211
src/Error.h
@ -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
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user