BFIOFILE.CPP 39 KB

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