diff --git a/libretro/main.cpp b/libretro/main.cpp index b95d8aeb1fa71..1c8adce93b385 100644 --- a/libretro/main.cpp +++ b/libretro/main.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "options.h" @@ -358,11 +360,60 @@ void retro_get_system_info(retro_system_info* info) #endif info->library_name = "pcsx2"; - info->valid_extensions = "elf|iso|ciso|cue|bin|gz"; + info->valid_extensions = "elf|iso|ciso|cue|bin|gz|m3u"; info->need_fullpath = true; info->block_extract = true; } + +static std::vector + read_m3u_file(const std::string& m3u_file) +{ + log_cb(RETRO_LOG_DEBUG, "Reading M3U file\n"); + std::vector result; + std::ifstream m3u_data{std::filesystem::path(m3u_file)}; + if (!m3u_data.is_open()) + { + log_cb(RETRO_LOG_ERROR, "M3U file \"%s\" cannot be read\n", m3u_file.c_str()); + return result; + } + const std::string m3u_parent = Path::Canonicalize(Path::GetDirectory(m3u_file)); + // This is the UTF-8 representation of U+FEFF. + const std::string utf8_bom = "\xEF\xBB\xBF"; + std::string line; + getline(m3u_data, line); + if (line.rfind(utf8_bom,0) == 0) + { + log_cb(RETRO_LOG_WARN, "M3U file \"%s\" contains UTF-8 BOM\n", m3u_file.c_str()); + line.erase(0, utf8_bom.length()); + } + for (line; !m3u_data.eof(); getline(m3u_data, line)) + { + if (!line.find('#') == 0) // Comments start with # + { + std::string m3u_path = line; + if (!Path::IsAbsolute(line) && !m3u_parent.empty()) + { + m3u_path = Path::Combine(m3u_parent, line); + } + std::ifstream discFile(m3u_path); + if (discFile.is_open()) + { + log_cb(RETRO_LOG_DEBUG, "Found disc image in M3U file, %s\n", m3u_path.c_str()); + result.push_back(m3u_path); + } + else + { + log_cb(RETRO_LOG_WARN, "File specified in the M3U file \"%s\" was not found\n", m3u_path.c_str()); + } + } + } + if (result.empty()) + log_cb(RETRO_LOG_ERROR, "No paths found in the M3U file \"%s\"\n", m3u_file.c_str()); + + return result; +} + void retro_get_system_av_info(retro_system_av_info* info) { if (Options::renderer == "Software" || Options::renderer == "Null") @@ -718,8 +769,18 @@ bool retro_load_game(const struct retro_game_info* game) VMBootParameters boot_params; if(game && game->path) { - disk_images.push_back(game->path); - boot_params.filename = game->path; + std::vector game_paths; + if (Path::GetExtension(game->path) == "m3u") + { + game_paths = read_m3u_file(game->path); + log_cb(RETRO_LOG_DEBUG, "Found %u game images in M3U file.", game_paths.size()); + } + else + { + game_paths.push_back(game->path); + } + disk_images.assign(game_paths.begin(), game_paths.end()); + boot_params.filename = disk_images[0]; } cpu_thread = std::thread(cpu_thread_entry, boot_params);