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