Files
itgmania212121/stepmania/src/RageFileManager.cpp
T

288 lines
7.7 KiB
C++
Raw Normal View History

2003-12-04 08:25:59 +00:00
#include "global.h"
#include "RageFileManager.h"
#include "RageFileDriver.h"
#include "RageUtil.h"
2003-12-04 08:25:59 +00:00
#include <errno.h>
RageFileManager *FILEMAN = NULL;
struct LoadedDriver
{
/* A loaded driver may have a base path, which modifies the path we
* pass to the driver. For example, if the base is "Songs/", and we
* want to send the path "Songs/Foo/Bar" to it, then we actually
* only send "Foo/Bar". The path "Themes/Foo" is out of the scope
* of the driver, and GetPath returns false. */
RageFileDriver *driver;
2003-12-05 00:07:18 +00:00
CString MountPoint;
2003-12-04 08:25:59 +00:00
CString GetPath( CString path );
};
static vector<LoadedDriver> g_Drivers;
RageFileManager::RageFileManager()
{
#if defined(XBOX)
2003-12-05 00:07:18 +00:00
RageFileManager::Mount( "dir", ".", "" );
2003-12-04 08:25:59 +00:00
/* XXX: drop BASE_PATH and do this instead */
2003-12-05 00:07:18 +00:00
// RageFileManager::Mount( "dir", "D:\\", "" );
2003-12-04 08:25:59 +00:00
#else
/* Paths relative to the CWD: */
2003-12-05 00:07:18 +00:00
RageFileManager::Mount( "dir", ".", "" );
2003-12-04 08:25:59 +00:00
/* Absolute paths. This is rarely used, eg. by Alsa9Buf::GetSoundCardDebugInfo(). */
2003-12-05 00:07:18 +00:00
RageFileManager::Mount( "dir", "/", "/" );
2003-12-04 08:25:59 +00:00
#endif
#if defined(WIN32)
/* Temporary hack for accessing files by drive letter. */
for( char c = 'A'; c <= 'Z'; ++c )
{
const CString path = ssprintf( "%c:/", c );
2003-12-05 00:07:18 +00:00
RageFileManager::Mount( "dir", path, path );
}
#endif
2003-12-04 08:25:59 +00:00
}
RageFileManager::~RageFileManager()
{
/* Note that drivers can use previously-loaded drivers, eg. to load a ZIP
* from the FS. Unload drivers in reverse order. */
for( int i = g_Drivers.size()-1; i >= 0; --i )
delete g_Drivers[i].driver;
}
CString LoadedDriver::GetPath( CString path )
{
2003-12-05 00:07:18 +00:00
/* If the path begins with @, default mount points don't count. */
const bool Dedicated = ( path.size() && path[0] == '@' );
if( MountPoint.size() == 0 )
return Dedicated? "":path;
2003-12-04 08:25:59 +00:00
/* Map all slashes to forward slash. */
path.Replace( "\\", "/" );
2003-12-05 00:07:18 +00:00
if( path.Left( MountPoint.size() ).CompareNoCase( MountPoint ) )
2003-12-04 08:25:59 +00:00
return ""; /* no match */
2003-12-05 00:07:18 +00:00
return path.Right( path.size() - MountPoint.size() );
2003-12-04 08:25:59 +00:00
}
2003-12-05 02:25:32 +00:00
void RageFileManager::GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
LoadedDriver &ld = g_Drivers[i];
const CString p = ld.GetPath( sPath );
if( p.size() == 0 )
continue;
const unsigned OldStart = AddTo.size();
g_Drivers[i].driver->GetDirListing( p, AddTo, bOnlyDirs, bReturnPathToo );
/* If returning the path, prepend the mountpoint name to the files this driver returned. */
if( bReturnPathToo )
for( unsigned j = OldStart; j < AddTo.size(); ++j )
AddTo[j] = ld.MountPoint + AddTo[j];
}
}
2003-12-04 08:25:59 +00:00
#include "RageFileDriverDirect.h"
2003-12-05 00:07:18 +00:00
void RageFileManager::Mount( CString Type, CString Root, CString MountPoint )
2003-12-04 08:25:59 +00:00
{
2003-12-05 00:07:18 +00:00
if( MountPoint.size() && MountPoint.Right(1) != "/" )
MountPoint += '/';
2003-12-04 08:25:59 +00:00
ASSERT( Root != "" );
if( Root.Right(1) != "/" )
Root += '/';
RageFileDriver *driver = NULL;
if( !Type.CompareNoCase("DIR") )
{
driver = new RageFileDriverDirect( Root );
}
if( !driver )
return;
LoadedDriver ld;
ld.driver = driver;
2003-12-05 00:07:18 +00:00
ld.MountPoint = MountPoint;
2003-12-04 08:25:59 +00:00
g_Drivers.push_back( ld );
}
2003-12-05 00:07:18 +00:00
bool RageFileManager::IsMounted( CString MountPoint )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
if( !g_Drivers[i].MountPoint.CompareNoCase( MountPoint ) )
return true;
return false;
}
/* Return true if the driver with the given root path is ready (eg. CD or memory card
* inserted). */
bool RageFileManager::MountpointIsReady( CString MountPoint )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
if( g_Drivers[i].MountPoint.CompareNoCase( MountPoint ) )
continue;
return g_Drivers[i].driver->Ready();
}
return false;
}
2003-12-04 08:25:59 +00:00
RageFileManager::FileType RageFileManager::GetFileType( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
FileType ret = g_Drivers[i].driver->GetFileType( p );
if( ret != TYPE_NONE )
return ret;
}
return TYPE_NONE;
}
int RageFileManager::GetFileSizeInBytes( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
int ret = g_Drivers[i].driver->GetFileSizeInBytes( p );
if( ret != -1 )
return ret;
}
return -1;
}
int RageFileManager::GetFileModTime( const CString &sPath )
{
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString p = g_Drivers[i].GetPath( sPath );
if( p.size() == 0 )
continue;
int ret = g_Drivers[i].driver->GetFileModTime( p );
if( ret != -1 )
return ret;
}
return -1;
}
2003-12-05 02:25:32 +00:00
static bool SortBySecond( const pair<int,int> &a, const pair<int,int> &b )
{
return a.second < b.second;
}
2003-12-04 08:25:59 +00:00
/* Used only by RageFile: */
RageFileObj *RageFileManager::Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err )
{
err = ENOENT;
2003-12-05 02:25:32 +00:00
/* If writing, we need to do a heuristic to figure out which driver to write with--there
* may be several that will work. */
if( mode == RageFile::WRITE )
return OpenForWriting( sPath, mode, p, err );
2003-12-04 08:25:59 +00:00
/* XXX: WRITE logic */
for( unsigned i = 0; i < g_Drivers.size(); ++i )
{
const CString path = g_Drivers[i].GetPath( sPath );
if( path.size() == 0 )
continue;
int error;
RageFileObj *ret = g_Drivers[i].driver->Open( path, mode, p, error );
if( ret )
return ret;
/* ENOENT (File not found) is low-priority: if some other error
* was reported, return that instead. */
if( error != ENOENT )
err = error;
}
return NULL;
}
2003-12-05 02:25:32 +00:00
RageFileObj *RageFileManager::OpenForWriting( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err )
{
/*
* The value for a driver to open a file is the number of directories and/or files
* that would have to be created in order to write it, or 0 if the file already exists.
* For example, if we're opening "foo/bar/baz.txt", and only "foo/" exists in a
* driver, we'd have to create the "bar" directory and the "baz.txt" file, so the
* value is 2. If "foo/bar/" exists, we'd only have to create the file, so the
* value is 1. Create the file with the driver that returns the lowest value;
* in case of a tie, earliest-loaded driver wins.
*
* The purpose of this is to create files in the expected place. For example, if we
* have both C:/games/StepMania and C:/games/DWI loaded, and we're writing
* "Songs/Music/Waltz/waltz.sm", and the song was loaded out of
* "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SM into the
* same directory (if possible). Don't split up files in the same directory any
* more than we have to.
*
* If the given path can not be created, return -1. This happens if a path
* that needs to be a directory is a file, or vice versa.
*/
vector< pair<int,int> > Values;
unsigned i;
for( i = 0; i < g_Drivers.size(); ++i )
{
LoadedDriver &ld = g_Drivers[i];
const CString path = ld.GetPath( sPath );
if( path.size() == 0 )
continue;
const int value = ld.driver->GetPathValue( path );
if( value == -1 )
continue;
Values.push_back( pair<int,int>( i, value ) );
}
if( !Values.size() )
{
err = EEXIST;
return NULL;
}
stable_sort( Values.begin(), Values.end(), SortBySecond );
int error = 0;
for( i = 0; i < Values.size(); ++i )
{
const int driver = Values[i].first;
LoadedDriver &ld = g_Drivers[driver];
const CString path = ld.GetPath( sPath );
ASSERT( path.size() );
RageFileObj *ret = ld.driver->Open( path, mode, p, error );
if( ret )
return ret;
}
err = error;
return NULL;
}
2003-12-04 08:25:59 +00:00
bool RageFileManager::IsAFile( const CString &sPath ) { return GetFileType(sPath) == TYPE_FILE; }
bool RageFileManager::IsADirectory( const CString &sPath ) { return GetFileType(sPath) == TYPE_DIR; }
bool RageFileManager::DoesFileExist( const CString &sPath ) { return GetFileType(sPath) != TYPE_NONE; }