diff --git a/additions/camoucfg/MaskConfig.hpp b/additions/camoucfg/MaskConfig.hpp index 76fc407..3e6370e 100644 --- a/additions/camoucfg/MaskConfig.hpp +++ b/additions/camoucfg/MaskConfig.hpp @@ -4,7 +4,6 @@ Written by daijro. */ #pragma once - #include "json.hpp" #include #include @@ -12,10 +11,12 @@ Written by daijro. #include #include #include "mozilla/glue/Debug.h" -#include -#include +#include +#include #include #include +#include +#include #ifdef _WIN32 # include @@ -23,182 +24,188 @@ Written by daijro. namespace MaskConfig { +// Function to get the value of an environment variable as a UTF-8 string. inline std::optional get_env_utf8(const std::string& name) { #ifdef _WIN32 - std::wstring wName(name.begin(), name.end()); - DWORD size = GetEnvironmentVariableW(wName.c_str(), nullptr, 0); - if (size == 0) return std::nullopt; // Environment variable not found + std::wstring wName(name.begin(), name.end()); + DWORD size = GetEnvironmentVariableW(wName.c_str(), nullptr, 0); + if (size == 0) return std::nullopt; // Environment variable not found - std::vector buffer(size); - GetEnvironmentVariableW(wName.c_str(), buffer.data(), size); - std::wstring wValue(buffer.data()); + std::vector buffer(size); + GetEnvironmentVariableW(wName.c_str(), buffer.data(), size); + std::wstring wValue(buffer.data()); - // Convert UTF-16 to UTF-8 - std::wstring_convert> converter; - return converter.to_bytes(wValue); + // Convert UTF-16 to UTF-8 + std::wstring_convert> converter; + return converter.to_bytes(wValue); #else - const char* value = getenv(name.c_str()); - if (!value) return std::nullopt; - return std::string(value); + const char* value = std::getenv(name.c_str()); + if (!value) return std::nullopt; + return std::string(value); #endif } -inline const nlohmann::json& GetJson() { - static const nlohmann::json jsonConfig = []() { +// Helper function to load and parse configuration from environment variables. +namespace { +nlohmann::json loadConfig() { std::string jsonString; int index = 1; + // Read environment variables CAMOU_CONFIG_1, CAMOU_CONFIG_2, ... while (true) { - std::string envName = "CAMOU_CONFIG_" + std::to_string(index); - auto partialConfig = get_env_utf8(envName); - if (!partialConfig) break; - - jsonString += *partialConfig; - index++; + std::string envName = "CAMOU_CONFIG_" + std::to_string(index); + auto partialConfig = get_env_utf8(envName); + if (!partialConfig) + break; + jsonString += *partialConfig; + index++; } + // If the concatenated string is empty, try reading the original CAMOU_CONFIG variable. if (jsonString.empty()) { - // Check for the original CAMOU_CONFIG as fallback - auto originalConfig = get_env_utf8("CAMOU_CONFIG"); - if (originalConfig) jsonString = *originalConfig; + auto originalConfig = get_env_utf8("CAMOU_CONFIG"); + if (originalConfig) + jsonString = *originalConfig; } - if (jsonString.empty()) return nlohmann::json{}; + // If no configuration is provided, return an empty JSON. + if (jsonString.empty()) { + return nlohmann::json{}; + } - // Validate + // Validate JSON correctness. if (!nlohmann::json::accept(jsonString)) { - printf_stderr("ERROR: Invalid JSON passed to CAMOU_CONFIG!\n"); - return nlohmann::json{}; + printf_stderr("ERROR: Invalid JSON passed to CAMOU_CONFIG!\n"); + return nlohmann::json{}; } - nlohmann::json result = nlohmann::json::parse(jsonString); - return result; - }(); - return jsonConfig; + return nlohmann::json::parse(jsonString); +} +} // namespace + +// Global configuration cache, initialized only once. +static const nlohmann::json g_jsonConfig = loadConfig(); + +// Function returns a reference to the already parsed JSON. +inline const nlohmann::json& GetJson() { + return g_jsonConfig; } -inline bool HasKey(const std::string& key, nlohmann::json& data) { - // printf_stderr("Property: %s\n", key.c_str()); - // printf_stderr("WARNING: Key not found: %s\n", key.c_str()); - return data.contains(key); +inline bool HasKey(const std::string& key, const nlohmann::json& data) { + return data.contains(key); } inline std::optional GetString(const std::string& key) { - // printf_stderr("GetString: %s\n", key.c_str()); - auto data = GetJson(); - if (!HasKey(key, data)) return std::nullopt; - return std::make_optional(data[key].get()); + const auto& data = GetJson(); + if (!HasKey(key, data)) return std::nullopt; + return data[key].get(); } inline std::vector GetStringList(const std::string& key) { - std::vector result; - - auto data = GetJson(); - if (!HasKey(key, data)) return {}; - // Build vector - for (const auto& item : data[key]) { - result.push_back(item.get()); - } - return result; + std::vector result; + const auto& data = GetJson(); + if (!HasKey(key, data)) return {}; + for (const auto& item : data[key]) { + result.push_back(item.get()); + } + return result; } inline std::vector GetStringListLower(const std::string& key) { - std::vector result = GetStringList(key); - for (auto& str : result) { - std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return std::tolower(c); }); - } - return result; + std::vector result = GetStringList(key); + for (auto& str : result) { + std::transform(str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); }); + } + return result; } template inline std::optional GetUintImpl(const std::string& key) { - auto data = GetJson(); - if (!HasKey(key, data)) return std::nullopt; - if (data[key].is_number_unsigned()) - return std::make_optional(data[key].get()); - printf_stderr("ERROR: Value for key '%s' is not an unsigned integer\n", - key.c_str()); - return std::nullopt; + const auto& data = GetJson(); + if (!HasKey(key, data)) return std::nullopt; + if (data[key].is_number_unsigned()) + return data[key].get(); + printf_stderr("ERROR: Value for key '%s' is not an unsigned integer\n", key.c_str()); + return std::nullopt; } inline std::optional GetUint64(const std::string& key) { - return GetUintImpl(key); + return GetUintImpl(key); } inline std::optional GetUint32(const std::string& key) { - return GetUintImpl(key); + return GetUintImpl(key); } inline std::optional GetInt32(const std::string& key) { - auto data = GetJson(); - if (!HasKey(key, data)) return std::nullopt; - if (data[key].is_number_integer()) - return std::make_optional(data[key].get()); - printf_stderr("ERROR: Value for key '%s' is not an integer\n", key.c_str()); - return std::nullopt; + const auto& data = GetJson(); + if (!HasKey(key, data)) return std::nullopt; + if (data[key].is_number_integer()) + return data[key].get(); + printf_stderr("ERROR: Value for key '%s' is not an integer\n", key.c_str()); + return std::nullopt; } inline std::optional GetDouble(const std::string& key) { - auto data = GetJson(); - if (!HasKey(key, data)) return std::nullopt; - if (data[key].is_number_float()) - return std::make_optional(data[key].get()); - if (data[key].is_number_unsigned() || data[key].is_number_integer()) - return std::make_optional(static_cast(data[key].get())); - printf_stderr("ERROR: Value for key '%s' is not a double\n", key.c_str()); - return std::nullopt; + const auto& data = GetJson(); + if (!HasKey(key, data)) return std::nullopt; + if (data[key].is_number_float()) + return data[key].get(); + if (data[key].is_number_unsigned() || data[key].is_number_integer()) + return static_cast(data[key].get()); + printf_stderr("ERROR: Value for key '%s' is not a double\n", key.c_str()); + return std::nullopt; } inline std::optional GetBool(const std::string& key) { - auto data = GetJson(); - if (!HasKey(key, data)) return std::nullopt; - if (data[key].is_boolean()) return std::make_optional(data[key].get()); - printf_stderr("ERROR: Value for key '%s' is not a boolean\n", key.c_str()); - return std::nullopt; + const auto& data = GetJson(); + if (!HasKey(key, data)) return std::nullopt; + if (data[key].is_boolean()) return data[key].get(); + printf_stderr("ERROR: Value for key '%s' is not a boolean\n", key.c_str()); + return std::nullopt; } inline bool CheckBool(const std::string& key) { - return GetBool(key).value_or(false); + return GetBool(key).value_or(false); } -inline std::optional> GetRect( - const std::string& left, const std::string& top, const std::string& width, - const std::string& height) { - // Make top and left default to 0 - std::array, 4> values = { - GetUint32(left).value_or(0), GetUint32(top).value_or(0), GetUint32(width), - GetUint32(height)}; +inline std::optional> GetRect(const std::string& left, + const std::string& top, + const std::string& width, + const std::string& height) { + std::array, 4> values = { + GetUint32(left).value_or(0), + GetUint32(top).value_or(0), + GetUint32(width), + GetUint32(height) + }; - // If height or width is std::nullopt, return std::nullopt - if (!values[2].has_value() || !values[3].has_value()) { - if (values[2].has_value() ^ values[3].has_value()) - printf_stderr( - "Both %s and %s must be provided. Using default " - "behavior.\n", - height.c_str(), width.c_str()); - return std::nullopt; - } + if (!values[2].has_value() || !values[3].has_value()) { + if (values[2].has_value() ^ values[3].has_value()) + printf_stderr("Both %s and %s must be provided. Using default behavior.\n", + height.c_str(), width.c_str()); + return std::nullopt; + } - // Convert std::optional to uint32_t - std::array result; - std::transform(values.begin(), values.end(), result.begin(), - [](const auto& value) { return value.value(); }); + std::array result; + std::transform(values.begin(), values.end(), result.begin(), + [](const auto& value) { return value.value(); }); - return result; -} - -inline std::optional> GetInt32Rect( - const std::string& left, const std::string& top, const std::string& width, - const std::string& height) { - // Calls GetRect but casts to int32_t - if (auto optValue = GetRect(left, top, width, height)) { - std::array result; - std::transform(optValue->begin(), optValue->end(), result.begin(), - [](const auto& val) { return static_cast(val); }); return result; - } - return std::nullopt; +} + +inline std::optional> GetInt32Rect(const std::string& left, + const std::string& top, + const std::string& width, + const std::string& height) { + if (auto optValue = GetRect(left, top, width, height)) { + std::array result; + std::transform(optValue->begin(), optValue->end(), result.begin(), + [](const auto& val) { return static_cast(val); }); + return result; + } + return std::nullopt; } // Helpers for WebGL