mirror of https://github.com/PCSX2/pcsx2.git
Folder memcards: Write metadata for directories
This commit is contained in:
parent
a6cec6a04e
commit
f8f783737d
|
@ -345,9 +345,8 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS
|
||||||
for ( const auto& file : GetOrderedFiles( dirPath ) ) {
|
for ( const auto& file : GetOrderedFiles( dirPath ) ) {
|
||||||
|
|
||||||
wxFileName fileInfo( dirPath, file.m_fileName );
|
wxFileName fileInfo( dirPath, file.m_fileName );
|
||||||
bool isFile = wxFile::Exists( fileInfo.GetFullPath() );
|
|
||||||
|
|
||||||
if ( isFile ) {
|
if ( file.m_isFile ) {
|
||||||
// don't load files in the root dir if we're filtering; no official software stores files there
|
// don't load files in the root dir if we're filtering; no official software stores files there
|
||||||
if ( enableFiltering && parent == nullptr ) {
|
if ( enableFiltering && parent == nullptr ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -371,11 +370,9 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS
|
||||||
}
|
}
|
||||||
|
|
||||||
// is a subdirectory
|
// is a subdirectory
|
||||||
wxDateTime creationTime, modificationTime;
|
|
||||||
fileInfo.AppendDir( fileInfo.GetFullName() );
|
fileInfo.AppendDir( fileInfo.GetFullName() );
|
||||||
fileInfo.SetName( L"" );
|
fileInfo.SetName( L"" );
|
||||||
fileInfo.ClearExt();
|
fileInfo.ClearExt();
|
||||||
fileInfo.GetTimes( NULL, &modificationTime, &creationTime );
|
|
||||||
|
|
||||||
// add entry for subdir in parent dir
|
// add entry for subdir in parent dir
|
||||||
MemoryCardFileEntry* newDirEntry = AppendFileEntryToDir( dirEntry );
|
MemoryCardFileEntry* newDirEntry = AppendFileEntryToDir( dirEntry );
|
||||||
|
@ -393,8 +390,8 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newDirEntry->entry.data.mode = MemoryCardFileEntry::DefaultDirMode;
|
newDirEntry->entry.data.mode = MemoryCardFileEntry::DefaultDirMode;
|
||||||
newDirEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromWxDateTime( creationTime );
|
newDirEntry->entry.data.timeCreated = MemoryCardFileEntryDateTime::FromTime( file.m_timeCreated );
|
||||||
newDirEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromWxDateTime( modificationTime );
|
newDirEntry->entry.data.timeModified = MemoryCardFileEntryDateTime::FromTime( file.m_timeModified );
|
||||||
strcpy( reinterpret_cast<char*>(newDirEntry->entry.data.name), file.m_fileName.mbc_str() );
|
strcpy( reinterpret_cast<char*>(newDirEntry->entry.data.name), file.m_fileName.mbc_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,11 +995,12 @@ void FolderMemoryCard::FlushFileEntries( const u32 dirCluster, const u32 remaini
|
||||||
|
|
||||||
if ( m_performFileWrites ) {
|
if ( m_performFileWrites ) {
|
||||||
// if this directory has nonstandard metadata, write that to the file system
|
// if this directory has nonstandard metadata, write that to the file system
|
||||||
wxFileName metaFileName( m_folderName.GetFullPath() + subDirPath + L"/_pcsx2_meta_directory" );
|
wxFileName metaFileName( m_folderName.GetFullPath() + subDirPath, L"_pcsx2_meta_directory" );
|
||||||
|
if ( !metaFileName.DirExists() ) {
|
||||||
|
metaFileName.Mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
if ( filenameCleaned || entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0 ) {
|
if ( filenameCleaned || entry->entry.data.mode != MemoryCardFileEntry::DefaultDirMode || entry->entry.data.attr != 0 ) {
|
||||||
if ( !metaFileName.DirExists() ) {
|
|
||||||
metaFileName.Mkdir();
|
|
||||||
}
|
|
||||||
wxFFile metaFile( metaFileName.GetFullPath(), L"wb" );
|
wxFFile metaFile( metaFileName.GetFullPath(), L"wb" );
|
||||||
if ( metaFile.IsOpened() ) {
|
if ( metaFile.IsOpened() ) {
|
||||||
metaFile.Write( entry->entry.raw, sizeof( entry->entry.raw ) );
|
metaFile.Write( entry->entry.raw, sizeof( entry->entry.raw ) );
|
||||||
|
@ -1013,6 +1011,20 @@ void FolderMemoryCard::FlushFileEntries( const u32 dirCluster, const u32 remaini
|
||||||
wxRemoveFile( metaFileName.GetFullPath() );
|
wxRemoveFile( metaFileName.GetFullPath() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write the directory index
|
||||||
|
metaFileName.SetName( L"_pcsx2_index" );
|
||||||
|
YAML::Node index = LoadYAMLFromFile( metaFileName.GetFullPath() );
|
||||||
|
YAML::Node entryNode = index[ "%ROOT" ];
|
||||||
|
|
||||||
|
entryNode["timeCreated"] = entry->entry.data.timeCreated.ToTime();
|
||||||
|
entryNode["timeModified"] = entry->entry.data.timeModified.ToTime();
|
||||||
|
|
||||||
|
// Write out the changes
|
||||||
|
wxFFile indexFile;
|
||||||
|
if ( indexFile.Open( metaFileName.GetFullPath(), L"w" ) ) {
|
||||||
|
indexFile.Write( YAML::Dump( index ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess( entry, parent );
|
MemoryCardFileMetadataReference* dirRef = AddDirEntryToMetadataQuickAccess( entry, parent );
|
||||||
|
@ -1335,14 +1347,17 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
|
||||||
wxDir dir( dirPath );
|
wxDir dir( dirPath );
|
||||||
if ( dir.IsOpened() ) {
|
if ( dir.IsOpened() ) {
|
||||||
|
|
||||||
YAML::Node index = LoadYAMLFromFile( wxFileName( dirPath, "_pcsx2_index" ).GetFullPath() );
|
const YAML::Node index = LoadYAMLFromFile( wxFileName( dirPath, "_pcsx2_index" ).GetFullPath() );
|
||||||
|
|
||||||
// We must be able to support legacy folder memcards without the index file, so for those
|
// We must be able to support legacy folder memcards without the index file, so for those
|
||||||
// track an order variable and make it negative - this way new files get their order preserved
|
// track an order variable and make it negative - this way new files get their order preserved
|
||||||
// and old files are listed first.
|
// and old files are listed first.
|
||||||
// In the YAML File order is stored as an unsigned int, so use a signed int64_t to accommodate for
|
// In the YAML File order is stored as an unsigned int, so use a signed int64_t to accommodate for
|
||||||
// all possible values without cutting them off
|
// all possible values without cutting them off
|
||||||
std::map<int64_t, EnumeratedFileEntry> sortContainer;
|
// Also exploit the fact pairs sort lexicographically to ensure directories are listed first
|
||||||
|
// (since they don't carry their own order in the index file)
|
||||||
|
std::map< std::pair<bool, int64_t>, EnumeratedFileEntry > sortContainer;
|
||||||
|
int64_t orderForDirectories = 1;
|
||||||
int64_t orderForLegacyFiles = -1;
|
int64_t orderForLegacyFiles = -1;
|
||||||
|
|
||||||
wxString fileName;
|
wxString fileName;
|
||||||
|
@ -1353,26 +1368,34 @@ std::vector<FolderMemoryCard::EnumeratedFileEntry> FolderMemoryCard::GetOrderedF
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxFileName fileInfo( dirPath, fileName );
|
wxFileName fileInfo( dirPath, fileName );
|
||||||
try {
|
if ( wxFile::Exists( fileInfo.GetFullPath() ) ) {
|
||||||
if ( wxFile::Exists( fileInfo.GetFullPath() ) ) {
|
|
||||||
const YAML::Node& node = index[ fileName.ToStdString() ];
|
|
||||||
|
|
||||||
EnumeratedFileEntry entry { fileName, node["timeCreated"].as<time_t>(), node["timeModified"].as<time_t>() };
|
|
||||||
sortContainer.try_emplace( node["order"].as<unsigned int>(), std::move(entry) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO: Implement directories, for now force it to use the fallback implementation
|
|
||||||
throw YAML::InvalidNode( fileName.ToStdString() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( YAML::Exception& /*e*/ ) {
|
|
||||||
// File doesn't exist in index or it's corrupted - fall back to file-based timestamps and a custom order
|
|
||||||
wxDateTime creationTime, modificationTime;
|
wxDateTime creationTime, modificationTime;
|
||||||
fileInfo.GetTimes( nullptr, &modificationTime, &creationTime );
|
fileInfo.GetTimes( nullptr, &modificationTime, &creationTime );
|
||||||
|
|
||||||
EnumeratedFileEntry entry { fileName, creationTime.GetTicks(), modificationTime.GetTicks() };
|
const YAML::Node& node = index[ fileName.ToStdString() ];
|
||||||
sortContainer.try_emplace( orderForLegacyFiles--, std::move(entry) );
|
|
||||||
|
// orderForLegacyFiles will decrement even if it ends up being unused, but that's fine
|
||||||
|
auto key = std::make_pair( true, node["order"].as<unsigned int>( orderForLegacyFiles-- ) );
|
||||||
|
EnumeratedFileEntry entry { fileName, node["timeCreated"].as<time_t>( creationTime.GetTicks() ),
|
||||||
|
node["timeModified"].as<time_t>( modificationTime.GetTicks() ), true };
|
||||||
|
sortContainer.try_emplace( std::move(key), std::move(entry) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fileInfo.AppendDir( fileInfo.GetFullName() );
|
||||||
|
fileInfo.SetName( L"" );
|
||||||
|
|
||||||
|
wxDateTime creationTime, modificationTime;
|
||||||
|
fileInfo.GetTimes( nullptr, &modificationTime, &creationTime );
|
||||||
|
|
||||||
|
const YAML::Node indexForDirectory = LoadYAMLFromFile( wxFileName( fileInfo.GetFullPath(), "_pcsx2_index" ).GetFullPath() );
|
||||||
|
const YAML::Node& node = indexForDirectory[ "%ROOT" ];
|
||||||
|
|
||||||
|
// orderForDirectories will increment even if it ends up being unused, but that's fine
|
||||||
|
auto key = std::make_pair( false, orderForDirectories++ );
|
||||||
|
EnumeratedFileEntry entry { fileName, node["timeCreated"].as<time_t>( creationTime.GetTicks() ),
|
||||||
|
node["timeModified"].as<time_t>( modificationTime.GetTicks() ), false };
|
||||||
|
sortContainer.try_emplace( std::move(key), std::move(entry) );
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNext = dir.GetNext( &fileName );
|
hasNext = dir.GetNext( &fileName );
|
||||||
|
@ -1542,7 +1565,7 @@ void FileAccessHelper::WriteIndex( wxFileName folderName, const MemoryCardFileMe
|
||||||
// Newly added file - figure out the sort order as the entry should be added to the end of the list
|
// Newly added file - figure out the sort order as the entry should be added to the end of the list
|
||||||
unsigned int order = 0;
|
unsigned int order = 0;
|
||||||
for ( const auto& node : index ) {
|
for ( const auto& node : index ) {
|
||||||
order = std::max( order, node.second["order"].as<unsigned int>() );
|
order = std::max( order, node.second["order"].as<unsigned int>(0) );
|
||||||
}
|
}
|
||||||
|
|
||||||
entryNode["order"] = order + 1;
|
entryNode["order"] = order + 1;
|
||||||
|
|
|
@ -390,6 +390,7 @@ protected:
|
||||||
wxString m_fileName; // TODO: Replace with std::string
|
wxString m_fileName; // TODO: Replace with std::string
|
||||||
time_t m_timeCreated;
|
time_t m_timeCreated;
|
||||||
time_t m_timeModified;
|
time_t m_timeModified;
|
||||||
|
bool m_isFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
// initializes memory card data, as if it was fresh from the factory
|
// initializes memory card data, as if it was fresh from the factory
|
||||||
|
|
Loading…
Reference in New Issue