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