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 +