diff --git a/lib/external/libwolv b/lib/external/libwolv index c24015b8f..3b7a928b7 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit c24015b8f5b5e99bab18978a9d10f2e8c859f9b2 +Subproject commit 3b7a928b7e53e98c5ef7372f1429032f6d622c10 diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 0c3dcfdc3..25922e11b 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 0c3dcfdc3c81002f209df4efa9c0425a376c55f9 +Subproject commit 25922e11b9cc6bbde1a321f5bd6ab2e622b07531 diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index c6485d1bd..d622c2ed5 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -23,7 +23,6 @@ set(LIBIMHEX_SOURCES source/helpers/fs.cpp source/helpers/magic.cpp source/helpers/crypto.cpp - source/helpers/net.cpp source/helpers/http_requests.cpp source/helpers/opengl.cpp source/helpers/patches.cpp diff --git a/lib/libimhex/include/hex/helpers/http_requests.hpp b/lib/libimhex/include/hex/helpers/http_requests.hpp index d4a097574..2eaa55242 100644 --- a/lib/libimhex/include/hex/helpers/http_requests.hpp +++ b/lib/libimhex/include/hex/helpers/http_requests.hpp @@ -9,6 +9,7 @@ #include +#include #include #include @@ -25,7 +26,8 @@ namespace hex { class ResultBase { public: - explicit ResultBase(u32 statusCode) : m_statusCode(statusCode) { } + ResultBase() = default; + explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { } [[nodiscard]] u32 getStatusCode() const { return this->m_statusCode; @@ -35,13 +37,19 @@ namespace hex { return this->getStatusCode() == 200; } + [[nodiscard]] bool isValid() const { + return this->m_valid; + } + private: - u32 m_statusCode; + u32 m_statusCode = 0; + bool m_valid = false; }; template class Result : public ResultBase { public: + Result() = default; Result(u32 statusCode, T data) : ResultBase(statusCode), m_data(std::move(data)) { } [[nodiscard]] @@ -102,6 +110,18 @@ namespace hex { HttpRequest::s_caCertData = std::move(data); } + static void setProxy(std::string proxy) { + HttpRequest::s_proxyUrl = std::move(proxy); + } + + void setMethod(std::string method) { + this->m_method = std::move(method); + } + + void setUrl(std::string url) { + this->m_url = std::move(url); + } + void addHeader(std::string key, std::string value) { this->m_headers[std::move(key)] = std::move(value); } @@ -110,24 +130,28 @@ namespace hex { this->m_body = std::move(body); } + void setTimeout(u32 timeout) { + this->m_timeout = timeout; + } + + float getProgress() const { + return this->m_progress; + } + + void cancel() { + this->m_canceled = true; + } + template std::future> downloadFile(const std::fs::path &path) { return std::async(std::launch::async, [this, path] { - T response; + std::vector response; wolv::io::File file(path, wolv::io::File::Mode::Create); - curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userdata){ - auto &file = *reinterpret_cast(userdata); - - file.write(reinterpret_cast(contents), size * nmemb); - - return size * nmemb; - }); + curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile); curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file); - this->executeImpl(response); - - return Result(200, std::move(response)); + return this->executeImpl(response); }); } @@ -135,13 +159,7 @@ namespace hex { return std::async(std::launch::async, [this] { std::vector response; - curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userdata){ - auto &response = *reinterpret_cast*>(userdata); - - response.insert(response.end(), reinterpret_cast(contents), reinterpret_cast(contents) + size * nmemb); - - return size * nmemb; - }); + curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector); curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &response); return this->executeImpl>(response); @@ -183,8 +201,8 @@ namespace hex { curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime); - T responseData; - curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer); + std::vector responseData; + curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector); curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData); return this->executeImpl(responseData); @@ -202,8 +220,8 @@ namespace hex { curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime); - T responseData; - curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer); + std::vector responseData; + curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector); curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData); return this->executeImpl(responseData); @@ -213,20 +231,46 @@ namespace hex { template std::future> execute() { return std::async(std::launch::async, [this] { - T data; - curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer); - curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &data); + std::vector responseData; + curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector); + curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData); - return this->executeImpl(data); + return this->executeImpl(responseData); }); } + std::string urlEncode(const std::string &input) { + auto escapedString = curl_easy_escape(this->m_curl, input.c_str(), std::strlen(input.c_str())); + + if (escapedString != nullptr) { + std::string output = escapedString; + curl_free(escapedString); + + return output; + } + + return {}; + } + + std::string urlDecode(const std::string &input) { + auto unescapedString = curl_easy_unescape(this->m_curl, input.c_str(), std::strlen(input.c_str()), nullptr); + + if (unescapedString != nullptr) { + std::string output = unescapedString; + curl_free(unescapedString); + + return output; + } + + return {}; + } + protected: void setDefaultConfig(); template - Result executeImpl(T &data) { + Result executeImpl(std::vector &data) { curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str()); curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str()); @@ -245,52 +289,49 @@ namespace hex { } curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers); - auto result = curl_easy_perform(this->m_curl); - printf("Curl result: %s\n", curl_easy_strerror(result)); + { + std::scoped_lock lock(this->m_transmissionMutex); + + auto result = curl_easy_perform(this->m_curl); + if (result != CURLE_OK){ + char *url = nullptr; + curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url); + log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result)); + if (!HttpRequest::s_proxyUrl.empty()){ + log::info("A custom proxy '{0}' is in use. Is it working correctly?", HttpRequest::s_proxyUrl); + } + + return { }; + } + } u32 statusCode = 0; curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode); - return Result(statusCode, std::move(data)); + return Result(statusCode, { data.begin(), data.end() }); } - [[maybe_unused]] - static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) { - hex::unused(ctx, userData); - - auto *cfg = static_cast(sslctx); - - auto crt = static_cast(userData); - mbedtls_x509_crt_init(crt); - - mbedtls_x509_crt_parse(crt, reinterpret_cast(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size()); - - mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr); - - return CURLE_OK; - } - - template - static size_t writeToContainer(void *contents, size_t size, size_t nmemb, void *userdata) { - auto &response = *reinterpret_cast(userdata); - auto startSize = response.size(); - - response.resize(startSize + size * nmemb); - std::memcpy(response.data() + startSize, contents, size * nmemb); - - return size * nmemb; - } + [[maybe_unused]] static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData); + static size_t writeToVector(void *contents, size_t size, size_t nmemb, void *userdata); + static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata); + static int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow); private: CURL *m_curl; + std::mutex m_transmissionMutex; + std::string m_method; std::string m_url; std::string m_body; std::map m_headers; + u32 m_timeout = 1000; + + float m_progress = 0.0F; + bool m_canceled = false; [[maybe_unused]] std::unique_ptr m_caCert; - static std::string s_caCertData; + static std::string s_caCertData, s_proxyUrl; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/net.hpp b/lib/libimhex/include/hex/helpers/net.hpp deleted file mode 100644 index 4bda03a73..000000000 --- a/lib/libimhex/include/hex/helpers/net.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -namespace hex { - - template - struct Response { - i32 code; - T body; - }; - - template<> - struct Response { - i32 code; - }; - - class Net { - public: - Net(); - ~Net(); - - constexpr static u32 DefaultTimeout = 2'000; - - std::future> getString(const std::string &url, u32 timeout = DefaultTimeout, const std::map &extraHeaders = {}, const std::string &body = {}); - std::future> getJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map &extraHeaders = {}, const std::string &body = {}); - - std::future> postJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map &extraHeaders = {}, const std::string &body = {}); - - std::future> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout); - std::future> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout); - - [[nodiscard]] std::string encode(const std::string &input); - [[nodiscard]] std::string decode(const std::string &input); - - [[nodiscard]] float getProgress() const { return this->m_progress; } - - void cancel() { this->m_shouldCancel = true; } - - static void setProxy(const std::string &url); - static void setCACert(const std::string &content); - - private: - void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map &extraHeaders = {}, const std::string &body = {}); - std::optional execute(); - - friend int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow); - friend CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData); - - private: - CURL *m_ctx; - mbedtls_x509_crt m_caCert; - curl_slist *m_headers = nullptr; - - std::mutex m_transmissionActive; - float m_progress = 0.0F; - bool m_shouldCancel = false; - - static std::string s_proxyUrl; - static std::string s_caCert; - }; - -} \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/tar.hpp b/lib/libimhex/include/hex/helpers/tar.hpp index 22a5bf578..888000bfb 100644 --- a/lib/libimhex/include/hex/helpers/tar.hpp +++ b/lib/libimhex/include/hex/helpers/tar.hpp @@ -26,11 +26,11 @@ namespace hex { void close(); - [[nodiscard]] std::vector read(const std::fs::path &path); + [[nodiscard]] std::vector readVector(const std::fs::path &path); [[nodiscard]] std::string readString(const std::fs::path &path); - void write(const std::fs::path &path, const std::vector &data); - void write(const std::fs::path &path, const std::string &data); + void writeVector(const std::fs::path &path, const std::vector &data); + void writeString(const std::fs::path &path, const std::string &data); [[nodiscard]] std::vector listEntries(const std::fs::path &basePath = "/"); [[nodiscard]] bool contains(const std::fs::path &path); diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index ec145a8ca..09de0fefa 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -7,7 +7,6 @@ #include #include -#include #include @@ -69,7 +68,7 @@ namespace hex { wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create); if (file.isValid()) { - file.write(getSettingsData().dump(4)); + file.writeString(getSettingsData().dump(4)); break; } } diff --git a/lib/libimhex/source/api/project_file_manager.cpp b/lib/libimhex/source/api/project_file_manager.cpp index 145b5fd8c..6acb338a1 100644 --- a/lib/libimhex/source/api/project_file_manager.cpp +++ b/lib/libimhex/source/api/project_file_manager.cpp @@ -40,7 +40,7 @@ namespace hex { return false; { - const auto metadataContent = tar.read(MetadataPath); + const auto metadataContent = tar.readVector(MetadataPath); if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic)) return false; @@ -131,7 +131,7 @@ namespace hex { { const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION); - tar.write(MetadataPath, metadataContent); + tar.writeString(MetadataPath, metadataContent); } ImHexApi::Provider::resetDirty(); diff --git a/lib/libimhex/source/helpers/http_requests.cpp b/lib/libimhex/source/helpers/http_requests.cpp index d92bb777a..21c01e1a8 100644 --- a/lib/libimhex/source/helpers/http_requests.cpp +++ b/lib/libimhex/source/helpers/http_requests.cpp @@ -3,6 +3,7 @@ namespace hex { std::string HttpRequest::s_caCertData; + std::string HttpRequest::s_proxyUrl; void HttpRequest::setDefaultConfig() { curl_easy_setopt(this->m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); @@ -13,8 +14,11 @@ namespace hex { curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYHOST, 2L); curl_easy_setopt(this->m_curl, CURLOPT_TIMEOUT_MS, 0L); - curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, 10000); + curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, this->m_timeout); curl_easy_setopt(this->m_curl, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this); + curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback); + curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str()); #if defined(IMHEX_USE_BUNDLED_CA) curl_easy_setopt(this->m_curl, CURLOPT_CAINFO, nullptr); @@ -27,4 +31,50 @@ namespace hex { #endif } + CURLcode HttpRequest::sslCtxFunction(CURL *ctx, void *sslctx, void *userData) { + hex::unused(ctx, userData); + + auto *cfg = static_cast(sslctx); + + auto crt = static_cast(userData); + mbedtls_x509_crt_init(crt); + + mbedtls_x509_crt_parse(crt, reinterpret_cast(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size()); + + mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr); + + return CURLE_OK; + } + + size_t HttpRequest::writeToVector(void *contents, size_t size, size_t nmemb, void *userdata) { + auto &response = *reinterpret_cast*>(userdata); + auto startSize = response.size(); + + response.resize(startSize + size * nmemb); + std::memcpy(response.data() + startSize, contents, size * nmemb); + + return size * nmemb; + } + + size_t HttpRequest::writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) { + auto &file = *reinterpret_cast(userdata); + + file.writeBuffer(reinterpret_cast(contents), size * nmemb); + + return size * nmemb; + } + + int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) { + auto &request = *static_cast(contents); + + if (dlTotal > 0) + request.m_progress = float(dlNow) / dlTotal; + else if (ulTotal > 0) + request.m_progress = float(ulNow) / ulTotal; + else + request.m_progress = 0.0F; + + return request.m_canceled ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK; + } + } \ No newline at end of file diff --git a/lib/libimhex/source/helpers/net.cpp b/lib/libimhex/source/helpers/net.cpp deleted file mode 100644 index 35d1ee6f0..000000000 --- a/lib/libimhex/source/helpers/net.cpp +++ /dev/null @@ -1,306 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include - -#include - -#include -#include - -namespace hex { - - Net::Net() { - AT_FIRST_TIME { - curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr); - curl_global_init(CURL_GLOBAL_ALL); - }; - - AT_FINAL_CLEANUP { - curl_global_cleanup(); - }; - - this->m_ctx = curl_easy_init(); - } - - Net::~Net() { - curl_easy_cleanup(this->m_ctx); - } - - static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userdata) { - static_cast(userdata)->append((char *)contents, size * nmemb); - return size * nmemb; - } - - static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) { - FILE *file = static_cast(userdata); - - return fwrite(contents, size, nmemb, file); - } - - [[maybe_unused]] - CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) { - hex::unused(ctx, userData); - - auto *cfg = static_cast(sslctx); - - auto crt = static_cast(userData); - mbedtls_x509_crt_init(crt); - - mbedtls_x509_crt_parse(crt, reinterpret_cast(Net::s_caCert.data()), Net::s_caCert.size()); - - mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr); - - return CURLE_OK; - } - - int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) { - auto &net = *static_cast(contents); - - if (dlTotal > 0) - net.m_progress = float(dlNow) / dlTotal; - else if (ulTotal > 0) - net.m_progress = float(ulNow) / ulTotal; - else - net.m_progress = 0.0F; - - return net.m_shouldCancel ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK; - } - - void Net::setCommonSettings(std::string &response, const std::string &url, u32 timeout, const std::map &extraHeaders, const std::string &body) { - this->m_headers = curl_slist_append(this->m_headers, "Cache-Control: no-cache"); - - if (!extraHeaders.empty()) - for (const auto &[key, value] : extraHeaders) { - std::string entry = key; - entry += ": "; - entry += value; - - this->m_headers = curl_slist_append(this->m_headers, entry.c_str()); - } - - if (!body.empty()) - curl_easy_setopt(this->m_ctx, CURLOPT_POSTFIELDS, body.c_str()); - - curl_easy_setopt(this->m_ctx, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); - curl_easy_setopt(this->m_ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); - curl_easy_setopt(this->m_ctx, CURLOPT_URL, url.c_str()); - curl_easy_setopt(this->m_ctx, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(this->m_ctx, CURLOPT_HTTPHEADER, this->m_headers); - curl_easy_setopt(this->m_ctx, CURLOPT_USERAGENT, "ImHex/1.0"); - curl_easy_setopt(this->m_ctx, CURLOPT_DEFAULT_PROTOCOL, "https"); - curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToString); - curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYHOST, 2L); - curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, &response); - curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L); - curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, timeout); - curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFODATA, this); - curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFOFUNCTION, progressCallback); - curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L); - -#if defined(IMHEX_USE_BUNDLED_CA) - curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr); - curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr); - curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction); - curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert); -#endif - - curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str()); - } - - std::optional Net::execute() { - CURLcode result = curl_easy_perform(this->m_ctx); - if (result != CURLE_OK){ - char *url = nullptr; - curl_easy_getinfo(this->m_ctx, CURLINFO_EFFECTIVE_URL, &url); - log::error("Net request '{0}' failed with error {1}: '{2}'", url, u32(result), curl_easy_strerror(result)); - if(!Net::s_proxyUrl.empty()){ - log::info("A custom proxy '{}' is in use. Is it working correctly?", Net::s_proxyUrl); - } - } - - long responseCode = 0; - curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode); - - curl_slist_free_all(this->m_headers); - this->m_headers = nullptr; - this->m_progress = 0.0F; - this->m_shouldCancel = false; - - if (result != CURLE_OK) - return std::nullopt; - else - return i32(responseCode); - } - - std::future> Net::getString(const std::string &url, u32 timeout, const std::map &extraHeaders, const std::string &body) { - this->m_transmissionActive.lock(); - - return std::async(std::launch::async, [=, this] { - std::string response; - - ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); - setCommonSettings(response, url, timeout, extraHeaders, body); - - auto responseCode = execute(); - - return Response { responseCode.value_or(0), response }; - }); - } - - std::future> Net::getJson(const std::string &url, u32 timeout, const std::map &extraHeaders, const std::string &body) { - this->m_transmissionActive.lock(); - - return std::async(std::launch::async, [=, this] { - std::string response; - - ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); - setCommonSettings(response, url, timeout, extraHeaders, body); - - auto responseCode = execute(); - if (!responseCode.has_value()) - return Response { 0, { } }; - else - return Response { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) }; - }); - } - - std::future> Net::postJson(const std::string &url, u32 timeout, const std::map &extraHeaders, const std::string &body) { - this->m_transmissionActive.lock(); - - return std::async(std::launch::async, [=, this] { - std::string response; - - ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST"); - setCommonSettings(response, url, timeout, extraHeaders, body); - - auto responseCode = execute(); - if (!responseCode.has_value()) - return Response { 0, { } }; - else - return Response { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) }; - }); - } - - std::future> Net::uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) { - this->m_transmissionActive.lock(); - - return std::async(std::launch::async, [=, this] { - std::string response; - - ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - - wolv::io::File file(filePath, wolv::io::File::Mode::Read); - if (!file.isValid()) - return Response { 400, {} }; - - curl_mime *mime = curl_mime_init(this->m_ctx); - curl_mimepart *part = curl_mime_addpart(mime); - - auto fileName = wolv::util::toUTF8String(filePath.filename()); - curl_mime_data_cb(part, file.getSize(), - [](char *buffer, size_t size, size_t nitems, void *arg) -> size_t { - auto file = static_cast(arg); - - return fread(buffer, size, nitems, file); - }, - [](void *arg, curl_off_t offset, int origin) -> int { - auto file = static_cast(arg); - - if (fseek(file, offset, origin) != 0) - return CURL_SEEKFUNC_CANTSEEK; - else - return CURL_SEEKFUNC_OK; - }, - [](void *arg) { - auto file = static_cast(arg); - - fclose(file); - }, - file.getHandle()); - curl_mime_filename(part, fileName.c_str()); - curl_mime_name(part, "file"); - - setCommonSettings(response, url, timeout); - curl_easy_setopt(this->m_ctx, CURLOPT_MIMEPOST, mime); - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST"); - - auto responseCode = execute(); - - return Response { responseCode.value_or(0), response }; - }); - } - - std::future> Net::downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) { - this->m_transmissionActive.lock(); - - return std::async(std::launch::async, [=, this] { - std::string response; - - ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - - wolv::io::File file(filePath, wolv::io::File::Mode::Create); - if (!file.isValid()) - return Response { 400 }; - - setCommonSettings(response, url, timeout); - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); - curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToFile); - curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, file.getHandle()); - auto responseCode = execute(); - - return Response { responseCode.value_or(0) }; - }); - } - - std::string Net::encode(const std::string &input) { - auto escapedString = curl_easy_escape(this->m_ctx, input.c_str(), std::strlen(input.c_str())); - - if (escapedString != nullptr) { - std::string output = escapedString; - curl_free(escapedString); - - return output; - } - - return {}; - } - - std::string Net::decode(const std::string &input) { - auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr); - - if (unescapedString != nullptr) { - std::string output = unescapedString; - curl_free(unescapedString); - - return output; - } - - return {}; - } - - std::string Net::s_proxyUrl; - void Net::setProxy(const std::string &url) { - Net::s_proxyUrl = url; - } - - std::string Net::s_caCert; - void Net::setCACert(const std::string &content) { - Net::s_caCert = content; - } - -} diff --git a/lib/libimhex/source/helpers/tar.cpp b/lib/libimhex/source/helpers/tar.cpp index 05255a7e0..58776929f 100644 --- a/lib/libimhex/source/helpers/tar.cpp +++ b/lib/libimhex/source/helpers/tar.cpp @@ -84,7 +84,7 @@ namespace hex { this->m_valid = false; } - std::vector Tar::read(const std::fs::path &path) { + std::vector Tar::readVector(const std::fs::path &path) { mtar_header_t header; auto fixedPath = path.string(); @@ -100,11 +100,11 @@ namespace hex { } std::string Tar::readString(const std::fs::path &path) { - auto result = this->read(path); + auto result = this->readVector(path); return { result.begin(), result.end() }; } - void Tar::write(const std::fs::path &path, const std::vector &data) { + void Tar::writeVector(const std::fs::path &path, const std::vector &data) { if (path.has_parent_path()) { std::fs::path pathPart; for (const auto &part : path.parent_path()) { @@ -126,8 +126,8 @@ namespace hex { mtar_write_data(&this->m_ctx, data.data(), data.size()); } - void Tar::write(const std::fs::path &path, const std::string &data) { - this->write(path, std::vector(data.begin(), data.end())); + void Tar::writeString(const std::fs::path &path, const std::string &data) { + this->writeVector(path, { data.begin(), data.end() }); } static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) { @@ -140,7 +140,7 @@ namespace hex { buffer.resize(std::min(BufferSize, header->size - offset)); mtar_read_data(ctx, buffer.data(), buffer.size()); - outputFile.write(buffer); + outputFile.writeVector(buffer); } } diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index 4e052b039..761ee6e97 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -55,7 +55,7 @@ namespace hex::prv { bufferSize = std::min(bufferSize, this->getActualSize() - offset); this->read(offset + this->getBaseAddress(), buffer.data(), bufferSize, true); - file.write(buffer.data(), bufferSize); + file.writeBuffer(buffer.data(), bufferSize); } } diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index f7d0c5882..892cb0da5 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -35,15 +34,23 @@ namespace hex::init { // Check if we should check for updates if (showCheckForUpdates == 1){ - hex::Net net; + HttpRequest request("GET", GitHubApiURL + "/releases/latest"s); + request.setTimeout(2000); // Query the GitHub API for the latest release version - auto releases = net.getJson(GitHubApiURL + "/releases/latest"s, 2000).get(); - if (releases.code != 200) + auto response = request.execute().get(); + if (response.getStatusCode() != 200) return false; + nlohmann::json releases; + try { + releases = nlohmann::json::parse(response.getData()); + } catch (std::exception &e) { + return false; + } + // Check if the response is valid - if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string()) + if (!releases.contains("tag_name") || !releases["tag_name"].is_string()) return false; // Convert the current version string to a format that can be compared to the latest release @@ -52,7 +59,7 @@ namespace hex::init { auto currVersion = "v" + versionString.substr(0, versionLength); // Get the latest release version string - auto latestVersion = releases.body["tag_name"].get(); + auto latestVersion = releases["tag_name"].get(); // Check if the latest release is different from the current version if (latestVersion != currVersion) @@ -86,7 +93,6 @@ namespace hex::init { else caCertData = std::string(romfs::get(CaCertFileName).string()); - Net::setCACert(caCertData); HttpRequest::setCACert(caCertData); return true; diff --git a/plugins/builtin/include/content/views/view_store.hpp b/plugins/builtin/include/content/views/view_store.hpp index 9524adc0f..eb3af8f9a 100644 --- a/plugins/builtin/include/content/views/view_store.hpp +++ b/plugins/builtin/include/content/views/view_store.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include @@ -48,9 +48,9 @@ namespace hex::plugin::builtin { [[nodiscard]] ImVec2 getMaxSize() const override { return { 900, 700 }; } private: - Net m_net; - std::future> m_apiRequest; - std::future> m_download; + HttpRequest m_httpRequest = HttpRequest("GET", ""); + std::future> m_apiRequest; + std::future> m_download; std::fs::path m_downloadPath; RequestStatus m_requestStatus = RequestStatus::NotAttempted; diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index cfa230b0d..f6840df23 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -69,7 +69,7 @@ namespace hex::plugin::builtin { return; } - auto base64 = inputFile.readBytes(); + auto base64 = inputFile.readVector(); if (!base64.empty()) { auto data = crypt::decode64(base64); @@ -83,7 +83,7 @@ namespace hex::plugin::builtin { if (!outputFile.isValid()) View::showErrorPopup("hex.builtin.menu.file.import.base64.popup.import_error"_lang); - outputFile.write(data); + outputFile.writeVector(data); }); } } else { @@ -95,7 +95,7 @@ namespace hex::plugin::builtin { void importIPSPatch() { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) { - auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readBytes(); + auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector(); auto patch = hex::loadIPSPatch(patchData); if (!patch.has_value()) { handleIPSError(patch.error()); @@ -121,7 +121,7 @@ namespace hex::plugin::builtin { void importIPS32Patch() { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) { - auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readBytes(); + auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector(); auto patch = hex::loadIPS32Patch(patchData); if (!patch.has_value()) { handleIPSError(patch.error()); @@ -148,7 +148,7 @@ namespace hex::plugin::builtin { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) { auto provider = ImHexApi::Provider::get(); - auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readBytes(); + auto patchData = wolv::io::File(path, wolv::io::File::Mode::Read).readVector(); if (patchData.size() != provider->getActualSize()) { View::showErrorPopup("hex.builtin.menu.file.import.modified_file.popup.invalid_size"_lang); @@ -202,7 +202,7 @@ namespace hex::plugin::builtin { bytes.resize(std::min(3000, provider->getActualSize() - address)); provider->read(provider->getBaseAddress() + address, bytes.data(), bytes.size()); - outputFile.write(crypt::encode64(bytes)); + outputFile.writeVector(crypt::encode64(bytes)); } }); }); @@ -232,7 +232,7 @@ namespace hex::plugin::builtin { } if (data.has_value()) - file.write(data.value()); + file.writeVector(data.value()); else { handleIPSError(data.error()); } @@ -265,7 +265,7 @@ namespace hex::plugin::builtin { } if (data.has_value()) - file.write(data.value()); + file.writeVector(data.value()); else handleIPSError(data.error()); }); diff --git a/plugins/builtin/source/content/pl_builtin_functions.cpp b/plugins/builtin/source/content/pl_builtin_functions.cpp index 7aade1383..ab32caac5 100644 --- a/plugins/builtin/source/content/pl_builtin_functions.cpp +++ b/plugins/builtin/source/content/pl_builtin_functions.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include @@ -9,6 +9,7 @@ #include #include + namespace hex::plugin::builtin { void registerPatternLanguageFunctions() { @@ -67,8 +68,8 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::addDangerousFunction(nsHexHttp, "get", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional { const auto url = params[0].toString(false); - hex::Net net; - return net.getString(url).get().body; + hex::HttpRequest request("GET", url); + return request.execute().get().getData(); }); } } diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index a88264927..cf129c2c0 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -67,11 +67,11 @@ namespace hex::plugin::builtin { json["type"] = provider->getTypeName(); json["settings"] = provider->storeSettings(); - tar.write(basePath / hex::format("{}.json", id), json.dump(4)); + tar.writeString(basePath / hex::format("{}.json", id), json.dump(4)); } - tar.write(basePath / "providers.json", - nlohmann::json({ {"providers", providerIds } }).dump(4) + tar.writeString(basePath / "providers.json", + nlohmann::json({ { "providers", providerIds } }).dump(4) ); return true; diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index c36812bc3..e920028a9 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -77,7 +77,7 @@ namespace hex::plugin::builtin { return; writeFile.seek(offset); - writeFile.write(reinterpret_cast(buffer), size); + writeFile.writeBuffer(reinterpret_cast(buffer), size); } void FileProvider::save() { diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 4f45ef146..5b3654a0a 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include #include @@ -517,8 +517,7 @@ namespace hex::plugin::builtin { static const std::string proxySetting { "hex.builtin.setting.proxy" }; - // init hex::Net proxy url - hex::Net::setProxy(ContentRegistry::Settings::read(proxySetting, "hex.builtin.setting.proxy.url", "")); + HttpRequest::setProxy(ContentRegistry::Settings::read(proxySetting, "hex.builtin.setting.proxy.url", "")); ContentRegistry::Settings::addCategoryDescription(proxySetting, "hex.builtin.setting.proxy.description"); @@ -531,14 +530,14 @@ namespace hex::plugin::builtin { if (ImGui::Checkbox("hex.builtin.setting.proxy.enable"_lang, &enableProxy)) { setting = enableProxy ? proxyUrl : ""; - hex::Net::setProxy(enableProxy ? proxyUrl : ""); + HttpRequest::setProxy(enableProxy ? proxyUrl : ""); result = true; } ImGui::BeginDisabled(!enableProxy); if (ImGui::InputText("##proxy_url", proxyUrl)) { setting = proxyUrl; - hex::Net::setProxy(proxyUrl); + HttpRequest::setProxy(proxyUrl); result = true; } ImGui::EndDisabled(); diff --git a/plugins/builtin/source/content/tools_entries.cpp b/plugins/builtin/source/content/tools_entries.cpp index 5830288f6..ff0347661 100644 --- a/plugins/builtin/source/content/tools_entries.cpp +++ b/plugins/builtin/source/content/tools_entries.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include #include @@ -570,8 +570,8 @@ namespace hex::plugin::builtin { std::string fileName, link, size; }; - static hex::Net net; - static std::future> uploadProcess; + static HttpRequest request("POST", "https://api.anonfiles.com/upload"); + static std::future> uploadProcess; static std::fs::path currFile; static std::vector links; @@ -581,19 +581,19 @@ namespace hex::plugin::builtin { if (!uploading) { if (ImGui::Button("hex.builtin.tools.file_uploader.upload"_lang)) { fs::openFileBrowser(fs::DialogMode::Open, {}, [&](auto path) { - uploadProcess = net.uploadFile("https://api.anonfiles.com/upload", path); + uploadProcess = request.uploadFile(path); currFile = path; }); } } else { if (ImGui::Button("hex.builtin.common.cancel"_lang)) { - net.cancel(); + request.cancel(); } } ImGui::SameLine(); - ImGui::ProgressBar(net.getProgress(), ImVec2(0, 0), uploading ? nullptr : "Done!"); + ImGui::ProgressBar(request.getProgress(), ImVec2(0, 0), uploading ? nullptr : "Done!"); ImGui::Header("hex.builtin.tools.file_uploader.recent"_lang); @@ -637,9 +637,9 @@ namespace hex::plugin::builtin { if (uploadProcess.valid() && uploadProcess.wait_for(0s) == std::future_status::ready) { auto response = uploadProcess.get(); - if (response.code == 200) { + if (response.getStatusCode() == 200) { try { - auto json = nlohmann::json::parse(response.body); + auto json = nlohmann::json::parse(response.getData()); links.push_back({ wolv::util::toUTF8String(currFile.filename()), json["data"]["file"]["url"]["short"], @@ -648,9 +648,9 @@ namespace hex::plugin::builtin { } catch (...) { View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang); } - } else if (response.code == 0) { + } else if (response.getStatusCode() == 0) { // Canceled by user, no action needed - } else View::showErrorPopup(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.code)); + } else View::showErrorPopup(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.getStatusCode())); uploadProcess = {}; currFile.clear(); @@ -663,19 +663,13 @@ namespace hex::plugin::builtin { } void drawWikiExplainer() { - static hex::Net net; + static HttpRequest request("GET", ""); static std::string resultTitle, resultExtract; - static std::future> searchProcess; + static std::future> searchProcess; static bool extendedSearch = false; - static auto searchString = [] { - std::string s; - s.reserve(0xFFFF); - std::memset(s.data(), 0x00, s.capacity()); - - return s; - }(); + std::string searchString; ImGui::Header("hex.builtin.tools.wiki_explain.control"_lang, true); @@ -689,7 +683,8 @@ namespace hex::plugin::builtin { ImGui::EndDisabled(); if (startSearch && !searchString.empty()) { - searchProcess = net.getString(getWikipediaApiUrl() + "&exintro"s + "&titles="s + net.encode(searchString)); + request.setUrl(getWikipediaApiUrl() + "&exintro"s + "&titles="s + request.urlEncode(searchString)); + searchProcess = request.execute(); } ImGui::Header("hex.builtin.tools.wiki_explain.results"_lang); @@ -705,16 +700,19 @@ namespace hex::plugin::builtin { if (searchProcess.valid() && searchProcess.wait_for(0s) == std::future_status::ready) { try { auto response = searchProcess.get(); - if (response.code != 200) throw std::runtime_error("Invalid response"); + if (response.getStatusCode() != 200) throw std::runtime_error("Invalid response"); - auto json = nlohmann::json::parse(response.body); + auto json = nlohmann::json::parse(response.getData()); resultTitle = json["query"]["pages"][0]["title"].get(); resultExtract = json["query"]["pages"][0]["extract"].get(); if (!extendedSearch && resultExtract.ends_with(':')) { extendedSearch = true; - searchProcess = net.getString(getWikipediaApiUrl() + "&titles="s + net.encode(searchString)); + + request.setUrl(getWikipediaApiUrl() + "&titles="s + request.urlEncode(searchString)); + searchProcess = request.execute(); + resultTitle.clear(); resultExtract.clear(); } else { @@ -839,7 +837,7 @@ namespace hex::plugin::builtin { for (const auto &pattern : overwritePattern) { for (u64 offset = 0; offset < fileSize; offset += 3) { - file.write(pattern.data(), std::min(pattern.size(), fileSize - offset)); + file.writeBuffer(pattern.data(), std::min(pattern.size(), fileSize - offset)); task.update(offset); } @@ -966,7 +964,7 @@ namespace hex::plugin::builtin { constexpr static auto BufferSize = 0xFF'FFFF; for (u64 partOffset = 0; partOffset < splitSize; partOffset += BufferSize) { - partFile.write(file.readBytes(std::min(BufferSize, splitSize - partOffset))); + partFile.writeVector(file.readVector(std::min(BufferSize, splitSize - partOffset))); partFile.flush(); } @@ -1093,7 +1091,7 @@ namespace hex::plugin::builtin { constexpr static auto BufferSize = 0xFF'FFFF; auto inputSize = input.getSize(); for (u64 inputOffset = 0; inputOffset < inputSize; inputOffset += BufferSize) { - output.write(input.readBytes(std::min(BufferSize, inputSize - inputOffset))); + output.writeVector(input.readVector(std::min(BufferSize, inputSize - inputOffset))); output.flush(); } } diff --git a/plugins/builtin/source/content/views/view_bookmarks.cpp b/plugins/builtin/source/content/views/view_bookmarks.cpp index 0ccea580c..afb64a58c 100644 --- a/plugins/builtin/source/content/views/view_bookmarks.cpp +++ b/plugins/builtin/source/content/views/view_bookmarks.cpp @@ -112,7 +112,7 @@ namespace hex::plugin::builtin { .basePath = "bookmarks.json", .required = false, .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { - auto fileContent = tar.read(basePath); + auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; @@ -124,7 +124,7 @@ namespace hex::plugin::builtin { nlohmann::json data; bool result = ViewBookmarks::exportBookmarks(provider, data); - tar.write(basePath, data.dump(4)); + tar.writeString(basePath, data.dump(4)); return result; } @@ -403,7 +403,7 @@ namespace hex::plugin::builtin { nlohmann::json json; exportBookmarks(ImHexApi::Provider::get(), json); - wolv::io::File(path, wolv::io::File::Mode::Create).write(json.dump(4)); + wolv::io::File(path, wolv::io::File::Mode::Create).writeString(json.dump(4)); }); }, []{ return ImHexApi::Provider::isValid() && !ProviderExtraData::getCurrent().bookmarks.empty(); diff --git a/plugins/builtin/source/content/views/view_constants.cpp b/plugins/builtin/source/content/views/view_constants.cpp index bae79de48..b965e2892 100644 --- a/plugins/builtin/source/content/views/view_constants.cpp +++ b/plugins/builtin/source/content/views/view_constants.cpp @@ -5,8 +5,8 @@ #include #include +#include -#include #include #include @@ -31,8 +31,8 @@ namespace hex::plugin::builtin { if (!file.is_regular_file()) continue; try { - nlohmann::json content; - std::ifstream(file.path()) >> content; + auto fileData = wolv::io::File(file.path(), wolv::io::File::Mode::Read).readString(); + auto content = nlohmann::json::parse(fileData); for (auto value : content["values"]) { Constant constant; diff --git a/plugins/builtin/source/content/views/view_data_processor.cpp b/plugins/builtin/source/content/views/view_data_processor.cpp index 820131fa7..242e8beb3 100644 --- a/plugins/builtin/source/content/views/view_data_processor.cpp +++ b/plugins/builtin/source/content/views/view_data_processor.cpp @@ -33,7 +33,7 @@ namespace hex::plugin::builtin { .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { auto &data = ProviderExtraData::get(provider).dataProcessor; - tar.write(basePath, ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); + tar.writeString(basePath, ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); return true; } @@ -88,7 +88,7 @@ namespace hex::plugin::builtin { [&](const std::fs::path &path) { wolv::io::File file(path, wolv::io::File::Mode::Create); if (file.isValid()) - file.write(ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); + file.writeString(ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); }); }, []{ auto &data = ProviderExtraData::getCurrent().dataProcessor; @@ -325,7 +325,7 @@ namespace hex::plugin::builtin { auto &node = *it; fs::openFileBrowser(fs::DialogMode::Save, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } }, [&](const std::fs::path &path){ wolv::io::File outputFile(path, wolv::io::File::Mode::Create); - outputFile.write(ViewDataProcessor::saveNode(node.get()).dump(4)); + outputFile.writeString(ViewDataProcessor::saveNode(node.get()).dump(4)); }); } } diff --git a/plugins/builtin/source/content/views/view_hashes.cpp b/plugins/builtin/source/content/views/view_hashes.cpp index 61b269174..667b9bf01 100644 --- a/plugins/builtin/source/content/views/view_hashes.cpp +++ b/plugins/builtin/source/content/views/view_hashes.cpp @@ -63,7 +63,7 @@ namespace hex::plugin::builtin { .basePath = "hashes.json", .required = false, .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { - auto fileContent = tar.read(basePath); + auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; @@ -76,7 +76,7 @@ namespace hex::plugin::builtin { nlohmann::json data; bool result = ViewHashes::exportHashes(provider, data); - tar.write(basePath, data.dump(4)); + tar.writeString(basePath, data.dump(4)); return result; } diff --git a/plugins/builtin/source/content/views/view_patches.cpp b/plugins/builtin/source/content/views/view_patches.cpp index a8c070e5e..a9d62fc84 100644 --- a/plugins/builtin/source/content/views/view_patches.cpp +++ b/plugins/builtin/source/content/views/view_patches.cpp @@ -17,14 +17,14 @@ namespace hex::plugin::builtin { .basePath = "patches.json", .required = false, .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { - auto json = nlohmann::json::parse(tar.read(basePath)); + auto json = nlohmann::json::parse(tar.readString(basePath)); provider->getPatches() = json["patches"].get>(); return true; }, .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { nlohmann::json json; json["patches"] = provider->getPatches(); - tar.write(basePath, json.dump(4)); + tar.writeString(basePath, json.dump(4)); return true; } diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 078f05dad..76feba1b6 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -885,7 +885,7 @@ namespace hex::plugin::builtin { [this](const auto &path) { wolv::io::File file(path, wolv::io::File::Mode::Create); - file.write(wolv::util::trim(this->m_textEditor.GetText())); + file.writeString(wolv::util::trim(this->m_textEditor.GetText())); }); }, ImHexApi::Provider::isValid); @@ -1047,7 +1047,7 @@ namespace hex::plugin::builtin { else sourceCode = ProviderExtraData::get(provider).patternLanguage.sourceCode; - tar.write(basePath, wolv::util::trim(sourceCode)); + tar.writeString(basePath, wolv::util::trim(sourceCode)); return true; } }); diff --git a/plugins/builtin/source/content/views/view_store.cpp b/plugins/builtin/source/content/views/view_store.cpp index fd34c8de0..05b5bf348 100644 --- a/plugins/builtin/source/content/views/view_store.cpp +++ b/plugins/builtin/source/content/views/view_store.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -34,6 +33,8 @@ namespace hex::plugin::builtin { TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.store.name").c_str()); }); this->getWindowOpenState() = true; }); + + this->m_httpRequest.setTimeout(30'0000); } void ViewStore::drawStore() { @@ -72,7 +73,7 @@ namespace hex::plugin::builtin { entry.downloading = false; auto response = this->m_download.get(); - if (response.code == 200) { + if (response.isSuccess()) { entry.installed = true; entry.hasUpdate = false; @@ -83,7 +84,7 @@ namespace hex::plugin::builtin { downloadDoneCallback(); } else - log::error("Download failed! HTTP Code {}", response.code); + log::error("Download failed! HTTP Code {}", response.getStatusCode()); this->m_download = {}; @@ -143,14 +144,15 @@ namespace hex::plugin::builtin { this->m_nodes.clear(); this->m_themes.clear(); - this->m_apiRequest = this->m_net.getString(ImHexApiURL + "/store"s, 30'0000); + this->m_httpRequest.setUrl(ImHexApiURL + "/store"s); + this->m_apiRequest = this->m_httpRequest.execute(); } void ViewStore::parseResponse() { auto response = this->m_apiRequest.get(); - this->m_requestStatus = response.code == 200 ? RequestStatus::Succeeded : RequestStatus::Failed; + this->m_requestStatus = response.isSuccess() ? RequestStatus::Succeeded : RequestStatus::Failed; if (this->m_requestStatus == RequestStatus::Succeeded) { - auto json = nlohmann::json::parse(response.body); + auto json = nlohmann::json::parse(response.getData()); auto parseStoreEntries = [](auto storeJson, const std::string &name, fs::ImHexPath pathType, std::vector &results) { // Check if the response handles the type of files @@ -172,11 +174,10 @@ namespace hex::plugin::builtin { if (wolv::io::fs::exists(path) && fs::isPathWritable(folder)) { storeEntry.installed = true; - std::ifstream file(path, std::ios::in | std::ios::binary); - std::vector data(wolv::io::fs::getFileSize(path), 0x00); - file.read(reinterpret_cast(data.data()), data.size()); + wolv::io::File file(path, wolv::io::File::Mode::Read); + auto bytes = file.readVector(); - auto fileHash = crypt::sha256(data); + auto fileHash = crypt::sha256(bytes); // Compare installed file hash with hash of repo file if (std::vector(fileHash.begin(), fileHash.end()) != crypt::decode16(storeEntry.hash)) @@ -233,7 +234,9 @@ namespace hex::plugin::builtin { if (!update || wolv::io::fs::exists(fullPath)) { downloading = true; this->m_downloadPath = fullPath; - this->m_download = this->m_net.downloadFile(url, fullPath, 30'0000); + + this->m_httpRequest.setUrl(url); + this->m_download = this->m_httpRequest.downloadFile(fullPath); break; } } diff --git a/plugins/builtin/source/content/views/view_theme_manager.cpp b/plugins/builtin/source/content/views/view_theme_manager.cpp index 29e18d779..519a0354e 100644 --- a/plugins/builtin/source/content/views/view_theme_manager.cpp +++ b/plugins/builtin/source/content/views/view_theme_manager.cpp @@ -58,7 +58,7 @@ namespace hex::plugin::builtin { auto json = api::ThemeManager::exportCurrentTheme(this->m_themeName); wolv::io::File outputFile(path, wolv::io::File::Mode::Create); - outputFile.write(json.dump(4)); + outputFile.writeString(json.dump(4)); }); } diff --git a/plugins/builtin/source/content/views/view_yara.cpp b/plugins/builtin/source/content/views/view_yara.cpp index 1d3c3989d..cdc1a034b 100644 --- a/plugins/builtin/source/content/views/view_yara.cpp +++ b/plugins/builtin/source/content/views/view_yara.cpp @@ -44,7 +44,7 @@ namespace hex::plugin::builtin { .basePath = "yara.json", .required = false, .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { - auto fileContent = tar.read(basePath); + auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; @@ -88,7 +88,7 @@ namespace hex::plugin::builtin { }); } - tar.write(basePath, data.dump(4)); + tar.writeString(basePath, data.dump(4)); return true; } diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index cc2774541..a1f53b2db 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -496,7 +496,7 @@ namespace hex::plugin::builtin { ProjectFile::clearPath(); if (auto settings = provider->storeSettings(); !settings.is_null()) - recentFile.write(settings.dump(4)); + recentFile.writeString(settings.dump(4)); ProjectFile::setPath(path); } diff --git a/tests/helpers/source/file.cpp b/tests/helpers/source/file.cpp index 636307876..9f63eeb30 100644 --- a/tests/helpers/source/file.cpp +++ b/tests/helpers/source/file.cpp @@ -15,7 +15,7 @@ TEST_SEQUENCE("FileAccess") { wolv::io::File file(FilePath, wolv::io::File::Mode::Create); TEST_ASSERT(file.isValid()); - file.write(FileContent); + file.writeString(FileContent); } { @@ -53,7 +53,7 @@ TEST_SEQUENCE("UTF-8 Path") { wolv::io::File file(FilePath, wolv::io::File::Mode::Create); TEST_ASSERT(file.isValid()); - file.write(FileContent); + file.writeU8String(FileContent); } { diff --git a/tests/helpers/source/net.cpp b/tests/helpers/source/net.cpp index 081ef17bf..8b4e06c47 100644 --- a/tests/helpers/source/net.cpp +++ b/tests/helpers/source/net.cpp @@ -1,47 +1,47 @@ #include -#include +#include #include #include using namespace std::literals::string_literals; TEST_SEQUENCE("StoreAPI") { - hex::Net net; + hex::HttpRequest request("GET", ImHexApiURL + "/store"s); - auto result = net.getString(ImHexApiURL + "/store"s).get(); + auto result = request.execute().get(); - if (result.code != 200) + if (result.getStatusCode() != 200) TEST_FAIL(); - if (result.body.empty()) + if (result.getData().empty()) TEST_FAIL(); TEST_SUCCESS(); }; TEST_SEQUENCE("TipsAPI") { - hex::Net net; + hex::HttpRequest request("GET", ImHexApiURL + "/tip"s); - auto result = net.getString(ImHexApiURL + "/tip"s).get(); + auto result = request.execute().get(); - if (result.code != 200) + if (result.getStatusCode() != 200) TEST_FAIL(); - if (result.body.empty()) + if (result.getData().empty()) TEST_FAIL(); TEST_SUCCESS(); }; TEST_SEQUENCE("ContentAPI") { - hex::Net net; + hex::HttpRequest request("GET", "https://api.werwolv.net/content/imhex/patterns/elf.hexpat"); const auto FilePath = std::fs::current_path() / "elf.hexpat"; - auto result = net.downloadFile("https://api.werwolv.net/content/imhex/patterns/elf.hexpat", FilePath).get(); + auto result = request.downloadFile(FilePath).get(); - TEST_ASSERT(result.code == 200); + TEST_ASSERT(result.getStatusCode() == 200); wolv::io::File file(FilePath, wolv::io::File::Mode::Read); if (!file.isValid())