From c3bfd575994e58380c751790f320eb15ab9ca24c Mon Sep 17 00:00:00 2001 From: Benjamin Wrensch Date: Sun, 18 Aug 2024 14:41:05 +0200 Subject: [PATCH] [add] cleanup and enable sol safeties for function objects --- iolite_plugins/CMakeLists.txt | 2 +- .../benchmark_plugin/benchmark_plugin.cpp | 4 - .../denoiser_oidn_plugin.cpp | 197 +++------------ iolite_plugins/lua_plugin/init_state.cpp | 2 +- iolite_plugins/shared/iolite_plugins_common.h | 9 +- .../shared/iolite_plugins_libraries.h | 239 ++++++++++++++++++ 6 files changed, 284 insertions(+), 169 deletions(-) create mode 100644 iolite_plugins/shared/iolite_plugins_libraries.h diff --git a/iolite_plugins/CMakeLists.txt b/iolite_plugins/CMakeLists.txt index 3c6e945..da4eaab 100644 --- a/iolite_plugins/CMakeLists.txt +++ b/iolite_plugins/CMakeLists.txt @@ -25,7 +25,7 @@ add_library(IoliteLuaPlugin SHARED ) list(APPEND PLUGINS IoliteLuaPlugin) -target_compile_definitions(IoliteLuaPlugin PUBLIC SOL_LUAJIT=1 SOL_ALL_SAFETIES_ON=1) +target_compile_definitions(IoliteLuaPlugin PUBLIC SOL_LUAJIT=1 SOL_ALL_SAFETIES_ON=1 SOL_SAFE_FUNCTION_OBJECTS=1) target_link_libraries(IoliteLuaPlugin ${LUA_JIT_LIBRARIES}) if(MSVC) diff --git a/iolite_plugins/benchmark_plugin/benchmark_plugin.cpp b/iolite_plugins/benchmark_plugin/benchmark_plugin.cpp index 4433b16..5323f62 100644 --- a/iolite_plugins/benchmark_plugin/benchmark_plugin.cpp +++ b/iolite_plugins/benchmark_plugin/benchmark_plugin.cpp @@ -22,11 +22,7 @@ // Dependencies #include -#include -#include #include -#include "ext/scalar_constants.hpp" -#include "geometric.hpp" #include "imgui.h" #include "IconsFontAwesome6.h" diff --git a/iolite_plugins/denoiser_oidn_plugin/denoiser_oidn_plugin.cpp b/iolite_plugins/denoiser_oidn_plugin/denoiser_oidn_plugin.cpp index 3a483d4..4995e2e 100644 --- a/iolite_plugins/denoiser_oidn_plugin/denoiser_oidn_plugin.cpp +++ b/iolite_plugins/denoiser_oidn_plugin/denoiser_oidn_plugin.cpp @@ -21,13 +21,12 @@ // SOFTWARE. // Dependencies -#include "oidn.h" #include // API #define _IO_PLUGIN_NAME "DenoiserOIDN" #include "iolite_api.h" -#include "iolite_plugins_common.h" +#include "iolite_plugins_libraries.h" // Interfaces we use //----------------------------------------------------------------------------// @@ -39,125 +38,7 @@ static const io_logging_i* io_logging = nullptr; static io_user_denoiser_i io_user_denoiser = {}; //----------------------------------------------------------------------------// -static struct oidn_t -{ - // NOLINTBEGIN - using oidn_set_device_int_t = void (*)(OIDNDevice device, const char* name, - int value); - using oidn_new_device_t = OIDNDevice (*)(OIDNDeviceType type); - using oidn_commit_device_t = void (*)(OIDNDevice device); - using oidn_new_filter_t = OIDNFilter (*)(OIDNDevice device, const char* type); - using oidn_new_buffer_t = OIDNBuffer (*)(OIDNDevice device, size_t byteSize); - using oidn_set_filter_image_t = void (*)(OIDNFilter filter, const char* name, - OIDNBuffer buffer, OIDNFormat format, - size_t width, size_t height, - size_t byteOffset, - size_t pixelByteStride, - size_t rowByteStride); - using oidn_set_shared_filter_image_t = - void (*)(OIDNFilter filter, const char* name, void* devPtr, - OIDNFormat format, size_t width, size_t height, - size_t byteOffset, size_t pixelByteStride, size_t rowByteStride); - using oidn_set_filter_bool_t = void (*)(OIDNFilter filter, const char* name, - bool value); - using oidn_set_filter_int_t = void (*)(OIDNFilter filter, const char* name, - int value); - using oidn_set_filter_progress_monitor_function_t = void (*)( - OIDNFilter filter, OIDNProgressMonitorFunction func, void* userPtr); - using oidn_commit_filter_t = void (*)(OIDNFilter filter); - using oidn_execute_filter_t = void (*)(OIDNFilter filter); - using oidn_get_device_error_t = OIDNError (*)(OIDNDevice device, - const char** outMessage); - using oidn_get_buffer_data_t = void* (*)(OIDNBuffer buffer); - using oidn_read_buffer_t = void (*)(OIDNBuffer buffer, size_t byteOffset, - size_t byteSize, void* dstHostPtr); - using oidn_write_buffer_t = void (*)(OIDNBuffer buffer, size_t byteOffset, - size_t byteSize, const void* srcHostPtr); - using oidn_release_filter_t = void (*)(OIDNFilter filter); - using oidn_release_buffer_t = void (*)(OIDNBuffer buffer); - using oidn_release_device_t = void (*)(OIDNDevice device); - - oidn_set_device_int_t oidnSetDeviceInt; - oidn_new_device_t oidnNewDevice; - oidn_commit_device_t oidnCommitDevice; - oidn_new_filter_t oidnNewFilter; - oidn_new_buffer_t oidnNewBuffer; - oidn_set_filter_image_t oidnSetFilterImage; - oidn_set_shared_filter_image_t oidnSetSharedFilterImage; - oidn_set_filter_bool_t oidnSetFilterBool; - oidn_set_filter_int_t oidnSetFilterInt; - oidn_set_filter_progress_monitor_function_t - oidnSetFilterProgressMonitorFunction; - oidn_commit_filter_t oidnCommitFilter; - oidn_execute_filter_t oidnExecuteFilter; - oidn_get_device_error_t oidnGetDeviceError; - oidn_read_buffer_t oidnReadBuffer; - oidn_write_buffer_t oidnWriteBuffer; - oidn_get_buffer_data_t oidnGetBufferData; - oidn_release_filter_t oidnReleaseFilter; - oidn_release_buffer_t oidnReleaseBuffer; - oidn_release_device_t oidnReleaseDevice; - // NOLINTEND - - void* oidn{nullptr}; - - bool init{false}; -} oidn; - -//----------------------------------------------------------------------------// -static io_bool_t unload_oidn(bool error = false) -{ - if (error) - common::log_message(io_logging, "Failed to load OIDN library!"); - - if (oidn.oidn) - common::unload_library(oidn.oidn); - - memset(&oidn, 0, sizeof(oidn)); - return !error; -}; - -//----------------------------------------------------------------------------// -static io_bool_t load_oidn() -{ - if (oidn.init) - return true; - - oidn.oidn = common::load_library("OpenImageDenoise"); - if (!oidn.oidn) - return unload_oidn(true); - -#define LOAD_FUNCTION(_function, _type) \ - oidn._function = \ - (oidn_t::_type)common::load_function(oidn.oidn, #_function); \ - if (!oidn._function) \ - return unload_oidn(true); - - LOAD_FUNCTION(oidnSetDeviceInt, oidn_set_device_int_t); - LOAD_FUNCTION(oidnNewDevice, oidn_new_device_t); - LOAD_FUNCTION(oidnCommitDevice, oidn_commit_device_t); - LOAD_FUNCTION(oidnNewFilter, oidn_new_filter_t); - LOAD_FUNCTION(oidnNewBuffer, oidn_new_buffer_t); - LOAD_FUNCTION(oidnSetFilterImage, oidn_set_filter_image_t); - LOAD_FUNCTION(oidnSetSharedFilterImage, oidn_set_shared_filter_image_t); - LOAD_FUNCTION(oidnSetFilterBool, oidn_set_filter_bool_t); - LOAD_FUNCTION(oidnSetFilterInt, oidn_set_filter_int_t); - LOAD_FUNCTION(oidnSetFilterProgressMonitorFunction, - oidn_set_filter_progress_monitor_function_t); - LOAD_FUNCTION(oidnCommitFilter, oidn_commit_filter_t); - LOAD_FUNCTION(oidnExecuteFilter, oidn_execute_filter_t); - LOAD_FUNCTION(oidnGetDeviceError, oidn_get_device_error_t); - LOAD_FUNCTION(oidnGetBufferData, oidn_get_buffer_data_t); - LOAD_FUNCTION(oidnReadBuffer, oidn_read_buffer_t); - LOAD_FUNCTION(oidnWriteBuffer, oidn_write_buffer_t); - LOAD_FUNCTION(oidnReleaseFilter, oidn_release_filter_t); - LOAD_FUNCTION(oidnReleaseBuffer, oidn_release_buffer_t); - LOAD_FUNCTION(oidnReleaseDevice, oidn_release_device_t); - -#undef LOAD_FUNCTION - - return true; -}; +static const char* get_name() { return "OIDN"; } //----------------------------------------------------------------------------// static bool on_progress_report(void* user_ptr, double n) @@ -170,62 +51,62 @@ static bool on_progress_report(void* user_ptr, double n) static void denoise(io_uint32_t width, io_uint32_t height, const io_vec4_t* input, io_vec4_t* output) { - if (!load_oidn()) + if (!libraries::load_oidn(io_logging)) return; common::log_message(io_logging, "Denoising image..."); - OIDNDevice device = oidn.oidnNewDevice(OIDN_DEVICE_TYPE_DEFAULT); - // oidn.oidnSetDeviceInt(device, "verbose", 4); - oidn.oidnCommitDevice(device); + OIDNDevice device = libraries::oidn.oidnNewDevice(OIDN_DEVICE_TYPE_DEFAULT); + // libraries::oidn.oidnSetDeviceInt(device, "verbose", 4); + libraries::oidn.oidnCommitDevice(device); OIDNBuffer input_buffer = - oidn.oidnNewBuffer(device, width * height * sizeof(*input)); + libraries::oidn.oidnNewBuffer(device, width * height * sizeof(*input)); OIDNBuffer output_buffer = - oidn.oidnNewBuffer(device, width * height * sizeof(*output)); - - oidn.oidnWriteBuffer(input_buffer, 0u, width * height * sizeof(*input), - input); - oidn.oidnWriteBuffer(output_buffer, 0u, width * height * sizeof(*input), - input); - - OIDNFilter filter = oidn.oidnNewFilter(device, "RT"); - oidn.oidnSetFilterImage(filter, "color", input_buffer, OIDN_FORMAT_FLOAT3, - width, height, 0, 16u, 0); - oidn.oidnSetFilterImage(filter, "output", output_buffer, OIDN_FORMAT_FLOAT3, - width, height, 0, 16u, 0); - oidn.oidnSetFilterBool(filter, "hdr", true); - // oidn.oidnSetFilterInt(filter, "quality", OIDN_QUALITY_HIGH); - oidn.oidnSetFilterProgressMonitorFunction(filter, on_progress_report, - nullptr); - oidn.oidnCommitFilter(filter); - oidn.oidnExecuteFilter(filter); + libraries::oidn.oidnNewBuffer(device, width * height * sizeof(*output)); + + libraries::oidn.oidnWriteBuffer(input_buffer, 0u, + width * height * sizeof(*input), input); + libraries::oidn.oidnWriteBuffer(output_buffer, 0u, + width * height * sizeof(*input), input); + + OIDNFilter filter = libraries::oidn.oidnNewFilter(device, "RT"); + libraries::oidn.oidnSetFilterImage(filter, "color", input_buffer, + OIDN_FORMAT_FLOAT3, width, height, 0, 16u, + 0); + libraries::oidn.oidnSetFilterImage(filter, "output", output_buffer, + OIDN_FORMAT_FLOAT3, width, height, 0, 16u, + 0); + libraries::oidn.oidnSetFilterBool(filter, "hdr", true); + // libraries::oidn.oidnSetFilterInt(filter, "quality", OIDN_QUALITY_HIGH); + libraries::oidn.oidnSetFilterProgressMonitorFunction( + filter, on_progress_report, nullptr); + libraries::oidn.oidnCommitFilter(filter); + libraries::oidn.oidnExecuteFilter(filter); const char* error_message; - if (oidn.oidnGetDeviceError(device, &error_message) != OIDN_ERROR_NONE) + if (libraries::oidn.oidnGetDeviceError(device, &error_message) != + OIDN_ERROR_NONE) { common::log_message(io_logging, "OIDN ERROR: %s", error_message); } else { - oidn.oidnReadBuffer(output_buffer, 0u, width * height * sizeof(*output), - output); + libraries::oidn.oidnReadBuffer(output_buffer, 0u, + width * height * sizeof(*output), output); } - oidn.oidnReleaseBuffer(input_buffer); - oidn.oidnReleaseBuffer(output_buffer); + libraries::oidn.oidnReleaseBuffer(input_buffer); + libraries::oidn.oidnReleaseBuffer(output_buffer); - oidn.oidnReleaseFilter(filter); - oidn.oidnReleaseDevice(device); + libraries::oidn.oidnReleaseFilter(filter); + libraries::oidn.oidnReleaseDevice(device); common::log_message(io_logging, "Done!"); - unload_oidn(); + libraries::unload_oidn(io_logging); } -//----------------------------------------------------------------------------// -static const char* get_name() { return "OIDN"; } - //----------------------------------------------------------------------------// IO_API_EXPORT io_uint32_t IO_API_CALL get_api_version() { @@ -241,12 +122,10 @@ IO_API_EXPORT int IO_API_CALL load_plugin(void* api_manager) io_logging = (const io_logging_i*)io_api_manager->find_first(IO_LOGGING_API_NAME); - if (!load_oidn()) - { + if (!libraries::load_oidn(io_logging)) // Unsupported if OIDN is not available return -1; - } - unload_oidn(); + libraries::unload_oidn(io_logging); // Register the interfaces we provide { diff --git a/iolite_plugins/lua_plugin/init_state.cpp b/iolite_plugins/lua_plugin/init_state.cpp index 41d72e1..c345762 100644 --- a/iolite_plugins/lua_plugin/init_state.cpp +++ b/iolite_plugins/lua_plugin/init_state.cpp @@ -2905,7 +2905,7 @@ void script_init_state(sol::state& s) // @function fill // @summary Fills all voxels in the range defined by min and max. // @param component Ref The voxel shape component. - // @param min U8Vec3 The min voxel coorindate of the area. + // @param min U8Vec3 The min voxel coordinate of the area. // @param max U8Vec3 The max voxel coordinate of the area. // @param palette_index number The palette index to set. s["VoxelShape"]["fill"] = io_component_voxel_shape->fill; diff --git a/iolite_plugins/shared/iolite_plugins_common.h b/iolite_plugins/shared/iolite_plugins_common.h index 8a16fa9..f7dd8db 100644 --- a/iolite_plugins/shared/iolite_plugins_common.h +++ b/iolite_plugins/shared/iolite_plugins_common.h @@ -26,6 +26,7 @@ #include "iolite_api.h" // Dependencies +#include #include #define STB_SPRINTF_IMPLEMENTATION #include "stb_sprintf.h" @@ -53,7 +54,7 @@ void* load_library(const char* name) #ifdef _WIN32 return LoadLibraryA(name); #else - void * handle = dlopen(name, RTLD_LAZY); + void* handle = dlopen(name, RTLD_LAZY); if (!handle) handle = dlopen((std::string("lib") + name).c_str(), RTLD_LAZY); if (!handle) @@ -88,14 +89,14 @@ void unload_library(void* handle) inline static void log_message(const io_logging_i* io_logging, const char* fmt, ...) { - char buffer[256]; + std::vector buffer(128u * 1024u); va_list args; va_start(args, fmt); - stbsp_vsnprintf(buffer, 256, fmt, args); + stbsp_vsnprintf(buffer.data(), buffer.size(), fmt, args); va_end(args); - io_logging->log_plugin(_IO_PLUGIN_NAME, buffer); + io_logging->log_plugin(_IO_PLUGIN_NAME, buffer.data()); } //----------------------------------------------------------------------------// diff --git a/iolite_plugins/shared/iolite_plugins_libraries.h b/iolite_plugins/shared/iolite_plugins_libraries.h new file mode 100644 index 0000000..7e9ea3b --- /dev/null +++ b/iolite_plugins/shared/iolite_plugins_libraries.h @@ -0,0 +1,239 @@ +// MIT License +// +// Copyright (c) 2023 Missing Deadlines (Benjamin Wrensch) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// Plugins +#include "iolite_api.h" +#include "iolite_plugins_common.h" + +// Dependencies +#include "curl.h" +#include "oidn.h" + +//----------------------------------------------------------------------------// +namespace libraries +{ + +// Open Image Denoise (OIDN) +//----------------------------------------------------------------------------// +static struct oidn_t +{ + // NOLINTBEGIN + using pfn_oidnSetDeviceInt = void (*)(OIDNDevice device, const char* name, + int value); + using pfn_oidnNewDevice = OIDNDevice (*)(OIDNDeviceType type); + using pfn_oidnCommitDevice = void (*)(OIDNDevice device); + using pfn_oidnNewFilter = OIDNFilter (*)(OIDNDevice device, const char* type); + using pfn_oidnNewBuffer = OIDNBuffer (*)(OIDNDevice device, size_t byteSize); + using pfn_oidnSetFilterImage = void (*)(OIDNFilter filter, const char* name, + OIDNBuffer buffer, OIDNFormat format, + size_t width, size_t height, + size_t byteOffset, + size_t pixelByteStride, + size_t rowByteStride); + using pfn_oidnSetSharedFilterImage = + void (*)(OIDNFilter filter, const char* name, void* devPtr, + OIDNFormat format, size_t width, size_t height, + size_t byteOffset, size_t pixelByteStride, size_t rowByteStride); + using pfn_oidnSetFilterBool = void (*)(OIDNFilter filter, const char* name, + bool value); + using pfn_oidnSetFilterInt = void (*)(OIDNFilter filter, const char* name, + int value); + using pfn_oidnSetFilterProgressMonitorFunction = void (*)( + OIDNFilter filter, OIDNProgressMonitorFunction func, void* userPtr); + using pfn_oidnCommitFilter = void (*)(OIDNFilter filter); + using pfn_oidnExecuteFilter = void (*)(OIDNFilter filter); + using pfn_oidnGetDeviceError = OIDNError (*)(OIDNDevice device, + const char** outMessage); + using pfn_oidnGetBufferData = void* (*)(OIDNBuffer buffer); + using pfn_oidnReadBuffer = void (*)(OIDNBuffer buffer, size_t byteOffset, + size_t byteSize, void* dstHostPtr); + using pfn_oidnWriteBuffer = void (*)(OIDNBuffer buffer, size_t byteOffset, + size_t byteSize, const void* srcHostPtr); + using pfn_oidnReleaseFilter = void (*)(OIDNFilter filter); + using pfn_oidnReleaseBuffer = void (*)(OIDNBuffer buffer); + using pfn_oidnReleaseDevice = void (*)(OIDNDevice device); + + pfn_oidnSetDeviceInt oidnSetDeviceInt; + pfn_oidnNewDevice oidnNewDevice; + pfn_oidnCommitDevice oidnCommitDevice; + pfn_oidnNewFilter oidnNewFilter; + pfn_oidnNewBuffer oidnNewBuffer; + pfn_oidnSetFilterImage oidnSetFilterImage; + pfn_oidnSetSharedFilterImage oidnSetSharedFilterImage; + pfn_oidnSetFilterBool oidnSetFilterBool; + pfn_oidnSetFilterInt oidnSetFilterInt; + pfn_oidnSetFilterProgressMonitorFunction oidnSetFilterProgressMonitorFunction; + pfn_oidnCommitFilter oidnCommitFilter; + pfn_oidnExecuteFilter oidnExecuteFilter; + pfn_oidnGetDeviceError oidnGetDeviceError; + pfn_oidnReadBuffer oidnReadBuffer; + pfn_oidnWriteBuffer oidnWriteBuffer; + pfn_oidnGetBufferData oidnGetBufferData; + pfn_oidnReleaseFilter oidnReleaseFilter; + pfn_oidnReleaseBuffer oidnReleaseBuffer; + pfn_oidnReleaseDevice oidnReleaseDevice; + // NOLINTEND + + void* oidn{nullptr}; + bool init{false}; +} oidn; + +//----------------------------------------------------------------------------// +static io_bool_t unload_oidn(const io_logging_i* io_logging, bool error = false) +{ + if (error) + common::log_message(io_logging, "Failed to load OIDN library!"); + + if (oidn.oidn) + common::unload_library(oidn.oidn); + + memset(&oidn, 0, sizeof(oidn)); + return !error; +}; + +//----------------------------------------------------------------------------// +static io_bool_t load_oidn(const io_logging_i* io_logging) +{ + if (oidn.init) + return true; + + oidn.oidn = common::load_library("OpenImageDenoise"); + if (!oidn.oidn) + return unload_oidn(io_logging, true); + +#define LOAD_FUNCTION(_function) \ + oidn._function = \ + (oidn_t::pfn_##_function)common::load_function(oidn.oidn, #_function); \ + if (!oidn._function) \ + return unload_oidn(io_logging, true); + + LOAD_FUNCTION(oidnSetDeviceInt) + LOAD_FUNCTION(oidnNewDevice); + LOAD_FUNCTION(oidnCommitDevice); + LOAD_FUNCTION(oidnNewFilter); + LOAD_FUNCTION(oidnNewBuffer); + LOAD_FUNCTION(oidnSetFilterImage); + LOAD_FUNCTION(oidnSetSharedFilterImage); + LOAD_FUNCTION(oidnSetFilterBool); + LOAD_FUNCTION(oidnSetFilterInt); + LOAD_FUNCTION(oidnSetFilterProgressMonitorFunction); + LOAD_FUNCTION(oidnCommitFilter); + LOAD_FUNCTION(oidnExecuteFilter); + LOAD_FUNCTION(oidnGetDeviceError); + LOAD_FUNCTION(oidnGetBufferData); + LOAD_FUNCTION(oidnReadBuffer); + LOAD_FUNCTION(oidnWriteBuffer); + LOAD_FUNCTION(oidnReleaseFilter); + LOAD_FUNCTION(oidnReleaseBuffer); + LOAD_FUNCTION(oidnReleaseDevice); + +#undef LOAD_FUNCTION + + return true; +}; + +// curl +//----------------------------------------------------------------------------// +static struct curl_t +{ + // NOLINTBEGIN + using pfn_curl_easy_init = CURL* (*)(void); + using pfn_curl_easy_setopt = CURLcode (*)(CURL* curl, CURLoption option, ...); + using pfn_curl_easy_perform = CURLcode (*)(CURL* curl); + using pfn_curl_easy_cleanup = void (*)(CURL* curl); + + using pfn_curl_slist_append = struct curl_slist* (*)(struct curl_slist* list, + const char* data); + using pfn_curl_slist_free_all = void (*)(struct curl_slist* list); + + using pfn_curl_global_init = void (*)(long flags); + using pfn_curl_global_cleanup = CURLcode (*)(void); + + pfn_curl_easy_init curl_easy_init{nullptr}; + pfn_curl_easy_setopt curl_easy_setopt{nullptr}; + pfn_curl_easy_perform curl_easy_perform{nullptr}; + pfn_curl_easy_cleanup curl_easy_cleanup{nullptr}; + + pfn_curl_slist_append curl_slist_append{nullptr}; + pfn_curl_slist_free_all curl_slist_free_all{nullptr}; + + pfn_curl_global_init curl_global_init{nullptr}; + pfn_curl_global_cleanup curl_global_cleanup{nullptr}; + // NOLINTEND + + void* curl{nullptr}; + bool init{false}; +} curl; + +//----------------------------------------------------------------------------// +static io_bool_t unload_curl(const io_logging_i* io_logging, bool error = false) +{ + if (error) + common::log_message(io_logging, "Failed to load CURL library!"); + + if (curl.curl) + common::unload_library(curl.curl); + + memset(&curl, 0, sizeof(curl)); + return !error; +}; + +//----------------------------------------------------------------------------// +static io_bool_t load_curl(const io_logging_i* io_logging) +{ + if (curl.init) + return true; + +#ifdef _WIN32 + curl.curl = common::load_library("libcurl-x64"); +#else + curl.curl = common::load_library("libcurl.so.4"); +#endif + + if (!curl.curl) + return unload_curl(io_logging, true); + +#define LOAD_FUNCTION(_function) \ + curl._function = \ + (curl_t::pfn_##_function)common::load_function(curl.curl, #_function); \ + if (!curl._function) \ + return unload_curl(io_logging, true); + + LOAD_FUNCTION(curl_easy_init); + LOAD_FUNCTION(curl_easy_setopt); + LOAD_FUNCTION(curl_easy_perform); + LOAD_FUNCTION(curl_easy_cleanup); + + LOAD_FUNCTION(curl_slist_append); + LOAD_FUNCTION(curl_slist_free_all); + + LOAD_FUNCTION(curl_global_init); + LOAD_FUNCTION(curl_global_cleanup); + +#undef LOAD_FUNCTION + + return true; +}; + +} // namespace libraries \ No newline at end of file