From d514ac4c1681834916b3375cb8c850cb13b2cef2 Mon Sep 17 00:00:00 2001 From: kellemar Date: Sun, 28 Dec 2025 03:17:22 +0800 Subject: [PATCH] libobs: Fix crash with non-ASCII characters in formatted filenames --- libobs/util/platform.c | 39 +++++++++++++++++++++++++++++++++++++-- libobs/util/platform.h | 2 ++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/libobs/util/platform.c b/libobs/util/platform.c index 548afc03f73ad7..d40b41b1977918 100644 --- a/libobs/util/platform.c +++ b/libobs/util/platform.c @@ -695,6 +695,41 @@ static void erase_ch(struct dstr *str, size_t pos) *str = new_str; } +size_t os_strftime_utf8(char *dst, size_t dst_size, const char *format, const struct tm *tm) +{ + if (!dst || !dst_size || !format || !tm) + return 0; + +#ifdef _WIN32 + /* + * On Windows, strftime() returns strings encoded in the system's + * ANSI codepage, not UTF-8. This causes issues when locale-specific + * format specifiers (like %Z for timezone) contain non-ASCII + * characters (e.g., German "Mitteleuropäische Zeit"). + * + * Use wcsftime() to get proper wide characters, then convert to UTF-8. + */ + wchar_t wformat[64]; + wchar_t wdst[256]; + + size_t format_len = os_utf8_to_wcs(format, 0, wformat, sizeof(wformat) / sizeof(wchar_t)); + if (!format_len) { + dst[0] = '\0'; + return 0; + } + + size_t wlen = wcsftime(wdst, sizeof(wdst) / sizeof(wchar_t), wformat, tm); + if (!wlen) { + dst[0] = '\0'; + return 0; + } + + return os_wcs_to_utf8(wdst, wlen, dst, dst_size); +#else + return strftime(dst, dst_size, format, tm); +#endif +} + char *os_generate_formatted_filename(const char *extension, bool space, const char *format) { time_t now = time(0); @@ -727,9 +762,9 @@ char *os_generate_formatted_filename(const char *extension, bool space, const ch if (astrcmp_n(cmp, spec[i][0], len) == 0) { if (strlen(spec[i][1])) - strftime(convert, sizeof(convert), spec[i][1], cur_time); + os_strftime_utf8(convert, sizeof(convert), spec[i][1], cur_time); else - strftime(convert, sizeof(convert), spec[i][0], cur_time); + os_strftime_utf8(convert, sizeof(convert), spec[i][0], cur_time); dstr_copy(&c, convert); if (c.len && valid_string(c.array)) diff --git a/libobs/util/platform.h b/libobs/util/platform.h index 592d9eca6e5c8c..4f19cfbb984e5e 100644 --- a/libobs/util/platform.h +++ b/libobs/util/platform.h @@ -166,6 +166,8 @@ EXPORT int os_safe_replace(const char *target_path, const char *from_path, const EXPORT char *os_generate_formatted_filename(const char *extension, bool space, const char *format); +EXPORT size_t os_strftime_utf8(char *dst, size_t dst_size, const char *format, const struct tm *tm); + struct os_inhibit_info; typedef struct os_inhibit_info os_inhibit_t;