OLD | NEW |
(Empty) | |
| 1 /* libFLAC - Free Lossless Audio Codec library |
| 2 * Copyright (C) 2013-2014 Xiph.Org Foundation |
| 3 * |
| 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions |
| 6 * are met: |
| 7 * |
| 8 * - Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. |
| 10 * |
| 11 * - Redistributions in binary form must reproduce the above copyright |
| 12 * notice, this list of conditions and the following disclaimer in the |
| 13 * documentation and/or other materials provided with the distribution. |
| 14 * |
| 15 * - Neither the name of the Xiph.org Foundation nor the names of its |
| 16 * contributors may be used to endorse or promote products derived from |
| 17 * this software without specific prior written permission. |
| 18 * |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 */ |
| 31 |
| 32 #ifdef HAVE_CONFIG_H |
| 33 # include <config.h> |
| 34 #endif |
| 35 |
| 36 #include <stdio.h> |
| 37 #include <sys/stat.h> |
| 38 #include <sys/utime.h> |
| 39 #include <io.h> |
| 40 #include <stdlib.h> |
| 41 #include <string.h> |
| 42 #include <stdarg.h> |
| 43 #define WIN32_LEAN_AND_MEAN |
| 44 #include <windows.h> /* for WideCharToMultiByte and MultiByteToWideChar */ |
| 45 |
| 46 #include "share/win_utf8_io.h" |
| 47 |
| 48 #define UTF8_BUFFER_SIZE 32768 |
| 49 |
| 50 static |
| 51 int local_vsnprintf(char *str, size_t size, const char *fmt, va_list va) |
| 52 { |
| 53 int rc; |
| 54 |
| 55 #if defined _MSC_VER |
| 56 if (size == 0) |
| 57 return 1024; |
| 58 rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va); |
| 59 if (rc < 0) |
| 60 rc = size - 1; |
| 61 #elif defined __MINGW32__ |
| 62 rc = __mingw_vsnprintf (str, size, fmt, va); |
| 63 #else |
| 64 rc = vsnprintf (str, size, fmt, va); |
| 65 #endif |
| 66 |
| 67 return rc; |
| 68 } |
| 69 |
| 70 static UINT win_utf8_io_codepage = CP_ACP; |
| 71 |
| 72 /* convert WCHAR stored Unicode string to UTF-8. Caller is responsible for freei
ng memory */ |
| 73 static |
| 74 char *utf8_from_wchar(const wchar_t *wstr) |
| 75 { |
| 76 char *utf8str; |
| 77 int len; |
| 78 |
| 79 if (!wstr) return NULL; |
| 80 if ((len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL
)) == 0) return NULL; |
| 81 if ((utf8str = (char *)malloc(++len)) == NULL) return NULL; |
| 82 if (WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8str, len, NULL, NULL)
== 0) { |
| 83 free(utf8str); |
| 84 utf8str = NULL; |
| 85 } |
| 86 |
| 87 return utf8str; |
| 88 } |
| 89 |
| 90 /* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */ |
| 91 static |
| 92 wchar_t *wchar_from_utf8(const char *str) |
| 93 { |
| 94 wchar_t *widestr; |
| 95 int len; |
| 96 |
| 97 if (!str) return NULL; |
| 98 len=(int)strlen(str)+1; |
| 99 if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) != NULL) { |
| 100 if (MultiByteToWideChar(win_utf8_io_codepage, 0, str, len, wides
tr, len) == 0) { |
| 101 if (MultiByteToWideChar(CP_ACP, 0, str, len, widestr, le
n) == 0) { /* try conversion from Ansi in case the initial UTF-8 conversion had
failed */ |
| 102 free(widestr); |
| 103 widestr = NULL; |
| 104 } |
| 105 } |
| 106 } |
| 107 |
| 108 return widestr; |
| 109 } |
| 110 |
| 111 /* retrieve WCHAR commandline, expand wildcards and convert everything to UTF-8
*/ |
| 112 int get_utf8_argv(int *argc, char ***argv) |
| 113 { |
| 114 typedef int (__cdecl *wgetmainargs_t)(int*, wchar_t***, wchar_t***, int,
int*); |
| 115 wgetmainargs_t wgetmainargs; |
| 116 HMODULE handle; |
| 117 int wargc; |
| 118 wchar_t **wargv; |
| 119 wchar_t **wenv; |
| 120 char **utf8argv; |
| 121 int ret, i; |
| 122 |
| 123 if ((handle = LoadLibraryA("msvcrt.dll")) == NULL) return 1; |
| 124 if ((wgetmainargs = (wgetmainargs_t)GetProcAddress(handle, "__wgetmainar
gs")) == NULL) return 1; |
| 125 i = 0; |
| 126 /* if __wgetmainargs expands wildcards then it also erroneously converts
\\?\c:\path\to\file.flac to \\file.flac */ |
| 127 if (wgetmainargs(&wargc, &wargv, &wenv, 1, &i) != 0) return 1; |
| 128 if ((utf8argv = (char **)calloc(wargc, sizeof(char*))) == NULL) return 1
; |
| 129 ret = 0; |
| 130 |
| 131 for (i=0; i<wargc; i++) { |
| 132 if ((utf8argv[i] = utf8_from_wchar(wargv[i])) == NULL) { |
| 133 ret = 1; |
| 134 break; |
| 135 } |
| 136 } |
| 137 |
| 138 FreeLibrary(handle); |
| 139 |
| 140 if (ret == 0) { |
| 141 win_utf8_io_codepage = CP_UTF8; |
| 142 *argc = wargc; |
| 143 *argv = utf8argv; |
| 144 } else { |
| 145 for (i=0; i<wargc; i++) |
| 146 free(utf8argv[i]); |
| 147 free(utf8argv); |
| 148 } |
| 149 |
| 150 return ret; |
| 151 } |
| 152 |
| 153 /* return number of characters in the UTF-8 string */ |
| 154 size_t strlen_utf8(const char *str) |
| 155 { |
| 156 size_t len; |
| 157 if ((len = MultiByteToWideChar(win_utf8_io_codepage, 0, str, -1, NULL, 0
)) == 0) |
| 158 len = strlen(str); |
| 159 return len; |
| 160 } |
| 161 |
| 162 /* get the console width in characters */ |
| 163 int win_get_console_width(void) |
| 164 { |
| 165 int width = 80; |
| 166 CONSOLE_SCREEN_BUFFER_INFO csbi; |
| 167 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); |
| 168 if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0) width = csbi.dwSize.X; |
| 169 return width; |
| 170 } |
| 171 |
| 172 /* print functions */ |
| 173 |
| 174 int print_console(FILE *stream, const wchar_t *text, size_t len) |
| 175 { |
| 176 static HANDLE hOut; |
| 177 static HANDLE hErr; |
| 178 DWORD out; |
| 179 hOut = GetStdHandle(STD_OUTPUT_HANDLE); |
| 180 hErr = GetStdHandle(STD_ERROR_HANDLE); |
| 181 if (stream == stdout && hOut != INVALID_HANDLE_VALUE && GetFileType(hOut
) == FILE_TYPE_CHAR) { |
| 182 if (WriteConsoleW(hOut, text, len, &out, NULL) == 0) return -1; |
| 183 return out; |
| 184 } else if (stream == stderr && hErr != INVALID_HANDLE_VALUE && GetFileTy
pe(hErr) == FILE_TYPE_CHAR) { |
| 185 if (WriteConsoleW(hErr, text, len, &out, NULL) == 0) return -1; |
| 186 return out; |
| 187 } else { |
| 188 int ret = fputws(text, stream); |
| 189 if (ret < 0) return ret; |
| 190 return len; |
| 191 } |
| 192 } |
| 193 |
| 194 int printf_utf8(const char *format, ...) |
| 195 { |
| 196 char *utmp = NULL; |
| 197 wchar_t *wout = NULL; |
| 198 int ret = -1; |
| 199 |
| 200 while (1) { |
| 201 va_list argptr; |
| 202 if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) bre
ak; |
| 203 va_start(argptr, format); |
| 204 ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr); |
| 205 va_end(argptr); |
| 206 if (ret < 0) break; |
| 207 if (!(wout = wchar_from_utf8(utmp))) { |
| 208 ret = -1; |
| 209 break; |
| 210 } |
| 211 ret = print_console(stdout, wout, wcslen(wout)); |
| 212 break; |
| 213 } |
| 214 if (utmp) free(utmp); |
| 215 if (wout) free(wout); |
| 216 |
| 217 return ret; |
| 218 } |
| 219 |
| 220 int fprintf_utf8(FILE *stream, const char *format, ...) |
| 221 { |
| 222 char *utmp = NULL; |
| 223 wchar_t *wout = NULL; |
| 224 int ret = -1; |
| 225 |
| 226 while (1) { |
| 227 va_list argptr; |
| 228 if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) bre
ak; |
| 229 va_start(argptr, format); |
| 230 ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argptr); |
| 231 va_end(argptr); |
| 232 if (ret < 0) break; |
| 233 if (!(wout = wchar_from_utf8(utmp))) { |
| 234 ret = -1; |
| 235 break; |
| 236 } |
| 237 ret = print_console(stream, wout, wcslen(wout)); |
| 238 break; |
| 239 } |
| 240 if (utmp) free(utmp); |
| 241 if (wout) free(wout); |
| 242 |
| 243 return ret; |
| 244 } |
| 245 |
| 246 int vfprintf_utf8(FILE *stream, const char *format, va_list argptr) |
| 247 { |
| 248 char *utmp = NULL; |
| 249 wchar_t *wout = NULL; |
| 250 int ret = -1; |
| 251 |
| 252 while (1) { |
| 253 if (!(utmp = (char *)malloc(UTF8_BUFFER_SIZE*sizeof(char)))) bre
ak; |
| 254 if ((ret = local_vsnprintf(utmp, UTF8_BUFFER_SIZE, format, argpt
r)) < 0) break; |
| 255 if (!(wout = wchar_from_utf8(utmp))) { |
| 256 ret = -1; |
| 257 break; |
| 258 } |
| 259 ret = print_console(stream, wout, wcslen(wout)); |
| 260 break; |
| 261 } |
| 262 if (utmp) free(utmp); |
| 263 if (wout) free(wout); |
| 264 |
| 265 return ret; |
| 266 } |
| 267 |
| 268 /* file functions */ |
| 269 |
| 270 FILE *fopen_utf8(const char *filename, const char *mode) |
| 271 { |
| 272 wchar_t *wname = NULL; |
| 273 wchar_t *wmode = NULL; |
| 274 FILE *f = NULL; |
| 275 |
| 276 while (1) { |
| 277 if (!(wname = wchar_from_utf8(filename))) break; |
| 278 if (!(wmode = wchar_from_utf8(mode))) break; |
| 279 f = _wfopen(wname, wmode); |
| 280 break; |
| 281 } |
| 282 if (wname) free(wname); |
| 283 if (wmode) free(wmode); |
| 284 |
| 285 return f; |
| 286 } |
| 287 |
| 288 int _stat64_utf8(const char *path, struct __stat64 *buffer) |
| 289 { |
| 290 wchar_t *wpath; |
| 291 int ret; |
| 292 |
| 293 if (!(wpath = wchar_from_utf8(path))) return -1; |
| 294 ret = _wstat64(wpath, buffer); |
| 295 free(wpath); |
| 296 |
| 297 return ret; |
| 298 } |
| 299 |
| 300 int chmod_utf8(const char *filename, int pmode) |
| 301 { |
| 302 wchar_t *wname; |
| 303 int ret; |
| 304 |
| 305 if (!(wname = wchar_from_utf8(filename))) return -1; |
| 306 ret = _wchmod(wname, pmode); |
| 307 free(wname); |
| 308 |
| 309 return ret; |
| 310 } |
| 311 |
| 312 int utime_utf8(const char *filename, struct utimbuf *times) |
| 313 { |
| 314 wchar_t *wname; |
| 315 struct __utimbuf64 ut; |
| 316 int ret; |
| 317 |
| 318 if (sizeof(*times) == sizeof(ut)) { |
| 319 memcpy(&ut, times, sizeof(ut)); |
| 320 } else { |
| 321 ut.actime = times->actime; |
| 322 ut.modtime = times->modtime; |
| 323 } |
| 324 |
| 325 if (!(wname = wchar_from_utf8(filename))) return -1; |
| 326 ret = _wutime64(wname, &ut); |
| 327 free(wname); |
| 328 |
| 329 return ret; |
| 330 } |
| 331 |
| 332 int unlink_utf8(const char *filename) |
| 333 { |
| 334 wchar_t *wname; |
| 335 int ret; |
| 336 |
| 337 if (!(wname = wchar_from_utf8(filename))) return -1; |
| 338 ret = _wunlink(wname); |
| 339 free(wname); |
| 340 |
| 341 return ret; |
| 342 } |
| 343 |
| 344 int rename_utf8(const char *oldname, const char *newname) |
| 345 { |
| 346 wchar_t *wold = NULL; |
| 347 wchar_t *wnew = NULL; |
| 348 int ret = -1; |
| 349 |
| 350 while (1) { |
| 351 if (!(wold = wchar_from_utf8(oldname))) break; |
| 352 if (!(wnew = wchar_from_utf8(newname))) break; |
| 353 ret = _wrename(wold, wnew); |
| 354 break; |
| 355 } |
| 356 if (wold) free(wold); |
| 357 if (wnew) free(wnew); |
| 358 |
| 359 return ret; |
| 360 } |
| 361 |
| 362 HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWO
RD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisp
osition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) |
| 363 { |
| 364 wchar_t *wname; |
| 365 HANDLE handle = INVALID_HANDLE_VALUE; |
| 366 |
| 367 if ((wname = wchar_from_utf8(lpFileName)) != NULL) { |
| 368 handle = CreateFileW(wname, dwDesiredAccess, dwShareMode, lpSecu
rityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); |
| 369 free(wname); |
| 370 } |
| 371 |
| 372 return handle; |
| 373 } |
OLD | NEW |