]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - fs.c
Delete (broken) cmake submodule that somehow got in from my cmake branch
[xonotic/darkplaces.git] / fs.c
diff --git a/fs.c b/fs.c
index cae6d309d66e971d78365d7fb8029d3697a6fff1..af62b898a3b2a330be6797f80ec34c2033bd91d3 100644 (file)
--- a/fs.c
+++ b/fs.c
 #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
@@ -105,6 +109,66 @@ static filedesc_t FILEDESC_DUP(const char *filename, filedesc_t fd) {
 }
 #endif
 
+
+/* This code seems to have originally been written with the assumption that
+ * read(..., n) returns n on success. This is not the case (refer to
+ * <https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html>).
+ * Ditto for write.
+ */
+
+/*
+====================
+ReadAll
+
+Read exactly length bytes from fd into buf. If end of file is reached,
+the number of bytes read is returned. If an error occurred, that error
+is returned. Note that if an error is returned, any previously read
+data is lost.
+====================
+*/
+static fs_offset_t ReadAll(const filedesc_t fd, void *const buf, const size_t length)
+{
+       char *const p = (char *)buf;
+       size_t cursor = 0;
+       do
+       {
+               const fs_offset_t result = FILEDESC_READ(fd, p + cursor, length - cursor);
+               if (result < 0) // Error
+                       return result;
+               if (result == 0) // EOF
+                       break;
+               cursor += result;
+       } while (cursor < length);
+       return cursor;
+}
+
+/*
+====================
+WriteAll
+
+Write exactly length bytes to fd from buf.
+If an error occurred, that error is returned.
+====================
+*/
+static fs_offset_t WriteAll(const filedesc_t fd, const void *const buf, const size_t length)
+{
+       const char *const p = (const char *)buf;
+       size_t cursor = 0;
+       do
+       {
+               const fs_offset_t result = FILEDESC_WRITE(fd, p + cursor, length - cursor);
+               if (result < 0) // Error
+                       return result;
+               cursor += result;
+       } while (cursor < length);
+       return cursor;
+}
+
+#undef FILEDESC_READ
+#define FILEDESC_READ ReadAll
+#undef FILEDESC_WRITE
+#define FILEDESC_WRITE WriteAll
+
 /** \page fs File System
 
 All of Quake's data access is through a hierchal file system, but the contents
@@ -438,10 +502,10 @@ static dllhandle_t zlib_dll = NULL;
 #endif
 
 #ifdef WIN32
-static HRESULT (WINAPI *qSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);
+static HRESULT (WINAPI *qSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
 static dllfunction_t shfolderfuncs[] =
 {
-       {"SHGetFolderPathA", (void **) &qSHGetFolderPath},
+       {"SHGetFolderPathW", (void **) &qSHGetFolderPath},
        {NULL, NULL}
 };
 static const char* shfolderdllnames [] =
@@ -451,7 +515,7 @@ static const char* shfolderdllnames [] =
 };
 static dllhandle_t shfolder_dll = NULL;
 
-const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}}; 
+const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}};
 #define qREFKNOWNFOLDERID const GUID *
 #define qKF_FLAG_CREATE 0x8000
 #define qKF_FLAG_NO_ALIAS 0x1000
@@ -683,7 +747,7 @@ static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
                        return -1;
                }
 
-               namesize = BuffLittleShort (&ptr[28]);  // filename length
+               namesize = (unsigned short)BuffLittleShort (&ptr[28]);  // filename length
 
                // Check encryption, compression, and attributes
                // 1st uint8  : general purpose bit flag
@@ -700,7 +764,7 @@ static int PK3_BuildFileList (pack_t *pack, const pk3_endOfCentralDir_t *eocd)
                if ((ptr[8] & 0x21) == 0 && (ptr[38] & 0x18) == 0)
                {
                        // Still enough bytes for the name?
-                       if (namesize < 0 || remaining < namesize || namesize >= (int)sizeof (*pack->files))
+                       if (remaining < namesize || namesize >= (int)sizeof (*pack->files))
                        {
                                Mem_Free (central_dir);
                                return -1;
@@ -926,14 +990,30 @@ static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack,
        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
@@ -945,7 +1025,6 @@ static void FS_mkdir (const char *path)
        }
 }
 
-
 /*
 ============
 FS_CreatePath
@@ -1513,13 +1592,16 @@ void FS_Rescan (void)
        // add back the selfpack as new first item
        FS_AddSelfPack();
 
-       // set the default screenshot name to either the mod name or the
-       // gamemode screenshot name
-       if (strcmp(com_modname, gamedirname1))
-               Cvar_SetQuick (&scr_screenshot_name, com_modname);
-       else
-               Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
-       
+       if (cls.state != ca_dedicated)
+       {
+               // set the default screenshot name to either the mod name or the
+               // gamemode screenshot name
+               if (strcmp(com_modname, gamedirname1))
+                       Cvar_SetQuick (&scr_screenshot_name, com_modname);
+               else
+                       Cvar_SetQuick (&scr_screenshot_name, gamescreenshotname);
+       }
+
        if((i = Sys_CheckParm("-modname")) && i < sys.argc - 1)
                strlcpy(com_modname, sys.argv[i+1], sizeof(com_modname));
 
@@ -1740,7 +1822,7 @@ const char *FS_CheckGameDir(const char *gamedir)
        ret = FS_SysCheckGameDir(va(vabuf, sizeof(vabuf), "%s%s/", fs_basedir, gamedir), buf, sizeof(buf));
        if(ret)
                return ret;
-       
+
        return fs_checkgamedir_missing;
 }
 
@@ -1773,7 +1855,7 @@ static void FS_ListGameDirs(void)
                        continue;
                if(!*info)
                        continue;
-               stringlistappend(&list2, list.strings[i]); 
+               stringlistappend(&list2, list.strings[i]);
        }
        stringlistfreecontents(&list);
 
@@ -1849,13 +1931,15 @@ static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t use
        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 mydocsdirw[WSTRBUF];
+       char mydocsdir[WSTRBUF];
        wchar_t *savedgamesdirw;
-       char savedgamesdir[MAX_OSPATH];
+       char savedgamesdir[WSTRBUF] = {0};
        int fd;
        char vabuf[1024];
 
@@ -1871,22 +1955,25 @@ static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t use
                if (!shfolder_dll)
                        Sys_LoadDependency(shfolderdllnames, &shfolder_dll, shfolderfuncs);
                mydocsdir[0] = 0;
-               if (qSHGetFolderPath && qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir) == S_OK)
+               if (qSHGetFolderPath && qSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydocsdirw) == S_OK)
                {
+                       narrow(mydocsdirw, mydocsdir);
                        dpsnprintf(userdir, userdirsize, "%s/My Games/%s/", mydocsdir, gameuserdirname);
                        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;
@@ -1911,12 +1998,7 @@ static int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t use
 */
                        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();
@@ -2279,6 +2361,9 @@ static filedesc_t FS_SysOpenFiledesc(const char *filepath, const char *mode, qbo
        int mod, opt;
        unsigned int ind;
        qbool dolock = false;
+       #ifdef WIN32
+       wchar filepathw[WSTRBUF] = {0};
+       #endif
 
        // Parse the mode string
        switch (mode[0])
@@ -2330,10 +2415,11 @@ static filedesc_t FS_SysOpenFiledesc(const char *filepath, const char *mode, qbo
        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);
@@ -2557,7 +2643,7 @@ int FS_CheckNastyPath (const char *path, qbool isgamedir)
 ====================
 FS_SanitizePath
 
-Sanitize path (replace non-portable characters 
+Sanitize path (replace non-portable characters
 with portable ones in-place, etc)
 ====================
 */
@@ -2714,7 +2800,7 @@ static qfile_t *FS_OpenReadFile (const char *filename, qbool quiet, qbool nonblo
                        if(count < 0)
                                return NULL;
                        linkbuf[count] = 0;
-                       
+
                        // Now combine the paths...
                        mergeslash = strrchr(filename, '/');
                        mergestart = linkbuf;
@@ -3592,8 +3678,10 @@ int FS_SysFileType (const char *path)
 # 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;
@@ -3946,7 +4034,7 @@ void FS_Which_f(cmd_state_t *cmd)
        {
                Con_Printf("usage:\n%s <file>\n", Cmd_Argv(cmd, 0));
                return;
-       }  
+       }
        filename = Cmd_Argv(cmd, 1);
        sp = FS_FindFile(filename, &index, true);
        if (!sp) {
@@ -4099,7 +4187,7 @@ unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflat
                Mem_Free(tmp);
                return NULL;
        }
-       
+
        if(qz_deflateEnd(&strm) != Z_OK)
        {
                Con_Printf("FS_Deflate: deflateEnd failed\n");
@@ -4126,7 +4214,7 @@ unsigned char *FS_Deflate(const unsigned char *data, size_t size, size_t *deflat
 
        memcpy(out, tmp, strm.total_out);
        Mem_Free(tmp);
-       
+
        return out;
 }
 
@@ -4193,7 +4281,7 @@ unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflat
                        case Z_STREAM_END:
                        case Z_OK:
                                break;
-                               
+
                        case Z_STREAM_ERROR:
                                Con_Print("FS_Inflate: stream error!\n");
                                break;
@@ -4209,7 +4297,7 @@ unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflat
                        default:
                                Con_Print("FS_Inflate: unknown error!\n");
                                break;
-                               
+
                }
                if(ret != Z_OK && ret != Z_STREAM_END)
                {
@@ -4237,6 +4325,6 @@ unsigned char *FS_Inflate(const unsigned char *data, size_t size, size_t *inflat
        Mem_Free(outbuf.data);
 
        *inflated_size = (size_t)outbuf.cursize;
-       
+
        return out;
 }