
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_FileStream.cpp
// Author : Andy Tate
// Date   : 9-Jun-2005
//
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "FileAccess/Asura_FileStream.h"

// Asura header-files...
#include "Debugging/Asura_Assert.h"

// Game header-files...


////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::Open
// Author       : Andy Tate
// Date         : 9-Jun-2005
//
// Description  : Opens the specified file for either reading or writing only.
//
// Parameters   : The type of open to perform.
//
// Return value : "true" if successful, "false" if failed to open.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileStream::Open (const OpenType eOpenType)
{
	const char*	szFilename	= m_xFilename.GetString ();


	// Is there already a file open?

	if (m_bIsOpen)
	{
		// Yes - report an error...

		Asura_Assertf	(!m_bIsOpen, ("\"%s\" has already been opened.", szFilename));
		return			(false);
	}

	else
	{
		// No - do we want to read the file?

		switch (eOpenType)
		{
			case READ_DATA:
			{
				m_xFileHandle	= CreateFile	(szFilename,
												GENERIC_READ,
												FILE_SHARE_READ,
												NULL,
												OPEN_EXISTING,
												FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
												NULL);
				break;
			}

			case WRITE_DATA:
			{
				m_xFileHandle	= CreateFile (szFilename,
											  GENERIC_WRITE,
											  0,
											  0,
											  CREATE_ALWAYS,
											  0,
											  0);
				break;
			}

			default:
			{
				Asura_Assertf	(false, ("Unexpected \"Asura_FileStream\" open type specified for \"%s\".", szFilename));
				break;
			}
		}		// End of switch.


		// Set the flags...

		m_eOpenType	= eOpenType;
		m_bIsOpen	= (INVALID_HANDLE_VALUE != m_xFileHandle);


		// Return whether we were successful...

		return	(m_bIsOpen);
	}
}

/// End of function 'Asura_FileStream::Open'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::Open
// Author       : Andy Tate
// Date         : 9-Jun-2005
//
// Description  : Opens the specified file for either reading or writing only.
//
// Parameters   : The name of the file to open.
//
// Return value : "true" if successful, "false" if failed to open.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileStream::Open (const char* szFilename,
							 const OpenType eOpenType,
							 const bool bUseFullPath)
{
	// Is there already a file open?

	if (m_bIsOpen)
	{
		// Yes - report an error...

		Asura_Assertf	(!m_bIsOpen, ("Cannot open \"%s\" - \"%s\" is already open.", szFilename, m_xFilename.GetString()));
		return			(false);
	}

	else
	{
		// No - do we need to use the full path?

		if (bUseFullPath)
		{
			// Yes - do so...

			m_xFilename	= szFilename;
//			m_xFilename	= Asura_PS2_OS::GetFullPath (szFilename);
		}

		else
		{
			// No - simple copy the filename...

			m_xFilename	= szFilename;
		}


		// Open this file...

		return	(Open(eOpenType));
	}
}

/// End of function 'Asura_FileStream::Open'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::ReadData
// Author       : Andy Tate
// Date         : 9-Jun-2005
//
// Description  : Reads the specified amount of data from the stream into the
//				  buffer given.
//
// Parameters   : The number of bytes to be read and a pointer to the address
//				  to read the data into.
//
// Return value : The number of bytes successfully read.
////////////////////////////////////////////////////////////////////////////////

u_int Asura_FileStream::ReadData (const u_int uNumberOfBytes,
								  void* pData)
{
	// Are we able to read?

	if (IsReading())
	{
		DWORD	dwNumBytesRead;


		// Yes - read the data...

		ReadFile	(m_xFileHandle, pData, uNumberOfBytes, &dwNumBytesRead, NULL);


		// Yes - return the number of bytes read...

		return	(static_cast<u_int>(dwNumBytesRead));
	}

	else
	{
		// No - cannot read anything...

		return	(0);
	}
}

/// End of function 'Asura_FileStream::ReadData'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::SkipData
// Author       : Andy Tate
// Date         : 9-Jun-2005
//
// Description  : Reads the specified amount of data from the stream into the
//				  buffer given.
//
// Parameters   : A pointer to the address to read the data into and the number
//				  of bytes to be read.
//
// Return value : The number of bytes successfully read.
////////////////////////////////////////////////////////////////////////////////

u_int Asura_FileStream::SkipData (const u_int uNumberOfBytes)
{
	// Is this file open?

	if (IsOpen())
	{
		DWORD dwResult = SetFilePointer(m_xFileHandle, (LONG)uNumberOfBytes, NULL, FILE_CURRENT);

		// Yes - return the number of bytes skipped...

		if (dwResult == INVALID_SET_FILE_POINTER)
		{
			return 0;
		}
		else
		{
			return	uNumberOfBytes;
		}
	}

	else
	{
		// No - cannot read anything...

		return	(0);
	}
}

/// End of function 'Asura_FileStream::SkipData'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::WriteData
// Author       : Andy Tate
// Date         : 9-Jun-2005
//
// Description  : Writes the specified amount of data from the stream into the
//				  buffer given.
//
// Parameters   : The number of bytes to be written and a pointer to the address
//				  to write the data into.
//
// Return value : The number of bytes successfully write.
////////////////////////////////////////////////////////////////////////////////

u_int Asura_FileStream::WriteData (const u_int uNumberOfBytes,
								   const void* pData)
{
	// Are we able to write?

	if (IsWriting())
	{
		DWORD	dwNumBytesWritten;


		// Yes - write the data...

		WriteFile	(m_xFileHandle, pData, uNumberOfBytes, &dwNumBytesWritten, NULL);


		// Return the number of bytes written...

		return	(static_cast<u_int>(dwNumBytesWritten));
	}

	else
	{
		// No - cannot write anything...

		return	(0);
	}
}

/// End of function 'Asura_FileStream::WriteData'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::GetCurrentPosition
// Author       : Anthony Gregson
// Date         : 05/07/05
//
// Description  : Gets the current byte position within the currently open file.
//
// Return value : The offset position within the current file.
////////////////////////////////////////////////////////////////////////////////

u_int Asura_FileStream::GetCurrentPosition (void) const
{
	// Is there already a file open?

	if (m_bIsOpen)
	{
		DWORD dwCurrentPosition = SetFilePointer(m_xFileHandle, 0, NULL, FILE_CURRENT);


		// Yes - return the current position...

		return static_cast<u_int>(dwCurrentPosition);
	}

	else
	{
		// No - report an error...

		Asura_Assert	(m_bIsOpen, "Cannot get the current position of a file which is not open.");
		return			(false);
	}
}

/// End of function 'Asura_FileStream::GetCurrentPosition'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::GetFileSize
// Author       : Anthony Gregson
// Date         : 05/07/05
//
// Description  : Gets the size of the currently open file.
//
// Return value : The size of the file.
////////////////////////////////////////////////////////////////////////////////

u_int Asura_FileStream::GetFileSize (void) const
{
	// Is there already a file open?

	if (m_bIsOpen)
	{
		DWORD dwCurrentPosition = SetFilePointer(m_xFileHandle, 0, NULL, FILE_CURRENT);


		// Yes - seek to the end of the file and take the size here...

		DWORD dwSize = SetFilePointer(m_xFileHandle, 0, NULL, FILE_END);

		SetFilePointer(m_xFileHandle, dwCurrentPosition, NULL, FILE_BEGIN);


		// Return the size of the file...

		return static_cast<u_int>(dwSize);
	}

	else
	{
		// No - report an error...

		Asura_Assert	(m_bIsOpen, "Cannot get the size of a file which is not open.");
		return			(0);
	}
}

/// End of function 'Asura_FileStream::GetFileSize'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::SetCurrentPosition
// Author       : Anthony Gregson
// Date         : 05/07/05
//
// Description  : Set the position in the file to an offset from the start
//
// Parameters   : The number of bytes into the file to move to.
//
// Return value : Whether the operation succeeded
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileStream::SetCurrentPosition(u_int uNumberOfBytes)
{
	// Is this file open?

	if (IsOpen())
	{
		DWORD dwResult = SetFilePointer(m_xFileHandle, (LONG)uNumberOfBytes, NULL, FILE_BEGIN);
		if (dwResult != INVALID_SET_FILE_POINTER)
		{
			// Success

			return	true;
		}

		else
		{
			// Failure

			return	false;
		}
	}

	else
	{
		// No - cannot set position...

		return	false;
	}
}

/// End of function 'Asura_FileStream::SkipData'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileStream::Close
// Author       : Andy Tate
// Date         : 10-Jun-2005
//
// Description  : Closes the currently open file.
//
// Return value : "true" if closed successfully, "false" if not.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileStream::Close (void)
{
	// Is the file open?

	if (m_bIsOpen)
	{
		// Yes - simply close the file...

		CloseHandle	(m_xFileHandle);


		// Reset the flags...

		m_xFileHandle	= INVALID_HANDLE_VALUE;
		m_bIsOpen		= false;


		// Return success...

		return	(true);
	}

	else
	{
		// No - can't close it then...

		return	(false);
	}
}

/// End of function 'Asura_FileStream::Close'. ///


/// End of file. ///
