VFS work
This commit is contained in:
+220
-44
@@ -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; i<as.size(); i++ )
|
||||
{
|
||||
if( as[i] == ".." )
|
||||
CStringArray as;
|
||||
split( sPath, SLASH, as );
|
||||
|
||||
for( unsigned i=0; i<as.size(); i++ )
|
||||
{
|
||||
as.erase( as.begin()+i-1 );
|
||||
as.erase( as.begin()+i-1 );
|
||||
i -= 2;
|
||||
if( as[i] == ".." )
|
||||
{
|
||||
as.erase( as.begin()+i-1 );
|
||||
as.erase( as.begin()+i-1 );
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
sPath = join( SLASH, as );
|
||||
sPath = join( SLASH, as );
|
||||
}
|
||||
|
||||
RageFile::RageFile()
|
||||
{
|
||||
m_File = NULL;
|
||||
m_BufUsed = 0;
|
||||
m_EOF = false;
|
||||
m_FilePos = 0;
|
||||
}
|
||||
|
||||
RageFile::RageFile( const CString& path, RageFile::OpenMode mode )
|
||||
{
|
||||
mFP = NULL;
|
||||
m_File = NULL;
|
||||
m_BufUsed = 0;
|
||||
m_EOF = false;
|
||||
m_FilePos = 0;
|
||||
Open(path, mode);
|
||||
}
|
||||
|
||||
CString RageFile::GetPath() const
|
||||
{
|
||||
if ( !IsOpen() )
|
||||
return "";
|
||||
|
||||
return m_File->GetDisplayPath();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+51
-36
@@ -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 <cstdio>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#include "global.h"
|
||||
#include "RageFileDriverDirect.h"
|
||||
#include "RageUtil.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,160 @@
|
||||
#include "global.h"
|
||||
#include "RageFileManager.h"
|
||||
#include "RageFileDriver.h"
|
||||
#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;
|
||||
CString base;
|
||||
|
||||
CString GetPath( CString path );
|
||||
};
|
||||
|
||||
static vector<LoadedDriver> 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; }
|
||||
|
||||
@@ -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
|
||||
@@ -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 != "" )
|
||||
|
||||
Reference in New Issue
Block a user