fix: handle UTF-8 file paths on Windows (#2145)

This commit is contained in:
therealshulgin authored and GitHub committed 2026-10-17 00:50:42 +08:00
1 parent 8c442fb0ad
commit 2f016e8e30
9 files changed
+100 -82

No files matched your search

+38 -29
View File
@@ -75,7 +75,7 @@ static std::string utf16_to_utf8(const std::wstring& wstr) {
return utf8;
}
static std::string argv_to_utf8(int index, const char** argv) {
std::string argv_to_utf8(int index, const char** argv) {
(void)argv;
int argc;
wchar_t** argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
@@ -91,7 +91,7 @@ static std::string argv_to_utf8(int index, const char** argv) {
}
#else // Linux / macOS
static std::string argv_to_utf8(int index, const char** argv) {
std::string argv_to_utf8(int index, const char** argv) {
return std::string(argv[index]);
}
@@ -839,16 +839,17 @@ ArgOptions SDContextParams::get_options() {
void SDContextParams::build_embedding_map() {
static const std::vector<std::string> valid_ext = {".gguf", ".safetensors", ".pt", ".ckpt"};
if (!fs::exists(embedding_dir) || !fs::is_directory(embedding_dir)) {
const fs::path embedding_dir_path = fs::u8path(embedding_dir);
if (!fs::exists(embedding_dir_path) || !fs::is_directory(embedding_dir_path)) {
return;
}
for (auto& p : fs::directory_iterator(embedding_dir)) {
for (auto& p : fs::directory_iterator(embedding_dir_path)) {
if (!p.is_regular_file())
continue;
auto path = p.path();
std::string ext = path.extension().string();
std::string ext = path.extension().u8string();
bool valid = false;
for (auto& e : valid_ext) {
@@ -860,8 +861,8 @@ void SDContextParams::build_embedding_map() {
if (!valid)
continue;
std::string key = path.stem().string();
std::string value = path.string();
std::string key = path.stem().u8string();
std::string value = path.u8string();
embedding_map[key] = value;
}
@@ -1572,7 +1573,7 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
ref_image_paths.push_back(argv[index]);
ref_image_paths.push_back(argv_to_utf8(index, argv));
return 1;
};
@@ -1580,7 +1581,7 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
ref_video_paths.push_back(argv[index]);
ref_video_paths.push_back(argv_to_utf8(index, argv));
return 1;
};
@@ -1588,7 +1589,7 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
ref_video_audio_paths.push_back(argv[index]);
ref_video_audio_paths.push_back(argv_to_utf8(index, argv));
return 1;
};
@@ -1596,7 +1597,7 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
ref_audio_paths.push_back(argv[index]);
ref_audio_paths.push_back(argv_to_utf8(index, argv));
return 1;
};
@@ -1604,7 +1605,7 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
ref_audio_paths.push_back(argv[index]);
ref_audio_paths.push_back(argv_to_utf8(index, argv));
return 1;
};
@@ -1703,15 +1704,15 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
const char* arg = argv[index];
std::ifstream f(arg, std::ios::binary);
const std::string arg = argv_to_utf8(index, argv);
std::ifstream f(fs::u8path(arg), std::ios::binary);
try {
prompt = std::string(std::istreambuf_iterator<char>{f}, {});
} catch (const std::ios_base::failure&) {
f.setstate(std::ios_base::failbit);
}
if (f.fail()) {
LOG_ERROR("error: failed to read prompt file '%s'\n", arg);
LOG_ERROR("error: failed to read prompt file '%s'\n", arg.c_str());
return -1;
}
return 1;
@@ -1721,15 +1722,15 @@ ArgOptions SDGenerationParams::get_options() {
if (++index >= argc) {
return -1;
}
const char* arg = argv[index];
std::ifstream f(arg, std::ios::binary);
const std::string arg = argv_to_utf8(index, argv);
std::ifstream f(fs::u8path(arg), std::ios::binary);
try {
negative_prompt = std::string(std::istreambuf_iterator<char>{f}, {});
} catch (const std::ios_base::failure&) {
f.setstate(std::ios_base::failbit);
}
if (f.fail()) {
LOG_ERROR("error: failed to read negative prompt file '%s'\n", arg);
LOG_ERROR("error: failed to read negative prompt file '%s'\n", arg.c_str());
return -1;
}
return 1;
@@ -2050,22 +2051,22 @@ static bool resolve_model_file_from_dir(const std::string& model_name,
if (model_name.empty() ||
model_name.find('/') != std::string::npos ||
model_name.find('\\') != std::string::npos ||
fs::path(model_name).has_root_path() ||
fs::u8path(model_name).has_root_path() ||
ends_with_valid_ext()) {
LOG_ERROR("%s must be a model name without path or extension: %s", label, model_name.c_str());
return false;
}
fs::path model_dir_path = model_dir;
fs::path model_dir_path = fs::u8path(model_dir);
for (const auto& ext : valid_ext) {
fs::path try_path = model_dir_path / (model_name + ext);
fs::path try_path = model_dir_path / fs::u8path(model_name + ext);
if (fs::exists(try_path) && fs::is_regular_file(try_path)) {
resolved_path = try_path.lexically_normal().string();
resolved_path = try_path.lexically_normal().u8string();
return true;
}
}
LOG_ERROR("can not find %s %s in %s", label, model_name.c_str(), model_dir_path.lexically_normal().string().c_str());
LOG_ERROR("can not find %s %s in %s", label, model_name.c_str(), model_dir_path.lexically_normal().u8string().c_str());
return false;
}
@@ -2359,10 +2360,18 @@ bool SDGenerationParams::extract_and_remove_lora(const std::string& lora_model_d
}
fs::path final_path;
if (is_absolute_path(raw_path)) {
final_path = raw_path;
} else {
final_path = fs::path(lora_model_dir) / raw_path;
try {
if (is_absolute_path(raw_path)) {
final_path = fs::u8path(raw_path);
} else {
final_path = fs::u8path(lora_model_dir) / fs::u8path(raw_path);
}
} catch (const std::exception&) { // not UTF-8, e.g. a prompt file in another encoding
LOG_WARN("invalid lora path %s", raw_path.c_str());
tmp = m.suffix().str();
prompt = std::regex_replace(prompt, re, "", std::regex_constants::format_first_only);
missing = true;
continue;
}
if (!fs::exists(final_path)) {
bool found = false;
@@ -2376,7 +2385,7 @@ bool SDGenerationParams::extract_and_remove_lora(const std::string& lora_model_d
}
}
if (!found) {
LOG_WARN("can not found lora %s", final_path.lexically_normal().string().c_str());
LOG_WARN("can not found lora %s", final_path.lexically_normal().u8string().c_str());
tmp = m.suffix().str();
prompt = std::regex_replace(prompt, re, "", std::regex_constants::format_first_only);
missing = true;
@@ -2384,7 +2393,7 @@ bool SDGenerationParams::extract_and_remove_lora(const std::string& lora_model_d
}
}
const std::string key = final_path.lexically_normal().string();
const std::string key = final_path.lexically_normal().u8string();
if (is_high_noise)
high_noise_lora_map[key] += mul;
+4
View File
@@ -12,6 +12,10 @@
#include "resource_owners.hpp"
#include "stable-diffusion.h"
// The command-line argument at `index` as UTF-8 (on Windows, read again from
// the UTF-16 command line: argv itself is in the ANSI code page).
std::string argv_to_utf8(int index, const char** argv);
#define SAFE_STR(s) ((s) ? (s) : "")
#define BOOL_STR(b) ((b) ? "true" : "false")
+7 -5
View File
@@ -15,10 +15,12 @@
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#define STBI_WINDOWS_UTF8
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_WRITE_STATIC
#define STBIW_WINDOWS_UTF8
#include "stb_image_write.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
@@ -147,7 +149,7 @@ private:
#endif
bool read_binary_file_bytes(const char* path, std::vector<uint8_t>& data) {
std::ifstream fin(fs::path(path), std::ios::binary);
std::ifstream fin(fs::u8path(path), std::ios::binary);
if (!fin) {
return false;
}
@@ -170,7 +172,7 @@ bool read_binary_file_bytes(const char* path, std::vector<uint8_t>& data) {
}
bool write_binary_file_bytes(const std::string& path, const std::vector<uint8_t>& data) {
std::ofstream fout(fs::path(path), std::ios::binary);
std::ofstream fout(fs::u8path(path), std::ios::binary);
if (!fout) {
return false;
}
@@ -714,7 +716,7 @@ static std::pair<uint64_t, uint64_t> audio_sample_range_for_video_frame(const sd
}
EncodedImageFormat encoded_image_format_from_path(const std::string& path) {
std::string ext = fs::path(path).extension().string();
std::string ext = fs::u8path(path).extension().u8string();
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if (ext == ".jpg" || ext == ".jpeg" || ext == ".jpe") {
@@ -1413,7 +1415,7 @@ bool write_wav_to_file(const std::string& path,
return false;
}
std::ofstream file(path, std::ios::binary);
std::ofstream file(fs::u8path(path), std::ios::binary);
if (!file.is_open()) {
return false;
}
@@ -1475,7 +1477,7 @@ bool load_wav_from_file(const std::string& path,
sample_rate = 0;
channels = 0;
std::ifstream file(path, std::ios::binary);
std::ifstream file(fs::u8path(path), std::ios::binary);
uint8_t riff_header[12];
if (!file.read(reinterpret_cast<char*>(riff_header), sizeof(riff_header)) ||
std::memcmp(riff_header, "RIFF", 4) != 0 ||