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