1109 lines
21 KiB
C++
1109 lines
21 KiB
C++
/*
|
|
** 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)
|
|
{
|
|
}
|