• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/FileStream.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #ifdef _WIN32
00018 #include <spl/configwin32.h>
00019 #include <stdio.h>
00020 #else
00021 #include <spl/autoconf/config.h>
00022 #endif
00023 #include <stdarg.h>
00024 #ifdef HAVE_ERRNO_H
00025 #include <errno.h>
00026 #endif
00027 #include <spl/io/FileStream.h>
00028 
00029 using namespace spl;
00030 
00031 extern FILE *_msokfopen(const char* filename, const char* mode);
00032 
00033 class FileStreamState_Closed : public IStreamState
00034 {
00035 public:
00036         FileStreamState_Closed(IStream* parent, IStreamState **parentStateVar);
00037         virtual ~FileStreamState_Closed();
00038 
00039         virtual void OnLeave(IStreamState *newState);
00040         virtual void OnEnter(IStreamState *oldState);
00041 
00042         virtual void Close();
00043         virtual void Flush();
00044         virtual int Read(Array<byte>& buffer, const int offset, int count);
00045         virtual int ReadByte();
00046         virtual long Seek(const long offset, const SeekOrigin origin);
00047         virtual void Write(const Array<byte>& buffer, const int offset, const int count);
00048         virtual void WriteByte(byte value);
00049 
00050         virtual bool CanRead() const;
00051         virtual bool CanSeek() const;
00052         virtual bool CanWrite() const;
00053 
00054         virtual long Length() const;
00055         virtual long Position() const;
00056 #ifdef DEBUG
00057         virtual void ValidateMem() const;
00058         virtual void CheckMem() const;
00059 #endif
00060 };
00061 
00062 FileStreamState_Closed::FileStreamState_Closed
00063 (
00064         IStream *parent, 
00065         IStreamState **parentStateVar
00066 )
00067 : IStreamState(parent, parentStateVar)
00068 {
00069 }
00070 
00071 FileStreamState_Closed::~FileStreamState_Closed()
00072 {
00073 }
00074 
00075 void FileStreamState_Closed::OnLeave(IStreamState *newState)
00076 {
00077 }
00078 
00079 void FileStreamState_Closed::OnEnter(IStreamState *oldState)
00080 {
00081 }
00082 
00083 void FileStreamState_Closed::Close()
00084 {
00085 }
00086 
00087 void FileStreamState_Closed::Flush()
00088 {
00089         throw new IOException("File is closed, so it can't be flushed");
00090 }
00091 
00092 int FileStreamState_Closed::Read(Array<byte>& buffer, const int offset, int count)
00093 {
00094         throw new IOException("File is closed, so it can't be read");
00095 }
00096 
00097 int FileStreamState_Closed::ReadByte()
00098 {
00099         throw new IOException("File is closed, so it can't be read");
00100 }
00101 
00102 long FileStreamState_Closed::Seek(const long offset, const SeekOrigin origin)
00103 {
00104         throw new IOException("File is closed, so it can't be seeked");
00105 }
00106 
00107 void FileStreamState_Closed::Write(const Array<byte>& buffer, const int offset, const int count)
00108 {
00109         throw new IOException("File is closed, so it can't be written");
00110 }
00111 
00112 void FileStreamState_Closed::WriteByte(byte value)
00113 {
00114         throw new IOException("File is closed, so it can't be written");
00115 }
00116 
00117 bool FileStreamState_Closed::CanRead() const
00118 {
00119         throw new NotImplementedException();
00120 }
00121 
00122 bool FileStreamState_Closed::CanSeek() const
00123 {
00124         throw new NotImplementedException();
00125 }
00126 
00127 bool FileStreamState_Closed::CanWrite() const
00128 {
00129         throw new NotImplementedException();
00130 }
00131 
00132 long FileStreamState_Closed::Length() const
00133 {
00134         throw new IOException("File is closed");
00135 }
00136 
00137 long FileStreamState_Closed::Position() const
00138 {
00139         throw new IOException("File is closed");
00140 }
00141 
00142 #ifdef DEBUG
00143 void FileStreamState_Closed::ValidateMem() const
00144 {
00145 }
00146 
00147 void FileStreamState_Closed::CheckMem() const
00148 {
00149 }
00150 #endif
00151 
00152 class FileStreamState_Open : public IStreamState
00153 {
00154 public:
00155         FileStreamState_Open(IStream *parent, IStreamState **parentStateVar);
00156         virtual ~FileStreamState_Open();
00157 
00158         virtual void OnLeave(IStreamState *newState);
00159         virtual void OnEnter(IStreamState *oldState);
00160 
00161         virtual void Close();
00162         virtual void Flush();
00163         virtual int Read(Array<byte>& buffer, const int offset, int count);
00164         virtual int ReadByte();
00165         virtual long Seek(const long offset, const SeekOrigin origin);
00166         virtual void Write(const Array<byte>& buffer, const int offset, const int count);
00167         virtual void WriteByte(byte value);
00168 
00169         virtual bool CanRead() const;
00170         virtual bool CanSeek() const;
00171         virtual bool CanWrite() const;
00172 
00173         virtual long Length() const;
00174         virtual long Position() const;
00175 #ifdef DEBUG
00176         virtual void ValidateMem() const;
00177         virtual void CheckMem() const;
00178 #endif
00179 };
00180 
00181 FileStreamState_Open::FileStreamState_Open
00182 (
00183         IStream *parent, 
00184         IStreamState **parentStateVar
00185 )
00186 : IStreamState(parent, parentStateVar)
00187 {
00188 }
00189 
00190 FileStreamState_Open::~FileStreamState_Open()
00191 {
00192 }
00193 
00194 void FileStreamState_Open::OnLeave(IStreamState *newState)
00195 {
00196         if ( ((FileStream *)m_parent)->m_canClose )
00197         {
00198                 fclose( ((FileStream *)m_parent)->m_fp );
00199         }
00200 }
00201 
00202 void FileStreamState_Open::OnEnter(IStreamState *oldState)
00203 {
00204 }
00205 
00206 void FileStreamState_Open::Close()
00207 {
00208         IStreamState *newstate = new FileStreamState_Closed(m_parent, m_holder);
00209         ChangeState(newstate);
00210 }
00211 
00212 void FileStreamState_Open::Flush()
00213 {
00214         fflush( ((FileStream *)m_parent)->m_fp);
00215 }
00216 
00217 int FileStreamState_Open::Read(Array<byte>& buffer, const int offset, int count)
00218 {
00219         int ret = (int)fread(&buffer[offset], 1, count, ((FileStream *)m_parent)->m_fp);
00220         ((FileStream *)m_parent)->m_lasterr = errno;
00221         return ret;
00222 }
00223 
00224 int FileStreamState_Open::ReadByte()
00225 {
00226         return fgetc(((FileStream *)m_parent)->m_fp);
00227 }
00228 
00229 long FileStreamState_Open::Seek(const long offset, const SeekOrigin origin)
00230 {
00231         if ( origin == FileStream::SEEK_Current )
00232         {
00233                 return fseek(((FileStream *)m_parent)->m_fp, offset, SEEK_CUR);
00234         }
00235         else if ( origin == FileStream::SEEK_Begin )
00236         {
00237                 return fseek(((FileStream *)m_parent)->m_fp, offset, SEEK_SET);
00238         }
00239         else
00240         {
00241                 return fseek(((FileStream *)m_parent)->m_fp, offset, SEEK_END);
00242         }
00243 }
00244 
00245 void FileStreamState_Open::Write(const Array<byte>& buffer, const int offset, const int count)
00246 {
00247         fwrite(&buffer[offset], 1, count, ((FileStream *)m_parent)->m_fp);
00248         ((FileStream *)m_parent)->m_lasterr = errno;
00249 }
00250 
00251 void FileStreamState_Open::WriteByte(byte value)
00252 {
00253         fputc(value, ((FileStream *)m_parent)->m_fp);
00254         ((FileStream *)m_parent)->m_lasterr = errno;
00255 }
00256 
00257 bool FileStreamState_Open::CanRead() const
00258 {
00259         throw new NotImplementedException();
00260 }
00261 
00262 bool FileStreamState_Open::CanSeek() const
00263 {
00264         throw new NotImplementedException();
00265 }
00266 
00267 bool FileStreamState_Open::CanWrite() const
00268 {
00269         throw new NotImplementedException();
00270 }
00271 
00272 long FileStreamState_Open::Length() const
00273 {
00274         long oldpos = ftell(((FileStream *)m_parent)->m_fp);
00275         fseek(((FileStream *)m_parent)->m_fp, 0, SEEK_END);
00276         long size = ftell(((FileStream *)m_parent)->m_fp);
00277         fseek(((FileStream *)m_parent)->m_fp, oldpos, SEEK_SET);
00278         return size;
00279 }
00280 
00281 long FileStreamState_Open::Position() const
00282 {
00283         return ftell(((FileStream *)m_parent)->m_fp);
00284 }
00285 
00286 #ifdef DEBUG
00287 void FileStreamState_Open::ValidateMem() const
00288 {
00289 }
00290 
00291 void FileStreamState_Open::CheckMem() const
00292 {
00293 }
00294 #endif
00295 
00296 FileStream::FileStream(FILE *fp, File::FileAccess access, bool canClose)
00297 : m_filepathname(""), m_mode(File::FILEMODE_Open), m_access(access), m_canClose(canClose), m_lasterr(0), m_state(NULL)
00298 {
00299         m_fp = fp;
00300         m_state = new FileStreamState_Open(this, &m_state);
00301 }
00302 
00303 void FileStream::Init()
00304 {
00305         if ( File::Exists(m_filepathname) )
00306         {
00307                 if ( File::FILEMODE_CreateNew == m_mode )
00308                 {
00309                         throw new IOException("File exists");
00310                 }
00311                 if ( File::FILEMODE_Truncate == m_mode )
00312                 {
00313                         if ( NULL != (m_fp = _msokfopen(m_filepathname.GetChars(), "w")) )
00314                         {
00315                                 fclose(m_fp);
00316                         }
00317                 }
00318         }
00319         else if ( File::FILEMODE_Open == m_mode )
00320         {
00321                 throw new IOException("File not found");
00322         }
00323         else
00324         {
00325                 // create the file
00326                 if ( NULL != (m_fp = _msokfopen(m_filepathname.GetChars(), "a")) )
00327                 {
00328                         fclose(m_fp);
00329                 }
00330         }
00331         if ( File::FILEMODE_Append == m_mode )
00332         {
00333                 if ( File::FILEACC_Read == m_access )
00334                 {
00335                         m_fp = _msokfopen(m_filepathname.GetChars(), "a+b");
00336                 }
00337                 else
00338                 {
00339                         m_fp = _msokfopen(m_filepathname.GetChars(), "ab");
00340                 }
00341         }
00342         else
00343         {
00344                 if ( File::FILEACC_Read == m_access )
00345                 {
00346                         m_fp = _msokfopen(m_filepathname.GetChars(), "rb");
00347                 }
00348                 else if ( File::FILEACC_Write == m_access )
00349                 {
00350                         m_fp = _msokfopen(m_filepathname.GetChars(), "r+b");
00351                 }
00352                 else
00353                 {
00354                         m_fp = _msokfopen(m_filepathname.GetChars(), "r+b");
00355                 }
00356         }
00357         if ( NULL == m_fp )
00358         {
00359                 throw new IOException("Can't open file");
00360         }
00361         else
00362         {
00363                 m_state = new FileStreamState_Open(this, &m_state);
00364         }
00365 }
00366 
00367 FileStream::FileStream(const char *path, File::FileMode mode, File::FileAccess access)
00368 : m_filepathname(path), m_mode(mode), m_access(access), 
00369 m_canClose(true), m_lasterr(0), m_state(NULL)
00370 {
00371         Init();
00372 }
00373 
00374 FileStream::FileStream(const String& path, File::FileMode mode, File::FileAccess access)
00375 : m_filepathname(path), m_mode(mode), m_access(access), 
00376 m_canClose(true), m_lasterr(0), m_state(NULL)
00377 {
00378         Init();
00379 }
00380 
00381 FileStream::~FileStream()
00382 {
00383         Close();
00384         delete m_state;
00385 }
00386 
00387 void FileStream::Close()
00388 {
00389         m_state->Close();
00390 }
00391 
00392 void FileStream::Flush()
00393 {
00394         m_state->Flush();
00395 }
00396 
00397 int FileStream::Read(Array<byte>& buffer, const int offset, int count)
00398 {
00399         return m_state->Read(buffer, offset, count);
00400 }
00401 
00402 int FileStream::ReadByte()
00403 {
00404         return m_state->ReadByte();
00405 }
00406 
00407 long FileStream::Seek(const long offset, const SeekOrigin origin)
00408 {
00409         return m_state->Seek(offset, origin);
00410 }
00411 
00412 void FileStream::Write(const Array<byte>& buffer, const int offset, const int count)
00413 {
00414         m_state->Write(buffer, offset, count);
00415 }
00416 
00417 void FileStream::WriteByte(byte value)
00418 {
00419         m_state->WriteByte(value);
00420 }
00421 
00422 bool FileStream::CanRead() const
00423 {
00424         return m_access != File::FILEACC_Write;
00425 }
00426 
00427 bool FileStream::CanSeek() const
00428 {
00429         return true;
00430 }
00431 
00432 bool FileStream::CanWrite() const
00433 {
00434         return m_access != File::FILEACC_Read;
00435 }
00436 
00437 long FileStream::Length() const
00438 {
00439         return m_state->Length();
00440 }
00441 
00442 long FileStream::Position() const
00443 {
00444         return m_state->Position();
00445 }
00446 
00447 #ifdef DEBUG
00448 void FileStream::ValidateMem() const
00449 {
00450         m_filepathname.ValidateMem();
00451         ASSERT_PTR( m_state );
00452         m_state->ValidateMem();
00453 }
00454 
00455 void FileStream::CheckMem() const
00456 {
00457         m_filepathname.CheckMem();
00458         DEBUG_NOTE_MEM( m_state );
00459         m_state->CheckMem();
00460 }
00461 #endif