FILEINIT.CPP 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. /***************************************************************************
  19. ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
  20. ***************************************************************************
  21. * *
  22. * Project Name : Library - Fileio init routines. *
  23. * *
  24. * File Name : FILEINIT.C *
  25. * *
  26. * Programmer : Scott K. Bowen *
  27. * *
  28. * Start Date : September 13, 1993 *
  29. * *
  30. * Last Update : April 19, 1994 [SKB] *
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions: *
  34. * WWDOS_Init -- Initialize the fileio WWS fileio system. *
  35. * WWDOS_Shutdown -- Clean up any things that needs to be to exit game. *
  36. * Init_FileData_Table -- Initializes or reads in FileData Table. *
  37. * Sort_FileData_Table -- Sorts the FileData table that is in memory. *
  38. * Preload_Files -- Loads files marked with FILEF_PRELOAD into cache. *
  39. * Init_File_Cache -- Initializes and allocs the file cache heap. *
  40. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  41. #ifndef WWSTD_H
  42. #include "wwstd.h"
  43. #endif
  44. #ifndef _FILE_H
  45. #include "_file.h"
  46. #endif
  47. #ifndef WWMEM_H
  48. #include <wwmem.h>
  49. #endif
  50. #ifndef MISC_H
  51. #include <misc.h>
  52. #endif
  53. #include <direct.h>
  54. #include <search.h>
  55. #include <string.h>
  56. /*=========================================================================*/
  57. /* The following PRIVATE functions are in this file: */
  58. /*=========================================================================*/
  59. PRIVATE FileInitErrorType cdecl Init_File_Cache(ULONG cachesize);
  60. PRIVATE FileInitErrorType cdecl Init_FileData_Table(BYTE const *filename);
  61. PRIVATE FileInitErrorType cdecl Set_Search_Drives( BYTE *cdpath );
  62. PRIVATE FileInitErrorType cdecl Preload_Files(VOID);
  63. PRIVATE int QSort_Comp_Func(const void *p1, const void *p2);
  64. PRIVATE VOID Sort_FileData_Table(VOID);
  65. /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  66. /***************************************************************************
  67. * WWDOS_INIT -- Initialize the fileio WWS fileio system. *
  68. * *
  69. * *
  70. * INPUT: ULONG cachesize - size wanted for the cache. *
  71. * BYTE *filedat - NULL or name of filedata table file. *
  72. * BYTE *cdpath - NULL or secondary search path on a CD. *
  73. * *
  74. * OUTPUT: Returns all errors encountered or'd together. *
  75. * *
  76. * WARNINGS: User should call the WWDOS_Init function for all file *
  77. * initialization. *
  78. * *
  79. * HISTORY: *
  80. * 04/19/1994 SKB : Created. *
  81. *=========================================================================*/
  82. FileInitErrorType cdecl WWDOS_Init(ULONG cachesize, BYTE *filedata, BYTE *cdpath)
  83. {
  84. // FileInitErrorType errors;
  85. unsigned errors ;
  86. // This has not been completed yet, when it is, uncomment it and add errors.
  87. Install_Hard_Error_Handler () ;
  88. Get_Devices();
  89. if (cachesize) {
  90. errors = Init_File_Cache(cachesize);
  91. } else {
  92. errors = FI_SUCCESS;
  93. }
  94. errors = errors | Init_FileData_Table(filedata);
  95. errors = errors | Set_Search_Drives(cdpath);
  96. errors = errors | Preload_Files();
  97. return ( FileInitErrorType ) errors ;
  98. }
  99. /***************************************************************************
  100. * WWDOS_SHUTDOWN -- Clean up any things that needs to be in file syste to *
  101. * exit game. *
  102. * One could shut down the file system and open it back *
  103. * up with a different size cache or filetable. *
  104. * *
  105. * INPUT: NONE. *
  106. * *
  107. * OUTPUT: NONE. *
  108. * *
  109. * WARNINGS: *
  110. * *
  111. * HISTORY: *
  112. * 04/19/1994 SKB : Created. *
  113. *=========================================================================*/
  114. VOID cdecl WWDOS_Shutdown(VOID)
  115. {
  116. FileDataType *filedata; // Pointer to the current FileData.
  117. WORD file_handle;
  118. FileHandleType *filehandletable; // Pointer to the current file handle.
  119. // Close all open files.
  120. filehandletable = FileHandleTable;
  121. for (file_handle = 0; file_handle < TABLE_MAX; file_handle++, filehandletable++) {
  122. if (!filehandletable->Empty) {
  123. Close_File(file_handle);
  124. }
  125. }
  126. // Free the file cache heap.
  127. if (FileCacheHeap) {
  128. // Get a pointer to the current filedata.
  129. if (FileDataPtr) {
  130. filedata = FileDataPtr;
  131. } else {
  132. filedata = FileData;
  133. }
  134. while(filedata->Name && filedata->Name[0]) {
  135. filedata->Ptr = NULL;
  136. filedata++;
  137. }
  138. Free(FileCacheHeap);
  139. FileCacheHeap = NULL;
  140. }
  141. // Free up the file data.
  142. if (FileDataPtr != FileData) {
  143. Free(FileDataPtr);
  144. }
  145. FileDataPtr = NULL;
  146. chdir(StartPath);
  147. ibm_setdisk(*StartPath - 'A');
  148. // This has not been completed yet, when it is, uncomment it and add errors.
  149. Remove_Hard_Error_Handler();
  150. }
  151. /***************************************************************************
  152. * INIT_FILE_CACHE -- Initializes and allocs the file cache heap. *
  153. * *
  154. * INPUT: ULONG cachesize - size of heap cache.. *
  155. * *
  156. * OUTPUT: FileInitErrorType error code. *
  157. * *
  158. * WARNINGS: *
  159. * *
  160. * HISTORY: *
  161. * 04/19/1994 SKB : Created. *
  162. *=========================================================================*/
  163. PRIVATE FileInitErrorType cdecl Init_File_Cache(ULONG cachesize)
  164. {
  165. // Allocate and initialize the file cache heap.
  166. if (FileCacheHeap) {
  167. return (FI_CACHE_ALREADY_INIT);
  168. }
  169. if ((Ram_Free(MEM_NORMAL) >= cachesize)) {
  170. FileCacheHeap = Alloc(cachesize, MEM_NORMAL);
  171. Mem_Init(FileCacheHeap, cachesize);
  172. }
  173. if (!FileCacheHeap) {
  174. return (FI_CACHE_TOO_BIG);
  175. }
  176. return (FI_SUCCESS);
  177. }
  178. /***************************************************************************
  179. * INIT_FILEDATA_TABLE -- Initializes or reads in FileData Table. *
  180. * *
  181. * INPUT: *
  182. * *
  183. * OUTPUT: FileInitErrorType error code. *
  184. * *
  185. * WARNINGS: *
  186. * *
  187. * HISTORY: *
  188. * 09/13/1993 SKB : Created. *
  189. *=========================================================================*/
  190. PRIVATE FileInitErrorType cdecl Init_FileData_Table(BYTE const *filename)
  191. {
  192. WORD fd;
  193. ULONG fsize;
  194. FileDataType *ptr;
  195. WORD index;
  196. BYTE fname[13];
  197. /*
  198. ** Inialize the file handle table to reflect no files open.
  199. */
  200. for (index = 0; index < TABLE_MAX; index++) {
  201. FileHandleTable[index].Empty = TRUE;
  202. }
  203. // Set up our FileData ptr to be the initial FileData table.
  204. FileDataPtr = FileData;
  205. // Sort the filedata table.
  206. // This needs to be done even if we load it off disk since the initial file data
  207. // table might contain a filename.
  208. Sort_FileData_Table();
  209. // If there is a file name, then the filedata table will be loaded from disk.
  210. if (filename) {
  211. if (!Find_File(filename)) {
  212. return (FI_FILEDATA_FILE_NOT_FOUND);
  213. }
  214. fd = Open_File(filename, READ);
  215. fsize = File_Size(fd);
  216. if ((Ram_Free(MEM_NORMAL) < fsize)) {
  217. Close_File(fd);
  218. return (FI_FILEDATA_TOO_BIG);
  219. }
  220. // Allocate some system memory.
  221. // Setup the new FileDataPtr and this time.
  222. FileDataPtr = ptr = (FileDataType *) Alloc(fsize, MEM_NORMAL);
  223. // Load the file up into memory.
  224. Read_File(fd, FileDataPtr, fsize);
  225. Close_File(fd);
  226. // Process the filetable. The filenames need their pointers adjusted.
  227. // At this time we will also count the number of files and number of PAK files.
  228. NumPAKFiles = NumFiles = 0;
  229. // Make sure that the file name will have a NUL at the end.
  230. fname[12] = 0;
  231. while(TRUE) {
  232. // Have we reached the end of the list?
  233. if (!ptr->Name) break;
  234. // Adjust the name pointer to point the the correct area.
  235. ptr->Name = (BYTE *)FileDataPtr + (LONG) ptr->Name;
  236. // Count up weather it is a PAK file or a normal file.
  237. if (!NumFiles && strstr((char *) ptr->Name, (char *) ".PAK")) {
  238. NumPAKFiles++;
  239. // Mark that it has been processed so that Open_File() will not do it.
  240. ptr->Flag |= FILEF_PROCESSED;
  241. } else {
  242. NumFiles++;
  243. }
  244. // Next record.
  245. ptr++;
  246. }
  247. }
  248. return (FI_SUCCESS);
  249. }
  250. /***************************************************************************
  251. * Set_Search_Drives -- Sets up the CDRom and HardDrive paths. *
  252. * *
  253. * INPUT: BYTE *cdpath - path of data files on a CD. *
  254. * Should pass in NULL for non CD products. *
  255. * *
  256. * OUTPUT: FileInitErrorType error code. *
  257. * Varibable defined: *
  258. * ExecPath = Full path of EXE file. *
  259. * StartPath = Directory user started in. *
  260. * DataPath = secondary search path (typically CD-ROM). *
  261. * Note: format of paths is "C:\PATH" *
  262. * *
  263. * WARNINGS: The cdpath may be overiden by a "-CD<path>" command line *
  264. * arguement that specifies another drive (HARD or CD) and path *
  265. * where the data resides. Whenever a file is opened, it checks *
  266. * the startup drive first, then the CD search path if the first *
  267. * search was unsuccessful. *
  268. * *
  269. * HISTORY: *
  270. * 01/14/1993 SB : Created. *
  271. * 04/19/1994 SKB : Mods for 32 bit library. *
  272. *=========================================================================*/
  273. PRIVATE FileInitErrorType cdecl Set_Search_Drives( BYTE *cdpath )
  274. {
  275. BYTE *ptr;
  276. #if LIB_EXTERNS_RESOLVED
  277. // NOTE: THIS IS WRONG, THIS IS NOT THE WAY TO GET THE EXE's PATH.
  278. // Locate the executable.
  279. strcpy(ExecPath, _argv[0]);
  280. // Find the very last '\' on the path.
  281. ptr = strrchr((char *) ExecPath, (int) '\\');
  282. #else
  283. ptr = NULL;
  284. #endif
  285. // Remove the exe name to just have the path.
  286. if (ptr == NULL) {
  287. *ExecPath = 0;
  288. }
  289. else {
  290. *ptr = 0;
  291. }
  292. // Did the user specify a second path?
  293. ptr = Find_Argv("-CD");
  294. // If so, set the data path to that.
  295. if (ptr) {
  296. strcpy(DataPath, ptr + 3);
  297. }
  298. // Otherwise check to see if there is a CD-Rom drive.
  299. else {
  300. if (cdpath && *cdpath) {
  301. #if LIB_EXTERNS_RESOLVED
  302. UseCD = GetCDDrive();
  303. #else
  304. UseCD = FALSE;
  305. #endif
  306. }
  307. else {
  308. UseCD = FALSE;
  309. }
  310. // If so, set the Drive to it and find out if any directories.
  311. if ( UseCD ) {
  312. strcpy( DataPath, "A:" );
  313. strcat( DataPath, cdpath);
  314. *DataPath = 'A'+UseCD;
  315. }
  316. // If not, set the Data path to the execacutable path.
  317. else {
  318. strcpy(DataPath, ExecPath);
  319. }
  320. }
  321. // Finnally, set the starting path.
  322. getcwd(StartPath, XMAXPATH);
  323. // Make sure they are all uppercase.
  324. strupr(StartPath);
  325. strupr(DataPath);
  326. strupr(ExecPath);
  327. // Change directories to the secondary search path (DataPath).
  328. if (*DataPath && chdir(DataPath)) {
  329. return (FI_SEARCH_PATH_NOT_FOUND);
  330. }
  331. // Lastley, Make sure we are in the startup directory. This will overide
  332. // the secondary data path if they are on the same drive.
  333. if (chdir(StartPath)) {
  334. return (FI_STARTUP_PATH_NOT_FOUND);
  335. }
  336. return (FI_SUCCESS);
  337. }
  338. /***************************************************************************
  339. * PRELOAD_FILES -- Loads files marked with FILEF_PRELOAD into cache. *
  340. * *
  341. * *
  342. * INPUT: none. *
  343. * *
  344. * OUTPUT: FileInitErrorType error code. *
  345. * *
  346. * WARNINGS: The FileData must be initialized and the file heap initialized*
  347. * in order for this to work. *
  348. * *
  349. * HISTORY: *
  350. * 04/19/1994 SKB : Created. *
  351. *=========================================================================*/
  352. PRIVATE FileInitErrorType cdecl Preload_Files(VOID)
  353. {
  354. FileDataType *filedata; // Working file data table pointer.
  355. BOOL oldflag; // Previous file flag.
  356. if (!FileDataPtr) {
  357. return (FI_FILETABLE_NOT_INIT);
  358. }
  359. if (!FileCacheHeap) {
  360. return (FI_NO_CACHE_FOR_PRELOAD);
  361. }
  362. /*
  363. ** Make all files flagged to be made resident at startup, resident.
  364. */
  365. filedata = FileDataPtr;
  366. while (filedata->Name && strlen(filedata->Name)) {
  367. if (filedata->Flag & FILEF_PRELOAD) {
  368. oldflag = filedata->Flag;
  369. filedata->Flag |= FILEF_RESIDENT; // Make it resident.
  370. filedata->Flag &= ~FILEF_FLUSH; // Don't purge on Close_File.
  371. Close_File(Open_File(filedata->Name, READ));
  372. filedata->Flag &= ~(FILEF_RESIDENT|FILEF_FLUSH); // Clear bits.
  373. filedata->Flag |= oldflag & (FILEF_RESIDENT|FILEF_FLUSH); // Restore bits.
  374. }
  375. filedata++;
  376. }
  377. return (FI_SUCCESS);
  378. }
  379. /***************************************************************************
  380. * SORT_FILEDATA_TABLE -- Sorts the FileData table that is in memory. *
  381. * *
  382. * INPUT: NONE *
  383. * *
  384. * OUTPUT: NONE. *
  385. * *
  386. * WARNINGS: *
  387. * *
  388. * HISTORY: *
  389. * 09/13/1993 SKB : Created. *
  390. *=========================================================================*/
  391. PRIVATE int QSort_Comp_Func(const void *p1, const void *p2)
  392. {
  393. return(strcmp(((FileDataType*)p1)->Name, ((FileDataType*)p2)->Name));
  394. }
  395. PRIVATE VOID Sort_FileData_Table(VOID)
  396. {
  397. /*
  398. ** Sort the filetable it but keep the pack file indexes correct.
  399. */
  400. /*
  401. ** The number of pak files in the file table.
  402. */
  403. NumPAKFiles = 0;
  404. strupr(FileData[NumPAKFiles].Name);
  405. while (strstr((char *) FileData[NumPAKFiles].Name, (char *) ".PAK")) {
  406. strupr(FileData[NumPAKFiles].Name);
  407. NumPAKFiles++;
  408. }
  409. /*
  410. ** Count the remaining files within the file table.
  411. */
  412. NumFiles = 0;
  413. while(FileData[NumFiles+NumPAKFiles].Name && FileData[NumFiles+NumPAKFiles].Name[0]) {
  414. strupr(FileData[NumFiles+NumPAKFiles].Name);
  415. NumFiles++;
  416. }
  417. /*
  418. ** Sort the file entries (past the pak files).
  419. */
  420. if (NumFiles) {
  421. qsort(&FileData[NumPAKFiles], NumFiles, sizeof(FileDataType), QSort_Comp_Func);
  422. }
  423. }
  424.