#ifndef WIN_MAIN_UTF8_H #define WIN_MAIN_UTF8_H /* For Windows systems this provides a way to get UTF-8 encoded argv strings, * and also overrides fopen to accept UTF-8 filenames. Working with wmain * directly complicates cross-platform compatibility, while normal main() in * Windows uses the current codepage (which has limited availability of * characters). * * For MinGW, you must link with -municode */ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include #ifdef __cplusplus #include #define STATIC_CAST(...) static_cast<__VA_ARGS__> #define REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__> #else #define STATIC_CAST(...) (__VA_ARGS__) #define REINTERPRET_CAST(...) (__VA_ARGS__) #endif static FILE *my_fopen(const char *fname, const char *mode) { wchar_t *wname=NULL, *wmode=NULL; int namelen, modelen; FILE *file = NULL; errno_t err; namelen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0); modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); if(namelen <= 0 || modelen <= 0) { fprintf(stderr, "Failed to convert UTF-8 fname \"%s\", mode \"%s\"\n", fname, mode); return NULL; } #ifdef __cplusplus auto strbuf = std::make_unique(static_cast(namelen)+modelen); wname = strbuf.get(); #else wname = (wchar_t*)calloc(sizeof(wchar_t), (size_t)namelen + modelen); #endif wmode = wname + namelen; MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen); MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen); err = _wfopen_s(&file, wname, wmode); if(err) { errno = err; file = NULL; } #ifndef __cplusplus free(wname); #endif return file; } #define fopen my_fopen /* SDL overrides main and provides UTF-8 args for us. */ #if !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) int my_main(int, char**); #define main my_main #ifdef __cplusplus extern "C" #endif int wmain(int argc, wchar_t **wargv) { char **argv; size_t total; int i; total = sizeof(*argv) * STATIC_CAST(size_t)(argc); for(i = 0;i < argc;i++) total += STATIC_CAST(size_t)(WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL)); #ifdef __cplusplus auto argbuf = std::make_unique(total); argv = reinterpret_cast(argbuf.get()); #else argv = (char**)calloc(1, total); #endif argv[0] = REINTERPRET_CAST(char*)(argv + argc); for(i = 0;i < argc-1;i++) { int len = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL); argv[i+1] = argv[i] + len; } WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL); #ifdef __cplusplus return main(argc, argv); #else i = main(argc, argv); free(argv); return i; #endif } #endif /* !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) */ #endif /* _WIN32 */ #endif /* WIN_MAIN_UTF8_H */