/* UTF-8 handling for Gust (Koei/Tecmo) PC games tools Copyright © 2019 VitaSmith This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include #include #define DUMP_LEAKS _CrtDumpMemoryLeaks() #else #define DUMP_LEAKS #endif #include #include #include #include #include #pragma once #if defined(_WIN32) #include #define stat64 _stat64 #define stat64_t stat64 static __inline char *utf16_to_utf8(const wchar_t *str16) { char *str8 = NULL; int str8_size = 0; if (str16[0] == 0) return calloc(1, 1); if (((str8_size = str8_size = WideCharToMultiByte(CP_UTF8, 0, str16, -1, NULL, 0, NULL, NULL)) <= 1) || ((str8 = (char *)calloc(str8_size, 1)) == NULL)) return NULL; if (WideCharToMultiByte(CP_UTF8, 0, str16, -1, str8, str8_size, NULL, NULL) != str8_size) { free(str8); return NULL; } return str8; } static __inline wchar_t *utf8_to_utf16(const char *str8) { wchar_t *str16 = NULL; int str16_size = 0; if (str8 == NULL) return NULL; if (str8[0] == 0) return calloc(1, sizeof(wchar_t)); if (((str16_size = MultiByteToWideChar(CP_UTF8, 0, str8, -1, NULL, 0)) <= 1) || ((str16 = (wchar_t *)calloc(str16_size, sizeof(wchar_t))) == NULL)) return NULL; if (MultiByteToWideChar(CP_UTF8, 0, str8, -1, str16, str16_size) != str16_size) { free(str16); return NULL; } return str16; } static __inline FILE *fopen_utf8(const char *filename, const char *mode) { FILE *r = NULL; wchar_t *filename16 = utf8_to_utf16(filename); wchar_t *mode16 = utf8_to_utf16(mode); _wfopen_s(&r, filename16, mode16); free(filename16); free(mode16); return r; } static __inline int rename_utf8(const char *oldname, const char *newname) { wchar_t *oldname16 = utf8_to_utf16(oldname); wchar_t *newname16 = utf8_to_utf16(newname); int r = _wrename(oldname16, newname16); free(oldname16); free(newname16); return r; } static __inline int stat64_utf8(const char *path, struct stat64 *buffer) { int r; wchar_t *path16 = utf8_to_utf16(path); r = _wstat64(path16, buffer); free(path16); return r; } static __inline BOOL CreateDirectory_utf8(const char *path, LPSECURITY_ATTRIBUTES attrs) { BOOL r; wchar_t *path16 = utf8_to_utf16(path); r = CreateDirectoryW(path16, attrs); free(path16); return r; } #define CALL_MAIN \ int wmain(int argc, wchar_t **argv16) { \ SetConsoleOutputCP(CP_UTF8); \ char **argv = calloc(argc, sizeof(char *)); \ if (argv == NULL) \ return EXIT_FAILURE; \ for (int i = 0; i < argc; i++) \ argv[i] = utf16_to_utf8(argv16[i]); \ int r = main_utf8(argc, argv); \ for (int i = 0; i < argc; i++) \ free(argv[i]); \ free(argv); \ DUMP_LEAKS; \ return r; \ } #else #define fopen_utf8 fopen #define rename_utf8 rename #if defined(__APPLE__) #define stat64_utf8 stat #define stat64_t stat #else #define stat64_utf8 stat64 #define stat64_t stat64 #endif #define CALL_MAIN \ int main(int argc, char **argv) { return main_utf8(argc, argv); } #endif