RAWFILE.CPP 54 KB

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