OVR_File.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /**************************************************************************
  2. Filename : OVR_File.cpp
  3. Content : File wrapper class implementation (Win32)
  4. Created : April 5, 1999
  5. Authors : Michael Antonov
  6. Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
  7. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
  8. you may not use the Oculus VR Rift SDK except in compliance with the License,
  9. which is provided at the time of installation or download, or which
  10. otherwise accompanies this software in either electronic or hard copy form.
  11. You may obtain a copy of the License at
  12. http://www.oculusvr.com/licenses/LICENSE-3.2
  13. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  14. distributed under the License is distributed on an "AS IS" BASIS,
  15. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. See the License for the specific language governing permissions and
  17. limitations under the License.
  18. **************************************************************************/
  19. #define GFILE_CXX
  20. // Standard C library (Captain Obvious guarantees!)
  21. #include <stdio.h>
  22. #include "OVR_File.h"
  23. namespace OVR {
  24. // Buffered file adds buffering to an existing file
  25. // FILEBUFFER_SIZE defines the size of internal buffer, while
  26. // FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
  27. #define FILEBUFFER_SIZE (8192-8)
  28. #define FILEBUFFER_TOLERANCE 4096
  29. // ** Constructor/Destructor
  30. // Hidden constructor
  31. // Not supposed to be used
  32. BufferedFile::BufferedFile() : DelegatedFile(0)
  33. {
  34. pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE);
  35. BufferMode = NoBuffer;
  36. FilePos = 0;
  37. Pos = 0;
  38. DataSize = 0;
  39. }
  40. // Takes another file as source
  41. BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
  42. {
  43. pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE);
  44. BufferMode = NoBuffer;
  45. FilePos = pfile->LTell();
  46. Pos = 0;
  47. DataSize = 0;
  48. }
  49. // Destructor
  50. BufferedFile::~BufferedFile()
  51. {
  52. // Flush in case there's data
  53. if (pFile)
  54. FlushBuffer();
  55. // Get rid of buffer
  56. if (pBuffer)
  57. OVR_FREE(pBuffer);
  58. }
  59. /*
  60. bool BufferedFile::VCopy(const Object &source)
  61. {
  62. if (!DelegatedFile::VCopy(source))
  63. return 0;
  64. // Data members
  65. BufferedFile *psource = (BufferedFile*)&source;
  66. // Buffer & the mode it's in
  67. pBuffer = psource->pBuffer;
  68. BufferMode = psource->BufferMode;
  69. Pos = psource->Pos;
  70. DataSize = psource->DataSize;
  71. return 1;
  72. }
  73. */
  74. // Initializes buffering to a certain mode
  75. bool BufferedFile::SetBufferMode(BufferModeType mode)
  76. {
  77. if (!pBuffer)
  78. return false;
  79. if (mode == BufferMode)
  80. return true;
  81. FlushBuffer();
  82. // Can't set write mode if we can't write
  83. if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
  84. return 0;
  85. // And SetMode
  86. BufferMode = mode;
  87. Pos = 0;
  88. DataSize = 0;
  89. return 1;
  90. }
  91. // Flushes buffer
  92. void BufferedFile::FlushBuffer()
  93. {
  94. switch(BufferMode)
  95. {
  96. case WriteBuffer:
  97. // Write data in buffer
  98. FilePos += pFile->Write(pBuffer,Pos);
  99. Pos = 0;
  100. break;
  101. case ReadBuffer:
  102. // Seek back & reset buffer data
  103. if ((DataSize-Pos)>0)
  104. FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
  105. DataSize = 0;
  106. Pos = 0;
  107. break;
  108. default:
  109. // not handled!
  110. break;
  111. }
  112. }
  113. // Reloads data for ReadBuffer
  114. void BufferedFile::LoadBuffer()
  115. {
  116. if (BufferMode == ReadBuffer)
  117. {
  118. // We should only reload once all of pre-loaded buffer is consumed.
  119. OVR_ASSERT(Pos == DataSize);
  120. // WARNING: Right now LoadBuffer() assumes the buffer's empty
  121. int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
  122. DataSize = sz<0 ? 0 : (unsigned)sz;
  123. Pos = 0;
  124. FilePos += DataSize;
  125. }
  126. }
  127. // ** Overridden functions
  128. // We override all the functions that can possibly
  129. // require buffer mode switch, flush, or extra calculations
  130. // Tell() requires buffer adjustment
  131. int BufferedFile::Tell()
  132. {
  133. if (BufferMode == ReadBuffer)
  134. return int (FilePos - DataSize + Pos);
  135. int pos = pFile->Tell();
  136. // Adjust position based on buffer mode & data
  137. if (pos!=-1)
  138. {
  139. OVR_ASSERT(BufferMode != ReadBuffer);
  140. if (BufferMode == WriteBuffer)
  141. pos += Pos;
  142. }
  143. return pos;
  144. }
  145. int64_t BufferedFile::LTell()
  146. {
  147. if (BufferMode == ReadBuffer)
  148. return FilePos - DataSize + Pos;
  149. int64_t pos = pFile->LTell();
  150. if (pos!=-1)
  151. {
  152. OVR_ASSERT(BufferMode != ReadBuffer);
  153. if (BufferMode == WriteBuffer)
  154. pos += Pos;
  155. }
  156. return pos;
  157. }
  158. int BufferedFile::GetLength()
  159. {
  160. int len = pFile->GetLength();
  161. // If writing through buffer, file length may actually be bigger
  162. if ((len!=-1) && (BufferMode==WriteBuffer))
  163. {
  164. int currPos = pFile->Tell() + Pos;
  165. if (currPos>len)
  166. len = currPos;
  167. }
  168. return len;
  169. }
  170. int64_t BufferedFile::LGetLength()
  171. {
  172. int64_t len = pFile->LGetLength();
  173. // If writing through buffer, file length may actually be bigger
  174. if ((len!=-1) && (BufferMode==WriteBuffer))
  175. {
  176. int64_t currPos = pFile->LTell() + Pos;
  177. if (currPos>len)
  178. len = currPos;
  179. }
  180. return len;
  181. }
  182. /*
  183. bool BufferedFile::Stat(FileStats *pfs)
  184. {
  185. // Have to fix up length is stat
  186. if (pFile->Stat(pfs))
  187. {
  188. if (BufferMode==WriteBuffer)
  189. {
  190. int64_t currPos = pFile->LTell() + Pos;
  191. if (currPos > pfs->Size)
  192. {
  193. pfs->Size = currPos;
  194. // ??
  195. pfs->Blocks = (pfs->Size+511) >> 9;
  196. }
  197. }
  198. return 1;
  199. }
  200. return 0;
  201. }
  202. */
  203. int BufferedFile::Write(const uint8_t *psourceBuffer, int numBytes)
  204. {
  205. if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
  206. {
  207. // If not data space in buffer, flush
  208. if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
  209. {
  210. FlushBuffer();
  211. // If bigger then tolerance, just write directly
  212. if (numBytes>FILEBUFFER_TOLERANCE)
  213. {
  214. int sz = pFile->Write(psourceBuffer,numBytes);
  215. if (sz > 0)
  216. FilePos += sz;
  217. return sz;
  218. }
  219. }
  220. // Enough space in buffer.. so copy to it
  221. memcpy(pBuffer+Pos, psourceBuffer, numBytes);
  222. Pos += numBytes;
  223. return numBytes;
  224. }
  225. int sz = pFile->Write(psourceBuffer,numBytes);
  226. if (sz > 0)
  227. FilePos += sz;
  228. return sz;
  229. }
  230. int BufferedFile::Read(uint8_t *pdestBuffer, int numBytes)
  231. {
  232. if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
  233. {
  234. // Data in buffer... copy it
  235. if ((int)(DataSize-Pos) >= numBytes)
  236. {
  237. memcpy(pdestBuffer, pBuffer+Pos, numBytes);
  238. Pos += numBytes;
  239. return numBytes;
  240. }
  241. // Not enough data in buffer, copy buffer
  242. int readBytes = DataSize-Pos;
  243. memcpy(pdestBuffer, pBuffer+Pos, readBytes);
  244. numBytes -= readBytes;
  245. pdestBuffer += readBytes;
  246. Pos = DataSize;
  247. // Don't reload buffer if more then tolerance
  248. // (No major advantage, and we don't want to write a loop)
  249. if (numBytes>FILEBUFFER_TOLERANCE)
  250. {
  251. numBytes = pFile->Read(pdestBuffer,numBytes);
  252. if (numBytes > 0)
  253. {
  254. FilePos += numBytes;
  255. Pos = DataSize = 0;
  256. }
  257. return readBytes + ((numBytes==-1) ? 0 : numBytes);
  258. }
  259. // Reload the buffer
  260. // WARNING: Right now LoadBuffer() assumes the buffer's empty
  261. LoadBuffer();
  262. if ((int)(DataSize-Pos) < numBytes)
  263. numBytes = (int)DataSize-Pos;
  264. memcpy(pdestBuffer, pBuffer+Pos, numBytes);
  265. Pos += numBytes;
  266. return numBytes + readBytes;
  267. /*
  268. // Alternative Read implementation. The one above is probably better
  269. // due to FILEBUFFER_TOLERANCE.
  270. int total = 0;
  271. do {
  272. int bufferBytes = (int)(DataSize-Pos);
  273. int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
  274. memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
  275. numBytes -= copyBytes;
  276. pdestBuffer += copyBytes;
  277. Pos += copyBytes;
  278. total += copyBytes;
  279. if (numBytes == 0)
  280. break;
  281. LoadBuffer();
  282. } while (DataSize > 0);
  283. return total;
  284. */
  285. }
  286. int sz = pFile->Read(pdestBuffer,numBytes);
  287. if (sz > 0)
  288. FilePos += sz;
  289. return sz;
  290. }
  291. int BufferedFile::SkipBytes(int numBytes)
  292. {
  293. int skippedBytes = 0;
  294. // Special case for skipping a little data in read buffer
  295. if (BufferMode==ReadBuffer)
  296. {
  297. skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
  298. Pos += skippedBytes;
  299. numBytes -= skippedBytes;
  300. }
  301. if (numBytes)
  302. {
  303. numBytes = pFile->SkipBytes(numBytes);
  304. // Make sure we return the actual number skipped, or error
  305. if (numBytes!=-1)
  306. {
  307. skippedBytes += numBytes;
  308. FilePos += numBytes;
  309. Pos = DataSize = 0;
  310. }
  311. else if (skippedBytes <= 0)
  312. skippedBytes = -1;
  313. }
  314. return skippedBytes;
  315. }
  316. int BufferedFile::BytesAvailable()
  317. {
  318. int available = pFile->BytesAvailable();
  319. // Adjust available size based on buffers
  320. switch(BufferMode)
  321. {
  322. case ReadBuffer:
  323. available += DataSize-Pos;
  324. break;
  325. case WriteBuffer:
  326. available -= Pos;
  327. if (available<0)
  328. available= 0;
  329. break;
  330. default:
  331. break;
  332. }
  333. return available;
  334. }
  335. bool BufferedFile::Flush()
  336. {
  337. FlushBuffer();
  338. return pFile->Flush();
  339. }
  340. // Seeking could be optimized better..
  341. int BufferedFile::Seek(int offset, int origin)
  342. {
  343. if (BufferMode == ReadBuffer)
  344. {
  345. if (origin == Seek_Cur)
  346. {
  347. // Seek can fall either before or after Pos in the buffer,
  348. // but it must be within bounds.
  349. if (((unsigned(offset) + Pos)) <= DataSize)
  350. {
  351. Pos += offset;
  352. return int (FilePos - DataSize + Pos);
  353. }
  354. // Lightweight buffer "Flush". We do this to avoid an extra seek
  355. // back operation which would take place if we called FlushBuffer directly.
  356. origin = Seek_Set;
  357. OVR_ASSERT(((FilePos - DataSize + Pos) + (uint64_t)offset) < ~(uint64_t)0);
  358. offset = (int)(FilePos - DataSize + Pos) + offset;
  359. Pos = DataSize = 0;
  360. }
  361. else if (origin == Seek_Set)
  362. {
  363. if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
  364. {
  365. OVR_ASSERT((FilePos-DataSize) < ~(uint64_t)0);
  366. Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
  367. return offset;
  368. }
  369. Pos = DataSize = 0;
  370. }
  371. else
  372. {
  373. FlushBuffer();
  374. }
  375. }
  376. else
  377. {
  378. FlushBuffer();
  379. }
  380. /*
  381. // Old Seek Logic
  382. if (origin == Seek_Cur && offset + Pos < DataSize)
  383. {
  384. //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
  385. Pos += offset;
  386. OVR_ASSERT(int (Pos) >= 0);
  387. return int (FilePos - DataSize + Pos);
  388. }
  389. else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
  390. {
  391. Pos = unsigned(offset - FilePos + DataSize);
  392. OVR_ASSERT(int (Pos) >= 0);
  393. return int (FilePos - DataSize + Pos);
  394. }
  395. FlushBuffer();
  396. */
  397. FilePos = pFile->Seek(offset,origin);
  398. return int (FilePos);
  399. }
  400. int64_t BufferedFile::LSeek(int64_t offset, int origin)
  401. {
  402. if (BufferMode == ReadBuffer)
  403. {
  404. if (origin == Seek_Cur)
  405. {
  406. // Seek can fall either before or after Pos in the buffer,
  407. // but it must be within bounds.
  408. if (((unsigned(offset) + Pos)) <= DataSize)
  409. {
  410. Pos += (unsigned)offset;
  411. return int64_t(FilePos - DataSize + Pos);
  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. offset = (int64_t)(FilePos - DataSize + Pos) + offset;
  417. Pos = DataSize = 0;
  418. }
  419. else if (origin == Seek_Set)
  420. {
  421. if (((uint64_t)offset - (FilePos-DataSize)) <= DataSize)
  422. {
  423. Pos = (unsigned)((uint64_t)offset - (FilePos-DataSize));
  424. return offset;
  425. }
  426. Pos = DataSize = 0;
  427. }
  428. else
  429. {
  430. FlushBuffer();
  431. }
  432. }
  433. else
  434. {
  435. FlushBuffer();
  436. }
  437. /*
  438. OVR_ASSERT(BufferMode != NoBuffer);
  439. if (origin == Seek_Cur && offset + Pos < DataSize)
  440. {
  441. Pos += int (offset);
  442. return FilePos - DataSize + Pos;
  443. }
  444. else if (origin == Seek_Set && offset >= int64_t(FilePos - DataSize) && offset < int64_t(FilePos))
  445. {
  446. Pos = unsigned(offset - FilePos + DataSize);
  447. return FilePos - DataSize + Pos;
  448. }
  449. FlushBuffer();
  450. */
  451. FilePos = pFile->LSeek(offset,origin);
  452. return FilePos;
  453. }
  454. int BufferedFile::CopyFromStream(File *pstream, int byteSize)
  455. {
  456. // We can't rely on overridden Write()
  457. // because delegation doesn't override virtual pointers
  458. // So, just re-implement
  459. uint8_t* buff = new uint8_t[0x4000];
  460. int count = 0;
  461. int szRequest, szRead, szWritten;
  462. while(byteSize)
  463. {
  464. szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
  465. szRead = pstream->Read(buff,szRequest);
  466. szWritten = 0;
  467. if (szRead > 0)
  468. szWritten = Write(buff,szRead);
  469. count +=szWritten;
  470. byteSize-=szWritten;
  471. if (szWritten < szRequest)
  472. break;
  473. }
  474. delete[] buff;
  475. return count;
  476. }
  477. // Closing files
  478. bool BufferedFile::Close()
  479. {
  480. switch(BufferMode)
  481. {
  482. case WriteBuffer:
  483. FlushBuffer();
  484. break;
  485. case ReadBuffer:
  486. // No need to seek back on close
  487. BufferMode = NoBuffer;
  488. break;
  489. default:
  490. break;
  491. }
  492. return pFile->Close();
  493. }
  494. // ***** Global path helpers
  495. // Find trailing short filename in a path.
  496. const char* OVR_CDECL GetShortFilename(const char* purl)
  497. {
  498. size_t len = OVR_strlen(purl);
  499. for (size_t i=len; i>0; i--)
  500. if (purl[i]=='\\' || purl[i]=='/')
  501. return purl+i+1;
  502. return purl;
  503. }
  504. } // OVR