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

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// Stdlib independent.
#include <string.h>

// Stdlib platform-specific.
#include <cell/fs/cell_fs_file_api.h>
#include <cell/sysmodule.h>

// Engine independent.
#include "Core/Asura_List.h"
#include "Core/Asura_String.h"
#include "Debugging/Asura_LogFile.h"
#include "FileAccess/Asura_FileAccess.h"
#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT
#include "Network/Asura_DLC_System.h"
#endif //#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT

// Engine platform-specific.
#include "FileAccess/Asura_PS3_FileSystem.h"
#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT
#include "Network/Asura_PS3_DLC_System.h"
#endif //#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT

//TEMP - remove when checks on CELL_SDK_VERSION below go
#include <sdk_version.h>

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

//#define USE_FAST_BUFFERED_LOAD

#define MAX_FILENAME_LENGTH         256
#define ASURA_PS3_FILE_BUFFER_SIZE  (128 * 1024)


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

// Buffer containing next <buffer size> bytes to be read...
static char*    g_apcFileBuffer [ASURA_MAX_NO_OF_OPEN_FILES];

// How far we are in the buffer...
static unsigned int g_auPositionInBuffer [ASURA_MAX_NO_OF_OPEN_FILES];

// How far we are in the file (marks END address of the buffer)...
static unsigned int g_auBufferPositionInFile [ASURA_MAX_NO_OF_OPEN_FILES];

// Remaining bytes in the file to be read...
static unsigned int g_auBytesToEnd [ASURA_MAX_NO_OF_OPEN_FILES];

// Size of the file in bytes
static u_int g_auFileSize[ ASURA_MAX_NO_OF_OPEN_FILES ];

// PS3 file handle...
static Asura_PS3_FileSystem::Handle g_axFileHandle [ASURA_MAX_NO_OF_OPEN_FILES];
static const char*                  g_apcFileFromMemory [ASURA_MAX_NO_OF_OPEN_FILES];


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

////////////////////////////////////////////////////////////////////////////////
// Function     : ReadNextBuffer
// Author       : Andy Tate
// Date         : 28-Jun-2005
//
// Description  : Reads the appropriate amount of data into the file buffer.
//
// Parameters   : The handle of the file to read.
//
// Return value : "true" if successful, "false" if failed.
////////////////////////////////////////////////////////////////////////////////

static bool ReadNextBuffer (const int iFileHandle)
{
    // Are we nearing the end of the file?
    if (ASURA_PS3_FILE_BUFFER_SIZE > g_auBytesToEnd [iFileHandle])
    {
        const u_int uSizeRead   = Asura_PS3_FileSystem::ReadData (g_axFileHandle [iFileHandle], g_auBytesToEnd [iFileHandle], g_apcFileBuffer [iFileHandle]);

        // Yes - read remaining bytes to end of file...
        if (uSizeRead == g_auBytesToEnd [iFileHandle])
        {
            // Update the file data...
            g_auBufferPositionInFile [iFileHandle]  += g_auBytesToEnd [iFileHandle];
            g_auBytesToEnd [iFileHandle]             = 0;

            // Return success...
            return  (true);
        }

        else
        {
            // Return failure...
            return  (false);
        }
    }

    else
    {
        const u_int uSizeRead   = Asura_PS3_FileSystem::ReadData (g_axFileHandle [iFileHandle], ASURA_PS3_FILE_BUFFER_SIZE, g_apcFileBuffer [iFileHandle]);

        // No - read in next ASURA_PS3_FILE_BUFFER_SIZE bytes...
        if (ASURA_PS3_FILE_BUFFER_SIZE == uSizeRead)
        {
            // Update the file data...
            g_auBufferPositionInFile [iFileHandle]  += ASURA_PS3_FILE_BUFFER_SIZE;
            g_auBytesToEnd [iFileHandle]            -= ASURA_PS3_FILE_BUFFER_SIZE;

            // Return success...
            return  (true);
        }

        else
        {
            // Return failure...
            return  (false);
        }
    }
}

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

//
// Asura_FileAccess
//

void Asura_FileAccess::Platform_Initialise( void )
{
#if CELL_SDK_VERSION >= 0x090002
    // Load the libfs PRX.
#ifdef ASURA_ASSERT
    Asura_Assert( cellSysmoduleLoadModule(CELL_SYSMODULE_FS) == CELL_OK, "PRX for libfs already loaded?" );
#else
    cellSysmoduleLoadModule( CELL_SYSMODULE_FS );
#endif
#endif

    // Allocate the file-buffers...
    for (int i = 0; i < ASURA_MAX_NO_OF_OPEN_FILES; i++)
    {
        g_apcFileBuffer [i] = static_cast<char*>(Asura_AllocateAlign(ASURA_PS3_FILE_BUFFER_SIZE, ASURA_ALIGN_128_BYTE));
    }

#ifndef ASURA_PS3_SONY_SUBMISSION
#ifdef ASURA_PS3_PROJECT_FILEDIR
	int iHandle;
	cellFsOpen("/app_home/SETROOT:"ASURA_PS3_PROJECT_FILEDIR, CELL_FS_O_CREAT, &iHandle, NULL, 0);
	cellFsClose(iHandle);
#else // #ifdef ASURA_PS3_PROJECT_FILEDIR
#error ASURA_PS3_PROJECT_FILEDIR is not defined - please define as "L:\\<project>\\PS3_Release"
#endif // #ifdef ASURA_PS3_PROJECT_FILEDIR
#endif // ndef ASURA_PS3_SONY_SUBMISSION
}


void Asura_FileAccess::Platform_Shutdown (void)
{
    for (int i = 0; i < ASURA_MAX_NO_OF_OPEN_FILES; i++)
    {
        Asura_DeallocateAlign   (g_apcFileBuffer [i]);
    }

// MH (10.8.07) - not bothering to unload the libfs module so that we can do logging at shutdown etc.
//#if CELL_SDK_VERSION >= 0x090002
//    // Unload the libfs PRX.
//#ifdef ASURA_ASSERT
//    Asura_Assert( cellSysmoduleUnloadModule(CELL_SYSMODULE_FS) == CELL_OK, "PRX for libfs already unloaded?" );
//#else
//    cellSysmoduleUnloadModule( CELL_SYSMODULE_FS );
//#endif
//#endif
}



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_FileExists
// Author       : Andy Tate
// Date         : 23-Sep-2005
//
// Description  : Checks whether the specified file exists.
//
// Parameters   : The name of the file to check for.
//
// Return value : "true" if it exists, "false" if not.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_FileExists (const char* szFilename)
{
    Asura_PS3_FileSystem::Handle    xHandle;

    // Can we open the file?
    if (Asura_PS3_FileSystem::OpenForReading(szFilename, &xHandle))
    {
        // Yes - close it and return success...
        Asura_PS3_FileSystem::Close (&xHandle);
        return                      (true);
    }

    else
    {
        // No - it doesn't exist then...
        return  (false);
    }
}

/// End of function 'Asura_FileAccess::Platform_FileExists'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_Open
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : Opens the specified 
//
// Parameters   : The file-handle to open and the name of the file itself.
//
// Return value : "true" if successfully opened, "false" if not.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_Open (Asura_Handle iHandle,
                                      const char* szFilename)
{
    // Open the file...
    Asura_OutputToDebugger  (("Opening \"%s\"\n", szFilename));

    if (Asura_PS3_FileSystem::OpenForReading(szFilename, &g_axFileHandle [iHandle]))
    {
        const u_int uFileSize   = Asura_PS3_FileSystem::GetFileSize (g_axFileHandle [iHandle]);

		// store the overall size of the file
		g_auFileSize[ iHandle ] = uFileSize;

        // Yes - store the size of the file AND re-seek to the start...
        g_auBytesToEnd [iHandle]    = uFileSize;

        Asura_OutputToDebugger  (("Loading: \"%s\" (filesize = %u bytes)\n", szFilename, uFileSize));

        // Read the next buffer's worth of data...
        if (ReadNextBuffer(iHandle))
        {
            // Read successfully...
            g_auPositionInBuffer [iHandle]  = 0;

            Asura_OutputToDebugger  (("Successfully opened \"%s\"\n", szFilename));
            return                  (true);
        }

        else
        {
            // Failed to read correctly...
            return  (false);
        }
    }

    else
    {
        // No - report an error...
        Asura_Assert    (false, "Failed to open file.");
        return          (false);
    }
}

/// End of function 'Asura_FileAccess::Platform_Open'. ///



//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION     Asura_FileAccess::Platform_OpenFromMemory().
// PARAMETERS   iFileHandle - effectively, index into open file array
//              pMem        - pointer to buffer containing file contents
//              uSize       - size of buffer
// RETURNS      true, as we support this method on PS3.
// DESCRIPTION  sets up file reading from memory that already contains a file.
// AUTHOR       Mike Healey - 17.08.2005.
//
//////////////////////////////////////////////////////////////////////////////
bool Asura_FileAccess::Platform_OpenFromMemory( Asura_Handle iFileHandle, const void* pMem, u_int uSize )
{
    g_apcFileFromMemory[iFileHandle]        = static_cast<const char*>(pMem);
    g_auBufferPositionInFile[iFileHandle]   = 0;
    g_auBytesToEnd[iFileHandle]             = uSize;
    return true;
}
// End function Asura_FileAccess::Platform_OpenFromMemory().



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_Close
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : Closes the specified previously opened file.
//
// Parameters   : The handle to the file to be closed.
//
// Return value : "true" if successful, "false" if failed.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_Close (Asura_Handle iFileHandle)
{
    if (g_apcFileFromMemory[iFileHandle])
    {
        g_apcFileFromMemory[iFileHandle] = NULL;
        return true;
    }

    // Simply close the file...

    Asura_OutputToDebugger  (("Finished loading at file position %i\n", g_auBufferPositionInFile [iFileHandle]));
    return                  (Asura_PS3_FileSystem::Close(&g_axFileHandle [iFileHandle]));
}

/// End of function 'Asura_FileAccess::Platform_Close'. ///

bool Asura_FileAccess::Platform_SeekFile(Asura_Handle iFileHandle, u_int uPosition)
{
	Asura_PS3_FileSystem::Handle xHandle = g_axFileHandle[iFileHandle];
	
	{
		Asura_PS3_FileSystem::SetCurrentPosition( xHandle, uPosition );
		const u_int uFileSize = g_auFileSize[ iFileHandle ];


		// Did we succeed in our seek?
		
		{
			if(IsFileRaw(iFileHandle))
			{
				g_auBufferPositionInFile[iFileHandle]	= uPosition;
				g_auBytesToEnd[iFileHandle]				= uFileSize-uPosition;
				g_auPositionInBuffer[iFileHandle]		= 0;
				return(true);
			}
			else
			{
				u_int	uSizeRead;

				g_auBytesToEnd[iFileHandle]	= uFileSize - uPosition;

				// Uses small buffer (size set at top of this file)
				if( g_auBytesToEnd[iFileHandle] < ASURA_PS3_FILE_BUFFER_SIZE)
				{
					// Read in entire file
					uSizeRead = Asura_PS3_FileSystem::ReadData( xHandle, g_auBytesToEnd[iFileHandle], g_apcFileBuffer[iFileHandle] );

					if (uSizeRead != g_auBytesToEnd[iFileHandle])
					{
						return(false);
					}
				}
				else
				{
					// Read in the first ASURA_PS3_FILE_BUFFER_SIZE bytes
					uSizeRead	= Asura_PS3_FileSystem::ReadData( xHandle, ASURA_PS3_FILE_BUFFER_SIZE, g_apcFileBuffer[iFileHandle]);

					if (uSizeRead != ASURA_PS3_FILE_BUFFER_SIZE)
					{
						return(false);
					}
				}
				g_auBufferPositionInFile[iFileHandle]	 = uSizeRead;
				g_auBytesToEnd[iFileHandle]				-= uSizeRead;
				g_auPositionInBuffer[iFileHandle]		 = 0;
				return(true);
			}
		}

	}
}

bool Asura_FileAccess::Platform_DiscExists(void)
{
	return ( Asura_PS3_FileSystem::DiscExists() );
}

#if defined(USE_FAST_BUFFERED_LOAD)

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_ReadData
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : Reads the specified number of bytes (from the file pointed to
//                by the handle) into memory.
//
// Parameters   : The handle of the file to be read along with the address where
//                the data is to be stored and the number of bytes to read.
//
// Return value : "true" if read successfully, "false" if failed.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_ReadData (Asura_Handle iFileHandle,
                                          void* pvDest, 
                                          u_int uNumBytes)
{
    if (g_apcFileFromMemory[iFileHandle])
    {
        if (uNumBytes <= g_auBytesToEnd[iFileHandle])
        {
            memcpy( pvDest, g_apcFileFromMemory[iFileHandle] + g_auBufferPositionInFile[iFileHandle], uNumBytes );
            g_auBufferPositionInFile[iFileHandle] += uNumBytes;
            g_auBytesToEnd[iFileHandle] -= uNumBytes;
            return true;
        }
        Asura_Assert(false, "tried to read too many bytes");
        return false;
    }

    unsigned int    uBytesRemaining = ASURA_PS3_FILE_BUFFER_SIZE - g_auPositionInBuffer [iFileHandle];
    char*           pcSrc           = g_apcFileBuffer [iFileHandle] + g_auPositionInBuffer [iFileHandle];
    char*           pcDest          = (char*)pvDest;

    if(uNumBytes < uBytesRemaining)
    {
        // Staying within this block
        memcpy(pcDest, pcSrc, uNumBytes);
        g_auPositionInBuffer[iFileHandle] += uNumBytes;
        return true;
    }

    else
    {
        // Copy to end of this buffer block

        uNumBytes   -= uBytesRemaining;

        memcpy  (pcDest, pcSrc, uBytesRemaining);

        pcDest  += uBytesRemaining;

        if (uNumBytes >= ASURA_PS3_FILE_BUFFER_SIZE)
        {
            const unsigned int  uBytesToRead    = ASURA_PS3_FILE_BUFFER_SIZE * (unsigned int)(uNumBytes / ASURA_PS3_FILE_BUFFER_SIZE);
			const u_int         uSizeRead       = Asura_PS3_FileSystem::ReadData( g_axFileHandle [iFileHandle], uBytesToRead, pcDest );


            // We have at least one entire block to read
            if (uSizeRead != uBytesToRead)
            {
                Asura_Assert    (false, "Error occurred when reading file");
            }

            pcDest                                  += uBytesToRead;
            g_auBytesToEnd [iFileHandle]            -= uBytesToRead;
            g_auBufferPositionInFile [iFileHandle]  += uBytesToRead;
            uNumBytes                               -= uBytesToRead;
        }


        // We're going to end up in the next block. Now read in the buffer
        if (g_auBytesToEnd[iFileHandle] < ASURA_PS3_FILE_BUFFER_SIZE)
        {
            const u_int uSizeRead   = Asura_PS3_FileSystem::ReadData( g_axFileHandle [iFileHandle], g_auBytesToEnd [iFileHandle], g_apcFileBuffer [iFileHandle] );


            // Read remaining bytes to end of file
            if ( uSizeRead != g_auBytesToEnd[iFileHandle] )
            {
                Asura_Assert    (false, "Error occurred when reading file");
            }
            g_auBufferPositionInFile[iFileHandle] += g_auBytesToEnd[iFileHandle];
        }

        else
        {
            const u_int uSizeRead   = Asura_PS3_FileSystem::ReadData( g_axFileHandle [iFileHandle], ASURA_PS3_FILE_BUFFER_SIZE, g_apcFileBuffer [iFileHandle] );


            // Read in next <buffer size> bytes
            if ( uSizeRead != ASURA_PS3_FILE_BUFFER_SIZE )
            {
                Asura_Assert(0, "Error occurred when reading file");
            }
            g_auBufferPositionInFile[iFileHandle] += ASURA_PS3_FILE_BUFFER_SIZE;
        }
        pcSrc = g_apcFileBuffer[iFileHandle];
        // Finally, copy last piece of data in if we need it.
        if(uNumBytes)
        {
            memcpy(pcDest, pcSrc, uNumBytes);
        }
        g_auBytesToEnd[iFileHandle] -= ASURA_PS3_FILE_BUFFER_SIZE;
        g_auPositionInBuffer[iFileHandle] = uNumBytes;
        return true;
    }
}

/// End of function 'Asura_FileAccess::Platform_ReadData'. ///

#else

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_ReadData
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : Reads the specified number of bytes (from the file pointed to
//                by the handle) into memory.
//
// Parameters   : The handle of the file to be read along with the address where
//                the data is to be stored and the number of bytes to read.
//
// Return value : "true" if read successfully, "false" if failed.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_ReadData (Asura_Handle iFileHandle,
                                          void* pvDest, 
                                          u_int uNumBytes)
{
    if (g_apcFileFromMemory[iFileHandle])
    {
        if (uNumBytes <= g_auBytesToEnd[iFileHandle])
        {
            memcpy( pvDest, g_apcFileFromMemory[iFileHandle] + g_auBufferPositionInFile[iFileHandle], uNumBytes );
            g_auBufferPositionInFile[iFileHandle] += uNumBytes;
            g_auBytesToEnd[iFileHandle] -= uNumBytes;
            return true;
        }
        Asura_Assert(false, "tried to read too many bytes");
        return false;
    }

    // Do we have any data to read?

    if (0 == uNumBytes)
    {
        // No - assume that all was well...

        return  (true);
    }

    else
    {
        unsigned int    uBytesRemaining = ASURA_PS3_FILE_BUFFER_SIZE - g_auPositionInBuffer [iFileHandle];
        const char*     pcSource        = g_apcFileBuffer [iFileHandle] + g_auPositionInBuffer [iFileHandle];
        char*           pcDest          = static_cast<char*>(pvDest);


        // Loop until we've read the data...

        while (uBytesRemaining <= uNumBytes)
        {
            // Copy entire buffer into destination...

            memcpy  (pcDest, pcSource, uBytesRemaining);

            pcDest      += uBytesRemaining;
            uNumBytes   -= uBytesRemaining;


            // Read the next buffer's worth of data...

            if (ReadNextBuffer(iFileHandle))
            {
                // Success - point back to the start of the buffer...

                g_auPositionInBuffer [iFileHandle]  = 0;

                uBytesRemaining                     = ASURA_PS3_FILE_BUFFER_SIZE;
                pcSource                            = g_apcFileBuffer [iFileHandle];
            }

            else
            {
                // Failed to read...

                return  (false);
            }
        }


        // Do we have any remaining bytes?

        if (0 < uNumBytes)
        {
            // Yes - copy them...

            memcpy  (pcDest, pcSource, uNumBytes);

            g_auPositionInBuffer [iFileHandle]  += uNumBytes;
        }


        // Return success...

        return  (true);
    }
}

#endif  // defined(USE_FAST_BUFFERED_LOAD)

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_SkipUncompressedData
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : "true" if successful, "false" if failed.
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_SkipUncompressedData (Asura_Handle iFileHandle,
                                                      u_int uNumBytes)
{
    if (g_apcFileFromMemory[iFileHandle])
    {
        if (uNumBytes <= g_auBytesToEnd[iFileHandle])
        {
            g_auBufferPositionInFile[iFileHandle] += uNumBytes;
            g_auBytesToEnd[iFileHandle] -= uNumBytes;
            return true;
        }
        Asura_Assert(false, "tried to read too many bytes");
        return false;
    }

    const u_int uBytesRemaining = ASURA_PS3_FILE_BUFFER_SIZE - g_auPositionInBuffer [iFileHandle];


    // Do we have enough data in the buffer?

    if (uBytesRemaining <= uNumBytes)
    {
        // No - skip to end of this buffer block...

        uNumBytes   -= uBytesRemaining;

        if (ASURA_PS3_FILE_BUFFER_SIZE <= uNumBytes)
        {
            const u_int uBlocksToSkip   = uNumBytes / ASURA_PS3_FILE_BUFFER_SIZE;
            const u_int uBytesToSkip    = uBlocksToSkip * ASURA_PS3_FILE_BUFFER_SIZE;
            const u_int uBytesSkipped   = Asura_PS3_FileSystem::SkipData (g_axFileHandle [iFileHandle], uBytesToSkip);


            // Did we skip correctly?

            if (uBytesToSkip == uBytesSkipped)
            {
                // Yes - update accordingly...

                g_auBytesToEnd [iFileHandle]            -= uBytesToSkip;
                g_auBufferPositionInFile [iFileHandle]  += uBytesToSkip;
                uNumBytes                               -= uBytesToSkip;
            }

            else
            {
                // No - return failure...

                return  (false);
            }
        }


        // Read the next buffer's worth of data...

        if (ReadNextBuffer(iFileHandle))
        {
            // Success - point into the current buffer...

            g_auPositionInBuffer [iFileHandle]   = uNumBytes;


            // Return success...

            return  (true);
        }

        else
        {
            // Failed to read...

            return  (false);
        }
    }

    else
    {
        // Yes - stay within this block...

        g_auPositionInBuffer [iFileHandle]  += uNumBytes;


        // Return success...

        return  (true);
    }
}

/// End of function 'Asura_FileAccess::Platform_SkipUncompressedData'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_LoadAsynchronous
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : 
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::Platform_LoadAsynchronous(Asura_Handle iHandle,const char* szFilename)
{
    Asura_Assert    (false, "Asynchronous loading not supported");
    return          (true); 
}

/// End of function 'Asura_FileAccess::Platform_LoadAsynchronous'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::Platform_GetAsynchronousLoadingStatus
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : Gets the current asynchronous loading status.
//
// Parameters   : The handle of the file to get the status for.
//
// Return value : The status of this file.
////////////////////////////////////////////////////////////////////////////////

ASURA_ASYNCLOADING_STATUS Asura_FileAccess::Platform_GetAsynchronousLoadingStatus (Asura_Handle iFileHandle)
{
    Asura_Assert    (false, "Asynchronous loading not supported");
    return          (ASURA_ASYNCLOADING_STATUS_ERROR);
}

/// End of function 'Asura_FileAccess::Platform_GetAsynchronousLoadingStatus'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::PlatformGetNetworkDir
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : 
////////////////////////////////////////////////////////////////////////////////

void Asura_FileAccess::PlatformGetNetworkDir (const char* szDir,
                                              char* szOutputBuffer,
                                              u_int uOutputBufferSize,
                                              bool bWarnIfOnlyLocal)
{
    Asura_Assert    (false, "Load from network not supported");
}

/// End of function 'Asura_FileAccess::PlatformGetNetworkDir'. ///


u_int Asura_FileAccess::Platform_GetFileSize( const char* szFilename )
{
    Asura_PS3_FileSystem::Handle xHandle;
    if( Asura_PS3_FileSystem::OpenForReading(szFilename, &xHandle) )
    {
        u_int uSize = Asura_PS3_FileSystem::GetFileSize( xHandle );
        Asura_PS3_FileSystem::Close( &xHandle );
        return uSize;
    }
    else
    {
    	return 0;
	}
}


u_int Asura_FileAccess::Platform_GetFileSize( const Asura_Handle iFileHandle )
{
	return Asura_PS3_FileSystem::GetFileSize( g_axFileHandle[iFileHandle] );
}

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::PlatformGetNetworkFilename
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : 
////////////////////////////////////////////////////////////////////////////////

void Asura_FileAccess::PlatformGetNetworkFilename (const char* szFilename,
                                                   char* szOutputBuffer,
                                                   u_int uOutputBufferSize)
{
    // Network loading not enabled.. just return the original filename...

    Asura_Assert    (szFilename, "");
    Asura_Assert    (strlen(szFilename) < uOutputBufferSize, "");
    strcpy          (szOutputBuffer, szFilename);
}

/// End of function 'Asura_FileAccess::PlatformGetNetworkFilename'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::PlatformUsingNetworkFile
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : 
////////////////////////////////////////////////////////////////////////////////

bool Asura_FileAccess::PlatformUsingNetworkFile (const char* szFilename)
{
    // Not supported - return failure...

    return  (false);
}

/// End of function 'Asura_FileAccess::PlatformUsingNetworkFile'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_FileAccess::PlatformRemoveNetworkOrExecutableDir
// Author       : Andy Tate
// Date         : 27-Jun-2005
//
// Description  : 
//
// Parameters   : 
//
// Return value : 
////////////////////////////////////////////////////////////////////////////////

const char* Asura_FileAccess::PlatformRemoveNetworkOrExecutableDir (const char* szPath)
{
    // Not supported - return the original path...

    return  (szPath);
}

/// End of function 'Asura_FileAccess::PlatformRemoveNetworkOrExecutableDir'. ///




void Asura_FileAccess::Platform_FindFiles(const char* szDirectory, const char* szExtension, void (*pfnCallback)(const char* szFilename), bool bRecursive /* = true */)
{
	// we call a callback for each file with this extension in a given directory (including subdirectories if recursive)

	// get a list of all the files in the dir
	Asura_List<Asura_String> xFiles;
	Asura_PS3_FileSystem::FindFiles(xFiles, Asura_PS3_FileSystem::GetMountPrefix(), szDirectory, bRecursive);

#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT
	// Additionally, search the DLC files if they exist.
	const char* szDLCDirectory = Asura_PS3_DLC_System::GetRootDirectory();
	if (szDLCDirectory)
	{
		Asura_PS3_FileSystem::FindFiles(xFiles, szDLCDirectory, szDirectory, bRecursive);
		// TODO - should we remove duplicates here?
	}
#endif //#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT

	//ensure that all string ends with given extension.
	Asura_String* pxCurrentString;

	for (Asura_List_It<Asura_String> xIt(&xFiles); !xIt.Done();)
	{
		pxCurrentString  = xIt.GetCurrent();
		const char* szFilename = pxCurrentString->GetString();
#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT
		// Check if this is an encrypted file. If it is, we need to make sure the DLC system has flagged it as valid, otherwise we can't use it.
		if (!Asura_PS3_DLC_System::IsEncryptedFile(szFilename) || Asura_DLC_System::IsDownloadedFile(szFilename))
#endif //#ifdef ASURA_SUPPORT_DOWNLOADABLE_CONTENT
		{
			if (pxCurrentString->EndsWith(szExtension))
			{
				pfnCallback(szFilename);
			}
		}
		// Clear the entry from the list and delete the string.
		xIt.DeleteCurrent();
		delete pxCurrentString;
	}
}


/// End of file. ///
