rawfile.cpp 59 KB

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