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