15db71995Sopenharmony_ci/*
25db71995Sopenharmony_ci * Copyright (c) 2021-2023 The Khronos Group Inc.
35db71995Sopenharmony_ci * Copyright (c) 2021-2023 Valve Corporation
45db71995Sopenharmony_ci * Copyright (c) 2021-2023 LunarG, Inc.
55db71995Sopenharmony_ci *
65db71995Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
75db71995Sopenharmony_ci * of this software and/or associated documentation files (the "Materials"), to
85db71995Sopenharmony_ci * deal in the Materials without restriction, including without limitation the
95db71995Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
105db71995Sopenharmony_ci * sell copies of the Materials, and to permit persons to whom the Materials are
115db71995Sopenharmony_ci * furnished to do so, subject to the following conditions:
125db71995Sopenharmony_ci *
135db71995Sopenharmony_ci * The above copyright notice(s) and this permission notice shall be included in
145db71995Sopenharmony_ci * all copies or substantial portions of the Materials.
155db71995Sopenharmony_ci *
165db71995Sopenharmony_ci * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175db71995Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185db71995Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
195db71995Sopenharmony_ci *
205db71995Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
215db71995Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
225db71995Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
235db71995Sopenharmony_ci * USE OR OTHER DEALINGS IN THE MATERIALS.
245db71995Sopenharmony_ci *
255db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com>
265db71995Sopenharmony_ci */
275db71995Sopenharmony_ci
285db71995Sopenharmony_ci#include "test_util.h"
295db71995Sopenharmony_ci
305db71995Sopenharmony_ci#if defined(WIN32)
315db71995Sopenharmony_ci#include <strsafe.h>
325db71995Sopenharmony_ciconst char* win_api_error_str(LSTATUS status) {
335db71995Sopenharmony_ci    if (status == ERROR_INVALID_FUNCTION) return "ERROR_INVALID_FUNCTION";
345db71995Sopenharmony_ci    if (status == ERROR_FILE_NOT_FOUND) return "ERROR_FILE_NOT_FOUND";
355db71995Sopenharmony_ci    if (status == ERROR_PATH_NOT_FOUND) return "ERROR_PATH_NOT_FOUND";
365db71995Sopenharmony_ci    if (status == ERROR_TOO_MANY_OPEN_FILES) return "ERROR_TOO_MANY_OPEN_FILES";
375db71995Sopenharmony_ci    if (status == ERROR_ACCESS_DENIED) return "ERROR_ACCESS_DENIED";
385db71995Sopenharmony_ci    if (status == ERROR_INVALID_HANDLE) return "ERROR_INVALID_HANDLE";
395db71995Sopenharmony_ci    if (status == ERROR_ENVVAR_NOT_FOUND) return "ERROR_ENVVAR_NOT_FOUND";
405db71995Sopenharmony_ci    if (status == ERROR_SETENV_FAILED) return "ERROR_SETENV_FAILED";
415db71995Sopenharmony_ci    return "UNKNOWN ERROR";
425db71995Sopenharmony_ci}
435db71995Sopenharmony_ci
445db71995Sopenharmony_civoid print_error_message(LSTATUS status, const char* function_name, std::string optional_message) {
455db71995Sopenharmony_ci    LPVOID lpMsgBuf;
465db71995Sopenharmony_ci    DWORD dw = GetLastError();
475db71995Sopenharmony_ci
485db71995Sopenharmony_ci    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dw,
495db71995Sopenharmony_ci                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPTSTR>(&lpMsgBuf), 0, nullptr);
505db71995Sopenharmony_ci
515db71995Sopenharmony_ci    std::cerr << function_name << " failed with " << win_api_error_str(status) << ": "
525db71995Sopenharmony_ci              << std::string(reinterpret_cast<LPTSTR>(lpMsgBuf));
535db71995Sopenharmony_ci    if (optional_message != "") {
545db71995Sopenharmony_ci        std::cerr << " | " << optional_message;
555db71995Sopenharmony_ci    }
565db71995Sopenharmony_ci    std::cerr << "\n";
575db71995Sopenharmony_ci    LocalFree(lpMsgBuf);
585db71995Sopenharmony_ci}
595db71995Sopenharmony_ci
605db71995Sopenharmony_civoid EnvVarWrapper::set_env_var() {
615db71995Sopenharmony_ci    BOOL ret = SetEnvironmentVariableW(widen(name).c_str(), widen(cur_value).c_str());
625db71995Sopenharmony_ci    if (ret == 0) {
635db71995Sopenharmony_ci        print_error_message(ERROR_SETENV_FAILED, "SetEnvironmentVariableW");
645db71995Sopenharmony_ci    }
655db71995Sopenharmony_ci}
665db71995Sopenharmony_civoid EnvVarWrapper::remove_env_var() const { SetEnvironmentVariableW(widen(name).c_str(), nullptr); }
675db71995Sopenharmony_cistd::string get_env_var(std::string const& name, bool report_failure) {
685db71995Sopenharmony_ci    std::wstring name_utf16 = widen(name);
695db71995Sopenharmony_ci    DWORD value_size = GetEnvironmentVariableW(name_utf16.c_str(), nullptr, 0);
705db71995Sopenharmony_ci    if (0 == value_size) {
715db71995Sopenharmony_ci        if (report_failure) print_error_message(ERROR_ENVVAR_NOT_FOUND, "GetEnvironmentVariableW");
725db71995Sopenharmony_ci        return {};
735db71995Sopenharmony_ci    }
745db71995Sopenharmony_ci    std::wstring value(value_size, L'\0');
755db71995Sopenharmony_ci    if (GetEnvironmentVariableW(name_utf16.c_str(), &value[0], value_size) != value_size - 1) {
765db71995Sopenharmony_ci        return {};
775db71995Sopenharmony_ci    }
785db71995Sopenharmony_ci    return narrow(value);
795db71995Sopenharmony_ci}
805db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS
815db71995Sopenharmony_ci
825db71995Sopenharmony_civoid EnvVarWrapper::set_env_var() { setenv(name.c_str(), cur_value.c_str(), 1); }
835db71995Sopenharmony_civoid EnvVarWrapper::remove_env_var() const { unsetenv(name.c_str()); }
845db71995Sopenharmony_cistd::string get_env_var(std::string const& name, bool report_failure) {
855db71995Sopenharmony_ci    char* ret = getenv(name.c_str());
865db71995Sopenharmony_ci    if (ret == nullptr) {
875db71995Sopenharmony_ci        if (report_failure) std::cerr << "Failed to get environment variable:" << name << "\n";
885db71995Sopenharmony_ci        return std::string();
895db71995Sopenharmony_ci    }
905db71995Sopenharmony_ci    return ret;
915db71995Sopenharmony_ci}
925db71995Sopenharmony_ci#endif
935db71995Sopenharmony_ci
945db71995Sopenharmony_citemplate <typename T>
955db71995Sopenharmony_civoid print_object_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
965db71995Sopenharmony_ci    if (vec.size() == 0) return;
975db71995Sopenharmony_ci    writer.StartKeyedObject(object_name);
985db71995Sopenharmony_ci    for (auto& element : vec) {
995db71995Sopenharmony_ci        element.get_manifest_str(writer);
1005db71995Sopenharmony_ci    }
1015db71995Sopenharmony_ci    writer.EndObject();
1025db71995Sopenharmony_ci}
1035db71995Sopenharmony_ci
1045db71995Sopenharmony_citemplate <typename T>
1055db71995Sopenharmony_civoid print_array_of_t(JsonWriter& writer, const char* object_name, std::vector<T> const& vec) {
1065db71995Sopenharmony_ci    if (vec.size() == 0) return;
1075db71995Sopenharmony_ci    writer.StartKeyedArray(object_name);
1085db71995Sopenharmony_ci    for (auto& element : vec) {
1095db71995Sopenharmony_ci        element.get_manifest_str(writer);
1105db71995Sopenharmony_ci    }
1115db71995Sopenharmony_ci    writer.EndArray();
1125db71995Sopenharmony_ci}
1135db71995Sopenharmony_civoid print_vector_of_strings(JsonWriter& writer, const char* object_name, std::vector<std::string> const& strings) {
1145db71995Sopenharmony_ci    if (strings.size() == 0) return;
1155db71995Sopenharmony_ci    writer.StartKeyedArray(object_name);
1165db71995Sopenharmony_ci    for (auto& str : strings) {
1175db71995Sopenharmony_ci        writer.AddString(fs::fixup_backslashes_in_path(str));
1185db71995Sopenharmony_ci    }
1195db71995Sopenharmony_ci    writer.EndArray();
1205db71995Sopenharmony_ci}
1215db71995Sopenharmony_ci
1225db71995Sopenharmony_cistd::string to_text(bool b) { return b ? std::string("true") : std::string("false"); }
1235db71995Sopenharmony_ci
1245db71995Sopenharmony_cistd::string ManifestICD::get_manifest_str() const {
1255db71995Sopenharmony_ci    JsonWriter writer;
1265db71995Sopenharmony_ci    writer.StartObject();
1275db71995Sopenharmony_ci    writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
1285db71995Sopenharmony_ci    writer.StartKeyedObject("ICD");
1295db71995Sopenharmony_ci    writer.AddKeyedString("library_path", fs::fixup_backslashes_in_path(lib_path).str());
1305db71995Sopenharmony_ci    writer.AddKeyedString("api_version", version_to_string(api_version));
1315db71995Sopenharmony_ci    writer.AddKeyedBool("is_portability_driver", is_portability_driver);
1325db71995Sopenharmony_ci    if (!library_arch.empty()) writer.AddKeyedString("library_arch", library_arch);
1335db71995Sopenharmony_ci    writer.EndObject();
1345db71995Sopenharmony_ci    writer.EndObject();
1355db71995Sopenharmony_ci    return writer.output;
1365db71995Sopenharmony_ci}
1375db71995Sopenharmony_ci
1385db71995Sopenharmony_civoid ManifestLayer::LayerDescription::Extension::get_manifest_str(JsonWriter& writer) const {
1395db71995Sopenharmony_ci    writer.StartObject();
1405db71995Sopenharmony_ci    writer.AddKeyedString("name", name);
1415db71995Sopenharmony_ci    writer.AddKeyedString("spec_version", std::to_string(spec_version));
1425db71995Sopenharmony_ci    writer.AddKeyedString("spec_version", std::to_string(spec_version));
1435db71995Sopenharmony_ci    print_vector_of_strings(writer, "entrypoints", entrypoints);
1445db71995Sopenharmony_ci    writer.EndObject();
1455db71995Sopenharmony_ci}
1465db71995Sopenharmony_ci
1475db71995Sopenharmony_civoid ManifestLayer::LayerDescription::get_manifest_str(JsonWriter& writer) const {
1485db71995Sopenharmony_ci    writer.AddKeyedString("name", name);
1495db71995Sopenharmony_ci    writer.AddKeyedString("type", get_type_str(type));
1505db71995Sopenharmony_ci    if (!lib_path.str().empty()) {
1515db71995Sopenharmony_ci        writer.AddKeyedString("library_path", fs::fixup_backslashes_in_path(lib_path.str()));
1525db71995Sopenharmony_ci    }
1535db71995Sopenharmony_ci    writer.AddKeyedString("api_version", version_to_string(api_version));
1545db71995Sopenharmony_ci    writer.AddKeyedString("implementation_version", std::to_string(implementation_version));
1555db71995Sopenharmony_ci    writer.AddKeyedString("description", description);
1565db71995Sopenharmony_ci    print_object_of_t(writer, "functions", functions);
1575db71995Sopenharmony_ci    print_array_of_t(writer, "instance_extensions", instance_extensions);
1585db71995Sopenharmony_ci    print_array_of_t(writer, "device_extensions", device_extensions);
1595db71995Sopenharmony_ci    if (!enable_environment.empty()) {
1605db71995Sopenharmony_ci        writer.StartKeyedObject("enable_environment");
1615db71995Sopenharmony_ci        writer.AddKeyedString(enable_environment, "1");
1625db71995Sopenharmony_ci        writer.EndObject();
1635db71995Sopenharmony_ci    }
1645db71995Sopenharmony_ci    if (!disable_environment.empty()) {
1655db71995Sopenharmony_ci        writer.StartKeyedObject("disable_environment");
1665db71995Sopenharmony_ci        writer.AddKeyedString(disable_environment, "1");
1675db71995Sopenharmony_ci        writer.EndObject();
1685db71995Sopenharmony_ci    }
1695db71995Sopenharmony_ci    print_vector_of_strings(writer, "component_layers", component_layers);
1705db71995Sopenharmony_ci    print_vector_of_strings(writer, "blacklisted_layers", blacklisted_layers);
1715db71995Sopenharmony_ci    print_vector_of_strings(writer, "override_paths", override_paths);
1725db71995Sopenharmony_ci    print_vector_of_strings(writer, "app_keys", app_keys);
1735db71995Sopenharmony_ci    print_object_of_t(writer, "pre_instance_functions", pre_instance_functions);
1745db71995Sopenharmony_ci    if (!library_arch.empty()) {
1755db71995Sopenharmony_ci        writer.AddKeyedString("library_arch", library_arch);
1765db71995Sopenharmony_ci    }
1775db71995Sopenharmony_ci}
1785db71995Sopenharmony_ci
1795db71995Sopenharmony_ciVkLayerProperties ManifestLayer::LayerDescription::get_layer_properties() const {
1805db71995Sopenharmony_ci    VkLayerProperties properties{};
1815db71995Sopenharmony_ci    copy_string_to_char_array(name, properties.layerName, VK_MAX_EXTENSION_NAME_SIZE);
1825db71995Sopenharmony_ci    copy_string_to_char_array(description, properties.description, VK_MAX_EXTENSION_NAME_SIZE);
1835db71995Sopenharmony_ci    properties.implementationVersion = implementation_version;
1845db71995Sopenharmony_ci    properties.specVersion = api_version;
1855db71995Sopenharmony_ci    return properties;
1865db71995Sopenharmony_ci}
1875db71995Sopenharmony_ci
1885db71995Sopenharmony_cistd::string ManifestLayer::get_manifest_str() const {
1895db71995Sopenharmony_ci    JsonWriter writer;
1905db71995Sopenharmony_ci    writer.StartObject();
1915db71995Sopenharmony_ci    writer.AddKeyedString("file_format_version", file_format_version.get_version_str());
1925db71995Sopenharmony_ci    if (layers.size() == 1) {
1935db71995Sopenharmony_ci        writer.StartKeyedObject("layer");
1945db71995Sopenharmony_ci        layers.at(0).get_manifest_str(writer);
1955db71995Sopenharmony_ci        writer.EndObject();
1965db71995Sopenharmony_ci    } else {
1975db71995Sopenharmony_ci        writer.StartKeyedArray("layers");
1985db71995Sopenharmony_ci        for (size_t i = 0; i < layers.size(); i++) {
1995db71995Sopenharmony_ci            writer.StartObject();
2005db71995Sopenharmony_ci            layers.at(i).get_manifest_str(writer);
2015db71995Sopenharmony_ci            writer.EndObject();
2025db71995Sopenharmony_ci        }
2035db71995Sopenharmony_ci        writer.EndArray();
2045db71995Sopenharmony_ci    }
2055db71995Sopenharmony_ci    writer.EndObject();
2065db71995Sopenharmony_ci    return writer.output;
2075db71995Sopenharmony_ci}
2085db71995Sopenharmony_ci
2095db71995Sopenharmony_cinamespace fs {
2105db71995Sopenharmony_cistd::string make_native(std::string const& in_path) {
2115db71995Sopenharmony_ci    std::string out;
2125db71995Sopenharmony_ci#if defined(WIN32)
2135db71995Sopenharmony_ci    for (auto& c : in_path) {
2145db71995Sopenharmony_ci        if (c == '/')
2155db71995Sopenharmony_ci            out += "\\";
2165db71995Sopenharmony_ci        else
2175db71995Sopenharmony_ci            out += c;
2185db71995Sopenharmony_ci    }
2195db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS
2205db71995Sopenharmony_ci    for (size_t i = 0; i < in_path.size(); i++) {
2215db71995Sopenharmony_ci        if (i + 1 < in_path.size() && in_path[i] == '\\' && in_path[i + 1] == '\\') {
2225db71995Sopenharmony_ci            out += '/';
2235db71995Sopenharmony_ci            i++;
2245db71995Sopenharmony_ci        } else
2255db71995Sopenharmony_ci            out += in_path[i];
2265db71995Sopenharmony_ci    }
2275db71995Sopenharmony_ci#endif
2285db71995Sopenharmony_ci    return out;
2295db71995Sopenharmony_ci}
2305db71995Sopenharmony_ci
2315db71995Sopenharmony_ci// Json doesn't allow `\` in strings, it must be escaped. Thus we have to convert '\\' to '\\\\' in strings
2325db71995Sopenharmony_cistd::string fixup_backslashes_in_path(std::string const& in_path) {
2335db71995Sopenharmony_ci    std::string out;
2345db71995Sopenharmony_ci    for (auto& c : in_path) {
2355db71995Sopenharmony_ci        if (c == '\\')
2365db71995Sopenharmony_ci            out += "\\\\";
2375db71995Sopenharmony_ci        else
2385db71995Sopenharmony_ci            out += c;
2395db71995Sopenharmony_ci    }
2405db71995Sopenharmony_ci    return out;
2415db71995Sopenharmony_ci}
2425db71995Sopenharmony_cifs::path fixup_backslashes_in_path(fs::path const& in_path) { return fixup_backslashes_in_path(in_path.str()); }
2435db71995Sopenharmony_ci
2445db71995Sopenharmony_cipath& path::operator+=(path const& in) {
2455db71995Sopenharmony_ci    contents += in.contents;
2465db71995Sopenharmony_ci    return *this;
2475db71995Sopenharmony_ci}
2485db71995Sopenharmony_cipath& path::operator+=(std::string const& in) {
2495db71995Sopenharmony_ci    contents += in;
2505db71995Sopenharmony_ci    return *this;
2515db71995Sopenharmony_ci}
2525db71995Sopenharmony_cipath& path::operator+=(const char* in) {
2535db71995Sopenharmony_ci    contents += std::string{in};
2545db71995Sopenharmony_ci    return *this;
2555db71995Sopenharmony_ci}
2565db71995Sopenharmony_cipath& path::operator/=(path const& in) {
2575db71995Sopenharmony_ci    if (contents.back() != path_separator && in.contents.front() != path_separator) contents += path_separator;
2585db71995Sopenharmony_ci    contents += in.contents;
2595db71995Sopenharmony_ci    return *this;
2605db71995Sopenharmony_ci}
2615db71995Sopenharmony_cipath& path::operator/=(std::string const& in) {
2625db71995Sopenharmony_ci    if (contents.back() != path_separator && in.front() != path_separator) contents += path_separator;
2635db71995Sopenharmony_ci    contents += in;
2645db71995Sopenharmony_ci    return *this;
2655db71995Sopenharmony_ci}
2665db71995Sopenharmony_cipath& path::operator/=(const char* in) {
2675db71995Sopenharmony_ci    std::string in_str{in};
2685db71995Sopenharmony_ci    if (contents.back() != path_separator && in_str.front() != path_separator) contents += path_separator;
2695db71995Sopenharmony_ci    contents += in_str;
2705db71995Sopenharmony_ci    return *this;
2715db71995Sopenharmony_ci}
2725db71995Sopenharmony_cipath path::operator+(path const& in) const {
2735db71995Sopenharmony_ci    path new_path = contents;
2745db71995Sopenharmony_ci    new_path += in;
2755db71995Sopenharmony_ci    return new_path;
2765db71995Sopenharmony_ci}
2775db71995Sopenharmony_cipath path::operator+(std::string const& in) const {
2785db71995Sopenharmony_ci    path new_path = contents;
2795db71995Sopenharmony_ci    new_path += in;
2805db71995Sopenharmony_ci    return new_path;
2815db71995Sopenharmony_ci}
2825db71995Sopenharmony_cipath path::operator+(const char* in) const {
2835db71995Sopenharmony_ci    path new_path(contents);
2845db71995Sopenharmony_ci    new_path += in;
2855db71995Sopenharmony_ci    return new_path;
2865db71995Sopenharmony_ci}
2875db71995Sopenharmony_ci
2885db71995Sopenharmony_cipath path::operator/(path const& in) const {
2895db71995Sopenharmony_ci    path new_path = contents;
2905db71995Sopenharmony_ci    new_path /= in;
2915db71995Sopenharmony_ci    return new_path;
2925db71995Sopenharmony_ci}
2935db71995Sopenharmony_cipath path::operator/(std::string const& in) const {
2945db71995Sopenharmony_ci    path new_path = contents;
2955db71995Sopenharmony_ci    new_path /= in;
2965db71995Sopenharmony_ci    return new_path;
2975db71995Sopenharmony_ci}
2985db71995Sopenharmony_cipath path::operator/(const char* in) const {
2995db71995Sopenharmony_ci    path new_path(contents);
3005db71995Sopenharmony_ci    new_path /= in;
3015db71995Sopenharmony_ci    return new_path;
3025db71995Sopenharmony_ci}
3035db71995Sopenharmony_ci
3045db71995Sopenharmony_cipath path::parent_path() const {
3055db71995Sopenharmony_ci    auto last_div = contents.rfind(path_separator);
3065db71995Sopenharmony_ci    if (last_div == std::string::npos) return "";
3075db71995Sopenharmony_ci    return path(contents.substr(0, last_div));
3085db71995Sopenharmony_ci}
3095db71995Sopenharmony_cibool path::has_parent_path() const {
3105db71995Sopenharmony_ci    auto last_div = contents.rfind(path_separator);
3115db71995Sopenharmony_ci    return last_div != std::string::npos;
3125db71995Sopenharmony_ci}
3135db71995Sopenharmony_cipath path::filename() const {
3145db71995Sopenharmony_ci    auto last_div = contents.rfind(path_separator);
3155db71995Sopenharmony_ci    return path(contents.substr(last_div + 1, contents.size() - last_div + 1));
3165db71995Sopenharmony_ci}
3175db71995Sopenharmony_ci
3185db71995Sopenharmony_cipath path::extension() const {
3195db71995Sopenharmony_ci    auto last_div = contents.rfind(path_separator);
3205db71995Sopenharmony_ci    auto ext_div = contents.rfind('.');
3215db71995Sopenharmony_ci    // Make sure to not get the special `.` and `..`, as well as any filename that being with a dot, like .profile
3225db71995Sopenharmony_ci    if (last_div + 1 == ext_div || (last_div + 2 == ext_div && contents[last_div + 1] == '.')) return path("");
3235db71995Sopenharmony_ci    path temp = path(contents.substr(ext_div, contents.size() - ext_div + 1));
3245db71995Sopenharmony_ci
3255db71995Sopenharmony_ci    return path(contents.substr(ext_div, contents.size() - ext_div + 1));
3265db71995Sopenharmony_ci}
3275db71995Sopenharmony_ci
3285db71995Sopenharmony_cipath path::stem() const {
3295db71995Sopenharmony_ci    auto last_div = contents.rfind(path_separator);
3305db71995Sopenharmony_ci    auto ext_div = contents.rfind('.');
3315db71995Sopenharmony_ci    if (last_div + 1 == ext_div || (last_div + 2 == ext_div && contents[last_div + 1] == '.')) {
3325db71995Sopenharmony_ci        return path(contents.substr(last_div + 1, contents.size() - last_div + 1));
3335db71995Sopenharmony_ci    }
3345db71995Sopenharmony_ci    return path(contents.substr(last_div + 1, ext_div - last_div - 1));
3355db71995Sopenharmony_ci}
3365db71995Sopenharmony_ci
3375db71995Sopenharmony_cipath& path::replace_filename(path const& replacement) {
3385db71995Sopenharmony_ci    *this = parent_path() / replacement.str();
3395db71995Sopenharmony_ci    return *this;
3405db71995Sopenharmony_ci}
3415db71995Sopenharmony_ci
3425db71995Sopenharmony_ci// internal implementation helper for per-platform creating & destroying folders
3435db71995Sopenharmony_ciint create_folder(path const& path) {
3445db71995Sopenharmony_ci#if defined(WIN32)
3455db71995Sopenharmony_ci    return _wmkdir(widen(path.str()).c_str());
3465db71995Sopenharmony_ci#else
3475db71995Sopenharmony_ci    mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
3485db71995Sopenharmony_ci    return 0;
3495db71995Sopenharmony_ci#endif
3505db71995Sopenharmony_ci}
3515db71995Sopenharmony_ci
3525db71995Sopenharmony_ciint delete_folder_contents(path const& folder) {
3535db71995Sopenharmony_ci#if defined(WIN32)
3545db71995Sopenharmony_ci    std::wstring folder_utf16 = widen(folder.str());
3555db71995Sopenharmony_ci    if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(folder_utf16.c_str()) && GetLastError() == ERROR_FILE_NOT_FOUND) {
3565db71995Sopenharmony_ci        // nothing to delete
3575db71995Sopenharmony_ci        return 0;
3585db71995Sopenharmony_ci    }
3595db71995Sopenharmony_ci    std::wstring search_path = folder_utf16 + L"/*.*";
3605db71995Sopenharmony_ci    std::string s_p = folder.str() + "/";
3615db71995Sopenharmony_ci    WIN32_FIND_DATAW fd;
3625db71995Sopenharmony_ci    HANDLE hFind = ::FindFirstFileW(search_path.c_str(), &fd);
3635db71995Sopenharmony_ci    if (hFind != INVALID_HANDLE_VALUE) {
3645db71995Sopenharmony_ci        do {
3655db71995Sopenharmony_ci            std::string file_name_utf8 = narrow(fd.cFileName);
3665db71995Sopenharmony_ci            if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
3675db71995Sopenharmony_ci                if (!string_eq(file_name_utf8.c_str(), ".") && !string_eq(file_name_utf8.c_str(), "..")) {
3685db71995Sopenharmony_ci                    delete_folder(s_p + file_name_utf8);
3695db71995Sopenharmony_ci                }
3705db71995Sopenharmony_ci            } else {
3715db71995Sopenharmony_ci                std::string child_name = s_p + file_name_utf8;
3725db71995Sopenharmony_ci                DeleteFileW(widen(child_name).c_str());
3735db71995Sopenharmony_ci            }
3745db71995Sopenharmony_ci        } while (::FindNextFileW(hFind, &fd));
3755db71995Sopenharmony_ci        ::FindClose(hFind);
3765db71995Sopenharmony_ci    }
3775db71995Sopenharmony_ci    return 0;
3785db71995Sopenharmony_ci#else
3795db71995Sopenharmony_ci    DIR* dir = opendir(folder.c_str());
3805db71995Sopenharmony_ci    if (!dir) {
3815db71995Sopenharmony_ci        return 0;
3825db71995Sopenharmony_ci    }
3835db71995Sopenharmony_ci    int ret = 0;
3845db71995Sopenharmony_ci    dirent* file;
3855db71995Sopenharmony_ci    while (!ret && (file = readdir(dir))) {
3865db71995Sopenharmony_ci        int ret2 = -1;
3875db71995Sopenharmony_ci
3885db71995Sopenharmony_ci        /* Skip the names "." and ".." as we don't want to recurse on them. */
3895db71995Sopenharmony_ci        if (string_eq(file->d_name, ".") || string_eq(file->d_name, "..")) continue;
3905db71995Sopenharmony_ci
3915db71995Sopenharmony_ci        path file_path = folder / file->d_name;
3925db71995Sopenharmony_ci        struct stat statbuf;
3935db71995Sopenharmony_ci        if (!stat(file_path.c_str(), &statbuf)) {
3945db71995Sopenharmony_ci            if (S_ISDIR(statbuf.st_mode))
3955db71995Sopenharmony_ci                ret2 = delete_folder(file_path);
3965db71995Sopenharmony_ci            else
3975db71995Sopenharmony_ci                ret2 = unlink(file_path.c_str());
3985db71995Sopenharmony_ci        }
3995db71995Sopenharmony_ci
4005db71995Sopenharmony_ci        ret = ret2;
4015db71995Sopenharmony_ci    }
4025db71995Sopenharmony_ci    closedir(dir);
4035db71995Sopenharmony_ci    return ret;
4045db71995Sopenharmony_ci#endif
4055db71995Sopenharmony_ci}
4065db71995Sopenharmony_ci
4075db71995Sopenharmony_ciint delete_folder(path const& folder) {
4085db71995Sopenharmony_ci    int ret = delete_folder_contents(folder);
4095db71995Sopenharmony_ci    if (ret != 0) return ret;
4105db71995Sopenharmony_ci#if defined(WIN32)
4115db71995Sopenharmony_ci    _wrmdir(widen(folder.str()).c_str());
4125db71995Sopenharmony_ci    return 0;
4135db71995Sopenharmony_ci#else
4145db71995Sopenharmony_ci    return rmdir(folder.c_str());
4155db71995Sopenharmony_ci#endif
4165db71995Sopenharmony_ci}
4175db71995Sopenharmony_ci
4185db71995Sopenharmony_ci#if defined(WIN32)
4195db71995Sopenharmony_cistd::wstring native_path(const std::string& utf8) { return widen(utf8); }
4205db71995Sopenharmony_ci#else
4215db71995Sopenharmony_ciconst std::string& native_path(const std::string& utf8) { return utf8; }
4225db71995Sopenharmony_ci#endif
4235db71995Sopenharmony_ci
4245db71995Sopenharmony_ciFolderManager::FolderManager(path root_path, std::string name) noexcept : folder(root_path / name) {
4255db71995Sopenharmony_ci    delete_folder_contents(folder);
4265db71995Sopenharmony_ci    create_folder(folder);
4275db71995Sopenharmony_ci}
4285db71995Sopenharmony_ciFolderManager::~FolderManager() noexcept {
4295db71995Sopenharmony_ci    if (folder.str().empty()) return;
4305db71995Sopenharmony_ci    auto list_of_files_to_delete = files;
4315db71995Sopenharmony_ci    // remove(file) modifies the files variable, copy the list before deleting it
4325db71995Sopenharmony_ci    // Note: the allocation tests currently leak the loaded driver handles because in an OOM scenario the loader doesn't bother
4335db71995Sopenharmony_ci    // removing those. Since this is in an OOM situation, it is a low priority to fix. It does have the effect that Windows will
4345db71995Sopenharmony_ci    // be unable to delete the binaries that were leaked.
4355db71995Sopenharmony_ci    for (auto& file : list_of_files_to_delete) {
4365db71995Sopenharmony_ci        remove(file);
4375db71995Sopenharmony_ci    }
4385db71995Sopenharmony_ci    delete_folder(folder);
4395db71995Sopenharmony_ci}
4405db71995Sopenharmony_ciFolderManager::FolderManager(FolderManager&& other) noexcept : folder(other.folder), files(other.files) {
4415db71995Sopenharmony_ci    other.folder.str().clear();
4425db71995Sopenharmony_ci}
4435db71995Sopenharmony_ciFolderManager& FolderManager::operator=(FolderManager&& other) noexcept {
4445db71995Sopenharmony_ci    folder = other.folder;
4455db71995Sopenharmony_ci    files = other.files;
4465db71995Sopenharmony_ci    other.folder.str().clear();
4475db71995Sopenharmony_ci    return *this;
4485db71995Sopenharmony_ci}
4495db71995Sopenharmony_ci
4505db71995Sopenharmony_cipath FolderManager::write_manifest(std::string const& name, std::string const& contents) {
4515db71995Sopenharmony_ci    path out_path = folder / name;
4525db71995Sopenharmony_ci    auto found = std::find(files.begin(), files.end(), name);
4535db71995Sopenharmony_ci    if (found != files.end()) {
4545db71995Sopenharmony_ci        std::cout << "Overwriting manifest " << name << ". Was this intended?\n";
4555db71995Sopenharmony_ci    } else {
4565db71995Sopenharmony_ci        files.emplace_back(name);
4575db71995Sopenharmony_ci    }
4585db71995Sopenharmony_ci    auto file = std::ofstream(native_path(out_path.str()), std::ios_base::trunc | std::ios_base::out);
4595db71995Sopenharmony_ci    if (!file) {
4605db71995Sopenharmony_ci        std::cerr << "Failed to create manifest " << name << " at " << out_path.str() << "\n";
4615db71995Sopenharmony_ci        return out_path;
4625db71995Sopenharmony_ci    }
4635db71995Sopenharmony_ci    file << contents << std::endl;
4645db71995Sopenharmony_ci    return out_path;
4655db71995Sopenharmony_ci}
4665db71995Sopenharmony_civoid FolderManager::add_existing_file(std::string const& file_name) { files.emplace_back(file_name); }
4675db71995Sopenharmony_ci
4685db71995Sopenharmony_ci// close file handle, delete file, remove `name` from managed file list.
4695db71995Sopenharmony_civoid FolderManager::remove(std::string const& name) {
4705db71995Sopenharmony_ci    path out_path = folder / name;
4715db71995Sopenharmony_ci    auto found = std::find(files.begin(), files.end(), name);
4725db71995Sopenharmony_ci    if (found != files.end()) {
4735db71995Sopenharmony_ci        int rc = std::remove(out_path.c_str());
4745db71995Sopenharmony_ci        if (rc != 0) {
4755db71995Sopenharmony_ci            std::cerr << "Failed to remove file " << name << " at " << out_path.str() << "\n";
4765db71995Sopenharmony_ci        }
4775db71995Sopenharmony_ci
4785db71995Sopenharmony_ci        files.erase(found);
4795db71995Sopenharmony_ci
4805db71995Sopenharmony_ci    } else {
4815db71995Sopenharmony_ci        std::cout << "Couldn't remove file " << name << " at " << out_path.str() << ".\n";
4825db71995Sopenharmony_ci    }
4835db71995Sopenharmony_ci}
4845db71995Sopenharmony_ci
4855db71995Sopenharmony_ci// copy file into this folder
4865db71995Sopenharmony_cipath FolderManager::copy_file(path const& file, std::string const& new_name) {
4875db71995Sopenharmony_ci    auto new_filepath = folder / new_name;
4885db71995Sopenharmony_ci    auto found = std::find(files.begin(), files.end(), new_name);
4895db71995Sopenharmony_ci    if (found != files.end()) {
4905db71995Sopenharmony_ci        std::cout << "File location already contains" << new_name << ". Is this a bug?\n";
4915db71995Sopenharmony_ci    } else if (file.str() == new_filepath.str()) {
4925db71995Sopenharmony_ci        std::cout << "Trying to copy " << new_name << " into itself. Is this a bug?\n";
4935db71995Sopenharmony_ci    } else {
4945db71995Sopenharmony_ci        files.emplace_back(new_name);
4955db71995Sopenharmony_ci    }
4965db71995Sopenharmony_ci    std::ifstream src(native_path(file.str()), std::ios::binary);
4975db71995Sopenharmony_ci    if (!src) {
4985db71995Sopenharmony_ci        std::cerr << "Failed to create file " << file.str() << " for copying from\n";
4995db71995Sopenharmony_ci        return new_filepath;
5005db71995Sopenharmony_ci    }
5015db71995Sopenharmony_ci    std::ofstream dst(native_path(new_filepath.str()), std::ios::binary);
5025db71995Sopenharmony_ci    if (!dst) {
5035db71995Sopenharmony_ci        std::cerr << "Failed to create file " << new_filepath.str() << " for copying to\n";
5045db71995Sopenharmony_ci        return new_filepath;
5055db71995Sopenharmony_ci    }
5065db71995Sopenharmony_ci    dst << src.rdbuf();
5075db71995Sopenharmony_ci    return new_filepath;
5085db71995Sopenharmony_ci}
5095db71995Sopenharmony_ci}  // namespace fs
5105db71995Sopenharmony_ci
5115db71995Sopenharmony_ciconst char* get_platform_wsi_extension([[maybe_unused]] const char* api_selection) {
5125db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_ANDROID_KHR)
5135db71995Sopenharmony_ci    return "VK_KHR_android_surface";
5145db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_DIRECTFB_EXT)
5155db71995Sopenharmony_ci    return "VK_EXT_directfb_surface";
5165db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_FUCHSIA)
5175db71995Sopenharmony_ci    return "VK_FUCHSIA_imagepipe_surface";
5185db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_GGP)
5195db71995Sopenharmony_ci    return "VK_GGP_stream_descriptor_surface";
5205db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_IOS_MVK)
5215db71995Sopenharmony_ci    return "VK_MVK_ios_surface";
5225db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT)
5235db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_MACOS_MVK)
5245db71995Sopenharmony_ci    if (string_eq(api_selection, "VK_USE_PLATFORM_MACOS_MVK")) return "VK_MVK_macos_surface";
5255db71995Sopenharmony_ci#endif
5265db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_METAL_EXT)
5275db71995Sopenharmony_ci    if (string_eq(api_selection, "VK_USE_PLATFORM_METAL_EXT")) return "VK_EXT_metal_surface";
5285db71995Sopenharmony_ci    return "VK_EXT_metal_surface";
5295db71995Sopenharmony_ci#endif
5305db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_SCREEN_QNX)
5315db71995Sopenharmony_ci    return "VK_QNX_screen_surface";
5325db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_VI_NN)
5335db71995Sopenharmony_ci    return "VK_NN_vi_surface";
5345db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
5355db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_XCB_KHR)
5365db71995Sopenharmony_ci    if (string_eq(api_selection, "VK_USE_PLATFORM_XCB_KHR")) return "VK_KHR_xcb_surface";
5375db71995Sopenharmony_ci#endif
5385db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_XLIB_KHR)
5395db71995Sopenharmony_ci    if (string_eq(api_selection, "VK_USE_PLATFORM_XLIB_KHR")) return "VK_KHR_xlib_surface";
5405db71995Sopenharmony_ci#endif
5415db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
5425db71995Sopenharmony_ci    if (string_eq(api_selection, "VK_USE_PLATFORM_WAYLAND_KHR")) return "VK_KHR_wayland_surface";
5435db71995Sopenharmony_ci#endif
5445db71995Sopenharmony_ci#if defined(VK_USE_PLATFORM_XCB_KHR)
5455db71995Sopenharmony_ci    return "VK_KHR_xcb_surface";
5465db71995Sopenharmony_ci#endif
5475db71995Sopenharmony_ci#elif defined(VK_USE_PLATFORM_WIN32_KHR)
5485db71995Sopenharmony_ci    return "VK_KHR_win32_surface";
5495db71995Sopenharmony_ci#else
5505db71995Sopenharmony_ci    return "VK_KHR_display";
5515db71995Sopenharmony_ci#endif
5525db71995Sopenharmony_ci}
5535db71995Sopenharmony_ci
5545db71995Sopenharmony_cibool string_eq(const char* a, const char* b) noexcept { return a && b && strcmp(a, b) == 0; }
5555db71995Sopenharmony_cibool string_eq(const char* a, const char* b, size_t len) noexcept { return a && b && strncmp(a, b, len) == 0; }
5565db71995Sopenharmony_ci
5575db71995Sopenharmony_ciInstanceCreateInfo::InstanceCreateInfo() {
5585db71995Sopenharmony_ci    instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
5595db71995Sopenharmony_ci    application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
5605db71995Sopenharmony_ci}
5615db71995Sopenharmony_ci
5625db71995Sopenharmony_ciVkInstanceCreateInfo* InstanceCreateInfo::get() noexcept {
5635db71995Sopenharmony_ci    if (fill_in_application_info) {
5645db71995Sopenharmony_ci        application_info.pApplicationName = app_name.c_str();
5655db71995Sopenharmony_ci        application_info.pEngineName = engine_name.c_str();
5665db71995Sopenharmony_ci        application_info.applicationVersion = app_version;
5675db71995Sopenharmony_ci        application_info.engineVersion = engine_version;
5685db71995Sopenharmony_ci        application_info.apiVersion = api_version;
5695db71995Sopenharmony_ci        instance_info.pApplicationInfo = &application_info;
5705db71995Sopenharmony_ci    }
5715db71995Sopenharmony_ci    instance_info.flags = flags;
5725db71995Sopenharmony_ci    instance_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
5735db71995Sopenharmony_ci    instance_info.ppEnabledLayerNames = enabled_layers.data();
5745db71995Sopenharmony_ci    instance_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
5755db71995Sopenharmony_ci    instance_info.ppEnabledExtensionNames = enabled_extensions.data();
5765db71995Sopenharmony_ci    return &instance_info;
5775db71995Sopenharmony_ci}
5785db71995Sopenharmony_ciInstanceCreateInfo& InstanceCreateInfo::set_api_version(uint32_t major, uint32_t minor, uint32_t patch) {
5795db71995Sopenharmony_ci    this->api_version = VK_MAKE_API_VERSION(0, major, minor, patch);
5805db71995Sopenharmony_ci    return *this;
5815db71995Sopenharmony_ci}
5825db71995Sopenharmony_ciInstanceCreateInfo& InstanceCreateInfo::setup_WSI(const char* api_selection) {
5835db71995Sopenharmony_ci    add_extensions({"VK_KHR_surface", get_platform_wsi_extension(api_selection)});
5845db71995Sopenharmony_ci    return *this;
5855db71995Sopenharmony_ci}
5865db71995Sopenharmony_ci
5875db71995Sopenharmony_ciDeviceQueueCreateInfo::DeviceQueueCreateInfo() { queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; }
5885db71995Sopenharmony_ciDeviceQueueCreateInfo::DeviceQueueCreateInfo(const VkDeviceQueueCreateInfo* create_info) {
5895db71995Sopenharmony_ci    queue_create_info = *create_info;
5905db71995Sopenharmony_ci    for (uint32_t i = 0; i < create_info->queueCount; i++) {
5915db71995Sopenharmony_ci        priorities.push_back(create_info->pQueuePriorities[i]);
5925db71995Sopenharmony_ci    }
5935db71995Sopenharmony_ci}
5945db71995Sopenharmony_ci
5955db71995Sopenharmony_ciVkDeviceQueueCreateInfo DeviceQueueCreateInfo::get() noexcept {
5965db71995Sopenharmony_ci    queue_create_info.pQueuePriorities = priorities.data();
5975db71995Sopenharmony_ci    queue_create_info.queueCount = 1;
5985db71995Sopenharmony_ci    queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
5995db71995Sopenharmony_ci    return queue_create_info;
6005db71995Sopenharmony_ci}
6015db71995Sopenharmony_ci
6025db71995Sopenharmony_ciDeviceCreateInfo::DeviceCreateInfo(const VkDeviceCreateInfo* create_info) {
6035db71995Sopenharmony_ci    dev = *create_info;
6045db71995Sopenharmony_ci    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
6055db71995Sopenharmony_ci        enabled_extensions.push_back(create_info->ppEnabledExtensionNames[i]);
6065db71995Sopenharmony_ci    }
6075db71995Sopenharmony_ci    for (uint32_t i = 0; i < create_info->enabledLayerCount; i++) {
6085db71995Sopenharmony_ci        enabled_layers.push_back(create_info->ppEnabledLayerNames[i]);
6095db71995Sopenharmony_ci    }
6105db71995Sopenharmony_ci    for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) {
6115db71995Sopenharmony_ci        device_queue_infos.push_back(create_info->pQueueCreateInfos[i]);
6125db71995Sopenharmony_ci    }
6135db71995Sopenharmony_ci}
6145db71995Sopenharmony_ci
6155db71995Sopenharmony_ciVkDeviceCreateInfo* DeviceCreateInfo::get() noexcept {
6165db71995Sopenharmony_ci    dev.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
6175db71995Sopenharmony_ci    dev.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
6185db71995Sopenharmony_ci    dev.ppEnabledLayerNames = enabled_layers.data();
6195db71995Sopenharmony_ci    dev.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
6205db71995Sopenharmony_ci    dev.ppEnabledExtensionNames = enabled_extensions.data();
6215db71995Sopenharmony_ci    uint32_t index = 0;
6225db71995Sopenharmony_ci    for (auto& queue : queue_info_details) {
6235db71995Sopenharmony_ci        queue.queue_create_info.queueFamilyIndex = index++;
6245db71995Sopenharmony_ci        queue.queue_create_info.queueCount = 1;
6255db71995Sopenharmony_ci        device_queue_infos.push_back(queue.get());
6265db71995Sopenharmony_ci    }
6275db71995Sopenharmony_ci
6285db71995Sopenharmony_ci    dev.queueCreateInfoCount = static_cast<uint32_t>(device_queue_infos.size());
6295db71995Sopenharmony_ci    dev.pQueueCreateInfos = device_queue_infos.data();
6305db71995Sopenharmony_ci    return &dev;
6315db71995Sopenharmony_ci}
6325db71995Sopenharmony_ci
6335db71995Sopenharmony_ci#if defined(WIN32)
6345db71995Sopenharmony_cistd::string narrow(const std::wstring& utf16) {
6355db71995Sopenharmony_ci    if (utf16.empty()) {
6365db71995Sopenharmony_ci        return {};
6375db71995Sopenharmony_ci    }
6385db71995Sopenharmony_ci    int size = WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), nullptr, 0, nullptr, nullptr);
6395db71995Sopenharmony_ci    if (size <= 0) {
6405db71995Sopenharmony_ci        return {};
6415db71995Sopenharmony_ci    }
6425db71995Sopenharmony_ci    std::string utf8(size, '\0');
6435db71995Sopenharmony_ci    if (WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.size()), &utf8[0], size, nullptr, nullptr) != size) {
6445db71995Sopenharmony_ci        return {};
6455db71995Sopenharmony_ci    }
6465db71995Sopenharmony_ci    return utf8;
6475db71995Sopenharmony_ci}
6485db71995Sopenharmony_ci
6495db71995Sopenharmony_cistd::wstring widen(const std::string& utf8) {
6505db71995Sopenharmony_ci    if (utf8.empty()) {
6515db71995Sopenharmony_ci        return {};
6525db71995Sopenharmony_ci    }
6535db71995Sopenharmony_ci    int size = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
6545db71995Sopenharmony_ci    if (size <= 0) {
6555db71995Sopenharmony_ci        return {};
6565db71995Sopenharmony_ci    }
6575db71995Sopenharmony_ci    std::wstring utf16(size, L'\0');
6585db71995Sopenharmony_ci    if (MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), &utf16[0], size) != size) {
6595db71995Sopenharmony_ci        return {};
6605db71995Sopenharmony_ci    }
6615db71995Sopenharmony_ci    return utf16;
6625db71995Sopenharmony_ci}
6635db71995Sopenharmony_ci#endif
664