OVR_FileFILE.cpp
Go to the documentation of this file.
00001 /**************************************************************************
00002 
00003 Filename    :   OVR_FileFILE.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 #include "OVR_Types.h"
00020 #include "OVR_Log.h"
00021 
00022 // Standard C library (Captain Obvious guarantees!)
00023 #include <stdio.h>
00024 #ifndef OVR_OS_WINCE
00025 #include <sys/stat.h>
00026 #endif
00027 
00028 #include "OVR_SysFile.h"
00029 
00030 #ifndef OVR_OS_WINCE
00031 #include <errno.h>
00032 #endif
00033 
00034 namespace OVR {
00035 
00036 // ***** File interface
00037 
00038 // ***** FILEFile - C streams file
00039 
00040 static int SFerror ()
00041 {
00042     if (errno == ENOENT)
00043         return FileConstants::Error_FileNotFound;
00044     else if (errno == EACCES || errno == EPERM)
00045         return FileConstants::Error_Access;
00046     else if (errno == ENOSPC)
00047         return FileConstants::Error_DiskFull;
00048     else
00049         return FileConstants::Error_IOError;
00050 };
00051 
00052 #ifdef OVR_OS_WIN32
00053 #include "windows.h"
00054 // A simple helper class to disable/enable system error mode, if necessary
00055 // Disabling happens conditionally only if a drive name is involved
00056 class SysErrorModeDisabler
00057 {
00058     BOOL    Disabled;
00059     UINT    OldMode;
00060 public:
00061     SysErrorModeDisabler(const char* pfileName)
00062     {
00063         if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
00064         {
00065             Disabled = 1;
00066             OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
00067         }
00068         else
00069             Disabled = 0;
00070     }
00071 
00072     ~SysErrorModeDisabler()
00073     {
00074         if (Disabled) ::SetErrorMode(OldMode);
00075     }
00076 };
00077 #else
00078 class SysErrorModeDisabler
00079 {
00080 public:
00081     SysErrorModeDisabler(const char* pfileName) { }
00082 };
00083 #endif // OVR_OS_WIN32
00084 
00085 
00086 // This macro enables verification of I/O results after seeks against a pre-loaded
00087 // full file buffer copy. This is generally not necessary, but can been used to debug
00088 // memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
00089 // under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
00090 //#define GFILE_VERIFY_SEEK_ERRORS
00091 
00092 
00093 // This is the simplest possible file implementation, it wraps around the descriptor
00094 // This file is delegated to by SysFile.
00095 
00096 class FILEFile : public File
00097 {
00098 protected:
00099 
00100     // Allocated filename
00101     String      FileName;
00102 
00103     // File handle & open mode
00104     bool        Opened;
00105     FILE*       fs;
00106     int         OpenFlags;
00107     // Error code for last request
00108     int         ErrorCode;
00109 
00110     int         LastOp;
00111 
00112 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00113     UByte*      pFileTestBuffer;
00114     unsigned    FileTestLength;
00115     unsigned    TestPos; // File pointer position during tests.
00116 #endif
00117 
00118 public:
00119 
00120     FILEFile()
00121     {
00122         Opened = 0; FileName = "";
00123 
00124 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00125         pFileTestBuffer =0;
00126         FileTestLength  =0;
00127         TestPos         =0;
00128 #endif
00129     }
00130     // Initialize file by opening it
00131     FILEFile(const String& fileName, int flags, int Mode);
00132     // The 'pfileName' should be encoded as UTF-8 to support international file names.
00133     FILEFile(const char* pfileName, int flags, int Mode);
00134 
00135     ~FILEFile()
00136     {
00137         if (Opened)
00138             Close();
00139     }
00140 
00141     virtual const char* GetFilePath();
00142 
00143     // ** File Information
00144     virtual bool        IsValid();
00145     virtual bool        IsWritable();
00146 
00147     // Return position / file size
00148     virtual int         Tell();
00149     virtual SInt64      LTell();
00150     virtual int         GetLength();
00151     virtual SInt64      LGetLength();
00152 
00153 //  virtual bool        Stat(FileStats *pfs);
00154     virtual int         GetErrorCode();
00155 
00156     // ** Stream implementation & I/O
00157     virtual int         Write(const UByte *pbuffer, int numBytes);
00158     virtual int         Read(UByte *pbuffer, int numBytes);
00159     virtual int         SkipBytes(int numBytes);
00160     virtual int         BytesAvailable();
00161     virtual bool        Flush();
00162     virtual int         Seek(int offset, int origin);
00163     virtual SInt64      LSeek(SInt64 offset, int origin);
00164     
00165     virtual int         CopyFromStream(File *pStream, int byteSize);
00166     virtual bool        Close();    
00167 private:
00168     void                init();
00169 };
00170 
00171 
00172 // Initialize file by opening it
00173 FILEFile::FILEFile(const String& fileName, int flags, int mode)
00174   : FileName(fileName), OpenFlags(flags)
00175 {
00176     OVR_UNUSED(mode);
00177     init();
00178 }
00179 
00180 // The 'pfileName' should be encoded as UTF-8 to support international file names.
00181 FILEFile::FILEFile(const char* pfileName, int flags, int mode)
00182   : FileName(pfileName), OpenFlags(flags)
00183 {
00184     OVR_UNUSED(mode);
00185     init();
00186 }
00187 
00188 void FILEFile::init()
00189 {
00190     // Open mode for file's open
00191     const char *omode = "rb";
00192 
00193     if (OpenFlags & Open_Truncate)
00194     {
00195         if (OpenFlags & Open_Read)
00196             omode = "w+b";
00197         else
00198             omode = "wb";
00199     }
00200     else if (OpenFlags & Open_Create)
00201     {
00202         if (OpenFlags & Open_Read)
00203             omode = "a+b";
00204         else
00205             omode = "ab";
00206     }
00207     else if (OpenFlags & Open_Write)
00208         omode = "r+b";
00209 
00210 #ifdef OVR_OS_WIN32
00211     SysErrorModeDisabler disabler(FileName.ToCStr());
00212 #endif
00213 
00214 #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
00215     wchar_t womode[16];
00216     wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
00217     UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
00218     OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
00219     UTF8Util::DecodeString(womode, omode);
00220     _wfopen_s(&fs, pwFileName, womode);
00221     OVR_FREE(pwFileName);
00222 #else
00223     fs = fopen(FileName.ToCStr(), omode);
00224 #endif
00225     if (fs)
00226         rewind (fs);
00227     Opened = (fs != NULL);
00228     // Set error code
00229     if (!Opened)
00230         ErrorCode = SFerror();
00231     else
00232     {
00233         // If we are testing file seek correctness, pre-load the entire file so
00234         // that we can do comparison tests later.
00235 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS        
00236         TestPos         = 0;
00237         fseek(fs, 0, SEEK_END);
00238         FileTestLength  = ftell(fs);
00239         fseek(fs, 0, SEEK_SET);
00240         pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
00241         if (pFileTestBuffer)
00242         {
00243             OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
00244             Seek(0, Seek_Set);
00245         }        
00246 #endif
00247 
00248         ErrorCode = 0;
00249     }
00250     LastOp = 0;
00251 }
00252 
00253 
00254 const char* FILEFile::GetFilePath()
00255 {
00256     return FileName.ToCStr();
00257 }
00258 
00259 
00260 // ** File Information
00261 bool    FILEFile::IsValid()
00262 {
00263     return Opened;
00264 }
00265 bool    FILEFile::IsWritable()
00266 {
00267     return IsValid() && (OpenFlags&Open_Write);
00268 }
00269 /*
00270 bool    FILEFile::IsRecoverable()
00271 {
00272     return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
00273 }
00274 */
00275 
00276 // Return position / file size
00277 int     FILEFile::Tell()
00278 {
00279     int pos = (int)ftell (fs);
00280     if (pos < 0)
00281         ErrorCode = SFerror();
00282     return pos;
00283 }
00284 
00285 SInt64  FILEFile::LTell()
00286 {
00287     SInt64 pos = ftell(fs);
00288     if (pos < 0)
00289         ErrorCode = SFerror();
00290     return pos;
00291 }
00292 
00293 int     FILEFile::GetLength()
00294 {
00295     int pos = Tell();
00296     if (pos >= 0)
00297     {
00298         Seek (0, Seek_End);
00299         int size = Tell();
00300         Seek (pos, Seek_Set);
00301         return size;
00302     }
00303     return -1;
00304 }
00305 SInt64  FILEFile::LGetLength()
00306 {
00307     SInt64 pos = LTell();
00308     if (pos >= 0)
00309     {
00310         LSeek (0, Seek_End);
00311         SInt64 size = LTell();
00312         LSeek (pos, Seek_Set);
00313         return size;
00314     }
00315     return -1;
00316 }
00317 
00318 int     FILEFile::GetErrorCode()
00319 {
00320     return ErrorCode;
00321 }
00322 
00323 // ** Stream implementation & I/O
00324 int     FILEFile::Write(const UByte *pbuffer, int numBytes)
00325 {
00326     if (LastOp && LastOp != Open_Write)
00327         fflush(fs);
00328     LastOp = Open_Write;
00329     int written = (int) fwrite(pbuffer, 1, numBytes, fs);
00330     if (written < numBytes)
00331         ErrorCode = SFerror();
00332 
00333 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00334     if (written > 0)
00335         TestPos += written;
00336 #endif
00337 
00338     return written;
00339 }
00340 
00341 int     FILEFile::Read(UByte *pbuffer, int numBytes)
00342 {
00343     if (LastOp && LastOp != Open_Read)
00344         fflush(fs);
00345     LastOp = Open_Read;
00346     int read = (int) fread(pbuffer, 1, numBytes, fs);
00347     if (read < numBytes)
00348         ErrorCode = SFerror();
00349 
00350 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00351     if (read > 0)
00352     {
00353         // Read-in data must match our pre-loaded buffer data!
00354         UByte* pcompareBuffer = pFileTestBuffer + TestPos;
00355         for (int i=0; i< read; i++)
00356         {
00357             OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
00358         }
00359 
00360         //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
00361         TestPos += read;
00362         OVR_ASSERT(ftell(fs) == (int)TestPos);
00363     }
00364 #endif
00365 
00366     return read;
00367 }
00368 
00369 // Seeks ahead to skip bytes
00370 int     FILEFile::SkipBytes(int numBytes)
00371 {
00372     SInt64 pos    = LTell();
00373     SInt64 newPos = LSeek(numBytes, Seek_Cur);
00374 
00375     // Return -1 for major error
00376     if ((pos==-1) || (newPos==-1))
00377     {
00378         return -1;
00379     }
00380     //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
00381 
00382     return int (newPos-(int)pos);
00383 }
00384 
00385 // Return # of bytes till EOF
00386 int     FILEFile::BytesAvailable()
00387 {
00388     SInt64 pos    = LTell();
00389     SInt64 endPos = LGetLength();
00390 
00391     // Return -1 for major error
00392     if ((pos==-1) || (endPos==-1))
00393     {
00394         ErrorCode = SFerror();
00395         return 0;
00396     }
00397     else
00398         ErrorCode = 0;
00399 
00400     return int (endPos-(int)pos);
00401 }
00402 
00403 // Flush file contents
00404 bool    FILEFile::Flush()
00405 {
00406     return !fflush(fs);
00407 }
00408 
00409 int     FILEFile::Seek(int offset, int origin)
00410 {
00411     int newOrigin = 0;
00412     switch(origin)
00413     {
00414     case Seek_Set: newOrigin = SEEK_SET; break;
00415     case Seek_Cur: newOrigin = SEEK_CUR; break;
00416     case Seek_End: newOrigin = SEEK_END; break;
00417     }
00418 
00419     if (newOrigin == SEEK_SET && offset == Tell())
00420         return Tell();
00421 
00422     if (fseek (fs, offset, newOrigin))
00423     {
00424 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00425         OVR_ASSERT(0);
00426 #endif
00427         return -1;
00428     }
00429     
00430 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00431     // Track file position after seeks for read verification later.
00432     switch(origin)
00433     {
00434     case Seek_Set:  TestPos = offset;       break;
00435     case Seek_Cur:  TestPos += offset;      break;    
00436     case Seek_End:  TestPos = FileTestLength + offset; break;
00437     }
00438     OVR_ASSERT((int)TestPos == Tell());
00439 #endif
00440 
00441     return (int)Tell();
00442 }
00443 
00444 SInt64  FILEFile::LSeek(SInt64 offset, int origin)
00445 {
00446     return Seek((int)offset,origin);
00447 }
00448 
00449 int FILEFile::CopyFromStream(File *pstream, int byteSize)
00450 {
00451     UByte   buff[0x4000];
00452     int     count = 0;
00453     int     szRequest, szRead, szWritten;
00454 
00455     while (byteSize)
00456     {
00457         szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
00458 
00459         szRead    = pstream->Read(buff, szRequest);
00460         szWritten = 0;
00461         if (szRead > 0)
00462             szWritten = Write(buff, szRead);
00463 
00464         count    += szWritten;
00465         byteSize -= szWritten;
00466         if (szWritten < szRequest)
00467             break;
00468     }
00469     return count;
00470 }
00471 
00472 
00473 bool FILEFile::Close()
00474 {
00475 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
00476     if (pFileTestBuffer)
00477     {
00478         OVR_FREE(pFileTestBuffer);
00479         pFileTestBuffer = 0;
00480         FileTestLength  = 0;
00481     }
00482 #endif
00483 
00484     bool closeRet = !fclose(fs);
00485 
00486     if (!closeRet)
00487     {
00488         ErrorCode = SFerror();
00489         return 0;
00490     }
00491     else
00492     {
00493         Opened    = 0;
00494         fs        = 0;
00495         ErrorCode = 0;
00496     }
00497 
00498     // Handle safe truncate
00499     /*
00500     if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
00501     {
00502         // Delete original file (if it existed)
00503         DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
00504         if (oldAttributes!=0xFFFFFFFF)
00505             if (!FileUtilWin32::DeleteFile(FileName))
00506             {
00507                 // Try to remove the readonly attribute
00508                 FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
00509                 // And delete the file again
00510                 if (!FileUtilWin32::DeleteFile(FileName))
00511                     return 0;
00512             }
00513 
00514         // Rename temp file to real filename
00515         if (!FileUtilWin32::MoveFile(TempName, FileName))
00516         {
00517             //ErrorCode = errno;
00518             return 0;
00519         }
00520     }
00521     */
00522     return 1;
00523 }
00524 
00525 /*
00526 bool    FILEFile::CloseCancel()
00527 {
00528     bool closeRet = (bool)::CloseHandle(fd);
00529 
00530     if (!closeRet)
00531     {
00532         //ErrorCode = errno;
00533         return 0;
00534     }
00535     else
00536     {
00537         Opened    = 0;
00538         fd        = INVALID_HANDLE_VALUE;
00539         ErrorCode = 0;
00540     }
00541 
00542     // Handle safe truncate (delete tmp file, leave original unchanged)
00543     if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
00544         if (!FileUtilWin32::DeleteFile(TempName))
00545         {
00546             //ErrorCode = errno;
00547             return 0;
00548         }
00549     return 1;
00550 }
00551 */
00552 
00553 File *FileFILEOpen(const String& path, int flags, int mode)
00554 {
00555     return new FILEFile(path, flags, mode);
00556 }
00557 
00558 // Helper function: obtain file information time.
00559 bool    SysFile::GetFileStat(FileStat* pfileStat, const String& path)
00560 {
00561 #if defined(OVR_OS_WIN32)
00562     // 64-bit implementation on Windows.
00563     struct __stat64 fileStat;
00564     // Stat returns 0 for success.
00565     wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
00566     UTF8Util::DecodeString(pwpath, path.ToCStr());
00567 
00568     int ret = _wstat64(pwpath, &fileStat);
00569     OVR_FREE(pwpath);
00570     if (ret) return false;
00571 #else
00572     struct stat fileStat;
00573     // Stat returns 0 for success.
00574     if (stat(path, &fileStat) != 0)
00575         return false;
00576 #endif
00577     pfileStat->AccessTime = fileStat.st_atime;
00578     pfileStat->ModifyTime = fileStat.st_mtime;
00579     pfileStat->FileSize   = fileStat.st_size;
00580     return true;
00581 }
00582 
00583 } // Scaleform


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