updated build system
This commit is contained in:
		
							
								
								
									
										5
									
								
								support/3rd_party/src/backward.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								support/3rd_party/src/backward.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,3 @@ | ||||
| #if defined(PROJECT_ENABLE_BACKWARD_CPP) | ||||
| // Pick your poison. | ||||
| // | ||||
| // On GNU/Linux, you have few choices to get the most out of your stack trace. | ||||
| @@ -33,12 +32,14 @@ | ||||
| // - apt-get install libunwind-dev | ||||
| // - g++/clang++ -lunwind | ||||
| // #define BACKWARD_HAS_LIBUNWIND 1 | ||||
|  | ||||
| #include "backward.hpp" | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_BACKWARD_CPP) | ||||
|  | ||||
| namespace backward { | ||||
|  | ||||
| backward::SignalHandling sh; | ||||
|  | ||||
| } // namespace backward | ||||
|  | ||||
| #endif // defined(PROJECT_ENABLE_BACKWARD_CPP) | ||||
|   | ||||
							
								
								
									
										169
									
								
								support/3rd_party/src/utils/common.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								support/3rd_party/src/utils/common.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/common.hpp" | ||||
|  | ||||
| #include "utils/string.hpp" | ||||
|  | ||||
| namespace repertory::utils { | ||||
| auto compare_version_strings(std::string version1, | ||||
|                              std::string version2) -> std::int32_t { | ||||
|  | ||||
|   if (utils::string::contains(version1, "-")) { | ||||
|     version1 = utils::string::split(version1, '-', true)[0U]; | ||||
|   } | ||||
|  | ||||
|   if (utils::string::contains(version2, "-")) { | ||||
|     version2 = utils::string::split(version2, '-', true)[0U]; | ||||
|   } | ||||
|  | ||||
|   auto nums1 = utils::string::split(version1, '.', true); | ||||
|   auto nums2 = utils::string::split(version2, '.', true); | ||||
|  | ||||
|   while (nums1.size() > nums2.size()) { | ||||
|     nums2.emplace_back("0"); | ||||
|   } | ||||
|  | ||||
|   while (nums2.size() > nums1.size()) { | ||||
|     nums1.emplace_back("0"); | ||||
|   } | ||||
|  | ||||
|   for (std::size_t idx = 0U; idx < nums1.size(); idx++) { | ||||
|     auto int1 = utils::string::to_uint32(nums1[idx]); | ||||
|     auto int2 = utils::string::to_uint32(nums2[idx]); | ||||
|     auto res = std::memcmp(&int1, &int2, sizeof(int1)); | ||||
|     if (res != 0) { | ||||
|       return res; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| auto compare_version_strings(std::wstring_view version1, | ||||
|                              std::wstring_view version2) -> std::int32_t { | ||||
|   return compare_version_strings(utils::string::to_utf8(version1), | ||||
|                                  utils::string::to_utf8(version2)); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_STDUUID) | ||||
| auto create_uuid_string() -> std::string { | ||||
|   std::random_device random_device; | ||||
|   auto seed_data = std::array<int, std::mt19937::state_size>{}; | ||||
|   std::generate(std::begin(seed_data), std::end(seed_data), | ||||
|                 std::ref(random_device)); | ||||
|   std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); | ||||
|   std::mt19937 generator(seq); | ||||
|   uuids::uuid_random_generator gen{generator}; | ||||
|  | ||||
|   return uuids::to_string(gen()); | ||||
| } | ||||
|  | ||||
| auto create_uuid_wstring() -> std::wstring { | ||||
|   return utils::string::from_utf8(create_uuid_string()); | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_STDUUID) | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto generate_random_string(std::uint16_t length) -> std::string { | ||||
|   std::string ret; | ||||
|   ret.resize(length); | ||||
|   for (std::uint16_t i = 0U; i < length; i++) { | ||||
|     do { | ||||
|       ret[i] = static_cast<char>(generate_random<std::uint8_t>() % 74 + 48); | ||||
|     } while (((ret[i] >= 91) && (ret[i] <= 96)) || | ||||
|              ((ret[i] >= 58) && (ret[i] <= 64))); | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|  | ||||
| auto get_environment_variable(std::string_view variable) -> std::string { | ||||
|   static std::mutex mtx{}; | ||||
|   mutex_lock lock{mtx}; | ||||
|  | ||||
|   const auto *val = std::getenv(std::string{variable}.c_str()); | ||||
|   return std::string{val == nullptr ? "" : val}; | ||||
| } | ||||
|  | ||||
| auto get_environment_variable(std::wstring_view variable) -> std::wstring { | ||||
|   return utils::string::from_utf8( | ||||
|       get_environment_variable(utils::string::to_utf8(variable))); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_BOOST) | ||||
| auto get_next_available_port(std::uint16_t first_port, | ||||
|                              std::uint16_t &available_port) -> bool { | ||||
|   using namespace boost::asio; | ||||
|   using ip::tcp; | ||||
|  | ||||
|   boost::system::error_code error_code{}; | ||||
|   while (first_port != 0U) { | ||||
|     io_service svc{}; | ||||
|     tcp::acceptor acceptor(svc); | ||||
|     acceptor.open(tcp::v4(), error_code) || | ||||
|         acceptor.bind({tcp::v4(), first_port}, error_code); | ||||
|     if (not error_code) { | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     ++first_port; | ||||
|   } | ||||
|  | ||||
|   if (not error_code) { | ||||
|     available_port = first_port; | ||||
|   } | ||||
|  | ||||
|   return not error_code; | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_BOOST) | ||||
|  | ||||
| auto resolve_variables(std::string str) -> std::string { | ||||
| #if defined(HAS_WORDEXP_H) | ||||
|   wordexp_t wt{}; | ||||
|   int ret{}; | ||||
|   if ((ret = wordexp(std::string{str}.c_str(), &wt, 0)) != 0) { | ||||
|     throw std::runtime_error("'wordexp()' failed|" + std::to_string(ret)); | ||||
|   } | ||||
|   str = wt.we_wordv[0U]; | ||||
|   wordfree(&wt); | ||||
| #else  // !defined(HAS_WORDEXP_H) | ||||
|   std::string dest; | ||||
|   dest.resize(::ExpandEnvironmentStringsA(str.c_str(), nullptr, 0)); | ||||
|   ::ExpandEnvironmentStringsA(str.c_str(), dest.data(), | ||||
|                               static_cast<DWORD>(dest.size())); | ||||
|   str = std::string(dest.c_str(), strlen(dest.c_str())); | ||||
|  | ||||
|   dest.resize(::GetFullPathNameA(str.c_str(), 0, nullptr, nullptr)); | ||||
|   ::GetFullPathNameA(str.c_str(), static_cast<DWORD>(dest.size()), dest.data(), | ||||
|                      nullptr); | ||||
|   str = std::string(dest.c_str(), strlen(dest.c_str())); | ||||
| #endif // defined(HAS_WORDEXP_H) | ||||
|  | ||||
|   return str; | ||||
| } | ||||
|  | ||||
| auto resolve_variables(std::wstring_view str) -> std::wstring { | ||||
|   return utils::string::from_utf8( | ||||
|       resolve_variables(utils::string::to_utf8(str))); | ||||
| } | ||||
| } // namespace repertory::utils | ||||
							
								
								
									
										103
									
								
								support/3rd_party/src/utils/encryption.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								support/3rd_party/src/utils/encryption.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/encryption.hpp" | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|  | ||||
| namespace { | ||||
| using nonce_t = | ||||
|     std::array<unsigned char, crypto_aead_xchacha20poly1305_ietf_NPUBBYTES>; | ||||
|  | ||||
| static constexpr const auto nonce_size{sizeof(nonce_t)}; | ||||
|  | ||||
| [[nodiscard]] static auto create_hash_256(std::string_view data) | ||||
|     -> repertory::utils::encryption::hash_256_t { | ||||
|   repertory::utils::encryption::hash_256_t hash{}; | ||||
|  | ||||
|   crypto_generichash_blake2b_state state{}; | ||||
|   crypto_generichash_blake2b_init(&state, nullptr, 0U, hash.size()); | ||||
|   crypto_generichash_blake2b_update( | ||||
|       &state, reinterpret_cast<const unsigned char *>(data.data()), | ||||
|       data.size()); | ||||
|   crypto_generichash_blake2b_final(&state, hash.data(), hash.size()); | ||||
|  | ||||
|   return hash; | ||||
| } | ||||
| } // namespace | ||||
|  | ||||
| namespace repertory::utils::encryption { | ||||
| auto decrypt_data(std::string_view data, std::string_view password, | ||||
|                   std::optional<hash_256_func_t> hasher) -> data_buffer { | ||||
|   auto key = | ||||
|       hasher.has_value() ? (*hasher)(password) : create_hash_256(password); | ||||
|  | ||||
|   data_buffer buf{}; | ||||
|   if (not decrypt_data(key, | ||||
|                        reinterpret_cast<const unsigned char *>(data.data()), | ||||
|                        data.size(), buf)) { | ||||
|     throw std::runtime_error("decryption failed"); | ||||
|   } | ||||
|  | ||||
|   return buf; | ||||
| } | ||||
|  | ||||
| auto encrypt_data(std::string_view data, std::string_view password, | ||||
|                   std::optional<hash_256_func_t> hasher) -> data_buffer { | ||||
|   auto key = | ||||
|       hasher.has_value() ? (*hasher)(password) : create_hash_256(password); | ||||
|  | ||||
|   data_buffer buf{}; | ||||
|   if (not encrypt_data(key, | ||||
|                        reinterpret_cast<const unsigned char *>(data.data()), | ||||
|                        data.size(), buf)) { | ||||
|     throw std::runtime_error("encryption failed"); | ||||
|   } | ||||
|  | ||||
|   return buf; | ||||
| } | ||||
|  | ||||
| auto generate_key(std::string_view encryption_token) -> key_type { | ||||
|   crypto_hash_sha256_state state{}; | ||||
|   auto res = crypto_hash_sha256_init(&state); | ||||
|   if (res != 0) { | ||||
|     throw std::runtime_error("failed to initialize sha256|" + | ||||
|                              std::to_string(res)); | ||||
|   } | ||||
|   res = crypto_hash_sha256_update( | ||||
|       &state, reinterpret_cast<const unsigned char *>(encryption_token.data()), | ||||
|       encryption_token.size()); | ||||
|   if (res != 0) { | ||||
|     throw std::runtime_error("failed to update sha256|" + std::to_string(res)); | ||||
|   } | ||||
|  | ||||
|   key_type ret{}; | ||||
|   res = crypto_hash_sha256_final(&state, ret.data()); | ||||
|   if (res != 0) { | ||||
|     throw std::runtime_error("failed to finalize sha256|" + | ||||
|                              std::to_string(res)); | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
| } // namespace repertory::utils::encryption | ||||
|  | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
							
								
								
									
										71
									
								
								support/3rd_party/src/utils/error.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								support/3rd_party/src/utils/error.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/error.hpp" | ||||
|  | ||||
| namespace { | ||||
| struct default_exception_handler final | ||||
|     : repertory::utils::error::i_exception_handler { | ||||
|   void handle_exception(std::string_view function_name) const override { | ||||
|     std::cerr << function_name << "|exception|unknown" << std::endl; | ||||
|   } | ||||
|  | ||||
|   void handle_exception(std::string_view function_name, | ||||
|                         const std::exception &ex) const override { | ||||
|     std::cerr << function_name << "|exception|" | ||||
|               << (ex.what() == nullptr ? "unknown" : ex.what()) << std::endl; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| static default_exception_handler default_handler{}; | ||||
|  | ||||
| static std::atomic<repertory::utils::error::i_exception_handler *> | ||||
|     exception_handler{ | ||||
|         &default_handler, | ||||
|     }; | ||||
| } // namespace | ||||
|  | ||||
| namespace repertory::utils::error { | ||||
| void handle_exception(std::string_view function_name) { | ||||
|   i_exception_handler *handler{exception_handler}; | ||||
|   if (handler != nullptr) { | ||||
|     handler->handle_exception(function_name); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   default_handler.handle_exception(function_name); | ||||
| } | ||||
|  | ||||
| void handle_exception(std::string_view function_name, | ||||
|                       const std::exception &ex) { | ||||
|   i_exception_handler *handler{exception_handler}; | ||||
|   if (handler != nullptr) { | ||||
|     handler->handle_exception(function_name, ex); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   default_handler.handle_exception(function_name, ex); | ||||
| } | ||||
|  | ||||
| void set_exception_handler(i_exception_handler *handler) { | ||||
|   exception_handler = handler; | ||||
| } | ||||
| } // namespace repertory::utils::error | ||||
							
								
								
									
										366
									
								
								support/3rd_party/src/utils/file.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								support/3rd_party/src/utils/file.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,366 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/file.hpp" | ||||
|  | ||||
| #include "utils/encryption.hpp" | ||||
| #include "utils/error.hpp" | ||||
| #include "utils/path.hpp" | ||||
| #include "utils/string.hpp" | ||||
|  | ||||
| namespace repertory::utils::file { | ||||
| auto file::open_file(std::filesystem::path path) -> file { | ||||
|   path = utils::path::absolute(path.string()); | ||||
|   if (not is_file(path.string())) { | ||||
|     throw std::runtime_error("file not found: " + path.string()); | ||||
|   } | ||||
|  | ||||
|   auto stream = std::fstream{ | ||||
|       path, | ||||
|       std::ios_base::binary | std::ios_base::in | std::ios_base::out, | ||||
|   }; | ||||
|   return { | ||||
|       std::move(stream), | ||||
|       path, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| auto file::open_or_create_file(std::filesystem::path path) -> file { | ||||
|   path = utils::path::absolute(path.string()); | ||||
|   auto stream = std::fstream{ | ||||
|       path.string().c_str(), | ||||
|       std::ios_base::binary | std::ios_base::trunc | std::ios_base::in | | ||||
|           std::ios_base::out, | ||||
|   }; | ||||
|  | ||||
|   return { | ||||
|       std::move(stream), | ||||
|       path, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| void file::close() { | ||||
|   if (stream_.is_open()) { | ||||
|     stream_.close(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| auto file::move_to(std::filesystem::path new_path) -> bool { | ||||
|   new_path = utils::path::absolute(new_path.string()); | ||||
|  | ||||
|   auto reopen{false}; | ||||
|   if (stream_.is_open()) { | ||||
|     reopen = true; | ||||
|     close(); | ||||
|   } | ||||
|  | ||||
|   std::filesystem::rename(path_, new_path, error_); | ||||
|   if (not error_) { | ||||
|     path_ = new_path; | ||||
|     if (reopen) { | ||||
|       *this = std::move(open_file(path_)); | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (reopen) { | ||||
|     *this = std::move(open_file(path_)); | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| auto file::read(unsigned char *data, std::size_t to_read, std::uint64_t offset, | ||||
|                 std::size_t *total_read) -> bool { | ||||
|   static constexpr const std::string_view function_name{ | ||||
|       static_cast<const char *>(__FUNCTION__), | ||||
|   }; | ||||
|  | ||||
|   if (total_read != nullptr) { | ||||
|     (*total_read) = 0U; | ||||
|   } | ||||
|  | ||||
|   try { | ||||
|     stream_.seekg(static_cast<std::streamoff>(offset)); | ||||
|  | ||||
|     auto before = stream_.tellg(); | ||||
|     if (before == -1) { | ||||
|       throw std::runtime_error("failed to tellg() before read"); | ||||
|     } | ||||
|  | ||||
|     stream_.read(reinterpret_cast<char *>(data), | ||||
|                  static_cast<std::streamoff>(to_read)); | ||||
|     if (total_read != nullptr) { | ||||
|       auto after = stream_.tellg(); | ||||
|       if (after == -1) { | ||||
|         throw std::runtime_error("failed to tellg() after read"); | ||||
|       } | ||||
|       (*total_read) = static_cast<std::size_t>(after - before); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } catch (const std::exception &e) { | ||||
|     utils::error::handle_exception(function_name, e); | ||||
|   } catch (...) { | ||||
|     utils::error::handle_exception(function_name); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| auto file::remove() -> bool { | ||||
|   close(); | ||||
|   return std::filesystem::remove(path_, error_); | ||||
| } | ||||
|  | ||||
| auto file::truncate(std::size_t size) -> bool { | ||||
|   auto reopen{false}; | ||||
|   if (stream_.is_open()) { | ||||
|     reopen = true; | ||||
|     close(); | ||||
|   } | ||||
|  | ||||
|   std::filesystem::resize_file(path_, size, error_); | ||||
|   if (reopen) { | ||||
|     *this = std::move(open_file(path_)); | ||||
|   } | ||||
|  | ||||
|   return not error_; | ||||
| } | ||||
|  | ||||
| auto file::write(const typename data_buffer::value_type *data, | ||||
|                  std::size_t to_write, std::size_t offset, | ||||
|                  std::size_t *total_written) -> bool { | ||||
|   static constexpr const std::string_view function_name{ | ||||
|       static_cast<const char *>(__FUNCTION__), | ||||
|   }; | ||||
|  | ||||
|   if (total_written != nullptr) { | ||||
|     (*total_written) = 0U; | ||||
|   } | ||||
|  | ||||
|   try { | ||||
|     stream_.seekp(static_cast<std::streamoff>(offset)); | ||||
|     auto before = stream_.tellp(); | ||||
|     if (before == -1) { | ||||
|       throw std::runtime_error("failed to tellp() before write"); | ||||
|     } | ||||
|  | ||||
|     stream_.write(reinterpret_cast<const char *>(data), | ||||
|                   static_cast<std::streamoff>(to_write)); | ||||
|  | ||||
|     auto after = stream_.tellp(); | ||||
|     if (after == -1) { | ||||
|       throw std::runtime_error("failed to tellp() after write"); | ||||
|     } | ||||
|  | ||||
|     if (total_written != nullptr) { | ||||
|       (*total_written) = static_cast<std::size_t>(after - before); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } catch (const std::exception &e) { | ||||
|     utils::error::handle_exception(function_name, e); | ||||
|   } catch (...) { | ||||
|     utils::error::handle_exception(function_name); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| auto get_file_size(std::string_view path, std::uint64_t &file_size) -> bool { | ||||
|   auto abs_path = utils::path::absolute(path); | ||||
|  | ||||
|   file_size = 0U; | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   struct _stat64 st {}; | ||||
|   if (_stat64(abs_path.c_str(), &st) != 0) { | ||||
| #else  // !defined(_WIN32) | ||||
|   struct stat st {}; | ||||
|   if (stat(abs_path.c_str(), &st) != 0) { | ||||
| #endif // defined(_WIN32) | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (st.st_size >= 0) { | ||||
|     file_size = static_cast<std::uint64_t>(st.st_size); | ||||
|   } | ||||
|  | ||||
|   return (st.st_size >= 0); | ||||
| } | ||||
|  | ||||
| auto get_file_size(std::wstring_view path, std::uint64_t &file_size) -> bool { | ||||
|   return get_file_size(utils::string::to_utf8(path), file_size); | ||||
| } | ||||
|  | ||||
| auto is_directory(std::string_view path) -> bool { | ||||
|   auto abs_path = utils::path::absolute(path); | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   return ::PathIsDirectory(abs_path.c_str()) != 0; | ||||
| #else  // !defined(_WIN32) | ||||
|   struct stat st {}; | ||||
|   return (stat(abs_path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)); | ||||
| #endif // defined(_WIN32) | ||||
| } | ||||
|  | ||||
| auto is_directory(std::wstring_view path) -> bool { | ||||
|   return is_directory(utils::string::to_utf8(path)); | ||||
| } | ||||
|  | ||||
| auto is_file(std::string_view path) -> bool { | ||||
|   auto abs_path = utils::path::absolute(path); | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   return (::PathFileExists(abs_path.c_str()) && | ||||
|           not ::PathIsDirectory(abs_path.c_str())); | ||||
| #else  // !defined(_WIN32) | ||||
|   struct stat st {}; | ||||
|   return (stat(abs_path.c_str(), &st) == 0 && not S_ISDIR(st.st_mode)); | ||||
| #endif // defined(_WIN32) | ||||
| } | ||||
|  | ||||
| auto is_file(std::wstring_view path) -> bool { | ||||
|   return is_file(utils::string::to_utf8(path)); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_JSON) | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto read_json_file(std::string_view path, nlohmann::json &data, | ||||
|                     std::optional<std::string_view> password) -> bool { | ||||
| #else  // !defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto read_json_file(std::string_view path, nlohmann::json &data) -> bool { | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|   static constexpr const std::string_view function_name{ | ||||
|       static_cast<const char *>(__FUNCTION__), | ||||
|   }; | ||||
|  | ||||
|   try { | ||||
|     auto abs_path = utils::path::absolute(path); | ||||
|     std::ifstream file_stream{ | ||||
|         abs_path.c_str(), | ||||
|         std::ios_base::binary | std::ios::in, | ||||
|     }; | ||||
|     if (not file_stream.is_open()) { | ||||
|       throw std::runtime_error("failed to open file: " + abs_path); | ||||
|     } | ||||
|  | ||||
|     auto ret{true}; | ||||
|     try { | ||||
|       std::stringstream stream; | ||||
|       stream << file_stream.rdbuf(); | ||||
|  | ||||
|       auto json_text = stream.str(); | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|       if (password.has_value()) { | ||||
|         auto data = utils::encryption::decrypt_data(json_text, *password); | ||||
|         json_text = {data.begin(), data.end()}; | ||||
|       } | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|       if (not json_text.empty()) { | ||||
|         data = nlohmann::json::parse(json_text.c_str()); | ||||
|       } | ||||
|     } catch (const std::exception &e) { | ||||
|       utils::error::handle_exception(function_name, e); | ||||
|       ret = false; | ||||
|     } catch (...) { | ||||
|       utils::error::handle_exception(function_name); | ||||
|       ret = false; | ||||
|     } | ||||
|  | ||||
|     file_stream.close(); | ||||
|     return ret; | ||||
|   } catch (const std::exception &e) { | ||||
|     utils::error::handle_exception(function_name, e); | ||||
|   } catch (...) { | ||||
|     utils::error::handle_exception(function_name); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto write_json_file(std::string_view path, const nlohmann::json &data, | ||||
|                      std::optional<std::string_view> password) -> bool { | ||||
| #else  // !defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto write_json_file(std::string_view path, | ||||
|                      const nlohmann::json &data) -> bool { | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|   static constexpr const std::string_view function_name{ | ||||
|       static_cast<const char *>(__FUNCTION__), | ||||
|   }; | ||||
|  | ||||
|   try { | ||||
|     auto file = file::open_or_create_file(path); | ||||
|     if (not file.truncate()) { | ||||
|       throw std::runtime_error("failed to truncate file: " + | ||||
|                                file.get_error_code().message()); | ||||
|     } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|     if (password.has_value()) { | ||||
|       return file.write(utils::encryption::encrypt_data(data.dump(), *password), | ||||
|                         0U); | ||||
|     } | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
|  | ||||
|     return file.write(data, 0U); | ||||
|   } catch (const std::exception &e) { | ||||
|     utils::error::handle_exception(function_name, e); | ||||
|   } catch (...) { | ||||
|     utils::error::handle_exception(function_name); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto read_json_file(std::wstring_view path, nlohmann::json &data, | ||||
|                     std::optional<std::wstring_view> password) -> bool { | ||||
|   if (password.has_value()) { | ||||
|     auto password_a = utils::string::to_utf8(*password); | ||||
|     return read_json_file(utils::string::to_utf8(path), data, password_a); | ||||
|   } | ||||
|  | ||||
|   return read_json_file(utils::string::to_utf8(path), data, std::nullopt); | ||||
| } | ||||
|  | ||||
| auto write_json_file(std::wstring_view path, const nlohmann::json &data, | ||||
|                      std::optional<std::wstring_view> password) -> bool { | ||||
|   if (password.has_value()) { | ||||
|     auto password_a = utils::string::to_utf8(*password); | ||||
|     return write_json_file(utils::string::to_utf8(path), data, password_a); | ||||
|   } | ||||
|  | ||||
|   return write_json_file(utils::string::to_utf8(path), data, std::nullopt); | ||||
| } | ||||
| #else  // !defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| auto read_json_file(std::wstring_view path, nlohmann::json &data) -> bool { | ||||
|   return read_json_file(utils::string::to_utf8(path), data); | ||||
| } | ||||
|  | ||||
| auto write_json_file(std::wstring_view path, | ||||
|                      const nlohmann::json &data) -> bool { | ||||
|   return write_json_file(utils::string::to_utf8(path), data); | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_LIBSODIUM) | ||||
| #endif // defined(PROJECT_ENABLE_JSON) | ||||
| } // namespace repertory::utils::file | ||||
							
								
								
									
										225
									
								
								support/3rd_party/src/utils/path.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								support/3rd_party/src/utils/path.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,225 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/path.hpp" | ||||
|  | ||||
| #include "utils/common.hpp" | ||||
| #include "utils/string.hpp" | ||||
| #include "utils/unix.hpp" | ||||
|  | ||||
| namespace { | ||||
| static const std::string directory_seperator_str{ | ||||
|     repertory::utils::path::directory_seperator, | ||||
| }; | ||||
|  | ||||
| static const std::wstring directory_seperator_str_w{ | ||||
|     repertory::utils::path::directory_seperator_w, | ||||
| }; | ||||
| } // namespace | ||||
|  | ||||
| namespace repertory::utils::path { | ||||
| auto find_program_in_path(const std::string &name_without_extension) | ||||
|     -> std::string { | ||||
|   static std::mutex mtx{}; | ||||
|   static std::unordered_map<std::string, std::string> found_items{}; | ||||
|  | ||||
|   mutex_lock lock(mtx); | ||||
|   if (found_items.contains(name_without_extension)) { | ||||
|     return found_items.at(name_without_extension); | ||||
|   } | ||||
|  | ||||
|   auto path = utils::get_environment_variable("PATH"); | ||||
|   if (path.empty()) { | ||||
|     return path; | ||||
|   } | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   static constexpr const std::array<std::string_view, 4U> extension_list{ | ||||
|       ".bat", | ||||
|       ".cmd", | ||||
|       ".exe", | ||||
|       ".ps1", | ||||
|   }; | ||||
|   static constexpr const auto split_char = ';'; | ||||
| #else  // !defined(_WIN32) | ||||
|   static constexpr const std::array<std::string_view, 2U> extension_list{ | ||||
|       "", | ||||
|       ".sh", | ||||
|   }; | ||||
|   static constexpr const auto split_char = ':'; | ||||
| #endif // defined(_WIN32) | ||||
|  | ||||
|   const auto search_path_list = utils::string::split(path, split_char, false); | ||||
|   for (auto &&search_path : search_path_list) { | ||||
|     for (auto &&extension : extension_list) { | ||||
|       auto exec_path = combine( | ||||
|           search_path, {name_without_extension + std::string{extension}}); | ||||
|       if (std::filesystem::exists(exec_path)) { | ||||
|         found_items[name_without_extension] = exec_path; | ||||
|         return exec_path; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ""; | ||||
| } | ||||
|  | ||||
| [[nodiscard]] auto | ||||
| find_program_in_path(std::wstring_view name_without_extension) -> std::wstring { | ||||
|   return utils::string::from_utf8( | ||||
|       find_program_in_path(utils::string::to_utf8(name_without_extension))); | ||||
| } | ||||
|  | ||||
| auto get_parent_directory(std::string_view path) -> std::string { | ||||
|   auto ret = std::filesystem::path{path}.parent_path().string(); | ||||
| #if !defined(_WIN32) | ||||
|   if (ret == ".") { | ||||
|     ret = "/"; | ||||
|   } | ||||
| #endif // !defined(_WIN32) | ||||
|  | ||||
|   return absolute(ret); | ||||
| } | ||||
|  | ||||
| auto get_parent_directory(std::wstring_view path) -> std::wstring { | ||||
|   return utils::string::from_utf8( | ||||
|       get_parent_directory(utils::string::to_utf8(path))); | ||||
| } | ||||
|  | ||||
| auto is_trash_directory(std::string_view path) -> bool { | ||||
|   auto trash_path = utils::string::to_lower(absolute(path)); | ||||
|   return utils::string::begins_with(trash_path, | ||||
|                                     directory_seperator_str + ".trash-") || | ||||
|          utils::string::begins_with(trash_path, | ||||
|                                     directory_seperator_str + ".trashes") || | ||||
|          utils::string::begins_with(trash_path, | ||||
|                                     directory_seperator_str + "$recycle.bin"); | ||||
| } | ||||
|  | ||||
| auto is_trash_directory(std::wstring_view path) -> bool { | ||||
|   auto trash_path = utils::string::to_lower(absolute(path)); | ||||
|   return utils::string::begins_with(trash_path, | ||||
|                                     directory_seperator_str_w + L".trash-") || | ||||
|          utils::string::begins_with(trash_path, | ||||
|                                     directory_seperator_str_w + L".trashes") || | ||||
|          utils::string::begins_with(trash_path, directory_seperator_str_w + | ||||
|                                                     L"$recycle.bin"); | ||||
| } | ||||
|  | ||||
| auto make_file_uri(std::string_view path) -> std::string { | ||||
|   auto abs_path = absolute(path); | ||||
| #if defined(_WIN32) | ||||
|   utils::string::replace(abs_path, '\\', '/'); | ||||
|   abs_path = '/' + abs_path; | ||||
| #endif // defined(_WIN32) | ||||
|   return "file://" + abs_path; | ||||
| } | ||||
|  | ||||
| auto make_file_uri(std::wstring_view path) -> std::wstring { | ||||
|   return utils::string::from_utf8(make_file_uri(utils::string::to_utf8(path))); | ||||
| } | ||||
|  | ||||
| auto remove_file_name(std::string_view path) -> std::string { | ||||
|   auto abs_path = absolute(path); | ||||
|  | ||||
| #if defined(_WIN32) | ||||
|   ::PathRemoveFileSpec(abs_path.data()); | ||||
|   abs_path = abs_path.c_str(); | ||||
| #else  // !defined(_WIN32) | ||||
|   if (abs_path != "/") { | ||||
|     auto idx{abs_path.size() - 1U}; | ||||
|     while ((idx != 0U) && (abs_path.at(idx) != '/')) { | ||||
|       idx--; | ||||
|     } | ||||
|  | ||||
|     abs_path = (idx > 0U) ? absolute(abs_path.substr(0U, idx)) : "/"; | ||||
|   } | ||||
| #endif // defined(_WIN32) | ||||
|  | ||||
|   return abs_path; | ||||
| } | ||||
|  | ||||
| #if !defined(_WIN32) | ||||
| auto resolve(std::string path) -> std::string { | ||||
|   std::string home{}; | ||||
|   use_getpwuid(getuid(), [&home](struct passwd *pw) { | ||||
|     home = (pw->pw_dir ? pw->pw_dir : ""); | ||||
|     if (home.empty() || ((home == "/") && (getuid() != 0))) { | ||||
|       home = combine("/home", {pw->pw_name}); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   return absolute(utils::string::replace(path, "~", home)); | ||||
| } | ||||
|  | ||||
| auto resolve(std::wstring_view path) -> std::wstring { | ||||
|   return utils::string::from_utf8(resolve(utils::string::to_utf8(path))); | ||||
| } | ||||
| #endif // !defined(_WIN32) | ||||
|  | ||||
| auto strip_to_file_name(std::string path) -> std::string { | ||||
| #if defined(_WIN32) | ||||
|   return ::PathFindFileName(path.c_str()); | ||||
| #else | ||||
|   return utils::string::contains(path, "/") ? basename(path.data()) : path; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| auto unmake_file_uri(std::string_view uri) -> std::string { | ||||
|   static constexpr const std::array<std::string_view, 23U> escape_characters = { | ||||
|       { | ||||
|           " ", "<", ">", "#", "%", "+", "{", "}", "|", "\\", "^", "~", | ||||
|           "[", "]", "`", ";", "/", "?", ":", "@", "=", "&",  "$", | ||||
|       }}; | ||||
|   static constexpr const std::array<std::string_view, 23U> | ||||
|       escape_sequences_lower = {{ | ||||
|           "%20", "%3c", "%3e", "%23", "%25", "%2b", "%7b", "%7d", | ||||
|           "%7c", "%5c", "%5e", "%7e", "%5b", "%5d", "%60", "%3b", | ||||
|           "%2f", "%3f", "%3a", "%40", "%3d", "%26", "%24", | ||||
|       }}; | ||||
|   static constexpr const std::array<std::string_view, 23U> | ||||
|       escape_sequences_upper = {{ | ||||
|           "%20", "%3C", "%3E", "%23", "%25", "%2B", "%7B", "%7D", | ||||
|           "%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60", "%3B", | ||||
|           "%2F", "%3F", "%3A", "%40", "%3D", "%26", "%24", | ||||
|       }}; | ||||
|  | ||||
|   std::string ret_uri{uri}; | ||||
| #if defined(_WIN32) | ||||
|   ret_uri = ret_uri.substr(8U); | ||||
| #else | ||||
|   ret_uri = ret_uri.substr(7U); | ||||
| #endif | ||||
|  | ||||
|   for (std::size_t idx = 0U; idx < escape_characters.size(); idx++) { | ||||
|     utils::string::replace(ret_uri, escape_sequences_lower.at(idx), | ||||
|                            escape_characters.at(idx)); | ||||
|     utils::string::replace(ret_uri, escape_sequences_upper.at(idx), | ||||
|                            escape_characters.at(idx)); | ||||
|   } | ||||
|  | ||||
|   return absolute(uri); | ||||
| } | ||||
|  | ||||
| auto unmake_file_uri(std::wstring_view uri) -> std::wstring { | ||||
|   return utils::string::from_utf8(unmake_file_uri(utils::string::to_utf8(uri))); | ||||
| } | ||||
| } // namespace repertory::utils::path | ||||
							
								
								
									
										138
									
								
								support/3rd_party/src/utils/string.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								support/3rd_party/src/utils/string.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/string.hpp" | ||||
|  | ||||
| namespace repertory::utils::string { | ||||
| auto from_bool(bool val) -> std::string { | ||||
|   return std::to_string(static_cast<int>(val)); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_BOOST) | ||||
| auto from_dynamic_bitset(const boost::dynamic_bitset<> &bitset) -> std::string { | ||||
|   std::stringstream stream; | ||||
|   boost::archive::text_oarchive archive(stream); | ||||
|   archive << bitset; | ||||
|   return stream.str(); | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_BOOST) | ||||
|  | ||||
| auto from_utf8(std::string_view str) -> std::wstring { | ||||
|   return str.empty() | ||||
|              ? L"" | ||||
|              : std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>() | ||||
|                    .from_bytes(std::string{str}); | ||||
| } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_SFML) | ||||
| auto replace_sf(sf::String &src, const sf::String &find, const sf::String &with, | ||||
|                 std::size_t start_pos) -> sf::String & { | ||||
|   if (not src.isEmpty() && (start_pos < src.getSize())) { | ||||
|     while ((start_pos = src.find(find, start_pos)) != std::string::npos) { | ||||
|       src.replace(start_pos, find.getSize(), with); | ||||
|       start_pos += with.getSize(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return src; | ||||
| } | ||||
|  | ||||
| auto split_sf(sf::String str, wchar_t delim, | ||||
|               bool should_trim) -> std::vector<sf::String> { | ||||
|   auto result = std::views::split(str.toWideString(), delim); | ||||
|  | ||||
|   std::vector<sf::String> ret{}; | ||||
|   for (auto &&word : result) { | ||||
|     auto val = std::wstring{word.begin(), word.end()}; | ||||
|     if (should_trim) { | ||||
|       trim(val); | ||||
|     } | ||||
|     ret.emplace_back(val); | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_SFML) | ||||
|  | ||||
| auto to_bool(std::string val) -> bool { | ||||
|   auto ret = false; | ||||
|  | ||||
|   trim(val); | ||||
|   if (is_numeric(val)) { | ||||
|     if (contains(val, ".")) { | ||||
|       ret = (to_double(val) != 0.0); | ||||
|     } else { | ||||
|       std::istringstream(val) >> ret; | ||||
|     } | ||||
|   } else { | ||||
|     std::istringstream(to_lower(val)) >> std::boolalpha >> ret; | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| auto to_double(const std::string &str) -> double { return std::stod(str); } | ||||
|  | ||||
| #if defined(PROJECT_ENABLE_BOOST) | ||||
| auto to_dynamic_bitset(const std::string &val) -> boost::dynamic_bitset<> { | ||||
|   std::stringstream stream(val); | ||||
|   boost::dynamic_bitset<> bitset; | ||||
|   boost::archive::text_iarchive archive(stream); | ||||
|   archive >> bitset; | ||||
|   return bitset; | ||||
| } | ||||
| #endif // defined(PROJECT_ENABLE_BOOST) | ||||
|  | ||||
| auto to_int32(const std::string &val) -> std::int32_t { return std::stoi(val); } | ||||
|  | ||||
| auto to_int64(const std::string &val) -> std::int64_t { | ||||
|   return std::stoll(val); | ||||
| } | ||||
|  | ||||
| auto to_size_t(const std::string &val) -> std::size_t { | ||||
|   return static_cast<std::size_t>(std::stoull(val)); | ||||
| } | ||||
|  | ||||
| auto to_uint8(const std::string &val) -> std::uint8_t { | ||||
|   return static_cast<std::uint8_t>(std::stoul(val)); | ||||
| } | ||||
|  | ||||
| auto to_uint16(const std::string &val) -> std::uint16_t { | ||||
|   return static_cast<std::uint16_t>(std::stoul(val)); | ||||
| } | ||||
|  | ||||
| auto to_uint32(const std::string &val) -> std::uint32_t { | ||||
|   return static_cast<std::uint32_t>(std::stoul(val)); | ||||
| } | ||||
|  | ||||
| auto to_uint64(const std::string &val) -> std::uint64_t { | ||||
|   return std::stoull(val); | ||||
| } | ||||
|  | ||||
| auto to_utf8(std::string_view str) -> std::string { return std::string{str}; } | ||||
|  | ||||
| auto to_utf8(std::wstring_view str) -> std::string { | ||||
|   return str.empty() | ||||
|              ? "" | ||||
|              : std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>() | ||||
|                    .to_bytes(std::wstring{str}); | ||||
| } | ||||
| } // namespace repertory::utils::string | ||||
							
								
								
									
										107
									
								
								support/3rd_party/src/utils/time.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								support/3rd_party/src/utils/time.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #include "utils/time.hpp" | ||||
|  | ||||
| namespace repertory::utils::time { | ||||
| #if defined(_WIN32) | ||||
| // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ | ||||
| auto filetime_to_unix_time(const FILETIME &file_time) -> std::uint64_t { | ||||
|   LARGE_INTEGER date{}; | ||||
|   date.HighPart = static_cast<LONG>(file_time.dwHighDateTime); | ||||
|   date.LowPart = file_time.dwLowDateTime; | ||||
|   date.QuadPart -= 116444736000000000LL; | ||||
|  | ||||
|   return static_cast<std::uint64_t>(date.QuadPart) * 100ULL; | ||||
| } | ||||
| #endif // defined(_WIN32) | ||||
|  | ||||
| auto get_file_time_now() -> std::uint64_t { | ||||
| #if defined(_WIN32) | ||||
|   SYSTEMTIME sys_time{}; | ||||
|   ::GetSystemTime(&sys_time); | ||||
|  | ||||
|   FILETIME file_time{}; | ||||
|   ::SystemTimeToFileTime(&sys_time, &file_time); | ||||
|   return static_cast<std::uint64_t>( | ||||
|       (reinterpret_cast<LARGE_INTEGER *>(&file_time))->QuadPart); | ||||
| #else  // !defined(_WIN32) | ||||
|   return get_time_now(); | ||||
| #endif // defined(_WIN32) | ||||
| } | ||||
|  | ||||
| void get_local_time_now(struct tm &local_time) { | ||||
|   std::memset(&local_time, 0, sizeof(local_time)); | ||||
|  | ||||
|   const auto now = | ||||
|       std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); | ||||
| #if defined(_WIN32) | ||||
|   localtime_s(&local_time, &now); | ||||
| #else  // !defined(_WIN32) | ||||
|   localtime_r(&now, &local_time); | ||||
| #endif // defined(_WIN32) | ||||
| } | ||||
|  | ||||
| auto get_time_now() -> std::uint64_t { | ||||
| #if defined(_WIN32) | ||||
|   return static_cast<std::uint64_t>( | ||||
|       std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); | ||||
| #endif // defined(_WIN32) | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
|   return std::chrono::nanoseconds( | ||||
|              std::chrono::system_clock::now().time_since_epoch()) | ||||
|       .count(); | ||||
| #else  // !defined(__APPLE__) | ||||
|   return static_cast<std::uint64_t>( | ||||
|       std::chrono::nanoseconds( | ||||
|           std::chrono::high_resolution_clock::now().time_since_epoch()) | ||||
|           .count()); | ||||
| #endif // defined(__APPLE__) | ||||
| } | ||||
|  | ||||
| #if defined(_WIN32) | ||||
| // https://stackoverflow.com/questions/321849/strptime-equivalent-on-windows | ||||
| auto strptime(const char *s, const char *f, struct tm *tm) -> const char * { | ||||
|   std::istringstream input{s}; | ||||
|   input.imbue(std::locale(setlocale(LC_ALL, nullptr))); | ||||
|   input >> std::get_time(tm, f); | ||||
|   if (input.fail()) { | ||||
|     return nullptr; | ||||
|   } | ||||
|  | ||||
|   return reinterpret_cast<const char *>(s + input.tellg()); | ||||
| } | ||||
|  | ||||
| auto time64_to_unix_time(const __time64_t &time) -> std::uint64_t { | ||||
|   return static_cast<std::uint64_t>(time * NANOS_PER_SECOND); | ||||
| } | ||||
|  | ||||
| // https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ | ||||
| auto unix_time_to_filetime(std::uint64_t unix_time) -> FILETIME { | ||||
|   const auto win_time = (unix_time / 100ULL) + 116444736000000000ULL; | ||||
|   FILETIME file_time{}; | ||||
|   file_time.dwHighDateTime = static_cast<DWORD>(win_time >> 32U); | ||||
|   file_time.dwLowDateTime = win_time & 0xFFFFFFFF; | ||||
|   return file_time; | ||||
| } | ||||
| #endif // defined(_WIN32) | ||||
| } // namespace repertory::utils::time | ||||
							
								
								
									
										76
									
								
								support/3rd_party/src/utils/unix.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								support/3rd_party/src/utils/unix.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #if !defined(_WIN32) | ||||
|  | ||||
| #include "utils/unix.hpp" | ||||
| #include "utils/collection.hpp" | ||||
|  | ||||
| namespace repertory::utils { | ||||
| #if !defined(__APPLE__) | ||||
| auto convert_to_uint64(const pthread_t &thread) -> std::uint64_t { | ||||
|   return static_cast<std::uint64_t>(thread); | ||||
| } | ||||
| #endif // !defined(__APPLE__) | ||||
|  | ||||
| auto get_last_error_code() -> int { return errno; } | ||||
|  | ||||
| auto get_thread_id() -> std::uint64_t { | ||||
|   return convert_to_uint64(pthread_self()); | ||||
| } | ||||
|  | ||||
| auto is_uid_member_of_group(const uid_t &uid, const gid_t &gid) -> bool { | ||||
|   std::vector<gid_t> groups{}; | ||||
|   use_getpwuid(uid, [&groups](struct passwd *pass) { | ||||
|     int group_count{}; | ||||
|     if (getgrouplist(pass->pw_name, pass->pw_gid, nullptr, &group_count) < 0) { | ||||
|       groups.resize(static_cast<std::size_t>(group_count)); | ||||
| #if defined(__APPLE__) | ||||
|       getgrouplist(pass->pw_name, pass->pw_gid, | ||||
|                    reinterpret_cast<int *>(groups.data()), &group_count); | ||||
| #else  // !defined(__APPLE__) | ||||
|       getgrouplist(pass->pw_name, pass->pw_gid, groups.data(), &group_count); | ||||
| #endif // defined(__APPLE__) | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   return collection::includes(groups, gid); | ||||
| } | ||||
|  | ||||
| auto use_getpwuid(uid_t uid, passwd_callback_t callback) -> result { | ||||
|   static constexpr const std::string_view function_name{ | ||||
|       static_cast<const char *>(__FUNCTION__), | ||||
|   }; | ||||
|  | ||||
|   static std::mutex mtx{}; | ||||
|   mutex_lock lock{mtx}; | ||||
|  | ||||
|   auto *temp_pw = getpwuid(uid); | ||||
|   if (temp_pw == nullptr) { | ||||
|     return {function_name, false, "'getpwuid' returned nullptr"}; | ||||
|   } | ||||
|  | ||||
|   callback(temp_pw); | ||||
|   return {function_name}; | ||||
| } | ||||
| } // namespace repertory::utils | ||||
|  | ||||
| #endif // !defined(_WIN32) | ||||
							
								
								
									
										105
									
								
								support/3rd_party/src/utils/windows.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								support/3rd_party/src/utils/windows.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| /* | ||||
|   Copyright <2018-2024> <scott.e.graves@protonmail.com> | ||||
|  | ||||
|   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. | ||||
| */ | ||||
| #if defined(_WIN32) | ||||
| #include "utils/windows.hpp" | ||||
|  | ||||
| #include "utils/com_init_wrapper.hpp" | ||||
| #include "utils/string.hpp" | ||||
|  | ||||
| namespace repertory::utils { | ||||
| auto get_last_error_code() -> DWORD { return ::GetLastError(); } | ||||
|  | ||||
| auto get_local_app_data_directory() -> const std::string & { | ||||
|   static std::string app_data = ([]() -> std::string { | ||||
|     com_init_wrapper cw; | ||||
|     PWSTR local_app_data{}; | ||||
|     if (SUCCEEDED(::SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, | ||||
|                                          &local_app_data))) { | ||||
|       auto ret = utils::string::to_utf8(local_app_data); | ||||
|       ::CoTaskMemFree(local_app_data); | ||||
|       return ret; | ||||
|     } | ||||
|  | ||||
|     throw std::runtime_error("unable to detect local application data folder"); | ||||
|   })(); | ||||
|  | ||||
|   return app_data; | ||||
| } | ||||
|  | ||||
| auto get_thread_id() -> std::uint64_t { | ||||
|   return static_cast<std::uint64_t>(::GetCurrentThreadId()); | ||||
| } | ||||
|  | ||||
| auto is_process_elevated() -> bool { | ||||
|   auto ret{false}; | ||||
|   HANDLE token{INVALID_HANDLE_VALUE}; | ||||
|   if (::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { | ||||
|     TOKEN_ELEVATION te{}; | ||||
|     DWORD sz = sizeof(te); | ||||
|     if (::GetTokenInformation(token, TokenElevation, &te, sizeof(te), &sz)) { | ||||
|       ret = (te.TokenIsElevated != 0); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (token != INVALID_HANDLE_VALUE) { | ||||
|     ::CloseHandle(token); | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| auto run_process_elevated(std::vector<const char *> args) -> int { | ||||
|   std::cout << "Elevating Process" << std::endl; | ||||
|   std::string parameters{"-hidden"}; | ||||
|   for (std::size_t idx = 1U; idx < args.size(); idx++) { | ||||
|     parameters += | ||||
|         (parameters.empty() ? args.at(idx) : " " + std::string(args.at(idx))); | ||||
|   } | ||||
|  | ||||
|   std::string full_path; | ||||
|   full_path.resize(MAX_PATH + 1); | ||||
|  | ||||
|   if (::GetModuleFileName(nullptr, full_path.data(), MAX_PATH)) { | ||||
|     SHELLEXECUTEINFO sei{}; | ||||
|     sei.fMask = SEE_MASK_NOCLOSEPROCESS; | ||||
|     sei.cbSize = sizeof(sei); | ||||
|     sei.lpVerb = "runas"; | ||||
|     sei.lpFile = full_path.c_str(); | ||||
|     sei.lpParameters = parameters.c_str(); | ||||
|     sei.hwnd = nullptr; | ||||
|     sei.nShow = SW_NORMAL; | ||||
|     if (::ShellExecuteEx(&sei)) { | ||||
|       ::WaitForSingleObject(sei.hProcess, INFINITE); | ||||
|       DWORD exit_code{}; | ||||
|       ::GetExitCodeProcess(sei.hProcess, &exit_code); | ||||
|       ::CloseHandle(sei.hProcess); | ||||
|       return static_cast<int>(exit_code); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return static_cast<int>(::GetLastError()); | ||||
| } | ||||
|  | ||||
| void set_last_error_code(DWORD error_code) { ::SetLastError(error_code); } | ||||
| } // namespace repertory::utils | ||||
|  | ||||
| #endif // defined(_WIN32) | ||||
		Reference in New Issue
	
	Block a user