CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

BFIOFILE.CPP (40482B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header: /CounterStrike/BFIOFILE.CPP 1     3/03/97 10:24a Joe_bostic $ */
     17 /***********************************************************************************************
     18  ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Westwood Library                                             *
     22  *                                                                                             *
     23  *                    File Name : RAMFILE.CPP                                                  *
     24  *                                                                                             *
     25  *                   Programmer : David R. Dettmer                                             *
     26  *                                                                                             *
     27  *                   Start Date : November 10, 1995                                            *
     28  *                                                                                             *
     29  *                  Last Update : November 10, 1995  [DRD]                                     *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object.     *
     34  *   BufferIOFileClass::BufferIOFileClass -- default constructor for a file object.            *
     35  *   BufferIOFileClass::Cache -- Load part or all of a file data into RAM.                     *
     36  *   BufferIOFileClass::Close -- Perform a closure of the file.                                *
     37  *   BufferIOFileClass::Commit -- Writes the cache to the file if it has changed.              *
     38  *   BufferIOFileClass::Free -- Frees the allocated buffer.                                    *
     39  *   BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk.        *
     40  *   BufferIOFileClass::Is_Open -- Determines if the file is open.                             *
     41  *   BufferIOFileClass::Open -- Assigns name and opens file in one operation.                  *
     42  *   BufferIOFileClass::Open -- Opens the file object with the rights specified.               *
     43  *   BufferIOFileClass::Read -- Reads data from the file cache.                                *
     44  *   BufferIOFileClass::Seek -- Moves the current file pointer in the file.                    *
     45  *   BufferIOFileClass::Set_Name -- Checks for name changed for a cached file.                 *
     46  *   BufferIOFileClass::Size -- Determines size of file (in bytes).                            *
     47  *   BufferIOFileClass::Write -- Writes data to the file cache.                                *
     48  *   BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object.                  *
     49  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     50 
     51 
     52 #include	"bfiofile.h"
     53 #include	<string.h>
     54 
     55 
     56 /***********************************************************************************************
     57  * BufferIOFileClass::BufferIOFileClass -- Filename based constructor for a file object.       *
     58  *                                                                                             *
     59  *    This constructor is called when a file object is created with a supplied filename, but   *
     60  *    not opened at the same time. In this case, an assumption is made that the supplied       *
     61  *    filename is a constant string. A duplicate of the filename string is not created since   *
     62  *    it would be wasteful in that case.                                                       *
     63  *                                                                                             *
     64  * INPUT:   filename -- The filename to assign to this file object.                            *
     65  *                                                                                             *
     66  * OUTPUT:  none                                                                               *
     67  *                                                                                             *
     68  * WARNINGS:   none                                                                            *
     69  *                                                                                             *
     70  * HISTORY:                                                                                    *
     71  *   11/10/1995 DRD : Created.                                                                 *
     72  *=============================================================================================*/
     73 BufferIOFileClass::BufferIOFileClass(char const * filename) :
     74 	IsAllocated(false),
     75 	IsOpen(false),
     76 	IsDiskOpen(false),
     77 	IsCached(false),
     78 	IsChanged(false),
     79 	UseBuffer(false),
     80 	BufferRights(0),
     81 	Buffer(0),
     82 	BufferSize(0),
     83 	BufferPos(0),
     84 	BufferFilePos(0),
     85 	BufferChangeBeg(-1),
     86 	BufferChangeEnd(-1),
     87 	FileSize(0),
     88 	FilePos(0),
     89 	TrueFileStart(0)
     90 {
     91 	BufferIOFileClass::Set_Name(filename);
     92 }
     93 
     94 
     95 /***********************************************************************************************
     96  * BufferIOFileClass::BufferIOFileClass -- default constructor for a file object.              *
     97  *                                                                                             *
     98  *    This is the default constructor for a file object.                                       *
     99  *                                                                                             *
    100  * INPUT:  none                                                                                *
    101  *                                                                                             *
    102  * OUTPUT:  none                                                                               *
    103  *                                                                                             *
    104  * WARNINGS:   none                                                                            *
    105  *                                                                                             *
    106  * HISTORY:                                                                                    *
    107  *   11/10/1995 DRD : Created.                                                                 *
    108  *=============================================================================================*/
    109 BufferIOFileClass::BufferIOFileClass(void) :
    110 	IsAllocated(false),
    111 	IsOpen(false),
    112 	IsDiskOpen(false),
    113 	IsCached(false),
    114 	IsChanged(false),
    115 	UseBuffer(false),
    116 	BufferRights(0),
    117 	Buffer(0),
    118 	BufferSize(0),
    119 	BufferPos(0),
    120 	BufferFilePos(0),
    121 	BufferChangeBeg(-1),
    122 	BufferChangeEnd(-1),
    123 	FileSize(0),
    124 	FilePos(0),
    125 	TrueFileStart(0)
    126 {
    127 }
    128 
    129 
    130 /***********************************************************************************************
    131  * BufferIOFileClass::~BufferIOFileClass -- Destructor for the file object.                    *
    132  *                                                                                             *
    133  *    This destructor will free all memory allocated thru using Cache routines.                *
    134  *                                                                                             *
    135  * INPUT:   none                                                                               *
    136  *                                                                                             *
    137  * OUTPUT:  none                                                                               *
    138  *                                                                                             *
    139  * WARNINGS:   none                                                                            *
    140  *                                                                                             *
    141  * HISTORY:                                                                                    *
    142  *   11/10/1995 DRD : Created.                                                                 *
    143  *=============================================================================================*/
    144 BufferIOFileClass::~BufferIOFileClass(void)
    145 {
    146 	Free();
    147 }
    148 
    149 
    150 /***********************************************************************************************
    151  * BufferIOFileClass::Cache -- Load part or all of a file data into RAM.                       *
    152  *                                                                                             *
    153  * INPUT:   none                                                                               *
    154  *                                                                                             *
    155  * OUTPUT:  bool; Was the file load successful?  It could fail if there wasn't enough room     *
    156  *                to allocate the raw data block.                                              *
    157  *                                                                                             *
    158  * WARNINGS:   This routine goes to disk for a potentially very long time.                     *
    159  *                                                                                             *
    160  * HISTORY:                                                                                    *
    161  *   11/10/1995 DRD : Created.                                                                 *
    162  *=============================================================================================*/
    163 bool BufferIOFileClass::Cache( long size, void * ptr )
    164 {
    165 	if (Buffer) {
    166 		//
    167 		// if trying to cache again with size or ptr fail
    168 		//
    169 		if (size || ptr) {
    170 			return( false );
    171 		} else {
    172 			return( true );
    173 		}
    174 	}
    175 
    176 	if ( Is_Available() ) {
    177 		FileSize = Size();
    178 	} else {
    179 		FileSize = 0;
    180 	}
    181 
    182 	if (size) {
    183 		//
    184 		// minimum buffer size for performance
    185 		//
    186 		if (size < MINIMUM_BUFFER_SIZE) {
    187 			size = MINIMUM_BUFFER_SIZE;
    188 
    189 			/*
    190 			**	Specifying a size smaller than the minimum is an error
    191 			**	IF a buffer pointer was also specified. In such a case the
    192 			**	system cannot use the buffer.
    193 			*/
    194 			if (ptr) {
    195 				Error(EINVAL);
    196 			}
    197 		}
    198 
    199 		BufferSize = size;
    200 	} else {
    201 		BufferSize = FileSize;
    202 	}
    203 
    204 	//
    205 	// if size == 0 and a ptr to a buffer is specified then that is invalid.
    206 	// if the BufferSize is 0 then this must be a new file and no size was
    207 	// specified so exit.
    208 	//
    209 	if ( (size == 0 && ptr) || !BufferSize) {
    210 		return( false );
    211 	}
    212 
    213 	if (ptr) {
    214 		Buffer = ptr;
    215 	} else {
    216 		Buffer = new char [BufferSize];
    217 	}
    218 
    219 	if (Buffer) {
    220 		IsAllocated			= true;
    221 		IsDiskOpen			= false;
    222 		BufferPos			= 0;
    223 		BufferFilePos		= 0;
    224 		BufferChangeBeg	= -1;
    225 		BufferChangeEnd	= -1;
    226 		FilePos				= 0;
    227 		TrueFileStart		= 0;
    228 
    229 		//
    230 		// the file was checked for availability then set the FileSize
    231 		//
    232 		if (FileSize) {
    233 			long readsize;
    234 			int opened = false;
    235 			long prevpos = 0;
    236 
    237 
    238 			if (FileSize <= BufferSize) {
    239 				readsize = FileSize;
    240 			} else {
    241 				readsize = BufferSize;
    242 			}
    243 
    244 			if ( Is_Open() ) {
    245 				//
    246 				// get previous file position
    247 				//
    248 				prevpos = Seek(0);
    249 
    250 				//
    251 				// get true file position
    252 				//
    253 				if ( RawFileClass::Is_Open() ) {
    254 					TrueFileStart = RawFileClass::Seek(0);
    255 				} else {
    256 					TrueFileStart = prevpos;
    257 				}
    258 
    259 				if (FileSize <= BufferSize) {
    260 					//
    261 					// if previous position is non-zero seek to the beginning
    262 					//
    263 					if (prevpos) {
    264 						Seek(0, SEEK_SET);
    265 					}
    266 
    267 					//
    268 					// set the buffer position for future reads/writes
    269 					//
    270 					BufferPos = prevpos;
    271 				} else {
    272 					BufferFilePos = prevpos;
    273 				}
    274 
    275 				FilePos = prevpos;
    276 			} else {
    277 				if ( Open() ) {
    278 					TrueFileStart = RawFileClass::Seek(0);
    279 					opened = true;
    280 				}
    281 			}
    282 
    283 			long actual = Read(Buffer, readsize);
    284 
    285 			if (actual != readsize) {
    286 				Error(EIO);
    287 			}
    288 
    289 			if (opened) {
    290 				Close();
    291 			} else {
    292 				//
    293 				// seek to the previous position in the file
    294 				//
    295 				Seek(prevpos, SEEK_SET);
    296 			}
    297 
    298 			IsCached = true;
    299 		}
    300 
    301 		UseBuffer = true;
    302 		return(true);
    303 	}
    304 
    305 	Error(ENOMEM);
    306 
    307 	return(false);
    308 }
    309 
    310 
    311 /***********************************************************************************************
    312  * BufferIOFileClass::Free -- Frees the allocated buffer.                                      *
    313  *                                                                                             *
    314  *    This routine will free the buffer. By using this in conjunction with the                 *
    315  *    Cache() function, one can maintain tight control of memory usage.                        *
    316  *                                                                                             *
    317  * INPUT:   none                                                                               *
    318  *                                                                                             *
    319  * OUTPUT:  none                                                                               *
    320  *                                                                                             *
    321  * WARNINGS:   none                                                                            *
    322  *                                                                                             *
    323  * HISTORY:                                                                                    *
    324  *   11/10/1995 DRD : Created.                                                                 *
    325  *=============================================================================================*/
    326 void BufferIOFileClass::Free(void)
    327 {
    328 	if (Buffer) {
    329 		if (IsAllocated) {
    330 			delete [] Buffer;
    331 			IsAllocated = false;
    332 		}
    333 
    334 		Buffer = 0;
    335 	}
    336 
    337 	BufferSize		= 0;
    338 	IsOpen			= false;
    339 	IsCached			= false;
    340 	IsChanged		= false;
    341 	UseBuffer		= false;
    342 }
    343 
    344 
    345 /***********************************************************************************************
    346  * BufferIOFileClass::Commit -- Writes the cache to the file if it has changed.                *
    347  *                                                                                             *
    348  *                                                                                             *
    349  * INPUT:   none                                                                               *
    350  *                                                                                             *
    351  * OUTPUT:  false, did not need to write the buffer.                                           *
    352  *          true, wrote the buffer.                                                            *
    353  *                                                                                             *
    354  * WARNINGS:   none                                                                            *
    355  *                                                                                             *
    356  * HISTORY:                                                                                    *
    357  *   11/15/1995 DRD : Created.                                                                 *
    358  *=============================================================================================*/
    359 bool BufferIOFileClass::Commit( void )
    360 {
    361 	long size;
    362 
    363 
    364 	if (UseBuffer) {
    365 		if (IsChanged) {
    366 			size = BufferChangeEnd - BufferChangeBeg;
    367 
    368 			if (IsDiskOpen) {
    369 				RawFileClass::Seek( TrueFileStart + BufferFilePos +
    370 										  BufferChangeBeg, SEEK_SET );
    371 				RawFileClass::Write( Buffer, size );
    372 				RawFileClass::Seek( TrueFileStart + FilePos, SEEK_SET );
    373 			} else {
    374 				RawFileClass::Open();
    375 				RawFileClass::Seek( TrueFileStart + BufferFilePos +
    376 										  BufferChangeBeg, SEEK_SET );
    377 				RawFileClass::Write( Buffer, size );
    378 				RawFileClass::Close();
    379 			}
    380 
    381 			IsChanged = false;
    382 			return( true );
    383 		} else {
    384 			return( false );
    385 		}
    386 	} else {
    387 		return( false );
    388 	}
    389 }
    390 
    391 
    392 /***********************************************************************************************
    393  * BufferIOFileClass::Set_Name -- Checks for name changed for a cached file.                   *
    394  *                                                                                             *
    395  *    Checks for a previous filename and that it is cached.  If so, then check the             *
    396  *    new filename against the old. If they are the same then return that filename.            *
    397  *    Otherwise, the file object's name is set with just the raw filename as passed            *
    398  *    to this routine.                                                                         *
    399  *                                                                                             *
    400  * INPUT:   filename -- Pointer to the filename to set as the name of this file object.        *
    401  *                                                                                             *
    402  * OUTPUT:  Returns a pointer to the final and complete filename of this file object. This     *
    403  *          may have a path attached to the file.                                              *
    404  *                                                                                             *
    405  * WARNINGS:   none                                                                            *
    406  *                                                                                             *
    407  * HISTORY:                                                                                    *
    408  *   11/15/1995 DRD : Created.                                                                 *
    409  *=============================================================================================*/
    410 char const * BufferIOFileClass::Set_Name(char const * filename)
    411 {
    412 	if ( File_Name() && UseBuffer) {
    413 		if ( strcmp(filename, File_Name() ) == 0) {
    414 			return( File_Name() );
    415 		} else {
    416 			Commit();
    417 			IsCached = false;
    418 		}
    419 	}
    420 
    421 	RawFileClass::Set_Name(filename);
    422 	return( File_Name() );
    423 }
    424 
    425 
    426 /***********************************************************************************************
    427  * BufferIOFileClass::Is_Available -- Checks for existence of file cached or on disk.          *
    428  *                                                                                             *
    429  *                                                                                             *
    430  * INPUT:   none                                                                               *
    431  *                                                                                             *
    432  * OUTPUT:  bool; Is the file available for opening?                                           *
    433  *                                                                                             *
    434  * WARNINGS:   none                                                                            *
    435  *                                                                                             *
    436  * HISTORY:                                                                                    *
    437  *   11/16/1995 DRD : Created.                                                                 *
    438  *=============================================================================================*/
    439 int BufferIOFileClass::Is_Available(int )
    440 {
    441 	if (UseBuffer) {
    442 		return(true);
    443 	}
    444 
    445 	return( RawFileClass::Is_Available() );
    446 }
    447 
    448 
    449 /***********************************************************************************************
    450  * BufferIOFileClass::Is_Open -- Determines if the file is open.                               *
    451  *                                                                                             *
    452  *    If part or all of the file is cached, then return that it is opened. A closed file       *
    453  *    doesn't have a valid pointer.                                                            *
    454  *                                                                                             *
    455  * INPUT:   none                                                                               *
    456  *                                                                                             *
    457  * OUTPUT:  bool; Is the file open?                                                            *
    458  *                                                                                             *
    459  * WARNINGS:   none                                                                            *
    460  *                                                                                             *
    461  * HISTORY:                                                                                    *
    462  *   11/14/1995 DRD : Created.                                                                 *
    463  *=============================================================================================*/
    464 int BufferIOFileClass::Is_Open(void) const
    465 {
    466 	if (IsOpen && UseBuffer) {
    467 		return( true );
    468 	}
    469 
    470 	return( RawFileClass::Is_Open() );
    471 }
    472 
    473 
    474 /***********************************************************************************************
    475  * BufferIOFileClass::Open -- Assigns name and opens file in one operation.                    *
    476  *                                                                                             *
    477  *    This routine will assign the specified filename to the file object and open it at the    *
    478  *    same time. If the file object was already open, then it will be closed first. If the     *
    479  *    file object was previously assigned a filename, then it will be replaced with the new    *
    480  *    name. Typically, this routine is used when an anonymous file object has been crated and  *
    481  *    now it needs to be assigned a name and opened.                                           *
    482  *                                                                                             *
    483  * INPUT:   filename -- The filename to assign to this file object.                            *
    484  *                                                                                             *
    485  *          rights   -- The open file access rights to use.                                    *
    486  *                                                                                             *
    487  * OUTPUT:  bool; Was the file opened? The return value of this is moot, since the open file   *
    488  *          is designed to never return unless it succeeded.                                   *
    489  *                                                                                             *
    490  * WARNINGS:   none                                                                            *
    491  *                                                                                             *
    492  * HISTORY:                                                                                    *
    493  *   11/14/1995 DRD : Created.                                                                 *
    494  *=============================================================================================*/
    495 int BufferIOFileClass::Open(char const * filename, int rights)
    496 {
    497 	Set_Name(filename);
    498 	return( BufferIOFileClass::Open( rights ) );
    499 }
    500 
    501 
    502 /***********************************************************************************************
    503  * BufferIOFileClass::Open -- Opens the file object with the rights specified.                 *
    504  *                                                                                             *
    505  *    This routine is used to open the specified file object with the access rights indicated. *
    506  *    This only works if the file has already been assigned a filename. It is guaranteed, by   *
    507  *    the error handler, that this routine will always return with success.                    *
    508  *                                                                                             *
    509  * INPUT:   rights   -- The file access rights to use when opening this file. This is a        *
    510  *                      combination of READ and/or WRITE bit flags.                            *
    511  *                                                                                             *
    512  * OUTPUT:  bool; Was the file opened successfully? This will always return true by reason of  *
    513  *          the error handler.                                                                 *
    514  *                                                                                             *
    515  * WARNINGS:   none                                                                            *
    516  *                                                                                             *
    517  * HISTORY:                                                                                    *
    518  *   11/14/1995 DRD : Created.                                                                 *
    519  *=============================================================================================*/
    520 int BufferIOFileClass::Open(int rights)
    521 {
    522 	BufferIOFileClass::Close();
    523 
    524 	if (UseBuffer) {
    525 
    526 		BufferRights = rights;		// save rights requested for checks later
    527 
    528 		if (rights != READ ||
    529 			 (rights == READ && FileSize > BufferSize) ) {
    530 
    531 			if (rights == WRITE) {
    532 				RawFileClass::Open( rights );
    533 				RawFileClass::Close();
    534 				rights = READ | WRITE;
    535 				TrueFileStart = 0;		// now writing to single file
    536 			}
    537 
    538 			if (TrueFileStart) {
    539 				UseBuffer = false;
    540 				Open( rights );
    541 				UseBuffer = true;
    542 			} else {
    543 				RawFileClass::Open( rights );
    544 			}
    545 
    546 			IsDiskOpen = true;
    547 
    548 			if (BufferRights == WRITE) {
    549 				FileSize = 0;
    550 			}
    551 
    552 		} else {
    553 			IsDiskOpen = false;
    554 		}
    555 
    556 		BufferPos			= 0;
    557 		BufferFilePos		= 0;
    558 		BufferChangeBeg	= -1;
    559 		BufferChangeEnd	= -1;
    560 		FilePos				= 0;
    561 		IsOpen				= true;
    562 	} else {
    563 		RawFileClass::Open( rights );
    564 	}
    565 
    566 	return( true );
    567 }
    568 
    569 
    570 /***********************************************************************************************
    571  * BufferIOFileClass::Write -- Writes data to the file cache.                                  *
    572  *                                                                                             *
    573  *                                                                                             *
    574  * INPUT:   buffer   -- Pointer to the buffer that holds the data to be written.               *
    575  *                                                                                             *
    576  *          size     -- The number of bytes to write.                                          *
    577  *                                                                                             *
    578  * OUTPUT:  Returns the number of bytes actually written.                                      *
    579  *                                                                                             *
    580  * WARNINGS:   none                                                                            *
    581  *                                                                                             *
    582  * HISTORY:                                                                                    *
    583  *   11/15/1995 DRD : Created.                                                                 *
    584  *=============================================================================================*/
    585 long BufferIOFileClass::Write(void const * buffer, long size)
    586 {
    587 	int opened = false;
    588 
    589 	if ( !Is_Open() ) {
    590 		if (!Open(WRITE)) {
    591 			return(0);
    592 		}
    593 		TrueFileStart = RawFileClass::Seek(0);
    594 		opened = true;
    595 	}
    596 
    597 	if (UseBuffer) {
    598 		long sizewritten = 0;
    599 
    600 		if (BufferRights != READ) {
    601 			while (size) {
    602 				long sizetowrite;
    603 
    604 				if (size >= (BufferSize - BufferPos) ) {
    605 					sizetowrite = (BufferSize - BufferPos);
    606 				} else {
    607 					sizetowrite = size;
    608 				}
    609 
    610 				if (sizetowrite != BufferSize) {
    611 
    612 					if ( !IsCached ) {
    613 						long readsize;
    614 
    615 						if (FileSize < BufferSize) {
    616 							readsize = FileSize;
    617 							BufferFilePos = 0;
    618 						} else {
    619 							readsize = BufferSize;
    620 							BufferFilePos = FilePos;
    621 						}
    622 
    623 						if (TrueFileStart) {
    624 							UseBuffer = false;
    625 							Seek( FilePos, SEEK_SET );
    626 							Read( Buffer, BufferSize );
    627 							Seek( FilePos, SEEK_SET );
    628 							UseBuffer = true;
    629 						} else {
    630 							RawFileClass::Seek( BufferFilePos, SEEK_SET );
    631 							RawFileClass::Read( Buffer, readsize );
    632 						}
    633 
    634 						BufferPos			= 0;
    635 						BufferChangeBeg	= -1;
    636 						BufferChangeEnd	= -1;
    637 
    638 						IsCached = true;
    639 					}
    640 				}
    641 
    642 				memmove((char *)Buffer + BufferPos, (char *)buffer + sizewritten, sizetowrite);
    643 
    644 				IsChanged = true;
    645 				sizewritten += sizetowrite;
    646 				size -= sizetowrite;
    647 
    648 				if (BufferChangeBeg == -1) {
    649 					BufferChangeBeg = BufferPos;
    650 					BufferChangeEnd = BufferPos;
    651 				} else {
    652 					if (BufferChangeBeg > BufferPos) {
    653 						BufferChangeBeg = BufferPos;
    654 					}
    655 				}
    656 
    657 				BufferPos += sizetowrite;
    658 
    659 				if (BufferChangeEnd < BufferPos) {
    660 					BufferChangeEnd = BufferPos;
    661 				}
    662 
    663 				FilePos = BufferFilePos + BufferPos;
    664 
    665 				if (FileSize < FilePos) {
    666 					FileSize = FilePos;
    667 				}
    668 
    669 				//
    670 				// end of buffer reached?
    671 				//
    672 				if (BufferPos == BufferSize) {
    673 					Commit();
    674 
    675 					BufferPos = 0;
    676 					BufferFilePos = FilePos;
    677 					BufferChangeBeg = -1;
    678 					BufferChangeEnd = -1;
    679 
    680 					if (size && FileSize > FilePos) {
    681 						if (TrueFileStart) {
    682 							UseBuffer = false;
    683 							Seek( FilePos, SEEK_SET );
    684 							Read( Buffer, BufferSize );
    685 							Seek( FilePos, SEEK_SET );
    686 							UseBuffer = true;
    687 						} else {
    688 							RawFileClass::Seek( FilePos, SEEK_SET );
    689 							RawFileClass::Read( Buffer, BufferSize );
    690 						}
    691 					} else {
    692 						IsCached = false;
    693 					}
    694 				}
    695 			}
    696 		} else {
    697 			Error(EACCES);
    698 		}
    699 
    700 		size = sizewritten;
    701 	} else {
    702 		size = RawFileClass::Write(buffer, size);
    703 	}
    704 
    705 	if (opened) {
    706 		Close();
    707 	}
    708 
    709 	return( size );
    710 }
    711 
    712 
    713 /***********************************************************************************************
    714  * BufferIOFileClass::Read -- Reads data from the file cache.                                  *
    715  *                                                                                             *
    716  *                                                                                             *
    717  * INPUT:   buffer   -- Pointer to the buffer to place the read data.                          *
    718  *                                                                                             *
    719  *          size     -- The number of bytes to read.                                           *
    720  *                                                                                             *
    721  * OUTPUT:  Returns the actual number of bytes read (this could be less than requested).       *
    722  *                                                                                             *
    723  * WARNINGS:   none                                                                            *
    724  *                                                                                             *
    725  * HISTORY:                                                                                    *
    726  *   11/15/1995 DRD : Created.                                                                 *
    727  *=============================================================================================*/
    728 long BufferIOFileClass::Read(void * buffer, long size)
    729 {
    730 	int opened = false;
    731 
    732 	if ( !Is_Open() ) {
    733 		if ( Open() ) {
    734 			TrueFileStart = RawFileClass::Seek(0);
    735 			opened = true;
    736 		}
    737 	}
    738 
    739 	if (UseBuffer) {
    740 		long sizeread = 0;
    741 
    742 		if (BufferRights != WRITE) {
    743 			while (size) {
    744 				long sizetoread;
    745 
    746 				if (size >= (BufferSize - BufferPos) ) {
    747 					sizetoread = (BufferSize - BufferPos);
    748 				} else {
    749 					sizetoread = size;
    750 				}
    751 
    752 				if ( !IsCached ) {
    753 					long readsize;
    754 
    755 					if (FileSize < BufferSize) {
    756 						readsize = FileSize;
    757 						BufferFilePos = 0;
    758 					} else {
    759 						readsize = BufferSize;
    760 						BufferFilePos = FilePos;
    761 					}
    762 
    763 					if (TrueFileStart) {
    764 						UseBuffer = false;
    765 						Seek( FilePos, SEEK_SET );
    766 						Read( Buffer, BufferSize );
    767 						Seek( FilePos, SEEK_SET );
    768 						UseBuffer = true;
    769 					} else {
    770 						RawFileClass::Seek( BufferFilePos, SEEK_SET );
    771 						RawFileClass::Read( Buffer, readsize );
    772 					}
    773 
    774 					BufferPos			= 0;
    775 					BufferChangeBeg	= -1;
    776 					BufferChangeEnd	= -1;
    777 
    778 					IsCached = true;
    779 				}
    780 
    781 				memmove((char *)buffer + sizeread, (char *)Buffer + BufferPos, sizetoread);
    782 
    783 				sizeread += sizetoread;
    784 				size -= sizetoread;
    785 				BufferPos += sizetoread;
    786 				FilePos = BufferFilePos + BufferPos;
    787 
    788 				//
    789 				// end of buffer reached?
    790 				//
    791 				if (BufferPos == BufferSize) {
    792 					Commit();
    793 
    794 					BufferPos = 0;
    795 					BufferFilePos = FilePos;
    796 					BufferChangeBeg = -1;
    797 					BufferChangeEnd = -1;
    798 
    799 					if (size && FileSize > FilePos) {
    800 						if (TrueFileStart) {
    801 							UseBuffer = false;
    802 							Seek( FilePos, SEEK_SET );
    803 							Read( Buffer, BufferSize );
    804 							Seek( FilePos, SEEK_SET );
    805 							UseBuffer = true;
    806 						} else {
    807 							RawFileClass::Seek( FilePos, SEEK_SET );
    808 							RawFileClass::Read( Buffer, BufferSize );
    809 						}
    810 					} else {
    811 						IsCached = false;
    812 					}
    813 				}
    814 			}
    815 		} else {
    816 			Error(EACCES);
    817 		}
    818 
    819 		size = sizeread;
    820 	} else {
    821 		size = RawFileClass::Read(buffer, size);
    822 	}
    823 
    824 	if (opened) {
    825 		Close();
    826 	}
    827 
    828 	return( size );
    829 }
    830 
    831 
    832 /***********************************************************************************************
    833  * BufferIOFileClass::Seek -- Moves the current file pointer in the file.                      *
    834  *                                                                                             *
    835  *    This routine will change the current file pointer to the position specified. It follows  *
    836  *    the same rules the a normal Seek() does, but if the file is part of the mixfile system,  *
    837  *    then only the position value needs to be updated.                                        *
    838  *                                                                                             *
    839  * INPUT:   pos      -- The position to move the file to relative to the position indicated    *
    840  *                      by the "dir" parameter.                                                *
    841  *                                                                                             *
    842  *          dir      -- The direction to affect the position change against. This can be       *
    843  *                      either SEEK_CUR, SEEK_END, or SEEK_SET.                                *
    844  *                                                                                             *
    845  * OUTPUT:  Returns with the position of the new location.                                     *
    846  *                                                                                             *
    847  * WARNINGS:   none                                                                            *
    848  *                                                                                             *
    849  * HISTORY:                                                                                    *
    850  *   11/15/1995 DRD : Created.                                                                 *
    851  *=============================================================================================*/
    852 long BufferIOFileClass::Seek(long pos, int dir)
    853 {
    854 	if (UseBuffer) {
    855 		bool adjusted = false;
    856 
    857 		switch (dir) {
    858 			case SEEK_END:
    859 				FilePos = FileSize;
    860 				break;
    861 
    862 			case SEEK_SET:
    863 				FilePos = 0;
    864 				break;
    865 
    866 			case SEEK_CUR:
    867 			default:
    868 				break;
    869 		}
    870 
    871 		if (TrueFileStart) {
    872 			if (pos >= TrueFileStart) {
    873 				pos -= TrueFileStart;
    874 				adjusted = true;
    875 			}
    876 		}
    877 
    878 		FilePos += pos;
    879 
    880 		if (FilePos < 0) {
    881 			FilePos = 0;
    882 		}
    883 
    884 		if (FilePos > FileSize ) {
    885 			FilePos = FileSize;
    886 		}
    887 
    888 		if (FileSize <= BufferSize) {
    889 			BufferPos = FilePos;
    890 		} else {
    891 			if (FilePos >= BufferFilePos &&
    892 				 FilePos < (BufferFilePos + BufferSize) ) {
    893 				BufferPos = FilePos - BufferFilePos;
    894 			} else {
    895 				Commit();
    896 // check!!
    897 				if (TrueFileStart) {
    898 					UseBuffer = false;
    899 					Seek(FilePos, SEEK_SET);
    900 					UseBuffer = true;
    901 				} else {
    902 					RawFileClass::Seek(FilePos, SEEK_SET);
    903 				}
    904 
    905 				IsCached = false;
    906 			}
    907 		}
    908 
    909 		if (TrueFileStart && adjusted) {
    910 			return( FilePos + TrueFileStart );
    911 		}
    912 
    913 		return( FilePos );
    914 	}
    915 
    916 	return( RawFileClass::Seek(pos, dir) );
    917 }
    918 
    919 
    920 /***********************************************************************************************
    921  * BufferIOFileClass::Size -- Determines size of file (in bytes).                              *
    922  *                                                                                             *
    923  *    If part or all of the file is cached, then the size of the file is already               *
    924  *    determined and available. Otherwise, go to the low level system to find the file         *
    925  *    size.                                                                                    *
    926  *                                                                                             *
    927  * INPUT:   none                                                                               *
    928  *                                                                                             *
    929  * OUTPUT:  Returns with the number of bytes in the file.                                      *
    930  *                                                                                             *
    931  * WARNINGS:   none                                                                            *
    932  *                                                                                             *
    933  * HISTORY:                                                                                    *
    934  *   11/14/1995 DRD : Created.                                                                 *
    935  *=============================================================================================*/
    936 long BufferIOFileClass::Size(void)
    937 {
    938 	if (IsOpen && UseBuffer) {
    939 		return( FileSize );
    940 	}
    941 
    942 	return( RawFileClass::Size() );
    943 }
    944 
    945 
    946 /***********************************************************************************************
    947  * BufferIOFileClass::Close -- Perform a closure of the file.                                  *
    948  *                                                                                             *
    949  *    Call Commit() to write the buffer if the file is cached and the buffer has changed,      *
    950  *    then call lower level Close().                                                           *
    951  *                                                                                             *
    952  * INPUT:   none                                                                               *
    953  *                                                                                             *
    954  * OUTPUT:  none                                                                               *
    955  *                                                                                             *
    956  * WARNINGS:   none                                                                            *
    957  *                                                                                             *
    958  * HISTORY:                                                                                    *
    959  *   11/14/1995 DRD : Created.                                                                 *
    960  *=============================================================================================*/
    961 void BufferIOFileClass::Close(void)
    962 {
    963 	if (UseBuffer) {
    964 		Commit();
    965 
    966 		if (IsDiskOpen) {
    967 
    968 			if (TrueFileStart) {
    969 				UseBuffer = false;
    970 				Close();
    971 				UseBuffer = true;
    972 			} else {
    973 				RawFileClass::Close();
    974 			}
    975 
    976 			IsDiskOpen = false;
    977 		}
    978 
    979 		IsOpen = false;
    980 	} else {
    981 		RawFileClass::Close();
    982 	}
    983 }
    984