diff --git a/CMakeLists.txt b/CMakeLists.txt index 28484a4..93c3774 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.6) project(TeaSpeak-Shared) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) if(NOT WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-reorder -Wno-sign-compare -fpermissive -ftemplate-depth=1000 ${MEMORY_DEBUG_FLAGS}") diff --git a/src/Error.h b/src/Error.h index b177307..f7e4efa 100644 --- a/src/Error.h +++ b/src/Error.h @@ -1,7 +1,7 @@ -#include - #pragma once +#include +#include #include #include #include @@ -13,6 +13,7 @@ #define _NDEBUG namespace ts { + struct CommandResult; namespace permission { enum PermissionType : uint16_t; } @@ -158,9 +159,10 @@ namespace ts { std::map extra_properties; }; + /* - * return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no deconstructor!) - * return command_result{permission::b_virtualserver_select_godmode}; => movabs rax,0xa08001700000001; ret; (Only if there is no deconstructor!) + * 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 { /* fixed size of 8 (64 bits) */ @@ -181,30 +183,32 @@ namespace ts { uint64_t data = 0; /* Test for mode 1 as described before */ - static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 63); + static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62); - inline error::type error_code() { + [[nodiscard]] inline error::type error_code() const { return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR); } - inline error::type permission_id() { - return (error::type) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION); + [[nodiscard]] inline permission::PermissionType permission_id() const { + return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION); } - inline detailed_command_result* details() { - return (detailed_command_result*) this->data; - } + [[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; } - inline bool is_detailed() { + [[nodiscard]] inline bool is_detailed() const { return (this->data & 0x1UL) == 0; } - inline detailed_command_result* release_details() { + inline std::unique_ptr release_details() { auto result = this->details(); this->data = 0; - return result; + return std::unique_ptr{result}; } + /* Attention: Releases the internal detailed pointer! */ + inline CommandResult as_command_result(); + #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; command_result(const command_result&) = delete; @@ -231,7 +235,7 @@ namespace ts { command_result(error::type error, const std::string& message) { auto details_ptr = new detailed_command_result{}; - assert(((uintptr_t) details_ptr & 0x01) == 0); // must be aligned! + assert(((uintptr_t) details_ptr & 0x03U) == 0); // must be aligned! this->data = (uintptr_t) details_ptr; @@ -239,7 +243,7 @@ namespace ts { details_ptr->extra_properties["extra_msg"] = message; } - command_result(error::type error, const std::map& properties) : command_result{error, ""} { + command_result(error::type error, const std::map& properties) : command_result{error, std::string{""}} { assert(this->is_detailed()); this->details()->extra_properties = properties; } @@ -311,6 +315,7 @@ namespace ts { 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; @@ -335,6 +340,22 @@ namespace ts { 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/src/query/command2.cpp b/src/query/command2.cpp index 3ea7c9f..c965c2f 100644 --- a/src/query/command2.cpp +++ b/src/query/command2.cpp @@ -46,7 +46,7 @@ command::command(const std::string& command, bool editable) { this->handle->command = command; } -std::string command::identifier() const { +const std::string& command::identifier() const { return this->handle->command; } diff --git a/src/query/command2.h b/src/query/command2.h index 5f7e3e6..22f96ca 100644 --- a/src/query/command2.h +++ b/src/query/command2.h @@ -59,22 +59,22 @@ namespace ts { static command parse(const std::string_view& /* command data */, bool /* expect type */ = true, bool /* drop non UTF-8 characters */ = false); explicit command(const std::string& /* command */ = "", bool /* editable */ = true); - std::string identifier() const; + [[nodiscard]] const std::string& identifier() const; void set_identifier(const std::string& /* command */); command_bulk bulk(size_t /* bulk index */); - const command_bulk bulk(size_t /* bulk index */) const; - size_t bulk_count() const; + [[nodiscard]] const command_bulk bulk(size_t /* bulk index */) const; + [[nodiscard]] size_t bulk_count() const; inline command_bulk operator[](size_t /* index */); inline const command_bulk operator[](size_t /* index */) const; command_entry value(const std::string& /* key */); - const command_entry value(const std::string& /* key */) const; - bool has_value(const std::string& /* key */) const; + [[nodiscard]] const command_entry value(const std::string& /* key */) const; + [[nodiscard]] bool has_value(const std::string& /* key */) const; command_entry operator[](const std::string& /* key */); const command_entry operator[](const std::string& /* key */) const; - bool has_trigger(const std::string& /* key */) const; + [[nodiscard]] bool has_trigger(const std::string& /* key */) const; void set_trigger(const std::string& /* key */, bool /* value */ = true); std::string build(format::value /* format */ = format::QUERY); @@ -86,9 +86,9 @@ namespace ts { class command_bulk { friend class command; public: - bool has(const std::string& /* key */) const; + [[nodiscard]] bool has(const std::string& /* key */) const; command_entry value(const std::string& /* key */); - command_entry const value(const std::string& /* key */) const; + [[nodiscard]] command_entry const value(const std::string& /* key */) const; inline command_entry operator[](const std::string& /* key */); @@ -120,7 +120,7 @@ namespace ts { return *this; } - const std::string string() const { + [[nodiscard]] const std::string string() const { if(this->is_empty()) return ""; if(!this->handle->casted || this->handle->value.type() == typeid(std::string)) //No cast needed @@ -130,9 +130,9 @@ namespace ts { return this->handle->to_string(this->handle->value); } - inline const std::string value() const { return (std::string) this->string(); } + [[nodiscard]] inline const std::string value() const { return (std::string) this->string(); } - inline operator std::string() const { + [[nodiscard]] inline operator std::string() const { return this->string(); } diff --git a/src/sql/mysql/MySQL.cpp b/src/sql/mysql/MySQL.cpp index fbb44bc..f3e8635 100644 --- a/src/sql/mysql/MySQL.cpp +++ b/src/sql/mysql/MySQL.cpp @@ -565,6 +565,7 @@ namespace sql::mysql { delete[] descriptors; } + ResultBind(size_t a, BindMemory* b, const ResultBindDescriptor** c) : field_count{a}, memory{b}, descriptors{c} {} ResultBind(const ResultBind&) = delete; ResultBind(ResultBind&&) = default; @@ -708,7 +709,7 @@ result MySQLManager::executeCommand(std::shared_ptr _ptr) { if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) return {ptr->sql_command, -1, "Failed to allocate bind memory!"}; - ResultBind bind_result_data{0, nullptr, nullptr}; + ResultBind bind_result_data{.field_count = 0, .memory = nullptr, .descriptors = nullptr}; auto connection = this->next_connection(); if(!connection) return {ptr->sql_command, -1, "Could not get a valid connection!"}; @@ -762,7 +763,7 @@ result MySQLManager::queryCommand(shared_ptr _ptr, const QueryCallb FreeGuard bind_parameter_memory{nullptr}; if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) return {ptr->sql_command, -1, "Failed to allocate bind memory!"}; - ResultBind bind_result_data{0, nullptr, nullptr}; + ResultBind bind_result_data{.field_count = 0, .memory = nullptr, .descriptors = nullptr}; auto connection = this->next_connection(); if(!connection) return {ptr->sql_command, -1, "Could not get a valid connection!"};