mirror of
https://github.com/thug1src/thug.git
synced 2024-12-02 12:56:45 +00:00
573 lines
16 KiB
C++
573 lines
16 KiB
C++
/*****************************************************************************
|
|
** **
|
|
** Neversoft Entertainment **
|
|
** **
|
|
** Copyright (C) 1999 - All Rights Reserved **
|
|
** **
|
|
******************************************************************************
|
|
** **
|
|
** Project: System Library **
|
|
** **
|
|
** Module: File IO (File) **
|
|
** **
|
|
** File name: p_filesys.cpp **
|
|
** **
|
|
** Created by: 09/25/00 - dc **
|
|
** **
|
|
** Description: XBox File System **
|
|
** **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Includes **
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <core/defines.h>
|
|
#include <core/support.h>
|
|
#include <sys/file/filesys.h>
|
|
#include <sys/file/PRE.h>
|
|
|
|
#include <sys/ngc/p_file.h>
|
|
|
|
/*****************************************************************************
|
|
** DBG Information **
|
|
*****************************************************************************/
|
|
|
|
namespace File
|
|
{
|
|
|
|
/*****************************************************************************
|
|
** Externals **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Defines **
|
|
*****************************************************************************/
|
|
|
|
#define CDROMx // Use this define to get CDROM behavior
|
|
|
|
#define RWGDFSGLOBAL(var) (RWPLUGINOFFSET(gdfsGlobals, RwEngineInstance, gdfsModuleInfo.globalsOffset)->var)
|
|
|
|
#define PREPEND_START_POS 8
|
|
|
|
/*****************************************************************************
|
|
** Private Types **
|
|
*****************************************************************************/
|
|
|
|
//#define READBUFFERSIZE (10240*5)
|
|
|
|
// GJ: I added this to track how many skyFiles are active
|
|
// at any given time. I am assuming that there's only one,
|
|
// in which case I can just create one global instance
|
|
// (previously, we were allocating it off the current heap,
|
|
// which was causing me grief during the CAS loading process)
|
|
//int g_fileOpenCount = 0;
|
|
|
|
struct skyFile
|
|
{
|
|
|
|
// the following must match the dumbSkyFile struct
|
|
// in pre.cpp, or else pre file i/o won't work properly
|
|
int gdfs;
|
|
int32 POS;
|
|
int32 SOF;
|
|
|
|
// the rest is skyFile-specific
|
|
// uint8 readBuffer[READBUFFERSIZE];
|
|
uint32 bufferPos;
|
|
bool bufferValid;
|
|
bool locked; // whether the skyfile is currently in use
|
|
|
|
// Used when CD
|
|
uint32 WadOffset;
|
|
const char *pFilename;
|
|
|
|
// Used when non-CD
|
|
#define MAX_PFILESYS_NAME_SIZE 100
|
|
char filename[ MAX_PFILESYS_NAME_SIZE ];
|
|
|
|
NsFile ngcFile;
|
|
};
|
|
|
|
/*****************************************************************************
|
|
** Private Data **
|
|
*****************************************************************************/
|
|
|
|
//static RwFileFunctions s_old_fs;
|
|
//static RwInt32 s_open_files = 0;
|
|
|
|
/*****************************************************************************
|
|
** Public Data **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Private Prototypes **
|
|
*****************************************************************************/
|
|
|
|
|
|
/*****************************************************************************
|
|
** Private Functions **
|
|
*****************************************************************************/
|
|
|
|
/******************************************************************/
|
|
/* prefopen */
|
|
/* Same as fopen() except it will prepend the data root directory */
|
|
/* For Xbox, path is always relative to location of .xbe image */
|
|
/* and default path from that location is d:\ */
|
|
/* So incoming files of the form: */
|
|
/* c:\skate3\data\foo... become d:\data\foo... */
|
|
/* foo... become d:\data\foo... */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
//static void* prefopen( const char *filename, const char *mode )
|
|
//{
|
|
// // Used for prepending the root data directory on filesystem calls.
|
|
// char nameConversionBuffer[256] = "d:\\data\\";
|
|
// int index = PREPEND_START_POS;
|
|
// const char* p_skip;
|
|
//
|
|
// if(( filename[0] == 'c' ) && ( filename[1] == ':' ))
|
|
// {
|
|
// // Filename is of the form c:\skate3\data\foo...
|
|
// p_skip = filename + 15;
|
|
// }
|
|
// else
|
|
// {
|
|
// // Filename is of the form foo...
|
|
// p_skip = filename;
|
|
// }
|
|
//
|
|
// while( nameConversionBuffer[index] = *p_skip )
|
|
// {
|
|
// // Switch forward slash directory separators to the supported backslash.
|
|
// if( nameConversionBuffer[index] == '/' )
|
|
// {
|
|
// nameConversionBuffer[index] = '\\';
|
|
// }
|
|
// ++index;
|
|
// ++p_skip;
|
|
// }
|
|
// nameConversionBuffer[index] = 0;
|
|
//
|
|
// // Final hack - if this is a .tex file, switch to a .txx file.
|
|
// if((( nameConversionBuffer[index - 1] ) == 'x' ) &&
|
|
// (( nameConversionBuffer[index - 2] ) == 'e' ) &&
|
|
// (( nameConversionBuffer[index - 3] ) == 't' ))
|
|
// {
|
|
// nameConversionBuffer[index - 2] = 'x';
|
|
// }
|
|
//
|
|
//// return fopen( nameConversionBuffer, mode );
|
|
//
|
|
// HANDLE h_file = CreateFile( nameConversionBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
|
|
// return ( h_file == INVALID_HANDLE_VALUE ) ? NULL : h_file;
|
|
//}
|
|
|
|
|
|
// At first, I assumed that only one skyfile could be open at
|
|
// a time, but that's not true when testing streams from the
|
|
// PC build.
|
|
// pc builds need to have two (one for normal files, and one for streams)
|
|
// GJ: for THPS4, we increased this to 3, so that we can play multiple streams
|
|
const int MAXOPENFILES = 3;
|
|
|
|
// Ken note: It used to be that MAXOPENFILES was defined to be 1 when __NOPT_CDROM__OLD
|
|
// was set. Now that __NOPT_CDROM__OLD is not used anymore and CD() is used at runtime
|
|
// instead, I made MAXOPENFILES always 2. Then, where MAXOPENFILES used to be used in the code
|
|
// it now uses a var set to 1 or 2 depending on CD()
|
|
static skyFile g_skyFile[MAXOPENFILES];
|
|
|
|
skyFile* lock_skyfile( void )
|
|
{
|
|
// cd builds can only have one file open at any given time
|
|
int max_open_files=MAXOPENFILES;
|
|
|
|
int i;
|
|
// this tries to find an unlocked skyfile
|
|
for ( i = 0; i < max_open_files; i++ )
|
|
{
|
|
if ( !g_skyFile[i].locked )
|
|
{
|
|
g_skyFile[i].locked = true;
|
|
g_skyFile[i].ngcFile.m_FileOpen = 0;
|
|
g_skyFile[i].ngcFile.m_sizeCached = 0;
|
|
g_skyFile[i].ngcFile.m_numCacheBytes = 0;
|
|
g_skyFile[i].ngcFile.m_seekOffset = 0;
|
|
g_skyFile[i].ngcFile.m_preHandle = NULL;
|
|
g_skyFile[i].ngcFile.m_unique_tag = 0x1234ABCD;
|
|
return &g_skyFile[i];
|
|
}
|
|
}
|
|
|
|
Dbg_Message( "Here are the files currently open:" );
|
|
for ( i = 0; i < max_open_files; i++ )
|
|
{
|
|
Dbg_Message( "%s", g_skyFile[ i ].filename );
|
|
}
|
|
|
|
// if we get here, that means that all the sky files were locked
|
|
Dbg_MsgAssert( 0, ( "Trying to open too many files simultaneously (max=%d)", max_open_files ) );
|
|
return NULL;
|
|
}
|
|
|
|
void unlock_skyfile( skyFile* pSkyFile )
|
|
{
|
|
// cd builds can only have one file open at any given time
|
|
int max_open_files=MAXOPENFILES;
|
|
|
|
|
|
// this tries to find the sky file that the caller is referencing
|
|
for ( int i = 0; i < max_open_files; i++ )
|
|
{
|
|
if ( pSkyFile == &g_skyFile[i] )
|
|
{
|
|
Dbg_MsgAssert( g_skyFile[i].locked, ( "Trying to unlock a sky file too many times" ) );
|
|
g_skyFile[i].locked = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if we get here, that means that the pointer didn't match one of the valid skyfiles
|
|
Dbg_MsgAssert( 0, ( "Unrecognized sky file" ) );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
** Public Functions **
|
|
*****************************************************************************/
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
long GetFileSize( void* pFP )
|
|
{
|
|
Dbg_MsgAssert(pFP,("NULL pFP sent to GetFileSize"));
|
|
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
int retval = PreMgr::pre_get_file_size((PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
return fp->ngcFile.size();
|
|
}
|
|
|
|
long GetFilePosition(void *pFP)
|
|
{
|
|
|
|
Dbg_MsgAssert(pFP,("NULL pFP sent to GetFilePosition"));
|
|
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
int retval = PreMgr::pre_get_file_position((PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
return fp->ngcFile.tell();
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void InstallFileSystem( void )
|
|
{
|
|
/*
|
|
RwFileFunctions* fs = RwOsGetFileInterface();
|
|
Dbg_MsgAssert( fs,( "File System not found" ));
|
|
|
|
s_old_fs = *fs;
|
|
|
|
fs->rwfexist = fexist;
|
|
fs->rwfopen = (rwFnFopen)prefopen;
|
|
fs->rwfclose = (rwFnFclose)fclose;
|
|
fs->rwfread = (rwFnFread)fread;
|
|
fs->rwfwrite = (rwFnFwrite)fwrite;
|
|
fs->rwfgets = (rwFnFgets)fgets;
|
|
fs->rwfputs = (rwFnFputs)fputs;
|
|
fs->rwfeof = (rwFnFeof)feof;
|
|
fs->rwfseek = (rwFnFseek)fseek;
|
|
fs->rwfflush = (rwFnFflush)fflush;
|
|
fs->rwftell = (rwFnFtell)ftell;
|
|
*/
|
|
}
|
|
|
|
void InitQuickFileSystem( void )
|
|
{
|
|
}
|
|
|
|
uint32 CanFileBeLoadedQuickly( const char* filename )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool LoadFileQuicklyPlease( const char* filename, uint8 *addr )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void StopStreaming( void )
|
|
{
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void UninstallFileSystem( void )
|
|
{
|
|
/*
|
|
RwFileFunctions* fs = RwOsGetFileInterface();
|
|
|
|
Dbg_MsgAssert( fs,( "File System not found" ));
|
|
|
|
*fs = s_old_fs; // restore old
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Our versions of the ANSI file IO functions. They call
|
|
// the PreMgr first to see if the file is in a PRE file.
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Exist
|
|
bool Exist( const char *filename )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
bool retval = PreMgr::pre_fexist(filename);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
NsFile f;
|
|
return f.exist( filename );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Open
|
|
void * Open( const char *filename, const char *access )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
void * retval = PreMgr::pre_fopen(filename, access);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile *fp = lock_skyfile();
|
|
if ( fp )
|
|
{
|
|
strcpy( fp->filename, filename );
|
|
|
|
if ( fp->ngcFile.open( filename ) )
|
|
{
|
|
fp->SOF = fp->ngcFile.size();
|
|
|
|
return (void *)fp;
|
|
}
|
|
else
|
|
{
|
|
unlock_skyfile( fp );
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Close
|
|
int Close( void *pFP )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
int retval = PreMgr::pre_fclose((PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
fp->ngcFile.close();
|
|
|
|
unlock_skyfile( fp );
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Read
|
|
size_t Read( void *addr, size_t size, size_t count, void *pFP )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
size_t retval = PreMgr::pre_fread(addr, size, count, (PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
return fp->ngcFile.read( addr, size * count );
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// Read an Integer in PS2 (littleendian) format
|
|
// we just read it directly into memory...
|
|
size_t ReadInt( void *addr, void *pFP )
|
|
{
|
|
return Read(addr,4,1,pFP);
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Write
|
|
size_t Write( const void *addr, size_t size, size_t count, void *pFP )
|
|
{
|
|
// if (PreMgr::sPreEnabled())
|
|
// {
|
|
// size_t retval = PreMgr::pre_fwrite(addr, size, count, (PreFile::FileHandle *) pFP);
|
|
// if (PreMgr::sPreExecuteSuccess())
|
|
// return retval;
|
|
// }
|
|
//
|
|
//// return skyFwrite(addr, size, count, pFP);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// GetS
|
|
char * GetS( char *buffer, int maxlen, void *pFP )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
char * retval = PreMgr::pre_fgets(buffer, maxlen, (PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
return fp->ngcFile.gets( buffer, maxlen );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// PutS
|
|
int PutS( const char *buffer, void *pFP )
|
|
{
|
|
// if (PreMgr::sPreEnabled())
|
|
// {
|
|
// int retval = PreMgr::pre_fputs(buffer, (PreFile::FileHandle *) pFP);
|
|
// if (PreMgr::sPreExecuteSuccess())
|
|
// return retval;
|
|
// }
|
|
//
|
|
//// return skyFputs(buffer, pFP);
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Eof
|
|
int Eof( void *pFP )
|
|
{
|
|
if (PreMgr::sPreEnabled())
|
|
{
|
|
int retval = PreMgr::pre_feof((PreFile::FileHandle *) pFP);
|
|
if (PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
|
|
skyFile* fp = (skyFile*)pFP;
|
|
return fp->ngcFile.eof();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Seek
|
|
int Seek( void *pFP, long offset, int origin )
|
|
{
|
|
if( PreMgr::sPreEnabled())
|
|
{
|
|
int retval = PreMgr::pre_fseek((PreFile::FileHandle *) pFP, offset, origin);
|
|
if( PreMgr::sPreExecuteSuccess())
|
|
return retval;
|
|
}
|
|
skyFile* fp = (skyFile*)pFP;
|
|
switch ( origin ) {
|
|
case SEEK_SET:
|
|
fp->ngcFile.seek( NsFileSeek_Start, offset );
|
|
break;
|
|
case SEEK_END:
|
|
fp->ngcFile.seek( NsFileSeek_End, offset );
|
|
break;
|
|
case SEEK_CUR:
|
|
default:
|
|
fp->ngcFile.seek( NsFileSeek_Current, offset );
|
|
break;
|
|
}
|
|
return fp->ngcFile.tell();
|
|
}
|
|
|
|
int32 Tell( void* pFP )
|
|
{
|
|
skyFile* fp = (skyFile *) pFP;
|
|
return fp->POS;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Flush
|
|
int Flush( void *pFP )
|
|
{
|
|
// if (PreMgr::sPreEnabled())
|
|
// {
|
|
// int retval = PreMgr::pre_fflush((PreFile::FileHandle *) pFP);
|
|
// if (PreMgr::sPreExecuteSuccess())
|
|
// return retval;
|
|
// }
|
|
//
|
|
//// return skyFflush(pFP);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
} // namespace File
|
|
|
|
|
|
|