ovr_sdk

view LibOVR/Src/Kernel/OVR_FileFILE.cpp @ 0:1b39a1b46319

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