1304 lines
51 KiB
C++
1304 lines
51 KiB
C++
/*
|
||
** 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 dr<64>cken f<>r erneuten Versuch.");
|
||
if (GraphicMode == TXT_MODE) strcat(message, "\n");
|
||
strcat(message, " <ESC> dr<64>cken, 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 dr<64>cken, 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)
|
||
{
|
||
}
|