From ea0ba6fcb9d6951672b553f85abd8a988929514f Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 4 Dec 2003 08:25:59 +0000 Subject: [PATCH] VFS work --- stepmania/src/RageFile.cpp | 264 ++++++++++++++++++++----- stepmania/src/RageFile.h | 87 ++++---- stepmania/src/RageFileDriver.cpp | 65 ++++++ stepmania/src/RageFileDriver.h | 43 ++++ stepmania/src/RageFileDriverDirect.cpp | 165 ++++++++++++++++ stepmania/src/RageFileDriverDirect.h | 21 ++ stepmania/src/RageFileManager.cpp | 160 +++++++++++++++ stepmania/src/RageFileManager.h | 31 +++ stepmania/src/StepMania.cpp | 6 +- 9 files changed, 761 insertions(+), 81 deletions(-) create mode 100644 stepmania/src/RageFileDriver.cpp create mode 100644 stepmania/src/RageFileDriver.h create mode 100644 stepmania/src/RageFileDriverDirect.cpp create mode 100644 stepmania/src/RageFileDriverDirect.h create mode 100644 stepmania/src/RageFileManager.cpp create mode 100644 stepmania/src/RageFileManager.h diff --git a/stepmania/src/RageFile.cpp b/stepmania/src/RageFile.cpp index 354ea556dc..b8c9b7d3a4 100644 --- a/stepmania/src/RageFile.cpp +++ b/stepmania/src/RageFile.cpp @@ -7,14 +7,15 @@ Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved. Chris Danford - Steve Checkoway + Steve Checkoway + Glenn Maynard ----------------------------------------------------------------------------- */ #include "global.h" #include "RageFile.h" #include "RageUtil.h" - +#include "RageFileDriver.h" void FixSlashesInPlace( CString &sPath ) { @@ -31,45 +32,76 @@ CString FixSlashes( CString sPath ) void CollapsePath( CString &sPath ) { - CStringArray as; - split( sPath, SLASH, as ); - - for( unsigned i=0; iGetDisplayPath(); +} + bool RageFile::Open( const CString& path, RageFile::OpenMode mode ) { + ASSERT( FILEMAN ); + Close(); - mPath = path; - FixSlashesInPlace(mPath); - mFP = fopen( mPath, mode == READ? "r":"w" ); + + m_Path = path; + FixSlashesInPlace(m_Path); + + m_Mode = mode; + m_EOF = false; + m_FilePos = 0; ResetBuf(); - return mFP == NULL; + int error; + m_File = FILEMAN->Open( path, mode, *this, error ); + + if( m_File == NULL ) + { + SetError( strerror(error) ); + return false; + } + + return true; } void RageFile::Close() { - if (IsOpen()) - fclose(mFP); - - mFP = NULL; + delete m_File; + m_File = NULL; } void RageFile::ResetBuf() @@ -80,21 +112,37 @@ void RageFile::ResetBuf() /* Read up to the next \n, and return it in out. Strip the \n. If the \n is * preceded by a \r (DOS newline), strip that, too. */ -void RageFile::GetLine( CString &out ) +int RageFile::GetLine( CString &out ) { out = ""; - if (!IsOpen()) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); + if ( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", m_Path.c_str()); + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading", GetPath().c_str()); + + bool GotData = false; while( 1 ) { bool done = false; /* Find the end of the block we'll move to out. */ char *p = (char *) memchr( m_pBuf, '\n', m_BufUsed ); + bool ReAddCR = false; if( p == NULL ) + { + /* Hack: If the last character of the buffer is \r, then it's likely that an + * \r\n has been split across buffers. Move everything else, then move the + * \r to the beginning of the buffer and handle it the next time around the loop. */ + if( m_pBuf[m_BufUsed-1] == '\r' ) + { + ReAddCR = true; + --m_BufUsed; + } + p = m_pBuf+m_BufUsed; /* everything */ + } else done = true; @@ -107,22 +155,54 @@ void RageFile::GetLine( CString &out ) if( done ) ++p; /* skip \n */ - m_BufUsed -= p-m_pBuf; - m_pBuf = p; + + const int used = p-m_pBuf; + if( used ) + { + m_BufUsed -= used; + m_FilePos += used; + GotData = true; + m_pBuf = p; + } + } + + if( ReAddCR ) + { + ASSERT( m_BufUsed == 0 ); + m_pBuf = m_Buffer; + m_Buffer[m_BufUsed] = '\r'; + ++m_BufUsed; } if( done ) break; - /* We need more data. That implies that we moved everything. */ - ASSERT( !m_BufUsed ); + /* We need more data. */ m_pBuf = m_Buffer; - size_t size = Read( m_pBuf, sizeof(m_Buffer) ); - if( size <= 0 ) + const int size = m_File->Read( m_pBuf+m_BufUsed, sizeof(m_Buffer)-m_BufUsed ); + + /* If we've read data already, then don't mark EOF yet. Wait until the + * next time we're called. */ + if( size == 0 && !GotData ) + { + m_EOF = true; + return 0; + } + if( size < 0 ) + return -1; // error + if( size == 0 ) break; // EOF or error m_BufUsed += size; } + return GotData? 1:0; +} + +CString RageFile::GetLine() +{ + CString ret; + GetLine( ret ); + return ret; } #if defined(_WIN32) @@ -133,46 +213,142 @@ void RageFile::GetLine( CString &out ) int RageFile::PutLine( const CString &str ) { - if( Write(str.data(), str.size()) == -1 ) + if( Write(str) == -1 ) return -1; - return Write( NEWLINE, strlen(NEWLINE) ); + return Write( CString(NEWLINE) ); } + int RageFile::Read( void *buffer, size_t bytes ) { if( !IsOpen() ) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); + + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading", GetPath().c_str()); int ret = 0; int FromBuffer = min( (int) bytes, m_BufUsed ); memcpy( buffer, m_pBuf, FromBuffer ); + ret += FromBuffer; - buffer = (char *) buffer + FromBuffer; + m_FilePos += FromBuffer; bytes -= FromBuffer; + m_BufUsed -= FromBuffer; + m_pBuf += FromBuffer; + + buffer = (char *) buffer + FromBuffer; if( bytes ) { - int FromFile = fread( buffer, 1L, bytes, mFP ); + int FromFile = m_File->Read( buffer, bytes ); if( FromFile < 0 ) return -1; + if( FromFile == 0 ) + m_EOF = true; ret += FromFile; + m_FilePos += FromFile; } + return ret; } -int RageFile::Write(const void *buffer, size_t bytes) +int RageFile::Write( const void *buffer, size_t bytes ) { - if (!IsOpen()) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); - return fwrite(buffer, 1L, bytes, mFP); + if( m_Mode != WRITE ) + RageException::Throw("\"%s\" is not open for writing", GetPath().c_str()); + + return m_File->Write( buffer, bytes ); } -CString RageFile::GetLine() +int RageFile::Seek( int offset ) { - CString ret; - GetLine( ret ); - return ret; + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); + + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str()); + + m_EOF = false; + + /* If the new position is within the buffer, just eat the buffered data. */ + int FromBuffer = offset - m_FilePos; + if( 0 < FromBuffer && FromBuffer <= m_BufUsed ) + { + m_FilePos += FromBuffer; + m_BufUsed -= FromBuffer; + m_pBuf += FromBuffer; + + return m_FilePos; + } + + /* It's not. Clear the buffer and do a real seek. */ + ResetBuf(); + + int pos = m_File->Seek( offset ); + if( pos == -1 ) + return -1; + + m_FilePos = pos; + return pos; } +int RageFile::SeekCur( int offset ) +{ + ASSERT( offset >= 0 ); + + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); + + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str()); + + if( !offset || m_EOF ) + return m_FilePos; + + int FromBuffer = min( offset, m_BufUsed ); + m_FilePos += FromBuffer; + offset -= FromBuffer; + m_BufUsed -= FromBuffer; + m_pBuf += FromBuffer; + + if( offset ) + { + int pos = m_File->SeekCur( offset ); + if( pos == -1 ) + return -1; + + m_FilePos = pos; + } + return m_FilePos; +} + +int RageFile::GetFileSize() +{ + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); + + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading; can't GetFileSize", GetPath().c_str()); + + return m_File->GetFileSize(); +} + +void RageFile::Rewind() +{ + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", GetPath().c_str()); + + if( m_Mode != READ ) + RageException::Throw("\"%s\" is not open for reading; can't GetFileSize", GetPath().c_str()); + + m_EOF = false; + + m_File->Rewind(); +} + + diff --git a/stepmania/src/RageFile.h b/stepmania/src/RageFile.h index c78e4d4cdc..10f0b034ca 100644 --- a/stepmania/src/RageFile.h +++ b/stepmania/src/RageFile.h @@ -7,61 +7,76 @@ Desc: Encapsulates C and C++ file classes to deal with arch-specific oddities. - Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. + Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved. Chris Danford Steve Checkoway + Glenn Maynard ----------------------------------------------------------------------------- */ -#include - // call FixSlashes on any path that came from the user void FixSlashesInPlace( CString &sPath ); CString FixSlashes( CString sPath ); - void CollapsePath( CString &sPath ); +class RageFileObj; class RageFile { + friend class RageFileObj; + +public: + enum OpenMode { READ, WRITE }; + RageFile(); + RageFile( const CString& path, OpenMode mode = READ ); + ~RageFile() { Close(); } + + const CString &GetRealPath() const { return m_Path; } + CString GetPath() const; + + bool Open( const CString& path, OpenMode mode = READ ); + void Close(); + + bool IsOpen() const { return m_File != NULL; } + bool AtEOF() const { return m_EOF; } + CString GetError() const { return m_Error; } + void ClearError() { m_Error = ""; } + + int Tell() const { return m_FilePos; } + int Seek( int offset ); + int SeekCur( int offset ); + int GetFileSize(); + void Rewind(); + + /* Raw I/O: */ + int Write( const void *buffer, size_t bytes ); + int Write( const CString& string ) { return Write( string.data(), string.size() ); } + int Read( void *buffer, size_t bytes ); + int Read( const CString &buffer, size_t bytes ); + + /* Line-based I/O: */ + CString GetLine(); + int GetLine( CString &out ); + int PutLine( const CString &str ); + +protected: + void SetError( const CString &err ) { m_Error = err; } /* called by RageFileObj::SetError */ + private: - FILE *mFP; - CString mPath; + void ResetBuf(); + + RageFileObj *m_File; + CString m_Path; + OpenMode m_Mode; + + CString m_Error; + bool m_EOF; + int m_FilePos; enum { BSIZE = 256 }; char m_Buffer[BSIZE]; char *m_pBuf; int m_BufUsed; - - void ResetBuf(); -public: - enum OpenMode { READ, WRITE }; - RageFile() : mPath("") { mFP = NULL; } - RageFile( const CString& path, OpenMode mode = READ ); - ~RageFile() { Close(); } - - bool Open( const CString& path, OpenMode mode = READ ); - void Close(); - - bool IsOpen() { return (mFP != NULL); } - bool AtEOF() { return (feof(mFP) != 0); } - int GetError() { return ferror(mFP); } - void ClearError() { clearerr(mFP); } - - long Tell() { return ftell(mFP); } - bool Seek(long offset) { return !fseek(mFP, offset, SEEK_SET); } - void Rewind() { rewind(mFP); } - - /* Raw I/O: */ - // GetLine() strips new lines - bool PutString(const CString& string) { return fputs(string, mFP) >= 0; } - int Read(void *buffer, size_t bytes); - int Write(const void *buffer, size_t bytes); - int PutLine( const CString &str ); - - /* Line-based I/O: */ - CString GetLine(); - void GetLine( CString &out ); }; #endif diff --git a/stepmania/src/RageFileDriver.cpp b/stepmania/src/RageFileDriver.cpp new file mode 100644 index 0000000000..9e23aca07b --- /dev/null +++ b/stepmania/src/RageFileDriver.cpp @@ -0,0 +1,65 @@ +#include "global.h" +#include "RageFileDriver.h" + +void RageFileObj::SetError( const CString &err ) +{ + parent.SetError( err ); +} + +int RageFileObj::Seek( int offset ) +{ + const int OldPos = parent.Tell(); + if( offset < OldPos ) + parent.Rewind(); + else + offset -= OldPos; + + char buf[256]; + while( offset ) + { + /* Must call parent.Read: */ + int got = parent.Read( buf, min( (int) sizeof(buf), offset ) ); + if( got == -1 ) + return -1; + + if( got == 0 ) + break; + offset -= got; + } + + return parent.Tell(); +} + +int RageFileObj::SeekCur( int offset ) +{ + return Seek( parent.Tell() + offset ); +} + +int RageFileObj::GetFileSize() +{ + int OldPos = parent.Tell(); + parent.Rewind(); + char buf[256]; + int ret = 0; + while( 1 ) + { + /* Must call parent.Read: */ + int got = parent.Read( buf, sizeof(buf) ); + if( got == -1 ) + { + ret = -1; + break; + } + if( got == 0 ) + break; + ret += got; + } + Seek( OldPos ); + return ret; +} + +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ + diff --git a/stepmania/src/RageFileDriver.h b/stepmania/src/RageFileDriver.h new file mode 100644 index 0000000000..bf2275ee49 --- /dev/null +++ b/stepmania/src/RageFileDriver.h @@ -0,0 +1,43 @@ +#ifndef RAGE_FILE_DRIVER_H +#define RAGE_FILE_DRIVER_H + +#include "RageFile.h" +#include "RageFileManager.h" + +class RageFileObj; +class RageFileDriver +{ +public: + virtual RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err ) = 0; + virtual RageFileManager::FileType GetFileType( CString sPath ) = 0; + virtual int GetFileSizeInBytes( CString sFilePath ) = 0; + virtual int GetFileModTime( CString sPath ) = 0; +}; + +class RageFileObj +{ +protected: + RageFile &parent; + void SetError( const CString &err ); + +public: + RageFileObj( RageFile &p ): parent(p) { } + virtual ~RageFileObj() { } + + void ClearError(); + +// virtual CString RealPath() const { return parent->GetPath(); } + + virtual int Seek( int offset ); + virtual int SeekCur( int offset ); + virtual int GetFileSize(); + virtual CString GetDisplayPath() const { return parent.GetRealPath(); } + + /* Raw I/O: */ + virtual int Read(void *buffer, size_t bytes) = 0; + virtual int Write(const void *buffer, size_t bytes) = 0; + virtual void Rewind() = 0; +}; + +#endif + diff --git a/stepmania/src/RageFileDriverDirect.cpp b/stepmania/src/RageFileDriverDirect.cpp new file mode 100644 index 0000000000..4f140f698f --- /dev/null +++ b/stepmania/src/RageFileDriverDirect.cpp @@ -0,0 +1,165 @@ +#include "global.h" +#include "RageFileDriverDirect.h" +#include "RageUtil.h" + +#include +#include +#include +#include + +#if defined(WIN32) +#include +#endif + +#if !defined(O_BINARY) +#define O_BINARY 0 +#endif + +/* XXX: Drop FileDB and cache/resolve in here. */ +#include "RageUtil_FileDB.h" + +/* This driver handles direct file access. */ + +class RageFileObjDirect: public RageFileObj +{ +private: + int fd; + +public: + RageFileObjDirect( int fd, RageFile &p ); + virtual ~RageFileObjDirect(); + virtual int Read(void *buffer, size_t bytes); + virtual int Write(const void *buffer, size_t bytes); + virtual void Rewind(); + virtual int Seek( int offset ); + virtual int SeekCur( int offset ); + virtual int GetFileSize(); +}; + + +RageFileDriverDirect::RageFileDriverDirect( CString root_ ): + root(root_) +{ +} + +RageFileObj *RageFileDriverDirect::Open( CString sPath, RageFile::OpenMode mode, RageFile &p, int &err ) +{ + ResolvePath( sPath ); + int flags = O_BINARY; + if( mode == RageFile::READ ) + flags |= O_RDONLY; + else + flags |= O_WRONLY|O_CREAT|O_TRUNC; + int fd = open( root + sPath, flags ); + if( fd == -1 ) + { + err = errno; + return NULL; + } + + return new RageFileObjDirect( fd, p ); +} + +static bool DoStat(CString sPath, struct stat *st) +{ + TrimRight(sPath, "/\\"); + return stat(sPath.c_str(), st) != -1; +} + +RageFileManager::FileType RageFileDriverDirect::GetFileType( CString sPath ) +{ + ResolvePath( sPath ); + + struct stat st; + if( !DoStat(sPath, &st) ) + return RageFileManager::TYPE_NONE; + + if( st.st_mode & S_IFDIR ) + return RageFileManager::TYPE_DIR; + + return RageFileManager::TYPE_FILE; +} + +int RageFileDriverDirect::GetFileSizeInBytes( CString sPath ) +{ + struct stat st; + if( !DoStat(sPath, &st) ) + return 0; + + return st.st_size; +} + +int RageFileDriverDirect::GetFileModTime( CString sPath ) +{ + struct stat st; + if( !DoStat(sPath, &st) ) + return -1; + + return st.st_mtime; +} + +RageFileObjDirect::RageFileObjDirect( int fd_, RageFile &p ): + RageFileObj( p ) +{ + fd = fd_; + ASSERT( fd != -1 ); +} + +RageFileObjDirect::~RageFileObjDirect() +{ + if( fd != -1 ) + close( fd ); +} + +int RageFileObjDirect::Read( void *buf, size_t bytes ) +{ + int ret = read( fd, buf, bytes ); + if( ret == -1 ) + { + SetError( strerror(errno) ); + return -1; + } + + return ret; +} + +int RageFileObjDirect::Write( const void *buf, size_t bytes ) +{ + int ret = write( fd, buf, bytes ); + if( ret == -1 ) + { + SetError( strerror(errno) ); + return -1; + } + + return ret; +} + +void RageFileObjDirect::Rewind() +{ + lseek( fd, 0, SEEK_SET ); +} + +int RageFileObjDirect::Seek( int offset ) +{ + return lseek( fd, offset, SEEK_SET ); +} + +int RageFileObjDirect::SeekCur( int offset ) +{ + return lseek( fd, offset, SEEK_CUR ); +} + +int RageFileObjDirect::GetFileSize() +{ + const int OldPos = lseek( fd, 0, SEEK_CUR ); + const int ret = lseek( fd, 0, SEEK_END ); + lseek( fd, OldPos, SEEK_SET ); + return ret; +} + +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ + diff --git a/stepmania/src/RageFileDriverDirect.h b/stepmania/src/RageFileDriverDirect.h new file mode 100644 index 0000000000..5fb35a2ba8 --- /dev/null +++ b/stepmania/src/RageFileDriverDirect.h @@ -0,0 +1,21 @@ +#ifndef RAGE_FILE_DRIVER_DIRECT_H +#define RAGE_FILE_DRIVER_DIRECT_H + +#include "RageFileDriver.h" + +class RageFileDriverDirect: public RageFileDriver +{ +public: + RageFileDriverDirect( CString root ); + virtual ~RageFileDriverDirect() { } + + RageFileObj *Open( CString path, RageFile::OpenMode mode, RageFile &p, int &err ); + RageFileManager::FileType GetFileType( CString sPath ); + int GetFileSizeInBytes( CString sFilePath ); + int GetFileModTime( CString sPath ); + +private: + CString root; +}; + +#endif diff --git a/stepmania/src/RageFileManager.cpp b/stepmania/src/RageFileManager.cpp new file mode 100644 index 0000000000..a9ca2922f2 --- /dev/null +++ b/stepmania/src/RageFileManager.cpp @@ -0,0 +1,160 @@ +#include "global.h" +#include "RageFileManager.h" +#include "RageFileDriver.h" +#include + +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; + CString base; + + CString GetPath( CString path ); +}; + +static vector g_Drivers; + + +RageFileManager::RageFileManager() +{ +#if defined(XBOX) + RageFileManager::AddFS( "dir", ".", "" ); + /* XXX: drop BASE_PATH and do this instead */ +// RageFileManager::AddFS( "dir", "D:\\", "" ); +#else + /* Paths relative to the CWD: */ + RageFileManager::AddFS( "dir", ".", "" ); + + /* Absolute paths. This is rarely used, eg. by Alsa9Buf::GetSoundCardDebugInfo(). */ + RageFileManager::AddFS( "dir", "/", "/" ); +#endif +} + +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 ) +{ + if( base.size() == 0 ) + return path; + + /* Map all slashes to forward slash. */ + path.Replace( "\\", "/" ); + + if( path.Left( base.size() ).CompareNoCase( base ) ) + return ""; /* no match */ + + return path.Right( path.size() - base.size() ); +} + + +#include "RageFileDriverDirect.h" +void RageFileManager::AddFS( CString Type, CString Root, CString Base ) +{ + if( Base.size() && Base.Right(1) != "/" ) + Base += '/'; + 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; + ld.base = Base; + g_Drivers.push_back( ld ); +} + +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; + +} + +/* Used only by RageFile: */ +RageFileObj *RageFileManager::Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ) +{ + err = ENOENT; + + /* 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; +} + +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; } + diff --git a/stepmania/src/RageFileManager.h b/stepmania/src/RageFileManager.h new file mode 100644 index 0000000000..1f0454aab7 --- /dev/null +++ b/stepmania/src/RageFileManager.h @@ -0,0 +1,31 @@ +#ifndef RAGE_FILE_MANAGER_H +#define RAGE_FILE_MANAGER_H + +#include "RageFile.h" + +class RageFileObj; +class RageFileManager +{ +public: + RageFileManager(); + ~RageFileManager(); + + enum FileType { TYPE_FILE, TYPE_DIR, TYPE_NONE }; + FileType GetFileType( const CString &sPath ); + + bool IsAFile( const CString &sPath ); + bool IsADirectory( const CString &sPath ); + bool DoesFileExist( const CString &sPath ); + + int GetFileSizeInBytes( const CString &sPath ); + int GetFileModTime( const CString &sPath ); + + void AddFS( CString Type, CString RealPath, CString Root ); + + /* Used only by RageFile: */ + RageFileObj *Open( const CString &sPath, RageFile::OpenMode mode, RageFile &p, int &err ); +}; + +extern RageFileManager *FILEMAN; + +#endif diff --git a/stepmania/src/StepMania.cpp b/stepmania/src/StepMania.cpp index 682ab72fcc..b3502ac34b 100644 --- a/stepmania/src/StepMania.cpp +++ b/stepmania/src/StepMania.cpp @@ -51,7 +51,7 @@ #include "BannerCache.h" #include "UnlockSystem.h" #include "arch/ArchHooks/ArchHooks.h" -#include "RageFile.h" +#include "RageFileManager.h" #include "Bookkeeper.h" #include "LightsManager.h" @@ -785,6 +785,9 @@ int main(int argc, char* argv[]) /* Whew--we should be able to crash safely now! */ + /* Everything except LOG uses this to read and write files. Load this early. */ + FILEMAN = new RageFileManager; + atexit(SDL_Quit); /* Clean up on exit */ /* Fire up the SDL, but don't actually start any subsystems. @@ -957,6 +960,7 @@ int main(int argc, char* argv[]) SAFE_DELETE( FONT ); SAFE_DELETE( TEXTUREMAN ); SAFE_DELETE( DISPLAY ); + SAFE_DELETE( FILEMAN ); SAFE_DELETE( LOG ); if( g_sErrorString != "" )