fae78a8abb3e57978a1b516f2eba9f26e02da38c
[platform/upstream/flac.git] / src / share / win_utf8_io / win_utf8_io.c
1
2 #include <stdio.h>
3 #include <sys/stat.h>
4 #include <sys/utime.h>
5 #include <io.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdarg.h>
9 #include <windows.h> /* for WideCharToMultiByte and MultiByteToWideChar */
10
11 #include "share/win_utf8_io.h"
12
13 static UINT win_utf8_io_codepage = CP_ACP;
14
15 /* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freeing memory */
16 static
17 char *utf8_from_wchar(const wchar_t *wstr)
18 {
19         char *utf8str;
20         int len;
21
22         if (!wstr) return NULL;
23         if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL)) == 0) return NULL;
24         if ((utf8str = (char *)malloc(++len)) == NULL) return NULL;
25         if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL) == 0) {
26                 free(utf8str);
27                 utf8str = NULL;
28         }
29
30         return utf8str;
31 }
32
33 /* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
34 static
35 wchar_t *wchar_from_utf8(const char *str)
36 {
37         wchar_t *widestr;
38         int len;
39
40         if (!str) return NULL;
41         len=(int)strlen(str)+1;
42         if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) != NULL) {
43                 if (MultiByteToWideChar(win_utf8_io_codepage, 0, str, len, widestr, len) == 0) {
44                         if (MultiByteToWideChar(CP_ACP, 0, str, len, widestr, len) == 0) { /* try conversion from Ansi in case the initial UTF-8 conversion had failed */
45                                 free(widestr);
46                                 widestr = NULL;
47                         }
48                 }
49         }
50
51         return widestr;
52 }
53
54 /* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8 */
55 int get_utf8_argv(int *argc, char ***argv)
56 {
57         typedef int (__cdecl *__wgetmainargs_)(int*, wchar_t***, wchar_t***, int, int*);
58         __wgetmainargs_ __wgetmainargs;
59         HMODULE handle;
60         int wargc;
61         wchar_t **wargv;
62         wchar_t **wenv;
63         char **utf8argv;
64         int ret, i;
65
66         if ((handle = LoadLibrary("msvcrt.dll")) == NULL) return 1;
67         if ((__wgetmainargs = (__wgetmainargs_)GetProcAddress(handle, "__wgetmainargs")) == NULL) return 1;
68         i = 0;
69         if (__wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) return 1;
70         if ((utf8argv = (char **)malloc(wargc*sizeof(char*))) == NULL) return 1;
71         ret = 0;
72
73         for (i=0; i<wargc; i++) {
74                 if ((utf8argv[i] = utf8_from_wchar(wargv[i])) == NULL) {
75                         ret = 1;
76                         break;
77                 }
78                 if (ret != 0) break;
79         }
80
81         FreeLibrary(handle);
82
83         if (ret == 0) {
84                 win_utf8_io_codepage = CP_UTF8;
85                 *argc = wargc;
86                 *argv = utf8argv;
87         } else {
88                 free(utf8argv);
89         }
90
91         return ret;
92 }
93
94 /* return number of characters in the UTF-8 string */
95 size_t strlen_utf8(const char *str)
96 {
97         size_t len;
98         if ((len = MultiByteToWideChar(win_utf8_io_codepage, 0, str, -1, NULL, 0)) == 0)
99                 len = strlen(str);
100         return len;
101 }
102
103 /* get the console width in characters */
104 int win_get_console_width()
105 {
106         int width = 80;
107         CONSOLE_SCREEN_BUFFER_INFO csbi;
108         HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
109         if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0) width = csbi.dwSize.X;
110         return width;
111 }
112
113 /* print functions */
114
115 int print_console(FILE *stream, const wchar_t *text, DWORD len)
116 {
117         static HANDLE hOut;
118         static HANDLE hErr;
119         DWORD out;
120         hOut = GetStdHandle(STD_OUTPUT_HANDLE);
121         hErr = GetStdHandle(STD_ERROR_HANDLE);
122         if (stream == stdout && hOut != INVALID_HANDLE_VALUE && GetFileType(hOut) == FILE_TYPE_CHAR) {
123                 if (WriteConsoleW(hOut, text, len, &out, NULL) == 0) return -1;
124                 return out;
125         } else if (stream == stderr && hErr != INVALID_HANDLE_VALUE && GetFileType(hErr) == FILE_TYPE_CHAR) {
126                 if (WriteConsoleW(hErr, text, len, &out, NULL) == 0) return -1;
127                 return out;
128         } else {
129                 int ret = fwprintf(stream, L"%s", text);
130                 if (ret < 0) return ret;
131                 return len;
132         }
133 }
134
135 int printf_utf8(const char *format, ...)
136 {
137         char *utmp = NULL;
138         wchar_t *wout = NULL;
139         int ret = -1;
140
141         while (1) {
142                 va_list argptr;
143                 if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
144                 va_start(argptr, format);
145                 ret = vsprintf(utmp, format, argptr);
146                 va_end(argptr);
147                 if (ret < 0) break;
148                 if (!(wout = wchar_from_utf8(utmp))) {
149                         ret = -1;
150                         break;
151                 }
152                 ret = print_console(stdout, wout, wcslen(wout));
153                 break;
154         }
155         if (utmp) free(utmp);
156         if (wout) free(wout);
157
158         return ret;
159 }
160
161 int fprintf_utf8(FILE *stream, const char *format, ...)
162 {
163         char *utmp = NULL;
164         wchar_t *wout = NULL;
165         int ret = -1;
166
167         while (1) {
168                 va_list argptr;
169                 if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
170                 va_start(argptr, format);
171                 ret = vsprintf(utmp, format, argptr);
172                 va_end(argptr);
173                 if (ret < 0) break;
174                 if (!(wout = wchar_from_utf8(utmp))) {
175                         ret = -1;
176                         break;
177                 }
178                 ret = print_console(stream, wout, wcslen(wout));
179                 break;
180         }
181         if (utmp) free(utmp);
182         if (wout) free(wout);
183
184         return ret;
185 }
186
187 int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
188 {
189         char *utmp = NULL;
190         wchar_t *wout = NULL;
191         int ret = -1;
192
193         while (1) {
194                 if (!(utmp = (char *)malloc(32768*sizeof(char)))) break;
195                 if ((ret = vsprintf(utmp, format, argptr)) < 0) break;
196                 if (!(wout = wchar_from_utf8(utmp))) {
197                         ret = -1;
198                         break;
199                 }
200                 ret = print_console(stream, wout, wcslen(wout));
201                 break;
202         }
203         if (utmp) free(utmp);
204         if (wout) free(wout);
205
206         return ret;
207 }
208
209 /* file functions */
210
211 FILE *fopen_utf8(const char *filename, const char *mode)
212 {
213         wchar_t *wname = NULL;
214         wchar_t *wmode = NULL;
215         FILE *f = NULL;
216
217         while (1) {
218                 if (!(wname = wchar_from_utf8(filename))) break;
219                 if (!(wmode = wchar_from_utf8(mode))) break;
220                 f = _wfopen(wname, wmode);
221                 break;
222         }
223         if (wname) free(wname);
224         if (wmode) free(wmode);
225
226         return f;
227 }
228
229 int _stat64_utf8(const char *path, struct __stat64 *buffer)
230 {
231         wchar_t *wpath;
232         int ret;
233
234         if (!(wpath = wchar_from_utf8(path))) return -1;
235         ret = _wstat64(wpath, buffer);
236         free(wpath);
237
238         return ret;
239 }
240
241 int chmod_utf8(const char *filename, int pmode)
242 {
243         wchar_t *wname;
244         int ret;
245
246         if (!(wname = wchar_from_utf8(filename))) return -1;
247         ret = _wchmod(wname, pmode);
248         free(wname);
249
250         return ret;
251 }
252
253 int utime_utf8(const char *filename, struct utimbuf *times)
254 {
255         wchar_t *wname;
256         struct _utimbuf ut;
257         int ret;
258
259         if (!(wname = wchar_from_utf8(filename))) return -1;
260         ret = _wutime(wname, &ut);
261         free(wname);
262
263         if (ret != -1) {
264                 if (sizeof(*times) == sizeof(ut)) {
265                         memcpy(times, &ut, sizeof(ut));
266                 } else {
267                         times->actime = ut.actime;
268                         times->modtime = ut.modtime;
269                 }
270         }
271
272         return ret;
273 }
274
275 int unlink_utf8(const char *filename)
276 {
277         wchar_t *wname;
278         int ret;
279
280         if (!(wname = wchar_from_utf8(filename))) return -1;
281         ret = _wunlink(wname);
282         free(wname);
283
284         return ret;
285 }
286
287 int rename_utf8(const char *oldname, const char *newname)
288 {
289         wchar_t *wold = NULL;
290         wchar_t *wnew = NULL;
291         int ret = -1;
292
293         while (1) {
294                 if (!(wold = wchar_from_utf8(oldname))) break;
295                 if (!(wnew = wchar_from_utf8(newname))) break;
296                 ret = _wrename(wold, wnew);
297                 break;
298         }
299         if (wold) free(wold);
300         if (wnew) free(wnew);
301
302         return ret;
303 }