]> icculus.org git repositories - taylor/freespace2.git/blob - src/cfile/cfile.cpp
stub/warning removal.
[taylor/freespace2.git] / src / cfile / cfile.cpp
1 /*
2  * $Logfile: /Freespace2/code/CFile/cfile.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Utilities for operating on files
8  *
9  * $Log$
10  * Revision 1.4  2002/06/05 08:05:28  relnev
11  * stub/warning removal.
12  *
13  * reworked the sound code.
14  *
15  * Revision 1.3  2002/05/28 08:52:03  relnev
16  * implemented two assembly stubs.
17  *
18  * cleaned up a few warnings.
19  *
20  * added a little demo hackery to make it progress a little farther.
21  *
22  * Revision 1.2  2002/05/28 06:28:20  theoddone33
23  * Filesystem mods, actually reads some data files now
24  *
25  * Revision 1.1.1.1  2002/05/03 03:28:08  root
26  * Initial import.
27  *
28  * 
29  * 20    9/08/99 10:01p Dave
30  * Make sure game won't run in a drive's root directory. Make sure
31  * standalone routes suqad war messages properly to the host.
32  * 
33  * 19    9/08/99 12:03a Dave
34  * Make squad logos render properly in D3D all the time. Added intel anim
35  * directory.
36  * 
37  * 18    9/06/99 2:35p Dave
38  * Rename briefing and debriefing voice direcrory paths properly.
39  * 
40  * 17    9/03/99 1:31a Dave
41  * CD checking by act. Added support to play 2 cutscenes in a row
42  * seamlessly. Fixed super low level cfile bug related to files in the
43  * root directory of a CD. Added cheat code to set campaign mission # in
44  * main hall.
45  * 
46  * 16    8/31/99 9:46a Dave
47  * Support for new cfile cbanims directory.
48  * 
49  * 15    8/06/99 11:20a Johns
50  * Don't call game_cd_changed() in a demo or multiplayer beta build.
51  * 
52  * 14    6/08/99 2:33p Dave
53  * Fixed release build warning. Put in hud config stuff.
54  * 
55  * 13    5/19/99 4:07p Dave
56  * Moved versioning code into a nice isolated common place. Fixed up
57  * updating code on the pxo screen. Fixed several stub problems.
58  * 
59  * 12    4/30/99 12:18p Dave
60  * Several minor bug fixes.
61  * 
62  * 11    4/07/99 5:54p Dave
63  * Fixes for encryption in updatelauncher.
64  * 
65  * 10    3/28/99 5:58p Dave
66  * Added early demo code. Make objects move. Nice and framerate
67  * independant, but not much else. Don't use yet unless you're me :)
68  * 
69  * 9     2/22/99 10:31p Andsager
70  * Get rid of unneeded includes.
71  * 
72  * 8     1/12/99 3:15a Dave
73  * Barracks screen support for selecting squad logos. We need real artwork
74  * :)
75  * 
76  * 7     11/30/98 1:07p Dave
77  * 16 bit conversion, first run.
78  * 
79  * 6     10/29/98 10:41a Dave
80  * Change the way cfile initializes exe directory.
81  * 
82  * 5     10/13/98 9:19a Andsager
83  * Add localization support to cfile.  Optional parameter with cfopen that
84  * looks for localized files.
85  * 
86  * 4     10/12/98 9:54a Dave
87  * Fixed a few file organization things.
88  * 
89  * 3     10/07/98 6:27p Dave
90  * Globalized mission and campaign file extensions. Removed Silent Threat
91  * special code. Moved \cache \players and \multidata into the \data
92  * directory.
93  * 
94  * 2     10/07/98 10:52a Dave
95  * Initial checkin.
96  * 
97  * 1     10/07/98 10:48a Dave
98  * 
99  * 110   9/17/98 10:31a Hoffoss
100  * Changed code to use location of executable as root rather than relying
101  * on the cwd being set correctly.  This is most helpful in the case of
102  * Fred launching due to the user double-clicking on an .fsm file in
103  * explorer or something (where the cwd is probably the location of the
104  * .fsm file).
105  * 
106  * 109   9/11/98 4:14p Dave
107  * Fixed file checksumming of < file_size. Put in more verbose kicking and
108  * PXO stats store reporting.
109  * 
110  * 108   9/09/98 5:53p Dave
111  * Put in new tracker packets in API. Change cfile to be able to checksum
112  * portions of a file.
113  * 
114  * 107   9/04/98 3:51p Dave
115  * Put in validated mission updating and application during stats
116  * updating.
117  * 
118  * 106   8/31/98 2:06p Dave
119  * Make cfile sort the ordering or vp files. Added support/checks for
120  * recognizing "mission disk" players.
121  * 
122  * 105   8/20/98 5:30p Dave
123  * Put in handy multiplayer logfile system. Now need to put in useful
124  * applications of it all over the code.
125  * 
126  * 104   8/12/98 4:53p Dave
127  * Put in 32 bit checksumming for PXO missions. No validation on the
128  * actual tracker yet, though.
129  * 
130  * 103   6/17/98 9:30a Allender
131  * fixed red alert replay stats clearing problem
132  * 
133  * 102   6/05/98 9:46a Lawrance
134  * check for CD change on cfopen()
135  * 
136  * 101   5/19/98 1:19p Allender
137  * new low level reliable socket reading code.  Make all missions/campaign
138  * load/save to data missions folder (i.e. we are rid of the player
139  * missions folder)
140  * 
141  * 100   5/13/98 10:22p John
142  * Added cfile functions to read/write rle compressed blocks of data.
143  * Made palman use it for .clr files.  Made alphacolors calculate on the
144  * fly rather than caching to/from disk.
145  * 
146  * 99    5/11/98 10:59a John
147  * Moved the low-level file reading code into cfilearchive.cpp.
148  * 
149  * 98    5/06/98 5:30p John
150  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
151  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
152  * DirectX header files and libs that fixed the Direct3D alpha blending
153  * problems.
154  * 
155  * 97    5/03/98 11:53a John
156  * Fixed filename case mangling.
157  * 
158  * 96    5/03/98 8:33a John
159  * Made sure there weren't any more broken function lurking around like
160  * the one Allender fixed.  
161  * 
162  * 95    5/02/98 11:05p Allender
163  * fix cfilelength for pack files
164  * 
165  *
166  * $NoKeywords: $
167  */
168 #define _CFILE_INTERNAL 
169
170 #include <stdlib.h>
171 #include <string.h>
172 #include <stdio.h>
173 #include <errno.h>
174 #ifndef PLAT_UNIX
175 #include <io.h>
176 #include <direct.h>
177 #include <windows.h>
178 #include <winbase.h>            /* needed for memory mapping of file functions */
179 #else
180 #include <unistd.h>
181 #include <sys/stat.h>
182 #include <sys/types.h>
183 #endif
184
185 #include "pstypes.h"
186 #include "cfile.h"
187 #include "encrypt.h"
188 //#include "outwnd.h"
189 //#include "vecmat.h"
190 //#include "timer.h"
191 #include "cfilesystem.h"
192 #include "cfilearchive.h"
193 #include "osapi.h"
194
195 char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
196
197 // During cfile_init, verify that Pathtypes[n].index == n for each item
198 // Each path must have a valid parent that can be tracable all the way back to the root 
199 // so that we can create directories when we need to.
200 //
201 cf_pathtype Pathtypes[CF_MAX_PATH_TYPES]  = {
202         // What type this is          Path                             Extensions              Parent type
203         { CF_TYPE_INVALID,                              NULL,                                                                           NULL,                                                   CF_TYPE_INVALID },
204         // Root must be index 1!!       
205         { CF_TYPE_ROOT,                                 "",                                                                             ".mve",                                                 CF_TYPE_ROOT    },
206         { CF_TYPE_DATA,                                 "Data",                                                                 ".cfg .log .txt",                       CF_TYPE_ROOT    },
207 #ifdef PLAT_UNIX
208         { CF_TYPE_MAPS,                                 "Data/Maps",                                                    ".pcx .ani .tga",                       CF_TYPE_DATA    },
209         { CF_TYPE_TEXT,                                 "Data/Text",                                                    ".txt .net",                            CF_TYPE_DATA    },
210         { CF_TYPE_MISSIONS,                             "Data/Missions",                                                ".fs2 .fc2 .ntl .ssv",  CF_TYPE_DATA    },
211         { CF_TYPE_MODELS,                                       "Data/Models",                                          ".pof",                                         CF_TYPE_DATA    },
212         { CF_TYPE_TABLES,                                       "Data/Tables",                                          ".tbl",                                         CF_TYPE_DATA    },
213         { CF_TYPE_SOUNDS,                                       "Data/Sounds",                                          ".wav",                                         CF_TYPE_DATA    },
214         { CF_TYPE_SOUNDS_8B22K,                 "Data/Sounds/8b22k",                            ".wav",                                         CF_TYPE_SOUNDS  },
215         { CF_TYPE_SOUNDS_16B11K,                "Data/Sounds/16b11k",                           ".wav",                                         CF_TYPE_SOUNDS  },
216         { CF_TYPE_VOICE,                                        "Data/Voice",                                                   "",                                                     CF_TYPE_DATA    },
217         { CF_TYPE_VOICE_BRIEFINGS,              "Data/Voice/Briefing",                  ".wav",                                         CF_TYPE_VOICE   },
218         { CF_TYPE_VOICE_CMD_BRIEF,              "Data/Voice/Command_briefings",".wav",                                          CF_TYPE_VOICE   },
219         { CF_TYPE_VOICE_DEBRIEFINGS,    "Data/Voice/Debriefing",                        ".wav",                                         CF_TYPE_VOICE   },
220         { CF_TYPE_VOICE_PERSONAS,               "Data/Voice/Personas",                  ".wav",                                         CF_TYPE_VOICE   },
221         { CF_TYPE_VOICE_SPECIAL,                "Data/Voice/Special",                           ".wav",                                         CF_TYPE_VOICE   },
222         { CF_TYPE_VOICE_TRAINING,               "Data/Voice/Training",                  ".wav",                                         CF_TYPE_VOICE   },
223         { CF_TYPE_MUSIC,                                        "Data/Music",                                                   ".wav",                                         CF_TYPE_VOICE   },
224         { CF_TYPE_MOVIES,                                       "Data/Movies",                                          ".mve .msb",                            CF_TYPE_DATA    },
225         { CF_TYPE_INTERFACE,                            "Data/Interface",                                       ".pcx .ani .tga",                       CF_TYPE_DATA    },
226         { CF_TYPE_FONT,                                 "Data/Fonts",                                                   ".vf",                                          CF_TYPE_DATA    },
227         { CF_TYPE_EFFECTS,                              "Data/Effects",                                         ".ani .pcx .neb .tga",  CF_TYPE_DATA    },
228         { CF_TYPE_HUD,                                          "Data/Hud",                                                     ".ani .pcx .tga",                       CF_TYPE_DATA    },
229         { CF_TYPE_PLAYER_MAIN,                  "Data/Players",                                         "",                                                     CF_TYPE_DATA    },
230         { CF_TYPE_PLAYER_IMAGES_MAIN,   "Data/Players/Images",                  ".pcx",                                         CF_TYPE_PLAYER_MAIN     },
231         { CF_TYPE_CACHE,                                        "Data/Cache",                                                   ".clr .tmp",                            CF_TYPE_DATA    },      //clr=cached color
232         { CF_TYPE_PLAYERS,                              "Data/Players",                                         ".hcf",                                         CF_TYPE_DATA    },      
233         { CF_TYPE_SINGLE_PLAYERS,               "Data/Players/Single",                  ".plr .csg .css",                       CF_TYPE_PLAYERS },
234         { CF_TYPE_MULTI_PLAYERS,                "Data/Players/Multi",                           ".plr",                                         CF_TYPE_DATA    },
235         { CF_TYPE_MULTI_CACHE,                  "Data/MultiData",                                       ".pcx .fs2",                            CF_TYPE_DATA    },
236         { CF_TYPE_CONFIG,                                       "Data/Config",                                          ".cfg",                                         CF_TYPE_DATA    },
237         { CF_TYPE_SQUAD_IMAGES_MAIN,    "Data/Players/Squads",                  ".pcx",                                         CF_TYPE_DATA    },
238         { CF_TYPE_DEMOS,                                        "Data/Demos",                                                   ".fsd",                                         CF_TYPE_DATA    },
239         { CF_TYPE_CBANIMS,                              "Data/CBAnims",                                         ".ani",                                         CF_TYPE_DATA    },
240         { CF_TYPE_INTEL_ANIMS,                  "Data/IntelAnims",                                      ".ani",                                         CF_TYPE_DATA    },
241 #else
242         { CF_TYPE_MAPS,                                 "Data\\Maps",                                                   ".pcx .ani .tga",                       CF_TYPE_DATA    },
243         { CF_TYPE_TEXT,                                 "Data\\Text",                                                   ".txt .net",                            CF_TYPE_DATA    },
244         { CF_TYPE_MISSIONS,                             "Data\\Missions",                                               ".fs2 .fc2 .ntl .ssv",  CF_TYPE_DATA    },
245         { CF_TYPE_MODELS,                                       "Data\\Models",                                         ".pof",                                         CF_TYPE_DATA    },
246         { CF_TYPE_TABLES,                                       "Data\\Tables",                                         ".tbl",                                         CF_TYPE_DATA    },
247         { CF_TYPE_SOUNDS,                                       "Data\\Sounds",                                         ".wav",                                         CF_TYPE_DATA    },
248         { CF_TYPE_SOUNDS_8B22K,                 "Data\\Sounds\\8b22k",                          ".wav",                                         CF_TYPE_SOUNDS  },
249         { CF_TYPE_SOUNDS_16B11K,                "Data\\Sounds\\16b11k",                         ".wav",                                         CF_TYPE_SOUNDS  },
250         { CF_TYPE_VOICE,                                        "Data\\Voice",                                                  "",                                                     CF_TYPE_DATA    },
251         { CF_TYPE_VOICE_BRIEFINGS,              "Data\\Voice\\Briefing",                        ".wav",                                         CF_TYPE_VOICE   },
252         { CF_TYPE_VOICE_CMD_BRIEF,              "Data\\Voice\\Command_briefings",".wav",                                                CF_TYPE_VOICE   },
253         { CF_TYPE_VOICE_DEBRIEFINGS,    "Data\\Voice\\Debriefing",                      ".wav",                                         CF_TYPE_VOICE   },
254         { CF_TYPE_VOICE_PERSONAS,               "Data\\Voice\\Personas",                        ".wav",                                         CF_TYPE_VOICE   },
255         { CF_TYPE_VOICE_SPECIAL,                "Data\\Voice\\Special",                         ".wav",                                         CF_TYPE_VOICE   },
256         { CF_TYPE_VOICE_TRAINING,               "Data\\Voice\\Training",                        ".wav",                                         CF_TYPE_VOICE   },
257         { CF_TYPE_MUSIC,                                        "Data\\Music",                                                  ".wav",                                         CF_TYPE_VOICE   },
258         { CF_TYPE_MOVIES,                                       "Data\\Movies",                                         ".mve .msb",                            CF_TYPE_DATA    },
259         { CF_TYPE_INTERFACE,                            "Data\\Interface",                                      ".pcx .ani .tga",                       CF_TYPE_DATA    },
260         { CF_TYPE_FONT,                                 "Data\\Fonts",                                                  ".vf",                                          CF_TYPE_DATA    },
261         { CF_TYPE_EFFECTS,                              "Data\\Effects",                                                ".ani .pcx .neb .tga",  CF_TYPE_DATA    },
262         { CF_TYPE_HUD,                                          "Data\\Hud",                                                    ".ani .pcx .tga",                       CF_TYPE_DATA    },
263         { CF_TYPE_PLAYER_MAIN,                  "Data\\Players",                                                "",                                                     CF_TYPE_DATA    },
264         { CF_TYPE_PLAYER_IMAGES_MAIN,   "Data\\Players\\Images",                        ".pcx",                                         CF_TYPE_PLAYER_MAIN     },
265         { CF_TYPE_CACHE,                                        "Data\\Cache",                                                  ".clr .tmp",                            CF_TYPE_DATA    },      //clr=cached color
266         { CF_TYPE_PLAYERS,                              "Data\\Players",                                                ".hcf",                                         CF_TYPE_DATA    },      
267         { CF_TYPE_SINGLE_PLAYERS,               "Data\\Players\\Single",                        ".plr .csg .css",                       CF_TYPE_PLAYERS },
268         { CF_TYPE_MULTI_PLAYERS,                "Data\\Players\\Multi",                         ".plr",                                         CF_TYPE_DATA    },
269         { CF_TYPE_MULTI_CACHE,                  "Data\\MultiData",                                      ".pcx .fs2",                            CF_TYPE_DATA    },
270         { CF_TYPE_CONFIG,                                       "Data\\Config",                                         ".cfg",                                         CF_TYPE_DATA    },
271         { CF_TYPE_SQUAD_IMAGES_MAIN,    "Data\\Players\\Squads",                        ".pcx",                                         CF_TYPE_DATA    },
272         { CF_TYPE_DEMOS,                                        "Data\\Demos",                                                  ".fsd",                                         CF_TYPE_DATA    },
273         { CF_TYPE_CBANIMS,                              "Data\\CBAnims",                                                ".ani",                                         CF_TYPE_DATA    },
274         { CF_TYPE_INTEL_ANIMS,                  "Data\\IntelAnims",                                     ".ani",                                         CF_TYPE_DATA    },
275 #endif
276 };
277
278
279 #define CFILE_STACK_MAX 8
280
281 int cfile_inited = 0;
282 int Cfile_stack_pos = 0;
283
284 char Cfile_stack[128][CFILE_STACK_MAX];
285
286 Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS];
287 CFILE Cfile_list[MAX_CFILE_BLOCKS];
288
289 char *Cfile_cdrom_dir = NULL;
290
291 //
292 // Function prototypes for internally-called functions
293 //
294 int cfget_cfile_block();
295 CFILE *cf_open_fill_cfblock(FILE * fp, int type);
296 CFILE *cf_open_packed_cfblock(FILE *fp, int type, int offset, int size);
297 CFILE *cf_open_mapped_fill_cfblock(HANDLE hFile, int type);
298 void cf_chksum_long_init();
299
300 void cfile_close()
301 {
302         cf_free_secondary_filelist();
303 }
304
305 // determine if the given path is in a root directory (c:\  or  c:\freespace2.exe  or  c:\fred2.exe   etc)
306 int cfile_in_root_dir(char *exe_path)
307 {
308         int token_count = 0;
309         char path_copy[2048] = "";
310         char *tok;
311
312         // bogus
313         if(exe_path == NULL){
314                 return 1;
315         }
316
317         // copy the path
318         memset(path_copy, 0, 2048);
319         strncpy(path_copy, exe_path, 2047);
320
321         // count how many slashes there are in the path
322 #ifdef PLAT_UNIX
323         tok = strtok(path_copy, "/");
324 #else
325         tok = strtok(path_copy, "\\");
326 #endif
327         if(tok == NULL){
328                 return 1;
329         }       
330         do {
331                 token_count++;
332 #ifdef PLAT_UNIX
333                 tok = strtok(NULL, "/");
334 #else
335                 tok = strtok(NULL, "\\");
336 #endif
337         } while(tok != NULL);
338                 
339         // root directory if we have <= 1 slash
340         if(token_count <= 2){
341                 return 1;
342         }
343
344         // not-root directory
345         return 0;
346 }
347
348 // cfile_init() initializes the cfile system.  Called once at application start.
349 //
350 //      returns:  success ==> 0
351 //           error   ==> non-zero
352 //
353 int cfile_init(char *exe_dir, char *cdrom_dir)
354 {
355         int i;
356
357         // initialize encryption
358         encrypt_init(); 
359
360         if ( !cfile_inited ) {
361                 char buf[128];
362
363                 cfile_inited = 1;
364
365                 strcpy(buf, exe_dir);
366                 i = strlen(buf);
367
368                 // are we in a root directory?          
369                 if(cfile_in_root_dir(buf)){
370 #ifdef PLAT_UNIX
371                         fprintf (stderr, "ERROR: Freespace2/Fred2 cannot be run from a drive root directory!\n");
372 #else
373                         MessageBox((HWND)NULL, "Freespace2/Fred2 cannot be run from a drive root directory!", "Error", MB_OK);
374 #endif
375                         return 1;
376                 }               
377
378                 while (i--) {
379 #ifdef PLAT_UNIX
380                         if (buf[i] == '/'){
381 #else
382                         if (buf[i] == '\\'){
383 #endif
384                                 break;
385                         }
386                 }                                               
387
388                 if (i >= 2) {                                   
389                         buf[i] = 0;                                             
390                         cfile_chdir(buf);
391                 } else {
392 #ifdef PLAT_UNIX
393                         fprintf (stderr, "Error trying to determine executable root directory!");
394 #else
395                         MessageBox((HWND)NULL, "Error trying to determine executable root directory!", "Error", MB_OK);
396 #endif
397                         return 1;
398                 }
399
400                 // set root directory
401                 strncpy(Cfile_root_dir, buf, CFILE_ROOT_DIRECTORY_LEN-1);
402
403                 for ( i = 0; i < MAX_CFILE_BLOCKS; i++ ) {
404                         Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
405                 }
406
407                 Cfile_cdrom_dir = cdrom_dir;
408                 cf_build_secondary_filelist(Cfile_cdrom_dir);
409
410                 // 32 bit CRC table init
411                 cf_chksum_long_init();
412
413                 atexit( cfile_close );
414         }
415
416         return 0;
417 }
418
419 // Call this if pack files got added or removed or the
420 // cdrom changed.  This will refresh the list of filenames 
421 // stored in packfiles and on the cdrom.
422 void cfile_refresh()
423 {
424         cf_build_secondary_filelist(Cfile_cdrom_dir);
425 }
426
427
428 // Changes to a drive if valid.. 1=A, 2=B, etc
429 // If flag, then changes to it.
430 // Returns 0 if not-valid, 1 if valid.
431 int cfile_chdrive( int DriveNum, int flag )
432 {
433 #ifdef PLAT_UNIX
434         STUB_FUNCTION;
435         return 0;
436 #else
437         int n, org;
438         int Valid = 0;
439
440         org = -1;
441         if (!flag)
442                 org = _getdrive();
443
444         _chdrive( DriveNum );
445         n = _getdrive();
446
447
448         if (n == DriveNum )
449                 Valid = 1;
450
451         if ( (!flag) && (n != org) )
452                 _chdrive( org );
453         return Valid;
454 #endif
455 }
456
457 // push current directory on a 'stack' (so we can restore it) and change the directory
458 int cfile_push_chdir(int type)
459 {
460         int e;
461         char dir[128];
462         char OriginalDirectory[128];
463         char *Path;
464         char NoDir[] = "\\.";
465
466         _getcwd(OriginalDirectory, 127);
467         Assert(Cfile_stack_pos < CFILE_STACK_MAX);
468         strcpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
469
470         cf_create_default_path_string( dir, type, NULL );
471         _strlwr(dir);
472 #ifndef PLAT_UNIX
473         char *Drive = strchr(dir, ':');
474
475         if (Drive) {
476                 if (!cfile_chdrive( *(Drive - 1) - 'a' + 1, 1))
477                         return 1;
478
479                 Path = Drive+1;
480
481         } else 
482 #endif
483         {
484                 Path = dir;
485         }
486
487         if (!(*Path)) {
488                 Path = NoDir;
489         }
490
491         // This chdir might get a critical error!
492         e = _chdir( Path );
493         if (e) {
494                 cfile_chdrive( OriginalDirectory[0] - 'a' + 1, 1 );
495                 return 2;
496         }
497
498         return 0;
499 }
500
501
502 int cfile_chdir(char *dir)
503 {
504         int e;
505         char OriginalDirectory[128];
506         char *Path;
507         char NoDir[] = "\\.";
508
509         _getcwd(OriginalDirectory, 127);
510         _strlwr(dir);
511
512 #ifndef PLAT_UNIX
513         char *Drive = strchr(dir, ':');
514         if (Drive)      {
515                 if (!cfile_chdrive( *(Drive - 1) - 'a' + 1, 1))
516                         return 1;
517
518                 Path = Drive+1;
519
520         } else 
521 #endif
522         {
523                 Path = dir;
524         }
525
526         if (!(*Path)) {
527                 Path = NoDir;
528         }
529
530         // This chdir might get a critical error!
531         e = _chdir( Path );
532         if (e) {
533                 cfile_chdrive( OriginalDirectory[0] - 'a' + 1, 1 );
534                 return 2;
535         }
536
537         return 0;
538 }
539
540 int cfile_pop_dir()
541 {
542         Assert(Cfile_stack_pos);
543         Cfile_stack_pos--;
544         return cfile_chdir(Cfile_stack[Cfile_stack_pos]);
545 }
546
547 // flush (delete all files in) the passed directory (by type), return the # of files deleted
548 // NOTE : WILL NOT DELETE READ-ONLY FILES
549 int cfile_flush_dir(int dir_type)
550 {
551 #ifdef PLAT_UNIX
552         STUB_FUNCTION;
553         return 0;
554 #else
555         int find_handle;
556         int del_count;
557         _finddata_t find;
558
559         Assert( CF_TYPE_SPECIFIED(dir_type) );
560
561         // attempt to change the directory to the passed type
562         if(cfile_push_chdir(dir_type)){
563                 return 0;
564         }
565
566         // proceed to delete the files
567         find_handle = _findfirst( "*", &find );
568         del_count = 0;
569         if (find_handle != -1) {
570                 do {                    
571                         if (!(find.attrib & _A_SUBDIR) && !(find.attrib & _A_RDONLY)) {
572                                 // delete the file
573                                 cf_delete(find.name,dir_type);                          
574
575                                 // increment the deleted count
576                                 del_count++;
577                         }
578                 } while (!_findnext(find_handle, &find));
579                 _findclose( find_handle );
580         }
581
582         // pop the directory back
583         cfile_pop_dir();
584
585         // return the # of files deleted
586         return del_count;
587 #endif
588 }
589
590
591 // add the given extention to a filename (or filepath) if it doesn't already have this
592 // extension.
593 //    filename = name of filename or filepath to process
594 //    ext = extension to add.  Must start with the period
595 //    Returns: new filename or filepath with extension.
596 char *cf_add_ext(char *filename, char *ext)
597 {
598         int flen, elen;
599         static char path[MAX_PATH_LEN];
600
601         flen = strlen(filename);
602         elen = strlen(ext);
603         Assert(flen < MAX_PATH_LEN);
604         strcpy(path, filename);
605         if ((flen < 4) || stricmp(path + flen - elen, ext)) {
606                 Assert(flen + elen < MAX_PATH_LEN);
607                 strcat(path, ext);
608         }
609
610         return path;
611 }
612
613 // Deletes a file.
614 void cf_delete( char *filename, int dir_type )
615 {
616         char longname[MAX_PATH_LEN];
617
618         Assert( CF_TYPE_SPECIFIED(dir_type) );
619
620         cf_create_default_path_string( longname, dir_type, filename );
621
622         FILE *fp = fopen(longname, "rb");
623         if (fp) {
624                 // delete the file
625                 fclose(fp);
626                 _unlink(longname);
627         }
628
629 }
630
631
632 // Same as _access function to read a file's access bits
633 int cf_access( char *filename, int dir_type, int mode )
634 {
635         char longname[MAX_PATH_LEN];
636
637         Assert( CF_TYPE_SPECIFIED(dir_type) );
638
639         cf_create_default_path_string( longname, dir_type, filename );
640
641         return access(longname,mode);
642 }
643
644
645 // Returns 1 if file exists, 0 if not.
646 int cf_exist( char *filename, int dir_type )
647 {
648         char longname[MAX_PATH_LEN];
649
650         Assert( CF_TYPE_SPECIFIED(dir_type) );
651
652         cf_create_default_path_string( longname, dir_type, filename );
653
654         FILE *fp = fopen(longname, "rb");
655         if (fp) {
656                 return 1;
657                 fclose(fp);
658         }
659
660         return 0;
661 }
662
663 void cf_attrib(char *filename, int set, int clear, int dir_type)
664 {
665         char longname[MAX_PATH_LEN];
666
667         Assert( CF_TYPE_SPECIFIED(dir_type) );
668
669         cf_create_default_path_string( longname, dir_type, filename );
670
671         FILE *fp = fopen(longname, "rb");
672         if (fp) {
673                 fclose(fp);
674
675 #ifdef PLAT_UNIX
676                 STUB_FUNCTION;
677 #else
678                 DWORD z = GetFileAttributes(longname);
679                 SetFileAttributes(longname, z | set & ~clear);
680 #endif
681         }
682
683 }
684
685 int cf_rename(char *old_name, char *name, int dir_type)
686 {
687         Assert( CF_TYPE_SPECIFIED(dir_type) );
688
689         int ret_code;
690         char old_longname[_MAX_PATH];
691         char new_longname[_MAX_PATH];
692         
693         cf_create_default_path_string( old_longname, dir_type, old_name );
694         cf_create_default_path_string( new_longname, dir_type, name );
695
696         ret_code = rename(old_longname, new_longname );         
697         if(ret_code != 0){
698                 switch(errno){
699                 case EACCES :
700                         return CF_RENAME_FAIL_ACCESS;
701                 case ENOENT :
702                 default:
703                         return CF_RENAME_FAIL_EXIST;
704                 }
705         }
706
707         return CF_RENAME_SUCCESS;
708         
709
710 }
711
712 // Creates the directory path if it doesn't exist. Even creates all its
713 // parent paths.
714 void cf_create_directory( int dir_type )
715 {
716         int num_dirs = 0;
717         int dir_tree[CF_MAX_PATH_TYPES];
718         char longname[MAX_PATH_LEN];
719
720         Assert( CF_TYPE_SPECIFIED(dir_type) );
721
722         int current_dir = dir_type;
723
724         do {
725                 Assert( num_dirs < CF_MAX_PATH_TYPES );         // Invalid Pathtypes data?
726
727                 dir_tree[num_dirs++] = current_dir;
728                 current_dir = Pathtypes[current_dir].parent_index;
729
730         } while( current_dir != CF_TYPE_ROOT );
731
732         
733         int i;
734
735         for (i=num_dirs-1; i>=0; i-- )  {
736                 cf_create_default_path_string( longname, dir_tree[i], NULL );
737
738 #ifdef PLAT_UNIX
739                 if ( _mkdir(longname, 0777)==0 )        {
740                         mprintf(( "CFILE: Created new directory '%s'\n", longname ));
741                 }
742 #else
743                 if ( _mkdir(longname)==0 )      {
744                         mprintf(( "CFILE: Created new directory '%s'\n", longname ));
745                 }
746 #endif
747         }
748
749
750 }
751
752
753 extern int game_cd_changed();
754
755 // cfopen()
756 //
757 // parameters:  *filepath ==> name of file to open (may be path+name)
758 //              *mode     ==> specifies how file should be opened (eg "rb" for read binary)
759 //                            passing NULL to mode deletes the file if it exists and returns NULL
760 //               type     ==> one of:    CFILE_NORMAL
761 //                                       CFILE_MEMORY_MAPPED
762 //                                        dir_type      =>      override extension check, value is one of CF_TYPE* #defines
763 //
764 //               NOTE: type parameter is an optional parameter.  The default value is CFILE_NORMAL
765 //
766 //
767 // returns:             success ==> address of CFILE structure
768 //                                      error   ==> NULL
769 //
770
771 CFILE *cfopen(char *file_path, char *mode, int type, int dir_type, bool localize)
772 {
773         char longname[_MAX_PATH];
774
775 //      nprintf(("CFILE", "CFILE -- trying to open %s\n", file_path ));
776 // #if !defined(MULTIPLAYER_BETA_BUILD) && !defined(FS2_DEMO)
777
778 // we no longer need to do this, and on machines with crappy-ass drivers it can slow things down horribly.
779 #if 0   
780         if ( game_cd_changed() ) {
781                 cfile_refresh();
782         }
783 #endif
784
785         //================================================
786         // Check that all the parameters make sense
787         Assert(file_path && strlen(file_path));
788         Assert( mode != NULL );
789         
790         // Can only open read-only binary files in memory mapped mode.
791         if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") ) {
792                 Int3();                         
793                 return NULL;
794         }
795
796         //===========================================================
797         // If in write mode, just try to open the file straight off
798         // the harddisk.  No fancy packfile stuff here!
799         
800         if ( strchr(mode,'w') ) {
801                 // For write-only files, require a full path or a path type
802                 if ( strpbrk(file_path,"/\\:")  ) {  
803                         // Full path given?
804                         strcpy(longname, file_path );
805                 } else {
806                         // Path type given?
807                         Assert( dir_type != CF_TYPE_ANY );
808
809                         // Create the directory if necessary
810                         cf_create_directory( dir_type );
811
812                         cf_create_default_path_string( longname, dir_type, file_path );
813                 }
814                 Assert( !(type & CFILE_MEMORY_MAPPED) );
815
816                 // JOHN: TODO, you should create the path if it doesn't exist.
817                                 
818                 FILE *fp = fopen(longname, mode);
819                 if (fp) {
820                         return cf_open_fill_cfblock(fp, dir_type);
821                 }
822                 return NULL;
823         } 
824
825
826         //================================================
827         // Search for file on disk, on cdrom, or in a packfile
828
829         int offset, size;
830         char copy_file_path[MAX_PATH_LEN];  // FIX change in memory from cf_find_file_location
831         strcpy(copy_file_path, file_path);
832
833
834         if ( cf_find_file_location( copy_file_path, dir_type, longname, &size, &offset, localize ) )    {
835
836                 // Fount it, now create a cfile out of it
837                 
838                 if ( type & CFILE_MEMORY_MAPPED ) {
839                 
840                         // Can't open memory mapped files out of pack files
841                         if ( offset == 0 )      {
842 #ifdef PLAT_UNIX
843                                 STUB_FUNCTION;
844 #else
845                                 HANDLE hFile;
846
847                                 hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
848
849                                 if (hFile != INVALID_HANDLE_VALUE)      {
850                                         return cf_open_mapped_fill_cfblock(hFile, dir_type);
851                                 }
852 #endif
853                         } 
854
855                 } else {
856
857                         FILE *fp = fopen( longname, "rb" );
858
859                         if ( fp )       {
860                                 if ( offset )   {
861                                         // Found it in a pack file
862                                         return cf_open_packed_cfblock(fp, dir_type, offset, size );
863                                 } else {
864                                         // Found it in a normal file
865                                         return cf_open_fill_cfblock(fp, dir_type);
866                                 } 
867                         }
868                 }
869
870         }
871
872         return NULL;
873 }
874
875
876 // ------------------------------------------------------------------------
877 // ctmpfile() 
878 //
879 // Open up a temporary file.  A unique name is automatically generated.  The
880 // file will be automatically deleted when file is closed.
881 //
882 // return:              NULL                                    =>              tmp file could not be opened
883 //                                      pointer to CFILE        =>              tmp file successfully opened
884 //
885 CFILE *ctmpfile()
886 {
887         FILE    *fp;
888         fp = tmpfile();
889         if ( fp )
890                 return cf_open_fill_cfblock(fp, 0);
891         else
892                 return NULL;
893 }
894
895
896
897 // cfget_cfile_block() will try to find an empty Cfile_block structure in the
898 //      Cfile_block_list[] array and return the index.
899 //
900 // returns:   success ==> index in Cfile_block_list[] array
901 //            failure ==> -1
902 //
903 int cfget_cfile_block()
904 {       
905         int i;
906         Cfile_block *cb;
907
908         for ( i = 0; i < MAX_CFILE_BLOCKS; i++ ) {
909                 cb = &Cfile_block_list[i];
910                 if ( cb->type == CFILE_BLOCK_UNUSED ) {
911                         cb->data = NULL;
912                         cb->fp = NULL;
913                         cb->type = CFILE_BLOCK_USED;
914                         return i;
915                 }
916         }
917
918         // If we've reached this point, a free Cfile_block could not be found
919         nprintf(("Warning","A free Cfile_block could not be found.\n"));
920         Assert(0);      // out of free cfile blocks
921         return -1;                      
922 }
923
924
925 // cfclose() closes the file
926 //
927 // returns:   success ==> 0
928 //                                failure ==> EOF
929 //
930 int cfclose( CFILE * cfile )
931 {
932         int result;
933
934         Assert(cfile != NULL);
935         Cfile_block *cb;
936         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
937         cb = &Cfile_block_list[cfile->id];      
938
939         result = 0;
940         if ( cb->data ) {
941                 // close memory mapped file
942 #ifdef PLAT_UNIX
943                 STUB_FUNCTION;
944 #else
945                 result = UnmapViewOfFile((void*)cb->data);
946                 Assert(result);
947                 result = CloseHandle(cb->hInFile);              
948                 Assert(result); // Ensure file handle is closed properly
949                 result = CloseHandle(cb->hMapFile);             
950                 Assert(result); // Ensure file handle is closed properly
951 #endif
952                 result = 0;
953
954         } else if ( cb->fp != NULL )    {
955                 Assert(cb->fp != NULL);
956                 result = fclose(cb->fp);
957         } else {
958                 // VP  do nothing
959         }
960
961         cb->type = CFILE_BLOCK_UNUSED;
962         return result;
963 }
964
965
966
967
968 // cf_open_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
969 // for the case of a file being opened by cf_open();
970 //
971 // returns:   success ==> ptr to CFILE structure.  
972 //            error   ==> NULL
973 //
974 CFILE *cf_open_fill_cfblock(FILE *fp, int type)
975 {
976         int cfile_block_index;
977
978         cfile_block_index = cfget_cfile_block();
979         if ( cfile_block_index == -1 ) {
980                 return NULL;
981         } else {
982                 CFILE *cfp;
983                 Cfile_block *cfbp;
984                 cfbp = &Cfile_block_list[cfile_block_index];
985                 cfp = &Cfile_list[cfile_block_index];;
986                 cfp->id = cfile_block_index;
987                 cfp->version = 0;
988                 cfbp->data = NULL;
989                 cfbp->fp = fp;
990                 cfbp->dir_type = type;
991                 
992                 cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)) );
993
994                 return cfp;
995         }
996 }
997
998
999 // cf_open_packed_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
1000 // for the case of a file being opened by cf_open();
1001 //
1002 // returns:   success ==> ptr to CFILE structure.  
1003 //            error   ==> NULL
1004 //
1005 CFILE *cf_open_packed_cfblock(FILE *fp, int type, int offset, int size)
1006 {
1007         // Found it in a pack file
1008         int cfile_block_index;
1009         
1010         cfile_block_index = cfget_cfile_block();
1011         if ( cfile_block_index == -1 ) {
1012                 return NULL;
1013         } else {
1014                 CFILE *cfp;
1015                 Cfile_block *cfbp;
1016                 cfbp = &Cfile_block_list[cfile_block_index];
1017         
1018                 cfp = &Cfile_list[cfile_block_index];
1019                 cfp->id = cfile_block_index;
1020                 cfp->version = 0;
1021                 cfbp->data = NULL;
1022                 cfbp->fp = fp;
1023                 cfbp->dir_type = type;
1024
1025                 cf_init_lowlevel_read_code(cfp,offset, size );
1026
1027                 return cfp;
1028         }
1029
1030 }
1031
1032
1033
1034 // cf_open_mapped_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
1035 // for the case of a file being opened by cf_open_mapped();
1036 //
1037 // returns:   ptr CFILE structure.  
1038 //
1039 CFILE *cf_open_mapped_fill_cfblock(HANDLE hFile, int type)
1040 {
1041         int cfile_block_index;
1042
1043         cfile_block_index = cfget_cfile_block();
1044         if ( cfile_block_index == -1 ) {
1045                 return NULL;
1046         }
1047         else {
1048                 CFILE *cfp;
1049                 Cfile_block *cfbp;
1050                 cfbp = &Cfile_block_list[cfile_block_index];
1051
1052                 cfp = &Cfile_list[cfile_block_index];
1053                 cfp->id = cfile_block_index;
1054                 cfbp->fp = NULL;
1055                 cfbp->hInFile = hFile;
1056                 cfbp->dir_type = type;
1057
1058                 cf_init_lowlevel_read_code(cfp,0 , 0 );
1059
1060 #ifdef PLAT_UNIX
1061                 STUB_FUNCTION;
1062 #else
1063                 cfbp->hMapFile = CreateFileMapping(cfbp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
1064                 if (cfbp->hMapFile == NULL) { 
1065                         nprintf(("Error", "Could not create file-mapping object.\n")); 
1066                         return NULL;
1067                 } 
1068         
1069                 cfbp->data = (ubyte*)MapViewOfFile(cfbp->hMapFile, FILE_MAP_READ, 0, 0, 0);
1070                 Assert( cfbp->data != NULL );           
1071 #endif
1072                 return cfp;
1073         }
1074 }
1075
1076 int cf_get_dir_type(CFILE *cfile)
1077 {
1078         return Cfile_block_list[cfile->id].dir_type;
1079 }
1080
1081 // cf_returndata() returns the data pointer for a memory-mapped file that is associated
1082 // with the CFILE structure passed as a parameter
1083 //
1084 // 
1085
1086 void *cf_returndata(CFILE *cfile)
1087 {
1088         Assert(cfile != NULL);
1089         Cfile_block *cb;
1090         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1091         cb = &Cfile_block_list[cfile->id];      
1092         Assert(cb->data != NULL);
1093         return cb->data;
1094 }
1095
1096
1097
1098 // version number of opened file.  Will be 0 unless you put something else here after you
1099 // open a file.  Once set, you can use minimum version numbers with the read functions.
1100 void cf_set_version( CFILE * cfile, int version )
1101 {
1102         Assert(cfile != NULL);
1103
1104         cfile->version = version;
1105 }
1106
1107 // routines to read basic data types from CFILE's.  Put here to
1108 // simplify mac/pc reading from cfiles.
1109
1110 float cfread_float(CFILE *file, int ver, float deflt)
1111 {
1112         float f;
1113
1114         if (file->version < ver)
1115                 return deflt;
1116
1117         if (cfread( &f, sizeof(f), 1, file) != 1)
1118                 return deflt;
1119
1120 //      i = INTEL_INT(i);                       //  hmm, not sure what to do here
1121         return f;
1122 }
1123
1124 int cfread_int(CFILE *file, int ver, int deflt)
1125 {
1126         int i;
1127
1128         if (file->version < ver)
1129                 return deflt;
1130
1131         if (cfread( &i, sizeof(i), 1, file) != 1)
1132                 return deflt;
1133
1134         i = INTEL_INT(i);
1135         return i;
1136 }
1137
1138 uint cfread_uint(CFILE *file, int ver, uint deflt)
1139 {
1140         uint i;
1141
1142         if (file->version < ver)
1143                 return deflt;
1144
1145         if (cfread( &i, sizeof(i), 1, file) != 1)
1146                 return deflt;
1147
1148         i = INTEL_INT(i);
1149         return i;
1150 }
1151
1152 short cfread_short(CFILE *file, int ver, short deflt)
1153 {
1154         short s;
1155
1156         if (file->version < ver)
1157                 return deflt;
1158
1159         if (cfread( &s, sizeof(s), 1, file) != 1)
1160                 return deflt;
1161
1162         s = INTEL_SHORT(s);
1163         return s;
1164 }
1165
1166 ushort cfread_ushort(CFILE *file, int ver, ushort deflt)
1167 {
1168         ushort s;
1169
1170         if (file->version < ver)
1171                 return deflt;
1172
1173         if (cfread( &s, sizeof(s), 1, file) != 1)
1174                 return deflt;
1175
1176         s = INTEL_SHORT(s);
1177         return s;
1178 }
1179
1180 ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
1181 {
1182         ubyte b;
1183
1184         if (file->version < ver)
1185                 return deflt;
1186
1187         if (cfread( &b, sizeof(b), 1, file) != 1)
1188                 return deflt;
1189
1190         return b;
1191 }
1192
1193 void cfread_vector(vector *vec, CFILE *file, int ver, vector *deflt)
1194 {
1195         if (file->version < ver) {
1196                 if (deflt)
1197                         *vec = *deflt;
1198                 else
1199                         vec->x = vec->y = vec->z = 0.0f;
1200
1201                 return;
1202         }
1203
1204         vec->x = cfread_float(file, ver, deflt ? deflt->x : 0.0f);
1205         vec->y = cfread_float(file, ver, deflt ? deflt->y : 0.0f);
1206         vec->z = cfread_float(file, ver, deflt ? deflt->z : 0.0f);
1207 }
1208         
1209 void cfread_angles(angles *ang, CFILE *file, int ver, angles *deflt)
1210 {
1211         if (file->version < ver) {
1212                 if (deflt)
1213                         *ang = *deflt;
1214                 else
1215                         ang->p = ang->b = ang->h = 0.0f;
1216
1217                 return;
1218         }
1219
1220         ang->p = cfread_float(file, ver, deflt ? deflt->p : 0.0f);
1221         ang->b = cfread_float(file, ver, deflt ? deflt->b : 0.0f);
1222         ang->h = cfread_float(file, ver, deflt ? deflt->h : 0.0f);
1223 }
1224
1225 char cfread_char(CFILE *file, int ver, char deflt)
1226 {
1227         char b;
1228
1229         if (file->version < ver)
1230                 return deflt;
1231
1232         if (cfread( &b, sizeof(b), 1, file) != 1)
1233                 return deflt;
1234
1235         return b;
1236 }
1237
1238 void cfread_string(char *buf, int n, CFILE *file)
1239 {
1240         char c;
1241
1242         do {
1243                 c = cfread_char(file);
1244                 if ( n > 0 )    {
1245                         *buf++ = c;
1246                         n--;
1247                 }
1248         } while (c != 0 );
1249 }
1250
1251 void cfread_string_len(char *buf,int n, CFILE *file)
1252 {
1253         int len;
1254         len = cfread_int(file);
1255         Assert( len < n );
1256         if (len)
1257                 cfread(buf, len, 1, file);
1258
1259         buf[len] = 0;
1260 }
1261
1262 // equivalent write functions of above read functions follow
1263
1264 int cfwrite_float(float f, CFILE *file)
1265 {
1266 //      i = INTEL_INT(i);                       //  hmm, not sure what to do here
1267         return cfwrite(&f, sizeof(f), 1, file);
1268 }
1269
1270 int cfwrite_int(int i, CFILE *file)
1271 {
1272         i = INTEL_INT(i);
1273         return cfwrite(&i, sizeof(i), 1, file);
1274 }
1275
1276 int cfwrite_uint(uint i, CFILE *file)
1277 {
1278         i = INTEL_INT(i);
1279         return cfwrite(&i, sizeof(i), 1, file);
1280 }
1281
1282 int cfwrite_short(short s, CFILE *file)
1283 {
1284         s = INTEL_SHORT(s);
1285         return cfwrite(&s, sizeof(s), 1, file);
1286 }
1287
1288 int cfwrite_ushort(ushort s, CFILE *file)
1289 {
1290         s = INTEL_SHORT(s);
1291         return cfwrite(&s, sizeof(s), 1, file);
1292 }
1293
1294 int cfwrite_ubyte(ubyte b, CFILE *file)
1295 {
1296         return cfwrite(&b, sizeof(b), 1, file);
1297 }
1298
1299 int cfwrite_vector(vector *vec, CFILE *file)
1300 {
1301         if(!cfwrite_float(vec->x, file)){
1302                 return 0;
1303         }
1304         if(!cfwrite_float(vec->y, file)){
1305                 return 0;
1306         }
1307         return cfwrite_float(vec->z, file);
1308 }
1309
1310 int cfwrite_angles(angles *ang, CFILE *file)
1311 {
1312         if(!cfwrite_float(ang->p, file)){
1313                 return 0;
1314         }
1315         if(!cfwrite_float(ang->b, file)){
1316                 return 0;
1317         }
1318         return cfwrite_float(ang->h, file);
1319 }
1320
1321 int cfwrite_char(char b, CFILE *file)
1322 {
1323         return cfwrite( &b, sizeof(b), 1, file);
1324 }
1325
1326 int cfwrite_string(char *buf, CFILE *file)
1327 {
1328         if ( (!buf) || (buf && !buf[0]) ) {
1329                 return cfwrite_char(0, file);
1330         } 
1331         int len = strlen(buf);
1332         if(!cfwrite(buf, len, 1, file)){
1333                 return 0;
1334         }
1335         return cfwrite_char(0, file);                   // write out NULL termination                   
1336 }
1337
1338 int cfwrite_string_len(char *buf, CFILE *file)
1339 {
1340         int len = strlen(buf);
1341
1342         if(!cfwrite_int(len, file)){
1343                 return 0;
1344         }
1345         if (len){
1346                 return cfwrite(buf,len,1,file);
1347         } 
1348
1349         return 1;
1350 }
1351
1352 // Get the filelength
1353 int cfilelength( CFILE * cfile )
1354 {
1355         Assert(cfile != NULL);
1356         Cfile_block *cb;
1357         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1358         cb = &Cfile_block_list[cfile->id];      
1359
1360         // TODO: return length of memory mapped file
1361         Assert( !cb->data );
1362
1363         Assert(cb->fp != NULL);
1364
1365         // cb->size gets set at cfopen
1366         return cb->size;
1367 }
1368
1369 // cfwrite() writes to the file
1370 //
1371 // returns:   number of full elements actually written
1372 //            
1373 //
1374 int cfwrite(void *buf, int elsize, int nelem, CFILE *cfile)
1375 {
1376         Assert(cfile != NULL);
1377         Assert(buf != NULL);
1378         Assert(elsize > 0);
1379         Assert(nelem > 0);
1380
1381         Cfile_block *cb;
1382         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1383         cb = &Cfile_block_list[cfile->id];      
1384
1385         int result = 0;
1386
1387         // cfwrite() not supported for memory-mapped files
1388         Assert( !cb->data );
1389
1390         Assert(cb->fp != NULL);
1391         Assert(cb->lib_offset == 0 );
1392         result = fwrite(buf, elsize, nelem, cb->fp);
1393
1394         return result;  
1395 }
1396
1397
1398 // cfputc() writes a character to a file
1399 //
1400 // returns:   success ==> returns character written
1401 //                                error   ==> EOF
1402 //
1403 int cfputc(int c, CFILE *cfile)
1404 {
1405         int result;
1406
1407         Assert(cfile != NULL);
1408         Cfile_block *cb;
1409         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1410         cb = &Cfile_block_list[cfile->id];      
1411
1412         result = 0;
1413         // cfputc() not supported for memory-mapped files
1414         Assert( !cb->data );
1415
1416         Assert(cb->fp != NULL);
1417         result = fputc(c, cb->fp);
1418
1419         return result;  
1420 }
1421
1422
1423 // cfgetc() reads a character from a file
1424 //
1425 // returns:   success ==> returns character read
1426 //                                error   ==> EOF
1427 //
1428 int cfgetc(CFILE *cfile)
1429 {
1430         Assert(cfile != NULL);
1431         
1432         char tmp;
1433
1434         int result = cfread(&tmp, 1, 1, cfile );
1435         if ( result == 1 )      {
1436                 result = char(tmp);
1437         } else {
1438                 result = CF_EOF;
1439         }
1440
1441         return result;  
1442 }
1443
1444
1445
1446
1447
1448 // cfgets() reads a string from a file
1449 //
1450 // returns:   success ==> returns pointer to string
1451 //                                error   ==> NULL
1452 //
1453 char *cfgets(char *buf, int n, CFILE *cfile)
1454 {
1455         Assert(cfile != NULL);
1456         Assert(buf != NULL);
1457         Assert(n > 0 );
1458
1459         char * t = buf;
1460         int i, c;
1461
1462         for (i=0; i<n-1; i++ )  {
1463                 do {
1464                         char tmp_c;
1465
1466                         int ret = cfread( &tmp_c, 1, 1, cfile );
1467                         if ( ret != 1 ) {
1468                                 *buf = 0;
1469                                 if ( buf > t )  {               
1470                                         return t;
1471                                 } else {
1472                                         return NULL;
1473                                 }
1474                         }
1475                         c = int(tmp_c);
1476                 } while ( c == 13 );
1477                 *buf++ = char(c);
1478                 if ( c=='\n' ) break;
1479         }
1480         *buf++ = 0;
1481
1482         return  t;
1483 }
1484
1485 // cfputs() writes a string to a file
1486 //
1487 // returns:   success ==> non-negative value
1488 //                                error   ==> EOF
1489 //
1490 int cfputs(char *str, CFILE *cfile)
1491 {
1492         Assert(cfile != NULL);
1493         Assert(str != NULL);
1494
1495         Cfile_block *cb;
1496         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1497         cb = &Cfile_block_list[cfile->id];      
1498
1499         int result;
1500
1501         result = 0;
1502         // cfputs() not supported for memory-mapped files
1503         Assert( !cb->data );
1504         Assert(cb->fp != NULL);
1505         result = fputs(str, cb->fp);
1506
1507         return result;  
1508 }
1509
1510
1511 // 16 and 32 bit checksum stuff ----------------------------------------------------------
1512
1513 // CRC code for mission validation.  given to us by Kevin Bentley on 7/20/98.   Some sort of
1514 // checksumming code that he wrote a while ago.  
1515 #define CRC32_POLYNOMIAL                                        0xEDB88320L
1516 unsigned long CRCTable[256];
1517
1518 #define CF_CHKSUM_SAMPLE_SIZE                           512
1519
1520 // update cur_chksum with the chksum of the new_data of size new_data_size
1521 ushort cf_add_chksum_short(ushort seed, char *buffer, int size)
1522 {
1523         ubyte * ptr = (ubyte *)buffer;
1524         unsigned int sum1,sum2;
1525
1526         sum1 = sum2 = (int)(seed);
1527
1528         while(size--)   {
1529                 sum1 += *ptr++;
1530                 if (sum1 >= 255 ) sum1 -= 255;
1531                 sum2 += sum1;
1532         }
1533         sum2 %= 255;
1534         
1535         return (unsigned short)((sum1<<8)+ sum2);
1536 }
1537
1538 // update cur_chksum with the chksum of the new_data of size new_data_size
1539 unsigned long cf_add_chksum_long(unsigned long seed, char *buffer, int size)
1540 {
1541         unsigned long crc;
1542         unsigned char *p;
1543         unsigned long temp1;
1544         unsigned long temp2;
1545
1546         p = (unsigned char*)buffer;
1547         crc = seed;     
1548
1549         while (size--!=0){
1550           temp1 = (crc>>8)&0x00FFFFFFL;
1551           temp2 = CRCTable[((int)crc^*p++)&0xff];
1552           crc = temp1^temp2;
1553         }       
1554         
1555         return crc;
1556 }
1557
1558 void cf_chksum_long_init()
1559 {
1560         int i,j;
1561         unsigned long crc;      
1562
1563         for( i=0;i<=255;i++) {
1564                 crc=i;
1565                 for(j=8;j>0;j--) {
1566                         if(crc&1)
1567                                  crc=(crc>>1)^CRC32_POLYNOMIAL;
1568                         else
1569                                  crc>>=1;
1570                 }
1571                 CRCTable[i]=crc;
1572         }       
1573 }
1574
1575 // single function convenient to use for both short and long checksums
1576 // NOTE : only one of chk_short or chk_long must be non-NULL (indicating which checksum to perform)
1577 int cf_chksum_do(CFILE *cfile, ushort *chk_short, uint *chk_long, int max_size)
1578 {
1579         char cf_buffer[CF_CHKSUM_SAMPLE_SIZE];
1580         int is_long;
1581         int cf_len = 0;
1582         int cf_total;
1583         int read_size;
1584
1585         // determine whether we're doing a short or long checksum
1586         is_long = 0;
1587         if(chk_short){
1588                 Assert(!chk_long);              
1589                 *chk_short = 0;
1590         } else {
1591                 Assert(chk_long);
1592                 is_long = 1;
1593                 *chk_long = 0;
1594         }
1595
1596         // if max_size is -1, set it to be the size of the file
1597         if(max_size < 0){
1598                 cfseek(cfile, 0, SEEK_SET);
1599                 max_size = cfilelength(cfile);
1600         }
1601         
1602         cf_total = 0;
1603         do {
1604                 // determine how much we want to read
1605                 if((max_size - cf_total) >= CF_CHKSUM_SAMPLE_SIZE){
1606                         read_size = CF_CHKSUM_SAMPLE_SIZE;
1607                 } else {
1608                         read_size = max_size - cf_total;
1609                 }
1610
1611                 // read in some buffer
1612                 cf_len = cfread(cf_buffer, 1, read_size, cfile);
1613
1614                 // total we've read so far
1615                 cf_total += cf_len;
1616
1617                 // add the checksum
1618                 if(cf_len > 0){
1619                         // do the proper short or long checksum
1620                         if(is_long){
1621                                 *chk_long = cf_add_chksum_long(*chk_long, cf_buffer, cf_len);
1622                         } else {
1623                                 *chk_short = cf_add_chksum_short(*chk_short, cf_buffer, cf_len);
1624                         }
1625                 }
1626         } while((cf_len > 0) && (cf_total < max_size));
1627
1628         return 1;
1629 }
1630
1631 // get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
1632 int cf_chksum_short(char *filename, ushort *chksum, int max_size, int cf_type)
1633 {
1634         int ret_val;
1635         CFILE *cfile = NULL;            
1636         
1637         // zero the checksum
1638         *chksum = 0;
1639
1640         // attempt to open the file
1641         cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
1642         if(cfile == NULL){              
1643                 return 0;
1644         }
1645         
1646         // call the overloaded cf_chksum function()
1647         ret_val = cf_chksum_do(cfile, chksum, NULL, max_size);
1648
1649         // close the file down
1650         cfclose(cfile);
1651         cfile = NULL;
1652
1653         // return the result
1654         return ret_val;
1655 }
1656
1657 // get the 2 byte checksum of the passed file - return 0 if operation failed, 1 if succeeded
1658 // NOTE : preserves current file position
1659 int cf_chksum_short(CFILE *file, ushort *chksum, int max_size)
1660 {
1661         int ret_code;
1662         int start_pos;
1663         
1664         // Returns current position of file.
1665         start_pos = cftell(file);
1666         if(start_pos == -1){
1667                 return 0;
1668         }
1669         
1670         // move to the beginning of the file
1671         if(cfseek(file, 0, CF_SEEK_SET)){
1672                 return 0;
1673         }
1674         ret_code = cf_chksum_do(file, chksum, NULL, max_size);
1675         // move back to the start position
1676         cfseek(file, start_pos, CF_SEEK_SET);
1677
1678         return ret_code;
1679 }
1680
1681 // get the 32 bit CRC checksum of the passed filename - return 0 if operation failed, 1 if succeeded
1682 int cf_chksum_long(char *filename, uint *chksum, int max_size, int cf_type)
1683 {
1684         int ret_val;
1685         CFILE *cfile = NULL;            
1686         
1687         // zero the checksum
1688         *chksum = 0;
1689
1690         // attempt to open the file
1691         cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
1692         if(cfile == NULL){              
1693                 return 0;
1694         }
1695         
1696         // call the overloaded cf_chksum function()
1697         ret_val = cf_chksum_do(cfile, NULL, chksum, max_size);
1698
1699         // close the file down
1700         cfclose(cfile);
1701         cfile = NULL;
1702
1703         // return the result
1704         return ret_val; 
1705 }
1706
1707 // get the 32 bit CRC checksum of the passed file - return 0 if operation failed, 1 if succeeded
1708 // NOTE : preserves current file position
1709 int cf_chksum_long(CFILE *file, uint *chksum, int max_size)
1710 {
1711         int ret_code;
1712         int start_pos;
1713         
1714         // Returns current position of file.
1715         start_pos = cftell(file);
1716         if(start_pos == -1){
1717                 return 0;
1718         }
1719         
1720         // move to the beginning of the file
1721         if(cfseek(file, 0, CF_SEEK_SET)){
1722                 return 0;
1723         }
1724         ret_code = cf_chksum_do(file, NULL, chksum, max_size);
1725         // move back to the start position
1726         cfseek(file, start_pos, CF_SEEK_SET);
1727
1728         return ret_code;
1729 }
1730
1731
1732 // Flush the open file buffer
1733 //
1734 // exit: 0 - success
1735 //                      1 - failure
1736 int cflush(CFILE *cfile)
1737 {
1738         Assert(cfile != NULL);
1739         Cfile_block *cb;
1740         Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1741         cb = &Cfile_block_list[cfile->id];      
1742
1743         // not supported for memory mapped files
1744         Assert( !cb->data );
1745
1746         Assert(cb->fp != NULL);
1747         return fflush(cb->fp);
1748 }
1749
1750
1751
1752
1753
1754
1755