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