]> icculus.org git repositories - taylor/freespace2.git/blob - src/cfile/cfile.cpp
remove extras_dir arg from cfile_init()
[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 <dirent.h>
224 #include <fnmatch.h>
225 #include <sys/stat.h>
226 #include <sys/types.h>
227 #endif
228
229 #include "pstypes.h"
230 #include "cfile.h"
231 #include "encrypt.h"
232 //#include "outwnd.h"
233 //#include "vecmat.h"
234 //#include "timer.h"
235 #include "cfilesystem.h"
236 #include "cfilearchive.h"
237 #include "osapi.h"
238 #include "osregistry.h"
239
240 char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
241 char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
242
243 // During cfile_init, verify that Pathtypes[n].index == n for each item
244 // Each path must have a valid parent that can be tracable all the way back to the root 
245 // so that we can create directories when we need to.
246 //
247 cf_pathtype Pathtypes[CF_MAX_PATH_TYPES]  = {
248         // What type this is          Path                             Extensions              Parent type
249         { CF_TYPE_INVALID,                              NULL,                                                                           NULL,                                                   CF_TYPE_INVALID },
250         // Root must be index 1!!       
251         { CF_TYPE_ROOT,                                 "",                                                                             ".mve",                                                 CF_TYPE_ROOT    },
252         { CF_TYPE_DATA,                                 "Data",                                                                 ".cfg .log .txt",                       CF_TYPE_ROOT    },
253         { CF_TYPE_MAPS,                                 "Data" DIR_SEPARATOR_STR "Maps",                                                        ".pcx .ani .tga",                       CF_TYPE_DATA    },
254         { CF_TYPE_TEXT,                                 "Data" DIR_SEPARATOR_STR "Text",                                                        ".txt .net",                            CF_TYPE_DATA    },
255 #ifdef MAKE_FS1
256         { CF_TYPE_MISSIONS,                             "Data" DIR_SEPARATOR_STR "Missions",                                            ".fsm .fsc .ntl .ssv",  CF_TYPE_DATA    },
257 #else
258         { CF_TYPE_MISSIONS,                             "Data" DIR_SEPARATOR_STR "Missions",                                            ".fs2 .fc2 .ntl .ssv",  CF_TYPE_DATA    },
259 #endif
260         { CF_TYPE_MODELS,                                       "Data" DIR_SEPARATOR_STR "Models",                                              ".pof",                                         CF_TYPE_DATA    },
261         { CF_TYPE_TABLES,                                       "Data" DIR_SEPARATOR_STR "Tables",                                              ".tbl",                                         CF_TYPE_DATA    },
262         { CF_TYPE_SOUNDS,                                       "Data" DIR_SEPARATOR_STR "Sounds",                                              ".wav",                                         CF_TYPE_DATA    },
263         { CF_TYPE_SOUNDS_8B22K,                 "Data" DIR_SEPARATOR_STR "Sounds" DIR_SEPARATOR_STR "8b22k",                            ".wav",                                         CF_TYPE_SOUNDS  },
264         { CF_TYPE_SOUNDS_16B11K,                "Data" DIR_SEPARATOR_STR "Sounds" DIR_SEPARATOR_STR "16b11k",                           ".wav",                                         CF_TYPE_SOUNDS  },
265         { CF_TYPE_VOICE,                                        "Data" DIR_SEPARATOR_STR "Voice",                                                       "",                                                     CF_TYPE_DATA    },
266 #ifdef MAKE_FS1
267         { CF_TYPE_VOICE_BRIEFINGS,              "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Briefings",                 ".wav",                                         CF_TYPE_VOICE   },
268 #else
269         { CF_TYPE_VOICE_BRIEFINGS,              "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Briefing",                  ".wav",                                         CF_TYPE_VOICE   },
270 #endif
271         { CF_TYPE_VOICE_CMD_BRIEF,              "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Command_briefings",".wav",                                          CF_TYPE_VOICE   },
272 #ifdef MAKE_FS1
273         { CF_TYPE_VOICE_DEBRIEFINGS,    "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Debriefings",                       ".wav",                                         CF_TYPE_VOICE   },
274 #else
275         { CF_TYPE_VOICE_DEBRIEFINGS,    "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Debriefing",                        ".wav",                                         CF_TYPE_VOICE   },
276 #endif
277         { CF_TYPE_VOICE_PERSONAS,               "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Personas",                  ".wav",                                         CF_TYPE_VOICE   },
278         { CF_TYPE_VOICE_SPECIAL,                "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Special",                           ".wav",                                         CF_TYPE_VOICE   },
279         { CF_TYPE_VOICE_TRAINING,               "Data" DIR_SEPARATOR_STR "Voice" DIR_SEPARATOR_STR "Training",                  ".wav",                                         CF_TYPE_VOICE   },
280         { CF_TYPE_MUSIC,                                        "Data" DIR_SEPARATOR_STR "Music",                                                       ".wav",                                         CF_TYPE_VOICE   },
281         { CF_TYPE_MOVIES,                                       "Data" DIR_SEPARATOR_STR "Movies",                                              ".mve .msb",                            CF_TYPE_DATA    },
282         { CF_TYPE_INTERFACE,                            "Data" DIR_SEPARATOR_STR "Interface",                                   ".pcx .ani .tga",                       CF_TYPE_DATA    },
283         { CF_TYPE_FONT,                                 "Data" DIR_SEPARATOR_STR "Fonts",                                                       ".vf",                                          CF_TYPE_DATA    },
284         { CF_TYPE_EFFECTS,                              "Data" DIR_SEPARATOR_STR "Effects",                                             ".ani .pcx .neb .tga",  CF_TYPE_DATA    },
285         { CF_TYPE_HUD,                                          "Data" DIR_SEPARATOR_STR "Hud",                                                 ".ani .pcx .tga",                       CF_TYPE_DATA    },
286         { CF_TYPE_PLAYER_MAIN,                  "Data" DIR_SEPARATOR_STR "Players",                                             "",                                                     CF_TYPE_DATA    },
287         { CF_TYPE_PLAYER_IMAGES_MAIN,   "Data" DIR_SEPARATOR_STR "Players" DIR_SEPARATOR_STR "Images",                  ".pcx",                                         CF_TYPE_PLAYER_MAIN     },
288         { CF_TYPE_CACHE,                                        "Data" DIR_SEPARATOR_STR "Cache",                                                       ".clr .tmp",                            CF_TYPE_DATA    },      //clr=cached color
289         { CF_TYPE_PLAYERS,                              "Data" DIR_SEPARATOR_STR "Players",                                             ".hcf",                                         CF_TYPE_DATA    },
290         { CF_TYPE_SINGLE_PLAYERS,               "Data" DIR_SEPARATOR_STR "Players" DIR_SEPARATOR_STR "Single",                  ".plr .csg .css",                       CF_TYPE_PLAYERS },
291         { CF_TYPE_MULTI_PLAYERS,                "Data" DIR_SEPARATOR_STR "Players" DIR_SEPARATOR_STR "Multi",                           ".plr",                                         CF_TYPE_DATA    },
292         { CF_TYPE_MULTI_CACHE,                  "Data" DIR_SEPARATOR_STR "MultiData",                                   ".pcx .fs2",                            CF_TYPE_DATA    },
293         { CF_TYPE_CONFIG,                                       "Data" DIR_SEPARATOR_STR "Config",                                              ".cfg",                                         CF_TYPE_DATA    },
294         { CF_TYPE_SQUAD_IMAGES_MAIN,    "Data" DIR_SEPARATOR_STR "Players" DIR_SEPARATOR_STR "Squads",                  ".pcx",                                         CF_TYPE_DATA    },
295         { CF_TYPE_DEMOS,                                        "Data" DIR_SEPARATOR_STR "Demos",                                                       ".fsd",                                         CF_TYPE_DATA    },
296         { CF_TYPE_CBANIMS,                              "Data" DIR_SEPARATOR_STR "CBAnims",                                             ".ani",                                         CF_TYPE_DATA    },
297         { CF_TYPE_INTEL_ANIMS,                  "Data" DIR_SEPARATOR_STR "IntelAnims",                                  ".ani",                                         CF_TYPE_DATA    },
298 };
299
300
301 #define CFILE_STACK_MAX 8
302
303 int cfile_inited = 0;
304
305 Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS];
306 CFILE Cfile_list[MAX_CFILE_BLOCKS];
307
308 //
309 // Function prototypes for internally-called functions
310 //
311 int cfget_cfile_block();
312 CFILE *cf_open_fill_cfblock(FILE * fp, int type);
313 CFILE *cf_open_packed_cfblock(FILE *fp, int type, int offset, int size);
314 CFILE *cf_open_mapped_fill_cfblock(HANDLE hFile, int type);
315 void cf_chksum_long_init();
316
317 void cfile_close()
318 {
319         cf_free_secondary_filelist();
320 }
321
322 // determine if the given path is in a root directory (c:\  or  c:\freespace2.exe  or  c:\fred2.exe   etc)
323 int cfile_in_root_dir(char *exe_path)
324 {
325         int token_count = 0;
326         char path_copy[2048] = "";
327         char *tok;
328
329         // bogus
330         if(exe_path == NULL){
331                 return 1;
332         }
333
334         // copy the path
335         memset(path_copy, 0, 2048);
336         SDL_strlcpy(path_copy, exe_path, sizeof(path_copy));
337
338         // count how many slashes there are in the path
339         tok = strtok(path_copy, DIR_SEPARATOR_STR);
340         if(tok == NULL){
341                 return 1;
342         }       
343         do {
344                 token_count++;
345                 tok = strtok(NULL, DIR_SEPARATOR_STR);
346         } while(tok != NULL);
347                 
348         // root directory if we have <= 1 slash
349         if(token_count <= 2){
350                 return 1;
351         }
352
353         // not-root directory
354         return 0;
355 }
356
357 // cfile_init() initializes the cfile system.  Called once at application start.
358 //
359 //      returns:  success ==> 0
360 //           error   ==> non-zero
361 //
362 int cfile_init()
363 {
364         int i;
365
366         // initialize encryption
367         encrypt_init(); 
368
369         if ( !cfile_inited ) {
370                 // initialize root and user paths (may have been done already)
371                 if ( cfile_init_paths() ) {
372                         return 1;
373                 }
374
375                 cfile_inited = 1;
376
377                 for ( i = 0; i < MAX_CFILE_BLOCKS; i++ ) {
378                         Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
379                 }
380
381                 const char *extras_dir = os_config_read_string(NULL, "ExtrasPath", NULL);
382
383                 if ( extras_dir && (strlen(extras_dir) >= MAX_PATH_LEN) ) {
384                         extras_dir = NULL;
385                 }
386
387                 cf_build_secondary_filelist(extras_dir);
388
389                 // 32 bit CRC table init
390                 cf_chksum_long_init();
391
392
393
394                 atexit( cfile_close );
395         }
396
397         return 0;
398 }
399
400
401 // flush (delete all files in) the passed directory (by type), return the # of files deleted
402 // NOTE : WILL NOT DELETE READ-ONLY FILES
403 int cfile_flush_dir(int dir_type)
404 {
405         char filespec[MAX_PATH_LEN];
406         int del_count;
407
408         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
409
410         cf_create_default_path_string(filespec, dir_type);
411
412         // proceed to delete the files
413         del_count = 0;
414
415 #ifdef PLAT_UNIX
416         DIR *dirp;
417         struct dirent *dir;
418
419         dirp = opendir(filespec);
420         if (dirp) {
421                 while ( (dir = readdir(dirp)) != NULL ) {
422                         if ( !fnmatch("*", dir->d_name, 0) ) {
423                                 char fn[MAX_PATH_LEN];
424                                 SDL_snprintf(fn, MAX_PATH_LEN, "%s/%s", filespec, dir->d_name);
425
426                                 struct stat buf;
427                                 if (stat(fn, &buf) == -1) {
428                                         continue;
429                                 }
430
431                                 if (!S_ISREG(buf.st_mode)) {
432                                         continue;
433                                 }
434
435                                 // delete the file
436                                 cf_delete(dir->d_name, dir_type);
437
438                                 // increment the deleted count
439                                 del_count++;
440                         }
441                 }
442
443                 closedir(dirp);
444         }
445 #else
446         int find_handle;
447         _finddata_t find;
448
449         SDL_strlcat( filespec, "*", sizeof(filespec) );
450
451         find_handle = _findfirst( filespec, &find );
452
453         if (find_handle != -1) {
454                 do {
455                         if (!(find.attrib & _A_SUBDIR) && !(find.attrib & _A_RDONLY)) {
456                                 // delete the file
457                                 cf_delete(find.name, dir_type);
458
459                                 // increment the deleted count
460                                 del_count++;
461                         }
462                 } while (!_findnext(find_handle, &find));
463
464                 _findclose( find_handle );
465         }
466 #endif
467
468         // return the # of files deleted
469         return del_count;
470 }
471
472
473 // add the given extention to a filename (or filepath) if it doesn't already have this
474 // extension.
475 //    filename = name of filename or filepath to process
476 //    ext = extension to add.  Must start with the period
477 //    Returns: new filename or filepath with extension.
478 char *cf_add_ext(const char *filename, const char *ext)
479 {
480         int flen, elen;
481         static char path[MAX_PATH_LEN];
482
483         flen = strlen(filename);
484         elen = strlen(ext);
485         SDL_assert(flen < MAX_PATH_LEN);
486         SDL_strlcpy(path, filename, sizeof(path));
487         if ((flen < 4) || SDL_strcasecmp(path + flen - elen, ext)) {
488                 SDL_assert(flen + elen < MAX_PATH_LEN);
489                 SDL_strlcat(path, ext, sizeof(path));
490         }
491
492         return path;
493 }
494
495 // Deletes a file.
496 void cf_delete( const char *filename, int dir_type )
497 {
498         char longname[MAX_PATH_LEN];
499
500         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
501
502         cf_create_default_path_string( longname, dir_type, filename );
503
504         FILE *fp = fopen(longname, "rb");
505         if (fp) {
506                 // delete the file
507                 fclose(fp);
508                 unlink(longname);
509         }
510
511 }
512
513
514 // Same as _access function to read a file's access bits
515 int cf_access( const char *filename, int dir_type, int mode )
516 {
517         char longname[MAX_PATH_LEN];
518
519         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
520
521         cf_create_default_path_string( longname, dir_type, filename );
522
523         return access(longname,mode);
524 }
525
526
527 // Returns 1 if file exists, 0 if not.
528 int cf_exist( const char *filename, int dir_type )
529 {
530         char longname[MAX_PATH_LEN];
531
532         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
533
534         cf_create_default_path_string( longname, dir_type, filename );
535
536         FILE *fp = fopen(longname, "rb");
537         if (fp) {
538                 fclose(fp);
539                 return 1;
540         }
541
542         return 0;
543 }
544
545 int cf_rename(const char *old_name, const char *name, int dir_type)
546 {
547         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
548
549         int ret_code;
550         char old_longname[MAX_PATH_LEN];
551         char new_longname[MAX_PATH_LEN];
552         
553         cf_create_default_path_string( old_longname, dir_type, old_name );
554         cf_create_default_path_string( new_longname, dir_type, name );
555
556         ret_code = rename(old_longname, new_longname );         
557         if(ret_code != 0){
558                 switch(errno){
559                 case EACCES :
560                         return CF_RENAME_FAIL_ACCESS;
561                 case ENOENT :
562                 default:
563                         return CF_RENAME_FAIL_EXIST;
564                 }
565         }
566
567         return CF_RENAME_SUCCESS;
568         
569
570 }
571
572 // Creates the directory path if it doesn't exist. Even creates all its
573 // parent paths.
574 void cf_create_directory( int dir_type )
575 {
576         int num_dirs = 0;
577         int dir_tree[CF_MAX_PATH_TYPES];
578         char longname[MAX_PATH_LEN];
579
580         SDL_assert( CF_TYPE_SPECIFIED(dir_type) );
581
582         int current_dir = dir_type;
583
584         do {
585                 SDL_assert( num_dirs < CF_MAX_PATH_TYPES );             // Invalid Pathtypes data?
586
587                 dir_tree[num_dirs++] = current_dir;
588                 current_dir = Pathtypes[current_dir].parent_index;
589
590         } while( current_dir != CF_TYPE_ROOT );
591
592         
593         int i;
594
595         for (i=num_dirs-1; i>=0; i-- )  {
596                 cf_create_default_path_string( longname, dir_tree[i], NULL );
597
598                 if ( mkdir(longname, 0700) == 0 )       {
599                         mprintf(( "CFILE: Created new directory '%s'\n", longname ));
600                 }
601         }
602
603
604 }
605
606
607 // cfopen()
608 //
609 // parameters:  *filepath ==> name of file to open (may be path+name)
610 //              *mode     ==> specifies how file should be opened (eg "rb" for read binary)
611 //                            passing NULL to mode deletes the file if it exists and returns NULL
612 //               type     ==> one of:    CFILE_NORMAL
613 //                                       CFILE_MEMORY_MAPPED
614 //                                        dir_type      =>      override extension check, value is one of CF_TYPE* #defines
615 //
616 //               NOTE: type parameter is an optional parameter.  The default value is CFILE_NORMAL
617 //
618 //
619 // returns:             success ==> address of CFILE structure
620 //                                      error   ==> NULL
621 //
622
623 CFILE *cfopen(const char *file_path, const char *mode, int type, int dir_type, bool localize)
624 {
625         char longname[MAX_PATH_LEN];
626
627 //      nprintf(("CFILE", "CFILE -- trying to open %s\n", file_path ));
628 // #if !defined(MULTIPLAYER_BETA_BUILD) && !defined(FS2_DEMO)
629
630         //================================================
631         // Check that all the parameters make sense
632         SDL_assert(file_path && strlen(file_path));
633         SDL_assert( mode != NULL );
634         
635         // Can only open read-only binary files in memory mapped mode.
636         if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") ) {
637                 Int3();                         
638                 return NULL;
639         }
640
641         //===========================================================
642         // If in write mode, just try to open the file straight off
643         // the harddisk.  No fancy packfile stuff here!
644         
645         if ( SDL_strchr(mode,'w') )     {
646                 // For write-only files, require a full path or a path type
647 #ifdef PLAT_UNIX
648                 if ( strpbrk(file_path, "/") ) {
649 #else
650                 if ( strpbrk(file_path,"/\\:")  ) {  
651 #endif
652                         // Full path given?
653                         SDL_strlcpy(longname, file_path, sizeof(longname));
654                 } else {
655                         // Path type given?
656                         SDL_assert( dir_type != CF_TYPE_ANY );
657
658                         // Create the directory if necessary
659                         cf_create_directory( dir_type );
660
661                         cf_create_default_path_string( longname, dir_type, file_path );
662                 }
663                 SDL_assert( !(type & CFILE_MEMORY_MAPPED) );
664
665                 // JOHN: TODO, you should create the path if it doesn't exist.
666                                 
667                 FILE *fp = fopen(longname, mode);
668                 if (fp) {
669                         return cf_open_fill_cfblock(fp, dir_type);
670                 }
671                 return NULL;
672         } 
673
674
675         //================================================
676         // Search for file on disk, on cdrom, or in a packfile
677
678         int offset, size;
679         char copy_file_path[MAX_PATH_LEN];  // FIX change in memory from cf_find_file_location
680         SDL_strlcpy(copy_file_path, file_path, sizeof(copy_file_path));
681
682
683         if ( cf_find_file_location( copy_file_path, dir_type, longname, &size, &offset, localize ) )    {
684
685                 // Fount it, now create a cfile out of it
686                 
687                 if ( type & CFILE_MEMORY_MAPPED ) {
688                 
689                         // Can't open memory mapped files out of pack files
690                         if ( offset == 0 )      {
691 #ifdef PLAT_UNIX
692                                 STUB_FUNCTION;
693 #else
694                                 HANDLE hFile;
695
696                                 hFile = CreateFile((LPCWSTR)longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
697
698                                 if (hFile != INVALID_HANDLE_VALUE)      {
699                                         return cf_open_mapped_fill_cfblock(hFile, dir_type);
700                                 }
701 #endif
702                         } 
703
704                 } else {
705
706                         FILE *fp = fopen( longname, "rb" );
707
708                         if ( fp )       {
709                                 if ( offset )   {
710                                         // Found it in a pack file
711                                         return cf_open_packed_cfblock(fp, dir_type, offset, size );
712                                 } else {
713                                         // Found it in a normal file
714                                         return cf_open_fill_cfblock(fp, dir_type);
715                                 } 
716                         }
717                 }
718
719         }
720
721         return NULL;
722 }
723
724
725 // ------------------------------------------------------------------------
726 // ctmpfile() 
727 //
728 // Open up a temporary file.  A unique name is automatically generated.  The
729 // file will be automatically deleted when file is closed.
730 //
731 // return:              NULL                                    =>              tmp file could not be opened
732 //                                      pointer to CFILE        =>              tmp file successfully opened
733 //
734 CFILE *ctmpfile()
735 {
736         FILE    *fp;
737         fp = tmpfile();
738         if ( fp )
739                 return cf_open_fill_cfblock(fp, 0);
740         else
741                 return NULL;
742 }
743
744
745
746 // cfget_cfile_block() will try to find an empty Cfile_block structure in the
747 //      Cfile_block_list[] array and return the index.
748 //
749 // returns:   success ==> index in Cfile_block_list[] array
750 //            failure ==> -1
751 //
752 int cfget_cfile_block()
753 {       
754         int i;
755         Cfile_block *cb;
756
757         for ( i = 0; i < MAX_CFILE_BLOCKS; i++ ) {
758                 cb = &Cfile_block_list[i];
759                 if ( cb->type == CFILE_BLOCK_UNUSED ) {
760                         cb->data = NULL;
761                         cb->fp = NULL;
762                         cb->type = CFILE_BLOCK_USED;
763                         return i;
764                 }
765         }
766
767         // If we've reached this point, a free Cfile_block could not be found
768         nprintf(("Warning","A free Cfile_block could not be found.\n"));
769         SDL_assert(0);  // out of free cfile blocks
770         return -1;                      
771 }
772
773
774 // cfclose() closes the file
775 //
776 // returns:   success ==> 0
777 //                                failure ==> EOF
778 //
779 int cfclose( CFILE * cfile )
780 {
781         int result;
782
783         SDL_assert(cfile != NULL);
784         Cfile_block *cb;
785         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
786         cb = &Cfile_block_list[cfile->id];      
787
788         result = 0;
789         if ( cb->data ) {
790                 // close memory mapped file
791 #ifdef PLAT_UNIX
792                 STUB_FUNCTION;
793 #else
794                 result = UnmapViewOfFile((void*)cb->data);
795                 SDL_assert(result);
796                 result = CloseHandle(cb->hInFile);              
797                 SDL_assert(result);     // Ensure file handle is closed properly
798                 result = CloseHandle(cb->hMapFile);             
799                 SDL_assert(result);     // Ensure file handle is closed properly
800 #endif
801                 result = 0;
802
803         } else if ( cb->fp != NULL )    {
804                 SDL_assert(cb->fp != NULL);
805                 result = fclose(cb->fp);
806         } else {
807                 // VP  do nothing
808         }
809
810         cb->type = CFILE_BLOCK_UNUSED;
811         return result;
812 }
813
814
815
816
817 // cf_open_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
818 // for the case of a file being opened by cf_open();
819 //
820 // returns:   success ==> ptr to CFILE structure.  
821 //            error   ==> NULL
822 //
823 CFILE *cf_open_fill_cfblock(FILE *fp, int type)
824 {
825         int cfile_block_index;
826
827         cfile_block_index = cfget_cfile_block();
828         if ( cfile_block_index == -1 ) {
829                 return NULL;
830         } else {
831                 CFILE *cfp;
832                 Cfile_block *cfbp;
833                 cfbp = &Cfile_block_list[cfile_block_index];
834                 cfp = &Cfile_list[cfile_block_index];;
835                 cfp->id = cfile_block_index;
836                 cfp->version = 0;
837                 cfbp->data = NULL;
838                 cfbp->fp = fp;
839                 cfbp->dir_type = type;
840                 
841                 cf_init_lowlevel_read_code(cfp,0,filelength(fileno(fp)) );
842
843                 return cfp;
844         }
845 }
846
847
848 // cf_open_packed_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
849 // for the case of a file being opened by cf_open();
850 //
851 // returns:   success ==> ptr to CFILE structure.  
852 //            error   ==> NULL
853 //
854 CFILE *cf_open_packed_cfblock(FILE *fp, int type, int offset, int size)
855 {
856         // Found it in a pack file
857         int cfile_block_index;
858         
859         cfile_block_index = cfget_cfile_block();
860         if ( cfile_block_index == -1 ) {
861                 return NULL;
862         } else {
863                 CFILE *cfp;
864                 Cfile_block *cfbp;
865                 cfbp = &Cfile_block_list[cfile_block_index];
866         
867                 cfp = &Cfile_list[cfile_block_index];
868                 cfp->id = cfile_block_index;
869                 cfp->version = 0;
870                 cfbp->data = NULL;
871                 cfbp->fp = fp;
872                 cfbp->dir_type = type;
873
874                 cf_init_lowlevel_read_code(cfp,offset, size );
875
876                 return cfp;
877         }
878
879 }
880
881
882
883 // cf_open_mapped_fill_cfblock() will fill up a Cfile_block element in the Cfile_block_list[] array
884 // for the case of a file being opened by cf_open_mapped();
885 //
886 // returns:   ptr CFILE structure.  
887 //
888 CFILE *cf_open_mapped_fill_cfblock(HANDLE hFile, int type)
889 {
890         int cfile_block_index;
891
892         cfile_block_index = cfget_cfile_block();
893         if ( cfile_block_index == -1 ) {
894                 return NULL;
895         }
896         else {
897                 CFILE *cfp;
898                 Cfile_block *cfbp;
899                 cfbp = &Cfile_block_list[cfile_block_index];
900
901                 cfp = &Cfile_list[cfile_block_index];
902                 cfp->id = cfile_block_index;
903                 cfbp->fp = NULL;
904                 cfbp->hInFile = hFile;
905                 cfbp->dir_type = type;
906
907                 cf_init_lowlevel_read_code(cfp,0 , 0 );
908
909 #ifdef PLAT_UNIX
910                 STUB_FUNCTION;
911 #else
912                 cfbp->hMapFile = CreateFileMapping(cfbp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
913                 if (cfbp->hMapFile == NULL) { 
914                         nprintf(("Error", "Could not create file-mapping object.\n")); 
915                         return NULL;
916                 } 
917         
918                 cfbp->data = (ubyte*)MapViewOfFile(cfbp->hMapFile, FILE_MAP_READ, 0, 0, 0);
919                 SDL_assert( cfbp->data != NULL );               
920 #endif
921                 return cfp;
922         }
923 }
924
925 int cf_get_dir_type(CFILE *cfile)
926 {
927         return Cfile_block_list[cfile->id].dir_type;
928 }
929
930 // cf_returndata() returns the data pointer for a memory-mapped file that is associated
931 // with the CFILE structure passed as a parameter
932 //
933 // 
934
935 void *cf_returndata(CFILE *cfile)
936 {
937         SDL_assert(cfile != NULL);
938         Cfile_block *cb;
939         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
940         cb = &Cfile_block_list[cfile->id];      
941         SDL_assert(cb->data != NULL);
942         return cb->data;
943 }
944
945
946
947 // version number of opened file.  Will be 0 unless you put something else here after you
948 // open a file.  Once set, you can use minimum version numbers with the read functions.
949 void cf_set_version( CFILE * cfile, int version )
950 {
951         SDL_assert(cfile != NULL);
952
953         cfile->version = version;
954 }
955
956 // routines to read basic data types from CFILE's.  Put here to
957 // simplify mac/pc reading from cfiles.
958 #ifdef __APPLE__
959 #include <stddef.h>
960 #endif
961
962 float cfread_float(CFILE *file, int ver, float deflt)
963 {
964         float f;
965
966         if (file->version < ver)
967                 return deflt;
968
969         if (cfread( &f, sizeof(f), 1, file) != 1)
970                 return deflt;
971
972     f = INTEL_FLOAT(f);
973         return f;
974 }
975
976 int cfread_int(CFILE *file, int ver, int deflt)
977 {
978         int i;
979
980         if (file->version < ver)
981                 return deflt;
982
983         if (cfread( &i, sizeof(i), 1, file) != 1)
984                 return deflt;
985
986         i = INTEL_INT(i);
987         return i;
988 }
989
990 uint cfread_uint(CFILE *file, int ver, uint deflt)
991 {
992         uint i;
993
994         if (file->version < ver)
995                 return deflt;
996
997         if (cfread( &i, sizeof(i), 1, file) != 1)
998                 return deflt;
999
1000         i = INTEL_INT(i);
1001         return i;
1002 }
1003
1004 short cfread_short(CFILE *file, int ver, short deflt)
1005 {
1006         short s;
1007
1008         if (file->version < ver)
1009                 return deflt;
1010
1011         if (cfread( &s, sizeof(s), 1, file) != 1)
1012                 return deflt;
1013
1014         s = INTEL_SHORT(s);
1015         return s;
1016 }
1017
1018 ushort cfread_ushort(CFILE *file, int ver, ushort deflt)
1019 {
1020         ushort s;
1021
1022         if (file->version < ver)
1023                 return deflt;
1024
1025         if (cfread( &s, sizeof(s), 1, file) != 1)
1026                 return deflt;
1027
1028         s = INTEL_SHORT(s);
1029         return s;
1030 }
1031
1032 ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
1033 {
1034         ubyte b;
1035
1036         if (file->version < ver)
1037                 return deflt;
1038
1039         if (cfread( &b, sizeof(b), 1, file) != 1)
1040                 return deflt;
1041
1042         return b;
1043 }
1044
1045 void cfread_vector(vector *vec, CFILE *file, int ver, vector *deflt)
1046 {
1047         if (file->version < ver) {
1048                 if (deflt)
1049                         *vec = *deflt;
1050                 else
1051                         vec->xyz.x = vec->xyz.y = vec->xyz.z = 0.0f;
1052
1053                 return;
1054         }
1055
1056         vec->xyz.x = cfread_float(file, ver, deflt ? deflt->xyz.x : 0.0f);
1057         vec->xyz.y = cfread_float(file, ver, deflt ? deflt->xyz.y : 0.0f);
1058         vec->xyz.z = cfread_float(file, ver, deflt ? deflt->xyz.z : 0.0f);
1059 }
1060         
1061 void cfread_angles(angles *ang, CFILE *file, int ver, angles *deflt)
1062 {
1063         if (file->version < ver) {
1064                 if (deflt)
1065                         *ang = *deflt;
1066                 else
1067                         ang->p = ang->b = ang->h = 0.0f;
1068
1069                 return;
1070         }
1071
1072         ang->p = cfread_float(file, ver, deflt ? deflt->p : 0.0f);
1073         ang->b = cfread_float(file, ver, deflt ? deflt->b : 0.0f);
1074         ang->h = cfread_float(file, ver, deflt ? deflt->h : 0.0f);
1075 }
1076
1077 char cfread_char(CFILE *file, int ver, char deflt)
1078 {
1079         char b;
1080
1081         if (file->version < ver)
1082                 return deflt;
1083
1084         if (cfread( &b, sizeof(b), 1, file) != 1)
1085                 return deflt;
1086
1087         return b;
1088 }
1089
1090 void cfread_string(char *buf, int n, CFILE *file)
1091 {
1092         char c;
1093
1094         do {
1095                 c = cfread_char(file);
1096                 if ( n > 0 )    {
1097                         *buf++ = c;
1098                         n--;
1099                 }
1100         } while (c != 0 );
1101 }
1102
1103 void cfread_string_len(char *buf,int n, CFILE *file)
1104 {
1105         int len;
1106         len = cfread_int(file);
1107         SDL_assert( len < n );
1108         if (len)
1109                 cfread(buf, len, 1, file);
1110
1111         buf[len] = 0;
1112 }
1113
1114 // equivalent write functions of above read functions follow
1115
1116 int cfwrite_float(float f, CFILE *file)
1117 {
1118     f = INTEL_FLOAT(f);
1119         return cfwrite(&f, sizeof(f), 1, file);
1120 }
1121
1122 int cfwrite_int(int i, CFILE *file)
1123 {
1124         i = INTEL_INT(i);
1125         return cfwrite(&i, sizeof(i), 1, file);
1126 }
1127
1128 int cfwrite_uint(uint i, CFILE *file)
1129 {
1130         i = INTEL_INT(i);
1131         return cfwrite(&i, sizeof(i), 1, file);
1132 }
1133
1134 int cfwrite_short(short s, CFILE *file)
1135 {
1136         s = INTEL_SHORT(s);
1137         return cfwrite(&s, sizeof(s), 1, file);
1138 }
1139
1140 int cfwrite_ushort(ushort s, CFILE *file)
1141 {
1142         s = INTEL_SHORT(s);
1143         return cfwrite(&s, sizeof(s), 1, file);
1144 }
1145
1146 int cfwrite_ubyte(ubyte b, CFILE *file)
1147 {
1148         return cfwrite(&b, sizeof(b), 1, file);
1149 }
1150
1151 int cfwrite_vector(vector *vec, CFILE *file)
1152 {
1153         if(!cfwrite_float(vec->xyz.x, file)){
1154                 return 0;
1155         }
1156         if(!cfwrite_float(vec->xyz.y, file)){
1157                 return 0;
1158         }
1159         return cfwrite_float(vec->xyz.z, file);
1160 }
1161
1162 int cfwrite_angles(angles *ang, CFILE *file)
1163 {
1164         if(!cfwrite_float(ang->p, file)){
1165                 return 0;
1166         }
1167         if(!cfwrite_float(ang->b, file)){
1168                 return 0;
1169         }
1170         return cfwrite_float(ang->h, file);
1171 }
1172
1173 int cfwrite_char(char b, CFILE *file)
1174 {
1175         return cfwrite( &b, sizeof(b), 1, file);
1176 }
1177
1178 int cfwrite_string(const char *buf, CFILE *file)
1179 {
1180         if ( (!buf) || (buf && !buf[0]) ) {
1181                 return cfwrite_char(0, file);
1182         } 
1183         int len = strlen(buf);
1184         if(!cfwrite(buf, len, 1, file)){
1185                 return 0;
1186         }
1187         return cfwrite_char(0, file);                   // write out NULL termination                   
1188 }
1189
1190 int cfwrite_string_len(const char *buf, CFILE *file)
1191 {
1192         int len = strlen(buf);
1193
1194         if(!cfwrite_int(len, file)){
1195                 return 0;
1196         }
1197         if (len){
1198                 return cfwrite(buf,len,1,file);
1199         } 
1200
1201         return 1;
1202 }
1203
1204 // Get the filelength
1205 int cfilelength( CFILE * cfile )
1206 {
1207         SDL_assert(cfile != NULL);
1208         Cfile_block *cb;
1209         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1210         cb = &Cfile_block_list[cfile->id];      
1211
1212         // TODO: return length of memory mapped file
1213         SDL_assert( !cb->data );
1214
1215         SDL_assert(cb->fp != NULL);
1216
1217         // cb->size gets set at cfopen
1218         return cb->size;
1219 }
1220
1221 // cfwrite() writes to the file
1222 //
1223 // returns:   number of full elements actually written
1224 //            
1225 //
1226 int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile)
1227 {
1228         SDL_assert(cfile != NULL);
1229         SDL_assert(buf != NULL);
1230         SDL_assert(elsize > 0);
1231         SDL_assert(nelem > 0);
1232
1233         Cfile_block *cb;
1234         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1235         cb = &Cfile_block_list[cfile->id];      
1236
1237         int size = elsize * nelem;
1238
1239         // cfwrite() not supported for memory-mapped files
1240         SDL_assert( !cb->data );
1241
1242         SDL_assert(cb->fp != NULL);
1243         SDL_assert(cb->lib_offset == 0 );
1244         int bytes_written = fwrite( buf, 1, size, cb->fp );
1245
1246         if (bytes_written > 0) {
1247                 cb->raw_position += bytes_written;
1248         }
1249
1250         #if defined(CHECK_POSITION) && !defined(NDEBUG)
1251                 int tmp_offset = ftell(cb->fp) - cb->lib_offset;
1252                 SDL_assert(tmp_offset == cb->raw_position);
1253         #endif
1254
1255         return bytes_written / elsize;
1256 }
1257
1258
1259 // cfputc() writes a character to a file
1260 //
1261 // returns:   success ==> returns character written
1262 //                                error   ==> EOF
1263 //
1264 int cfputc(int c, CFILE *cfile)
1265 {
1266         int result = 0;
1267
1268         SDL_assert(cfile != NULL);
1269         Cfile_block *cb;
1270         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1271         cb = &Cfile_block_list[cfile->id];      
1272
1273         // cfputc() not supported for memory-mapped files
1274         SDL_assert( !cb->data );
1275
1276         SDL_assert(cb->fp != NULL);
1277         result = fputc(c, cb->fp);
1278
1279         return result;  
1280 }
1281
1282
1283 // cfgetc() reads a character from a file
1284 //
1285 // returns:   success ==> returns character read
1286 //                                error   ==> EOF
1287 //
1288 int cfgetc(CFILE *cfile)
1289 {
1290         SDL_assert(cfile != NULL);
1291         
1292         char tmp;
1293
1294         int result = cfread(&tmp, 1, 1, cfile );
1295         if ( result == 1 )      {
1296                 result = char(tmp);
1297         } else {
1298                 result = CF_EOF;
1299         }
1300
1301         return result;  
1302 }
1303
1304
1305
1306
1307
1308 // cfgets() reads a string from a file
1309 //
1310 // returns:   success ==> returns pointer to string
1311 //                                error   ==> NULL
1312 //
1313 char *cfgets(char *buf, int n, CFILE *cfile)
1314 {
1315         SDL_assert(cfile != NULL);
1316         SDL_assert(buf != NULL);
1317         SDL_assert(n > 0 );
1318
1319         char * t = buf;
1320         int i, c;
1321
1322         for (i=0; i<n-1; i++ )  {
1323                 do {
1324                         char tmp_c;
1325
1326                         int ret = cfread( &tmp_c, 1, 1, cfile );
1327                         if ( ret != 1 ) {
1328                                 *buf = 0;
1329                                 if ( buf > t )  {               
1330                                         return t;
1331                                 } else {
1332                                         return NULL;
1333                                 }
1334                         }
1335                         c = int(tmp_c);
1336                 } while ( c == 13 );
1337                 *buf++ = char(c);
1338                 if ( c=='\n' ) break;
1339         }
1340         *buf++ = 0;
1341
1342         return  t;
1343 }
1344
1345 // cfputs() writes a string to a file
1346 //
1347 // returns:   success ==> non-negative value
1348 //                                error   ==> EOF
1349 //
1350 int cfputs(const char *str, CFILE *cfile)
1351 {
1352         SDL_assert(cfile != NULL);
1353         SDL_assert(str != NULL);
1354
1355         Cfile_block *cb;
1356         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1357         cb = &Cfile_block_list[cfile->id];      
1358
1359         int result = 0;
1360
1361         // cfputs() not supported for memory-mapped files
1362         SDL_assert( !cb->data );
1363         SDL_assert(cb->fp != NULL);
1364         result = fputs(str, cb->fp);
1365
1366         return result;  
1367 }
1368
1369
1370 // 16 and 32 bit checksum stuff ----------------------------------------------------------
1371
1372 // CRC code for mission validation.  given to us by Kevin Bentley on 7/20/98.   Some sort of
1373 // checksumming code that he wrote a while ago.  
1374 #define CRC32_POLYNOMIAL                                        0xEDB88320L
1375 unsigned long CRCTable[256];
1376
1377 #define CF_CHKSUM_SAMPLE_SIZE                           512
1378
1379 // update cur_chksum with the chksum of the new_data of size new_data_size
1380 ushort cf_add_chksum_short(ushort seed, const char *buffer, int size)
1381 {
1382         const ubyte * ptr = (const ubyte *)buffer;
1383         unsigned int sum1,sum2;
1384
1385         sum1 = sum2 = (int)(seed);
1386
1387         while(size--)   {
1388                 sum1 += *ptr++;
1389                 if (sum1 >= 255 ) sum1 -= 255;
1390                 sum2 += sum1;
1391         }
1392         sum2 %= 255;
1393         
1394         return (unsigned short)((sum1<<8)+ sum2);
1395 }
1396
1397 // update cur_chksum with the chksum of the new_data of size new_data_size
1398 unsigned long cf_add_chksum_long(unsigned long seed, const char *buffer, int size)
1399 {
1400         unsigned long crc;
1401         unsigned const char *p;
1402         unsigned long temp1;
1403         unsigned long temp2;
1404
1405         p = (unsigned const char*)buffer;
1406         crc = seed;     
1407
1408         while (size--!=0){
1409           temp1 = (crc>>8)&0x00FFFFFFL;
1410           temp2 = CRCTable[((int)crc^*p++)&0xff];
1411           crc = temp1^temp2;
1412         }       
1413         
1414         return crc;
1415 }
1416
1417 void cf_chksum_long_init()
1418 {
1419         int i,j;
1420         unsigned long crc;      
1421
1422         for( i=0;i<=255;i++) {
1423                 crc=i;
1424                 for(j=8;j>0;j--) {
1425                         if(crc&1)
1426                                  crc=(crc>>1)^CRC32_POLYNOMIAL;
1427                         else
1428                                  crc>>=1;
1429                 }
1430                 CRCTable[i]=crc;
1431         }       
1432 }
1433
1434 // single function convenient to use for both short and long checksums
1435 // NOTE : only one of chk_short or chk_long must be non-NULL (indicating which checksum to perform)
1436 int cf_chksum_do(CFILE *cfile, ushort *chk_short, uint *chk_long, int max_size)
1437 {
1438         char cf_buffer[CF_CHKSUM_SAMPLE_SIZE];
1439         int is_long;
1440         int cf_len = 0;
1441         int cf_total;
1442         int read_size;
1443
1444         // determine whether we're doing a short or long checksum
1445         is_long = 0;
1446         if(chk_short){
1447                 SDL_assert(!chk_long);          
1448                 *chk_short = 0;
1449         } else {
1450                 SDL_assert(chk_long);
1451                 is_long = 1;
1452                 *chk_long = 0;
1453         }
1454
1455         // if max_size is -1, set it to be the size of the file
1456         if(max_size < 0){
1457                 cfseek(cfile, 0, SEEK_SET);
1458                 max_size = cfilelength(cfile);
1459         }
1460         
1461         cf_total = 0;
1462         do {
1463                 // determine how much we want to read
1464                 if((max_size - cf_total) >= CF_CHKSUM_SAMPLE_SIZE){
1465                         read_size = CF_CHKSUM_SAMPLE_SIZE;
1466                 } else {
1467                         read_size = max_size - cf_total;
1468                 }
1469
1470                 // read in some buffer
1471                 cf_len = cfread(cf_buffer, 1, read_size, cfile);
1472
1473                 // total we've read so far
1474                 cf_total += cf_len;
1475
1476                 // add the checksum
1477                 if(cf_len > 0){
1478                         // do the proper short or long checksum
1479                         if(is_long){
1480                                 *chk_long = cf_add_chksum_long(*chk_long, cf_buffer, cf_len);
1481                         } else {
1482                                 *chk_short = cf_add_chksum_short(*chk_short, cf_buffer, cf_len);
1483                         }
1484                 }
1485         } while((cf_len > 0) && (cf_total < max_size));
1486
1487         return 1;
1488 }
1489
1490 // get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
1491 int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_type)
1492 {
1493         int ret_val;
1494         CFILE *cfile = NULL;            
1495         
1496         // zero the checksum
1497         *chksum = 0;
1498
1499         // attempt to open the file
1500         cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
1501         if(cfile == NULL){              
1502                 return 0;
1503         }
1504         
1505         // call the overloaded cf_chksum function()
1506         ret_val = cf_chksum_do(cfile, chksum, NULL, max_size);
1507
1508         // close the file down
1509         cfclose(cfile);
1510         cfile = NULL;
1511
1512         // return the result
1513         return ret_val;
1514 }
1515
1516 // get the 2 byte checksum of the passed file - return 0 if operation failed, 1 if succeeded
1517 // NOTE : preserves current file position
1518 int cf_chksum_short(CFILE *file, ushort *chksum, int max_size)
1519 {
1520         int ret_code;
1521         int start_pos;
1522         
1523         // Returns current position of file.
1524         start_pos = cftell(file);
1525         if(start_pos == -1){
1526                 return 0;
1527         }
1528         
1529         // move to the beginning of the file
1530         if(cfseek(file, 0, CF_SEEK_SET)){
1531                 return 0;
1532         }
1533         ret_code = cf_chksum_do(file, chksum, NULL, max_size);
1534         // move back to the start position
1535         cfseek(file, start_pos, CF_SEEK_SET);
1536
1537         return ret_code;
1538 }
1539
1540 // get the 32 bit CRC checksum of the passed filename - return 0 if operation failed, 1 if succeeded
1541 int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type)
1542 {
1543         int ret_val;
1544         CFILE *cfile = NULL;            
1545         
1546         // zero the checksum
1547         *chksum = 0;
1548
1549         // attempt to open the file
1550         cfile = cfopen(filename,"rt",CFILE_NORMAL,cf_type);
1551         if(cfile == NULL){              
1552                 return 0;
1553         }
1554         
1555         // call the overloaded cf_chksum function()
1556         ret_val = cf_chksum_do(cfile, NULL, chksum, max_size);
1557
1558         // close the file down
1559         cfclose(cfile);
1560         cfile = NULL;
1561
1562         // return the result
1563         return ret_val; 
1564 }
1565
1566 // get the 32 bit CRC checksum of the passed file - return 0 if operation failed, 1 if succeeded
1567 // NOTE : preserves current file position
1568 int cf_chksum_long(CFILE *file, uint *chksum, int max_size)
1569 {
1570         int ret_code;
1571         int start_pos;
1572         
1573         // Returns current position of file.
1574         start_pos = cftell(file);
1575         if(start_pos == -1){
1576                 return 0;
1577         }
1578         
1579         // move to the beginning of the file
1580         if(cfseek(file, 0, CF_SEEK_SET)){
1581                 return 0;
1582         }
1583         ret_code = cf_chksum_do(file, NULL, chksum, max_size);
1584         // move back to the start position
1585         cfseek(file, start_pos, CF_SEEK_SET);
1586
1587         return ret_code;
1588 }
1589
1590
1591 // Flush the open file buffer
1592 //
1593 // exit: 0 - success
1594 //                      1 - failure
1595 int cflush(CFILE *cfile)
1596 {
1597         SDL_assert(cfile != NULL);
1598         Cfile_block *cb;
1599         SDL_assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
1600         cb = &Cfile_block_list[cfile->id];      
1601
1602         // not supported for memory mapped files
1603         SDL_assert( !cb->data );
1604
1605         SDL_assert(cb->fp != NULL);
1606         return fflush(cb->fp);
1607 }
1608
1609 // fill in Cfile_root_dir[] and Cfile_user_dir[]
1610 // this can be called at any time, even before cfile_init()
1611 //  returns: non-zero on error
1612 int cfile_init_paths()
1613 {
1614         if ( strlen(Cfile_root_dir) && strlen(Cfile_user_dir) ) {
1615                 return 0;
1616         }
1617
1618         char *t_path = SDL_GetBasePath();
1619
1620         // make sure we have something
1621         if (t_path == NULL) {
1622                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Error trying to determine executable directory!", NULL);
1623                 return 1;
1624         }
1625
1626         // size check
1627         if ( strlen(t_path) >= CFILE_ROOT_DIRECTORY_LEN ) {
1628                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Executable path is too long!", NULL);
1629                 return 1;
1630         }
1631
1632         // set root directory
1633         SDL_strlcpy(Cfile_root_dir, t_path, sizeof(Cfile_root_dir));
1634         // free SDL copy
1635         SDL_free(t_path);
1636         t_path = NULL;
1637
1638         // are we in a root directory?
1639         if ( cfile_in_root_dir(Cfile_root_dir) ) {
1640                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Freespace2/Fred2 cannot be run from a drive root directory!", NULL);
1641                 return 1;
1642         }
1643
1644         // now for the user/pref directory, the writable location
1645         char *u_path = SDL_GetPrefPath(Osreg_company_name, Osreg_title);
1646
1647         // make sure we have something
1648         if (u_path == NULL) {
1649                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Error trying to determine preferences directory!", NULL);
1650                 return 1;
1651         }
1652
1653         // size check
1654         if ( strlen(u_path) >= CFILE_ROOT_DIRECTORY_LEN ) {
1655                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Preferences path is too long!", NULL);
1656                 return 1;
1657         }
1658
1659         // set user/pref directory
1660         SDL_strlcpy(Cfile_user_dir, u_path, sizeof(Cfile_user_dir));
1661         // free SDL copy
1662         SDL_free(u_path);
1663         u_path = NULL;
1664
1665         return 0;
1666 }