From 0c622929ba0cf1d9c7030029ad86505024e5bbaa Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 25 Dec 2018 16:32:58 +0100 Subject: [PATCH] Add M3U file support for automatic disc switching --- Source/Core/Core/Boot/Boot.cpp | 71 +++++++++++++++++---- Source/Core/DolphinQt/Info.plist.in | 1 + Source/Core/DolphinQt/MainWindow.cpp | 2 +- Source/Core/DolphinQt/Settings/PathPane.cpp | 2 +- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index c429b7ee2c..6533a2719a 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -4,6 +4,12 @@ #include "Core/Boot/Boot.h" +#ifdef _MSC_VER +#include +namespace fs = std::experimental::filesystem; +#define HAS_STD_FILESYSTEM +#endif + #include #include #include @@ -54,10 +60,52 @@ #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" -std::vector ReadM3UFile(const std::string& path) +std::vector ReadM3UFile(const std::string& m3u_path, const std::string& folder_path) { - // TODO - return {}; +#ifndef HAS_STD_FILESYSTEM + ASSERT(folder_path.back() == '/'); +#endif + + std::vector result; + std::vector nonexistent; + + std::ifstream s; + File::OpenFStream(s, m3u_path, std::ios_base::in); + + std::string line; + while (std::getline(s, line)) + { + if (StringBeginsWith(line, u8"\uFEFF")) + { + WARN_LOG(BOOT, "UTF-8 BOM in file: %s", m3u_path.c_str()); + line.erase(0, 3); + } + + if (!line.empty() && line.front() != '#') // Comments start with # + { +#ifdef HAS_STD_FILESYSTEM + const fs::path path_line = fs::u8path(line); + const std::string path_to_add = + path_line.is_relative() ? fs::u8path(folder_path).append(path_line).u8string() : line; +#else + const std::string path_to_add = line.front() != '/' ? folder_path + line : line; +#endif + + (File::Exists(path_to_add) ? result : nonexistent).push_back(path_to_add); + } + } + + if (!nonexistent.empty()) + { + PanicAlertT("Files specified in the M3U file \"%s\" were not found:\n%s", m3u_path.c_str(), + JoinStrings(nonexistent, "\n").c_str()); + return {}; + } + + if (result.empty()) + PanicAlertT("No paths found in the M3U file \"%s\"", m3u_path.c_str()); + + return result; } BootParameters::BootParameters(Parameters&& parameters_, @@ -88,20 +136,19 @@ BootParameters::GenerateFromFile(std::vector paths, return {}; } + std::string folder_path; std::string extension; - SplitPath(paths.front(), nullptr, nullptr, &extension); + SplitPath(paths.front(), &folder_path, nullptr, &extension); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if (extension == ".m3u") + if (extension == ".m3u" || extension == ".m3u8") { - std::vector new_paths = ReadM3UFile(paths.front()); - if (!new_paths.empty()) - { - paths = new_paths; + paths = ReadM3UFile(paths.front(), folder_path); + if (paths.empty()) + return {}; - SplitPath(paths.front(), nullptr, nullptr, &extension); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - } + SplitPath(paths.front(), nullptr, nullptr, &extension); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); } const std::string path = paths.front(); diff --git a/Source/Core/DolphinQt/Info.plist.in b/Source/Core/DolphinQt/Info.plist.in index 08fcfc511f..7fd60fa8e0 100644 --- a/Source/Core/DolphinQt/Info.plist.in +++ b/Source/Core/DolphinQt/Info.plist.in @@ -13,6 +13,7 @@ gcm gcz iso + m3u tgc wad wbfs diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index ed4379ea98..bab9e280da 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -627,7 +627,7 @@ QStringList MainWindow::PromptFileNames() QStringList paths = QFileDialog::getOpenFileNames( this, tr("Select a File"), settings.value(QStringLiteral("mainwindow/lastdir"), QStringLiteral("")).toString(), - tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff);;" + tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.dff *.m3u);;" "All Files (*)")); if (!paths.isEmpty()) diff --git a/Source/Core/DolphinQt/Settings/PathPane.cpp b/Source/Core/DolphinQt/Settings/PathPane.cpp index 97e6f63b2b..9338751f6f 100644 --- a/Source/Core/DolphinQt/Settings/PathPane.cpp +++ b/Source/Core/DolphinQt/Settings/PathPane.cpp @@ -43,7 +43,7 @@ void PathPane::BrowseDefaultGame() { QString file = QDir::toNativeSeparators(QFileDialog::getOpenFileName( this, tr("Select a Game"), Settings::Instance().GetDefaultGame(), - tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad);;" + tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad *.m3u);;" "All Files (*)"))); if (!file.isEmpty())