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