Browse Source

Filesystem port

pull/2/head
Alibek Omarov 7 years ago
parent
commit
d564a062ce
  1. 1
      engine/common/common.h
  2. 187
      engine/common/filesystem.c

1
engine/common/common.h

@ -191,6 +191,7 @@ typedef enum
#define FS_STATIC_PATH 1 // FS_ClearSearchPath will be ignore this path #define FS_STATIC_PATH 1 // FS_ClearSearchPath will be ignore this path
#define FS_NOWRITE_PATH 2 // default behavior - last added gamedir set as writedir. This flag disables it #define FS_NOWRITE_PATH 2 // default behavior - last added gamedir set as writedir. This flag disables it
#define FS_GAMEDIR_PATH 4 // just a marker for gamedir path #define FS_GAMEDIR_PATH 4 // just a marker for gamedir path
#define FS_CUSTOM_PATH 8 // custom directory
#define GI SI.GameInfo #define GI SI.GameInfo
#define FS_Gamedir() SI.GameInfo->gamedir #define FS_Gamedir() SI.GameInfo->gamedir

187
engine/common/filesystem.c

@ -14,10 +14,15 @@ GNU General Public License for more details.
*/ */
#include <fcntl.h> #include <fcntl.h>
#include <direct.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <io.h>
#include <time.h> #include <time.h>
#ifdef _WIN32
#include <direct.h>
#include <io.h>
#else
#include <dirent.h>
#include <errno.h>
#endif
#include "common.h" #include "common.h"
#include "wadfile.h" #include "wadfile.h"
#include "filesystem.h" #include "filesystem.h"
@ -109,6 +114,9 @@ char fs_basedir[MAX_SYSPATH]; // base game directory
char fs_gamedir[MAX_SYSPATH]; // game current directory char fs_gamedir[MAX_SYSPATH]; // game current directory
char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course) char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course)
qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
#ifndef _WIN32
qboolean fs_caseinsensitive = true; // try to search missing files
#endif
static const wadtype_t wad_hints[10]; static const wadtype_t wad_hints[10];
static void FS_InitMemory( void ); static void FS_InitMemory( void );
@ -117,7 +125,7 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match
static dpackfile_t *FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size ); static dpackfile_t *FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size );
static byte *W_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly ); static byte *W_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly );
static wfile_t *W_Open( const char *filename, int *errorcode ); static wfile_t *W_Open( const char *filename, int *errorcode );
static qboolean FS_SysFileExists( const char *path ); static qboolean FS_SysFileExists( const char *path, qboolean caseinsensitive );
static qboolean FS_SysFolderExists( const char *path ); static qboolean FS_SysFolderExists( const char *path );
static long FS_SysFileTime( const char *filename ); static long FS_SysFileTime( const char *filename );
static char W_TypeFromExt( const char *lumpname ); static char W_TypeFromExt( const char *lumpname );
@ -256,14 +264,21 @@ static void listlowercase( stringlist_t *list )
} }
} }
static void listdirectory( stringlist_t *list, const char *path ) static void listdirectory( stringlist_t *list, const char *path, qboolean lowercase )
{ {
int i;
signed char *c;
#ifdef _WIN32
char pattern[4096]; char pattern[4096];
struct _finddata_t n_file; struct _finddata_t n_file;
long hFile; int hFile;
#else
DIR *dir;
struct dirent *entry;
#endif
Q_strncpy( pattern, path, sizeof( pattern )); #ifdef _WIN32
Q_strncat( pattern, "*", sizeof( pattern )); Q_snprintf( pattern, sizeof( pattern ), "%s*", path );
// ask for the directory listing handle // ask for the directory listing handle
hFile = _findfirst( pattern, &n_file ); hFile = _findfirst( pattern, &n_file );
@ -271,14 +286,23 @@ static void listdirectory( stringlist_t *list, const char *path )
// start a new chain with the the first name // start a new chain with the the first name
stringlistappend( list, n_file.name ); stringlistappend( list, n_file.name );
// iterate through the directory // iterate through the directory
while( _findnext( hFile, &n_file ) == 0 ) while( _findnext( hFile, &n_file ) == 0 )
stringlistappend( list, n_file.name ); stringlistappend( list, n_file.name );
_findclose( hFile ); _findclose( hFile );
#else
if( !( dir = opendir( path ) ) )
return;
// iterate through the directory
while( ( entry = readdir( dir ) ))
stringlistappend( list, entry->d_name );
closedir( dir );
#endif
// g-cont. disabled for some reasons // convert names to lowercase because windows doesn't care, but pattern matching code often does
// listlowercase( list ); if( lowercase )
listlowercase( list );
} }
/* /*
@ -288,6 +312,71 @@ OTHER PRIVATE FUNCTIONS
============================================================================= =============================================================================
*/ */
/*
==================
FS_FixFileCase
emulate WIN32 FS behaviour when opening local file
==================
*/
static const char *FS_FixFileCase( const char *path )
{
#if !defined _WIN32 && !TARGET_OS_IPHONE // assume case insensitive
DIR *dir; struct dirent *entry;
char path2[PATH_MAX], *fname;
if( !fs_caseinsensitive )
return path;
Q_snprintf( path2, sizeof( path2 ), "./%s", path );
fname = Q_strrchr( path2, '/' );
if( fname )
*fname++ = 0;
else
{
fname = (char*)path;
Q_strcpy( path2, ".");
}
/* android has too slow directory scanning,
so drop out some not useful cases */
if( fname - path2 > 4 )
{
char *point;
// too many wad textures
if( !Q_stricmp( fname - 5, ".wad") )
return path;
point = Q_strchr( fname, '.' );
if( point )
{
if( !Q_strcmp( point, ".mip") || !Q_strcmp( point, ".dds" ) || !Q_strcmp( point, ".ent" ) )
return path;
if( fname[0] == '{' )
return path;
}
}
//MsgDev( D_NOTE, "FS_FixFileCase: %s\n", path );
if( !( dir = opendir( path2 ) ) )
return path;
while( ( entry = readdir( dir ) ) )
{
if( Q_stricmp( entry->d_name, fname ) )
continue;
path = va( "%s/%s", path2, entry->d_name );
//MsgDev( D_NOTE, "FS_FixFileCase: %s %s %s\n", path2, fname, entry->d_name );
break;
}
closedir( dir );
#endif
return path;
}
/* /*
==================== ====================
FS_AddFileToPack FS_AddFileToPack
@ -412,6 +501,15 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error )
packhandle = open( packfile, O_RDONLY|O_BINARY ); packhandle = open( packfile, O_RDONLY|O_BINARY );
#ifndef _WIN32
if( packhandle < 0 )
{
const char *fpackfile = FS_FixFileCase( packfile );
if( fpackfile!= packfile )
packhandle = open( fpackfile, O_RDONLY|O_BINARY );
}
#endif
if( packhandle < 0 ) if( packhandle < 0 )
{ {
MsgDev( D_NOTE, "%s couldn't open\n", packfile ); MsgDev( D_NOTE, "%s couldn't open\n", packfile );
@ -614,7 +712,7 @@ void FS_AddGameDirectory( const char *dir, int flags )
Q_strncpy( fs_writedir, dir, sizeof( fs_writedir )); Q_strncpy( fs_writedir, dir, sizeof( fs_writedir ));
stringlistinit( &list ); stringlistinit( &list );
listdirectory( &list, dir ); listdirectory( &list, dir, false );
stringlistsort( &list ); stringlistsort( &list );
// add any PAK package in the directory // add any PAK package in the directory
@ -1351,11 +1449,16 @@ void FS_Init( void )
Cmd_AddCommand( "fs_path", FS_Path_f, "show filesystem search pathes" ); Cmd_AddCommand( "fs_path", FS_Path_f, "show filesystem search pathes" );
Cmd_AddCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" ); Cmd_AddCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
#ifndef _WIN32
if( Sys_CheckParm( "-casesensitive" ) )
fs_caseinsensitive = false;
#endif
// ignore commandlineoption "-game" for other stuff // ignore commandlineoption "-game" for other stuff
if( host.type == HOST_NORMAL || host.type == HOST_DEDICATED ) if( host.type == HOST_NORMAL || host.type == HOST_DEDICATED )
{ {
stringlistinit( &dirs ); stringlistinit( &dirs );
listdirectory( &dirs, "./" ); listdirectory( &dirs, "./", false );
stringlistsort( &dirs ); stringlistsort( &dirs );
SI.numgames = 0; SI.numgames = 0;
@ -1513,6 +1616,15 @@ static file_t *FS_SysOpen( const char *filepath, const char *mode )
file->handle = open( filepath, mod|opt, 0666 ); file->handle = open( filepath, mod|opt, 0666 );
#ifndef _WIN32
if( file->handle < 0 )
{
const char *ffilepath = FS_FixFileCase( filepath );
if( ffilepath != filepath )
file->handle = open( ffilepath, mod|opt, 0666 );
}
#endif
if( file->handle < 0 ) if( file->handle < 0 )
{ {
Mem_Free( file ); Mem_Free( file );
@ -1568,8 +1680,9 @@ FS_SysFileExists
Look for a file in the filesystem only Look for a file in the filesystem only
================== ==================
*/ */
qboolean FS_SysFileExists( const char *path ) qboolean FS_SysFileExists( const char *path, qboolean caseinsensitive )
{ {
#ifdef _WIN32
int desc; int desc;
if(( desc = open( path, O_RDONLY|O_BINARY )) < 0 ) if(( desc = open( path, O_RDONLY|O_BINARY )) < 0 )
@ -1577,6 +1690,25 @@ qboolean FS_SysFileExists( const char *path )
close( desc ); close( desc );
return true; return true;
#else
int ret;
struct stat buf;
ret = stat( path, &buf );
// speedup custom path search
if( caseinsensitive && ( ret < 0 ) )
{
const char *fpath = FS_FixFileCase( path );
if( fpath != path )
ret = stat( fpath, &buf );
}
if( ret < 0 )
return false;
return S_ISREG( buf.st_mode );
#endif
} }
/* /*
@ -1588,9 +1720,28 @@ Look for a existing folder
*/ */
qboolean FS_SysFolderExists( const char *path ) qboolean FS_SysFolderExists( const char *path )
{ {
#ifdef _WIN32
DWORD dwFlags = GetFileAttributes( path ); DWORD dwFlags = GetFileAttributes( path );
return ( dwFlags != -1 ) && FBitSet( dwFlags, FILE_ATTRIBUTE_DIRECTORY ); return ( dwFlags != -1 ) && ( dwFlags & FILE_ATTRIBUTE_DIRECTORY );
#else
DIR *dir = opendir( path );
if( dir )
{
closedir( dir );
return true;
}
else if( (errno == ENOENT) || (errno == ENOTDIR) )
{
return false;
}
else
{
MsgDev( D_ERROR, "FS_SysFolderExists: problem while opening dir: %s\n", strerror( errno ) );
return false;
}
#endif
} }
/* /*
@ -1693,7 +1844,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir
Q_sprintf( netpath, "%s%s", search->filename, name ); Q_sprintf( netpath, "%s%s", search->filename, name );
if( FS_SysFileExists( netpath )) if( FS_SysFileExists( netpath, !( search->flags & FS_CUSTOM_PATH ) ))
{ {
if( index != NULL ) *index = -1; if( index != NULL ) *index = -1;
return search; return search;
@ -1714,7 +1865,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir
Q_strcat( search->filename, "\\" ); Q_strcat( search->filename, "\\" );
Q_snprintf( netpath, MAX_SYSPATH, "%s%s", search->filename, name ); Q_snprintf( netpath, MAX_SYSPATH, "%s%s", search->filename, name );
if( FS_SysFileExists( netpath )) if( FS_SysFileExists( netpath, !( search->flags & FS_CUSTOM_PATH ) ))
{ {
if( index != NULL ) if( index != NULL )
*index = -1; *index = -1;
@ -1730,7 +1881,7 @@ static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedir
Q_strcat( search->filename, "\\" ); Q_strcat( search->filename, "\\" );
Q_snprintf( netpath, MAX_SYSPATH, "%s%s", search->filename, name ); Q_snprintf( netpath, MAX_SYSPATH, "%s%s", search->filename, name );
if( FS_SysFileExists( netpath )) if( FS_SysFileExists( netpath, !( search->flags & FS_CUSTOM_PATH ) ))
{ {
if( index != NULL ) if( index != NULL )
*index = -1; *index = -1;
@ -2686,7 +2837,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
// get a directory listing and look at each name // get a directory listing and look at each name
Q_sprintf( netpath, "%s%s", searchpath->filename, basepath ); Q_sprintf( netpath, "%s%s", searchpath->filename, basepath );
stringlistinit( &dirlist ); stringlistinit( &dirlist );
listdirectory( &dirlist, netpath ); listdirectory( &dirlist, netpath, caseinsensitive );
for( dirlistindex = 0; dirlistindex < dirlist.numstrings; dirlistindex++ ) for( dirlistindex = 0; dirlistindex < dirlist.numstrings; dirlistindex++ )
{ {

Loading…
Cancel
Save