RAWFILE.CPP 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /CounterStrike/RAWFILE.CPP 1 3/03/97 10:25a Joe_bostic $ */
  15. /***********************************************************************************************
  16. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Westwood Library *
  20. * *
  21. * File Name : RAWFILE.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : August 8, 1994 *
  26. * *
  27. * Last Update : August 4, 1996 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
  32. * RawFileClass::Close -- Perform a closure of the file. *
  33. * RawFileClass::Create -- Creates an empty file. *
  34. * RawFileClass::Delete -- Deletes the file object from the disk. *
  35. * RawFileClass::Error -- Handles displaying a file error message. *
  36. * RawFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
  37. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  38. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  39. * RawFileClass::Open -- Opens the file object with the rights specified. *
  40. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  41. * RawFileClass::Raw_Seek -- Performs a seek on the unbiased file *
  42. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  43. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  44. * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
  45. * RawFileClass::Set_Name -- Manually sets the name for a file object. *
  46. * RawFileClass::Size -- Determines size of file (in bytes). *
  47. * RawFileClass::Write -- Writes the specified data to the buffer specified. *
  48. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  49. #include <stdlib.h>
  50. #include <stdio.h>
  51. #include <string.h>
  52. #include <direct.h>
  53. #include <share.h>
  54. #include <stddef.h>
  55. #include "rawfile.h"
  56. #ifndef WIN32
  57. #include <fcntl.h>
  58. #include <io.h>
  59. #include <dos.h>
  60. extern short Hard_Error_Occured;
  61. #endif
  62. /***********************************************************************************************
  63. * RawFileClass::Error -- Handles displaying a file error message. *
  64. * *
  65. * Display an error message as indicated. If it is allowed to retry, then pressing a key *
  66. * will return from this function. Otherwise, it will exit the program with "exit()". *
  67. * *
  68. * INPUT: error -- The error number (same as the DOSERR.H error numbers). *
  69. * *
  70. * canretry -- Can this routine exit normally so that retrying can occur? If this is *
  71. * false, then the program WILL exit in this routine. *
  72. * *
  73. * filename -- Optional filename to report with this error. If no filename is *
  74. * supplied, then no filename is listed in the error message. *
  75. * *
  76. * OUTPUT: none, but this routine might not return at all if the "canretry" parameter is *
  77. * false or the player pressed ESC. *
  78. * *
  79. * WARNINGS: This routine may not return at all. It handles being in text mode as well as *
  80. * if in a graphic mode. *
  81. * *
  82. * HISTORY: *
  83. * 10/17/1994 JLB : Created. *
  84. *=============================================================================================*/
  85. void RawFileClass::Error(int , int , char const * )
  86. {
  87. }
  88. /***********************************************************************************************
  89. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  90. * *
  91. * This constructor is called when a file object is created with a supplied filename, but *
  92. * not opened at the same time. In this case, an assumption is made that the supplied *
  93. * filename is a constant string. A duplicate of the filename string is not created since *
  94. * it would be wasteful in that case. *
  95. * *
  96. * INPUT: filename -- The filename to assign to this file object. *
  97. * *
  98. * OUTPUT: none *
  99. * *
  100. * WARNINGS: none *
  101. * *
  102. * HISTORY: *
  103. * 10/17/1994 JLB : Created. *
  104. *=============================================================================================*/
  105. RawFileClass::RawFileClass(char const * filename) :
  106. Rights(0),
  107. BiasStart(0),
  108. BiasLength(-1),
  109. Handle(NULL_HANDLE),
  110. Filename(filename),
  111. Date(0),
  112. Time(0),
  113. Allocated(false)
  114. {
  115. }
  116. /***********************************************************************************************
  117. * RawFileClass::Set_Name -- Manually sets the name for a file object. *
  118. * *
  119. * This routine will set the name for the file object to the name specified. This name is *
  120. * duplicated in free store. This allows the supplied name to be a temporarily constructed *
  121. * text string. Setting the name in this fashion doesn't affect the closed or opened state *
  122. * of the file. *
  123. * *
  124. * INPUT: filename -- The filename to assign to this file object. *
  125. * *
  126. * OUTPUT: Returns with a pointer to the allocated copy of this filename. This pointer is *
  127. * guaranteed to remain valid for the duration of this file object or until the name *
  128. * is changed -- whichever is sooner. *
  129. * *
  130. * WARNINGS: Because of the allocation this routine must perform, memory could become *
  131. * fragmented. *
  132. * *
  133. * HISTORY: *
  134. * 10/17/1994 JLB : Created. *
  135. *=============================================================================================*/
  136. #pragma warning(disable:4996)
  137. char const * RawFileClass::Set_Name(char const * filename)
  138. {
  139. if (Filename != NULL && Allocated) {
  140. free((char *)Filename);
  141. ((char *&)Filename) = 0;
  142. Allocated = false;
  143. }
  144. if (filename == NULL) return(NULL);
  145. Bias(0);
  146. Filename = strdup(filename);
  147. if (Filename == NULL) {
  148. Error(ENOMEM, false, filename);
  149. }
  150. Allocated = true;
  151. return(Filename);
  152. }
  153. /***********************************************************************************************
  154. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  155. * *
  156. * This routine will assign the specified filename to the file object and open it at the *
  157. * same time. If the file object was already open, then it will be closed first. If the *
  158. * file object was previously assigned a filename, then it will be replaced with the new *
  159. * name. Typically, this routine is used when an anonymous file object has been crated and *
  160. * now it needs to be assigned a name and opened. *
  161. * *
  162. * INPUT: filename -- The filename to assign to this file object. *
  163. * *
  164. * rights -- The open file access rights to use. *
  165. * *
  166. * OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
  167. * is designed to never return unless it succeeded. *
  168. * *
  169. * WARNINGS: none *
  170. * *
  171. * HISTORY: *
  172. * 10/17/1994 JLB : Created. *
  173. *=============================================================================================*/
  174. int RawFileClass::Open(char const * filename, int rights)
  175. {
  176. Set_Name(filename);
  177. return(Open(rights));
  178. }
  179. /***********************************************************************************************
  180. * RawFileClass::Open -- Opens the file object with the rights specified. *
  181. * *
  182. * This routine is used to open the specified file object with the access rights indicated. *
  183. * This only works if the file has already been assigned a filename. It is guaranteed, by *
  184. * the error handler, that this routine will always return with success. *
  185. * *
  186. * INPUT: rights -- The file access rights to use when opening this file. This is a *
  187. * combination of READ and/or WRITE bit flags. *
  188. * *
  189. * OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
  190. * the error handler. *
  191. * *
  192. * WARNINGS: none *
  193. * *
  194. * HISTORY: *
  195. * 10/17/1994 JLB : Created. *
  196. *=============================================================================================*/
  197. int RawFileClass::Open(int rights)
  198. {
  199. Close();
  200. /*
  201. ** Verify that there is a filename associated with this file object. If not, then this is a
  202. ** big error condition.
  203. */
  204. if (Filename == NULL) {
  205. Error(ENOENT, false);
  206. }
  207. /*
  208. ** Record the access rights used for this open call. These rights will be used if the
  209. ** file object is duplicated.
  210. */
  211. Rights = rights;
  212. /*
  213. ** Repetitively try to open the file. Abort if a fatal error condition occurs.
  214. */
  215. for (;;) {
  216. /*
  217. ** Try to open the file according to the access rights specified.
  218. */
  219. #ifndef WIN32
  220. Hard_Error_Occured = 0;
  221. #endif
  222. switch (rights) {
  223. /*
  224. ** If the access rights are not recognized, then report this as
  225. ** an invalid access code.
  226. */
  227. default:
  228. errno = EINVAL;
  229. break;
  230. case READ:
  231. #ifdef WIN32
  232. Handle = CreateFile(Filename, GENERIC_READ, FILE_SHARE_READ,
  233. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  234. #else
  235. _dos_open(Filename, O_RDONLY|SH_DENYNO, &Handle);
  236. #endif
  237. break;
  238. case WRITE:
  239. #ifdef WIN32
  240. Handle = CreateFile(Filename, GENERIC_WRITE, 0,
  241. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  242. #else
  243. _dos_creat(Filename, 0, &Handle);
  244. #endif
  245. break;
  246. case READ|WRITE:
  247. #ifdef WIN32
  248. Handle = CreateFile(Filename, GENERIC_READ | GENERIC_WRITE, 0,
  249. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  250. #else
  251. _dos_open(Filename, O_RDWR|O_CREAT|SH_DENYWR, &Handle);
  252. #endif
  253. break;
  254. }
  255. /*
  256. ** Biased files must be positioned past the bias start position.
  257. */
  258. if (BiasStart != 0 || BiasLength != -1) {
  259. Seek(0, SEEK_SET);
  260. }
  261. /*
  262. ** If the handle indicates the file is not open, then this is an error condition.
  263. ** For the case of the file cannot be found, then allow a retry. All other cases
  264. ** are fatal.
  265. */
  266. if (Handle == NULL_HANDLE) {
  267. #ifdef WIN32
  268. // return(false);
  269. Error(GetLastError(), false, Filename);
  270. // continue;
  271. #else
  272. /*
  273. ** If this flag is set, then some hard error occurred. Just assume that the error
  274. ** is probably a removed CD-ROM and allow a retry.
  275. */
  276. if (Hard_Error_Occured) {
  277. Error(Hard_Error_Occured, true, Filename);
  278. } else {
  279. if (errno == ENOENT) {
  280. Error(ENOENT, true, Filename);
  281. } else {
  282. Error(errno, false, Filename);
  283. }
  284. }
  285. continue;
  286. #endif
  287. }
  288. break;
  289. }
  290. return(true);
  291. }
  292. /***********************************************************************************************
  293. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  294. * *
  295. * This routine will examine the disk system to see if the specified file can be opened *
  296. * or not. Use this routine before opening a file in order to make sure that is available *
  297. * or to perform other necessary actions. *
  298. * *
  299. * INPUT: force -- Should this routine keep retrying until the file becomes available? If *
  300. * in this case it doesn't become available, then the program will abort. *
  301. * *
  302. * OUTPUT: bool; Is the file available to be opened? *
  303. * *
  304. * WARNINGS: Depending on the parameter passed in, this routine may never return. *
  305. * *
  306. * HISTORY: *
  307. * 10/18/1994 JLB : Created. *
  308. *=============================================================================================*/
  309. int RawFileClass::Is_Available(int forced)
  310. {
  311. #ifndef WIN32
  312. bool open_failed;
  313. #endif
  314. if (Filename == NULL) return(false);
  315. /*
  316. ** If the file is already open, then is must have already passed the availability check.
  317. ** Return true in this case.
  318. */
  319. if (Is_Open()) return(true);
  320. /*
  321. ** If this is a forced check, then go through the normal open channels, since those
  322. ** channels ensure that the file must exist.
  323. */
  324. if (forced) {
  325. RawFileClass::Open(READ);
  326. RawFileClass::Close();
  327. return(true);
  328. }
  329. /*
  330. ** Perform a raw open of the file. If this open fails for ANY REASON, including a missing
  331. ** CD-ROM, this routine will return a failure condition. In all but the missing file
  332. ** condition, go through the normal error recover channels.
  333. */
  334. for (;;) {
  335. #ifdef WIN32
  336. Handle = CreateFile(Filename, GENERIC_READ, FILE_SHARE_READ,
  337. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  338. if (Handle == NULL_HANDLE) {
  339. return(false);
  340. }
  341. break;
  342. #else
  343. Hard_Error_Occured = 0;
  344. open_failed = _dos_open(Filename, O_RDONLY|SH_DENYNO, &Handle);
  345. /*
  346. ** If DOS reports that everything is just fine except that the file is not present,
  347. ** then return with this fact. Any other case will fall through to the error handler
  348. ** routine.
  349. */
  350. if (open_failed && errno == ENOENT) return(false);
  351. /*
  352. ** If we got an access error it could be because there is no cd in
  353. ** the drive. Call the error handler but allow a continue if it
  354. ** returns.
  355. */
  356. if (open_failed && errno == EACCES) {
  357. Error(errno, true, Filename);
  358. continue;
  359. }
  360. /*
  361. ** If the file could not be found, then return with this information. If a more
  362. ** serious error occurred, then display the error message and abort.
  363. */
  364. if (Hard_Error_Occured) {
  365. Error(Hard_Error_Occured, true, Filename);
  366. continue;
  367. } else {
  368. if (open_failed) {
  369. /*
  370. ** An unhandled error condition is fatal. Display the error message and then
  371. ** abort.
  372. */
  373. Error(errno, false, Filename);
  374. }
  375. }
  376. if (!open_failed) break;
  377. #endif
  378. }
  379. /*
  380. ** Since the file could be opened, then close it and return that the file exists.
  381. */
  382. #ifdef WIN32
  383. if (!CloseHandle(Handle)) {
  384. Error(GetLastError(), false, Filename);
  385. }
  386. #else
  387. if (_dos_close(Handle)) {
  388. Error(errno, false, Filename);
  389. }
  390. #endif
  391. Handle = NULL_HANDLE;
  392. return(true);
  393. }
  394. /***********************************************************************************************
  395. * RawFileClass::Close -- Perform a closure of the file. *
  396. * *
  397. * Close the file object. In the rare case of an error, handle it as appropriate. *
  398. * *
  399. * INPUT: none *
  400. * *
  401. * OUTPUT: none *
  402. * *
  403. * WARNINGS: Some rare error conditions may cause this routine to abort the program. *
  404. * *
  405. * HISTORY: *
  406. * 10/18/1994 JLB : Created. *
  407. *=============================================================================================*/
  408. void RawFileClass::Close(void)
  409. {
  410. /*
  411. ** If the file is open, then close it. If the file is already closed, then just return. This
  412. ** isn't considered an error condition.
  413. */
  414. if (Is_Open()) {
  415. #ifdef WIN32
  416. /*
  417. ** Try to close the file. If there was an error (who knows what that could be), then
  418. ** call the error routine.
  419. */
  420. if (!CloseHandle(Handle)) {
  421. Error(GetLastError(), false, Filename);
  422. }
  423. #else
  424. for (;;) {
  425. /*
  426. ** Close the file. If there was an error in the close operation -- abort.
  427. */
  428. Hard_Error_Occured = 0;
  429. if (_dos_close(Handle)) {
  430. /*
  431. ** By definition, this error can only be a bad file handle. This a fatal condition
  432. ** of course, so abort with an error message.
  433. */
  434. Error(errno, false, Filename);
  435. }
  436. /*
  437. ** In the condition (if it is even possible) of a hard error occurring, then
  438. ** assume it is the case of missing media. Display an error message and try
  439. ** again if indicated.
  440. */
  441. if (Hard_Error_Occured) {
  442. Error(Hard_Error_Occured, true, Filename);
  443. continue;
  444. }
  445. break;
  446. }
  447. #endif
  448. /*
  449. ** At this point the file must have been closed. Mark the file as empty and return.
  450. */
  451. Handle = NULL_HANDLE;
  452. }
  453. }
  454. /***********************************************************************************************
  455. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  456. * *
  457. * This routine will read the specified number of bytes and place the data into the buffer *
  458. * indicated. It is legal to call this routine with a request for more bytes than are in *
  459. * the file. This condition can result in fewer bytes being read than requested. Determine *
  460. * this by examining the return value. *
  461. * *
  462. * INPUT: buffer -- Pointer to the buffer to read data into. If NULL is passed, no read *
  463. * is performed. *
  464. * *
  465. * size -- The number of bytes to read. If NULL is passed, then no read is *
  466. * performed. *
  467. * *
  468. * OUTPUT: Returns with the number of bytes read into the buffer. If this number is less *
  469. * than requested, it indicates that the file has been exhausted. *
  470. * *
  471. * WARNINGS: none *
  472. * *
  473. * HISTORY: *
  474. * 10/18/1994 JLB : Created. *
  475. *=============================================================================================*/
  476. long RawFileClass::Read(void * buffer, long size)
  477. {
  478. long bytesread = 0; // Running count of the number of bytes read into the buffer.
  479. int opened = false; // Was the file opened by this routine?
  480. /*
  481. ** If the file isn't opened, open it. This serves as a convenience
  482. ** for the programmer.
  483. */
  484. if (!Is_Open()) {
  485. /*
  486. ** The error check here is moot. Open will never return unless it succeeded.
  487. */
  488. if (!Open(READ)) {
  489. return(0);
  490. }
  491. opened = true;
  492. }
  493. /*
  494. ** A biased file has the requested read length limited to the bias length of
  495. ** the file.
  496. */
  497. if (BiasLength != -1) {
  498. int remainder = BiasLength - Seek(0);
  499. size = size < remainder ? size : remainder;
  500. }
  501. #ifdef WIN32
  502. long total = 0;
  503. while (size > 0) {
  504. bytesread = 0;
  505. SetErrorMode(SEM_FAILCRITICALERRORS);
  506. if (!ReadFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL)) {
  507. size -= bytesread;
  508. total += bytesread;
  509. Error(GetLastError(), true, Filename);
  510. SetErrorMode(0);
  511. continue;
  512. }
  513. SetErrorMode(0);
  514. size -= bytesread;
  515. total += bytesread;
  516. if (bytesread == 0) break;
  517. }
  518. bytesread = total;
  519. #else
  520. int readresult;
  521. /*
  522. ** Read the file in convenient chunk sizes. When the actual number
  523. ** of bytes read does not match the desired, then assume that the file
  524. ** is exhausted and bail. This loop was adjusted to take into
  525. ** consideration the fact that "read" returns a SIGNED value whereas
  526. ** it takes an UNSIGNED value as the byte count.
  527. */
  528. while (size) {
  529. unsigned desired; // Bytes desired to be read this pass.
  530. unsigned actual; // Actual number of bytes read.
  531. /*
  532. ** Break the read request into chunks no bigger than the low level DOS read
  533. ** can handle.
  534. */
  535. desired = size < 32000L ? size : 32000L;
  536. Hard_Error_Occured = 0;
  537. readresult = _dos_read(Handle, buffer, desired, &actual);
  538. /*
  539. ** If a hard error occurred, then assume that it is the case of the CD-ROM or
  540. ** floppy media having been removed. Display the error and retry as directed.
  541. */
  542. if (Hard_Error_Occured) {
  543. Error(Hard_Error_Occured, true, Filename);
  544. continue; // Not technically needed, but to be consistent...
  545. } else {
  546. /*
  547. ** If negative one is returned from the read operation, then this indicates
  548. ** either a bad file number or invalid access. These are fatal conditions, so
  549. ** display the error and then abort.
  550. */
  551. if (readresult != 0) {
  552. Error(errno, false, Filename);
  553. } else {
  554. /*
  555. ** No error occurred during the read. Adjust the pointers and size counters and
  556. ** loop again if more data is needed to be read.
  557. */
  558. buffer = (char *)buffer + actual;
  559. bytesread += actual;
  560. size -= actual;
  561. if (actual != desired) break; // No more data?
  562. }
  563. }
  564. }
  565. #endif //WIN32
  566. /*
  567. ** Close the file if it was opened by this routine and return
  568. ** the actual number of bytes read into the buffer.
  569. */
  570. if (opened) Close();
  571. return(bytesread);
  572. }
  573. /***********************************************************************************************
  574. * RawFileClass::Write -- Writes the specified data to the buffer specified. *
  575. * *
  576. * This routine will write the data specified to the file. *
  577. * *
  578. * INPUT: buffer -- The buffer that holds the data to write. *
  579. * *
  580. * size -- The number of bytes to write to the file. *
  581. * *
  582. * OUTPUT: Returns with the number of bytes written to the file. This routine catches the *
  583. * case of a disk full condition, so this routine will always return with the number *
  584. * matching the size request. *
  585. * *
  586. * WARNINGS: A fatal file condition could cause this routine to never return. *
  587. * *
  588. * HISTORY: *
  589. * 10/18/1994 JLB : Created. *
  590. *=============================================================================================*/
  591. long RawFileClass::Write(void const * buffer, long size)
  592. {
  593. long bytesread = 0;
  594. int opened = false; // Was the file manually opened?
  595. /*
  596. ** Check to open status of the file. If the file is open, then merely write to
  597. ** it. Otherwise, open the file for writing and then close the file when the
  598. ** output is finished.
  599. */
  600. if (!Is_Open()) {
  601. if (!Open(WRITE)) {
  602. return(0);
  603. }
  604. opened = true;
  605. }
  606. #ifdef WIN32
  607. if (!WriteFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL)) {
  608. Error(GetLastError(), false, Filename);
  609. }
  610. #else
  611. int writeresult;
  612. /*
  613. ** Write the data to the file in chunks no bigger than what the low level DOS write
  614. ** can handle.
  615. */
  616. while (size) {
  617. unsigned desired; // Bytes desired to be write this pass.
  618. unsigned actual; // Actual number of bytes written.
  619. Hard_Error_Occured = 0;
  620. // desired = (unsigned)MIN(size, Transfer_Block_Size());
  621. desired = size;
  622. writeresult = _dos_write(Handle, buffer, desired, &actual);
  623. /*
  624. ** If a hard error occurred, then assume it is the case of the media being
  625. ** removed. Print the error message an retry as directed.
  626. */
  627. if (Hard_Error_Occured) {
  628. Error(Hard_Error_Occured, true, Filename);
  629. continue; // Not technically needed, but to be consistent...
  630. } else {
  631. /*
  632. ** If negative one is returned by the DOS read, then this indicates a bad file
  633. ** handle or invalid access. Either condition is fatal -- display error condition
  634. ** and abort.
  635. */
  636. if (writeresult != 0) {
  637. Error(errno, false, Filename);
  638. } else {
  639. /*
  640. ** A successful write occurred. Update pointers and byte counter as appropriate.
  641. */
  642. buffer = (char *)buffer + actual;
  643. bytesread += actual;
  644. size -= actual;
  645. /*
  646. ** If the actual bytes written is less than requested, assume this is a case of
  647. ** the disk being full. Consider this a fatal error condition.
  648. */
  649. if (actual != desired) {
  650. Error(ENOSPC, false, Filename);
  651. }
  652. }
  653. }
  654. }
  655. #endif //WIN32
  656. /*
  657. ** Fixup the bias length if necessary.
  658. */
  659. if (BiasLength != -1) {
  660. if (Raw_Seek(0) > BiasStart+BiasLength) {
  661. BiasLength = Raw_Seek(0) - BiasStart;
  662. }
  663. }
  664. /*
  665. ** If this routine had to open the file, then close it before returning.
  666. */
  667. if (opened) {
  668. Close();
  669. }
  670. /*
  671. ** Return with the number of bytes written. This will always be the number of bytes
  672. ** requested, since the case of the disk being full is caught by this routine.
  673. */
  674. return(bytesread);
  675. }
  676. /***********************************************************************************************
  677. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  678. * *
  679. * Use this routine to move the filepointer to the position indicated. It can move either *
  680. * relative to current position or absolute from the beginning or ending of the file. This *
  681. * routine will only return if it successfully performed the seek. *
  682. * *
  683. * INPUT: pos -- The position to seek to. This is interpreted as relative to the position *
  684. * indicated by the "dir" parameter. *
  685. * *
  686. * dir -- The relative position to relate the seek to. This can be either SEEK_SET *
  687. * for the beginning of the file, SEEK_CUR for the current position, or *
  688. * SEEK_END for the end of the file. *
  689. * *
  690. * OUTPUT: This routine returns the position that the seek ended up at. *
  691. * *
  692. * WARNINGS: If there was a file error, then this routine might never return. *
  693. * *
  694. * HISTORY: *
  695. * 10/18/1994 JLB : Created. *
  696. *=============================================================================================*/
  697. long RawFileClass::Seek(long pos, int dir)
  698. {
  699. /*
  700. ** A file that is biased will have a seek operation modified so that the file appears to
  701. ** exist only within the bias range. All bytes outside of this range appear to be
  702. ** non-existant.
  703. */
  704. if (BiasLength != -1) {
  705. switch (dir) {
  706. case SEEK_SET:
  707. if (pos > BiasLength) {
  708. pos = BiasLength;
  709. }
  710. pos += BiasStart;
  711. break;
  712. case SEEK_CUR:
  713. break;
  714. case SEEK_END:
  715. dir = SEEK_SET;
  716. pos += BiasStart + BiasLength;
  717. // pos = (pos <= BiasStart+BiasLength) ? pos : BiasStart+BiasLength;
  718. // pos = (pos >= BiasStart) ? pos : BiasStart;
  719. break;
  720. }
  721. /*
  722. ** Perform the modified raw seek into the file.
  723. */
  724. long newpos = Raw_Seek(pos, dir) - BiasStart;
  725. /*
  726. ** Perform a final double check to make sure the file position fits with the bias range.
  727. */
  728. if (newpos < 0) {
  729. newpos = Raw_Seek(BiasStart, SEEK_SET) - BiasStart;
  730. }
  731. if (newpos > BiasLength) {
  732. newpos = Raw_Seek(BiasStart+BiasLength, SEEK_SET) - BiasStart;
  733. }
  734. return(newpos);
  735. }
  736. /*
  737. ** If the file is not biased in any fashion, then the normal seek logic will
  738. ** work just fine.
  739. */
  740. return(Raw_Seek(pos, dir));
  741. }
  742. /***********************************************************************************************
  743. * RawFileClass::Size -- Determines size of file (in bytes). *
  744. * *
  745. * Use this routine to determine the size of the file. The file must exist or this is an *
  746. * error condition. *
  747. * *
  748. * INPUT: none *
  749. * *
  750. * OUTPUT: Returns with the number of bytes in the file. *
  751. * *
  752. * WARNINGS: This routine handles error conditions and will not return unless the file *
  753. * exists and can successfully be queried for file length. *
  754. * *
  755. * HISTORY: *
  756. * 10/18/1994 JLB : Created. *
  757. *=============================================================================================*/
  758. long RawFileClass::Size(void)
  759. {
  760. long size = 0;
  761. /*
  762. ** A biased file already has its length determined.
  763. */
  764. if (BiasLength != -1) {
  765. return(BiasLength);
  766. }
  767. /*
  768. ** If the file is open, then proceed normally.
  769. */
  770. if (Is_Open()) {
  771. #ifdef WIN32
  772. size = GetFileSize(Handle, NULL);
  773. /*
  774. ** If there was in internal error, then call the error function.
  775. */
  776. if (size == 0xFFFFFFFF) {
  777. Error(GetLastError(), false, Filename);
  778. }
  779. #else
  780. /*
  781. ** Repetitively try to determine the file size until a fatal error condition or success
  782. ** is achieved.
  783. */
  784. for (;;) {
  785. Hard_Error_Occured = 0;
  786. size = filelength(Handle);
  787. /*
  788. ** If a hard error occurred, then assume it is the case of removed media. Display an
  789. ** error condition and allow retry.
  790. */
  791. if (Hard_Error_Occured) {
  792. Error(Hard_Error_Occured, true, Filename);
  793. continue;
  794. } else {
  795. if (size == -1) {
  796. Error(errno, false, Filename);
  797. }
  798. }
  799. break;
  800. }
  801. #endif
  802. } else {
  803. /*
  804. ** If the file wasn't open, then open the file and call this routine again. Count on
  805. ** the fact that the open function must succeed.
  806. */
  807. if (Open()) {
  808. size = Size();
  809. /*
  810. ** Since we needed to open the file we must remember to close the file when the
  811. ** size has been determined.
  812. */
  813. Close();
  814. }
  815. }
  816. BiasLength = size-BiasStart;
  817. return(BiasLength);
  818. }
  819. /***********************************************************************************************
  820. * RawFileClass::Create -- Creates an empty file. *
  821. * *
  822. * This routine will create an empty file from the file object. The file object's filename *
  823. * must already have been assigned before this routine will function. *
  824. * *
  825. * INPUT: none *
  826. * *
  827. * OUTPUT: bool; Was the file successfully created? This routine will always return true. *
  828. * *
  829. * WARNINGS: A fatal error condition could occur with this routine. Especially if the disk *
  830. * is full or a read-only media was selected. *
  831. * *
  832. * HISTORY: *
  833. * 10/18/1994 JLB : Created. *
  834. *=============================================================================================*/
  835. int RawFileClass::Create(void)
  836. {
  837. Close();
  838. if (Open(WRITE)) {
  839. /*
  840. ** A biased file must be at least as long as the bias offset. Seeking to the
  841. ** appropriate start offset has the effect of lengthening the file to the
  842. ** correct length.
  843. */
  844. if (BiasLength != -1) {
  845. Seek(0, SEEK_SET);
  846. }
  847. Close();
  848. return(true);
  849. }
  850. return(false);
  851. }
  852. /***********************************************************************************************
  853. * RawFileClass::Delete -- Deletes the file object from the disk. *
  854. * *
  855. * This routine will delete the file object from the disk. If the file object doesn't *
  856. * exist, then this routine will return as if it had succeeded (since the effect is the *
  857. * same). *
  858. * *
  859. * INPUT: none *
  860. * *
  861. * OUTPUT: bool; Was the file deleted? If the file was already missing, the this value will *
  862. * be false. *
  863. * *
  864. * WARNINGS: none *
  865. * *
  866. * HISTORY: *
  867. * 10/18/1994 JLB : Created. *
  868. *=============================================================================================*/
  869. int RawFileClass::Delete(void)
  870. {
  871. /*
  872. ** If the file was open, then it must be closed first.
  873. */
  874. Close();
  875. /*
  876. ** If there is no filename associated with this object, then this indicates a fatal error
  877. ** condition. Report this and abort.
  878. */
  879. if (!Filename) {
  880. Error(ENOENT, false);
  881. }
  882. /*
  883. ** Repetitively try to delete the file if possible. Either return with success, or
  884. ** abort the program with an error.
  885. */
  886. for (;;) {
  887. /*
  888. ** If the file is already missing, then return with this fact. No action is necessary.
  889. ** This can occur as this section loops if the file exists on a floppy and the floppy
  890. ** was removed, the file deleted on another machine, and then the floppy was
  891. ** reinserted. Admittedly, this is a rare case, but is handled here.
  892. */
  893. if (!Is_Available()) {
  894. return(false);
  895. }
  896. #ifdef WIN32
  897. if (!DeleteFile(Filename)) {
  898. Error(GetLastError(), false, Filename);
  899. return(false);
  900. }
  901. #else
  902. Hard_Error_Occured = 0;
  903. if (remove(Filename) == -1) {
  904. /*
  905. ** If a hard error occurred, then assume that the media has been removed. Display
  906. ** error message and retry as directed.
  907. */
  908. if (Hard_Error_Occured) {
  909. Error(Hard_Error_Occured, true, Filename);
  910. continue;
  911. }
  912. /*
  913. ** If at this point, DOS says the file doesn't exist, then just exit with this
  914. ** fact. It should have been caught earlier, but in any case, this is a legal
  915. ** condition.
  916. */
  917. if (errno == ENOENT) break;
  918. /*
  919. ** The only way it can reach this point is if DOS indicates that access is denied
  920. ** on the file. This occurs when trying to delete a file on a read-only media such
  921. ** as a CD-ROM. Report this as a fatal error and then abort.
  922. */
  923. Error(errno, false, Filename);
  924. }
  925. #endif
  926. break;
  927. }
  928. /*
  929. ** DOS reports that the file was successfully deleted. Return with this fact.
  930. */
  931. return(true);
  932. }
  933. /***********************************************************************************************
  934. * RawFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
  935. * *
  936. * Use this routine to get the date and time of the file. *
  937. * *
  938. * INPUT: none *
  939. * *
  940. * OUTPUT: Returns with the file date and time as a long. *
  941. * Use the YEAR(long), MONTH(),.... *
  942. * *
  943. * WARNINGS: none *
  944. * *
  945. * HISTORY: *
  946. * 11/14/1995 DRD : Created. *
  947. * 07/13/1996 JLB : Handles win32 method. *
  948. *=============================================================================================*/
  949. unsigned long RawFileClass::Get_Date_Time(void)
  950. {
  951. #ifdef WIN32
  952. BY_HANDLE_FILE_INFORMATION info;
  953. if (GetFileInformationByHandle(Handle, &info)) {
  954. WORD dosdate;
  955. WORD dostime;
  956. FileTimeToDosDateTime(&info.ftLastWriteTime, &dosdate, &dostime);
  957. return((dosdate << 16) | dostime);
  958. }
  959. return(0);
  960. #else
  961. unsigned short time;
  962. unsigned short date;
  963. unsigned long datetime = 0;
  964. //
  965. // If the file is open, then proceed normally.
  966. //
  967. if ( RawFileClass::Is_Open() ) {
  968. if ( _dos_getftime( Handle, &date, &time ) ) {
  969. //
  970. // return 0 indicating error with no date and time
  971. //
  972. return( datetime );
  973. }
  974. } else {
  975. //
  976. // If the file wasn't open, then see if the file exists.
  977. //
  978. if ( RawFileClass::Is_Available() ) {
  979. RawFileClass::Open();
  980. if ( _dos_getftime( Handle, &date, &time ) ) {
  981. RawFileClass::Close();
  982. //
  983. // return 0 indicating error with no date and time
  984. //
  985. return( datetime );
  986. }
  987. RawFileClass::Close();
  988. } else {
  989. //
  990. // return 0 indicating error with no date and time
  991. //
  992. return( datetime );
  993. }
  994. }
  995. //
  996. // combine the date and time as a long
  997. //
  998. datetime = (date << 16) + time;
  999. return( datetime );
  1000. #endif
  1001. }
  1002. /***********************************************************************************************
  1003. * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
  1004. * *
  1005. * Use this routine to set the date and time of the file. *
  1006. * *
  1007. * INPUT: the file date and time as a long *
  1008. * *
  1009. * OUTPUT: successful or not if the file date and time was changed. *
  1010. * *
  1011. * WARNINGS: none *
  1012. * *
  1013. * HISTORY: *
  1014. * 11/14/1995 DRD : Created. *
  1015. * 07/13/1996 JLB : Handles win 32 method *
  1016. *=============================================================================================*/
  1017. bool RawFileClass::Set_Date_Time(unsigned long datetime)
  1018. {
  1019. #ifdef WIN32
  1020. if (RawFileClass::Is_Open()) {
  1021. BY_HANDLE_FILE_INFORMATION info;
  1022. if (GetFileInformationByHandle(Handle, &info)) {
  1023. FILETIME filetime;
  1024. if (DosDateTimeToFileTime((WORD)(datetime >> 16), (WORD)(datetime & 0x0FFFF), &filetime)) {
  1025. return(SetFileTime(Handle, &info.ftCreationTime, &filetime, &filetime));
  1026. }
  1027. }
  1028. }
  1029. return(false);
  1030. #else
  1031. unsigned short time;
  1032. unsigned short date;
  1033. //
  1034. // If the file is open, then proceed normally.
  1035. //
  1036. if ( RawFileClass::Is_Open() ) {
  1037. //
  1038. // only set the date and time if open for READ only
  1039. //
  1040. if ( Rights == READ ) {
  1041. time = (unsigned short)(datetime & 0xFFFF);
  1042. date = (unsigned short)((datetime >> 16) & 0xFFFF);
  1043. if ( !_dos_setftime( Handle, date, time ) ) {
  1044. //
  1045. // return true indicating success
  1046. //
  1047. return( true );
  1048. }
  1049. }
  1050. } else {
  1051. //
  1052. // If the file wasn't open, then see if the file exists.
  1053. //
  1054. if ( RawFileClass::Is_Available() ) {
  1055. RawFileClass::Open();
  1056. time = (unsigned short)(datetime & 0xFFFF);
  1057. date = (unsigned short)((datetime >> 16) & 0xFFFF);
  1058. if ( !_dos_setftime( Handle, date, time ) ) {
  1059. RawFileClass::Close();
  1060. //
  1061. // return true indicating success
  1062. //
  1063. return( true );
  1064. }
  1065. RawFileClass::Close();
  1066. }
  1067. }
  1068. //
  1069. // return false indicating error
  1070. //
  1071. return( false );
  1072. #endif
  1073. }
  1074. /***********************************************************************************************
  1075. * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
  1076. * *
  1077. * This will bias a file by giving it an artificial starting position and length. By *
  1078. * using this routine, it is possible to 'fool' the file into ignoring a header and *
  1079. * trailing extra data. An example of this would be a file inside of a mixfile. *
  1080. * *
  1081. * INPUT: start -- The starting offset that will now be considered the start of the *
  1082. * file. *
  1083. * *
  1084. * length -- The forced length of the file. For files that are opened for write, *
  1085. * this serves as the artificial constraint on the file's length. For *
  1086. * files opened for read, this limits the usable file size. *
  1087. * *
  1088. * OUTPUT: none *
  1089. * *
  1090. * WARNINGS: none *
  1091. * *
  1092. * HISTORY: *
  1093. * 06/02/1996 JLB : Created. *
  1094. *=============================================================================================*/
  1095. void RawFileClass::Bias(int start, int length)
  1096. {
  1097. if (start == 0) {
  1098. BiasStart = 0;
  1099. BiasLength = -1;
  1100. return;
  1101. }
  1102. BiasLength = RawFileClass::Size();
  1103. BiasStart += start;
  1104. if (length != -1) {
  1105. BiasLength = BiasLength < length ? BiasLength : length;
  1106. }
  1107. BiasLength = BiasLength > 0 ? BiasLength : 0;
  1108. /*
  1109. ** Move the current file offset to a legal position if necessary and the
  1110. ** file was open.
  1111. */
  1112. if (Is_Open()) {
  1113. RawFileClass::Seek(0, SEEK_SET);
  1114. }
  1115. }
  1116. /***********************************************************************************************
  1117. * RawFileClass::Raw_Seek -- Performs a seek on the unbiased file *
  1118. * *
  1119. * This will perform a seek on the file as if it were unbiased. This is in spite of any *
  1120. * bias setting the file may have. The ability to perform a raw seek in this fasion is *
  1121. * necessary to maintain the bias ability. *
  1122. * *
  1123. * INPUT: pos -- The position to seek the file relative to the "dir" parameter. *
  1124. * *
  1125. * dir -- The origin of the seek operation. *
  1126. * *
  1127. * OUTPUT: Returns with the new position of the seek operation. *
  1128. * *
  1129. * WARNINGS: none *
  1130. * *
  1131. * HISTORY: *
  1132. * 08/04/1996 JLB : Created. *
  1133. *=============================================================================================*/
  1134. long RawFileClass::Raw_Seek(long pos, int dir)
  1135. {
  1136. /*
  1137. ** If the file isn't opened, then this is a fatal error condition.
  1138. */
  1139. if (!Is_Open()) {
  1140. Error(EBADF, false, Filename);
  1141. }
  1142. #ifdef WIN32
  1143. switch (dir) {
  1144. case SEEK_SET:
  1145. dir = FILE_BEGIN;
  1146. break;
  1147. case SEEK_CUR:
  1148. dir = FILE_CURRENT;
  1149. break;
  1150. case SEEK_END:
  1151. dir = FILE_END;
  1152. break;
  1153. }
  1154. pos = SetFilePointer(Handle, pos, NULL, dir);
  1155. /*
  1156. ** If there was an error in the seek, then bail with an error condition.
  1157. */
  1158. if (pos == 0xFFFFFFFF) {
  1159. Error(GetLastError(), false, Filename);
  1160. }
  1161. #else
  1162. /*
  1163. ** Keep trying to seek until a non-retry condition occurs.
  1164. */
  1165. for (;;) {
  1166. /*
  1167. ** Perform the low level seek on the file.
  1168. */
  1169. Hard_Error_Occured = 0;
  1170. pos = lseek(Handle, pos, dir);
  1171. /*
  1172. ** If a hard error occurred, then assume that it is the case of removed media. Display
  1173. ** error message and retry.
  1174. */
  1175. if (Hard_Error_Occured) {
  1176. Error(Hard_Error_Occured, true, Filename);
  1177. continue;
  1178. } else {
  1179. /*
  1180. ** A negative one indicates a fatal error with the seek operation. Display error
  1181. ** condition and then abort.
  1182. */
  1183. if (pos == -1) {
  1184. Error(errno, false, Filename);
  1185. }
  1186. }
  1187. break;
  1188. }
  1189. #endif
  1190. /*
  1191. ** Return with the new position of the file. This will range between zero and the number of
  1192. ** bytes the file contains.
  1193. */
  1194. return(pos);
  1195. }