oculus1
view libovr/Src/Kernel/OVR_FileFILE.cpp @ 10:b2abb08c8f94
proper FPS-style vr tracking
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 20 Sep 2013 06:49:39 +0300 |
parents | e2f9e4603129 |
children |
line source
1 /**************************************************************************
3 Filename : OVR_FileFILE.cpp
4 Content : File wrapper class implementation (Win32)
6 Created : April 5, 1999
7 Authors : Michael Antonov
9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
11 Use of this software is subject to the terms of the Oculus license
12 agreement provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 **************************************************************************/
17 #define GFILE_CXX
19 #include "OVR_Types.h"
20 #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
28 #include "OVR_SysFile.h"
30 #ifndef OVR_OS_WINCE
31 #include <errno.h>
32 #endif
34 namespace OVR {
36 // ***** File interface
38 // ***** FILEFile - C streams file
40 static int SFerror ()
41 {
42 if (errno == ENOENT)
43 return FileConstants::Error_FileNotFound;
44 else if (errno == EACCES || errno == EPERM)
45 return FileConstants::Error_Access;
46 else if (errno == ENOSPC)
47 return FileConstants::Error_DiskFull;
48 else
49 return FileConstants::Error_IOError;
50 };
52 #ifdef OVR_OS_WIN32
53 #include "windows.h"
54 // A simple helper class to disable/enable system error mode, if necessary
55 // Disabling happens conditionally only if a drive name is involved
56 class SysErrorModeDisabler
57 {
58 BOOL Disabled;
59 UINT OldMode;
60 public:
61 SysErrorModeDisabler(const char* pfileName)
62 {
63 if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
64 {
65 Disabled = 1;
66 OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
67 }
68 else
69 Disabled = 0;
70 }
72 ~SysErrorModeDisabler()
73 {
74 if (Disabled) ::SetErrorMode(OldMode);
75 }
76 };
77 #else
78 class SysErrorModeDisabler
79 {
80 public:
81 SysErrorModeDisabler(const char* pfileName) { }
82 };
83 #endif // OVR_OS_WIN32
86 // This macro enables verification of I/O results after seeks against a pre-loaded
87 // full file buffer copy. This is generally not necessary, but can been used to debug
88 // memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
89 // under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
90 //#define GFILE_VERIFY_SEEK_ERRORS
93 // This is the simplest possible file implementation, it wraps around the descriptor
94 // This file is delegated to by SysFile.
96 class FILEFile : public File
97 {
98 protected:
100 // Allocated filename
101 String FileName;
103 // File handle & open mode
104 bool Opened;
105 FILE* fs;
106 int OpenFlags;
107 // Error code for last request
108 int ErrorCode;
110 int LastOp;
112 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
113 UByte* pFileTestBuffer;
114 unsigned FileTestLength;
115 unsigned TestPos; // File pointer position during tests.
116 #endif
118 public:
120 FILEFile()
121 {
122 Opened = 0; FileName = "";
124 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
125 pFileTestBuffer =0;
126 FileTestLength =0;
127 TestPos =0;
128 #endif
129 }
130 // Initialize file by opening it
131 FILEFile(const String& fileName, int flags, int Mode);
132 // The 'pfileName' should be encoded as UTF-8 to support international file names.
133 FILEFile(const char* pfileName, int flags, int Mode);
135 ~FILEFile()
136 {
137 if (Opened)
138 Close();
139 }
141 virtual const char* GetFilePath();
143 // ** File Information
144 virtual bool IsValid();
145 virtual bool IsWritable();
147 // Return position / file size
148 virtual int Tell();
149 virtual SInt64 LTell();
150 virtual int GetLength();
151 virtual SInt64 LGetLength();
153 // virtual bool Stat(FileStats *pfs);
154 virtual int GetErrorCode();
156 // ** Stream implementation & I/O
157 virtual int Write(const UByte *pbuffer, int numBytes);
158 virtual int Read(UByte *pbuffer, int numBytes);
159 virtual int SkipBytes(int numBytes);
160 virtual int BytesAvailable();
161 virtual bool Flush();
162 virtual int Seek(int offset, int origin);
163 virtual SInt64 LSeek(SInt64 offset, int origin);
165 virtual int CopyFromStream(File *pStream, int byteSize);
166 virtual bool Close();
167 private:
168 void init();
169 };
172 // Initialize file by opening it
173 FILEFile::FILEFile(const String& fileName, int flags, int mode)
174 : FileName(fileName), OpenFlags(flags)
175 {
176 OVR_UNUSED(mode);
177 init();
178 }
180 // The 'pfileName' should be encoded as UTF-8 to support international file names.
181 FILEFile::FILEFile(const char* pfileName, int flags, int mode)
182 : FileName(pfileName), OpenFlags(flags)
183 {
184 OVR_UNUSED(mode);
185 init();
186 }
188 void FILEFile::init()
189 {
190 // Open mode for file's open
191 const char *omode = "rb";
193 if (OpenFlags & Open_Truncate)
194 {
195 if (OpenFlags & Open_Read)
196 omode = "w+b";
197 else
198 omode = "wb";
199 }
200 else if (OpenFlags & Open_Create)
201 {
202 if (OpenFlags & Open_Read)
203 omode = "a+b";
204 else
205 omode = "ab";
206 }
207 else if (OpenFlags & Open_Write)
208 omode = "r+b";
210 #ifdef OVR_OS_WIN32
211 SysErrorModeDisabler disabler(FileName.ToCStr());
212 #endif
214 #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
215 wchar_t womode[16];
216 wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
217 UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
218 OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
219 UTF8Util::DecodeString(womode, omode);
220 _wfopen_s(&fs, pwFileName, womode);
221 OVR_FREE(pwFileName);
222 #else
223 fs = fopen(FileName.ToCStr(), omode);
224 #endif
225 if (fs)
226 rewind (fs);
227 Opened = (fs != NULL);
228 // Set error code
229 if (!Opened)
230 ErrorCode = SFerror();
231 else
232 {
233 // If we are testing file seek correctness, pre-load the entire file so
234 // that we can do comparison tests later.
235 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
236 TestPos = 0;
237 fseek(fs, 0, SEEK_END);
238 FileTestLength = ftell(fs);
239 fseek(fs, 0, SEEK_SET);
240 pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
241 if (pFileTestBuffer)
242 {
243 OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
244 Seek(0, Seek_Set);
245 }
246 #endif
248 ErrorCode = 0;
249 }
250 LastOp = 0;
251 }
254 const char* FILEFile::GetFilePath()
255 {
256 return FileName.ToCStr();
257 }
260 // ** File Information
261 bool FILEFile::IsValid()
262 {
263 return Opened;
264 }
265 bool FILEFile::IsWritable()
266 {
267 return IsValid() && (OpenFlags&Open_Write);
268 }
269 /*
270 bool FILEFile::IsRecoverable()
271 {
272 return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
273 }
274 */
276 // Return position / file size
277 int FILEFile::Tell()
278 {
279 int pos = (int)ftell (fs);
280 if (pos < 0)
281 ErrorCode = SFerror();
282 return pos;
283 }
285 SInt64 FILEFile::LTell()
286 {
287 SInt64 pos = ftell(fs);
288 if (pos < 0)
289 ErrorCode = SFerror();
290 return pos;
291 }
293 int FILEFile::GetLength()
294 {
295 int pos = Tell();
296 if (pos >= 0)
297 {
298 Seek (0, Seek_End);
299 int size = Tell();
300 Seek (pos, Seek_Set);
301 return size;
302 }
303 return -1;
304 }
305 SInt64 FILEFile::LGetLength()
306 {
307 SInt64 pos = LTell();
308 if (pos >= 0)
309 {
310 LSeek (0, Seek_End);
311 SInt64 size = LTell();
312 LSeek (pos, Seek_Set);
313 return size;
314 }
315 return -1;
316 }
318 int FILEFile::GetErrorCode()
319 {
320 return ErrorCode;
321 }
323 // ** Stream implementation & I/O
324 int FILEFile::Write(const UByte *pbuffer, int numBytes)
325 {
326 if (LastOp && LastOp != Open_Write)
327 fflush(fs);
328 LastOp = Open_Write;
329 int written = (int) fwrite(pbuffer, 1, numBytes, fs);
330 if (written < numBytes)
331 ErrorCode = SFerror();
333 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
334 if (written > 0)
335 TestPos += written;
336 #endif
338 return written;
339 }
341 int FILEFile::Read(UByte *pbuffer, int numBytes)
342 {
343 if (LastOp && LastOp != Open_Read)
344 fflush(fs);
345 LastOp = Open_Read;
346 int read = (int) fread(pbuffer, 1, numBytes, fs);
347 if (read < numBytes)
348 ErrorCode = SFerror();
350 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
351 if (read > 0)
352 {
353 // Read-in data must match our pre-loaded buffer data!
354 UByte* pcompareBuffer = pFileTestBuffer + TestPos;
355 for (int i=0; i< read; i++)
356 {
357 OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
358 }
360 //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
361 TestPos += read;
362 OVR_ASSERT(ftell(fs) == (int)TestPos);
363 }
364 #endif
366 return read;
367 }
369 // Seeks ahead to skip bytes
370 int FILEFile::SkipBytes(int numBytes)
371 {
372 SInt64 pos = LTell();
373 SInt64 newPos = LSeek(numBytes, Seek_Cur);
375 // Return -1 for major error
376 if ((pos==-1) || (newPos==-1))
377 {
378 return -1;
379 }
380 //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
382 return int (newPos-(int)pos);
383 }
385 // Return # of bytes till EOF
386 int FILEFile::BytesAvailable()
387 {
388 SInt64 pos = LTell();
389 SInt64 endPos = LGetLength();
391 // Return -1 for major error
392 if ((pos==-1) || (endPos==-1))
393 {
394 ErrorCode = SFerror();
395 return 0;
396 }
397 else
398 ErrorCode = 0;
400 return int (endPos-(int)pos);
401 }
403 // Flush file contents
404 bool FILEFile::Flush()
405 {
406 return !fflush(fs);
407 }
409 int FILEFile::Seek(int offset, int origin)
410 {
411 int newOrigin = 0;
412 switch(origin)
413 {
414 case Seek_Set: newOrigin = SEEK_SET; break;
415 case Seek_Cur: newOrigin = SEEK_CUR; break;
416 case Seek_End: newOrigin = SEEK_END; break;
417 }
419 if (newOrigin == SEEK_SET && offset == Tell())
420 return Tell();
422 if (fseek (fs, offset, newOrigin))
423 {
424 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
425 OVR_ASSERT(0);
426 #endif
427 return -1;
428 }
430 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
431 // Track file position after seeks for read verification later.
432 switch(origin)
433 {
434 case Seek_Set: TestPos = offset; break;
435 case Seek_Cur: TestPos += offset; break;
436 case Seek_End: TestPos = FileTestLength + offset; break;
437 }
438 OVR_ASSERT((int)TestPos == Tell());
439 #endif
441 return (int)Tell();
442 }
444 SInt64 FILEFile::LSeek(SInt64 offset, int origin)
445 {
446 return Seek((int)offset,origin);
447 }
449 int FILEFile::CopyFromStream(File *pstream, int byteSize)
450 {
451 UByte buff[0x4000];
452 int count = 0;
453 int szRequest, szRead, szWritten;
455 while (byteSize)
456 {
457 szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
459 szRead = pstream->Read(buff, szRequest);
460 szWritten = 0;
461 if (szRead > 0)
462 szWritten = Write(buff, szRead);
464 count += szWritten;
465 byteSize -= szWritten;
466 if (szWritten < szRequest)
467 break;
468 }
469 return count;
470 }
473 bool FILEFile::Close()
474 {
475 #ifdef OVR_FILE_VERIFY_SEEK_ERRORS
476 if (pFileTestBuffer)
477 {
478 OVR_FREE(pFileTestBuffer);
479 pFileTestBuffer = 0;
480 FileTestLength = 0;
481 }
482 #endif
484 bool closeRet = !fclose(fs);
486 if (!closeRet)
487 {
488 ErrorCode = SFerror();
489 return 0;
490 }
491 else
492 {
493 Opened = 0;
494 fs = 0;
495 ErrorCode = 0;
496 }
498 // Handle safe truncate
499 /*
500 if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
501 {
502 // Delete original file (if it existed)
503 DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
504 if (oldAttributes!=0xFFFFFFFF)
505 if (!FileUtilWin32::DeleteFile(FileName))
506 {
507 // Try to remove the readonly attribute
508 FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
509 // And delete the file again
510 if (!FileUtilWin32::DeleteFile(FileName))
511 return 0;
512 }
514 // Rename temp file to real filename
515 if (!FileUtilWin32::MoveFile(TempName, FileName))
516 {
517 //ErrorCode = errno;
518 return 0;
519 }
520 }
521 */
522 return 1;
523 }
525 /*
526 bool FILEFile::CloseCancel()
527 {
528 bool closeRet = (bool)::CloseHandle(fd);
530 if (!closeRet)
531 {
532 //ErrorCode = errno;
533 return 0;
534 }
535 else
536 {
537 Opened = 0;
538 fd = INVALID_HANDLE_VALUE;
539 ErrorCode = 0;
540 }
542 // Handle safe truncate (delete tmp file, leave original unchanged)
543 if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
544 if (!FileUtilWin32::DeleteFile(TempName))
545 {
546 //ErrorCode = errno;
547 return 0;
548 }
549 return 1;
550 }
551 */
553 File *FileFILEOpen(const String& path, int flags, int mode)
554 {
555 return new FILEFile(path, flags, mode);
556 }
558 // Helper function: obtain file information time.
559 bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
560 {
561 #if defined(OVR_OS_WIN32)
562 // 64-bit implementation on Windows.
563 struct __stat64 fileStat;
564 // Stat returns 0 for success.
565 wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
566 UTF8Util::DecodeString(pwpath, path.ToCStr());
568 int ret = _wstat64(pwpath, &fileStat);
569 OVR_FREE(pwpath);
570 if (ret) return false;
571 #else
572 struct stat fileStat;
573 // Stat returns 0 for success.
574 if (stat(path, &fileStat) != 0)
575 return false;
576 #endif
577 pfileStat->AccessTime = fileStat.st_atime;
578 pfileStat->ModifyTime = fileStat.st_mtime;
579 pfileStat->FileSize = fileStat.st_size;
580 return true;
581 }
583 } // Scaleform