2024-07-30 11:42:36 +00:00
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
2022-08-28 21:31:19 +00:00
# include "MemoryCardConvertDialog.h"
# include <QtWidgets/QMessageBox>
# include <QtWidgets/QPushButton>
# include <QtWidgets/QProgressDialog>
2023-12-22 11:17:46 +00:00
# include "common/Console.h"
2022-08-28 21:31:19 +00:00
# include "common/Path.h"
# include "common/StringUtil.h"
2024-09-17 01:21:27 +00:00
# include <unistd.h>
2022-08-28 21:31:19 +00:00
MemoryCardConvertDialog : : MemoryCardConvertDialog ( QWidget * parent , QString selectedCard )
: QDialog ( parent )
{
m_ui . setupUi ( this ) ;
2023-06-30 12:38:07 +00:00
// For some reason, setting these in the .ui doesn't work..
m_ui . conversionTypeDescription - > setFrameStyle ( QFrame : : Sunken ) ;
m_ui . conversionTypeDescription - > setFrameShape ( QFrame : : WinPanel ) ;
m_ui . note - > setFrameStyle ( QFrame : : Sunken ) ;
m_ui . note - > setFrameShape ( QFrame : : WinPanel ) ;
2022-08-28 21:31:19 +00:00
m_selectedCard = selectedCard ;
std : : optional < AvailableMcdInfo > srcCardInfo = FileMcd_GetCardInfo ( m_selectedCard . toStdString ( ) ) ;
if ( srcCardInfo . has_value ( ) )
{
m_srcCardInfo = srcCardInfo . value ( ) ;
}
isSetup = SetupPicklist ( ) ;
setWindowFlags ( windowFlags ( ) & ~ Qt : : WindowContextHelpButtonHint ) ;
m_ui . progressBar - > setRange ( 0 , 100 ) ;
m_ui . progressBar - > setValue ( 0 ) ;
connect ( m_ui . conversionTypeSelect , & QComboBox : : currentIndexChanged , this , [ this ] ( )
{
switch ( m_srcCardInfo . type )
{
case MemoryCardType : : File :
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : Folder , MemoryCardFileType : : Unknown , tr ( " Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
case MemoryCardType : : Folder :
switch ( m_ui . conversionTypeSelect - > currentData ( ) . toInt ( ) )
{
case 8 :
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_8MB , tr ( " A standard, 8 MB Memory Card. Most compatible, but smallest capacity. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
case 16 :
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_16MB , tr ( " 2x larger than a standard Memory Card. May have some compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
case 32 :
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_32MB , tr ( " 4x larger than a standard Memory Card. Likely to have compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
case 64 :
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_64MB , tr ( " 8x larger than a standard Memory Card. Likely to have compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
default :
2023-03-18 21:14:55 +00:00
//: MemoryCardType should be left as-is.
2022-08-28 21:31:19 +00:00
QMessageBox : : critical ( this , tr ( " Convert Memory Card Failed " ) , tr ( " Invalid MemoryCardType " ) ) ;
return ;
}
break ;
default :
2023-03-18 21:14:55 +00:00
//: MemoryCardType should be left as-is.
2022-08-28 21:31:19 +00:00
QMessageBox : : critical ( this , tr ( " Convert Memory Card Failed " ) , tr ( " Invalid MemoryCardType " ) ) ;
return ;
}
}
) ;
disconnect ( m_ui . buttonBox , & QDialogButtonBox : : accepted , this , nullptr ) ;
connect ( m_ui . buttonBox - > button ( QDialogButtonBox : : Ok ) , & QPushButton : : clicked , this , & MemoryCardConvertDialog : : ConvertCard ) ;
connect ( m_ui . buttonBox - > button ( QDialogButtonBox : : Cancel ) , & QPushButton : : clicked , this , & MemoryCardConvertDialog : : close ) ;
}
MemoryCardConvertDialog : : ~ MemoryCardConvertDialog ( ) = default ;
bool MemoryCardConvertDialog : : IsSetup ( )
{
return isSetup ;
}
void MemoryCardConvertDialog : : onStatusUpdated ( )
{
}
void MemoryCardConvertDialog : : onProgressUpdated ( int value , int range )
{
m_ui . progressBar - > setRange ( 0 , range ) ;
m_ui . progressBar - > setValue ( value ) ;
}
void MemoryCardConvertDialog : : onThreadFinished ( )
{
2023-03-13 00:34:20 +00:00
QMessageBox : : information ( this , tr ( " Conversion Complete " ) , tr ( " Memory Card \" %1 \" converted to \" %2 \" " ) . arg ( m_selectedCard ) . arg ( m_destCardName ) ) ;
2022-08-28 21:31:19 +00:00
accept ( ) ;
}
void MemoryCardConvertDialog : : StartThread ( )
{
m_thread = std : : make_unique < MemoryCardConvertWorker > ( this , m_srcCardInfo . type , m_fileType , m_selectedCard . toStdString ( ) , m_destCardName . toStdString ( ) ) ;
connect ( m_thread . get ( ) , & MemoryCardConvertWorker : : statusUpdated , this , & MemoryCardConvertDialog : : onStatusUpdated ) ;
connect ( m_thread . get ( ) , & MemoryCardConvertWorker : : progressUpdated , this , & MemoryCardConvertDialog : : onProgressUpdated ) ;
connect ( m_thread . get ( ) , & MemoryCardConvertWorker : : threadFinished , this , & MemoryCardConvertDialog : : onThreadFinished ) ;
m_thread - > start ( ) ;
UpdateEnabled ( ) ;
}
void MemoryCardConvertDialog : : CancelThread ( )
{
if ( ! m_thread )
{
return ;
}
m_thread - > requestInterruption ( ) ;
m_thread - > join ( ) ;
m_thread . reset ( ) ;
}
void MemoryCardConvertDialog : : UpdateEnabled ( )
{
if ( m_thread )
{
m_ui . buttonBox - > button ( QDialogButtonBox : : Ok ) - > setEnabled ( false ) ;
m_ui . buttonBox - > button ( QDialogButtonBox : : Cancel ) - > setEnabled ( false ) ;
}
}
bool MemoryCardConvertDialog : : SetupPicklist ( )
{
FileSystem : : FindResultsArray rootDir ;
size_t sizeBytes = 0 ;
bool typeSet = false ;
m_ui . conversionTypeSelect - > clear ( ) ;
switch ( m_srcCardInfo . type )
{
case MemoryCardType : : File :
m_ui . conversionTypeSelect - > addItems ( { " Folder " } ) ;
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : Folder , MemoryCardFileType : : Unknown , tr ( " Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card. " ) ) ;
2022-08-28 21:31:19 +00:00
break ;
case MemoryCardType : : Folder :
// Compute which file types should be allowed.
FileSystem : : FindFiles ( m_srcCardInfo . path . c_str ( ) , " * " , FLAGS , & rootDir ) ;
for ( auto dirEntry : rootDir )
{
const std : : string_view fileName = Path : : GetFileName ( dirEntry . FileName ) ;
if ( fileName . size ( ) > = 7 & & fileName . substr ( 0 , 7 ) . compare ( " _pcsx2_ " ) = = 0 )
{
continue ;
}
else if ( dirEntry . Attributes & FILESYSTEM_FILE_ATTRIBUTE_DIRECTORY )
{
sizeBytes + = 512 ;
}
else
{
size_t toAdd = static_cast < size_t > ( dirEntry . Size + ( 1024 - ( dirEntry . Size % 1024 ) ) ) ;
sizeBytes + = toAdd + 512 ; // The file content needs to be added, PLUS a directory entry
}
}
// Finally, round up to the nearest erase block.
sizeBytes + = ( 512 * 16 ) - ( sizeBytes % ( 512 * 16 ) ) ;
if ( sizeBytes < CardCapacity : : _8_MB )
{
2023-06-30 12:38:07 +00:00
m_ui . conversionTypeSelect - > addItem ( tr ( " 8 MB File " ) , 8 ) ;
2022-08-28 21:31:19 +00:00
if ( ! typeSet )
{
SetType_8 ( ) ;
typeSet = true ;
}
}
if ( sizeBytes < CardCapacity : : _16_MB )
{
2023-06-30 12:38:07 +00:00
m_ui . conversionTypeSelect - > addItem ( tr ( " 16 MB File " ) , 16 ) ;
2022-08-28 21:31:19 +00:00
if ( ! typeSet )
{
SetType_16 ( ) ;
typeSet = true ;
}
}
if ( sizeBytes < CardCapacity : : _32_MB )
{
2023-06-30 12:38:07 +00:00
m_ui . conversionTypeSelect - > addItem ( tr ( " 32 MB File " ) , 32 ) ;
2022-08-28 21:31:19 +00:00
if ( ! typeSet )
{
SetType_32 ( ) ;
typeSet = true ;
}
}
if ( sizeBytes < CardCapacity : : _64_MB )
{
2023-06-30 12:38:07 +00:00
m_ui . conversionTypeSelect - > addItem ( tr ( " 64 MB File " ) , 64 ) ;
2022-08-28 21:31:19 +00:00
if ( ! typeSet )
{
SetType_64 ( ) ;
typeSet = true ;
}
}
if ( ! typeSet )
{
2023-03-13 00:34:20 +00:00
QMessageBox : : critical ( this , tr ( " Cannot Convert Memory Card " ) , tr ( " Your folder Memory Card has too much data inside it to be converted to a file Memory Card. The largest supported file Memory Card has a capacity of 64 MB. To convert your folder Memory Card, you must remove game folders until its size is 64 MB or less. " ) ) ;
2022-08-28 21:31:19 +00:00
return false ;
}
break ;
default :
2023-03-18 21:14:55 +00:00
//: MemoryCardType should be left as-is.
2022-08-28 21:31:19 +00:00
QMessageBox : : critical ( this , tr ( " Convert Memory Card Failed " ) , tr ( " Invalid MemoryCardType " ) ) ;
return false ;
}
return true ;
}
void MemoryCardConvertDialog : : ConvertCard ( )
{
if ( m_thread )
{
CancelThread ( ) ;
}
else
{
QString baseName = m_selectedCard ;
// Get our destination file name
size_t extensionPos = baseName . lastIndexOf ( " .ps2 " , - 1 ) ;
// Strip the extension off of it
baseName . replace ( extensionPos , 4 , " " ) ;
// Add _converted to the end of it
baseName . append ( " _converted " ) ;
size_t num = 0 ;
QString destName = baseName ;
destName . append ( " .ps2 " ) ;
2024-09-17 01:21:27 +00:00
QString fullPath = Path : : Combine ( EmuFolders : : MemoryCards , destName . toStdString ( ) ) . c_str ( ) ;
QDir destinationDir ( fullPath ) ;
QString absolutePath = destinationDir . absolutePath ( ) ; // Get the absolute path
if ( access ( absolutePath . toStdString ( ) . c_str ( ) , R_OK | W_OK | X_OK ) ! = 0 )
{
QMessageBox : : critical ( this , tr ( " Cannot Convert Memory Card " ) ,
2024-09-17 10:51:00 +00:00
tr ( " You have insufficient permissions to convert this Memory Card. Please ensure that your user owns the directory of your Memory Cards. \n \" %1 \" . " )
2024-09-17 01:21:27 +00:00
. arg ( absolutePath ) ) ;
return ;
}
2022-08-28 21:31:19 +00:00
// If a match is found, revert back to the base name, add a number and the extension, and try again.
// Keep incrementing the number until we get a unique result.
while ( m_srcCardInfo . type = = MemoryCardType : : File ? FileSystem : : DirectoryExists ( Path : : Combine ( EmuFolders : : MemoryCards , destName . toStdString ( ) ) . c_str ( ) ) : FileSystem : : FileExists ( Path : : Combine ( EmuFolders : : MemoryCards , destName . toStdString ( ) ) . c_str ( ) ) )
{
destName = baseName ;
2024-01-06 05:40:43 +00:00
destName . append ( StringUtil : : StdStringFromFormat ( " _%02zd.ps2 " , + + num ) . c_str ( ) ) ;
2022-08-28 21:31:19 +00:00
}
m_destCardName = destName ;
StartThread ( ) ;
}
}
void MemoryCardConvertDialog : : ConvertCallback ( )
{
Console . WriteLn ( " %s() Finished " , __FUNCTION__ ) ;
}
void MemoryCardConvertDialog : : SetType ( MemoryCardType type , MemoryCardFileType fileType , const QString & description )
{
m_type = type ;
m_fileType = fileType ;
2023-06-30 12:38:07 +00:00
m_ui . conversionTypeDescription - > setText ( QStringLiteral ( " <center>%1</center> " ) . arg ( description ) ) ;
2022-08-28 21:31:19 +00:00
}
void MemoryCardConvertDialog : : SetType_8 ( )
{
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_8MB , tr ( " A standard, 8 MB Memory Card. Most compatible, but smallest capacity. " ) ) ;
2022-08-28 21:31:19 +00:00
}
void MemoryCardConvertDialog : : SetType_16 ( )
{
2023-09-30 10:58:25 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_16MB , tr ( " 2x larger than a standard Memory Card. May have some compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
}
void MemoryCardConvertDialog : : SetType_32 ( )
{
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_32MB , tr ( " 4x larger than a standard Memory Card. Likely to have compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
}
void MemoryCardConvertDialog : : SetType_64 ( )
{
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : File , MemoryCardFileType : : PS2_64MB , tr ( " 8x larger than a standard Memory Card. Likely to have compatibility issues. " ) ) ;
2022-08-28 21:31:19 +00:00
}
void MemoryCardConvertDialog : : SetType_Folder ( )
{
2023-06-30 12:38:07 +00:00
SetType ( MemoryCardType : : Folder , MemoryCardFileType : : Unknown , tr ( " Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card. " ) ) ;
2022-08-28 21:31:19 +00:00
}