diff --git a/stepmania/src/Bookkeeper.cpp b/stepmania/src/Bookkeeper.cpp index 74376c43bf..e19faf0262 100644 --- a/stepmania/src/Bookkeeper.cpp +++ b/stepmania/src/Bookkeeper.cpp @@ -92,7 +92,7 @@ void Bookkeeper::ReadFromDisk() ini.GetValue( "MachineStatistics", "TotalPlays", m_iTotalPlays ); // read dat - RageFile file(COINS_DAT, "r"); + RageFile file( COINS_DAT ); if (file.IsOpen()) { const CString line = file.GetLine(); @@ -130,7 +130,7 @@ void Bookkeeper::WriteToDisk() ini.WriteFile(); // write dat - RageFile file(COINS_DAT, "w"); + RageFile file( COINS_DAT, RageFile::WRITE ); if (file.IsOpen()) { diff --git a/stepmania/src/RageFile.cpp b/stepmania/src/RageFile.cpp index b8f47bce00..ace4fa275a 100644 --- a/stepmania/src/RageFile.cpp +++ b/stepmania/src/RageFile.cpp @@ -46,63 +46,120 @@ void CollapsePath( CString &sPath ) sPath = join( SLASH, as ); } -RageFile::RageFile(const CString& path, const char *mode) +RageFile::RageFile( const CString& path, RageFile::OpenMode mode ) { mFP = NULL; - Open(path, mode); + m_BufUsed = 0; + Open(path, mode); } -bool RageFile::Open(const CString& path, const char *mode) +bool RageFile::Open( const CString& path, RageFile::OpenMode mode ) { - Close(); - mPath = path; - FixSlashesInPlace(mPath); - mFP = fopen(mPath, mode); - + Close(); + mPath = path; + FixSlashesInPlace(mPath); + mFP = fopen( mPath, mode == READ? "r":"w" ); + ResetBuf(); + return mFP == NULL; } void RageFile::Close() { - if (IsOpen()) - fclose(mFP); + if (IsOpen()) + fclose(mFP); - mFP = NULL; + mFP = NULL; +} + +void RageFile::ResetBuf() +{ + m_BufUsed = 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. */ +void RageFile::GetLine( CString &out ) +{ + out = ""; + + if (!IsOpen()) + RageException::Throw("\"%s\" is not open.", mPath.c_str()); + + 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 ); + if( p == NULL ) + p = m_pBuf+m_BufUsed; /* 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 */ + m_BufUsed -= p-m_pBuf; + m_pBuf = p; + } + + if( done ) + break; + + /* We need more data. That implies that we moved everything. */ + ASSERT( !m_BufUsed ); + m_pBuf = m_Buffer; + + size_t size = Read( m_pBuf, sizeof(m_Buffer) ); + if( size <= 0 ) + break; // EOF or error + m_BufUsed += size; + } +} + +int RageFile::Read( void *buffer, size_t bytes ) +{ + if( !IsOpen() ) + RageException::Throw("\"%s\" is not open.", mPath.c_str()); + + int ret = 0; + + int FromBuffer = min( (int) bytes, m_BufUsed ); + memcpy( buffer, m_pBuf, FromBuffer ); + ret += FromBuffer; + buffer = (char *) buffer + FromBuffer; + bytes -= FromBuffer; + + if( bytes ) + { + int FromFile = fread( buffer, 1L, bytes, mFP ); + if( FromFile < 0 ) + return -1; + ret += FromFile; + } + return ret; +} + +int RageFile::Write(const void *buffer, size_t bytes) +{ + if (!IsOpen()) + RageException::Throw("\"%s\" is not open.", mPath.c_str()); + + return fwrite(buffer, 1L, bytes, mFP); } CString RageFile::GetLine() { - if (!IsOpen()) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); - - CString buf(""); - char buffer[256]; // long line! - - do - { - char *ret = fgets(buffer, 256, mFP); - - buf += buffer; - - if (ret == NULL) - break; // EOF or error - } while (strlen(buffer) == 255); - - return buf; + CString ret; + GetLine( ret ); + return ret; } -size_t RageFile::Read(void *buffer, size_t bytes) -{ - if (!IsOpen()) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); - - return fread(buffer, 1L, bytes, mFP); -} - -size_t RageFile::Write(const void *buffer, size_t bytes) -{ - if (!IsOpen()) - RageException::Throw("\"%s\" is not open.", mPath.c_str()); - - return fwrite(buffer, 1L, bytes, mFP); -} diff --git a/stepmania/src/RageFile.h b/stepmania/src/RageFile.h index 4c058f2956..ec52f9abee 100644 --- a/stepmania/src/RageFile.h +++ b/stepmania/src/RageFile.h @@ -27,13 +27,20 @@ class RageFile private: FILE *mFP; CString mPath; - + + 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, const char *mode = "r"); + RageFile( const CString& path, OpenMode mode = READ ); ~RageFile() { Close(); } - bool Open(const CString& path, const char *mode = "r"); + bool Open( const CString& path, OpenMode mode = READ ); void Close(); bool IsOpen() { return (mFP != NULL); } @@ -45,11 +52,15 @@ public: bool Seek(long offset, int origin = SEEK_CUR) { return !fseek(mFP, offset, origin); } 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); + + /* Line-based I/O: */ CString GetLine(); - bool PutString(const CString& string) { return fputs(string, mFP) >= 0; } - size_t Read(void *buffer, size_t bytes); - size_t Write(const void *buffer, size_t bytes); + void GetLine( CString &out ); }; #endif