dolphin/Source/Core/Core/TitleDatabase.cpp
JosJuice 6902bbb696 When NAND is damaged, show title names from save files
The earlier code always tried to use TitleDatabase for getting
title names, but that didn't work for disc-based games, because
there was no way to get the maker ID.
2017-11-03 23:17:36 +01:00

185 lines
6.0 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/TitleDatabase.h"
#include <cstddef>
#include <fstream>
#include <functional>
#include <unordered_map>
#include <utility>
#include "Common/FileUtil.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/IOS/ES/Formats.h"
#include "DiscIO/Enums.h"
namespace Core
{
static std::string GetLanguageCode(DiscIO::Language language)
{
switch (language)
{
case DiscIO::Language::LANGUAGE_JAPANESE:
return "ja";
case DiscIO::Language::LANGUAGE_ENGLISH:
return "en";
case DiscIO::Language::LANGUAGE_GERMAN:
return "de";
case DiscIO::Language::LANGUAGE_FRENCH:
return "fr";
case DiscIO::Language::LANGUAGE_SPANISH:
return "es";
case DiscIO::Language::LANGUAGE_ITALIAN:
return "it";
case DiscIO::Language::LANGUAGE_DUTCH:
return "nl";
case DiscIO::Language::LANGUAGE_SIMPLIFIED_CHINESE:
return "zh_CN";
case DiscIO::Language::LANGUAGE_TRADITIONAL_CHINESE:
return "zh_TW";
case DiscIO::Language::LANGUAGE_KOREAN:
return "ko";
default:
return "en";
}
}
using Map = std::unordered_map<std::string, std::string>;
// Note that this function will not overwrite entries that already are in the maps
static bool LoadMap(const std::string& file_path, Map& map,
std::function<bool(const std::string& game_id)> predicate)
{
std::ifstream txt;
File::OpenFStream(txt, file_path, std::ios::in);
if (!txt.is_open())
return false;
std::string line;
while (std::getline(txt, line))
{
if (line.empty())
continue;
const size_t equals_index = line.find('=');
if (equals_index != std::string::npos)
{
const std::string game_id = StripSpaces(line.substr(0, equals_index));
if (game_id.length() >= 4 && predicate(game_id))
map.emplace(game_id, StripSpaces(line.substr(equals_index + 1)));
}
}
return true;
}
// This should only be used with the common game ID format (used by WiiTDBs), not Dolphin's.
// Otherwise, TurboGrafx-16 VC games (with the system ID P) will be misdetected as GameCube titles.
// The formats differ in that Dolphin's uses 6 characters for non-disc titles instead of 4.
static bool IsGCTitle(const std::string& game_id)
{
const char system_id = game_id[0];
return game_id.length() == 6 &&
(system_id == 'G' || system_id == 'D' || system_id == 'U' || system_id == 'P');
}
static bool IsWiiTitle(const std::string& game_id)
{
// Assume that any non-GameCube title is a Wii title.
return !IsGCTitle(game_id);
}
static bool IsJapaneseGCTitle(const std::string& game_id)
{
return IsGCTitle(game_id) && DiscIO::CountrySwitch(game_id[3]) == DiscIO::Country::COUNTRY_JAPAN;
}
static bool IsNonJapaneseGCTitle(const std::string& game_id)
{
return IsGCTitle(game_id) && DiscIO::CountrySwitch(game_id[3]) != DiscIO::Country::COUNTRY_JAPAN;
}
// Note that this function will not overwrite entries that already are in the maps
static bool LoadMap(const std::string& file_path, Map& gc_map, Map& wii_map)
{
Map map;
if (!LoadMap(file_path, map, [](const auto& game_id) { return true; }))
return false;
for (auto& entry : map)
{
auto& destination_map = IsGCTitle(entry.first) ? gc_map : wii_map;
destination_map.emplace(std::move(entry));
}
return true;
}
TitleDatabase::TitleDatabase()
{
// Load the user databases.
const std::string& load_directory = File::GetUserPath(D_LOAD_IDX);
if (!LoadMap(load_directory + "wiitdb.txt", m_gc_title_map, m_wii_title_map))
LoadMap(load_directory + "titles.txt", m_gc_title_map, m_wii_title_map);
if (!SConfig::GetInstance().m_use_builtin_title_database)
return;
// Load the database in the console language.
// Note: The GameCube language setting can't be set to Japanese,
// so instead, we use Japanese names iff the games are NTSC-J.
const std::string gc_code = GetLanguageCode(SConfig::GetInstance().GetCurrentLanguage(false));
const std::string wii_code = GetLanguageCode(SConfig::GetInstance().GetCurrentLanguage(true));
LoadMap(File::GetSysDirectory() + "wiitdb-ja.txt", m_gc_title_map, IsJapaneseGCTitle);
if (gc_code != "en")
{
LoadMap(File::GetSysDirectory() + "wiitdb-" + gc_code + ".txt", m_gc_title_map,
IsNonJapaneseGCTitle);
}
if (wii_code != "en")
LoadMap(File::GetSysDirectory() + "wiitdb-" + wii_code + ".txt", m_wii_title_map, IsWiiTitle);
// Load the English database as the base database.
LoadMap(File::GetSysDirectory() + "wiitdb-en.txt", m_gc_title_map, m_wii_title_map);
// Titles that cannot be part of the Wii TDB,
// but common enough to justify having entries for them.
// i18n: "Wii Menu" (or System Menu) refers to the Wii's main menu,
// which is (usually) the first thing users see when a Wii console starts.
m_wii_title_map.emplace("0000000100000002", GetStringT("Wii Menu"));
for (const auto& id : {"HAXX", "JODI", "00010001af1bf516", "LULZ", "OHBC"})
m_wii_title_map.emplace(id, "The Homebrew Channel");
}
TitleDatabase::~TitleDatabase() = default;
std::string TitleDatabase::GetTitleName(const std::string& game_id, TitleType type) const
{
const auto& map = IsWiiTitle(game_id) ? m_wii_title_map : m_gc_title_map;
const std::string key =
type == TitleType::Channel && game_id.length() == 6 ? game_id.substr(0, 4) : game_id;
const auto iterator = map.find(key);
return iterator != map.end() ? iterator->second : "";
}
std::string TitleDatabase::GetChannelName(u64 title_id) const
{
const std::string id{
{static_cast<char>((title_id >> 24) & 0xff), static_cast<char>((title_id >> 16) & 0xff),
static_cast<char>((title_id >> 8) & 0xff), static_cast<char>(title_id & 0xff)}};
return GetTitleName(id, TitleType::Channel);
}
std::string TitleDatabase::Describe(const std::string& game_id, TitleType type) const
{
const std::string title_name = GetTitleName(game_id, type);
if (title_name.empty())
return game_id;
return StringFromFormat("%s (%s)", title_name.c_str(), game_id.c_str());
}
} // namespace Core