RAWFILE.CPP 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /*
  2. ** Command & Conquer(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\rawfile.cpv 2.18 16 Oct 1995 16:50:54 JOE_BOSTIC $ */
  19. /***********************************************************************************************
  20. *** 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 ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Westwood Library *
  24. * *
  25. * File Name : RAWFILE.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : August 8, 1994 *
  30. * *
  31. * Last Update : October 18, 1994 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * RawFileClass::Close -- Perform a closure of the file. *
  36. * RawFileClass::Create -- Creates an empty file. *
  37. * RawFileClass::Delete -- Deletes the file object from the disk. *
  38. * RawFileClass::Error -- Handles displaying a file error message. *
  39. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  40. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  41. * RawFileClass::Open -- Opens the file object with the rights specified. *
  42. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  43. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  44. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  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 "function.h"
  50. #include <stdlib.h>
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <direct.h>
  54. #include <fcntl.h>
  55. #include <io.h>
  56. #include <dos.h>
  57. #include <share.h>
  58. #include "wwlib32.h"
  59. #include "compat.h"
  60. #include "rawfile.h"
  61. extern GraphicBufferClass SeenBuff;
  62. extern GraphicBufferClass HidPage;
  63. /***********************************************************************************************
  64. * RawFileClass::Error -- Handles displaying a file error message. *
  65. * *
  66. * Display an error message as indicated. If it is allowed to retry, then pressing a key *
  67. * will return from this function. Otherwise, it will exit the program with "exit()". *
  68. * *
  69. * INPUT: error -- The error number (same as the DOSERR.H error numbers). *
  70. * *
  71. * canretry -- Can this routine exit normally so that retrying can occur? If this is *
  72. * false, then the program WILL exit in this routine. *
  73. * *
  74. * filename -- Optional filename to report with this error. If no filename is *
  75. * supplied, then no filename is listed in the error message. *
  76. * *
  77. * OUTPUT: none, but this routine might not return at all if the "canretry" parameter is *
  78. * false or the player pressed ESC. *
  79. * *
  80. * WARNINGS: This routine may not return at all. It handles being in text mode as well as *
  81. * if in a graphic mode. *
  82. * *
  83. * HISTORY: *
  84. * 10/17/1994 JLB : Created. *
  85. *=============================================================================================*/
  86. void RawFileClass::Error(int error, int canretry, char const * filename)
  87. {
  88. char message[256]; // Staging buffer for error message string.
  89. /*
  90. ** Build the complete text of the error message. This text is used in either the graphic
  91. ** mode or the text mode version.
  92. */
  93. #ifdef GERMAN
  94. strcpy(message, "DATEIFEHLER");
  95. #else
  96. #ifdef FRENCH
  97. strcpy(message, "ERREUR DE FICHIER");
  98. #else
  99. strcpy(message, "FILE ERROR");
  100. #endif
  101. #endif
  102. if (filename) {
  103. strcat(message, "(");
  104. strcat(message, filename);
  105. strcat(message, ")");
  106. }
  107. strcat(message, ": ");
  108. //BG: Borland only strcat(message, _sys_errlist[error]);
  109. strcat(message, strerror(error) );
  110. strcat(message, ". ");
  111. /*
  112. ** If it can't properly handle displaying the error message in the
  113. ** current graphic mode, then this forces the error to become non
  114. ** recoverable. Go into text mode and proceed.
  115. */
  116. if (!FontPtr && GraphicMode != TXT_MODE) {
  117. Set_Video_Mode(RESET_MODE);
  118. canretry = false;
  119. GraphicMode = TXT_MODE;
  120. }
  121. /*
  122. ** Add the text explaining the valid actions to take.
  123. */
  124. if (canretry) {
  125. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  126. #ifdef GERMAN
  127. strcat(message, " Beliebige Taste dr�cken f�r erneuten Versuch.");
  128. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  129. strcat(message, " <ESC> dr�cken, um das Programm zu verlassen.");
  130. #else
  131. #ifdef FRENCH
  132. strcat(message, " Appuyez sur une touche pour recommencer.");
  133. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  134. strcat(message, " Appuyez sur Echap pour quitter le programme.");
  135. #else
  136. strcat(message, " Press any key to retry.");
  137. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  138. strcat(message, " Press <ESC> to exit program.");
  139. #endif
  140. #endif
  141. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  142. } else {
  143. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  144. #ifdef GERMAN
  145. strcat(message, " Beliebige Taste dr�cken, um das Programm zu verlassen.");
  146. #else
  147. #ifdef FRENCH
  148. strcat(message, " Appuyez sur une touche pour quitter le programme.");
  149. #else
  150. strcat(message, " Press any key to exit program.");
  151. #endif
  152. #endif
  153. if (GraphicMode == TXT_MODE) strcat(message, "\n");
  154. }
  155. /*
  156. ** In text mode, the error handler is very simple. It just prints the error message
  157. ** to the screen and waits for a response.
  158. */
  159. if (GraphicMode == TXT_MODE) {
  160. int input;
  161. /*
  162. ** Display the error message and wait for a response.
  163. */
  164. printf(message);
  165. Keyboard::Clear();
  166. input = Keyboard::Get();
  167. /*
  168. ** Check for input. If the ESC key was pressed or if retrying is not allowed,
  169. ** then exit the program. Otherwise, return from this routine for a retry
  170. ** attempt.
  171. */
  172. if (input == KN_ESC || !canretry) {
  173. Prog_End();
  174. exit(EXIT_FAILURE);
  175. }
  176. } else {
  177. /*
  178. ** The graphic mode version of the error handler will display a simple message
  179. ** box on the screen. If the palette is black at this point, then the error will
  180. ** be invisible. For more thorough and pleasing results, you should replace this
  181. ** virtual function with one of your own, that is more aware of the environment
  182. ** in which is exists.
  183. */
  184. void *background; // Pointer to background saving buffer.
  185. GraphicBufferClass * oldpage; // Copy of old logic page.
  186. int oldwindow; // Copy of old window number.
  187. void const *oldfont; // Copy of old font pointer.
  188. int oldspacing; // Old font X spacing.
  189. /*
  190. ** Setup display in preparation for printing the error message.
  191. */
  192. oldpage = Set_Logic_Page(SeenBuff);
  193. oldwindow = Change_Window(ErrorWindow);
  194. oldfont = Set_Font(FontPtr);
  195. oldspacing = FontXSpacing; FontXSpacing = 0;
  196. Hide_Mouse();
  197. /*
  198. ** Try to allocate a storage buffer for the background to the
  199. ** error window.
  200. */
  201. background = new char [Size_Of_Region(WinW<<3, WinH)];
  202. /*
  203. ** If there is memory for the background storage, then save the
  204. ** screen image area to that buffer.
  205. */
  206. if (background) {
  207. SeenBuff.To_Buffer(WinX<<3, WinY, WinW<<3, WinH, background, Size_Of_Region(WinW<<3, WinH));
  208. }
  209. /*
  210. ** Draw a rudimentary box.
  211. */
  212. New_Window();
  213. LogicPage->Draw_Rect(WinX<<3, WinY, (WinX+WinW)<<3, WinY+WinH, WinC);
  214. /*
  215. ** shrinks window down one byte in all directions.
  216. */
  217. WindowList[Window][WINDOWX] += 1;
  218. WindowList[Window][WINDOWY] += 1<<3;
  219. WindowList[Window][WINDOWWIDTH] -= 1<<1;
  220. WindowList[Window][WINDOWHEIGHT] -= 1<<4;
  221. Change_Window(Window);
  222. WinCx = WinCy = 0;
  223. Window_Print(message);
  224. Keyboard::Clear();
  225. /*
  226. ** Check for input. If the ESC key was pressed or if retrying is not allowed,
  227. ** then exit the program. Otherwise, return from this routine for a retry
  228. ** attempt.
  229. */
  230. int input = Keyboard::Get();
  231. if (input == KN_ESC || !canretry) {
  232. Prog_End();
  233. exit(EXIT_FAILURE);
  234. }
  235. /*
  236. ** Restore the window back to its original size.
  237. */
  238. WindowList[Window][WINDOWX] -= 1;
  239. WindowList[Window][WINDOWY] -= 1<<3;
  240. WindowList[Window][WINDOWWIDTH] += 1<<1;
  241. WindowList[Window][WINDOWHEIGHT] += 1<<4;
  242. Change_Window(Window);
  243. WinCx = WinCy = 0;
  244. /*
  245. ** If the background was saved off, then restore it.
  246. */
  247. if (background) {
  248. Buffer_To_Page(WinX<<3, WinY, WinW<<3, WinH, background, SeenBuff);
  249. delete [] background;
  250. }
  251. /*
  252. ** Restore the system global settings to original values.
  253. */
  254. Show_Mouse();
  255. Change_Window(oldwindow);
  256. Set_Font(oldfont);
  257. Set_Logic_Page(oldpage);
  258. FontXSpacing = oldspacing;
  259. }
  260. }
  261. /***********************************************************************************************
  262. * RawFileClass::RawFileClass -- Simple constructor for a file object. *
  263. * *
  264. * This constructor is called when a file object is created with a supplied filename, but *
  265. * not opened at the same time. In this case, an assumption is made that the supplied *
  266. * filename is a constant string. A duplicate of the filename string is not created since *
  267. * it would be wasteful in that case. *
  268. * *
  269. * INPUT: filename -- The filename to assign to this file object. *
  270. * *
  271. * OUTPUT: none *
  272. * *
  273. * WARNINGS: none *
  274. * *
  275. * HISTORY: *
  276. * 10/17/1994 JLB : Created. *
  277. *=============================================================================================*/
  278. RawFileClass::RawFileClass(char const *filename) :
  279. Handle(-1),
  280. Filename(filename),
  281. Allocated(false)
  282. {
  283. }
  284. RawFileClass::~RawFileClass(void)
  285. {
  286. if (Allocated && Filename) {
  287. free((char *)Filename);
  288. }
  289. Allocated = false;
  290. Filename = 0;
  291. }
  292. /***********************************************************************************************
  293. * RawFileClass::Set_Name -- Manually sets the name for a file object. *
  294. * *
  295. * This routine will set the name for the file object to the name specified. This name is *
  296. * duplicated in free store. This allows the supplied name to be a temporarily constructed *
  297. * text string. Setting the name in this fashion doesn't affect the closed or opened state *
  298. * of the file. *
  299. * *
  300. * INPUT: filename -- The filename to assign to this file object. *
  301. * *
  302. * OUTPUT: Returns with a pointer to the allocated copy of this filename. This pointer is *
  303. * guaranteed to remain valid for the duration of this file object or until the name *
  304. * is changed -- whichever is sooner. *
  305. * *
  306. * WARNINGS: Because of the allocation this routine must perform, memory could become *
  307. * fragmented. *
  308. * *
  309. * HISTORY: *
  310. * 10/17/1994 JLB : Created. *
  311. *=============================================================================================*/
  312. char const * RawFileClass::Set_Name(char const *filename)
  313. {
  314. if (Filename && Allocated) {
  315. free((char*)Filename);
  316. Filename = 0;
  317. Allocated = false;
  318. }
  319. if (!filename) return(NULL);
  320. Filename = strdup(filename);
  321. if (!Filename) {
  322. Error(ENOMEM, false, filename);
  323. }
  324. Allocated = true;
  325. return(Filename);
  326. }
  327. /***********************************************************************************************
  328. * RawFileClass::Open -- Assigns name and opens file in one operation. *
  329. * *
  330. * This routine will assign the specified filename to the file object and open it at the *
  331. * same time. If the file object was already open, then it will be closed first. If the *
  332. * file object was previously assigned a filename, then it will be replaced with the new *
  333. * name. Typically, this routine is used when an anonymous file object has been crated and *
  334. * now it needs to be assigned a name and opened. *
  335. * *
  336. * INPUT: filename -- The filename to assign to this file object. *
  337. * *
  338. * rights -- The open file access rights to use. *
  339. * *
  340. * OUTPUT: bool; Was the file opened? The return value of this is moot, since the open file *
  341. * is designed to never return unless it succeeded. *
  342. * *
  343. * WARNINGS: none *
  344. * *
  345. * HISTORY: *
  346. * 10/17/1994 JLB : Created. *
  347. *=============================================================================================*/
  348. int RawFileClass::Open(char const *filename, int rights)
  349. {
  350. Set_Name(filename);
  351. return(Open(rights));
  352. }
  353. /***********************************************************************************************
  354. * RawFileClass::Open -- Opens the file object with the rights specified. *
  355. * *
  356. * This routine is used to open the specified file object with the access rights indicated. *
  357. * This only works if the file has already been assigned a filename. It is guaranteed, by *
  358. * the error handler, that this routine will always return with success. *
  359. * *
  360. * INPUT: rights -- The file access rights to use when opening this file. This is a *
  361. * combination of READ and/or WRITE bit flags. *
  362. * *
  363. * OUTPUT: bool; Was the file opened successfully? This will always return true by reason of *
  364. * the error handler. *
  365. * *
  366. * WARNINGS: none *
  367. * *
  368. * HISTORY: *
  369. * 10/17/1994 JLB : Created. *
  370. *=============================================================================================*/
  371. int RawFileClass::Open(int rights)
  372. {
  373. Close();
  374. /*
  375. ** Verify that there is a filename associated with this file object. If not, then this is a
  376. ** big error condition.
  377. */
  378. if (!Filename) {
  379. Error(ENOENT, false);
  380. }
  381. /*
  382. ** Record the access rights used for this open call. These rights will be used if the
  383. ** file object is duplicated.
  384. */
  385. Rights = rights;
  386. /*
  387. ** Repetatively try to open the file. Abort if a fatal error condition occurs.
  388. */
  389. for (;;) {
  390. /*
  391. ** Try to open the file according to the access rights specified.
  392. */
  393. Hard_Error_Occured = 0;
  394. switch (rights) {
  395. /*
  396. ** If the access rights are not recognized, then report this as
  397. ** an invalid access code.
  398. */
  399. default:
  400. errno = EINVAL;
  401. break;
  402. case READ:
  403. _dos_open(Filename, O_RDONLY|SH_DENYNO, &Handle);
  404. break;
  405. case WRITE:
  406. _dos_creat(Filename, 0, &Handle);
  407. break;
  408. case READ|WRITE:
  409. _dos_open(Filename, O_RDWR|O_CREAT|SH_DENYWR, &Handle);
  410. break;
  411. }
  412. /*
  413. ** If the handle indicates the file is not open, then this is an error condition.
  414. ** For the case of the file cannot be found, then allow a retry. All other cases
  415. ** are fatal.
  416. */
  417. if (Handle < 0) {
  418. /*
  419. ** If this flag is set, then some hard error occurred. Just assume that the error
  420. ** is probably a removed CD-ROM and allow a retry.
  421. */
  422. if (Hard_Error_Occured) {
  423. Error(Hard_Error_Occured, true, Filename);
  424. } else {
  425. if (errno == ENOENT) {
  426. Error(ENOENT, true, Filename);
  427. } else {
  428. Error(errno, false, Filename);
  429. }
  430. }
  431. continue;
  432. }
  433. break;
  434. }
  435. return(true);
  436. }
  437. /***********************************************************************************************
  438. * RawFileClass::Is_Available -- Checks to see if the specified file is available to open. *
  439. * *
  440. * This routine will examine the disk system to see if the specified file can be opened *
  441. * or not. Use this routine before opening a file in order to make sure that is available *
  442. * or to perform other necessary actions. *
  443. * *
  444. * INPUT: force -- Should this routine keep retrying until the file becomes available? If *
  445. * in this case it doesn't become available, then the program will abort. *
  446. * *
  447. * OUTPUT: bool; Is the file available to be opened? *
  448. * *
  449. * WARNINGS: Depending on the parameter passed in, this routine may never return. *
  450. * *
  451. * HISTORY: *
  452. * 10/18/1994 JLB : Created. *
  453. *=============================================================================================*/
  454. int RawFileClass::Is_Available(int forced)
  455. {
  456. int file; // Working file handle.
  457. int open_failed;
  458. /*
  459. ** If the file is already open, then is must have already passed the availability check.
  460. ** Return true in this case.
  461. */
  462. if (Is_Open()) {
  463. return(true);
  464. }
  465. /*
  466. ** If this is a forced check, then go through the normal open channels, since those
  467. ** channels ensure that the file must exist.
  468. */
  469. if (forced) {
  470. RawFileClass::Open(READ);
  471. RawFileClass::Close();
  472. return(true);
  473. }
  474. /*
  475. ** Perform a raw open of the file. If this open fails for ANY REASON, including a missing
  476. ** CD-ROM, this routine will return a failure condition. In all but the missing file
  477. ** condition, go through the normal error recover channels.
  478. */
  479. for (;;) {
  480. Hard_Error_Occured = 0;
  481. open_failed = _dos_open(Filename, O_RDONLY|SH_DENYNO, &file);
  482. /*
  483. ** If DOS reports that everything is just fine except that the file is not present,
  484. ** then return with this fact. Any other case will fall through to the error handler
  485. ** routine.
  486. */
  487. if (open_failed && errno == ENOENT) {
  488. return(false);
  489. }
  490. /*
  491. ** If we got an access error it could be because there is no cd in
  492. ** the drive. Call the error handler but allow a continue if it
  493. ** returns.
  494. */
  495. if (open_failed && errno == EACCES) {
  496. // Error(errno, true, Filename);
  497. // continue;
  498. return(false);
  499. }
  500. /*
  501. ** If the file could not be found, then return with this information. If a more
  502. ** serious error occurred, then display the error message and abort.
  503. */
  504. if (Hard_Error_Occured) {
  505. return(false);
  506. // Error(Hard_Error_Occured, true, Filename);
  507. // continue;
  508. } else {
  509. if (open_failed) {
  510. /*
  511. ** An unhandled error condition is fatal. Display the error message and then
  512. ** abort.
  513. */
  514. // Error(errno, false, Filename);
  515. return(false);
  516. }
  517. }
  518. break;
  519. }
  520. /*
  521. ** Since the file could be opened, then close it and return that the file exists.
  522. */
  523. if (_dos_close(file)) {
  524. Error(errno, false, Filename);
  525. }
  526. return(true);
  527. }
  528. /***********************************************************************************************
  529. * RawFileClass::Close -- Perform a closure of the file. *
  530. * *
  531. * Close the file object. In the rare case of an error, handle it as appropriate. *
  532. * *
  533. * INPUT: none *
  534. * *
  535. * OUTPUT: none *
  536. * *
  537. * WARNINGS: Some rare error conditions may cause this routine to abort the program. *
  538. * *
  539. * HISTORY: *
  540. * 10/18/1994 JLB : Created. *
  541. *=============================================================================================*/
  542. void RawFileClass::Close(void)
  543. {
  544. /*
  545. ** If the file is open, then close it. If the file is already closed, then just return. This
  546. ** isn't considered an error condition.
  547. */
  548. if (Is_Open()) {
  549. for (;;) {
  550. /*
  551. ** Close the file. If there was an error in the close operation -- abort.
  552. */
  553. Hard_Error_Occured = 0;
  554. if (_dos_close(Handle)) {
  555. /*
  556. ** By definition, this error can only be a bad file handle. This a fatal condition
  557. ** of course, so abort with an error message.
  558. */
  559. Error(errno, false, Filename);
  560. }
  561. /*
  562. ** In the condition (if it is even possible) of a hard error occurring, then
  563. ** assume it is the case of missing media. Display an error message and try
  564. ** again if indicated.
  565. */
  566. if (Hard_Error_Occured) {
  567. Error(Hard_Error_Occured, true, Filename);
  568. continue;
  569. }
  570. break;
  571. }
  572. /*
  573. ** At this point the file must have been closed. Mark the file as empty and return.
  574. */
  575. Handle = -1;
  576. }
  577. }
  578. /***********************************************************************************************
  579. * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
  580. * *
  581. * This routine will read the specified number of bytes and place the data into the buffer *
  582. * indicated. It is legal to call this routine with a request for more bytes than are in *
  583. * the file. This condition can result in fewer bytes being read than requested. Determine *
  584. * this by examining the return value. *
  585. * *
  586. * INPUT: buffer -- Pointer to the buffer to read data into. If NULL is passed, no read *
  587. * is performed. *
  588. * *
  589. * size -- The number of bytes to read. If NULL is passed, then no read is *
  590. * performed. *
  591. * *
  592. * OUTPUT: Returns with the number of bytes read into the buffer. If this number is less *
  593. * than requested, it indicates that the file has been exhausted. *
  594. * *
  595. * WARNINGS: none *
  596. * *
  597. * HISTORY: *
  598. * 10/18/1994 JLB : Created. *
  599. *=============================================================================================*/
  600. long RawFileClass::Read(void *buffer, long size)
  601. {
  602. long bytesread = 0; // Running count of the number of bytes read into the buffer.
  603. int opened = false; // Was the file opened by this routine?
  604. int readresult;
  605. /*
  606. ** If the file isn't opened, open it. This serves as a convenience
  607. ** for the programmer.
  608. */
  609. if (!Is_Open()) {
  610. /*
  611. ** The error check here is moot. Open will never return unless it succeeded.
  612. */
  613. if (!Open(READ)) {
  614. return(0);
  615. }
  616. opened = true;
  617. }
  618. /*
  619. ** Read the file in convenient chunk sizes. When the actual number
  620. ** of bytes read does not match the desired, then assume that the file
  621. ** is exhausted and bail. This loop was adjusted to take into
  622. ** consideration the fact that "read" returns a SIGNED value whereas
  623. ** it takes an UNSIGNED value as the byte count.
  624. */
  625. while (size) {
  626. unsigned desired; // Bytes desired to be read this pass.
  627. unsigned actual; // Actual number of bytes read.
  628. /*
  629. ** Break the read request into chunks no bigger than the low level DOS read
  630. ** can handle.
  631. */
  632. desired = size;
  633. Hard_Error_Occured = 0;
  634. readresult = _dos_read(Handle, buffer, desired, &actual);
  635. /*
  636. ** If a hard error occurred, then assume that it is the case of the CD-ROM or
  637. ** floppy media having been removed. Display the error and retry as directed.
  638. */
  639. if (Hard_Error_Occured) {
  640. Error(Hard_Error_Occured, true, Filename);
  641. continue; // Not technically needed, but to be consistent...
  642. } else {
  643. /*
  644. ** If negative one is returned from the read operation, then this indicates
  645. ** either a bad file number or invalid access. These are fatal conditions, so
  646. ** display the error and then abort.
  647. */
  648. if (readresult != 0) {
  649. Error(errno, false, Filename);
  650. } else {
  651. /*
  652. ** No error occurred during the read. Adjust the pointers and size counters and
  653. ** loop again if more data is needed to be read.
  654. */
  655. buffer = Add_Long_To_Pointer(buffer, actual);
  656. bytesread += actual;
  657. size -= actual;
  658. if (actual != desired) break; // No more data?
  659. }
  660. }
  661. }
  662. /*
  663. ** Close the file if it was opened by this routine and return
  664. ** the actual number of bytes read into the buffer.
  665. */
  666. if (opened) Close();
  667. return(bytesread);
  668. }
  669. /***********************************************************************************************
  670. * RawFileClass::Write -- Writes the specified data to the buffer specified. *
  671. * *
  672. * This routine will write the data specified to the file. *
  673. * *
  674. * INPUT: buffer -- The buffer that holds the data to write. *
  675. * *
  676. * size -- The number of bytes to write to the file. *
  677. * *
  678. * OUTPUT: Returns with the number of bytes written to the file. This routine catches the *
  679. * case of a disk full condition, so this routine will always return with the number *
  680. * matching the size request. *
  681. * *
  682. * WARNINGS: A fatal file condition could cause this routine to never return. *
  683. * *
  684. * HISTORY: *
  685. * 10/18/1994 JLB : Created. *
  686. *=============================================================================================*/
  687. long RawFileClass::Write(void const *buffer, long size)
  688. {
  689. long bytesread = 0;
  690. int opened = false; // Was the file manually opened?
  691. int writeresult;
  692. /*
  693. ** Check to open status of the file. If the file is open, then merely write to
  694. ** it. Otherwise, open the file for writing and then close the file when the
  695. ** output is finished.
  696. */
  697. if (!Is_Open()) {
  698. if (!Open(WRITE)) {
  699. return(0);
  700. }
  701. opened = true;
  702. }
  703. /*
  704. ** Write the data to the file in chunks no bigger than what the low level DOS write
  705. ** can handle.
  706. */
  707. while (size) {
  708. unsigned desired; // Bytes desired to be write this pass.
  709. unsigned actual; // Actual number of bytes written.
  710. Hard_Error_Occured = 0;
  711. // desired = (unsigned)MIN(size, Transfer_Block_Size());
  712. desired = size;
  713. writeresult = _dos_write(Handle, buffer, desired, &actual);
  714. /*
  715. ** If a hard error occurred, then assume it is the case of the media being
  716. ** removed. Print the error message an retry as directed.
  717. */
  718. if (Hard_Error_Occured) {
  719. Error(Hard_Error_Occured, true, Filename);
  720. continue; // Not technically needed, but to be consistent...
  721. } else {
  722. /*
  723. ** If negative one is returned by the DOS read, then this indicates a bad file
  724. ** handle or invalid access. Either condition is fatal -- display error condition
  725. ** and abort.
  726. */
  727. if (writeresult != 0) {
  728. Error(errno, false, Filename);
  729. } else {
  730. /*
  731. ** A successful write occurred. Update pointers and byte counter as appropriate.
  732. */
  733. buffer = Add_Long_To_Pointer((void *)buffer, actual);
  734. bytesread += actual;
  735. size -= actual;
  736. /*
  737. ** If the actual bytes written is less than requested, assume this is a case of
  738. ** the disk being full. Consider this a fatal error condition.
  739. */
  740. if (actual != desired) {
  741. Error(ENOSPC, false, Filename);
  742. }
  743. }
  744. }
  745. }
  746. /*
  747. ** If this routine had to open the file, then close it before returning.
  748. */
  749. if (opened) {
  750. Close();
  751. }
  752. /*
  753. ** Return with the number of bytes written. This will always be the number of bytes
  754. ** requested, since the case of the disk being full is caught by this routine.
  755. */
  756. return(bytesread);
  757. }
  758. /***********************************************************************************************
  759. * RawFileClass::Seek -- Reposition the file pointer as indicated. *
  760. * *
  761. * Use this routine to move the filepointer to the position indicated. It can move either *
  762. * relative to current position or absolute from the beginning or ending of the file. This *
  763. * routine will only return if it successfully performed the seek. *
  764. * *
  765. * INPUT: pos -- The position to seek to. This is interpreted as relative to the position *
  766. * indicated by the "dir" parameter. *
  767. * *
  768. * dir -- The relative position to relate the seek to. This can be either SEEK_SET *
  769. * for the beginning of the file, SEEK_CUR for the current position, or *
  770. * SEEK_END for the end of the file. *
  771. * *
  772. * OUTPUT: This routine returns the position that the seek ended up at. *
  773. * *
  774. * WARNINGS: If there was a file error, then this routine might never return. *
  775. * *
  776. * HISTORY: *
  777. * 10/18/1994 JLB : Created. *
  778. *=============================================================================================*/
  779. long RawFileClass::Seek(long pos, int dir)
  780. {
  781. /*
  782. ** If the file isn't opened, then this is a fatal error condition.
  783. */
  784. if (!Is_Open()) {
  785. Error(EBADF, false, Filename);
  786. }
  787. /*
  788. ** Keep trying to seek until a non-retry condition occurs.
  789. */
  790. for (;;) {
  791. /*
  792. ** Perform the low level seek on the file.
  793. */
  794. Hard_Error_Occured = 0;
  795. pos = lseek(Handle, pos, dir);
  796. /*
  797. ** If a hard error occurred, then assume that it is the case of removed media. Display
  798. ** error message and retry.
  799. */
  800. if (Hard_Error_Occured) {
  801. Error(Hard_Error_Occured, true, Filename);
  802. continue;
  803. } else {
  804. /*
  805. ** A negative one indicates a fatal error with the seek operation. Display error
  806. ** condition and then abort.
  807. */
  808. if (pos == -1) {
  809. Error(errno, false, Filename);
  810. }
  811. }
  812. break;
  813. }
  814. /*
  815. ** Return with the new position of the file. This will range between zero and the number of
  816. ** bytes the file contains.
  817. */
  818. return(pos);
  819. }
  820. /***********************************************************************************************
  821. * RawFileClass::Size -- Determines size of file (in bytes). *
  822. * *
  823. * Use this routine to determine the size of the file. The file must exist or this is an *
  824. * error condition. *
  825. * *
  826. * INPUT: none *
  827. * *
  828. * OUTPUT: Returns with the number of bytes in the file. *
  829. * *
  830. * WARNINGS: This routine handles error conditions and will not return unless the file *
  831. * exists and can successfully be queried for file length. *
  832. * *
  833. * HISTORY: *
  834. * 10/18/1994 JLB : Created. *
  835. *=============================================================================================*/
  836. long RawFileClass::Size(void)
  837. {
  838. long size = 0;
  839. /*
  840. ** If the file is open, then proceed normally.
  841. */
  842. if (Is_Open()) {
  843. /*
  844. ** Repetitively try to determine the file size until a fatal error condition or success
  845. ** is achieved.
  846. */
  847. for (;;) {
  848. Hard_Error_Occured = 0;
  849. size = filelength(Handle);
  850. /*
  851. ** If a hard error occurred, then assume it is the case of removed media. Display an
  852. ** error condition and allow retry.
  853. */
  854. if (Hard_Error_Occured) {
  855. Error(Hard_Error_Occured, true, Filename);
  856. continue;
  857. } else {
  858. if (size == -1) {
  859. Error(errno, false, Filename);
  860. }
  861. }
  862. break;
  863. }
  864. } else {
  865. /*
  866. ** If the file wasn't open, then open the file and call this routine again. Count on
  867. ** the fact that the open function must succeed.
  868. */
  869. if (Open()) {
  870. size = Size();
  871. /*
  872. ** Since we needed to open the file we must remember to close the file when the
  873. ** size has been determined.
  874. */
  875. Close();
  876. }
  877. }
  878. return(size);
  879. }
  880. /***********************************************************************************************
  881. * RawFileClass::Create -- Creates an empty file. *
  882. * *
  883. * This routine will create an empty file from the file object. The file object's filename *
  884. * must already have been assigned before this routine will function. *
  885. * *
  886. * INPUT: none *
  887. * *
  888. * OUTPUT: bool; Was the file successfully created? This routine will always return true. *
  889. * *
  890. * WARNINGS: A fatal error condition could occur with this routine. Especially if the disk *
  891. * is full or a read-only media was selected. *
  892. * *
  893. * HISTORY: *
  894. * 10/18/1994 JLB : Created. *
  895. *=============================================================================================*/
  896. int RawFileClass::Create(void)
  897. {
  898. Close();
  899. if (Open(WRITE)) {
  900. Close();
  901. return(true);
  902. }
  903. return(false);
  904. }
  905. /***********************************************************************************************
  906. * RawFileClass::Delete -- Deletes the file object from the disk. *
  907. * *
  908. * This routine will delete the file object from the disk. If the file object doesn't *
  909. * exist, then this routine will return as if it had succeeded (since the effect is the *
  910. * same). *
  911. * *
  912. * INPUT: none *
  913. * *
  914. * OUTPUT: bool; Was the file deleted? If the file was already missing, the this value will *
  915. * be false. *
  916. * *
  917. * WARNINGS: none *
  918. * *
  919. * HISTORY: *
  920. * 10/18/1994 JLB : Created. *
  921. *=============================================================================================*/
  922. int RawFileClass::Delete(void)
  923. {
  924. /*
  925. ** If the file was open, then it must be closed first.
  926. */
  927. Close();
  928. /*
  929. ** If there is no filename associated with this object, then this indicates a fatal error
  930. ** condition. Report this and abort.
  931. */
  932. if (!Filename) {
  933. Error(ENOENT, false);
  934. }
  935. /*
  936. ** Repetitively try to delete the file if possible. Either return with success, or
  937. ** abort the program with an error.
  938. */
  939. for (;;) {
  940. /*
  941. ** If the file is already missing, then return with this fact. No action is necessary.
  942. ** This can occur as this section loops if the file exists on a floppy and the floppy
  943. ** was removed, the file deleted on another machine, and then the floppy was
  944. ** reinserted. Admittedly, this is a rare case, but is handled here.
  945. */
  946. if (!Is_Available()) {
  947. return(false);
  948. }
  949. Hard_Error_Occured = 0;
  950. if (remove(Filename) == -1) {
  951. /*
  952. ** If a hard error occurred, then assume that the media has been removed. Display
  953. ** error message and retry as directed.
  954. */
  955. if (Hard_Error_Occured) {
  956. Error(Hard_Error_Occured, true, Filename);
  957. continue;
  958. }
  959. /*
  960. ** If at this point, DOS says the file doesn't exist, then just exit with this
  961. ** fact. It should have been caught earlier, but in any case, this is a legal
  962. ** condition.
  963. */
  964. if (errno == ENOENT) break;
  965. /*
  966. ** The only way it can reach this point is if DOS indicates that access is denied
  967. ** on the file. This occurs when trying to delete a file on a read-only media such
  968. ** as a CD-ROM. Report this as a fatal error and then abort.
  969. */
  970. Error(errno, false, Filename);
  971. }
  972. break;
  973. }
  974. /*
  975. ** DOS reports that the file was successfully deleted. Return with this fact.
  976. */
  977. return(true);
  978. }