1 /* $Id: cfile.c,v 1.27 2004-08-28 23:17:45 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.
43 typedef struct hogfile {
49 #define MAX_HOGFILES 300
51 hogfile HogFiles[MAX_HOGFILES];
52 char Hogfile_initialized = 0;
56 hogfile D1HogFiles[MAX_HOGFILES];
57 char D1Hogfile_initialized = 0;
58 int D1Num_hogfiles = 0;
59 char D1HogFilename[64];
61 hogfile AltHogFiles[MAX_HOGFILES];
62 char AltHogfile_initialized = 0;
63 int AltNum_hogfiles = 0;
64 char AltHogFilename[64];
67 char AltHogdir_initialized = 0;
69 // routine to take a DOS path and turn it into a macintosh
70 // pathname. This routine is based on the fact that we should
71 // see a \ character in the dos path. The sequence .\ a tthe
72 // beginning of a path is turned into a :
75 void macify_dospath(char *dos_path, char *mac_path)
79 if (!strncmp(dos_path, ".\\", 2)) {
80 strcpy(mac_path, ":");
81 strcat(mac_path, &(dos_path[2]) );
83 strcpy(mac_path, dos_path);
85 while ( (p = strchr(mac_path, '\\')) != NULL)
91 void cfile_use_alternate_hogdir( char * path )
94 strcpy( AltHogDir, path );
95 AltHogdir_initialized = 1;
97 AltHogdir_initialized = 0;
101 //in case no one installs one
102 int default_error_counter=0;
104 //ptr to counter of how many critical errors
105 int *critical_error_counter_ptr=&default_error_counter;
107 //tell cfile about your critical error counter
108 void cfile_set_critical_error_counter_ptr(int *ptr)
110 critical_error_counter_ptr = ptr;
115 FILE * cfile_get_filehandle( char * filename, char * mode )
120 *critical_error_counter_ptr = 0;
121 fp = fopen( filename, mode );
122 if ( fp && *critical_error_counter_ptr ) {
126 if ( (fp==NULL) && (AltHogdir_initialized) ) {
127 strcpy( temp, AltHogDir );
129 strcat( temp, filename );
130 *critical_error_counter_ptr = 0;
131 fp = fopen( temp, mode );
132 if ( fp && *critical_error_counter_ptr ) {
140 //returns 1 if file loaded with no errors
141 int cfile_init_hogfile(char *fname, hogfile * hog_files, int * nfiles )
149 fp = cfile_get_filehandle( fname, "rb" );
150 if ( fp == NULL ) return 0;
152 fread( id, 3, 1, fp );
153 if ( strncmp( id, "DHF", 3 ) ) {
160 if ( *nfiles >= MAX_HOGFILES ) {
162 Error( "HOGFILE is limited to %d files.\n", MAX_HOGFILES );
164 i = fread( hog_files[*nfiles].name, 13, 1, fp );
165 if ( i != 1 ) { //eof here is ok
169 i = fread( &len, 4, 1, fp );
174 hog_files[*nfiles].length = INTEL_INT(len);
175 hog_files[*nfiles].offset = ftell( fp );
176 *nfiles = (*nfiles) + 1;
178 i = fseek( fp, INTEL_INT(len), SEEK_CUR );
182 //Specify the name of the hogfile. Returns 1 if hogfile found & had files
183 int cfile_init(char *hogname)
188 macify_dospath(hogname, mac_path);
191 Assert(Hogfile_initialized == 0);
194 if (cfile_init_hogfile(hogname, HogFiles, &Num_hogfiles )) {
195 strcpy( HogFilename, hogname );
197 if (cfile_init_hogfile(mac_path, HogFiles, &Num_hogfiles )) {
198 strcpy( HogFilename, mac_path );
200 Hogfile_initialized = 1;
204 return 0; //not loaded!
208 int cfile_size(char *hogname)
213 fp = cfopen(hogname, "rb");
216 size = ffilelength(fp->file);
222 * return handle for file called "name", embedded in one of the hogfiles
224 FILE * cfile_find_libfile(char * name, int * length)
229 if ( AltHogfile_initialized ) {
230 for (i=0; i<AltNum_hogfiles; i++ ) {
231 if ( !stricmp( AltHogFiles[i].name, name )) {
232 fp = cfile_get_filehandle( AltHogFilename, "rb" );
233 if ( fp == NULL ) return NULL;
234 fseek( fp, AltHogFiles[i].offset, SEEK_SET );
235 *length = AltHogFiles[i].length;
241 if ( !Hogfile_initialized ) {
242 //@@cfile_init_hogfile( "DESCENT2.HOG", HogFiles, &Num_hogfiles );
243 //@@Hogfile_initialized = 1;
245 //Int3(); //hogfile ought to be initialized
248 for (i=0; i<Num_hogfiles; i++ ) {
249 if ( !stricmp( HogFiles[i].name, name )) {
250 fp = cfile_get_filehandle( HogFilename, "rb" );
251 if ( fp == NULL ) return NULL;
252 fseek( fp, HogFiles[i].offset, SEEK_SET );
253 *length = HogFiles[i].length;
258 if (D1Hogfile_initialized) {
259 for (i = 0; i < D1Num_hogfiles; i++) {
260 if (!stricmp(D1HogFiles[i].name, name)) {
261 fp = cfile_get_filehandle(D1HogFilename, "rb");
262 if (fp == NULL) return NULL;
263 fseek(fp, D1HogFiles[i].offset, SEEK_SET);
264 *length = D1HogFiles[i].length;
273 int cfile_use_alternate_hogfile( char * name )
279 macify_dospath(name, mac_path);
280 strcpy( AltHogFilename, mac_path);
282 strcpy( AltHogFilename, name );
284 cfile_init_hogfile( AltHogFilename, AltHogFiles, &AltNum_hogfiles );
285 AltHogfile_initialized = 1;
286 return (AltNum_hogfiles > 0);
288 AltHogfile_initialized = 0;
293 int cfile_use_descent1_hogfile( char * name )
299 macify_dospath(name, mac_path);
300 strcpy(D1HogFilename, mac_path);
302 strcpy(D1HogFilename, name);
304 cfile_init_hogfile(D1HogFilename, D1HogFiles, &D1Num_hogfiles);
305 D1Hogfile_initialized = 1;
306 return (D1Num_hogfiles > 0);
308 D1Hogfile_initialized = 0;
314 // cfeof() Tests for end-of-file on a stream
316 // returns a nonzero value after the first read operation that attempts to read
317 // past the end of the file. It returns 0 if the current position is not end of file.
318 // There is no error return.
320 int cfeof(CFILE *cfile)
322 Assert(cfile != NULL);
324 Assert(cfile->file != NULL);
326 return (cfile->raw_position >= cfile->size);
330 int cferror(CFILE *cfile)
332 return ferror(cfile->file);
336 int cfexist( char * filename )
342 if (filename[0] != '\x01')
343 fp = cfile_get_filehandle( filename, "rb" ); // Check for non-hog file first...
345 fp = NULL; //don't look in dir, only in hogfile
354 fp = cfile_find_libfile(filename, &length );
357 return 2; // file found in hog
360 return 0; // Couldn't find it.
365 int cfile_delete(char *filename)
368 return remove(filename);
370 return !DeleteFile(filename);
376 int cfile_rename(char *oldname, char *newname)
379 return rename(oldname, newname);
381 return !MoveFile(oldname, newname);
387 int cfile_mkdir(char *pathname)
391 return !CreateDirectory(pathname, NULL);
393 return _mkdir(pathname);
395 #elif defined(macintosh)
398 long dirID; // Insists on returning this
400 macify_posix_path(pathname, mac_path);
401 CopyCStringToPascal(mac_path, pascal_path);
402 return DirCreate(0, 0, pascal_path, &dirID);
404 return mkdir(pathname, 0755);
409 CFILE * cfopen(char * filename, char * mode )
415 if (filename[0] != '\x01') {
419 macify_dospath(filename, mac_path);
420 fp = cfile_get_filehandle( mac_path, mode);
422 fp = cfile_get_filehandle( filename, mode ); // Check for non-hog file first...
425 fp = NULL; //don't look in dir, only in hogfile
430 fp = cfile_find_libfile(filename, &length );
432 return NULL; // No file found
433 if (stricmp(mode, "rb"))
434 Error("mode must be rb for files in hog.\n");
435 cfile = d_malloc ( sizeof(CFILE) );
436 if ( cfile == NULL ) {
441 cfile->size = length;
442 cfile->lib_offset = ftell( fp );
443 cfile->raw_position = 0;
446 cfile = d_malloc ( sizeof(CFILE) );
447 if ( cfile == NULL ) {
452 cfile->size = ffilelength(fp);
453 cfile->lib_offset = 0;
454 cfile->raw_position = 0;
459 int cfilelength( CFILE *fp )
465 // cfwrite() writes to the file
467 // returns: number of full elements actually written
470 int cfwrite(void *buf, int elsize, int nelem, CFILE *cfile)
474 Assert(cfile != NULL);
478 Assert(cfile->file != NULL);
479 Assert(cfile->lib_offset == 0);
481 items_written = fwrite(buf, elsize, nelem, cfile->file);
482 cfile->raw_position = ftell(cfile->file);
484 return items_written;
488 // cfputc() writes a character to a file
490 // returns: success ==> returns character written
493 int cfputc(int c, CFILE *cfile)
497 Assert(cfile != NULL);
499 Assert(cfile->file != NULL);
500 Assert(cfile->lib_offset == 0);
502 char_written = fputc(c, cfile->file);
503 cfile->raw_position = ftell(cfile->file);
509 int cfgetc( CFILE * fp )
513 if (fp->raw_position >= fp->size ) return EOF;
515 c = getc( fp->file );
517 fp->raw_position = ftell(fp->file)-fp->lib_offset;
523 // cfputs() writes a string to a file
525 // returns: success ==> non-negative value
528 int cfputs(char *str, CFILE *cfile)
532 Assert(cfile != NULL);
535 Assert(cfile->file != NULL);
537 ret = fputs(str, cfile->file);
538 cfile->raw_position = ftell(cfile->file);
544 char * cfgets( char * buf, size_t n, CFILE * fp )
550 #if 0 // don't use the standard fgets, because it will only handle the native line-ending style
551 if (fp->lib_offset == 0) // This is not an archived file
553 t = fgets(buf, n, fp->file);
554 fp->raw_position = ftell(fp->file);
559 for (i=0; i<n-1; i++ ) {
561 if (fp->raw_position >= fp->size ) {
566 if (c == 0 || c == 10) // Unix line ending
568 if (c == 13) { // Mac or DOS line ending
572 if (c1 != EOF) // The file could end with a Mac line ending
573 cfseek(fp, -1, SEEK_CUR);
574 if ( c1 == 10 ) // DOS line ending
576 else // Mac line ending
580 if ( c == 13 ) // because cr-lf is a bad thing on the mac
581 c = '\n'; // and anyway -- 0xod is CR on mac, not 0x0a
583 if ( c=='\n' ) break;
589 size_t cfread( void * buf, size_t elsize, size_t nelem, CFILE * fp )
591 unsigned int i, size;
593 size = elsize * nelem;
594 if ( size < 1 ) return 0;
596 i = fread ( buf, 1, size, fp->file );
597 fp->raw_position += i;
602 int cftell( CFILE *fp )
604 return fp->raw_position;
607 int cfseek( CFILE *fp, long int offset, int where )
609 int c, goal_position;
613 goal_position = offset;
616 goal_position = fp->raw_position+offset;
619 goal_position = fp->size+offset;
624 c = fseek( fp->file, fp->lib_offset + goal_position, SEEK_SET );
625 fp->raw_position = ftell(fp->file)-fp->lib_offset;
629 int cfclose(CFILE *fp)
633 result = fclose(fp->file);
639 // routines to read basic data types from CFILE's. Put here to
640 // simplify mac/pc reading from cfiles.
642 int cfile_read_int(CFILE *file)
646 if (cfread( &i, sizeof(i), 1, file) != 1)
647 Error( "Error reading int in cfile_read_int()" );
653 short cfile_read_short(CFILE *file)
657 if (cfread( &s, sizeof(s), 1, file) != 1)
658 Error( "Error reading short in cfile_read_short()" );
664 sbyte cfile_read_byte(CFILE *file)
668 if (cfread( &b, sizeof(b), 1, file) != 1)
669 Error( "Error reading byte in cfile_read_byte()" );
674 fix cfile_read_fix(CFILE *file)
678 if (cfread( &f, sizeof(f), 1, file) != 1)
679 Error( "Error reading fix in cfile_read_fix()" );
681 f = (fix)INTEL_INT((int)f);
685 fixang cfile_read_fixang(CFILE *file)
689 if (cfread(&f, 2, 1, file) != 1)
690 Error("Error reading fixang in cfile_read_fixang()");
692 f = (fixang) INTEL_SHORT((int) f);
696 void cfile_read_vector(vms_vector *v, CFILE *file)
698 v->x = cfile_read_fix(file);
699 v->y = cfile_read_fix(file);
700 v->z = cfile_read_fix(file);
703 void cfile_read_angvec(vms_angvec *v, CFILE *file)
705 v->p = cfile_read_fixang(file);
706 v->b = cfile_read_fixang(file);
707 v->h = cfile_read_fixang(file);
710 void cfile_read_matrix(vms_matrix *m,CFILE *file)
712 cfile_read_vector(&m->rvec,file);
713 cfile_read_vector(&m->uvec,file);
714 cfile_read_vector(&m->fvec,file);
718 void cfile_read_string(char *buf, int n, CFILE *file)
723 c = (char)cfile_read_byte(file);
733 // equivalent write functions of above read functions follow
735 int cfile_write_int(int i, CFILE *file)
738 return cfwrite(&i, sizeof(i), 1, file);
742 int cfile_write_short(short s, CFILE *file)
745 return cfwrite(&s, sizeof(s), 1, file);
749 int cfile_write_byte(sbyte b, CFILE *file)
751 return cfwrite(&b, sizeof(b), 1, file);
755 int cfile_write_string(char *buf, CFILE *file)
759 if ((!buf) || (buf && !buf[0]))
760 return cfile_write_byte(0, file);
763 if (!cfwrite(buf, len, 1, file))
766 return cfile_write_byte(0, file); // write out NULL termination