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