thug/Code/Sys/MemCard/XBox/p_McMan.cpp

1032 lines
28 KiB
C++
Raw Normal View History

2016-02-13 21:39:12 +00:00
/*****************************************************************************
** **
** Neversoft Entertainment. **
** **
** Copyright (C) 2000 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: SYS **
** **
** Module: Mc **
** **
** File name: memcard.cpp **
** **
** Created by: 03/06/01 - spg **
** **
** Description: Memcard - platform-specific implementations **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <xtl.h>
#include <core/defines.h>
#include <core/singleton.h>
#include <sys/mcman.h>
/*****************************************************************************
** DBG Information **
*****************************************************************************/
namespace Mc
{
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
#define MAX_FILENAME_LENGTH 128
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
DefineSingletonClass( Manager, "MemCard Manager" );
static char cardFilenameBuffer[MAX_FILENAME_LENGTH];
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
Manager::Manager( void )
{
int i, j;
for( i = 0; i < vMAX_PORT; i++ )
{
for( j = 0; j < vMAX_SLOT; j++ )
{
m_card[i][j].m_port = i;
m_card[i][j].m_slot = j;
}
}
m_hard_drive.SetAsHardDrive();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
Manager::~Manager( void )
{
}
/*****************************************************************************
** Public Functions **
*****************************************************************************/
int Manager::GetMaxSlots( int port )
{
return vMAX_SLOT;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
Card* Manager::GetCard( int port, int slot )
{
// Ignore port and slot, since on the XBox we're only using the hard drive.
return &m_hard_drive;
}
// Skate3 code, disabled for now.
# if 0
Card* Manager::GetHardDrive( )
{
return &m_hard_drive;
}
const char* Manager::GetLastCardName( int port, int slot )
{
Dbg_Assert( port < vMAX_PORT );
Dbg_Assert( slot < vMAX_SLOT );
Card *p_card = &m_card[port][slot];
return p_card->GetLastPersonalizedName();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
const char *Card::GetPersonalizedName()
{
// Only get the name if the card is mounted and is not the hard drive.
if (m_mounted_drive_letter && m_mounted_drive_letter!='u')
{
sprintf(mp_personalized_name,"");
WCHAR p_personalized_name[MAX_MUNAME+10];
DWORD rv=XMUNameFromDriveLetter(m_mounted_drive_letter,p_personalized_name,MAX_MUNAME);
if (rv==ERROR_SUCCESS)
{
// Instead of doing a wsprintfA( mp_personalized_name, "%ls", p_personalized_name );
// which will terminate as soon as it hits a bad char, convert each WCHAR one at a
// time so that all good characters come across.
char *p_dest=mp_personalized_name;
int count=0;
WCHAR p_temp[2]; // A buffer for holding one WCHAR at a time for sending to wsprintfA
p_temp[1]=0;
const WCHAR *p_scan=p_personalized_name;
while (*p_scan) // WCHAR strings are terminated by a 0 just like normal strings, except its a 2byte 0.
{
p_temp[0]=*p_scan++;
char p_one_char[10];
wsprintfA( p_one_char, "%ls", p_temp);
// p_one_char now contains a one char string.
if (count<MAX_MUNAME)
{
if (*p_one_char)
{
*p_dest=*p_one_char;
}
else
{
// Bad char, so write a ~ so that it appears as a xbox null char.
*p_dest='~';
}
++p_dest;
++count;
}
}
*p_dest=0;
int len=strlen(mp_personalized_name);
for (int i=0; i<len; ++i)
{
// Force any special characters (arrows or button icons) to be displayed
// as the xbox NULL character by changing them to an invalid character.
switch (mp_personalized_name[i])
{
case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>':
case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>':
case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>': case '<EFBFBD>':
case -1: // This is the weird lower-case-y-umlaut character.
// Note: The upper case y-umlaut character appears to be viewed as a
// terminator character by XMUNameFromDriveLetter ( = bug?)
mp_personalized_name[i]='~';
break;
default:
break;
}
}
}
else
{
#ifdef __NOPT_ASSERT__
char p_temp[100];
sprintf(p_temp,"XMUNameFromDriveLetter error code = %d\n",rv);
OutputDebugString(p_temp);
#endif
}
}
return mp_personalized_name;
}
const char *Card::GetLastPersonalizedName()
{
return mp_personalized_name;
}
bool Card::THPS3SavesExist()
{
if ( m_mounted_drive_letter == 0 )
{
return false;
}
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
XGAME_FIND_DATA data;
HANDLE rv=XFindFirstSaveGame(cardFilenameBuffer,&data);
if (rv==INVALID_HANDLE_VALUE)
{
return false;
}
else
{
XFindClose(rv);
return true;
}
}
bool Card::CasParkOrReplaysExist()
{
if ( m_mounted_drive_letter == 0 )
{
return false;
}
char p_optpros_name[100];
sprintf( p_optpros_name,"/Options and Pros" );
ConvertDirectory( p_optpros_name, p_optpros_name );
strcat(p_optpros_name,"\\");
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
XGAME_FIND_DATA data;
HANDLE rv=XFindFirstSaveGame(cardFilenameBuffer,&data);
if (rv==INVALID_HANDLE_VALUE)
{
return false;
}
bool cas_park_or_replays_exist=false;
while (true)
{
if (stricmp(data.szSaveGameDirectory+3,p_optpros_name)==0)
{
// It's the optpros file
}
else
{
// It either a cas, park or replay.
cas_park_or_replays_exist=true;
break;
}
if (XFindNextSaveGame(rv,&data))
{
}
else
{
break;
}
}
XFindClose(rv);
return cas_park_or_replays_exist;
}
// Returns true if the total number of cas, park or replay files is the max allowed.
bool Card::MaxFilesReached()
{
if ( m_mounted_drive_letter == 0 )
{
return false;
}
char p_optpros_name[100];
sprintf( p_optpros_name,"/Options and Pros" );
ConvertDirectory( p_optpros_name, p_optpros_name );
strcat(p_optpros_name,"\\");
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
XGAME_FIND_DATA data;
HANDLE rv=XFindFirstSaveGame(cardFilenameBuffer,&data);
if (rv==INVALID_HANDLE_VALUE)
{
return false;
}
int num_files=0;
while (true)
{
if (stricmp(data.szSaveGameDirectory+3,p_optpros_name)==0)
{
// It's the optpros file
}
else
{
// It either a cas, park or replay.
++num_files;
}
if (!XFindNextSaveGame(rv,&data))
{
break;
}
}
XFindClose(rv);
if (num_files>=75)
{
return true;
}
return false;
}
# endif
// Note: dir_name must no longer start with a backslash, it should just be "Career2-Career" etc.
bool Card::MakeDirectory( const char* dir_name )
{
char output_dir[vDIRECTORY_NAME_BUF_SIZE];
WCHAR input_name[vDIRECTORY_NAME_BUF_SIZE];
wsprintfW( input_name, L"%hs", dir_name );
DWORD rv = XCreateSaveGame( "u:\\", // Root of device on which to create the save game.
input_name, // Name of save game (effectively directory name).
OPEN_ALWAYS, // Open disposition.
0, // Creation flags.
output_dir, // String to take resultant directory name buffer.
vDIRECTORY_NAME_BUF_SIZE ); // Size of directory name buffer.
if( rv == ERROR_SUCCESS )
{
return true;
}
if (rv==ERROR_DISK_FULL)
{
m_last_error=vINSUFFICIENT_SPACE;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
const char *Card::ConvertDirectory( const char* dir_name )
{
static char output_dir[vDIRECTORY_NAME_BUF_SIZE];
WCHAR input_name[vDIRECTORY_NAME_BUF_SIZE];
wsprintfW( input_name, L"%hs", dir_name );
DWORD rv = XCreateSaveGame( "u:\\", // Root of device on which to create the save game.
input_name, // Name of save game (effectively directory name).
OPEN_EXISTING, // Open disposition.
0, // Creation flags.
output_dir, // String to take resultant directory name buffer.
vDIRECTORY_NAME_BUF_SIZE ); // Size of directory name buffer.
if( rv == ERROR_SUCCESS )
{
// Remove the initial "u:\" and the final "\"
strcpy(output_dir,output_dir+3);
output_dir[strlen(output_dir)-1]=0;
return output_dir;
}
return NULL;
}
// Skate3 code, disabled for now.
#if 0
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::ConvertDirectory( const char* dir_name, char* output_name )
{
// K: This used to assert.
if (m_mounted_drive_letter==0)
{
return false;
}
// Seems incoming filenames are of the form /foo etc.
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
++dir_name;
int index = 4;
while( cardFilenameBuffer[index] = *dir_name )
{
// Switch forward slash directory separators to the supported backslash.
if( cardFilenameBuffer[index] == '/' )
{
cardFilenameBuffer[index] = '\\';
}
++index;
++dir_name;
}
char output_dir[64];
WCHAR input_name[64];
wsprintfW( input_name, L"%hs", &cardFilenameBuffer[4] );
DWORD rv = XCreateSaveGame( cardFilenameBuffer, // Root of device on which to create the save game.
input_name, // Name of save game (effectively directory name).
OPEN_EXISTING, // Open disposition.
0, // Creation flags.
output_dir, // String to take resultant directory name buffer.
64 ); // Size of directory name buffer.
if( rv == ERROR_SUCCESS )
{
// Copy over output directory, stripping leading drive, colon and backslash, and removing trailing backslash.
strcpy( output_name, &output_dir[3] );
output_name[strlen( output_name ) - 1] = 0;
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::DeleteDirectory( const char* dir_name )
{
Dbg_Assert( m_mounted_drive_letter != 0 );
// Seems incoming filenames are of the form /foo etc.
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
++dir_name;
int index = 4;
while( cardFilenameBuffer[index] = *dir_name )
{
// Switch forward slash directory separators to the supported backslash.
if( cardFilenameBuffer[index] == '/' )
{
cardFilenameBuffer[index] = '\\';
}
++index;
++dir_name;
}
WCHAR input_name[64];
wsprintfW( input_name, L"%hs", &cardFilenameBuffer[4] );
DWORD rv = XDeleteSaveGame( cardFilenameBuffer, // Root of device on which to create the save game.
input_name );
if( rv == ERROR_SUCCESS )
{
return true;
}
return false;
}
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
// Given the name of a file, this will delete it's directory, which
// will result in the deletion of the directory, the file, and the icon.
// The name must not be preceded with a backslash, ie should be "Career12-Career" for example.
bool Card::DeleteDirectory( const char* dir_name )
{
WCHAR input_name[64];
wsprintfW( input_name, L"%hs", dir_name );
DWORD rv = XDeleteSaveGame( "u:\\", input_name );
if( rv == ERROR_SUCCESS )
{
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::ChangeDirectory( const char* dir_name )
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::Format( void )
{
// Not supported from within an Xbox title.
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::Unformat( void )
{
// Not supported from within an Xbox title.
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::IsFormatted( void )
{
// Must be formatted to have got this far on an Xbox title.
return true;
}
void Card::SetAsHardDrive()
{
m_mounted_drive_letter='u';
}
// Skate3 code, disabled for now.
#if 0
bool Card::IsHardDrive()
{
return m_mounted_drive_letter=='u';
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void Card::UnMount( void )
{
// Can't unmount the hard drive.
if( m_mounted_drive_letter=='u' )
{
return;
}
m_mount_error=false;
m_mount_failed_due_to_card_full=false;
m_mount_failed_due_to_card_unformatted=false;
if( m_mounted_drive_letter )
{
DWORD rv = XUnmountMU(m_port, ( m_slot == 0 ) ? XDEVICE_TOP_SLOT : XDEVICE_BOTTOM_SLOT);
if (rv != ERROR_SUCCESS)
{
m_mount_error=true;
if (rv==ERROR_DISK_FULL)
{
m_mount_failed_due_to_card_full=true;
}
if (rv==ERROR_UNRECOGNIZED_VOLUME)
{
m_mount_failed_due_to_card_unformatted=true;
}
}
m_mounted_drive_letter=0;
}
}
#endif
int Card::GetDeviceType( void )
{
return vDEV_XBOX_HARD_DRIVE;
}
// Skate3 code, disabled for now.
#if 0
bool Card::GetMountError()
{
return m_mount_error;
}
bool Card::MountFailedDueToCardFull()
{
return m_mount_failed_due_to_card_full;
}
bool Card::MountFailedDueToCardUnformatted()
{
return m_mount_failed_due_to_card_unformatted;
}
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
int Card::GetNumFreeClusters( void )
{
if( m_mounted_drive_letter )
{
char p_drive[20];
strcpy(p_drive,"z:\\");
ULARGE_INTEGER uliFreeAvail;
ULARGE_INTEGER uliTotal;
p_drive[0] = m_mounted_drive_letter;
BOOL br = GetDiskFreeSpaceEx( p_drive, &uliFreeAvail, &uliTotal, NULL );
if( br )
{
// Each increment of HighPart represents 2^32 bytes, which is (2^32)/16384=262144 blocks.
return uliFreeAvail.HighPart*262144 + uliFreeAvail.LowPart/16384;
}
else
{
return 0;
}
}
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int Card::GetNumFreeEntries( const char* path )
{
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::Delete( const char* filename )
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::Rename( const char* old_name, const char* new_name )
{
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
File* Card::Open( const char* filename, int mode, int size )
{
Dbg_Assert( m_mounted_drive_letter != 0 );
m_last_error=0;
File* p_file = NULL;
HANDLE handle;
// Seems incoming filenames are of the form /foo/bar etc.
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
int index = 2;
while( cardFilenameBuffer[index] = *filename )
{
// Switch forward slash directory separators to the supported backslash.
if( cardFilenameBuffer[index] == '/' )
{
cardFilenameBuffer[index] = '\\';
}
++index;
++filename;
}
DWORD dwDesiredAccess;
DWORD dwCreationDisposition;
switch( mode )
{
case File::mMODE_READ:
{
dwDesiredAccess = GENERIC_READ;
dwCreationDisposition = OPEN_EXISTING;
break;
}
case File::mMODE_WRITE:
{
dwDesiredAccess = GENERIC_WRITE;
dwCreationDisposition = OPEN_EXISTING;
break;
}
case ( File::mMODE_WRITE | File::mMODE_CREATE ):
{
dwDesiredAccess = GENERIC_WRITE;
dwCreationDisposition = OPEN_ALWAYS;
break;
}
case File::mMODE_CREATE:
{
dwDesiredAccess = GENERIC_WRITE;
dwCreationDisposition = CREATE_NEW;
break;
}
case ( File::mMODE_READ | File::mMODE_WRITE ):
{
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
dwCreationDisposition = OPEN_EXISTING;
break;
}
default:
{
Dbg_Assert( 0 );
return NULL;
}
}
handle = CreateFile( cardFilenameBuffer, // file name
dwDesiredAccess, // access mode
0, // share mode
NULL, // security attributes
dwCreationDisposition, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes and flags
NULL ); // handle to template file
if( handle != INVALID_HANDLE_VALUE )
{
p_file = new File( (int)handle, this );
WIN32_FILE_ATTRIBUTE_DATA file_attribute_data;
if (GetFileAttributesEx(cardFilenameBuffer,GetFileExInfoStandard,&file_attribute_data))
{
// Skate3 code, disabled for now.
# if 0
p_file->m_file_time=file_attribute_data.ftLastWriteTime;
# endif
}
return p_file;
}
else
{
if (GetLastError()==ERROR_DISK_FULL)
{
m_last_error=vINSUFFICIENT_SPACE;
}
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool Card::GetFileList( const char* mask, Lst::Head< File > &file_list )
{
HANDLE handle;
XGAME_FIND_DATA find_data;
cardFilenameBuffer[0] = m_mounted_drive_letter;
cardFilenameBuffer[1] = ':';
cardFilenameBuffer[2] = '\\';
cardFilenameBuffer[3] = 0;
if(( handle = XFindFirstSaveGame( cardFilenameBuffer, &find_data )) == INVALID_HANDLE_VALUE )
{
return true;
}
do
{
File* new_file = new File( 0, this );
// Skip copying the drive stuff, just copy the directory, and strip the trailing '\'.
strcpy( new_file->m_Filename, (char*)&find_data.szSaveGameDirectory[3] );
new_file->m_Filename[strlen( new_file->m_Filename ) - 1] = 0;
wsprintfA( new_file->m_DisplayFilename, "%ls", find_data.szSaveGameName );
FILETIME local_file_time;
FileTimeToLocalFileTime(&find_data.wfd.ftLastWriteTime,&local_file_time);
SYSTEMTIME system_file_time;
FileTimeToSystemTime(&local_file_time,&system_file_time);
new_file->m_Modified.m_Year=system_file_time.wYear;
new_file->m_Modified.m_Month=system_file_time.wMonth;
new_file->m_Modified.m_Day=system_file_time.wDay;
new_file->m_Modified.m_Hour=system_file_time.wHour;
new_file->m_Modified.m_Minutes=system_file_time.wMinute;
new_file->m_Modified.m_Seconds=system_file_time.wSecond;
new_file->m_Size = find_data.wfd.nFileSizeLow;
new_file->m_Attribs = 0;
file_list.AddToTail( new_file );
}
while( XFindNextSaveGame( handle, &find_data ));
XFindClose( handle );
return true;
}
File::File( int fd, Card* card ) : Lst::Node< File > ( this ), m_fd( fd ), m_card( card )
{
}
File::~File()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int File::Seek( int offset, FilePointerBase base )
{
Dbg_Assert( m_fd != 0 );
DWORD dwMoveMethod;
switch( base )
{
case BASE_START:
dwMoveMethod = FILE_BEGIN;
break;
case BASE_CURRENT:
dwMoveMethod = FILE_CURRENT;
break;
case BASE_END:
dwMoveMethod = FILE_END;
break;
default:
dwMoveMethod = FILE_END;
Dbg_MsgAssert( 0,( "Invalid FilePointerBase\n" ));
break;
}
DWORD result = SetFilePointer( (HANDLE)m_fd, // handle to file
offset, // bytes to move pointer
NULL, // high-order bytes to move pointer
dwMoveMethod ); // starting point
return result;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool File::Flush( void )
{
Dbg_Assert( m_fd != 0 );
FlushFileBuffers((HANDLE)m_fd );
// The FlushFileBuffers() is pretty strict about what types of files wmay be flushed,
// whereas the PS2 equivalent doesn't really care. Just return a positive response always,
// no critical stuff predicated on this return anway.
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int File::Write( void* data, int len )
{
Dbg_Assert( m_fd != 0 );
// Skate3 code, disabled for now.
# if 0
m_not_enough_space_to_write_file=false;
# endif
DWORD bytes_written;
BOOL rv = WriteFile( (HANDLE)m_fd, // handle to file
data, // data buffer
len, // number of bytes to write
&bytes_written, // number of bytes written
NULL ); // overlapped buffer
// Skate3 code, disabled for now.
# if 0
if (rv==ERROR_NOT_ENOUGH_MEMORY)
{
m_not_enough_space_to_write_file=true;
}
if (GetLastError()==ERROR_DISK_FULL)
{
m_not_enough_space_to_write_file=true;
}
# endif
if( rv )
{
return (int)bytes_written;
}
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int File::Read( void* buff, int len )
{
Dbg_Assert( m_fd != 0 );
DWORD bytes_read;
BOOL rv = ReadFile( (HANDLE)m_fd, // handle to file
buff, // data buffer
len, // number of bytes to read
&bytes_read, // number of bytes read
NULL ); // overlapped buffer
if( rv )
{
return (int)bytes_read;
}
return 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool File::Close( void )
{
Dbg_Assert( m_fd != 0 );
return CloseHandle((HANDLE)m_fd );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
} // namespace Mc