diff --git a/pcsx2/gui/MemoryCardFile.cpp b/pcsx2/gui/MemoryCardFile.cpp index bafcf95db5..5463334cce 100644 --- a/pcsx2/gui/MemoryCardFile.cpp +++ b/pcsx2/gui/MemoryCardFile.cpp @@ -75,8 +75,6 @@ public: s32 EraseBlock ( uint slot, u32 adr ); u64 GetCRC ( uint slot ); - void NextFrame( uint slot ); - protected: bool Seek( wxFFile& f, u32 adr ); bool Create( const wxString& mcdFile, uint sizeInMB ); @@ -408,11 +406,6 @@ u64 FileMemoryCard::GetCRC( uint slot ) return retval; } -void FileMemoryCard::NextFrame( uint slot ) -{ - -} - // -------------------------------------------------------------------------------------- // MemoryCard Component API Bindings // -------------------------------------------------------------------------------------- @@ -542,9 +535,9 @@ static u64 PS2E_CALLBACK FileMcd_GetCRC( PS2E_THISPTR thisptr, uint port, uint s static void PS2E_CALLBACK FileMcd_NextFrame( PS2E_THISPTR thisptr, uint port, uint slot ) { const uint combinedSlot = FileMcd_ConvertToSlot( port, slot ); switch ( g_Conf->Mcd[combinedSlot].Type ) { - case MemoryCardType::MemoryCard_File: - thisptr->impl.NextFrame( combinedSlot ); - break; + //case MemoryCardType::MemoryCard_File: + // thisptr->impl.NextFrame( combinedSlot ); + // break; case MemoryCardType::MemoryCard_Folder: thisptr->implFolder.NextFrame( combinedSlot ); break; diff --git a/pcsx2/gui/MemoryCardFolder.cpp b/pcsx2/gui/MemoryCardFolder.cpp index b20c7d14fc..cc3824fe11 100644 --- a/pcsx2/gui/MemoryCardFolder.cpp +++ b/pcsx2/gui/MemoryCardFolder.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team + * Copyright (C) 2002-2015 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -47,14 +47,18 @@ bool FolderMemoryCard::IsFormatted() { } void FolderMemoryCard::Open( const bool enableFiltering, const wxString& filter ) { + Open( g_Conf->FullpathToMcd( m_slot ), g_Conf->Mcd[m_slot], enableFiltering, filter ); +} + +void FolderMemoryCard::Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const bool enableFiltering, const wxString& filter ) { InitializeInternalData(); - wxFileName configuredFileName( g_Conf->FullpathToMcd( m_slot ) ); - folderName = wxFileName( configuredFileName.GetFullPath() + L"/" ); + wxFileName configuredFileName( fullPath ); + m_folderName = wxFileName( configuredFileName.GetFullPath() + L"/" ); wxString str( configuredFileName.GetFullPath() ); bool disabled = false; - if ( g_Conf->Mcd[m_slot].Enabled && g_Conf->Mcd[m_slot].Type == MemoryCardType::MemoryCard_Folder ) { + if ( mcdOptions.Enabled && mcdOptions.Type == MemoryCardType::MemoryCard_Folder ) { if ( configuredFileName.GetFullName().IsEmpty() ) { str = L"[empty filename]"; disabled = true; @@ -65,8 +69,8 @@ void FolderMemoryCard::Open( const bool enableFiltering, const wxString& filter } // if nothing exists at a valid location, create a directory for the memory card - if ( !disabled && !folderName.DirExists() ) { - if ( !folderName.Mkdir() ) { + if ( !disabled && !m_folderName.DirExists() ) { + if ( !m_folderName.Mkdir() ) { str = L"[couldn't create folder]"; disabled = true; } @@ -91,7 +95,7 @@ void FolderMemoryCard::Close() { Flush(); - wxFileName superBlockFileName( folderName.GetPath(), L"_pcsx2_superblock" ); + wxFileName superBlockFileName( m_folderName.GetPath(), L"_pcsx2_superblock" ); wxFFile superBlockFile( superBlockFileName.GetFullPath().c_str(), L"wb" ); if ( superBlockFile.IsOpened() ) { superBlockFile.Write( &m_superBlock.raw, sizeof( m_superBlock.raw ) ); @@ -102,7 +106,7 @@ void FolderMemoryCard::LoadMemoryCardData( const bool enableFiltering, const wxS bool formatted = false; // read superblock if it exists - wxFileName superBlockFileName( folderName.GetPath(), L"_pcsx2_superblock" ); + wxFileName superBlockFileName( m_folderName.GetPath(), L"_pcsx2_superblock" ); if ( superBlockFileName.FileExists() ) { wxFFile superBlockFile( superBlockFileName.GetFullPath().c_str(), L"rb" ); if ( superBlockFile.IsOpened() && superBlockFile.Read( &m_superBlock.raw, sizeof( m_superBlock.raw ) ) >= sizeof( m_superBlock.data ) ) { @@ -121,7 +125,7 @@ void FolderMemoryCard::LoadMemoryCardData( const bool enableFiltering, const wxS CreateFat(); CreateRootDir(); MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0]; - AddFolder( rootDirEntry, folderName.GetPath(), enableFiltering, filter ); + AddFolder( rootDirEntry, m_folderName.GetPath(), enableFiltering, filter ); } } @@ -224,29 +228,6 @@ u32 FolderMemoryCard::GetLastClusterOfData( const u32 cluster ) { return entryCluster; } -u64 FolderMemoryCard::ConvertToMemoryCardTimestamp( const wxDateTime& time ) { - if ( !time.IsValid() ) { - return 0; - } - - union { - MemoryCardFileEntryDateTime data; - u64 value; - } t; - - wxDateTime::Tm tm = time.GetTm( wxDateTime::GMT9 ); - - t.data.unused = 0; - t.data.second = tm.sec; - t.data.minute = tm.min; - t.data.hour = tm.hour; - t.data.day = tm.mday; - t.data.month = tm.mon + 1; - t.data.year = tm.year; - - return t.value; -} - MemoryCardFileEntry* FolderMemoryCard::AppendFileEntryToDir( MemoryCardFileEntry* const dirEntry ) { u32 entryCluster = GetLastClusterOfData( dirEntry->entry.data.cluster ); @@ -358,8 +339,8 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS metaFile.Close(); } else { newDirEntry->entry.data.mode = MemoryCardFileEntry::DefaultDirMode; - newDirEntry->entry.data.timeCreated.value = ConvertToMemoryCardTimestamp( creationTime ); - newDirEntry->entry.data.timeModified.value = ConvertToMemoryCardTimestamp( modificationTime ); + newDirEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromWxDateTime( creationTime ); + newDirEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromWxDateTime( modificationTime ); } newDirEntry->entry.data.length = 2; @@ -398,7 +379,7 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS bool FolderMemoryCard::AddFile( MemoryCardFileEntry* const dirEntry, const wxString& dirPath, const wxString& fileName ) { wxFileName relativeFilePath( dirPath, fileName ); - relativeFilePath.MakeRelativeTo( folderName.GetPath() ); + relativeFilePath.MakeRelativeTo( m_folderName.GetPath() ); Console.WriteLn( L"(FolderMcd) Adding file: %s", WX_STR( relativeFilePath.GetFullPath() ) ); wxFileName fileInfo( dirPath, fileName ); @@ -430,8 +411,8 @@ bool FolderMemoryCard::AddFile( MemoryCardFileEntry* const dirEntry, const wxStr metaFile.Close(); } else { newFileEntry->entry.data.mode = MemoryCardFileEntry::DefaultFileMode; - newFileEntry->entry.data.timeCreated.value = ConvertToMemoryCardTimestamp( creationTime ); - newFileEntry->entry.data.timeModified.value = ConvertToMemoryCardTimestamp( modificationTime ); + newFileEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromWxDateTime( creationTime ); + newFileEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromWxDateTime( modificationTime ); } newFileEntry->entry.data.length = filesize; @@ -601,7 +582,7 @@ bool FolderMemoryCard::ReadFromFile( u8 *dest, u32 adr, u32 dataLength ) { const u32 fatCluster = cluster - m_superBlock.data.alloc_offset; // figure out which file to read from - wxFileName fileName( folderName ); + wxFileName fileName( m_folderName ); u32 clusterNumber; const MemoryCardFileEntry* const entry = GetFileEntryFromFileDataCluster( m_superBlock.data.rootdir_cluster, fatCluster, &fileName, fileName.GetDirCount(), &clusterNumber ); if ( entry != nullptr ) { @@ -768,6 +749,7 @@ void FolderMemoryCard::Flush() { const u32 rootDirCluster = m_superBlock.data.rootdir_cluster; const u32 rootDirPage = ( rootDirCluster + m_superBlock.data.alloc_offset ) * 2; Flush( rootDirPage ); + Flush( rootDirPage + 1 ); MemoryCardFileEntryCluster* rootEntries = &m_fileEntryDict[rootDirCluster]; if ( rootEntries->entries[0].IsValid() && rootEntries->entries[0].IsUsed() ) { FlushFileEntries( rootDirCluster, rootEntries->entries[0].entry.data.length ); @@ -807,7 +789,7 @@ void FolderMemoryCard::FlushFileEntries( const u32 dirCluster, const u32 remaini const wxString subDirPath = dirPath + L"/" + subDirName; // if this directory has nonstandard metadata, write that to the file system - wxFileName metaFileName( folderName.GetFullPath() + subDirPath + L"/_pcsx2_meta_directory" ); + wxFileName metaFileName( m_folderName.GetFullPath() + subDirPath + L"/_pcsx2_meta_directory" ); if ( entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0 ) { if ( !metaFileName.DirExists() ) { metaFileName.Mkdir(); @@ -879,7 +861,7 @@ bool FolderMemoryCard::WriteToFile( const u8* src, u32 adr, u32 dataLength ) { const u32 fatCluster = cluster - m_superBlock.data.alloc_offset; // figure out which file to write to - wxFileName fileName( folderName ); + wxFileName fileName( m_folderName ); u32 clusterNumber; const MemoryCardFileEntry* const entry = GetFileEntryFromFileDataCluster( m_superBlock.data.rootdir_cluster, fatCluster, &fileName, fileName.GetDirCount(), &clusterNumber ); if ( entry != nullptr ) { @@ -1024,19 +1006,19 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) { } FolderMemoryCardAggregator::FolderMemoryCardAggregator() { - for ( uint i = 0; i < totalCardSlots; ++i ) { + for ( uint i = 0; i < TotalCardSlots; ++i ) { m_cards[i].SetSlot( i ); } } void FolderMemoryCardAggregator::Open() { - for ( int i = 0; i < totalCardSlots; ++i ) { + for ( int i = 0; i < TotalCardSlots; ++i ) { m_cards[i].Open( m_enableFiltering, m_lastKnownFilter ); } } void FolderMemoryCardAggregator::Close() { - for ( int i = 0; i < totalCardSlots; ++i ) { + for ( int i = 0; i < TotalCardSlots; ++i ) { m_cards[i].Close(); } } diff --git a/pcsx2/gui/MemoryCardFolder.h b/pcsx2/gui/MemoryCardFolder.h index 94ea5e8c0f..9d4a9b881d 100644 --- a/pcsx2/gui/MemoryCardFolder.h +++ b/pcsx2/gui/MemoryCardFolder.h @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 PCSX2 Dev Team + * Copyright (C) 2002-2015 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -17,11 +17,11 @@ #include #include -#include #include #include #include "PluginCallbacks.h" +#include "AppConfig.h" // -------------------------------------------------------------------------------------- // Superblock Header Struct @@ -57,6 +57,32 @@ struct MemoryCardFileEntryDateTime { u8 day; u8 month; u16 year; + + static MemoryCardFileEntryDateTime FromWxDateTime( const wxDateTime& time ) { + MemoryCardFileEntryDateTime t; + + if ( time.IsValid() ) { + wxDateTime::Tm tm = time.GetTm( wxDateTime::GMT9 ); + + t.unused = 0; + t.second = tm.sec; + t.minute = tm.min; + t.hour = tm.hour; + t.day = tm.mday; + t.month = tm.mon + 1; + t.year = tm.year; + } else { + t.unused = 0; + t.second = 0; + t.minute = 0; + t.hour = 0; + t.day = 0; + t.month = 0; + t.year = 0; + } + + return t; + } }; #pragma pack(pop) @@ -70,18 +96,10 @@ struct MemoryCardFileEntry { struct MemoryCardFileEntryData { u32 mode; u32 length; // number of bytes for file, number of files for dir - union { - MemoryCardFileEntryDateTime data; - u64 value; - u8 raw[8]; - } timeCreated; + MemoryCardFileEntryDateTime timeCreated; u32 cluster; // cluster the start of referred file or folder can be found in u32 dirEntry; // parent directory entry number, only used if "." entry of subdir - union { - MemoryCardFileEntryDateTime data; - u64 value; - u8 raw[8]; - } timeModified; + MemoryCardFileEntryDateTime timeModified; u32 attr; u8 padding[0x1C]; u8 name[0x20]; @@ -118,9 +136,7 @@ struct MemoryCardPage { // -------------------------------------------------------------------------------------- // Fakes a memory card using a regular folder/file structure in the host file system class FolderMemoryCard { -protected: - wxFileName folderName; - +public: // a few constants so we could in theory change the memory card size without too much effort static const int IndirectFatClusterCount = 1; // should be 32 but only 1 is ever used static const int PageSize = MemoryCardPage::PageSize; @@ -133,9 +149,11 @@ protected: static const int TotalPages = 0x4000; static const int TotalClusters = TotalPages / 2; static const int TotalBlocks = TotalClusters / 8; + static const int TotalSizeRaw = TotalPages * PageSizeRaw; static const int FramesAfterWriteUntilFlush = 60; +protected: union superBlockUnion { superblock data; u8 raw[BlockSize]; @@ -151,15 +169,24 @@ protected: u8 m_backupBlock1[BlockSize]; u8 m_backupBlock2[BlockSize]; + // stores directory and file metadata std::map m_fileEntryDict; - // holds a copy of modified areas of the memory card, in page-sized chunks + // holds a copy of modified pages of the memory card before they're flushed to the file system std::map m_cache; - - uint m_slot; - bool m_isEnabled; - u64 m_timeLastWritten; + // if > 0, the amount of frames until data is flushed to the file system + // reset to FramesAfterWriteUntilFlush on each write int m_framesUntilFlush; + // used to figure out if contents were changed for savestate-related purposes, see GetCRC() + u64 m_timeLastWritten; + + // path to the folder that contains the files of this memory card + wxFileName m_folderName; + + // PS2 memory card slot this card is inserted into + uint m_slot; + + bool m_isEnabled; public: FolderMemoryCard(); @@ -168,7 +195,10 @@ public: void Lock(); void Unlock(); + // Initialize & Load Memory Card with values configured in the Memory Card Manager void Open( const bool enableFiltering, const wxString& filter ); + // Initialize & Load Memory Card with provided custom values + void Open( const wxString& fullPath, const AppConfig::McdOptions& mcdOptions, const bool enableFiltering, const wxString& filter ); void Close(); s32 IsPresent(); @@ -219,8 +249,8 @@ protected: // loads files and folders from the host file system if a superblock exists in the root directory - // if enableFiltering is set to true, only folders whose name contain the filter string are loaded - // filter string can include multiple filters by separating them with "/" + // - enableFiltering: if set to true, only folders whose name contain the filter string are loaded + // - filter: can include multiple filters by separating them with "/" void LoadMemoryCardData( const bool enableFiltering, const wxString& filter ); // creates the FAT and indirect FAT @@ -244,8 +274,6 @@ protected: // returns the final cluster of the file or directory which is (partially) stored in the given cluster u32 GetLastClusterOfData( const u32 cluster ); - u64 ConvertToMemoryCardTimestamp( const wxDateTime& time ); - // creates and returns a new file entry in the given directory entry, ready to be filled // returns nullptr when the memory card is full @@ -282,6 +310,7 @@ protected: void SetTimeLastWrittenToNow(); + wxString GetDisabledMessage( uint slot ) const { return wxsFormat( pxE( L"The PS2-slot %d has been automatically disabled. You can correct the problem\nand re-enable it at any time using Config:Memory cards from the main menu." ), slot//TODO: translate internal slot index to human-readable slot description @@ -298,8 +327,11 @@ protected: // Forwards the API's requests for specific memory card slots to the correct FolderMemoryCard. class FolderMemoryCardAggregator { protected: - static const int totalCardSlots = 8; - FolderMemoryCard m_cards[totalCardSlots]; + static const int TotalCardSlots = 8; + FolderMemoryCard m_cards[TotalCardSlots]; + + // stores the specifics of the current filtering settings, so they can be + // re-applied automatically when memory cards are reloaded bool m_enableFiltering = true; wxString m_lastKnownFilter = L"";