RAWFILE.CPP 51 KB

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