ovr_sdk

view 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 source
1 /**************************************************************************
3 Filename : OVR_File.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 // Standard C library (Captain Obvious guarantees!)
31 #include <stdio.h>
33 #include "OVR_File.h"
35 namespace OVR {
37 // Buffered file adds buffering to an existing file
38 // FILEBUFFER_SIZE defines the size of internal buffer, while
39 // FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
40 #define FILEBUFFER_SIZE (8192-8)
41 #define FILEBUFFER_TOLERANCE 4096
43 // ** Constructor/Destructor
45 // Hidden constructor
46 // Not supposed to be used
47 BufferedFile::BufferedFile() : DelegatedFile(0)
48 {
49 pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE);
50 BufferMode = NoBuffer;
51 FilePos = 0;
52 Pos = 0;
53 DataSize = 0;
54 }
56 // Takes another file as source
57 BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
58 {
59 pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE);
60 BufferMode = NoBuffer;
61 FilePos = pfile->LTell();
62 Pos = 0;
63 DataSize = 0;
64 }
67 // Destructor
68 BufferedFile::~BufferedFile()
69 {
70 // Flush in case there's data
71 if (pFile)
72 FlushBuffer();
73 // Get rid of buffer
74 if (pBuffer)
75 OVR_FREE(pBuffer);
76 }
78 /*
79 bool BufferedFile::VCopy(const Object &source)
80 {
81 if (!DelegatedFile::VCopy(source))
82 return 0;
84 // Data members
85 BufferedFile *psource = (BufferedFile*)&source;
87 // Buffer & the mode it's in
88 pBuffer = psource->pBuffer;
89 BufferMode = psource->BufferMode;
90 Pos = psource->Pos;
91 DataSize = psource->DataSize;
92 return 1;
93 }
94 */
96 // Initializes buffering to a certain mode
97 bool BufferedFile::SetBufferMode(BufferModeType mode)
98 {
99 if (!pBuffer)
100 return false;
101 if (mode == BufferMode)
102 return true;
104 FlushBuffer();
106 // Can't set write mode if we can't write
107 if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
108 return 0;
110 // And SetMode
111 BufferMode = mode;
112 Pos = 0;
113 DataSize = 0;
114 return 1;
115 }
117 // Flushes buffer
118 void BufferedFile::FlushBuffer()
119 {
120 switch(BufferMode)
121 {
122 case WriteBuffer:
123 // Write data in buffer
124 FilePos += pFile->Write(pBuffer,Pos);
125 Pos = 0;
126 break;
128 case ReadBuffer:
129 // Seek back & reset buffer data
130 if ((DataSize-Pos)>0)
131 FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
132 DataSize = 0;
133 Pos = 0;
134 break;
135 default:
136 // not handled!
137 break;
138 }
139 }
141 // Reloads data for ReadBuffer
142 void BufferedFile::LoadBuffer()
143 {
144 if (BufferMode == ReadBuffer)
145 {
146 // We should only reload once all of pre-loaded buffer is consumed.
147 OVR_ASSERT(Pos == DataSize);
149 // WARNING: Right now LoadBuffer() assumes the buffer's empty
150 int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
151 DataSize = sz<0 ? 0 : (unsigned)sz;
152 Pos = 0;
153 FilePos += DataSize;
154 }
155 }
158 // ** Overridden functions
160 // We override all the functions that can possibly
161 // require buffer mode switch, flush, or extra calculations
163 // Tell() requires buffer adjustment
164 int BufferedFile::Tell()
165 {
166 if (BufferMode == ReadBuffer)
167 return int (FilePos - DataSize + Pos);
169 int pos = pFile->Tell();
170 // Adjust position based on buffer mode & data
171 if (pos!=-1)
172 {
173 OVR_ASSERT(BufferMode != ReadBuffer);
174 if (BufferMode == WriteBuffer)
175 pos += Pos;
176 }
177 return pos;
178 }
180 int64_t BufferedFile::LTell()
181 {
182 if (BufferMode == ReadBuffer)
183 return FilePos - DataSize + Pos;
185 int64_t pos = pFile->LTell();
186 if (pos!=-1)
187 {
188 OVR_ASSERT(BufferMode != ReadBuffer);
189 if (BufferMode == WriteBuffer)
190 pos += Pos;
191 }
192 return pos;
193 }
195 int BufferedFile::GetLength()
196 {
197 int len = pFile->GetLength();
198 // If writing through buffer, file length may actually be bigger
199 if ((len!=-1) && (BufferMode==WriteBuffer))
200 {
201 int currPos = pFile->Tell() + Pos;
202 if (currPos>len)
203 len = currPos;
204 }
205 return len;
206 }
207 int64_t BufferedFile::LGetLength()
208 {
209 int64_t len = pFile->LGetLength();
210 // If writing through buffer, file length may actually be bigger
211 if ((len!=-1) && (BufferMode==WriteBuffer))
212 {
213 int64_t currPos = pFile->LTell() + Pos;
214 if (currPos>len)
215 len = currPos;
216 }
217 return len;
218 }
220 /*
221 bool BufferedFile::Stat(FileStats *pfs)
222 {
223 // Have to fix up length is stat
224 if (pFile->Stat(pfs))
225 {
226 if (BufferMode==WriteBuffer)
227 {
228 int64_t currPos = pFile->LTell() + Pos;
229 if (currPos > pfs->Size)
230 {
231 pfs->Size = currPos;
232 // ??
233 pfs->Blocks = (pfs->Size+511) >> 9;
234 }
235 }
236 return 1;
237 }
238 return 0;
239 }
240 */
242 int BufferedFile::Write(const uint8_t *psourceBuffer, int numBytes)
243 {
244 if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
245 {
246 // If not data space in buffer, flush
247 if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
248 {
249 FlushBuffer();
250 // If bigger then tolerance, just write directly
251 if (numBytes>FILEBUFFER_TOLERANCE)
252 {
253 int sz = pFile->Write(psourceBuffer,numBytes);
254 if (sz > 0)
255 FilePos += sz;
256 return sz;
257 }
258 }
260 // Enough space in buffer.. so copy to it
261 memcpy(pBuffer+Pos, psourceBuffer, numBytes);
262 Pos += numBytes;
263 return numBytes;
264 }
265 int sz = pFile->Write(psourceBuffer,numBytes);
266 if (sz > 0)
267 FilePos += sz;
268 return sz;
269 }
271 int BufferedFile::Read(uint8_t *pdestBuffer, int numBytes)
272 {
273 if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
274 {
275 // Data in buffer... copy it
276 if ((int)(DataSize-Pos) >= numBytes)
277 {
278 memcpy(pdestBuffer, pBuffer+Pos, numBytes);
279 Pos += numBytes;
280 return numBytes;
281 }
283 // Not enough data in buffer, copy buffer
284 int readBytes = DataSize-Pos;
285 memcpy(pdestBuffer, pBuffer+Pos, readBytes);
286 numBytes -= readBytes;
287 pdestBuffer += readBytes;
288 Pos = DataSize;
290 // Don't reload buffer if more then tolerance
291 // (No major advantage, and we don't want to write a loop)
292 if (numBytes>FILEBUFFER_TOLERANCE)
293 {
294 numBytes = pFile->Read(pdestBuffer,numBytes);
295 if (numBytes > 0)
296 {
297 FilePos += numBytes;
298 Pos = DataSize = 0;
299 }
300 return readBytes + ((numBytes==-1) ? 0 : numBytes);
301 }
303 // Reload the buffer
304 // WARNING: Right now LoadBuffer() assumes the buffer's empty
305 LoadBuffer();
306 if ((int)(DataSize-Pos) < numBytes)
307 numBytes = (int)DataSize-Pos;
309 memcpy(pdestBuffer, pBuffer+Pos, numBytes);
310 Pos += numBytes;
311 return numBytes + readBytes;
313 /*
314 // Alternative Read implementation. The one above is probably better
315 // due to FILEBUFFER_TOLERANCE.
316 int total = 0;
318 do {
319 int bufferBytes = (int)(DataSize-Pos);
320 int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
322 memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
323 numBytes -= copyBytes;
324 pdestBuffer += copyBytes;
325 Pos += copyBytes;
326 total += copyBytes;
328 if (numBytes == 0)
329 break;
330 LoadBuffer();
332 } while (DataSize > 0);
334 return total;
335 */
336 }
337 int sz = pFile->Read(pdestBuffer,numBytes);
338 if (sz > 0)
339 FilePos += sz;
340 return sz;
341 }
344 int BufferedFile::SkipBytes(int numBytes)
345 {
346 int skippedBytes = 0;
348 // Special case for skipping a little data in read buffer
349 if (BufferMode==ReadBuffer)
350 {
351 skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
352 Pos += skippedBytes;
353 numBytes -= skippedBytes;
354 }
356 if (numBytes)
357 {
358 numBytes = pFile->SkipBytes(numBytes);
359 // Make sure we return the actual number skipped, or error
360 if (numBytes!=-1)
361 {
362 skippedBytes += numBytes;
363 FilePos += numBytes;
364 Pos = DataSize = 0;
365 }
366 else if (skippedBytes <= 0)
367 skippedBytes = -1;
368 }
369 return skippedBytes;
370 }
372 int BufferedFile::BytesAvailable()
373 {
374 int available = pFile->BytesAvailable();
375 // Adjust available size based on buffers
376 switch(BufferMode)
377 {
378 case ReadBuffer:
379 available += DataSize-Pos;
380 break;
381 case WriteBuffer:
382 available -= Pos;
383 if (available<0)
384 available= 0;
385 break;
386 default:
387 break;
388 }
389 return available;
390 }
392 bool BufferedFile::Flush()
393 {
394 FlushBuffer();
395 return pFile->Flush();
396 }
398 // Seeking could be optimized better..
399 int BufferedFile::Seek(int offset, int origin)
400 {
401 if (BufferMode == ReadBuffer)
402 {
403 if (origin == Seek_Cur)
404 {
405 // Seek can fall either before or after Pos in the buffer,
406 // but it must be within bounds.
407 if (((unsigned(offset) + Pos)) <= DataSize)
408 {
409 Pos += offset;
410 return int (FilePos - DataSize + Pos);
411 }
413 // Lightweight buffer "Flush". We do this to avoid an extra seek
414 // back operation which would take place if we called FlushBuffer directly.
415 origin = Seek_Set;
416 OVR_ASSERT(((FilePos - DataSize + Pos) + (uint64_t)offset) < ~(uint64_t)0);
417 offset = (int)(FilePos - DataSize + Pos) + offset;
418 Pos = DataSize = 0;
419 }
420 else if (origin == Seek_Set)
421 {
422 if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
423 {
424 OVR_ASSERT((FilePos-DataSize) < ~(uint64_t)0);
425 Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
426 return offset;
427 }
428 Pos = DataSize = 0;
429 }
430 else
431 {
432 FlushBuffer();
433 }
434 }
435 else
436 {
437 FlushBuffer();
438 }
440 /*
441 // Old Seek Logic
442 if (origin == Seek_Cur && offset + Pos < DataSize)
443 {
444 //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
445 Pos += offset;
446 OVR_ASSERT(int (Pos) >= 0);
447 return int (FilePos - DataSize + Pos);
448 }
449 else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
450 {
451 Pos = unsigned(offset - FilePos + DataSize);
452 OVR_ASSERT(int (Pos) >= 0);
453 return int (FilePos - DataSize + Pos);
454 }
456 FlushBuffer();
457 */
460 FilePos = pFile->Seek(offset,origin);
461 return int (FilePos);
462 }
464 int64_t BufferedFile::LSeek(int64_t offset, int origin)
465 {
466 if (BufferMode == ReadBuffer)
467 {
468 if (origin == Seek_Cur)
469 {
470 // Seek can fall either before or after Pos in the buffer,
471 // but it must be within bounds.
472 if (((unsigned(offset) + Pos)) <= DataSize)
473 {
474 Pos += (unsigned)offset;
475 return int64_t(FilePos - DataSize + Pos);
476 }
478 // Lightweight buffer "Flush". We do this to avoid an extra seek
479 // back operation which would take place if we called FlushBuffer directly.
480 origin = Seek_Set;
481 offset = (int64_t)(FilePos - DataSize + Pos) + offset;
482 Pos = DataSize = 0;
483 }
484 else if (origin == Seek_Set)
485 {
486 if (((uint64_t)offset - (FilePos-DataSize)) <= DataSize)
487 {
488 Pos = (unsigned)((uint64_t)offset - (FilePos-DataSize));
489 return offset;
490 }
491 Pos = DataSize = 0;
492 }
493 else
494 {
495 FlushBuffer();
496 }
497 }
498 else
499 {
500 FlushBuffer();
501 }
503 /*
504 OVR_ASSERT(BufferMode != NoBuffer);
506 if (origin == Seek_Cur && offset + Pos < DataSize)
507 {
508 Pos += int (offset);
509 return FilePos - DataSize + Pos;
510 }
511 else if (origin == Seek_Set && offset >= int64_t(FilePos - DataSize) && offset < int64_t(FilePos))
512 {
513 Pos = unsigned(offset - FilePos + DataSize);
514 return FilePos - DataSize + Pos;
515 }
517 FlushBuffer();
518 */
520 FilePos = pFile->LSeek(offset,origin);
521 return FilePos;
522 }
524 int BufferedFile::CopyFromStream(File *pstream, int byteSize)
525 {
526 // We can't rely on overridden Write()
527 // because delegation doesn't override virtual pointers
528 // So, just re-implement
529 uint8_t* buff = new uint8_t[0x4000];
530 int count = 0;
531 int szRequest, szRead, szWritten;
533 while(byteSize)
534 {
535 szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
537 szRead = pstream->Read(buff,szRequest);
538 szWritten = 0;
539 if (szRead > 0)
540 szWritten = Write(buff,szRead);
542 count +=szWritten;
543 byteSize-=szWritten;
544 if (szWritten < szRequest)
545 break;
546 }
548 delete[] buff;
550 return count;
551 }
553 // Closing files
554 bool BufferedFile::Close()
555 {
556 switch(BufferMode)
557 {
558 case WriteBuffer:
559 FlushBuffer();
560 break;
561 case ReadBuffer:
562 // No need to seek back on close
563 BufferMode = NoBuffer;
564 break;
565 default:
566 break;
567 }
568 return pFile->Close();
569 }
572 // ***** Global path helpers
574 // Find trailing short filename in a path.
575 const char* OVR_CDECL GetShortFilename(const char* purl)
576 {
577 size_t len = OVR_strlen(purl);
578 for (size_t i=len; i>0; i--)
579 if (purl[i]=='\\' || purl[i]=='/')
580 return purl+i+1;
581 return purl;
582 }
584 } // OVR