Game Accessibility Library logo SourceForge.net Logo
Game Accessibility Suite: CAT/CATStreamFile.cpp Source File

CATStreamFile.cpp

Go to the documentation of this file.
00001 /// \file CATStreamFile.cpp
00002 /// \brief File stream class
00003 /// \ingroup CAT
00004 ///
00005 /// Copyright (c) 2003-2007 by Michael Ellison.
00006 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00007 ///
00008 // $Author: mikeellison $
00009 // $Date: 2008-01-21 08:33:12 -0600 (Mon, 21 Jan 2008) $
00010 // $Revision:   $
00011 // $NoKeywords: $
00012 
00013 #include "CATStreamFile.h"
00014 #include "CATStreamSub.h"
00015 
00016 CATStreamFile::CATStreamFile() : CATStream()
00017 {
00018    fFileHandle = 0;
00019 }
00020 
00021 //---------------------------------------------------------------------------
00022 // Destructor will close file handle if its unclosed, but
00023 // will assert in debug mode if you do this.
00024 //
00025 // Please call Close() before destroying a file if you
00026 // have opened it previously.
00027 // \sa Close()
00028 //---------------------------------------------------------------------------
00029 CATStreamFile::~CATStreamFile()
00030 {   
00031    CATASSERT(fFileHandle == 0, "Close your streams....");
00032    if (fFileHandle != 0)
00033    {
00034       this->Close();
00035    }
00036 }
00037 
00038 // Open() opens a file from a pathname.
00039 //
00040 // Call close when done.
00041 CATResult CATStreamFile::Open(const CATWChar* pathname, OPEN_MODE mode)
00042 {   
00043    CATASSERT(fFileHandle == 0, "Trying to open an already open stream!");
00044    if (fFileHandle != 0)
00045    {
00046       // Argh... let 'em do it in release mode, but complain in debug.
00047       (void)this->Close();      
00048    }
00049       
00050    // fopen() interface doesn't split these cleanly.
00051    // 
00052    // Sharing is unsupported in generic CATStreamFile,
00053    // thus we can just switch on modes.
00054 
00055    switch (mode)
00056    {
00057       case READ_ONLY:
00058          fFileHandle = _wfopen(pathname,L"rb");
00059          break;
00060 
00061       case READ_WRITE_EXISTING_ONLY:
00062          fFileHandle = _wfopen(pathname,L"rb+");
00063          break;
00064 
00065       case READ_WRITE_EXISTING_FIRST:
00066          fFileHandle = _wfopen(pathname,L"rb+");
00067          if (fFileHandle == 0)
00068          {
00069             fFileHandle = _wfopen(pathname,L"wb+");
00070          }
00071          break;
00072 
00073       case READ_WRITE_CREATE_TRUNC:  
00074           {
00075               DWORD attribs = ::GetFileAttributes(pathname);
00076               if (attribs != 0xFFFFFFFF)
00077                   ::DeleteFile(pathname);
00078               
00079              fFileHandle = _wfopen(pathname,L"wb+");
00080           }
00081          break;
00082 
00083         case WRITE_CREATE_ONLY:
00084             fFileHandle = _wfopen(pathname,L"wb");
00085             break;
00086 
00087       default:
00088          CATASSERT(false,"Unsupported open mode.");
00089          return CATRESULT(CAT_ERR_FILE_UNSUPPORTED_MODE);
00090          break;
00091    }
00092 
00093    if (fFileHandle == 0)
00094    {
00095       return CATRESULTFILE(CAT_ERR_FILE_OPEN,pathname);
00096    }
00097 
00098    fFilename = pathname;
00099 
00100    return CATRESULT(CAT_SUCCESS);
00101 }
00102 
00103 //---------------------------------------------------------------------------
00104 // Close() closes a previously opened file.
00105 // 
00106 // File must have been previously successfuly opened.
00107 //
00108 // \return CATResult - CAT_SUCCESS on success.
00109 // \sa Open()
00110 //---------------------------------------------------------------------------
00111 CATResult CATStreamFile::Close()
00112 {
00113    CATASSERT(fFileHandle != 0, "Attempting to close an already closed file.");
00114  
00115    CATASSERT(fSubCount == 0, "There are still substreams left open!");
00116    if (fSubCount != 0)
00117    {
00118       return CATRESULT(CAT_ERR_FILE_HAS_OPEN_SUBSTREAMS);
00119    }
00120  
00121    
00122 
00123 
00124    if (fFileHandle == 0)
00125    {
00126       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00127    }
00128 
00129    fFilename = L"";
00130    
00131    fclose(fFileHandle);
00132    fFileHandle = 0;
00133 
00134    return CATRESULT(CAT_SUCCESS);
00135 }
00136 
00137 //---------------------------------------------------------------------------
00138 // IsOpen() returns true if the file has been opened, and false otherwise.
00139 //
00140 // \return bool - true if file is open.
00141 // \sa Open(), Close()
00142 //---------------------------------------------------------------------------
00143 bool CATStreamFile::IsOpen()
00144 {
00145    return (fFileHandle != 0);
00146 }
00147 
00148 
00149 //---------------------------------------------------------------------------
00150 // Read() reads the requested amount of data into a buffer.
00151 //
00152 // Will read up to, but not necessarily, [length] bytes.
00153 // On return, length is set to the number of bytes actually read.
00154 // buffer *must* be large enough for max value of length.
00155 // 
00156 // \param buffer - target buffer for read
00157 // \param length - min(length of buffer, desired read length).
00158 //        Set to amount read on return.
00159 // \return CATResult - CAT_SUCCESS on success
00160 // \sa Write()
00161 //---------------------------------------------------------------------------
00162 CATResult CATStreamFile::Read(void* buffer, CATUInt32& length)
00163 {
00164    CATASSERT(fFileHandle != 0, "Reading from closed file.");
00165    CATASSERT(buffer != 0, "Null buffer passed to read.");
00166 
00167    if (!IsOpen())
00168    {
00169       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00170    }
00171 
00172    CATUInt32 amountRead = (CATUInt32)fread(buffer,1,length,fFileHandle);
00173    if (length != amountRead)
00174    {
00175       if (feof(fFileHandle))
00176       {
00177          // File is at eof. Store amount read, return status code.
00178          // Note: this status is not an error code - user must
00179          // check explicitly.
00180          length = amountRead;
00181          return CATRESULT(CAT_STAT_FILE_AT_EOF);
00182       }
00183 
00184       length = amountRead;
00185       return CATRESULTFILE(CAT_ERR_FILE_READ,fFilename);
00186    }
00187    else
00188    {
00189       return CATRESULT(CAT_SUCCESS);
00190    }
00191 }
00192 
00193 //---------------------------------------------------------------------------
00194 // Write() writes the requested amount of data from a buffer.
00195 //
00196 // Incomplete writes are treated as an error.
00197 // 
00198 // \param buffer - source buffer to write from.
00199 // \param length - length of data to write
00200 // \return CATResult - CAT_SUCCESS on success
00201 // \sa Read()
00202 //---------------------------------------------------------------------------
00203 CATResult CATStreamFile::Write(const void* buffer, CATUInt32 length)
00204 {
00205    CATASSERT(fFileHandle != 0, "Reading from closed file.");
00206    CATASSERT(buffer != 0, "Null buffer passed to read.");
00207 
00208    if (!IsOpen())
00209    {
00210       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00211    }
00212 
00213    CATUInt32 amountWritten = (CATUInt32)fwrite(buffer,1,length,fFileHandle);
00214 
00215    if (length != amountWritten)
00216    {
00217       return CATRESULTFILE(CAT_ERR_FILE_WRITE,fFilename);
00218    }
00219    else
00220    {
00221       // Allow for immediate read
00222       fflush(fFileHandle);
00223       return CAT_SUCCESS;
00224    }
00225 }
00226 
00227 //---------------------------------------------------------------------------
00228 // Size() returns the size of the object in filesize.
00229 //
00230 // This should be cached and optimized later.
00231 //
00232 // This may not be supported on all stream types.
00233 // \param filesize - 64-bit length of file.
00234 // \return CATResult - CAT_SUCCESS on success
00235 //---------------------------------------------------------------------------
00236 CATResult CATStreamFile::Size(CATInt64& filesize)
00237 {
00238    CATASSERT(fFileHandle != 0, "File must be opened first.");
00239    if (!IsOpen())
00240    {
00241       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00242    }
00243 
00244    // Get current position so we can restore it later.
00245    fpos_t curPos;
00246    if (0 != fgetpos(fFileHandle, &curPos))
00247    {
00248       return CATRESULTFILE(CAT_ERR_FILE_GET_POSITION,fFilename);
00249    }
00250 
00251    // Go to the end of the file, then get the position.
00252    if (0 != fseek(fFileHandle,0,SEEK_END))
00253    {
00254       return CATRESULTFILE(CAT_ERR_FILE_SEEK,fFilename);
00255    }
00256    
00257    fpos_t eofPos;
00258 
00259    if (0 != fgetpos(fFileHandle, &eofPos))
00260    {
00261       return CATRESULTFILE(CAT_ERR_FILE_GET_POSITION,fFilename);
00262    }
00263 
00264    // Return to original pos
00265    if (0 != fsetpos(fFileHandle,&curPos))
00266    {
00267       return CATRESULTFILE(CAT_ERR_FILE_SET_POSITION,fFilename);
00268    }
00269 
00270    filesize = eofPos;
00271 
00272    return CAT_SUCCESS;
00273 }
00274 
00275 //---------------------------------------------------------------------------
00276 // IsSeekable() returns true for files.
00277 //---------------------------------------------------------------------------
00278 bool CATStreamFile::IsSeekable()
00279 {
00280    return true;
00281 }
00282 
00283 //---------------------------------------------------------------------------
00284 // SeekRelative() seeks from current position to a
00285 // relative location.
00286 //
00287 // \param offset - signed offset from current position
00288 // \return CATResult - CAT_SUCCESS on success.
00289 // \sa IsSeekable(), SeekAbsolute(), SeekFromEnd()
00290 //---------------------------------------------------------------------------
00291 CATResult CATStreamFile::SeekRelative(CATInt32  offset)
00292 {
00293    CATASSERT(fFileHandle != 0, "File must be opened first.");
00294    if (!IsOpen())
00295    {
00296       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00297    }
00298 
00299    if ( 0 != fseek(fFileHandle,offset,SEEK_CUR))
00300    {
00301       return CATRESULTFILE(CAT_ERR_FILE_SEEK,fFilename);
00302    }
00303    return CAT_SUCCESS;
00304 }
00305 
00306 
00307 //---------------------------------------------------------------------------
00308 // SeekAbsolute() seeks from the start of the file
00309 // to an absolute position.
00310 //
00311 // \param position - unsigned absolute position to seek to.
00312 // \return CATResult - CAT_SUCCESS on success.
00313 // \sa IsSeekable(), SeekRelative(), SeekFromEnd()
00314 //---------------------------------------------------------------------------
00315 CATResult CATStreamFile::SeekAbsolute(CATInt64 position)
00316 {
00317    CATASSERT(fFileHandle != 0, "File must be opened first.");
00318    if (!IsOpen())
00319    {
00320       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00321    }
00322 
00323    fpos_t filePos = position;
00324    if (0 != fsetpos(fFileHandle,&filePos))
00325    {
00326       return CATRESULTFILE(CAT_ERR_FILE_SET_POSITION,fFilename);
00327    }
00328 
00329    return CAT_SUCCESS;
00330 }
00331 
00332 //---------------------------------------------------------------------------
00333 // SeekFromEnd() seeks from the end of the file.
00334 //
00335 // \param offset - signed offset from end of stream
00336 // \return CATResult - CAT_SUCCESS on success.
00337 // \sa IsSeekable(), SeekRelative(), SeekAbsolute()
00338 //---------------------------------------------------------------------------
00339 CATResult CATStreamFile::SeekFromEnd(CATInt32 offset)
00340 {
00341    CATASSERT(fFileHandle != 0, "File must be opened first.");
00342    if (!IsOpen())
00343    {
00344       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00345    }
00346 
00347    if (0 != fseek(fFileHandle,-offset,SEEK_END))
00348    {
00349       return CATRESULTFILE(CAT_ERR_FILE_SEEK,fFilename);
00350    }
00351 
00352    return CAT_SUCCESS;
00353 }
00354 
00355 
00356 //---------------------------------------------------------------------------
00357 // GetPosition() returns the current position in the stream
00358 // in position.
00359 //
00360 // \param position - current position - set on successful return.
00361 // \return CATResult - CAT_SUCCESS on success.
00362 // \sa IsSeekable(), Size()
00363 //---------------------------------------------------------------------------
00364 CATResult CATStreamFile::GetPosition(CATInt64& position)
00365 {
00366    CATASSERT(fFileHandle != 0, "File must be opened first.");
00367    if (!IsOpen())
00368    {
00369       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00370    }
00371 
00372    fpos_t curPos;
00373    if (0 != fgetpos(fFileHandle, &curPos))
00374    {
00375       return CATRESULTFILE(CAT_ERR_FILE_GET_POSITION,fFilename);
00376    }
00377 
00378    position = curPos;
00379 
00380    return CAT_SUCCESS;
00381 }
00382 
00383 
00384 
00385 //---------------------------------------------------------------------------
00386 CATString CATStreamFile::GetName() const
00387 {
00388    return fFilename;
00389 }
00390 
00391 //---------------------------------------------------------------------------
00392 // ReadAbs() reads from the specified location, but does
00393 // not change the current stream position.
00394 //
00395 // ReadAbs() is mainly for use in substreams, and may not be
00396 // available from all stream types.  If you're not implementing
00397 // it, then please return an error from your derived class.
00398 //
00399 // \param buffer - target buffer for read
00400 // \param length - min(length of buffer, desired read length).
00401 //                 set to amount read on return.
00402 // \param position - position within stream to read.
00403 //  \return CATResult - CAT_SUCCESS on success.
00404 //---------------------------------------------------------------------------
00405 CATResult CATStreamFile::ReadAbs(void *buffer, CATUInt32& length, CATInt64 position)
00406 {
00407    CATResult result = CAT_SUCCESS;
00408    CATInt64 orgPos = 0;
00409 
00410    if (CATFAILED(result = this->GetPosition(orgPos)))
00411    {
00412       return result;
00413    }
00414    
00415    // On errors, at least try to restore the old position.
00416    if (CATFAILED(result = this->SeekAbsolute(position)))
00417    {
00418       this->SeekAbsolute(orgPos);
00419       return result;
00420    }
00421 
00422    if (CATFAILED(result = this->Read(buffer,length)))
00423    {
00424       this->SeekAbsolute(orgPos);
00425       return result;
00426    }
00427 
00428    return this->SeekAbsolute(orgPos);
00429 }
00430 
00431 //---------------------------------------------------------------------------
00432 // WriteAbs() Writes from the specified location, but does
00433 // not change the current stream position.
00434 //
00435 // WriteAbs() is mainly for use in substreams, and may not be
00436 // available from all stream types.  If you're not implementing
00437 // it, then please return an error from your derived class.
00438 //
00439 // \param buffer - target buffer for Write
00440 // \param length - length of data to write        
00441 // \param position - position within stream to read.
00442 //  \return CATResult - CAT_SUCCESS on success.
00443 //---------------------------------------------------------------------------
00444 CATResult CATStreamFile::WriteAbs(const void *buffer, CATUInt32 length, CATInt64 position)
00445 {
00446    CATResult result = CAT_SUCCESS;
00447    CATInt64 orgPos = 0;
00448 
00449    if (CATFAILED(result = this->GetPosition(orgPos)))
00450    {
00451       return result;
00452    }
00453    
00454    // On errors, at least try to restore the old position.
00455    if (CATFAILED(result = this->SeekAbsolute(position)))
00456    {
00457       this->SeekAbsolute(orgPos);
00458       return result;
00459    }
00460 
00461    if (CATFAILED(result = this->Write(buffer,length)))
00462    {
00463       this->SeekAbsolute(orgPos);
00464       return result;
00465    }
00466 
00467    return this->SeekAbsolute(orgPos);
00468 }
00469 

Generated on Mon Feb 11 04:09:47 2008 for Game Accessibility Suite by doxygen 1.5.4