Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OVR_File.cpp
Go to the documentation of this file.
1 /**************************************************************************
2 
3 Filename : OVR_File.cpp
4 Content : File wrapper class implementation (Win32)
5 
6 Created : April 5, 1999
7 Authors : Michael Antonov
8 
9 Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
10 
11 Licensed under the Oculus VR Rift SDK License Version 3.1 (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.
15 
16 You may obtain a copy of the License at
17 
18 http://www.oculusvr.com/licenses/LICENSE-3.1
19 
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.
25 
26 **************************************************************************/
27 
28 #define GFILE_CXX
29 
30 // Standard C library (Captain Obvious guarantees!)
31 #include <stdio.h>
32 
33 #include "OVR_File.h"
34 
35 namespace OVR {
36 
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
42 
43 // ** Constructor/Destructor
44 
45 // Hidden constructor
46 // Not supposed to be used
48 {
51  FilePos = 0;
52  Pos = 0;
53  DataSize = 0;
54 }
55 
56 // Takes another file as source
58 {
61  FilePos = pfile->LTell();
62  Pos = 0;
63  DataSize = 0;
64 }
65 
66 
67 // Destructor
69 {
70  // Flush in case there's data
71  if (pFile)
72  FlushBuffer();
73  // Get rid of buffer
74  if (pBuffer)
76 }
77 
78 /*
79 bool BufferedFile::VCopy(const Object &source)
80 {
81  if (!DelegatedFile::VCopy(source))
82  return 0;
83 
84  // Data members
85  BufferedFile *psource = (BufferedFile*)&source;
86 
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 */
95 
96 // Initializes buffering to a certain mode
98 {
99  if (!pBuffer)
100  return false;
101  if (mode == BufferMode)
102  return true;
103 
104  FlushBuffer();
105 
106  // Can't set write mode if we can't write
107  if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
108  return 0;
109 
110  // And SetMode
111  BufferMode = mode;
112  Pos = 0;
113  DataSize = 0;
114  return 1;
115 }
116 
117 // Flushes buffer
119 {
120  switch(BufferMode)
121  {
122  case WriteBuffer:
123  // Write data in buffer
124  FilePos += pFile->Write(pBuffer,Pos);
125  Pos = 0;
126  break;
127 
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 }
140 
141 // Reloads data for ReadBuffer
143 {
144  if (BufferMode == ReadBuffer)
145  {
146  // We should only reload once all of pre-loaded buffer is consumed.
147  OVR_ASSERT(Pos == DataSize);
148 
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 }
156 
157 
158 // ** Overridden functions
159 
160 // We override all the functions that can possibly
161 // require buffer mode switch, flush, or extra calculations
162 
163 // Tell() requires buffer adjustment
165 {
166  if (BufferMode == ReadBuffer)
167  return int (FilePos - DataSize + Pos);
168 
169  int pos = pFile->Tell();
170  // Adjust position based on buffer mode & data
171  if (pos!=-1)
172  {
174  if (BufferMode == WriteBuffer)
175  pos += Pos;
176  }
177  return pos;
178 }
179 
181 {
182  if (BufferMode == ReadBuffer)
183  return FilePos - DataSize + Pos;
184 
185  SInt64 pos = pFile->LTell();
186  if (pos!=-1)
187  {
189  if (BufferMode == WriteBuffer)
190  pos += Pos;
191  }
192  return pos;
193 }
194 
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 }
208 {
209  SInt64 len = pFile->LGetLength();
210  // If writing through buffer, file length may actually be bigger
211  if ((len!=-1) && (BufferMode==WriteBuffer))
212  {
213  SInt64 currPos = pFile->LTell() + Pos;
214  if (currPos>len)
215  len = currPos;
216  }
217  return len;
218 }
219 
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  SInt64 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 */
241 
242 int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
243 {
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  }
259 
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 }
270 
271 int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
272 {
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  }
282 
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;
289 
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  }
302 
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;
308 
309  memcpy(pdestBuffer, pBuffer+Pos, numBytes);
310  Pos += numBytes;
311  return numBytes + readBytes;
312 
313  /*
314  // Alternative Read implementation. The one above is probably better
315  // due to FILEBUFFER_TOLERANCE.
316  int total = 0;
317 
318  do {
319  int bufferBytes = (int)(DataSize-Pos);
320  int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
321 
322  memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
323  numBytes -= copyBytes;
324  pdestBuffer += copyBytes;
325  Pos += copyBytes;
326  total += copyBytes;
327 
328  if (numBytes == 0)
329  break;
330  LoadBuffer();
331 
332  } while (DataSize > 0);
333 
334  return total;
335  */
336  }
337  int sz = pFile->Read(pdestBuffer,numBytes);
338  if (sz > 0)
339  FilePos += sz;
340  return sz;
341 }
342 
343 
344 int BufferedFile::SkipBytes(int numBytes)
345 {
346  int skippedBytes = 0;
347 
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  }
355 
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 }
371 
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 }
391 
393 {
394  FlushBuffer();
395  return pFile->Flush();
396 }
397 
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  }
412 
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)offset) < ~(UInt64)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  {
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  }
439 
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  }
455 
456  FlushBuffer();
457  */
458 
459 
460  FilePos = pFile->Seek(offset,origin);
461  return int (FilePos);
462 }
463 
464 SInt64 BufferedFile::LSeek(SInt64 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 SInt64(FilePos - DataSize + Pos);
476  }
477 
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 = (SInt64)(FilePos - DataSize + Pos) + offset;
482  Pos = DataSize = 0;
483  }
484  else if (origin == Seek_Set)
485  {
486  if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
487  {
488  Pos = (unsigned)((UInt64)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  }
502 
503 /*
504  OVR_ASSERT(BufferMode != NoBuffer);
505 
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 >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
512  {
513  Pos = unsigned(offset - FilePos + DataSize);
514  return FilePos - DataSize + Pos;
515  }
516 
517  FlushBuffer();
518  */
519 
520  FilePos = pFile->LSeek(offset,origin);
521  return FilePos;
522 }
523 
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  UByte buff[0x4000];
530  int count = 0;
531  int szRequest, szRead, szWritten;
532 
533  while(byteSize)
534  {
535  szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
536 
537  szRead = pstream->Read(buff,szRequest);
538  szWritten = 0;
539  if (szRead > 0)
540  szWritten = Write(buff,szRead);
541 
542  count +=szWritten;
543  byteSize-=szWritten;
544  if (szWritten < szRequest)
545  break;
546  }
547  return count;
548 }
549 
550 // Closing files
552 {
553  switch(BufferMode)
554  {
555  case WriteBuffer:
556  FlushBuffer();
557  break;
558  case ReadBuffer:
559  // No need to seek back on close
561  break;
562  default:
563  break;
564  }
565  return pFile->Close();
566 }
567 
568 
569 // ***** Global path helpers
570 
571 // Find trailing short filename in a path.
572 const char* OVR_CDECL GetShortFilename(const char* purl)
573 {
574  UPInt len = OVR_strlen(purl);
575  for (UPInt i=len; i>0; i--)
576  if (purl[i]=='\\' || purl[i]=='/')
577  return purl+i+1;
578  return purl;
579 }
580 
581 } // OVR
582 
#define OVR_CDECL
virtual int BytesAvailable()
Definition: OVR_File.cpp:372
virtual bool Close()
Definition: OVR_File.cpp:551
BufferModeType BufferMode
Definition: OVR_File.h:346
bool SetBufferMode(BufferModeType mode)
Definition: OVR_File.cpp:97
virtual int CopyFromStream(File *pstream, int byteSize)
Definition: OVR_File.cpp:524
__BEGIN_NAMESPACE_STD void * memcpy(void *__restrict __dest, const void *__restrict __src, size_t __n) __THROW __nonnull((1
uint64_t UInt64
Definition: OVR_Types.h:255
unsigned DataSize
Definition: OVR_File.h:350
virtual int Write(const UByte *pbufer, int numBytes)
Definition: OVR_File.cpp:242
UByte * pBuffer
Definition: OVR_File.h:345
size_t UPInt
Definition: OVR_Types.h:218
uint8_t UByte
Definition: OVR_Types.h:249
virtual SInt64 LTell()=0
virtual bool Flush()
Definition: OVR_File.cpp:392
#define FILEBUFFER_SIZE
Definition: OVR_File.cpp:40
#define OVR_ASSERT(p)
#define FILEBUFFER_TOLERANCE
Definition: OVR_File.cpp:41
int64_t SInt64
Definition: OVR_Types.h:254
const char *OVR_CDECL GetShortFilename(const char *purl)
Definition: OVR_File.cpp:572
Ptr< File > pFile
Definition: OVR_File.h:279
virtual int SkipBytes(int numBytes)
Definition: OVR_File.cpp:344
unsigned Pos
Definition: OVR_File.h:348
#define OVR_ALLOC(s)
virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set)
Definition: OVR_File.cpp:464
virtual int Read(UByte *pbufer, int numBytes)=0
virtual SInt64 LTell()
Definition: OVR_File.cpp:180
virtual int Tell()
Definition: OVR_File.cpp:164
#define OVR_FREE(p)
UPInt OVR_CDECL OVR_strlen(const char *str)
Definition: OVR_Std.h:143
virtual int GetLength()
Definition: OVR_File.cpp:195
virtual int Seek(int offset, int origin=Seek_Set)
Definition: OVR_File.cpp:399
virtual int Read(UByte *pbufer, int numBytes)
Definition: OVR_File.cpp:271
virtual SInt64 LGetLength()
Definition: OVR_File.cpp:207