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