|
|
@@ -13,6 +13,8 @@
|
|
|
#include <windows.h>
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <errno.h>
|
|
|
#include <ctype.h>
|
|
|
#include <time.h>
|
|
|
#include <assert.h>
|
|
|
@@ -20,26 +22,51 @@
|
|
|
#define __PHYSICSFS_INTERNAL__
|
|
|
#include "physfs_internal.h"
|
|
|
|
|
|
-#ifndef _MSC_VER /* for Cygwin, etc. */
|
|
|
-#define _alloca alloca
|
|
|
+#ifdef _MSC_VER /* for Cygwin, etc. */
|
|
|
+#define alloca _alloca
|
|
|
#endif
|
|
|
|
|
|
#define LOWORDER_UINT64(pos) (PHYSFS_uint32)(pos & 0x00000000FFFFFFFF)
|
|
|
#define HIGHORDER_UINT64(pos) (PHYSFS_uint32)(pos & 0xFFFFFFFF00000000)
|
|
|
|
|
|
-const char *__PHYSFS_platformDirSeparator = "\\";
|
|
|
+/* GetUserProfileDirectory() is only available on >= NT4 (no 9x/ME systems!) */
|
|
|
+typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETUSERPROFILEDIR) (
|
|
|
+ HANDLE hToken,
|
|
|
+ LPTSTR lpProfileDir,
|
|
|
+ LPDWORD lpcchSize);
|
|
|
+
|
|
|
+/* GetFileAttributesEx() is only available on >= Win98 or WinNT4 ... */
|
|
|
+typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETFILEATTRIBUTESEX) (
|
|
|
+ LPCTSTR lpFileName,
|
|
|
+ GET_FILEEX_INFO_LEVELS fInfoLevelId,
|
|
|
+ LPVOID lpFileInformation);
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ HANDLE handle;
|
|
|
+ int readonly;
|
|
|
+} win32file;
|
|
|
|
|
|
-static int runningNT = 0; /* TRUE if NT derived OS */
|
|
|
-static OSVERSIONINFO OSVersionInfo; /* Information about the OS */
|
|
|
-static char *ProfileDirectory = NULL; /* User profile folder */
|
|
|
+const char *__PHYSFS_platformDirSeparator = "\\";
|
|
|
+static LPFNGETFILEATTRIBUTESEX pGetFileAttributesEx = NULL;
|
|
|
+static HANDLE libKernel32 = NULL;
|
|
|
+static char *userDir = NULL;
|
|
|
|
|
|
-/* Users without the platform SDK don't have this defined. The original docs
|
|
|
- for SetFilePointer() just said to compare with 0xFFFFFFF, so this should
|
|
|
- work as desired */
|
|
|
+/*
|
|
|
+ * Users without the platform SDK don't have this defined. The original docs
|
|
|
+ * for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
|
|
|
+ * work as desired
|
|
|
+ */
|
|
|
#ifndef INVALID_SET_FILE_POINTER
|
|
|
-#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
|
|
|
+# define INVALID_SET_FILE_POINTER 0xFFFFFFFF
|
|
|
#endif
|
|
|
|
|
|
+/* just in case... */
|
|
|
+#ifndef INVALID_FILE_ATTRIBUTES
|
|
|
+# define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Figure out what the last failing Win32 API call was, and
|
|
|
* generate a human-readable string for the error message.
|
|
|
@@ -50,6 +77,7 @@ static char *ProfileDirectory = NULL; /* User profile folder */
|
|
|
static const char *win32strerror(void)
|
|
|
{
|
|
|
static TCHAR msgbuf[255];
|
|
|
+ TCHAR *ptr = msgbuf;
|
|
|
|
|
|
FormatMessage(
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
@@ -62,120 +90,181 @@ static const char *win32strerror(void)
|
|
|
NULL
|
|
|
);
|
|
|
|
|
|
+ /* chop off newlines. */
|
|
|
+ for (ptr = msgbuf; *ptr; ptr++)
|
|
|
+ {
|
|
|
+ if ((*ptr == '\n') || (*ptr == '\r'))
|
|
|
+ {
|
|
|
+ *ptr = ' ';
|
|
|
+ break;
|
|
|
+ } /* if */
|
|
|
+ } /* for */
|
|
|
+
|
|
|
return((const char *) msgbuf);
|
|
|
} /* win32strerror */
|
|
|
|
|
|
|
|
|
-/*
|
|
|
- * Uninitialize any NT specific stuff done in doNTInit().
|
|
|
- *
|
|
|
- * Return zero if there was a catastrophic failure and non-zero otherwise.
|
|
|
- */
|
|
|
-static int doNTDeinit(void)
|
|
|
+static char *getExePath(const char *argv0)
|
|
|
{
|
|
|
- /* nothing NT-specific to deinit at this point. */
|
|
|
- return 1; /* It's all good */
|
|
|
-} /* doNTDeinit */
|
|
|
+ DWORD buflen;
|
|
|
+ int success = 0;
|
|
|
+ char *ptr = NULL;
|
|
|
+ char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
|
|
|
+
|
|
|
+ BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
|
|
|
+
|
|
|
+ retval[0] = '\0';
|
|
|
+ buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
|
|
|
+ if (buflen <= 0)
|
|
|
+ __PHYSFS_setError(win32strerror());
|
|
|
+ else
|
|
|
+ {
|
|
|
+ retval[buflen] = '\0'; /* does API always null-terminate this? */
|
|
|
+
|
|
|
+ /* make sure the string was not truncated. */
|
|
|
+ if (__PHYSFS_platformStricmp(&retval[buflen - 4], ".exe") != 0)
|
|
|
+ __PHYSFS_setError("WIN32: GetModuleFileName() got truncated.");
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ptr = strrchr(retval, '\\');
|
|
|
+ if (ptr == NULL)
|
|
|
+ __PHYSFS_setError("WIN32: GetModuleFileName() had no dir.");
|
|
|
+ else
|
|
|
+ {
|
|
|
+ *(ptr + 1) = '\0'; /* chop off filename. */
|
|
|
+ success = 1;
|
|
|
+ } /* else */
|
|
|
+ } /* else */
|
|
|
+ } /* else */
|
|
|
+
|
|
|
+ /* if any part of the previous approach failed, try SearchPath()... */
|
|
|
+
|
|
|
+ if (!success)
|
|
|
+ {
|
|
|
+ if (argv0 == NULL)
|
|
|
+ __PHYSFS_setError("WIN32: argv0 is NULL.");
|
|
|
+ else
|
|
|
+ {
|
|
|
+ buflen = SearchPath(NULL, argv0, NULL, MAX_PATH+1, retval, &ptr);
|
|
|
+ if (buflen == 0)
|
|
|
+ __PHYSFS_setError(win32strerror());
|
|
|
+ else if (buflen > MAX_PATH)
|
|
|
+ __PHYSFS_setError("Win32: SearchPath() got truncated.");
|
|
|
+ else
|
|
|
+ success = 1;
|
|
|
+ } /* else */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ if (!success)
|
|
|
+ {
|
|
|
+ free(retval);
|
|
|
+ return(NULL); /* physfs error message will be set, above. */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ /* free up the bytes we didn't actually use. */
|
|
|
+ ptr = (char *) realloc(retval, strlen(retval) + 1);
|
|
|
+ if (ptr != NULL)
|
|
|
+ retval = ptr;
|
|
|
+
|
|
|
+ return(retval); /* w00t. */
|
|
|
+} /* getExePath */
|
|
|
|
|
|
|
|
|
-typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETUSERPROFILEDIR) (
|
|
|
- HANDLE hToken,
|
|
|
- LPTSTR lpProfileDir,
|
|
|
- LPDWORD lpcchSize);
|
|
|
-
|
|
|
/*
|
|
|
- * Initialize any NT specific stuff. This includes any OS based on NT.
|
|
|
+ * Try to make use of GetUserProfileDirectory(), which isn't available on
|
|
|
+ * some common variants of Win32. If we can't use this, we just punt and
|
|
|
+ * use the physfs base dir for the user dir, too.
|
|
|
*
|
|
|
- * Return zero if there was a catastrophic failure and non-zero otherwise.
|
|
|
+ * On success, module-scope variable (userDir) will have a pointer to
|
|
|
+ * a malloc()'d string of the user's profile dir, and a non-zero value is
|
|
|
+ * returned. If we can't determine the profile dir, (userDir) will
|
|
|
+ * be NULL, and zero is returned.
|
|
|
*/
|
|
|
-static int doNTInit(void)
|
|
|
+static int determineUserDir(void)
|
|
|
{
|
|
|
- DWORD pathsize = 0;
|
|
|
+ DWORD psize = 0;
|
|
|
char dummy[1];
|
|
|
BOOL rc = 0;
|
|
|
- HANDLE ProcessHandle = NULL; /* Current process handle */
|
|
|
- HANDLE AccessTokenHandle = NULL; /* Security handle to process */
|
|
|
- LPFNGETUSERPROFILEDIR GetUserProfileDirectory = NULL;
|
|
|
- HMODULE lib = NULL;
|
|
|
- const char *err = NULL;
|
|
|
+ HANDLE processHandle; /* Current process handle */
|
|
|
+ HANDLE accessToken = NULL; /* Security handle to process */
|
|
|
+ LPFNGETUSERPROFILEDIR GetUserProfileDirectory;
|
|
|
+ HMODULE lib;
|
|
|
|
|
|
- /* Hooray for spaghetti code! */
|
|
|
+ assert(userDir == NULL);
|
|
|
|
|
|
- lib = LoadLibrary("userenv.dll");
|
|
|
- if (!lib)
|
|
|
- goto ntinit_failed;
|
|
|
+ /*
|
|
|
+ * GetUserProfileDirectory() is only available on NT 4.0 and later.
|
|
|
+ * This means Win95/98/ME (and CE?) users have to do without, so for
|
|
|
+ * them, we'll default to the base directory when we can't get the
|
|
|
+ * function pointer.
|
|
|
+ */
|
|
|
|
|
|
- /* !!! FIXME: Handle Unicode? */
|
|
|
- GetUserProfileDirectory = (LPFNGETUSERPROFILEDIR)
|
|
|
+ lib = LoadLibrary("userenv.dll");
|
|
|
+ if (lib)
|
|
|
+ {
|
|
|
+ /* !!! FIXME: Handle Unicode? */
|
|
|
+ GetUserProfileDirectory = (LPFNGETUSERPROFILEDIR)
|
|
|
GetProcAddress(lib, "GetUserProfileDirectoryA");
|
|
|
- if (!GetUserProfileDirectory)
|
|
|
- goto ntinit_failed;
|
|
|
-
|
|
|
- /* Create a process handle associated with the current process ID */
|
|
|
- ProcessHandle = GetCurrentProcess();
|
|
|
-
|
|
|
- /* Create a process access token handle */
|
|
|
- if(!OpenProcessToken(ProcessHandle, TOKEN_QUERY, &AccessTokenHandle))
|
|
|
- goto ntinit_failed; /* we need that token to get the profile dir. */
|
|
|
+ if (GetUserProfileDirectory)
|
|
|
+ {
|
|
|
+ processHandle = GetCurrentProcess();
|
|
|
+ if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken))
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ * Should fail. Will write the size of the profile path in
|
|
|
+ * psize. Also note that the second parameter can't be
|
|
|
+ * NULL or the function fails.
|
|
|
+ */
|
|
|
+ rc = GetUserProfileDirectory(accessToken, dummy, &psize);
|
|
|
+ assert(!rc); /* success?! */
|
|
|
+
|
|
|
+ /* Allocate memory for the profile directory */
|
|
|
+ userDir = (char *) malloc(psize);
|
|
|
+ if (userDir != NULL)
|
|
|
+ {
|
|
|
+ if (!GetUserProfileDirectory(accessToken, userDir, &psize))
|
|
|
+ {
|
|
|
+ free(userDir);
|
|
|
+ userDir = NULL;
|
|
|
+ } /* if */
|
|
|
+ } /* else */
|
|
|
+ } /* if */
|
|
|
|
|
|
- /* Should fail. Will write the size of the profile path in pathsize */
|
|
|
- /* Second parameter can't be NULL or the function fails. */
|
|
|
- rc = GetUserProfileDirectory(AccessTokenHandle, dummy, &pathsize);
|
|
|
- assert(!rc); /* success?! */
|
|
|
+ CloseHandle(accessToken);
|
|
|
+ } /* if */
|
|
|
|
|
|
- /* Allocate memory for the profile directory */
|
|
|
- ProfileDirectory = (char *) malloc(pathsize);
|
|
|
- if (ProfileDirectory == NULL)
|
|
|
- {
|
|
|
- err = ERR_OUT_OF_MEMORY;
|
|
|
- goto ntinit_failed;
|
|
|
+ FreeLibrary(lib);
|
|
|
} /* if */
|
|
|
|
|
|
- /* Try to get the profile directory */
|
|
|
- if(!GetUserProfileDirectory(AccessTokenHandle, ProfileDirectory, &pathsize))
|
|
|
- goto ntinit_failed;
|
|
|
-
|
|
|
- goto ntinit_succeeded; /* We made it: hit the showers. */
|
|
|
-
|
|
|
-ntinit_failed:
|
|
|
- if (err == NULL) /* set an error string if we haven't yet. */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
-
|
|
|
- if (ProfileDirectory != NULL)
|
|
|
+ if (userDir == NULL) /* couldn't get profile for some reason. */
|
|
|
{
|
|
|
- free(ProfileDirectory);
|
|
|
- ProfileDirectory = NULL;
|
|
|
+ /* Might just be a non-NT system; resort to the basedir. */
|
|
|
+ userDir = getExePath(NULL);
|
|
|
+ BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */
|
|
|
} /* if */
|
|
|
|
|
|
- /* drop through and clean up the rest of the stuff... */
|
|
|
-
|
|
|
-ntinit_succeeded:
|
|
|
- if (lib != NULL)
|
|
|
- FreeLibrary(lib);
|
|
|
-
|
|
|
- if (AccessTokenHandle != NULL)
|
|
|
- CloseHandle(AccessTokenHandle);
|
|
|
+ return(1); /* We made it: hit the showers. */
|
|
|
+} /* determineUserDir */
|
|
|
|
|
|
- return ((err == NULL) ? 1 : 0);
|
|
|
-} /* doNTInit */
|
|
|
|
|
|
-static BOOL MediaInDrive(const char *DriveLetter)
|
|
|
+static BOOL mediaInDrive(const char *driveLetter)
|
|
|
{
|
|
|
- UINT OldErrorMode;
|
|
|
- DWORD DummyValue;
|
|
|
- BOOL ReturnValue;
|
|
|
+ UINT oldErrorMode;
|
|
|
+ DWORD dummyValue;
|
|
|
+ BOOL returnValue;
|
|
|
|
|
|
/* Prevent windows warning message to appear when checking media size */
|
|
|
- OldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
+ oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
|
|
/* If this function succeeds, there's media in the drive */
|
|
|
- ReturnValue = GetDiskFreeSpace(DriveLetter, &DummyValue, &DummyValue, &DummyValue, &DummyValue);
|
|
|
+ returnValue = GetDiskFreeSpace(driveLetter, &dummyValue, &dummyValue, &dummyValue, &dummyValue);
|
|
|
|
|
|
/* Revert back to old windows error handler */
|
|
|
- SetErrorMode(OldErrorMode);
|
|
|
+ SetErrorMode(oldErrorMode);
|
|
|
+
|
|
|
+ return(returnValue);
|
|
|
+} /* mediaInDrive */
|
|
|
|
|
|
- return ReturnValue;
|
|
|
-} /* MediaInDrive */
|
|
|
|
|
|
char **__PHYSFS_platformDetectAvailableCDs(void)
|
|
|
{
|
|
|
@@ -185,16 +274,16 @@ char **__PHYSFS_platformDetectAvailableCDs(void)
|
|
|
|
|
|
for (drive_str[0] = 'A'; drive_str[0] <= 'Z'; drive_str[0]++)
|
|
|
{
|
|
|
- if (GetDriveType(drive_str) == DRIVE_CDROM && MediaInDrive(drive_str))
|
|
|
+ if (GetDriveType(drive_str) == DRIVE_CDROM && mediaInDrive(drive_str))
|
|
|
{
|
|
|
- char **tmp = realloc(retval, sizeof (char *) * cd_count + 1);
|
|
|
+ char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
|
|
|
if (tmp)
|
|
|
{
|
|
|
retval = tmp;
|
|
|
- retval[cd_count-1] = (char *) malloc(4);
|
|
|
- if (retval[cd_count-1])
|
|
|
+ retval[cd_count - 1] = (char *) malloc(4);
|
|
|
+ if (retval[cd_count - 1])
|
|
|
{
|
|
|
- strcpy(retval[cd_count-1], drive_str);
|
|
|
+ strcpy(retval[cd_count - 1], drive_str);
|
|
|
cd_count++;
|
|
|
} /* if */
|
|
|
} /* if */
|
|
|
@@ -206,51 +295,6 @@ char **__PHYSFS_platformDetectAvailableCDs(void)
|
|
|
} /* __PHYSFS_detectAvailableCDs */
|
|
|
|
|
|
|
|
|
-static char *getExePath(const char *argv0)
|
|
|
-{
|
|
|
- char *filepart = NULL;
|
|
|
- char *retval;
|
|
|
- DWORD buflen;
|
|
|
-
|
|
|
- retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
|
|
|
- BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
|
|
|
- buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
|
|
|
- if (buflen == 0)
|
|
|
- {
|
|
|
- const char *err = win32strerror();
|
|
|
- free(retval);
|
|
|
- BAIL_MACRO(err, NULL);
|
|
|
- } /* if */
|
|
|
-
|
|
|
- retval[buflen] = '\0'; /* does API always null-terminate the string? */
|
|
|
-
|
|
|
- /* make sure the string was not truncated. */
|
|
|
- if (__PHYSFS_platformStricmp(&retval[buflen - 4], ".exe") == 0)
|
|
|
- {
|
|
|
- char *ptr = strrchr(retval, '\\');
|
|
|
- if (ptr != NULL)
|
|
|
- {
|
|
|
- *(ptr + 1) = '\0'; /* chop off filename. */
|
|
|
-
|
|
|
- /* free up the bytes we didn't actually use. */
|
|
|
- ptr = (char *) realloc(retval, strlen(retval) + 1);
|
|
|
- if (ptr != NULL)
|
|
|
- retval = ptr;
|
|
|
-
|
|
|
- return(retval);
|
|
|
- } /* if */
|
|
|
- } /* if */
|
|
|
-
|
|
|
- /* if any part of the previous approach failed, try SearchPath()... */
|
|
|
- buflen = SearchPath(NULL, argv0, NULL, buflen, NULL, NULL);
|
|
|
- retval = (char *) realloc(retval, buflen);
|
|
|
- BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
|
|
|
- SearchPath(NULL, argv0, NULL, buflen, retval, &filepart);
|
|
|
-
|
|
|
- return(retval);
|
|
|
-} /* getExePath */
|
|
|
-
|
|
|
-
|
|
|
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|
|
{
|
|
|
if (strchr(argv0, '\\') != NULL) /* default behaviour can handle this. */
|
|
|
@@ -283,16 +327,16 @@ char *__PHYSFS_platformGetUserName(void)
|
|
|
|
|
|
char *__PHYSFS_platformGetUserDir(void)
|
|
|
{
|
|
|
- char *retval = (char *) malloc(strlen(ProfileDirectory) + 1);
|
|
|
+ char *retval = (char *) malloc(strlen(userDir) + 1);
|
|
|
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
|
|
|
- strcpy(retval, ProfileDirectory); /* calculated at init time. */
|
|
|
- return retval;
|
|
|
+ strcpy(retval, userDir); /* calculated at init time. */
|
|
|
+ return(retval);
|
|
|
} /* __PHYSFS_platformGetUserDir */
|
|
|
|
|
|
|
|
|
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
|
|
|
{
|
|
|
- return((PHYSFS_uint64)GetCurrentThreadId());
|
|
|
+ return((PHYSFS_uint64) GetCurrentThreadId());
|
|
|
} /* __PHYSFS_platformGetThreadID */
|
|
|
|
|
|
|
|
|
@@ -323,7 +367,7 @@ int __PHYSFS_platformStricmp(const char *x, const char *y)
|
|
|
|
|
|
int __PHYSFS_platformExists(const char *fname)
|
|
|
{
|
|
|
- return(GetFileAttributes(fname) != 0xffffffff);
|
|
|
+ return(GetFileAttributes(fname) != INVALID_FILE_ATTRIBUTES);
|
|
|
} /* __PHYSFS_platformExists */
|
|
|
|
|
|
|
|
|
@@ -387,7 +431,7 @@ LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
|
|
|
size_t len = strlen(dirname);
|
|
|
|
|
|
/* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
|
|
|
- SearchPath = (char *) _alloca(len + 3);
|
|
|
+ SearchPath = (char *) alloca(len + 3);
|
|
|
BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);
|
|
|
|
|
|
/* Copy current dirname */
|
|
|
@@ -587,108 +631,151 @@ int __PHYSFS_platformMkDir(const char *path)
|
|
|
} /* __PHYSFS_platformMkDir */
|
|
|
|
|
|
|
|
|
-/*
|
|
|
- * Get OS info and save it.
|
|
|
+/*
|
|
|
+ * Get OS info and save the important parts.
|
|
|
*
|
|
|
* Returns non-zero if successful, otherwise it returns zero on failure.
|
|
|
*/
|
|
|
-int getOSInfo(void)
|
|
|
+static int getOSInfo(void)
|
|
|
{
|
|
|
- /* Get OS info */
|
|
|
+#if 0 /* we don't actually use this at the moment, but may in the future. */
|
|
|
+ OSVERSIONINFO OSVersionInfo; /* Information about the OS */
|
|
|
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
|
|
|
BAIL_IF_MACRO(!GetVersionEx(&OSVersionInfo), win32strerror(), 0);
|
|
|
|
|
|
/* Set to TRUE if we are runnign a WinNT based OS 4.0 or greater */
|
|
|
- runningNT = (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
|
- (OSVersionInfo.dwMajorVersion > 3);
|
|
|
+ runningNT = ((OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
|
+ (OSVersionInfo.dwMajorVersion >= 4));
|
|
|
+#endif
|
|
|
|
|
|
- return 1;
|
|
|
-}
|
|
|
+ return(1);
|
|
|
+} /* getOSInfo */
|
|
|
|
|
|
-int __PHYSFS_platformInit(void)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Some things we want/need are in external DLLs that may or may not be
|
|
|
+ * available, based on the operating system, etc. This function loads those
|
|
|
+ * libraries and hunts down the needed pointers.
|
|
|
+ *
|
|
|
+ * Libraries that are one-shot deals, or better loaded as needed, are loaded
|
|
|
+ * elsewhere (see determineUserDir()).
|
|
|
+ *
|
|
|
+ * Returns zero if a needed library couldn't load, non-zero if we have enough
|
|
|
+ * to go on (which means some useful but non-crucial libraries may _NOT_ be
|
|
|
+ * loaded; check the related module-scope variables).
|
|
|
+ */
|
|
|
+static int loadLibraries(void)
|
|
|
{
|
|
|
- BAIL_IF_MACRO(!getOSInfo(), NULL, 0);
|
|
|
+ /* !!! FIXME: Make this table driven? */
|
|
|
+ int allNeededLibrariesLoaded = 1; /* flip to zero as needed. */
|
|
|
|
|
|
- /* If running an NT system (NT/Win2k/XP, etc...) */
|
|
|
- if(runningNT)
|
|
|
+ libKernel32 = LoadLibrary("kernel32.dll");
|
|
|
+ if (libKernel32)
|
|
|
{
|
|
|
- BAIL_IF_MACRO(!doNTInit(), NULL, 0);
|
|
|
+ pGetFileAttributesEx = (LPFNGETFILEATTRIBUTESEX)
|
|
|
+ GetProcAddress(libKernel32, "GetFileAttributesExA");
|
|
|
} /* if */
|
|
|
- else
|
|
|
+
|
|
|
+ /* add other DLLs here... */
|
|
|
+
|
|
|
+
|
|
|
+ /* see if there's any reason to keep kernel32.dll around... */
|
|
|
+ if (libKernel32)
|
|
|
{
|
|
|
- /* Profile directory is the exe path on 95/98/ME systems. */
|
|
|
- ProfileDirectory = getExePath(NULL);
|
|
|
- BAIL_IF_MACRO(ProfileDirectory == NULL, win32strerror(), 0);
|
|
|
- } /* else */
|
|
|
+ if ((pGetFileAttributesEx == NULL) /* && (somethingElse == NULL) */ )
|
|
|
+ {
|
|
|
+ FreeLibrary(libKernel32);
|
|
|
+ libKernel32 = NULL;
|
|
|
+ } /* if */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ return(allNeededLibrariesLoaded);
|
|
|
+} /* loadLibraries */
|
|
|
+
|
|
|
+
|
|
|
+int __PHYSFS_platformInit(void)
|
|
|
+{
|
|
|
+ BAIL_IF_MACRO(!getOSInfo(), NULL, 0);
|
|
|
+ BAIL_IF_MACRO(!loadLibraries(), NULL, 0);
|
|
|
+ BAIL_IF_MACRO(!determineUserDir(), NULL, 0);
|
|
|
+
|
|
|
+ return(1); /* It's all good */
|
|
|
+} /* __PHYSFS_platformInit */
|
|
|
|
|
|
- return 1; /* It's all good */
|
|
|
-}
|
|
|
|
|
|
int __PHYSFS_platformDeinit(void)
|
|
|
{
|
|
|
- if (runningNT)
|
|
|
+ if (userDir != NULL)
|
|
|
{
|
|
|
- BAIL_IF_MACRO(!doNTDeinit(), NULL, 0);
|
|
|
+ free(userDir);
|
|
|
+ userDir = NULL;
|
|
|
} /* if */
|
|
|
|
|
|
- if (ProfileDirectory != NULL)
|
|
|
+ return(1); /* It's all good */
|
|
|
+} /* __PHYSFS_platformDeinit */
|
|
|
+
|
|
|
+
|
|
|
+static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly)
|
|
|
+{
|
|
|
+ HANDLE fileHandle;
|
|
|
+ win32file *retval;
|
|
|
+
|
|
|
+ fileHandle = CreateFile(fname, mode, FILE_SHARE_READ, NULL,
|
|
|
+ creation, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
+
|
|
|
+ BAIL_IF_MACRO(fileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
|
|
|
+
|
|
|
+ retval = malloc(sizeof (win32file));
|
|
|
+ if (retval == NULL)
|
|
|
{
|
|
|
- free(ProfileDirectory);
|
|
|
- ProfileDirectory = NULL;
|
|
|
+ CloseHandle(fileHandle);
|
|
|
+ BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
|
|
|
} /* if */
|
|
|
|
|
|
- return 1; /* It's all good */
|
|
|
-}
|
|
|
+ retval->readonly = rdonly;
|
|
|
+ retval->handle = fileHandle;
|
|
|
+ return(retval);
|
|
|
+} /* doOpen */
|
|
|
+
|
|
|
|
|
|
void *__PHYSFS_platformOpenRead(const char *filename)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
-
|
|
|
- /* Open an existing file for read only. File can be opened by others
|
|
|
- who request read access on the file only. */
|
|
|
- FileHandle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
+ return(doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1));
|
|
|
+} /* __PHYSFS_platformOpenRead */
|
|
|
|
|
|
- BAIL_IF_MACRO(FileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
|
|
|
- return (void *)FileHandle;
|
|
|
-}
|
|
|
|
|
|
void *__PHYSFS_platformOpenWrite(const char *filename)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
-
|
|
|
- /* Open an existing file for write only. File can be opened by others
|
|
|
- who request read access to the file only */
|
|
|
- FileHandle = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
|
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
+ return(doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0));
|
|
|
+} /* __PHYSFS_platformOpenWrite */
|
|
|
|
|
|
- BAIL_IF_MACRO(FileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
|
|
|
- return (void *)FileHandle;
|
|
|
-}
|
|
|
|
|
|
void *__PHYSFS_platformOpenAppend(const char *filename)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
-
|
|
|
- /* Open an existing file for appending only. File can be opened by others
|
|
|
- who request read access to the file only. */
|
|
|
- FileHandle = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
|
|
- OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
+ void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0);
|
|
|
+ if (retval != NULL)
|
|
|
+ {
|
|
|
+ HANDLE h = ((win32file *) retval)->handle;
|
|
|
+ if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
|
|
|
+ {
|
|
|
+ const char *err = win32strerror();
|
|
|
+ CloseHandle(h);
|
|
|
+ free(retval);
|
|
|
+ BAIL_MACRO(err, NULL);
|
|
|
+ } /* if */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformOpenAppend */
|
|
|
|
|
|
- BAIL_IF_MACRO(FileHandle == INVALID_HANDLE_VALUE, win32strerror(), NULL);
|
|
|
- return (void *)FileHandle;
|
|
|
-}
|
|
|
|
|
|
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
|
|
|
PHYSFS_uint32 size, PHYSFS_uint32 count)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
DWORD CountOfBytesRead;
|
|
|
PHYSFS_sint64 retval;
|
|
|
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
-
|
|
|
/* Read data from the file */
|
|
|
/*!!! - uint32 might be a greater # than DWORD */
|
|
|
if(!ReadFile(FileHandle, buffer, count * size, &CountOfBytesRead, NULL))
|
|
|
@@ -702,19 +789,17 @@ PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
|
|
|
retval = CountOfBytesRead / size;
|
|
|
} /* else */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformRead */
|
|
|
+
|
|
|
|
|
|
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
|
|
|
PHYSFS_uint32 size, PHYSFS_uint32 count)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
DWORD CountOfBytesWritten;
|
|
|
PHYSFS_sint64 retval;
|
|
|
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
-
|
|
|
/* Read data from the file */
|
|
|
/*!!! - uint32 might be a greater # than DWORD */
|
|
|
if(!WriteFile(FileHandle, buffer, count * size, &CountOfBytesWritten, NULL))
|
|
|
@@ -728,248 +813,258 @@ PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
|
|
|
retval = CountOfBytesWritten / size;
|
|
|
} /* else */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformWrite */
|
|
|
+
|
|
|
|
|
|
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
- int retval;
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
DWORD HighOrderPos;
|
|
|
-
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
+ DWORD rc;
|
|
|
|
|
|
/* Get the high order 32-bits of the position */
|
|
|
HighOrderPos = HIGHORDER_UINT64(pos);
|
|
|
|
|
|
/*!!! SetFilePointer needs a signed 64-bit value. */
|
|
|
/* Move pointer "pos" count from start of file */
|
|
|
- if((SetFilePointer(FileHandle, LOWORDER_UINT64(pos), &HighOrderPos, FILE_BEGIN)
|
|
|
- == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
- {
|
|
|
- /* An error occured. Set the error to GetLastError */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
+ rc = SetFilePointer(FileHandle, LOWORDER_UINT64(pos),
|
|
|
+ &HighOrderPos, FILE_BEGIN);
|
|
|
|
|
|
- retval = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* No error occured */
|
|
|
- retval = 1;
|
|
|
- }
|
|
|
+ if ((rc == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
+ BAIL_MACRO(win32strerror(), 0);
|
|
|
+
|
|
|
+ return(1); /* No error occured */
|
|
|
+} /* __PHYSFS_platformSeek */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
- DWORD HighOrderPos = 0;
|
|
|
- DWORD LowOrderPos;
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
+ DWORD HighPos = 0;
|
|
|
+ DWORD LowPos;
|
|
|
PHYSFS_sint64 retval;
|
|
|
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
-
|
|
|
/* Get current position */
|
|
|
- if(((LowOrderPos = SetFilePointer(FileHandle, 0, &HighOrderPos, FILE_CURRENT))
|
|
|
- == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
+ LowPos = SetFilePointer(FileHandle, 0, &HighPos, FILE_CURRENT);
|
|
|
+ if ((LowPos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
{
|
|
|
- /* Set the error to GetLastError */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
- /* We errored out */
|
|
|
- retval = 0;
|
|
|
- }
|
|
|
+ BAIL_MACRO(win32strerror(), 0);
|
|
|
+ } /* if */
|
|
|
else
|
|
|
{
|
|
|
/* Combine the high/low order to create the 64-bit position value */
|
|
|
- retval = HighOrderPos;
|
|
|
- retval = retval << 32;
|
|
|
- retval |= LowOrderPos;
|
|
|
- }
|
|
|
+ retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos;
|
|
|
+ assert(retval >= 0);
|
|
|
+ } /* else */
|
|
|
+
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformTell */
|
|
|
|
|
|
- /*!!! Can't find a file pointer routine?!?!?!!?!?*/
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
-PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle)
|
|
|
+PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
- DWORD FileSizeHigh;
|
|
|
- DWORD FileSizeLow;
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
+ DWORD SizeHigh;
|
|
|
+ DWORD SizeLow;
|
|
|
PHYSFS_sint64 retval;
|
|
|
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)handle;
|
|
|
-
|
|
|
- /* Get the file size. Condition evaluates to TRUE if an error occured */
|
|
|
- if(((FileSizeLow = GetFileSize(FileHandle, &FileSizeHigh))
|
|
|
- == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
+ SizeLow = GetFileSize(FileHandle, &SizeHigh);
|
|
|
+ if ((SizeLow == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
|
|
|
{
|
|
|
BAIL_MACRO(win32strerror(), -1);
|
|
|
} /* if */
|
|
|
else
|
|
|
{
|
|
|
/* Combine the high/low order to create the 64-bit position value */
|
|
|
- retval = FileSizeHigh;
|
|
|
- retval = retval << 32;
|
|
|
- retval |= FileSizeLow;
|
|
|
+ retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow;
|
|
|
+ assert(retval >= 0);
|
|
|
} /* else */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformFileLength */
|
|
|
+
|
|
|
|
|
|
int __PHYSFS_platformEOF(void *opaque)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
PHYSFS_sint64 FilePosition;
|
|
|
int retval = 0;
|
|
|
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
-
|
|
|
/* Get the current position in the file */
|
|
|
- if((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
|
|
|
+ if ((FilePosition = __PHYSFS_platformTell(opaque)) != 0)
|
|
|
{
|
|
|
/* Non-zero if EOF is equal to the file length */
|
|
|
retval = FilePosition == __PHYSFS_platformFileLength(opaque);
|
|
|
- }
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ return(retval);
|
|
|
+} /* __PHYSFS_platformEOF */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
int __PHYSFS_platformFlush(void *opaque)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
- int retval;
|
|
|
-
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
+ win32file *fh = ((win32file *) opaque);
|
|
|
+ if (!fh->readonly)
|
|
|
+ BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), win32strerror(), 0);
|
|
|
|
|
|
- /* Close the file */
|
|
|
- if(!(retval = FlushFileBuffers(FileHandle)))
|
|
|
- {
|
|
|
- /* Set the error to GetLastError */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
- }
|
|
|
+ return(1);
|
|
|
+} /* __PHYSFS_platformFlush */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
int __PHYSFS_platformClose(void *opaque)
|
|
|
{
|
|
|
- HANDLE FileHandle;
|
|
|
- int retval;
|
|
|
-
|
|
|
- /* Cast the generic handle to a Win32 handle */
|
|
|
- FileHandle = (HANDLE)opaque;
|
|
|
-
|
|
|
- /* Close the file */
|
|
|
- if(!(retval = CloseHandle(FileHandle)))
|
|
|
- {
|
|
|
- /* Set the error to GetLastError */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
- }
|
|
|
+ HANDLE FileHandle = ((win32file *) opaque)->handle;
|
|
|
+ BAIL_IF_MACRO(!CloseHandle(FileHandle), win32strerror(), 0);
|
|
|
+ free(opaque);
|
|
|
+ return(1);
|
|
|
+} /* __PHYSFS_platformClose */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
int __PHYSFS_platformDelete(const char *path)
|
|
|
{
|
|
|
- int retval;
|
|
|
-
|
|
|
/* If filename is a folder */
|
|
|
- if(GetFileAttributes(path) == FILE_ATTRIBUTE_DIRECTORY)
|
|
|
+ if (GetFileAttributes(path) == FILE_ATTRIBUTE_DIRECTORY)
|
|
|
{
|
|
|
- retval = RemoveDirectory(path);
|
|
|
- }
|
|
|
+ BAIL_IF_MACRO(!RemoveDirectory(path), win32strerror(), 0);
|
|
|
+ } /* if */
|
|
|
else
|
|
|
{
|
|
|
- retval = DeleteFile(path);
|
|
|
- }
|
|
|
+ BAIL_IF_MACRO(!DeleteFile(path), win32strerror(), 0);
|
|
|
+ } /* else */
|
|
|
|
|
|
- if(!retval)
|
|
|
- {
|
|
|
- /* Set the error to GetLastError */
|
|
|
- __PHYSFS_setError(win32strerror());
|
|
|
- }
|
|
|
+ return(1); /* if you got here, it worked. */
|
|
|
+} /* __PHYSFS_platformDelete */
|
|
|
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
void *__PHYSFS_platformCreateMutex(void)
|
|
|
{
|
|
|
- return (void *)CreateMutex(NULL, FALSE, NULL);
|
|
|
-}
|
|
|
+ return((void *) CreateMutex(NULL, FALSE, NULL));
|
|
|
+} /* __PHYSFS_platformCreateMutex */
|
|
|
+
|
|
|
|
|
|
void __PHYSFS_platformDestroyMutex(void *mutex)
|
|
|
{
|
|
|
- CloseHandle((HANDLE)mutex);
|
|
|
-}
|
|
|
+ CloseHandle((HANDLE) mutex);
|
|
|
+} /* __PHYSFS_platformDestroyMutex */
|
|
|
+
|
|
|
|
|
|
int __PHYSFS_platformGrabMutex(void *mutex)
|
|
|
{
|
|
|
- int retval;
|
|
|
+ return(WaitForSingleObject((HANDLE) mutex, INFINITE) != WAIT_FAILED);
|
|
|
+} /* __PHYSFS_platformGrabMutex */
|
|
|
|
|
|
- if(WaitForSingleObject((HANDLE)mutex, INFINITE) == WAIT_FAILED)
|
|
|
- {
|
|
|
- /* Our wait failed for some unknown reason */
|
|
|
- retval = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* Good to go */
|
|
|
- retval = 1;
|
|
|
- }
|
|
|
-
|
|
|
- return retval;
|
|
|
-}
|
|
|
|
|
|
void __PHYSFS_platformReleaseMutex(void *mutex)
|
|
|
{
|
|
|
- ReleaseMutex((HANDLE)mutex);
|
|
|
-}
|
|
|
+ ReleaseMutex((HANDLE) mutex);
|
|
|
+} /* __PHYSFS_platformReleaseMutex */
|
|
|
+
|
|
|
|
|
|
-static time_t FileTimeToTimeT(FILETIME *ft)
|
|
|
+static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
|
|
|
{
|
|
|
SYSTEMTIME st_utc;
|
|
|
SYSTEMTIME st_localtz;
|
|
|
- TIME_ZONE_INFORMATION TimeZoneInfo;
|
|
|
+ TIME_ZONE_INFORMATION tzi;
|
|
|
+ DWORD tzid;
|
|
|
+ PHYSFS_sint64 retval;
|
|
|
struct tm tm;
|
|
|
|
|
|
- FileTimeToSystemTime(ft, &st_utc);
|
|
|
- GetTimeZoneInformation(&TimeZoneInfo);
|
|
|
- SystemTimeToTzSpecificLocalTime(&TimeZoneInfo, &st_utc, &st_localtz);
|
|
|
+ BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), win32strerror(), -1);
|
|
|
+ tzid = GetTimeZoneInformation(&tzi);
|
|
|
+ BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, win32strerror(), -1);
|
|
|
|
|
|
+ /* (This API is unsupported and fails on non-NT systems. */
|
|
|
+ if (!SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz))
|
|
|
+ {
|
|
|
+ /* do it by hand. Grumble... */
|
|
|
+ ULARGE_INTEGER ui64;
|
|
|
+ FILETIME new_ft;
|
|
|
+ ui64.LowPart = ft->dwLowDateTime;
|
|
|
+ ui64.HighPart = ft->dwHighDateTime;
|
|
|
+
|
|
|
+ if (tzid == TIME_ZONE_ID_STANDARD)
|
|
|
+ tzi.Bias += tzi.StandardBias;
|
|
|
+ else if (tzid == TIME_ZONE_ID_DAYLIGHT)
|
|
|
+ tzi.Bias += tzi.DaylightBias;
|
|
|
+
|
|
|
+ /* convert from minutes to 100-nanosecond increments... */
|
|
|
+ #if 0 /* For compilers that puke on 64-bit math. */
|
|
|
+ /* goddamn this is inefficient... */
|
|
|
+ while (tzi.Bias > 0)
|
|
|
+ {
|
|
|
+ DWORD tmp = ui64.LowPart - 60000000;
|
|
|
+ if ((ui64.LowPart < tmp) && (tmp > 60000000))
|
|
|
+ ui64.HighPart--;
|
|
|
+ ui64.LowPart = tmp;
|
|
|
+ tzi.Bias--;
|
|
|
+ } /* while */
|
|
|
+
|
|
|
+ while (tzi.Bias < 0)
|
|
|
+ {
|
|
|
+ DWORD tmp = ui64.LowPart + 60000000;
|
|
|
+ if ((ui64.LowPart > tmp) && (tmp < 60000000))
|
|
|
+ ui64.HighPart++;
|
|
|
+ ui64.LowPart = tmp;
|
|
|
+ tzi.Bias++;
|
|
|
+ } /* while */
|
|
|
+ #else
|
|
|
+ ui64.QuadPart -= (((LONGLONG) tzi.Bias) * (600000000));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ /* Move it back into a FILETIME structure... */
|
|
|
+ new_ft.dwLowDateTime = ui64.LowPart;
|
|
|
+ new_ft.dwHighDateTime = ui64.HighPart;
|
|
|
+
|
|
|
+ /* Convert to something human-readable... */
|
|
|
+ if (!FileTimeToSystemTime(&new_ft, &st_localtz))
|
|
|
+ BAIL_MACRO(win32strerror(), -1);
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ /* Convert to a format that mktime() can grok... */
|
|
|
tm.tm_sec = st_localtz.wSecond;
|
|
|
tm.tm_min = st_localtz.wMinute;
|
|
|
tm.tm_hour = st_localtz.wHour;
|
|
|
tm.tm_mday = st_localtz.wDay;
|
|
|
tm.tm_mon = st_localtz.wMonth - 1;
|
|
|
tm.tm_year = st_localtz.wYear - 1900;
|
|
|
- tm.tm_wday = st_localtz.wDayOfWeek;
|
|
|
+ tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
|
|
|
tm.tm_yday = -1;
|
|
|
tm.tm_isdst = -1;
|
|
|
- return mktime(&tm);
|
|
|
-} /* FileTimeToTimeT */
|
|
|
+
|
|
|
+ /* Convert to a format PhysicsFS can grok... */
|
|
|
+ retval = (PHYSFS_sint64) mktime(&tm);
|
|
|
+ BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
|
|
|
+ return(retval);
|
|
|
+} /* FileTimeToPhysfsTime */
|
|
|
+
|
|
|
|
|
|
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
|
|
|
{
|
|
|
- WIN32_FILE_ATTRIBUTE_DATA AttributeData;
|
|
|
+ PHYSFS_sint64 retval = -1;
|
|
|
+ WIN32_FILE_ATTRIBUTE_DATA attrData;
|
|
|
+ memset(&attrData, '\0', sizeof (attrData));
|
|
|
|
|
|
- GetFileAttributesEx(fname, GetFileExInfoStandard, &AttributeData);
|
|
|
- /* 0 return value indicates an error or not supported */
|
|
|
- if(AttributeData.ftLastWriteTime.dwHighDateTime == 0 &&
|
|
|
- AttributeData.ftLastWriteTime.dwLowDateTime == 0)
|
|
|
+ if (pGetFileAttributesEx != NULL)
|
|
|
{
|
|
|
- /* Return error */
|
|
|
- BAIL_MACRO(win32strerror(), -1);
|
|
|
- }
|
|
|
+ if (pGetFileAttributesEx(fname, GetFileExInfoStandard, &attrData))
|
|
|
+ {
|
|
|
+ /* 0 return value indicates an error or not supported */
|
|
|
+ if ( (attrData.ftLastWriteTime.dwHighDateTime != 0) ||
|
|
|
+ (attrData.ftLastWriteTime.dwLowDateTime != 0) )
|
|
|
+ {
|
|
|
+ retval = FileTimeToPhysfsTime(&attrData.ftLastWriteTime);
|
|
|
+ } /* if */
|
|
|
+ } /* if */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ if (retval == -1) /* try a fallback... */
|
|
|
+ {
|
|
|
+ /* !!! FIXME: uhh...? */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ return(retval);
|
|
|
|
|
|
- /* Return UNIX time_t version of last write time */
|
|
|
- return (PHYSFS_sint64)FileTimeToTimeT(&AttributeData.ftLastWriteTime);
|
|
|
- /*return (PHYSFS_sint64)FileTimeToTimeT(&AttributeData.ftCreationTime);*/
|
|
|
+ /*return(FileTimeToPhysfsTime(&attrData.ftCreationTime));*/
|
|
|
} /* __PHYSFS_platformGetLastModTime */
|
|
|
|
|
|
/* end of win32.c ... */
|