ovr_sdk
diff LibOVR/Src/Kernel/OVR_File.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_File.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,585 @@ 1.4 +/************************************************************************** 1.5 + 1.6 +Filename : OVR_File.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 +// Standard C library (Captain Obvious guarantees!) 1.34 +#include <stdio.h> 1.35 + 1.36 +#include "OVR_File.h" 1.37 + 1.38 +namespace OVR { 1.39 + 1.40 +// Buffered file adds buffering to an existing file 1.41 +// FILEBUFFER_SIZE defines the size of internal buffer, while 1.42 +// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer 1.43 +#define FILEBUFFER_SIZE (8192-8) 1.44 +#define FILEBUFFER_TOLERANCE 4096 1.45 + 1.46 +// ** Constructor/Destructor 1.47 + 1.48 +// Hidden constructor 1.49 +// Not supposed to be used 1.50 +BufferedFile::BufferedFile() : DelegatedFile(0) 1.51 +{ 1.52 + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); 1.53 + BufferMode = NoBuffer; 1.54 + FilePos = 0; 1.55 + Pos = 0; 1.56 + DataSize = 0; 1.57 +} 1.58 + 1.59 +// Takes another file as source 1.60 +BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile) 1.61 +{ 1.62 + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); 1.63 + BufferMode = NoBuffer; 1.64 + FilePos = pfile->LTell(); 1.65 + Pos = 0; 1.66 + DataSize = 0; 1.67 +} 1.68 + 1.69 + 1.70 +// Destructor 1.71 +BufferedFile::~BufferedFile() 1.72 +{ 1.73 + // Flush in case there's data 1.74 + if (pFile) 1.75 + FlushBuffer(); 1.76 + // Get rid of buffer 1.77 + if (pBuffer) 1.78 + OVR_FREE(pBuffer); 1.79 +} 1.80 + 1.81 +/* 1.82 +bool BufferedFile::VCopy(const Object &source) 1.83 +{ 1.84 + if (!DelegatedFile::VCopy(source)) 1.85 + return 0; 1.86 + 1.87 + // Data members 1.88 + BufferedFile *psource = (BufferedFile*)&source; 1.89 + 1.90 + // Buffer & the mode it's in 1.91 + pBuffer = psource->pBuffer; 1.92 + BufferMode = psource->BufferMode; 1.93 + Pos = psource->Pos; 1.94 + DataSize = psource->DataSize; 1.95 + return 1; 1.96 +} 1.97 +*/ 1.98 + 1.99 +// Initializes buffering to a certain mode 1.100 +bool BufferedFile::SetBufferMode(BufferModeType mode) 1.101 +{ 1.102 + if (!pBuffer) 1.103 + return false; 1.104 + if (mode == BufferMode) 1.105 + return true; 1.106 + 1.107 + FlushBuffer(); 1.108 + 1.109 + // Can't set write mode if we can't write 1.110 + if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) ) 1.111 + return 0; 1.112 + 1.113 + // And SetMode 1.114 + BufferMode = mode; 1.115 + Pos = 0; 1.116 + DataSize = 0; 1.117 + return 1; 1.118 +} 1.119 + 1.120 +// Flushes buffer 1.121 +void BufferedFile::FlushBuffer() 1.122 +{ 1.123 + switch(BufferMode) 1.124 + { 1.125 + case WriteBuffer: 1.126 + // Write data in buffer 1.127 + FilePos += pFile->Write(pBuffer,Pos); 1.128 + Pos = 0; 1.129 + break; 1.130 + 1.131 + case ReadBuffer: 1.132 + // Seek back & reset buffer data 1.133 + if ((DataSize-Pos)>0) 1.134 + FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur); 1.135 + DataSize = 0; 1.136 + Pos = 0; 1.137 + break; 1.138 + default: 1.139 + // not handled! 1.140 + break; 1.141 + } 1.142 +} 1.143 + 1.144 +// Reloads data for ReadBuffer 1.145 +void BufferedFile::LoadBuffer() 1.146 +{ 1.147 + if (BufferMode == ReadBuffer) 1.148 + { 1.149 + // We should only reload once all of pre-loaded buffer is consumed. 1.150 + OVR_ASSERT(Pos == DataSize); 1.151 + 1.152 + // WARNING: Right now LoadBuffer() assumes the buffer's empty 1.153 + int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE); 1.154 + DataSize = sz<0 ? 0 : (unsigned)sz; 1.155 + Pos = 0; 1.156 + FilePos += DataSize; 1.157 + } 1.158 +} 1.159 + 1.160 + 1.161 +// ** Overridden functions 1.162 + 1.163 +// We override all the functions that can possibly 1.164 +// require buffer mode switch, flush, or extra calculations 1.165 + 1.166 +// Tell() requires buffer adjustment 1.167 +int BufferedFile::Tell() 1.168 +{ 1.169 + if (BufferMode == ReadBuffer) 1.170 + return int (FilePos - DataSize + Pos); 1.171 + 1.172 + int pos = pFile->Tell(); 1.173 + // Adjust position based on buffer mode & data 1.174 + if (pos!=-1) 1.175 + { 1.176 + OVR_ASSERT(BufferMode != ReadBuffer); 1.177 + if (BufferMode == WriteBuffer) 1.178 + pos += Pos; 1.179 + } 1.180 + return pos; 1.181 +} 1.182 + 1.183 +int64_t BufferedFile::LTell() 1.184 +{ 1.185 + if (BufferMode == ReadBuffer) 1.186 + return FilePos - DataSize + Pos; 1.187 + 1.188 + int64_t pos = pFile->LTell(); 1.189 + if (pos!=-1) 1.190 + { 1.191 + OVR_ASSERT(BufferMode != ReadBuffer); 1.192 + if (BufferMode == WriteBuffer) 1.193 + pos += Pos; 1.194 + } 1.195 + return pos; 1.196 +} 1.197 + 1.198 +int BufferedFile::GetLength() 1.199 +{ 1.200 + int len = pFile->GetLength(); 1.201 + // If writing through buffer, file length may actually be bigger 1.202 + if ((len!=-1) && (BufferMode==WriteBuffer)) 1.203 + { 1.204 + int currPos = pFile->Tell() + Pos; 1.205 + if (currPos>len) 1.206 + len = currPos; 1.207 + } 1.208 + return len; 1.209 +} 1.210 +int64_t BufferedFile::LGetLength() 1.211 +{ 1.212 + int64_t len = pFile->LGetLength(); 1.213 + // If writing through buffer, file length may actually be bigger 1.214 + if ((len!=-1) && (BufferMode==WriteBuffer)) 1.215 + { 1.216 + int64_t currPos = pFile->LTell() + Pos; 1.217 + if (currPos>len) 1.218 + len = currPos; 1.219 + } 1.220 + return len; 1.221 +} 1.222 + 1.223 +/* 1.224 +bool BufferedFile::Stat(FileStats *pfs) 1.225 +{ 1.226 + // Have to fix up length is stat 1.227 + if (pFile->Stat(pfs)) 1.228 + { 1.229 + if (BufferMode==WriteBuffer) 1.230 + { 1.231 + int64_t currPos = pFile->LTell() + Pos; 1.232 + if (currPos > pfs->Size) 1.233 + { 1.234 + pfs->Size = currPos; 1.235 + // ?? 1.236 + pfs->Blocks = (pfs->Size+511) >> 9; 1.237 + } 1.238 + } 1.239 + return 1; 1.240 + } 1.241 + return 0; 1.242 +} 1.243 +*/ 1.244 + 1.245 +int BufferedFile::Write(const uint8_t *psourceBuffer, int numBytes) 1.246 +{ 1.247 + if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer)) 1.248 + { 1.249 + // If not data space in buffer, flush 1.250 + if ((FILEBUFFER_SIZE-(int)Pos)<numBytes) 1.251 + { 1.252 + FlushBuffer(); 1.253 + // If bigger then tolerance, just write directly 1.254 + if (numBytes>FILEBUFFER_TOLERANCE) 1.255 + { 1.256 + int sz = pFile->Write(psourceBuffer,numBytes); 1.257 + if (sz > 0) 1.258 + FilePos += sz; 1.259 + return sz; 1.260 + } 1.261 + } 1.262 + 1.263 + // Enough space in buffer.. so copy to it 1.264 + memcpy(pBuffer+Pos, psourceBuffer, numBytes); 1.265 + Pos += numBytes; 1.266 + return numBytes; 1.267 + } 1.268 + int sz = pFile->Write(psourceBuffer,numBytes); 1.269 + if (sz > 0) 1.270 + FilePos += sz; 1.271 + return sz; 1.272 +} 1.273 + 1.274 +int BufferedFile::Read(uint8_t *pdestBuffer, int numBytes) 1.275 +{ 1.276 + if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer)) 1.277 + { 1.278 + // Data in buffer... copy it 1.279 + if ((int)(DataSize-Pos) >= numBytes) 1.280 + { 1.281 + memcpy(pdestBuffer, pBuffer+Pos, numBytes); 1.282 + Pos += numBytes; 1.283 + return numBytes; 1.284 + } 1.285 + 1.286 + // Not enough data in buffer, copy buffer 1.287 + int readBytes = DataSize-Pos; 1.288 + memcpy(pdestBuffer, pBuffer+Pos, readBytes); 1.289 + numBytes -= readBytes; 1.290 + pdestBuffer += readBytes; 1.291 + Pos = DataSize; 1.292 + 1.293 + // Don't reload buffer if more then tolerance 1.294 + // (No major advantage, and we don't want to write a loop) 1.295 + if (numBytes>FILEBUFFER_TOLERANCE) 1.296 + { 1.297 + numBytes = pFile->Read(pdestBuffer,numBytes); 1.298 + if (numBytes > 0) 1.299 + { 1.300 + FilePos += numBytes; 1.301 + Pos = DataSize = 0; 1.302 + } 1.303 + return readBytes + ((numBytes==-1) ? 0 : numBytes); 1.304 + } 1.305 + 1.306 + // Reload the buffer 1.307 + // WARNING: Right now LoadBuffer() assumes the buffer's empty 1.308 + LoadBuffer(); 1.309 + if ((int)(DataSize-Pos) < numBytes) 1.310 + numBytes = (int)DataSize-Pos; 1.311 + 1.312 + memcpy(pdestBuffer, pBuffer+Pos, numBytes); 1.313 + Pos += numBytes; 1.314 + return numBytes + readBytes; 1.315 + 1.316 + /* 1.317 + // Alternative Read implementation. The one above is probably better 1.318 + // due to FILEBUFFER_TOLERANCE. 1.319 + int total = 0; 1.320 + 1.321 + do { 1.322 + int bufferBytes = (int)(DataSize-Pos); 1.323 + int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes; 1.324 + 1.325 + memcpy(pdestBuffer, pBuffer+Pos, copyBytes); 1.326 + numBytes -= copyBytes; 1.327 + pdestBuffer += copyBytes; 1.328 + Pos += copyBytes; 1.329 + total += copyBytes; 1.330 + 1.331 + if (numBytes == 0) 1.332 + break; 1.333 + LoadBuffer(); 1.334 + 1.335 + } while (DataSize > 0); 1.336 + 1.337 + return total; 1.338 + */ 1.339 + } 1.340 + int sz = pFile->Read(pdestBuffer,numBytes); 1.341 + if (sz > 0) 1.342 + FilePos += sz; 1.343 + return sz; 1.344 +} 1.345 + 1.346 + 1.347 +int BufferedFile::SkipBytes(int numBytes) 1.348 +{ 1.349 + int skippedBytes = 0; 1.350 + 1.351 + // Special case for skipping a little data in read buffer 1.352 + if (BufferMode==ReadBuffer) 1.353 + { 1.354 + skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos); 1.355 + Pos += skippedBytes; 1.356 + numBytes -= skippedBytes; 1.357 + } 1.358 + 1.359 + if (numBytes) 1.360 + { 1.361 + numBytes = pFile->SkipBytes(numBytes); 1.362 + // Make sure we return the actual number skipped, or error 1.363 + if (numBytes!=-1) 1.364 + { 1.365 + skippedBytes += numBytes; 1.366 + FilePos += numBytes; 1.367 + Pos = DataSize = 0; 1.368 + } 1.369 + else if (skippedBytes <= 0) 1.370 + skippedBytes = -1; 1.371 + } 1.372 + return skippedBytes; 1.373 +} 1.374 + 1.375 +int BufferedFile::BytesAvailable() 1.376 +{ 1.377 + int available = pFile->BytesAvailable(); 1.378 + // Adjust available size based on buffers 1.379 + switch(BufferMode) 1.380 + { 1.381 + case ReadBuffer: 1.382 + available += DataSize-Pos; 1.383 + break; 1.384 + case WriteBuffer: 1.385 + available -= Pos; 1.386 + if (available<0) 1.387 + available= 0; 1.388 + break; 1.389 + default: 1.390 + break; 1.391 + } 1.392 + return available; 1.393 +} 1.394 + 1.395 +bool BufferedFile::Flush() 1.396 +{ 1.397 + FlushBuffer(); 1.398 + return pFile->Flush(); 1.399 +} 1.400 + 1.401 +// Seeking could be optimized better.. 1.402 +int BufferedFile::Seek(int offset, int origin) 1.403 +{ 1.404 + if (BufferMode == ReadBuffer) 1.405 + { 1.406 + if (origin == Seek_Cur) 1.407 + { 1.408 + // Seek can fall either before or after Pos in the buffer, 1.409 + // but it must be within bounds. 1.410 + if (((unsigned(offset) + Pos)) <= DataSize) 1.411 + { 1.412 + Pos += offset; 1.413 + return int (FilePos - DataSize + Pos); 1.414 + } 1.415 + 1.416 + // Lightweight buffer "Flush". We do this to avoid an extra seek 1.417 + // back operation which would take place if we called FlushBuffer directly. 1.418 + origin = Seek_Set; 1.419 + OVR_ASSERT(((FilePos - DataSize + Pos) + (uint64_t)offset) < ~(uint64_t)0); 1.420 + offset = (int)(FilePos - DataSize + Pos) + offset; 1.421 + Pos = DataSize = 0; 1.422 + } 1.423 + else if (origin == Seek_Set) 1.424 + { 1.425 + if (((unsigned)offset - (FilePos-DataSize)) <= DataSize) 1.426 + { 1.427 + OVR_ASSERT((FilePos-DataSize) < ~(uint64_t)0); 1.428 + Pos = (unsigned)offset - (unsigned)(FilePos-DataSize); 1.429 + return offset; 1.430 + } 1.431 + Pos = DataSize = 0; 1.432 + } 1.433 + else 1.434 + { 1.435 + FlushBuffer(); 1.436 + } 1.437 + } 1.438 + else 1.439 + { 1.440 + FlushBuffer(); 1.441 + } 1.442 + 1.443 + /* 1.444 + // Old Seek Logic 1.445 + if (origin == Seek_Cur && offset + Pos < DataSize) 1.446 + { 1.447 + //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset)); 1.448 + Pos += offset; 1.449 + OVR_ASSERT(int (Pos) >= 0); 1.450 + return int (FilePos - DataSize + Pos); 1.451 + } 1.452 + else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos) 1.453 + { 1.454 + Pos = unsigned(offset - FilePos + DataSize); 1.455 + OVR_ASSERT(int (Pos) >= 0); 1.456 + return int (FilePos - DataSize + Pos); 1.457 + } 1.458 + 1.459 + FlushBuffer(); 1.460 + */ 1.461 + 1.462 + 1.463 + FilePos = pFile->Seek(offset,origin); 1.464 + return int (FilePos); 1.465 +} 1.466 + 1.467 +int64_t BufferedFile::LSeek(int64_t offset, int origin) 1.468 +{ 1.469 + if (BufferMode == ReadBuffer) 1.470 + { 1.471 + if (origin == Seek_Cur) 1.472 + { 1.473 + // Seek can fall either before or after Pos in the buffer, 1.474 + // but it must be within bounds. 1.475 + if (((unsigned(offset) + Pos)) <= DataSize) 1.476 + { 1.477 + Pos += (unsigned)offset; 1.478 + return int64_t(FilePos - DataSize + Pos); 1.479 + } 1.480 + 1.481 + // Lightweight buffer "Flush". We do this to avoid an extra seek 1.482 + // back operation which would take place if we called FlushBuffer directly. 1.483 + origin = Seek_Set; 1.484 + offset = (int64_t)(FilePos - DataSize + Pos) + offset; 1.485 + Pos = DataSize = 0; 1.486 + } 1.487 + else if (origin == Seek_Set) 1.488 + { 1.489 + if (((uint64_t)offset - (FilePos-DataSize)) <= DataSize) 1.490 + { 1.491 + Pos = (unsigned)((uint64_t)offset - (FilePos-DataSize)); 1.492 + return offset; 1.493 + } 1.494 + Pos = DataSize = 0; 1.495 + } 1.496 + else 1.497 + { 1.498 + FlushBuffer(); 1.499 + } 1.500 + } 1.501 + else 1.502 + { 1.503 + FlushBuffer(); 1.504 + } 1.505 + 1.506 +/* 1.507 + OVR_ASSERT(BufferMode != NoBuffer); 1.508 + 1.509 + if (origin == Seek_Cur && offset + Pos < DataSize) 1.510 + { 1.511 + Pos += int (offset); 1.512 + return FilePos - DataSize + Pos; 1.513 + } 1.514 + else if (origin == Seek_Set && offset >= int64_t(FilePos - DataSize) && offset < int64_t(FilePos)) 1.515 + { 1.516 + Pos = unsigned(offset - FilePos + DataSize); 1.517 + return FilePos - DataSize + Pos; 1.518 + } 1.519 + 1.520 + FlushBuffer(); 1.521 + */ 1.522 + 1.523 + FilePos = pFile->LSeek(offset,origin); 1.524 + return FilePos; 1.525 +} 1.526 + 1.527 +int BufferedFile::CopyFromStream(File *pstream, int byteSize) 1.528 +{ 1.529 + // We can't rely on overridden Write() 1.530 + // because delegation doesn't override virtual pointers 1.531 + // So, just re-implement 1.532 + uint8_t* buff = new uint8_t[0x4000]; 1.533 + int count = 0; 1.534 + int szRequest, szRead, szWritten; 1.535 + 1.536 + while(byteSize) 1.537 + { 1.538 + szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize; 1.539 + 1.540 + szRead = pstream->Read(buff,szRequest); 1.541 + szWritten = 0; 1.542 + if (szRead > 0) 1.543 + szWritten = Write(buff,szRead); 1.544 + 1.545 + count +=szWritten; 1.546 + byteSize-=szWritten; 1.547 + if (szWritten < szRequest) 1.548 + break; 1.549 + } 1.550 + 1.551 + delete[] buff; 1.552 + 1.553 + return count; 1.554 +} 1.555 + 1.556 +// Closing files 1.557 +bool BufferedFile::Close() 1.558 +{ 1.559 + switch(BufferMode) 1.560 + { 1.561 + case WriteBuffer: 1.562 + FlushBuffer(); 1.563 + break; 1.564 + case ReadBuffer: 1.565 + // No need to seek back on close 1.566 + BufferMode = NoBuffer; 1.567 + break; 1.568 + default: 1.569 + break; 1.570 + } 1.571 + return pFile->Close(); 1.572 +} 1.573 + 1.574 + 1.575 +// ***** Global path helpers 1.576 + 1.577 +// Find trailing short filename in a path. 1.578 +const char* OVR_CDECL GetShortFilename(const char* purl) 1.579 +{ 1.580 + size_t len = OVR_strlen(purl); 1.581 + for (size_t i=len; i>0; i--) 1.582 + if (purl[i]=='\\' || purl[i]=='/') 1.583 + return purl+i+1; 1.584 + return purl; 1.585 +} 1.586 + 1.587 +} // OVR 1.588 +