🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
2.9 KiB

  1. #ifndef WIN_MAIN_UTF8_H
  2. #define WIN_MAIN_UTF8_H
  3. /* For Windows systems this provides a way to get UTF-8 encoded argv strings,
  4. * and also overrides fopen to accept UTF-8 filenames. Working with wmain
  5. * directly complicates cross-platform compatibility, while normal main() in
  6. * Windows uses the current codepage (which has limited availability of
  7. * characters).
  8. *
  9. * For MinGW, you must link with -municode
  10. */
  11. #ifdef _WIN32
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <windows.h>
  14. #include <shellapi.h>
  15. #include <wchar.h>
  16. #ifdef __cplusplus
  17. #include <memory>
  18. #define STATIC_CAST(...) static_cast<__VA_ARGS__>
  19. #define REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
  20. #else
  21. #define STATIC_CAST(...) (__VA_ARGS__)
  22. #define REINTERPRET_CAST(...) (__VA_ARGS__)
  23. #endif
  24. static FILE *my_fopen(const char *fname, const char *mode)
  25. {
  26. wchar_t *wname=NULL, *wmode=NULL;
  27. int namelen, modelen;
  28. FILE *file = NULL;
  29. errno_t err;
  30. namelen = MultiByteToWideChar(CP_UTF8, 0, fname, -1, NULL, 0);
  31. modelen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
  32. if(namelen <= 0 || modelen <= 0)
  33. {
  34. fprintf(stderr, "Failed to convert UTF-8 fname \"%s\", mode \"%s\"\n", fname, mode);
  35. return NULL;
  36. }
  37. #ifdef __cplusplus
  38. auto strbuf = std::make_unique<wchar_t[]>(static_cast<size_t>(namelen+modelen));
  39. wname = strbuf.get();
  40. #else
  41. wname = (wchar_t*)calloc(sizeof(wchar_t), (size_t)(namelen+modelen));
  42. #endif
  43. wmode = wname + namelen;
  44. MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen);
  45. MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen);
  46. err = _wfopen_s(&file, wname, wmode);
  47. if(err)
  48. {
  49. errno = err;
  50. file = NULL;
  51. }
  52. #ifndef __cplusplus
  53. free(wname);
  54. #endif
  55. return file;
  56. }
  57. #define fopen my_fopen
  58. /* SDL overrides main and provides UTF-8 args for us. */
  59. #if !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE)
  60. int my_main(int, char**);
  61. #define main my_main
  62. #ifdef __cplusplus
  63. extern "C"
  64. #endif
  65. int wmain(int argc, wchar_t **wargv)
  66. {
  67. char **argv;
  68. size_t total;
  69. int i;
  70. total = sizeof(*argv) * STATIC_CAST(size_t)(argc);
  71. for(i = 0;i < argc;i++)
  72. total += STATIC_CAST(size_t)(WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL,
  73. NULL));
  74. #ifdef __cplusplus
  75. auto argbuf = std::make_unique<char[]>(total);
  76. argv = reinterpret_cast<char**>(argbuf.get());
  77. #else
  78. argv = (char**)calloc(1, total);
  79. #endif
  80. argv[0] = REINTERPRET_CAST(char*)(argv + argc);
  81. for(i = 0;i < argc-1;i++)
  82. {
  83. int len = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
  84. argv[i+1] = argv[i] + len;
  85. }
  86. WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
  87. #ifdef __cplusplus
  88. return main(argc, argv);
  89. #else
  90. i = main(argc, argv);
  91. free(argv);
  92. return i;
  93. #endif
  94. }
  95. #endif /* !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) */
  96. #endif /* _WIN32 */
  97. #endif /* WIN_MAIN_UTF8_H */