rawfile.cpp 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. /*
  2. ** Command & Conquer Renegade(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. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Commando/Code/wwlib/rawfile.cpp $*
  25. * *
  26. * $Author:: Jani_p $*
  27. * *
  28. * $Modtime:: 11/25/01 1:26p $*
  29. * *
  30. * $Revision:: 13 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
  35. * RawFileClass::Close -- Perform a closure of the file. *
  36. * RawFileClass::Create -- Creates an empty file. *
  37. * RawFileClass::Delete -- Deletes the file object from the disk. *
  38. * RawFileClass::Error -- Handles displaying a file error message. *
  39. * RawFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
  40. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  41. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  42. * RawFileClass::Open -- Opens the file object with the rights specified. *
  43. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  44. * RawFileClass::Raw_Seek -- Performs a seek on the unbiased file *
  45. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  46. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  47. * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
  48. * RawFileClass::Set_Name -- Manually sets the name for a file object. *
  49. * RawFileClass::Size -- Determines size of file (in bytes). *
  50. * RawFileClass::Write -- Writes the specified data to the buffer specified. *
  51. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  52. #include "always.h"
  53. #include "rawfile.h"
  54. #include <direct.h>
  55. //#include <share.h>
  56. #include <stddef.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include "win.h"
  61. #include <limits.h>
  62. #include <errno.h>
  63. #ifdef _UNIX
  64. #include <sys/types.h>
  65. #include <sys/stat.h>
  66. #endif
  67. #if 0 //#ifdef NEVER (gth) the MAX sdk must #define NEVER! yikes :-)
  68. /*
  69. ** This is a duplicate of the error numbers. The error handler for the RawFileClass handles
  70. ** these errors. If the error routine is overridden and additional errors are defined, then
  71. ** use numbers starting with 100. Note that these errors here are listed in numerical order.
  72. ** These errors are defined in the standard header file "ERRNO.H".
  73. */
  74. EZERO, // Non-error.
  75. EINVFNC, // Invalid function number.
  76. ENOFILE, // File not found.
  77. ENOENT=ENOFILE, // No such file or directory.
  78. ENOPATH, // Path not found.
  79. EMFILE, // Too many open files.
  80. EACCES, // Permission denied.
  81. EBADF, // Bad file number.
  82. ECONTR, // Memory blocks destroyed.
  83. ENOMEM, // Not enough core memory.
  84. EINVMEM, // Invalid memory block address.
  85. EINVENV, // Invalid environment.
  86. EINVFMT, // Invalid format.
  87. EINVACC, // Invalid access code.
  88. EINVDAT, // Invalid data.
  89. EFAULT, // Unknown error.
  90. EINVDRV, // Invalid drive specified.
  91. ENODEV=EINVDRV, // No such device.
  92. ECURDIR, // Attempt to remove CurDir.
  93. ENOTSAM, // Not same device.
  94. ENMFILE, // No more files.
  95. EINVAL, // Invalid argument.
  96. E2BIG, // Argument list too long.
  97. ENOEXEC, // exec format error.
  98. EXDEV, // Cross-device link.
  99. ENFILE, // Too many open files.
  100. ECHILD, // No child process.
  101. ENOTTY, // not used
  102. ETXTBSY, // not used
  103. EFBIG, // not used
  104. ENOSPC, // No space left on device.
  105. ESPIPE, // Illegal seek.
  106. EROFS, // Read-only file system.
  107. EMLINK, // not used
  108. EPIPE, // Broken pipe.
  109. EDOM, // Math argument.
  110. ERANGE, // Result too large.
  111. EEXIST, // File already exists.
  112. EDEADLOCK, // Locking violation.
  113. EPERM, // Operation not permitted.
  114. ESRCH, // not used
  115. EINTR, // Interrupted function call.
  116. EIO, // Input/output error.
  117. ENXIO, // No such device or address.
  118. EAGAIN, // Resource temporarily unavailable.
  119. ENOTBLK, // not used
  120. EBUSY, // Resource busy.
  121. ENOTDIR, // not used
  122. EISDIR, // not used
  123. EUCLEAN, // not used
  124. #endif
  125. /***********************************************************************************************
  126. * RawFileClass::RawFileClass -- Default constructor for a file object. *
  127. * *
  128. * This constructs a null file object. A null file object has no file handle or filename *
  129. * associated with it. In order to use a file object created in this fashion it must be *
  130. * assigned a name and then opened. *
  131. * *
  132. * INPUT: none *
  133. * *
  134. * OUTPUT: none *
  135. * *
  136. * WARNINGS: none *
  137. * *
  138. * HISTORY: *
  139. * 10/18/1994 JLB : Created. *
  140. *=============================================================================================*/
  141. RawFileClass::RawFileClass(void) :
  142. Rights(READ),
  143. BiasStart(0),
  144. BiasLength(-1),
  145. Handle(NULL_HANDLE),
  146. Filename(""),
  147. Date(0),
  148. Time(0)
  149. {
  150. }
  151. /***********************************************************************************************
  152. * RawFileClass::Is_Open -- Checks to see if the file is open or not. *
  153. * *
  154. * Use this routine to determine if the file is open. It returns true if it is. *
  155. * *
  156. * INPUT: none *
  157. * *
  158. * OUTPUT: bool; Is the file open? *
  159. * *
  160. * *
  161. * WARNINGS: none *
  162. * *
  163. * HISTORY: *
  164. * 10/18/1994 JLB : Created. *
  165. *=============================================================================================*/
  166. bool RawFileClass::Is_Open(void) const
  167. {
  168. return(Handle != NULL_HANDLE);
  169. }
  170. /***********************************************************************************************
  171. * RawFileClass::Error -- Handles displaying a file error message. *
  172. * *
  173. * Display an error message as indicated. If it is allowed to retry, then pressing a key *
  174. * will return from this function. Otherwise, it will exit the program with "exit()". *
  175. * *
  176. * INPUT: error -- The error number (same as the DOSERR.H error numbers). *
  177. * *
  178. * canretry -- Can this routine exit normally so that retrying can occur? If this is *
  179. * false, then the program WILL exit in this routine. *
  180. * *
  181. * filename -- Optional filename to report with this error. If no filename is *
  182. * supplied, then no filename is listed in the error message. *
  183. * *
  184. * OUTPUT: none, but this routine might not return at all if the "canretry" parameter is *
  185. * false or the player pressed ESC. *
  186. * *
  187. * WARNINGS: This routine may not return at all. It handles being in text mode as well as *
  188. * if in a graphic mode. *
  189. * *
  190. * HISTORY: *
  191. * 10/17/1994 JLB : Created. *
  192. *=============================================================================================*/
  193. void RawFileClass::Error(int, int, char const * )
  194. {
  195. }
  196. /***********************************************************************************************
  197. * RawFileClass::Transfer_Block_Size *
  198. * *
  199. * This function returns the largest size a low level DOS read or write may *
  200. * perform. Larger file transfers are performed in chunks of this size or less. *
  201. * *
  202. * INPUT: none *
  203. * *
  204. * OUTPUT: *
  205. * *
  206. * *
  207. * WARNINGS: none *
  208. * *
  209. * HISTORY: *
  210. * 10/18/1994 JLB : Created. *
  211. *=============================================================================================*/
  212. int RawFileClass::Transfer_Block_Size(void)
  213. {
  214. return (int)((unsigned)UINT_MAX)-16L;
  215. }
  216. /***********************************************************************************************
  217. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  218. * *
  219. * This constructor is called when a file object is created with a supplied filename, but *
  220. * not opened at the same time. In this case, an assumption is made that the supplied *
  221. * filename is a constant string. A duplicate of the filename string is not created since *
  222. * it would be wasteful in that case. *
  223. * *
  224. * INPUT: filename -- The filename to assign to this file object. *
  225. * *
  226. * OUTPUT: none *
  227. * *
  228. * WARNINGS: none *
  229. * *
  230. * HISTORY: *
  231. * 10/17/1994 JLB : Created. *
  232. *=============================================================================================*/
  233. RawFileClass::RawFileClass(char const * filename) :
  234. Rights(0),
  235. BiasStart(0),
  236. BiasLength(-1),
  237. Handle(NULL_HANDLE),
  238. Filename(filename),
  239. Date(0),
  240. Time(0)
  241. {
  242. }
  243. /***********************************************************************************************
  244. * RawFileClass::~RawFileClass -- Default deconstructor for a file object. *
  245. * *
  246. * This constructs a null file object. A null file object has no file handle or filename *
  247. * associated with it. In order to use a file object created in this fashion it must be *
  248. * assigned a name and then opened. *
  249. * *
  250. * INPUT: none *
  251. * *
  252. * OUTPUT: none *
  253. * *
  254. * WARNINGS: none *
  255. * *
  256. * HISTORY: *
  257. * 10/18/1994 JLB : Created. *
  258. *=============================================================================================*/
  259. RawFileClass::~RawFileClass(void)
  260. {
  261. Reset ();
  262. }
  263. /***********************************************************************************************
  264. * RawFileClass::Reset -- Closes the file handle and resets the object's state.
  265. * *
  266. * INPUT: none *
  267. * *
  268. * OUTPUT: none *
  269. * *
  270. * WARNINGS: none *
  271. * *
  272. * HISTORY: *
  273. * 06/10/1999 PDS : Created. *
  274. *=============================================================================================*/
  275. void RawFileClass::Reset(void)
  276. {
  277. Close();
  278. Filename = "";
  279. }
  280. /***********************************************************************************************
  281. * RawFileClass::Set_Name -- Manually sets the name for a file object. *
  282. * *
  283. * This routine will set the name for the file object to the name specified. Setting the *
  284. * name in this fashion doesn't affect the closed or opened state *
  285. * of the file. *
  286. * *
  287. * INPUT: filename -- The filename to assign to this file object. *
  288. * *
  289. * OUTPUT: pointer to filename. *
  290. * *
  291. * *
  292. * HISTORY: *
  293. * 10/17/1994 JLB : Created. *
  294. * 11/25/2001 Jani : Changed the name storage from strdup to StringClass to benefit from our *
  295. * Fast memory allocation system.
  296. *=============================================================================================*/
  297. char const * RawFileClass::Set_Name(char const * filename)
  298. {
  299. Bias(0);
  300. Filename=filename;
  301. /*
  302. ** If this is a UNIX build, fix the filename from the DOS-like name passed in
  303. */
  304. #ifdef _UNIX
  305. for (int i=0; i<Filename.Length(); i++)
  306. {
  307. if (Filename[i]=='\\')
  308. Filename[i]='/';
  309. Filename[i]=tolower(Filename[i]); // don't preserve case
  310. }
  311. #endif
  312. return(Filename);
  313. }
  314. /***********************************************************************************************
  315. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  316. * *
  317. * This routine will assign the specified filename to the file object and open it at the *
  318. * same time. If the file object was already open, then it will be closed first. If the *
  319. * file object was previously assigned a filename, then it will be replaced with the new *
  320. * name. Typically, this routine is used when an anonymous file object has been crated and *
  321. * now it needs to be assigned a name and opened. *
  322. * *
  323. * INPUT: filename -- The filename to assign to this file object. *
  324. * *
  325. * rights -- The open file access rights to use. *
  326. * *
  327. * OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
  328. * is designed to never return unless it succeeded. *
  329. * *
  330. * WARNINGS: none *
  331. * *
  332. * HISTORY: *
  333. * 10/17/1994 JLB : Created. *
  334. *=============================================================================================*/
  335. int RawFileClass::Open(char const * filename, int rights)
  336. {
  337. Set_Name(filename);
  338. return(Open(rights));
  339. }
  340. /***********************************************************************************************
  341. * RawFileClass::Open -- Opens the file object with the rights specified. *
  342. * *
  343. * This routine is used to open the specified file object with the access rights indicated. *
  344. * This only works if the file has already been assigned a filename. It is guaranteed, by *
  345. * the error handler, that this routine will always return with success. *
  346. * *
  347. * INPUT: rights -- The file access rights to use when opening this file. This is a *
  348. * combination of READ and/or WRITE bit flags. *
  349. * *
  350. * OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
  351. * the error handler. *
  352. * *
  353. * WARNINGS: none *
  354. * *
  355. * HISTORY: *
  356. * 10/17/1994 JLB : Created. *
  357. *=============================================================================================*/
  358. int RawFileClass::Open(int rights)
  359. {
  360. Close();
  361. /*
  362. ** Verify that there is a filename associated with this file object. If not, then this is a
  363. ** big error condition.
  364. */
  365. if (Filename.Get_Length()==0) {
  366. Error(ENOENT, false);
  367. }
  368. /*
  369. ** Record the access rights used for this open call. These rights will be used if the
  370. ** file object is duplicated.
  371. */
  372. Rights = rights;
  373. /*
  374. ** Repetitively try to open the file. Abort if a fatal error condition occurs.
  375. */
  376. for (;;) {
  377. /*
  378. ** Try to open the file according to the access rights specified.
  379. */
  380. switch (rights) {
  381. /*
  382. ** If the access rights are not recognized, then report this as
  383. ** an invalid access code.
  384. */
  385. default:
  386. errno = EINVAL;
  387. break;
  388. case READ:
  389. #ifdef _UNIX
  390. Handle = fopen(Filename, "r");
  391. #else
  392. Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ,
  393. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  394. #endif
  395. break;
  396. case WRITE:
  397. #ifdef _UNIX
  398. Handle = fopen(Filename, "w");
  399. #else
  400. Handle = CreateFileA(Filename, GENERIC_WRITE, 0,
  401. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  402. #endif
  403. break;
  404. case READ|WRITE:
  405. #ifdef _UNIX
  406. Handle = fopen(Filename, "w");
  407. #else
  408. // SKB 5/13/99 use OPEN_ALWAYS instead of CREATE_ALWAYS so that files
  409. // does not get destroyed.
  410. Handle = CreateFileA(Filename, GENERIC_READ | GENERIC_WRITE, 0,
  411. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  412. #endif
  413. break;
  414. }
  415. /*
  416. ** Biased files must be positioned past the bias start position.
  417. */
  418. if (BiasStart != 0 || BiasLength != -1) {
  419. Seek(0, SEEK_SET);
  420. }
  421. /*
  422. ** If the handle indicates the file is not open, then this is an error condition.
  423. ** For the case of the file cannot be found, then allow a retry. All other cases
  424. ** are fatal.
  425. */
  426. if (Handle == NULL_HANDLE) {
  427. return(false);
  428. // Error(GetLastError(), false, Filename);
  429. // continue;
  430. }
  431. break;
  432. }
  433. return(true);
  434. }
  435. /***********************************************************************************************
  436. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  437. * *
  438. * This routine will examine the disk system to see if the specified file can be opened *
  439. * or not. Use this routine before opening a file in order to make sure that is available *
  440. * or to perform other necessary actions. *
  441. * *
  442. * INPUT: force -- Should this routine keep retrying until the file becomes available? If *
  443. * in this case it doesn't become available, then the program will abort. *
  444. * *
  445. * OUTPUT: bool; Is the file available to be opened? *
  446. * *
  447. * WARNINGS: Depending on the parameter passed in, this routine may never return. *
  448. * *
  449. * HISTORY: *
  450. * 10/18/1994 JLB : Created. *
  451. *=============================================================================================*/
  452. bool RawFileClass::Is_Available(int forced)
  453. {
  454. if (Filename.Get_Length()==0) return(false);
  455. /*
  456. ** If the file is already open, then is must have already passed the availability check.
  457. ** Return true in this case.
  458. */
  459. if (Is_Open()) return(true);
  460. /*
  461. ** If this is a forced check, then go through the normal open channels, since those
  462. ** channels ensure that the file must exist.
  463. */
  464. if (forced) {
  465. RawFileClass::Open(READ);
  466. RawFileClass::Close();
  467. return(true);
  468. }
  469. /*
  470. ** Perform a raw open of the file. If this open fails for ANY REASON, including a missing
  471. ** CD-ROM, this routine will return a failure condition. In all but the missing file
  472. ** condition, go through the normal error recover channels.
  473. */
  474. for (;;) {
  475. #ifdef _UNIX
  476. Handle=fopen(Filename,"r");
  477. #else
  478. Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ,
  479. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  480. #endif
  481. if (Handle == NULL_HANDLE) {
  482. return(false);
  483. }
  484. break;
  485. }
  486. /*
  487. ** Since the file could be opened, then close it and return that the file exists.
  488. */
  489. int closeok;
  490. #ifdef _UNIX
  491. closeok=((fclose(Handle)==0)?TRUE:FALSE);
  492. #else
  493. closeok=CloseHandle(Handle);
  494. #endif
  495. if (! closeok) {
  496. Error(GetLastError(), false, Filename);
  497. }
  498. Handle = NULL_HANDLE;
  499. return(true);
  500. }
  501. /***********************************************************************************************
  502. * RawFileClass::Close -- Perform a closure of the file. *
  503. * *
  504. * Close the file object. In the rare case of an error, handle it as appropriate. *
  505. * *
  506. * INPUT: none *
  507. * *
  508. * OUTPUT: none *
  509. * *
  510. * WARNINGS: Some rare error conditions may cause this routine to abort the program. *
  511. * *
  512. * HISTORY: *
  513. * 10/18/1994 JLB : Created. *
  514. *=============================================================================================*/
  515. void RawFileClass::Close(void)
  516. {
  517. /*
  518. ** If the file is open, then close it. If the file is already closed, then just return. This
  519. ** isn't considered an error condition.
  520. */
  521. if (Is_Open()) {
  522. /*
  523. ** Try to close the file. If there was an error (who knows what that could be), then
  524. ** call the error routine.
  525. */
  526. int closeok;
  527. #ifdef _UNIX
  528. closeok=(fclose(Handle)==0)?TRUE:FALSE;
  529. #else
  530. closeok=CloseHandle(Handle);
  531. #endif
  532. if (!closeok) {
  533. Error(GetLastError(), false, Filename);
  534. }
  535. /*
  536. ** At this point the file must have been closed. Mark the file as empty and return.
  537. */
  538. Handle = NULL_HANDLE;
  539. }
  540. }
  541. /***********************************************************************************************
  542. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  543. * *
  544. * This routine will read the specified number of bytes and place the data into the buffer *
  545. * indicated. It is legal to call this routine with a request for more bytes than are in *
  546. * the file. This condition can result in fewer bytes being read than requested. Determine *
  547. * this by examining the return value. *
  548. * *
  549. * INPUT: buffer -- Pointer to the buffer to read data into. If NULL is passed, no read *
  550. * is performed. *
  551. * *
  552. * size -- The number of bytes to read. If NULL is passed, then no read is *
  553. * performed. *
  554. * *
  555. * OUTPUT: Returns with the number of bytes read into the buffer. If this number is less *
  556. * than requested, it indicates that the file has been exhausted. *
  557. * *
  558. * WARNINGS: none *
  559. * *
  560. * HISTORY: *
  561. * 10/18/1994 JLB : Created. *
  562. *=============================================================================================*/
  563. int RawFileClass::Read(void * buffer, int size)
  564. {
  565. long bytesread = 0; // Running count of the number of bytes read into the buffer.
  566. int opened = false; // Was the file opened by this routine?
  567. /*
  568. ** If the file isn't opened, open it. This serves as a convenience
  569. ** for the programmer.
  570. */
  571. if (!Is_Open()) {
  572. /*
  573. ** The error check here is moot. Open will never return unless it succeeded.
  574. */
  575. if (!Open(READ)) {
  576. return(0);
  577. }
  578. opened = true;
  579. }
  580. /*
  581. ** A biased file has the requested read length limited to the bias length of
  582. ** the file.
  583. */
  584. if (BiasLength != -1) {
  585. int remainder = BiasLength - Seek(0);
  586. size = size < remainder ? size : remainder;
  587. }
  588. long total = 0;
  589. while (size > 0) {
  590. bytesread = 0;
  591. int readok=TRUE;
  592. #ifdef _UNIX
  593. readok=TRUE;
  594. bytesread=fread(buffer,1,size,Handle);
  595. if ((bytesread == 0)&&( ! feof(Handle)))
  596. readok=ferror(Handle);
  597. #else
  598. readok=ReadFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL);
  599. #endif
  600. if (! readok) {
  601. size -= bytesread;
  602. total += bytesread;
  603. Error(GetLastError(), true, Filename);
  604. continue;
  605. }
  606. size -= bytesread;
  607. total += bytesread;
  608. if (bytesread == 0) break;
  609. }
  610. bytesread = total;
  611. /*
  612. ** Close the file if it was opened by this routine and return
  613. ** the actual number of bytes read into the buffer.
  614. */
  615. if (opened) Close();
  616. return(bytesread);
  617. }
  618. /***********************************************************************************************
  619. * RawFileClass::Write -- Writes the specified data to the buffer specified. *
  620. * *
  621. * This routine will write the data specified to the file. *
  622. * *
  623. * INPUT: buffer -- The buffer that holds the data to write. *
  624. * *
  625. * size -- The number of bytes to write to the file. *
  626. * *
  627. * OUTPUT: Returns with the number of bytes written to the file. This routine catches the *
  628. * case of a disk full condition, so this routine will always return with the number *
  629. * matching the size request. *
  630. * *
  631. * WARNINGS: A fatal file condition could cause this routine to never return. *
  632. * *
  633. * HISTORY: *
  634. * 10/18/1994 JLB : Created. *
  635. *=============================================================================================*/
  636. int RawFileClass::Write(void const * buffer, int size)
  637. {
  638. long byteswritten = 0;
  639. int opened = false; // Was the file manually opened?
  640. /*
  641. ** Check to open status of the file. If the file is open, then merely write to
  642. ** it. Otherwise, open the file for writing and then close the file when the
  643. ** output is finished.
  644. */
  645. if (!Is_Open()) {
  646. if (!Open(WRITE)) {
  647. return(0);
  648. }
  649. opened = true;
  650. }
  651. int writeok=TRUE;
  652. #ifdef _UNIX
  653. byteswritten = fwrite(buffer, 1, size, Handle);
  654. if (byteswritten != size)
  655. writeok = FALSE;
  656. #else
  657. writeok=WriteFile(Handle, buffer, size, &(unsigned long&)byteswritten, NULL);
  658. #endif
  659. if (! writeok) {
  660. Error(GetLastError(), false, Filename);
  661. }
  662. /*
  663. ** Fixup the bias length if necessary.
  664. */
  665. if (BiasLength != -1) {
  666. if (Raw_Seek(0) > BiasStart+BiasLength) {
  667. BiasLength = Raw_Seek(0) - BiasStart;
  668. }
  669. }
  670. /*
  671. ** If this routine had to open the file, then close it before returning.
  672. */
  673. if (opened) {
  674. Close();
  675. }
  676. /*
  677. ** Return with the number of bytes written. This will always be the number of bytes
  678. ** requested, since the case of the disk being full is caught by this routine.
  679. */
  680. return(byteswritten);
  681. }
  682. /***********************************************************************************************
  683. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  684. * *
  685. * Use this routine to move the filepointer to the position indicated. It can move either *
  686. * relative to current position or absolute from the beginning or ending of the file. This *
  687. * routine will only return if it successfully performed the seek. *
  688. * *
  689. * INPUT: pos -- The position to seek to. This is interpreted as relative to the position *
  690. * indicated by the "dir" parameter. *
  691. * *
  692. * dir -- The relative position to relate the seek to. This can be either SEEK_SET *
  693. * for the beginning of the file, SEEK_CUR for the current position, or *
  694. * SEEK_END for the end of the file. *
  695. * *
  696. * OUTPUT: This routine returns the position that the seek ended up at. *
  697. * *
  698. * WARNINGS: If there was a file error, then this routine might never return. *
  699. * *
  700. * HISTORY: *
  701. * 10/18/1994 JLB : Created. *
  702. *=============================================================================================*/
  703. int RawFileClass::Seek(int pos, int dir)
  704. {
  705. /*
  706. ** A file that is biased will have a seek operation modified so that the file appears to
  707. ** exist only within the bias range. All bytes outside of this range appear to be
  708. ** non-existant.
  709. */
  710. if (BiasLength != -1) {
  711. switch (dir) {
  712. case SEEK_SET:
  713. if (pos > BiasLength) {
  714. pos = BiasLength;
  715. }
  716. pos += BiasStart;
  717. break;
  718. case SEEK_CUR:
  719. break;
  720. case SEEK_END:
  721. dir = SEEK_SET;
  722. pos += BiasStart + BiasLength;
  723. // pos = (pos <= BiasStart+BiasLength) ? pos : BiasStart+BiasLength;
  724. // pos = (pos >= BiasStart) ? pos : BiasStart;
  725. break;
  726. }
  727. /*
  728. ** Perform the modified raw seek into the file.
  729. */
  730. long newpos = Raw_Seek(pos, dir) - BiasStart;
  731. /*
  732. ** Perform a final double check to make sure the file position fits with the bias range.
  733. */
  734. if (newpos < 0) {
  735. newpos = Raw_Seek(BiasStart, SEEK_SET) - BiasStart;
  736. }
  737. if (newpos > BiasLength) {
  738. newpos = Raw_Seek(BiasStart+BiasLength, SEEK_SET) - BiasStart;
  739. }
  740. return(newpos);
  741. }
  742. /*
  743. ** If the file is not biased in any fashion, then the normal seek logic will
  744. ** work just fine.
  745. */
  746. return(Raw_Seek(pos, dir));
  747. }
  748. /***********************************************************************************************
  749. * RawFileClass::Size -- Determines size of file (in bytes). *
  750. * *
  751. * Use this routine to determine the size of the file. The file must exist or this is an *
  752. * error condition. *
  753. * *
  754. * INPUT: none *
  755. * *
  756. * OUTPUT: Returns with the number of bytes in the file. *
  757. * *
  758. * WARNINGS: This routine handles error conditions and will not return unless the file *
  759. * exists and can successfully be queried for file length. *
  760. * *
  761. * HISTORY: *
  762. * 10/18/1994 JLB : Created. *
  763. *=============================================================================================*/
  764. int RawFileClass::Size(void)
  765. {
  766. int size = 0;
  767. /*
  768. ** A biased file already has its length determined.
  769. */
  770. if (BiasLength != -1) {
  771. return(BiasLength);
  772. }
  773. /*
  774. ** If the file is open, then proceed normally.
  775. */
  776. if (Is_Open()) {
  777. #ifdef _UNIX
  778. fpos_t curpos,startpos,endpos;
  779. fgetpos(Handle,&curpos);
  780. fseek(Handle,0,SEEK_SET);
  781. fgetpos(Handle,&startpos);
  782. fseek(Handle,0,SEEK_END);
  783. fgetpos(Handle,&endpos);
  784. size=endpos-startpos;
  785. fsetpos(Handle,&curpos);
  786. #else
  787. size = GetFileSize(Handle, NULL);
  788. #endif
  789. /*
  790. ** If there was in internal error, then call the error function.
  791. */
  792. if (size == 0xFFFFFFFF) {
  793. Error(GetLastError(), false, Filename);
  794. }
  795. } else {
  796. /*
  797. ** If the file wasn't open, then open the file and call this routine again. Count on
  798. ** the fact that the open function must succeed.
  799. */
  800. if (Open()) {
  801. size = Size();
  802. /*
  803. ** Since we needed to open the file we must remember to close the file when the
  804. ** size has been determined.
  805. */
  806. Close();
  807. }
  808. }
  809. BiasLength = size-BiasStart;
  810. return(BiasLength);
  811. }
  812. /***********************************************************************************************
  813. * RawFileClass::Create -- Creates an empty file. *
  814. * *
  815. * This routine will create an empty file from the file object. The file object's filename *
  816. * must already have been assigned before this routine will function. *
  817. * *
  818. * INPUT: none *
  819. * *
  820. * OUTPUT: bool; Was the file successfully created? This routine will always return true. *
  821. * *
  822. * WARNINGS: A fatal error condition could occur with this routine. Especially if the disk *
  823. * is full or a read-only media was selected. *
  824. * *
  825. * HISTORY: *
  826. * 10/18/1994 JLB : Created. *
  827. *=============================================================================================*/
  828. int RawFileClass::Create(void)
  829. {
  830. Close();
  831. if (Open(WRITE)) {
  832. /*
  833. ** A biased file must be at least as long as the bias offset. Seeking to the
  834. ** appropriate start offset has the effect of lengthening the file to the
  835. ** correct length.
  836. */
  837. if (BiasLength != -1) {
  838. Seek(0, SEEK_SET);
  839. }
  840. Close();
  841. return(true);
  842. }
  843. return(false);
  844. }
  845. /***********************************************************************************************
  846. * RawFileClass::Delete -- Deletes the file object from the disk. *
  847. * *
  848. * This routine will delete the file object from the disk. If the file object doesn't *
  849. * exist, then this routine will return as if it had succeeded (since the effect is the *
  850. * same). *
  851. * *
  852. * INPUT: none *
  853. * *
  854. * OUTPUT: bool; Was the file deleted? If the file was already missing, the this value will *
  855. * be false. *
  856. * *
  857. * WARNINGS: none *
  858. * *
  859. * HISTORY: *
  860. * 10/18/1994 JLB : Created. *
  861. *=============================================================================================*/
  862. int RawFileClass::Delete(void)
  863. {
  864. /*
  865. ** If the file was open, then it must be closed first.
  866. */
  867. Close();
  868. /*
  869. ** If there is no filename associated with this object, then this indicates a fatal error
  870. ** condition. Report this and abort.
  871. */
  872. if (!Filename) {
  873. Error(ENOENT, false);
  874. }
  875. /*
  876. ** Repetitively try to delete the file if possible. Either return with success, or
  877. ** abort the program with an error.
  878. */
  879. for (;;) {
  880. /*
  881. ** If the file is already missing, then return with this fact. No action is necessary.
  882. ** This can occur as this section loops if the file exists on a floppy and the floppy
  883. ** was removed, the file deleted on another machine, and then the floppy was
  884. ** reinserted. Admittedly, this is a rare case, but is handled here.
  885. */
  886. if (!Is_Available()) {
  887. return(false);
  888. }
  889. int deleteok;
  890. #ifdef _UNIX
  891. deleteok=(unlink(Filename)==0)?TRUE:FALSE;
  892. #else
  893. deleteok=DeleteFile(Filename);
  894. #endif
  895. if (! deleteok) {
  896. Error(GetLastError(), false, Filename);
  897. return(false);
  898. }
  899. break;
  900. }
  901. /*
  902. ** DOS reports that the file was successfully deleted. Return with this fact.
  903. */
  904. return(true);
  905. }
  906. /***********************************************************************************************
  907. * RawFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
  908. * *
  909. * Use this routine to get the date and time of the file. *
  910. * *
  911. * INPUT: none *
  912. * *
  913. * OUTPUT: Returns with the file date and time as a long. *
  914. * Use the YEAR(long), MONTH(),.... *
  915. * *
  916. * WARNINGS: none *
  917. * *
  918. * HISTORY: *
  919. * 11/14/1995 DRD : Created. *
  920. * 07/13/1996 JLB : Handles win32 method. *
  921. *=============================================================================================*/
  922. unsigned long RawFileClass::Get_Date_Time(void)
  923. {
  924. #ifdef _UNIX
  925. struct stat statbuf;
  926. lstat(Filename, &statbuf);
  927. return(statbuf.st_mtime);
  928. #else
  929. BY_HANDLE_FILE_INFORMATION info;
  930. if (GetFileInformationByHandle(Handle, &info)) {
  931. WORD dosdate;
  932. WORD dostime;
  933. FileTimeToDosDateTime(&info.ftLastWriteTime, &dosdate, &dostime);
  934. return((dosdate << 16) | dostime);
  935. }
  936. return(0);
  937. #endif
  938. }
  939. /***********************************************************************************************
  940. * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
  941. * *
  942. * Use this routine to set the date and time of the file. *
  943. * *
  944. * INPUT: the file date and time as a long *
  945. * *
  946. * OUTPUT: successful or not if the file date and time was changed. *
  947. * *
  948. * WARNINGS: none *
  949. * *
  950. * HISTORY: *
  951. * 11/14/1995 DRD : Created. *
  952. * 07/13/1996 JLB : Handles win 32 method *
  953. *=============================================================================================*/
  954. bool RawFileClass::Set_Date_Time(unsigned long datetime)
  955. {
  956. #ifdef _UNIX
  957. assert(0);
  958. return(false);
  959. #else
  960. if (RawFileClass::Is_Open()) {
  961. BY_HANDLE_FILE_INFORMATION info;
  962. if (GetFileInformationByHandle(Handle, &info)) {
  963. FILETIME filetime;
  964. if (DosDateTimeToFileTime((WORD)(datetime >> 16), (WORD)(datetime & 0x0FFFF), &filetime)) {
  965. return(SetFileTime(Handle, &info.ftCreationTime, &filetime, &filetime) != 0);
  966. }
  967. }
  968. }
  969. return(false);
  970. #endif
  971. }
  972. /***********************************************************************************************
  973. * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
  974. * *
  975. * This will bias a file by giving it an artificial starting position and length. By *
  976. * using this routine, it is possible to 'fool' the file into ignoring a header and *
  977. * trailing extra data. An example of this would be a file inside of a mixfile. *
  978. * *
  979. * INPUT: start -- The starting offset that will now be considered the start of the *
  980. * file. *
  981. * *
  982. * length -- The forced length of the file. For files that are opened for write, *
  983. * this serves as the artificial constraint on the file's length. For *
  984. * files opened for read, this limits the usable file size. *
  985. * *
  986. * OUTPUT: none *
  987. * *
  988. * WARNINGS: none *
  989. * *
  990. * HISTORY: *
  991. * 06/02/1996 JLB : Created. *
  992. *=============================================================================================*/
  993. void RawFileClass::Bias(int start, int length)
  994. {
  995. if (start == 0) {
  996. BiasStart = 0;
  997. BiasLength = -1;
  998. return;
  999. }
  1000. BiasLength = RawFileClass::Size();
  1001. BiasStart += start;
  1002. if (length != -1) {
  1003. BiasLength = BiasLength < length ? BiasLength : length;
  1004. }
  1005. BiasLength = BiasLength > 0 ? BiasLength : 0;
  1006. /*
  1007. ** Move the current file offset to a legal position if necessary and the
  1008. ** file was open.
  1009. */
  1010. if (Is_Open()) {
  1011. RawFileClass::Seek(0, SEEK_SET);
  1012. }
  1013. }
  1014. /***********************************************************************************************
  1015. * RawFileClass::Raw_Seek -- Performs a seek on the unbiased file *
  1016. * *
  1017. * This will perform a seek on the file as if it were unbiased. This is in spite of any *
  1018. * bias setting the file may have. The ability to perform a raw seek in this fasion is *
  1019. * necessary to maintain the bias ability. *
  1020. * *
  1021. * INPUT: pos -- The position to seek the file relative to the "dir" parameter. *
  1022. * *
  1023. * dir -- The origin of the seek operation. *
  1024. * *
  1025. * OUTPUT: Returns with the new position of the seek operation. *
  1026. * *
  1027. * WARNINGS: none *
  1028. * *
  1029. * HISTORY: *
  1030. * 08/04/1996 JLB : Created. *
  1031. *=============================================================================================*/
  1032. int RawFileClass::Raw_Seek(int pos, int dir)
  1033. {
  1034. /*
  1035. ** If the file isn't opened, then this is a fatal error condition.
  1036. */
  1037. if (!Is_Open()) {
  1038. Error(EBADF, false, Filename);
  1039. }
  1040. #ifdef _UNIX
  1041. pos=fseek(Handle, pos, dir);
  1042. #else
  1043. switch (dir) {
  1044. case SEEK_SET:
  1045. dir = FILE_BEGIN;
  1046. break;
  1047. case SEEK_CUR:
  1048. dir = FILE_CURRENT;
  1049. break;
  1050. case SEEK_END:
  1051. dir = FILE_END;
  1052. break;
  1053. }
  1054. pos = SetFilePointer(Handle, pos, NULL, dir);
  1055. #endif
  1056. /*
  1057. ** If there was an error in the seek, then bail with an error condition.
  1058. */
  1059. if (pos == 0xFFFFFFFF) {
  1060. Error(GetLastError(), false, Filename);
  1061. }
  1062. /*
  1063. ** Return with the new position of the file. This will range between zero and the number of
  1064. ** bytes the file contains.
  1065. */
  1066. return(pos);
  1067. }
  1068. /***********************************************************************************************
  1069. * RawFileClass::Attach -- Provides a file handle for the class to use.
  1070. * *
  1071. * INPUT: handle -- the Win32 file handle.
  1072. * *
  1073. * OUTPUT:
  1074. * *
  1075. * WARNINGS: none *
  1076. * *
  1077. * HISTORY: *
  1078. * 06/10/1999 PDS : Created. *
  1079. *=============================================================================================*/
  1080. void RawFileClass::Attach (void *handle, int rights)
  1081. {
  1082. Reset ();
  1083. Rights = rights;
  1084. BiasStart = 0;
  1085. BiasLength = -1;
  1086. Date = 0;
  1087. Time = 0;
  1088. #ifdef _UNIX
  1089. Handle = (FILE *)handle;
  1090. #else
  1091. Handle = handle;
  1092. #endif
  1093. }
  1094. /***********************************************************************************************
  1095. * RawFileClass::Detach -- Removes the file handle from the object without closing the handle.
  1096. * *
  1097. * INPUT
  1098. * *
  1099. * OUTPUT:
  1100. * *
  1101. * WARNINGS: none *
  1102. * *
  1103. * HISTORY: *
  1104. * 06/10/1999 PDS : Created. *
  1105. *=============================================================================================*/
  1106. void RawFileClass::Detach (void)
  1107. {
  1108. Rights = 0;
  1109. BiasStart = 0;
  1110. BiasLength = -1;
  1111. Date = 0;
  1112. Time = 0;
  1113. Handle = NULL_HANDLE;
  1114. }