diff --git a/pcsx2/gui/MemoryCardFolder.cpp b/pcsx2/gui/MemoryCardFolder.cpp index de815c6ea1..e0f147a5ea 100644 --- a/pcsx2/gui/MemoryCardFolder.cpp +++ b/pcsx2/gui/MemoryCardFolder.cpp @@ -39,6 +39,7 @@ void FolderMemoryCard::InitializeInternalData() { m_timeLastWritten = 0; m_isEnabled = false; m_framesUntilFlush = 0; + m_lastAccessedFile.Close(); } bool FolderMemoryCard::IsFormatted() { @@ -100,6 +101,8 @@ void FolderMemoryCard::Close() { if ( superBlockFile.IsOpened() ) { superBlockFile.Write( &m_superBlock.raw, sizeof( m_superBlock.raw ) ); } + + m_lastAccessedFile.Close(); } void FolderMemoryCard::LoadMemoryCardData( const bool enableFiltering, const wxString& filter ) { @@ -589,21 +592,21 @@ bool FolderMemoryCard::ReadFromFile( u8 *dest, u32 adr, u32 dataLength ) { if ( !fileName.DirExists() ) { fileName.Mkdir(); } - wxFFile file( fileName.GetFullPath(), L"rb" ); - if ( file.IsOpened() ) { + wxFFile* file = m_lastAccessedFile.ReOpen( fileName.GetFullPath(), L"rb" ); + if ( file->IsOpened() ) { const u32 clusterOffset = ( page % 2 ) * PageSize + offset; const u32 fileOffset = clusterNumber * ClusterSize + clusterOffset; - file.Seek( fileOffset ); - size_t bytesRead = file.Read( dest, dataLength ); + if ( fileOffset != file->Tell() ) { + file->Seek( fileOffset ); + } + size_t bytesRead = file->Read( dest, dataLength ); // if more bytes were requested than actually exist, fill the rest with 0xFF if ( bytesRead < dataLength ) { memset( &dest[bytesRead], 0xFF, dataLength - bytesRead ); } - file.Close(); - return bytesRead > 0; } } @@ -666,6 +669,8 @@ s32 FolderMemoryCard::Read( u8 *dest, u32 adr, int size ) { memcpy( dest + eccOffset, ecc, eccLength ); } + SetTimeLastReadToNow(); + // return 0 on fail, 1 on success? return 1; } @@ -712,11 +717,15 @@ s32 FolderMemoryCard::Save( const u8 *src, u32 adr, int size ) { void FolderMemoryCard::NextFrame() { if ( m_framesUntilFlush > 0 && --m_framesUntilFlush == 0 ) { Flush(); + m_lastAccessedFile.Close(); } } void FolderMemoryCard::Flush() { - Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system.", m_slot ); + if ( m_cache.empty() ) { return; } + + Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system...", m_slot ); + const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue(); // first write the superblock if necessary Flush( 0 ); @@ -762,6 +771,10 @@ void FolderMemoryCard::Flush() { Flush( i ); } + m_lastAccessedFile.Close(); + + const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue(); + Console.WriteLn( L"(FolderMcd) Done! Took %u ms.", timeFlushEnd - timeFlushStart ); } void FolderMemoryCard::Flush( const u32 page ) { @@ -873,29 +886,31 @@ bool FolderMemoryCard::WriteToFile( const u8* src, u32 adr, u32 dataLength ) { wxFFile createEmptyFile( fileName.GetFullPath(), L"wb" ); createEmptyFile.Close(); } - wxFFile file( fileName.GetFullPath(), L"r+b" ); - if ( file.IsOpened() ) { + wxFFile* file = m_lastAccessedFile.ReOpen( fileName.GetFullPath(), L"r+b" ); + if ( file->IsOpened() ) { const u32 clusterOffset = ( page % 2 ) * PageSize + offset; const u32 fileSize = entry->entry.data.length; const u32 fileOffsetStart = std::min( clusterNumber * ClusterSize + clusterOffset, fileSize );; const u32 fileOffsetEnd = std::min( fileOffsetStart + dataLength, fileSize ); const u32 bytesToWrite = fileOffsetEnd - fileOffsetStart; - wxFileOffset actualFileSize = file.Length(); + wxFileOffset actualFileSize = file->Length(); if ( actualFileSize < fileOffsetStart ) { + file->Seek( actualFileSize ); const u32 diff = fileOffsetStart - actualFileSize; u8 temp = 0xFF; for ( u32 i = 0; i < diff; ++i ) { - file.Write( &temp, 1 ); + file->Write( &temp, 1 ); } } - file.Seek( fileOffsetStart ); - if ( bytesToWrite > 0 ) { - file.Write( src, bytesToWrite ); + const wxFileOffset fileOffset = file->Tell(); + if ( fileOffset != fileOffsetStart ) { + file->Seek( fileOffsetStart ); + } + if ( bytesToWrite > 0 ) { + file->Write( src, bytesToWrite ); } - - file.Close(); } else { return false; } @@ -980,6 +995,10 @@ void FolderMemoryCard::SetSizeInMB( u32 megaBytes ) { SetSizeInClusters( ( megaBytes * 1024 * 1024 ) / ClusterSize ); } +void FolderMemoryCard::SetTimeLastReadToNow() { + m_framesUntilFlush = FramesAfterWriteUntilFlush; +} + void FolderMemoryCard::SetTimeLastWrittenToNow() { m_timeLastWritten = wxGetLocalTimeMillis().GetValue(); m_framesUntilFlush = FramesAfterWriteUntilFlush; @@ -1031,6 +1050,40 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) { return; } + +FileAccessHelper::FileAccessHelper() { + m_file = nullptr; +} + +FileAccessHelper::~FileAccessHelper() { + this->Close(); +} + +wxFFile* FileAccessHelper::Open( const wxString& filename, const wxString& mode ) { + this->Close(); + m_file = new wxFFile( filename, mode ); + m_filename = filename; + m_mode = mode; + return m_file; +} + +wxFFile* FileAccessHelper::ReOpen( const wxString& filename, const wxString& mode ) { + if ( m_file && mode == m_mode && filename == m_filename ) { + return m_file; + } else { + return this->Open( filename, mode ); + } +} + +void FileAccessHelper::Close() { + if ( m_file ) { + m_file->Close(); + delete m_file; + m_file = nullptr; + } +} + + FolderMemoryCardAggregator::FolderMemoryCardAggregator() { for ( uint i = 0; i < TotalCardSlots; ++i ) { m_cards[i].SetSlot( i ); diff --git a/pcsx2/gui/MemoryCardFolder.h b/pcsx2/gui/MemoryCardFolder.h index a9c42df13a..adea2547d9 100644 --- a/pcsx2/gui/MemoryCardFolder.h +++ b/pcsx2/gui/MemoryCardFolder.h @@ -131,6 +131,30 @@ struct MemoryCardPage { }; #pragma pack(pop) +// -------------------------------------------------------------------------------------- +// FileAccessHelper +// -------------------------------------------------------------------------------------- +// Small helper class to keep memory card files opened between calls to Read()/Save() +class FileAccessHelper { +protected: + wxFFile* m_file; + wxString m_filename; + wxString m_mode; + +public: + FileAccessHelper(); + ~FileAccessHelper(); + + // Get an already opened file if possible, or open a new one and remember it + wxFFile* ReOpen( const wxString& filename, const wxString& mode ); + // Close an open file, if any + void Close(); + +protected: + // Open a new file and remember it for later + wxFFile* Open( const wxString& filename, const wxString& mode ); +}; + // -------------------------------------------------------------------------------------- // FolderMemoryCard // -------------------------------------------------------------------------------------- @@ -180,6 +204,9 @@ protected: // used to figure out if contents were changed for savestate-related purposes, see GetCRC() u64 m_timeLastWritten; + // remembers and keeps the last accessed file open for further access + FileAccessHelper m_lastAccessedFile; + // path to the folder that contains the files of this memory card wxFileName m_folderName; @@ -316,6 +343,7 @@ protected: // write data as Save() normally would, but ignore the cache; used for flushing s32 WriteWithoutCache( const u8 *src, u32 adr, int size ); + void SetTimeLastReadToNow(); void SetTimeLastWrittenToNow();