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

CATStreamRAM.cpp

Go to the documentation of this file.
00001 //---------------------------------------------------------------------------
00002 /// \file CATStreamRAM.cpp
00003 /// \brief RAM stream
00004 /// \ingroup CAT
00005 ///
00006 /// Copyright (c) 2003-2007 by Michael Ellison.
00007 /// See COPYING.txt for the \ref gaslicense License (MIT License).
00008 ///
00009 // $Author: mikeellison $
00010 // $Date: 2008-01-21 08:33:12 -0600 (Mon, 21 Jan 2008) $
00011 // $Revision:   $
00012 // $NoKeywords: $
00013 //
00014 //---------------------------------------------------------------------------
00015 #include "CATStreamRAM.h"
00016 #include "CATStreamFile.h"
00017 #include "CATStreamSub.h"
00018 
00019 // Default RAM streams to 10k in size. 
00020 const CATInt32 kCATSTREAM_DEFSIZE = 1024*10;
00021 
00022 CATStreamRAM::CATStreamRAM() : CATStream()
00023 {
00024    fRamCache   = 0;
00025    fCacheSize  = 0;
00026    fSize       = 0;
00027    fCurPos     = 0;   
00028 }
00029 
00030 //---------------------------------------------------------------------------
00031 // Destructor will clean up the RAM, but it'll
00032 // assert in debug mode if you do this.
00033 //
00034 // Please call Close() before destroying a stream if you
00035 // have opened it previously.
00036 // \sa Close()
00037 //---------------------------------------------------------------------------
00038 CATStreamRAM::~CATStreamRAM()
00039 {
00040    if (fRamCache != 0)
00041    {
00042       this->Close();
00043    }
00044 }
00045 
00046 //---------------------------------------------------------------------------
00047 // Open() opens a named RAM stream.
00048 //
00049 // Call close when done.
00050 //
00051 // \param pathname - CATString providing stream name
00052 // \param mode - combination of OPEN_MODE enumerated flags.
00053 //
00054 // \return CATResult - CAT_SUCCESS on success.
00055 // \sa Close()
00056 //---------------------------------------------------------------------------
00057 CATResult CATStreamRAM::Open(const CATWChar* name, OPEN_MODE mode)
00058 {   
00059    CATASSERT(fRamCache == 0, "Trying to open an already open stream!");
00060    if (fRamCache != 0)
00061    {
00062       // Argh... let 'em do it in release mode, but complain in debug.
00063       (void)this->Close();      
00064    }
00065       
00066    // Mode flags are currently ignored.
00067    fStreamName = name;
00068    
00069    fCacheSize = 0;
00070 
00071    try
00072    {
00073       fRamCache = new CATUInt8[kCATSTREAM_DEFSIZE];
00074       fCacheSize = kCATSTREAM_DEFSIZE;
00075    }
00076    catch (...)
00077    {
00078       fRamCache = 0;      
00079    }
00080 
00081    if (fRamCache == 0)
00082    {
00083       return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00084    }
00085 
00086    return CAT_SUCCESS;
00087 }
00088 
00089 //---------------------------------------------------------------------------
00090 // Close() closes a previously opened stream.
00091 // 
00092 // stream must have been previously successfuly opened.
00093 //
00094 // \return CATResult - CAT_SUCCESS on success.
00095 // \sa Open()
00096 //---------------------------------------------------------------------------
00097 CATResult CATStreamRAM::Close()
00098 {
00099    CATASSERT(fRamCache != 0, "Attempting to close an already closed stream.");
00100 
00101    CATASSERT(fSubCount == 0, "There are still substreams left open!");
00102    if (fSubCount != 0)
00103    {
00104       return CATRESULT(CAT_ERR_FILE_HAS_OPEN_SUBSTREAMS);
00105    }
00106     
00107    fStreamName = "";
00108    fCacheSize = 0;
00109 
00110    if (fRamCache == 0)
00111    {      
00112       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00113    }
00114 
00115    delete [] fRamCache;
00116    fRamCache = 0;
00117 
00118    return CAT_SUCCESS;
00119 }
00120 
00121 //---------------------------------------------------------------------------
00122 // IsOpen() returns true if the stream has been opened, and false otherwise.
00123 //
00124 // \return bool - true if stream is open.
00125 // \sa Open(), Close()
00126 //---------------------------------------------------------------------------
00127 bool CATStreamRAM::IsOpen()
00128 {
00129    return (fRamCache != 0);
00130 }
00131 
00132 
00133 //---------------------------------------------------------------------------
00134 // Read() reads the requested amount of data into a buffer.
00135 //
00136 // Will read up to, but not necessarily, [length] bytes.
00137 // On return, length is set to the number of bytes actually read.
00138 // buffer *must* be large enough for max value of length.
00139 // 
00140 // \param buffer - target buffer for read
00141 // \param length - min(length of buffer, desired read length).
00142 //        Set to amount read on return.
00143 // \return CATResult - CAT_SUCCESS on success
00144 // \sa Write()
00145 //---------------------------------------------------------------------------
00146 CATResult CATStreamRAM::Read(void* buffer, CATUInt32& length)
00147 {
00148    CATASSERT(fRamCache != 0, "Reading from closed file.");
00149    CATASSERT(buffer != 0, "Null buffer passed to read.");
00150 
00151    if (!IsOpen())
00152    {
00153       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00154    }
00155 
00156    if (fCurPos >= fSize)
00157    {
00158       length = 0;      
00159       return CATRESULT(CAT_STAT_FILE_AT_EOF);
00160    }
00161 
00162    CATUInt32 amountRead = 0;
00163    
00164    CATResult result = CAT_SUCCESS;
00165 
00166    if ((CATInt32)(fCurPos + length) >= fSize)
00167    {
00168       result = CATRESULT(CAT_STAT_FILE_AT_EOF);
00169       amountRead = fSize - fCurPos;
00170    }
00171    else
00172    {
00173       amountRead = length;
00174    }
00175 
00176    memcpy(buffer,fRamCache + fCurPos, amountRead);
00177    fCurPos += amountRead;
00178    length = amountRead;
00179 
00180    return result;
00181 }
00182 
00183 //---------------------------------------------------------------------------
00184 // Write() writes the requested amount of data from a buffer.
00185 //
00186 // Incomplete writes are treated as an error.
00187 // 
00188 // \param buffer - source buffer to write from.
00189 // \param length - length of data to write
00190 // \return CATResult - CAT_SUCCESS on success
00191 // \sa Read()
00192 //---------------------------------------------------------------------------
00193 CATResult CATStreamRAM::Write(const void* buffer, CATUInt32 length)
00194 {
00195    CATASSERT(fRamCache != 0, "Reading from closed file.");
00196    CATASSERT(buffer != 0, "Null buffer passed to read.");
00197 
00198    if (!IsOpen())
00199    {
00200       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00201    }
00202 
00203    CATUInt32 amountWritten = length; 
00204    if ((CATInt32)(fCurPos + amountWritten) > fCacheSize)
00205    {
00206       CATResult result = ReallocCache(amountWritten + fCurPos);
00207       if (CATFAILED(result))
00208       {
00209          return result;
00210       }
00211    }
00212    
00213    memcpy(fRamCache + fCurPos, buffer, amountWritten);
00214    fCurPos += amountWritten;
00215    if (fCurPos > fSize)
00216    {
00217       fSize = fCurPos;
00218    }
00219    
00220    return CAT_SUCCESS;
00221 }
00222 
00223 //---------------------------------------------------------------------------
00224 // Size() returns the size of the object in filesize.
00225 //
00226 // This should be cached and optimized later.
00227 //
00228 // This may not be supported on all stream types.
00229 // \param filesize - 64-bit length of file.
00230 // \return CATResult - CAT_SUCCESS on success
00231 //---------------------------------------------------------------------------
00232 CATResult CATStreamRAM::Size(CATInt64& filesize)
00233 {
00234    CATASSERT(fRamCache != 0, "File must be opened first.");
00235    if (!IsOpen())
00236    {
00237       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00238    }
00239 
00240    filesize = fSize;
00241 
00242    return CAT_SUCCESS;
00243 }
00244 
00245 //---------------------------------------------------------------------------
00246 // IsSeekable() returns true for files.
00247 //---------------------------------------------------------------------------
00248 bool CATStreamRAM::IsSeekable()
00249 {
00250    return true;
00251 }
00252 
00253 //---------------------------------------------------------------------------
00254 // SeekRelative() seeks from current position to a
00255 // relative location.
00256 //
00257 // \param offset - signed offset from current position
00258 // \return CATResult - CAT_SUCCESS on success.
00259 // \sa IsSeekable(), SeekAbsolute(), SeekFromEnd()
00260 //---------------------------------------------------------------------------
00261 CATResult CATStreamRAM::SeekRelative(CATInt32  offset)
00262 {         
00263    CATASSERT(fRamCache != 0, "File must be opened first.");
00264    if (!IsOpen())
00265    {
00266       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00267    }
00268 
00269    if (fCurPos + offset < 0)
00270    {
00271       fCurPos = 0;
00272       return CATRESULTFILE(CAT_ERR_FILE_SEEK,this->fStreamName);
00273    }
00274 
00275    if (fCurPos + offset > fCacheSize)
00276    {
00277       CATResult result = ReallocCache(fCurPos + offset);
00278       if (CATFAILED(result))
00279          return result;
00280    }
00281 
00282    fCurPos += offset;
00283    if (fCurPos > fSize)
00284       fSize = fCurPos;
00285             
00286    return CAT_SUCCESS;
00287 }
00288 
00289 
00290 //---------------------------------------------------------------------------
00291 // SeekAbsolute() seeks from the start of the file
00292 // to an absolute position.
00293 //
00294 // \param position - unsigned absolute position to seek to.
00295 // \return CATResult - CAT_SUCCESS on success.
00296 // \sa IsSeekable(), SeekRelative(), SeekFromEnd()
00297 //---------------------------------------------------------------------------
00298 CATResult CATStreamRAM::SeekAbsolute(CATInt64 position)
00299 {
00300    CATASSERT(fRamCache != 0, "File must be opened first.");
00301    if (!IsOpen())
00302    {
00303       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00304    }
00305 
00306    if (position > fCacheSize)
00307    {
00308       CATResult result = ReallocCache((CATInt32)position);
00309       if (CATFAILED(result))
00310       {
00311          return result;
00312       }
00313    }
00314 
00315    fCurPos = (CATInt32)position;
00316 
00317    if (fCurPos > fSize)
00318    {
00319       fSize = fCurPos;
00320    }
00321 
00322    return CAT_SUCCESS;
00323 }
00324 
00325 //---------------------------------------------------------------------------
00326 // SeekFromEnd() seeks from the end of the file.
00327 //
00328 // \param offset - signed offset from end of stream
00329 // \return CATResult - CAT_SUCCESS on success.
00330 // \sa IsSeekable(), SeekRelative(), SeekAbsolute()
00331 //---------------------------------------------------------------------------
00332 CATResult CATStreamRAM::SeekFromEnd(CATInt32 offset)
00333 {
00334    return SeekAbsolute(fSize - offset);
00335 }
00336 
00337 
00338 //---------------------------------------------------------------------------
00339 // GetPosition() returns the current position in the stream
00340 // in position.
00341 //
00342 // \param position - current position - set on successful return.
00343 // \return CATResult - CAT_SUCCESS on success.
00344 // \sa IsSeekable(), Size()
00345 //---------------------------------------------------------------------------
00346 CATResult CATStreamRAM::GetPosition(CATInt64& position)
00347 {
00348    CATASSERT(fRamCache != 0, "File must be opened first.");
00349    if (!IsOpen())
00350    {
00351       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00352    }
00353 
00354    position = fCurPos;
00355    return CAT_SUCCESS;
00356 }
00357 
00358 
00359 
00360 //---------------------------------------------------------------------------
00361 CATString CATStreamRAM::GetName() const
00362 {
00363    return fStreamName;
00364 }
00365 
00366 
00367 //---------------------------------------------------------------------------
00368 // ReallocCache() reallocates the cache memory to at least
00369 // as large as minLength.
00370 //---------------------------------------------------------------------------
00371 CATResult CATStreamRAM::ReallocCache( CATInt32 minLength )
00372 {
00373    // allocate more ram. Bail on failure.
00374    CATUInt8*  newRam = 0;
00375 
00376    // Default to doubling each time.
00377    CATInt32  newSize = fCacheSize*2;
00378    
00379    // If we're writing more than double, double the write size + cursize
00380    if ( minLength > newSize)
00381    {
00382       newSize = minLength * 2;
00383    }
00384 
00385    try 
00386    {
00387       newRam = new CATUInt8[newSize];
00388    }
00389    catch (...)
00390    {
00391       newRam = 0;
00392    }
00393 
00394    if (newRam == 0)
00395    {
00396       return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00397    }
00398    
00399    CATTRACE((CATString)"Reallocating from " << fCacheSize << " to " << newSize);
00400 
00401    // Copy and swap buffers
00402    memcpy(newRam,fRamCache,fSize);   
00403    delete [] fRamCache;
00404    fRamCache = newRam;         
00405    fCacheSize = newSize;
00406    return CAT_SUCCESS;
00407 }
00408 
00409 //---------------------------------------------------------------------------
00410 // ShrinkCache() shrinks the cache to exactly the current fSize().
00411 //---------------------------------------------------------------------------
00412 CATResult CATStreamRAM::ShrinkCache()
00413 {
00414    // allocate more ram. Bail on failure.
00415    CATUInt8*  newRam = 0;
00416 
00417    // Default to doubling each time.
00418    CATInt32  newSize = fSize;
00419    
00420    try 
00421    {
00422       newRam = new CATUInt8[newSize];
00423    }
00424    catch (...)
00425    {
00426       newRam = 0;
00427    }
00428 
00429    if (newRam == 0)
00430    {
00431       return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00432    }
00433    
00434    memcpy(newRam, fRamCache, fSize);
00435    delete [] fRamCache;  
00436    fRamCache = newRam;
00437    fCacheSize = newSize;   
00438    return CAT_SUCCESS;
00439 }
00440 
00441 //---------------------------------------------------------------------------
00442 // FromFile() loads a file into the RAM stream. This is analogous
00443 // to calling Open() on a file stream, only your read/writes
00444 // will be a hell of a lot faster.
00445 //
00446 // As in Open(), please close prior to opening a new one, and 
00447 // close before destroying.
00448 //
00449 // \param pathName - path of file to open
00450 //
00451 // \return CATResult - CAT_SUCCESS on success.
00452 //---------------------------------------------------------------------------
00453 CATResult CATStreamRAM::FromFile(const CATWChar* pathName)
00454 {
00455    CATResult result = CAT_SUCCESS;
00456 
00457    CATASSERT(fRamCache == 0, "Trying to open an already open stream!");
00458    if (fRamCache != 0)
00459    {
00460       // Argh... let 'em do it in release mode, but complain in debug.
00461       (void)this->Close();      
00462    }
00463 
00464    CATStreamFile *fileStream = new CATStreamFile();
00465    if (CATFAILED(result = fileStream->Open(pathName,CATStream::READ_ONLY)))
00466    {
00467       delete fileStream;
00468       return result;
00469    }
00470 
00471    CATInt64 fileSize = 0;
00472    fileStream->Size(fileSize);
00473 
00474    this->fCacheSize = (CATInt32)fileSize;
00475    this->fSize = fCacheSize;
00476    
00477    try
00478    {
00479       this->fRamCache = new CATUInt8[fSize];
00480    }
00481    catch (...)
00482    {
00483       this->fRamCache = 0;
00484    }
00485 
00486    if (fRamCache == 0)
00487    {
00488       fCacheSize = 0;
00489       fSize = 0;
00490       fileStream->Close();
00491       delete fileStream;
00492       return CATRESULT(CAT_ERR_OUT_OF_MEMORY);
00493    }
00494 
00495    CATUInt32 readSize = (CATUInt32)fSize;
00496    result = fileStream->Read(fRamCache,readSize);
00497 
00498    CATASSERT((CATInt32)readSize == fSize, "Error reading entire file!");
00499 
00500    (void)fileStream->Close();
00501    delete fileStream;
00502 
00503    return result;
00504 }
00505 
00506 //---------------------------------------------------------------------------
00507 // ToFile() saves the stream to a file.
00508 //
00509 // \param pathName - path of file to save
00510 // \param overwrite - if false, will return an error if the file already exists.
00511 //
00512 // \return CATResult - CAT_SUCCESS on success.
00513 //---------------------------------------------------------------------------
00514 CATResult CATStreamRAM::ToFile(const CATWChar* pathName, bool overwrite)
00515 {
00516    CATResult result = CAT_SUCCESS;
00517 
00518    CATASSERT(fRamCache != 0, "Trying to open an already open stream!");
00519    if (fRamCache == 0)
00520    {
00521       return CATRESULT(CAT_ERR_FILE_NOT_OPEN);
00522    }
00523 
00524    CATStreamFile *fileStream = new CATStreamFile();
00525    if (overwrite == false)
00526    {
00527       if (CATSUCCEEDED(result = fileStream->Open(pathName,CATStream::READ_ONLY)))
00528       {
00529          fileStream->Close();
00530          delete fileStream;
00531          return CATRESULT(CAT_ERR_FILE_ALREADY_EXISTS);
00532       }
00533    }
00534 
00535    if (CATFAILED(result = fileStream->Open(pathName,CATStream::READ_WRITE_CREATE_TRUNC)))
00536    {
00537       fileStream->Close();
00538       delete fileStream;
00539       return result;
00540    }
00541 
00542    result = fileStream->Write(fRamCache,fSize);
00543 
00544    (void)fileStream->Close();
00545    delete fileStream;
00546 
00547 
00548    return result;
00549 }
00550 
00551 //---------------------------------------------------------------------------
00552 // GetRawCache() retrieves a raw pointer to the buffer.
00553 // WARNING: this pointer is only valid until another stream command
00554 // is made.  Stream operations may change the cache pointer, causing
00555 // use of the returned pointer to cause an access violation.
00556 // \return CATUInt8* - temporary pointer to cache
00557 //---------------------------------------------------------------------------
00558 CATUInt8* CATStreamRAM::GetRawCache()
00559 {
00560    return fRamCache;
00561 }
00562 
00563 //---------------------------------------------------------------------------
00564 // ReadAbs() reads from the specified location, but does
00565 // not change the current stream position.
00566 //
00567 // ReadAbs() is mainly for use in substreams, and may not be
00568 // available from all stream types.  If you're not implementing
00569 // it, then please return an error from your derived class.
00570 //
00571 // \param buffer - target buffer for read
00572 // \param length - min(length of buffer, desired read length).
00573 //                 set to amount read on return.
00574 // \param position - position within stream to read.
00575 //  \return CATRESULT - CAT_SUCCESS on success.
00576 //---------------------------------------------------------------------------
00577 CATResult CATStreamRAM::ReadAbs(void *buffer, CATUInt32& length, CATInt64 position)
00578 {
00579    CATResult result = CAT_SUCCESS;
00580    CATInt64 orgPos = 0;
00581 
00582    if (CATFAILED(result = this->GetPosition(orgPos)))
00583    {
00584       return result;
00585    }
00586    
00587    // On errors, at least try to restore the old position.
00588    if (CATFAILED(result = this->SeekAbsolute(position)))
00589    {
00590       this->SeekAbsolute(orgPos);
00591       return result;
00592    }
00593 
00594    if (CATFAILED(result = this->Read(buffer,length)))
00595    {
00596       this->SeekAbsolute(orgPos);
00597       return result;
00598    }
00599 
00600    return this->SeekAbsolute(orgPos);
00601 }
00602 
00603 //---------------------------------------------------------------------------
00604 // WriteAbs() Writes from the specified location, but does
00605 // not change the current stream position.
00606 //
00607 // WriteAbs() is mainly for use in substreams, and may not be
00608 // available from all stream types.  If you're not implementing
00609 // it, then please return an error from your derived class.
00610 //
00611 // \param buffer - target buffer for Write
00612 // \param length - length of data to write        
00613 // \param position - position within stream to read.
00614 //  \return CATRESULT - CAT_SUCCESS on success.
00615 //---------------------------------------------------------------------------
00616 CATResult CATStreamRAM::WriteAbs(const void *buffer, CATUInt32 length, CATInt64 position)
00617 {
00618    CATResult result = CAT_SUCCESS;
00619    CATInt64 orgPos = 0;
00620 
00621    if (CATFAILED(result = this->GetPosition(orgPos)))
00622    {
00623       return result;
00624    }
00625    
00626    // On errors, at least try to restore the old position.
00627    if (CATFAILED(result = this->SeekAbsolute(position)))
00628    {
00629       this->SeekAbsolute(orgPos);
00630       return result;
00631    }
00632 
00633    if (CATFAILED(result = this->Write(buffer,length)))
00634    {
00635       this->SeekAbsolute(orgPos);
00636       return result;
00637    }
00638 
00639    return this->SeekAbsolute(orgPos);
00640 }
00641 

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