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