diff options
Diffstat (limited to 'ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_File.cpp')
-rw-r--r-- | ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_File.cpp | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_File.cpp b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_File.cpp new file mode 100644 index 0000000..5f370c0 --- /dev/null +++ b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_File.cpp @@ -0,0 +1,521 @@ +/************************************************************************** + +Filename : OVR_File.cpp +Content : File wrapper class implementation (Win32) + +Created : April 5, 1999 +Authors : Michael Antonov + +Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved. + +Licensed under the Oculus Master SDK License Version 1.0 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +https://developer.oculus.com/licenses/oculusmastersdk-1.0 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +**************************************************************************/ + +#define GFILE_CXX + +// Standard C library (Captain Obvious guarantees!) +#include <stdio.h> + +#include "OVR_File.h" + +namespace OVR { + +// Buffered file adds buffering to an existing file +// FILEBUFFER_SIZE defines the size of internal buffer, while +// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer +#define FILEBUFFER_SIZE (8192 - 8) +#define FILEBUFFER_TOLERANCE 4096 + +// ** Constructor/Destructor + +// Hidden constructor +// Not supposed to be used +BufferedFile::BufferedFile() : DelegatedFile(0) { + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); + BufferMode = NoBuffer; + FilePos = 0; + Pos = 0; + DataSize = 0; +} + +// Takes another file as source +BufferedFile::BufferedFile(File* pfile) : DelegatedFile(pfile) { + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); + BufferMode = NoBuffer; + FilePos = pfile->LTell(); + Pos = 0; + DataSize = 0; +} + +// Destructor +BufferedFile::~BufferedFile() { + // Flush in case there's data + if (pFile) + FlushBuffer(); + // Get rid of buffer + if (pBuffer) + OVR_FREE(pBuffer); +} + +/* +bool BufferedFile::VCopy(const Object &source) +{ + if (!DelegatedFile::VCopy(source)) + return 0; + + // Data members + BufferedFile *psource = (BufferedFile*)&source; + + // Buffer & the mode it's in + pBuffer = psource->pBuffer; + BufferMode = psource->BufferMode; + Pos = psource->Pos; + DataSize = psource->DataSize; + return 1; +} +*/ + +// Initializes buffering to a certain mode +bool BufferedFile::SetBufferMode(BufferModeType mode) { + if (!pBuffer) + return false; + if (mode == BufferMode) + return true; + + FlushBuffer(); + + // Can't set write mode if we can't write + if ((mode == WriteBuffer) && (!pFile || !pFile->IsWritable())) + return 0; + + // And SetMode + BufferMode = mode; + Pos = 0; + DataSize = 0; + return 1; +} + +// Flushes buffer +void BufferedFile::FlushBuffer() { + switch (BufferMode) { + case WriteBuffer: + // Write data in buffer + FilePos += pFile->Write(pBuffer, Pos); + Pos = 0; + break; + + case ReadBuffer: + // Seek back & reset buffer data + if ((DataSize - Pos) > 0) + FilePos = pFile->LSeek(-(int)(DataSize - Pos), Seek_Cur); + DataSize = 0; + Pos = 0; + break; + default: + // not handled! + break; + } +} + +// Reloads data for ReadBuffer +void BufferedFile::LoadBuffer() { + if (BufferMode == ReadBuffer) { + // We should only reload once all of pre-loaded buffer is consumed. + OVR_ASSERT(Pos == DataSize); + + // WARNING: Right now LoadBuffer() assumes the buffer's empty + int sz = pFile->Read(pBuffer, FILEBUFFER_SIZE); + DataSize = sz < 0 ? 0 : (unsigned)sz; + Pos = 0; + FilePos += DataSize; + } +} + +// ** Overridden functions + +// We override all the functions that can possibly +// require buffer mode switch, flush, or extra calculations + +// Tell() requires buffer adjustment +int BufferedFile::Tell() { + if (BufferMode == ReadBuffer) + return int(FilePos - DataSize + Pos); + + int pos = pFile->Tell(); + // Adjust position based on buffer mode & data + if (pos != -1) { + OVR_ASSERT(BufferMode != ReadBuffer); + if (BufferMode == WriteBuffer) + pos += Pos; + } + return pos; +} + +int64_t BufferedFile::LTell() { + if (BufferMode == ReadBuffer) + return FilePos - DataSize + Pos; + + int64_t pos = pFile->LTell(); + if (pos != -1) { + OVR_ASSERT(BufferMode != ReadBuffer); + if (BufferMode == WriteBuffer) + pos += Pos; + } + return pos; +} + +int BufferedFile::GetLength() { + int len = pFile->GetLength(); + // If writing through buffer, file length may actually be bigger + if ((len != -1) && (BufferMode == WriteBuffer)) { + int currPos = pFile->Tell() + Pos; + if (currPos > len) + len = currPos; + } + return len; +} +int64_t BufferedFile::LGetLength() { + int64_t len = pFile->LGetLength(); + // If writing through buffer, file length may actually be bigger + if ((len != -1) && (BufferMode == WriteBuffer)) { + int64_t currPos = pFile->LTell() + Pos; + if (currPos > len) + len = currPos; + } + return len; +} + +/* +bool BufferedFile::Stat(FileStats *pfs) +{ + // Have to fix up length is stat + if (pFile->Stat(pfs)) + { + if (BufferMode==WriteBuffer) + { + int64_t currPos = pFile->LTell() + Pos; + if (currPos > pfs->Size) + { + pfs->Size = currPos; + // ?? + pfs->Blocks = (pfs->Size+511) >> 9; + } + } + return 1; + } + return 0; +} +*/ + +int BufferedFile::Write(const uint8_t* psourceBuffer, int numBytes) { + if ((BufferMode == WriteBuffer) || SetBufferMode(WriteBuffer)) { + // If not data space in buffer, flush + if ((FILEBUFFER_SIZE - (int)Pos) < numBytes) { + FlushBuffer(); + // If bigger then tolerance, just write directly + if (numBytes > FILEBUFFER_TOLERANCE) { + int sz = pFile->Write(psourceBuffer, numBytes); + if (sz > 0) + FilePos += sz; + return sz; + } + } + + // Enough space in buffer.. so copy to it + memcpy(pBuffer + Pos, psourceBuffer, numBytes); + Pos += numBytes; + return numBytes; + } + int sz = pFile->Write(psourceBuffer, numBytes); + if (sz > 0) + FilePos += sz; + return sz; +} + +int BufferedFile::Read(uint8_t* pdestBuffer, int numBytes) { + if ((BufferMode == ReadBuffer) || SetBufferMode(ReadBuffer)) { + // Data in buffer... copy it + if ((int)(DataSize - Pos) >= numBytes) { + memcpy(pdestBuffer, pBuffer + Pos, numBytes); + Pos += numBytes; + return numBytes; + } + + // Not enough data in buffer, copy buffer + int readBytes = DataSize - Pos; + memcpy(pdestBuffer, pBuffer + Pos, readBytes); + numBytes -= readBytes; + pdestBuffer += readBytes; + Pos = DataSize; + + // Don't reload buffer if more then tolerance + // (No major advantage, and we don't want to write a loop) + if (numBytes > FILEBUFFER_TOLERANCE) { + numBytes = pFile->Read(pdestBuffer, numBytes); + if (numBytes > 0) { + FilePos += numBytes; + Pos = DataSize = 0; + } + return readBytes + ((numBytes == -1) ? 0 : numBytes); + } + + // Reload the buffer + // WARNING: Right now LoadBuffer() assumes the buffer's empty + LoadBuffer(); + if ((int)(DataSize - Pos) < numBytes) + numBytes = (int)DataSize - Pos; + + memcpy(pdestBuffer, pBuffer + Pos, numBytes); + Pos += numBytes; + return numBytes + readBytes; + + /* + // Alternative Read implementation. The one above is probably better + // due to FILEBUFFER_TOLERANCE. + int total = 0; + + do { + int bufferBytes = (int)(DataSize-Pos); + int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes; + + memcpy(pdestBuffer, pBuffer+Pos, copyBytes); + numBytes -= copyBytes; + pdestBuffer += copyBytes; + Pos += copyBytes; + total += copyBytes; + + if (numBytes == 0) + break; + LoadBuffer(); + + } while (DataSize > 0); + + return total; + */ + } + int sz = pFile->Read(pdestBuffer, numBytes); + if (sz > 0) + FilePos += sz; + return sz; +} + +int BufferedFile::SkipBytes(int numBytes) { + int skippedBytes = 0; + + // Special case for skipping a little data in read buffer + if (BufferMode == ReadBuffer) { + skippedBytes = (((int)DataSize - (int)Pos) >= numBytes) ? numBytes : (DataSize - Pos); + Pos += skippedBytes; + numBytes -= skippedBytes; + } + + if (numBytes) { + numBytes = pFile->SkipBytes(numBytes); + // Make sure we return the actual number skipped, or error + if (numBytes != -1) { + skippedBytes += numBytes; + FilePos += numBytes; + Pos = DataSize = 0; + } else if (skippedBytes <= 0) + skippedBytes = -1; + } + return skippedBytes; +} + +int BufferedFile::BytesAvailable() { + int available = pFile->BytesAvailable(); + // Adjust available size based on buffers + switch (BufferMode) { + case ReadBuffer: + available += DataSize - Pos; + break; + case WriteBuffer: + available -= Pos; + if (available < 0) + available = 0; + break; + default: + break; + } + return available; +} + +bool BufferedFile::Flush() { + FlushBuffer(); + return pFile->Flush(); +} + +// Seeking could be optimized better.. +int BufferedFile::Seek(int offset, int origin) { + if (BufferMode == ReadBuffer) { + if (origin == Seek_Cur) { + // Seek can fall either before or after Pos in the buffer, + // but it must be within bounds. + if (((unsigned(offset) + Pos)) <= DataSize) { + Pos += offset; + return int(FilePos - DataSize + Pos); + } + + // Lightweight buffer "Flush". We do this to avoid an extra seek + // back operation which would take place if we called FlushBuffer directly. + origin = Seek_Set; + OVR_ASSERT(((FilePos - DataSize + Pos) + (uint64_t)offset) < ~(uint64_t)0); + offset = (int)(FilePos - DataSize + Pos) + offset; + Pos = DataSize = 0; + } else if (origin == Seek_Set) { + if (((unsigned)offset - (FilePos - DataSize)) <= DataSize) { + OVR_ASSERT((FilePos - DataSize) < ~(uint64_t)0); + Pos = (unsigned)offset - (unsigned)(FilePos - DataSize); + return offset; + } + Pos = DataSize = 0; + } else { + FlushBuffer(); + } + } else { + FlushBuffer(); + } + + /* + // Old Seek Logic + if (origin == Seek_Cur && offset + Pos < DataSize) + { + //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset)); + Pos += offset; + OVR_ASSERT(int (Pos) >= 0); + return int (FilePos - DataSize + Pos); + } + else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < + FilePos) + { + Pos = unsigned(offset - FilePos + DataSize); + OVR_ASSERT(int (Pos) >= 0); + return int (FilePos - DataSize + Pos); + } + + FlushBuffer(); + */ + + FilePos = pFile->Seek(offset, origin); + return int(FilePos); +} + +int64_t BufferedFile::LSeek(int64_t offset, int origin) { + if (BufferMode == ReadBuffer) { + if (origin == Seek_Cur) { + // Seek can fall either before or after Pos in the buffer, + // but it must be within bounds. + if (((unsigned(offset) + Pos)) <= DataSize) { + Pos += (unsigned)offset; + return int64_t(FilePos - DataSize + Pos); + } + + // Lightweight buffer "Flush". We do this to avoid an extra seek + // back operation which would take place if we called FlushBuffer directly. + origin = Seek_Set; + offset = (int64_t)(FilePos - DataSize + Pos) + offset; + Pos = DataSize = 0; + } else if (origin == Seek_Set) { + if (((uint64_t)offset - (FilePos - DataSize)) <= DataSize) { + Pos = (unsigned)((uint64_t)offset - (FilePos - DataSize)); + return offset; + } + Pos = DataSize = 0; + } else { + FlushBuffer(); + } + } else { + FlushBuffer(); + } + + /* + OVR_ASSERT(BufferMode != NoBuffer); + + if (origin == Seek_Cur && offset + Pos < DataSize) + { + Pos += int (offset); + return FilePos - DataSize + Pos; + } + else if (origin == Seek_Set && offset >= int64_t(FilePos - DataSize) && offset < + int64_t(FilePos)) + { + Pos = unsigned(offset - FilePos + DataSize); + return FilePos - DataSize + Pos; + } + + FlushBuffer(); + */ + + FilePos = pFile->LSeek(offset, origin); + return FilePos; +} + +int BufferedFile::CopyFromStream(File* pstream, int byteSize) { + // We can't rely on overridden Write() + // because delegation doesn't override virtual pointers + // So, just re-implement + uint8_t* buff = new uint8_t[0x4000]; + int count = 0; + int szRequest, szRead, szWritten; + + while (byteSize) { + szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize; + + szRead = pstream->Read(buff, szRequest); + szWritten = 0; + if (szRead > 0) + szWritten = Write(buff, szRead); + + count += szWritten; + byteSize -= szWritten; + if (szWritten < szRequest) + break; + } + + delete[] buff; + + return count; +} + +// Closing files +bool BufferedFile::Close() { + switch (BufferMode) { + case WriteBuffer: + FlushBuffer(); + break; + case ReadBuffer: + // No need to seek back on close + BufferMode = NoBuffer; + break; + default: + break; + } + return pFile->Close(); +} + +// ***** Global path helpers + +// Find trailing short filename in a path. +const char* OVR_CDECL GetShortFilename(const char* purl) { + size_t len = OVR_strlen(purl); + for (size_t i = len; i > 0; i--) + if (purl[i] == '\\' || purl[i] == '/') + return purl + i + 1; + return purl; +} + +} // namespace OVR |