fix briefing stuff
[btb/d2x.git] / cfile / cfile.c
1 /* $Id: cfile.c,v 1.7 2002-08-23 01:52:59 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include <conf.h>
17 #endif
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/stat.h>
22
23 #include "pstypes.h"
24 #include "u_mem.h"
25 #include "strutil.h"
26 #include "d_io.h"
27 #include "error.h"
28 #include "cfile.h"
29 #include "byteswap.h"
30
31 typedef struct hogfile {
32         char    name[13];
33         int     offset;
34         int     length;
35 } hogfile;
36
37 #define MAX_HOGFILES 300
38
39 hogfile HogFiles[MAX_HOGFILES];
40 char Hogfile_initialized = 0;
41 int Num_hogfiles = 0;
42
43 hogfile AltHogFiles[MAX_HOGFILES];
44 char AltHogfile_initialized = 0;
45 int AltNum_hogfiles = 0;
46 char HogFilename[64];
47 char AltHogFilename[64];
48
49 char AltHogDir[64];
50 char AltHogdir_initialized = 0;
51
52 // routine to take a DOS path and turn it into a macintosh
53 // pathname.  This routine is based on the fact that we should
54 // see a \ character in the dos path.  The sequence .\ a tthe
55 // beginning of a path is turned into a :
56
57 #ifdef MACINTOSH
58 void macify_dospath(char *dos_path, char *mac_path)
59 {
60         char *p;
61
62         if (!strncmp(dos_path, ".\\", 2)) {
63                 strcpy(mac_path, ":");
64                 strcat(mac_path, &(dos_path[2]) );
65         } else
66                 strcpy(mac_path, dos_path);
67
68         while ( (p = strchr(mac_path, '\\')) != NULL)
69                 *p = ':';
70
71 }
72 #endif
73
74 void cfile_use_alternate_hogdir( char * path )
75 {
76         if ( path )     {
77                 strcpy( AltHogDir, path );
78                 AltHogdir_initialized = 1;
79         } else {
80                 AltHogdir_initialized = 0;
81         }
82 }
83
84 //in case no one installs one
85 int default_error_counter=0;
86
87 //ptr to counter of how many critical errors
88 int *critical_error_counter_ptr=&default_error_counter;
89
90 //tell cfile about your critical error counter
91 void cfile_set_critical_error_counter_ptr(int *ptr)
92 {
93         critical_error_counter_ptr = ptr;
94
95 }
96
97
98 FILE * cfile_get_filehandle( char * filename, char * mode )
99 {
100         FILE * fp;
101         char temp[128];
102
103         *critical_error_counter_ptr = 0;
104         fp = fopen( filename, mode );
105         if ( fp && *critical_error_counter_ptr )        {
106                 fclose(fp);
107                 fp = NULL;
108         }
109         if ( (fp==NULL) && (AltHogdir_initialized) )    {
110                 strcpy( temp, AltHogDir );
111                 strcat( temp, "/");
112                 strcat( temp, filename );
113                 *critical_error_counter_ptr = 0;
114                 fp = fopen( temp, mode );
115                 if ( fp && *critical_error_counter_ptr )        {
116                         fclose(fp);
117                         fp = NULL;
118                 }
119         }
120         return fp;
121 }
122
123 //returns 1 if file loaded with no errors
124 int cfile_init_hogfile(char *fname, hogfile * hog_files, int * nfiles )
125 {
126         char id[4];
127         FILE * fp;
128         int i, len;
129
130         *nfiles = 0;
131
132         fp = cfile_get_filehandle( fname, "rb" );
133         if ( fp == NULL ) return 0;
134
135         fread( id, 3, 1, fp );
136         if ( strncmp( id, "DHF", 3 ) )  {
137                 fclose(fp);
138                 return 0;
139         }
140
141         while( 1 )
142         {
143                 if ( *nfiles >= MAX_HOGFILES ) {
144                         fclose(fp);
145                         Error( "HOGFILE is limited to %d files.\n",  MAX_HOGFILES );
146                 }
147                 i = fread( hog_files[*nfiles].name, 13, 1, fp );
148                 if ( i != 1 )   {               //eof here is ok
149                         fclose(fp);
150                         return 1;
151                 }
152                 i = fread( &len, 4, 1, fp );
153                 if ( i != 1 )   {
154                         fclose(fp);
155                         return 0;
156                 }
157                 hog_files[*nfiles].length = INTEL_INT(len);
158                 hog_files[*nfiles].offset = ftell( fp );
159                 *nfiles = (*nfiles) + 1;
160                 // Skip over
161                 i = fseek( fp, INTEL_INT(len), SEEK_CUR );
162         }
163 }
164
165 //Specify the name of the hogfile.  Returns 1 if hogfile found & had files
166 int cfile_init(char *hogname)
167 {
168         #ifdef MACINTOSH
169         char mac_path[255];
170
171         macify_dospath(hogname, mac_path);
172         #endif
173
174         Assert(Hogfile_initialized == 0);
175
176         #ifndef MACINTOSH
177         if (cfile_init_hogfile(hogname, HogFiles, &Num_hogfiles )) {
178                 strcpy( HogFilename, hogname );
179         #else
180         if (cfile_init_hogfile(mac_path, HogFiles, &Num_hogfiles )) {
181                 strcpy( HogFilename, mac_path );
182         #endif
183                 Hogfile_initialized = 1;
184                 return 1;
185         }
186         else
187                 return 0;       //not loaded!
188 }
189
190
191 int cfile_size(char *hogname)
192 {
193         CFILE *fp;
194         struct stat statbuf;
195
196         fp = cfopen(hogname, "rb");
197         if (fp == NULL)
198                 return -1;
199         fstat(fileno(fp->file), &statbuf);
200         cfclose(fp);
201         return statbuf.st_size;
202 }
203
204 FILE * cfile_find_libfile(char * name, int * length)
205 {
206         FILE * fp;
207         int i;
208
209         if ( AltHogfile_initialized )   {
210                 for (i=0; i<AltNum_hogfiles; i++ )      {
211                         if ( !stricmp( AltHogFiles[i].name, name ))     {
212                                 fp = cfile_get_filehandle( AltHogFilename, "rb" );
213                                 if ( fp == NULL ) return NULL;
214                                 fseek( fp,  AltHogFiles[i].offset, SEEK_SET );
215                                 *length = AltHogFiles[i].length;
216                                 return fp;
217                         }
218                 }
219         }
220
221         if ( !Hogfile_initialized )     {
222                 //@@cfile_init_hogfile( "DESCENT2.HOG", HogFiles, &Num_hogfiles );
223                 //@@Hogfile_initialized = 1;
224
225                 //Int3();       //hogfile ought to be initialized
226         }
227
228         for (i=0; i<Num_hogfiles; i++ ) {
229                 if ( !stricmp( HogFiles[i].name, name ))        {
230                         fp = cfile_get_filehandle( HogFilename, "rb" );
231                         if ( fp == NULL ) return NULL;
232                         fseek( fp,  HogFiles[i].offset, SEEK_SET );
233                         *length = HogFiles[i].length;
234                         return fp;
235                 }
236         }
237         return NULL;
238 }
239
240 int cfile_use_alternate_hogfile( char * name )
241 {
242         if ( name )     {
243                 #ifdef MACINTOSH
244                 char mac_path[255];
245
246                 macify_dospath(name, mac_path);
247                 strcpy( AltHogFilename, mac_path);
248                 #else
249                 strcpy( AltHogFilename, name );
250                 #endif
251                 cfile_init_hogfile( AltHogFilename, AltHogFiles, &AltNum_hogfiles );
252                 AltHogfile_initialized = 1;
253                 return (AltNum_hogfiles > 0);
254         } else {
255                 AltHogfile_initialized = 0;
256                 return 1;
257         }
258 }
259
260 int cfexist( char * filename )
261 {
262         int length;
263         FILE *fp;
264
265
266         if (filename[0] != '\x01')
267                 fp = cfile_get_filehandle( filename, "rb" );            // Check for non-hog file first...
268         else {
269                 fp = NULL;              //don't look in dir, only in hogfile
270                 filename++;
271         }
272
273         if ( fp )       {
274                 fclose(fp);
275                 return 1;
276         }
277
278         fp = cfile_find_libfile(filename, &length );
279         if ( fp )       {
280                 fclose(fp);
281                 return 2;               // file found in hog
282         }
283
284         return 0;               // Couldn't find it.
285 }
286
287
288 CFILE * cfopen(char * filename, char * mode )
289 {
290         int length;
291         FILE * fp;
292         CFILE *cfile;
293
294         if (stricmp( mode, "rb"))       {
295                 Error( "cfiles can only be opened with mode==rb\n" );
296         }
297
298         if (filename[0] != '\x01') {
299                 #ifdef MACINTOSH
300                 char mac_path[255];
301
302                 macify_dospath(filename, mac_path);
303                 fp = cfile_get_filehandle( mac_path, mode);
304                 #else
305                 fp = cfile_get_filehandle( filename, mode );            // Check for non-hog file first...
306                 #endif
307         } else {
308                 fp = NULL;              //don't look in dir, only in hogfile
309                 filename++;
310         }
311
312         if ( !fp ) {
313                 fp = cfile_find_libfile(filename, &length );
314                 if ( !fp )
315                         return NULL;            // No file found
316                 cfile = d_malloc ( sizeof(CFILE) );
317                 if ( cfile == NULL ) {
318                         fclose(fp);
319                         return NULL;
320                 }
321                 cfile->file = fp;
322                 cfile->size = length;
323                 cfile->lib_offset = ftell( fp );
324                 cfile->raw_position = 0;
325                 return cfile;
326         } else {
327                 cfile = d_malloc ( sizeof(CFILE) );
328                 if ( cfile == NULL ) {
329                         fclose(fp);
330                         return NULL;
331                 }
332                 cfile->file = fp;
333                 cfile->size = filelength( fileno(fp) );
334                 cfile->lib_offset = 0;
335                 cfile->raw_position = 0;
336                 return cfile;
337         }
338 }
339
340 int cfilelength( CFILE *fp )
341 {
342         return fp->size;
343 }
344
345 int cfgetc( CFILE * fp )
346 {
347         int c;
348
349         if (fp->raw_position >= fp->size ) return EOF;
350
351         c = getc( fp->file );
352         if (c!=EOF)
353                 fp->raw_position++;
354
355 //      Assert( fp->raw_position==(ftell(fp->file)-fp->lib_offset) );
356
357         return c;
358 }
359
360 /*
361  * read string terminated by zero or a platform's line ending.
362  * Martin: cleaned up line ending mess, and made it read
363  * zero-terminated strings (for descent 1 levels).
364  * assumed that no string has any zero's or other platform's line
365  * endings inside
366  * platform's line endings reference: UN*X: LF (10), Mac: CR (13),
367  * DOS: CR,LF
368  */
369 char * cfgets( char * buf, size_t n, CFILE * fp )
370 {
371         char * t = buf;
372         int i;
373         int c;
374
375         for (i=0; i<n-1; i++ )  {
376                 if (fp->raw_position >= fp->size ) {
377                         *buf = 0;
378                         return NULL;
379                 }
380                 c = fgetc( fp->file );
381                 fp->raw_position++;
382                 if (c == 0 || c == 10) // UN*X line ending or zero
383                         break;
384                 if (c == 13) { // it could be Mac or DOS line ending
385                         c = fgetc( fp->file );
386                         if ( c == 10 ) { // DOS line ending
387                                 break;
388                         } else { // Mac line ending, undo last character read
389                                 fseek( fp->file, -1, SEEK_CUR);
390                                 break;
391                         }
392                 }
393                 *buf++ = c;
394         }
395         *buf++ = 0;
396         return  t;
397 }
398
399 size_t cfread( void * buf, size_t elsize, size_t nelem, CFILE * fp ) 
400 {
401         unsigned int i, size;
402
403         size = elsize * nelem;
404         if ( size < 1 ) return 0;
405
406         i = fread ( buf, 1, size, fp->file );
407         fp->raw_position += i;
408         return i/elsize;
409 }
410
411
412 int cftell( CFILE *fp ) 
413 {
414         return fp->raw_position;
415 }
416
417 int cfseek( CFILE *fp, long int offset, int where )
418 {
419         int c, goal_position;
420
421         switch( where ) {
422         case SEEK_SET:
423                 goal_position = offset;
424                 break;
425         case SEEK_CUR:
426                 goal_position = fp->raw_position+offset;
427                 break;
428         case SEEK_END:
429                 goal_position = fp->size+offset;
430                 break;
431         default:
432                 return 1;
433         }       
434         c = fseek( fp->file, fp->lib_offset + goal_position, SEEK_SET );
435         fp->raw_position = ftell(fp->file)-fp->lib_offset;
436         return c;
437 }
438
439 void cfclose( CFILE * fp ) 
440 {       
441         fclose(fp->file);
442         d_free(fp);
443         return;
444 }
445
446 // routines to read basic data types from CFILE's.  Put here to
447 // simplify mac/pc reading from cfiles.
448
449 int cfile_read_int(CFILE *file)
450 {
451         int32_t i;
452
453         if (cfread( &i, sizeof(i), 1, file) != 1)
454                 Error( "Error reading int in cfile_read_int()" );
455
456         i = INTEL_INT(i);
457         return i;
458 }
459
460 short cfile_read_short(CFILE *file)
461 {
462         int16_t s;
463
464         if (cfread( &s, sizeof(s), 1, file) != 1)
465                 Error( "Error reading short in cfile_read_short()" );
466
467         s = INTEL_SHORT(s);
468         return s;
469 }
470
471 byte cfile_read_byte(CFILE *file)
472 {
473         byte b;
474
475         if (cfread( &b, sizeof(b), 1, file) != 1)
476                 Error( "Error reading byte in cfile_read_byte()" );
477
478         return b;
479 }
480
481 fix cfile_read_fix(CFILE *file)
482 {
483         fix f;
484
485         if (cfread( &f, sizeof(f), 1, file) != 1)
486                 Error( "Error reading fix in cfile_read_fix()" );
487
488         f = (fix)INTEL_INT((int)f);
489         return f;
490 }
491
492 fixang cfile_read_fixang(CFILE *file)
493 {
494         fixang f;
495
496         if (cfread(&f, 2, 1, file) != 1)
497                 Error("Error reading fixang in cfile_read_fixang()");
498
499         f = (fixang) INTEL_SHORT((int) f);
500         return f;
501 }
502
503 void cfile_read_vector(vms_vector *v, CFILE *file)
504 {
505         v->x = cfile_read_fix(file);
506         v->y = cfile_read_fix(file);
507         v->z = cfile_read_fix(file);
508 }
509
510 void cfile_read_angvec(vms_angvec *v, CFILE *file)
511 {
512         v->p = cfile_read_fixang(file);
513         v->b = cfile_read_fixang(file);
514         v->h = cfile_read_fixang(file);
515 }
516
517 void cfile_read_matrix(vms_matrix *m,CFILE *file)
518 {
519         cfile_read_vector(&m->rvec,file);
520         cfile_read_vector(&m->uvec,file);
521         cfile_read_vector(&m->fvec,file);
522 }
523