/*
**	Command & Conquer Red Alert(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* $Header:   F:\projects\c&c\vcs\code\rawfile.cpv   2.17   06 Sep 1995 16:38:30   JOE_BOSTIC  $ */
/***********************************************************************************************
 ***             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               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Westwood Library                                             *
 *                                                                                             *
 *                    File Name : RAWFILE.CPP                                                  *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic                                                *
 *                                                                                             *
 *                   Start Date : August 8, 1994                                               *
 *                                                                                             *
 *                  Last Update : October 18, 1994   [JLB]                                     *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   RawFileClass::Close -- Perform a closure of the file.                                     *
 *   RawFileClass::Create -- Creates an empty file.                                            *
 *   RawFileClass::Delete -- Deletes the file object from the disk.                            *
 *   RawFileClass::Error -- Handles displaying a file error message.                           *
 *   RawFileClass::Is_Available -- Checks to see if the specified file is available to open.   *
 *   RawFileClass::Open -- Assigns name and opens file in one operation.                       *
 *   RawFileClass::Open -- Opens the file object with the rights specified.                    *
 *   RawFileClass::RawFileClass -- Simple constructor for a file object.                       *
 *   RawFileClass::Read -- Reads the specified number of bytes into a memory buffer.           *
 *   RawFileClass::Seek -- Reposition the file pointer as indicated.                           *
 *   RawFileClass::Set_Name -- Manually sets the name for a file object.                       *
 *   RawFileClass::Size -- Determines size of file (in bytes).                                 *
 *   RawFileClass::Write -- Writes the specified data to the buffer specified.                 *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

 #define	true	1
 #define	false	0

#define	WIN32
#define	_WIN32
#include 	<windows.h>

#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	<direct.h>
#include	<fcntl.h>
#include	<io.h>
#include	<dos.h>
#include	<share.h>
#include	<sys\stat.h>
#include	<wwstd.h>

//#include "wwlib32.h"
//#include	"compat.h"
#include	"rawfile.h"


/***********************************************************************************************
 * RawFileClass::Error -- Handles displaying a file error message.                             *
 *                                                                                             *
 *    Display an error message as indicated. If it is allowed to retry, then pressing a key    *
 *    will return from this function. Otherwise, it will exit the program with "exit()".       *
 *                                                                                             *
 * INPUT:   error    -- The error number (same as the DOSERR.H error numbers).                 *
 *                                                                                             *
 *          canretry -- Can this routine exit normally so that retrying can occur? If this is  *
 *                      false, then the program WILL exit in this routine.                     *
 *                                                                                             *
 *          filename -- Optional filename to report with this error. If no filename is         *
 *                      supplied, then no filename is listed in the error message.             *
 *                                                                                             *
 * OUTPUT:  none, but this routine might not return at all if the "canretry" parameter is      *
 *          false or the player pressed ESC.                                                   *
 *                                                                                             *
 * WARNINGS:   This routine may not return at all. It handles being in text mode as well as    *
 *             if in a graphic mode.                                                           *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/17/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
#pragma argsused
//void RawFileClass::Error(int error, int canretry, char const * filename)
void RawFileClass::Error(int error, int , char const *)
{
	char buffer[256];

	wsprintf(buffer, "File Error #%d", error);
///////	MessageBox(NULL, buffer, "Error", MB_OK);

#ifdef NEVER
	char	message[256];				// Staging buffer for error message string.

	/*
	**	Build the complete text of the error message. This text is used in either the graphic
	**	mode or the text mode version.
	*/
#ifdef GERMAN
	strcpy(message, "DATEIFEHLER");
#else
#ifdef FRENCH
	strcpy(message, "ERREUR DE FICHIER");
#else
	strcpy(message, "FILE ERROR");
#endif
#endif
	if (filename) {
		strcat(message, "(");
		strcat(message, filename);
		strcat(message, ")");
	}
	strcat(message, ": ");
//BG: Borland only	strcat(message, _sys_errlist[error]);
	strcat(message, strerror(error) );
	strcat(message, ". ");

	/*
	**	If it can't properly handle displaying the error message in the
	**	current graphic mode, then this forces the error to become non
	**	recoverable. Go into text mode and proceed.
	*/
	if (!FontPtr && GraphicMode != TXT_MODE) {
		Set_Video_Mode(RESET_MODE);
		canretry = false;
		GraphicMode = TXT_MODE;
	}

	/*
	**	Add the text explaining the valid actions to take.
	*/
	if (canretry) {
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
#ifdef GERMAN
		strcat(message, " Beliebige Taste drcken fr erneuten Versuch.");
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
		strcat(message, " <ESC> drcken, um das Programm zu verlassen.");
#else
#ifdef FRENCH
		strcat(message, " Appuyez sur une touche pour recommencer.");
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
		strcat(message, " Appuyez sur Echap pour quitter le programme.");
#else
		strcat(message, " Press any key to retry.");
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
		strcat(message, " Press <ESC> to exit program.");
#endif
#endif
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
	} else {
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
#ifdef GERMAN
		strcat(message, " Beliebige Taste drcken, um das Programm zu verlassen.");
#else
#ifdef FRENCH
		strcat(message, " Appuyez sur une touche pour quitter le programme.");
#else
		strcat(message, " Press any key to exit program.");
#endif
#endif
		if (GraphicMode == TXT_MODE) strcat(message, "\n");
	}

	/*
	**	In text mode, the error handler is very simple. It just prints the error message
	**	to the screen and waits for a response.
	*/
	if (GraphicMode == TXT_MODE) {
		int	input;

		/*
		**	Display the error message and wait for a response.
		*/
		printf(message);
		Keyboard::Clear();
		input = Keyboard::Get();

		/*
		**	Check for input. If the ESC key was pressed or if retrying is not allowed,
		**	then exit the program. Otherwise, return from this routine for a retry
		**	attempt.
		*/
		if (input == KN_ESC || !canretry) {
			Prog_End();
			exit(EXIT_FAILURE);
		}

	} else {

		/*
		**	The graphic mode version of the error handler will display a simple message
		**	box on the screen. If the palette is black at this point, then the error will
		**	be invisible. For more thorough and pleasing results, you should replace this
		**	virtual function with one of your own, that is more aware of the environment
		**	in which is exists.
		*/
		void			*background;		// Pointer to background saving buffer.
		GraphicBufferClass * 	oldpage;				// Copy of old logic page.
		int			oldwindow;			// Copy of old window number.
		void const	*oldfont;			// Copy of old font pointer.
		int			oldspacing;			// Old font X spacing.

		/*
		**	Setup display in preparation for printing the error message.
		*/
		oldpage = Set_Logic_Page(SeenBuff);
		oldwindow = Change_Window(ErrorWindow);
		oldfont = Set_Font(FontPtr);
		oldspacing = FontXSpacing; FontXSpacing = 0;
		Hide_Mouse();

		/*
		**	Try to allocate a storage buffer for the background to the
		**	error window.
		*/
		background = new char [Size_Of_Region(WinW<<3, WinH)];

		/*
		**	If there is memory for the background storage, then save the
		**	screen image area to that buffer.
		*/
		if (background) {
			SeenPage.To_Buffer(WinX<<3, WinY, WinW<<3, WinH, background, Size_Of_Region(WinW<<3, WinH));
		}

		/*
		**	Draw a rudimentary box.
		*/
		New_Window();
		LogicPage->Draw_Rect(WinX<<3, WinY, (WinX+WinW)<<3, WinY+WinH, WinC);

		/*
		** shrinks window down one byte in all directions.
		*/
		WindowList[Window][WINDOWX] += 1;
		WindowList[Window][WINDOWY] += 1<<3;
		WindowList[Window][WINDOWWIDTH] -= 1<<1;
		WindowList[Window][WINDOWHEIGHT] -= 1<<4;
		Change_Window(Window);
		WinCx = WinCy = 0;

		Window_Print(message);
		Keyboard::Clear();

		/*
		**	Check for input. If the ESC key was pressed or if retrying is not allowed,
		**	then exit the program. Otherwise, return from this routine for a retry
		**	attempt.
		*/
		int input = Keyboard::Get();
		if (input == KN_ESC || !canretry) {
			Prog_End();
			exit(EXIT_FAILURE);
		}

		/*
		**	Restore the window back to its original size.
		*/
		WindowList[Window][WINDOWX] -= 1;
		WindowList[Window][WINDOWY] -= 1<<3;
		WindowList[Window][WINDOWWIDTH] += 1<<1;
		WindowList[Window][WINDOWHEIGHT] += 1<<4;
		Change_Window(Window);
		WinCx = WinCy = 0;

		/*
		**	If the background was saved off, then restore it.
		*/
		if (background) {
			Buffer_To_Page(WinX<<3, WinY, WinW<<3, WinH, background, SeenPage);
			delete [] background;
		}

		/*
		**	Restore the system global settings to original values.
		*/
		Show_Mouse();
		Change_Window(oldwindow);
		Set_Font(oldfont);
		Set_Logic_Page(oldpage);
		FontXSpacing = oldspacing;
	}
#endif
}


/***********************************************************************************************
 * RawFileClass::RawFileClass -- Simple constructor for a file object.                         *
 *                                                                                             *
 *    This constructor is called when a file object is created with a supplied filename, but   *
 *    not opened at the same time. In this case, an assumption is made that the supplied       *
 *    filename is a constant string. A duplicate of the filename string is not created since   *
 *    it would be wasteful in that case.                                                       *
 *                                                                                             *
 * INPUT:   filename -- The filename to assign to this file object.                            *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/17/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
RawFileClass::RawFileClass(char const *filename) : Filename(filename)
{
	Handle = -1;
	Allocated = false;
}


/***********************************************************************************************
 * RawFileClass::Set_Name -- Manually sets the name for a file object.                         *
 *                                                                                             *
 *    This routine will set the name for the file object to the name specified. This name is   *
 *    duplicated in free store. This allows the supplied name to be a temporarily constructed  *
 *    text string. Setting the name in this fashion doesn't affect the closed or opened state  *
 *    of the file.                                                                             *
 *                                                                                             *
 * INPUT:   filename -- The filename to assign to this file object.                            *
 *                                                                                             *
 * OUTPUT:  Returns with a pointer to the allocated copy of this filename. This pointer is     *
 *          guaranteed to remain valid for the duration of this file object or until the name  *
 *          is changed -- whichever is sooner.                                                 *
 *                                                                                             *
 * WARNINGS:   Because of the allocation this routine must perform, memory could become        *
 *             fragmented.                                                                     *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/17/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
char const * RawFileClass::Set_Name(char const *filename)
{
	if (Filename && Allocated) {
// Heap_Dump_Check( "Before raw free" );
		free((char *)Filename);
// Heap_Dump_Check( "After raw free" );
		((char *&)Filename) = 0;
		Allocated = false;
	}

	if (!filename) return(NULL);

// Heap_Dump_Check( "Before raw strdup" );
	((char *&)Filename) = strdup(filename);
// Heap_Dump_Check( "After raw strdup" );
	if (!Filename) {
		Error(ENOMEM, false, filename);
	}
	Allocated = true;
	return(Filename);
}


/***********************************************************************************************
 * RawFileClass::Open -- Assigns name and opens file in one operation.                         *
 *                                                                                             *
 *    This routine will assign the specified filename to the file object and open it at the    *
 *    same time. If the file object was already open, then it will be closed first. If the     *
 *    file object was previously assigned a filename, then it will be replaced with the new    *
 *    name. Typically, this routine is used when an anonymous file object has been crated and  *
 *    now it needs to be assigned a name and opened.                                           *
 *                                                                                             *
 * INPUT:   filename -- The filename to assign to this file object.                            *
 *                                                                                             *
 *          rights   -- The open file access rights to use.                                    *
 *                                                                                             *
 * OUTPUT:  bool; Was the file opened? The return value of this is moot, since the open file   *
 *          is designed to never return unless it succeeded.                                   *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/17/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
int RawFileClass::Open(char const *filename, int rights)
{
	Set_Name(filename);
	return(Open(rights));
}


/***********************************************************************************************
 * RawFileClass::Open -- Opens the file object with the rights specified.                      *
 *                                                                                             *
 *    This routine is used to open the specified file object with the access rights indicated. *
 *    This only works if the file has already been assigned a filename. It is guaranteed, by   *
 *    the error handler, that this routine will always return with success.                    *
 *                                                                                             *
 * INPUT:   rights   -- The file access rights to use when opening this file. This is a        *
 *                      combination of READ and/or WRITE bit flags.                            *
 *                                                                                             *
 * OUTPUT:  bool; Was the file opened successfully? This will always return true by reason of  *
 *          the error handler.                                                                 *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/17/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
int RawFileClass::Open(int rights)
{
	Close();

	/*
	**	Verify that there is a filename associated with this file object. If not, then this is a
	**	big error condition.
	*/
	if (!Filename) {
		Error(ENOENT, false);
	}

	/*
	**	Record the access rights used for this open call. These rights will be used if the
	**	file object is duplicated.
	*/
	Rights = rights;

	/*
	**	Repetatively try to open the file. Abort if a fatal error condition occurs.
	*/
	for (;;) {

		/*
		**	Try to open the file according to the access rights specified.
		*/
//		Hard_Error_Occured = 0;
		switch (rights) {

			/*
			**	If the access rights are not recognized, then report this as
			**	an invalid access code.
			*/
			default:
				errno = EINVAL;
				break;

			case READ:
				Handle = (int)mmioOpen((char*)Filename, NULL, MMIO_READ);
				//Handle = open(Filename, O_RDONLY|O_BINARY);
				break;

			case WRITE:
				Handle = (int)mmioOpen((char*)Filename, NULL, MMIO_WRITE | MMIO_CREATE);
				//Handle = open(Filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY , S_IWRITE);
				break;

			case READ|WRITE:
				Handle = (int)mmioOpen((char*)Filename, NULL, MMIO_READWRITE);
				//Handle = open(Filename, O_RDWR|O_CREAT|O_BINARY);
				break;
		}

		/*
		**	If the handle indicates the file is not open, then this is an error condition.
		**	For the case of the file cannot be found, then allow a retry. All other cases
		**	are fatal.
		*/
		if (Handle == 0) {

//			Error(errno, false, Filename);		//this kills windoze!!!!    ST - 9/28/95 5:33PM
#ifdef NEVER
			/*
			**	If this flag is set, then some hard error occurred. Just assume that the error
			**	is probably a removed CD-ROM and allow a retry.
			*/
			if (Hard_Error_Occured) {
				Error(Hard_Error_Occured, true, Filename);
			} else {
				if (errno == ENOENT) {
					Error(ENOENT, true, Filename);
				} else {
					Error(errno, false, Filename);
				}
			}
#endif
			continue;
		}
		break;
	}
	return(true);
}




void RawFileClass::Set_Buffer_Size (int size)
{
	if (Handle){
		mmioSetBuffer((HMMIO)Handle, NULL, size, 0);
	}
}




/***********************************************************************************************
 * RawFileClass::Is_Available -- Checks to see if the specified file is available to open.     *
 *                                                                                             *
 *    This routine will examine the disk system to see if the specified file can be opened     *
 *    or not. Use this routine before opening a file in order to make sure that is available   *
 *    or to perform other necessary actions.                                                   *
 *                                                                                             *
 * INPUT:   force -- Should this routine keep retrying until the file becomes available? If    *
 *                   in this case it doesn't become available, then the program will abort.    *
 *                                                                                             *
 * OUTPUT:  bool; Is the file available to be opened?                                          *
 *                                                                                             *
 * WARNINGS:   Depending on the parameter passed in, this routine may never return.            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
int RawFileClass::Is_Available(int forced)
{
	int	file;		// Working file handle.
	int	open_failed;
	/*
	**	If the file is already open, then is must have already passed the availability check.
	**	Return true in this case.
	*/
	if (Is_Open()) return(true);

	/*
	**	If this is a forced check, then go through the normal open channels, since those
	**	channels ensure that the file must exist.
	*/
	if (forced) {
		RawFileClass::Open(READ);
		RawFileClass::Close();
		return(true);
	}

	/*
	**	Perform a raw open of the file. If this open fails for ANY REASON, including a missing
	**	CD-ROM, this routine will return a failure condition. In all but the missing file
	**	condition, go through the normal error recover channels.
	*/
	for (;;) {

//		Hard_Error_Occured = 0;
		file = open(Filename, O_RDONLY|O_BINARY);
		open_failed = (file == -1);

		/*
		**	If DOS reports that everything is just fine except that the file is not present,
		**	then return with this fact. Any other case will fall through to the error handler
		**	routine.
		*/
		if (open_failed && errno == ENOENT) return(false);

		/*
		** If we got an access error it could be because there is no cd in
		** the drive.  Call the error handler but allow a continue if it
		** returns.
		*/
		if (open_failed && errno == EACCES) {
			Error(errno, true, Filename);
			continue;
		}

		/*
		**	If the file could not be found, then return with this information. If a more
		**	serious error occurred, then display the error message and abort.
		*/
//		if (Hard_Error_Occured) {
//			Error(Hard_Error_Occured, true, Filename);
//			continue;
//		} else {
			if (open_failed) {
				/*
				**	An unhandled error condition is fatal. Display the error message and then
				**	abort.
				*/
				Error(errno, false, Filename);
			}
//		}
		if (!open_failed) break;
	}

	/*
	**	Since the file could be opened, then close it and return that the file exists.
	*/
	if (close(file)) {
		Error(errno, false, Filename);
	}
	return(true);
}


/***********************************************************************************************
 * RawFileClass::Close -- Perform a closure of the file.                                       *
 *                                                                                             *
 *    Close the file object. In the rare case of an error, handle it as appropriate.           *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Some rare error conditions may cause this routine to abort the program.         *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void RawFileClass::Close(void)
{

	/*
	**	If the file is open, then close it. If the file is already closed, then just return. This
	**	isn't considered an error condition.
	*/
	if (Is_Open()) {

		for (;;) {
			/*
			**	Close the file. If there was an error in the close operation -- abort.
			*/
//			Hard_Error_Occured = 0;
			if (mmioClose((HMMIO)Handle, 0)) {

				/*
				**	By definition, this error can only be a bad file handle. This a fatal condition
				**	of course, so abort with an error message.
				*/
				Error(errno, false, Filename);
			}

			/*
			**	In the condition (if it is even possible) of a hard error occurring, then
			**	assume it is the case of missing media. Display an error message and try
			**	again if indicated.
			*/
//			if (Hard_Error_Occured) {
//				Error(Hard_Error_Occured, true, Filename);
//				continue;
//			}
			break;
		}

		/*
		**	At this point the file must have been closed. Mark the file as empty and return.
		*/
		Handle = -1;
	}
}


/***********************************************************************************************
 * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer.             *
 *                                                                                             *
 *    This routine will read the specified number of bytes and place the data into the buffer  *
 *    indicated. It is legal to call this routine with a request for more bytes than are in    *
 *    the file. This condition can result in fewer bytes being read than requested. Determine  *
 *    this by examining the return value.                                                      *
 *                                                                                             *
 * INPUT:   buffer   -- Pointer to the buffer to read data into. If NULL is passed, no read    *
 *                      is performed.                                                          *
 *                                                                                             *
 *          size     -- The number of bytes to read. If NULL is passed, then no read is        *
 *                      performed.                                                             *
 *                                                                                             *
 * OUTPUT:  Returns with the number of bytes read into the buffer. If this number is less      *
 *          than requested, it indicates that the file has been exhausted.                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
long RawFileClass::Read(void *buffer, long size)
{
	long	bytesread = 0;			// Running count of the number of bytes read into the buffer.
	int	opened = false;		// Was the file opened by this routine?
	int	readresult;

	/*
	**	If the file isn't opened, open it. This serves as a convenience
	**	for the programmer.
	*/
	if (!Is_Open()) {

		/*
		**	The error check here is moot. Open will never return unless it succeeded.
		*/
		if (!Open(READ)) {
			return(0);
		}
		opened = true;
	}

	/*
	**	Read the file in convenient chunk sizes. When the actual number
	**	of bytes read does not match the desired, then assume that the file
	**	is exhausted and bail. This loop was adjusted to take into
	**	consideration the fact that "read" returns a SIGNED value whereas
	**	it takes an UNSIGNED value as the byte count.
	*/
	while (size) {
		unsigned	desired;		// Bytes desired to be read this pass.
		unsigned actual;		// Actual number of bytes read.

		/*
		**	Break the read request into chunks no bigger than the low level DOS read
		**	can handle.
		*/
		desired = size;

//		Hard_Error_Occured = 0;
		readresult = 0;
		actual = mmioRead((HMMIO)Handle, (char*)buffer, desired);
		//actual = read(Handle, buffer, desired);
		if (actual != desired) readresult = errno;

		/*
		**	If a hard error occurred, then assume that it is the case of the CD-ROM or
		**	floppy media having been removed. Display the error and retry as directed.
		*/
//		if (Hard_Error_Occured) {
//			Error(Hard_Error_Occured, true, Filename);
//			continue;			// Not technically needed, but to be consistent...
//		} else {

			/*
			**	If negative one is returned from the read operation, then this indicates
			**	either a bad file number or invalid access. These are fatal conditions, so
			**	display the error and then abort.
			*/
			if (readresult != 0) {
				Error(errno, false, Filename);
			}// else {

				/*
				**	No error occurred during the read. Adjust the pointers and size counters and
				**	loop again if more data is needed to be read.
				*/
				buffer = (void *) ((long)buffer + actual);
				bytesread += actual;
				size -= actual;
				if (actual != desired) break;		// No more data?
			//}
//		}
	}

	/*
	**	Close the file if it was opened by this routine and return
	**	the actual number of bytes read into the buffer.
	*/
	if (opened) Close();
	return(bytesread);
}


/***********************************************************************************************
 * RawFileClass::Write -- Writes the specified data to the buffer specified.                   *
 *                                                                                             *
 *    This routine will write the data specified to the file.                                  *
 *                                                                                             *
 * INPUT:   buffer   -- The buffer that holds the data to write.                               *
 *                                                                                             *
 *          size     -- The number of bytes to write to the file.                              *
 *                                                                                             *
 * OUTPUT:  Returns with the number of bytes written to the file. This routine catches the     *
 *          case of a disk full condition, so this routine will always return with the number  *
 *          matching the size request.                                                         *
 *                                                                                             *
 * WARNINGS:   A fatal file condition could cause this routine to never return.                *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
long RawFileClass::Write(void const *buffer, long size)
{
	long	bytesread = 0;
	int	opened = false;		// Was the file manually opened?
	int	writeresult;

	/*
	**	Check to open status of the file. If the file is open, then merely write to
	**	it. Otherwise, open the file for writing and then close the file when the
	**	output is finished.
	*/
	if (!Is_Open()) {
		if (!Open(WRITE)) {
			return(0);
		}
		opened = true;
	}

	/*
	**	Write the data to the file in chunks no bigger than what the low level DOS write
	**	can handle.
	*/
	while (size) {
		unsigned	desired;		// Bytes desired to be write this pass.
		unsigned actual;		// Actual number of bytes written.

//		Hard_Error_Occured = 0;
//		desired = (unsigned)MIN(size, Transfer_Block_Size());
		desired = size;
		writeresult = 0;
		actual = mmioWrite((HMMIO)Handle, (char*)buffer, desired);
		//actual = write(Handle, buffer, desired);
		if (actual != desired) writeresult = errno;

		/*
		**	If a hard error occurred, then assume it is the case of the media being
		**	removed. Print the error message an retry as directed.
		*/
//		if (Hard_Error_Occured) {
//			Error(Hard_Error_Occured, true, Filename);
//			continue;			// Not technically needed, but to be consistent...
//		} else {

			/*
			**	If negative one is returned by the DOS read, then this indicates a bad file
			**	handle or invalid access. Either condition is fatal -- display error condition
			**	and abort.
			*/
			if (writeresult != 0) {
				Error(errno, false, Filename);
			} else {

				/*
				**	A successful write occurred. Update pointers and byte counter as appropriate.
				*/
				buffer = (void *)((long)buffer + actual);
				bytesread += actual;
				size -= actual;

				/*
				**	If the actual bytes written is less than requested, assume this is a case of
				**	the disk being full. Consider this a fatal error condition.
				*/
				if (actual != desired) {
					Error(ENOSPC, false, Filename);
				}
			}
//		}
	}

	/*
	**	If this routine had to open the file, then close it before returning.
	*/
	if (opened) {
		Close();
	}

	/*
	**	Return with the number of bytes written. This will always be the number of bytes
	**	requested, since the case of the disk being full is caught by this routine.
	*/
	return(bytesread);
}


/***********************************************************************************************
 * RawFileClass::Seek -- Reposition the file pointer as indicated.                             *
 *                                                                                             *
 *    Use this routine to move the filepointer to the position indicated. It can move either   *
 *    relative to current position or absolute from the beginning or ending of the file. This  *
 *    routine will only return if it successfully performed the seek.                          *
 *                                                                                             *
 * INPUT:   pos   -- The position to seek to. This is interpreted as relative to the position  *
 *                   indicated by the "dir" parameter.                                         *
 *                                                                                             *
 *          dir   -- The relative position to relate the seek to. This can be either SEEK_SET  *
 *                   for the beginning of the file, SEEK_CUR for the current position, or      *
 *                   SEEK_END for the end of the file.                                         *
 *                                                                                             *
 * OUTPUT:  This routine returns the position that the seek ended up at.                       *
 *                                                                                             *
 * WARNINGS:   If there was a file error, then this routine might never return.                *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
long RawFileClass::Seek(long pos, int dir)
{
	/*
	**	If the file isn't opened, then this is a fatal error condition.
	*/
	if (!Is_Open()) {
		Error(EBADF, false, Filename);
	}

	/*
	**	Keep trying to seek until a non-retry condition occurs.
	*/
	for (;;) {

		/*
		**	Perform the low level seek on the file.
		*/
//		Hard_Error_Occured = 0;
		pos = mmioSeek((HMMIO)Handle, pos, dir);
		//pos = lseek(Handle, pos, dir);

		/*
		**	If a hard error occurred, then assume that it is the case of removed media. Display
		**	error message and retry.
		*/
//		if (Hard_Error_Occured) {
//			Error(Hard_Error_Occured, true, Filename);
//			continue;
//		} else {

			/*
			**	A negative one indicates a fatal error with the seek operation. Display error
			**	condition and then abort.
			*/
			if (pos == -1) {
				Error(errno, false, Filename);
			}
//		}
		break;
	}

	/*
	**	Return with the new position of the file. This will range between zero and the number of
	**	bytes the file contains.
	*/
	return(pos);
}


/***********************************************************************************************
 * RawFileClass::Size -- Determines size of file (in bytes).                                   *
 *                                                                                             *
 *    Use this routine to determine the size of the file. The file must exist or this is an    *
 *    error condition.                                                                         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of bytes in the file.                                      *
 *                                                                                             *
 * WARNINGS:   This routine handles error conditions and will not return unless the file       *
 *             exists and can successfully be queried for file length.                         *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
long RawFileClass::Size(void)
{
	long	size = 0;
	int	handle = 0;

	/*
	**	If the file is open, then proceed normally.
	*/
	if (Is_Open()) {

		/*
		**	Repetitively try to determine the file size until a fatal error condition or success
		**	is achieved.
		*/
		for (;;) {
//			Hard_Error_Occured = 0;

			handle = open(Filename, O_RDONLY|O_BINARY);
			if (handle > 0){
				size = filelength(handle);
				close(handle);
			}

			/*
			**	If a hard error occurred, then assume it is the case of removed media. Display an
			**	error condition and allow retry.
			*/
//			if (Hard_Error_Occured) {
//				Error(Hard_Error_Occured, true, Filename);
//				continue;
//			} else {
				if (size == -1) {
					Error(errno, false, Filename);
				}
//			}
			break;
		}
	} else {

		/*
		**	If the file wasn't open, then open the file and call this routine again. Count on
		**	the fact that the open function must succeed.
		*/
		if (Open()) {
			size = Size();

			/*
			**	Since we needed to open the file we must remember to close the file when the
			**	size has been determined.
			*/
			Close();
		}
	}
	return(size);
}


/***********************************************************************************************
 * RawFileClass::Create -- Creates an empty file.                                              *
 *                                                                                             *
 *    This routine will create an empty file from the file object. The file object's filename  *
 *    must already have been assigned before this routine will function.                       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the file successfully created? This routine will always return true.     *
 *                                                                                             *
 * WARNINGS:   A fatal error condition could occur with this routine. Especially if the disk   *
 *             is full or a read-only media was selected.                                      *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
int RawFileClass::Create(void)
{
	Close();
	if (Open(WRITE)) {
		Close();
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * RawFileClass::Delete -- Deletes the file object from the disk.                              *
 *                                                                                             *
 *    This routine will delete the file object from the disk. If the file object doesn't       *
 *    exist, then this routine will return as if it had succeeded (since the effect is the     *
 *    same).                                                                                   *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the file deleted? If the file was already missing, the this value will   *
 *                be false.                                                                    *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/18/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
int RawFileClass::Delete(void)
{
	/*
	**	If the file was open, then it must be closed first.
	*/
	Close();

	/*
	**	If there is no filename associated with this object, then this indicates a fatal error
	**	condition. Report this and abort.
	*/
	if (!Filename) {
		Error(ENOENT, false);
	}

	/*
	**	Repetitively try to delete the file if possible. Either return with success, or
	**	abort the program with an error.
	*/
	for (;;) {

		/*
		**	If the file is already missing, then return with this fact. No action is necessary.
		**	This can occur as this section loops if the file exists on a floppy and the floppy
		**	was removed, the file deleted on another machine, and then the floppy was
		**	reinserted. Admittedly, this is a rare case, but is handled here.
		*/
		if (!Is_Available()) {
			return(false);
		}

//		Hard_Error_Occured = 0;
		if (remove(Filename) == -1) {

			/*
			**	If a hard error occurred, then assume that the media has been removed. Display
			**	error message and retry as directed.
			*/
//			if (Hard_Error_Occured) {
//				Error(Hard_Error_Occured, true, Filename);
//				continue;
//			}

			/*
			**	If at this point, DOS says the file doesn't exist, then just exit with this
			**	fact. It should have been caught earlier, but in any case, this is a legal
			**	condition.
			*/
			if (errno == ENOENT) break;

			/*
			**	The only way it can reach this point is if DOS indicates that access is denied
			**	on the file. This occurs when trying to delete a file on a read-only media such
			**	as a CD-ROM. Report this as a fatal error and then abort.
			*/
			Error(errno, false, Filename);
		}
		break;
	}

	/*
	**	DOS reports that the file was successfully deleted. Return with this fact.
	*/
	return(true);
}






//extern "C" {

#define	MAX_HANDLES	10
static RawFileClass Handles[MAX_HANDLES];

#ifdef NEVER
bool __cdecl Set_Search_Drives(BYTE const *)
{
	RawFileClass::Set_Search_Path(path);
	return(true);
}
#endif



int __cdecl Open_File(char const *file_name, int mode)
{
	for (int index = 0; index < MAX_HANDLES; index++) {
		if (!Handles[index].Is_Open()) {
			if (Handles[index].Open(file_name,mode)) {
				return(index);
			}
			break;
		}
	}
	return(WW_ERROR);
}

VOID __cdecl Close_File(int handle)
{
	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
		Handles[handle].Close();
	}
}

LONG __cdecl Read_File(int handle, VOID *buf, ULONG bytes)
{
	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
		return(Handles[handle].Read(buf, bytes));
	}
	return(0);
}

LONG __cdecl Write_File(int handle, VOID const *buf, ULONG bytes)
{
	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
		return(Handles[handle].Write(buf, bytes));
	}
	return(0);
}

int __cdecl Find_File(char const *file_name)
{
	RawFileClass file(file_name);
	return(file.Is_Available());
}

#ifdef NEVER
int __cdecl Delete_File(BYTE const *file_name)
{
	return(RawFileClass(file_name).Delete());
}

int __cdecl Create_File(BYTE const *file_name)
{
	return(RawFileClass(file_name).Create());
}

ULONG __cdecl Load_Data(BYTE const *name, VOID *ptr, ULONG size)
{
	return(RawFileClass(name).Read(ptr, size));
}

VOID * __cdecl Load_Alloc_Data(char const *name, int )
{
	RawFileClass file(name);

	return(Load_Alloc_Data(file));
}
#endif

ULONG __cdecl File_Size(int handle)
{
	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
		return(Handles[handle].Size());
	}
	return(0);
}

#ifdef NEVER
ULONG __cdecl Write_Data(BYTE const *name, VOID const *ptr, ULONG size)
{
	return(RawFileClass(name).Write(ptr, size));
}
#endif

ULONG __cdecl Seek_File(int handle, LONG offset, int starting)
{
	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
		return(Handles[handle].Seek(offset, starting));
	}
	return(0);
}

#ifdef NEVER
bool __cdecl Multi_Drive_Search(bool on)
{
//	return(RawFileClass::Multi_Drive_Search(on));
	return(on);
}

VOID __cdecl WWDOS_Init(VOID)
{
}

VOID __cdecl WWDOS_Shutdown(VOID)
{
}

int __cdecl Find_Disk_Number(BYTE const *)
{
	return(0);
}
#endif




/***********************************************************************************************
 * Load_File -- load an entire file into memory                                                *
 *                                                                                             *
 *                                                                                             *
 *                                                                                             *
 * INPUT:    File name                                                                         *
 *           Load address                                                                      *
 *                                                                                             *
 * OUTPUT:   bytes loaded                                                                      *
 *                                                                                             *
 * WARNINGS: None                                                                              *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *    9/28/95 5:09PM ST : Created                                                              *
 *=============================================================================================*/

int __cdecl Load_File ( const char *file_name , void *load_addr )
{
	int		bytes_read=0;
	int		handle;

	handle=Open_File ( file_name , READ );

	if ( handle>=0 ){
		bytes_read = Read_File ( handle , load_addr , File_Size ( handle ) );
		Close_File ( handle );
	}
	return ( bytes_read );
}




//ULONG cdecl Load_Uncompress(BYTE const *file, BuffType uncomp_buff, BuffType dest_buff, VOID *reserved_data)
//{
//	return(Load_Uncompress(RawFileClass(file), uncomp_buff, dest_buff, reserved_data));
//	return(RawFileClass(file).Load_Uncompress(uncomp_buff, dest_buff, reserved_data));
//}
extern "C" {
int MaxDevice;
int DefaultDrive;
char CallingDOSInt;

}


void Unfragment_File_Cache(void)
{
}
