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