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