Move buffering logic from RageFile into RageFileObj.

Common file interface class, RageBasicFile, shared by RageFile
and RageFileObj.  This makes most uses of these objects interchangeable.
RageFile is now just a simple wrapper for RageFileObj, to create
files in FILEMAN's namespace; file objects can also be created
independently.  This means that, for example, IniFile can be used
to write a file to a CString, without having to jump through hoops,
and without having to use a separate file access wrapper; just do
something like:

RageFileObjMem string_file;
ini.WriteFile( string );
const CString &sString = string_file.GetString();
This commit is contained in:
Glenn Maynard
2004-12-10 08:48:18 +00:00
parent 4feb167b6e
commit 287a150db7
7 changed files with 421 additions and 355 deletions
+71 -299
View File
@@ -1,3 +1,10 @@
/*
* This provides an interface to open files in RageFileManager's namespace
* This is just a simple RageBasicFile wrapper on top of another RageBasicFile;
* when a file is open, is acts like the underlying RageBasicFile, except that
* a few extra sanity checks are made to check file modes.
*/
#include "global.h"
#include "RageFile.h"
#include "RageUtil.h"
@@ -6,26 +13,15 @@
RageFile::RageFile()
{
m_File = NULL;
m_BufAvail = 0;
m_EOF = false;
m_FilePos = 0;
}
RageFile::RageFile( const RageFile &cpy )
RageFile::RageFile( const RageFile &cpy ):
RageBasicFile( cpy )
{
ResetBuf();
/* This will copy the file driver, including its internal file pointer. */
m_File = FILEMAN->CopyFileObj( cpy.m_File );
m_Path = cpy.m_Path;
m_Mode = cpy.m_Mode;
m_Error = cpy.m_Error;
m_EOF = cpy.m_EOF;
m_FilePos = cpy.m_FilePos;
memcpy( this->m_Buffer, cpy.m_Buffer, sizeof(m_Buffer) );
m_pBuf = m_Buffer + (cpy.m_pBuf-cpy.m_Buffer);
m_BufAvail = cpy.m_BufAvail;
}
CString RageFile::GetPath() const
@@ -49,9 +45,6 @@ bool RageFile::Open( const CString& path, int mode )
FixSlashesInPlace(m_Path);
m_Mode = mode;
m_EOF = false;
m_FilePos = 0;
ResetBuf();
if( (m_Mode&READ) && (m_Mode&WRITE) )
{
@@ -83,291 +76,90 @@ void RageFile::Close()
m_File = NULL;
}
/* Fill the internal buffer. This never marks EOF, since this is an internal, hidden
* read; EOF should only be set as a result of a real read. (That is, disabling buffering
* shouldn't cause the results of AtEOF to change.) */
int RageFile::FillBuf()
{
/* The buffer starts at m_Buffer; any data in it starts at m_pBuf; space between
* the two is old data that we've read. (Don't mangle that data; we can use it
* for seeking backwards.) */
const int iBufAvail = sizeof(m_Buffer) - (m_pBuf-m_Buffer) - m_BufAvail;
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_Buffer, (int) sizeof(m_Buffer) ) );
const int size = m_File->Read( m_pBuf+m_BufAvail, iBufAvail );
if( size == -1 )
SetError( m_File->GetError() );
if( size > 0 )
m_BufAvail += size;
return size;
}
void RageFile::ResetBuf()
{
m_BufAvail = 0;
m_pBuf = m_Buffer;
}
/* 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. */
#define ASSERT_OPEN ASSERT_M( IsOpen(), ssprintf("\"%s\" is not open.", m_Path.c_str()) );
#define ASSERT_READ ASSERT_OPEN; ASSERT_M( !!(m_Mode&READ), ssprintf("\"%s\" is not open for reading", m_Path.c_str()) );
#define ASSERT_WRITE ASSERT_OPEN; ASSERT_M( !!(m_Mode&WRITE), ssprintf("\"%s\" is not open for writing", m_Path.c_str()) );
int RageFile::GetLine( CString &out )
{
out = "";
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());
if( m_EOF )
return 0;
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_BufAvail );
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_BufAvail && m_pBuf[m_BufAvail-1] == '\r' )
{
ReAddCR = true;
--m_BufAvail;
}
p = m_pBuf+m_BufAvail; /* everything */
}
else
done = true;
if( p >= m_pBuf )
{
char *RealEnd = p;
if( done && p > m_pBuf && p[-1] == '\r' )
--RealEnd; /* not including \r */
out.append( m_pBuf, RealEnd );
if( done )
++p; /* skip \n */
const int used = p-m_pBuf;
if( used )
{
m_BufAvail -= used;
m_FilePos += used;
GotData = true;
m_pBuf = p;
}
}
if( ReAddCR )
{
ASSERT( m_BufAvail == 0 );
m_pBuf = m_Buffer;
m_Buffer[m_BufAvail] = '\r';
++m_BufAvail;
}
if( done )
break;
/* We need more data. */
m_pBuf = m_Buffer;
const int size = FillBuf();
/* 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 == -1 )
return -1; // error
if( size == 0 )
break; // EOF or error
}
return GotData? 1:0;
ASSERT_READ;
return m_File->GetLine( out );
}
// Always use "\r\n". Even though the program may be running on Unix, the
// files written to a memory card are likely to be edited using Windows.
//#if defined(_WIN32)
#define NEWLINE "\r\n"
//#else
//#define NEWLINE "\n"
//#endif
int RageFile::PutLine( const CString &str )
{
if( Write(str) == -1 )
return -1;
return Write( CString(NEWLINE) );
ASSERT_WRITE;
return m_File->PutLine( str );
}
bool RageFile::AtEOF() const
{
ASSERT_READ;
return m_File->AtEOF();
}
void RageFile::ClearError()
{
if( m_File != NULL )
m_File->ClearError();
m_sError = "";
}
CString RageFile::GetError() const
{
if( m_File != NULL && m_File->GetError() != "" )
return m_File->GetError();
return m_sError;
}
int RageFile::Read( void *buffer, size_t bytes )
void RageFile::SetError( const CString &err )
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( m_File != NULL )
m_File->ClearError();
m_sError = err;
}
if( !(m_Mode&READ) )
RageException::Throw("\"%s\" is not open for reading", GetPath().c_str());
int ret = 0;
while( !m_EOF && bytes > 0 )
{
/* Copy data out of the buffer first. */
int FromBuffer = min( (int) bytes, m_BufAvail );
memcpy( buffer, m_pBuf, FromBuffer );
ret += FromBuffer;
m_FilePos += FromBuffer;
bytes -= FromBuffer;
m_BufAvail -= FromBuffer;
m_pBuf += FromBuffer;
buffer = (char *) buffer + FromBuffer;
if( !bytes )
break;
ASSERT( !m_BufAvail );
/* We need more; either fill the buffer and keep going, or just read directly
* into the destination buffer. */
if( bytes >= sizeof(m_Buffer) )
{
/* We have a lot more to read, so don't waste time copying it into the
* buffer. */
int FromFile = m_File->Read( buffer, bytes );
if( FromFile == -1 )
{
SetError( m_File->GetError() );
return -1;
}
if( FromFile == 0 )
m_EOF = true;
ret += FromFile;
m_FilePos += FromFile;
return ret;
}
m_pBuf = m_Buffer;
int got = FillBuf();
if( got < 0 )
return got;
if( got == 0 )
m_EOF = true;
}
return ret;
int RageFile::Read( void *pBuffer, size_t iBytes )
{
ASSERT_READ;
return m_File->Read( pBuffer, iBytes );
}
int RageFile::Seek( int offset )
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
ASSERT_READ;
return m_File->Seek( offset );
}
if( !(m_Mode&READ) )
RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str());
m_EOF = false;
ResetBuf();
int pos = m_File->Seek( offset );
if( pos == -1 )
{
SetError( m_File->GetError() );
return -1;
}
m_FilePos = pos;
return pos;
int RageFile::Tell() const
{
ASSERT_READ;
return m_File->Tell();
}
int RageFile::GetFileSize() const
{
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());
/* GetFileSize() may need to do non-const-like things--the default implementation reads
* until the end of file to emulate it. However, it should always restore the state to
* the way it was, so pretend it's const. */
int iRet = const_cast<RageFileObj*>(m_File)->GetFileSize();
ASSERT_M( iRet >= 0, ssprintf("%i", iRet) );
return iRet;
ASSERT_READ;
return m_File->GetFileSize();
}
int RageFile::Read( CString &buffer, int bytes )
{
buffer.erase( buffer.begin(), buffer.end() );
buffer.reserve( bytes != -1? bytes: this->GetFileSize() );
int ret = 0;
char buf[4096];
while( bytes == -1 || ret < bytes )
{
int ToRead = sizeof(buf);
if( bytes != -1 )
ToRead = min( ToRead, bytes-ret );
const int got = Read( buf, ToRead );
if( got == 0 )
break;
if( got == -1 )
return -1;
buffer.append( buf, got );
ret += got;
}
return ret;
ASSERT_READ;
return m_File->Read( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes )
{
if( !IsOpen() )
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
if( !(m_Mode&WRITE) )
RageException::Throw("\"%s\" is not open for writing", GetPath().c_str());
int iRet = m_File->Write( buffer, bytes );
if( iRet == -1 )
{
SetError( m_File->GetError() );
return -1;
}
return iRet;
ASSERT_WRITE;
return m_File->Write( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes, int nmemb )
{
/* Simple write. We never return partial writes. */
int ret = Write( buffer, bytes*nmemb ) / bytes;
if( ret == -1 )
{
SetError( m_File->GetError() );
return -1;
}
return ret / bytes;
ASSERT_WRITE;
return m_File->Write( buffer, bytes, nmemb );
}
int RageFile::Flush()
@@ -378,42 +170,22 @@ int RageFile::Flush()
return -1;
}
int iRet = m_File->Flush();
if( iRet == -1 )
{
SetError( m_File->GetError() );
return -1;
}
return iRet;
return m_File->Flush();
}
int RageFile::Read( void *buffer, size_t bytes, int nmemb )
{
const int ret = Read( buffer, bytes*nmemb );
if( ret == -1 )
return -1;
/* If we're reading 10-byte blocks, and we got 27 bytes, we have 7 extra bytes.
* Seek back. */
const int extra = ret % bytes;
Seek( Tell()-extra );
return ret/bytes;
ASSERT_READ;
return m_File->Read( buffer, bytes, nmemb );
}
int RageFile::Seek( int offset, int whence )
{
switch( whence )
{
case SEEK_CUR:
return Seek( Tell() + offset );
case SEEK_END:
offset += GetFileSize();
}
return Seek( (int) offset );
ASSERT_READ;
return m_File->Seek( offset, whence );
}
void FileReading::ReadBytes( RageFile &f, void *buf, int size, CString &sError )
void FileReading::ReadBytes( RageBasicFile &f, void *buf, int size, CString &sError )
{
if( sError.size() != 0 )
return;
@@ -425,7 +197,7 @@ void FileReading::ReadBytes( RageFile &f, void *buf, int size, CString &sError )
sError = "Unexpected end of file";
}
uint8_t FileReading::read_8( RageFile &f, CString &sError )
uint8_t FileReading::read_8( RageBasicFile &f, CString &sError )
{
uint8_t val;
ReadBytes( f, &val, sizeof(uint8_t), sError );
@@ -435,7 +207,7 @@ uint8_t FileReading::read_8( RageFile &f, CString &sError )
return 0;
}
uint16_t FileReading::read_u16_le( RageFile &f, CString &sError )
uint16_t FileReading::read_u16_le( RageBasicFile &f, CString &sError )
{
uint16_t val;
ReadBytes( f, &val, sizeof(uint16_t), sError );
@@ -445,7 +217,7 @@ uint16_t FileReading::read_u16_le( RageFile &f, CString &sError )
return 0;
}
int16_t FileReading::read_16_le( RageFile &f, CString &sError )
int16_t FileReading::read_16_le( RageBasicFile &f, CString &sError )
{
int16_t val;
ReadBytes( f, &val, sizeof(int16_t), sError );
@@ -455,7 +227,7 @@ int16_t FileReading::read_16_le( RageFile &f, CString &sError )
return 0;
}
uint32_t FileReading::read_u32_le( RageFile &f, CString &sError )
uint32_t FileReading::read_u32_le( RageBasicFile &f, CString &sError )
{
uint32_t val;
ReadBytes( f, &val, sizeof(uint32_t), sError );
@@ -465,7 +237,7 @@ uint32_t FileReading::read_u32_le( RageFile &f, CString &sError )
return 0;
}
int32_t FileReading::read_32_le( RageFile &f, CString &sError )
int32_t FileReading::read_32_le( RageBasicFile &f, CString &sError )
{
int32_t val;
ReadBytes( f, &val, sizeof(int32_t), sError );
+66 -33
View File
@@ -7,10 +7,55 @@
class RageFileObj;
class RageFile
{
friend class RageFileObj;
/* This is a simple file I/O interface. Although most of these operations
* are straightforward, there are several of them; most of the time, you'll
* only want to implement RageFileObj. */
class RageBasicFile
{
public:
virtual ~RageBasicFile() { }
virtual CString GetError() const = 0;
virtual void ClearError() = 0;
virtual bool AtEOF() const = 0;
/* Seek to the given absolute offset. Return to the position actually
* seeked to; if the position given was beyond the end of the file, the
* return value will be the size of the file. */
virtual int Seek( int iOffset ) = 0;
virtual int Seek( int offset, int whence ) = 0;
virtual int Tell() const = 0;
/* Read at most iSize bytes into pBuf. Return the number of bytes read,
* 0 on end of stream, or -1 on error. Note that reading less than iSize
* does not necessarily mean that the end of the stream has been reached;
* keep reading until 0 is returned. */
virtual int Read( void *pBuffer, size_t iBytes ) = 0;
virtual int Read( CString &buffer, int bytes = -1 ) = 0;
virtual int Read( void *buffer, size_t bytes, int nmemb ) = 0;
/* Write iSize bytes of data from pBuf. Return 0 on success, -1 on error. */
virtual int Write( const void *pBuffer, size_t iBytes ) = 0;
virtual int Write( const CString &sString ) = 0;
virtual int Write( const void *buffer, size_t bytes, int nmemb ) = 0;
/* Due to buffering, writing may not happen by the end of a Write() call, so not
* all errors may be returned by it. Data will be flushed when the stream (or its
* underlying object) is destroyed, but errors can no longer be returned. Call
* Flush() to flush pending data, in order to check for errors. */
virtual int Flush() = 0;
virtual int GetLine( CString &out ) = 0;
virtual int PutLine( const CString &str ) = 0;
virtual int GetFileSize() const = 0;
};
/* This is the high-level interface, which interfaces with RageFileObj implementations
* and RageFileManager. */
class RageFile: public RageBasicFile
{
public:
enum
{
@@ -25,8 +70,8 @@ public:
SLOW_FLUSH = 0x8
};
RageFile();
~RageFile() { Close(); }
RageFile();
~RageFile() { Close(); }
RageFile( const RageFile &cpy );
/* Use GetRealPath to get the path this file was opened with; use that if you
@@ -38,17 +83,16 @@ public:
const CString &GetRealPath() const { return m_Path; }
CString GetPath() const;
bool Open( const CString& path, int mode = READ );
void Close();
bool Open( const CString& path, int mode = READ );
void Close();
bool IsOpen() const { return m_File != NULL; }
int GetOpenMode() const { return m_Mode; }
bool AtEOF() const { return m_EOF; }
CString GetError() const { return m_Error; }
void ClearError() { m_Error = ""; }
bool IsGood() const { return IsOpen() && !AtEOF() && m_Error.empty(); }
int Tell() const { return m_FilePos; }
bool AtEOF() const;
CString GetError() const;
void ClearError();
bool IsGood() const { return IsOpen() && !AtEOF() && GetError().empty(); }
int Tell() const;
int Seek( int offset );
int GetFileSize() const;
@@ -69,24 +113,13 @@ public:
int PutLine( const CString &str );
protected:
void SetError( const CString &err ) { m_Error = err; } /* called by RageFileObj::SetError */
void SetError( const CString &err );
private:
int FillBuf();
void ResetBuf();
RageFileObj *m_File;
CString m_Path;
CString m_sError;
int m_Mode;
CString m_Error;
bool m_EOF;
int m_FilePos;
enum { BSIZE = 1024 };
char m_Buffer[BSIZE];
char *m_pBuf;
int m_BufAvail;
};
/* Convenience wrappers for reading binary files. */
@@ -94,12 +127,12 @@ namespace FileReading
{
/* On error, these set sError to the error message. If sError is already
* non-empty, nothing happens. */
void ReadBytes( RageFile &f, void *buf, int size, CString &sError );
uint8_t read_8( RageFile &f, CString &sError );
int16_t read_16_le( RageFile &f, CString &sError );
uint16_t read_u16_le( RageFile &f, CString &sError );
int32_t read_32_le( RageFile &f, CString &sError );
uint32_t read_u32_le( RageFile &f, CString &sError );
void ReadBytes( RageBasicFile &f, void *buf, int size, CString &sError );
uint8_t read_8( RageBasicFile &f, CString &sError );
int16_t read_16_le( RageBasicFile &f, CString &sError );
uint16_t read_u16_le( RageBasicFile &f, CString &sError );
int32_t read_32_le( RageBasicFile &f, CString &sError );
uint32_t read_u32_le( RageBasicFile &f, CString &sError );
};
#endif
+250 -2
View File
@@ -91,14 +91,129 @@ RageFileDriver *MakeFileDriver( CString Type, CString Root )
}
RageFileObj::RageFileObj()
{
ResetBuf();
m_iBufAvail = 0;
m_bEOF = false;
m_iFilePos = 0;
}
int RageFileObj::Seek( int iOffset )
{
return SeekInternal( iOffset );
m_bEOF = false;
ResetBuf();
int iPos = SeekInternal( iOffset );
if( iPos != -1 )
m_iFilePos = iPos;
return iPos;
}
int RageFileObj::Seek( int offset, int whence )
{
switch( whence )
{
case SEEK_CUR:
return Seek( Tell() + offset );
case SEEK_END:
offset += GetFileSize();
}
return Seek( (int) offset );
}
int RageFileObj::Read( void *pBuffer, size_t iBytes )
{
return ReadInternal( pBuffer, iBytes );
int ret = 0;
while( !m_bEOF && iBytes > 0 )
{
/* Copy data out of the buffer first. */
int FromBuffer = min( (int) iBytes, m_iBufAvail );
memcpy( pBuffer, m_pBuf, FromBuffer );
ret += FromBuffer;
m_iFilePos += FromBuffer;
iBytes -= FromBuffer;
m_iBufAvail -= FromBuffer;
m_pBuf += FromBuffer;
pBuffer = (char *) pBuffer + FromBuffer;
if( !iBytes )
break;
ASSERT( m_iBufAvail == 0 );
/* We need more; either fill the buffer and keep going, or just read directly
* into the destination buffer. */
if( iBytes >= sizeof(m_Buffer) )
{
/* We have a lot more to read, so don't waste time copying it into the
* buffer. */
int iFromFile = this->ReadInternal( pBuffer, iBytes );
if( iFromFile == -1 )
return -1;
if( iFromFile == 0 )
m_bEOF = true;
ret += iFromFile;
m_iFilePos += iFromFile;
return ret;
}
m_pBuf = m_Buffer;
int got = FillBuf();
if( got < 0 )
return got;
if( got == 0 )
m_bEOF = true;
}
return ret;
}
int RageFileObj::Read( CString &sBuffer, int iBytes )
{
sBuffer.erase( sBuffer.begin(), sBuffer.end() );
sBuffer.reserve( iBytes != -1? iBytes: this->GetFileSize() );
int iRet = 0;
char buf[4096];
while( iBytes == -1 || iRet < iBytes )
{
int ToRead = sizeof(buf);
if( iBytes != -1 )
ToRead = min( ToRead, iBytes-iRet );
const int iGot = Read( buf, ToRead );
if( iGot == 0 )
break;
if( iGot == -1 )
return -1;
sBuffer.append( buf, iGot );
iRet += iGot;
}
return iRet;
}
int RageFileObj::Read( void *buffer, size_t bytes, int nmemb )
{
const int iRet = Read( buffer, bytes*nmemb );
if( iRet == -1 )
return -1;
/* If we're reading 10-byte blocks, and we got 27 bytes, we have 7 extra bytes.
* Seek back. XXX: seeking is very slow for eg. deflated ZIPs. If the block is
* small enough, we may be able to stuff the extra data into the buffer. */
const int iExtra = iRet % bytes;
Seek( Tell()-iExtra );
return iRet/bytes;
}
int RageFileObj::Write( const void *pBuffer, size_t iBytes )
@@ -106,11 +221,144 @@ int RageFileObj::Write( const void *pBuffer, size_t iBytes )
return WriteInternal( pBuffer, iBytes );
}
int RageFileObj::Write( const void *buffer, size_t bytes, int nmemb )
{
/* Simple write. We never return partial writes. */
int ret = Write( buffer, bytes*nmemb ) / bytes;
if( ret == -1 )
return -1;
return ret / bytes;
}
int RageFileObj::Flush()
{
return FlushInternal();
}
/* 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. */
int RageFileObj::GetLine( CString &out )
{
out = "";
if( m_bEOF )
return 0;
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_iBufAvail );
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_iBufAvail && m_pBuf[m_iBufAvail-1] == '\r' )
{
ReAddCR = true;
--m_iBufAvail;
}
p = m_pBuf+m_iBufAvail; /* everything */
}
else
done = true;
if( p >= m_pBuf )
{
char *RealEnd = p;
if( done && p > m_pBuf && p[-1] == '\r' )
--RealEnd; /* not including \r */
out.append( m_pBuf, RealEnd );
if( done )
++p; /* skip \n */
const int used = p-m_pBuf;
if( used )
{
m_iBufAvail -= used;
m_iFilePos += used;
GotData = true;
m_pBuf = p;
}
}
if( ReAddCR )
{
ASSERT( m_iBufAvail == 0 );
m_pBuf = m_Buffer;
m_Buffer[m_iBufAvail] = '\r';
++m_iBufAvail;
}
if( done )
break;
/* We need more data. */
m_pBuf = m_Buffer;
const int size = FillBuf();
/* 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_bEOF = true;
return 0;
}
if( size == -1 )
return -1; // error
if( size == 0 )
break; // EOF or error
}
return GotData? 1:0;
}
// Always use "\r\n". Even though the program may be running on Unix, the
// files written to a memory card are likely to be edited using Windows.
//#if defined(_WIN32)
#define NEWLINE "\r\n"
//#else
//#define NEWLINE "\n"
//#endif
int RageFileObj::PutLine( const CString &str )
{
if( Write(str) == -1 )
return -1;
return Write( CString(NEWLINE) );
}
/* Fill the internal buffer. This never marks EOF, since this is an internal, hidden
* read; EOF should only be set as a result of a real read. (That is, disabling buffering
* shouldn't cause the results of AtEOF to change.) */
int RageFileObj::FillBuf()
{
/* The buffer starts at m_Buffer; any data in it starts at m_pBuf; space between
* the two is old data that we've read. (Don't mangle that data; we can use it
* for seeking backwards.) */
const int iBufAvail = sizeof(m_Buffer) - (m_pBuf-m_Buffer) - m_iBufAvail;
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_Buffer, (int) sizeof(m_Buffer) ) );
const int size = this->ReadInternal( m_pBuf+m_iBufAvail, iBufAvail );
if( size > 0 )
m_iBufAvail += size;
return size;
}
void RageFileObj::ResetBuf()
{
m_iBufAvail = 0;
m_pBuf = m_Buffer;
}
/*
* Copyright (c) 2003-2004 Glenn Maynard
* All rights reserved.
+29 -16
View File
@@ -31,34 +31,35 @@ protected:
FilenameDB *FDB;
};
class RageFileObj
class RageFileObj: public RageBasicFile
{
public:
RageFileObj();
virtual ~RageFileObj() { }
virtual CString GetError() const { return m_sError; }
CString GetError() const { return m_sError; }
void ClearError() { SetError(""); }
/* Seek to the given absolute offset. Return to the position actually
* seeked to; if the position given was beyond the end of the file, the
* return value will be the size of the file. */
bool AtEOF() const { return m_bEOF; }
int Seek( int iOffset );
int Seek( int offset, int whence );
int Tell() const { return m_iFilePos; }
/* Read at most iSize bytes into pBuf. Return the number of bytes read,
* 0 on end of stream, or -1 on error. Note that reading less than iSize
* does not necessarily mean that the end of the stream has been reached;
* keep reading until 0 is returned. */
int Read( void *pBuffer, size_t iBytes );
int Read( CString &buffer, int bytes = -1 );
int Read( void *buffer, size_t bytes, int nmemb );
/* Write iSize bytes of data from pBuf. Return 0 on success, -1 on error. */
int Write( const void *pBuffer, size_t iBytes );
int Write( const CString &sString ) { return Write( sString.data(), sString.size() ); }
int Write( const void *buffer, size_t bytes, int nmemb );
/* Due to buffering, writing may not happen by the end of a Write() call, so not
* all errors may be returned by it. Data will be flushed when the stream (or its
* underlying object) is destroyed, but errors can no longer be returned. Call
* Flush() to flush pending data, in order to check for errors. */
int Flush();
virtual int GetFileSize() = 0;
int GetLine( CString &out );
int PutLine( const CString &str );
virtual int GetFileSize() const = 0;
virtual CString GetDisplayPath() const { return ""; }
virtual RageFileObj *Copy() const { FAIL_M( "Copying unimplemented" ); }
@@ -68,8 +69,20 @@ protected:
virtual int WriteInternal( const void *pBuffer, size_t iBytes ) = 0;
virtual int FlushInternal() { return 0; }
virtual void SetError( const CString &sError ) { m_sError = sError; }
void SetError( const CString &sError ) { m_sError = sError; }
CString m_sError;
private:
int FillBuf();
void ResetBuf();
bool m_bEOF;
int m_iFilePos;
enum { BSIZE = 1024 };
char m_Buffer[BSIZE];
char *m_pBuf;
int m_iBufAvail;
};
/* This is used to register the driver, so RageFileManager can see it. */
+2 -2
View File
@@ -49,7 +49,7 @@ public:
virtual int SeekInternal( int offset );
virtual RageFileObj *Copy() const;
virtual CString GetDisplayPath() const { return path; }
virtual int GetFileSize();
virtual int GetFileSize() const;
};
@@ -365,7 +365,7 @@ int RageFileObjDirect::SeekInternal( int offset )
return lseek( fd, offset, SEEK_SET );
}
int RageFileObjDirect::GetFileSize()
int RageFileObjDirect::GetFileSize() const
{
const int OldPos = lseek( fd, 0, SEEK_CUR );
ASSERT_M( OldPos != -1, strerror(errno) );
+1 -1
View File
@@ -73,7 +73,7 @@ public:
return m_iFilePos;
}
int GetFileSize()
int GetFileSize() const
{
LockMut(m_pFile->m_Mutex);
return m_pFile->m_sBuf.size();
+2 -2
View File
@@ -84,7 +84,7 @@ public:
int ReadInternal( void *pBuffer, size_t iBytes );
int WriteInternal( const void *pBuffer, size_t iBytes ) { SetError( "Not implemented" ); return -1; }
int SeekInternal( int iOffset );
int GetFileSize() { return info.uncompr_size; }
int GetFileSize() const { return info.uncompr_size; }
RageFileObj *Copy() const
{
RageException::Throw( "Loading ZIPs from deflated ZIPs is currently disabled; see RageFileObjZipDeflated" );
@@ -106,7 +106,7 @@ public:
int WriteInternal( const void *pBuffer, size_t iBytes ) { SetError( "Not implemented" ); return -1; }
int SeekInternal( int iOffset );
int GetFileSize() { return info.uncompr_size; }
int GetFileSize() const { return info.uncompr_size; }
RageFileObj *Copy() const
{