comments/formatting
[btb/d2x.git] / cfile / cfile.c
1 /* $Id: cfile.c,v 1.23 2003-11-27 00:36:14 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 /*
16  *
17  * Functions for accessing compressed files.
18  *
19  * Old Log:
20  * Revision 1.7  1995/10/27  15:18:20  allender
21  * get back to descent directory before trying to read a hog file
22  *
23  * Revision 1.6  1995/10/21  23:48:24  allender
24  * hogfile(s) are now in :Data: folder
25  *
26  * Revision 1.5  1995/08/14  09:27:31  allender
27  * added byteswap header
28  *
29  * Revision 1.4  1995/05/12  11:54:33  allender
30  * changed memory stuff again
31  *
32  * Revision 1.3  1995/05/04  20:03:38  allender
33  * added code that was missing...use NewPtr instead of malloc
34  *
35  * Revision 1.2  1995/04/03  09:59:49  allender
36  * *** empty log message ***
37  *
38  * Revision 1.1  1995/03/30  10:25:02  allender
39  * Initial revision
40  *
41  *
42  * --- PC RCS Information ---
43  * Revision 1.24  1995/03/15  14:20:27  john
44  * Added critical error checker.
45  *
46  * Revision 1.23  1995/03/13  15:16:53  john
47  * Added alternate directory stuff.
48  *
49  * Revision 1.22  1995/02/09  23:08:47  matt
50  * Increased the max number of files in hogfile to 250
51  *
52  * Revision 1.21  1995/02/01  20:56:47  john
53  * Added cfexist function
54  *
55  * Revision 1.20  1995/01/21  17:53:48  john
56  * Added alternate pig file thing.
57  *
58  * Revision 1.19  1994/12/29  15:10:02  john
59  * Increased hogfile max files to 200.
60  *
61  * Revision 1.18  1994/12/12  13:20:57  john
62  * Made cfile work with fiellentth.
63  *
64  * Revision 1.17  1994/12/12  13:14:25  john
65  * Made cfiles prefer non-hog files.
66  *
67  * Revision 1.16  1994/12/09  18:53:26  john
68  * *** empty log message ***
69  *
70  * Revision 1.15  1994/12/09  18:52:56  john
71  * Took out mem, error checking.
72  *
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.
76  *
77  * Revision 1.13  1994/12/09  17:53:51  john
78  * Added error checking to number of hogfiles..
79  *
80  * Revision 1.12  1994/12/08  19:02:55  john
81  * Added cfgets.
82  *
83  * Revision 1.11  1994/12/07  21:57:48  john
84  * Took out data dir.
85  *
86  * Revision 1.10  1994/12/07  21:38:02  john
87  * Made cfile not return error..
88  *
89  * Revision 1.9  1994/12/07  21:35:34  john
90  * Made it read from data directory.
91  *
92  * Revision 1.8  1994/12/07  21:33:55  john
93  * Stripped out compression stuff...
94  *
95  * Revision 1.7  1994/04/13  23:44:59  matt
96  * When file cannot be opened, free up the buffer for that file.
97  *
98  * Revision 1.6  1994/02/18  12:38:20  john
99  * Optimized a bit
100  *
101  * Revision 1.5  1994/02/15  18:13:20  john
102  * Fixed more bugs.
103  *
104  * Revision 1.4  1994/02/15  13:27:58  john
105  * Works ok...
106  *
107  * Revision 1.3  1994/02/15  12:51:57  john
108  * Crappy inbetween version
109  *
110  * Revision 1.2  1994/02/14  20:12:29  john
111  * First version working with new cfile stuff.
112  *
113  * Revision 1.1  1994/02/14  15:51:33  john
114  * Initial revision
115  *
116  * Revision 1.1  1994/02/10  15:45:12  john
117  * Initial revision
118  *
119  *
120  */
121
122 #ifdef HAVE_CONFIG_H
123 #include <conf.h>
124 #endif
125
126 #include <stdio.h>
127 #include <string.h>
128 #ifndef _WIN32_WCE
129 #include <sys/stat.h>
130 #else
131 # include <windows.h>
132 #endif
133
134 #include "pstypes.h"
135 #include "u_mem.h"
136 #include "strutil.h"
137 #include "d_io.h"
138 #include "error.h"
139 #include "cfile.h"
140 #include "byteswap.h"
141
142 struct CFILE {
143         FILE    *file;
144         int     size;
145         int     lib_offset;
146         int     raw_position;
147 };
148
149 typedef struct hogfile {
150         char    name[13];
151         int     offset;
152         int     length;
153 } hogfile;
154
155 #define MAX_HOGFILES 300
156
157 hogfile HogFiles[MAX_HOGFILES];
158 char Hogfile_initialized = 0;
159 int Num_hogfiles = 0;
160 char HogFilename[64];
161
162 hogfile D1HogFiles[MAX_HOGFILES];
163 char D1Hogfile_initialized = 0;
164 int D1Num_hogfiles = 0;
165 char D1HogFilename[64];
166
167 hogfile AltHogFiles[MAX_HOGFILES];
168 char AltHogfile_initialized = 0;
169 int AltNum_hogfiles = 0;
170 char AltHogFilename[64];
171
172 char AltHogDir[64];
173 char AltHogdir_initialized = 0;
174
175 // routine to take a DOS path and turn it into a macintosh
176 // pathname.  This routine is based on the fact that we should
177 // see a \ character in the dos path.  The sequence .\ a tthe
178 // beginning of a path is turned into a :
179
180 #ifdef MACINTOSH
181 void macify_dospath(char *dos_path, char *mac_path)
182 {
183         char *p;
184
185         if (!strncmp(dos_path, ".\\", 2)) {
186                 strcpy(mac_path, ":");
187                 strcat(mac_path, &(dos_path[2]) );
188         } else
189                 strcpy(mac_path, dos_path);
190
191         while ( (p = strchr(mac_path, '\\')) != NULL)
192                 *p = ':';
193
194 }
195 #endif
196
197 void cfile_use_alternate_hogdir( char * path )
198 {
199         if ( path )     {
200                 strcpy( AltHogDir, path );
201                 AltHogdir_initialized = 1;
202         } else {
203                 AltHogdir_initialized = 0;
204         }
205 }
206
207 //in case no one installs one
208 int default_error_counter=0;
209
210 //ptr to counter of how many critical errors
211 int *critical_error_counter_ptr=&default_error_counter;
212
213 //tell cfile about your critical error counter
214 void cfile_set_critical_error_counter_ptr(int *ptr)
215 {
216         critical_error_counter_ptr = ptr;
217
218 }
219
220
221 FILE * cfile_get_filehandle( char * filename, char * mode )
222 {
223         FILE * fp;
224         char temp[128];
225
226         *critical_error_counter_ptr = 0;
227         fp = fopen( filename, mode );
228         if ( fp && *critical_error_counter_ptr )        {
229                 fclose(fp);
230                 fp = NULL;
231         }
232         if ( (fp==NULL) && (AltHogdir_initialized) )    {
233                 strcpy( temp, AltHogDir );
234                 strcat( temp, "/");
235                 strcat( temp, filename );
236                 *critical_error_counter_ptr = 0;
237                 fp = fopen( temp, mode );
238                 if ( fp && *critical_error_counter_ptr )        {
239                         fclose(fp);
240                         fp = NULL;
241                 }
242         }
243         return fp;
244 }
245
246 //returns 1 if file loaded with no errors
247 int cfile_init_hogfile(char *fname, hogfile * hog_files, int * nfiles )
248 {
249         char id[4];
250         FILE * fp;
251         int i, len;
252
253         *nfiles = 0;
254
255         fp = cfile_get_filehandle( fname, "rb" );
256         if ( fp == NULL ) return 0;
257
258         fread( id, 3, 1, fp );
259         if ( strncmp( id, "DHF", 3 ) )  {
260                 fclose(fp);
261                 return 0;
262         }
263
264         while( 1 )
265         {
266                 if ( *nfiles >= MAX_HOGFILES ) {
267                         fclose(fp);
268                         Error( "HOGFILE is limited to %d files.\n",  MAX_HOGFILES );
269                 }
270                 i = fread( hog_files[*nfiles].name, 13, 1, fp );
271                 if ( i != 1 )   {               //eof here is ok
272                         fclose(fp);
273                         return 1;
274                 }
275                 i = fread( &len, 4, 1, fp );
276                 if ( i != 1 )   {
277                         fclose(fp);
278                         return 0;
279                 }
280                 hog_files[*nfiles].length = INTEL_INT(len);
281                 hog_files[*nfiles].offset = ftell( fp );
282                 *nfiles = (*nfiles) + 1;
283                 // Skip over
284                 i = fseek( fp, INTEL_INT(len), SEEK_CUR );
285         }
286 }
287
288 //Specify the name of the hogfile.  Returns 1 if hogfile found & had files
289 int cfile_init(char *hogname)
290 {
291         #ifdef MACINTOSH
292         char mac_path[255];
293
294         macify_dospath(hogname, mac_path);
295         #endif
296
297         Assert(Hogfile_initialized == 0);
298
299         #ifndef MACINTOSH
300         if (cfile_init_hogfile(hogname, HogFiles, &Num_hogfiles )) {
301                 strcpy( HogFilename, hogname );
302         #else
303         if (cfile_init_hogfile(mac_path, HogFiles, &Num_hogfiles )) {
304                 strcpy( HogFilename, mac_path );
305         #endif
306                 Hogfile_initialized = 1;
307                 return 1;
308         }
309         else
310                 return 0;       //not loaded!
311 }
312
313
314 int cfile_size(char *hogname)
315 {
316 #ifndef _WIN32_WCE
317         CFILE *fp;
318         struct stat statbuf;
319
320         fp = cfopen(hogname, "rb");
321         if (fp == NULL)
322                 return -1;
323         fstat(fileno(fp->file), &statbuf);
324         cfclose(fp);
325         return statbuf.st_size;
326 #else
327         CFILE *fp;
328         DWORD size;
329
330         fp = cfopen(hogname, "rb");
331         if (fp == NULL)
332                 return -1;
333         size = GetFileSize(fileno(fp->file), NULL);
334         cfclose(fp);
335         return size;
336 #endif
337 }
338
339 /*
340  * return handle for file called "name", embedded in one of the hogfiles
341  */
342 FILE * cfile_find_libfile(char * name, int * length)
343 {
344         FILE * fp;
345         int i;
346
347         if ( AltHogfile_initialized )   {
348                 for (i=0; i<AltNum_hogfiles; i++ )      {
349                         if ( !stricmp( AltHogFiles[i].name, name ))     {
350                                 fp = cfile_get_filehandle( AltHogFilename, "rb" );
351                                 if ( fp == NULL ) return NULL;
352                                 fseek( fp,  AltHogFiles[i].offset, SEEK_SET );
353                                 *length = AltHogFiles[i].length;
354                                 return fp;
355                         }
356                 }
357         }
358
359         if ( !Hogfile_initialized )     {
360                 //@@cfile_init_hogfile( "DESCENT2.HOG", HogFiles, &Num_hogfiles );
361                 //@@Hogfile_initialized = 1;
362
363                 //Int3();       //hogfile ought to be initialized
364         }
365
366         for (i=0; i<Num_hogfiles; i++ ) {
367                 if ( !stricmp( HogFiles[i].name, name ))        {
368                         fp = cfile_get_filehandle( HogFilename, "rb" );
369                         if ( fp == NULL ) return NULL;
370                         fseek( fp,  HogFiles[i].offset, SEEK_SET );
371                         *length = HogFiles[i].length;
372                         return fp;
373                 }
374         }
375
376         if (D1Hogfile_initialized)      {
377                 for (i = 0; i < D1Num_hogfiles; i++) {
378                         if (!stricmp(D1HogFiles[i].name, name)) {
379                                 fp = cfile_get_filehandle(D1HogFilename, "rb");
380                                 if (fp == NULL) return NULL;
381                                 fseek(fp,  D1HogFiles[i].offset, SEEK_SET);
382                                 *length = D1HogFiles[i].length;
383                                 return fp;
384                         }
385                 }
386         }
387
388         return NULL;
389 }
390
391 int cfile_use_alternate_hogfile( char * name )
392 {
393         if ( name )     {
394                 #ifdef MACINTOSH
395                 char mac_path[255];
396
397                 macify_dospath(name, mac_path);
398                 strcpy( AltHogFilename, mac_path);
399                 #else
400                 strcpy( AltHogFilename, name );
401                 #endif
402                 cfile_init_hogfile( AltHogFilename, AltHogFiles, &AltNum_hogfiles );
403                 AltHogfile_initialized = 1;
404                 return (AltNum_hogfiles > 0);
405         } else {
406                 AltHogfile_initialized = 0;
407                 return 1;
408         }
409 }
410
411 int cfile_use_descent1_hogfile( char * name )
412 {
413         if (name)       {
414 #ifdef MACINTOSH
415                 char mac_path[255];
416
417                 macify_dospath(name, mac_path);
418                 strcpy(D1HogFilename, mac_path);
419 #else
420                 strcpy(D1HogFilename, name);
421 #endif
422                 cfile_init_hogfile(D1HogFilename, D1HogFiles, &D1Num_hogfiles);
423                 D1Hogfile_initialized = 1;
424                 return (D1Num_hogfiles > 0);
425         } else {
426                 D1Hogfile_initialized = 0;
427                 return 1;
428         }
429 }
430
431
432 // cfeof() Tests for end-of-file on a stream
433 //
434 // returns a nonzero value after the first read operation that attempts to read
435 // past the end of the file. It returns 0 if the current position is not end of file.
436 // There is no error return.
437
438 int cfeof(CFILE *cfile)
439 {
440         Assert(cfile != NULL);
441
442         Assert(cfile->file != NULL);
443
444     return (cfile->raw_position >= cfile->size);
445 }
446
447
448 int cferror(CFILE *cfile)
449 {
450         return ferror(cfile->file);
451 }
452
453
454 int cfexist( char * filename )
455 {
456         int length;
457         FILE *fp;
458
459
460         if (filename[0] != '\x01')
461                 fp = cfile_get_filehandle( filename, "rb" );            // Check for non-hog file first...
462         else {
463                 fp = NULL;              //don't look in dir, only in hogfile
464                 filename++;
465         }
466
467         if ( fp )       {
468                 fclose(fp);
469                 return 1;
470         }
471
472         fp = cfile_find_libfile(filename, &length );
473         if ( fp )       {
474                 fclose(fp);
475                 return 2;               // file found in hog
476         }
477
478         return 0;               // Couldn't find it.
479 }
480
481
482 // Deletes a file.
483 int cfile_delete(char *filename)
484 {
485 #ifndef _WIN32_WCE
486         return remove(filename);
487 #else
488         return !DeleteFile(filename);
489 #endif
490 }
491
492
493 // Rename a file.
494 int cfile_rename(char *oldname, char *newname)
495 {
496 #ifndef _WIN32_WCE
497         return rename(oldname, newname);
498 #else
499         return !MoveFile(oldname, newname);
500 #endif
501 }
502
503
504 // Make a directory.
505 int cfile_mkdir(char *pathname)
506 {
507 #ifdef _WIN32
508 # ifdef _WIN32_WCE
509         return !CreateDirectory(pathname, NULL);
510 # else
511         return _mkdir(pathname);
512 # endif
513 #else
514         return mkdir(pathname, 0755);
515 #endif
516 }
517
518
519 CFILE * cfopen(char * filename, char * mode )
520 {
521         int length;
522         FILE * fp;
523         CFILE *cfile;
524
525         if (filename[0] != '\x01') {
526                 #ifdef MACINTOSH
527                 char mac_path[255];
528
529                 macify_dospath(filename, mac_path);
530                 fp = cfile_get_filehandle( mac_path, mode);
531                 #else
532                 fp = cfile_get_filehandle( filename, mode );            // Check for non-hog file first...
533                 #endif
534         } else {
535                 fp = NULL;              //don't look in dir, only in hogfile
536                 filename++;
537         }
538
539         if ( !fp ) {
540                 fp = cfile_find_libfile(filename, &length );
541                 if ( !fp )
542                         return NULL;            // No file found
543                 if (stricmp(mode, "rb"))
544                         Error("mode must be rb for files in hog.\n");
545                 cfile = d_malloc ( sizeof(CFILE) );
546                 if ( cfile == NULL ) {
547                         fclose(fp);
548                         return NULL;
549                 }
550                 cfile->file = fp;
551                 cfile->size = length;
552                 cfile->lib_offset = ftell( fp );
553                 cfile->raw_position = 0;
554                 return cfile;
555         } else {
556                 cfile = d_malloc ( sizeof(CFILE) );
557                 if ( cfile == NULL ) {
558                         fclose(fp);
559                         return NULL;
560                 }
561                 cfile->file = fp;
562                 cfile->size = ffilelength(fp);
563                 cfile->lib_offset = 0;
564                 cfile->raw_position = 0;
565                 return cfile;
566         }
567 }
568
569 int cfilelength( CFILE *fp )
570 {
571         return fp->size;
572 }
573
574
575 // cfwrite() writes to the file
576 //
577 // returns:   number of full elements actually written
578 //
579 //
580 int cfwrite(void *buf, int elsize, int nelem, CFILE *cfile)
581 {
582         int items_written;
583
584         Assert(cfile != NULL);
585         Assert(buf != NULL);
586         Assert(elsize > 0);
587
588         Assert(cfile->file != NULL);
589         Assert(cfile->lib_offset == 0);
590
591         items_written = fwrite(buf, elsize, nelem, cfile->file);
592         cfile->raw_position = ftell(cfile->file);
593
594         return items_written;
595 }
596
597
598 // cfputc() writes a character to a file
599 //
600 // returns:   success ==> returns character written
601 //            error   ==> EOF
602 //
603 int cfputc(int c, CFILE *cfile)
604 {
605         int char_written;
606
607         Assert(cfile != NULL);
608
609         Assert(cfile->file != NULL);
610         Assert(cfile->lib_offset == 0);
611
612         char_written = fputc(c, cfile->file);
613         cfile->raw_position = ftell(cfile->file);
614
615         return char_written;
616 }
617
618
619 int cfgetc( CFILE * fp )
620 {
621         int c;
622
623         if (fp->raw_position >= fp->size ) return EOF;
624
625         c = getc( fp->file );
626         if (c!=EOF)
627                 fp->raw_position = ftell(fp->file)-fp->lib_offset;
628
629         return c;
630 }
631
632
633 // cfputs() writes a string to a file
634 //
635 // returns:   success ==> non-negative value
636 //            error   ==> EOF
637 //
638 int cfputs(char *str, CFILE *cfile)
639 {
640         int ret;
641
642         Assert(cfile != NULL);
643         Assert(str != NULL);
644
645         Assert(cfile->file != NULL);
646
647         ret = fputs(str, cfile->file);
648         cfile->raw_position = ftell(cfile->file);
649
650         return ret;
651 }
652
653
654 char * cfgets( char * buf, size_t n, CFILE * fp )
655 {
656         char * t = buf;
657         int i;
658         int c;
659
660 #if 0 // don't use the standard fgets, because it will only handle the native line-ending style
661         if (fp->lib_offset == 0) // This is not an archived file
662         {
663                 t = fgets(buf, n, fp->file);
664                 fp->raw_position = ftell(fp->file);
665                 return t;
666         }
667 #endif
668
669         for (i=0; i<n-1; i++ ) {
670                 do {
671                         if (fp->raw_position >= fp->size ) {
672                                 *buf = 0;
673                                 return NULL;
674                         }
675                         c = cfgetc(fp);
676                         if (c == 0 || c == 10)        // Unix line ending
677                                 break;
678                         if (c == 13) {      // Mac or DOS line ending
679                                 int c1;
680
681                                 c1 = cfgetc(fp);
682                                 cfseek(fp, -1, SEEK_CUR);
683                                 if ( c1 == 10 ) // DOS line ending
684                                         continue;
685                                 else            // Mac line ending
686                                         break;
687                         }
688                 } while ( c == 13 );
689                 if ( c == 13 )  // because cr-lf is a bad thing on the mac
690                         c = '\n';   // and anyway -- 0xod is CR on mac, not 0x0a
691                 *buf++ = c;
692                 if ( c=='\n' ) break;
693         }
694         *buf++ = 0;
695         return  t;
696 }
697
698 size_t cfread( void * buf, size_t elsize, size_t nelem, CFILE * fp ) 
699 {
700         unsigned int i, size;
701
702         size = elsize * nelem;
703         if ( size < 1 ) return 0;
704
705         i = fread ( buf, 1, size, fp->file );
706         fp->raw_position += i;
707         return i/elsize;
708 }
709
710
711 int cftell( CFILE *fp ) 
712 {
713         return fp->raw_position;
714 }
715
716 int cfseek( CFILE *fp, long int offset, int where )
717 {
718         int c, goal_position;
719
720         switch( where ) {
721         case SEEK_SET:
722                 goal_position = offset;
723                 break;
724         case SEEK_CUR:
725                 goal_position = fp->raw_position+offset;
726                 break;
727         case SEEK_END:
728                 goal_position = fp->size+offset;
729                 break;
730         default:
731                 return 1;
732         }       
733         c = fseek( fp->file, fp->lib_offset + goal_position, SEEK_SET );
734         fp->raw_position = ftell(fp->file)-fp->lib_offset;
735         return c;
736 }
737
738 int cfclose(CFILE *fp)
739 {
740         int result;
741
742         result = fclose(fp->file);
743         d_free(fp);
744
745         return result;
746 }
747
748 // routines to read basic data types from CFILE's.  Put here to
749 // simplify mac/pc reading from cfiles.
750
751 int cfile_read_int(CFILE *file)
752 {
753         int32_t i;
754
755         if (cfread( &i, sizeof(i), 1, file) != 1)
756                 Error( "Error reading int in cfile_read_int()" );
757
758         i = INTEL_INT(i);
759         return i;
760 }
761
762 short cfile_read_short(CFILE *file)
763 {
764         int16_t s;
765
766         if (cfread( &s, sizeof(s), 1, file) != 1)
767                 Error( "Error reading short in cfile_read_short()" );
768
769         s = INTEL_SHORT(s);
770         return s;
771 }
772
773 sbyte cfile_read_byte(CFILE *file)
774 {
775         sbyte b;
776
777         if (cfread( &b, sizeof(b), 1, file) != 1)
778                 Error( "Error reading byte in cfile_read_byte()" );
779
780         return b;
781 }
782
783 fix cfile_read_fix(CFILE *file)
784 {
785         fix f;
786
787         if (cfread( &f, sizeof(f), 1, file) != 1)
788                 Error( "Error reading fix in cfile_read_fix()" );
789
790         f = (fix)INTEL_INT((int)f);
791         return f;
792 }
793
794 fixang cfile_read_fixang(CFILE *file)
795 {
796         fixang f;
797
798         if (cfread(&f, 2, 1, file) != 1)
799                 Error("Error reading fixang in cfile_read_fixang()");
800
801         f = (fixang) INTEL_SHORT((int) f);
802         return f;
803 }
804
805 void cfile_read_vector(vms_vector *v, CFILE *file)
806 {
807         v->x = cfile_read_fix(file);
808         v->y = cfile_read_fix(file);
809         v->z = cfile_read_fix(file);
810 }
811
812 void cfile_read_angvec(vms_angvec *v, CFILE *file)
813 {
814         v->p = cfile_read_fixang(file);
815         v->b = cfile_read_fixang(file);
816         v->h = cfile_read_fixang(file);
817 }
818
819 void cfile_read_matrix(vms_matrix *m,CFILE *file)
820 {
821         cfile_read_vector(&m->rvec,file);
822         cfile_read_vector(&m->uvec,file);
823         cfile_read_vector(&m->fvec,file);
824 }
825
826
827 void cfile_read_string(char *buf, int n, CFILE *file)
828 {
829         char c;
830
831         do {
832                 c = (char)cfile_read_byte(file);
833                 if (n > 0)
834                 {
835                         *buf++ = c;
836                         n--;
837                 }
838         } while (c != 0);
839 }
840
841
842 // equivalent write functions of above read functions follow
843
844 int cfile_write_int(int i, CFILE *file)
845 {
846         i = INTEL_INT(i);
847         return cfwrite(&i, sizeof(i), 1, file);
848 }
849
850
851 int cfile_write_short(short s, CFILE *file)
852 {
853         s = INTEL_SHORT(s);
854         return cfwrite(&s, sizeof(s), 1, file);
855 }
856
857
858 int cfile_write_byte(sbyte b, CFILE *file)
859 {
860         return cfwrite(&b, sizeof(b), 1, file);
861 }
862
863
864 int cfile_write_string(char *buf, CFILE *file)
865 {
866         int len;
867
868         if ((!buf) || (buf && !buf[0]))
869                 return cfile_write_byte(0, file);
870
871         len = strlen(buf);
872         if (!cfwrite(buf, len, 1, file))
873                 return 0;
874
875         return cfile_write_byte(0, file);   // write out NULL termination
876 }