Move GameList to FrontendCommon

Reduces libretro core dependencies further.
This commit is contained in:
Connor McLaughlin 2020-09-01 12:29:22 +10:00
parent 13e3095801
commit 6bbbb96d4b
25 changed files with 356 additions and 353 deletions

View File

@ -5,10 +5,10 @@
#include "common/string.h"
#include "common/timestamp.h"
#include "core/controller.h"
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/host_display.h"
#include "core/system.h"
#include "frontend-common/game_list.h"
#include "frontend-common/imgui_styles.h"
#include "frontend-common/opengl_host_display.h"
#include "frontend-common/vulkan_host_display.h"

View File

@ -2,9 +2,7 @@ add_subdirectory(cubeb)
add_subdirectory(glad)
add_subdirectory(googletest)
add_subdirectory(libcue)
add_subdirectory(simpleini)
add_subdirectory(stb)
add_subdirectory(tinyxml2)
add_subdirectory(zlib)
add_subdirectory(minizip)
add_subdirectory(lzma)
@ -17,6 +15,8 @@ add_subdirectory(vulkan-loader)
if(NOT BUILD_LIBRETRO_CORE)
add_subdirectory(imgui)
add_subdirectory(simpleini)
add_subdirectory(tinyxml2)
endif()
if(ENABLE_DISCORD_PRESENCE)

View File

@ -24,10 +24,6 @@ add_library(core
digital_controller.h
dma.cpp
dma.h
game_list.cpp
game_list.h
game_settings.cpp
game_settings.h
gpu.cpp
gpu.h
gpu_commands.cpp
@ -98,7 +94,7 @@ set(RECOMPILER_SRCS
target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common tinyxml2 zlib vulkan-loader simpleini)
target_link_libraries(core PUBLIC Threads::Threads common zlib vulkan-loader)
target_link_libraries(core PRIVATE glad stb)
if(WIN32)

View File

@ -3,7 +3,6 @@
#include "common/log.h"
#include "common/state_wrapper.h"
#include "dma.h"
#include "game_list.h"
#include "interrupt_controller.h"
#include "settings.h"
#include "spu.h"
@ -446,7 +445,7 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media)
RemoveMedia();
// set the region from the system area of the disc
m_disc_region = GameList::GetRegionForImage(media.get());
m_disc_region = System::GetRegionForImage(media.get());
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s", Settings::GetDiscRegionName(m_disc_region),
Settings::GetConsoleRegionName(System::GetRegion()));

View File

@ -59,8 +59,6 @@
<ClCompile Include="cpu_recompiler_register_cache.cpp" />
<ClCompile Include="cpu_types.cpp" />
<ClCompile Include="digital_controller.cpp" />
<ClCompile Include="game_list.cpp" />
<ClCompile Include="game_settings.cpp" />
<ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_hw_d3d11.cpp" />
<ClCompile Include="gpu_hw_shadergen.cpp" />
@ -107,8 +105,6 @@
<ClInclude Include="cpu_recompiler_thunks.h" />
<ClInclude Include="cpu_recompiler_types.h" />
<ClInclude Include="digital_controller.h" />
<ClInclude Include="game_list.h" />
<ClInclude Include="game_settings.h" />
<ClInclude Include="gpu_hw_d3d11.h" />
<ClInclude Include="gpu_hw_shadergen.h" />
<ClInclude Include="gpu_hw_vulkan.h" />
@ -147,14 +143,14 @@
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\simpleini\simpleini.vcxproj">
<Project>{3773f4cc-614e-4028-8595-22e08ca649e3}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\stb\stb.vcxproj">
<Project>{ed601289-ac1a-46b8-a8ed-17db9eb73423}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\tinyxml2\tinyxml2.vcxproj">
<Project>{933118a9-68c5-47b4-b151-b03c93961623}</Project>
<ProjectReference Include="..\..\dep\vulkan-loader\vulkan-loader.vcxproj">
<Project>{9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\zlib\zlib.vcxproj">
<Project>{7ff9fdb9-d504-47db-a16a-b08071999620}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
@ -307,7 +303,7 @@
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -333,7 +329,7 @@
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -359,7 +355,7 @@
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
@ -388,7 +384,7 @@
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
@ -416,7 +412,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -443,7 +439,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -471,7 +467,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -498,7 +494,7 @@
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_IMGUI=1;WITH_RECOMPILER=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\xbyak\xbyak;$(SolutionDir)dep\zlib\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>

View File

@ -31,7 +31,6 @@
<ClCompile Include="cpu_recompiler_code_generator.cpp" />
<ClCompile Include="cpu_recompiler_code_generator_generic.cpp" />
<ClCompile Include="cpu_types.cpp" />
<ClCompile Include="game_list.cpp" />
<ClCompile Include="cpu_recompiler_code_generator_aarch64.cpp" />
<ClCompile Include="sio.cpp" />
<ClCompile Include="controller.cpp" />
@ -47,7 +46,6 @@
<ClCompile Include="resources.cpp" />
<ClCompile Include="host_interface_progress_callback.cpp" />
<ClCompile Include="pgxp.cpp" />
<ClCompile Include="game_settings.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -82,7 +80,6 @@
<ClInclude Include="cpu_recompiler_register_cache.h" />
<ClInclude Include="cpu_recompiler_thunks.h" />
<ClInclude Include="cpu_recompiler_code_generator.h" />
<ClInclude Include="game_list.h" />
<ClInclude Include="sio.h" />
<ClInclude Include="controller.h" />
<ClInclude Include="analog_controller.h" />
@ -98,6 +95,5 @@
<ClInclude Include="gte_types.h" />
<ClInclude Include="pgxp.h" />
<ClInclude Include="cpu_core_private.h" />
<ClInclude Include="game_settings.h" />
</ItemGroup>
</Project>

View File

@ -4,6 +4,7 @@
#include "cdrom.h"
#include "common/audio_stream.h"
#include "common/file_system.h"
#include "common/iso_reader.h"
#include "common/log.h"
#include "common/state_wrapper.h"
#include "common/string_util.h"
@ -11,7 +12,6 @@
#include "cpu_code_cache.h"
#include "cpu_core.h"
#include "dma.h"
#include "game_list.h"
#include "gpu.h"
#include "gte.h"
#include "host_display.h"
@ -27,6 +27,7 @@
#include "spu.h"
#include "timers.h"
#include <cstdio>
#include <fstream>
#include <limits>
Log_SetChannel(System);
@ -203,6 +204,71 @@ float GetThrottleFrequency()
return s_throttle_frequency;
}
bool IsExeFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension &&
(StringUtil::Strcasecmp(extension, ".exe") == 0 || StringUtil::Strcasecmp(extension, ".psexe") == 0));
}
bool IsPsfFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension && StringUtil::Strcasecmp(extension, ".psf") == 0);
}
bool IsM3UFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension && StringUtil::Strcasecmp(extension, ".m3u") == 0);
}
std::vector<std::string> ParseM3UFile(const char* path)
{
std::ifstream ifs(path);
if (!ifs.is_open())
{
Log_ErrorPrintf("Failed to open %s", path);
return {};
}
std::vector<std::string> entries;
std::string line;
while (std::getline(ifs, line))
{
u32 start_offset = 0;
while (start_offset < line.size() && std::isspace(line[start_offset]))
start_offset++;
// skip comments
if (start_offset == line.size() || line[start_offset] == '#')
continue;
// strip ending whitespace
u32 end_offset = static_cast<u32>(line.size()) - 1;
while (std::isspace(line[end_offset]) && end_offset > start_offset)
end_offset--;
// anything?
if (start_offset == end_offset)
continue;
std::string entry_path(line.begin() + start_offset, line.begin() + end_offset + 1);
if (!FileSystem::IsAbsolutePath(entry_path))
{
SmallString absolute_path;
FileSystem::BuildPathRelativeToFile(absolute_path, path, entry_path.c_str());
entry_path = absolute_path;
}
Log_DevPrintf("Read path from m3u: '%s'", entry_path.c_str());
entries.push_back(std::move(entry_path));
}
Log_InfoPrintf("Loaded %zu paths from m3u '%s'", entries.size(), path);
return entries;
}
ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region)
{
switch (region)
@ -220,6 +286,188 @@ ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region)
}
}
std::string_view GetTitleForPath(const char* path)
{
const char* extension = std::strrchr(path, '.');
if (path == extension)
return path;
const char* path_end = path + std::strlen(path);
const char* title_end = extension ? (extension - 1) : (path_end);
const char* title_start = std::max(std::strrchr(path, '/'), std::strrchr(path, '\\'));
if (!title_start || title_start == path)
return std::string_view(path, title_end - title_start);
else
return std::string_view(title_start + 1, title_end - title_start);
}
std::string GetGameCodeForPath(const char* image_path)
{
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path);
if (!cdi)
return {};
return GetGameCodeForImage(cdi.get());
}
std::string GetGameCodeForImage(CDImage* cdi)
{
ISOReader iso;
if (!iso.Open(cdi, 1))
return {};
// Read SYSTEM.CNF
std::vector<u8> system_cnf_data;
if (!iso.ReadFile("SYSTEM.CNF", &system_cnf_data))
return {};
// Parse lines
std::vector<std::pair<std::string, std::string>> lines;
std::pair<std::string, std::string> current_line;
bool reading_value = false;
for (size_t pos = 0; pos < system_cnf_data.size(); pos++)
{
const char ch = static_cast<char>(system_cnf_data[pos]);
if (ch == '\r' || ch == '\n')
{
if (!current_line.first.empty())
{
lines.push_back(std::move(current_line));
current_line = {};
reading_value = false;
}
}
else if (ch == ' ' || (ch >= 0x09 && ch <= 0x0D))
{
continue;
}
else if (ch == '=' && !reading_value)
{
reading_value = true;
}
else
{
if (reading_value)
current_line.second.push_back(ch);
else
current_line.first.push_back(ch);
}
}
if (!current_line.first.empty())
lines.push_back(std::move(current_line));
// Find the BOOT line
auto iter = std::find_if(lines.begin(), lines.end(),
[](const auto& it) { return StringUtil::Strcasecmp(it.first.c_str(), "boot") == 0; });
if (iter == lines.end())
return {};
// cdrom:\SCES_123.45;1
std::string code = iter->second;
std::string::size_type pos = code.rfind('\\');
if (pos != std::string::npos)
{
code.erase(0, pos + 1);
}
else
{
// cdrom:SCES_123.45;1
pos = code.rfind(':');
if (pos != std::string::npos)
code.erase(0, pos + 1);
}
pos = code.find(';');
if (pos != std::string::npos)
code.erase(pos);
// SCES_123.45 -> SCES-12345
for (pos = 0; pos < code.size();)
{
if (code[pos] == '.')
{
code.erase(pos, 1);
continue;
}
if (code[pos] == '_')
code[pos] = '-';
else
code[pos] = static_cast<char>(std::toupper(code[pos]));
pos++;
}
return code;
}
DiscRegion GetRegionForCode(std::string_view code)
{
std::string prefix;
for (size_t pos = 0; pos < code.length(); pos++)
{
const int ch = std::tolower(code[pos]);
if (ch < 'a' || ch > 'z')
break;
prefix.push_back(static_cast<char>(ch));
}
if (prefix == "sces" || prefix == "sced" || prefix == "sles" || prefix == "sled")
return DiscRegion::PAL;
else if (prefix == "scps" || prefix == "slps" || prefix == "slpm" || prefix == "sczs" || prefix == "papx")
return DiscRegion::NTSC_J;
else if (prefix == "scus" || prefix == "slus")
return DiscRegion::NTSC_U;
else
return DiscRegion::Other;
}
DiscRegion GetRegionFromSystemArea(CDImage* cdi)
{
// The license code is on sector 4 of the disc.
u8 sector[CDImage::DATA_SECTOR_SIZE];
if (!cdi->Seek(1, 4) || cdi->Read(CDImage::ReadMode::DataOnly, 1, sector) != 1)
return DiscRegion::Other;
static constexpr char ntsc_u_string[] = " Licensed by Sony Computer Entertainment Amer ica ";
static constexpr char ntsc_j_string[] = " Licensed by Sony Computer Entertainment Inc.";
static constexpr char pal_string[] = " Licensed by Sony Computer Entertainment Euro pe";
// subtract one for the terminating null
if (std::equal(ntsc_u_string, ntsc_u_string + countof(ntsc_u_string) - 1, sector))
return DiscRegion::NTSC_U;
else if (std::equal(ntsc_j_string, ntsc_j_string + countof(ntsc_j_string) - 1, sector))
return DiscRegion::NTSC_J;
else if (std::equal(pal_string, pal_string + countof(pal_string) - 1, sector))
return DiscRegion::PAL;
else
return DiscRegion::Other;
}
DiscRegion GetRegionForImage(CDImage* cdi)
{
DiscRegion system_area_region = GetRegionFromSystemArea(cdi);
if (system_area_region != DiscRegion::Other)
return system_area_region;
std::string code = GetGameCodeForImage(cdi);
if (code.empty())
return DiscRegion::Other;
return GetRegionForCode(code);
}
std::optional<DiscRegion> GetRegionForPath(const char* image_path)
{
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path);
if (!cdi)
return {};
return GetRegionForImage(cdi.get());
}
bool RecreateGPU(GPURenderer renderer)
{
g_gpu->RestoreGraphicsAPIState();
@ -297,8 +545,8 @@ bool Boot(const SystemBootParameters& params)
bool psf_boot = false;
if (!params.filename.empty())
{
exe_boot = GameList::IsExeFileName(params.filename.c_str());
psf_boot = (!exe_boot && GameList::IsPsfFileName(params.filename.c_str()));
exe_boot = IsExeFileName(params.filename.c_str());
psf_boot = (!exe_boot && IsPsfFileName(params.filename.c_str()));
if (exe_boot || psf_boot)
{
// TODO: Pull region from PSF
@ -311,9 +559,9 @@ bool Boot(const SystemBootParameters& params)
else
{
u32 playlist_index;
if (GameList::IsM3UFileName(params.filename.c_str()))
if (IsM3UFileName(params.filename.c_str()))
{
s_media_playlist = GameList::ParseM3UFile(params.filename.c_str());
s_media_playlist = ParseM3UFile(params.filename.c_str());
s_media_playlist_filename = params.filename;
if (s_media_playlist.empty())
{
@ -350,7 +598,7 @@ bool Boot(const SystemBootParameters& params)
if (s_region == ConsoleRegion::Auto)
{
const DiscRegion disc_region = GameList::GetRegionForImage(media.get());
const DiscRegion disc_region = GetRegionForImage(media.get());
if (disc_region != DiscRegion::Other)
{
s_region = GetConsoleRegionForDiscRegion(disc_region);
@ -689,7 +937,7 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer)
return false;
}
playlist_entries = GameList::ParseM3UFile(playlist_filename.c_str());
playlist_entries = ParseM3UFile(playlist_filename.c_str());
if (playlist_entries.empty())
{
g_host_interface->ReportFormattedError("Failed to load save state playlist entries from '%s'",
@ -1191,7 +1439,7 @@ void UpdateMemoryCards()
{
if (!s_media_playlist_filename.empty() && g_settings.memory_card_use_playlist_title)
{
const std::string playlist_title(GameList::GetTitleForPath(s_media_playlist_filename.c_str()));
const std::string playlist_title(GetTitleForPath(s_media_playlist_filename.c_str()));
card = MemoryCard::Open(g_host_interface->GetGameMemoryCardPath(playlist_title.c_str(), i));
}
else if (s_running_game_title.empty())

View File

@ -45,9 +45,29 @@ enum class State
Paused
};
/// Returns true if the filename is a PlayStation executable we can inject.
bool IsExeFileName(const char* path);
/// Returns true if the filename is a Portable Sound Format file we can uncompress/load.
bool IsPsfFileName(const char* path);
/// Returns true if the filename is a M3U Playlist we can handle.
bool IsM3UFileName(const char* path);
/// Parses an M3U playlist, returning the entries.
std::vector<std::string> ParseM3UFile(const char* path);
/// Returns the preferred console type for a disc.
ConsoleRegion GetConsoleRegionForDiscRegion(DiscRegion region);
std::string GetGameCodeForImage(CDImage* cdi);
std::string GetGameCodeForPath(const char* image_path);
DiscRegion GetRegionForCode(std::string_view code);
DiscRegion GetRegionFromSystemArea(CDImage* cdi);
DiscRegion GetRegionForImage(CDImage* cdi);
std::optional<DiscRegion> GetRegionForPath(const char* image_path);
std::string_view GetTitleForPath(const char* path);
State GetState();
void SetState(State new_state);
bool IsRunning();

View File

@ -7,7 +7,6 @@
#include "core/analog_controller.h"
#include "core/bus.h"
#include "core/digital_controller.h"
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/system.h"
#include "libretro_audio_stream.h"
@ -132,7 +131,7 @@ bool LibretroHostInterface::ConfirmMessage(const char* message)
void LibretroHostInterface::GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title)
{
// Just use the filename for now... we don't have the game list. Unless we can pull this from the frontend somehow?
*title = GameList::GetTitleForPath(path);
*title = System::GetTitleForPath(path);
code->clear();
}
@ -1158,7 +1157,7 @@ bool LibretroHostInterface::DiskControlGetImageLabel(unsigned index, char* label
if (image_path.empty())
return false;
const std::string_view title = GameList::GetTitleForPath(label);
const std::string_view title = System::GetTitleForPath(label);
StringUtil::Strlcpy(label, title, len);
Log_DevPrintf("DiskControlGetImagePath(%u) -> %s", index, label);
return true;

View File

@ -1,5 +1,6 @@
#include "gamelistmodel.h"
#include "common/string_util.h"
#include "core/system.h"
static constexpr std::array<const char*, GameListModel::Column_Count> s_column_names = {
{"Type", "Code", "Title", "File Title", "Size", "Region", "Compatibility"}};
@ -69,7 +70,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
case Column_FileTitle:
{
const std::string_view file_title(GameList::GetTitleForPath(ge.path.c_str()));
const std::string_view file_title(System::GetTitleForPath(ge.path.c_str()));
return QString::fromUtf8(file_title.data(), static_cast<int>(file_title.length()));
}
@ -96,7 +97,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
case Column_FileTitle:
{
const std::string_view file_title(GameList::GetTitleForPath(ge.path.c_str()));
const std::string_view file_title(System::GetTitleForPath(ge.path.c_str()));
return QString::fromUtf8(file_title.data(), static_cast<int>(file_title.length()));
}
@ -234,8 +235,8 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
case Column_FileTitle:
{
const std::string_view file_title_left(GameList::GetTitleForPath(left.path.c_str()));
const std::string_view file_title_right(GameList::GetTitleForPath(right.path.c_str()));
const std::string_view file_title_left(System::GetTitleForPath(left.path.c_str()));
const std::string_view file_title_right(System::GetTitleForPath(right.path.c_str()));
if (file_title_left == file_title_right)
return titlesLessThan(left_row, right_row, ascending);

View File

@ -1,6 +1,6 @@
#pragma once
#include "core/game_list.h"
#include "core/types.h"
#include "frontend-common/game_list.h"
#include <QtCore/QAbstractTableModel>
#include <QtGui/QPixmap>
#include <array>

View File

@ -2,7 +2,7 @@
#include "common/assert.h"
#include "common/minizip_helpers.h"
#include "common/string_util.h"
#include "core/game_list.h"
#include "frontend-common/game_list.h"
#include "gamelistsearchdirectoriesmodel.h"
#include "qthostinterface.h"
#include "qtutils.h"

View File

@ -1,7 +1,7 @@
#include "gamelistwidget.h"
#include "common/string_util.h"
#include "core/game_list.h"
#include "core/settings.h"
#include "frontend-common/game_list.h"
#include "gamelistmodel.h"
#include "qthostinterface.h"
#include "qtutils.h"

View File

@ -1,8 +1,8 @@
#include "gamepropertiesdialog.h"
#include "common/cd_image.h"
#include "common/cd_image_hasher.h"
#include "core/game_list.h"
#include "core/settings.h"
#include "frontend-common/game_list.h"
#include "qthostinterface.h"
#include "qtprogresscallback.h"
#include "qtutils.h"

View File

@ -1,5 +1,5 @@
#pragma once
#include "core/game_settings.h"
#include "frontend-common/game_settings.h"
#include "ui_gamepropertiesdialog.h"
#include <QtWidgets/QDialog>
#include <array>

View File

@ -2,10 +2,10 @@
#include "aboutdialog.h"
#include "autoupdaterdialog.h"
#include "common/assert.h"
#include "core/game_list.h"
#include "core/host_display.h"
#include "core/settings.h"
#include "core/system.h"
#include "frontend-common/game_list.h"
#include "gamelistsettingswidget.h"
#include "gamelistwidget.h"
#include "gamepropertiesdialog.h"

View File

@ -6,9 +6,9 @@
#include "common/log.h"
#include "common/string_util.h"
#include "core/controller.h"
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/system.h"
#include "frontend-common/game_list.h"
#include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h"
#include "frontend-common/opengl_host_display.h"

View File

@ -3,6 +3,10 @@ add_library(frontend-common
common_host_interface.h
controller_interface.cpp
controller_interface.h
game_list.cpp
game_list.h
game_settings.cpp
game_settings.h
icon.cpp
icon.h
imgui_styles.cpp
@ -17,7 +21,7 @@ add_library(frontend-common
vulkan_host_display.h
)
target_link_libraries(frontend-common PUBLIC core common imgui simpleini scmversion glad vulkan-loader)
target_link_libraries(frontend-common PUBLIC core common imgui simpleini tinyxml2 scmversion glad vulkan-loader)
if(WIN32)
target_sources(frontend-common PRIVATE

View File

@ -9,7 +9,6 @@
#include "core/cdrom.h"
#include "core/cpu_code_cache.h"
#include "core/dma.h"
#include "core/game_list.h"
#include "core/gpu.h"
#include "core/host_display.h"
#include "core/mdec.h"
@ -18,6 +17,7 @@
#include "core/spu.h"
#include "core/system.h"
#include "core/timers.h"
#include "game_list.h"
#include "imgui.h"
#include "ini_settings_interface.h"
#include "save_state_selector_ui.h"
@ -368,7 +368,7 @@ bool CommonHostInterface::ParseCommandLineParameters(int argc, char* argv[],
else
{
// find the game id, and get its save state path
std::string game_code = m_game_list->GetGameCodeForPath(boot_filename.c_str());
std::string game_code = System::GetGameCodeForPath(boot_filename.c_str());
if (game_code.empty())
{
Log_WarningPrintf("Could not identify game code for '%s', cannot load save state %d.", boot_filename.c_str(),
@ -2032,13 +2032,13 @@ void CommonHostInterface::GetGameInfo(const char* path, CDImage* image, std::str
else
{
if (image)
*code = GameList::GetGameCodeForImage(image);
*code = System::GetGameCodeForImage(image);
const GameListDatabaseEntry* db_entry = (!code->empty()) ? m_game_list->GetDatabaseEntryForCode(*code) : nullptr;
if (db_entry)
*title = db_entry->title;
else
*title = GameList::GetTitleForPath(path);
*title = System::GetTitleForPath(path);
}
}

View File

@ -53,6 +53,9 @@
<ProjectReference Include="..\..\dep\simpleini\simpleini.vcxproj">
<Project>{3773f4cc-614e-4028-8595-22e08ca649e3}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\tinyxml2\tinyxml2.vcxproj">
<Project>{933118a9-68c5-47b4-b151-b03c93961623}</Project>
</ProjectReference>
<ProjectReference Include="..\..\dep\vulkan-loader\vulkan-loader.vcxproj">
<Project>{9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035}</Project>
</ProjectReference>
@ -67,6 +70,8 @@
<ClCompile Include="common_host_interface.cpp" />
<ClCompile Include="controller_interface.cpp" />
<ClCompile Include="d3d11_host_display.cpp" />
<ClCompile Include="game_list.cpp" />
<ClCompile Include="game_settings.cpp" />
<ClCompile Include="icon.cpp" />
<ClCompile Include="imgui_styles.cpp" />
<ClCompile Include="ini_settings_interface.cpp" />
@ -82,6 +87,8 @@
<ClInclude Include="common_host_interface.h" />
<ClInclude Include="controller_interface.h" />
<ClInclude Include="d3d11_host_display.h" />
<ClInclude Include="game_list.h" />
<ClInclude Include="game_settings.h" />
<ClInclude Include="icon.h" />
<ClInclude Include="imgui_styles.h" />
<ClInclude Include="ini_settings_interface.h" />
@ -241,7 +248,7 @@
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
@ -269,7 +276,7 @@
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<SupportJustMyCode>false</SupportJustMyCode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -300,7 +307,7 @@
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
@ -328,7 +335,7 @@
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;_ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<SupportJustMyCode>false</SupportJustMyCode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@ -360,7 +367,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>
<WholeProgramOptimization>false</WholeProgramOptimization>
@ -390,7 +397,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OmitFramePointers>true</OmitFramePointers>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -422,7 +429,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>
<WholeProgramOptimization>false</WholeProgramOptimization>
@ -452,7 +459,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_SDL2=1;WITH_DISCORD_PRESENCE=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\tinyxml2\include;$(SolutionDir)dep\discord-rpc\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OmitFramePointers>true</OmitFramePointers>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<LanguageStandard>stdcpp17</LanguageStandard>

View File

@ -14,6 +14,8 @@
<ClCompile Include="d3d11_host_display.cpp" />
<ClCompile Include="opengl_host_display.cpp" />
<ClCompile Include="xinput_controller_interface.cpp" />
<ClCompile Include="game_settings.cpp" />
<ClCompile Include="game_list.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="icon.h" />
@ -29,6 +31,8 @@
<ClInclude Include="d3d11_host_display.h" />
<ClInclude Include="opengl_host_display.h" />
<ClInclude Include="xinput_controller_interface.h" />
<ClInclude Include="game_list.h" />
<ClInclude Include="game_settings.h" />
</ItemGroup>
<ItemGroup>
<None Include="font_roboto_regular.inl" />

View File

@ -1,5 +1,4 @@
#include "game_list.h"
#include "bios.h"
#include "common/assert.h"
#include "common/byte_stream.h"
#include "common/cd_image.h"
@ -8,12 +7,13 @@
#include "common/log.h"
#include "common/progress_callback.h"
#include "common/string_util.h"
#include "host_interface.h"
#include "settings.h"
#include "core/bios.h"
#include "core/host_interface.h"
#include "core/settings.h"
#include "core/system.h"
#include <algorithm>
#include <array>
#include <cctype>
#include <fstream>
#include <string_view>
#include <tinyxml2.h>
#include <utility>
@ -36,238 +36,6 @@ const char* GameList::EntryCompatibilityRatingToString(GameListCompatibilityRati
return names[static_cast<int>(rating)];
}
std::string GameList::GetGameCodeForPath(const char* image_path)
{
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path);
if (!cdi)
return {};
return GetGameCodeForImage(cdi.get());
}
std::string GameList::GetGameCodeForImage(CDImage* cdi)
{
ISOReader iso;
if (!iso.Open(cdi, 1))
return {};
// Read SYSTEM.CNF
std::vector<u8> system_cnf_data;
if (!iso.ReadFile("SYSTEM.CNF", &system_cnf_data))
return {};
// Parse lines
std::vector<std::pair<std::string, std::string>> lines;
std::pair<std::string, std::string> current_line;
bool reading_value = false;
for (size_t pos = 0; pos < system_cnf_data.size(); pos++)
{
const char ch = static_cast<char>(system_cnf_data[pos]);
if (ch == '\r' || ch == '\n')
{
if (!current_line.first.empty())
{
lines.push_back(std::move(current_line));
current_line = {};
reading_value = false;
}
}
else if (ch == ' ' || (ch >= 0x09 && ch <= 0x0D))
{
continue;
}
else if (ch == '=' && !reading_value)
{
reading_value = true;
}
else
{
if (reading_value)
current_line.second.push_back(ch);
else
current_line.first.push_back(ch);
}
}
if (!current_line.first.empty())
lines.push_back(std::move(current_line));
// Find the BOOT line
auto iter = std::find_if(lines.begin(), lines.end(),
[](const auto& it) { return StringUtil::Strcasecmp(it.first.c_str(), "boot") == 0; });
if (iter == lines.end())
return {};
// cdrom:\SCES_123.45;1
std::string code = iter->second;
std::string::size_type pos = code.rfind('\\');
if (pos != std::string::npos)
{
code.erase(0, pos + 1);
}
else
{
// cdrom:SCES_123.45;1
pos = code.rfind(':');
if (pos != std::string::npos)
code.erase(0, pos + 1);
}
pos = code.find(';');
if (pos != std::string::npos)
code.erase(pos);
// SCES_123.45 -> SCES-12345
for (pos = 0; pos < code.size();)
{
if (code[pos] == '.')
{
code.erase(pos, 1);
continue;
}
if (code[pos] == '_')
code[pos] = '-';
else
code[pos] = static_cast<char>(std::toupper(code[pos]));
pos++;
}
return code;
}
DiscRegion GameList::GetRegionForCode(std::string_view code)
{
std::string prefix;
for (size_t pos = 0; pos < code.length(); pos++)
{
const int ch = std::tolower(code[pos]);
if (ch < 'a' || ch > 'z')
break;
prefix.push_back(static_cast<char>(ch));
}
if (prefix == "sces" || prefix == "sced" || prefix == "sles" || prefix == "sled")
return DiscRegion::PAL;
else if (prefix == "scps" || prefix == "slps" || prefix == "slpm" || prefix == "sczs" || prefix == "papx")
return DiscRegion::NTSC_J;
else if (prefix == "scus" || prefix == "slus")
return DiscRegion::NTSC_U;
else
return DiscRegion::Other;
}
DiscRegion GameList::GetRegionFromSystemArea(CDImage* cdi)
{
// The license code is on sector 4 of the disc.
u8 sector[CDImage::DATA_SECTOR_SIZE];
if (!cdi->Seek(1, 4) || cdi->Read(CDImage::ReadMode::DataOnly, 1, sector) != 1)
return DiscRegion::Other;
static constexpr char ntsc_u_string[] = " Licensed by Sony Computer Entertainment Amer ica ";
static constexpr char ntsc_j_string[] = " Licensed by Sony Computer Entertainment Inc.";
static constexpr char pal_string[] = " Licensed by Sony Computer Entertainment Euro pe";
// subtract one for the terminating null
if (std::equal(ntsc_u_string, ntsc_u_string + countof(ntsc_u_string) - 1, sector))
return DiscRegion::NTSC_U;
else if (std::equal(ntsc_j_string, ntsc_j_string + countof(ntsc_j_string) - 1, sector))
return DiscRegion::NTSC_J;
else if (std::equal(pal_string, pal_string + countof(pal_string) - 1, sector))
return DiscRegion::PAL;
else
return DiscRegion::Other;
}
DiscRegion GameList::GetRegionForImage(CDImage* cdi)
{
DiscRegion system_area_region = GetRegionFromSystemArea(cdi);
if (system_area_region != DiscRegion::Other)
return system_area_region;
std::string code = GetGameCodeForImage(cdi);
if (code.empty())
return DiscRegion::Other;
return GetRegionForCode(code);
}
std::optional<DiscRegion> GameList::GetRegionForPath(const char* image_path)
{
std::unique_ptr<CDImage> cdi = CDImage::Open(image_path);
if (!cdi)
return {};
return GetRegionForImage(cdi.get());
}
bool GameList::IsExeFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension &&
(StringUtil::Strcasecmp(extension, ".exe") == 0 || StringUtil::Strcasecmp(extension, ".psexe") == 0));
}
bool GameList::IsPsfFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension && StringUtil::Strcasecmp(extension, ".psf") == 0);
}
bool GameList::IsM3UFileName(const char* path)
{
const char* extension = std::strrchr(path, '.');
return (extension && StringUtil::Strcasecmp(extension, ".m3u") == 0);
}
std::vector<std::string> GameList::ParseM3UFile(const char* path)
{
std::ifstream ifs(path);
if (!ifs.is_open())
{
Log_ErrorPrintf("Failed to open %s", path);
return {};
}
std::vector<std::string> entries;
std::string line;
while (std::getline(ifs, line))
{
u32 start_offset = 0;
while (start_offset < line.size() && std::isspace(line[start_offset]))
start_offset++;
// skip comments
if (start_offset == line.size() || line[start_offset] == '#')
continue;
// strip ending whitespace
u32 end_offset = static_cast<u32>(line.size()) - 1;
while (std::isspace(line[end_offset]) && end_offset > start_offset)
end_offset--;
// anything?
if (start_offset == end_offset)
continue;
std::string entry_path(line.begin() + start_offset, line.begin() + end_offset + 1);
if (!FileSystem::IsAbsolutePath(entry_path))
{
SmallString absolute_path;
FileSystem::BuildPathRelativeToFile(absolute_path, path, entry_path.c_str());
entry_path = absolute_path;
}
Log_DevPrintf("Read path from m3u: '%s'", entry_path.c_str());
entries.push_back(std::move(entry_path));
}
Log_InfoPrintf("Loaded %zu paths from m3u '%s'", entries.size(), path);
return entries;
}
const char* GameList::GetGameListCompatibilityRatingString(GameListCompatibilityRating rating)
{
static constexpr std::array<const char*, static_cast<size_t>(GameListCompatibilityRating::Count)> names = {
@ -292,21 +60,6 @@ static std::string_view GetFileNameFromPath(const char* path)
return std::string_view(filename_start + 1, filename_end - filename_start);
}
std::string_view GameList::GetTitleForPath(const char* path)
{
const char* extension = std::strrchr(path, '.');
if (path == extension)
return path;
const char* path_end = path + std::strlen(path);
const char* title_end = extension ? (extension - 1) : (path_end);
const char* title_start = std::max(std::strrchr(path, '/'), std::strrchr(path, '\\'));
if (!title_start || title_start == path)
return std::string_view(path, title_end - title_start);
else
return std::string_view(title_start + 1, title_end - title_start);
}
bool GameList::GetExeListEntry(const char* path, GameListEntry* entry)
{
FILESYSTEM_STAT_DATA ffd;
@ -360,12 +113,12 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
if (!FileSystem::StatFile(path, &ffd))
return false;
std::vector<std::string> entries = ParseM3UFile(path);
std::vector<std::string> entries = System::ParseM3UFile(path);
if (entries.empty())
return false;
entry->code.clear();
entry->title = GetTitleForPath(path);
entry->title = System::GetTitleForPath(path);
entry->path = path;
entry->region = DiscRegion::Other;
entry->total_size = 0;
@ -385,11 +138,11 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
entry->total_size += static_cast<u64>(CDImage::RAW_SECTOR_SIZE) * static_cast<u64>(entry_image->GetLBACount());
if (entry->region == DiscRegion::Other)
entry->region = GetRegionForImage(entry_image.get());
entry->region = System::GetRegionForImage(entry_image.get());
if (entry->compatibility_rating == GameListCompatibilityRating::Unknown)
{
std::string code = GetGameCodeForImage(entry_image.get());
std::string code = System::GetGameCodeForImage(entry_image.get());
const GameListCompatibilityEntry* compatibility_entry = GetCompatibilityEntryForCode(entry->code);
if (compatibility_entry)
entry->compatibility_rating = compatibility_entry->compatibility_rating;
@ -403,19 +156,19 @@ bool GameList::GetM3UListEntry(const char* path, GameListEntry* entry)
bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
{
if (IsExeFileName(path.c_str()))
if (System::IsExeFileName(path.c_str()))
return GetExeListEntry(path.c_str(), entry);
if (IsM3UFileName(path.c_str()))
if (System::IsM3UFileName(path.c_str()))
return GetM3UListEntry(path.c_str(), entry);
std::unique_ptr<CDImage> cdi = CDImage::Open(path.c_str());
if (!cdi)
return false;
std::string code = GetGameCodeForImage(cdi.get());
DiscRegion region = GetRegionFromSystemArea(cdi.get());
std::string code = System::GetGameCodeForImage(cdi.get());
DiscRegion region = System::GetRegionFromSystemArea(cdi.get());
if (region == DiscRegion::Other)
region = GetRegionForCode(code);
region = System::GetRegionForCode(code);
entry->path = path;
entry->code = std::move(code);
@ -428,7 +181,7 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
if (entry->code.empty())
{
// no game code, so use the filename title
entry->title = GetTitleForPath(path.c_str());
entry->title = System::GetTitleForPath(path.c_str());
entry->compatibility_rating = GameListCompatibilityRating::Unknown;
}
else
@ -444,7 +197,7 @@ bool GameList::GetGameListEntry(const std::string& path, GameListEntry* entry)
else
{
Log_WarningPrintf("'%s' not found in database", entry->code.c_str());
entry->title = GetTitleForPath(path.c_str());
entry->title = System::GetTitleForPath(path.c_str());
}
const GameListCompatibilityEntry* compatibility_entry = GetCompatibilityEntryForCode(entry->code);
@ -825,7 +578,7 @@ public:
{
GameListDatabaseEntry gde;
gde.code = std::move(code);
gde.region = GameList::GetRegionForCode(gde.code);
gde.region = System::GetRegionForCode(gde.code);
gde.title = name;
m_database.emplace(gde.code, std::move(gde));
}

View File

@ -1,6 +1,6 @@
#pragma once
#include "core/types.h"
#include "game_settings.h"
#include "types.h"
#include <memory>
#include <optional>
#include <string>
@ -74,29 +74,9 @@ public:
static const char* EntryTypeToString(GameListEntryType type);
static const char* EntryCompatibilityRatingToString(GameListCompatibilityRating rating);
/// Returns true if the filename is a PlayStation executable we can inject.
static bool IsExeFileName(const char* path);
/// Returns true if the filename is a Portable Sound Format file we can uncompress/load.
static bool IsPsfFileName(const char* path);
/// Returns true if the filename is a M3U Playlist we can handle.
static bool IsM3UFileName(const char* path);
/// Parses an M3U playlist, returning the entries.
static std::vector<std::string> ParseM3UFile(const char* path);
/// Returns a string representation of a compatibility level.
static const char* GetGameListCompatibilityRatingString(GameListCompatibilityRating rating);
static std::string GetGameCodeForImage(CDImage* cdi);
static std::string GetGameCodeForPath(const char* image_path);
static DiscRegion GetRegionForCode(std::string_view code);
static DiscRegion GetRegionFromSystemArea(CDImage* cdi);
static DiscRegion GetRegionForImage(CDImage* cdi);
static std::optional<DiscRegion> GetRegionForPath(const char* image_path);
static std::string_view GetTitleForPath(const char* path);
const EntryList& GetEntries() const { return m_entries; }
const u32 GetEntryCount() const { return static_cast<u32>(m_entries.size()); }

View File

@ -5,8 +5,8 @@
#include "common/log.h"
#include "common/string.h"
#include "common/string_util.h"
#include "host_interface.h"
#include "settings.h"
#include "core/host_interface.h"
#include "core/settings.h"
#include <array>
#include <utility>
Log_SetChannel(GameSettings);

View File

@ -1,5 +1,5 @@
#pragma once
#include "types.h"
#include "core/types.h"
#include <bitset>
#include <optional>
#include <string>