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:
+71
-299
@@ -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 "global.h"
|
||||||
#include "RageFile.h"
|
#include "RageFile.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
@@ -6,26 +13,15 @@
|
|||||||
RageFile::RageFile()
|
RageFile::RageFile()
|
||||||
{
|
{
|
||||||
m_File = NULL;
|
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. */
|
/* This will copy the file driver, including its internal file pointer. */
|
||||||
m_File = FILEMAN->CopyFileObj( cpy.m_File );
|
m_File = FILEMAN->CopyFileObj( cpy.m_File );
|
||||||
m_Path = cpy.m_Path;
|
m_Path = cpy.m_Path;
|
||||||
m_Mode = cpy.m_Mode;
|
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
|
CString RageFile::GetPath() const
|
||||||
@@ -49,9 +45,6 @@ bool RageFile::Open( const CString& path, int mode )
|
|||||||
FixSlashesInPlace(m_Path);
|
FixSlashesInPlace(m_Path);
|
||||||
|
|
||||||
m_Mode = mode;
|
m_Mode = mode;
|
||||||
m_EOF = false;
|
|
||||||
m_FilePos = 0;
|
|
||||||
ResetBuf();
|
|
||||||
|
|
||||||
if( (m_Mode&READ) && (m_Mode&WRITE) )
|
if( (m_Mode&READ) && (m_Mode&WRITE) )
|
||||||
{
|
{
|
||||||
@@ -83,291 +76,90 @@ void RageFile::Close()
|
|||||||
m_File = NULL;
|
m_File = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill the internal buffer. This never marks EOF, since this is an internal, hidden
|
#define ASSERT_OPEN ASSERT_M( IsOpen(), ssprintf("\"%s\" is not open.", m_Path.c_str()) );
|
||||||
* read; EOF should only be set as a result of a real read. (That is, disabling buffering
|
#define ASSERT_READ ASSERT_OPEN; ASSERT_M( !!(m_Mode&READ), ssprintf("\"%s\" is not open for reading", m_Path.c_str()) );
|
||||||
* shouldn't cause the results of AtEOF to change.) */
|
#define ASSERT_WRITE ASSERT_OPEN; ASSERT_M( !!(m_Mode&WRITE), ssprintf("\"%s\" is not open for writing", m_Path.c_str()) );
|
||||||
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. */
|
|
||||||
int RageFile::GetLine( CString &out )
|
int RageFile::GetLine( CString &out )
|
||||||
{
|
{
|
||||||
out = "";
|
ASSERT_READ;
|
||||||
|
return m_File->GetLine( 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 )
|
int RageFile::PutLine( const CString &str )
|
||||||
{
|
{
|
||||||
if( Write(str) == -1 )
|
ASSERT_WRITE;
|
||||||
return -1;
|
return m_File->PutLine( str );
|
||||||
return Write( CString(NEWLINE) );
|
}
|
||||||
|
|
||||||
|
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() )
|
if( m_File != NULL )
|
||||||
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
|
m_File->ClearError();
|
||||||
|
m_sError = err;
|
||||||
|
}
|
||||||
|
|
||||||
if( !(m_Mode&READ) )
|
int RageFile::Read( void *pBuffer, size_t iBytes )
|
||||||
RageException::Throw("\"%s\" is not open for reading", GetPath().c_str());
|
{
|
||||||
|
ASSERT_READ;
|
||||||
int ret = 0;
|
return m_File->Read( pBuffer, iBytes );
|
||||||
|
|
||||||
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::Seek( int offset )
|
int RageFile::Seek( int offset )
|
||||||
{
|
{
|
||||||
if( !IsOpen() )
|
ASSERT_READ;
|
||||||
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
|
return m_File->Seek( offset );
|
||||||
|
}
|
||||||
|
|
||||||
if( !(m_Mode&READ) )
|
int RageFile::Tell() const
|
||||||
RageException::Throw("\"%s\" is not open for reading; can't seek", GetPath().c_str());
|
{
|
||||||
|
ASSERT_READ;
|
||||||
m_EOF = false;
|
return m_File->Tell();
|
||||||
|
|
||||||
ResetBuf();
|
|
||||||
|
|
||||||
int pos = m_File->Seek( offset );
|
|
||||||
if( pos == -1 )
|
|
||||||
{
|
|
||||||
SetError( m_File->GetError() );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_FilePos = pos;
|
|
||||||
return pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::GetFileSize() const
|
int RageFile::GetFileSize() const
|
||||||
{
|
{
|
||||||
if( !IsOpen() )
|
ASSERT_READ;
|
||||||
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
|
return m_File->GetFileSize();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::Read( CString &buffer, int bytes )
|
int RageFile::Read( CString &buffer, int bytes )
|
||||||
{
|
{
|
||||||
buffer.erase( buffer.begin(), buffer.end() );
|
ASSERT_READ;
|
||||||
buffer.reserve( bytes != -1? bytes: this->GetFileSize() );
|
return m_File->Read( buffer, bytes );
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::Write( const void *buffer, size_t bytes )
|
int RageFile::Write( const void *buffer, size_t bytes )
|
||||||
{
|
{
|
||||||
if( !IsOpen() )
|
ASSERT_WRITE;
|
||||||
RageException::Throw("\"%s\" is not open.", GetPath().c_str());
|
return m_File->Write( buffer, bytes );
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int RageFile::Write( const void *buffer, size_t bytes, int nmemb )
|
int RageFile::Write( const void *buffer, size_t bytes, int nmemb )
|
||||||
{
|
{
|
||||||
/* Simple write. We never return partial writes. */
|
ASSERT_WRITE;
|
||||||
int ret = Write( buffer, bytes*nmemb ) / bytes;
|
return m_File->Write( buffer, bytes, nmemb );
|
||||||
if( ret == -1 )
|
|
||||||
{
|
|
||||||
SetError( m_File->GetError() );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return ret / bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::Flush()
|
int RageFile::Flush()
|
||||||
@@ -378,42 +170,22 @@ int RageFile::Flush()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iRet = m_File->Flush();
|
return m_File->Flush();
|
||||||
if( iRet == -1 )
|
|
||||||
{
|
|
||||||
SetError( m_File->GetError() );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return iRet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::Read( void *buffer, size_t bytes, int nmemb )
|
int RageFile::Read( void *buffer, size_t bytes, int nmemb )
|
||||||
{
|
{
|
||||||
const int ret = Read( buffer, bytes*nmemb );
|
ASSERT_READ;
|
||||||
if( ret == -1 )
|
return m_File->Read( buffer, bytes, nmemb );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFile::Seek( int offset, int whence )
|
int RageFile::Seek( int offset, int whence )
|
||||||
{
|
{
|
||||||
switch( whence )
|
ASSERT_READ;
|
||||||
{
|
return m_File->Seek( offset, whence );
|
||||||
case SEEK_CUR:
|
|
||||||
return Seek( Tell() + offset );
|
|
||||||
case SEEK_END:
|
|
||||||
offset += GetFileSize();
|
|
||||||
}
|
|
||||||
return Seek( (int) offset );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
if( sError.size() != 0 )
|
||||||
return;
|
return;
|
||||||
@@ -425,7 +197,7 @@ void FileReading::ReadBytes( RageFile &f, void *buf, int size, CString &sError )
|
|||||||
sError = "Unexpected end of file";
|
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;
|
uint8_t val;
|
||||||
ReadBytes( f, &val, sizeof(uint8_t), sError );
|
ReadBytes( f, &val, sizeof(uint8_t), sError );
|
||||||
@@ -435,7 +207,7 @@ uint8_t FileReading::read_8( RageFile &f, CString &sError )
|
|||||||
return 0;
|
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;
|
uint16_t val;
|
||||||
ReadBytes( f, &val, sizeof(uint16_t), sError );
|
ReadBytes( f, &val, sizeof(uint16_t), sError );
|
||||||
@@ -445,7 +217,7 @@ uint16_t FileReading::read_u16_le( RageFile &f, CString &sError )
|
|||||||
return 0;
|
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;
|
int16_t val;
|
||||||
ReadBytes( f, &val, sizeof(int16_t), sError );
|
ReadBytes( f, &val, sizeof(int16_t), sError );
|
||||||
@@ -455,7 +227,7 @@ int16_t FileReading::read_16_le( RageFile &f, CString &sError )
|
|||||||
return 0;
|
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;
|
uint32_t val;
|
||||||
ReadBytes( f, &val, sizeof(uint32_t), sError );
|
ReadBytes( f, &val, sizeof(uint32_t), sError );
|
||||||
@@ -465,7 +237,7 @@ uint32_t FileReading::read_u32_le( RageFile &f, CString &sError )
|
|||||||
return 0;
|
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;
|
int32_t val;
|
||||||
ReadBytes( f, &val, sizeof(int32_t), sError );
|
ReadBytes( f, &val, sizeof(int32_t), sError );
|
||||||
|
|||||||
+66
-33
@@ -7,10 +7,55 @@
|
|||||||
|
|
||||||
class RageFileObj;
|
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:
|
public:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -25,8 +70,8 @@ public:
|
|||||||
SLOW_FLUSH = 0x8
|
SLOW_FLUSH = 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
RageFile();
|
RageFile();
|
||||||
~RageFile() { Close(); }
|
~RageFile() { Close(); }
|
||||||
RageFile( const RageFile &cpy );
|
RageFile( const RageFile &cpy );
|
||||||
|
|
||||||
/* Use GetRealPath to get the path this file was opened with; use that if you
|
/* 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; }
|
const CString &GetRealPath() const { return m_Path; }
|
||||||
CString GetPath() const;
|
CString GetPath() const;
|
||||||
|
|
||||||
bool Open( const CString& path, int mode = READ );
|
bool Open( const CString& path, int mode = READ );
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
bool IsOpen() const { return m_File != NULL; }
|
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 Seek( int offset );
|
||||||
int GetFileSize() const;
|
int GetFileSize() const;
|
||||||
|
|
||||||
@@ -69,24 +113,13 @@ public:
|
|||||||
int PutLine( const CString &str );
|
int PutLine( const CString &str );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetError( const CString &err ) { m_Error = err; } /* called by RageFileObj::SetError */
|
void SetError( const CString &err );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int FillBuf();
|
|
||||||
void ResetBuf();
|
|
||||||
|
|
||||||
RageFileObj *m_File;
|
RageFileObj *m_File;
|
||||||
CString m_Path;
|
CString m_Path;
|
||||||
|
CString m_sError;
|
||||||
int m_Mode;
|
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. */
|
/* 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
|
/* On error, these set sError to the error message. If sError is already
|
||||||
* non-empty, nothing happens. */
|
* non-empty, nothing happens. */
|
||||||
void ReadBytes( RageFile &f, void *buf, int size, CString &sError );
|
void ReadBytes( RageBasicFile &f, void *buf, int size, CString &sError );
|
||||||
uint8_t read_8( RageFile &f, CString &sError );
|
uint8_t read_8( RageBasicFile &f, CString &sError );
|
||||||
int16_t read_16_le( RageFile &f, CString &sError );
|
int16_t read_16_le( RageBasicFile &f, CString &sError );
|
||||||
uint16_t read_u16_le( RageFile &f, CString &sError );
|
uint16_t read_u16_le( RageBasicFile &f, CString &sError );
|
||||||
int32_t read_32_le( RageFile &f, CString &sError );
|
int32_t read_32_le( RageBasicFile &f, CString &sError );
|
||||||
uint32_t read_u32_le( RageFile &f, CString &sError );
|
uint32_t read_u32_le( RageBasicFile &f, CString &sError );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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 )
|
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 )
|
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 )
|
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 );
|
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()
|
int RageFileObj::Flush()
|
||||||
{
|
{
|
||||||
return FlushInternal();
|
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
|
* Copyright (c) 2003-2004 Glenn Maynard
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|||||||
@@ -31,34 +31,35 @@ protected:
|
|||||||
FilenameDB *FDB;
|
FilenameDB *FDB;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RageFileObj
|
class RageFileObj: public RageBasicFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
RageFileObj();
|
||||||
virtual ~RageFileObj() { }
|
virtual ~RageFileObj() { }
|
||||||
|
|
||||||
virtual CString GetError() const { return m_sError; }
|
CString GetError() const { return m_sError; }
|
||||||
|
void ClearError() { SetError(""); }
|
||||||
|
|
||||||
|
bool AtEOF() const { return m_bEOF; }
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
int Seek( int iOffset );
|
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( 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 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();
|
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 CString GetDisplayPath() const { return ""; }
|
||||||
virtual RageFileObj *Copy() const { FAIL_M( "Copying unimplemented" ); }
|
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 WriteInternal( const void *pBuffer, size_t iBytes ) = 0;
|
||||||
virtual int FlushInternal() { return 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;
|
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. */
|
/* This is used to register the driver, so RageFileManager can see it. */
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
virtual int SeekInternal( int offset );
|
virtual int SeekInternal( int offset );
|
||||||
virtual RageFileObj *Copy() const;
|
virtual RageFileObj *Copy() const;
|
||||||
virtual CString GetDisplayPath() const { return path; }
|
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 );
|
return lseek( fd, offset, SEEK_SET );
|
||||||
}
|
}
|
||||||
|
|
||||||
int RageFileObjDirect::GetFileSize()
|
int RageFileObjDirect::GetFileSize() const
|
||||||
{
|
{
|
||||||
const int OldPos = lseek( fd, 0, SEEK_CUR );
|
const int OldPos = lseek( fd, 0, SEEK_CUR );
|
||||||
ASSERT_M( OldPos != -1, strerror(errno) );
|
ASSERT_M( OldPos != -1, strerror(errno) );
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
return m_iFilePos;
|
return m_iFilePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetFileSize()
|
int GetFileSize() const
|
||||||
{
|
{
|
||||||
LockMut(m_pFile->m_Mutex);
|
LockMut(m_pFile->m_Mutex);
|
||||||
return m_pFile->m_sBuf.size();
|
return m_pFile->m_sBuf.size();
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
int ReadInternal( void *pBuffer, size_t iBytes );
|
int ReadInternal( void *pBuffer, size_t iBytes );
|
||||||
int WriteInternal( const void *pBuffer, size_t iBytes ) { SetError( "Not implemented" ); return -1; }
|
int WriteInternal( const void *pBuffer, size_t iBytes ) { SetError( "Not implemented" ); return -1; }
|
||||||
int SeekInternal( int iOffset );
|
int SeekInternal( int iOffset );
|
||||||
int GetFileSize() { return info.uncompr_size; }
|
int GetFileSize() const { return info.uncompr_size; }
|
||||||
RageFileObj *Copy() const
|
RageFileObj *Copy() const
|
||||||
{
|
{
|
||||||
RageException::Throw( "Loading ZIPs from deflated ZIPs is currently disabled; see RageFileObjZipDeflated" );
|
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 WriteInternal( const void *pBuffer, size_t iBytes ) { SetError( "Not implemented" ); return -1; }
|
||||||
|
|
||||||
int SeekInternal( int iOffset );
|
int SeekInternal( int iOffset );
|
||||||
int GetFileSize() { return info.uncompr_size; }
|
int GetFileSize() const { return info.uncompr_size; }
|
||||||
|
|
||||||
RageFileObj *Copy() const
|
RageFileObj *Copy() const
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user