#include "darkplaces.h"
+#ifdef WIN32
+#include "utf8lib.h"
+#endif
+
// LadyHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such...
int matchpattern(const char *in, const char *pattern, int caseinsensitive)
#ifdef WIN32
void listdirectory(stringlist_t *list, const char *basepath, const char *path)
{
- char pattern[4096];
- WIN32_FIND_DATA n_file;
+ #define BUFSIZE 4096
+ char pattern[BUFSIZE] = {0};
+ wchar patternw[BUFSIZE] = {0};
+ char filename[BUFSIZE] = {0};
+ wchar *filenamew;
+ int lenw = 0;
+ WIN32_FIND_DATAW n_file;
HANDLE hFile;
strlcpy (pattern, basepath, sizeof(pattern));
strlcat (pattern, path, sizeof (pattern));
strlcat (pattern, "*", sizeof (pattern));
+ fromwtf8(pattern, strlen(pattern), patternw, BUFSIZE);
// ask for the directory listing handle
- hFile = FindFirstFile(pattern, &n_file);
+ hFile = FindFirstFileW(patternw, &n_file);
if(hFile == INVALID_HANDLE_VALUE)
return;
do {
- adddirentry(list, path, n_file.cFileName);
- } while (FindNextFile(hFile, &n_file) != 0);
+ filenamew = n_file.cFileName;
+ lenw = 0;
+ while(filenamew[lenw] != 0) ++lenw;
+ towtf8(filenamew, lenw, filename, BUFSIZE);
+ adddirentry(list, path, filename);
+ } while (FindNextFileW(hFile, &n_file) != 0);
FindClose(hFile);
+ #undef BUFSIZE
}
#else
void listdirectory(stringlist_t *list, const char *basepath, const char *path)
#include "fs.h"
#include "wad.h"
+#ifdef WIN32
+#include "utf8lib.h"
+#endif
+
// Win32 requires us to add O_BINARY, but the other OSes don't have it
#ifndef O_BINARY
# define O_BINARY 0
static HRESULT (WINAPI *qSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);
static dllfunction_t shfolderfuncs[] =
{
- {"SHGetFolderPathA", (void **) &qSHGetFolderPath},
+ {"SHGetFolderPathW", (void **) &qSHGetFolderPath},
{NULL, NULL}
};
static const char* shfolderdllnames [] =
return pfile;
}
+#if WIN32
+#define WSTRBUF 4096
+static inline int wstrlen(wchar *wstr)
+{
+ int len = 0;
+ while (wstr[len] != 0 && len < WSTRBUF)
+ ++len;
+ return len;
+}
+#define widen(str, wstr) fromwtf8(str, strlen(str), wstr, WSTRBUF)
+#define narrow(wstr, str) towtf8(wstr, wstrlen(wstr), str, WSTRBUF)
+#endif
static void FS_mkdir (const char *path)
{
+#if WIN32
+ wchar pathw[WSTRBUF] = {0};
+#endif
if(Sys_CheckParm("-readonly"))
return;
#if WIN32
- if (_mkdir (path) == -1)
+ widen(path, pathw);
+ if (_wmkdir (pathw) == -1)
#else
if (mkdir (path, 0777) == -1)
#endif
}
}
-
/*
============
FS_CreatePath
return -1;
#elif defined(WIN32)
- char *homedir;
+ char homedir[WSTRBUF];
+ wchar *homedirw;
#if _MSC_VER >= 1400
- size_t homedirlen;
+ size_t homedirwlen;
#endif
TCHAR mydocsdir[MAX_PATH + 1];
wchar_t *savedgamesdirw;
- char savedgamesdir[MAX_OSPATH];
+ char savedgamesdir[WSTRBUF] = {0};
int fd;
char vabuf[1024];
break;
}
#if _MSC_VER >= 1400
- _dupenv_s(&homedir, &homedirlen, "USERPROFILE");
- if(homedir)
+ _wdupenv_s(&homedirw, &homedirwlen, L"USERPROFILE");
+ narrow(homedirw, homedir);
+ if(homedir[0])
{
dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname);
- free(homedir);
+ free(homedirw);
break;
}
#else
- homedir = getenv("USERPROFILE");
- if(homedir)
+ homedirw = _wgetenv(L"USERPROFILE");
+ narrow(homedirw, homedir);
+ if(homedir[0])
{
dpsnprintf(userdir, userdirsize, "%s/.%s/", homedir, gameuserdirname);
break;
*/
if (qSHGetKnownFolderPath(&qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &savedgamesdirw) == S_OK)
{
- memset(savedgamesdir, 0, sizeof(savedgamesdir));
-#if _MSC_VER >= 1400
- wcstombs_s(NULL, savedgamesdir, sizeof(savedgamesdir), savedgamesdirw, sizeof(savedgamesdir)-1);
-#else
- wcstombs(savedgamesdir, savedgamesdirw, sizeof(savedgamesdir)-1);
-#endif
+ narrow(savedgamesdirw, savedgamesdir);
qCoTaskMemFree(savedgamesdirw);
}
qCoUninitialize();
int mod, opt;
unsigned int ind;
qbool dolock = false;
+ #ifdef WIN32
+ wchar filepathw[WSTRBUF] = {0};
+ #endif
// Parse the mode string
switch (mode[0])
handle = SDL_RWFromFile(filepath, mode);
#else
# ifdef WIN32
+ widen(filepath, filepathw);
# if _MSC_VER >= 1400
- _sopen_s(&handle, filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+ _wsopen_s(&handle, filepathw, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
# else
- handle = _sopen (filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+ handle = _wsopen (filepathw, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
# endif
# else
handle = open (filepath, mod | opt, 0666);
# ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
# endif
-
- DWORD result = GetFileAttributes(path);
+ wchar pathw[WSTRBUF] = {0};
+ DWORD result;
+ widen(path, pathw);
+ result = GetFileAttributesW(pathw);
if(result == INVALID_FILE_ATTRIBUTES)
return FS_FILETYPE_NONE;
return dpsnprintf(out, outsize, "%*s%.*s%*s", lpad, "", prec, in, rpad, "");
}
+#ifdef WIN32
+
+/**
+ * Convert Windows "wide" characters to WTF-8 for internal manipulation
+ */
+int towtf8(const wchar *wstr, int wlen, char *cstr, int maxclen)
+{
+ int p = 0;
+ int i;
+ for (i = 0; i < wlen; ++i)
+ {
+ wchar point = wstr[i];
+ if (point < 0x80)
+ {
+ if (p + 1 >= maxclen) break;
+ cstr[p++] = point;
+ }
+ else if (point < 0x800)
+ {
+ if (p + 2 >= maxclen) break;
+ cstr[p++] = (0xc0 | ((point >> 6) & 0x1f));
+ cstr[p++] = (0x80 | ((point >> 0) & 0x3f));
+ }
+ else
+ #if U32
+ if (point < 0x10000)
+ #endif
+ {
+ if (p + 3 >= maxclen) break;
+ cstr[p++] = (0xe0 | ((point >> 12) & 0x0f));
+ cstr[p++] = (0x80 | ((point >> 6) & 0x3f));
+ cstr[p++] = (0x80 | ((point >> 0) & 0x3f));
+ }
+ #if U32
+ else
+ #if CHECKS
+ if (point < 0x110000)
+ #endif
+ {
+ if (p + 4 >= maxclen) break;
+ cstr[p++] = (0xf0 | ((point >> 18) & 0x07));
+ cstr[p++] = (0x80 | ((point >> 12) & 0x3f));
+ cstr[p++] = (0x80 | ((point >> 6) & 0x3f));
+ cstr[p++] = (0x80 | ((point >> 0) & 0x3f));
+ }
+ #endif
+ }
+ cstr[p] = 0x00;
+ return p;
+}
+
+/**
+ * Convert WTF-8 string to "wide" characters used by Windows
+ */
+int fromwtf8(const char *cstr, int clen, wchar *wstr, int maxwlen)
+{
+ int p = 0;
+ int i;
+ for (i = 0; i < clen;)
+ {
+ char byte = cstr[i++];
+ wchar point = byte;
+ int length = 1;
+ if (p + 1 >= maxwlen) break;
+ #if CHECKS
+ if ((byte & 0xf8) == 0xf8)
+ return -1;
+ #endif
+ if ((byte & 0xf8) == 0xf0)
+ {
+ length = 4;
+ point = byte & 0x07;
+ }
+ else if ((byte & 0xf0) == 0xe0)
+ {
+ length = 3;
+ point = byte & 0x0f;
+ }
+ else if ((byte & 0xe0) == 0xc0)
+ {
+ length = 2;
+ point = byte & 0x1f;
+ }
+ #if CHECKS
+ else if ((byte & 0xc0) == 0x80)
+ {
+ return -1;
+ }
+ #endif
+ while (--length)
+ {
+ byte = cstr[i++];
+ #if CHECKS
+ if (byte == -1) return -1;
+ else if ((byte & 0xc0) != 0x80) return -1;
+ #endif
+ point = (point << 6) | (byte & 0x3f);
+ }
+ wstr[p++] = point;
+ }
+ wstr[p] = 0x00;
+ return p;
+}
+
+#endif // WIN32
+
/*
The two following functions (u8_toupper, u8_tolower) are derived from
Uchar u8_toupper(Uchar ch);
Uchar u8_tolower(Uchar ch);
+#ifdef WIN32
+
+// WTF-8 encoding to circumvent Windows encodings, be it UTF-16 or random codepages
+// https://simonsapin.github.io/wtf-8/
+#define U32 0
+#define CHECKS 1
+typedef wchar_t wchar;
+
+int towtf8(const wchar* wstr, int wlen, char* cstr, int maxclen);
+int fromwtf8(const char* cstr, int clen, wchar* wstr, int maxwlen);
+
+#endif // WIN32
+
#endif // UTF8LIB_H__