]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/vfspk3/vfs.cpp
fix include
[xonotic/netradiant.git] / plugins / vfspk3 / vfs.cpp
index ea786030ce495a9cc46bf632f26ca741f79eb8d4..44c2ebb5290630fe13f17d1415773c27f55dc8eb 100644 (file)
@@ -42,6 +42,7 @@
 //
 
 #include "vfs.h"
+#include "globaldefs.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,11 +60,12 @@ ArchiveModules& FileSystemQ3API_getArchiveModules();
 #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
 
@@ -126,13 +128,12 @@ static void FixDOSName( char *src ){
        }
 }
 
-
-
 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 ) );
 
@@ -143,7 +144,7 @@ static Archive* InitPakFile( ArchiveModules& archiveModules, const char *filenam
                entry.archive = table->m_pfnOpenArchive( filename );
                entry.is_pakfile = true;
                g_archives.push_back( entry );
-               globalOutputStream() << "  pak file: " << filename << "\n";
+               globalOutputStream() << "pak file: " << filename << "\n";
 
                return entry.archive;
        }
@@ -281,9 +282,10 @@ bool operator()( const CopiedString& self, const CopiedString& other ) const {
 
 typedef std::set<CopiedString, PakLess> Archives;
 
-Archive* AddPk3Dir( const char* fullpath ){
+Archive* AddPakDir( const char* fullpath ){
        if ( g_numDirs == VFS_MAXDIRS ) return 0;
 
+       globalOutputStream() << "pak directory: " << fullpath << "\n";
        strncpy( g_strDirs[g_numDirs], fullpath, PATH_MAX );
        g_strDirs[g_numDirs][PATH_MAX] = '\0';
        g_numDirs++;
@@ -299,16 +301,16 @@ Archive* AddPk3Dir( const char* fullpath ){
        }
 }
 
-// for unvanquished
+// for Daemon DPK VFS
 
-bool IsUnvanquished(){
-       return strncmp( GlobalRadiant().getGameFile(), "unvanquished", 12 ) == 0;
+Archive* AddDpkDir( const char* fullpath ){
+       return AddPakDir( fullpath );
 }
 
 struct pakfile_path_t
 {
        CopiedString fullpath;  // full pak dir or pk3dir name
-       bool is_pakfile;  // defines is it .pk3dir or .pk3 file
+       bool is_pakfile;  // tells it is .pk3dir or .pk3 file
 };
 
 typedef std::pair<CopiedString, pakfile_path_t> PakfilePathsKV;
@@ -316,69 +318,15 @@ typedef std::map<CopiedString, pakfile_path_t> PakfilePaths;  // key must have n
 
 static PakfilePaths g_pakfile_paths;
 
-void AddUnvPak( const char* name, const char* fullpath, bool is_pakfile ){
+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;
-}
-
 // takes name without ext, returns without ext
-static const char* GetLatestVersionOfUnvPak( const char* name ){
+static const char* GetLatestDpkPakVersion( const char* name ){
        const char* maxversion = 0;
        const char* result = 0;
        const char* pakname;
@@ -390,7 +338,7 @@ static const char* GetLatestVersionOfUnvPak( const char* name ){
                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 ){
+               if ( maxversion == 0 || DpkPakVersionCmp( pakversion, maxversion ) > 0 ){
                        maxversion = pakversion;
                        result = pakname;
                }
@@ -399,7 +347,7 @@ static const char* GetLatestVersionOfUnvPak( const char* name ){
 }
 
 // release string after using
-static char* GetCurrentMapPakName(){
+static char* GetCurrentMapDpkPakName(){
        char* mapdir;
        char* mapname;
        int mapnamelen;
@@ -411,7 +359,7 @@ static char* GetCurrentMapPakName(){
        mapdir = strrchr( mapname, '/' );
        if ( mapdir ) {
                mapdir -= 12;
-               if ( strncmp( mapdir, ".pk3dir/maps/", 13 ) == 0 ) {
+               if ( strncmp( mapdir, ".dpkdir/maps/", 13 ) == 0 ) {
                        *mapdir = '\0';
                        mapdir = strrchr( mapname, '/' );
                        if ( mapdir ) mapdir++;
@@ -426,73 +374,76 @@ static char* GetCurrentMapPakName(){
 }
 
 // prevent loading duplicates or circular references
-static Archives g_loaded_unv_paks;
+static Archives g_loaded_dpk_paks;
 
 // actual pak adding on initialise, deferred from InitDirectory
-// Unvanquished filesystem doesn't need load all paks it finds
-static void LoadPakWithDeps( const char* pakname ){
-       const char* und = strrchr( pakname, '_' );
-       if ( !und ) pakname = GetLatestVersionOfUnvPak( pakname );
-       if ( !pakname || g_loaded_unv_paks.find( pakname ) != g_loaded_unv_paks.end() ) return;
-
-       PakfilePaths::iterator i = g_pakfile_paths.find( pakname );
-       if ( i == g_pakfile_paths.end() ) return;
-
+// Daemon DPK filesystem doesn't need load all paks it finds
+static void LoadDpkPakWithDeps( const char* pakname ){
        Archive* arc;
-       if ( i->second.is_pakfile ){
-               arc = InitPakFile( FileSystemQ3API_getArchiveModules(), i->second.fullpath.c_str() );
+       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 {
-               arc = AddPk3Dir( i->second.fullpath.c_str() );
+               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" );
        }
-       g_loaded_unv_paks.insert( pakname );
 
-       ArchiveTextFile* depsFile = arc->openTextFile( "DEPS" );
-       if ( !depsFile ) return;
+       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;
+               char *p_name;
+               char *p_version;
                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 = GetLatestVersionOfUnvPak( name_final.c_str() );
-                               if ( !p_pakname ) continue;
-                               LoadPakWithDeps( p_pakname );
+                       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 = ( p_name_end - p_name ) + ( p_version_end - p_version ) + 1;
+                               int len = string_length( p_name ) + string_length( 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 );
-                               LoadPakWithDeps( p_pakname );
+                               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 unvanquished
+// end for Daemon DPK vfs
 
 // =============================================================================
 // Global functions
@@ -503,6 +454,7 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
 
        g_numForbiddenDirs = 0;
        StringTokeniser st( GlobalRadiant().getGameDescriptionKeyValue( "forbidden_paths" ), " " );
+
        for ( j = 0; j < VFS_MAXDIRS; ++j )
        {
                const char *t = st.getToken();
@@ -528,6 +480,7 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                }
                g_free( dbuf );
        }
+
        if ( j < g_numForbiddenDirs ) {
                printf( "Directory %s matched by forbidden dirs, removed\n", directory );
                return;
@@ -558,16 +511,22 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
 
                GDir* dir = g_dir_open( path, 0, 0 );
 
-               if ( dir != 0 ) {
+               if ( dir != NULL ) {
                        globalOutputStream() << "vfs directory: " << path << "\n";
 
-                       bool unv;
-                       unv = IsUnvanquished();
-
+                       Archives archives;
+                       Archives archivesOverride;
                        const char* ignore_prefix = "";
                        const char* override_prefix = "";
+                       bool is_wad_vfs, is_pak_vfs, is_pk3_vfs, is_pk4_vfs, is_dpk_vfs;
 
-                       if ( !unv ) {
+                       is_wad_vfs = !!GetArchiveTable( archiveModules, "wad" );
+                       is_pak_vfs = !!GetArchiveTable( archiveModules, "pak" );
+                       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();
 
@@ -581,12 +540,11 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                }
                        }
 
-                       Archives archives;
-                       Archives archivesOverride;
-                       for (;; )
+                       while ( true )
                        {
                                const char* name = g_dir_read_name( dir );
-                               if ( name == 0 ) {
+
+                               if ( name == nullptr ) {
                                        break;
                                }
 
@@ -598,28 +556,36 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                                break;
                                        }
                                }
+
                                if ( j < g_numForbiddenDirs ) {
                                        continue;
                                }
 
                                const char *ext = strrchr( name, '.' );
-                               char tmppath[PATH_MAX];
-
-                               if ( ext && !string_compare_nocase_upper( ext, ".pk3dir" ) ) {
-
-                                       snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
-                                       tmppath[PATH_MAX] = '\0';
-                                       FixDOSName( tmppath );
-                                       AddSlash( tmppath );
+                               char tmppath[PATH_MAX + 1];
+
+                               if ( ext != nullptr ) {
+                                       if ( is_dpk_vfs && !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 ( unv ) {
-                                               AddUnvPak( CopiedString( StringRange( name, ext ) ).c_str(), tmppath, false );
-                                       } else {
-                                               AddPk3Dir( tmppath );
+                                       else if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".pakdir" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3dir" ) )
+                                               || ( is_pk4_vfs && !string_compare_nocase_upper( ext, ".pk4dir" ) ) ) {
+                                               snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
+                                               tmppath[PATH_MAX] = '\0';
+                                               FixDOSName( tmppath );
+                                               AddSlash( tmppath );
+                                               AddPakDir( tmppath );
                                        }
                                }
 
-                               if ( ( ext == 0 ) || *( ++ext ) == '\0' || GetArchiveTable( archiveModules, ext ) == 0 ) {
+                               // GetArchiveTable() needs "pk3" if ext is ".pk3"
+                               if ( ( ext == nullptr ) || *( ext + 1 ) == '\0' || GetArchiveTable( archiveModules, ext + 1 ) == 0 ) {
                                        continue;
                                }
 
@@ -627,13 +593,18 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                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 ( unv ) {
-                                               archives.insert( name );
-                                       } else {
+                                       if ( !string_compare_nocase_upper( ext, ".dpk" ) ) {
+                                               if ( is_dpk_vfs ) {
+                                                       archives.insert( name );
+                                                       continue;
+                                               }
+                                       }
+                                       else {
                                                archivesOverride.insert( name );
+                                               continue;
                                        }
-                                       continue;
                                }
 
                                archives.insert( name );
@@ -643,27 +614,47 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
 
                        // add the entries to the vfs
                        char* fullpath;
-                       if ( unv ) {
+                       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, '.' );
-                                       CopiedString name_final = CopiedString( StringRange( name, ext ) );
-                                       fullpath = string_new_concat( path, name );
-                                       AddUnvPak( name_final.c_str(), fullpath, true );
-                                       string_release( fullpath, string_length( fullpath ) );
+                                       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 ) );
+                                       }
                                }
-                       } else {
+                       }
+                       else
+                       {
                                for ( Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i )
                                {
-                                       fullpath = string_new_concat( path, i->c_str() );
-                                       InitPakFile( archiveModules, fullpath );
-                                       string_release( fullpath, string_length( fullpath ) );
+                                       const char* name = i->c_str();
+                                       const char* ext = strrchr( name, '.' );
+                                       if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".wad" ) )
+                                               || ( is_pak_vfs && !string_compare_nocase_upper( ext, ".pak" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3" ) )
+                                               || ( is_pk4_vfs && !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 )
                                {
-                                       fullpath = string_new_concat( path, i->c_str() );
-                                       InitPakFile( archiveModules, fullpath );
-                                       string_release( fullpath, string_length( fullpath ) );
+                                       const char* name = i->c_str();
+                                       const char* ext = strrchr( name, '.' );
+                                       if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".wad" ) )
+                                               || ( is_pak_vfs && !string_compare_nocase_upper( ext, ".pak" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3" ) )
+                                               || ( is_pk4_vfs && !string_compare_nocase_upper( ext, ".pk4" ) ) ) {
+                                               fullpath = string_new_concat( path, i->c_str() );
+                                               InitPakFile( archiveModules, fullpath );
+                                               string_release( fullpath, string_length( fullpath ) );
+                                       }
                                }
                        }
                }
@@ -688,11 +679,11 @@ void Shutdown(){
        g_numForbiddenDirs = 0;
 
        g_pakfile_paths.clear();
-       g_loaded_unv_paks.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;
@@ -708,8 +699,8 @@ int GetFileCount( const char *filename, int flag ){
 
        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 ).is_pakfile && ( flag & VFS_SEARCH_PAK ) != 0)
+                        || (!( *i ).is_pakfile && ( flag & VFS_SEARCH_DIR ) != 0) ) {
                        if ( ( *i ).archive->containsFile( fixed ) ) {
                                ++count;
                        }
@@ -822,44 +813,48 @@ void initDirectory( const char *path ){
        InitDirectory( path, FileSystemQ3API_getArchiveModules() );
 }
 void initialise(){
-       if ( IsUnvanquished() ) {
+       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_unv_paks.clear();
+               g_loaded_dpk_paks.clear();
 
-               pakname = GetLatestVersionOfUnvPak( "radiant" );
-               if ( pakname ) LoadPakWithDeps( pakname );
+               // Load DEPS from game pack
+               LoadDpkPakWithDeps( NULL );
 
                // prevent VFS double start, for MapName="" and MapName="unnamed.map"
                if ( string_length( GlobalRadiant().getMapName() ) ){
-                       // map's tex-* paks have precedence over any other tex-* paks
-                       char* mappakname = GetCurrentMapPakName();
-                       if ( mappakname ) {
-                               LoadPakWithDeps( mappakname );
+                       // load map's paks from DEPS
+                       char* mappakname = GetCurrentMapDpkPakName();
+                       if ( mappakname != NULL ) {
+                               LoadDpkPakWithDeps( mappakname );
                                string_release( mappakname, string_length( mappakname ) );
                        }
-
-                       for ( PakfilePaths::iterator i = g_pakfile_paths.begin(); i != g_pakfile_paths.end(); ++i ) {
-                               if ( strncmp( i->first.c_str(), "tex-", 4 ) != 0 ) continue;
-                               // firstly load latest version of pak
-                               const char *paknamever = i->first.c_str();
-                               const char *c = strchr( paknamever, '_' );
-                               char *paknameonly;
-                               if ( c ) paknameonly = string_clone_range( StringRange( paknamever, c ) );
-                               pakname = GetLatestVersionOfUnvPak( paknameonly );
-                               LoadPakWithDeps( pakname );
-                               if ( c ) string_release( paknameonly, string_length( paknameonly ) );
-                               // then load this specific version
-                               LoadPakWithDeps( paknamever );
-                       }
                }
 
                g_pakfile_paths.clear();
-               g_loaded_unv_paks.clear();
+               g_loaded_dpk_paks.clear();
        }
+}
 
-       globalOutputStream() << "filesystem initialised\n";
-       g_observers.realise();
+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";
@@ -939,6 +934,9 @@ Archive* getArchive( const char* archiveName, bool pakonly ){
                if ( path_equal( ( *i ).name.c_str(), archiveName ) ) {
                        return ( *i ).archive;
                }
+               else if ( path_equal( path_get_filename_start( ( *i ).name.c_str() ), archiveName ) ) {
+                       return ( *i ).archive;
+               }
        }
        return 0;
 }