oculus1
view libovr/Src/Kernel/OVR_File.cpp @ 3:b069a5c27388
added a couple more stuff, fixed all the LibOVR line endings
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 15 Sep 2013 04:10:05 +0300 |
parents | e2f9e4603129 |
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 2012 Oculus VR, Inc. All Rights reserved.
11 Use of this software is subject to the terms of the Oculus license
12 agreement provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 **************************************************************************/
17 #define GFILE_CXX
19 // Standard C library (Captain Obvious guarantees!)
20 #include <stdio.h>
22 #include "OVR_File.h"
24 namespace OVR {
26 // Buffered file adds buffering to an existing file
27 // FILEBUFFER_SIZE defines the size of internal buffer, while
28 // FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
29 #define FILEBUFFER_SIZE (8192-8)
30 #define FILEBUFFER_TOLERANCE 4096
32 // ** Constructor/Destructor
34 // Hidden constructor
35 // Not supposed to be used
36 BufferedFile::BufferedFile() : DelegatedFile(0)
37 {
38 pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
39 BufferMode = NoBuffer;
40 FilePos = 0;
41 Pos = 0;
42 DataSize = 0;
43 }
45 // Takes another file as source
46 BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
47 {
48 pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
49 BufferMode = NoBuffer;
50 FilePos = pfile->LTell();
51 Pos = 0;
52 DataSize = 0;
53 }
56 // Destructor
57 BufferedFile::~BufferedFile()
58 {
59 // Flush in case there's data
60 if (pFile)
61 FlushBuffer();
62 // Get rid of buffer
63 if (pBuffer)
64 OVR_FREE(pBuffer);
65 }
67 /*
68 bool BufferedFile::VCopy(const Object &source)
69 {
70 if (!DelegatedFile::VCopy(source))
71 return 0;
73 // Data members
74 BufferedFile *psource = (BufferedFile*)&source;
76 // Buffer & the mode it's in
77 pBuffer = psource->pBuffer;
78 BufferMode = psource->BufferMode;
79 Pos = psource->Pos;
80 DataSize = psource->DataSize;
81 return 1;
82 }
83 */
85 // Initializes buffering to a certain mode
86 bool BufferedFile::SetBufferMode(BufferModeType mode)
87 {
88 if (!pBuffer)
89 return false;
90 if (mode == BufferMode)
91 return true;
93 FlushBuffer();
95 // Can't set write mode if we can't write
96 if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
97 return 0;
99 // And SetMode
100 BufferMode = mode;
101 Pos = 0;
102 DataSize = 0;
103 return 1;
104 }
106 // Flushes buffer
107 void BufferedFile::FlushBuffer()
108 {
109 switch(BufferMode)
110 {
111 case WriteBuffer:
112 // Write data in buffer
113 FilePos += pFile->Write(pBuffer,Pos);
114 Pos = 0;
115 break;
117 case ReadBuffer:
118 // Seek back & reset buffer data
119 if ((DataSize-Pos)>0)
120 FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
121 DataSize = 0;
122 Pos = 0;
123 break;
124 default:
125 // not handled!
126 break;
127 }
128 }
130 // Reloads data for ReadBuffer
131 void BufferedFile::LoadBuffer()
132 {
133 if (BufferMode == ReadBuffer)
134 {
135 // We should only reload once all of pre-loaded buffer is consumed.
136 OVR_ASSERT(Pos == DataSize);
138 // WARNING: Right now LoadBuffer() assumes the buffer's empty
139 int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
140 DataSize = sz<0 ? 0 : (unsigned)sz;
141 Pos = 0;
142 FilePos += DataSize;
143 }
144 }
147 // ** Overridden functions
149 // We override all the functions that can possibly
150 // require buffer mode switch, flush, or extra calculations
152 // Tell() requires buffer adjustment
153 int BufferedFile::Tell()
154 {
155 if (BufferMode == ReadBuffer)
156 return int (FilePos - DataSize + Pos);
158 int pos = pFile->Tell();
159 // Adjust position based on buffer mode & data
160 if (pos!=-1)
161 {
162 OVR_ASSERT(BufferMode != ReadBuffer);
163 if (BufferMode == WriteBuffer)
164 pos += Pos;
165 }
166 return pos;
167 }
169 SInt64 BufferedFile::LTell()
170 {
171 if (BufferMode == ReadBuffer)
172 return FilePos - DataSize + Pos;
174 SInt64 pos = pFile->LTell();
175 if (pos!=-1)
176 {
177 OVR_ASSERT(BufferMode != ReadBuffer);
178 if (BufferMode == WriteBuffer)
179 pos += Pos;
180 }
181 return pos;
182 }
184 int BufferedFile::GetLength()
185 {
186 int len = pFile->GetLength();
187 // If writing through buffer, file length may actually be bigger
188 if ((len!=-1) && (BufferMode==WriteBuffer))
189 {
190 int currPos = pFile->Tell() + Pos;
191 if (currPos>len)
192 len = currPos;
193 }
194 return len;
195 }
196 SInt64 BufferedFile::LGetLength()
197 {
198 SInt64 len = pFile->LGetLength();
199 // If writing through buffer, file length may actually be bigger
200 if ((len!=-1) && (BufferMode==WriteBuffer))
201 {
202 SInt64 currPos = pFile->LTell() + Pos;
203 if (currPos>len)
204 len = currPos;
205 }
206 return len;
207 }
209 /*
210 bool BufferedFile::Stat(FileStats *pfs)
211 {
212 // Have to fix up length is stat
213 if (pFile->Stat(pfs))
214 {
215 if (BufferMode==WriteBuffer)
216 {
217 SInt64 currPos = pFile->LTell() + Pos;
218 if (currPos > pfs->Size)
219 {
220 pfs->Size = currPos;
221 // ??
222 pfs->Blocks = (pfs->Size+511) >> 9;
223 }
224 }
225 return 1;
226 }
227 return 0;
228 }
229 */
231 int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
232 {
233 if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
234 {
235 // If not data space in buffer, flush
236 if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
237 {
238 FlushBuffer();
239 // If bigger then tolerance, just write directly
240 if (numBytes>FILEBUFFER_TOLERANCE)
241 {
242 int sz = pFile->Write(psourceBuffer,numBytes);
243 if (sz > 0)
244 FilePos += sz;
245 return sz;
246 }
247 }
249 // Enough space in buffer.. so copy to it
250 memcpy(pBuffer+Pos, psourceBuffer, numBytes);
251 Pos += numBytes;
252 return numBytes;
253 }
254 int sz = pFile->Write(psourceBuffer,numBytes);
255 if (sz > 0)
256 FilePos += sz;
257 return sz;
258 }
260 int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
261 {
262 if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
263 {
264 // Data in buffer... copy it
265 if ((int)(DataSize-Pos) >= numBytes)
266 {
267 memcpy(pdestBuffer, pBuffer+Pos, numBytes);
268 Pos += numBytes;
269 return numBytes;
270 }
272 // Not enough data in buffer, copy buffer
273 int readBytes = DataSize-Pos;
274 memcpy(pdestBuffer, pBuffer+Pos, readBytes);
275 numBytes -= readBytes;
276 pdestBuffer += readBytes;
277 Pos = DataSize;
279 // Don't reload buffer if more then tolerance
280 // (No major advantage, and we don't want to write a loop)
281 if (numBytes>FILEBUFFER_TOLERANCE)
282 {
283 numBytes = pFile->Read(pdestBuffer,numBytes);
284 if (numBytes > 0)
285 {
286 FilePos += numBytes;
287 Pos = DataSize = 0;
288 }
289 return readBytes + ((numBytes==-1) ? 0 : numBytes);
290 }
292 // Reload the buffer
293 // WARNING: Right now LoadBuffer() assumes the buffer's empty
294 LoadBuffer();
295 if ((int)(DataSize-Pos) < numBytes)
296 numBytes = (int)DataSize-Pos;
298 memcpy(pdestBuffer, pBuffer+Pos, numBytes);
299 Pos += numBytes;
300 return numBytes + readBytes;
302 /*
303 // Alternative Read implementation. The one above is probably better
304 // due to FILEBUFFER_TOLERANCE.
305 int total = 0;
307 do {
308 int bufferBytes = (int)(DataSize-Pos);
309 int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
311 memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
312 numBytes -= copyBytes;
313 pdestBuffer += copyBytes;
314 Pos += copyBytes;
315 total += copyBytes;
317 if (numBytes == 0)
318 break;
319 LoadBuffer();
321 } while (DataSize > 0);
323 return total;
324 */
325 }
326 int sz = pFile->Read(pdestBuffer,numBytes);
327 if (sz > 0)
328 FilePos += sz;
329 return sz;
330 }
333 int BufferedFile::SkipBytes(int numBytes)
334 {
335 int skippedBytes = 0;
337 // Special case for skipping a little data in read buffer
338 if (BufferMode==ReadBuffer)
339 {
340 skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
341 Pos += skippedBytes;
342 numBytes -= skippedBytes;
343 }
345 if (numBytes)
346 {
347 numBytes = pFile->SkipBytes(numBytes);
348 // Make sure we return the actual number skipped, or error
349 if (numBytes!=-1)
350 {
351 skippedBytes += numBytes;
352 FilePos += numBytes;
353 Pos = DataSize = 0;
354 }
355 else if (skippedBytes <= 0)
356 skippedBytes = -1;
357 }
358 return skippedBytes;
359 }
361 int BufferedFile::BytesAvailable()
362 {
363 int available = pFile->BytesAvailable();
364 // Adjust available size based on buffers
365 switch(BufferMode)
366 {
367 case ReadBuffer:
368 available += DataSize-Pos;
369 break;
370 case WriteBuffer:
371 available -= Pos;
372 if (available<0)
373 available= 0;
374 break;
375 default:
376 break;
377 }
378 return available;
379 }
381 bool BufferedFile::Flush()
382 {
383 FlushBuffer();
384 return pFile->Flush();
385 }
387 // Seeking could be optimized better..
388 int BufferedFile::Seek(int offset, int origin)
389 {
390 if (BufferMode == ReadBuffer)
391 {
392 if (origin == Seek_Cur)
393 {
394 // Seek can fall either before or after Pos in the buffer,
395 // but it must be within bounds.
396 if (((unsigned(offset) + Pos)) <= DataSize)
397 {
398 Pos += offset;
399 return int (FilePos - DataSize + Pos);
400 }
402 // Lightweight buffer "Flush". We do this to avoid an extra seek
403 // back operation which would take place if we called FlushBuffer directly.
404 origin = Seek_Set;
405 OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
406 offset = (int)(FilePos - DataSize + Pos) + offset;
407 Pos = DataSize = 0;
408 }
409 else if (origin == Seek_Set)
410 {
411 if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
412 {
413 OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
414 Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
415 return offset;
416 }
417 Pos = DataSize = 0;
418 }
419 else
420 {
421 FlushBuffer();
422 }
423 }
424 else
425 {
426 FlushBuffer();
427 }
429 /*
430 // Old Seek Logic
431 if (origin == Seek_Cur && offset + Pos < DataSize)
432 {
433 //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
434 Pos += offset;
435 OVR_ASSERT(int (Pos) >= 0);
436 return int (FilePos - DataSize + Pos);
437 }
438 else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
439 {
440 Pos = unsigned(offset - FilePos + DataSize);
441 OVR_ASSERT(int (Pos) >= 0);
442 return int (FilePos - DataSize + Pos);
443 }
445 FlushBuffer();
446 */
449 FilePos = pFile->Seek(offset,origin);
450 return int (FilePos);
451 }
453 SInt64 BufferedFile::LSeek(SInt64 offset, int origin)
454 {
455 if (BufferMode == ReadBuffer)
456 {
457 if (origin == Seek_Cur)
458 {
459 // Seek can fall either before or after Pos in the buffer,
460 // but it must be within bounds.
461 if (((unsigned(offset) + Pos)) <= DataSize)
462 {
463 Pos += (unsigned)offset;
464 return SInt64(FilePos - DataSize + Pos);
465 }
467 // Lightweight buffer "Flush". We do this to avoid an extra seek
468 // back operation which would take place if we called FlushBuffer directly.
469 origin = Seek_Set;
470 offset = (SInt64)(FilePos - DataSize + Pos) + offset;
471 Pos = DataSize = 0;
472 }
473 else if (origin == Seek_Set)
474 {
475 if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
476 {
477 Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
478 return offset;
479 }
480 Pos = DataSize = 0;
481 }
482 else
483 {
484 FlushBuffer();
485 }
486 }
487 else
488 {
489 FlushBuffer();
490 }
492 /*
493 OVR_ASSERT(BufferMode != NoBuffer);
495 if (origin == Seek_Cur && offset + Pos < DataSize)
496 {
497 Pos += int (offset);
498 return FilePos - DataSize + Pos;
499 }
500 else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
501 {
502 Pos = unsigned(offset - FilePos + DataSize);
503 return FilePos - DataSize + Pos;
504 }
506 FlushBuffer();
507 */
509 FilePos = pFile->LSeek(offset,origin);
510 return FilePos;
511 }
513 int BufferedFile::CopyFromStream(File *pstream, int byteSize)
514 {
515 // We can't rely on overridden Write()
516 // because delegation doesn't override virtual pointers
517 // So, just re-implement
518 UByte buff[0x4000];
519 int count = 0;
520 int szRequest, szRead, szWritten;
522 while(byteSize)
523 {
524 szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
526 szRead = pstream->Read(buff,szRequest);
527 szWritten = 0;
528 if (szRead > 0)
529 szWritten = Write(buff,szRead);
531 count +=szWritten;
532 byteSize-=szWritten;
533 if (szWritten < szRequest)
534 break;
535 }
536 return count;
537 }
539 // Closing files
540 bool BufferedFile::Close()
541 {
542 switch(BufferMode)
543 {
544 case WriteBuffer:
545 FlushBuffer();
546 break;
547 case ReadBuffer:
548 // No need to seek back on close
549 BufferMode = NoBuffer;
550 break;
551 default:
552 break;
553 }
554 return pFile->Close();
555 }
558 // ***** Global path helpers
560 // Find trailing short filename in a path.
561 const char* OVR_CDECL GetShortFilename(const char* purl)
562 {
563 UPInt len = OVR_strlen(purl);
564 for (UPInt i=len; i>0; i--)
565 if (purl[i]=='\\' || purl[i]=='/')
566 return purl+i+1;
567 return purl;
568 }
570 } // OVR