From ee4c7540f011d17cdac9c170e02c60296ae2487a Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Tue, 28 Apr 2020 18:27:46 +0200 Subject: [PATCH] Some updates --- src/Error.cpp | 8 -- src/Error.h | 211 ++++++++++++++++++++++++++++--------------- test/CommandTest.cpp | 2 +- 3 files changed, 137 insertions(+), 84 deletions(-) diff --git a/src/Error.cpp b/src/Error.cpp index 9ee8ed4..b78947f 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -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; } \ No newline at end of file diff --git a/src/Error.h b/src/Error.h index c83bedf..d33fbbb 100644 --- a/src/Error.h +++ b/src/Error.h @@ -184,15 +184,22 @@ namespace ts { std::map 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 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 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{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* bulks() const { + assert(this->type() == command_result_type::bulked); + return (std::vector*) (this->data & MASK_PTR); + } + + /* only valid for command_result_type::bulked */ + [[nodiscard]] inline std::vector* bulks() { + assert(this->type() == command_result_type::bulked); + return (std::vector*) (this->data & MASK_PTR); + } + +#if 0 // Dont use release_bulks. Use release_data instead + [[nodiscard]] inline std::vector release_bulks() { + auto type = this->type(); + if(type != command_result_type::bulked) return {}; + + std::vector result{}; + auto bulks = reinterpret_cast*>(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& 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(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 results{}; + }; + + inline command_result::command_result(ts::command_result_bulk &&bulk) { + auto bulks = new std::vector{}; + 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 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 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 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 \ No newline at end of file diff --git a/test/CommandTest.cpp b/test/CommandTest.cpp index f425b87..1a98a7e 100644 --- a/test/CommandTest.cpp +++ b/test/CommandTest.cpp @@ -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();