//
#include "vfs.h"
+#include "globaldefs.h"
#include <stdio.h>
#include <stdlib.h>
#include "qerplugin.h"
#include "idatastream.h"
#include "iarchive.h"
-ArchiveModules& FileSystemQ3API_getArchiveModules();
+
+ArchiveModules &FileSystemQ3API_getArchiveModules();
+
#include "ifilesystem.h"
#include "generic/callback.h"
#include "os/path.h"
#include "moduleobservers.h"
#include "filematch.h"
+#include "dpkdeps.h"
-#define VFS_MAXDIRS 64
+const int VFS_MAXDIRS = 64;
-#if defined( WIN32 )
+#if GDEF_OS_WINDOWS
#define PATH_MAX 260
#endif
// =============================================================================
// Global variables
-Archive* OpenArchive( const char* name );
+Archive *OpenArchive(const char *name);
-struct archive_entry_t
-{
- CopiedString name;
- Archive* archive;
- bool is_pakfile;
+struct archive_entry_t {
+ CopiedString name;
+ Archive *archive;
+ bool is_pakfile;
};
#include <list>
// =============================================================================
// Static functions
-static void AddSlash( char *str ){
- std::size_t n = strlen( str );
- if ( n > 0 ) {
- if ( str[n - 1] != '\\' && str[n - 1] != '/' ) {
- globalErrorStream() << "WARNING: directory path does not end with separator: " << str << "\n";
- strcat( str, "/" );
- }
- }
+static void AddSlash(char *str)
+{
+ std::size_t n = strlen(str);
+ if (n > 0) {
+ if (str[n - 1] != '\\' && str[n - 1] != '/') {
+ globalErrorStream() << "WARNING: directory path does not end with separator: " << str << "\n";
+ strcat(str, "/");
+ }
+ }
}
-static void FixDOSName( char *src ){
- if ( src == 0 || strchr( src, '\\' ) == 0 ) {
- return;
- }
+static void FixDOSName(char *src)
+{
+ if (src == 0 || strchr(src, '\\') == 0) {
+ return;
+ }
- globalErrorStream() << "WARNING: invalid path separator '\\': " << src << "\n";
+ globalErrorStream() << "WARNING: invalid path separator '\\': " << src << "\n";
- while ( *src )
- {
- if ( *src == '\\' ) {
- *src = '/';
- }
- src++;
- }
+ while (*src) {
+ if (*src == '\\') {
+ *src = '/';
+ }
+ src++;
+ }
}
-const _QERArchiveTable* GetArchiveTable( ArchiveModules& archiveModules, const char* ext ){
- StringOutputStream tmp( 16 );
- tmp << LowerCase( ext );
- return archiveModules.findModule( tmp.c_str() );
+const _QERArchiveTable *GetArchiveTable(ArchiveModules &archiveModules, const char *ext)
+{
+ StringOutputStream tmp(16);
+ tmp << LowerCase(ext);
+ return archiveModules.findModule(tmp.c_str());
}
-static Archive* InitPakFile( ArchiveModules& archiveModules, const char *filename ){
- const _QERArchiveTable* table = GetArchiveTable( archiveModules, path_get_extension( filename ) );
+static Archive *InitPakFile(ArchiveModules &archiveModules, const char *filename)
+{
+ const _QERArchiveTable *table = GetArchiveTable(archiveModules, path_get_extension(filename));
- if ( table != 0 ) {
- archive_entry_t entry;
- entry.name = filename;
+ if (table != 0) {
+ archive_entry_t entry;
+ entry.name = filename;
- entry.archive = table->m_pfnOpenArchive( filename );
- entry.is_pakfile = true;
- g_archives.push_back( entry );
- globalOutputStream() << " pak file: " << filename << "\n";
+ entry.archive = table->m_pfnOpenArchive(filename);
+ entry.is_pakfile = true;
+ g_archives.push_back(entry);
+ globalOutputStream() << " pak file: " << filename << "\n";
- return entry.archive;
- }
+ return entry.archive;
+ }
- return 0;
+ return 0;
}
-inline void pathlist_prepend_unique( GSList*& pathlist, char* path ){
- if ( g_slist_find_custom( pathlist, path, (GCompareFunc)path_compare ) == 0 ) {
- pathlist = g_slist_prepend( pathlist, path );
- }
- else
- {
- g_free( path );
- }
+inline void pathlist_prepend_unique(GSList *&pathlist, char *path)
+{
+ if (g_slist_find_custom(pathlist, path, (GCompareFunc) path_compare) == 0) {
+ pathlist = g_slist_prepend(pathlist, path);
+ } else {
+ g_free(path);
+ }
}
-class DirectoryListVisitor : public Archive::Visitor
-{
-GSList*& m_matches;
-const char* m_directory;
+class DirectoryListVisitor : public Archive::Visitor {
+ GSList *&m_matches;
+ const char *m_directory;
public:
-DirectoryListVisitor( GSList*& matches, const char* directory )
- : m_matches( matches ), m_directory( directory )
-{}
-void visit( const char* name ){
- const char* subname = path_make_relative( name, m_directory );
- if ( subname != name ) {
- if ( subname[0] == '/' ) {
- ++subname;
- }
- char* dir = g_strdup( subname );
- char* last_char = dir + strlen( dir );
- if ( last_char != dir && *( --last_char ) == '/' ) {
- *last_char = '\0';
- }
- pathlist_prepend_unique( m_matches, dir );
- }
-}
+ DirectoryListVisitor(GSList *&matches, const char *directory)
+ : m_matches(matches), m_directory(directory)
+ {}
+
+ void visit(const char *name)
+ {
+ const char *subname = path_make_relative(name, m_directory);
+ if (subname != name) {
+ if (subname[0] == '/') {
+ ++subname;
+ }
+ char *dir = g_strdup(subname);
+ char *last_char = dir + strlen(dir);
+ if (last_char != dir && *(--last_char) == '/') {
+ *last_char = '\0';
+ }
+ pathlist_prepend_unique(m_matches, dir);
+ }
+ }
};
-class FileListVisitor : public Archive::Visitor
-{
-GSList*& m_matches;
-const char* m_directory;
-const char* m_extension;
+class FileListVisitor : public Archive::Visitor {
+ GSList *&m_matches;
+ const char *m_directory;
+ const char *m_extension;
public:
-FileListVisitor( GSList*& matches, const char* directory, const char* extension )
- : m_matches( matches ), m_directory( directory ), m_extension( extension )
-{}
-void visit( const char* name ){
- const char* subname = path_make_relative( name, m_directory );
- if ( subname != name ) {
- if ( subname[0] == '/' ) {
- ++subname;
- }
- if ( m_extension[0] == '*' || extension_equal( path_get_extension( subname ), m_extension ) ) {
- pathlist_prepend_unique( m_matches, g_strdup( subname ) );
- }
- }
-}
+ FileListVisitor(GSList *&matches, const char *directory, const char *extension)
+ : m_matches(matches), m_directory(directory), m_extension(extension)
+ {}
+
+ void visit(const char *name)
+ {
+ const char *subname = path_make_relative(name, m_directory);
+ if (subname != name) {
+ if (subname[0] == '/') {
+ ++subname;
+ }
+ if (m_extension[0] == '*' || extension_equal(path_get_extension(subname), m_extension)) {
+ pathlist_prepend_unique(m_matches, g_strdup(subname));
+ }
+ }
+ }
};
-static GSList* GetListInternal( const char *refdir, const char *ext, bool directories, std::size_t depth ){
- GSList* files = 0;
-
- ASSERT_MESSAGE( refdir[strlen( refdir ) - 1] == '/', "search path does not end in '/'" );
-
- if ( directories ) {
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- DirectoryListVisitor visitor( files, refdir );
- ( *i ).archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eDirectories, depth ), refdir );
- }
- }
- else
- {
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- FileListVisitor visitor( files, refdir, ext );
- ( *i ).archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, depth ), refdir );
- }
- }
-
- files = g_slist_reverse( files );
-
- return files;
+static GSList *GetListInternal(const char *refdir, const char *ext, bool directories, std::size_t depth)
+{
+ GSList *files = 0;
+
+ ASSERT_MESSAGE(refdir[strlen(refdir) - 1] == '/', "search path does not end in '/'");
+
+ if (directories) {
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ DirectoryListVisitor visitor(files, refdir);
+ (*i).archive->forEachFile(Archive::VisitorFunc(visitor, Archive::eDirectories, depth), refdir);
+ }
+ } else {
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ FileListVisitor visitor(files, refdir, ext);
+ (*i).archive->forEachFile(Archive::VisitorFunc(visitor, Archive::eFiles, depth), refdir);
+ }
+ }
+
+ files = g_slist_reverse(files);
+
+ return files;
}
-inline int ascii_to_upper( int c ){
- if ( c >= 'a' && c <= 'z' ) {
- return c - ( 'a' - 'A' );
- }
- return c;
+inline int ascii_to_upper(int c)
+{
+ if (c >= 'a' && c <= 'z') {
+ return c - ('a' - 'A');
+ }
+ return c;
}
/*!
it converts all alphabet chars to uppercase before comparison,
while stricmp converts them to lowercase.
*/
-static int string_compare_nocase_upper( const char* a, const char* b ){
- for (;; )
- {
- int c1 = ascii_to_upper( *a++ );
- int c2 = ascii_to_upper( *b++ );
-
- if ( c1 < c2 ) {
- return -1; // a < b
- }
- if ( c1 > c2 ) {
- return 1; // a > b
- }
- if ( c1 == 0 ) {
- return 0; // a == b
- }
- }
+static int string_compare_nocase_upper(const char *a, const char *b)
+{
+ for (;;) {
+ int c1 = ascii_to_upper(*a++);
+ int c2 = ascii_to_upper(*b++);
+
+ if (c1 < c2) {
+ return -1; // a < b
+ }
+ if (c1 > c2) {
+ return 1; // a > b
+ }
+ if (c1 == 0) {
+ return 0; // a == b
+ }
+ }
}
// Arnout: note - sort pakfiles in reverse order. This ensures that
// last one in the list that is).
//!\todo Analyse the code in rtcw/q3 to see which order it sorts pak files.
-class PakLess
-{
+class PakLess {
public:
-bool operator()( const CopiedString& self, const CopiedString& other ) const {
- return string_compare_nocase_upper( self.c_str(), other.c_str() ) > 0;
-}
+ bool operator()(const CopiedString &self, const CopiedString &other) const
+ {
+ return string_compare_nocase_upper(self.c_str(), other.c_str()) > 0;
+ }
};
typedef std::set<CopiedString, PakLess> Archives;
-Archive* AddPk3Dir( const char* fullpath ){
- if ( g_numDirs == VFS_MAXDIRS ) return 0;
+Archive *AddPk3Dir(const char *fullpath)
+{
+ if (g_numDirs == VFS_MAXDIRS) { return 0; }
- strncpy( g_strDirs[g_numDirs], fullpath, PATH_MAX );
- g_strDirs[g_numDirs][PATH_MAX] = '\0';
- g_numDirs++;
+ strncpy(g_strDirs[g_numDirs], fullpath, PATH_MAX);
+ g_strDirs[g_numDirs][PATH_MAX] = '\0';
+ g_numDirs++;
- {
- archive_entry_t entry;
- entry.name = fullpath;
- entry.archive = OpenArchive( fullpath );
- entry.is_pakfile = false;
- g_archives.push_back( entry );
+ {
+ archive_entry_t entry;
+ entry.name = fullpath;
+ entry.archive = OpenArchive(fullpath);
+ entry.is_pakfile = false;
+ g_archives.push_back(entry);
- return entry.archive;
- }
+ return entry.archive;
+ }
}
// for Daemon DPK vfs
-Archive* AddDpkDir( const char* fullpath ){
- return AddPk3Dir( fullpath );
+Archive *AddDpkDir(const char *fullpath)
+{
+ return AddPk3Dir(fullpath);
}
-struct pakfile_path_t
-{
- CopiedString fullpath; // full pak dir or pk3dir name
- bool is_pakfile; // defines is it .pk3dir or .pk3 file
+struct pakfile_path_t {
+ CopiedString fullpath; // full pak dir or pk3dir name
+ bool is_pakfile; // defines is it .pk3dir or .pk3 file
};
typedef std::pair<CopiedString, pakfile_path_t> PakfilePathsKV;
static PakfilePaths g_pakfile_paths;
-void AddDpkPak( const char* name, const char* fullpath, bool is_pakfile ){
- pakfile_path_t pakfile_path;
- pakfile_path.fullpath = fullpath;
- pakfile_path.is_pakfile = is_pakfile;
- g_pakfile_paths.insert( PakfilePathsKV( name, pakfile_path ) );
-}
-
-// Comparaison function for version numbers
-// Implementation is based on dpkg's version comparison code (verrevcmp() and order())
-// http://anonscm.debian.org/gitweb/?p=dpkg/dpkg.git;a=blob;f=lib/dpkg/version.c;hb=74946af470550a3295e00cf57eca1747215b9311
-static int char_weight(char c){
- if (std::isdigit(c))
- return 0;
- else if (std::isalpha(c))
- return c;
- else if (c == '~')
- return -1;
- else if (c)
- return c + 256;
- else
- return 0;
-}
-
-static int VersionCmp(const char* a, const char* b){
- while (*a || *b) {
- int firstDiff = 0;
-
- while ((*a && !std::isdigit(*a)) || (*b && !std::isdigit(*b))) {
- int ac = char_weight(*a);
- int bc = char_weight(*b);
-
- if (ac != bc)
- return ac - bc;
-
- a++;
- b++;
- }
-
- while (*a == '0')
- a++;
- while (*b == '0')
- b++;
-
- while (std::isdigit(*a) && std::isdigit(*b)) {
- if (firstDiff == 0)
- firstDiff = *a - *b;
- a++;
- b++;
- }
-
- if (std::isdigit(*a))
- return 1;
- if (std::isdigit(*b))
- return -1;
- if (firstDiff)
- return firstDiff;
- }
-
- return false;
+void AddDpkPak(const char *name, const char *fullpath, bool is_pakfile)
+{
+ pakfile_path_t pakfile_path;
+ pakfile_path.fullpath = fullpath;
+ pakfile_path.is_pakfile = is_pakfile;
+ g_pakfile_paths.insert(PakfilePathsKV(name, pakfile_path));
}
// takes name without ext, returns without ext
-static const char* GetLatestDpkPakVersion( const char* name ){
- const char* maxversion = 0;
- const char* result = 0;
- const char* pakname;
- const char* pakversion;
- int namelen = string_length( name );
-
- for ( PakfilePaths::iterator i = g_pakfile_paths.begin(); i != g_pakfile_paths.end(); ++i )
- {
- pakname = i->first.c_str();
- if ( strncmp( pakname, name, namelen ) != 0 || pakname[namelen] != '_' ) continue;
- pakversion = pakname + (namelen + 1);
- if ( maxversion == 0 || VersionCmp( pakversion, maxversion ) > 0 ){
- maxversion = pakversion;
- result = pakname;
- }
- }
- return result;
+static const char *GetLatestDpkPakVersion(const char *name)
+{
+ const char *maxversion = 0;
+ const char *result = 0;
+ const char *pakname;
+ const char *pakversion;
+ int namelen = string_length(name);
+
+ for (PakfilePaths::iterator i = g_pakfile_paths.begin(); i != g_pakfile_paths.end(); ++i) {
+ pakname = i->first.c_str();
+ if (strncmp(pakname, name, namelen) != 0 || pakname[namelen] != '_') { continue; }
+ pakversion = pakname + (namelen + 1);
+ if (maxversion == 0 || DpkPakVersionCmp(pakversion, maxversion) > 0) {
+ maxversion = pakversion;
+ result = pakname;
+ }
+ }
+ return result;
}
// release string after using
-static char* GetCurrentMapDpkPakName(){
- char* mapdir;
- char* mapname;
- int mapnamelen;
- char* result = 0;
-
- mapname = string_clone( GlobalRadiant().getMapName() );
- mapnamelen = string_length( mapname );
-
- mapdir = strrchr( mapname, '/' );
- if ( mapdir ) {
- mapdir -= 12;
- if ( strncmp( mapdir, ".dpkdir/maps/", 13 ) == 0 ) {
- *mapdir = '\0';
- mapdir = strrchr( mapname, '/' );
- if ( mapdir ) mapdir++;
- else mapdir = mapname;
- result = string_clone( mapdir );
- }
- }
-
- string_release( mapname, mapnamelen );
- return result;
+static char *GetCurrentMapDpkPakName()
+{
+ char *mapdir;
+ char *mapname;
+ int mapnamelen;
+ char *result = 0;
+
+ mapname = string_clone(GlobalRadiant().getMapName());
+ mapnamelen = string_length(mapname);
+
+ mapdir = strrchr(mapname, '/');
+ if (mapdir) {
+ mapdir -= 12;
+ if (strncmp(mapdir, ".dpkdir/maps/", 13) == 0) {
+ *mapdir = '\0';
+ mapdir = strrchr(mapname, '/');
+ if (mapdir) { mapdir++; }
+ else { mapdir = mapname; }
+ result = string_clone(mapdir);
+ }
+ }
+
+ string_release(mapname, mapnamelen);
+ return result;
}
// actual pak adding on initialise, deferred from InitDirectory
// Daemon DPK filesystem doesn't need load all paks it finds
-static void LoadDpkPakWithDeps( const char* pakname ){
- const char* und = strrchr( pakname, '_' );
- if ( !und ) pakname = GetLatestDpkPakVersion( pakname );
- if ( !pakname || g_loaded_dpk_paks.find( pakname ) != g_loaded_dpk_paks.end() ) return;
-
- PakfilePaths::iterator i = g_pakfile_paths.find( pakname );
- if ( i == g_pakfile_paths.end() ) return;
-
- Archive* arc;
- if ( i->second.is_pakfile ){
- arc = InitPakFile( FileSystemQ3API_getArchiveModules(), i->second.fullpath.c_str() );
- } else {
- arc = AddDpkDir( i->second.fullpath.c_str() );
- }
- g_loaded_dpk_paks.insert( pakname );
-
- ArchiveTextFile* depsFile = arc->openTextFile( "DEPS" );
- if ( !depsFile ) return;
-
- {
- TextLinesInputStream<TextInputStream> istream = depsFile->getInputStream();
-
- CopiedString line;
- const char* c;
- const char* p_name;
- const char* p_name_end;
- const char* p_version;
- const char* p_version_end;
- while ( line = istream.readLine(), string_length( line.c_str() ) ) {
- c = line.c_str();
- while ( std::isspace( *c ) && *c != '\0' ) ++c;
- p_name = c;
- while ( !std::isspace( *c ) && *c != '\0' ) ++c;
- p_name_end = c;
- while ( std::isspace( *c ) && *c != '\0' ) ++c;
- p_version = c;
- while ( !std::isspace( *c ) && *c != '\0' ) ++c;
- p_version_end = c;
-
- if ( p_name_end - p_name == 0 ) continue;
- if ( p_version_end - p_version == 0 ) {
- const char* p_pakname;
- CopiedString name_final = CopiedString( StringRange( p_name, p_name_end ) );
- p_pakname = GetLatestDpkPakVersion( name_final.c_str() );
- if ( p_pakname != NULL ) {
- LoadDpkPakWithDeps( p_pakname );
- }
- } else {
- int len = ( p_name_end - p_name ) + ( p_version_end - p_version ) + 1;
- char* p_pakname = string_new( len );
- strncpy( p_pakname, p_name, p_name_end - p_name );
- p_pakname[ p_name_end - p_name ] = '\0';
- strcat( p_pakname, "_" );
- strncat( p_pakname, p_version, p_version_end - p_version );
- LoadDpkPakWithDeps( p_pakname );
- string_release( p_pakname, len );
- }
- }
- }
-
- depsFile->release();
+static void LoadDpkPakWithDeps(const char *pakname)
+{
+ Archive *arc;
+ ArchiveTextFile *depsFile;
+
+ if (pakname == NULL) {
+ // load DEPS from game pack
+ StringOutputStream baseDirectory(256);
+ const char *basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue("basegame");
+ baseDirectory << GlobalRadiant().getGameToolsPath() << basegame << '/';
+ arc = AddDpkDir(baseDirectory.c_str());
+ depsFile = arc->openTextFile("DEPS");
+ } else {
+ const char *und = strrchr(pakname, '_');
+ if (!und) {
+ pakname = GetLatestDpkPakVersion(pakname);
+ }
+ if (!pakname || g_loaded_dpk_paks.find(pakname) != g_loaded_dpk_paks.end()) {
+ return;
+ }
+
+ PakfilePaths::iterator i = g_pakfile_paths.find(pakname);
+ if (i == g_pakfile_paths.end()) {
+ return;
+ }
+
+ if (i->second.is_pakfile) {
+ arc = InitPakFile(FileSystemQ3API_getArchiveModules(), i->second.fullpath.c_str());
+ } else {
+ arc = AddDpkDir(i->second.fullpath.c_str());
+ }
+ g_loaded_dpk_paks.insert(pakname);
+
+ depsFile = arc->openTextFile("DEPS");
+ }
+
+ if (!depsFile) {
+ return;
+ }
+
+ {
+ TextLinesInputStream<TextInputStream> istream = depsFile->getInputStream();
+
+ CopiedString line;
+ char *p_name;
+ char *p_version;
+ while (line = istream.readLine(), string_length(line.c_str())) {
+ if (!DpkReadDepsLine(line.c_str(), &p_name, &p_version)) { continue; }
+ if (!p_version) {
+ const char *p_latest = GetLatestDpkPakVersion(p_name);
+ if (p_latest) { LoadDpkPakWithDeps(p_latest); }
+ } else {
+ int len = string_length(p_name) + string_length(p_version) + 1;
+ char *p_pakname = string_new(len);
+ sprintf(p_pakname, "%s_%s", p_name, p_version);
+ LoadDpkPakWithDeps(p_pakname);
+ string_release(p_pakname, len);
+ }
+ string_release(p_name, string_length(p_name));
+ if (p_version) { string_release(p_version, string_length(p_version)); }
+ }
+ }
+
+ depsFile->release();
}
// end for Daemon DPK vfs
// Global functions
// reads all pak files from a dir
-void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
- int j;
-
- g_numForbiddenDirs = 0;
- StringTokeniser st( GlobalRadiant().getGameDescriptionKeyValue( "forbidden_paths" ), " " );
- for ( j = 0; j < VFS_MAXDIRS; ++j )
- {
- const char *t = st.getToken();
- if ( string_empty( t ) ) {
- break;
- }
- strncpy( g_strForbiddenDirs[g_numForbiddenDirs], t, PATH_MAX );
- g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = '\0';
- ++g_numForbiddenDirs;
- }
-
- for ( j = 0; j < g_numForbiddenDirs; ++j )
- {
- char* dbuf = g_strdup( directory );
- if ( *dbuf && dbuf[strlen( dbuf ) - 1] == '/' ) {
- dbuf[strlen( dbuf ) - 1] = 0;
- }
- const char *p = strrchr( dbuf, '/' );
- p = ( p ? ( p + 1 ) : dbuf );
- if ( matchpattern( p, g_strForbiddenDirs[j], TRUE ) ) {
- g_free( dbuf );
- break;
- }
- g_free( dbuf );
- }
- if ( j < g_numForbiddenDirs ) {
- printf( "Directory %s matched by forbidden dirs, removed\n", directory );
- return;
- }
-
- if ( g_numDirs == VFS_MAXDIRS ) {
- return;
- }
-
- strncpy( g_strDirs[g_numDirs], directory, PATH_MAX );
- g_strDirs[g_numDirs][PATH_MAX] = '\0';
- FixDOSName( g_strDirs[g_numDirs] );
- AddSlash( g_strDirs[g_numDirs] );
-
- const char* path = g_strDirs[g_numDirs];
-
- g_numDirs++;
-
- {
- archive_entry_t entry;
- entry.name = path;
- entry.archive = OpenArchive( path );
- entry.is_pakfile = false;
- g_archives.push_back( entry );
- }
-
- if ( g_bUsePak ) {
-
- GDir* dir = g_dir_open( path, 0, 0 );
-
- if ( dir != 0 ) {
- globalOutputStream() << "vfs directory: " << path << "\n";
-
- Archives archives;
- Archives archivesOverride;
- const char* ignore_prefix = "";
- const char* override_prefix = "";
- bool is_pk3_vfs, is_pk4_vfs, is_dpk_vfs;
-
- is_pk3_vfs = GetArchiveTable( archiveModules, "pk3" );
- is_pk4_vfs = GetArchiveTable( archiveModules, "pk4" );
- is_dpk_vfs = GetArchiveTable( archiveModules, "dpk" );
-
- if ( !is_dpk_vfs ) {
- // See if we are in "sp" or "mp" mapping mode
- const char* gamemode = gamemode_get();
-
- if ( strcmp( gamemode, "sp" ) == 0 ) {
- ignore_prefix = "mp_";
- override_prefix = "sp_";
- }
- else if ( strcmp( gamemode, "mp" ) == 0 ) {
- ignore_prefix = "sp_";
- override_prefix = "mp_";
- }
- }
-
- for (;; )
- {
- const char* name = g_dir_read_name( dir );
- if ( name == 0 ) {
- break;
- }
-
- for ( j = 0; j < g_numForbiddenDirs; ++j )
- {
- const char *p = strrchr( name, '/' );
- p = ( p ? ( p + 1 ) : name );
- if ( matchpattern( p, g_strForbiddenDirs[j], TRUE ) ) {
- break;
- }
- }
- if ( j < g_numForbiddenDirs ) {
- continue;
- }
-
- const char *ext = strrchr( name, '.' );
- char tmppath[PATH_MAX];
-
- if ( is_dpk_vfs ) {
- if ( !!ext && !string_compare_nocase_upper( ext, ".dpkdir" ) ) {
- snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
- tmppath[PATH_MAX] = '\0';
- FixDOSName( tmppath );
- AddSlash( tmppath );
- AddDpkPak( CopiedString( StringRange( name, ext ) ).c_str(), tmppath, false );
- }
- }
-
- if ( is_pk3_vfs || is_pk4_vfs ) {
- if ( !!ext && ( !string_compare_nocase_upper( ext, ".pk3dir" )
- || !string_compare_nocase_upper( ext, ".pk4dir" ) ) ) {
- snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
- tmppath[PATH_MAX] = '\0';
- FixDOSName( tmppath );
- AddSlash( tmppath );
- AddPk3Dir( tmppath );
- }
- }
-
- // GetArchiveTable() needs "pk3" if ext is ".pk3"
- if ( ( ext == 0 ) || *( ext + 1 ) == '\0' || GetArchiveTable( archiveModules, ext + 1 ) == 0 ) {
- continue;
- }
-
- // using the same kludge as in engine to ensure consistency
- if ( !string_empty( ignore_prefix ) && strncmp( name, ignore_prefix, strlen( ignore_prefix ) ) == 0 ) {
- continue;
- }
- if ( !string_empty( override_prefix ) && strncmp( name, override_prefix, strlen( override_prefix ) ) == 0 ) {
- if ( !string_compare_nocase_upper( ext, ".dpk" ) ) {
- if ( is_dpk_vfs ) {
- archives.insert( name );
- }
- }
- else {
- archivesOverride.insert( name );
- }
- continue;
- }
-
- archives.insert( name );
- }
-
- g_dir_close( dir );
-
- // add the entries to the vfs
- char* fullpath;
- if ( is_dpk_vfs ) {
- for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i ) {
- const char* name = i->c_str();
- const char* ext = strrchr( name, '.' );
- if ( !string_compare_nocase_upper( ext, "dpk" ) ) {
- CopiedString name_final = CopiedString( StringRange( name, ext ) );
- fullpath = string_new_concat( path, name );
- AddDpkPak( name_final.c_str(), fullpath, true );
- string_release( fullpath, string_length( fullpath ) );
- }
- }
- }
- if ( is_pk3_vfs || is_pk4_vfs ) {
- for ( Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i )
- {
- const char* name = i->c_str();
- const char* ext = strrchr( name, '.' );
- if ( !string_compare_nocase_upper( ext, "pk3" )
- || !string_compare_nocase_upper( ext, "pk4" ) ) {
- fullpath = string_new_concat( path, i->c_str() );
- InitPakFile( archiveModules, fullpath );
- string_release( fullpath, string_length( fullpath ) );
- }
- }
- for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i )
- {
- const char* name = i->c_str();
- const char* ext = strrchr( name, '.' );
- if ( !string_compare_nocase_upper( ext, "pk3" )
- || !string_compare_nocase_upper( ext, "pk4" ) ) {
- fullpath = string_new_concat( path, i->c_str() );
- InitPakFile( archiveModules, fullpath );
- string_release( fullpath, string_length( fullpath ) );
- }
- }
- }
- }
- else
- {
- globalErrorStream() << "vfs directory not found: " << path << "\n";
- }
- }
+void InitDirectory(const char *directory, ArchiveModules &archiveModules)
+{
+ int j;
+
+ g_numForbiddenDirs = 0;
+ StringTokeniser st(GlobalRadiant().getGameDescriptionKeyValue("forbidden_paths"), " ");
+ for (j = 0; j < VFS_MAXDIRS; ++j) {
+ const char *t = st.getToken();
+ if (string_empty(t)) {
+ break;
+ }
+ strncpy(g_strForbiddenDirs[g_numForbiddenDirs], t, PATH_MAX);
+ g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = '\0';
+ ++g_numForbiddenDirs;
+ }
+
+ for (j = 0; j < g_numForbiddenDirs; ++j) {
+ char *dbuf = g_strdup(directory);
+ if (*dbuf && dbuf[strlen(dbuf) - 1] == '/') {
+ dbuf[strlen(dbuf) - 1] = 0;
+ }
+ const char *p = strrchr(dbuf, '/');
+ p = (p ? (p + 1) : dbuf);
+ if (matchpattern(p, g_strForbiddenDirs[j], TRUE)) {
+ g_free(dbuf);
+ break;
+ }
+ g_free(dbuf);
+ }
+ if (j < g_numForbiddenDirs) {
+ printf("Directory %s matched by forbidden dirs, removed\n", directory);
+ return;
+ }
+
+ if (g_numDirs == VFS_MAXDIRS) {
+ return;
+ }
+
+ strncpy(g_strDirs[g_numDirs], directory, PATH_MAX);
+ g_strDirs[g_numDirs][PATH_MAX] = '\0';
+ FixDOSName(g_strDirs[g_numDirs]);
+ AddSlash(g_strDirs[g_numDirs]);
+
+ const char *path = g_strDirs[g_numDirs];
+
+ g_numDirs++;
+
+ {
+ archive_entry_t entry;
+ entry.name = path;
+ entry.archive = OpenArchive(path);
+ entry.is_pakfile = false;
+ g_archives.push_back(entry);
+ }
+
+ if (g_bUsePak) {
+
+ GDir *dir = g_dir_open(path, 0, 0);
+
+ if (dir != 0) {
+ globalOutputStream() << "vfs directory: " << path << "\n";
+
+ Archives archives;
+ Archives archivesOverride;
+ const char *ignore_prefix = "";
+ const char *override_prefix = "";
+ bool is_pk3_vfs, is_pk4_vfs, is_dpk_vfs;
+
+ is_pk3_vfs = GetArchiveTable(archiveModules, "pk3");
+ is_pk4_vfs = GetArchiveTable(archiveModules, "pk4");
+ is_dpk_vfs = GetArchiveTable(archiveModules, "dpk");
+
+ if (!is_dpk_vfs) {
+ // See if we are in "sp" or "mp" mapping mode
+ const char *gamemode = gamemode_get();
+
+ if (strcmp(gamemode, "sp") == 0) {
+ ignore_prefix = "mp_";
+ override_prefix = "sp_";
+ } else if (strcmp(gamemode, "mp") == 0) {
+ ignore_prefix = "sp_";
+ override_prefix = "mp_";
+ }
+ }
+
+ for (;;) {
+ const char *name = g_dir_read_name(dir);
+ if (name == 0) {
+ break;
+ }
+
+ for (j = 0; j < g_numForbiddenDirs; ++j) {
+ const char *p = strrchr(name, '/');
+ p = (p ? (p + 1) : name);
+ if (matchpattern(p, g_strForbiddenDirs[j], TRUE)) {
+ break;
+ }
+ }
+ if (j < g_numForbiddenDirs) {
+ continue;
+ }
+
+ const char *ext = strrchr(name, '.');
+ char tmppath[PATH_MAX];
+
+ if (is_dpk_vfs) {
+ if (!!ext && !string_compare_nocase_upper(ext, ".dpkdir")) {
+ snprintf(tmppath, PATH_MAX, "%s%s/", path, name);
+ tmppath[PATH_MAX] = '\0';
+ FixDOSName(tmppath);
+ AddSlash(tmppath);
+ AddDpkPak(CopiedString(StringRange(name, ext)).c_str(), tmppath, false);
+ }
+ }
+
+ if (is_pk3_vfs || is_pk4_vfs) {
+ if (!!ext && (!string_compare_nocase_upper(ext, ".pk3dir")
+ || !string_compare_nocase_upper(ext, ".pk4dir"))) {
+ snprintf(tmppath, PATH_MAX, "%s%s/", path, name);
+ tmppath[PATH_MAX] = '\0';
+ FixDOSName(tmppath);
+ AddSlash(tmppath);
+ AddPk3Dir(tmppath);
+ }
+ }
+
+ // GetArchiveTable() needs "pk3" if ext is ".pk3"
+ if ((ext == 0) || *(ext + 1) == '\0' || GetArchiveTable(archiveModules, ext + 1) == 0) {
+ continue;
+ }
+
+ // using the same kludge as in engine to ensure consistency
+ if (!string_empty(ignore_prefix) && strncmp(name, ignore_prefix, strlen(ignore_prefix)) == 0) {
+ continue;
+ }
+ if (!string_empty(override_prefix) && strncmp(name, override_prefix, strlen(override_prefix)) == 0) {
+ if (!string_compare_nocase_upper(ext, ".dpk")) {
+ if (is_dpk_vfs) {
+ archives.insert(name);
+ }
+ } else {
+ archivesOverride.insert(name);
+ }
+ continue;
+ }
+
+ archives.insert(name);
+ }
+
+ g_dir_close(dir);
+
+ // add the entries to the vfs
+ char *fullpath;
+ if (is_dpk_vfs) {
+ for (Archives::iterator i = archives.begin(); i != archives.end(); ++i) {
+ const char *name = i->c_str();
+ const char *ext = strrchr(name, '.');
+ if (!string_compare_nocase_upper(ext, ".dpk")) {
+ CopiedString name_final = CopiedString(StringRange(name, ext));
+ fullpath = string_new_concat(path, name);
+ AddDpkPak(name_final.c_str(), fullpath, true);
+ string_release(fullpath, string_length(fullpath));
+ }
+ }
+ }
+ if (is_pk3_vfs || is_pk4_vfs) {
+ for (Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i) {
+ const char *name = i->c_str();
+ const char *ext = strrchr(name, '.');
+ if (!string_compare_nocase_upper(ext, ".pk3")
+ || !string_compare_nocase_upper(ext, ".pk4")) {
+ fullpath = string_new_concat(path, i->c_str());
+ InitPakFile(archiveModules, fullpath);
+ string_release(fullpath, string_length(fullpath));
+ }
+ }
+ for (Archives::iterator i = archives.begin(); i != archives.end(); ++i) {
+ const char *name = i->c_str();
+ const char *ext = strrchr(name, '.');
+ if (!string_compare_nocase_upper(ext, ".pk3")
+ || !string_compare_nocase_upper(ext, ".pk4")) {
+ fullpath = string_new_concat(path, i->c_str());
+ InitPakFile(archiveModules, fullpath);
+ string_release(fullpath, string_length(fullpath));
+ }
+ }
+ }
+ } else {
+ globalErrorStream() << "vfs directory not found: " << path << "\n";
+ }
+ }
}
// frees all memory that we allocated
// FIXME TTimo this should be improved so that we can shutdown and restart the VFS without exiting Radiant?
// (for instance when modifying the project settings)
-void Shutdown(){
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- ( *i ).archive->release();
- }
- g_archives.clear();
-
- g_numDirs = 0;
- g_numForbiddenDirs = 0;
-
- g_pakfile_paths.clear();
- g_loaded_dpk_paks.clear();
+void Shutdown()
+{
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ (*i).archive->release();
+ }
+ g_archives.clear();
+
+ g_numDirs = 0;
+ g_numForbiddenDirs = 0;
+
+ g_pakfile_paths.clear();
+ g_loaded_dpk_paks.clear();
}
-#define VFS_SEARCH_PAK 0x1
-#define VFS_SEARCH_DIR 0x2
+const int VFS_SEARCH_PAK = 0x1;
+const int VFS_SEARCH_DIR = 0x2;
-int GetFileCount( const char *filename, int flag ){
- int count = 0;
- char fixed[PATH_MAX + 1];
+int GetFileCount(const char *filename, int flag)
+{
+ int count = 0;
+ char fixed[PATH_MAX + 1];
- strncpy( fixed, filename, PATH_MAX );
- fixed[PATH_MAX] = '\0';
- FixDOSName( fixed );
+ strncpy(fixed, filename, PATH_MAX);
+ fixed[PATH_MAX] = '\0';
+ FixDOSName(fixed);
- if ( !flag ) {
- flag = VFS_SEARCH_PAK | VFS_SEARCH_DIR;
- }
+ if (!flag) {
+ flag = VFS_SEARCH_PAK | VFS_SEARCH_DIR;
+ }
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- if ( ( *i ).is_pakfile && ( flag & VFS_SEARCH_PAK ) != 0
- || !( *i ).is_pakfile && ( flag & VFS_SEARCH_DIR ) != 0 ) {
- if ( ( *i ).archive->containsFile( fixed ) ) {
- ++count;
- }
- }
- }
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ if (((*i).is_pakfile && (flag & VFS_SEARCH_PAK) != 0)
+ || (!(*i).is_pakfile && (flag & VFS_SEARCH_DIR) != 0)) {
+ if ((*i).archive->containsFile(fixed)) {
+ ++count;
+ }
+ }
+ }
- return count;
+ return count;
}
-ArchiveFile* OpenFile( const char* filename ){
- ASSERT_MESSAGE( strchr( filename, '\\' ) == 0, "path contains invalid separator '\\': \"" << filename << "\"" );
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- ArchiveFile* file = ( *i ).archive->openFile( filename );
- if ( file != 0 ) {
- return file;
- }
- }
-
- return 0;
-}
+ArchiveFile *OpenFile(const char *filename)
+{
+ ASSERT_MESSAGE(strchr(filename, '\\') == 0, "path contains invalid separator '\\': \"" << filename << "\"");
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ ArchiveFile *file = (*i).archive->openFile(filename);
+ if (file != 0) {
+ return file;
+ }
+ }
-ArchiveTextFile* OpenTextFile( const char* filename ){
- ASSERT_MESSAGE( strchr( filename, '\\' ) == 0, "path contains invalid separator '\\': \"" << filename << "\"" );
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- ArchiveTextFile* file = ( *i ).archive->openTextFile( filename );
- if ( file != 0 ) {
- return file;
- }
- }
-
- return 0;
+ return 0;
}
-// NOTE: when loading a file, you have to allocate one extra byte and set it to \0
-std::size_t LoadFile( const char *filename, void **bufferptr, int index ){
- char fixed[PATH_MAX + 1];
+ArchiveTextFile *OpenTextFile(const char *filename)
+{
+ ASSERT_MESSAGE(strchr(filename, '\\') == 0, "path contains invalid separator '\\': \"" << filename << "\"");
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ ArchiveTextFile *file = (*i).archive->openTextFile(filename);
+ if (file != 0) {
+ return file;
+ }
+ }
- strncpy( fixed, filename, PATH_MAX );
- fixed[PATH_MAX] = '\0';
- FixDOSName( fixed );
+ return 0;
+}
- ArchiveFile* file = OpenFile( fixed );
+// NOTE: when loading a file, you have to allocate one extra byte and set it to \0
+std::size_t LoadFile(const char *filename, void **bufferptr, int index)
+{
+ char fixed[PATH_MAX + 1];
- if ( file != 0 ) {
- *bufferptr = malloc( file->size() + 1 );
- // we need to end the buffer with a 0
- ( (char*) ( *bufferptr ) )[file->size()] = 0;
+ strncpy(fixed, filename, PATH_MAX);
+ fixed[PATH_MAX] = '\0';
+ FixDOSName(fixed);
- std::size_t length = file->getInputStream().read( (InputStream::byte_type*)*bufferptr, file->size() );
- file->release();
- return length;
- }
+ ArchiveFile *file = OpenFile(fixed);
- *bufferptr = 0;
- return 0;
-}
+ if (file != 0) {
+ *bufferptr = malloc(file->size() + 1);
+ // we need to end the buffer with a 0
+ ((char *) (*bufferptr))[file->size()] = 0;
-void FreeFile( void *p ){
- free( p );
-}
+ std::size_t length = file->getInputStream().read((InputStream::byte_type *) *bufferptr, file->size());
+ file->release();
+ return length;
+ }
-GSList* GetFileList( const char *dir, const char *ext, std::size_t depth ){
- return GetListInternal( dir, ext, false, depth );
+ *bufferptr = 0;
+ return 0;
}
-GSList* GetDirList( const char *dir, std::size_t depth ){
- return GetListInternal( dir, 0, true, depth );
+void FreeFile(void *p)
+{
+ free(p);
}
-void ClearFileDirList( GSList **lst ){
- while ( *lst )
- {
- g_free( ( *lst )->data );
- *lst = g_slist_remove( *lst, ( *lst )->data );
- }
+GSList *GetFileList(const char *dir, const char *ext, std::size_t depth)
+{
+ return GetListInternal(dir, ext, false, depth);
}
-const char* FindFile( const char* relative ){
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- if ( ( *i ).archive->containsFile( relative ) ) {
- return ( *i ).name.c_str();
- }
- }
-
- return "";
+GSList *GetDirList(const char *dir, std::size_t depth)
+{
+ return GetListInternal(dir, 0, true, depth);
}
-const char* FindPath( const char* absolute ){
- const char *best = "";
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- if ( string_length( ( *i ).name.c_str() ) > string_length( best ) ) {
- if ( path_equal_n( absolute, ( *i ).name.c_str(), string_length( ( *i ).name.c_str() ) ) ) {
- best = ( *i ).name.c_str();
- }
- }
- }
-
- return best;
+void ClearFileDirList(GSList **lst)
+{
+ while (*lst) {
+ g_free((*lst)->data);
+ *lst = g_slist_remove(*lst, (*lst)->data);
+ }
}
-
-class Quake3FileSystem : public VirtualFileSystem
+const char *FindFile(const char *relative)
{
-public:
-void initDirectory( const char *path ){
- InitDirectory( path, FileSystemQ3API_getArchiveModules() );
-}
-void initialise(){
- ArchiveModules& archiveModules = FileSystemQ3API_getArchiveModules();
- bool is_dpk_vfs = GetArchiveTable( archiveModules, "dpk" );
-
- if ( is_dpk_vfs ) {
- const char* pakname;
- g_loaded_dpk_paks.clear();
-
- pakname = GetLatestDpkPakVersion( "tex-common" );
- if (pakname != NULL) {
- LoadDpkPakWithDeps( pakname );
- }
-
- // prevent VFS double start, for MapName="" and MapName="unnamed.map"
- if ( string_length( GlobalRadiant().getMapName() ) ){
- // load map's paks from DEPS
- char* mappakname = GetCurrentMapDpkPakName();
- if ( mappakname != NULL ) {
- LoadDpkPakWithDeps( mappakname );
- string_release( mappakname, string_length( mappakname ) );
- }
- }
-
- g_pakfile_paths.clear();
- g_loaded_dpk_paks.clear();
- }
-
- globalOutputStream() << "filesystem initialised\n";
- g_observers.realise();
-}
-void shutdown(){
- g_observers.unrealise();
- globalOutputStream() << "filesystem shutdown\n";
- Shutdown();
-}
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ if ((*i).archive->containsFile(relative)) {
+ return (*i).name.c_str();
+ }
+ }
-int getFileCount( const char *filename, int flags ){
- return GetFileCount( filename, flags );
-}
-ArchiveFile* openFile( const char* filename ){
- return OpenFile( filename );
+ return "";
}
-ArchiveTextFile* openTextFile( const char* filename ){
- return OpenTextFile( filename );
-}
-std::size_t loadFile( const char *filename, void **buffer ){
- return LoadFile( filename, buffer, 0 );
-}
-void freeFile( void *p ){
- FreeFile( p );
-}
-
-void forEachDirectory( const char* basedir, const FileNameCallback& callback, std::size_t depth ){
- GSList* list = GetDirList( basedir, depth );
-
- for ( GSList* i = list; i != 0; i = g_slist_next( i ) )
- {
- callback( reinterpret_cast<const char*>( ( *i ).data ) );
- }
- ClearFileDirList( &list );
-}
-void forEachFile( const char* basedir, const char* extension, const FileNameCallback& callback, std::size_t depth ){
- GSList* list = GetFileList( basedir, extension, depth );
-
- for ( GSList* i = list; i != 0; i = g_slist_next( i ) )
- {
- const char* name = reinterpret_cast<const char*>( ( *i ).data );
- if ( extension_equal( path_get_extension( name ), extension ) ) {
- callback( name );
- }
- }
-
- ClearFileDirList( &list );
-}
-GSList* getDirList( const char *basedir ){
- return GetDirList( basedir, 1 );
-}
-GSList* getFileList( const char *basedir, const char *extension ){
- return GetFileList( basedir, extension, 1 );
-}
-void clearFileDirList( GSList **lst ){
- ClearFileDirList( lst );
-}
+const char *FindPath(const char *absolute)
+{
+ const char *best = "";
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ if (string_length((*i).name.c_str()) > string_length(best)) {
+ if (path_equal_n(absolute, (*i).name.c_str(), string_length((*i).name.c_str()))) {
+ best = (*i).name.c_str();
+ }
+ }
+ }
-const char* findFile( const char *name ){
- return FindFile( name );
-}
-const char* findRoot( const char *name ){
- return FindPath( name );
+ return best;
}
-void attach( ModuleObserver& observer ){
- g_observers.attach( observer );
-}
-void detach( ModuleObserver& observer ){
- g_observers.detach( observer );
-}
-Archive* getArchive( const char* archiveName, bool pakonly ){
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- if ( pakonly && !( *i ).is_pakfile ) {
- continue;
- }
-
- if ( path_equal( ( *i ).name.c_str(), archiveName ) ) {
- return ( *i ).archive;
- }
- }
- return 0;
-}
-void forEachArchive( const ArchiveNameCallback& callback, bool pakonly, bool reverse ){
- if ( reverse ) {
- g_archives.reverse();
- }
-
- for ( archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i )
- {
- if ( pakonly && !( *i ).is_pakfile ) {
- continue;
- }
-
- callback( ( *i ).name.c_str() );
- }
-
- if ( reverse ) {
- g_archives.reverse();
- }
-}
+class Quake3FileSystem : public VirtualFileSystem {
+public:
+ void initDirectory(const char *path)
+ {
+ InitDirectory(path, FileSystemQ3API_getArchiveModules());
+ }
+
+ void initialise()
+ {
+ load();
+ globalOutputStream() << "filesystem initialised\n";
+ g_observers.realise();
+ }
+
+ void load()
+ {
+ ArchiveModules &archiveModules = FileSystemQ3API_getArchiveModules();
+ bool is_dpk_vfs = GetArchiveTable(archiveModules, "dpk");
+
+ if (is_dpk_vfs) {
+ const char *pakname;
+ g_loaded_dpk_paks.clear();
+
+ // Load DEPS from game pack
+ LoadDpkPakWithDeps(NULL);
+
+ // prevent VFS double start, for MapName="" and MapName="unnamed.map"
+ if (string_length(GlobalRadiant().getMapName())) {
+ // load map's paks from DEPS
+ char *mappakname = GetCurrentMapDpkPakName();
+ if (mappakname != NULL) {
+ LoadDpkPakWithDeps(mappakname);
+ string_release(mappakname, string_length(mappakname));
+ }
+ }
+
+ g_pakfile_paths.clear();
+ g_loaded_dpk_paks.clear();
+ }
+ }
+
+ void clear()
+ {
+ // like shutdown() but does not unrealise (keep map etc.)
+ Shutdown();
+ }
+
+ void refresh()
+ {
+ // like initialise() but does not realise (keep map etc.)
+ load();
+ globalOutputStream() << "filesystem refreshed\n";
+ }
+
+ void shutdown()
+ {
+ g_observers.unrealise();
+ globalOutputStream() << "filesystem shutdown\n";
+ Shutdown();
+ }
+
+ int getFileCount(const char *filename, int flags)
+ {
+ return GetFileCount(filename, flags);
+ }
+
+ ArchiveFile *openFile(const char *filename)
+ {
+ return OpenFile(filename);
+ }
+
+ ArchiveTextFile *openTextFile(const char *filename)
+ {
+ return OpenTextFile(filename);
+ }
+
+ std::size_t loadFile(const char *filename, void **buffer)
+ {
+ return LoadFile(filename, buffer, 0);
+ }
+
+ void freeFile(void *p)
+ {
+ FreeFile(p);
+ }
+
+ void forEachDirectory(const char *basedir, const FileNameCallback &callback, std::size_t depth)
+ {
+ GSList *list = GetDirList(basedir, depth);
+
+ for (GSList *i = list; i != 0; i = g_slist_next(i)) {
+ callback(reinterpret_cast<const char *>((*i).data ));
+ }
+
+ ClearFileDirList(&list);
+ }
+
+ void forEachFile(const char *basedir, const char *extension, const FileNameCallback &callback, std::size_t depth)
+ {
+ GSList *list = GetFileList(basedir, extension, depth);
+
+ for (GSList *i = list; i != 0; i = g_slist_next(i)) {
+ const char *name = reinterpret_cast<const char *>((*i).data );
+ if (extension_equal(path_get_extension(name), extension)) {
+ callback(name);
+ }
+ }
+
+ ClearFileDirList(&list);
+ }
+
+ GSList *getDirList(const char *basedir)
+ {
+ return GetDirList(basedir, 1);
+ }
+
+ GSList *getFileList(const char *basedir, const char *extension)
+ {
+ return GetFileList(basedir, extension, 1);
+ }
+
+ void clearFileDirList(GSList **lst)
+ {
+ ClearFileDirList(lst);
+ }
+
+ const char *findFile(const char *name)
+ {
+ return FindFile(name);
+ }
+
+ const char *findRoot(const char *name)
+ {
+ return FindPath(name);
+ }
+
+ void attach(ModuleObserver &observer)
+ {
+ g_observers.attach(observer);
+ }
+
+ void detach(ModuleObserver &observer)
+ {
+ g_observers.detach(observer);
+ }
+
+ Archive *getArchive(const char *archiveName, bool pakonly)
+ {
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ if (pakonly && !(*i).is_pakfile) {
+ continue;
+ }
+
+ if (path_equal((*i).name.c_str(), archiveName)) {
+ return (*i).archive;
+ }
+ }
+ return 0;
+ }
+
+ void forEachArchive(const ArchiveNameCallback &callback, bool pakonly, bool reverse)
+ {
+ if (reverse) {
+ g_archives.reverse();
+ }
+
+ for (archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) {
+ if (pakonly && !(*i).is_pakfile) {
+ continue;
+ }
+
+ callback((*i).name.c_str());
+ }
+
+ if (reverse) {
+ g_archives.reverse();
+ }
+ }
};
Quake3FileSystem g_Quake3FileSystem;
-VirtualFileSystem& GetFileSystem(){
- return g_Quake3FileSystem;
+VirtualFileSystem &GetFileSystem()
+{
+ return g_Quake3FileSystem;
}
-void FileSystem_Init(){
+void FileSystem_Init()
+{
}
-void FileSystem_Shutdown(){
+void FileSystem_Shutdown()
+{
}