physfs/platform/win32.c

582 lines
15 KiB
C
Raw Normal View History

2001-08-23 17:22:52 +02:00
/*
2001-08-23 18:02:51 +02:00
* Win32 support routines for PhysicsFS.
2001-08-23 17:22:52 +02:00
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#if (defined __STRICT_ANSI__)
#define __PHYSFS_DOING_STRICT_ANSI__
#endif
#include <windows.h>
#include <userenv.h>
2001-08-23 17:22:52 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
2001-08-23 17:22:52 +02:00
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = "\\";
static HANDLE ProcessHandle = NULL; /* Current process handle */
static HANDLE AccessTokenHandle = NULL; /* Security handle to process */
static DWORD ProcessID; /* ID assigned to current process */
static int runningNT; /* TRUE if NT derived OS */
static OSVERSIONINFO OSVersionInfo; /* Information about the OS */
/* NT specific information */
static char *ProfileDirectory = NULL; /* User profile folder */
2001-08-23 17:22:52 +02:00
static const char *win32strerror(void)
{
2001-08-23 18:02:51 +02:00
static TCHAR msgbuf[255];
2001-08-23 17:22:52 +02:00
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
2001-08-23 18:02:51 +02:00
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
msgbuf,
sizeof (msgbuf) / sizeof (TCHAR),
2001-08-23 17:22:52 +02:00
NULL
);
2001-08-23 18:02:51 +02:00
return((const char *) msgbuf);
2001-08-23 17:22:52 +02:00
} /* win32strerror */
char **__PHYSFS_platformDetectAvailableCDs(void)
{
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1; /* We count the NULL entry. */
char drive_str[4] = "x:\\";
for (drive_str[0] = 'A'; drive_str[0] <= 'Z'; drive_str[0]++)
{
if (GetDriveType(drive_str) == DRIVE_CDROM)
{
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])
{
strcpy(retval[cd_count-1], drive_str);
cd_count++;
} /* if */
} /* if */
} /* if */
} /* for */
retval[cd_count - 1] = NULL;
return(retval);
} /* __PHYSFS_detectAvailableCDs */
2002-03-21 04:22:04 +01:00
static char *getExePath(const char *argv0)
2001-08-23 17:22:52 +02:00
{
char *filepart = NULL;
2001-10-09 17:41:33 +02:00
char *retval = (char *) malloc(sizeof (TCHAR) * (MAX_PATH + 1));
2002-03-21 04:22:04 +01:00
DWORD buflen = GetModuleFileName(NULL, retval, MAX_PATH + 1);
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. */
retval = (char *) realloc(retval, strlen(retval) + 1);
if (retval != NULL)
return(retval);
} /* if */
} /* if */
/* if any part of the previous approach failed, try SearchPath()... */
2001-08-23 18:02:51 +02:00
buflen = SearchPath(NULL, argv0, NULL, buflen, NULL, NULL);
retval = (char *) realloc(retval, buflen);
2001-08-23 17:22:52 +02:00
BAIL_IF_MACRO(!retval, ERR_OUT_OF_MEMORY, NULL);
2001-08-23 18:02:51 +02:00
SearchPath(NULL, argv0, NULL, buflen, retval, &filepart);
2001-08-23 17:22:52 +02:00
return(retval);
2001-10-09 17:41:33 +02:00
} /* getExePath */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
if (strchr(argv0, '\\') != NULL) /* default behaviour can handle this. */
return(NULL);
2002-03-21 04:22:04 +01:00
return(getExePath(argv0));
2001-08-23 17:22:52 +02:00
} /* __PHYSFS_platformCalcBaseDir */
char *__PHYSFS_platformGetUserName(void)
{
2001-08-23 18:02:51 +02:00
DWORD bufsize = 0;
2001-08-23 17:22:52 +02:00
LPTSTR retval = NULL;
if (GetUserName(NULL, &bufsize) == 0) /* This SHOULD fail. */
{
retval = (LPTSTR) malloc(bufsize);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (GetUserName(retval, &bufsize) == 0) /* ?! */
{
free(retval);
retval = NULL;
} /* if */
} /* if */
return((char *) retval);
} /* __PHYSFS_platformGetUserName */
static char *copyEnvironmentVariable(const char *varname)
{
const char *envr = getenv(varname);
char *retval = NULL;
if (envr != NULL)
{
retval = malloc(strlen(envr) + 1);
if (retval != NULL)
strcpy(retval, envr);
} /* if */
return(retval);
} /* copyEnvironmentVariable */
2001-08-23 17:22:52 +02:00
char *__PHYSFS_platformGetUserDir(void)
{
char *userdir = NULL;
/*!!!TODO - Need to get the userdir for non-NT based OSes */
if(runningNT)
{
userdir = ProfileDirectory;
}
return userdir;
2001-08-23 17:22:52 +02:00
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformGetThreadID(void)
{
return((int) GetCurrentThreadId());
} /* __PHYSFS_platformGetThreadID */
2001-08-23 18:02:51 +02:00
/* ...make this Cygwin AND Visual C friendly... */
2001-08-23 17:22:52 +02:00
int __PHYSFS_platformStricmp(const char *x, const char *y)
{
2001-08-23 18:02:51 +02:00
int ux, uy;
do
{
ux = toupper((int) *x);
uy = toupper((int) *y);
if (ux > uy)
return(1);
else if (ux < uy)
return(-1);
x++;
y++;
} while ((ux) && (uy));
return(0);
2001-08-23 17:22:52 +02:00
} /* __PHYSFS_platformStricmp */
int __PHYSFS_platformExists(const char *fname)
{
return(GetFileAttributes(fname) != 0xffffffff);
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
return(0); /* no symlinks on win32. */
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
return((GetFileAttributes(fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
} /* __PHYSFS_platformIsDirectory */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
char *retval = malloc(len);
2001-08-23 18:02:51 +02:00
char *p;
2001-08-23 17:22:52 +02:00
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
if (prepend)
strcpy(retval, prepend);
else
retval[0] = '\0';
strcat(retval, dirName);
if (append)
strcat(retval, append);
for (p = strchr(retval, '/'); p != NULL; p = strchr(p + 1, '/'))
*p = '\\';
return(retval);
} /* __PHYSFS_platformCvtToDependent */
/* Much like my college days, try to sleep for 10 milliseconds at a time... */
void __PHYSFS_platformTimeslice(void)
{
Sleep(10);
} /* __PHYSFS_platformTimeslice */
LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks)
{
LinkedStringList *retval = NULL;
LinkedStringList *l = NULL;
LinkedStringList *prev = NULL;
HANDLE dir;
WIN32_FIND_DATA ent;
dir = FindFirstFile(dirname, &ent);
BAIL_IF_MACRO(dir == INVALID_HANDLE_VALUE, win32strerror(), NULL);
2002-03-05 20:28:02 +01:00
while (FindNextFile(dir, &ent) != 0)
2001-08-23 17:22:52 +02:00
{
if (strcmp(ent.cFileName, ".") == 0)
continue;
if (strcmp(ent.cFileName, "..") == 0)
continue;
l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
if (l == NULL)
break;
l->str = (char *) malloc(strlen(ent.cFileName) + 1);
if (l->str == NULL)
{
free(l);
break;
} /* if */
strcpy(l->str, ent.cFileName);
if (retval == NULL)
retval = l;
else
prev->next = l;
prev = l;
l->next = NULL;
} /* while */
FindClose(dir);
return(retval);
} /* __PHYSFS_platformEnumerateFiles */
int __PHYSFS_platformFileLength(FILE *handle)
{
fpos_t curpos;
int retval;
fgetpos(handle, &curpos);
fseek(handle, 0, SEEK_END);
retval = ftell(handle);
fsetpos(handle, &curpos);
return(retval);
} /* __PHYSFS_platformFileLength */
char *__PHYSFS_platformCurrentDir(void)
{
2001-08-23 18:02:51 +02:00
LPTSTR retval;
2001-08-23 17:22:52 +02:00
DWORD buflen = 0;
2001-08-23 18:02:51 +02:00
buflen = GetCurrentDirectory(buflen, NULL);
retval = (LPTSTR) malloc(sizeof (TCHAR) * (buflen + 2));
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
2001-08-23 18:02:51 +02:00
GetCurrentDirectory(buflen, retval);
if (retval[buflen - 2] != '\\')
strcat(retval, "\\");
2001-08-23 17:22:52 +02:00
return((char *) retval);
} /* __PHYSFS_platformCurrentDir */
/* this could probably use a cleanup. */
2001-08-23 17:22:52 +02:00
char *__PHYSFS_platformRealPath(const char *path)
{
char *retval = NULL;
char *p = NULL;
BAIL_IF_MACRO(path == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(*path == '\0', ERR_INVALID_ARGUMENT, NULL);
retval = (char *) malloc(MAX_PATH);
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
/*
* If in \\server\path format, it's already an absolute path.
* We'll need to check for "." and ".." dirs, though, just in case.
*/
if ((path[0] == '\\') && (path[1] == '\\'))
strcpy(retval, path);
else
{
char *currentDir = __PHYSFS_platformCurrentDir();
if (currentDir == NULL)
{
free(retval);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
if (path[1] == ':') /* drive letter specified? */
{
/*
* Apparently, "D:mypath" is the same as "D:\\mypath" if
* D: is not the current drive. However, if D: is the
* current drive, then "D:mypath" is a relative path. Ugh.
*/
if (path[2] == '\\') /* maybe an absolute path? */
strcpy(retval, path);
else /* definitely an absolute path. */
{
if (path[0] == currentDir[0]) /* current drive; relative. */
{
strcpy(retval, currentDir);
strcat(retval, path + 2);
} /* if */
else /* not current drive; absolute. */
{
retval[0] = path[0];
retval[1] = ':';
retval[2] = '\\';
strcpy(retval + 3, path + 2);
} /* else */
} /* else */
} /* if */
else /* no drive letter specified. */
{
if (path[0] == '\\') /* absolute path. */
{
retval[0] = currentDir[0];
retval[1] = ':';
strcpy(retval + 2, path);
} /* if */
else
{
strcpy(retval, currentDir);
strcat(retval, path);
} /* else */
} /* else */
free(currentDir);
} /* else */
/* (whew.) Ok, now take out "." and ".." path entries... */
p = retval;
while ( (p = strstr(p, "\\.")) != NULL)
{
/* it's a "." entry that doesn't end the string. */
if (p[2] == '\\')
memmove(p + 1, p + 3, strlen(p + 3) + 1);
/* it's a "." entry that ends the string. */
else if (p[2] == '\0')
p[0] = '\0';
/* it's a ".." entry. */
else if (p[2] == '.')
{
char *prevEntry = p - 1;
while ((prevEntry != retval) && (*prevEntry != '\\'))
prevEntry--;
if (prevEntry == retval) /* make it look like a "." entry. */
memmove(p + 1, p + 2, strlen(p + 2) + 1);
else
{
if (p[3] != '\0') /* doesn't end string. */
*prevEntry = '\0';
else /* ends string. */
memmove(prevEntry + 1, p + 4, strlen(p + 4) + 1);
p = prevEntry;
} /* else */
} /* else if */
else
{
p++; /* look past current char. */
} /* else */
} /* while */
/* shrink the retval's memory block if possible... */
p = (char *) realloc(retval, strlen(retval) + 1);
if (p != NULL)
retval = p;
return(retval);
2001-08-23 17:22:52 +02:00
} /* __PHYSFS_platformRealPath */
int __PHYSFS_platformMkDir(const char *path)
{
2001-08-23 18:02:51 +02:00
DWORD rc = CreateDirectory(path, NULL);
2001-08-23 17:22:52 +02:00
BAIL_IF_MACRO(rc == 0, win32strerror(), 0);
return(1);
} /* __PHYSFS_platformMkDir */
/*
* Initialize any NT specific stuff. This includes any OS based on NT.
*
* Return zero if there was a catastrophic failure and non-zero otherwise.
*/
static int doNTInit()
{
DWORD pathsize = 0;
char TempProfileDirectory[1];
/* Create a process access token handle */
if(!OpenProcessToken(ProcessHandle, TOKEN_QUERY, &AccessTokenHandle))
{
/* Access token is required by other win32 functions */
return 0;
}
/* Should fail. Will write the size of the profile path in pathsize*/
/*!!! Second parameter can't be NULL or the function fails??? */
if(!GetUserProfileDirectory(AccessTokenHandle, TempProfileDirectory, &pathsize))
{
const char *temp;
temp = win32strerror();
/* Allocate memory for the profile directory */
ProfileDirectory = (char *)malloc(pathsize);
BAIL_IF_MACRO(ProfileDirectory == NULL, ERR_OUT_OF_MEMORY, 0);
/* Try to get the profile directory */
if(!GetUserProfileDirectory(AccessTokenHandle, ProfileDirectory, &pathsize))
{
free(ProfileDirectory);
return 0;
}
}
/* Everything initialized okay */
return 1;
}
/*
* Get OS info and save it.
*
* Returns non-zero if successful, otherwise it returns zero on failure.
*/
int getOSInfo(void)
{
/* Get OS info */
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVersionInfo);
if(!GetVersionEx(&OSVersionInfo))
{
return 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);
return 1;
}
int __PHYSFS_platformInit(void)
{
if(!getOSInfo())
{
return 0;
}
/* Get Windows ProcessID associated with the current process */
ProcessID = GetCurrentProcessId();
/* Create a process handle associated with the current process ID */
ProcessHandle = GetCurrentProcess();
if(ProcessHandle == NULL)
{
/* Process handle is required by other win32 functions */
return 0;
}
/* If running an NT system (NT/Win2k/XP, etc...) */
if(runningNT)
{
if(!doNTInit())
{
/* Error initializing NT stuff */
return 0;
}
}
/* It's all good */
return 1;
}
/*
* Uninitialize any NT specific stuff done in doNTInit().
*
* Return zero if there was a catastrophic failure and non-zero otherwise.
*/
static int doNTDeinit()
{
if(CloseHandle(AccessTokenHandle) != S_OK)
{
return 0;
}
free(ProfileDirectory);
/* It's all good */
return 1;
}
int __PHYSFS_platformDeinit(void)
{
if(!doNTDeinit())
return 0;
if(CloseHandle(ProcessHandle) != S_OK)
return 0;
/* It's all good */
return 1;
}
2001-08-23 17:22:52 +02:00
/* end of win32.c ... */