CDImage: Support sub-images, use subimages for m3u

This commit is contained in:
Connor McLaughlin
2021-03-27 02:19:23 +10:00
parent 573aa6d9cc
commit 50d712c3fe
23 changed files with 443 additions and 312 deletions

View File

@ -847,27 +847,19 @@ void GameChanged(const std::string& path, CDImage* image)
s_http_downloader->WaitForAllRequests();
const u32 playlist_count = System::GetMediaPlaylistCount();
if (playlist_count > 1 && s_use_first_disc_from_playlist)
if (image && image->HasSubImages() && image->GetCurrentSubImage() != 0)
{
// have to pass the path in, because the image isn't owned by the system yet
const u32 playlist_index = System::GetMediaPlaylistIndexForPath(path);
if (playlist_index > 0 && playlist_index < playlist_count)
std::unique_ptr<CDImage> image_copy(CDImage::Open(image->GetFileName().c_str(), nullptr));
if (!image_copy)
{
const std::string& first_disc_path(System::GetMediaPlaylistPath(0));
std::unique_ptr<CDImage> first_disc_image(CDImage::Open(first_disc_path.c_str(), nullptr));
if (first_disc_image)
{
Log_InfoPrintf("Using first disc '%s' from playlist (currently '%s')", first_disc_path.c_str(), path.c_str());
GameChanged(first_disc_path, first_disc_image.get());
return;
}
else
{
Log_ErrorPrintf("Failed to open first disc '%s' from playlist", first_disc_path.c_str());
return;
}
Log_ErrorPrintf("Failed to reopen image '%s'", image->GetFileName().c_str());
return;
}
// this will go to subimage zero automatically
Assert(image_copy->GetCurrentSubImage() == 0);
GameChanged(path, image_copy.get());
return;
}
ClearGameInfo();

View File

@ -666,20 +666,20 @@ static void DoChangeDiscFromFile()
static void DoChangeDisc()
{
const u32 playlist_count = System::GetMediaPlaylistCount();
if (playlist_count == 0)
if (!System::HasMediaSubImages())
{
DoChangeDiscFromFile();
return;
}
const u32 current_index = (playlist_count > 0) ? System::GetMediaPlaylistIndex() : 0;
const u32 current_index = System::GetMediaSubImageIndex();
const u32 count = System::GetMediaSubImageCount();
ImGuiFullscreen::ChoiceDialogOptions options;
options.reserve(playlist_count + 1);
options.reserve(count + 1);
options.emplace_back("From File...", false);
for (u32 i = 0; i < playlist_count; i++)
options.emplace_back(System::GetMediaPlaylistPath(i), i == current_index);
for (u32 i = 0; i < count; i++)
options.emplace_back(System::GetMediaSubImageTitle(i), i == current_index);
auto callback = [](s32 index, const std::string& title, bool checked) {
if (index == 0)
@ -690,7 +690,7 @@ static void DoChangeDisc()
}
else if (index > 0)
{
System::SwitchMediaFromPlaylist(static_cast<u32>(index - 1));
System::SwitchMediaSubImage(static_cast<u32>(index - 1));
}
ClearImGuiFocus();
@ -1798,10 +1798,10 @@ void DrawSettingsWindow()
MenuHeading("Shared Settings");
settings_changed |= ToggleButton(
"Use Single Card For Playlist",
"When using a playlist (m3u) and per-game (title) memory cards, use a single memory card for all discs.",
&s_settings_copy.memory_card_use_playlist_title);
settings_changed |= ToggleButton("Use Single Card For Sub-Images",
"When using a multi-disc image (m3u/pbp) and per-game (title) memory cards, "
"use a single memory card for all discs.",
&s_settings_copy.memory_card_use_playlist_title);
static std::string memory_card_directory;
if (memory_card_directory.empty())

View File

@ -147,61 +147,12 @@ bool GameList::GetPsfListEntry(const char* path, GameListEntry* entry)
return true;
}
bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
{
FILESYSTEM_STAT_DATA ffd;
if (!FileSystem::StatFile(path, &ffd))
return false;
std::vector<std::string> entries = System::ParseM3UFile(path);
if (entries.empty())
return false;
entry->code.clear();
entry->title = System::GetTitleForPath(path);
entry->path = path;
entry->region = DiscRegion::Other;
entry->total_size = 0;
entry->last_modified_time = ffd.ModificationTime.AsUnixTimestamp();
entry->type = GameListEntryType::Playlist;
entry->compatibility_rating = GameListCompatibilityRating::Unknown;
for (size_t i = 0; i < entries.size(); i++)
{
std::unique_ptr<CDImage> entry_image = CDImage::Open(entries[i].c_str(), nullptr);
if (!entry_image)
{
Log_ErrorPrintf("Failed to open entry %zu ('%s') in playlist %s", i, entries[i].c_str(), path);
return false;
}
entry->total_size += static_cast<u64>(CDImage::RAW_SECTOR_SIZE) * static_cast<u64>(entry_image->GetLBACount());
if (entry->region == DiscRegion::Other)
entry->region = System::GetRegionForImage(entry_image.get());
if (entry->compatibility_rating == GameListCompatibilityRating::Unknown)
{
std::string code = System::GetGameCodeForImage(entry_image.get(), true);
const GameListCompatibilityEntry* compatibility_entry = GetCompatibilityEntryForCode(entry->code);
if (compatibility_entry)
entry->compatibility_rating = compatibility_entry->compatibility_rating;
else
Log_WarningPrintf("'%s' (%s) not found in compatibility list", entry->code.c_str(), entry->title.c_str());
}
}
return true;
}
bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
{
if (System::IsExeFileName(path.c_str()))
return GetExeListEntry(path.c_str(), entry);
if (System::IsPsfFileName(path.c_str()))
return GetPsfListEntry(path.c_str(), entry);
if (System::IsM3UFileName(path.c_str()))
return GetM3UListEntry(path.c_str(), entry);
std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str(), nullptr);
if (!cdi)
@ -218,7 +169,6 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
entry->total_size = static_cast<u64>(CDImage::RAW_SECTOR_SIZE) * static_cast<u64>(cdi->GetLBACount());
entry->type = GameListEntryType::Disc;
entry->compatibility_rating = GameListCompatibilityRating::Unknown;
cdi.reset();
if (entry->code.empty())
{
@ -255,6 +205,28 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
entry->settings = *settings;
}
if (cdi->HasSubImages())
{
entry->type = GameListEntryType::Playlist;
std::string image_title(cdi->GetMetadata("title"));
if (!image_title.empty())
entry->title = std::move(image_title);
// get the size of all the subimages
const u32 subimage_count = cdi->GetSubImageCount();
for (u32 i = 1; i < subimage_count; i++)
{
if (!cdi->SwitchSubImage(i, nullptr))
{
Log_ErrorPrintf("Failed to switch to subimage %u in '%s'", i, entry->path.c_str());
continue;
}
entry->total_size += static_cast<u64>(CDImage::RAW_SECTOR_SIZE) * static_cast<u64>(cdi->GetLBACount());
}
}
FILESYSTEM_STAT_DATA ffd;
if (!FileSystem::StatFile(path.c_str(), &ffd))
return false;