ovr_sdk
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_FileFILE.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,609 @@ 1.4 +/************************************************************************** 1.5 + 1.6 +Filename : OVR_FileFILE.cpp 1.7 +Content : File wrapper class implementation (Win32) 1.8 + 1.9 +Created : April 5, 1999 1.10 +Authors : Michael Antonov 1.11 + 1.12 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.13 + 1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.16 +which is provided at the time of installation or download, or which 1.17 +otherwise accompanies this software in either electronic or hard copy form. 1.18 + 1.19 +You may obtain a copy of the License at 1.20 + 1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.22 + 1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.24 +distributed under the License is distributed on an "AS IS" BASIS, 1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.26 +See the License for the specific language governing permissions and 1.27 +limitations under the License. 1.28 + 1.29 +**************************************************************************/ 1.30 + 1.31 +#define GFILE_CXX 1.32 + 1.33 +#include "OVR_Types.h" 1.34 +#include "OVR_Log.h" 1.35 + 1.36 +// Standard C library (Captain Obvious guarantees!) 1.37 +#include <stdio.h> 1.38 +#ifndef OVR_OS_WINCE 1.39 +#include <sys/stat.h> 1.40 +#endif 1.41 + 1.42 +#include "OVR_SysFile.h" 1.43 + 1.44 +#ifndef OVR_OS_WINCE 1.45 +#include <errno.h> 1.46 +#endif 1.47 + 1.48 +namespace OVR { 1.49 + 1.50 +// ***** File interface 1.51 + 1.52 +// ***** FILEFile - C streams file 1.53 + 1.54 +static int SFerror () 1.55 +{ 1.56 + if (errno == ENOENT) 1.57 + return FileConstants::Error_FileNotFound; 1.58 + else if (errno == EACCES || errno == EPERM) 1.59 + return FileConstants::Error_Access; 1.60 + else if (errno == ENOSPC) 1.61 + return FileConstants::Error_DiskFull; 1.62 + else 1.63 + return FileConstants::Error_IOError; 1.64 +}; 1.65 + 1.66 +#if defined(OVR_OS_WIN32) 1.67 +#define WIN32_LEAN_AND_MEAN 1.68 +#include "windows.h" 1.69 +// A simple helper class to disable/enable system error mode, if necessary 1.70 +// Disabling happens conditionally only if a drive name is involved 1.71 +class SysErrorModeDisabler 1.72 +{ 1.73 + BOOL Disabled; 1.74 + UINT OldMode; 1.75 +public: 1.76 + SysErrorModeDisabler(const char* pfileName) 1.77 + { 1.78 + if (pfileName && (pfileName[0]!=0) && pfileName[1]==':') 1.79 + { 1.80 + Disabled = TRUE; 1.81 + OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS); 1.82 + } 1.83 + else 1.84 + { 1.85 + Disabled = 0; 1.86 + OldMode = 0; 1.87 + } 1.88 + } 1.89 + 1.90 + ~SysErrorModeDisabler() 1.91 + { 1.92 + if (Disabled) 1.93 + ::SetErrorMode(OldMode); 1.94 + } 1.95 +}; 1.96 +#else 1.97 +class SysErrorModeDisabler 1.98 +{ 1.99 +public: 1.100 + SysErrorModeDisabler(const char* pfileName) { OVR_UNUSED(pfileName); } 1.101 +}; 1.102 +#endif // OVR_OS_WIN32 1.103 + 1.104 + 1.105 +// This macro enables verification of I/O results after seeks against a pre-loaded 1.106 +// full file buffer copy. This is generally not necessary, but can been used to debug 1.107 +// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory 1.108 +// under FMOD with XP64 (32-bit) and Realtek HA Audio driver. 1.109 +//#define GFILE_VERIFY_SEEK_ERRORS 1.110 + 1.111 + 1.112 +// This is the simplest possible file implementation, it wraps around the descriptor 1.113 +// This file is delegated to by SysFile. 1.114 + 1.115 +class FILEFile : public File 1.116 +{ 1.117 +protected: 1.118 + 1.119 + // Allocated filename 1.120 + String FileName; 1.121 + 1.122 + // File handle & open mode 1.123 + bool Opened; 1.124 + FILE* fs; 1.125 + int OpenFlags; 1.126 + // Error code for last request 1.127 + int ErrorCode; 1.128 + 1.129 + int LastOp; 1.130 + 1.131 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.132 + uint8_t* pFileTestBuffer; 1.133 + unsigned FileTestLength; 1.134 + unsigned TestPos; // File pointer position during tests. 1.135 +#endif 1.136 + 1.137 +public: 1.138 + 1.139 + FILEFile() : 1.140 + FileName(), 1.141 + Opened(false), 1.142 + fs(NULL), 1.143 + OpenFlags(0), 1.144 + ErrorCode(0), 1.145 + LastOp(0) 1.146 + #ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.147 + ,pFileTestBuffer(NULL) 1.148 + ,FileTestLength(0) 1.149 + ,TestPos(0) 1.150 + #endif 1.151 + { 1.152 + } 1.153 + 1.154 + // Initialize file by opening it 1.155 + FILEFile(const String& fileName, int flags, int Mode); 1.156 + 1.157 + // The 'pfileName' should be encoded as UTF-8 to support international file names. 1.158 + FILEFile(const char* pfileName, int flags, int Mode); 1.159 + 1.160 + ~FILEFile() 1.161 + { 1.162 + if (Opened) 1.163 + Close(); 1.164 + } 1.165 + 1.166 + virtual const char* GetFilePath(); 1.167 + 1.168 + // ** File Information 1.169 + virtual bool IsValid(); 1.170 + virtual bool IsWritable(); 1.171 + 1.172 + // Return position / file size 1.173 + virtual int Tell(); 1.174 + virtual int64_t LTell(); 1.175 + virtual int GetLength(); 1.176 + virtual int64_t LGetLength(); 1.177 + 1.178 +// virtual bool Stat(FileStats *pfs); 1.179 + virtual int GetErrorCode(); 1.180 + 1.181 + // ** Stream implementation & I/O 1.182 + virtual int Write(const uint8_t *pbuffer, int numBytes); 1.183 + virtual int Read(uint8_t *pbuffer, int numBytes); 1.184 + virtual int SkipBytes(int numBytes); 1.185 + virtual int BytesAvailable(); 1.186 + virtual bool Flush(); 1.187 + virtual int Seek(int offset, int origin); 1.188 + virtual int64_t LSeek(int64_t offset, int origin); 1.189 + 1.190 + virtual int CopyFromStream(File *pStream, int byteSize); 1.191 + virtual bool Close(); 1.192 +private: 1.193 + void init(); 1.194 +}; 1.195 + 1.196 + 1.197 +// Initialize file by opening it 1.198 +FILEFile::FILEFile(const String& fileName, int flags, int mode) 1.199 + : FileName(fileName), OpenFlags(flags) 1.200 +{ 1.201 + OVR_UNUSED(mode); 1.202 + init(); 1.203 +} 1.204 + 1.205 +// The 'pfileName' should be encoded as UTF-8 to support international file names. 1.206 +FILEFile::FILEFile(const char* pfileName, int flags, int mode) 1.207 + : FileName(pfileName), OpenFlags(flags) 1.208 +{ 1.209 + OVR_UNUSED(mode); 1.210 + init(); 1.211 +} 1.212 + 1.213 +void FILEFile::init() 1.214 +{ 1.215 + // Open mode for file's open 1.216 + const char *omode = "rb"; 1.217 + 1.218 + if (OpenFlags & Open_Truncate) 1.219 + { 1.220 + if (OpenFlags & Open_Read) 1.221 + omode = "w+b"; 1.222 + else 1.223 + omode = "wb"; 1.224 + } 1.225 + else if (OpenFlags & Open_Create) 1.226 + { 1.227 + if (OpenFlags & Open_Read) 1.228 + omode = "a+b"; 1.229 + else 1.230 + omode = "ab"; 1.231 + } 1.232 + else if (OpenFlags & Open_Write) 1.233 + omode = "r+b"; 1.234 + 1.235 +#if defined(OVR_OS_MS) 1.236 + SysErrorModeDisabler disabler(FileName.ToCStr()); 1.237 +#endif 1.238 + 1.239 +#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) 1.240 + wchar_t womode[16]; 1.241 + wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t)); 1.242 + UTF8Util::DecodeString(pwFileName, FileName.ToCStr()); 1.243 + OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0])); 1.244 + UTF8Util::DecodeString(womode, omode); 1.245 + _wfopen_s(&fs, pwFileName, womode); 1.246 + OVR_FREE(pwFileName); 1.247 +#else 1.248 + fs = fopen(FileName.ToCStr(), omode); 1.249 +#endif 1.250 + if (fs) 1.251 + rewind (fs); 1.252 + Opened = (fs != NULL); 1.253 + // Set error code 1.254 + if (!Opened) 1.255 + ErrorCode = SFerror(); 1.256 + else 1.257 + { 1.258 + // If we are testing file seek correctness, pre-load the entire file so 1.259 + // that we can do comparison tests later. 1.260 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.261 + TestPos = 0; 1.262 + fseek(fs, 0, SEEK_END); 1.263 + FileTestLength = ftell(fs); 1.264 + fseek(fs, 0, SEEK_SET); 1.265 + pFileTestBuffer = (uint8_t*)OVR_ALLOC(FileTestLength); 1.266 + if (pFileTestBuffer) 1.267 + { 1.268 + OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength)); 1.269 + Seek(0, Seek_Set); 1.270 + } 1.271 +#endif 1.272 + 1.273 + ErrorCode = 0; 1.274 + } 1.275 + LastOp = 0; 1.276 +} 1.277 + 1.278 + 1.279 +const char* FILEFile::GetFilePath() 1.280 +{ 1.281 + return FileName.ToCStr(); 1.282 +} 1.283 + 1.284 + 1.285 +// ** File Information 1.286 +bool FILEFile::IsValid() 1.287 +{ 1.288 + return Opened; 1.289 +} 1.290 +bool FILEFile::IsWritable() 1.291 +{ 1.292 + return IsValid() && (OpenFlags&Open_Write); 1.293 +} 1.294 +/* 1.295 +bool FILEFile::IsRecoverable() 1.296 +{ 1.297 + return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC); 1.298 +} 1.299 +*/ 1.300 + 1.301 +// Return position / file size 1.302 +int FILEFile::Tell() 1.303 +{ 1.304 + int pos = (int)ftell (fs); 1.305 + if (pos < 0) 1.306 + ErrorCode = SFerror(); 1.307 + return pos; 1.308 +} 1.309 + 1.310 +int64_t FILEFile::LTell() 1.311 +{ 1.312 + int64_t pos = ftell(fs); 1.313 + if (pos < 0) 1.314 + ErrorCode = SFerror(); 1.315 + return pos; 1.316 +} 1.317 + 1.318 +int FILEFile::GetLength() 1.319 +{ 1.320 + int pos = Tell(); 1.321 + if (pos >= 0) 1.322 + { 1.323 + Seek (0, Seek_End); 1.324 + int size = Tell(); 1.325 + Seek (pos, Seek_Set); 1.326 + return size; 1.327 + } 1.328 + return -1; 1.329 +} 1.330 +int64_t FILEFile::LGetLength() 1.331 +{ 1.332 + int64_t pos = LTell(); 1.333 + if (pos >= 0) 1.334 + { 1.335 + LSeek (0, Seek_End); 1.336 + int64_t size = LTell(); 1.337 + LSeek (pos, Seek_Set); 1.338 + return size; 1.339 + } 1.340 + return -1; 1.341 +} 1.342 + 1.343 +int FILEFile::GetErrorCode() 1.344 +{ 1.345 + return ErrorCode; 1.346 +} 1.347 + 1.348 +// ** Stream implementation & I/O 1.349 +int FILEFile::Write(const uint8_t *pbuffer, int numBytes) 1.350 +{ 1.351 + if (LastOp && LastOp != Open_Write) 1.352 + fflush(fs); 1.353 + LastOp = Open_Write; 1.354 + int written = (int) fwrite(pbuffer, 1, numBytes, fs); 1.355 + if (written < numBytes) 1.356 + ErrorCode = SFerror(); 1.357 + 1.358 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.359 + if (written > 0) 1.360 + TestPos += written; 1.361 +#endif 1.362 + 1.363 + return written; 1.364 +} 1.365 + 1.366 +int FILEFile::Read(uint8_t *pbuffer, int numBytes) 1.367 +{ 1.368 + if (LastOp && LastOp != Open_Read) 1.369 + fflush(fs); 1.370 + LastOp = Open_Read; 1.371 + int read = (int) fread(pbuffer, 1, numBytes, fs); 1.372 + if (read < numBytes) 1.373 + ErrorCode = SFerror(); 1.374 + 1.375 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.376 + if (read > 0) 1.377 + { 1.378 + // Read-in data must match our pre-loaded buffer data! 1.379 + uint8_t* pcompareBuffer = pFileTestBuffer + TestPos; 1.380 + for (int i=0; i< read; i++) 1.381 + { 1.382 + OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]); 1.383 + } 1.384 + 1.385 + //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read)); 1.386 + TestPos += read; 1.387 + OVR_ASSERT(ftell(fs) == (int)TestPos); 1.388 + } 1.389 +#endif 1.390 + 1.391 + return read; 1.392 +} 1.393 + 1.394 +// Seeks ahead to skip bytes 1.395 +int FILEFile::SkipBytes(int numBytes) 1.396 +{ 1.397 + int64_t pos = LTell(); 1.398 + int64_t newPos = LSeek(numBytes, Seek_Cur); 1.399 + 1.400 + // Return -1 for major error 1.401 + if ((pos==-1) || (newPos==-1)) 1.402 + { 1.403 + return -1; 1.404 + } 1.405 + //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0; 1.406 + 1.407 + return int (newPos-(int)pos); 1.408 +} 1.409 + 1.410 +// Return # of bytes till EOF 1.411 +int FILEFile::BytesAvailable() 1.412 +{ 1.413 + int64_t pos = LTell(); 1.414 + int64_t endPos = LGetLength(); 1.415 + 1.416 + // Return -1 for major error 1.417 + if ((pos==-1) || (endPos==-1)) 1.418 + { 1.419 + ErrorCode = SFerror(); 1.420 + return 0; 1.421 + } 1.422 + else 1.423 + ErrorCode = 0; 1.424 + 1.425 + return int (endPos-(int)pos); 1.426 +} 1.427 + 1.428 +// Flush file contents 1.429 +bool FILEFile::Flush() 1.430 +{ 1.431 + return !fflush(fs); 1.432 +} 1.433 + 1.434 +int FILEFile::Seek(int offset, int origin) 1.435 +{ 1.436 + int newOrigin = 0; 1.437 + switch(origin) 1.438 + { 1.439 + case Seek_Set: newOrigin = SEEK_SET; break; 1.440 + case Seek_Cur: newOrigin = SEEK_CUR; break; 1.441 + case Seek_End: newOrigin = SEEK_END; break; 1.442 + } 1.443 + 1.444 + if (newOrigin == SEEK_SET && offset == Tell()) 1.445 + return Tell(); 1.446 + 1.447 + if (fseek (fs, offset, newOrigin)) 1.448 + { 1.449 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.450 + OVR_ASSERT(0); 1.451 +#endif 1.452 + return -1; 1.453 + } 1.454 + 1.455 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.456 + // Track file position after seeks for read verification later. 1.457 + switch(origin) 1.458 + { 1.459 + case Seek_Set: TestPos = offset; break; 1.460 + case Seek_Cur: TestPos += offset; break; 1.461 + case Seek_End: TestPos = FileTestLength + offset; break; 1.462 + } 1.463 + OVR_ASSERT((int)TestPos == Tell()); 1.464 +#endif 1.465 + 1.466 + return (int)Tell(); 1.467 +} 1.468 + 1.469 +int64_t FILEFile::LSeek(int64_t offset, int origin) 1.470 +{ 1.471 + return Seek((int)offset,origin); 1.472 +} 1.473 + 1.474 +int FILEFile::CopyFromStream(File *pstream, int byteSize) 1.475 +{ 1.476 + uint8_t* buff = new uint8_t[0x4000]; 1.477 + int count = 0; 1.478 + int szRequest, szRead, szWritten; 1.479 + 1.480 + while (byteSize) 1.481 + { 1.482 + szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize; 1.483 + 1.484 + szRead = pstream->Read(buff, szRequest); 1.485 + szWritten = 0; 1.486 + if (szRead > 0) 1.487 + szWritten = Write(buff, szRead); 1.488 + 1.489 + count += szWritten; 1.490 + byteSize -= szWritten; 1.491 + if (szWritten < szRequest) 1.492 + break; 1.493 + } 1.494 + 1.495 + delete[] buff; 1.496 + 1.497 + return count; 1.498 +} 1.499 + 1.500 + 1.501 +bool FILEFile::Close() 1.502 +{ 1.503 +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS 1.504 + if (pFileTestBuffer) 1.505 + { 1.506 + OVR_FREE(pFileTestBuffer); 1.507 + pFileTestBuffer = 0; 1.508 + FileTestLength = 0; 1.509 + } 1.510 +#endif 1.511 + 1.512 + bool closeRet = !fclose(fs); 1.513 + 1.514 + if (!closeRet) 1.515 + { 1.516 + ErrorCode = SFerror(); 1.517 + return 0; 1.518 + } 1.519 + else 1.520 + { 1.521 + Opened = 0; 1.522 + fs = 0; 1.523 + ErrorCode = 0; 1.524 + } 1.525 + 1.526 + // Handle safe truncate 1.527 + /* 1.528 + if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC) 1.529 + { 1.530 + // Delete original file (if it existed) 1.531 + DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName); 1.532 + if (oldAttributes!=0xFFFFFFFF) 1.533 + if (!FileUtilWin32::DeleteFile(FileName)) 1.534 + { 1.535 + // Try to remove the readonly attribute 1.536 + FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) ); 1.537 + // And delete the file again 1.538 + if (!FileUtilWin32::DeleteFile(FileName)) 1.539 + return 0; 1.540 + } 1.541 + 1.542 + // Rename temp file to real filename 1.543 + if (!FileUtilWin32::MoveFile(TempName, FileName)) 1.544 + { 1.545 + //ErrorCode = errno; 1.546 + return 0; 1.547 + } 1.548 + } 1.549 + */ 1.550 + return 1; 1.551 +} 1.552 + 1.553 +/* 1.554 +bool FILEFile::CloseCancel() 1.555 +{ 1.556 + bool closeRet = (bool)::CloseHandle(fd); 1.557 + 1.558 + if (!closeRet) 1.559 + { 1.560 + //ErrorCode = errno; 1.561 + return 0; 1.562 + } 1.563 + else 1.564 + { 1.565 + Opened = 0; 1.566 + fd = INVALID_HANDLE_VALUE; 1.567 + ErrorCode = 0; 1.568 + } 1.569 + 1.570 + // Handle safe truncate (delete tmp file, leave original unchanged) 1.571 + if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC) 1.572 + if (!FileUtilWin32::DeleteFile(TempName)) 1.573 + { 1.574 + //ErrorCode = errno; 1.575 + return 0; 1.576 + } 1.577 + return 1; 1.578 +} 1.579 +*/ 1.580 + 1.581 +Ptr<File> FileFILEOpen(const String& path, int flags, int mode) 1.582 +{ 1.583 + Ptr<File> result = *new FILEFile(path, flags, mode); 1.584 + return result; 1.585 +} 1.586 + 1.587 +// Helper function: obtain file information time. 1.588 +bool SysFile::GetFileStat(FileStat* pfileStat, const String& path) 1.589 +{ 1.590 +#if defined(OVR_OS_MS) 1.591 + // 64-bit implementation on Windows. 1.592 + struct __stat64 fileStat; 1.593 + // Stat returns 0 for success. 1.594 + wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t)); 1.595 + UTF8Util::DecodeString(pwpath, path.ToCStr()); 1.596 + 1.597 + int ret = _wstat64(pwpath, &fileStat); 1.598 + OVR_FREE(pwpath); 1.599 + if (ret) return false; 1.600 +#else 1.601 + struct stat fileStat; 1.602 + // Stat returns 0 for success. 1.603 + if (stat(path, &fileStat) != 0) 1.604 + return false; 1.605 +#endif 1.606 + pfileStat->AccessTime = fileStat.st_atime; 1.607 + pfileStat->ModifyTime = fileStat.st_mtime; 1.608 + pfileStat->FileSize = fileStat.st_size; 1.609 + return true; 1.610 +} 1.611 + 1.612 +} // Namespace OVR