BFIOFILE.CPP 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /CounterStrike/BFIOFILE.CPP 1 3/03/97 10:24a Joe_bostic $ */
  15. /***********************************************************************************************
  16. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Westwood Library *
  20. * *
  21. * File Name : RAMFILE.CPP *
  22. * *
  23. * Programmer : David R. Dettmer *
  24. * *
  25. * Start Date : November 10, 1995 *
  26. * *
  27. * Last Update : November 10, 1995 [DRD] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object. *
  32. * BufferIOFileClass::BufferIOFileClass -- default constructor for a file object. *
  33. * BufferIOFileClass::Cache -- Load part or all of a file data into RAM. *
  34. * BufferIOFileClass::Close -- Perform a closure of the file. *
  35. * BufferIOFileClass::Commit -- Writes the cache to the file if it has changed. *
  36. * BufferIOFileClass::Free -- Frees the allocated buffer. *
  37. * BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk. *
  38. * BufferIOFileClass::Is_Open -- Determines if the file is open. *
  39. * BufferIOFileClass::Open -- Assigns name and opens file in one operation. *
  40. * BufferIOFileClass::Open -- Opens the file object with the rights specified. *
  41. * BufferIOFileClass::Read -- Reads data from the file cache. *
  42. * BufferIOFileClass::Seek -- Moves the current file pointer in the file. *
  43. * BufferIOFileClass::Set_Name -- Checks for name changed for a cached file. *
  44. * BufferIOFileClass::Size -- Determines size of file (in bytes). *
  45. * BufferIOFileClass::Write -- Writes data to the file cache. *
  46. * BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object. *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #include "bfiofile.h"
  49. #include <string.h>
  50. /***********************************************************************************************
  51. * BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object. *
  52. * *
  53. * This constructor is called when a file object is created with a supplied filename, but *
  54. * not opened at the same time. In this case, an assumption is made that the supplied *
  55. * filename is a constant string. A duplicate of the filename string is not created since *
  56. * it would be wasteful in that case. *
  57. * *
  58. * INPUT: filename -- The filename to assign to this file object. *
  59. * *
  60. * OUTPUT: none *
  61. * *
  62. * WARNINGS: none *
  63. * *
  64. * HISTORY: *
  65. * 11/10/1995 DRD : Created. *
  66. *=============================================================================================*/
  67. BufferIOFileClass::BufferIOFileClass(char const * filename) :
  68. IsAllocated(false),
  69. IsOpen(false),
  70. IsDiskOpen(false),
  71. IsCached(false),
  72. IsChanged(false),
  73. UseBuffer(false),
  74. BufferRights(0),
  75. Buffer(0),
  76. BufferSize(0),
  77. BufferPos(0),
  78. BufferFilePos(0),
  79. BufferChangeBeg(-1),
  80. BufferChangeEnd(-1),
  81. FileSize(0),
  82. FilePos(0),
  83. TrueFileStart(0)
  84. {
  85. BufferIOFileClass::Set_Name(filename);
  86. }
  87. /***********************************************************************************************
  88. * BufferIOFileClass::BufferIOFileClass -- default constructor for a file object. *
  89. * *
  90. * This is the default constructor for a file object. *
  91. * *
  92. * INPUT: none *
  93. * *
  94. * OUTPUT: none *
  95. * *
  96. * WARNINGS: none *
  97. * *
  98. * HISTORY: *
  99. * 11/10/1995 DRD : Created. *
  100. *=============================================================================================*/
  101. BufferIOFileClass::BufferIOFileClass(void) :
  102. IsAllocated(false),
  103. IsOpen(false),
  104. IsDiskOpen(false),
  105. IsCached(false),
  106. IsChanged(false),
  107. UseBuffer(false),
  108. BufferRights(0),
  109. Buffer(0),
  110. BufferSize(0),
  111. BufferPos(0),
  112. BufferFilePos(0),
  113. BufferChangeBeg(-1),
  114. BufferChangeEnd(-1),
  115. FileSize(0),
  116. FilePos(0),
  117. TrueFileStart(0)
  118. {
  119. }
  120. /***********************************************************************************************
  121. * BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object. *
  122. * *
  123. * This destructor will free all memory allocated thru using Cache routines. *
  124. * *
  125. * INPUT: none *
  126. * *
  127. * OUTPUT: none *
  128. * *
  129. * WARNINGS: none *
  130. * *
  131. * HISTORY: *
  132. * 11/10/1995 DRD : Created. *
  133. *=============================================================================================*/
  134. BufferIOFileClass::~BufferIOFileClass(void)
  135. {
  136. Free();
  137. }
  138. /***********************************************************************************************
  139. * BufferIOFileClass::Cache -- Load part or all of a file data into RAM. *
  140. * *
  141. * INPUT: none *
  142. * *
  143. * OUTPUT: bool; Was the file load successful? It could fail if there wasn't enough room *
  144. * to allocate the raw data block. *
  145. * *
  146. * WARNINGS: This routine goes to disk for a potentially very long time. *
  147. * *
  148. * HISTORY: *
  149. * 11/10/1995 DRD : Created. *
  150. *=============================================================================================*/
  151. bool BufferIOFileClass::Cache( long size, void * ptr )
  152. {
  153. if (Buffer) {
  154. //
  155. // if trying to cache again with size or ptr fail
  156. //
  157. if (size || ptr) {
  158. return( false );
  159. } else {
  160. return( true );
  161. }
  162. }
  163. if ( Is_Available() ) {
  164. FileSize = Size();
  165. } else {
  166. FileSize = 0;
  167. }
  168. if (size) {
  169. //
  170. // minimum buffer size for performance
  171. //
  172. if (size < MINIMUM_BUFFER_SIZE) {
  173. size = MINIMUM_BUFFER_SIZE;
  174. /*
  175. ** Specifying a size smaller than the minimum is an error
  176. ** IF a buffer pointer was also specified. In such a case the
  177. ** system cannot use the buffer.
  178. */
  179. if (ptr) {
  180. Error(EINVAL);
  181. }
  182. }
  183. BufferSize = size;
  184. } else {
  185. BufferSize = FileSize;
  186. }
  187. //
  188. // if size == 0 and a ptr to a buffer is specified then that is invalid.
  189. // if the BufferSize is 0 then this must be a new file and no size was
  190. // specified so exit.
  191. //
  192. if ( (size == 0 && ptr) || !BufferSize) {
  193. return( false );
  194. }
  195. if (ptr) {
  196. Buffer = ptr;
  197. } else {
  198. Buffer = new char [BufferSize];
  199. }
  200. if (Buffer) {
  201. IsAllocated = true;
  202. IsDiskOpen = false;
  203. BufferPos = 0;
  204. BufferFilePos = 0;
  205. BufferChangeBeg = -1;
  206. BufferChangeEnd = -1;
  207. FilePos = 0;
  208. TrueFileStart = 0;
  209. //
  210. // the file was checked for availability then set the FileSize
  211. //
  212. if (FileSize) {
  213. long readsize;
  214. int opened = false;
  215. long prevpos = 0;
  216. if (FileSize <= BufferSize) {
  217. readsize = FileSize;
  218. } else {
  219. readsize = BufferSize;
  220. }
  221. if ( Is_Open() ) {
  222. //
  223. // get previous file position
  224. //
  225. prevpos = Seek(0);
  226. //
  227. // get true file position
  228. //
  229. if ( RawFileClass::Is_Open() ) {
  230. TrueFileStart = RawFileClass::Seek(0);
  231. } else {
  232. TrueFileStart = prevpos;
  233. }
  234. if (FileSize <= BufferSize) {
  235. //
  236. // if previous position is non-zero seek to the beginning
  237. //
  238. if (prevpos) {
  239. Seek(0, SEEK_SET);
  240. }
  241. //
  242. // set the buffer position for future reads/writes
  243. //
  244. BufferPos = prevpos;
  245. } else {
  246. BufferFilePos = prevpos;
  247. }
  248. FilePos = prevpos;
  249. } else {
  250. if ( Open() ) {
  251. TrueFileStart = RawFileClass::Seek(0);
  252. opened = true;
  253. }
  254. }
  255. long actual = Read(Buffer, readsize);
  256. if (actual != readsize) {
  257. Error(EIO);
  258. }
  259. if (opened) {
  260. Close();
  261. } else {
  262. //
  263. // seek to the previous position in the file
  264. //
  265. Seek(prevpos, SEEK_SET);
  266. }
  267. IsCached = true;
  268. }
  269. UseBuffer = true;
  270. return(true);
  271. }
  272. Error(ENOMEM);
  273. return(false);
  274. }
  275. /***********************************************************************************************
  276. * BufferIOFileClass::Free -- Frees the allocated buffer. *
  277. * *
  278. * This routine will free the buffer. By using this in conjunction with the *
  279. * Cache() function, one can maintain tight control of memory usage. *
  280. * *
  281. * INPUT: none *
  282. * *
  283. * OUTPUT: none *
  284. * *
  285. * WARNINGS: none *
  286. * *
  287. * HISTORY: *
  288. * 11/10/1995 DRD : Created. *
  289. *=============================================================================================*/
  290. void BufferIOFileClass::Free(void)
  291. {
  292. if (Buffer) {
  293. if (IsAllocated) {
  294. delete [] Buffer;
  295. IsAllocated = false;
  296. }
  297. Buffer = 0;
  298. }
  299. BufferSize = 0;
  300. IsOpen = false;
  301. IsCached = false;
  302. IsChanged = false;
  303. UseBuffer = false;
  304. }
  305. /***********************************************************************************************
  306. * BufferIOFileClass::Commit -- Writes the cache to the file if it has changed. *
  307. * *
  308. * *
  309. * INPUT: none *
  310. * *
  311. * OUTPUT: false, did not need to write the buffer. *
  312. * true, wrote the buffer. *
  313. * *
  314. * WARNINGS: none *
  315. * *
  316. * HISTORY: *
  317. * 11/15/1995 DRD : Created. *
  318. *=============================================================================================*/
  319. bool BufferIOFileClass::Commit( void )
  320. {
  321. long size;
  322. if (UseBuffer) {
  323. if (IsChanged) {
  324. size = BufferChangeEnd - BufferChangeBeg;
  325. if (IsDiskOpen) {
  326. RawFileClass::Seek( TrueFileStart + BufferFilePos +
  327. BufferChangeBeg, SEEK_SET );
  328. RawFileClass::Write( Buffer, size );
  329. RawFileClass::Seek( TrueFileStart + FilePos, SEEK_SET );
  330. } else {
  331. RawFileClass::Open();
  332. RawFileClass::Seek( TrueFileStart + BufferFilePos +
  333. BufferChangeBeg, SEEK_SET );
  334. RawFileClass::Write( Buffer, size );
  335. RawFileClass::Close();
  336. }
  337. IsChanged = false;
  338. return( true );
  339. } else {
  340. return( false );
  341. }
  342. } else {
  343. return( false );
  344. }
  345. }
  346. /***********************************************************************************************
  347. * BufferIOFileClass::Set_Name -- Checks for name changed for a cached file. *
  348. * *
  349. * Checks for a previous filename and that it is cached. If so, then check the *
  350. * new filename against the old. If they are the same then return that filename. *
  351. * Otherwise, the file object's name is set with just the raw filename as passed *
  352. * to this routine. *
  353. * *
  354. * INPUT: filename -- Pointer to the filename to set as the name of this file object. *
  355. * *
  356. * OUTPUT: Returns a pointer to the final and complete filename of this file object. This *
  357. * may have a path attached to the file. *
  358. * *
  359. * WARNINGS: none *
  360. * *
  361. * HISTORY: *
  362. * 11/15/1995 DRD : Created. *
  363. *=============================================================================================*/
  364. char const * BufferIOFileClass::Set_Name(char const * filename)
  365. {
  366. if ( File_Name() && UseBuffer) {
  367. if ( strcmp(filename, File_Name() ) == 0) {
  368. return( File_Name() );
  369. } else {
  370. Commit();
  371. IsCached = false;
  372. }
  373. }
  374. RawFileClass::Set_Name(filename);
  375. return( File_Name() );
  376. }
  377. /***********************************************************************************************
  378. * BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk. *
  379. * *
  380. * *
  381. * INPUT: none *
  382. * *
  383. * OUTPUT: bool; Is the file available for opening? *
  384. * *
  385. * WARNINGS: none *
  386. * *
  387. * HISTORY: *
  388. * 11/16/1995 DRD : Created. *
  389. *=============================================================================================*/
  390. int BufferIOFileClass::Is_Available(int )
  391. {
  392. if (UseBuffer) {
  393. return(true);
  394. }
  395. return( RawFileClass::Is_Available() );
  396. }
  397. /***********************************************************************************************
  398. * BufferIOFileClass::Is_Open -- Determines if the file is open. *
  399. * *
  400. * If part or all of the file is cached, then return that it is opened. A closed file *
  401. * doesn't have a valid pointer. *
  402. * *
  403. * INPUT: none *
  404. * *
  405. * OUTPUT: bool; Is the file open? *
  406. * *
  407. * WARNINGS: none *
  408. * *
  409. * HISTORY: *
  410. * 11/14/1995 DRD : Created. *
  411. *=============================================================================================*/
  412. int BufferIOFileClass::Is_Open(void) const
  413. {
  414. if (IsOpen && UseBuffer) {
  415. return( true );
  416. }
  417. return( RawFileClass::Is_Open() );
  418. }
  419. /***********************************************************************************************
  420. * BufferIOFileClass::Open -- Assigns name and opens file in one operation. *
  421. * *
  422. * This routine will assign the specified filename to the file object and open it at the *
  423. * same time. If the file object was already open, then it will be closed first. If the *
  424. * file object was previously assigned a filename, then it will be replaced with the new *
  425. * name. Typically, this routine is used when an anonymous file object has been crated and *
  426. * now it needs to be assigned a name and opened. *
  427. * *
  428. * INPUT: filename -- The filename to assign to this file object. *
  429. * *
  430. * rights -- The open file access rights to use. *
  431. * *
  432. * OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
  433. * is designed to never return unless it succeeded. *
  434. * *
  435. * WARNINGS: none *
  436. * *
  437. * HISTORY: *
  438. * 11/14/1995 DRD : Created. *
  439. *=============================================================================================*/
  440. int BufferIOFileClass::Open(char const * filename, int rights)
  441. {
  442. Set_Name(filename);
  443. return( BufferIOFileClass::Open( rights ) );
  444. }
  445. /***********************************************************************************************
  446. * BufferIOFileClass::Open -- Opens the file object with the rights specified. *
  447. * *
  448. * This routine is used to open the specified file object with the access rights indicated. *
  449. * This only works if the file has already been assigned a filename. It is guaranteed, by *
  450. * the error handler, that this routine will always return with success. *
  451. * *
  452. * INPUT: rights -- The file access rights to use when opening this file. This is a *
  453. * combination of READ and/or WRITE bit flags. *
  454. * *
  455. * OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
  456. * the error handler. *
  457. * *
  458. * WARNINGS: none *
  459. * *
  460. * HISTORY: *
  461. * 11/14/1995 DRD : Created. *
  462. *=============================================================================================*/
  463. int BufferIOFileClass::Open(int rights)
  464. {
  465. BufferIOFileClass::Close();
  466. if (UseBuffer) {
  467. BufferRights = rights; // save rights requested for checks later
  468. if (rights != READ ||
  469. (rights == READ && FileSize > BufferSize) ) {
  470. if (rights == WRITE) {
  471. RawFileClass::Open( rights );
  472. RawFileClass::Close();
  473. rights = READ | WRITE;
  474. TrueFileStart = 0; // now writing to single file
  475. }
  476. if (TrueFileStart) {
  477. UseBuffer = false;
  478. Open( rights );
  479. UseBuffer = true;
  480. } else {
  481. RawFileClass::Open( rights );
  482. }
  483. IsDiskOpen = true;
  484. if (BufferRights == WRITE) {
  485. FileSize = 0;
  486. }
  487. } else {
  488. IsDiskOpen = false;
  489. }
  490. BufferPos = 0;
  491. BufferFilePos = 0;
  492. BufferChangeBeg = -1;
  493. BufferChangeEnd = -1;
  494. FilePos = 0;
  495. IsOpen = true;
  496. } else {
  497. RawFileClass::Open( rights );
  498. }
  499. return( true );
  500. }
  501. /***********************************************************************************************
  502. * BufferIOFileClass::Write -- Writes data to the file cache. *
  503. * *
  504. * *
  505. * INPUT: buffer -- Pointer to the buffer that holds the data to be written. *
  506. * *
  507. * size -- The number of bytes to write. *
  508. * *
  509. * OUTPUT: Returns the number of bytes actually written. *
  510. * *
  511. * WARNINGS: none *
  512. * *
  513. * HISTORY: *
  514. * 11/15/1995 DRD : Created. *
  515. *=============================================================================================*/
  516. long BufferIOFileClass::Write(void const * buffer, long size)
  517. {
  518. int opened = false;
  519. if ( !Is_Open() ) {
  520. if (!Open(WRITE)) {
  521. return(0);
  522. }
  523. TrueFileStart = RawFileClass::Seek(0);
  524. opened = true;
  525. }
  526. if (UseBuffer) {
  527. long sizewritten = 0;
  528. if (BufferRights != READ) {
  529. while (size) {
  530. long sizetowrite;
  531. if (size >= (BufferSize - BufferPos) ) {
  532. sizetowrite = (BufferSize - BufferPos);
  533. } else {
  534. sizetowrite = size;
  535. }
  536. if (sizetowrite != BufferSize) {
  537. if ( !IsCached ) {
  538. long readsize;
  539. if (FileSize < BufferSize) {
  540. readsize = FileSize;
  541. BufferFilePos = 0;
  542. } else {
  543. readsize = BufferSize;
  544. BufferFilePos = FilePos;
  545. }
  546. if (TrueFileStart) {
  547. UseBuffer = false;
  548. Seek( FilePos, SEEK_SET );
  549. Read( Buffer, BufferSize );
  550. Seek( FilePos, SEEK_SET );
  551. UseBuffer = true;
  552. } else {
  553. RawFileClass::Seek( BufferFilePos, SEEK_SET );
  554. RawFileClass::Read( Buffer, readsize );
  555. }
  556. BufferPos = 0;
  557. BufferChangeBeg = -1;
  558. BufferChangeEnd = -1;
  559. IsCached = true;
  560. }
  561. }
  562. memmove((char *)Buffer + BufferPos, (char *)buffer + sizewritten, sizetowrite);
  563. IsChanged = true;
  564. sizewritten += sizetowrite;
  565. size -= sizetowrite;
  566. if (BufferChangeBeg == -1) {
  567. BufferChangeBeg = BufferPos;
  568. BufferChangeEnd = BufferPos;
  569. } else {
  570. if (BufferChangeBeg > BufferPos) {
  571. BufferChangeBeg = BufferPos;
  572. }
  573. }
  574. BufferPos += sizetowrite;
  575. if (BufferChangeEnd < BufferPos) {
  576. BufferChangeEnd = BufferPos;
  577. }
  578. FilePos = BufferFilePos + BufferPos;
  579. if (FileSize < FilePos) {
  580. FileSize = FilePos;
  581. }
  582. //
  583. // end of buffer reached?
  584. //
  585. if (BufferPos == BufferSize) {
  586. Commit();
  587. BufferPos = 0;
  588. BufferFilePos = FilePos;
  589. BufferChangeBeg = -1;
  590. BufferChangeEnd = -1;
  591. if (size && FileSize > FilePos) {
  592. if (TrueFileStart) {
  593. UseBuffer = false;
  594. Seek( FilePos, SEEK_SET );
  595. Read( Buffer, BufferSize );
  596. Seek( FilePos, SEEK_SET );
  597. UseBuffer = true;
  598. } else {
  599. RawFileClass::Seek( FilePos, SEEK_SET );
  600. RawFileClass::Read( Buffer, BufferSize );
  601. }
  602. } else {
  603. IsCached = false;
  604. }
  605. }
  606. }
  607. } else {
  608. Error(EACCES);
  609. }
  610. size = sizewritten;
  611. } else {
  612. size = RawFileClass::Write(buffer, size);
  613. }
  614. if (opened) {
  615. Close();
  616. }
  617. return( size );
  618. }
  619. /***********************************************************************************************
  620. * BufferIOFileClass::Read -- Reads data from the file cache. *
  621. * *
  622. * *
  623. * INPUT: buffer -- Pointer to the buffer to place the read data. *
  624. * *
  625. * size -- The number of bytes to read. *
  626. * *
  627. * OUTPUT: Returns the actual number of bytes read (this could be less than requested). *
  628. * *
  629. * WARNINGS: none *
  630. * *
  631. * HISTORY: *
  632. * 11/15/1995 DRD : Created. *
  633. *=============================================================================================*/
  634. long BufferIOFileClass::Read(void * buffer, long size)
  635. {
  636. int opened = false;
  637. if ( !Is_Open() ) {
  638. if ( Open() ) {
  639. TrueFileStart = RawFileClass::Seek(0);
  640. opened = true;
  641. }
  642. }
  643. if (UseBuffer) {
  644. long sizeread = 0;
  645. if (BufferRights != WRITE) {
  646. while (size) {
  647. long sizetoread;
  648. if (size >= (BufferSize - BufferPos) ) {
  649. sizetoread = (BufferSize - BufferPos);
  650. } else {
  651. sizetoread = size;
  652. }
  653. if ( !IsCached ) {
  654. long readsize;
  655. if (FileSize < BufferSize) {
  656. readsize = FileSize;
  657. BufferFilePos = 0;
  658. } else {
  659. readsize = BufferSize;
  660. BufferFilePos = FilePos;
  661. }
  662. if (TrueFileStart) {
  663. UseBuffer = false;
  664. Seek( FilePos, SEEK_SET );
  665. Read( Buffer, BufferSize );
  666. Seek( FilePos, SEEK_SET );
  667. UseBuffer = true;
  668. } else {
  669. RawFileClass::Seek( BufferFilePos, SEEK_SET );
  670. RawFileClass::Read( Buffer, readsize );
  671. }
  672. BufferPos = 0;
  673. BufferChangeBeg = -1;
  674. BufferChangeEnd = -1;
  675. IsCached = true;
  676. }
  677. memmove((char *)buffer + sizeread, (char *)Buffer + BufferPos, sizetoread);
  678. sizeread += sizetoread;
  679. size -= sizetoread;
  680. BufferPos += sizetoread;
  681. FilePos = BufferFilePos + BufferPos;
  682. //
  683. // end of buffer reached?
  684. //
  685. if (BufferPos == BufferSize) {
  686. Commit();
  687. BufferPos = 0;
  688. BufferFilePos = FilePos;
  689. BufferChangeBeg = -1;
  690. BufferChangeEnd = -1;
  691. if (size && FileSize > FilePos) {
  692. if (TrueFileStart) {
  693. UseBuffer = false;
  694. Seek( FilePos, SEEK_SET );
  695. Read( Buffer, BufferSize );
  696. Seek( FilePos, SEEK_SET );
  697. UseBuffer = true;
  698. } else {
  699. RawFileClass::Seek( FilePos, SEEK_SET );
  700. RawFileClass::Read( Buffer, BufferSize );
  701. }
  702. } else {
  703. IsCached = false;
  704. }
  705. }
  706. }
  707. } else {
  708. Error(EACCES);
  709. }
  710. size = sizeread;
  711. } else {
  712. size = RawFileClass::Read(buffer, size);
  713. }
  714. if (opened) {
  715. Close();
  716. }
  717. return( size );
  718. }
  719. /***********************************************************************************************
  720. * BufferIOFileClass::Seek -- Moves the current file pointer in the file. *
  721. * *
  722. * This routine will change the current file pointer to the position specified. It follows *
  723. * the same rules the a normal Seek() does, but if the file is part of the mixfile system, *
  724. * then only the position value needs to be updated. *
  725. * *
  726. * INPUT: pos -- The position to move the file to relative to the position indicated *
  727. * by the "dir" parameter. *
  728. * *
  729. * dir -- The direction to affect the position change against. This can be *
  730. * either SEEK_CUR, SEEK_END, or SEEK_SET. *
  731. * *
  732. * OUTPUT: Returns with the position of the new location. *
  733. * *
  734. * WARNINGS: none *
  735. * *
  736. * HISTORY: *
  737. * 11/15/1995 DRD : Created. *
  738. *=============================================================================================*/
  739. long BufferIOFileClass::Seek(long pos, int dir)
  740. {
  741. if (UseBuffer) {
  742. bool adjusted = false;
  743. switch (dir) {
  744. case SEEK_END:
  745. FilePos = FileSize;
  746. break;
  747. case SEEK_SET:
  748. FilePos = 0;
  749. break;
  750. case SEEK_CUR:
  751. default:
  752. break;
  753. }
  754. if (TrueFileStart) {
  755. if (pos >= TrueFileStart) {
  756. pos -= TrueFileStart;
  757. adjusted = true;
  758. }
  759. }
  760. FilePos += pos;
  761. if (FilePos < 0) {
  762. FilePos = 0;
  763. }
  764. if (FilePos > FileSize ) {
  765. FilePos = FileSize;
  766. }
  767. if (FileSize <= BufferSize) {
  768. BufferPos = FilePos;
  769. } else {
  770. if (FilePos >= BufferFilePos &&
  771. FilePos < (BufferFilePos + BufferSize) ) {
  772. BufferPos = FilePos - BufferFilePos;
  773. } else {
  774. Commit();
  775. // check!!
  776. if (TrueFileStart) {
  777. UseBuffer = false;
  778. Seek(FilePos, SEEK_SET);
  779. UseBuffer = true;
  780. } else {
  781. RawFileClass::Seek(FilePos, SEEK_SET);
  782. }
  783. IsCached = false;
  784. }
  785. }
  786. if (TrueFileStart && adjusted) {
  787. return( FilePos + TrueFileStart );
  788. }
  789. return( FilePos );
  790. }
  791. return( RawFileClass::Seek(pos, dir) );
  792. }
  793. /***********************************************************************************************
  794. * BufferIOFileClass::Size -- Determines size of file (in bytes). *
  795. * *
  796. * If part or all of the file is cached, then the size of the file is already *
  797. * determined and available. Otherwise, go to the low level system to find the file *
  798. * size. *
  799. * *
  800. * INPUT: none *
  801. * *
  802. * OUTPUT: Returns with the number of bytes in the file. *
  803. * *
  804. * WARNINGS: none *
  805. * *
  806. * HISTORY: *
  807. * 11/14/1995 DRD : Created. *
  808. *=============================================================================================*/
  809. long BufferIOFileClass::Size(void)
  810. {
  811. if (IsOpen && UseBuffer) {
  812. return( FileSize );
  813. }
  814. return( RawFileClass::Size() );
  815. }
  816. /***********************************************************************************************
  817. * BufferIOFileClass::Close -- Perform a closure of the file. *
  818. * *
  819. * Call Commit() to write the buffer if the file is cached and the buffer has changed, *
  820. * then call lower level Close(). *
  821. * *
  822. * INPUT: none *
  823. * *
  824. * OUTPUT: none *
  825. * *
  826. * WARNINGS: none *
  827. * *
  828. * HISTORY: *
  829. * 11/14/1995 DRD : Created. *
  830. *=============================================================================================*/
  831. void BufferIOFileClass::Close(void)
  832. {
  833. if (UseBuffer) {
  834. Commit();
  835. if (IsDiskOpen) {
  836. if (TrueFileStart) {
  837. UseBuffer = false;
  838. Close();
  839. UseBuffer = true;
  840. } else {
  841. RawFileClass::Close();
  842. }
  843. IsDiskOpen = false;
  844. }
  845. IsOpen = false;
  846. } else {
  847. RawFileClass::Close();
  848. }
  849. }