| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109 |
- /*
- ** Command & Conquer Renegade(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/>.
- */
- /******************************************************************************
- *
- * FILE
- * $Archive: /Commando/Code/Launcher/Toolkit/Storage/File.cpp $
- *
- * DESCRIPTION
- * File functionality for WIN32
- *
- * PROGRAMMER
- * Denzil E. Long, Jr.
- * $Author: Denzil_l $
- *
- * VERSION INFO
- * $Modtime: 9/23/00 6:19p $
- * $Revision: 1 $
- *
- ******************************************************************************/
- #include "File.h"
- #include <Debug\DebugPrint.h>
- #include <assert.h>
- // This should be whatever the file system uses for invalid files
- const HANDLE File::INVALID_HANDLE = INVALID_HANDLE_VALUE;
- /******************************************************************************
- *
- * NAME
- * File
- *
- * DESCRIPTION
- * Default constructor
- *
- * INPUTS
- * NONE
- *
- * RETURN
- * NONE
- *
- ******************************************************************************/
- File::File()
- : mRights(Rights_ReadOnly),
- mHandle(INVALID_HANDLE)
- {
- }
- /******************************************************************************
- *
- * NAME
- * File
- *
- * DESCRIPTION
- * Create a file instance with the specified name and access rights.
- *
- * INPUTS
- * Name - Name of file
- * Rights - Access rights
- *
- * RETURN
- * NONE
- *
- ******************************************************************************/
- File::File(const Char* name, ERights rights)
- : mRights(rights),
- mHandle(INVALID_HANDLE)
- {
- SetName(name);
- }
- /******************************************************************************
- *
- * NAME
- * File
- *
- * DESCRIPTION
- * Create a file instance with the specified name and access rights.
- *
- * INPUTS
- * Name - Name of file
- * Rights - Access rights
- *
- * RETURN
- * NONE
- *
- ******************************************************************************/
- File::File(const UString& name, ERights rights)
- : mName(name),
- mRights(rights),
- mHandle(INVALID_HANDLE)
- {
- }
- /******************************************************************************
- *
- * NAME
- * ~File
- *
- * DESCRIPTION
- * Destroy a file representation.
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- File::~File()
- {
- // Close any open file.
- Close();
- }
- /******************************************************************************
- *
- * NAME
- * GetName
- *
- * DESCRIPTION
- * Retrieve name of file
- *
- * INPUTS
- * NONE
- *
- * RETURN
- * Name - Name of file.
- *
- ******************************************************************************/
- const UString& File::GetName(void) const
- {
- return mName;
- }
- /******************************************************************************
- *
- * NAME
- * SetName
- *
- * DESCRIPTION
- * Associate a filename to the file class. Any operations will be performed
- * on the associated file with the specified name.
- *
- * INPUTS
- * Filename - Name of file to associate.
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void File::SetName(const UString& name)
- {
- mName = name;
- }
- /******************************************************************************
- *
- * NAME
- * GetRights
- *
- * DESCRIPTION
- * Retrieve file access rights
- *
- * INPUTS
- * NONE
- *
- * RETURN
- * Rights - Current access rights for file
- *
- ******************************************************************************/
- ERights File::GetRights(void) const
- {
- return mRights;
- }
- /******************************************************************************
- *
- * NAME
- * SetRights
- *
- * DESCRIPTION
- * Set file access rights
- *
- * INPUTS
- * Rights - New rights
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void File::SetRights(ERights rights)
- {
- mRights = rights;
- }
- /******************************************************************************
- *
- * NAME
- * IsAvailable
- *
- * DESCRIPTION
- * Checks if the associated file is available for access. If the force
- * flag is true then the file is check for availabilty until it is found
- * or the proceedure is aborted via OnError().
- *
- * INPUTS
- * Force - Force file availability flag.
- *
- * RESULT
- * Success - Success/Failure condition flag.
- *
- ******************************************************************************/
- bool File::IsAvailable(bool force)
- {
- // If the filename is invalid then the file is not available.
- if (mName.Length() == 0)
- {
- return false;
- }
- // If the file is open then it must be available.
- if (IsOpen())
- {
- return true;
- }
- // If this is a forced open then go through the standard file open
- // procedure so that the abort/retry logic gets called.
- if (force == true)
- {
- Open(GetRights());
- Close();
- return true;
- }
- char name[MAX_PATH];
- mName.ConvertToANSI(name, sizeof(name));
- // Attempt to open the file
- mHandle = CreateFile(name, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- // If the open failed then the file is not available.
- if (mHandle == INVALID_HANDLE)
- {
- return false;
- }
- // Close the file.
- CloseHandle(mHandle);
- mHandle = INVALID_HANDLE;
- return true;
- }
- /******************************************************************************
- *
- * NAME
- * IsOpen
- *
- * DESCRIPTION
- * Check if the file is open.
- *
- * INPUTS
- * NONE
- *
- * RETURN
- * Opened - File is opened if true; otherwise false
- *
- ******************************************************************************/
- bool File::IsOpen(void) const
- {
- return ((mHandle != INVALID_HANDLE) ? true : false);
- }
- /******************************************************************************
- *
- * NAME
- * Open
- *
- * DESCRIPTION
- * Opens the file associated with this file class.
- *
- * INPUTS
- * Rights - Access rights for the file to open.
- *
- * RESULT
- * Success - Success/Failure condition flag.
- *
- ******************************************************************************/
- File::EFileError File::Open(ERights rights)
- {
- // Close any currently opened file
- Close();
- // If the filename is invalid then there is no way to open the file.
- if (mName.Length() == 0)
- {
- OnFileError(FileError_FNF, false);
- return FileError_FNF;
- }
- mRights = rights;
- char name[MAX_PATH];
- mName.ConvertToANSI(name, sizeof(name));
- // Continue attempting open until successful or aborted.
- for (;;)
- {
- switch (rights)
- {
- // Read only access
- case Rights_ReadOnly:
- mHandle = CreateFile(name, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- break;
- // Write only access
- case Rights_WriteOnly:
- mHandle = CreateFile(name, GENERIC_WRITE, 0,
- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- break;
- // Read and Write access
- case Rights_ReadWrite:
- mHandle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
- NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- break;
- // Unknown rights access violation
- default:
- OnFileError(FileError_Access, false);
- return FileError_Access;
- break;
- }
- // Check for open failure
- if (mHandle == INVALID_HANDLE)
- {
- PrintWin32Error("File::Open(%S)", mName.Get());
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- {
- if (OnFileError(FileError_FNF, true) == false)
- {
- return FileError_FNF;
- }
- else
- {
- continue;
- }
- }
- else
- {
- OnFileError(FileError_Open, false);
- return FileError_Open;
- }
- }
- break;
- }
- return FileError_None;
- }
- /******************************************************************************
- *
- * NAME
- * Open
- *
- * DESCRIPTION
- * Associate a file then open that file.
- *
- * INPUTS
- * Filename - Name of file to open.
- * Rights - Access rights to file.
- *
- * RESULT
- * Success - Success/Failure condition flag.
- *
- ******************************************************************************/
- File::EFileError File::Open(const UString& name, ERights rights)
- {
- // Associate the file then attempt to open it.
- SetName(name);
- return Open(rights);
- }
- /******************************************************************************
- *
- * NAME
- * Close
- *
- * DESCRIPTION
- * Close access to the file.
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void File::Close(void)
- {
- if (IsOpen())
- {
- CloseHandle(mHandle);
- mHandle = INVALID_HANDLE;
- }
- }
- /******************************************************************************
- *
- * NAME
- * Create
- *
- * DESCRIPTION
- * Creates a file on the local file system with a filename previously
- * associated with a call to SetName().
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * Success - Success/Failure condition flag.
- *
- ******************************************************************************/
- File::EFileError File::Create(void)
- {
- // Close any previous handle
- Close();
- // Open the file for writing
- EFileError error = Open(Rights_WriteOnly);
- if (error == FileError_None)
- {
- Close();
- }
- return error;
- }
- /******************************************************************************
- *
- * NAME
- * Delete
- *
- * DESCRIPTION
- * Deletes the file on the local file system with the name previously
- * associated by calling SetName().
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * Success - Success/Failure condition flag.
- *
- ******************************************************************************/
- File::EFileError File::Delete(void)
- {
- // Make sure the file is closed.
- Close();
- // The file must be available before it can be deleted.
- if (IsAvailable() == false)
- {
- return FileError_FNF;
- }
- else
- {
- // Delete the file. Pass error conditions to OnError()
- char name[MAX_PATH];
- mName.ConvertToANSI(name, sizeof(name));
- if (!DeleteFile(name))
- {
- OnFileError(FileError_Fault, false);
- return FileError_Fault;
- }
- }
- return FileError_None;
- }
- /******************************************************************************
- *
- * NAME
- * Load
- *
- * DESCRIPTION
- * The entire contents of the file is loaded into the specified buffer.
- *
- * INPUTS
- * outBuffer - Buffer with file contents.
- *
- * RESULT
- *
- ******************************************************************************/
- File::EFileError File::Load(void*& outBuffer, UInt32& outSize)
- {
- outBuffer = NULL;
- outSize = 0;
- // Enforce access control
- if (mRights == Rights_WriteOnly)
- {
- OnFileError(FileError_Access, false);
- return FileError_Access;
- }
- EFileError result = FileError_None;
- // Open the file here if it isn't already.
- bool openedHere = false;
- if (IsOpen() == false)
- {
- result = Open(GetRights());
-
- if (result != FileError_None)
- {
- return result;
- }
- // The file was opened here.
- openedHere = true;
- }
- // Get the size of the file
- UInt32 size = GetFileSize(mHandle, NULL);
- if (size == 0xFFFFFFFF)
- {
- PrintWin32Error("File::Load(%S) - GetFileSize", mName.Get());
- result = FileError_Fault;
- OnFileError(result, false);
- }
- if (result == FileError_None)
- {
- // Allocate buffer to hold file contents
- outBuffer = malloc(size);
- outSize = size;
- // If allocation succeded then load file data.
- if (outBuffer != NULL)
- {
- // Fill the buffer with the file contents
- while (size > 0)
- {
- unsigned long bytesRead = 0;
- // Read in some bytes.
- if (ReadFile(mHandle, outBuffer, size, &bytesRead, NULL) == 0)
- {
- result = FileError_Read;
- if (OnFileError(result, true) == false)
- {
- break;
- }
- result = FileError_None;
- }
- size -= bytesRead;
-
- if (bytesRead == 0)
- {
- break;
- }
- }
- }
- else
- {
- result = FileError_Nomem;
- OnFileError(result, false);
- }
- }
- // Close the file if we opened it here.
- if (openedHere == true)
- {
- Close();
- }
- return result;
- }
- /******************************************************************************
- *
- * NAME
- * Save
- *
- * DESCRIPTION
- * Save data to the file.
- *
- * INPUTS
- * Buffer - Pointer to data to write.
- * Size - Number of bytes to write.
- *
- * RESULT
- *
- ******************************************************************************/
- File::EFileError File::Save(const void* buffer, UInt32 size)
- {
- // Enforce access control
- if (mRights == Rights_ReadOnly)
- {
- OnFileError(FileError_Access, false);
- return FileError_Access;
- }
- EFileError result = FileError_None;
- // Open the file if it isn't already.
- bool openedHere = false;
- if (IsOpen() == false)
- {
- result = Open(GetRights());
- if (result == FileError_None)
- {
- openedHere = true;
- }
- }
- if (result == FileError_None)
- {
- SetMarker(0, EStreamFrom::FromStart);
- // Write the data to the file.
- unsigned long bytesWritten = 0;
- if (WriteFile(mHandle, buffer, size, &bytesWritten, NULL) == 0)
- {
- result = FileError_Write;
- OnFileError(result, false);
- }
- else
- {
- SetEndOfFile(mHandle);
- }
- }
- // If we opened the file here then we must close it here.
- if (openedHere == true)
- {
- Close();
- }
- // Return the number of actual butes written.
- return result;
- }
- /******************************************************************************
- *
- * NAME
- * OnFileError(Error, CanRetry)
- *
- * DESCRIPTION
- *
- * INPUTS
- * Error - Error condition code.
- * CanRetry - Retry allowed flag. If this is false then retrys are not
- * permitted for this failure condition.
- *
- * RESULT
- * Retry - Retry flag.
- *
- ******************************************************************************/
- #pragma warning(disable:4100)
- bool File::OnFileError(EFileError error, bool)
- {
- #ifdef _DEBUG
- const char* _errorNames[] =
- {
- "FileError_None",
- "FileError_FNF",
- "FileError_Access",
- "FileError_Open",
- "FileError_Read",
- "FileError_Write",
- "FileError_Seek",
- "FileError_Nomem",
- "FileError_Fault",
- };
- DebugPrint("File::OnFileError(%S) - %s\n", mName.Get(), _errorNames[error]);
- #endif
- return false;
- }
-
- /******************************************************************************
- *
- * NAME
- * GetLength
- *
- * DESCRIPTION
- * Get the size of the file and return it to the caller.
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * Length of the file in bytes.
- *
- ******************************************************************************/
- UInt32 File::GetLength(void)
- {
- // If the file is not open then it must be opened first.
- bool openedHere = false;
- if (IsOpen() == false)
- {
- if (Open(GetRights()) != FileError_None)
- {
- return 0xFFFFFFFF;
- }
- openedHere = true;
- }
- UInt32 length = GetFileSize(mHandle, NULL);
- if (length == 0xFFFFFFFF)
- {
- OnFileError(FileError_Fault, false);
- }
- // If the file was opened here then we need to close it.
- if (openedHere == true)
- {
- Close();
- }
- return length;
- }
- /******************************************************************************
- *
- * NAME
- * SetLength
- *
- * DESCRIPTION
- * Set the length of the streamable file.
- *
- * INPUTS
- * Length - Length of stream in bytes
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void File::SetLength(UInt32 length)
- {
- // Get the current file position
- UInt32 position = SetFilePointer(mHandle, 0, NULL, FILE_CURRENT);
- // Extend the file size by positioning the Win32 file pointer to the
- // specified location then setting the end of file.
- SetFilePointer(mHandle, length, NULL, FILE_BEGIN);
- SetEndOfFile(mHandle);
- // Restore file position
- SetFilePointer(mHandle, position, NULL, FILE_BEGIN);
- }
- /******************************************************************************
- *
- * NAME
- * GetMarker
- *
- * DESCRIPTION
- * Returns the current position in the file stream.
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * Current position in file
- *
- ******************************************************************************/
- UInt32 File::GetMarker(void)
- {
- return SetFilePointer(mHandle, 0, NULL, FILE_CURRENT);
- }
- /******************************************************************************
- *
- * NAME
- * SetMarker
- *
- * DESCRIPTION
- * Position the marker within the file stream.
- *
- * INPUTS
- * Offset - Offset to adjust marker by
- * From -
- *
- * RESULT
- * NONE
- *
- ******************************************************************************/
- void File::SetMarker(Int32 offset, EStreamFrom from)
- {
- // The file must be open before we can seek into it.
- if (IsOpen() == false)
- {
- OnFileError(FileError_Seek, false);
- }
- else
- {
- unsigned long dir;
- switch (from)
- {
- default:
- case Stream::FromStart:
- dir = FILE_BEGIN;
- break;
- case Stream::FromMarker:
- dir = FILE_CURRENT;
- break;
- case Stream::FromEnd:
- dir = FILE_END;
- break;
- }
- offset = SetFilePointer(mHandle, offset, NULL, dir);
- if (offset == 0xFFFFFFFF)
- {
- OnFileError(FileError_Seek, false);
- }
- }
- }
- /******************************************************************************
- *
- * NAME
- * AtEnd
- *
- * DESCRIPTION
- * Test if at the end of stream.
- *
- * INPUTS
- * NONE
- *
- * RESULT
- * End - True if at end; otherwise False.
- *
- ******************************************************************************/
- bool File::AtEnd(void)
- {
- return (GetMarker() >= GetLength());
- }
- /******************************************************************************
- *
- * NAME
- * GetBytes
- *
- * DESCRIPTION
- * Retrieve an arbitrary number of bytes from the file stream.
- *
- * INPUTS
- * Buffer - Pointer to buffer to receive data
- * Bytes - Number of bytes to read
- *
- * RESULT
- * Read - Number of bytes actually read.
- *
- ******************************************************************************/
- UInt32 File::GetBytes(void* ptr, UInt32 bytes)
- {
- // Parameter check; Null pointers are bad!
- assert(ptr != NULL);
- // Enforce rights control
- if (GetRights() == Rights_WriteOnly)
- {
- OnFileError(FileError_Access, false);
- return 0;
- }
- // Open the file if it isn't already
- if (IsOpen() == false)
- {
- if (Open(GetRights()) != FileError_None)
- {
- return 0;
- }
- }
- // Zero total bytes read count
- UInt32 totalRead = 0;
- UInt32 bytesToRead = bytes;
- while (bytesToRead > 0)
- {
- unsigned long read;
- if (ReadFile(mHandle, ptr, bytesToRead, &read, NULL) == 0)
- {
- if (OnFileError(FileError_Read, true) == false)
- {
- return 0;
- }
- }
- // End of file condition?
- if (read == 0)
- {
- break;
- }
- // Adjust counts
- bytesToRead -= read;
- totalRead += read;
- }
- return totalRead;
- }
- /******************************************************************************
- *
- * NAME
- * PutBytes(Buffer, Bytes)
- *
- * DESCRIPTION
- * Write an arbitrary number of bytes to the stream
- *
- * INPUTS
- * Buffer - Pointer to buffer containing data to write
- * Bytes - Number of bytes to transfer
- *
- * RESULT
- * Actual number of bytes written
- *
- ******************************************************************************/
- UInt32 File::PutBytes(const void* ptr, UInt32 bytes)
- {
- // Parameter check; Null pointers are bad!
- assert(ptr != NULL);
- // Enforce access control
- if (GetRights() == Rights_ReadOnly)
- {
- OnFileError(FileError_Access, false);
- return 0;
- }
- // The file must already be open.
- if (IsOpen() == false)
- {
- if (Open(GetRights()) != FileError_None)
- {
- return 0;
- }
- }
- // Zero total bytes written count
- UInt32 totalWritten = 0;
- UInt32 bytesToWrite = bytes;
- while (bytesToWrite > 0)
- {
- unsigned long written;
- if (WriteFile(mHandle, ptr, bytes, &written, NULL) == 0)
- {
- if (OnFileError(FileError_Write, true) == false)
- {
- return 0;
- }
- }
- bytesToWrite -= written;
- totalWritten += written;
- }
- return totalWritten;
- }
- /******************************************************************************
- *
- * NAME
- * PeekBytes(Buffer, Bytes)
- *
- * DESCRIPTION
- * Retrieve bytes from the stream without moving the position marker.
- *
- * INPUTS
- * Buffer - Pointer to buffer to receive data
- * Bytes - Number of bytes to retrieve
- *
- * RESULT
- * Actual number of bytes transfered
- *
- ******************************************************************************/
- UInt32 File::PeekBytes(void* ptr, UInt32 bytes)
- {
- // Parameter check; NULL pointers are bad!
- assert(ptr != NULL);
- // Get current position
- UInt32 pos = GetMarker();
- // Get bytes
- UInt32 bytesPeeked = GetBytes(ptr, bytes);
-
- // Restore previous position
- SetMarker(pos, Stream::FromStart);
- return bytesPeeked;
- }
- /******************************************************************************
- *
- * NAME
- *
- * DESCRIPTION
- *
- * INPUTS
- *
- * RESULT
- *
- ******************************************************************************/
- void File::Flush(void)
- {
- }
|