2009-05-24 10:11:17 +00:00
# include "quakedef.h"
# include "fs.h"
2013-11-21 23:02:28 +00:00
# include "winquake.h"
2009-05-24 10:11:17 +00:00
2015-05-16 08:02:05 +00:00
//FIXME: find somewhere better for this win32 utility code.
//(its here instead of sys_win.c because dedicated servers don't use sys_win.c)
2013-12-07 00:30:48 +00:00
//outlen is the size of out in _BYTES_.
2015-04-14 23:12:17 +00:00
wchar_t * widen ( wchar_t * out , size_t outbytes , const char * utf8 )
2013-11-21 23:16:59 +00:00
{
2015-04-14 23:12:17 +00:00
size_t outlen ;
2013-11-21 23:16:59 +00:00
wchar_t * ret = out ;
//utf-8 to utf-16, not ucs-2.
unsigned int codepoint ;
int error ;
2015-04-14 23:12:17 +00:00
outlen = outbytes / sizeof ( wchar_t ) ;
2013-11-21 23:16:59 +00:00
if ( ! outlen )
return L " " ;
outlen - - ;
while ( * utf8 )
{
codepoint = utf8_decode ( & error , utf8 , ( void * ) & utf8 ) ;
2013-11-29 14:36:47 +00:00
if ( error | | codepoint > 0x10FFFFu )
2013-11-21 23:16:59 +00:00
codepoint = 0xFFFDu ;
if ( codepoint > 0xffff )
{
if ( outlen < 2 )
break ;
outlen - = 2 ;
codepoint - = 0x10000u ;
* out + + = 0xD800 | ( codepoint > > 10 ) ;
* out + + = 0xDC00 | ( codepoint & 0x3ff ) ;
}
else
{
if ( outlen < 1 )
break ;
outlen - = 1 ;
* out + + = codepoint ;
}
}
* out = 0 ;
return ret ;
}
char * narrowen ( char * out , size_t outlen , wchar_t * wide )
{
char * ret = out ;
int bytes ;
unsigned int codepoint ;
if ( ! outlen )
return " " ;
outlen - - ;
//utf-8 to utf-16, not ucs-2.
while ( * wide )
{
codepoint = * wide + + ;
if ( codepoint > = 0xD800u & & codepoint < = 0xDBFFu )
{ //handle utf-16 surrogates
if ( * wide > = 0xDC00u & & * wide < = 0xDFFFu )
{
codepoint = ( codepoint & 0x3ff ) < < 10 ;
codepoint | = * wide + + & 0x3ff ;
}
else
codepoint = 0xFFFDu ;
}
bytes = utf8_encode ( out , codepoint , outlen ) ;
if ( bytes < = 0 )
break ;
out + = bytes ;
outlen - = bytes ;
}
* out = 0 ;
return ret ;
}
2013-11-21 23:02:28 +00:00
2015-05-16 08:02:05 +00:00
int MyRegGetIntValue ( void * base , const char * keyname , const char * valuename , int defaultval )
{
int result = defaultval ;
DWORD datalen = sizeof ( result ) ;
HKEY subkey ;
DWORD type = REG_NONE ;
wchar_t wide [ MAX_PATH ] ;
if ( RegOpenKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , KEY_READ , & subkey ) = = ERROR_SUCCESS )
{
if ( ERROR_SUCCESS ! = RegQueryValueExW ( subkey , widen ( wide , sizeof ( wide ) , valuename ) , NULL , & type , ( void * ) & result , & datalen ) | | type ! = REG_DWORD )
result = defaultval ;
RegCloseKey ( subkey ) ;
}
return result ;
}
//result is utf-8
qboolean MyRegGetStringValue ( void * base , const char * keyname , const char * valuename , void * data , size_t datalen )
{
qboolean result = false ;
HKEY subkey ;
DWORD type = REG_NONE ;
wchar_t wide [ MAX_PATH ] ;
wchar_t wdata [ 2048 ] ;
DWORD dwlen = sizeof ( wdata ) - sizeof ( wdata [ 0 ] ) ;
if ( RegOpenKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , KEY_READ , & subkey ) = = ERROR_SUCCESS )
{
result = ERROR_SUCCESS = = RegQueryValueExW ( subkey , widen ( wide , sizeof ( wide ) , valuename ) , NULL , & type , ( BYTE * ) wdata , & dwlen ) ;
RegCloseKey ( subkey ) ;
}
if ( result & & ( type = = REG_SZ | | type = = REG_EXPAND_SZ ) )
{
wdata [ dwlen / sizeof ( wchar_t ) ] = 0 ;
narrowen ( data , datalen , wdata ) ;
}
else
( ( char * ) data ) [ 0 ] = 0 ;
return result ;
}
2015-05-16 08:14:14 +00:00
qboolean MyRegGetStringValueMultiSz ( void * base , const char * keyname , const char * valuename , void * data , int datalen )
2015-05-16 08:02:05 +00:00
{
qboolean result = false ;
HKEY subkey ;
wchar_t wide [ MAX_PATH ] ;
DWORD type = REG_NONE ;
if ( RegOpenKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , KEY_READ , & subkey ) = = ERROR_SUCCESS )
{
DWORD dwlen = datalen ;
result = ERROR_SUCCESS = = RegQueryValueEx ( subkey , valuename , NULL , & type , data , & dwlen ) ;
datalen = dwlen ;
RegCloseKey ( subkey ) ;
}
if ( type = = REG_MULTI_SZ )
return result ;
return false ;
}
qboolean MyRegSetValue ( void * base , const char * keyname , const char * valuename , int type , const void * data , int datalen )
{
qboolean result = false ;
HKEY subkey ;
wchar_t wide [ MAX_PATH ] ;
wchar_t wided [ 2048 ] ;
if ( type = = REG_SZ )
{
data = widen ( wided , sizeof ( wided ) , data ) ;
datalen = wcslen ( wided ) * 2 ;
}
//'trivially' return success if its already set.
//this allows success even when we don't have write access.
if ( RegOpenKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , KEY_READ , & subkey ) = = ERROR_SUCCESS )
{
DWORD oldtype ;
char olddata [ 2048 ] ;
DWORD olddatalen = sizeof ( olddata ) ;
result = ERROR_SUCCESS = = RegQueryValueExW ( subkey , widen ( wide , sizeof ( wide ) , valuename ) , NULL , & oldtype , olddata , & olddatalen ) ;
RegCloseKey ( subkey ) ;
if ( oldtype = = REG_SZ | | oldtype = = REG_EXPAND_SZ )
{ //ignore any null terminators that may have come along for the ride
while ( olddatalen > 1 & & olddata [ olddatalen - 2 ] & & olddata [ olddatalen - 1 ] = = 0 )
olddatalen - = 2 ;
}
if ( result & & datalen = = olddatalen & & type = = oldtype & & ! memcmp ( data , olddata , datalen ) )
return result ;
result = false ;
}
if ( RegCreateKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , NULL , REG_OPTION_NON_VOLATILE , KEY_WRITE , NULL , & subkey , NULL ) = = ERROR_SUCCESS )
{
result = ERROR_SUCCESS = = RegSetValueExW ( subkey , widen ( wide , sizeof ( wide ) , valuename ) , 0 , type , data , datalen ) ;
RegCloseKey ( subkey ) ;
}
return result ;
}
2015-05-16 08:08:30 +00:00
void MyRegDeleteKeyValue ( void * base , const char * keyname , const char * valuename )
2015-05-16 08:02:05 +00:00
{
HKEY subkey ;
wchar_t wide [ MAX_PATH ] ;
if ( RegOpenKeyExW ( base , widen ( wide , sizeof ( wide ) , keyname ) , 0 , KEY_WRITE , & subkey ) = = ERROR_SUCCESS )
{
RegDeleteValueW ( subkey , widen ( wide , sizeof ( wide ) , valuename ) ) ;
RegCloseKey ( subkey ) ;
}
}
2013-11-21 23:02:28 +00:00
2014-03-30 08:55:06 +00:00
# ifndef WINRT //winrt is too annoying. lets just use stdio.
# ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ~0
# endif
//read-only memory mapped files.
//for write access, we use the stdio module as a fallback.
//do you think anyone will ever notice that utf8 filenames work even in windows? probably not. oh well, worth a try.
# define VFSW32_Open VFSOS_Open
# define VFSW32_OpenPath VFSOS_OpenPath
typedef struct {
searchpathfuncs_t pub ;
HANDLE changenotification ;
void ( QDECL * AddFileHash ) ( int depth , const char * fname , fsbucket_t * filehandle , void * pathhandle ) ;
int hashdepth ;
char rootpath [ 1 ] ;
} vfsw32path_t ;
typedef struct {
vfsfile_t funcs ;
HANDLE hand ;
HANDLE mmh ;
void * mmap ;
unsigned int length ;
unsigned int offset ;
} vfsw32file_t ;
2013-05-03 04:28:08 +00:00
static int QDECL VFSW32_ReadBytes ( struct vfsfile_s * file , void * buffer , int bytestoread )
2009-05-24 10:11:17 +00:00
{
DWORD read ;
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
{
if ( intfile - > offset + bytestoread > intfile - > length )
bytestoread = intfile - > length - intfile - > offset ;
memcpy ( buffer , ( char * ) intfile - > mmap + intfile - > offset , bytestoread ) ;
intfile - > offset + = bytestoread ;
return bytestoread ;
}
if ( ! ReadFile ( intfile - > hand , buffer , bytestoread , & read , NULL ) )
return 0 ;
return read ;
}
2013-05-03 04:28:08 +00:00
static int QDECL VFSW32_WriteBytes ( struct vfsfile_s * file , const void * buffer , int bytestoread )
2009-05-24 10:11:17 +00:00
{
DWORD written ;
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
{
if ( intfile - > offset + bytestoread > intfile - > length )
bytestoread = intfile - > length - intfile - > offset ;
memcpy ( ( char * ) intfile - > mmap + intfile - > offset , buffer , bytestoread ) ;
intfile - > offset + = bytestoread ;
return bytestoread ;
}
if ( ! WriteFile ( intfile - > hand , buffer , bytestoread , & written , NULL ) )
return 0 ;
return written ;
}
2014-02-07 08:38:40 +00:00
static qboolean QDECL VFSW32_Seek ( struct vfsfile_s * file , qofs_t pos )
2009-05-24 10:11:17 +00:00
{
2014-02-07 08:38:40 +00:00
DWORD hi , lo ;
2009-05-24 10:11:17 +00:00
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
{
intfile - > offset = pos ;
return true ;
}
2014-02-07 08:38:40 +00:00
lo = qofs_Low ( pos ) ;
hi = qofs_High ( pos ) ;
return SetFilePointer ( intfile - > hand , lo , & hi , FILE_BEGIN ) ! = INVALID_SET_FILE_POINTER ;
2009-05-24 10:11:17 +00:00
}
2014-02-07 08:38:40 +00:00
static qofs_t QDECL VFSW32_Tell ( struct vfsfile_s * file )
2009-05-24 10:11:17 +00:00
{
2014-02-07 08:38:40 +00:00
DWORD hi = 0 , lo ;
2009-05-24 10:11:17 +00:00
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
return intfile - > offset ;
2014-02-07 08:38:40 +00:00
lo = SetFilePointer ( intfile - > hand , 0 , & hi , FILE_CURRENT ) ;
return qofs_Make ( lo , hi ) ;
2009-05-24 10:11:17 +00:00
}
2013-05-03 04:28:08 +00:00
static void QDECL VFSW32_Flush ( struct vfsfile_s * file )
2009-05-24 10:11:17 +00:00
{
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
FlushViewOfFile ( intfile - > mmap , intfile - > length ) ;
FlushFileBuffers ( intfile - > hand ) ;
}
2014-02-07 08:38:40 +00:00
static qofs_t QDECL VFSW32_GetSize ( struct vfsfile_s * file )
2009-05-24 10:11:17 +00:00
{
2014-02-07 08:38:40 +00:00
DWORD lo , hi = 0 ;
2009-05-24 10:11:17 +00:00
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
return intfile - > length ;
2014-02-07 08:38:40 +00:00
lo = GetFileSize ( intfile - > hand , & hi ) ;
return qofs_Make ( lo , hi ) ;
2009-05-24 10:11:17 +00:00
}
2014-03-30 08:55:06 +00:00
static qboolean QDECL VFSW32_Close ( vfsfile_t * file )
2009-05-24 10:11:17 +00:00
{
vfsw32file_t * intfile = ( vfsw32file_t * ) file ;
if ( intfile - > mmap )
{
UnmapViewOfFile ( intfile - > mmap ) ;
CloseHandle ( intfile - > mmh ) ;
}
CloseHandle ( intfile - > hand ) ;
Z_Free ( file ) ;
2014-03-30 08:55:06 +00:00
return true ;
2009-05-24 10:11:17 +00:00
}
2014-02-07 08:38:40 +00:00
//WARNING: handle can be null
static vfsfile_t * QDECL VFSW32_OpenInternal ( vfsw32path_t * handle , const char * quakename , const char * osname , const char * mode )
2009-05-24 10:11:17 +00:00
{
HANDLE h , mh ;
unsigned int fsize ;
void * mmap ;
2014-02-07 08:38:40 +00:00
qboolean didexist = true ;
2009-05-24 10:11:17 +00:00
vfsw32file_t * file ;
qboolean read = ! ! strchr ( mode , ' r ' ) ;
qboolean write = ! ! strchr ( mode , ' w ' ) ;
qboolean append = ! ! strchr ( mode , ' a ' ) ;
qboolean text = ! ! strchr ( mode , ' t ' ) ;
write | = append ;
2010-07-11 02:22:39 +00:00
if ( strchr ( mode , ' + ' ) )
read = write = true ;
2009-05-24 10:11:17 +00:00
2014-03-30 08:55:06 +00:00
if ( fs_readonly & & ( write | | append ) )
return NULL ;
2013-11-21 23:02:28 +00:00
if ( ! WinNT )
{
2015-06-04 06:15:14 +00:00
//FILE_SHARE_DELETE is not supported in 9x, sorry.
2013-11-21 23:02:28 +00:00
if ( ( write & & read ) | | append )
2015-06-04 06:15:14 +00:00
h = CreateFileA ( osname , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-11-21 23:02:28 +00:00
else if ( write )
h = CreateFileA ( osname , GENERIC_READ | GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
else if ( read )
2015-06-04 06:15:14 +00:00
h = CreateFileA ( osname , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-11-21 23:02:28 +00:00
else
h = INVALID_HANDLE_VALUE ;
}
2009-05-24 10:28:26 +00:00
else
2013-11-21 23:02:28 +00:00
{
wchar_t wide [ MAX_OSPATH ] ;
widen ( wide , sizeof ( wide ) , osname ) ;
2014-02-07 08:38:40 +00:00
h = INVALID_HANDLE_VALUE ;
if ( write | | append )
{
2014-03-30 08:55:06 +00:00
//this extra block is to avoid flushing fs caches needlessly
2014-04-06 15:16:39 +00:00
h = CreateFileW ( wide , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_DELETE , NULL , ( ! read & & ! append ) ? CREATE_ALWAYS : OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2014-02-07 08:38:40 +00:00
if ( h = = INVALID_HANDLE_VALUE )
didexist = false ;
}
if ( h ! = INVALID_HANDLE_VALUE )
;
else if ( ( write & & read ) | | append )
h = CreateFileW ( wide , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_DELETE , NULL , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-11-21 23:02:28 +00:00
else if ( write )
2014-02-07 08:38:40 +00:00
h = CreateFileW ( wide , GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_DELETE , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-11-21 23:02:28 +00:00
else if ( read )
2014-02-07 08:38:40 +00:00
h = CreateFileW ( wide , GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_DELETE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2013-11-21 23:02:28 +00:00
else
h = INVALID_HANDLE_VALUE ;
}
2009-05-24 10:11:17 +00:00
if ( h = = INVALID_HANDLE_VALUE )
2014-03-30 08:55:06 +00:00
{
DWORD e = GetLastError ( ) ;
2009-05-24 10:11:17 +00:00
return NULL ;
2014-03-30 08:55:06 +00:00
}
2009-05-24 10:11:17 +00:00
2014-02-07 08:38:40 +00:00
if ( ! didexist )
{
if ( handle & & handle - > AddFileHash )
handle - > AddFileHash ( handle - > hashdepth , quakename , NULL , handle ) ;
else
COM_RefreshFSCache_f ( ) ; //no idea where this path is. if its inside a quake path, make sure it gets flushed properly. FIXME: his shouldn't be needed if we have change notifications working properly.
}
2013-10-29 17:38:22 +00:00
fsize = GetFileSize ( h , NULL ) ;
if ( write | | append | | text | | fsize > 1024 * 1024 * 5 )
2009-05-24 10:11:17 +00:00
{
fsize = 0 ;
mh = INVALID_HANDLE_VALUE ;
mmap = NULL ;
2011-07-14 13:05:36 +00:00
/*if appending, set the access position to the end of the file*/
if ( append )
2011-07-28 01:42:10 +00:00
SetFilePointer ( h , 0 , NULL , FILE_END ) ;
2009-05-24 10:11:17 +00:00
}
else
{
mh = CreateFileMapping ( h , NULL , PAGE_READONLY , 0 , 0 , NULL ) ;
if ( mh = = INVALID_HANDLE_VALUE )
mmap = NULL ;
else
{
mmap = MapViewOfFile ( mh , FILE_MAP_READ , 0 , 0 , fsize ) ;
if ( mmap = = NULL )
{
CloseHandle ( mh ) ;
mh = INVALID_HANDLE_VALUE ;
}
}
}
file = Z_Malloc ( sizeof ( vfsw32file_t ) ) ;
2012-07-05 19:42:36 +00:00
# ifdef _DEBUG
Q_strncpyz ( file - > funcs . dbgname , osname , sizeof ( file - > funcs . dbgname ) ) ;
# endif
2009-05-24 10:11:17 +00:00
file - > funcs . ReadBytes = read ? VFSW32_ReadBytes : NULL ;
file - > funcs . WriteBytes = ( write | | append ) ? VFSW32_WriteBytes : NULL ;
file - > funcs . Seek = VFSW32_Seek ;
file - > funcs . Tell = VFSW32_Tell ;
file - > funcs . GetLen = VFSW32_GetSize ;
file - > funcs . Close = VFSW32_Close ;
file - > funcs . Flush = VFSW32_Flush ;
file - > hand = h ;
file - > mmh = mh ;
file - > mmap = mmap ;
file - > offset = 0 ;
file - > length = fsize ;
2015-04-14 23:12:17 +00:00
return & file - > funcs ;
2009-05-24 10:11:17 +00:00
}
2014-02-07 08:38:40 +00:00
vfsfile_t * QDECL VFSW32_Open ( const char * osname , const char * mode )
{
//called without regard to a search path
return VFSW32_OpenInternal ( NULL , NULL , osname , mode ) ;
}
2013-06-24 09:04:00 +00:00
static vfsfile_t * QDECL VFSW32_OpenVFS ( searchpathfuncs_t * handle , flocation_t * loc , const char * mode )
2009-05-24 10:11:17 +00:00
{
//path is already cleaned, as anything that gets a valid loc needs cleaning up first.
2014-02-07 08:38:40 +00:00
vfsw32path_t * wp = ( void * ) handle ;
return VFSW32_OpenInternal ( wp , loc - > rawname + strlen ( wp - > rootpath ) + 1 , loc - > rawname , mode ) ;
2009-05-24 10:11:17 +00:00
}
2013-06-24 09:04:00 +00:00
static void QDECL VFSW32_ClosePath ( searchpathfuncs_t * handle )
2009-05-24 10:11:17 +00:00
{
2013-06-24 09:04:00 +00:00
vfsw32path_t * wp = ( void * ) handle ;
2012-05-09 15:30:53 +00:00
if ( wp - > changenotification ! = INVALID_HANDLE_VALUE )
FindCloseChangeNotification ( wp - > changenotification ) ;
Z_Free ( wp ) ;
}
2013-06-24 09:04:00 +00:00
static qboolean QDECL VFSW32_PollChanges ( searchpathfuncs_t * handle )
2012-05-09 15:30:53 +00:00
{
qboolean result = false ;
2013-06-24 09:04:00 +00:00
vfsw32path_t * wp = ( void * ) handle ;
2012-05-09 15:30:53 +00:00
if ( wp - > changenotification = = INVALID_HANDLE_VALUE )
return true ;
for ( ; ; )
{
switch ( WaitForSingleObject ( wp - > changenotification , 0 ) )
{
case WAIT_OBJECT_0 :
result = true ;
break ;
case WAIT_TIMEOUT :
return result ;
default :
FindCloseChangeNotification ( wp - > changenotification ) ;
wp - > changenotification = INVALID_HANDLE_VALUE ;
return true ;
}
FindNextChangeNotification ( wp - > changenotification ) ;
}
return result ;
2009-05-24 10:11:17 +00:00
}
2015-02-02 08:01:53 +00:00
static int QDECL VFSW32_RebuildFSHash ( const char * filename , qofs_t filesize , time_t mtime , void * handle , searchpathfuncs_t * spath )
2012-05-09 15:30:53 +00:00
{
2013-06-24 09:04:00 +00:00
vfsw32path_t * wp = ( void * ) spath ;
2009-05-24 10:11:17 +00:00
if ( filename [ strlen ( filename ) - 1 ] = = ' / ' )
{ //this is actually a directory
char childpath [ 256 ] ;
2011-07-22 15:11:35 +00:00
Q_snprintfz ( childpath , sizeof ( childpath ) , " %s* " , filename ) ;
2013-05-03 04:28:08 +00:00
Sys_EnumerateFiles ( wp - > rootpath , childpath , VFSW32_RebuildFSHash , handle , spath ) ;
2009-05-24 10:11:17 +00:00
return true ;
}
2014-02-07 08:38:40 +00:00
wp - > AddFileHash ( wp - > hashdepth , filename , NULL , wp ) ;
2009-05-24 10:11:17 +00:00
return true ;
}
2013-06-24 09:04:00 +00:00
static void QDECL VFSW32_BuildHash ( searchpathfuncs_t * handle , int hashdepth , void ( QDECL * AddFileHash ) ( int depth , const char * fname , fsbucket_t * filehandle , void * pathhandle ) )
2009-05-24 10:11:17 +00:00
{
2013-06-24 09:04:00 +00:00
vfsw32path_t * wp = ( void * ) handle ;
2014-02-07 08:38:40 +00:00
wp - > AddFileHash = AddFileHash ;
2012-05-09 15:30:53 +00:00
wp - > hashdepth = hashdepth ;
2013-05-03 04:28:08 +00:00
Sys_EnumerateFiles ( wp - > rootpath , " * " , VFSW32_RebuildFSHash , AddFileHash , handle ) ;
2009-05-24 10:11:17 +00:00
}
2014-03-30 08:55:06 +00:00
# include <errno.h>
2014-02-07 08:38:40 +00:00
static unsigned int QDECL VFSW32_FLocate ( searchpathfuncs_t * handle , flocation_t * loc , const char * filename , void * hashedresult )
2009-05-24 10:11:17 +00:00
{
2013-06-24 09:04:00 +00:00
vfsw32path_t * wp = ( void * ) handle ;
2009-05-24 10:11:17 +00:00
char netpath [ MAX_OSPATH ] ;
2013-11-21 23:02:28 +00:00
wchar_t wide [ MAX_OSPATH ] ;
2014-03-30 08:55:06 +00:00
qofs_t len ;
HANDLE h ;
DWORD attr ;
2009-05-24 10:11:17 +00:00
2012-05-09 15:30:53 +00:00
if ( hashedresult & & ( void * ) hashedresult ! = wp )
2014-01-13 02:42:25 +00:00
return FF_NOTFOUND ;
2009-05-24 10:11:17 +00:00
/*
if ( ! static_registered )
{ // if not a registered version, don't ever go beyond base
if ( strchr ( filename , ' / ' ) | | strchr ( filename , ' \\ ' ) )
continue ;
}
*/
// check a file in the directory tree
2012-05-09 15:30:53 +00:00
snprintf ( netpath , sizeof ( netpath ) - 1 , " %s/%s " , wp - > rootpath , filename ) ;
2009-05-24 10:11:17 +00:00
2013-11-21 23:02:28 +00:00
if ( ! WinNT )
2014-03-30 08:55:06 +00:00
{
WIN32_FIND_DATAA fda ;
h = FindFirstFileA ( netpath , & fda ) ;
attr = fda . dwFileAttributes ;
len = ( h = = INVALID_HANDLE_VALUE ) ? 0 : qofs_Make ( fda . nFileSizeLow , fda . nFileSizeHigh ) ;
}
2013-11-21 23:02:28 +00:00
else
2014-03-30 08:55:06 +00:00
{
WIN32_FIND_DATAW fdw ;
h = FindFirstFileW ( widen ( wide , sizeof ( wide ) , netpath ) , & fdw ) ;
attr = fdw . dwFileAttributes ;
len = ( h = = INVALID_HANDLE_VALUE ) ? 0 : qofs_Make ( fdw . nFileSizeLow , fdw . nFileSizeHigh ) ;
}
if ( h = = INVALID_HANDLE_VALUE )
{
// int e = GetLastError();
// if (e == ERROR_PATH_NOT_FOUND) //then look inside a zip
2014-01-13 02:42:25 +00:00
return FF_NOTFOUND ;
2014-03-30 08:55:06 +00:00
}
FindClose ( h ) ;
2009-05-24 10:11:17 +00:00
if ( loc )
{
loc - > len = len ;
loc - > offset = 0 ;
loc - > index = 0 ;
2014-03-30 08:55:06 +00:00
Q_strncpyz ( loc - > rawname , netpath , sizeof ( loc - > rawname ) ) ;
2009-05-24 10:11:17 +00:00
}
2014-03-30 08:55:06 +00:00
if ( attr & FILE_ATTRIBUTE_DIRECTORY )
return FF_DIRECTORY ; //not actually openable.
2014-01-13 02:42:25 +00:00
return FF_FOUND ;
2009-05-24 10:11:17 +00:00
}
2013-06-24 09:04:00 +00:00
static void QDECL VFSW32_ReadFile ( searchpathfuncs_t * handle , flocation_t * loc , char * buffer )
2009-05-24 10:11:17 +00:00
{
2012-05-09 15:30:53 +00:00
// vfsw32path_t *wp = handle;
2009-05-24 10:11:17 +00:00
FILE * f ;
2013-11-21 23:02:28 +00:00
wchar_t wide [ MAX_OSPATH ] ;
if ( ! WinNT )
f = fopen ( loc - > rawname , " rb " ) ;
else
f = _wfopen ( widen ( wide , sizeof ( wide ) , loc - > rawname ) , L " rb " ) ;
2009-05-24 10:11:17 +00:00
if ( ! f ) //err...
return ;
fseek ( f , loc - > offset , SEEK_SET ) ;
fread ( buffer , 1 , loc - > len , f ) ;
fclose ( f ) ;
}
2015-02-02 08:01:53 +00:00
static int QDECL VFSW32_EnumerateFiles ( searchpathfuncs_t * handle , const char * match , int ( QDECL * func ) ( const char * , qofs_t , time_t mtime , void * , searchpathfuncs_t * spath ) , void * parm )
2009-05-24 10:11:17 +00:00
{
2013-06-23 02:17:02 +00:00
vfsw32path_t * wp = ( vfsw32path_t * ) handle ;
2013-03-31 04:21:08 +00:00
return Sys_EnumerateFiles ( wp - > rootpath , match , func , parm , handle ) ;
2009-05-24 10:11:17 +00:00
}
2014-01-13 02:42:25 +00:00
static qboolean QDECL VFSW32_RenameFile ( searchpathfuncs_t * handle , const char * oldfname , const char * newfname )
2013-11-21 23:02:28 +00:00
{
vfsw32path_t * wp = ( vfsw32path_t * ) handle ;
char oldsyspath [ MAX_OSPATH ] ;
char newsyspath [ MAX_OSPATH ] ;
2014-03-30 08:55:06 +00:00
if ( fs_readonly )
return false ;
2013-11-21 23:02:28 +00:00
snprintf ( oldsyspath , sizeof ( oldsyspath ) - 1 , " %s/%s " , wp - > rootpath , oldfname ) ;
snprintf ( newsyspath , sizeof ( newsyspath ) - 1 , " %s/%s " , wp - > rootpath , newfname ) ;
return Sys_Rename ( oldsyspath , newsyspath ) ;
}
2014-01-13 02:42:25 +00:00
static qboolean QDECL VFSW32_RemoveFile ( searchpathfuncs_t * handle , const char * filename )
2013-11-21 23:02:28 +00:00
{
vfsw32path_t * wp = ( vfsw32path_t * ) handle ;
char syspath [ MAX_OSPATH ] ;
2014-03-30 08:55:06 +00:00
if ( fs_readonly )
return false ;
2013-11-21 23:02:28 +00:00
snprintf ( syspath , sizeof ( syspath ) - 1 , " %s/%s " , wp - > rootpath , filename ) ;
return Sys_remove ( syspath ) ;
}
2014-01-13 02:42:25 +00:00
static qboolean QDECL VFSW32_MkDir ( searchpathfuncs_t * handle , const char * filename )
2013-11-21 23:02:28 +00:00
{
vfsw32path_t * wp = ( vfsw32path_t * ) handle ;
char syspath [ MAX_OSPATH ] ;
2014-03-30 08:55:06 +00:00
if ( fs_readonly )
return false ;
2013-11-21 23:02:28 +00:00
snprintf ( syspath , sizeof ( syspath ) - 1 , " %s/%s " , wp - > rootpath , filename ) ;
Sys_mkdir ( syspath ) ;
return true ;
}
2012-05-09 15:30:53 +00:00
2013-06-23 02:17:02 +00:00
searchpathfuncs_t * QDECL VFSW32_OpenPath ( vfsfile_t * mustbenull , const char * desc )
{
vfsw32path_t * np ;
int dlen = strlen ( desc ) ;
if ( mustbenull )
return NULL ;
np = Z_Malloc ( sizeof ( * np ) + dlen ) ;
if ( np )
{
2013-11-21 23:02:28 +00:00
wchar_t wide [ MAX_OSPATH ] ;
2013-06-23 02:17:02 +00:00
memcpy ( np - > rootpath , desc , dlen + 1 ) ;
2013-11-21 23:02:28 +00:00
if ( ! WinNT )
np - > changenotification = FindFirstChangeNotificationA ( np - > rootpath , true , FILE_NOTIFY_CHANGE_FILE_NAME ) ;
else
np - > changenotification = FindFirstChangeNotificationW ( widen ( wide , sizeof ( wide ) , np - > rootpath ) , true , FILE_NOTIFY_CHANGE_FILE_NAME ) ;
2013-06-23 02:17:02 +00:00
}
np - > pub . fsver = FSVER ;
np - > pub . ClosePath = VFSW32_ClosePath ;
np - > pub . BuildHash = VFSW32_BuildHash ;
np - > pub . FindFile = VFSW32_FLocate ;
np - > pub . ReadFile = VFSW32_ReadFile ;
np - > pub . EnumerateFiles = VFSW32_EnumerateFiles ;
np - > pub . OpenVFS = VFSW32_OpenVFS ;
np - > pub . PollChanges = VFSW32_PollChanges ;
2013-11-21 23:02:28 +00:00
np - > pub . RenameFile = VFSW32_RenameFile ;
np - > pub . RemoveFile = VFSW32_RemoveFile ;
np - > pub . MkDir = VFSW32_MkDir ;
2013-06-23 02:17:02 +00:00
return & np - > pub ;
2013-06-24 09:04:00 +00:00
}
2014-03-30 08:55:06 +00:00
# endif