OVR_File.cpp
Go to the documentation of this file.
00001 /**************************************************************************
00002 
00003 Filename    :   OVR_File.cpp
00004 Content     :   File wrapper class implementation (Win32)
00005 
00006 Created     :   April 5, 1999
00007 Authors     :   Michael Antonov
00008 
00009 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
00010 
00011 Use of this software is subject to the terms of the Oculus license
00012 agreement provided at the time of installation or download, or which
00013 otherwise accompanies this software in either electronic or hard copy form.
00014 
00015 **************************************************************************/
00016 
00017 #define  GFILE_CXX
00018 
00019 // Standard C library (Captain Obvious guarantees!)
00020 #include <stdio.h>
00021 
00022 #include "OVR_File.h"
00023 
00024 namespace OVR {
00025 
00026 // Buffered file adds buffering to an existing file
00027 // FILEBUFFER_SIZE defines the size of internal buffer, while
00028 // FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
00029 #define FILEBUFFER_SIZE         (8192-8)
00030 #define FILEBUFFER_TOLERANCE    4096
00031 
00032 // ** Constructor/Destructor
00033 
00034 // Hidden constructor
00035 // Not supposed to be used
00036 BufferedFile::BufferedFile() : DelegatedFile(0)
00037 {
00038     pBuffer     = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
00039     BufferMode  = NoBuffer;
00040     FilePos     = 0;
00041     Pos         = 0;
00042     DataSize    = 0;
00043 }
00044 
00045 // Takes another file as source
00046 BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
00047 {
00048     pBuffer     = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
00049     BufferMode  = NoBuffer;
00050     FilePos     = pfile->LTell();
00051     Pos         = 0;
00052     DataSize    = 0;
00053 }
00054 
00055 
00056 // Destructor
00057 BufferedFile::~BufferedFile()
00058 {
00059     // Flush in case there's data
00060     if (pFile)
00061         FlushBuffer();
00062     // Get rid of buffer
00063     if (pBuffer)
00064         OVR_FREE(pBuffer);
00065 }
00066 
00067 /*
00068 bool    BufferedFile::VCopy(const Object &source)
00069 {
00070     if (!DelegatedFile::VCopy(source))
00071         return 0;
00072 
00073     // Data members
00074     BufferedFile *psource = (BufferedFile*)&source;
00075 
00076     // Buffer & the mode it's in
00077     pBuffer         = psource->pBuffer;
00078     BufferMode      = psource->BufferMode;
00079     Pos             = psource->Pos;
00080     DataSize        = psource->DataSize;
00081     return 1;
00082 }
00083 */
00084 
00085 // Initializes buffering to a certain mode
00086 bool    BufferedFile::SetBufferMode(BufferModeType mode)
00087 {
00088     if (!pBuffer)
00089         return false;
00090     if (mode == BufferMode)
00091         return true;
00092      
00093     FlushBuffer();
00094 
00095     // Can't set write mode if we can't write
00096     if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
00097         return 0;
00098 
00099     // And SetMode
00100     BufferMode = mode;
00101     Pos        = 0;
00102     DataSize   = 0;
00103     return 1;
00104 }
00105 
00106 // Flushes buffer
00107 void    BufferedFile::FlushBuffer()
00108 {
00109     switch(BufferMode)
00110     {
00111         case WriteBuffer:
00112             // Write data in buffer
00113             FilePos += pFile->Write(pBuffer,Pos);
00114             Pos = 0;
00115             break;
00116 
00117         case ReadBuffer:
00118             // Seek back & reset buffer data
00119             if ((DataSize-Pos)>0)
00120                 FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
00121             DataSize = 0;
00122             Pos      = 0;
00123             break;
00124         default:
00125             // not handled!
00126             break;
00127     }
00128 }
00129 
00130 // Reloads data for ReadBuffer
00131 void    BufferedFile::LoadBuffer()
00132 {
00133     if (BufferMode == ReadBuffer)
00134     {
00135         // We should only reload once all of pre-loaded buffer is consumed.
00136         OVR_ASSERT(Pos == DataSize);
00137 
00138         // WARNING: Right now LoadBuffer() assumes the buffer's empty
00139         int sz   = pFile->Read(pBuffer,FILEBUFFER_SIZE);
00140         DataSize = sz<0 ? 0 : (unsigned)sz;
00141         Pos      = 0;
00142         FilePos  += DataSize;
00143     }
00144 }
00145 
00146 
00147 // ** Overridden functions
00148 
00149 // We override all the functions that can possibly
00150 // require buffer mode switch, flush, or extra calculations
00151 
00152 // Tell() requires buffer adjustment
00153 int     BufferedFile::Tell()
00154 {
00155     if (BufferMode == ReadBuffer)
00156         return int (FilePos - DataSize + Pos);
00157 
00158     int pos = pFile->Tell();
00159     // Adjust position based on buffer mode & data
00160     if (pos!=-1)
00161     {
00162         OVR_ASSERT(BufferMode != ReadBuffer);
00163         if (BufferMode == WriteBuffer)
00164             pos += Pos;
00165     }
00166     return pos;
00167 }
00168 
00169 SInt64  BufferedFile::LTell()
00170 {
00171     if (BufferMode == ReadBuffer)
00172         return FilePos - DataSize + Pos;
00173 
00174     SInt64 pos = pFile->LTell();
00175     if (pos!=-1)
00176     {
00177         OVR_ASSERT(BufferMode != ReadBuffer);
00178         if (BufferMode == WriteBuffer)
00179             pos += Pos;
00180     }
00181     return pos;
00182 }
00183 
00184 int     BufferedFile::GetLength()
00185 {
00186     int len = pFile->GetLength();
00187     // If writing through buffer, file length may actually be bigger
00188     if ((len!=-1) && (BufferMode==WriteBuffer))
00189     {
00190         int currPos = pFile->Tell() + Pos;
00191         if (currPos>len)
00192             len = currPos;
00193     }
00194     return len;
00195 }
00196 SInt64  BufferedFile::LGetLength()
00197 {
00198     SInt64 len = pFile->LGetLength();
00199     // If writing through buffer, file length may actually be bigger
00200     if ((len!=-1) && (BufferMode==WriteBuffer))
00201     {
00202         SInt64 currPos = pFile->LTell() + Pos;
00203         if (currPos>len)
00204             len = currPos;
00205     }
00206     return len;
00207 }
00208 
00209 /*
00210 bool    BufferedFile::Stat(FileStats *pfs)
00211 {
00212     // Have to fix up length is stat
00213     if (pFile->Stat(pfs))
00214     {
00215         if (BufferMode==WriteBuffer)
00216         {
00217             SInt64 currPos = pFile->LTell() + Pos;
00218             if (currPos > pfs->Size)
00219             {
00220                 pfs->Size   = currPos;
00221                 // ??
00222                 pfs->Blocks = (pfs->Size+511) >> 9;
00223             }
00224         }
00225         return 1;
00226     }
00227     return 0;
00228 }
00229 */
00230 
00231 int     BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
00232 {
00233     if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
00234     {
00235         // If not data space in buffer, flush
00236         if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
00237         {
00238             FlushBuffer();
00239             // If bigger then tolerance, just write directly
00240             if (numBytes>FILEBUFFER_TOLERANCE)
00241             {
00242                 int sz = pFile->Write(psourceBuffer,numBytes);
00243                 if (sz > 0)
00244                     FilePos += sz;
00245                 return sz;
00246             }
00247         }
00248 
00249         // Enough space in buffer.. so copy to it
00250         memcpy(pBuffer+Pos, psourceBuffer, numBytes);
00251         Pos += numBytes;
00252         return numBytes;
00253     }
00254     int sz = pFile->Write(psourceBuffer,numBytes);
00255     if (sz > 0)
00256         FilePos += sz;
00257     return sz;
00258 }
00259 
00260 int     BufferedFile::Read(UByte *pdestBuffer, int numBytes)
00261 {
00262     if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
00263     {
00264         // Data in buffer... copy it
00265         if ((int)(DataSize-Pos) >= numBytes)
00266         {
00267             memcpy(pdestBuffer, pBuffer+Pos, numBytes);
00268             Pos += numBytes;
00269             return numBytes;
00270         }
00271 
00272         // Not enough data in buffer, copy buffer
00273         int     readBytes = DataSize-Pos;
00274         memcpy(pdestBuffer, pBuffer+Pos, readBytes);
00275         numBytes    -= readBytes;
00276         pdestBuffer += readBytes;
00277         Pos = DataSize;
00278 
00279         // Don't reload buffer if more then tolerance
00280         // (No major advantage, and we don't want to write a loop)
00281         if (numBytes>FILEBUFFER_TOLERANCE)
00282         {
00283             numBytes = pFile->Read(pdestBuffer,numBytes);
00284             if (numBytes > 0)
00285             {
00286                 FilePos += numBytes;
00287                 Pos = DataSize = 0;
00288             }
00289             return readBytes + ((numBytes==-1) ? 0 : numBytes);
00290         }
00291 
00292         // Reload the buffer
00293         // WARNING: Right now LoadBuffer() assumes the buffer's empty
00294         LoadBuffer();
00295         if ((int)(DataSize-Pos) < numBytes)
00296             numBytes = (int)DataSize-Pos;
00297 
00298         memcpy(pdestBuffer, pBuffer+Pos, numBytes);
00299         Pos += numBytes;
00300         return numBytes + readBytes;
00301         
00302         /*
00303         // Alternative Read implementation. The one above is probably better
00304         // due to FILEBUFFER_TOLERANCE.
00305         int     total = 0;
00306 
00307         do {
00308             int     bufferBytes = (int)(DataSize-Pos);
00309             int     copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
00310 
00311             memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
00312             numBytes    -= copyBytes;
00313             pdestBuffer += copyBytes;
00314             Pos         += copyBytes;
00315             total       += copyBytes;
00316 
00317             if (numBytes == 0)
00318                 break;
00319             LoadBuffer();
00320 
00321         } while (DataSize > 0);
00322 
00323         return total;
00324         */     
00325     }
00326     int sz = pFile->Read(pdestBuffer,numBytes);
00327     if (sz > 0)
00328         FilePos += sz;
00329     return sz;
00330 }
00331 
00332 
00333 int     BufferedFile::SkipBytes(int numBytes)
00334 {
00335     int skippedBytes = 0;
00336 
00337     // Special case for skipping a little data in read buffer
00338     if (BufferMode==ReadBuffer)
00339     {
00340         skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
00341         Pos          += skippedBytes;
00342         numBytes     -= skippedBytes;
00343     }
00344 
00345     if (numBytes)
00346     {
00347         numBytes = pFile->SkipBytes(numBytes);
00348         // Make sure we return the actual number skipped, or error
00349         if (numBytes!=-1)
00350         {
00351             skippedBytes += numBytes;
00352             FilePos += numBytes;
00353             Pos = DataSize = 0;
00354         }
00355         else if (skippedBytes <= 0)
00356             skippedBytes = -1;
00357     }
00358     return skippedBytes;
00359 }
00360 
00361 int     BufferedFile::BytesAvailable()
00362 {
00363     int available = pFile->BytesAvailable();
00364     // Adjust available size based on buffers
00365     switch(BufferMode)
00366     {
00367         case ReadBuffer:
00368             available += DataSize-Pos;
00369             break;
00370         case WriteBuffer:
00371             available -= Pos;
00372             if (available<0)
00373                 available= 0;
00374             break;
00375         default:
00376             break;
00377     }
00378     return available;
00379 }
00380 
00381 bool    BufferedFile::Flush()
00382 {
00383     FlushBuffer();
00384     return pFile->Flush();
00385 }
00386 
00387 // Seeking could be optimized better..
00388 int     BufferedFile::Seek(int offset, int origin)
00389 {    
00390     if (BufferMode == ReadBuffer)
00391     {
00392         if (origin == Seek_Cur)
00393         {
00394             // Seek can fall either before or after Pos in the buffer,
00395             // but it must be within bounds.
00396             if (((unsigned(offset) + Pos)) <= DataSize)
00397             {
00398                 Pos += offset;
00399                 return int (FilePos - DataSize + Pos);
00400             }
00401 
00402             // Lightweight buffer "Flush". We do this to avoid an extra seek
00403             // back operation which would take place if we called FlushBuffer directly.
00404             origin = Seek_Set;
00405             OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
00406             offset = (int)(FilePos - DataSize + Pos) + offset;
00407             Pos = DataSize = 0;
00408         }
00409         else if (origin == Seek_Set)
00410         {
00411             if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
00412             {
00413                 OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
00414                 Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
00415                 return offset;
00416             }
00417             Pos = DataSize = 0;
00418         }
00419         else
00420         {
00421             FlushBuffer();
00422         }
00423     }
00424     else
00425     {
00426         FlushBuffer();
00427     }    
00428 
00429     /*
00430     // Old Seek Logic
00431     if (origin == Seek_Cur && offset + Pos < DataSize)
00432     {
00433         //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
00434         Pos += offset;
00435         OVR_ASSERT(int (Pos) >= 0);
00436         return int (FilePos - DataSize + Pos);
00437     }
00438     else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
00439     {
00440         Pos = unsigned(offset - FilePos + DataSize);
00441         OVR_ASSERT(int (Pos) >= 0);
00442         return int (FilePos - DataSize + Pos);
00443     }   
00444     
00445     FlushBuffer();
00446     */
00447 
00448 
00449     FilePos = pFile->Seek(offset,origin);
00450     return int (FilePos);
00451 }
00452 
00453 SInt64  BufferedFile::LSeek(SInt64 offset, int origin)
00454 {
00455     if (BufferMode == ReadBuffer)
00456     {
00457         if (origin == Seek_Cur)
00458         {
00459             // Seek can fall either before or after Pos in the buffer,
00460             // but it must be within bounds.
00461             if (((unsigned(offset) + Pos)) <= DataSize)
00462             {
00463                 Pos += (unsigned)offset;
00464                 return SInt64(FilePos - DataSize + Pos);
00465             }
00466 
00467             // Lightweight buffer "Flush". We do this to avoid an extra seek
00468             // back operation which would take place if we called FlushBuffer directly.
00469             origin = Seek_Set;            
00470             offset = (SInt64)(FilePos - DataSize + Pos) + offset;
00471             Pos = DataSize = 0;
00472         }
00473         else if (origin == Seek_Set)
00474         {
00475             if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
00476             {                
00477                 Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
00478                 return offset;
00479             }
00480             Pos = DataSize = 0;
00481         }
00482         else
00483         {
00484             FlushBuffer();
00485         }
00486     }
00487     else
00488     {
00489         FlushBuffer();
00490     }
00491 
00492 /*
00493     OVR_ASSERT(BufferMode != NoBuffer);
00494 
00495     if (origin == Seek_Cur && offset + Pos < DataSize)
00496     {
00497         Pos += int (offset);
00498         return FilePos - DataSize + Pos;
00499     }
00500     else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
00501     {
00502         Pos = unsigned(offset - FilePos + DataSize);
00503         return FilePos - DataSize + Pos;
00504     }
00505 
00506     FlushBuffer();
00507     */
00508 
00509     FilePos = pFile->LSeek(offset,origin);
00510     return FilePos;
00511 }
00512 
00513 int     BufferedFile::CopyFromStream(File *pstream, int byteSize)
00514 {
00515     // We can't rely on overridden Write()
00516     // because delegation doesn't override virtual pointers
00517     // So, just re-implement
00518     UByte   buff[0x4000];
00519     int     count = 0;
00520     int     szRequest, szRead, szWritten;
00521 
00522     while(byteSize)
00523     {
00524         szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
00525 
00526         szRead    = pstream->Read(buff,szRequest);
00527         szWritten = 0;
00528         if (szRead > 0)
00529             szWritten = Write(buff,szRead);
00530 
00531         count   +=szWritten;
00532         byteSize-=szWritten;
00533         if (szWritten < szRequest)
00534             break;
00535     }
00536     return count;
00537 }
00538 
00539 // Closing files
00540 bool    BufferedFile::Close()
00541 {
00542     switch(BufferMode)
00543     {
00544         case WriteBuffer:
00545             FlushBuffer();
00546             break;
00547         case ReadBuffer:
00548             // No need to seek back on close
00549             BufferMode = NoBuffer;
00550             break;
00551         default:
00552             break;
00553     }
00554     return pFile->Close();
00555 }
00556 
00557 
00558 // ***** Global path helpers
00559 
00560 // Find trailing short filename in a path.
00561 const char* OVR_CDECL GetShortFilename(const char* purl)
00562 {    
00563     UPInt len = OVR_strlen(purl);
00564     for (UPInt i=len; i>0; i--) 
00565         if (purl[i]=='\\' || purl[i]=='/')
00566             return purl+i+1;
00567     return purl;
00568 }
00569 
00570 } // OVR
00571 


oculus_sdk
Author(s):
autogenerated on Mon Oct 6 2014 03:01:18