1 /* $Id: cfile.c,v 1.26 2004-08-17 19:36:50 schaffner Exp $ */
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.
17 * Functions for accessing compressed files.
20 * Revision 1.7 1995/10/27 15:18:20 allender
21 * get back to descent directory before trying to read a hog file
23 * Revision 1.6 1995/10/21 23:48:24 allender
24 * hogfile(s) are now in :Data: folder
26 * Revision 1.5 1995/08/14 09:27:31 allender
27 * added byteswap header
29 * Revision 1.4 1995/05/12 11:54:33 allender
30 * changed memory stuff again
32 * Revision 1.3 1995/05/04 20:03:38 allender
33 * added code that was missing...use NewPtr instead of malloc
35 * Revision 1.2 1995/04/03 09:59:49 allender
36 * *** empty log message ***
38 * Revision 1.1 1995/03/30 10:25:02 allender
42 * --- PC RCS Information ---
43 * Revision 1.24 1995/03/15 14:20:27 john
44 * Added critical error checker.
46 * Revision 1.23 1995/03/13 15:16:53 john
47 * Added alternate directory stuff.
49 * Revision 1.22 1995/02/09 23:08:47 matt
50 * Increased the max number of files in hogfile to 250
52 * Revision 1.21 1995/02/01 20:56:47 john
53 * Added cfexist function
55 * Revision 1.20 1995/01/21 17:53:48 john
56 * Added alternate pig file thing.
58 * Revision 1.19 1994/12/29 15:10:02 john
59 * Increased hogfile max files to 200.
61 * Revision 1.18 1994/12/12 13:20:57 john
62 * Made cfile work with fiellentth.
64 * Revision 1.17 1994/12/12 13:14:25 john
65 * Made cfiles prefer non-hog files.
67 * Revision 1.16 1994/12/09 18:53:26 john
68 * *** empty log message ***
70 * Revision 1.15 1994/12/09 18:52:56 john
71 * Took out mem, error checking.
73 * Revision 1.14 1994/12/09 18:10:31 john
74 * Speed up cfgets, which was slowing down the reading of
75 * bitmaps.tbl, which was making POF loading look slow.
77 * Revision 1.13 1994/12/09 17:53:51 john
78 * Added error checking to number of hogfiles..
80 * Revision 1.12 1994/12/08 19:02:55 john
83 * Revision 1.11 1994/12/07 21:57:48 john
86 * Revision 1.10 1994/12/07 21:38:02 john
87 * Made cfile not return error..
89 * Revision 1.9 1994/12/07 21:35:34 john
90 * Made it read from data directory.
92 * Revision 1.8 1994/12/07 21:33:55 john
93 * Stripped out compression stuff...
95 * Revision 1.7 1994/04/13 23:44:59 matt
96 * When file cannot be opened, free up the buffer for that file.
98 * Revision 1.6 1994/02/18 12:38:20 john
101 * Revision 1.5 1994/02/15 18:13:20 john
104 * Revision 1.4 1994/02/15 13:27:58 john
107 * Revision 1.3 1994/02/15 12:51:57 john
108 * Crappy inbetween version
110 * Revision 1.2 1994/02/14 20:12:29 john
111 * First version working with new cfile stuff.
113 * Revision 1.1 1994/02/14 15:51:33 john
116 * Revision 1.1 1994/02/10 15:45:12 john
135 #include "byteswap.h"
144 typedef struct hogfile {
150 #define MAX_HOGFILES 300
152 hogfile HogFiles[MAX_HOGFILES];
153 char Hogfile_initialized = 0;
154 int Num_hogfiles = 0;
155 char HogFilename[64];
157 hogfile D1HogFiles[MAX_HOGFILES];
158 char D1Hogfile_initialized = 0;
159 int D1Num_hogfiles = 0;
160 char D1HogFilename[64];
162 hogfile AltHogFiles[MAX_HOGFILES];
163 char AltHogfile_initialized = 0;
164 int AltNum_hogfiles = 0;
165 char AltHogFilename[64];
168 char AltHogdir_initialized = 0;
170 // routine to take a DOS path and turn it into a macintosh
171 // pathname. This routine is based on the fact that we should
172 // see a \ character in the dos path. The sequence .\ a tthe
173 // beginning of a path is turned into a :
176 void macify_dospath(char *dos_path, char *mac_path)
180 if (!strncmp(dos_path, ".\\", 2)) {
181 strcpy(mac_path, ":");
182 strcat(mac_path, &(dos_path[2]) );
184 strcpy(mac_path, dos_path);
186 while ( (p = strchr(mac_path, '\\')) != NULL)
192 void cfile_use_alternate_hogdir( char * path )
195 strcpy( AltHogDir, path );
196 AltHogdir_initialized = 1;
198 AltHogdir_initialized = 0;
202 //in case no one installs one
203 int default_error_counter=0;
205 //ptr to counter of how many critical errors
206 int *critical_error_counter_ptr=&default_error_counter;
208 //tell cfile about your critical error counter
209 void cfile_set_critical_error_counter_ptr(int *ptr)
211 critical_error_counter_ptr = ptr;
216 FILE * cfile_get_filehandle( char * filename, char * mode )
221 *critical_error_counter_ptr = 0;
222 fp = fopen( filename, mode );
223 if ( fp && *critical_error_counter_ptr ) {
227 if ( (fp==NULL) && (AltHogdir_initialized) ) {
228 strcpy( temp, AltHogDir );
230 strcat( temp, filename );
231 *critical_error_counter_ptr = 0;
232 fp = fopen( temp, mode );
233 if ( fp && *critical_error_counter_ptr ) {
241 //returns 1 if file loaded with no errors
242 int cfile_init_hogfile(char *fname, hogfile * hog_files, int * nfiles )
250 fp = cfile_get_filehandle( fname, "rb" );
251 if ( fp == NULL ) return 0;
253 fread( id, 3, 1, fp );
254 if ( strncmp( id, "DHF", 3 ) ) {
261 if ( *nfiles >= MAX_HOGFILES ) {
263 Error( "HOGFILE is limited to %d files.\n", MAX_HOGFILES );
265 i = fread( hog_files[*nfiles].name, 13, 1, fp );
266 if ( i != 1 ) { //eof here is ok
270 i = fread( &len, 4, 1, fp );
275 hog_files[*nfiles].length = INTEL_INT(len);
276 hog_files[*nfiles].offset = ftell( fp );
277 *nfiles = (*nfiles) + 1;
279 i = fseek( fp, INTEL_INT(len), SEEK_CUR );
283 //Specify the name of the hogfile. Returns 1 if hogfile found & had files
284 int cfile_init(char *hogname)
289 macify_dospath(hogname, mac_path);
292 Assert(Hogfile_initialized == 0);
295 if (cfile_init_hogfile(hogname, HogFiles, &Num_hogfiles )) {
296 strcpy( HogFilename, hogname );
298 if (cfile_init_hogfile(mac_path, HogFiles, &Num_hogfiles )) {
299 strcpy( HogFilename, mac_path );
301 Hogfile_initialized = 1;
305 return 0; //not loaded!
309 int cfile_size(char *hogname)
314 fp = cfopen(hogname, "rb");
317 size = ffilelength(fp->file);
323 * return handle for file called "name", embedded in one of the hogfiles
325 FILE * cfile_find_libfile(char * name, int * length)
330 if ( AltHogfile_initialized ) {
331 for (i=0; i<AltNum_hogfiles; i++ ) {
332 if ( !stricmp( AltHogFiles[i].name, name )) {
333 fp = cfile_get_filehandle( AltHogFilename, "rb" );
334 if ( fp == NULL ) return NULL;
335 fseek( fp, AltHogFiles[i].offset, SEEK_SET );
336 *length = AltHogFiles[i].length;
342 if ( !Hogfile_initialized ) {
343 //@@cfile_init_hogfile( "DESCENT2.HOG", HogFiles, &Num_hogfiles );
344 //@@Hogfile_initialized = 1;
346 //Int3(); //hogfile ought to be initialized
349 for (i=0; i<Num_hogfiles; i++ ) {
350 if ( !stricmp( HogFiles[i].name, name )) {
351 fp = cfile_get_filehandle( HogFilename, "rb" );
352 if ( fp == NULL ) return NULL;
353 fseek( fp, HogFiles[i].offset, SEEK_SET );
354 *length = HogFiles[i].length;
359 if (D1Hogfile_initialized) {
360 for (i = 0; i < D1Num_hogfiles; i++) {
361 if (!stricmp(D1HogFiles[i].name, name)) {
362 fp = cfile_get_filehandle(D1HogFilename, "rb");
363 if (fp == NULL) return NULL;
364 fseek(fp, D1HogFiles[i].offset, SEEK_SET);
365 *length = D1HogFiles[i].length;
374 int cfile_use_alternate_hogfile( char * name )
380 macify_dospath(name, mac_path);
381 strcpy( AltHogFilename, mac_path);
383 strcpy( AltHogFilename, name );
385 cfile_init_hogfile( AltHogFilename, AltHogFiles, &AltNum_hogfiles );
386 AltHogfile_initialized = 1;
387 return (AltNum_hogfiles > 0);
389 AltHogfile_initialized = 0;
394 int cfile_use_descent1_hogfile( char * name )
400 macify_dospath(name, mac_path);
401 strcpy(D1HogFilename, mac_path);
403 strcpy(D1HogFilename, name);
405 cfile_init_hogfile(D1HogFilename, D1HogFiles, &D1Num_hogfiles);
406 D1Hogfile_initialized = 1;
407 return (D1Num_hogfiles > 0);
409 D1Hogfile_initialized = 0;
415 // cfeof() Tests for end-of-file on a stream
417 // returns a nonzero value after the first read operation that attempts to read
418 // past the end of the file. It returns 0 if the current position is not end of file.
419 // There is no error return.
421 int cfeof(CFILE *cfile)
423 Assert(cfile != NULL);
425 Assert(cfile->file != NULL);
427 return (cfile->raw_position >= cfile->size);
431 int cferror(CFILE *cfile)
433 return ferror(cfile->file);
437 int cfexist( char * filename )
443 if (filename[0] != '\x01')
444 fp = cfile_get_filehandle( filename, "rb" ); // Check for non-hog file first...
446 fp = NULL; //don't look in dir, only in hogfile
455 fp = cfile_find_libfile(filename, &length );
458 return 2; // file found in hog
461 return 0; // Couldn't find it.
466 int cfile_delete(char *filename)
469 return remove(filename);
471 return !DeleteFile(filename);
477 int cfile_rename(char *oldname, char *newname)
480 return rename(oldname, newname);
482 return !MoveFile(oldname, newname);
488 int cfile_mkdir(char *pathname)
492 return !CreateDirectory(pathname, NULL);
494 return _mkdir(pathname);
496 #elif defined(macintosh)
499 long dirID; // Insists on returning this
501 macify_posix_path(pathname, mac_path);
502 CopyCStringToPascal(mac_path, pascal_path);
503 return DirCreate(0, 0, pascal_path, &dirID);
505 return mkdir(pathname, 0755);
510 CFILE * cfopen(char * filename, char * mode )
516 if (filename[0] != '\x01') {
520 macify_dospath(filename, mac_path);
521 fp = cfile_get_filehandle( mac_path, mode);
523 fp = cfile_get_filehandle( filename, mode ); // Check for non-hog file first...
526 fp = NULL; //don't look in dir, only in hogfile
531 fp = cfile_find_libfile(filename, &length );
533 return NULL; // No file found
534 if (stricmp(mode, "rb"))
535 Error("mode must be rb for files in hog.\n");
536 cfile = d_malloc ( sizeof(CFILE) );
537 if ( cfile == NULL ) {
542 cfile->size = length;
543 cfile->lib_offset = ftell( fp );
544 cfile->raw_position = 0;
547 cfile = d_malloc ( sizeof(CFILE) );
548 if ( cfile == NULL ) {
553 cfile->size = ffilelength(fp);
554 cfile->lib_offset = 0;
555 cfile->raw_position = 0;
560 int cfilelength( CFILE *fp )
566 // cfwrite() writes to the file
568 // returns: number of full elements actually written
571 int cfwrite(void *buf, int elsize, int nelem, CFILE *cfile)
575 Assert(cfile != NULL);
579 Assert(cfile->file != NULL);
580 Assert(cfile->lib_offset == 0);
582 items_written = fwrite(buf, elsize, nelem, cfile->file);
583 cfile->raw_position = ftell(cfile->file);
585 return items_written;
589 // cfputc() writes a character to a file
591 // returns: success ==> returns character written
594 int cfputc(int c, CFILE *cfile)
598 Assert(cfile != NULL);
600 Assert(cfile->file != NULL);
601 Assert(cfile->lib_offset == 0);
603 char_written = fputc(c, cfile->file);
604 cfile->raw_position = ftell(cfile->file);
610 int cfgetc( CFILE * fp )
614 if (fp->raw_position >= fp->size ) return EOF;
616 c = getc( fp->file );
618 fp->raw_position = ftell(fp->file)-fp->lib_offset;
624 // cfputs() writes a string to a file
626 // returns: success ==> non-negative value
629 int cfputs(char *str, CFILE *cfile)
633 Assert(cfile != NULL);
636 Assert(cfile->file != NULL);
638 ret = fputs(str, cfile->file);
639 cfile->raw_position = ftell(cfile->file);
645 char * cfgets( char * buf, size_t n, CFILE * fp )
651 #if 0 // don't use the standard fgets, because it will only handle the native line-ending style
652 if (fp->lib_offset == 0) // This is not an archived file
654 t = fgets(buf, n, fp->file);
655 fp->raw_position = ftell(fp->file);
660 for (i=0; i<n-1; i++ ) {
662 if (fp->raw_position >= fp->size ) {
667 if (c == 0 || c == 10) // Unix line ending
669 if (c == 13) { // Mac or DOS line ending
673 if (c1 != EOF) // The file could end with a Mac line ending
674 cfseek(fp, -1, SEEK_CUR);
675 if ( c1 == 10 ) // DOS line ending
677 else // Mac line ending
681 if ( c == 13 ) // because cr-lf is a bad thing on the mac
682 c = '\n'; // and anyway -- 0xod is CR on mac, not 0x0a
684 if ( c=='\n' ) break;
690 size_t cfread( void * buf, size_t elsize, size_t nelem, CFILE * fp )
692 unsigned int i, size;
694 size = elsize * nelem;
695 if ( size < 1 ) return 0;
697 i = fread ( buf, 1, size, fp->file );
698 fp->raw_position += i;
703 int cftell( CFILE *fp )
705 return fp->raw_position;
708 int cfseek( CFILE *fp, long int offset, int where )
710 int c, goal_position;
714 goal_position = offset;
717 goal_position = fp->raw_position+offset;
720 goal_position = fp->size+offset;
725 c = fseek( fp->file, fp->lib_offset + goal_position, SEEK_SET );
726 fp->raw_position = ftell(fp->file)-fp->lib_offset;
730 int cfclose(CFILE *fp)
734 result = fclose(fp->file);
740 // routines to read basic data types from CFILE's. Put here to
741 // simplify mac/pc reading from cfiles.
743 int cfile_read_int(CFILE *file)
747 if (cfread( &i, sizeof(i), 1, file) != 1)
748 Error( "Error reading int in cfile_read_int()" );
754 short cfile_read_short(CFILE *file)
758 if (cfread( &s, sizeof(s), 1, file) != 1)
759 Error( "Error reading short in cfile_read_short()" );
765 sbyte cfile_read_byte(CFILE *file)
769 if (cfread( &b, sizeof(b), 1, file) != 1)
770 Error( "Error reading byte in cfile_read_byte()" );
775 fix cfile_read_fix(CFILE *file)
779 if (cfread( &f, sizeof(f), 1, file) != 1)
780 Error( "Error reading fix in cfile_read_fix()" );
782 f = (fix)INTEL_INT((int)f);
786 fixang cfile_read_fixang(CFILE *file)
790 if (cfread(&f, 2, 1, file) != 1)
791 Error("Error reading fixang in cfile_read_fixang()");
793 f = (fixang) INTEL_SHORT((int) f);
797 void cfile_read_vector(vms_vector *v, CFILE *file)
799 v->x = cfile_read_fix(file);
800 v->y = cfile_read_fix(file);
801 v->z = cfile_read_fix(file);
804 void cfile_read_angvec(vms_angvec *v, CFILE *file)
806 v->p = cfile_read_fixang(file);
807 v->b = cfile_read_fixang(file);
808 v->h = cfile_read_fixang(file);
811 void cfile_read_matrix(vms_matrix *m,CFILE *file)
813 cfile_read_vector(&m->rvec,file);
814 cfile_read_vector(&m->uvec,file);
815 cfile_read_vector(&m->fvec,file);
819 void cfile_read_string(char *buf, int n, CFILE *file)
824 c = (char)cfile_read_byte(file);
834 // equivalent write functions of above read functions follow
836 int cfile_write_int(int i, CFILE *file)
839 return cfwrite(&i, sizeof(i), 1, file);
843 int cfile_write_short(short s, CFILE *file)
846 return cfwrite(&s, sizeof(s), 1, file);
850 int cfile_write_byte(sbyte b, CFILE *file)
852 return cfwrite(&b, sizeof(b), 1, file);
856 int cfile_write_string(char *buf, CFILE *file)
860 if ((!buf) || (buf && !buf[0]))
861 return cfile_write_byte(0, file);
864 if (!cfwrite(buf, len, 1, file))
867 return cfile_write_byte(0, file); // write out NULL termination