Improved dynamic loader and initial Unicode work in windows.c ...
This commit is contained in:
parent
71e6a8dc3f
commit
dc0d27228c
|
@ -2,6 +2,7 @@
|
||||||
* CHANGELOG.
|
* CHANGELOG.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
03252007 - Improved dynamic loader and initial Unicode work in windows.c ...
|
||||||
03242007 - Replaced BeOS semaphores with BLockers for the mutex implementation.
|
03242007 - Replaced BeOS semaphores with BLockers for the mutex implementation.
|
||||||
It's much simpler, it has "benaphores" built in behind the scenes
|
It's much simpler, it has "benaphores" built in behind the scenes
|
||||||
for faster performance, and it's recursive...also, we were
|
for faster performance, and it's recursive...also, we were
|
||||||
|
|
|
@ -26,32 +26,6 @@
|
||||||
#define HIGHORDER_UINT64(pos) (PHYSFS_uint32) \
|
#define HIGHORDER_UINT64(pos) (PHYSFS_uint32) \
|
||||||
(((pos & 0xFFFFFFFF00000000) >> 32) & 0x00000000FFFFFFFF)
|
(((pos & 0xFFFFFFFF00000000) >> 32) & 0x00000000FFFFFFFF)
|
||||||
|
|
||||||
|
|
||||||
/* !!! FIXME: unicode version. */
|
|
||||||
/* GetUserProfileDirectory() is only available on >= NT4 (no 9x/ME systems!) */
|
|
||||||
typedef BOOL (STDMETHODCALLTYPE FAR * LPFNGETUSERPROFILEDIR) (
|
|
||||||
HANDLE hToken,
|
|
||||||
LPTSTR lpProfileDir,
|
|
||||||
LPDWORD lpcchSize);
|
|
||||||
|
|
||||||
/* !!! FIXME: unicode version. */
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
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
|
* Users without the platform SDK don't have this defined. The original docs
|
||||||
* for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
|
* for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should
|
||||||
|
@ -62,6 +36,100 @@ static char *userDir = NULL;
|
||||||
/* just in case... */
|
/* just in case... */
|
||||||
#define PHYSFS_INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
|
#define PHYSFS_INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \
|
||||||
|
if (str == NULL) \
|
||||||
|
w_assignto = NULL; \
|
||||||
|
else { \
|
||||||
|
const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) * 4) + 1); \
|
||||||
|
w_assignto = (char *) __PHYSFS_smallAlloc(len); \
|
||||||
|
PHYSFS_uc2fromutf8(str, (PHYSFS_uint16 *) w_assignto, len); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HANDLE handle;
|
||||||
|
int readonly;
|
||||||
|
} win32file;
|
||||||
|
|
||||||
|
const char *__PHYSFS_platformDirSeparator = "\\";
|
||||||
|
|
||||||
|
|
||||||
|
/* pointers for APIs that may not exist on some Windows versions... */
|
||||||
|
static HANDLE libKernel32 = NULL;
|
||||||
|
static HANDLE libUserEnv = NULL;
|
||||||
|
static HANDLE libAdvApi32 = NULL;
|
||||||
|
static DWORD (WINAPI *pGetModuleFileNameA)(HMODULE, LPCH, DWORD);
|
||||||
|
static DWORD (WINAPI *pGetModuleFileNameW)(HMODULE, LPWCH, DWORD);
|
||||||
|
static BOOL (WINAPI *pGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
|
||||||
|
static BOOL (WINAPI *pGetUserNameW)(LPWSTR, LPDWORD);
|
||||||
|
static DWORD (WINAPI *pGetFileAttributesW)(LPCWSTR);
|
||||||
|
static HANDLE (WINAPI *pFindFirstFileW)(LPCWSTR, LPWIN32_FIND_DATAW);
|
||||||
|
static BOOL (WINAPI *pFindNextFileW)(HANDLE, LPWIN32_FIND_DATAW);
|
||||||
|
static DWORD (WINAPI *pGetCurrentDirectoryW)(DWORD, LPWSTR);
|
||||||
|
static BOOL (WINAPI *pDeleteFileW)(LPCWSTR);
|
||||||
|
static BOOL (WINAPI *pRemoveDirectoryW)(LPCWSTR);
|
||||||
|
static BOOL (WINAPI *pCreateDirectoryW)(LPCWSTR, LPSECURITY_ATTRIBUTES);
|
||||||
|
static BOOL (WINAPI *pGetFileAttributesExA)
|
||||||
|
(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
|
||||||
|
static BOOL (WINAPI *pGetFileAttributesExW)
|
||||||
|
(LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
|
||||||
|
static DWORD (WINAPI *pFormatMessageW)
|
||||||
|
(DWORD, LPCVOID, DWORD, DWORD, LPWSTR, DWORD, va_list *);
|
||||||
|
static DWORD (WINAPI *pSearchPathW)
|
||||||
|
(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPWSTR, LPWSTR *);
|
||||||
|
static HANDLE (WINAPI *pCreateFileW)
|
||||||
|
(LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
|
||||||
|
|
||||||
|
static char *userDir = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* A blatant abuse of pointer casting... */
|
||||||
|
static void symLookup(HMODULE dll, void **addr, const char *sym)
|
||||||
|
{
|
||||||
|
*addr = GetProcAddress(dll, sym);
|
||||||
|
} /* symLookup */
|
||||||
|
|
||||||
|
|
||||||
|
static int findApiSymbols(void)
|
||||||
|
{
|
||||||
|
HMODULE dll = NULL;
|
||||||
|
|
||||||
|
#define LOOKUP(x) { symLookup(dll, (void **) &p##x, #x); }
|
||||||
|
|
||||||
|
dll = libUserEnv = LoadLibrary("userenv.dll");
|
||||||
|
if (dll != NULL)
|
||||||
|
LOOKUP(GetUserProfileDirectoryW);
|
||||||
|
|
||||||
|
/* !!! FIXME: what do they call advapi32.dll on Win64? */
|
||||||
|
dll = libAdvApi32 = LoadLibrary("advapi32.dll");
|
||||||
|
if (dll != NULL)
|
||||||
|
LOOKUP(GetUserNameW);
|
||||||
|
|
||||||
|
/* !!! FIXME: what do they call kernel32.dll on Win64? */
|
||||||
|
dll = libKernel32 = LoadLibrary("kernel32.dll");
|
||||||
|
if (dll != NULL)
|
||||||
|
{
|
||||||
|
LOOKUP(GetModuleFileNameA);
|
||||||
|
LOOKUP(GetModuleFileNameW);
|
||||||
|
LOOKUP(FormatMessageW);
|
||||||
|
LOOKUP(FindFirstFileW);
|
||||||
|
LOOKUP(FindNextFileW);
|
||||||
|
LOOKUP(GetFileAttributesW);
|
||||||
|
LOOKUP(GetFileAttributesExA);
|
||||||
|
LOOKUP(GetFileAttributesExW);
|
||||||
|
LOOKUP(GetCurrentDirectoryW);
|
||||||
|
LOOKUP(CreateDirectoryW);
|
||||||
|
LOOKUP(RemoveDirectoryW);
|
||||||
|
LOOKUP(CreateFileW);
|
||||||
|
LOOKUP(DeleteFileW);
|
||||||
|
LOOKUP(SearchPathW);
|
||||||
|
} /* if */
|
||||||
|
|
||||||
|
#undef LOOKUP
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
} /* findApiSymbols */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -175,7 +243,7 @@ static char *getExePath(const char *argv0)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to make use of GetUserProfileDirectory(), which isn't available on
|
* Try to make use of GetUserProfileDirectoryW(), which isn't available on
|
||||||
* some common variants of Win32. If we can't use this, we just punt and
|
* 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.
|
* use the physfs base dir for the user dir, too.
|
||||||
*
|
*
|
||||||
|
@ -186,64 +254,52 @@ static char *getExePath(const char *argv0)
|
||||||
*/
|
*/
|
||||||
static int determineUserDir(void)
|
static int determineUserDir(void)
|
||||||
{
|
{
|
||||||
DWORD psize = 0;
|
if (userDir != NULL)
|
||||||
char dummy[1];
|
return(1); /* already good to go. */
|
||||||
BOOL rc = 0;
|
|
||||||
HANDLE processHandle; /* Current process handle */
|
|
||||||
HANDLE accessToken = NULL; /* Security handle to process */
|
|
||||||
LPFNGETUSERPROFILEDIR GetUserProfileDirectory;
|
|
||||||
HMODULE lib;
|
|
||||||
|
|
||||||
assert(userDir == NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetUserProfileDirectory() is only available on NT 4.0 and later.
|
* GetUserProfileDirectoryW() is only available on NT 4.0 and later.
|
||||||
* This means Win95/98/ME (and CE?) users have to do without, so for
|
* 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
|
* them, we'll default to the base directory when we can't get the
|
||||||
* function pointer.
|
* function pointer. Since this is originally an NT API, we don't
|
||||||
|
* offer a non-Unicode fallback.
|
||||||
*/
|
*/
|
||||||
|
if (pGetUserProfileDirectoryW != NULL)
|
||||||
lib = LoadLibrary("userenv.dll");
|
|
||||||
if (lib)
|
|
||||||
{
|
{
|
||||||
/* !!! FIXME: unicode version. */
|
HANDLE accessToken = NULL; /* Security handle to process */
|
||||||
GetUserProfileDirectory = (LPFNGETUSERPROFILEDIR)
|
HANDLE processHandle = GetCurrentProcess();
|
||||||
GetProcAddress(lib, "GetUserProfileDirectoryA");
|
if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken))
|
||||||
if (GetUserProfileDirectory)
|
|
||||||
{
|
{
|
||||||
processHandle = GetCurrentProcess();
|
DWORD psize = 0;
|
||||||
if (OpenProcessToken(processHandle, TOKEN_QUERY, &accessToken))
|
WCHAR dummy = 0;
|
||||||
|
LPWSTR wstr = NULL;
|
||||||
|
BOOL rc = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = pGetUserProfileDirectoryW(accessToken, &dummy, &psize);
|
||||||
|
assert(!rc); /* !!! FIXME: handle this gracefully. */
|
||||||
|
|
||||||
|
/* Allocate memory for the profile directory */
|
||||||
|
wstr = (LPWSTR) __PHYSFS_smallAlloc(psize * sizeof (WCHAR));
|
||||||
|
if (wstr != NULL)
|
||||||
{
|
{
|
||||||
/*
|
if (pGetUserProfileDirectoryW(accessToken, wstr, &psize))
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
/* !!! FIXME: unicode version. */
|
|
||||||
rc = GetUserProfileDirectory(accessToken, dummy, &psize);
|
|
||||||
assert(!rc); /* success?! */
|
|
||||||
|
|
||||||
/* Allocate memory for the profile directory */
|
|
||||||
userDir = (char *) allocator.Malloc(psize);
|
|
||||||
if (userDir != NULL)
|
|
||||||
{
|
{
|
||||||
/* !!! FIXME: unicode version. */
|
const PHYSFS_uint64 buflen = psize * 6;
|
||||||
if (GetUserProfileDirectory(accessToken, userDir, &psize))
|
userDir = (char *) allocator.Malloc(buflen);
|
||||||
{
|
if (userDir != NULL)
|
||||||
/* !!! FIXME: convert to UTF-8. */
|
PHYSFS_utf8FromUcs2((const PHYSFS_uint16 *) wstr, userDir, buflen);
|
||||||
} /* if */
|
/* !!! FIXME: shrink allocation... */
|
||||||
else
|
} /* if */
|
||||||
{
|
__PHYSFS_smallFree(wstr);
|
||||||
allocator.Free(userDir);
|
} /* else */
|
||||||
userDir = NULL;
|
|
||||||
} /* else */
|
|
||||||
} /* else */
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
CloseHandle(accessToken);
|
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
FreeLibrary(lib);
|
CloseHandle(accessToken);
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
if (userDir == NULL) /* couldn't get profile for some reason. */
|
if (userDir == NULL) /* couldn't get profile for some reason. */
|
||||||
|
@ -251,7 +307,6 @@ static int determineUserDir(void)
|
||||||
/* Might just be a non-NT system; resort to the basedir. */
|
/* Might just be a non-NT system; resort to the basedir. */
|
||||||
userDir = getExePath(NULL);
|
userDir = getExePath(NULL);
|
||||||
BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */
|
BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */
|
||||||
/* !!! FIXME: convert to UTF-8. */
|
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
return(1); /* We made it: hit the showers. */
|
return(1); /* We made it: hit the showers. */
|
||||||
|
@ -445,6 +500,8 @@ void __PHYSFS_platformEnumerateFiles(const char *dirname,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
callback(callbackdata, origdir, ent.cFileName);
|
callback(callbackdata, origdir, ent.cFileName);
|
||||||
|
|
||||||
|
/* !!! FIXME: unicode version. */
|
||||||
} while (FindNextFile(dir, &ent) != 0);
|
} while (FindNextFile(dir, &ent) != 0);
|
||||||
|
|
||||||
FindClose(dir);
|
FindClose(dir);
|
||||||
|
@ -622,71 +679,30 @@ static int getOSInfo(void)
|
||||||
} /* getOSInfo */
|
} /* getOSInfo */
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
/* If this get unwieldy, make it table driven. */
|
|
||||||
|
|
||||||
int allNeededLibrariesLoaded = 1; /* flip to zero as needed. */
|
|
||||||
|
|
||||||
libKernel32 = LoadLibrary("kernel32.dll");
|
|
||||||
if (libKernel32)
|
|
||||||
{
|
|
||||||
pGetFileAttributesEx = (LPFNGETFILEATTRIBUTESEX)
|
|
||||||
GetProcAddress(libKernel32, "GetFileAttributesExA");
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
/* add other DLLs here... */
|
|
||||||
|
|
||||||
|
|
||||||
/* see if there's any reason to keep kernel32.dll around... */
|
|
||||||
if (libKernel32)
|
|
||||||
{
|
|
||||||
if ((pGetFileAttributesEx == NULL) /* && (somethingElse == NULL) */ )
|
|
||||||
{
|
|
||||||
FreeLibrary(libKernel32);
|
|
||||||
libKernel32 = NULL;
|
|
||||||
} /* if */
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
return(allNeededLibrariesLoaded);
|
|
||||||
} /* loadLibraries */
|
|
||||||
|
|
||||||
|
|
||||||
int __PHYSFS_platformInit(void)
|
int __PHYSFS_platformInit(void)
|
||||||
{
|
{
|
||||||
|
BAIL_IF_MACRO(!findApiSymbols(), NULL, 0);
|
||||||
BAIL_IF_MACRO(!getOSInfo(), NULL, 0);
|
BAIL_IF_MACRO(!getOSInfo(), NULL, 0);
|
||||||
BAIL_IF_MACRO(!loadLibraries(), NULL, 0);
|
|
||||||
BAIL_IF_MACRO(!determineUserDir(), NULL, 0);
|
BAIL_IF_MACRO(!determineUserDir(), NULL, 0);
|
||||||
|
|
||||||
return(1); /* It's all good */
|
return(1); /* It's all good */
|
||||||
} /* __PHYSFS_platformInit */
|
} /* __PHYSFS_platformInit */
|
||||||
|
|
||||||
|
|
||||||
int __PHYSFS_platformDeinit(void)
|
int __PHYSFS_platformDeinit(void)
|
||||||
{
|
{
|
||||||
if (userDir != NULL)
|
HANDLE *libs[] = { &libKernel32, &libUserEnv, &libAdvApi32, NULL };
|
||||||
{
|
int i;
|
||||||
allocator.Free(userDir);
|
|
||||||
userDir = NULL;
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
if (libKernel32)
|
allocator.Free(userDir);
|
||||||
|
userDir = NULL;
|
||||||
|
|
||||||
|
for (i = 0; libs[i] != NULL; i++)
|
||||||
{
|
{
|
||||||
FreeLibrary(libKernel32);
|
const HANDLE lib = *(libs[i]);
|
||||||
libKernel32 = NULL;
|
if (lib)
|
||||||
} /* if */
|
FreeLibrary(lib);
|
||||||
|
*(libs[i]) = NULL;
|
||||||
|
} /* for */
|
||||||
|
|
||||||
return(1); /* It's all good */
|
return(1); /* It's all good */
|
||||||
} /* __PHYSFS_platformDeinit */
|
} /* __PHYSFS_platformDeinit */
|
||||||
|
@ -1054,10 +1070,10 @@ PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
|
||||||
memset(&attrData, '\0', sizeof (attrData));
|
memset(&attrData, '\0', sizeof (attrData));
|
||||||
|
|
||||||
/* GetFileAttributesEx didn't show up until Win98 and NT4. */
|
/* GetFileAttributesEx didn't show up until Win98 and NT4. */
|
||||||
if (pGetFileAttributesEx != NULL)
|
if (pGetFileAttributesExA != NULL)
|
||||||
{
|
{
|
||||||
/* !!! FIXME: unicode version. */
|
/* !!! FIXME: unicode version. */
|
||||||
if (pGetFileAttributesEx(fname, GetFileExInfoStandard, &attrData))
|
if (pGetFileAttributesExA(fname, GetFileExInfoStandard, &attrData))
|
||||||
{
|
{
|
||||||
/* 0 return value indicates an error or not supported */
|
/* 0 return value indicates an error or not supported */
|
||||||
if ( (attrData.ftLastWriteTime.dwHighDateTime != 0) ||
|
if ( (attrData.ftLastWriteTime.dwHighDateTime != 0) ||
|
||||||
|
|
Loading…
Reference in New Issue