LocalFile.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /*
  2. ** Command & Conquer Generals Zero Hour(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. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. //----------------------------------------------------------------------------
  24. //
  25. // Westwood Studios Pacific.
  26. //
  27. // Confidential Information
  28. // Copyright(C) 2001 - All Rights Reserved
  29. //
  30. //----------------------------------------------------------------------------
  31. //
  32. // Project: WSYS Library
  33. //
  34. // Module: IO_
  35. //
  36. // File name: IO_LocalFile.cpp
  37. //
  38. // Created: 4/23/01
  39. //
  40. //----------------------------------------------------------------------------
  41. //----------------------------------------------------------------------------
  42. // Includes
  43. //----------------------------------------------------------------------------
  44. #include "PreRTS.h"
  45. #include <stdio.h>
  46. #include <fcntl.h>
  47. #include <io.h>
  48. #include <string.h>
  49. #include <sys/stat.h>
  50. #include <stdlib.h>
  51. #include <ctype.h>
  52. #include "Common/LocalFile.h"
  53. #include "Common/RAMFile.h"
  54. #include "Lib/BaseType.h"
  55. #include "Common/PerfTimer.h"
  56. #ifdef _INTERNAL
  57. // for occasional debugging...
  58. //#pragma optimize("", off)
  59. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  60. #endif
  61. //----------------------------------------------------------------------------
  62. // Externals
  63. //----------------------------------------------------------------------------
  64. //----------------------------------------------------------------------------
  65. // Defines
  66. //----------------------------------------------------------------------------
  67. //----------------------------------------------------------------------------
  68. // Private Types
  69. //----------------------------------------------------------------------------
  70. //----------------------------------------------------------------------------
  71. // Private Data
  72. //----------------------------------------------------------------------------
  73. static Int s_totalOpen = 0;
  74. //----------------------------------------------------------------------------
  75. // Public Data
  76. //----------------------------------------------------------------------------
  77. //----------------------------------------------------------------------------
  78. // Private Prototypes
  79. //----------------------------------------------------------------------------
  80. //----------------------------------------------------------------------------
  81. // Private Functions
  82. //----------------------------------------------------------------------------
  83. //=================================================================
  84. // LocalFile::LocalFile
  85. //=================================================================
  86. LocalFile::LocalFile()
  87. #ifdef USE_BUFFERED_IO
  88. : m_file(NULL)
  89. #else
  90. : m_handle(-1)
  91. #endif
  92. {
  93. }
  94. //----------------------------------------------------------------------------
  95. // Public Functions
  96. //----------------------------------------------------------------------------
  97. //=================================================================
  98. // LocalFile::~LocalFile
  99. //=================================================================
  100. LocalFile::~LocalFile()
  101. {
  102. #ifdef USE_BUFFERED_IO
  103. if (m_file)
  104. {
  105. fclose(m_file);
  106. m_file = NULL;
  107. --s_totalOpen;
  108. }
  109. #else
  110. if( m_handle != -1 )
  111. {
  112. _close( m_handle );
  113. m_handle = -1;
  114. --s_totalOpen;
  115. }
  116. #endif
  117. File::close();
  118. }
  119. //=================================================================
  120. // LocalFile::open
  121. //=================================================================
  122. /**
  123. * This function opens a file using the standard C open() call. Access flags
  124. * are mapped to the appropriate open flags. Returns true if file was opened
  125. * successfully.
  126. */
  127. //=================================================================
  128. //DECLARE_PERF_TIMER(LocalFile)
  129. Bool LocalFile::open( const Char *filename, Int access )
  130. {
  131. //USE_PERF_TIMER(LocalFile)
  132. if( !File::open( filename, access) )
  133. {
  134. return FALSE;
  135. }
  136. /* here we translate WSYS file access to the std C equivalent */
  137. #ifdef USE_BUFFERED_IO
  138. char mode[32];
  139. char* m = mode;
  140. if (m_access & APPEND)
  141. {
  142. DEBUG_CRASH(("not yet supported by buffered mode"));
  143. }
  144. if (m_access & TRUNCATE)
  145. {
  146. DEBUG_CRASH(("not yet supported by buffered mode"));
  147. }
  148. if((m_access & READWRITE ) == READWRITE )
  149. {
  150. if (m_access & CREATE)
  151. {
  152. *m++ = 'w';
  153. *m++ = '+';
  154. }
  155. else
  156. {
  157. *m++ = 'r';
  158. *m++ = '+';
  159. }
  160. }
  161. else if(m_access & WRITE)
  162. {
  163. *m++ = 'w';
  164. }
  165. else
  166. {
  167. *m++ = 'r';
  168. DEBUG_ASSERTCRASH(!(m_access & TRUNCATE), ("cannot truncate with read-only"));
  169. }
  170. if (m_access & TEXT)
  171. {
  172. *m++ = 't';
  173. }
  174. if (m_access & BINARY)
  175. {
  176. *m++ = 'b';
  177. }
  178. *m++ = 0;
  179. m_file = fopen(filename, mode);
  180. if (m_file == NULL)
  181. {
  182. goto error;
  183. }
  184. //setvbuf(m_file, m_vbuf, _IOFBF, sizeof(BUF_SIZE));
  185. #else
  186. int flags = 0;
  187. if (m_access & CREATE)
  188. {
  189. flags |= _O_CREAT;
  190. }
  191. if (m_access & TRUNCATE)
  192. {
  193. flags |= _O_TRUNC;
  194. }
  195. if (m_access & APPEND)
  196. {
  197. flags |= _O_APPEND;
  198. }
  199. if (m_access & TEXT)
  200. {
  201. flags |= _O_TEXT;
  202. }
  203. if (m_access & BINARY)
  204. {
  205. flags |= _O_BINARY;
  206. }
  207. if((m_access & READWRITE )== READWRITE )
  208. {
  209. flags |= _O_RDWR;
  210. }
  211. else if(m_access & WRITE)
  212. {
  213. flags |= _O_WRONLY;
  214. flags |= _O_CREAT;
  215. }
  216. else
  217. {
  218. flags |= _O_RDONLY;
  219. }
  220. m_handle = _open( filename, flags , _S_IREAD | _S_IWRITE);
  221. if( m_handle == -1 )
  222. {
  223. goto error;
  224. }
  225. #endif
  226. ++s_totalOpen;
  227. /// DEBUG_LOG(("LocalFile::open %s (total %d)\n",filename,s_totalOpen));
  228. if ( m_access & APPEND )
  229. {
  230. if ( seek ( 0, END ) < 0 )
  231. {
  232. goto error;
  233. }
  234. }
  235. return TRUE;
  236. error:
  237. close();
  238. return FALSE;
  239. }
  240. //=================================================================
  241. // LocalFile::close
  242. //=================================================================
  243. /**
  244. * Closes the current file if it is open.
  245. * Must call LocalFile::close() for each successful LocalFile::open() call.
  246. */
  247. //=================================================================
  248. void LocalFile::close( void )
  249. {
  250. File::close();
  251. }
  252. //=================================================================
  253. // LocalFile::read
  254. //=================================================================
  255. Int LocalFile::read( void *buffer, Int bytes )
  256. {
  257. //USE_PERF_TIMER(LocalFile)
  258. if( !m_open )
  259. {
  260. return -1;
  261. }
  262. if (buffer == NULL)
  263. {
  264. #ifdef USE_BUFFERED_IO
  265. fseek(m_file, bytes, SEEK_CUR);
  266. #else
  267. _lseek(m_handle, bytes, SEEK_CUR);
  268. #endif
  269. return bytes;
  270. }
  271. #ifdef USE_BUFFERED_IO
  272. Int ret = fread(buffer, 1, bytes, m_file);
  273. #else
  274. Int ret = _read( m_handle, buffer, bytes );
  275. #endif
  276. return ret;
  277. }
  278. //=================================================================
  279. // LocalFile::write
  280. //=================================================================
  281. Int LocalFile::write( const void *buffer, Int bytes )
  282. {
  283. if( !m_open || !buffer )
  284. {
  285. return -1;
  286. }
  287. #ifdef USE_BUFFERED_IO
  288. Int ret = fwrite(buffer, 1, bytes, m_file);
  289. #else
  290. Int ret = _write( m_handle, buffer, bytes );
  291. #endif
  292. return ret;
  293. }
  294. //=================================================================
  295. // LocalFile::seek
  296. //=================================================================
  297. Int LocalFile::seek( Int pos, seekMode mode)
  298. {
  299. int lmode;
  300. switch( mode )
  301. {
  302. case START:
  303. lmode = SEEK_SET;
  304. break;
  305. case CURRENT:
  306. lmode = SEEK_CUR;
  307. break;
  308. case END:
  309. DEBUG_ASSERTCRASH(pos <= 0, ("LocalFile::seek - pos should be <= 0 for a seek starting at the end of the file"));
  310. lmode = SEEK_END;
  311. break;
  312. default:
  313. // bad seek mode
  314. return -1;
  315. }
  316. #ifdef USE_BUFFERED_IO
  317. Int ret = fseek(m_file, pos, lmode);
  318. if (ret == 0)
  319. return ftell(m_file);
  320. else
  321. return -1;
  322. #else
  323. Int ret = _lseek( m_handle, pos, lmode );
  324. #endif
  325. return ret;
  326. }
  327. //=================================================================
  328. // LocalFile::scanInt
  329. //=================================================================
  330. // skips preceding whitespace and stops at the first non-number
  331. // or at EOF
  332. Bool LocalFile::scanInt(Int &newInt)
  333. {
  334. newInt = 0;
  335. AsciiString tempstr;
  336. Char c;
  337. Int val;
  338. // skip preceding non-numeric characters
  339. do {
  340. #ifdef USE_BUFFERED_IO
  341. val = fread(&c, 1, 1, m_file);
  342. #else
  343. val = _read( m_handle, &c, 1);
  344. #endif
  345. } while ((val != 0) && (((c < '0') || (c > '9')) && (c != '-')));
  346. if (val == 0) {
  347. return FALSE;
  348. }
  349. do {
  350. tempstr.concat(c);
  351. #ifdef USE_BUFFERED_IO
  352. val = fread(&c, 1, 1, m_file);
  353. #else
  354. val = _read( m_handle, &c, 1);
  355. #endif
  356. } while ((val != 0) && ((c >= '0') && (c <= '9')));
  357. // put the last read char back, since we didn't use it.
  358. if (val != 0) {
  359. #ifdef USE_BUFFERED_IO
  360. fseek(m_file, -1, SEEK_CUR);
  361. #else
  362. _lseek(m_handle, -1, SEEK_CUR);
  363. #endif
  364. }
  365. newInt = atoi(tempstr.str());
  366. return TRUE;
  367. }
  368. //=================================================================
  369. // LocalFile::scanReal
  370. //=================================================================
  371. // skips preceding whitespace and stops at the first non-number
  372. // or at EOF
  373. Bool LocalFile::scanReal(Real &newReal)
  374. {
  375. newReal = 0.0;
  376. AsciiString tempstr;
  377. Char c;
  378. Int val;
  379. Bool sawDec = FALSE;
  380. // skip the preceding white space
  381. do {
  382. #ifdef USE_BUFFERED_IO
  383. val = fread(&c, 1, 1, m_file);
  384. #else
  385. val = _read( m_handle, &c, 1);
  386. #endif
  387. } while ((val != 0) && (((c < '0') || (c > '9')) && (c != '-') && (c != '.')));
  388. if (val == 0) {
  389. return FALSE;
  390. }
  391. do {
  392. tempstr.concat(c);
  393. if (c == '.') {
  394. sawDec = TRUE;
  395. }
  396. #ifdef USE_BUFFERED_IO
  397. val = fread(&c, 1, 1, m_file);
  398. #else
  399. val = _read(m_handle, &c, 1);
  400. #endif
  401. } while ((val != 0) && (((c >= '0') && (c <= '9')) || ((c == '.') && !sawDec)));
  402. if (val != 0) {
  403. #ifdef USE_BUFFERED_IO
  404. fseek(m_file, -1, SEEK_CUR);
  405. #else
  406. _lseek(m_handle, -1, SEEK_CUR);
  407. #endif
  408. }
  409. newReal = atof(tempstr.str());
  410. return TRUE;
  411. }
  412. //=================================================================
  413. // LocalFile::scanString
  414. //=================================================================
  415. // skips preceding whitespace and stops at the first whitespace
  416. // or at EOF
  417. Bool LocalFile::scanString(AsciiString &newString)
  418. {
  419. Char c;
  420. Int val;
  421. newString.clear();
  422. // skip the preceding whitespace
  423. do {
  424. #ifdef USE_BUFFERED_IO
  425. val = fread(&c, 1, 1, m_file);
  426. #else
  427. val = _read(m_handle, &c, 1);
  428. #endif
  429. } while ((val != 0) && (isspace(c)));
  430. if (val == 0) {
  431. return FALSE;
  432. }
  433. do {
  434. newString.concat(c);
  435. #ifdef USE_BUFFERED_IO
  436. val = fread(&c, 1, 1, m_file);
  437. #else
  438. val = _read(m_handle, &c, 1);
  439. #endif
  440. } while ((val != 0) && (!isspace(c)));
  441. if (val != 0) {
  442. #ifdef USE_BUFFERED_IO
  443. fseek(m_file, -1, SEEK_CUR);
  444. #else
  445. _lseek(m_handle, -1, SEEK_CUR);
  446. #endif
  447. }
  448. return TRUE;
  449. }
  450. //=================================================================
  451. // LocalFile::nextLine
  452. //=================================================================
  453. // scans to the first character after a new-line or at EOF
  454. void LocalFile::nextLine(Char *buf, Int bufSize)
  455. {
  456. Char c = 0;
  457. Int val;
  458. Int i = 0;
  459. // seek to the next new-line.
  460. do {
  461. if ((buf == NULL) || (i >= (bufSize-1))) {
  462. #ifdef USE_BUFFERED_IO
  463. val = fread(&c, 1, 1, m_file);
  464. #else
  465. val = _read(m_handle, &c, 1);
  466. #endif
  467. } else {
  468. #ifdef USE_BUFFERED_IO
  469. val = fread(buf + i, 1, 1, m_file);
  470. #else
  471. val = _read(m_handle, buf + i, 1);
  472. #endif
  473. c = buf[i];
  474. }
  475. ++i;
  476. } while ((val != 0) && (c != '\n'));
  477. if (buf != NULL) {
  478. if (i < bufSize) {
  479. buf[i] = 0;
  480. } else {
  481. buf[bufSize] = 0;
  482. }
  483. }
  484. }
  485. //=================================================================
  486. //=================================================================
  487. File* LocalFile::convertToRAMFile()
  488. {
  489. RAMFile *ramFile = newInstance( RAMFile );
  490. if (ramFile->open(this))
  491. {
  492. if (this->m_deleteOnClose)
  493. {
  494. ramFile->deleteOnClose();
  495. this->close(); // is deleteonclose, so should delete.
  496. }
  497. else
  498. {
  499. this->close();
  500. this->deleteInstance();
  501. }
  502. return ramFile;
  503. }
  504. else
  505. {
  506. ramFile->close();
  507. ramFile->deleteInstance();
  508. return this;
  509. }
  510. }
  511. //=================================================================
  512. // LocalFile::readEntireAndClose
  513. //=================================================================
  514. /**
  515. Allocate a buffer large enough to hold entire file, read
  516. the entire file into the buffer, then close the file.
  517. the buffer is owned by the caller, who is responsible
  518. for freeing is (via delete[]). This is a Good Thing to
  519. use because it minimizes memory copies for BIG files.
  520. */
  521. char* LocalFile::readEntireAndClose()
  522. {
  523. UnsignedInt fileSize = size();
  524. char* buffer = NEW char[fileSize];
  525. read(buffer, fileSize);
  526. close();
  527. return buffer;
  528. }