From 3138d2c4a2e09811b4942f1366822b1643b0a639 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sat, 28 Aug 2021 00:45:59 +0200 Subject: [PATCH] tools: Added Anonfiles uploader --- .../builtin/source/content/tools_entries.cpp | 98 +++++++++ plugins/builtin/source/content/ui_items.cpp | 2 +- plugins/builtin/source/lang/de_DE.cpp | 10 + plugins/builtin/source/lang/en_US.cpp | 11 + plugins/builtin/source/lang/it_IT.cpp | 10 + plugins/libimhex/include/hex/helpers/net.hpp | 30 ++- .../libimhex/include/hex/helpers/utils.hpp | 103 ++++++++-- plugins/libimhex/include/hex/views/view.hpp | 8 - plugins/libimhex/source/helpers/net.cpp | 191 +++++++++++++----- plugins/libimhex/source/helpers/utils.cpp | 26 +++ plugins/libimhex/source/views/view.cpp | 26 --- source/init/tasks.cpp | 10 +- source/views/view_hexeditor.cpp | 30 +-- source/views/view_pattern.cpp | 2 +- 14 files changed, 423 insertions(+), 134 deletions(-) diff --git a/plugins/builtin/source/content/tools_entries.cpp b/plugins/builtin/source/content/tools_entries.cpp index 7d4a0e2eb..cddf35158 100644 --- a/plugins/builtin/source/content/tools_entries.cpp +++ b/plugins/builtin/source/content/tools_entries.cpp @@ -1,6 +1,9 @@ #include +#include + #include +#include #include #include "math_evaluator.hpp" @@ -9,6 +12,8 @@ namespace hex::plugin::builtin { namespace { + using namespace std::literals::chrono_literals; + void drawDemangler() { static std::vector mangledBuffer(0xF'FFFF, 0x00); static std::string demangledName; @@ -399,6 +404,98 @@ namespace hex::plugin::builtin { } + void drawFileUploader() { + struct UploadedFile { + std::string fileName, link, size; + }; + + static hex::Net net; + static std::future> uploadProcess; + static std::filesystem::path currFile; + static std::vector links; + + bool uploading = uploadProcess.valid() && uploadProcess.wait_for(0s) != std::future_status::ready; + + ImGui::Header("hex.builtin.tools.file_uploader.control"_lang, true); + if (!uploading) { + if (ImGui::Button("hex.builtin.tools.file_uploader.upload"_lang)) { + hex::openFileBrowser("hex.builtin.tools.file_uploader.done"_lang, DialogMode::Open, { }, [&](auto path){ + uploadProcess = net.uploadFile("https://api.anonfiles.com/upload", path); + currFile = path; + }); + } + } else { + if (ImGui::Button("hex.common.cancel"_lang)) { + net.cancel(); + } + } + + ImGui::SameLine(); + + ImGui::ProgressBar(net.getProgress(), ImVec2(0, 0), uploading ? nullptr : "Done!"); + + ImGui::Header("hex.builtin.tools.file_uploader.recent"_lang); + + if (ImGui::BeginTable("##links", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg, ImVec2(0, 400))) { + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableSetupColumn("hex.common.file"_lang); + ImGui::TableSetupColumn("hex.common.link"_lang); + ImGui::TableSetupColumn("hex.common.size"_lang); + ImGui::TableHeadersRow(); + + ImGuiListClipper clipper; + clipper.Begin(links.size()); + + while (clipper.Step()) { + for (s32 i = clipper.DisplayEnd - 1; i >= clipper.DisplayStart; i--) { + auto &[fileName, link, size] = links[i]; + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(fileName.c_str()); + + ImGui::TableNextColumn(); + if (ImGui::Hyperlink(link.c_str())) { + if (ImGui::GetMergedKeyModFlags() == ImGuiKeyModFlags_Ctrl) + hex::openWebpage(link); + else + ImGui::SetClipboardText(link.c_str()); + } + + ImGui::InfoTooltip("hex.builtin.tools.file_uploader.tooltip"_lang); + + ImGui::TableNextColumn(); + ImGui::TextUnformatted(size.c_str()); + } + } + + clipper.End(); + + ImGui::EndTable(); + } + + if (uploadProcess.valid() && uploadProcess.wait_for(0s) == std::future_status::ready) { + auto response = uploadProcess.get(); + if (response.code == 200) { + try { + auto json = nlohmann::json::parse(response.body); + links.push_back({ + currFile.filename().string(), + json["data"]["file"]["url"]["short"], + json["data"]["file"]["metadata"]["size"]["readable"] + }); + } catch (...) { + View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang); + } + } else if (response.code == 0) { + // Canceled by user, no action needed + } else View::showErrorPopup(hex::format("hex.builtin.tools.file_uploader.error"_lang, response.code)); + + uploadProcess = { }; + currFile.clear(); + } + } + void registerToolEntries() { ContentRegistry::Tools::add("hex.builtin.tools.demangler", drawDemangler); ContentRegistry::Tools::add("hex.builtin.tools.ascii_table", drawASCIITable); @@ -407,6 +504,7 @@ namespace hex::plugin::builtin { ContentRegistry::Tools::add("hex.builtin.tools.calc", drawMathEvaluator); ContentRegistry::Tools::add("hex.builtin.tools.base_converter", drawBaseConverter); ContentRegistry::Tools::add("hex.builtin.tools.permissions", drawPermissionsCalculator); + ContentRegistry::Tools::add("hex.builtin.tools.file_uploader", drawFileUploader); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index a0f739fa8..e31f399ff 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -60,7 +60,7 @@ namespace hex::plugin::builtin { // Save file as ImGui::Disabled([&provider] { if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize)) - View::openFileBrowser("hex.view.hexeditor.save_as"_lang, View::DialogMode::Save, { }, [&provider](auto path) { + hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [&provider](auto path) { provider->saveAs(path); }); }, provider == nullptr || !provider->isSavable()); diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 99d1647f7..e2963e8f0 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -76,6 +76,8 @@ namespace hex::plugin::builtin { { "hex.common.set", "Setzen" }, { "hex.common.close", "Schliessen" }, { "hex.common.dont_show_again", "Nicht mehr anzeigen" }, + { "hex.common.link", "Link" }, + { "hex.common.file", "Datei" }, { "hex.view.bookmarks.name", "Lesezeichen" }, { "hex.view.bookmarks.default_title", "Lesezeichen [0x{0:X} - 0x{1:X}]" }, @@ -538,6 +540,14 @@ namespace hex::plugin::builtin { { "hex.builtin.tools.permissions.setuid_error", "User benötigt execute Rechte, damit setuid bit gilt!" }, { "hex.builtin.tools.permissions.setgid_error", "Group benötigt execute Rechte, damit setgid bit gilt!" }, { "hex.builtin.tools.permissions.sticky_error", "Other benötigt execute Rechte, damit sticky bit gilt!" }, + { "hex.builtin.tools.file_uploader", "File Uploader" }, + { "hex.builtin.tools.file_uploader.control", "Einstellungen" }, + { "hex.builtin.tools.file_uploader.upload", "Upload" }, + { "hex.builtin.tools.file_uploader.done", "Fertig!" }, + { "hex.builtin.tools.file_uploader.recent", "Letzte Uploads" }, + { "hex.builtin.tools.file_uploader.tooltip", "Klicken zum Kopieren\nCTRL + Klicken zum öffnen" }, + { "hex.builtin.tools.file_uploader.invalid_response", "Ungültige Antwort von Anonfiles!"_lang }, + { "hex.builtin.tools.file_uploader.error", "Dateiupload fehlgeschlagen\n\nError Code: {0}"_lang }, { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 471e06458..eefb07e2c 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -76,6 +76,8 @@ namespace hex::plugin::builtin { { "hex.common.set", "Set" }, { "hex.common.close", "Close" }, { "hex.common.dont_show_again", "Don't show again" }, + { "hex.common.link", "Link" }, + { "hex.common.file", "File" }, { "hex.view.bookmarks.name", "Bookmarks" }, { "hex.view.bookmarks.default_title", "Bookmark [0x{0:X} - 0x{1:X}]" }, @@ -538,6 +540,15 @@ namespace hex::plugin::builtin { { "hex.builtin.tools.permissions.setuid_error", "User must have execute rights for setuid bit to apply!" }, { "hex.builtin.tools.permissions.setgid_error", "Group must have execute rights for setgid bit to apply!" }, { "hex.builtin.tools.permissions.sticky_error", "Other must have execute rights for sticky bit to apply!" }, + { "hex.builtin.tools.file_uploader", "File Uploader" }, + { "hex.builtin.tools.file_uploader.control", "Control" }, + { "hex.builtin.tools.file_uploader.upload", "Upload" }, + { "hex.builtin.tools.file_uploader.done", "Done!" }, + { "hex.builtin.tools.file_uploader.recent", "Recent Uploads" }, + { "hex.builtin.tools.file_uploader.tooltip", "Click to copy\nCTRL + Click to open" }, + { "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Anonfiles!" }, + { "hex.builtin.tools.file_uploader.error", "Failed to upload file!\n\nError Code: {0}" }, + { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "Recent Files" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 720407ac5..8f13f3592 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -75,6 +75,8 @@ namespace hex::plugin::builtin { { "hex.common.set", "Imposta" }, //{ "hex.common.close", "Close" }, //{ "hex.common.dont_show_again", "Don't show again" }, + //{ "hex.common.link", "Link" }, + //{ "hex.common.file", "File" }, { "hex.view.bookmarks.name", "Segnalibri" }, { "hex.view.bookmarks.default_title", "Segnalibro [0x{0:X} - 0x{1:X}]" }, @@ -537,6 +539,14 @@ namespace hex::plugin::builtin { //{ "hex.builtin.tools.permissions.setuid_error", "User must have execute rights for setuid bit to apply!" }, //{ "hex.builtin.tools.permissions.setgid_error", "Group must have execute rights for setgid bit to apply!" }, //{ "hex.builtin.tools.permissions.sticky_error", "Other must have execute rights for sticky bit to apply!" }, + //{ "hex.builtin.tools.file_uploader", "File Uploader" }, + //{ "hex.builtin.tools.file_uploader.control", "Control" }, + //{ "hex.builtin.tools.file_uploader.upload", "Upload" }, + //{ "hex.builtin.tools.file_uploader.done", "Done!" }, + //{ "hex.builtin.tools.file_uploader.recent", "Recent Uploads" }, + //{ "hex.builtin.tools.file_uploader.tooltip", "Click to copy\nCTRL + Click to open" }, + //{ "hex.builtin.tools.file_uploader.invalid_response", "Invalid response from Anonfiles!" }, + //{ "hex.builtin.tools.file_uploader.error", "Failed to upload file!\n\nError Code: {0}" }, { "hex.builtin.setting.imhex", "ImHex" }, { "hex.builtin.setting.imhex.recent_files", "File recenti" }, diff --git a/plugins/libimhex/include/hex/helpers/net.hpp b/plugins/libimhex/include/hex/helpers/net.hpp index 028b7c22d..6954dd66f 100644 --- a/plugins/libimhex/include/hex/helpers/net.hpp +++ b/plugins/libimhex/include/hex/helpers/net.hpp @@ -2,17 +2,20 @@ #include #include +#include +#include +#include -#include #include +#include namespace hex { template struct Response { - u32 code; - T response; + s32 code; + T body; }; class Net { @@ -20,11 +23,28 @@ namespace hex { Net(); ~Net(); - Response getString(std::string_view url); - Response getJson(std::string_view url); + std::future> getString(const std::string &url); + std::future> getJson(const std::string &url); + + std::future> uploadFile(const std::string &url, const std::filesystem::path &filePath); + + [[nodiscard]] + float getProgress() const { return this->m_progress; } + + void cancel() { this->m_shouldCancel = true; } + private: + void setCommonSettings(std::string &response, const std::string &url, 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); private: CURL *m_ctx; + struct curl_slist *m_headers = nullptr; + + std::mutex m_transmissionActive; + float m_progress = 0.0F; + bool m_shouldCancel = false; }; } \ No newline at end of file diff --git a/plugins/libimhex/include/hex/helpers/utils.hpp b/plugins/libimhex/include/hex/helpers/utils.hpp index 6f2211fab..96dba52ba 100644 --- a/plugins/libimhex/include/hex/helpers/utils.hpp +++ b/plugins/libimhex/include/hex/helpers/utils.hpp @@ -15,11 +15,13 @@ #include #ifdef __MINGW32__ -#include +#include #else #include #endif +#include + #if defined(__APPLE__) || defined(__FreeBSD__) #define off64_t off_t #define fopen64 fopen @@ -331,30 +333,87 @@ namespace hex { std::vector getPath(ImHexPath path); - #define SCOPE_GUARD ::hex::ScopeGuardOnExit() + [&]() - #define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD - template - class ScopeGuard { - private: - F m_func; - bool m_active; - public: - constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { } - ~ScopeGuard() { if (this->m_active) { this->m_func(); } } - void release() { this->m_active = false; } - - ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) { - other.cancel(); - } - - ScopeGuard& operator=(ScopeGuard &&) = delete; + enum class DialogMode { + Open, + Save, + Folder }; - enum class ScopeGuardOnExit { }; + void openFileBrowser(std::string_view title, DialogMode mode, const std::vector &validExtensions, const std::function &callback); + + namespace scope_guard { + + #define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]() + #define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD + + template + class ScopeGuard { + private: + F m_func; + bool m_active; + public: + constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { } + ~ScopeGuard() { if (this->m_active) { this->m_func(); } } + void release() { this->m_active = false; } + + ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) { + other.cancel(); + } + + ScopeGuard& operator=(ScopeGuard &&) = delete; + }; + + enum class ScopeGuardOnExit { }; + + template + constexpr ScopeGuard operator+(ScopeGuardOnExit, F&& f) { + return ScopeGuard(std::forward(f)); + } + + } + + namespace first_time_exec { + + #define FIRST_TIME static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]() + + template + class FirstTimeExecute { + public: + constexpr FirstTimeExecute(F func) { func(); } + + FirstTimeExecute& operator=(FirstTimeExecute &&) = delete; + }; + + enum class FirstTimeExecutor { }; + + template + constexpr FirstTimeExecute operator+(FirstTimeExecutor, F&& f) { + return FirstTimeExecute(std::forward(f)); + } + + } + + namespace final_cleanup { + + #define FINAL_CLEANUP static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]() + + template + class FinalCleanupExecute { + F m_func; + public: + constexpr FinalCleanupExecute(F func) : m_func(func) { } + constexpr ~FinalCleanupExecute() { this->m_func(); } + + FinalCleanupExecute& operator=(FinalCleanupExecute &&) = delete; + }; + + enum class FinalCleanupExecutor { }; + + template + constexpr FinalCleanupExecute operator+(FinalCleanupExecutor, F&& f) { + return FinalCleanupExecute(std::forward(f)); + } - template - constexpr ScopeGuard operator+(ScopeGuardOnExit, F&& f) { - return ScopeGuard(std::forward(f)); } struct Region { diff --git a/plugins/libimhex/include/hex/views/view.hpp b/plugins/libimhex/include/hex/views/view.hpp index bdf5a4310..346a619ec 100644 --- a/plugins/libimhex/include/hex/views/view.hpp +++ b/plugins/libimhex/include/hex/views/view.hpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -32,13 +31,6 @@ namespace hex { virtual bool isAvailable(); virtual bool shouldProcess() { return this->isAvailable() && this->getWindowOpenState(); } - enum class DialogMode { - Open, - Save, - Folder - }; - - static void openFileBrowser(std::string_view title, DialogMode mode, const std::vector &validExtensions, const std::function &callback); static void doLater(std::function &&function); static std::vector>& getDeferedCalls(); diff --git a/plugins/libimhex/source/helpers/net.cpp b/plugins/libimhex/source/helpers/net.cpp index 807617533..710f6bf3d 100644 --- a/plugins/libimhex/source/helpers/net.cpp +++ b/plugins/libimhex/source/helpers/net.cpp @@ -3,10 +3,9 @@ #include #include +#include #include -#include -#include #include #include @@ -14,21 +13,33 @@ namespace hex { Net::Net() { - curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr); - curl_global_init(CURL_GLOBAL_ALL); + FIRST_TIME { + curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr); + curl_global_init(CURL_GLOBAL_ALL); + }; + + FINAL_CLEANUP { + curl_global_cleanup(); + }; + this->m_ctx = curl_easy_init(); } Net::~Net() { curl_easy_cleanup(this->m_ctx); - curl_global_cleanup(); } - static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userp){ - static_cast(userp)->append((char*)contents, size * nmemb); + 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 readFromFile(void *contents, size_t size, size_t nmemb, void *userdata) { + FILE *file = static_cast(userdata); + + return fread(contents, size, nmemb, file); + } + static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userdata) { auto* cfg = static_cast(sslctx); @@ -41,9 +52,21 @@ namespace hex { return CURLE_OK; } - static void setCommonSettings(CURL *ctx, std::string &response, std::string_view path, const std::map &extraHeaders, const std::string &body) { - struct curl_slist *headers = nullptr; - headers = curl_slist_append(headers, "Cache-Control: no-cache"); + 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, 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) { @@ -51,65 +74,131 @@ namespace hex { entry += ": "; entry += value; - headers = curl_slist_append(headers, entry.c_str()); + this->m_headers = curl_slist_append(this->m_headers, entry.c_str()); } if (!body.empty()) - curl_easy_setopt(ctx, CURLOPT_POSTFIELDS, body.c_str()); + curl_easy_setopt(this->m_ctx, CURLOPT_POSTFIELDS, body.c_str()); - curl_easy_setopt(ctx, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); - curl_easy_setopt(ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2); - curl_easy_setopt(ctx, CURLOPT_URL, path.data()); - curl_easy_setopt(ctx, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(ctx, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(ctx, CURLOPT_USERAGENT, "ImHex/1.0"); - curl_easy_setopt(ctx, CURLOPT_DEFAULT_PROTOCOL, "https"); - curl_easy_setopt(ctx, CURLOPT_WRITEFUNCTION, writeToString); - curl_easy_setopt(ctx, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(ctx, CURLOPT_SSL_VERIFYHOST, 2L); - curl_easy_setopt(ctx, CURLOPT_CAINFO, nullptr); - curl_easy_setopt(ctx, CURLOPT_CAPATH, nullptr); - curl_easy_setopt(ctx, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction); - curl_easy_setopt(ctx, CURLOPT_WRITEDATA, &response); - curl_easy_setopt(ctx, CURLOPT_TIMEOUT_MS, 2000L); - curl_easy_setopt(ctx, CURLOPT_CONNECTTIMEOUT_MS, 2000L); - curl_easy_setopt(ctx, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(ctx, CURLOPT_NOSIGNAL, 1L); + 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_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_WRITEDATA, &response); + curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L); + curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, 2000L); + 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); } - Response Net::getString(std::string_view url) { - std::string response; - - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); - setCommonSettings(this->m_ctx, response, url, {}, ""); - + std::optional Net::execute() { CURLcode result = curl_easy_perform(this->m_ctx); - u32 responseCode = 0; + s32 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 Response{ responseCode, "" }; + return { }; else - return Response{ responseCode, response }; + return responseCode; } - Response Net::getJson(std::string_view url) { - std::string response; + std::future> Net::getString(const std::string &url) { + this->m_transmissionActive.lock(); - curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); - setCommonSettings(this->m_ctx, response, url, {}, ""); + return std::async(std::launch::async, [=, this]{ + std::string response; - CURLcode result = curl_easy_perform(this->m_ctx); + ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; - u32 responseCode = 0; - curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode); + curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET"); + setCommonSettings(response, url); - if (result != CURLE_OK) - return Response{ responseCode, { } }; - else - return Response{ responseCode, nlohmann::json::parse(response) }; + auto responseCode = execute(); + + return Response { responseCode.value_or(0), response }; + }); + } + + std::future> Net::getJson(const std::string &url) { + 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, {}); + + auto responseCode = execute(); + + return Response { responseCode.value_or(0), nlohmann::json::parse(response) }; + }); + } + + std::future> Net::uploadFile(const std::string &url, const std::filesystem::path &filePath) { + this->m_transmissionActive.lock(); + + return std::async(std::launch::async, [=, this] { + std::string response; + + ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); }; + + FILE *file = fopen(filePath.string().c_str(), "rb"); + if (file == nullptr) + return Response { 400, { } }; + + fseek(file, 0, SEEK_END); + size_t fileSize = ftell(file); + rewind(file); + + curl_mime *mime = curl_mime_init(this->m_ctx); + curl_mimepart *part = curl_mime_addpart(mime); + + auto fileName = filePath.filename().string(); + curl_mime_data_cb(part, fileSize, + [](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); + fseek(file, offset, origin); + return CURL_SEEKFUNC_OK; + }, + [](void *arg) { + auto file = static_cast(arg); + fclose(file); + }, file); + curl_mime_filename(part, fileName.c_str()); + curl_mime_name(part, "file"); + + setCommonSettings(response, url); + 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 }; + }); } } \ No newline at end of file diff --git a/plugins/libimhex/source/helpers/utils.cpp b/plugins/libimhex/source/helpers/utils.cpp index edcbe305a..aec6f62ce 100644 --- a/plugins/libimhex/source/helpers/utils.cpp +++ b/plugins/libimhex/source/helpers/utils.cpp @@ -296,4 +296,30 @@ namespace hex { #endif } + void openFileBrowser(std::string_view title, DialogMode mode, const std::vector &validExtensions, const std::function &callback) { + NFD::Init(); + + nfdchar_t *outPath; + nfdresult_t result; + switch (mode) { + case DialogMode::Open: + result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr); + break; + case DialogMode::Save: + result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr); + break; + case DialogMode::Folder: + result = NFD::PickFolder(outPath, nullptr); + break; + default: __builtin_unreachable(); + } + + if (result == NFD_OKAY) { + callback(outPath); + NFD::FreePath(outPath); + } + + NFD::Quit(); + } + } \ No newline at end of file diff --git a/plugins/libimhex/source/views/view.cpp b/plugins/libimhex/source/views/view.cpp index 4a0d10250..417ab6712 100644 --- a/plugins/libimhex/source/views/view.cpp +++ b/plugins/libimhex/source/views/view.cpp @@ -24,32 +24,6 @@ namespace hex { return SharedData::deferredCalls; } - void View::openFileBrowser(std::string_view title, DialogMode mode, const std::vector &validExtensions, const std::function &callback) { - NFD::Init(); - - nfdchar_t *outPath; - nfdresult_t result; - switch (mode) { - case DialogMode::Open: - result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr); - break; - case DialogMode::Save: - result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr); - break; - case DialogMode::Folder: - result = NFD::PickFolder(outPath, nullptr); - break; - default: __builtin_unreachable(); - } - - if (result == NFD_OKAY) { - callback(outPath); - NFD::FreePath(outPath); - } - - NFD::Quit(); - } - void View::drawCommonInterfaces() { if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("%s", SharedData::errorPopupMessage.c_str()); diff --git a/source/init/tasks.cpp b/source/init/tasks.cpp index 8b566d066..9080fe59b 100644 --- a/source/init/tasks.cpp +++ b/source/init/tasks.cpp @@ -31,15 +31,15 @@ namespace hex::init { static bool checkForUpdates() { hex::Net net; - auto releases = net.getJson("https://api.github.com/repos/WerWolv/ImHex/releases/latest"); + auto releases = net.getJson("https://api.github.com/repos/WerWolv/ImHex/releases/latest").get(); if (releases.code != 200) return false; - if (!releases.response.contains("tag_name") || !releases.response["tag_name"].is_string()) + if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string()) return false; auto currVersion = "v" + std::string(IMHEX_VERSION).substr(0, 5); - auto latestVersion = releases.response["tag_name"].get(); + auto latestVersion = releases.body["tag_name"].get(); if (latestVersion != currVersion) getInitArguments().push_back({ "update-available", latestVersion.data() }); @@ -50,11 +50,11 @@ namespace hex::init { static bool downloadInformation() { hex::Net net; - auto tip = net.getString("https://api.werwolv.net/imhex/tip"); + auto tip = net.getString("https://api.werwolv.net/imhex/tip").get(); if (tip.code != 200) return false; - getInitArguments().push_back({ "tip-of-the-day", tip.response }); + getInitArguments().push_back({ "tip-of-the-day", tip.body }); return true; } diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index 796910ed0..f6e6a820e 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -176,7 +176,7 @@ namespace hex { EventManager::subscribe(this, [this](std::string name) { if (name == "Create File") { - View::openFileBrowser("hex.view.hexeditor.create_file"_lang, DialogMode::Save, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.create_file"_lang, DialogMode::Save, { }, [this](auto path) { if (!this->createFile(path)) { View::showErrorPopup("hex.view.hexeditor.error.create"_lang); return; @@ -185,12 +185,12 @@ namespace hex { this->getWindowOpenState() = true; }); } else if (name == "Open File") { - View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { this->openFile(path); this->getWindowOpenState() = true; }); } else if (name == "Open Project") { - View::openFileBrowser("hex.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) { ProjectFile::load(path); EventManager::post(); this->getWindowOpenState() = true; @@ -271,7 +271,7 @@ namespace hex { } static void saveAs() { - View::openFileBrowser("hex.view.hexeditor.save_as"_lang, View::DialogMode::Save, { }, [](auto path) { + hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [](auto path) { auto provider = SharedData::currentProvider; provider->saveAs(path); }); @@ -306,14 +306,14 @@ namespace hex { ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); if (ImGui::Button("hex.view.hexeditor.script.script"_lang)) { - View::openFileBrowser("hex.view.hexeditor.script.script.title"_lang, DialogMode::Open, { { "Python Script", "py" } }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.script.script.title"_lang, DialogMode::Open, { { "Python Script", "py" } }, [this](auto path) { this->m_loaderScriptScriptPath = path; }); } ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); if (ImGui::Button("hex.view.hexeditor.script.file"_lang)) { - View::openFileBrowser("hex.view.hexeditor.script.file.title"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.script.file.title"_lang, DialogMode::Open, { }, [this](auto path) { this->m_loaderScriptFilePath = path; }); } @@ -384,7 +384,7 @@ namespace hex { if (ImGui::BeginMenu("hex.menu.file"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_file"_lang, "CTRL + O")) { - View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { EventManager::post(path); }); } @@ -416,7 +416,7 @@ namespace hex { ImGui::Separator(); if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_project"_lang, "")) { - View::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) { ProjectFile::load(path); EventManager::post(); }); @@ -424,7 +424,7 @@ namespace hex { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save_project"_lang, "", false, provider != nullptr && provider->isWritable())) { if (ProjectFile::getProjectFilePath() == "") { - View::openFileBrowser("hex.view.hexeditor.save_project"_lang, DialogMode::Save, { { "Project File", "hexproj" } }, [](auto path) { + hex::openFileBrowser("hex.view.hexeditor.save_project"_lang, DialogMode::Save, { { "Project File", "hexproj" } }, [](auto path) { if (path.ends_with(".hexproj")) { ProjectFile::store(path); } @@ -438,7 +438,7 @@ namespace hex { } if (ImGui::MenuItem("hex.view.hexeditor.menu.file.load_encoding_file"_lang)) { - View::openFileBrowser("hex.view.hexeditor.load_enconding_file"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.load_enconding_file"_lang, DialogMode::Open, { }, [this](auto path) { this->m_currEncodingFile = EncodingFile(EncodingFile::Type::Thingy, path); }); } @@ -448,7 +448,7 @@ namespace hex { if (ImGui::BeginMenu("hex.view.hexeditor.menu.file.import"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.base64"_lang)) { - View::openFileBrowser("hex.view.hexeditor.menu.file.import.base64"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.menu.file.import.base64"_lang, DialogMode::Open, { }, [this](auto path) { std::vector base64; this->loadFromFile(path, base64); @@ -468,7 +468,7 @@ namespace hex { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips"_lang)) { - View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { auto patchData = hex::readFile(path); auto patch = hex::loadIPSPatch(patchData); @@ -482,7 +482,7 @@ namespace hex { } if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips32"_lang)) { - View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) { auto patchData = hex::readFile(path); auto patch = hex::loadIPS32Patch(patchData); @@ -512,7 +512,7 @@ namespace hex { } this->m_dataToSave = generateIPSPatch(patches); - View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) { this->saveToFile(path, this->m_dataToSave); }); } @@ -525,7 +525,7 @@ namespace hex { } this->m_dataToSave = generateIPS32Patch(patches); - View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) { + hex::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) { this->saveToFile(path, this->m_dataToSave); }); } diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 9bd26f35d..218d89ac4 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -213,7 +213,7 @@ namespace hex { void ViewPattern::drawMenu() { if (ImGui::BeginMenu("hex.menu.file"_lang)) { if (ImGui::MenuItem("hex.view.pattern.menu.file.load_pattern"_lang)) { - View::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) { + hex::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) { this->loadPatternFile(path); }); }