]> icculus.org git repositories - btb/d2x.git/blob - cfile/cfile.c
swap min and max size to correct places
[btb/d2x.git] / cfile / cfile.c
1 /* $Id: cfile.c,v 1.26 2004-08-17 19:36:50 schaffner 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
129 #include "pstypes.h"
130 #include "u_mem.h"
131 #include "strutil.h"
132 #include "d_io.h"
133 #include "error.h"
134 #include "cfile.h"
135 #include "byteswap.h"
136
137 struct CFILE {
138         FILE    *file;
139         int     size;
140         int     lib_offset;
141         int     raw_position;
142 };
143
144 typedef struct hogfile {
145         char    name[13];
146         int     offset;
147         int     length;
148 } hogfile;
149
150 #define MAX_HOGFILES 300
151
152 hogfile HogFiles[MAX_HOGFILES];
153 char Hogfile_initialized = 0;
154 int Num_hogfiles = 0;
155 char HogFilename[64];
156
157 hogfile D1HogFiles[MAX_HOGFILES];
158 char D1Hogfile_initialized = 0;
159 int D1Num_hogfiles = 0;
160 char D1HogFilename[64];
161
162 hogfile AltHogFiles[MAX_HOGFILES];
163 char AltHogfile_initialized = 0;
164 int AltNum_hogfiles = 0;
165 char AltHogFilename[64];
166
167 char AltHogDir[64];
168 char AltHogdir_initialized = 0;
169
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 :
174
175 #ifdef MACINTOSH
176 void macify_dospath(char *dos_path, char *mac_path)
177 {
178         char *p;
179
180         if (!strncmp(dos_path, ".\\", 2)) {
181                 strcpy(mac_path, ":");
182                 strcat(mac_path, &(dos_path[2]) );
183         } else
184                 strcpy(mac_path, dos_path);
185
186         while ( (p = strchr(mac_path, '\\')) != NULL)
187                 *p = ':';
188
189 }
190 #endif
191
192 void cfile_use_alternate_hogdir( char * path )
193 {
194         if ( path )     {
195                 strcpy( AltHogDir, path );
196                 AltHogdir_initialized = 1;
197         } else {
198                 AltHogdir_initialized = 0;
199         }
200 }
201
202 //in case no one installs one
203 int default_error_counter=0;
204
205 //ptr to counter of how many critical errors
206 int *critical_error_counter_ptr=&default_error_counter;
207
208 //tell cfile about your critical error counter
209 void cfile_set_critical_error_counter_ptr(int *ptr)
210 {
211         critical_error_counter_ptr = ptr;
212
213 }
214
215
216 FILE * cfile_get_filehandle( char * filename, char * mode )
217 {
218         FILE * fp;
219         char temp[128];
220
221         *critical_error_counter_ptr = 0;
222         fp = fopen( filename, mode );
223         if ( fp && *critical_error_counter_ptr )        {
224                 fclose(fp);
225                 fp = NULL;
226         }
227         if ( (fp==NULL) && (AltHogdir_initialized) )    {
228                 strcpy( temp, AltHogDir );
229                 strcat( temp, "/");
230                 strcat( temp, filename );
231                 *critical_error_counter_ptr = 0;
232                 fp = fopen( temp, mode );
233                 if ( fp && *critical_error_counter_ptr )        {
234                         fclose(fp);
235                         fp = NULL;
236                 }
237         }
238         return fp;
239 }
240
241 //returns 1 if file loaded with no errors
242 int cfile_init_hogfile(char *fname, hogfile * hog_files, int * nfiles )
243 {
244         char id[4];
245         FILE * fp;
246         int i, len;
247
248         *nfiles = 0;
249
250         fp = cfile_get_filehandle( fname, "rb" );
251         if ( fp == NULL ) return 0;
252
253         fread( id, 3, 1, fp );
254         if ( strncmp( id, "DHF", 3 ) )  {
255                 fclose(fp);
256                 return 0;
257         }
258
259         while( 1 )
260         {
261                 if ( *nfiles >= MAX_HOGFILES ) {
262                         fclose(fp);
263                         Error( "HOGFILE is limited to %d files.\n",  MAX_HOGFILES );
264                 }
265                 i = fread( hog_files[*nfiles].name, 13, 1, fp );
266                 if ( i != 1 )   {               //eof here is ok
267                         fclose(fp);
268                         return 1;
269                 }
270                 i = fread( &len, 4, 1, fp );
271                 if ( i != 1 )   {
272                         fclose(fp);
273                         return 0;
274                 }
275                 hog_files[*nfiles].length = INTEL_INT(len);
276                 hog_files[*nfiles].offset = ftell( fp );
277                 *nfiles = (*nfiles) + 1;
278                 // Skip over
279                 i = fseek( fp, INTEL_INT(len), SEEK_CUR );
280         }
281 }
282
283 //Specify the name of the hogfile.  Returns 1 if hogfile found & had files
284 int cfile_init(char *hogname)
285 {
286         #ifdef MACINTOSH
287         char mac_path[255];
288
289         macify_dospath(hogname, mac_path);
290         #endif
291
292         Assert(Hogfile_initialized == 0);
293
294         #ifndef MACINTOSH
295         if (cfile_init_hogfile(hogname, HogFiles, &Num_hogfiles )) {
296                 strcpy( HogFilename, hogname );
297         #else
298         if (cfile_init_hogfile(mac_path, HogFiles, &Num_hogfiles )) {
299                 strcpy( HogFilename, mac_path );
300         #endif
301                 Hogfile_initialized = 1;
302                 return 1;
303         }
304         else
305                 return 0;       //not loaded!
306 }
307
308
309 int cfile_size(char *hogname)
310 {
311         CFILE *fp;
312         int size;
313
314         fp = cfopen(hogname, "rb");
315         if (fp == NULL)
316                 return -1;
317         size = ffilelength(fp->file);
318         cfclose(fp);
319         return size;
320 }
321
322 /*
323  * return handle for file called "name", embedded in one of the hogfiles
324  */
325 FILE * cfile_find_libfile(char * name, int * length)
326 {
327         FILE * fp;
328         int i;
329
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;
337                                 return fp;
338                         }
339                 }
340         }
341
342         if ( !Hogfile_initialized )     {
343                 //@@cfile_init_hogfile( "DESCENT2.HOG", HogFiles, &Num_hogfiles );
344                 //@@Hogfile_initialized = 1;
345
346                 //Int3();       //hogfile ought to be initialized
347         }
348
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;
355                         return fp;
356                 }
357         }
358
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;
366                                 return fp;
367                         }
368                 }
369         }
370
371         return NULL;
372 }
373
374 int cfile_use_alternate_hogfile( char * name )
375 {
376         if ( name )     {
377                 #ifdef MACINTOSH
378                 char mac_path[255];
379
380                 macify_dospath(name, mac_path);
381                 strcpy( AltHogFilename, mac_path);
382                 #else
383                 strcpy( AltHogFilename, name );
384                 #endif
385                 cfile_init_hogfile( AltHogFilename, AltHogFiles, &AltNum_hogfiles );
386                 AltHogfile_initialized = 1;
387                 return (AltNum_hogfiles > 0);
388         } else {
389                 AltHogfile_initialized = 0;
390                 return 1;
391         }
392 }
393
394 int cfile_use_descent1_hogfile( char * name )
395 {
396         if (name)       {
397 #ifdef MACINTOSH
398                 char mac_path[255];
399
400                 macify_dospath(name, mac_path);
401                 strcpy(D1HogFilename, mac_path);
402 #else
403                 strcpy(D1HogFilename, name);
404 #endif
405                 cfile_init_hogfile(D1HogFilename, D1HogFiles, &D1Num_hogfiles);
406                 D1Hogfile_initialized = 1;
407                 return (D1Num_hogfiles > 0);
408         } else {
409                 D1Hogfile_initialized = 0;
410                 return 1;
411         }
412 }
413
414
415 // cfeof() Tests for end-of-file on a stream
416 //
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.
420
421 int cfeof(CFILE *cfile)
422 {
423         Assert(cfile != NULL);
424
425         Assert(cfile->file != NULL);
426
427     return (cfile->raw_position >= cfile->size);
428 }
429
430
431 int cferror(CFILE *cfile)
432 {
433         return ferror(cfile->file);
434 }
435
436
437 int cfexist( char * filename )
438 {
439         int length;
440         FILE *fp;
441
442
443         if (filename[0] != '\x01')
444                 fp = cfile_get_filehandle( filename, "rb" );            // Check for non-hog file first...
445         else {
446                 fp = NULL;              //don't look in dir, only in hogfile
447                 filename++;
448         }
449
450         if ( fp )       {
451                 fclose(fp);
452                 return 1;
453         }
454
455         fp = cfile_find_libfile(filename, &length );
456         if ( fp )       {
457                 fclose(fp);
458                 return 2;               // file found in hog
459         }
460
461         return 0;               // Couldn't find it.
462 }
463
464
465 // Deletes a file.
466 int cfile_delete(char *filename)
467 {
468 #ifndef _WIN32_WCE
469         return remove(filename);
470 #else
471         return !DeleteFile(filename);
472 #endif
473 }
474
475
476 // Rename a file.
477 int cfile_rename(char *oldname, char *newname)
478 {
479 #ifndef _WIN32_WCE
480         return rename(oldname, newname);
481 #else
482         return !MoveFile(oldname, newname);
483 #endif
484 }
485
486
487 // Make a directory.
488 int cfile_mkdir(char *pathname)
489 {
490 #ifdef _WIN32
491 # ifdef _WIN32_WCE
492         return !CreateDirectory(pathname, NULL);
493 # else
494         return _mkdir(pathname);
495 # endif
496 #elif defined(macintosh)
497     char        mac_path[256];
498     Str255      pascal_path;
499     long        dirID;  // Insists on returning this
500
501     macify_posix_path(pathname, mac_path);
502     CopyCStringToPascal(mac_path, pascal_path);
503     return DirCreate(0, 0, pascal_path, &dirID);
504 #else
505         return mkdir(pathname, 0755);
506 #endif
507 }
508
509
510 CFILE * cfopen(char * filename, char * mode )
511 {
512         int length;
513         FILE * fp;
514         CFILE *cfile;
515
516         if (filename[0] != '\x01') {
517                 #ifdef MACINTOSH
518                 char mac_path[255];
519
520                 macify_dospath(filename, mac_path);
521                 fp = cfile_get_filehandle( mac_path, mode);
522                 #else
523                 fp = cfile_get_filehandle( filename, mode );            // Check for non-hog file first...
524                 #endif
525         } else {
526                 fp = NULL;              //don't look in dir, only in hogfile
527                 filename++;
528         }
529
530         if ( !fp ) {
531                 fp = cfile_find_libfile(filename, &length );
532                 if ( !fp )
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 ) {
538                         fclose(fp);
539                         return NULL;
540                 }
541                 cfile->file = fp;
542                 cfile->size = length;
543                 cfile->lib_offset = ftell( fp );
544                 cfile->raw_position = 0;
545                 return cfile;
546         } else {
547                 cfile = d_malloc ( sizeof(CFILE) );
548                 if ( cfile == NULL ) {
549                         fclose(fp);
550                         return NULL;
551                 }
552                 cfile->file = fp;
553                 cfile->size = ffilelength(fp);
554                 cfile->lib_offset = 0;
555                 cfile->raw_position = 0;
556                 return cfile;
557         }
558 }
559
560 int cfilelength( CFILE *fp )
561 {
562         return fp->size;
563 }
564
565
566 // cfwrite() writes to the file
567 //
568 // returns:   number of full elements actually written
569 //
570 //
571 int cfwrite(void *buf, int elsize, int nelem, CFILE *cfile)
572 {
573         int items_written;
574
575         Assert(cfile != NULL);
576         Assert(buf != NULL);
577         Assert(elsize > 0);
578
579         Assert(cfile->file != NULL);
580         Assert(cfile->lib_offset == 0);
581
582         items_written = fwrite(buf, elsize, nelem, cfile->file);
583         cfile->raw_position = ftell(cfile->file);
584
585         return items_written;
586 }
587
588
589 // cfputc() writes a character to a file
590 //
591 // returns:   success ==> returns character written
592 //            error   ==> EOF
593 //
594 int cfputc(int c, CFILE *cfile)
595 {
596         int char_written;
597
598         Assert(cfile != NULL);
599
600         Assert(cfile->file != NULL);
601         Assert(cfile->lib_offset == 0);
602
603         char_written = fputc(c, cfile->file);
604         cfile->raw_position = ftell(cfile->file);
605
606         return char_written;
607 }
608
609
610 int cfgetc( CFILE * fp )
611 {
612         int c;
613
614         if (fp->raw_position >= fp->size ) return EOF;
615
616         c = getc( fp->file );
617         if (c!=EOF)
618                 fp->raw_position = ftell(fp->file)-fp->lib_offset;
619
620         return c;
621 }
622
623
624 // cfputs() writes a string to a file
625 //
626 // returns:   success ==> non-negative value
627 //            error   ==> EOF
628 //
629 int cfputs(char *str, CFILE *cfile)
630 {
631         int ret;
632
633         Assert(cfile != NULL);
634         Assert(str != NULL);
635
636         Assert(cfile->file != NULL);
637
638         ret = fputs(str, cfile->file);
639         cfile->raw_position = ftell(cfile->file);
640
641         return ret;
642 }
643
644
645 char * cfgets( char * buf, size_t n, CFILE * fp )
646 {
647         char * t = buf;
648         int i;
649         int c;
650
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
653         {
654                 t = fgets(buf, n, fp->file);
655                 fp->raw_position = ftell(fp->file);
656                 return t;
657         }
658 #endif
659
660         for (i=0; i<n-1; i++ ) {
661                 do {
662                         if (fp->raw_position >= fp->size ) {
663                                 *buf = 0;
664                                 return NULL;
665                         }
666                         c = cfgetc(fp);
667                         if (c == 0 || c == 10)        // Unix line ending
668                                 break;
669                         if (c == 13) {      // Mac or DOS line ending
670                                 int c1;
671
672                                 c1 = cfgetc(fp);
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
676                                         continue;
677                                 else            // Mac line ending
678                                         break;
679                         }
680                 } while ( c == 13 );
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
683                 *buf++ = c;
684                 if ( c=='\n' ) break;
685         }
686         *buf++ = 0;
687         return  t;
688 }
689
690 size_t cfread( void * buf, size_t elsize, size_t nelem, CFILE * fp ) 
691 {
692         unsigned int i, size;
693
694         size = elsize * nelem;
695         if ( size < 1 ) return 0;
696
697         i = fread ( buf, 1, size, fp->file );
698         fp->raw_position += i;
699         return i/elsize;
700 }
701
702
703 int cftell( CFILE *fp ) 
704 {
705         return fp->raw_position;
706 }
707
708 int cfseek( CFILE *fp, long int offset, int where )
709 {
710         int c, goal_position;
711
712         switch( where ) {
713         case SEEK_SET:
714                 goal_position = offset;
715                 break;
716         case SEEK_CUR:
717                 goal_position = fp->raw_position+offset;
718                 break;
719         case SEEK_END:
720                 goal_position = fp->size+offset;
721                 break;
722         default:
723                 return 1;
724         }       
725         c = fseek( fp->file, fp->lib_offset + goal_position, SEEK_SET );
726         fp->raw_position = ftell(fp->file)-fp->lib_offset;
727         return c;
728 }
729
730 int cfclose(CFILE *fp)
731 {
732         int result;
733
734         result = fclose(fp->file);
735         d_free(fp);
736
737         return result;
738 }
739
740 // routines to read basic data types from CFILE's.  Put here to
741 // simplify mac/pc reading from cfiles.
742
743 int cfile_read_int(CFILE *file)
744 {
745         int32_t i;
746
747         if (cfread( &i, sizeof(i), 1, file) != 1)
748                 Error( "Error reading int in cfile_read_int()" );
749
750         i = INTEL_INT(i);
751         return i;
752 }
753
754 short cfile_read_short(CFILE *file)
755 {
756         int16_t s;
757
758         if (cfread( &s, sizeof(s), 1, file) != 1)
759                 Error( "Error reading short in cfile_read_short()" );
760
761         s = INTEL_SHORT(s);
762         return s;
763 }
764
765 sbyte cfile_read_byte(CFILE *file)
766 {
767         sbyte b;
768
769         if (cfread( &b, sizeof(b), 1, file) != 1)
770                 Error( "Error reading byte in cfile_read_byte()" );
771
772         return b;
773 }
774
775 fix cfile_read_fix(CFILE *file)
776 {
777         fix f;
778
779         if (cfread( &f, sizeof(f), 1, file) != 1)
780                 Error( "Error reading fix in cfile_read_fix()" );
781
782         f = (fix)INTEL_INT((int)f);
783         return f;
784 }
785
786 fixang cfile_read_fixang(CFILE *file)
787 {
788         fixang f;
789
790         if (cfread(&f, 2, 1, file) != 1)
791                 Error("Error reading fixang in cfile_read_fixang()");
792
793         f = (fixang) INTEL_SHORT((int) f);
794         return f;
795 }
796
797 void cfile_read_vector(vms_vector *v, CFILE *file)
798 {
799         v->x = cfile_read_fix(file);
800         v->y = cfile_read_fix(file);
801         v->z = cfile_read_fix(file);
802 }
803
804 void cfile_read_angvec(vms_angvec *v, CFILE *file)
805 {
806         v->p = cfile_read_fixang(file);
807         v->b = cfile_read_fixang(file);
808         v->h = cfile_read_fixang(file);
809 }
810
811 void cfile_read_matrix(vms_matrix *m,CFILE *file)
812 {
813         cfile_read_vector(&m->rvec,file);
814         cfile_read_vector(&m->uvec,file);
815         cfile_read_vector(&m->fvec,file);
816 }
817
818
819 void cfile_read_string(char *buf, int n, CFILE *file)
820 {
821         char c;
822
823         do {
824                 c = (char)cfile_read_byte(file);
825                 if (n > 0)
826                 {
827                         *buf++ = c;
828                         n--;
829                 }
830         } while (c != 0);
831 }
832
833
834 // equivalent write functions of above read functions follow
835
836 int cfile_write_int(int i, CFILE *file)
837 {
838         i = INTEL_INT(i);
839         return cfwrite(&i, sizeof(i), 1, file);
840 }
841
842
843 int cfile_write_short(short s, CFILE *file)
844 {
845         s = INTEL_SHORT(s);
846         return cfwrite(&s, sizeof(s), 1, file);
847 }
848
849
850 int cfile_write_byte(sbyte b, CFILE *file)
851 {
852         return cfwrite(&b, sizeof(b), 1, file);
853 }
854
855
856 int cfile_write_string(char *buf, CFILE *file)
857 {
858         int len;
859
860         if ((!buf) || (buf && !buf[0]))
861                 return cfile_write_byte(0, file);
862
863         len = strlen(buf);
864         if (!cfwrite(buf, len, 1, file))
865                 return 0;
866
867         return cfile_write_byte(0, file);   // write out NULL termination
868 }