OVR_FileFILE.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /**************************************************************************
  2. Filename : OVR_FileFILE.cpp
  3. Content : File wrapper class implementation (Win32)
  4. Created : April 5, 1999
  5. Authors : Michael Antonov
  6. Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
  7. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
  8. you may not use the Oculus VR Rift SDK except in compliance with the License,
  9. which is provided at the time of installation or download, or which
  10. otherwise accompanies this software in either electronic or hard copy form.
  11. You may obtain a copy of the License at
  12. http://www.oculusvr.com/licenses/LICENSE-3.2
  13. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  14. distributed under the License is distributed on an "AS IS" BASIS,
  15. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. See the License for the specific language governing permissions and
  17. limitations under the License.
  18. **************************************************************************/
  19. #define GFILE_CXX
  20. #include "OVR_Types.h"
  21. #include "OVR_Log.h"
  22. // Standard C library (Captain Obvious guarantees!)
  23. #include <stdio.h>
  24. #ifndef OVR_OS_WINCE
  25. #include <sys/stat.h>
  26. #endif
  27. #include "OVR_SysFile.h"
  28. #ifndef OVR_OS_WINCE
  29. #include <errno.h>
  30. #endif
  31. namespace OVR {
  32. // ***** File interface
  33. // ***** FILEFile - C streams file
  34. static int SFerror ()
  35. {
  36. if (errno == ENOENT)
  37. return FileConstants::Error_FileNotFound;
  38. else if (errno == EACCES || errno == EPERM)
  39. return FileConstants::Error_Access;
  40. else if (errno == ENOSPC)
  41. return FileConstants::Error_DiskFull;
  42. else
  43. return FileConstants::Error_IOError;
  44. };
  45. #if defined(OVR_CC_MSVC)
  46. #include "share.h"
  47. #endif
  48. #if defined(OVR_OS_WIN32)
  49. #include "OVR_Win32_IncludeWindows.h"
  50. // A simple helper class to disable/enable system error mode, if necessary
  51. // Disabling happens conditionally only if a drive name is involved
  52. class SysErrorModeDisabler
  53. {
  54. BOOL Disabled;
  55. UINT OldMode;
  56. public:
  57. SysErrorModeDisabler(const char* pfileName)
  58. {
  59. if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
  60. {
  61. Disabled = TRUE;
  62. OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
  63. }
  64. else
  65. {
  66. Disabled = 0;
  67. OldMode = 0;
  68. }
  69. }
  70. ~SysErrorModeDisabler()
  71. {
  72. if (Disabled)
  73. ::SetErrorMode(OldMode);
  74. }
  75. };
  76. #else
  77. class SysErrorModeDisabler
  78. {
  79. public:
  80. SysErrorModeDisabler(const char* pfileName) { OVR_UNUSED(pfileName); }
  81. };
  82. #endif // OVR_OS_WIN32
  83. // This macro enables verification of I/O results after seeks against a pre-loaded
  84. // full file buffer copy. This is generally not necessary, but can been used to debug
  85. // memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
  86. // under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
  87. //#define GFILE_VERIFY_SEEK_ERRORS
  88. // This is the simplest possible file implementation, it wraps around the descriptor
  89. // This file is delegated to by SysFile.
  90. class FILEFile : public File
  91. {
  92. protected:
  93. // Allocated filename
  94. String FileName;
  95. // File handle & open mode
  96. bool Opened;
  97. FILE* fs;
  98. int OpenFlags;
  99. // Error code for last request
  100. int ErrorCode;
  101. int LastOp;
  102. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  103. uint8_t* pFileTestBuffer;
  104. unsigned FileTestLength;
  105. unsigned TestPos; // File pointer position during tests.
  106. #endif
  107. public:
  108. FILEFile() :
  109. FileName(),
  110. Opened(false),
  111. fs(NULL),
  112. OpenFlags(0),
  113. ErrorCode(0),
  114. LastOp(0)
  115. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  116. ,pFileTestBuffer(NULL)
  117. ,FileTestLength(0)
  118. ,TestPos(0)
  119. #endif
  120. {
  121. }
  122. // Initialize file by opening it
  123. FILEFile(const String& fileName, int flags, int Mode);
  124. // The 'pfileName' should be encoded as UTF-8 to support international file names.
  125. FILEFile(const char* pfileName, int flags, int Mode);
  126. ~FILEFile()
  127. {
  128. if (Opened)
  129. Close();
  130. }
  131. virtual const char* GetFilePath();
  132. // ** File Information
  133. virtual bool IsValid();
  134. virtual bool IsWritable();
  135. // Return position / file size
  136. virtual int Tell();
  137. virtual int64_t LTell();
  138. virtual int GetLength();
  139. virtual int64_t LGetLength();
  140. // virtual bool Stat(FileStats *pfs);
  141. virtual int GetErrorCode();
  142. // ** Stream implementation & I/O
  143. virtual int Write(const uint8_t *pbuffer, int numBytes);
  144. virtual int Read(uint8_t *pbuffer, int numBytes);
  145. virtual int SkipBytes(int numBytes);
  146. virtual int BytesAvailable();
  147. virtual bool Flush();
  148. virtual int Seek(int offset, int origin);
  149. virtual int64_t LSeek(int64_t offset, int origin);
  150. virtual int CopyFromStream(File *pStream, int byteSize);
  151. virtual bool Close();
  152. private:
  153. void init();
  154. };
  155. // Initialize file by opening it
  156. FILEFile::FILEFile(const String& fileName, int flags, int mode)
  157. : FileName(fileName), OpenFlags(flags)
  158. {
  159. OVR_UNUSED(mode);
  160. init();
  161. }
  162. // The 'pfileName' should be encoded as UTF-8 to support international file names.
  163. FILEFile::FILEFile(const char* pfileName, int flags, int mode)
  164. : FileName(pfileName), OpenFlags(flags)
  165. {
  166. OVR_UNUSED(mode);
  167. init();
  168. }
  169. void FILEFile::init()
  170. {
  171. // Open mode for file's open
  172. const char *omode = "rb";
  173. if (OpenFlags & Open_Truncate)
  174. {
  175. if (OpenFlags & Open_Read)
  176. omode = "w+b";
  177. else
  178. omode = "wb";
  179. }
  180. else if (OpenFlags & Open_Create)
  181. {
  182. if (OpenFlags & Open_Read)
  183. omode = "a+b";
  184. else
  185. omode = "ab";
  186. }
  187. else if (OpenFlags & Open_Write)
  188. omode = "r+b";
  189. #if defined(OVR_OS_MS)
  190. SysErrorModeDisabler disabler(FileName.ToCStr());
  191. #endif
  192. #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
  193. wchar_t womode[16];
  194. wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
  195. UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
  196. OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
  197. UTF8Util::DecodeString(womode, omode);
  198. fs = _wfsopen(pwFileName, womode, _SH_DENYWR); // Allow others to read the file when we are writing it.
  199. OVR_FREE(pwFileName);
  200. #else
  201. fs = fopen(FileName.ToCStr(), omode);
  202. #endif
  203. if (fs)
  204. rewind (fs);
  205. Opened = (fs != NULL);
  206. // Set error code
  207. if (!Opened)
  208. ErrorCode = SFerror();
  209. else
  210. {
  211. // If we are testing file seek correctness, pre-load the entire file so
  212. // that we can do comparison tests later.
  213. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  214. TestPos = 0;
  215. fseek(fs, 0, SEEK_END);
  216. FileTestLength = ftell(fs);
  217. fseek(fs, 0, SEEK_SET);
  218. pFileTestBuffer = (uint8_t*)OVR_ALLOC(FileTestLength);
  219. if (pFileTestBuffer)
  220. {
  221. OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
  222. Seek(0, Seek_Set);
  223. }
  224. #endif
  225. ErrorCode = 0;
  226. }
  227. LastOp = 0;
  228. }
  229. const char* FILEFile::GetFilePath()
  230. {
  231. return FileName.ToCStr();
  232. }
  233. // ** File Information
  234. bool FILEFile::IsValid()
  235. {
  236. return Opened;
  237. }
  238. bool FILEFile::IsWritable()
  239. {
  240. return IsValid() && (OpenFlags&Open_Write);
  241. }
  242. /*
  243. bool FILEFile::IsRecoverable()
  244. {
  245. return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
  246. }
  247. */
  248. // Return position / file size
  249. int FILEFile::Tell()
  250. {
  251. int pos = (int)ftell (fs);
  252. if (pos < 0)
  253. ErrorCode = SFerror();
  254. return pos;
  255. }
  256. int64_t FILEFile::LTell()
  257. {
  258. int64_t pos = ftell(fs);
  259. if (pos < 0)
  260. ErrorCode = SFerror();
  261. return pos;
  262. }
  263. int FILEFile::GetLength()
  264. {
  265. int pos = Tell();
  266. if (pos >= 0)
  267. {
  268. Seek (0, Seek_End);
  269. int size = Tell();
  270. Seek (pos, Seek_Set);
  271. return size;
  272. }
  273. return -1;
  274. }
  275. int64_t FILEFile::LGetLength()
  276. {
  277. int64_t pos = LTell();
  278. if (pos >= 0)
  279. {
  280. LSeek (0, Seek_End);
  281. int64_t size = LTell();
  282. LSeek (pos, Seek_Set);
  283. return size;
  284. }
  285. return -1;
  286. }
  287. int FILEFile::GetErrorCode()
  288. {
  289. return ErrorCode;
  290. }
  291. // ** Stream implementation & I/O
  292. int FILEFile::Write(const uint8_t *pbuffer, int numBytes)
  293. {
  294. if (LastOp && LastOp != Open_Write)
  295. fflush(fs);
  296. LastOp = Open_Write;
  297. int written = (int) fwrite(pbuffer, 1, numBytes, fs);
  298. if (written < numBytes)
  299. ErrorCode = SFerror();
  300. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  301. if (written > 0)
  302. TestPos += written;
  303. #endif
  304. return written;
  305. }
  306. int FILEFile::Read(uint8_t *pbuffer, int numBytes)
  307. {
  308. if (LastOp && LastOp != Open_Read)
  309. fflush(fs);
  310. LastOp = Open_Read;
  311. int read = (int) fread(pbuffer, 1, numBytes, fs);
  312. if (read < numBytes)
  313. ErrorCode = SFerror();
  314. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  315. if (read > 0)
  316. {
  317. // Read-in data must match our pre-loaded buffer data!
  318. uint8_t* pcompareBuffer = pFileTestBuffer + TestPos;
  319. for (int i=0; i< read; i++)
  320. {
  321. OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
  322. }
  323. //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
  324. TestPos += read;
  325. OVR_ASSERT(ftell(fs) == (int)TestPos);
  326. }
  327. #endif
  328. return read;
  329. }
  330. // Seeks ahead to skip bytes
  331. int FILEFile::SkipBytes(int numBytes)
  332. {
  333. int64_t pos = LTell();
  334. int64_t newPos = LSeek(numBytes, Seek_Cur);
  335. // Return -1 for major error
  336. if ((pos==-1) || (newPos==-1))
  337. {
  338. return -1;
  339. }
  340. //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
  341. return int (newPos-(int)pos);
  342. }
  343. // Return # of bytes till EOF
  344. int FILEFile::BytesAvailable()
  345. {
  346. int64_t pos = LTell();
  347. int64_t endPos = LGetLength();
  348. // Return -1 for major error
  349. if ((pos==-1) || (endPos==-1))
  350. {
  351. ErrorCode = SFerror();
  352. return 0;
  353. }
  354. else
  355. ErrorCode = 0;
  356. return int (endPos-(int)pos);
  357. }
  358. // Flush file contents
  359. bool FILEFile::Flush()
  360. {
  361. return !fflush(fs);
  362. }
  363. int FILEFile::Seek(int offset, int origin)
  364. {
  365. int newOrigin = 0;
  366. switch(origin)
  367. {
  368. case Seek_Set: newOrigin = SEEK_SET; break;
  369. case Seek_Cur: newOrigin = SEEK_CUR; break;
  370. case Seek_End: newOrigin = SEEK_END; break;
  371. }
  372. if (newOrigin == SEEK_SET && offset == Tell())
  373. return Tell();
  374. if (fseek (fs, offset, newOrigin))
  375. {
  376. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  377. OVR_ASSERT(0);
  378. #endif
  379. return -1;
  380. }
  381. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  382. // Track file position after seeks for read verification later.
  383. switch(origin)
  384. {
  385. case Seek_Set: TestPos = offset; break;
  386. case Seek_Cur: TestPos += offset; break;
  387. case Seek_End: TestPos = FileTestLength + offset; break;
  388. }
  389. OVR_ASSERT((int)TestPos == Tell());
  390. #endif
  391. return (int)Tell();
  392. }
  393. int64_t FILEFile::LSeek(int64_t offset, int origin)
  394. {
  395. return Seek((int)offset,origin);
  396. }
  397. int FILEFile::CopyFromStream(File *pstream, int byteSize)
  398. {
  399. uint8_t* buff = new uint8_t[0x4000];
  400. int count = 0;
  401. int szRequest, szRead, szWritten;
  402. while (byteSize)
  403. {
  404. szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
  405. szRead = pstream->Read(buff, szRequest);
  406. szWritten = 0;
  407. if (szRead > 0)
  408. szWritten = Write(buff, szRead);
  409. count += szWritten;
  410. byteSize -= szWritten;
  411. if (szWritten < szRequest)
  412. break;
  413. }
  414. delete[] buff;
  415. return count;
  416. }
  417. bool FILEFile::Close()
  418. {
  419. #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
  420. if (pFileTestBuffer)
  421. {
  422. OVR_FREE(pFileTestBuffer);
  423. pFileTestBuffer = 0;
  424. FileTestLength = 0;
  425. }
  426. #endif
  427. bool closeRet = !fclose(fs);
  428. if (!closeRet)
  429. {
  430. ErrorCode = SFerror();
  431. return 0;
  432. }
  433. else
  434. {
  435. Opened = 0;
  436. fs = 0;
  437. ErrorCode = 0;
  438. }
  439. // Handle safe truncate
  440. /*
  441. if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
  442. {
  443. // Delete original file (if it existed)
  444. DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
  445. if (oldAttributes!=0xFFFFFFFF)
  446. if (!FileUtilWin32::DeleteFile(FileName))
  447. {
  448. // Try to remove the readonly attribute
  449. FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
  450. // And delete the file again
  451. if (!FileUtilWin32::DeleteFile(FileName))
  452. return 0;
  453. }
  454. // Rename temp file to real filename
  455. if (!FileUtilWin32::MoveFile(TempName, FileName))
  456. {
  457. //ErrorCode = errno;
  458. return 0;
  459. }
  460. }
  461. */
  462. return 1;
  463. }
  464. /*
  465. bool FILEFile::CloseCancel()
  466. {
  467. bool closeRet = (bool)::CloseHandle(fd);
  468. if (!closeRet)
  469. {
  470. //ErrorCode = errno;
  471. return 0;
  472. }
  473. else
  474. {
  475. Opened = 0;
  476. fd = INVALID_HANDLE_VALUE;
  477. ErrorCode = 0;
  478. }
  479. // Handle safe truncate (delete tmp file, leave original unchanged)
  480. if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
  481. if (!FileUtilWin32::DeleteFile(TempName))
  482. {
  483. //ErrorCode = errno;
  484. return 0;
  485. }
  486. return 1;
  487. }
  488. */
  489. Ptr<File> FileFILEOpen(const String& path, int flags, int mode)
  490. {
  491. Ptr<File> result = *new FILEFile(path, flags, mode);
  492. return result;
  493. }
  494. // Helper function: obtain file information time.
  495. bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
  496. {
  497. #if defined(OVR_OS_MS)
  498. // 64-bit implementation on Windows.
  499. struct __stat64 fileStat;
  500. // Stat returns 0 for success.
  501. wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
  502. UTF8Util::DecodeString(pwpath, path.ToCStr());
  503. int ret = _wstat64(pwpath, &fileStat);
  504. OVR_FREE(pwpath);
  505. if (ret) return false;
  506. #else
  507. struct stat fileStat;
  508. // Stat returns 0 for success.
  509. if (stat(path, &fileStat) != 0)
  510. return false;
  511. #endif
  512. pfileStat->AccessTime = fileStat.st_atime;
  513. pfileStat->ModifyTime = fileStat.st_mtime;
  514. pfileStat->FileSize = fileStat.st_size;
  515. return true;
  516. }
  517. } // Namespace OVR