| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262 |
- /*
- ** Command & Conquer Generals Zero Hour(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/>.
- */
- /***********************************************************************************************
- *** 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 : Command & Conquer *
- * *
- * $Archive:: /VSS_Sync/wwlib/rawfile.cpp $*
- * *
- * $Author:: Vss_sync $*
- * *
- * $Modtime:: 8/29/01 10:24p $*
- * *
- * $Revision:: 12 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
- * 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::Get_Date_Time -- Gets the date and time the file was last modified. *
- * 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::Raw_Seek -- Performs a seek on the unbiased file *
- * RawFileClass::Read -- Reads the specified number of bytes into a memory buffer. *
- * RawFileClass::Seek -- Reposition the file pointer as indicated. *
- * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
- * 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. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "always.h"
- #include "rawfile.h"
- #include <direct.h>
- //#include <share.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "win.h"
- #include <limits.h>
- #include <errno.h>
- #ifdef _UNIX
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
- #if 0 //#ifdef NEVER (gth) the MAX sdk must #define NEVER! yikes :-)
- /*
- ** This is a duplicate of the error numbers. The error handler for the RawFileClass handles
- ** these errors. If the error routine is overridden and additional errors are defined, then
- ** use numbers starting with 100. Note that these errors here are listed in numerical order.
- ** These errors are defined in the standard header file "ERRNO.H".
- */
- EZERO, // Non-error.
- EINVFNC, // Invalid function number.
- ENOFILE, // File not found.
- ENOENT=ENOFILE, // No such file or directory.
- ENOPATH, // Path not found.
- EMFILE, // Too many open files.
- EACCES, // Permission denied.
- EBADF, // Bad file number.
- ECONTR, // Memory blocks destroyed.
- ENOMEM, // Not enough core memory.
- EINVMEM, // Invalid memory block address.
- EINVENV, // Invalid environment.
- EINVFMT, // Invalid format.
- EINVACC, // Invalid access code.
- EINVDAT, // Invalid data.
- EFAULT, // Unknown error.
- EINVDRV, // Invalid drive specified.
- ENODEV=EINVDRV, // No such device.
- ECURDIR, // Attempt to remove CurDir.
- ENOTSAM, // Not same device.
- ENMFILE, // No more files.
- EINVAL, // Invalid argument.
- E2BIG, // Argument list too long.
- ENOEXEC, // exec format error.
- EXDEV, // Cross-device link.
- ENFILE, // Too many open files.
- ECHILD, // No child process.
- ENOTTY, // not used
- ETXTBSY, // not used
- EFBIG, // not used
- ENOSPC, // No space left on device.
- ESPIPE, // Illegal seek.
- EROFS, // Read-only file system.
- EMLINK, // not used
- EPIPE, // Broken pipe.
- EDOM, // Math argument.
- ERANGE, // Result too large.
- EEXIST, // File already exists.
- EDEADLOCK, // Locking violation.
- EPERM, // Operation not permitted.
- ESRCH, // not used
- EINTR, // Interrupted function call.
- EIO, // Input/output error.
- ENXIO, // No such device or address.
- EAGAIN, // Resource temporarily unavailable.
- ENOTBLK, // not used
- EBUSY, // Resource busy.
- ENOTDIR, // not used
- EISDIR, // not used
- EUCLEAN, // not used
- #endif
- /***********************************************************************************************
- * RawFileClass::RawFileClass -- Default constructor for a file object. *
- * *
- * This constructs a null file object. A null file object has no file handle or filename *
- * associated with it. In order to use a file object created in this fashion it must be *
- * assigned a name and then opened. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/18/1994 JLB : Created. *
- *=============================================================================================*/
- RawFileClass::RawFileClass(void) :
- Rights(READ),
- BiasStart(0),
- BiasLength(-1),
- Handle(NULL_HANDLE),
- Filename(0),
- Date(0),
- Time(0),
- Allocated(false)
- {
- }
- /***********************************************************************************************
- * RawFileClass::Is_Open -- Checks to see if the file is open or not. *
- * *
- * Use this routine to determine if the file is open. It returns true if it is. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Is the file open? *
- * *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/18/1994 JLB : Created. *
- *=============================================================================================*/
- bool RawFileClass::Is_Open(void) const
- {
- return(Handle != NULL_HANDLE);
- }
- /***********************************************************************************************
- * 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. *
- *=============================================================================================*/
- void RawFileClass::Error(int, int, char const * )
- {
- }
- /***********************************************************************************************
- * RawFileClass::Transfer_Block_Size *
- * *
- * This function returns the largest size a low level DOS read or write may *
- * perform. Larger file transfers are performed in chunks of this size or less. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: *
- * *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/18/1994 JLB : Created. *
- *=============================================================================================*/
- int RawFileClass::Transfer_Block_Size(void)
- {
- return (int)((unsigned)UINT_MAX)-16L;
- }
- /***********************************************************************************************
- * 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) :
- Rights(0),
- BiasStart(0),
- BiasLength(-1),
- Handle(NULL_HANDLE),
- Filename(filename),
- Date(0),
- Time(0),
- Allocated(false)
- {
- }
- /***********************************************************************************************
- * RawFileClass::~RawFileClass -- Default deconstructor for a file object. *
- * *
- * This constructs a null file object. A null file object has no file handle or filename *
- * associated with it. In order to use a file object created in this fashion it must be *
- * assigned a name and then opened. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/18/1994 JLB : Created. *
- *=============================================================================================*/
- RawFileClass::~RawFileClass(void)
- {
- Reset ();
- }
- /***********************************************************************************************
- * RawFileClass::Reset -- Closes the file handle and resets the object's state.
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/10/1999 PDS : Created. *
- *=============================================================================================*/
- void RawFileClass::Reset(void)
- {
- Close();
- if (Allocated && Filename) {
- free((char *)Filename);
- Filename = NULL;
- 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 != NULL && Allocated) {
- free((char *)Filename);
- Filename = NULL;
- Allocated = false;
- }
- if (filename == NULL) return(NULL);
- Bias(0);
- char *nameptr = strdup(filename);
- if (nameptr == NULL) {
- Error(ENOMEM, false, filename);
- }
- /*
- ** If this is a UNIX build, fix the filename from the DOS-like name passed in
- */
- #ifdef _UNIX
- for (int i=0; i<strlen(nameptr); i++)
- {
- if (nameptr[i]=='\\')
- nameptr[i]='/';
- nameptr[i]=tolower(nameptr[i]); // don't preserve case
- }
- #endif
- Filename = nameptr;
- 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 == NULL) {
- 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;
- /*
- ** Repetitively try to open the file. Abort if a fatal error condition occurs.
- */
- for (;;) {
- /*
- ** Try to open the file according to the access rights specified.
- */
- switch (rights) {
- /*
- ** If the access rights are not recognized, then report this as
- ** an invalid access code.
- */
- default:
- errno = EINVAL;
- break;
- case READ:
- #ifdef _UNIX
- Handle = fopen(Filename, "r");
- #else
- Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- #endif
- break;
- case WRITE:
- #ifdef _UNIX
- Handle = fopen(Filename, "w");
- #else
- Handle = CreateFileA(Filename, GENERIC_WRITE, 0,
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- #endif
- break;
- case READ|WRITE:
- #ifdef _UNIX
- Handle = fopen(Filename, "w");
- #else
- // SKB 5/13/99 use OPEN_ALWAYS instead of CREATE_ALWAYS so that files
- // does not get destroyed.
- Handle = CreateFileA(Filename, GENERIC_READ | GENERIC_WRITE, 0,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- #endif
- break;
- }
- /*
- ** Biased files must be positioned past the bias start position.
- */
- if (BiasStart != 0 || BiasLength != -1) {
- Seek(0, SEEK_SET);
- }
- /*
- ** 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 == NULL_HANDLE) {
- return(false);
- // Error(GetLastError(), false, Filename);
- // continue;
- }
- break;
- }
- return(true);
- }
- /***********************************************************************************************
- * 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. *
- *=============================================================================================*/
- bool RawFileClass::Is_Available(int forced)
- {
- if (Filename == NULL) return(false);
- /*
- ** 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 (;;) {
- #ifdef _UNIX
- Handle=fopen(Filename,"r");
- #else
- Handle = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- #endif
- if (Handle == NULL_HANDLE) {
- return(false);
- }
- break;
- }
- /*
- ** Since the file could be opened, then close it and return that the file exists.
- */
- int closeok;
- #ifdef _UNIX
- closeok=((fclose(Handle)==0)?TRUE:FALSE);
- #else
- closeok=CloseHandle(Handle);
- #endif
- if (! closeok) {
- Error(GetLastError(), false, Filename);
- }
- Handle = NULL_HANDLE;
- 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()) {
- /*
- ** Try to close the file. If there was an error (who knows what that could be), then
- ** call the error routine.
- */
- int closeok;
- #ifdef _UNIX
- closeok=(fclose(Handle)==0)?TRUE:FALSE;
- #else
- closeok=CloseHandle(Handle);
- #endif
- if (!closeok) {
- Error(GetLastError(), false, Filename);
- }
- /*
- ** At this point the file must have been closed. Mark the file as empty and return.
- */
- Handle = NULL_HANDLE;
- }
- }
- /***********************************************************************************************
- * 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. *
- *=============================================================================================*/
- int RawFileClass::Read(void * buffer, int 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?
- /*
- ** 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;
- }
- /*
- ** A biased file has the requested read length limited to the bias length of
- ** the file.
- */
- if (BiasLength != -1) {
- int remainder = BiasLength - Seek(0);
- size = size < remainder ? size : remainder;
- }
- long total = 0;
- while (size > 0) {
- bytesread = 0;
- int readok=TRUE;
- #ifdef _UNIX
- readok=TRUE;
- bytesread=fread(buffer,1,size,Handle);
- if ((bytesread == 0)&&( ! feof(Handle)))
- readok=ferror(Handle);
- #else
- readok=ReadFile(Handle, buffer, size, &(unsigned long&)bytesread, NULL);
- #endif
-
- if (! readok) {
- size -= bytesread;
- total += bytesread;
- Error(GetLastError(), true, Filename);
- continue;
- }
- size -= bytesread;
- total += bytesread;
- if (bytesread == 0) break;
- }
- bytesread = total;
- /*
- ** 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. *
- *=============================================================================================*/
- int RawFileClass::Write(void const * buffer, int size)
- {
- long byteswritten = 0;
- int opened = false; // Was the file manually opened?
- /*
- ** 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;
- }
- int writeok=TRUE;
- #ifdef _UNIX
- byteswritten = fwrite(buffer, 1, size, Handle);
- if (byteswritten != size)
- writeok = FALSE;
- #else
- writeok=WriteFile(Handle, buffer, size, &(unsigned long&)byteswritten, NULL);
- #endif
- if (! writeok) {
- Error(GetLastError(), false, Filename);
- }
- /*
- ** Fixup the bias length if necessary.
- */
- if (BiasLength != -1) {
- if (Raw_Seek(0) > BiasStart+BiasLength) {
- BiasLength = Raw_Seek(0) - BiasStart;
- }
- }
- /*
- ** 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(byteswritten);
- }
- /***********************************************************************************************
- * 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. *
- *=============================================================================================*/
- int RawFileClass::Seek(int pos, int dir)
- {
- /*
- ** A file that is biased will have a seek operation modified so that the file appears to
- ** exist only within the bias range. All bytes outside of this range appear to be
- ** non-existant.
- */
- if (BiasLength != -1) {
- switch (dir) {
- case SEEK_SET:
- if (pos > BiasLength) {
- pos = BiasLength;
- }
- pos += BiasStart;
- break;
- case SEEK_CUR:
- break;
- case SEEK_END:
- dir = SEEK_SET;
- pos += BiasStart + BiasLength;
- // pos = (pos <= BiasStart+BiasLength) ? pos : BiasStart+BiasLength;
- // pos = (pos >= BiasStart) ? pos : BiasStart;
- break;
- }
- /*
- ** Perform the modified raw seek into the file.
- */
- long newpos = Raw_Seek(pos, dir) - BiasStart;
- /*
- ** Perform a final double check to make sure the file position fits with the bias range.
- */
- if (newpos < 0) {
- newpos = Raw_Seek(BiasStart, SEEK_SET) - BiasStart;
- }
- if (newpos > BiasLength) {
- newpos = Raw_Seek(BiasStart+BiasLength, SEEK_SET) - BiasStart;
- }
- return(newpos);
- }
- /*
- ** If the file is not biased in any fashion, then the normal seek logic will
- ** work just fine.
- */
- return(Raw_Seek(pos, dir));
- }
- /***********************************************************************************************
- * 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. *
- *=============================================================================================*/
- int RawFileClass::Size(void)
- {
- int size = 0;
- /*
- ** A biased file already has its length determined.
- */
- if (BiasLength != -1) {
- return(BiasLength);
- }
- /*
- ** If the file is open, then proceed normally.
- */
- if (Is_Open()) {
- #ifdef _UNIX
- fpos_t curpos,startpos,endpos;
- fgetpos(Handle,&curpos);
- fseek(Handle,0,SEEK_SET);
- fgetpos(Handle,&startpos);
- fseek(Handle,0,SEEK_END);
- fgetpos(Handle,&endpos);
- size=endpos-startpos;
- fsetpos(Handle,&curpos);
- #else
- size = GetFileSize(Handle, NULL);
- #endif
- /*
- ** If there was in internal error, then call the error function.
- */
- if (size == 0xFFFFFFFF) {
- Error(GetLastError(), false, Filename);
- }
- } 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();
- }
- }
- BiasLength = size-BiasStart;
- return(BiasLength);
- }
- /***********************************************************************************************
- * 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)) {
- /*
- ** A biased file must be at least as long as the bias offset. Seeking to the
- ** appropriate start offset has the effect of lengthening the file to the
- ** correct length.
- */
- if (BiasLength != -1) {
- Seek(0, SEEK_SET);
- }
- 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);
- }
- int deleteok;
- #ifdef _UNIX
- deleteok=(unlink(Filename)==0)?TRUE:FALSE;
- #else
- deleteok=DeleteFile(Filename);
- #endif
- if (! deleteok) {
- Error(GetLastError(), false, Filename);
- return(false);
- }
- break;
- }
- /*
- ** DOS reports that the file was successfully deleted. Return with this fact.
- */
- return(true);
- }
- /***********************************************************************************************
- * RawFileClass::Get_Date_Time -- Gets the date and time the file was last modified. *
- * *
- * Use this routine to get the date and time of the file. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the file date and time as a long. *
- * Use the YEAR(long), MONTH(),.... *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 11/14/1995 DRD : Created. *
- * 07/13/1996 JLB : Handles win32 method. *
- *=============================================================================================*/
- unsigned long RawFileClass::Get_Date_Time(void)
- {
- #ifdef _UNIX
- struct stat statbuf;
- lstat(Filename, &statbuf);
- return(statbuf.st_mtime);
- #else
- BY_HANDLE_FILE_INFORMATION info;
- if (GetFileInformationByHandle(Handle, &info)) {
- WORD dosdate;
- WORD dostime;
- FileTimeToDosDateTime(&info.ftLastWriteTime, &dosdate, &dostime);
- return((dosdate << 16) | dostime);
- }
- return(0);
- #endif
- }
- /***********************************************************************************************
- * RawFileClass::Set_Date_Time -- Sets the date and time the file was last modified. *
- * *
- * Use this routine to set the date and time of the file. *
- * *
- * INPUT: the file date and time as a long *
- * *
- * OUTPUT: successful or not if the file date and time was changed. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 11/14/1995 DRD : Created. *
- * 07/13/1996 JLB : Handles win 32 method *
- *=============================================================================================*/
- bool RawFileClass::Set_Date_Time(unsigned long datetime)
- {
- #ifdef _UNIX
- assert(0);
- return(false);
- #else
- if (RawFileClass::Is_Open()) {
- BY_HANDLE_FILE_INFORMATION info;
- if (GetFileInformationByHandle(Handle, &info)) {
- FILETIME filetime;
- if (DosDateTimeToFileTime((WORD)(datetime >> 16), (WORD)(datetime & 0x0FFFF), &filetime)) {
- return(SetFileTime(Handle, &info.ftCreationTime, &filetime, &filetime) != 0);
- }
- }
- }
- return(false);
- #endif
- }
- /***********************************************************************************************
- * RawFileClass::Bias -- Bias a file with a specific starting position and length. *
- * *
- * This will bias a file by giving it an artificial starting position and length. By *
- * using this routine, it is possible to 'fool' the file into ignoring a header and *
- * trailing extra data. An example of this would be a file inside of a mixfile. *
- * *
- * INPUT: start -- The starting offset that will now be considered the start of the *
- * file. *
- * *
- * length -- The forced length of the file. For files that are opened for write, *
- * this serves as the artificial constraint on the file's length. For *
- * files opened for read, this limits the usable file size. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/02/1996 JLB : Created. *
- *=============================================================================================*/
- void RawFileClass::Bias(int start, int length)
- {
- if (start == 0) {
- BiasStart = 0;
- BiasLength = -1;
- return;
- }
- BiasLength = RawFileClass::Size();
- BiasStart += start;
- if (length != -1) {
- BiasLength = BiasLength < length ? BiasLength : length;
- }
- BiasLength = BiasLength > 0 ? BiasLength : 0;
- /*
- ** Move the current file offset to a legal position if necessary and the
- ** file was open.
- */
- if (Is_Open()) {
- RawFileClass::Seek(0, SEEK_SET);
- }
- }
- /***********************************************************************************************
- * RawFileClass::Raw_Seek -- Performs a seek on the unbiased file *
- * *
- * This will perform a seek on the file as if it were unbiased. This is in spite of any *
- * bias setting the file may have. The ability to perform a raw seek in this fasion is *
- * necessary to maintain the bias ability. *
- * *
- * INPUT: pos -- The position to seek the file relative to the "dir" parameter. *
- * *
- * dir -- The origin of the seek operation. *
- * *
- * OUTPUT: Returns with the new position of the seek operation. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/04/1996 JLB : Created. *
- *=============================================================================================*/
- int RawFileClass::Raw_Seek(int pos, int dir)
- {
- /*
- ** If the file isn't opened, then this is a fatal error condition.
- */
- if (!Is_Open()) {
- Error(EBADF, false, Filename);
- }
- #ifdef _UNIX
- pos=fseek(Handle, pos, dir);
- #else
- switch (dir) {
- case SEEK_SET:
- dir = FILE_BEGIN;
- break;
- case SEEK_CUR:
- dir = FILE_CURRENT;
- break;
- case SEEK_END:
- dir = FILE_END;
- break;
- }
- pos = SetFilePointer(Handle, pos, NULL, dir);
- #endif
- /*
- ** If there was an error in the seek, then bail with an error condition.
- */
- if (pos == 0xFFFFFFFF) {
- Error(GetLastError(), false, Filename);
- }
- /*
- ** Return with the new position of the file. This will range between zero and the number of
- ** bytes the file contains.
- */
- return(pos);
- }
- /***********************************************************************************************
- * RawFileClass::Attach -- Provides a file handle for the class to use.
- * *
- * INPUT: handle -- the Win32 file handle.
- * *
- * OUTPUT:
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/10/1999 PDS : Created. *
- *=============================================================================================*/
- void RawFileClass::Attach (void *handle, int rights)
- {
- Reset ();
-
- Rights = rights;
- BiasStart = 0;
- BiasLength = -1;
- Date = 0;
- Time = 0;
- Allocated = false;
- #ifdef _UNIX
- Handle = (FILE *)handle;
- #else
- Handle = handle;
- #endif
- }
- /***********************************************************************************************
- * RawFileClass::Detach -- Removes the file handle from the object without closing the handle.
- * *
- * INPUT
- * *
- * OUTPUT:
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/10/1999 PDS : Created. *
- *=============================================================================================*/
- void RawFileClass::Detach (void)
- {
- Rights = 0;
- BiasStart = 0;
- BiasLength = -1;
- Date = 0;
- Time = 0;
- Allocated = false;
- Handle = NULL_HANDLE;
- }
|