From 235ecfbed71986f0be2ecf469a10e1105dcb3c96 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Thu, 9 Apr 2015 17:44:53 +0200 Subject: [PATCH 1/5] Return GetNames languages, to avoid hardcoded language lists in callers This makes the code cleaner and also leads to some user-visible changes: The wx game properties will no longer let the user select WAD languages that don't have any names. The Qt game list will now display names using the languages set in the configuration instead of always using English for PAL GC games and Japanese for WADs. If a WAD doesn't have a name in the user's preferred language, English is now selected as a fallback before Japanese. --- Source/Core/Core/CoreParameter.cpp | 14 ++ Source/Core/Core/CoreParameter.h | 2 + Source/Core/DiscIO/BannerLoader.h | 6 +- Source/Core/DiscIO/BannerLoaderGC.cpp | 60 ++++---- Source/Core/DiscIO/BannerLoaderGC.h | 5 +- Source/Core/DiscIO/BannerLoaderWii.cpp | 23 +-- Source/Core/DiscIO/BannerLoaderWii.h | 5 +- Source/Core/DiscIO/Volume.h | 60 +++++--- Source/Core/DiscIO/VolumeCommon.cpp | 3 +- Source/Core/DiscIO/VolumeDirectory.cpp | 7 +- Source/Core/DiscIO/VolumeDirectory.h | 2 +- Source/Core/DiscIO/VolumeGC.cpp | 7 +- Source/Core/DiscIO/VolumeGC.h | 3 +- Source/Core/DiscIO/VolumeWad.cpp | 20 ++- Source/Core/DiscIO/VolumeWad.h | 3 +- Source/Core/DiscIO/VolumeWiiCrypted.cpp | 7 +- Source/Core/DiscIO/VolumeWiiCrypted.h | 3 +- Source/Core/DolphinQt/GameList/GameFile.cpp | 131 ++++++++++-------- Source/Core/DolphinQt/GameList/GameFile.h | 18 +-- Source/Core/DolphinQt/GameList/GameGrid.cpp | 2 +- Source/Core/DolphinQt/GameList/GameTree.cpp | 2 +- .../Core/DolphinWX/Config/WiiConfigPane.cpp | 63 ++++----- Source/Core/DolphinWX/Config/WiiConfigPane.h | 3 +- Source/Core/DolphinWX/GameListCtrl.cpp | 47 ++----- Source/Core/DolphinWX/ISOFile.cpp | 98 +++++++------ Source/Core/DolphinWX/ISOFile.h | 18 ++- Source/Core/DolphinWX/ISOProperties.cpp | 116 ++++++++-------- Source/Core/DolphinWX/ISOProperties.h | 4 +- Source/Core/DolphinWX/MainAndroid.cpp | 5 +- Source/Core/DolphinWX/NetPlay/NetWindow.cpp | 2 +- 30 files changed, 399 insertions(+), 340 deletions(-) diff --git a/Source/Core/Core/CoreParameter.cpp b/Source/Core/Core/CoreParameter.cpp index 0694b4c07d..bce8101b09 100644 --- a/Source/Core/Core/CoreParameter.cpp +++ b/Source/Core/Core/CoreParameter.cpp @@ -373,6 +373,20 @@ void SCoreStartupParameter::CheckMemcardPath(std::string& memcardPath, std::stri } } +IVolume::ELanguage SCoreStartupParameter::GetCurrentLanguage(bool wii) const +{ + IVolume::ELanguage language; + if (wii) + language = (IVolume::ELanguage)SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); + else + language = (IVolume::ELanguage)(SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage + 1); + + // Get rid of invalid values (probably doesn't matter, but might as well do it) + if (language > IVolume::ELanguage::LANGUAGE_UNKNOWN || language < 0) + language = IVolume::ELanguage::LANGUAGE_UNKNOWN; + return language; +} + IniFile SCoreStartupParameter::LoadDefaultGameIni() const { return LoadDefaultGameIni(GetUniqueID(), m_revision); diff --git a/Source/Core/Core/CoreParameter.h b/Source/Core/Core/CoreParameter.h index e5f9cac9b1..381128a1f0 100644 --- a/Source/Core/Core/CoreParameter.h +++ b/Source/Core/Core/CoreParameter.h @@ -7,6 +7,7 @@ #include #include "Common/IniFile.h" +#include "DiscIO/Volume.h" enum Hotkey { @@ -248,6 +249,7 @@ struct SCoreStartupParameter bool AutoSetup(EBootBS2 _BootBS2); const std::string &GetUniqueID() const { return m_strUniqueID; } void CheckMemcardPath(std::string& memcardPath, std::string gameRegion, bool isSlotA); + DiscIO::IVolume::ELanguage GetCurrentLanguage(bool wii) const; IniFile LoadDefaultGameIni() const; IniFile LoadLocalGameIni() const; diff --git a/Source/Core/DiscIO/BannerLoader.h b/Source/Core/DiscIO/BannerLoader.h index 7d6a25b8cf..31a09f56d0 100644 --- a/Source/Core/DiscIO/BannerLoader.h +++ b/Source/Core/DiscIO/BannerLoader.h @@ -4,10 +4,12 @@ #pragma once +#include #include #include #include "Common/CommonTypes.h" +#include "DiscIO/Volume.h" namespace DiscIO { @@ -28,9 +30,9 @@ public: virtual std::vector GetBanner(int* pWidth, int* pHeight) = 0; - virtual std::vector GetNames() = 0; + virtual std::map GetNames() = 0; virtual std::string GetCompany() = 0; - virtual std::vector GetDescriptions() = 0; + virtual std::map GetDescriptions() = 0; bool IsValid() { diff --git a/Source/Core/DiscIO/BannerLoaderGC.cpp b/Source/Core/DiscIO/BannerLoaderGC.cpp index ce265a016e..a5da3c4512 100644 --- a/Source/Core/DiscIO/BannerLoaderGC.cpp +++ b/Source/Core/DiscIO/BannerLoaderGC.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include @@ -60,9 +61,9 @@ std::vector CBannerLoaderGC::GetBanner(int* pWidth, int* pHeight) } -std::vector CBannerLoaderGC::GetNames() +std::map CBannerLoaderGC::GetNames() { - std::vector names; + std::map names; if (!IsValid()) { @@ -70,16 +71,21 @@ std::vector CBannerLoaderGC::GetNames() } u32 name_count = 0; + IVolume::ELanguage language; + bool is_japanese = m_country == IVolume::ECountry::COUNTRY_JAPAN; // find Banner type switch (m_BNRType) { case CBannerLoaderGC::BANNER_BNR1: name_count = 1; + language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; break; + // English, German, French, Spanish, Italian, Dutch case CBannerLoaderGC::BANNER_BNR2: name_count = 6; + language = IVolume::ELanguage::LANGUAGE_ENGLISH; break; default: @@ -88,20 +94,16 @@ std::vector CBannerLoaderGC::GetNames() auto const banner = reinterpret_cast(m_pBannerFile); - for (u32 i = 0; i != name_count; ++i) + for (u32 i = 0; i < name_count; ++i) { auto& comment = banner->comment[i]; + std::string name = GetDecodedString(comment.longTitle); - if (comment.longTitle[0]) - { - auto& data = comment.longTitle; - names.push_back(GetDecodedString(data)); - } - else - { - auto& data = comment.shortTitle; - names.push_back(GetDecodedString(data)); - } + if (name.empty()) + name = GetDecodedString(comment.shortTitle); + + if (!name.empty()) + names[(IVolume::ELanguage)(language + i)] = name; } return names; @@ -123,9 +125,9 @@ std::string CBannerLoaderGC::GetCompany() } -std::vector CBannerLoaderGC::GetDescriptions() +std::map CBannerLoaderGC::GetDescriptions() { - std::vector descriptions; + std::map descriptions; if (!IsValid()) { @@ -133,16 +135,20 @@ std::vector CBannerLoaderGC::GetDescriptions() } u32 desc_count = 0; + IVolume::ELanguage language; + bool is_japanese = m_country == IVolume::ECountry::COUNTRY_JAPAN; // find Banner type switch (m_BNRType) { case CBannerLoaderGC::BANNER_BNR1: desc_count = 1; + language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; break; // English, German, French, Spanish, Italian, Dutch case CBannerLoaderGC::BANNER_BNR2: + language = IVolume::ELanguage::LANGUAGE_ENGLISH; desc_count = 6; break; @@ -152,10 +158,13 @@ std::vector CBannerLoaderGC::GetDescriptions() auto banner = reinterpret_cast(m_pBannerFile); - for (u32 i = 0; i != desc_count; ++i) + for (u32 i = 0; i < desc_count; ++i) { auto& data = banner->comment[i].comment; - descriptions.push_back(GetDecodedString(data)); + std::string description = GetDecodedString(data); + + if (!description.empty()) + descriptions[(IVolume::ELanguage)(language + i)] = description; } return descriptions; @@ -164,20 +173,15 @@ std::vector CBannerLoaderGC::GetDescriptions() CBannerLoaderGC::BANNER_TYPE CBannerLoaderGC::getBannerType() { u32 bannerSignature = *(u32*)m_pBannerFile; - CBannerLoaderGC::BANNER_TYPE type = CBannerLoaderGC::BANNER_UNKNOWN; switch (bannerSignature) { - // "BNR1" - case 0x31524e42: - type = CBannerLoaderGC::BANNER_BNR1; - break; - - // "BNR2" - case 0x32524e42: - type = CBannerLoaderGC::BANNER_BNR2; - break; + case 0x31524e42: // "BNR1" + return CBannerLoaderGC::BANNER_BNR1; + case 0x32524e42: // "BNR2" + return CBannerLoaderGC::BANNER_BNR2; + default: + return CBannerLoaderGC::BANNER_UNKNOWN; } - return type; } } // namespace diff --git a/Source/Core/DiscIO/BannerLoaderGC.h b/Source/Core/DiscIO/BannerLoaderGC.h index 94e261699c..b381e10f92 100644 --- a/Source/Core/DiscIO/BannerLoaderGC.h +++ b/Source/Core/DiscIO/BannerLoaderGC.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -28,9 +29,9 @@ public: virtual std::vector GetBanner(int* pWidth, int* pHeight) override; - virtual std::vector GetNames() override; + virtual std::map GetNames() override; virtual std::string GetCompany() override; - virtual std::vector GetDescriptions() override; + virtual std::map GetDescriptions() override; private: enum diff --git a/Source/Core/DiscIO/BannerLoaderWii.cpp b/Source/Core/DiscIO/BannerLoaderWii.cpp index eaab54a942..1de9120c10 100644 --- a/Source/Core/DiscIO/BannerLoaderWii.cpp +++ b/Source/Core/DiscIO/BannerLoaderWii.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -91,14 +92,15 @@ bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::stri return false; } -std::vector CBannerLoaderWii::GetNames() +std::map CBannerLoaderWii::GetNames() { - std::vector ret(1); + std::map result; - if (!GetStringFromComments(NAME_IDX, ret[0])) - ret.clear(); + std::string name; + if (GetStringFromComments(NAME_IDX, name)) + result[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; - return ret; + return result; } std::string CBannerLoaderWii::GetCompany() @@ -106,11 +108,14 @@ std::string CBannerLoaderWii::GetCompany() return ""; } -std::vector CBannerLoaderWii::GetDescriptions() +std::map CBannerLoaderWii::GetDescriptions() { - std::vector result(1); - if (!GetStringFromComments(DESC_IDX, result[0])) - result.clear(); + std::map result; + + std::string name; + if (GetStringFromComments(DESC_IDX, name)) + result[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; + return result; } diff --git a/Source/Core/DiscIO/BannerLoaderWii.h b/Source/Core/DiscIO/BannerLoaderWii.h index 1bbe077509..29d3b0f470 100644 --- a/Source/Core/DiscIO/BannerLoaderWii.h +++ b/Source/Core/DiscIO/BannerLoaderWii.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -25,9 +26,9 @@ public: virtual std::vector GetBanner(int* pWidth, int* pHeight) override; - virtual std::vector GetNames() override; + virtual std::map GetNames() override; virtual std::string GetCompany() override; - virtual std::vector GetDescriptions() override; + virtual std::map GetDescriptions() override; private: enum diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 6efe04a37f..50e09c34d1 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -16,6 +17,43 @@ namespace DiscIO class IVolume { public: + // Increment CACHE_REVISION if the enums below are modified (ISOFile.cpp & GameFile.cpp) + enum ECountry + { + COUNTRY_EUROPE = 0, + COUNTRY_JAPAN, + COUNTRY_USA, + COUNTRY_AUSTRALIA, + COUNTRY_FRANCE, + COUNTRY_GERMANY, + COUNTRY_ITALY, + COUNTRY_KOREA, + COUNTRY_NETHERLANDS, + COUNTRY_RUSSIA, + COUNTRY_SPAIN, + COUNTRY_TAIWAN, + COUNTRY_WORLD, + COUNTRY_UNKNOWN, + NUMBER_OF_COUNTRIES + }; + + // Languages 0 - 9 match the official Wii language numbering. + // Languages 1 - 6 match the official GC PAL languages 0 - 5. + enum ELanguage + { + LANGUAGE_JAPANESE = 0, + LANGUAGE_ENGLISH = 1, + LANGUAGE_GERMAN = 2, + LANGUAGE_FRENCH = 3, + LANGUAGE_SPANISH = 4, + LANGUAGE_ITALIAN = 5, + LANGUAGE_DUTCH = 6, + LANGUAGE_SIMPLIFIED_CHINESE = 7, + LANGUAGE_TRADITIONAL_CHINESE = 8, + LANGUAGE_KOREAN = 9, + LANGUAGE_UNKNOWN + }; + IVolume() {} virtual ~IVolume() {} @@ -39,7 +77,7 @@ public: virtual int GetRevision() const { return 0; } // TODO: eliminate? virtual std::string GetName() const; - virtual std::vector GetNames() const = 0; + virtual std::map GetNames() const = 0; virtual u32 GetFSTSize() const = 0; virtual std::string GetApploaderDate() const = 0; @@ -50,26 +88,6 @@ public: virtual bool CheckIntegrity() const { return false; } virtual bool ChangePartition(u64 offset) { return false; } - // Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) - enum ECountry - { - COUNTRY_EUROPE = 0, - COUNTRY_JAPAN, - COUNTRY_USA, - COUNTRY_AUSTRALIA, - COUNTRY_FRANCE, - COUNTRY_GERMANY, - COUNTRY_ITALY, - COUNTRY_KOREA, - COUNTRY_NETHERLANDS, - COUNTRY_RUSSIA, - COUNTRY_SPAIN, - COUNTRY_TAIWAN, - COUNTRY_WORLD, - COUNTRY_UNKNOWN, - NUMBER_OF_COUNTRIES - }; - virtual ECountry GetCountry() const = 0; virtual u64 GetSize() const = 0; diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index 87f0c722a7..1728e78732 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include #include #include @@ -104,7 +105,7 @@ std::string IVolume::GetName() const if (names.empty()) return ""; else - return names[0]; + return names.cbegin()->second; } } diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 6f3e4ccb7f..9db6e58e46 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "Common/CommonPaths.h" @@ -183,9 +182,11 @@ std::string CVolumeDirectory::GetMakerID() const return "VOID"; } -std::vector CVolumeDirectory::GetNames() const +std::map CVolumeDirectory::GetNames() const { - return std::vector(1, (char*)(&m_diskHeader[0x20])); + std::map names; + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = (char*)(&m_diskHeader[0x20]); + return names; } void CVolumeDirectory::SetName(const std::string& name) diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h index c3e9c881c2..d283e9051b 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -39,7 +39,7 @@ public: std::string GetMakerID() const override; - std::vector GetNames() const override; + std::map GetNames() const override; void SetName(const std::string&); u32 GetFSTSize() const override; diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp index 132a630cf0..272408011e 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include @@ -92,15 +93,15 @@ int CVolumeGC::GetRevision() const return revision; } -std::vector CVolumeGC::GetNames() const +std::map CVolumeGC::GetNames() const { - std::vector names; + std::map names; auto const string_decoder = GetStringDecoder(GetCountry()); char name[0x60 + 1] = {}; if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) - names.push_back(string_decoder(name)); + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = string_decoder(name); return names; } diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index c2efcd6e9f..e9757df948 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -27,7 +28,7 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector GetNames() const override; + std::map GetNames() const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index 1dc746ea4d..5bc27738da 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -117,9 +118,9 @@ bool CVolumeWAD::IsWadFile() const return true; } -std::vector CVolumeWAD::GetNames() const +std::map CVolumeWAD::GetNames() const { - std::vector names; + std::map names; u32 footer_size; if (!Read(0x1C, 4, (u8*)&footer_size)) @@ -129,26 +130,23 @@ std::vector CVolumeWAD::GetNames() const footer_size = Common::swap32(footer_size); - //Japanese, English, German, French, Spanish, Italian, Dutch, unknown, unknown, Korean - for (int i = 0; i != 10; ++i) + //Japanese, English, German, French, Spanish, Italian, Dutch, Simplified Chinese, Traditional Chinese, Korean + for (int i = 0; i < 10; ++i) { static const u32 string_length = 42; static const u32 bytes_length = string_length * sizeof(u16); u16 temp[string_length]; - if (footer_size < 0xF1 || !Read(0x9C + (i * bytes_length) + m_opening_bnr_offset, bytes_length, (u8*)&temp)) - { - names.push_back(""); - } - else + if (footer_size >= 0xF1 && Read(0x9C + (i * bytes_length) + m_opening_bnr_offset, bytes_length, (u8*)&temp)) { std::wstring out_temp; out_temp.resize(string_length); std::transform(temp, temp + out_temp.size(), out_temp.begin(), (u16(&)(u16))Common::swap16); out_temp.erase(std::find(out_temp.begin(), out_temp.end(), 0x00), out_temp.end()); - - names.push_back(UTF16ToUTF8(out_temp)); + std::string name = UTF16ToUTF8(out_temp); + if (!name.empty()) + names[(IVolume::ELanguage)i] = name; } } diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index 3205da3a24..33dc213aee 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -30,7 +31,7 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector GetNames() const override; + std::map GetNames() const override; u32 GetFSTSize() const override { return 0; } std::string GetApploaderDate() const override { return "0"; } diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index 4c703fdb3f..935d18b8f8 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -191,15 +192,15 @@ int CVolumeWiiCrypted::GetRevision() const return revision; } -std::vector CVolumeWiiCrypted::GetNames() const +std::map CVolumeWiiCrypted::GetNames() const { - std::vector names; + std::map names; auto const string_decoder = CVolumeGC::GetStringDecoder(GetCountry()); char name[0xFF] = {}; if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name, true)) - names.push_back(string_decoder(name)); + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = string_decoder(name); return names; } diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h index 4816bc2ebc..f4712fd230 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/VolumeWiiCrypted.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -30,7 +31,7 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector GetNames() const override; + std::map GetNames() const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; diff --git a/Source/Core/DolphinQt/GameList/GameFile.cpp b/Source/Core/DolphinQt/GameList/GameFile.cpp index 67b7d7855f..9b36e86069 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt/GameList/GameFile.cpp @@ -26,25 +26,50 @@ #include "DolphinQt/Utils/Resources.h" #include "DolphinQt/Utils/Utils.h" -static const u32 CACHE_REVISION = 0x006; +static const u32 CACHE_REVISION = 0x007; static const u32 DATASTREAM_REVISION = 15; // Introduced in Qt 5.2 -static QStringList VectorToStringList(std::vector vec, bool trim = false) +static QMap ConvertLocalizedStrings(std::map strings) { - QStringList result; - if (trim) - { - for (const std::string& member : vec) - result.append(QString::fromStdString(member).trimmed()); - } - else - { - for (const std::string& member : vec) - result.append(QString::fromStdString(member)); - } + QMap result; + + for (auto entry : strings) + result.insert(entry.first, QString::fromStdString(entry.second).trimmed()); + return result; } +template +static QMap CastLocalizedStrings(QMap strings) +{ + QMap result; + + auto end = strings.cend(); + for (auto it = strings.cbegin(); it != end; ++it) + result.insert((to)it.key(), it.value()); + + return result; +} + +static QString GetLanguageString(IVolume::ELanguage language, QMap strings) +{ + if (strings.contains(language)) + return strings.value(language); + + // English tends to be a good fallback when the requested language isn't available + if (language != IVolume::ELanguage::LANGUAGE_ENGLISH) + { + if (strings.contains(IVolume::ELanguage::LANGUAGE_ENGLISH)) + return strings.value(IVolume::ELanguage::LANGUAGE_ENGLISH); + } + + // If English isn't available either, just pick something + if (!strings.empty()) + return strings.cbegin().value(); + + return SL(""); +} + GameFile::GameFile(const QString& fileName) : m_file_name(fileName) { @@ -66,7 +91,7 @@ GameFile::GameFile(const QString& fileName) else m_platform = WII_WAD; - m_volume_names = VectorToStringList(volume->GetNames()); + m_volume_names = ConvertLocalizedStrings(volume->GetNames()); m_country = volume->GetCountry(); m_file_size = volume->GetRawSize(); @@ -92,9 +117,9 @@ GameFile::GameFile(const QString& fileName) if (bannerLoader->IsValid()) { if (m_platform != WII_WAD) - m_names = VectorToStringList(bannerLoader->GetNames()); + m_names = ConvertLocalizedStrings(bannerLoader->GetNames()); m_company = QString::fromStdString(bannerLoader->GetCompany()); - m_descriptions = VectorToStringList(bannerLoader->GetDescriptions(), true); + m_descriptions = ConvertLocalizedStrings(bannerLoader->GetDescriptions()); int width, height; std::vector buffer = bannerLoader->GetBanner(&width, &height); @@ -158,11 +183,15 @@ bool GameFile::LoadFromCache() if (cache_rev != CACHE_REVISION) return false; - int country; + u32 country; + QMap volume_names; + QMap names; + QMap descriptions; stream >> m_folder_name - >> m_volume_names + >> volume_names + >> names >> m_company - >> m_descriptions + >> descriptions >> m_unique_id >> m_file_size >> m_volume_size @@ -173,6 +202,9 @@ bool GameFile::LoadFromCache() >> m_is_disc_two >> m_revision; m_country = (DiscIO::IVolume::ECountry)country; + m_volume_names = CastLocalizedStrings(volume_names); + m_names = CastLocalizedStrings(names); + m_descriptions = CastLocalizedStrings(descriptions); file.close(); return true; } @@ -198,13 +230,14 @@ void GameFile::SaveToCache() stream << CACHE_REVISION; stream << m_folder_name - << m_volume_names + << CastLocalizedStrings(m_volume_names) + << CastLocalizedStrings(m_names) << m_company - << m_descriptions + << CastLocalizedStrings(m_descriptions) << m_unique_id << m_file_size << m_volume_size - << (int)m_country + << (u32)m_country << m_banner << m_compressed << m_platform @@ -233,55 +266,36 @@ QString GameFile::CreateCacheFilename() QString GameFile::GetCompany() const { - if (m_company.isEmpty()) - return QObject::tr("N/A"); - else - return m_company; + return m_company; } -// For all of the following functions that accept an "index" parameter, -// (-1 = Japanese, 0 = English, etc)? - -QString GameFile::GetDescription(int index) const +QString GameFile::GetDescription(IVolume::ELanguage language) const { - if (index < m_descriptions.size()) - return m_descriptions[index]; - - if (!m_descriptions.empty()) - return m_descriptions[0]; - - return SL(""); + return GetLanguageString(language, m_descriptions); } -QString GameFile::GetVolumeName(int index) const +QString GameFile::GetDescription() const { - if (index < m_volume_names.size() && !m_volume_names[index].isEmpty()) - return m_volume_names[index]; - - if (!m_volume_names.isEmpty()) - return m_volume_names[0]; - - return SL(""); + return GetDescription(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_platform != GAMECUBE_DISC)); } -QString GameFile::GetBannerName(int index) const +QString GameFile::GetVolumeName(IVolume::ELanguage language) const { - if (index < m_names.size() && !m_names[index].isEmpty()) - return m_names[index]; - - if (!m_names.isEmpty()) - return m_names[0]; - - return SL(""); + return GetLanguageString(language, m_volume_names); } -QString GameFile::GetName(int index) const +QString GameFile::GetBannerName(IVolume::ELanguage language) const +{ + return GetLanguageString(language, m_names); +} + +QString GameFile::GetName(IVolume::ELanguage language) const { // Prefer name from banner, fallback to name from volume, fallback to filename - QString name = GetBannerName(index); + QString name = GetBannerName(language); if (name.isEmpty()) - name = GetVolumeName(index); + name = GetVolumeName(language); if (name.isEmpty()) { @@ -294,6 +308,11 @@ QString GameFile::GetName(int index) const return name; } +QString GameFile::GetName() const +{ + return GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_platform != GAMECUBE_DISC)); +} + const QString GameFile::GetWiiFSPath() const { std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(m_file_name.toStdString())); diff --git a/Source/Core/DolphinQt/GameList/GameFile.h b/Source/Core/DolphinQt/GameList/GameFile.h index bc6e0ea17a..e6732d3c49 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.h +++ b/Source/Core/DolphinQt/GameList/GameFile.h @@ -4,9 +4,9 @@ #pragma once +#include #include #include -#include #include @@ -22,11 +22,13 @@ public: bool IsValid() const { return m_valid; } QString GetFileName() { return m_file_name; } QString GetFolderName() { return m_folder_name; } - QString GetBannerName(int index) const; - QString GetVolumeName(int index) const; - QString GetName(int index) const; + QString GetBannerName(DiscIO::IVolume::ELanguage language) const; + QString GetVolumeName(DiscIO::IVolume::ELanguage language) const; + QString GetName(DiscIO::IVolume::ELanguage language) const; + QString GetName() const; QString GetCompany() const; - QString GetDescription(int index = 0) const; + QString GetDescription(DiscIO::IVolume::ELanguage language) const; + QString GetDescription() const; int GetRevision() const { return m_revision; } const QString GetUniqueID() const { return m_unique_id; } const QString GetWiiFSPath() const; @@ -53,11 +55,11 @@ private: QString m_folder_name; // TODO: eliminate this and overwrite with names from banner when available? - QStringList m_volume_names; + QMap m_volume_names; QString m_company; - QStringList m_names; - QStringList m_descriptions; + QMap m_names; + QMap m_descriptions; QString m_unique_id; diff --git a/Source/Core/DolphinQt/GameList/GameGrid.cpp b/Source/Core/DolphinQt/GameList/GameGrid.cpp index a326c21d21..c4dd2831d8 100644 --- a/Source/Core/DolphinQt/GameList/GameGrid.cpp +++ b/Source/Core/DolphinQt/GameList/GameGrid.cpp @@ -76,7 +76,7 @@ void DGameGrid::AddGame(GameFile* gameItem) QListWidgetItem* i = new QListWidgetItem; i->setIcon(QIcon(gameItem->GetBitmap() .scaled(GRID_BANNER_WIDTH, GRID_BANNER_HEIGHT, Qt::KeepAspectRatio, Qt::SmoothTransformation))); - i->setText(gameItem->GetName(0)); + i->setText(gameItem->GetName()); if (gameItem->IsCompressed()) i->setTextColor(QColor("#00F")); diff --git a/Source/Core/DolphinQt/GameList/GameTree.cpp b/Source/Core/DolphinQt/GameList/GameTree.cpp index e5039751b2..69a1a84294 100644 --- a/Source/Core/DolphinQt/GameList/GameTree.cpp +++ b/Source/Core/DolphinQt/GameList/GameTree.cpp @@ -110,7 +110,7 @@ void DGameTree::AddGame(GameFile* item) QTreeWidgetItem* i = new QTreeWidgetItem; i->setIcon(COL_TYPE, QIcon(Resources::GetPlatformPixmap(item->GetPlatform()))); i->setIcon(COL_BANNER, QIcon(item->GetBitmap())); - i->setText(COL_TITLE, item->GetName(0)); + i->setText(COL_TITLE, item->GetName()); i->setText(COL_DESCRIPTION, item->GetDescription()); i->setIcon(COL_REGION, QIcon(Resources::GetRegionPixmap(item->GetCountry()))); i->setText(COL_SIZE, NiceSizeFormat(item->GetFileSize())); diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp index 31b957ce89..b2e08b5bee 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp @@ -11,6 +11,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "DiscIO/Volume.h" #include "DolphinWX/WxUtils.h" #include "DolphinWX/Config/WiiConfigPane.h" @@ -125,7 +126,7 @@ void WiiConfigPane::OnConnectKeyboardCheckBoxChanged(wxCommandEvent& event) void WiiConfigPane::OnSystemLanguageChoiceChanged(wxCommandEvent& event) { - int wii_system_lang = m_system_language_choice->GetSelection(); + IVolume::ELanguage wii_system_lang = (IVolume::ELanguage)m_system_language_choice->GetSelection(); SConfig::GetInstance().m_SYSCONF->SetData("IPL.LNG", wii_system_lang); u8 country_code = GetSADRCountryCode(wii_system_lang); @@ -138,41 +139,33 @@ void WiiConfigPane::OnAspectRatioChoiceChanged(wxCommandEvent& event) SConfig::GetInstance().m_SYSCONF->SetData("IPL.AR", m_aspect_ratio_choice->GetSelection()); } -// Change from IPL.LNG value to IPL.SADR country code -u8 WiiConfigPane::GetSADRCountryCode(int language) +// Change from IPL.LNG value to IPL.SADR country code. +// http://wiibrew.org/wiki/Country_Codes +u8 WiiConfigPane::GetSADRCountryCode(IVolume::ELanguage language) { - //http://wiibrew.org/wiki/Country_Codes - u8 country_code = language; - switch (country_code) + switch (language) { - case 0: //Japanese - country_code = 1; //Japan - break; - case 1: //English - country_code = 49; //USA - break; - case 2: //German - country_code = 78; //Germany - break; - case 3: //French - country_code = 77; //France - break; - case 4: //Spanish - country_code = 105; //Spain - break; - case 5: //Italian - country_code = 83; //Italy - break; - case 6: //Dutch - country_code = 94; //Netherlands - break; - case 7: //Simplified Chinese - case 8: //Traditional Chinese - country_code = 157; //China - break; - case 9: //Korean - country_code = 136; //Korea - break; + case IVolume::LANGUAGE_JAPANESE: + return 1; // Japan + case IVolume::LANGUAGE_ENGLISH: + return 49; // USA + case IVolume::LANGUAGE_GERMAN: + return 78; // Germany + case IVolume::LANGUAGE_FRENCH: + return 77; // France + case IVolume::LANGUAGE_SPANISH: + return 105; // Spain + case IVolume::LANGUAGE_ITALIAN: + return 83; // Italy + case IVolume::LANGUAGE_DUTCH: + return 94; // Netherlands + case IVolume::LANGUAGE_SIMPLIFIED_CHINESE: + case IVolume::LANGUAGE_TRADITIONAL_CHINESE: + return 157; // China + case IVolume::LANGUAGE_KOREAN: + return 136; // Korea } - return country_code; + + PanicAlert("Invalid language"); + return 1; } diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.h b/Source/Core/DolphinWX/Config/WiiConfigPane.h index 72ea81548a..1fb57887ca 100644 --- a/Source/Core/DolphinWX/Config/WiiConfigPane.h +++ b/Source/Core/DolphinWX/Config/WiiConfigPane.h @@ -7,6 +7,7 @@ #include #include #include "Common/CommonTypes.h" +#include "DiscIO/Volume.h" class wxCheckBox; class wxChoice; @@ -29,7 +30,7 @@ private: void OnSystemLanguageChoiceChanged(wxCommandEvent&); void OnAspectRatioChoiceChanged(wxCommandEvent&); - static u8 GetSADRCountryCode(int language); + static u8 GetSADRCountryCode(IVolume::ELanguage language); wxArrayString m_system_language_strings; wxArrayString m_aspect_ratio_strings; diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index 66677d0f90..f0bd9268c6 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -99,34 +99,13 @@ static int CompareGameListItems(const GameListItem* iso1, const GameListItem* is sortData = -sortData; } - int indexOne = 0; - int indexOther = 0; - - - // index only matters for WADS and PAL GC games, but invalid indicies for the others - // will return the (only) language in the list - if (iso1->GetPlatform() == GameListItem::WII_WAD) - { - indexOne = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); - } - else // GC - { - indexOne = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage; - } - - if (iso2->GetPlatform() == GameListItem::WII_WAD) - { - indexOther = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); - } - else // GC - { - indexOther = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage; - } + IVolume::ELanguage languageOne = SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(iso1->GetPlatform() != GameListItem::GAMECUBE_DISC); + IVolume::ELanguage languageOther = SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(iso2->GetPlatform() != GameListItem::GAMECUBE_DISC); switch (sortData) { case CGameListCtrl::COLUMN_TITLE: - if (!strcasecmp(iso1->GetName(indexOne).c_str(),iso2->GetName(indexOther).c_str())) + if (!strcasecmp(iso1->GetName(languageOne).c_str(), iso2->GetName(languageOther).c_str())) { if (iso1->GetUniqueID() != iso2->GetUniqueID()) return t * (iso1->GetUniqueID() > iso2->GetUniqueID() ? 1 : -1); @@ -135,16 +114,16 @@ static int CompareGameListItems(const GameListItem* iso1, const GameListItem* is if (iso1->IsDiscTwo() != iso2->IsDiscTwo()) return t * (iso1->IsDiscTwo() ? 1 : -1); } - return strcasecmp(iso1->GetName(indexOne).c_str(), - iso2->GetName(indexOther).c_str()) * t; + return strcasecmp(iso1->GetName(languageOne).c_str(), + iso2->GetName(languageOther).c_str()) * t; case CGameListCtrl::COLUMN_NOTES: { std::string cmp1 = (iso1->GetPlatform() == GameListItem::GAMECUBE_DISC) ? - iso1->GetCompany() : iso1->GetDescription(indexOne); + iso1->GetCompany() : iso1->GetDescription(languageOne); std::string cmp2 = (iso2->GetPlatform() == GameListItem::GAMECUBE_DISC) ? - iso2->GetCompany() : iso2->GetDescription(indexOther); + iso2->GetCompany() : iso2->GetDescription(languageOther); return strcasecmp(cmp1.c_str(), cmp2.c_str()) * t; } case CGameListCtrl::COLUMN_ID: @@ -433,15 +412,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index) // Set the game's banner in the second column SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex); - int SelectedLanguage = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage; - - // Is this sane? - if (rISOFile.GetPlatform() == GameListItem::WII_WAD) - { - SelectedLanguage = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); - } - - std::string name = rISOFile.GetName(SelectedLanguage); + std::string name = rISOFile.GetName(); std::ifstream titlestxt; OpenFStream(titlestxt, File::GetUserPath(D_LOAD_IDX) + "titles.txt", std::ios::in); @@ -474,7 +445,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index) // We show the company string on GameCube only // On Wii we show the description instead as the company string is empty std::string const notes = (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC) ? - rISOFile.GetCompany() : rISOFile.GetDescription(SelectedLanguage); + rISOFile.GetCompany() : rISOFile.GetDescription(); SetItem(_Index, COLUMN_NOTES, StrToWxStr(notes), -1); // Emulation state diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index db1c141de6..5190849435 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -37,11 +38,33 @@ #include "DolphinWX/ISOFile.h" #include "DolphinWX/WxUtils.h" -static const u32 CACHE_REVISION = 0x122; +static const u32 CACHE_REVISION = 0x123; #define DVD_BANNER_WIDTH 96 #define DVD_BANNER_HEIGHT 32 +static std::string GetLanguageString(IVolume::ELanguage language, std::map strings) +{ + auto end = strings.end(); + auto it = strings.find(language); + if (it != end) + return it->second; + + // English tends to be a good fallback when the requested language isn't available + if (language != IVolume::ELanguage::LANGUAGE_ENGLISH) + { + it = strings.find(IVolume::ELanguage::LANGUAGE_ENGLISH); + if (it != end) + return it->second; + } + + // If English isn't available either, just pick something + if (!strings.empty()) + return strings.cbegin()->second; + + return ""; +} + GameListItem::GameListItem(const std::string& _rFileName) : m_FileName(_rFileName) , m_emu_state(0) @@ -202,63 +225,37 @@ std::string GameListItem::CreateCacheFilename() std::string GameListItem::GetCompany() const { - if (m_company.empty()) - return "N/A"; - else - return m_company; + return m_company; } -// (-1 = Japanese, 0 = English, etc)? -std::string GameListItem::GetDescription(int _index) const +std::string GameListItem::GetDescription(IVolume::ELanguage language) const { - const u32 index = _index; - - if (index < m_descriptions.size()) - return m_descriptions[index]; - - if (!m_descriptions.empty()) - return m_descriptions[0]; - - return ""; + return GetLanguageString(language, m_descriptions); } -// (-1 = Japanese, 0 = English, etc)? -std::string GameListItem::GetVolumeName(int _index) const +std::string GameListItem::GetDescription() const { - u32 const index = _index; - - if (index < m_volume_names.size() && !m_volume_names[index].empty()) - return m_volume_names[index]; - - if (!m_volume_names.empty()) - return m_volume_names[0]; - - return ""; + return GetDescription(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_Platform != GAMECUBE_DISC)); } -// (-1 = Japanese, 0 = English, etc)? -std::string GameListItem::GetBannerName(int _index) const +std::string GameListItem::GetVolumeName(IVolume::ELanguage language) const { - u32 const index = _index; - - if (index < m_banner_names.size() && !m_banner_names[index].empty()) - return m_banner_names[index]; - - if (!m_banner_names.empty()) - return m_banner_names[0]; - - return ""; + return GetLanguageString(language, m_volume_names); } -// (-1 = Japanese, 0 = English, etc)? -std::string GameListItem::GetName(int _index) const +std::string GameListItem::GetBannerName(IVolume::ELanguage language) const +{ + return GetLanguageString(language, m_banner_names); +} + +std::string GameListItem::GetName(IVolume::ELanguage language) const { // Prefer name from banner, fallback to name from volume, fallback to filename - std::string name = GetBannerName(_index); + std::string name = GetBannerName(language); if (name.empty()) - name = GetVolumeName(_index); + name = GetVolumeName(language); if (name.empty()) { @@ -269,6 +266,23 @@ std::string GameListItem::GetName(int _index) const return name; } +std::string GameListItem::GetName() const +{ + return GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_Platform != GAMECUBE_DISC)); +} + +std::vector GameListItem::GetLanguages() const +{ + std::map language_strings = m_banner_names; + if (m_volume_names.size() > m_banner_names.size()) + language_strings = m_volume_names; + + std::vector languages; + for (std::pair language_string : language_strings) + languages.emplace_back(language_string.first); + return languages; +} + const std::string GameListItem::GetWiiFSPath() const { DiscIO::IVolume *iso = DiscIO::CreateVolumeFromFilename(m_FileName); diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h index d56f3412b8..9370028a48 100644 --- a/Source/Core/DolphinWX/ISOFile.h +++ b/Source/Core/DolphinWX/ISOFile.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "Common/Common.h" @@ -24,11 +25,14 @@ public: bool IsValid() const {return m_Valid;} const std::string& GetFileName() const {return m_FileName;} - std::string GetBannerName(int index) const; - std::string GetVolumeName(int index) const; - std::string GetName(int index) const; + std::string GetBannerName(IVolume::ELanguage language) const; + std::string GetVolumeName(IVolume::ELanguage language) const; + std::string GetName(IVolume::ELanguage language) const; + std::string GetName() const; std::string GetCompany() const; - std::string GetDescription(int index = 0) const; + std::string GetDescription(IVolume::ELanguage language) const; + std::string GetDescription() const; + std::vector GetLanguages() const; int GetRevision() const { return m_Revision; } const std::string& GetUniqueID() const {return m_UniqueID;} const std::string GetWiiFSPath() const; @@ -58,12 +62,12 @@ private: std::string m_FileName; // TODO: eliminate this and overwrite with names from banner when available? - std::vector m_volume_names; + std::map m_volume_names; // Stuff from banner std::string m_company; - std::vector m_banner_names; - std::vector m_descriptions; + std::map m_banner_names; + std::map m_descriptions; std::string m_UniqueID; diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp index 4d08a5b008..7d93cef1e7 100644 --- a/Source/Core/DolphinWX/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties.cpp @@ -114,9 +114,8 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW { // Load ISO data OpenISO = DiscIO::CreateVolumeFromFilename(fileName); - bool IsWad = OpenISO->IsWadFile(); - // TODO: Is it really necessary to use GetTitleID in case GetUniqueID fails? + // Is it really necessary to use GetTitleID if GetUniqueID fails? game_id = OpenISO->GetUniqueID(); if (game_id.empty()) { @@ -137,7 +136,7 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW bRefreshList = false; - CreateGUIControls(IsWad); + CreateGUIControls(); LoadGameConfig(); @@ -173,33 +172,15 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW break; case DiscIO::IVolume::COUNTRY_USA: m_Country->SetValue(_("USA")); - if (!IsWad) // For (non wad) NTSC Games, there's no multi lang - { - m_Lang->SetSelection(0); - m_Lang->Disable(); - } - break; case DiscIO::IVolume::COUNTRY_JAPAN: m_Country->SetValue(_("Japan")); - if (!IsWad) // For (non wad) NTSC Games, there's no multi lang - { - m_Lang->Insert(_("Japanese"), 0); - m_Lang->SetSelection(0); - m_Lang->Disable(); - } break; case DiscIO::IVolume::COUNTRY_KOREA: m_Country->SetValue(_("Korea")); break; case DiscIO::IVolume::COUNTRY_TAIWAN: m_Country->SetValue(_("Taiwan")); - if (!IsWad) // For (non wad) NTSC Games, there's no multi lang - { - m_Lang->Insert(_("Taiwan"), 0); - m_Lang->SetSelection(0); - m_Lang->Disable(); - } break; case DiscIO::IVolume::COUNTRY_WORLD: m_Country->SetValue(_("World")); @@ -210,27 +191,14 @@ CISOProperties::CISOProperties(const std::string fileName, wxWindow* parent, wxW break; } - if (OpenISO->IsWiiDisc()) // Only one language with Wii banners - { - m_Lang->SetSelection(0); - m_Lang->Disable(); - } - wxString temp = "0x" + StrToWxStr(OpenISO->GetMakerID()); m_MakerID->SetValue(temp); m_Revision->SetValue(wxString::Format("%u", OpenISO->GetRevision())); m_Date->SetValue(StrToWxStr(OpenISO->GetApploaderDate())); m_FST->SetValue(wxString::Format("%u", OpenISO->GetFSTSize())); - // Here we set all the info to be shown (be it SJIS or Ascii) + we set the window title - if (!IsWad) - { - ChangeBannerDetails(SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage); - } - else - { - ChangeBannerDetails(SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG")); - } + // Here we set all the info to be shown + we set the window title + ChangeBannerDetails(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(OpenISO->IsWadFile() || OpenISO->IsWiiDisc())); m_Banner->SetBitmap(OpenGameListItem->GetBitmap()); m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this); @@ -343,7 +311,7 @@ long CISOProperties::GetElementStyle(const char* section, const char* key) return wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER; } -void CISOProperties::CreateGUIControls(bool IsWad) +void CISOProperties::CreateGUIControls() { wxButton* const EditConfig = new wxButton(this, ID_EDITCONFIG, _("Edit Config")); EditConfig->SetToolTip(_("This will let you manually edit the INI config file.")); @@ -526,24 +494,58 @@ void CISOProperties::CreateGUIControls(bool IsWad) m_MD5SumCompute = new wxButton(m_Information, ID_MD5SUMCOMPUTE, _("Compute")); wxStaticText* const m_LangText = new wxStaticText(m_Information, wxID_ANY, _("Show Language:")); - arrayStringFor_Lang.Add(_("English")); - arrayStringFor_Lang.Add(_("German")); - arrayStringFor_Lang.Add(_("French")); - arrayStringFor_Lang.Add(_("Spanish")); - arrayStringFor_Lang.Add(_("Italian")); - arrayStringFor_Lang.Add(_("Dutch")); - int language = SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage; - if (IsWad) - { - arrayStringFor_Lang.Insert(_("Japanese"), 0); - arrayStringFor_Lang.Add(_("Simplified Chinese")); - arrayStringFor_Lang.Add(_("Traditional Chinese")); - arrayStringFor_Lang.Add(_("Korean")); - language = SConfig::GetInstance().m_SYSCONF->GetData("IPL.LNG"); + IVolume::ELanguage preferred_language = SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(OpenISO->IsWadFile() || OpenISO->IsWiiDisc()); + + std::vector languages = OpenGameListItem->GetLanguages(); + int preferred_language_index = 0; + for (size_t i = 0; i < languages.size(); ++i) + { + if (languages[i] == preferred_language) + preferred_language_index = i; + + switch (languages[i]) + { + case IVolume::LANGUAGE_JAPANESE: + arrayStringFor_Lang.Add(_("Japanese")); + break; + case IVolume::LANGUAGE_ENGLISH: + arrayStringFor_Lang.Add(_("English")); + break; + case IVolume::LANGUAGE_GERMAN: + arrayStringFor_Lang.Add(_("German")); + break; + case IVolume::LANGUAGE_FRENCH: + arrayStringFor_Lang.Add(_("French")); + break; + case IVolume::LANGUAGE_SPANISH: + arrayStringFor_Lang.Add(_("Spanish")); + break; + case IVolume::LANGUAGE_ITALIAN: + arrayStringFor_Lang.Add(_("Italian")); + break; + case IVolume::LANGUAGE_DUTCH: + arrayStringFor_Lang.Add(_("Dutch")); + break; + case IVolume::LANGUAGE_SIMPLIFIED_CHINESE: + arrayStringFor_Lang.Add(_("Simplified Chinese")); + break; + case IVolume::LANGUAGE_TRADITIONAL_CHINESE: + arrayStringFor_Lang.Add(_("Traditional Chinese")); + break; + case IVolume::LANGUAGE_KOREAN: + arrayStringFor_Lang.Add(_("Korean")); + break; + case IVolume::LANGUAGE_UNKNOWN: + default: + arrayStringFor_Lang.Add(_("Unknown")); + break; + } } m_Lang = new wxChoice(m_Information, ID_LANG, wxDefaultPosition, wxDefaultSize, arrayStringFor_Lang); - m_Lang->SetSelection(language); + m_Lang->SetSelection(preferred_language_index); + if (arrayStringFor_Lang.size() <= 1) + m_Lang->Disable(); wxStaticText* const m_ShortText = new wxStaticText(m_Information, wxID_ANY, _("Short Name:")); m_ShortName = new wxTextCtrl(m_Information, ID_SHORTNAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY); @@ -603,7 +605,7 @@ void CISOProperties::CreateGUIControls(bool IsWad) sInfoPage->Add(sbBannerDetails, 0, wxEXPAND|wxALL, 5); m_Information->SetSizer(sInfoPage); - if (!IsWad) + if (!OpenISO->IsWadFile()) { wxPanel* const m_Filesystem = new wxPanel(m_Notebook, ID_FILESYSTEM); m_Notebook->AddPage(m_Filesystem, _("Filesystem")); @@ -1477,13 +1479,13 @@ void CISOProperties::ActionReplayButtonClicked(wxCommandEvent& event) void CISOProperties::OnChangeBannerLang(wxCommandEvent& event) { - ChangeBannerDetails(event.GetSelection()); + ChangeBannerDetails(OpenGameListItem->GetLanguages()[event.GetSelection()]); } -void CISOProperties::ChangeBannerDetails(int lang) +void CISOProperties::ChangeBannerDetails(IVolume::ELanguage language) { - wxString const shortName = StrToWxStr(OpenGameListItem->GetName(lang)); - wxString const comment = StrToWxStr(OpenGameListItem->GetDescription(lang)); + wxString const shortName = StrToWxStr(OpenGameListItem->GetName(language)); + wxString const comment = StrToWxStr(OpenGameListItem->GetDescription(language)); wxString const maker = StrToWxStr(OpenGameListItem->GetCompany()); // Updates the information shown in the window diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h index cf771942ff..0c36d64d60 100644 --- a/Source/Core/DolphinWX/ISOProperties.h +++ b/Source/Core/DolphinWX/ISOProperties.h @@ -197,7 +197,7 @@ private: void LaunchExternalEditor(const std::string& filename); - void CreateGUIControls(bool); + void CreateGUIControls(); void OnClose(wxCloseEvent& event); void OnCloseClick(wxCommandEvent& event); void OnEditConfig(wxCommandEvent& event); @@ -240,7 +240,7 @@ private: void PatchList_Load(); void PatchList_Save(); void ActionReplayList_Save(); - void ChangeBannerDetails(int lang); + void ChangeBannerDetails(IVolume::ELanguage language); long GetElementStyle(const char* section, const char* key); void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox); diff --git a/Source/Core/DolphinWX/MainAndroid.cpp b/Source/Core/DolphinWX/MainAndroid.cpp index 1ab7be8c57..9ac5f7735b 100644 --- a/Source/Core/DolphinWX/MainAndroid.cpp +++ b/Source/Core/DolphinWX/MainAndroid.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -114,8 +115,8 @@ static bool MsgAlert(const char* caption, const char* text, bool /*yes_no*/, int #define DVD_BANNER_WIDTH 96 #define DVD_BANNER_HEIGHT 32 -std::vector m_volume_names; -std::vector m_names; +std::map m_volume_names; +std::map m_names; static inline u32 Average32(u32 a, u32 b) { return ((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f); diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp index febb30e570..75d839fe1b 100644 --- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp +++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp @@ -69,7 +69,7 @@ static wxString FailureReasonStringForHostLabel(int reason) static std::string BuildGameName(const GameListItem& game) { // Lang needs to be consistent - auto const lang = 0; + IVolume::ELanguage const lang = IVolume::LANGUAGE_ENGLISH; std::string name(game.GetName(lang)); From ee694e327ada8c42949a3907d6fa222f73f276b0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 10 Apr 2015 22:10:49 +0200 Subject: [PATCH 2/5] Get rid of banner loaders and move their functionality to volumes Having some data available in banner loaders and some other data data available in volumes gets messy, especially with GetNames(), which is available in both but returns different results depending on which one is used. This change drops support for reading names and descriptions from Wii save data. --- Source/Core/DiscIO/BannerLoader.cpp | 28 --- Source/Core/DiscIO/BannerLoader.h | 49 ----- Source/Core/DiscIO/BannerLoaderGC.cpp | 187 -------------------- Source/Core/DiscIO/BannerLoaderGC.h | 87 --------- Source/Core/DiscIO/BannerLoaderWii.cpp | 122 ------------- Source/Core/DiscIO/BannerLoaderWii.h | 64 ------- Source/Core/DiscIO/CMakeLists.txt | 5 +- Source/Core/DiscIO/DiscIO.vcxproj | 6 - Source/Core/DiscIO/DiscIO.vcxproj.filters | 18 -- Source/Core/DiscIO/Volume.h | 26 ++- Source/Core/DiscIO/VolumeCommon.cpp | 55 ++++-- Source/Core/DiscIO/VolumeDirectory.cpp | 13 +- Source/Core/DiscIO/VolumeDirectory.h | 2 + Source/Core/DiscIO/VolumeGC.cpp | 167 ++++++++++++++++- Source/Core/DiscIO/VolumeGC.h | 47 ++++- Source/Core/DiscIO/VolumeWad.h | 5 +- Source/Core/DiscIO/VolumeWiiCrypted.cpp | 18 +- Source/Core/DiscIO/VolumeWiiCrypted.h | 1 + Source/Core/DolphinQt/GameList/GameFile.cpp | 86 +++------ Source/Core/DolphinQt/GameList/GameFile.h | 9 +- Source/Core/DolphinWX/ISOFile.cpp | 80 +++------ Source/Core/DolphinWX/ISOFile.h | 12 +- Source/Core/DolphinWX/MainAndroid.cpp | 97 +++++----- 23 files changed, 393 insertions(+), 791 deletions(-) delete mode 100644 Source/Core/DiscIO/BannerLoader.cpp delete mode 100644 Source/Core/DiscIO/BannerLoader.h delete mode 100644 Source/Core/DiscIO/BannerLoaderGC.cpp delete mode 100644 Source/Core/DiscIO/BannerLoaderGC.h delete mode 100644 Source/Core/DiscIO/BannerLoaderWii.cpp delete mode 100644 Source/Core/DiscIO/BannerLoaderWii.h diff --git a/Source/Core/DiscIO/BannerLoader.cpp b/Source/Core/DiscIO/BannerLoader.cpp deleted file mode 100644 index b5353b5a0f..0000000000 --- a/Source/Core/DiscIO/BannerLoader.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "DiscIO/BannerLoader.h" -#include "DiscIO/BannerLoaderGC.h" -#include "DiscIO/BannerLoaderWii.h" -#include "DiscIO/Filesystem.h" - -namespace DiscIO -{ - -class IBannerLoader; -class IVolume; - -IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume *pVolume) -{ - if (pVolume->IsWiiDisc() || pVolume->IsWadFile()) - return new CBannerLoaderWii(pVolume); - if (_rFileSystem.IsValid()) - return new CBannerLoaderGC(_rFileSystem, pVolume); - - return nullptr; -} - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoader.h b/Source/Core/DiscIO/BannerLoader.h deleted file mode 100644 index 31a09f56d0..0000000000 --- a/Source/Core/DiscIO/BannerLoader.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "DiscIO/Volume.h" - -namespace DiscIO -{ - -class IFileSystem; -class IVolume; - -class IBannerLoader -{ -public: - IBannerLoader() - : m_IsValid(false) - , m_pBannerFile(nullptr) - {} - - virtual ~IBannerLoader() - {} - - virtual std::vector GetBanner(int* pWidth, int* pHeight) = 0; - - virtual std::map GetNames() = 0; - virtual std::string GetCompany() = 0; - virtual std::map GetDescriptions() = 0; - - bool IsValid() - { - return m_IsValid; - } - -protected: - bool m_IsValid; - u8* m_pBannerFile; -}; - -IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume *pVolume); - -} // namespace DiscIO diff --git a/Source/Core/DiscIO/BannerLoaderGC.cpp b/Source/Core/DiscIO/BannerLoaderGC.cpp deleted file mode 100644 index a5da3c4512..0000000000 --- a/Source/Core/DiscIO/BannerLoaderGC.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include -#include -#include - -#include "Common/ColorUtil.h" -#include "Common/CommonTypes.h" -#include "Common/MsgHandler.h" -#include "Common/Logging/Log.h" -#include "DiscIO/BannerLoaderGC.h" -#include "DiscIO/Filesystem.h" -#include "DiscIO/Volume.h" - -namespace DiscIO -{ -CBannerLoaderGC::CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume* volume) - : m_country(volume->GetCountry()) -{ - // load the opening.bnr - size_t FileSize = (size_t) _rFileSystem.GetFileSize("opening.bnr"); - if (FileSize == BNR1_SIZE || FileSize == BNR2_SIZE) - { - m_pBannerFile = new u8[FileSize]; - if (m_pBannerFile) - { - _rFileSystem.ReadFile("opening.bnr", m_pBannerFile, FileSize); - m_BNRType = getBannerType(); - if (m_BNRType == BANNER_UNKNOWN) - PanicAlertT("Invalid opening.bnr found in gcm:\n%s\n You may need to redump this game.", - _rFileSystem.GetVolume()->GetName().c_str()); - else m_IsValid = true; - } - } - else WARN_LOG(DISCIO, "Invalid opening.bnr size: %0lx", - (unsigned long)FileSize); -} - - -CBannerLoaderGC::~CBannerLoaderGC() -{ - if (m_pBannerFile) - { - delete [] m_pBannerFile; - m_pBannerFile = nullptr; - } -} - -std::vector CBannerLoaderGC::GetBanner(int* pWidth, int* pHeight) -{ - std::vector Buffer; - Buffer.resize(DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT); - auto const pBanner = (DVDBanner*)m_pBannerFile; - ColorUtil::decode5A3image(&Buffer[0], pBanner->image, DVD_BANNER_WIDTH, DVD_BANNER_HEIGHT); - *pWidth = DVD_BANNER_WIDTH; - *pHeight = DVD_BANNER_HEIGHT; - return Buffer; -} - - -std::map CBannerLoaderGC::GetNames() -{ - std::map names; - - if (!IsValid()) - { - return names; - } - - u32 name_count = 0; - IVolume::ELanguage language; - bool is_japanese = m_country == IVolume::ECountry::COUNTRY_JAPAN; - - // find Banner type - switch (m_BNRType) - { - case CBannerLoaderGC::BANNER_BNR1: - name_count = 1; - language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; - break; - - // English, German, French, Spanish, Italian, Dutch - case CBannerLoaderGC::BANNER_BNR2: - name_count = 6; - language = IVolume::ELanguage::LANGUAGE_ENGLISH; - break; - - default: - break; - } - - auto const banner = reinterpret_cast(m_pBannerFile); - - for (u32 i = 0; i < name_count; ++i) - { - auto& comment = banner->comment[i]; - std::string name = GetDecodedString(comment.longTitle); - - if (name.empty()) - name = GetDecodedString(comment.shortTitle); - - if (!name.empty()) - names[(IVolume::ELanguage)(language + i)] = name; - } - - return names; -} - - -std::string CBannerLoaderGC::GetCompany() -{ - std::string company; - - if (IsValid()) - { - auto const pBanner = (DVDBanner*)m_pBannerFile; - auto& data = pBanner->comment[0].shortMaker; - company = GetDecodedString(data); - } - - return company; -} - - -std::map CBannerLoaderGC::GetDescriptions() -{ - std::map descriptions; - - if (!IsValid()) - { - return descriptions; - } - - u32 desc_count = 0; - IVolume::ELanguage language; - bool is_japanese = m_country == IVolume::ECountry::COUNTRY_JAPAN; - - // find Banner type - switch (m_BNRType) - { - case CBannerLoaderGC::BANNER_BNR1: - desc_count = 1; - language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; - break; - - // English, German, French, Spanish, Italian, Dutch - case CBannerLoaderGC::BANNER_BNR2: - language = IVolume::ELanguage::LANGUAGE_ENGLISH; - desc_count = 6; - break; - - default: - break; - } - - auto banner = reinterpret_cast(m_pBannerFile); - - for (u32 i = 0; i < desc_count; ++i) - { - auto& data = banner->comment[i].comment; - std::string description = GetDecodedString(data); - - if (!description.empty()) - descriptions[(IVolume::ELanguage)(language + i)] = description; - } - - return descriptions; -} - -CBannerLoaderGC::BANNER_TYPE CBannerLoaderGC::getBannerType() -{ - u32 bannerSignature = *(u32*)m_pBannerFile; - switch (bannerSignature) - { - case 0x31524e42: // "BNR1" - return CBannerLoaderGC::BANNER_BNR1; - case 0x32524e42: // "BNR2" - return CBannerLoaderGC::BANNER_BNR2; - default: - return CBannerLoaderGC::BANNER_UNKNOWN; - } -} - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoaderGC.h b/Source/Core/DiscIO/BannerLoaderGC.h deleted file mode 100644 index b381e10f92..0000000000 --- a/Source/Core/DiscIO/BannerLoaderGC.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -#include "Common/CommonTypes.h" - -#include "DiscIO/BannerLoader.h" -#include "DiscIO/Volume.h" -#include "DiscIO/VolumeGC.h" - -namespace DiscIO -{ - -class IFileSystem; - -class CBannerLoaderGC - : public IBannerLoader -{ -public: - CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume* volume); - virtual ~CBannerLoaderGC(); - - virtual std::vector GetBanner(int* pWidth, int* pHeight) override; - - virtual std::map GetNames() override; - virtual std::string GetCompany() override; - virtual std::map GetDescriptions() override; - -private: - enum - { - DVD_BANNER_WIDTH = 96, - DVD_BANNER_HEIGHT = 32 - }; - - enum BANNER_TYPE - { - BANNER_UNKNOWN, - BANNER_BNR1, - BANNER_BNR2, - }; - - // Banner Comment - struct DVDBannerComment - { - char shortTitle[32]; // Short game title shown in IPL menu - char shortMaker[32]; // Short developer, publisher names shown in IPL menu - char longTitle[64]; // Long game title shown in IPL game start screen - char longMaker[64]; // Long developer, publisher names shown in IPL game start screen - char comment[128]; // Game description shown in IPL game start screen in two lines. - }; - - // "opening.bnr" file format for EU console - struct DVDBanner - { - u32 id; // 'BNR2' - u32 padding[7]; - u16 image[DVD_BANNER_WIDTH * DVD_BANNER_HEIGHT]; // RGB5A3 96x32 texture image - DVDBannerComment comment[6]; // Comments in six languages (only 1 for BNR1 type) - }; - - static const u32 BNR1_SIZE = sizeof(DVDBanner) - sizeof(DVDBannerComment) * 5; - static const u32 BNR2_SIZE = sizeof(DVDBanner); - - template - std::string GetDecodedString(const char (&data)[N]) - { - auto const string_decoder = CVolumeGC::GetStringDecoder(m_country); - - // strnlen to trim NULLs - return string_decoder(std::string(data, strnlen(data, sizeof(data)))); - } - - BANNER_TYPE m_BNRType; - BANNER_TYPE getBannerType(); - - DiscIO::IVolume::ECountry const m_country; -}; - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoaderWii.cpp b/Source/Core/DiscIO/BannerLoaderWii.cpp deleted file mode 100644 index 1de9120c10..0000000000 --- a/Source/Core/DiscIO/BannerLoaderWii.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include - -#include "Common/ColorUtil.h" -#include "Common/CommonFuncs.h" -#include "Common/CommonTypes.h" -#include "Common/FileUtil.h" -#include "Common/StringUtil.h" - -#include "DiscIO/BannerLoaderWii.h" -#include "DiscIO/Volume.h" - -namespace DiscIO -{ - -CBannerLoaderWii::CBannerLoaderWii(DiscIO::IVolume *pVolume) -{ - u64 TitleID = 0; - pVolume->GetTitleID((u8*)&TitleID); - TitleID = Common::swap64(TitleID); - - std::string Filename = StringFromFormat("%stitle/%08x/%08x/data/banner.bin", - File::GetUserPath(D_WIIUSER_IDX).c_str(), (u32)(TitleID>>32), (u32)TitleID); - - if (!File::Exists(Filename)) - { - m_IsValid = false; - return; - } - - // load the banner.bin - size_t FileSize = (size_t) File::GetSize(Filename); - - if (FileSize > 0) - { - m_pBannerFile = new u8[FileSize]; - File::IOFile pFile(Filename, "rb"); - if (pFile) - { - pFile.ReadBytes(m_pBannerFile, FileSize); - m_IsValid = true; - } - } -} - -CBannerLoaderWii::~CBannerLoaderWii() -{ - if (m_pBannerFile) - { - delete [] m_pBannerFile; - m_pBannerFile = nullptr; - } -} - -std::vector CBannerLoaderWii::GetBanner(int* pWidth, int* pHeight) -{ - SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile; - std::vector Buffer; - Buffer.resize(192 * 64); - ColorUtil::decode5A3image(&Buffer[0], (u16*)pBanner->m_BannerTexture, 192, 64); - *pWidth = 192; - *pHeight = 64; - return Buffer; -} - -bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::string& result) -{ - if (IsValid()) - { - auto const banner = reinterpret_cast(m_pBannerFile); - auto const src_ptr = banner->m_Comment[index]; - - // Trim at first nullptr - auto const length = std::find(src_ptr, src_ptr + COMMENT_SIZE, 0x0) - src_ptr; - - std::wstring src; - src.resize(length); - std::transform(src_ptr, src_ptr + src.size(), src.begin(), (u16(&)(u16))Common::swap16); - result = UTF16ToUTF8(src); - - return true; - } - - return false; -} - -std::map CBannerLoaderWii::GetNames() -{ - std::map result; - - std::string name; - if (GetStringFromComments(NAME_IDX, name)) - result[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; - - return result; -} - -std::string CBannerLoaderWii::GetCompany() -{ - return ""; -} - -std::map CBannerLoaderWii::GetDescriptions() -{ - std::map result; - - std::string name; - if (GetStringFromComments(DESC_IDX, name)) - result[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; - - return result; -} - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoaderWii.h b/Source/Core/DiscIO/BannerLoaderWii.h deleted file mode 100644 index 29d3b0f470..0000000000 --- a/Source/Core/DiscIO/BannerLoaderWii.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "Common/CommonTypes.h" -#include "DiscIO/BannerLoader.h" - -namespace DiscIO -{ - -class IVolume; - -class CBannerLoaderWii - : public IBannerLoader -{ -public: - CBannerLoaderWii(DiscIO::IVolume *pVolume); - - virtual ~CBannerLoaderWii(); - - virtual std::vector GetBanner(int* pWidth, int* pHeight) override; - - virtual std::map GetNames() override; - virtual std::string GetCompany() override; - virtual std::map GetDescriptions() override; - -private: - enum - { - TEXTURE_SIZE = 192 * 64 * 2, - ICON_SIZE = 48 * 48 * 2, - COMMENT_SIZE = 32 - }; - - enum CommentIndex - { - NAME_IDX, - DESC_IDX - }; - - struct SWiiBanner - { - u32 ID; - - u32 m_Flag; - u16 m_Speed; - u8 m_Unknown[22]; - - // Not null terminated! - u16 m_Comment[2][COMMENT_SIZE]; - u8 m_BannerTexture[TEXTURE_SIZE]; - u8 m_IconTexture[8][ICON_SIZE]; - }; - - bool GetStringFromComments(const CommentIndex index, std::string& s); -}; - -} // namespace diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 7cc2859053..e9f20ffe8d 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -1,7 +1,4 @@ -set(SRCS BannerLoader.cpp - BannerLoaderGC.cpp - BannerLoaderWii.cpp - Blob.cpp +set(SRCS Blob.cpp CISOBlob.cpp WbfsBlob.cpp CompressedBlob.cpp diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index 5ef6853456..b0a9ef63fd 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -35,9 +35,6 @@ - - - @@ -58,9 +55,6 @@ - - - diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index 1f5f383831..3d27813cba 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -24,15 +24,6 @@ DiscScrubber - - FileHandler - - - FileHandler - - - FileHandler - FileSystem @@ -89,15 +80,6 @@ DiscScrubber - - FileHandler - - - FileHandler - - - FileHandler - FileSystem diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 50e09c34d1..ff7e6a8b63 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -11,6 +11,7 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/StringUtil.h" namespace DiscIO { @@ -74,10 +75,12 @@ public: } virtual std::string GetUniqueID() const = 0; virtual std::string GetMakerID() const = 0; - virtual int GetRevision() const { return 0; } - // TODO: eliminate? - virtual std::string GetName() const; + virtual int GetRevision() const = 0; + virtual std::string GetName() const = 0; virtual std::map GetNames() const = 0; + virtual std::map GetDescriptions() const { return std::map(); } + virtual std::string GetCompany() const { return std::string(); } + virtual std::vector GetBanner(int* width, int* height) const; virtual u32 GetFSTSize() const = 0; virtual std::string GetApploaderDate() const = 0; @@ -93,6 +96,23 @@ public: // Size on disc (compressed size) virtual u64 GetRawSize() const = 0; + +protected: + template + std::string DecodeString(const char(&data)[N]) const + { + // strnlen to trim NULLs + std::string string(data, strnlen(data, sizeof(data))); + + // There don't seem to be any GC discs with the country set to Taiwan... + // But maybe they would use Shift_JIS if they existed? Not sure + bool use_shift_jis = (COUNTRY_JAPAN == GetCountry() || COUNTRY_TAIWAN == GetCountry()); + + if (use_shift_jis) + return SHIFTJISToUTF8(string); + else + return CP1252ToUTF8(string); + } }; // Generic Switch function for all volumes diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index 1728e78732..e2c3117170 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -4,15 +4,59 @@ #include #include +#include #include +#include "Common/ColorUtil.h" +#include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/FileUtil.h" +#include "Common/StringUtil.h" #include "Common/Logging/Log.h" #include "DiscIO/Volume.h" -// Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) namespace DiscIO { + +static const unsigned int WII_BANNER_WIDTH = 192; +static const unsigned int WII_BANNER_HEIGHT = 64; +static const unsigned int WII_BANNER_SIZE = WII_BANNER_WIDTH * WII_BANNER_HEIGHT * 2; +static const unsigned int WII_BANNER_OFFSET = 0xA0; + +std::vector IVolume::GetBanner(int* width, int* height) const +{ + *width = 0; + *height = 0; + + u64 TitleID = 0; + GetTitleID((u8*)&TitleID); + TitleID = Common::swap64(TitleID); + + std::string file_name = StringFromFormat("%stitle/%08x/%08x/data/banner.bin", + File::GetUserPath(D_WIIUSER_IDX).c_str(), (u32)(TitleID >> 32), (u32)TitleID); + if (!File::Exists(file_name)) + return std::vector(); + + if (File::GetSize(file_name) < WII_BANNER_OFFSET + WII_BANNER_SIZE) + return std::vector(); + + File::IOFile file(file_name, "rb"); + if (!file.Seek(WII_BANNER_OFFSET, SEEK_SET)) + return std::vector(); + + std::vector banner_file(WII_BANNER_SIZE); + if (!file.ReadBytes(banner_file.data(), banner_file.size())) + return std::vector(); + + std::vector image_buffer(WII_BANNER_WIDTH * WII_BANNER_HEIGHT); + ColorUtil::decode5A3image(image_buffer.data(), (u16*)banner_file.data(), WII_BANNER_WIDTH, WII_BANNER_HEIGHT); + + *width = WII_BANNER_WIDTH; + *height = WII_BANNER_HEIGHT; + return image_buffer; +} + +// Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) IVolume::ECountry CountrySwitch(u8 country_code) { switch (country_code) @@ -99,13 +143,4 @@ u8 GetSysMenuRegion(u16 _TitleVersion) } } -std::string IVolume::GetName() const -{ - auto names = GetNames(); - if (names.empty()) - return ""; - else - return names.cbegin()->second; -} - } diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 9db6e58e46..876848b2d3 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -182,10 +182,21 @@ std::string CVolumeDirectory::GetMakerID() const return "VOID"; } +std::string CVolumeDirectory::GetName() const +{ + char name[0x60]; + if (Read(0x20, 0x60, (u8*)name, false)) + return DecodeString(name); + else + return ""; +} + std::map CVolumeDirectory::GetNames() const { std::map names; - names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = (char*)(&m_diskHeader[0x20]); + std::string name = GetName(); + if (!name.empty()) + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; return names; } diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h index d283e9051b..7187e8a017 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -39,6 +39,8 @@ public: std::string GetMakerID() const override; + int GetRevision() const override { return 0; } + std::string GetName() const override; std::map GetNames() const override; void SetName(const std::string&); diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp index 272408011e..dd18338f63 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -8,10 +8,13 @@ #include #include +#include "Common/ColorUtil.h" #include "Common/CommonTypes.h" #include "Common/StringUtil.h" +#include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/FileMonitor.h" +#include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeGC.h" @@ -93,19 +96,133 @@ int CVolumeGC::GetRevision() const return revision; } +std::string CVolumeGC::GetName() const +{ + char name[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) + return DecodeString(name); + else + return ""; +} + std::map CVolumeGC::GetNames() const { std::map names; - auto const string_decoder = GetStringDecoder(GetCountry()); + if (!LoadBannerFile()) + return names; - char name[0x60 + 1] = {}; - if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) - names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = string_decoder(name); + u32 name_count = 0; + IVolume::ELanguage language; + bool is_japanese = GetCountry() == IVolume::ECountry::COUNTRY_JAPAN; + + switch (m_banner_file_type) + { + case BANNER_BNR1: + name_count = 1; + language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; + break; + + case BANNER_BNR2: + name_count = 6; + language = IVolume::ELanguage::LANGUAGE_ENGLISH; + break; + + case BANNER_INVALID: + case BANNER_NOT_LOADED: + break; + } + + auto const banner = reinterpret_cast(m_banner_file.data()); + + for (u32 i = 0; i < name_count; ++i) + { + auto& comment = banner->comment[i]; + std::string name = DecodeString(comment.longTitle); + + if (name.empty()) + name = DecodeString(comment.shortTitle); + + if (!name.empty()) + names[(IVolume::ELanguage)(language + i)] = name; + } return names; } +std::map CVolumeGC::GetDescriptions() const +{ + std::map descriptions; + + if (!LoadBannerFile()) + return descriptions; + + u32 desc_count = 0; + IVolume::ELanguage language; + bool is_japanese = GetCountry() == IVolume::ECountry::COUNTRY_JAPAN; + + switch (m_banner_file_type) + { + case BANNER_BNR1: + desc_count = 1; + language = is_japanese ? IVolume::ELanguage::LANGUAGE_JAPANESE : IVolume::ELanguage::LANGUAGE_ENGLISH; + break; + + case BANNER_BNR2: + language = IVolume::ELanguage::LANGUAGE_ENGLISH; + desc_count = 6; + break; + + case BANNER_INVALID: + case BANNER_NOT_LOADED: + break; + } + + auto banner = reinterpret_cast(m_banner_file.data()); + + for (u32 i = 0; i < desc_count; ++i) + { + auto& data = banner->comment[i].comment; + std::string description = DecodeString(data); + + if (!description.empty()) + descriptions[(IVolume::ELanguage)(language + i)] = description; + } + + return descriptions; +} + +std::string CVolumeGC::GetCompany() const +{ + if (!LoadBannerFile()) + return ""; + + auto const pBanner = (GCBanner*)m_banner_file.data(); + std::string company = DecodeString(pBanner->comment[0].longMaker); + + if (company.empty()) + company = DecodeString(pBanner->comment[0].shortMaker); + + return company; +} + +std::vector CVolumeGC::GetBanner(int* width, int* height) const +{ + if (!LoadBannerFile()) + { + *width = 0; + *height = 0; + return std::vector(); + } + + std::vector image_buffer(GC_BANNER_WIDTH * GC_BANNER_HEIGHT); + auto const pBanner = (GCBanner*)m_banner_file.data(); + ColorUtil::decode5A3image(image_buffer.data(), pBanner->image, GC_BANNER_WIDTH, GC_BANNER_HEIGHT); + *width = GC_BANNER_WIDTH; + *height = GC_BANNER_HEIGHT; + return image_buffer; +} + u32 CVolumeGC::GetFSTSize() const { if (m_pReader == nullptr) @@ -155,10 +272,46 @@ bool CVolumeGC::IsDiscTwo() const return (disc_two_check == 1); } -CVolumeGC::StringDecoder CVolumeGC::GetStringDecoder(ECountry country) +bool CVolumeGC::LoadBannerFile() const { - return (COUNTRY_JAPAN == country || COUNTRY_TAIWAN == country) ? - SHIFTJISToUTF8 : CP1252ToUTF8; + // The methods GetNames, GetDescriptions, GetCompany and GetBanner + // all need to access the opening.bnr file. These four methods are + // typically called after each other, so we store the file in RAM + // to avoid reading it from the disc several times. However, + // if none of these methods are called, the file is never loaded. + + if (m_banner_file_type != BANNER_NOT_LOADED) + return m_banner_file_type != BANNER_INVALID; + + std::unique_ptr file_system(CreateFileSystem(this)); + size_t file_size = (size_t)file_system->GetFileSize("opening.bnr"); + if (file_size == BNR1_SIZE || file_size == BNR2_SIZE) + { + m_banner_file.resize(file_size); + file_system->ReadFile("opening.bnr", m_banner_file.data(), m_banner_file.size()); + + u32 bannerSignature = *(u32*)m_banner_file.data(); + switch (bannerSignature) + { + case 0x31524e42: // "BNR1" + m_banner_file_type = BANNER_BNR1; + break; + case 0x32524e42: // "BNR2" + m_banner_file_type = BANNER_BNR2; + break; + default: + m_banner_file_type = BANNER_INVALID; + WARN_LOG(DISCIO, "Invalid opening.bnr type"); + break; + } + } + else + { + m_banner_file_type = BANNER_INVALID; + WARN_LOG(DISCIO, "Invalid opening.bnr size: %0lx", (unsigned long)file_size); + } + + return m_banner_file_type != BANNER_INVALID; } } // namespace diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h index e9757df948..3c4abcba31 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -28,7 +28,11 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::map GetNames() const override; + virtual std::string GetName() const override; + std::map GetNames() const override; + std::map GetDescriptions() const override; + std::string GetCompany() const override; + std::vector GetBanner(int* width, int* height) const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; @@ -38,11 +42,44 @@ public: u64 GetSize() const override; u64 GetRawSize() const override; - typedef std::string(*StringDecoder)(const std::string&); - - static StringDecoder GetStringDecoder(ECountry country); - private: + bool LoadBannerFile() const; + + static const int GC_BANNER_WIDTH = 96; + static const int GC_BANNER_HEIGHT = 32; + + // Banner Comment + struct GCBannerComment + { + char shortTitle[32]; // Short game title shown in IPL menu + char shortMaker[32]; // Short developer, publisher names shown in IPL menu + char longTitle[64]; // Long game title shown in IPL game start screen + char longMaker[64]; // Long developer, publisher names shown in IPL game start screen + char comment[128]; // Game description shown in IPL game start screen in two lines. + }; + + struct GCBanner + { + u32 id; // "BNR1" for NTSC, "BNR2" for PAL + u32 padding[7]; + u16 image[GC_BANNER_WIDTH * GC_BANNER_HEIGHT]; // RGB5A3 96x32 image + GCBannerComment comment[6]; // Comments in six languages (only one for BNR1 type) + }; + + static const size_t BNR1_SIZE = sizeof(GCBanner) - sizeof(GCBannerComment) * 5; + static const size_t BNR2_SIZE = sizeof(GCBanner); + + enum BannerFileType + { + BANNER_NOT_LOADED, + BANNER_INVALID, + BANNER_BNR1, + BANNER_BNR2 + }; + + mutable BannerFileType m_banner_file_type = BANNER_NOT_LOADED; + mutable std::vector m_banner_file; + std::unique_ptr m_pReader; }; diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index 33dc213aee..229ec6d31b 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -31,9 +31,10 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; + std::string GetName() const override { return ""; } std::map GetNames() const override; - u32 GetFSTSize() const override { return 0; } - std::string GetApploaderDate() const override { return "0"; } + u32 GetFSTSize() const override { return 0; } + std::string GetApploaderDate() const override { return ""; } bool IsWadFile() const override; diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index 935d18b8f8..baf96f2e5d 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -192,16 +192,20 @@ int CVolumeWiiCrypted::GetRevision() const return revision; } +std::string CVolumeWiiCrypted::GetName() const +{ + char name_buffer[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name_buffer, false)) + return DecodeString(name_buffer); + + return ""; +} + std::map CVolumeWiiCrypted::GetNames() const { + // TODO: Read opening.bnr std::map names; - - auto const string_decoder = CVolumeGC::GetStringDecoder(GetCountry()); - - char name[0xFF] = {}; - if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name, true)) - names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = string_decoder(name); - + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = GetName(); return names; } diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h index f4712fd230..11092c33d1 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/VolumeWiiCrypted.h @@ -31,6 +31,7 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; + std::string GetName() const override; std::map GetNames() const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; diff --git a/Source/Core/DolphinQt/GameList/GameFile.cpp b/Source/Core/DolphinQt/GameList/GameFile.cpp index 9b36e86069..e97117d033 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.cpp +++ b/Source/Core/DolphinQt/GameList/GameFile.cpp @@ -18,7 +18,6 @@ #include "Core/ConfigManager.h" -#include "DiscIO/BannerLoader.h" #include "DiscIO/CompressedBlob.h" #include "DiscIO/Filesystem.h" @@ -82,7 +81,7 @@ GameFile::GameFile(const QString& fileName) } else { - DiscIO::IVolume* volume = DiscIO::CreateVolumeFromFilename(fileName.toStdString()); + std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(fileName.toStdString())); if (volume != nullptr) { @@ -91,7 +90,9 @@ GameFile::GameFile(const QString& fileName) else m_platform = WII_WAD; - m_volume_names = ConvertLocalizedStrings(volume->GetNames()); + m_names = ConvertLocalizedStrings(volume->GetNames()); + m_descriptions = ConvertLocalizedStrings(volume->GetDescriptions()); + m_company = QString::fromStdString(volume->GetCompany()); m_country = volume->GetCountry(); m_file_size = volume->GetRawSize(); @@ -105,43 +106,22 @@ GameFile::GameFile(const QString& fileName) QFileInfo info(m_file_name); m_folder_name = info.absoluteDir().dirName(); - // check if we can get some info from the banner file too - DiscIO::IFileSystem* fileSystem = DiscIO::CreateFileSystem(volume); - - if (fileSystem != nullptr || m_platform == WII_WAD) + int width, height; + std::vector buffer = volume->GetBanner(&width, &height); + QImage banner(width, height, QImage::Format_RGB888); + for (int i = 0; i < width * height; i++) { - std::unique_ptr bannerLoader(DiscIO::CreateBannerLoader(*fileSystem, volume)); - - if (bannerLoader != nullptr) - { - if (bannerLoader->IsValid()) - { - if (m_platform != WII_WAD) - m_names = ConvertLocalizedStrings(bannerLoader->GetNames()); - m_company = QString::fromStdString(bannerLoader->GetCompany()); - m_descriptions = ConvertLocalizedStrings(bannerLoader->GetDescriptions()); - - int width, height; - std::vector buffer = bannerLoader->GetBanner(&width, &height); - QImage banner(width, height, QImage::Format_RGB888); - for (int i = 0; i < width * height; i++) - { - int x = i % width, y = i / width; - banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16, - (buffer[i] & 0x00FF00) >> 8, - (buffer[i] & 0x0000FF) >> 0)); - } - - if (!banner.isNull()) - { - hasBanner = true; - m_banner = QPixmap::fromImage(banner); - } - } - } - delete fileSystem; + int x = i % width, y = i / width; + banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16, + (buffer[i] & 0x00FF00) >> 8, + (buffer[i] & 0x0000FF) >> 0)); + } + + if (!banner.isNull()) + { + hasBanner = true; + m_banner = QPixmap::fromImage(banner); } - delete volume; m_valid = true; if (hasBanner) @@ -184,14 +164,12 @@ bool GameFile::LoadFromCache() return false; u32 country; - QMap volume_names; QMap names; QMap descriptions; stream >> m_folder_name - >> volume_names >> names - >> m_company >> descriptions + >> m_company >> m_unique_id >> m_file_size >> m_volume_size @@ -202,7 +180,6 @@ bool GameFile::LoadFromCache() >> m_is_disc_two >> m_revision; m_country = (DiscIO::IVolume::ECountry)country; - m_volume_names = CastLocalizedStrings(volume_names); m_names = CastLocalizedStrings(names); m_descriptions = CastLocalizedStrings(descriptions); file.close(); @@ -230,10 +207,9 @@ void GameFile::SaveToCache() stream << CACHE_REVISION; stream << m_folder_name - << CastLocalizedStrings(m_volume_names) << CastLocalizedStrings(m_names) - << m_company << CastLocalizedStrings(m_descriptions) + << m_company << m_unique_id << m_file_size << m_volume_size @@ -279,24 +255,14 @@ QString GameFile::GetDescription() const return GetDescription(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_platform != GAMECUBE_DISC)); } -QString GameFile::GetVolumeName(IVolume::ELanguage language) const -{ - return GetLanguageString(language, m_volume_names); -} - -QString GameFile::GetBannerName(IVolume::ELanguage language) const +QString GameFile::GetName(IVolume::ELanguage language) const { return GetLanguageString(language, m_names); } -QString GameFile::GetName(IVolume::ELanguage language) const +QString GameFile::GetName() const { - // Prefer name from banner, fallback to name from volume, fallback to filename - QString name = GetBannerName(language); - - if (name.isEmpty()) - name = GetVolumeName(language); - + QString name = GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_platform != GAMECUBE_DISC)); if (name.isEmpty()) { // No usable name, return filename (better than nothing) @@ -304,15 +270,9 @@ QString GameFile::GetName(IVolume::ELanguage language) const SplitPath(m_file_name.toStdString(), nullptr, &nametemp, nullptr); name = QString::fromStdString(nametemp); } - return name; } -QString GameFile::GetName() const -{ - return GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_platform != GAMECUBE_DISC)); -} - const QString GameFile::GetWiiFSPath() const { std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(m_file_name.toStdString())); diff --git a/Source/Core/DolphinQt/GameList/GameFile.h b/Source/Core/DolphinQt/GameList/GameFile.h index e6732d3c49..5618c29f02 100644 --- a/Source/Core/DolphinQt/GameList/GameFile.h +++ b/Source/Core/DolphinQt/GameList/GameFile.h @@ -22,13 +22,11 @@ public: bool IsValid() const { return m_valid; } QString GetFileName() { return m_file_name; } QString GetFolderName() { return m_folder_name; } - QString GetBannerName(DiscIO::IVolume::ELanguage language) const; - QString GetVolumeName(DiscIO::IVolume::ELanguage language) const; QString GetName(DiscIO::IVolume::ELanguage language) const; QString GetName() const; - QString GetCompany() const; QString GetDescription(DiscIO::IVolume::ELanguage language) const; QString GetDescription() const; + QString GetCompany() const; int GetRevision() const { return m_revision; } const QString GetUniqueID() const { return m_unique_id; } const QString GetWiiFSPath() const; @@ -54,12 +52,9 @@ private: QString m_file_name; QString m_folder_name; - // TODO: eliminate this and overwrite with names from banner when available? - QMap m_volume_names; - - QString m_company; QMap m_names; QMap m_descriptions; + QString m_company; QString m_unique_id; diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 5190849435..5e3580ab43 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -29,7 +29,6 @@ #include "Core/CoreParameter.h" #include "Core/Boot/Boot.h" -#include "DiscIO/BannerLoader.h" #include "DiscIO/CompressedBlob.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -90,7 +89,9 @@ GameListItem::GameListItem(const std::string& _rFileName) else m_Platform = WII_WAD; - m_volume_names = pVolume->GetNames(); + m_names = pVolume->GetNames(); + m_descriptions = pVolume->GetDescriptions(); + m_company = pVolume->GetCompany(); m_Country = pVolume->GetCountry(); m_FileSize = pVolume->GetRawSize(); @@ -101,34 +102,15 @@ GameListItem::GameListItem(const std::string& _rFileName) m_IsDiscTwo = pVolume->IsDiscTwo(); m_Revision = pVolume->GetRevision(); - // check if we can get some info from the banner file too - DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume); + std::vector Buffer = pVolume->GetBanner(&m_ImageWidth, &m_ImageHeight); + u32* pData = Buffer.data(); + m_pImage.resize(m_ImageWidth * m_ImageHeight * 3); - if (pFileSystem != nullptr || m_Platform == WII_WAD) + for (int i = 0; i < m_ImageWidth * m_ImageHeight; i++) { - std::unique_ptr pBannerLoader(DiscIO::CreateBannerLoader(*pFileSystem, pVolume)); - - if (pBannerLoader != nullptr && pBannerLoader->IsValid()) - { - if (m_Platform != WII_WAD) - m_banner_names = pBannerLoader->GetNames(); - m_company = pBannerLoader->GetCompany(); - m_descriptions = pBannerLoader->GetDescriptions(); - - std::vector Buffer = pBannerLoader->GetBanner(&m_ImageWidth, &m_ImageHeight); - u32* pData = &Buffer[0]; - // resize vector to image size - m_pImage.resize(m_ImageWidth * m_ImageHeight * 3); - - for (int i = 0; i < m_ImageWidth * m_ImageHeight; i++) - { - m_pImage[i * 3 + 0] = (pData[i] & 0xFF0000) >> 16; - m_pImage[i * 3 + 1] = (pData[i] & 0x00FF00) >> 8; - m_pImage[i * 3 + 2] = (pData[i] & 0x0000FF) >> 0; - } - } - - delete pFileSystem; + m_pImage[i * 3 + 0] = (pData[i] & 0xFF0000) >> 16; + m_pImage[i * 3 + 1] = (pData[i] & 0x00FF00) >> 8; + m_pImage[i * 3 + 2] = (pData[i] & 0x0000FF) >> 0; } delete pVolume; @@ -154,7 +136,7 @@ GameListItem::GameListItem(const std::string& _rFileName) wxImage Image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true); double Scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); // Note: This uses nearest neighbor, which subjectively looks a lot - // better for GC banners than smooths caling. + // better for GC banners than smooth scaling. Image.Rescale(DVD_BANNER_WIDTH * Scale, DVD_BANNER_HEIGHT * Scale); #ifdef __APPLE__ m_Bitmap = wxBitmap(Image, -1, Scale); @@ -188,10 +170,9 @@ void GameListItem::SaveToCache() void GameListItem::DoState(PointerWrap &p) { - p.Do(m_volume_names); - p.Do(m_company); - p.Do(m_banner_names); + p.Do(m_names); p.Do(m_descriptions); + p.Do(m_company); p.Do(m_UniqueID); p.Do(m_FileSize); p.Do(m_VolumeSize); @@ -238,48 +219,27 @@ std::string GameListItem::GetDescription() const return GetDescription(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_Platform != GAMECUBE_DISC)); } -std::string GameListItem::GetVolumeName(IVolume::ELanguage language) const -{ - return GetLanguageString(language, m_volume_names); -} - -std::string GameListItem::GetBannerName(IVolume::ELanguage language) const -{ - return GetLanguageString(language, m_banner_names); -} - std::string GameListItem::GetName(IVolume::ELanguage language) const { - // Prefer name from banner, fallback to name from volume, fallback to filename - - std::string name = GetBannerName(language); - - if (name.empty()) - name = GetVolumeName(language); + return GetLanguageString(language, m_names); +} +std::string GameListItem::GetName() const +{ + std::string name = GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_Platform != GAMECUBE_DISC)); if (name.empty()) { // No usable name, return filename (better than nothing) SplitPath(GetFileName(), nullptr, &name, nullptr); } - return name; } -std::string GameListItem::GetName() const -{ - return GetName(SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_Platform != GAMECUBE_DISC)); -} - std::vector GameListItem::GetLanguages() const { - std::map language_strings = m_banner_names; - if (m_volume_names.size() > m_banner_names.size()) - language_strings = m_volume_names; - std::vector languages; - for (std::pair language_string : language_strings) - languages.emplace_back(language_string.first); + for (std::pair name : m_names) + languages.push_back(name.first); return languages; } diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h index 9370028a48..2f65d7eec4 100644 --- a/Source/Core/DolphinWX/ISOFile.h +++ b/Source/Core/DolphinWX/ISOFile.h @@ -25,14 +25,12 @@ public: bool IsValid() const {return m_Valid;} const std::string& GetFileName() const {return m_FileName;} - std::string GetBannerName(IVolume::ELanguage language) const; - std::string GetVolumeName(IVolume::ELanguage language) const; std::string GetName(IVolume::ELanguage language) const; std::string GetName() const; - std::string GetCompany() const; std::string GetDescription(IVolume::ELanguage language) const; std::string GetDescription() const; std::vector GetLanguages() const; + std::string GetCompany() const; int GetRevision() const { return m_Revision; } const std::string& GetUniqueID() const {return m_UniqueID;} const std::string GetWiiFSPath() const; @@ -61,13 +59,9 @@ public: private: std::string m_FileName; - // TODO: eliminate this and overwrite with names from banner when available? - std::map m_volume_names; - - // Stuff from banner - std::string m_company; - std::map m_banner_names; + std::map m_names; std::map m_descriptions; + std::string m_company; std::string m_UniqueID; diff --git a/Source/Core/DolphinWX/MainAndroid.cpp b/Source/Core/DolphinWX/MainAndroid.cpp index 9ac5f7735b..0d5f71dc99 100644 --- a/Source/Core/DolphinWX/MainAndroid.cpp +++ b/Source/Core/DolphinWX/MainAndroid.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -38,9 +37,6 @@ #include "Core/HW/Wiimote.h" #include "Core/PowerPC/PowerPC.h" -// Banner loading -#include "DiscIO/BannerLoader.h" -#include "DiscIO/Filesystem.h" #include "DiscIO/VolumeCreator.h" #include "UICommon/UICommon.h" @@ -115,8 +111,8 @@ static bool MsgAlert(const char* caption, const char* text, bool /*yes_no*/, int #define DVD_BANNER_WIDTH 96 #define DVD_BANNER_HEIGHT 32 -std::map m_volume_names; std::map m_names; +bool m_is_wii_title; static inline u32 Average32(u32 a, u32 b) { return ((a >> 1) & 0x7f7f7f7f) + ((b >> 1) & 0x7f7f7f7f); @@ -131,54 +127,39 @@ static inline u32 GetPixel(u32 *buffer, unsigned int x, unsigned int y) { static bool LoadBanner(std::string filename, u32 *Banner) { - DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(filename); + std::unique_ptr pVolume(DiscIO::CreateVolumeFromFilename(filename)); if (pVolume != nullptr) { - bool bIsWad = false; - if (DiscIO::IsVolumeWadFile(pVolume)) - bIsWad = true; + m_names = pVolume->GetNames(); + m_is_wii_title = pVolume->IsWiiDisc() || pVolume->IsWadFile(); - m_volume_names = pVolume->GetNames(); - - // check if we can get some info from the banner file too - DiscIO::IFileSystem* pFileSystem = DiscIO::CreateFileSystem(pVolume); - - if (pFileSystem != nullptr || bIsWad) + int Width, Height; + std::vector BannerVec = pVolume->GetBanner(&Width, &Height); + // This code (along with above inlines) is moved from + // elsewhere. Someone who knows anything about Android + // please get rid of it and use proper high-resolution + // images. + if (Height == 64 && Width == 192) { - DiscIO::IBannerLoader* pBannerLoader = DiscIO::CreateBannerLoader(*pFileSystem, pVolume); - - if (pBannerLoader != nullptr) - if (pBannerLoader->IsValid()) + u32* Buffer = &BannerVec[0]; + for (int y = 0; y < 32; y++) + { + for (int x = 0; x < 96; x++) { - m_names = pBannerLoader->GetNames(); - int Width, Height; - std::vector BannerVec = pBannerLoader->GetBanner(&Width, &Height); - // This code (along with above inlines) is moved from - // elsewhere. Someone who knows anything about Android - // please get rid of it and use proper high-resolution - // images. - if (Height == 64) - { - u32* Buffer = &BannerVec[0]; - for (int y = 0; y < 32; y++) - { - for (int x = 0; x < 96; x++) - { - // simplified plus-shaped "gaussian" - u32 surround = Average32( - Average32(GetPixel(Buffer, x*2 - 1, y*2), GetPixel(Buffer, x*2 + 1, y*2)), - Average32(GetPixel(Buffer, x*2, y*2 - 1), GetPixel(Buffer, x*2, y*2 + 1))); - Banner[y * 96 + x] = Average32(GetPixel(Buffer, x*2, y*2), surround); - } - } - } - else - { - memcpy(Banner, &BannerVec[0], 96 * 32 * 4); - } - return true; + // simplified plus-shaped "gaussian" + u32 surround = Average32( + Average32(GetPixel(Buffer, x*2 - 1, y*2), GetPixel(Buffer, x*2 + 1, y*2)), + Average32(GetPixel(Buffer, x*2, y*2 - 1), GetPixel(Buffer, x*2, y*2 + 1))); + Banner[y * 96 + x] = Average32(GetPixel(Buffer, x*2, y*2), surround); } + } + return true; + } + else if (Height == 32 && Width == 96) + { + memcpy(Banner, &BannerVec[0], 96 * 32 * 4); + return true; } } @@ -187,15 +168,28 @@ static bool LoadBanner(std::string filename, u32 *Banner) static std::string GetName(std::string filename) { - if (!m_names.empty()) - return m_names[0]; + DiscIO::IVolume::ELanguage language = SConfig::GetInstance().m_LocalCoreStartupParameter.GetCurrentLanguage(m_is_wii_title); + + auto end = m_names.end(); + auto it = m_names.find(language); + if (it != end) + return it->second; + + // English tends to be a good fallback when the requested language isn't available + if (language != IVolume::ELanguage::LANGUAGE_ENGLISH) + { + it = m_names.find(IVolume::ELanguage::LANGUAGE_ENGLISH); + if (it != end) + return it->second; + } + + // If English isn't available either, just pick something + if (!m_names.empty()) + return m_names.cbegin()->second; - if (!m_volume_names.empty()) - return m_volume_names[0]; // No usable name, return filename (better than nothing) std::string name; SplitPath(filename, nullptr, &name, nullptr); - return name; } @@ -277,7 +271,6 @@ JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetTitle( std::string file = GetJString(env, jFile); std::string name = GetName(file); m_names.clear(); - m_volume_names.clear(); return env->NewStringUTF(name.c_str()); } From 272f9d3cbc35c65bc98d89bcd36da3adabf648f9 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 28 Apr 2015 16:47:03 +0200 Subject: [PATCH 3/5] FileSystemGCWii: Allow reading files partially --- Source/Core/DiscIO/FileSystemGCWii.cpp | 14 ++++++++------ Source/Core/DiscIO/FileSystemGCWii.h | 2 +- Source/Core/DiscIO/Filesystem.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index 381d1bdbd4..e23a8cb177 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -63,7 +63,7 @@ const std::string CFileSystemGCWii::GetFileName(u64 _Address) return ""; } -u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, size_t _MaxBufferSize) +u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile) { if (!m_Initialized) InitFileSystem(); @@ -72,14 +72,16 @@ u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, size if (pFileInfo == nullptr) return 0; - if (pFileInfo->m_FileSize > _MaxBufferSize) + if (_OffsetInFile >= pFileInfo->m_FileSize) return 0; - DEBUG_LOG(DISCIO, "Filename: %s. Offset: %" PRIx64 ". Size: %" PRIx64, _rFullPath.c_str(), - pFileInfo->m_Offset, pFileInfo->m_FileSize); + u64 read_length = std::min(_MaxBufferSize, pFileInfo->m_FileSize - _OffsetInFile); - m_rVolume->Read(pFileInfo->m_Offset, pFileInfo->m_FileSize, _pBuffer, m_Wii); - return pFileInfo->m_FileSize; + DEBUG_LOG(DISCIO, "Reading %" PRIx64 " bytes at %" PRIx64 " from file %s. Offset: %" PRIx64 " Size: %" PRIx64, + read_length, _OffsetInFile, _rFullPath.c_str(), pFileInfo->m_Offset, pFileInfo->m_FileSize); + + m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_Wii); + return read_length; } bool CFileSystemGCWii::ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) diff --git a/Source/Core/DiscIO/FileSystemGCWii.h b/Source/Core/DiscIO/FileSystemGCWii.h index 24a1c65ab3..03f4bb9eff 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.h +++ b/Source/Core/DiscIO/FileSystemGCWii.h @@ -25,7 +25,7 @@ public: virtual u64 GetFileSize(const std::string& _rFullPath) override; virtual size_t GetFileList(std::vector &_rFilenames) override; virtual const std::string GetFileName(u64 _Address) override; - virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, size_t _MaxBufferSize) override; + virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile) override; virtual bool ExportFile(const std::string& _rFullPath, const std::string&_rExportFilename) override; virtual bool ExportApploader(const std::string& _rExportFolder) const override; virtual bool ExportDOL(const std::string& _rExportFolder) const override; diff --git a/Source/Core/DiscIO/Filesystem.h b/Source/Core/DiscIO/Filesystem.h index 78f179d6dd..181c25f354 100644 --- a/Source/Core/DiscIO/Filesystem.h +++ b/Source/Core/DiscIO/Filesystem.h @@ -45,7 +45,7 @@ public: virtual bool IsValid() const = 0; virtual size_t GetFileList(std::vector &_rFilenames) = 0; virtual u64 GetFileSize(const std::string& _rFullPath) = 0; - virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, size_t _MaxBufferSize) = 0; + virtual u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile = 0) = 0; virtual bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) = 0; virtual bool ExportApploader(const std::string& _rExportFolder) const = 0; virtual bool ExportDOL(const std::string& _rExportFolder) const = 0; From 2d5d5fa83e9ccb32252756fc0390740c952121b1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 10 Apr 2015 23:18:41 +0200 Subject: [PATCH 4/5] Read opening.bnr to get names from Wii discs This makes Dolphin display the same names as the Disc Channel. --- Source/Core/DiscIO/Volume.h | 7 +++++ Source/Core/DiscIO/VolumeCommon.cpp | 22 +++++++++++++++ Source/Core/DiscIO/VolumeWad.cpp | 36 +++---------------------- Source/Core/DiscIO/VolumeWiiCrypted.cpp | 9 ++++--- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index ff7e6a8b63..c0fea6ccc4 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -113,6 +113,13 @@ protected: else return CP1252ToUTF8(string); } + + static std::map ReadWiiNames(std::vector& data); + + static const size_t NUMBER_OF_LANGUAGES = 10; + static const size_t NAME_STRING_LENGTH = 42; + static const size_t NAME_BYTES_LENGTH = NAME_STRING_LENGTH * sizeof(u16); + static const size_t NAMES_TOTAL_BYTES = NAME_BYTES_LENGTH * NUMBER_OF_LANGUAGES; }; // Generic Switch function for all volumes diff --git a/Source/Core/DiscIO/VolumeCommon.cpp b/Source/Core/DiscIO/VolumeCommon.cpp index e2c3117170..d9b5240327 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include #include #include #include @@ -56,6 +57,27 @@ std::vector IVolume::GetBanner(int* width, int* height) const return image_buffer; } +std::map IVolume::ReadWiiNames(std::vector& data) +{ + std::map names; + for (size_t i = 0; i < NUMBER_OF_LANGUAGES; ++i) + { + size_t name_start = NAME_BYTES_LENGTH * i; + size_t name_end = name_start + NAME_BYTES_LENGTH; + if (data.size() >= name_end) + { + u16* temp = (u16*)(data.data() + name_start); + std::wstring out_temp(NAME_STRING_LENGTH, '\0'); + std::transform(temp, temp + out_temp.size(), out_temp.begin(), (u16(&)(u16))Common::swap16); + out_temp.erase(std::find(out_temp.begin(), out_temp.end(), 0x00), out_temp.end()); + std::string name = UTF16ToUTF8(out_temp); + if (!name.empty()) + names[(IVolume::ELanguage)i] = name; + } + } + return names; +} + // Increment CACHE_REVISION if the code below is modified (ISOFile.cpp & GameFile.cpp) IVolume::ECountry CountrySwitch(u8 country_code) { diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index 5bc27738da..7b52e7a82e 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -2,7 +2,6 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include #include #include #include @@ -120,37 +119,10 @@ bool CVolumeWAD::IsWadFile() const std::map CVolumeWAD::GetNames() const { - std::map names; - - u32 footer_size; - if (!Read(0x1C, 4, (u8*)&footer_size)) - { - return names; - } - - footer_size = Common::swap32(footer_size); - - //Japanese, English, German, French, Spanish, Italian, Dutch, Simplified Chinese, Traditional Chinese, Korean - for (int i = 0; i < 10; ++i) - { - static const u32 string_length = 42; - static const u32 bytes_length = string_length * sizeof(u16); - - u16 temp[string_length]; - - if (footer_size >= 0xF1 && Read(0x9C + (i * bytes_length) + m_opening_bnr_offset, bytes_length, (u8*)&temp)) - { - std::wstring out_temp; - out_temp.resize(string_length); - std::transform(temp, temp + out_temp.size(), out_temp.begin(), (u16(&)(u16))Common::swap16); - out_temp.erase(std::find(out_temp.begin(), out_temp.end(), 0x00), out_temp.end()); - std::string name = UTF16ToUTF8(out_temp); - if (!name.empty()) - names[(IVolume::ELanguage)i] = name; - } - } - - return names; + std::vector name_data(NAMES_TOTAL_BYTES); + if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, name_data.data())) + return std::map(); + return ReadWiiNames(name_data); } u64 CVolumeWAD::GetSize() const diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp index baf96f2e5d..7657c0a28d 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -16,6 +16,7 @@ #include "Common/Logging/Log.h" #include "DiscIO/Blob.h" #include "DiscIO/FileMonitor.h" +#include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeCreator.h" #include "DiscIO/VolumeGC.h" @@ -203,10 +204,10 @@ std::string CVolumeWiiCrypted::GetName() const std::map CVolumeWiiCrypted::GetNames() const { - // TODO: Read opening.bnr - std::map names; - names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = GetName(); - return names; + std::unique_ptr file_system(CreateFileSystem(this)); + std::vector opening_bnr(NAMES_TOTAL_BYTES); + opening_bnr.resize(file_system->ReadFile("opening.bnr", opening_bnr.data(), opening_bnr.size(), 0x5C)); + return ReadWiiNames(opening_bnr); } u32 CVolumeWiiCrypted::GetFSTSize() const From df8e768b77b551832ace0d552ec10c1b062c55f3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 20 Apr 2015 13:00:15 +0200 Subject: [PATCH 5/5] wx: Now that Wii doesn't support descriptions, rename Notes to Maker I'm not sure if Maker is the best name (Developer? Publisher? Company? Copyright?) but I went with it because it's what the game properties window uses. For the sake of backwards compatibility, the INI option wasn't renamed. --- Source/Core/Core/ConfigManager.cpp | 4 +-- Source/Core/Core/ConfigManager.h | 2 +- Source/Core/DolphinWX/FrameTools.cpp | 8 +++--- Source/Core/DolphinWX/GameListCtrl.cpp | 40 ++++++++------------------ Source/Core/DolphinWX/GameListCtrl.h | 2 +- Source/Core/DolphinWX/Globals.h | 2 +- 6 files changed, 21 insertions(+), 37 deletions(-) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 89d561cfca..be488180c7 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -304,7 +304,7 @@ void SConfig::SaveGameListSettings(IniFile& ini) gamelist->Set("ColumnPlatform", m_showSystemColumn); gamelist->Set("ColumnBanner", m_showBannerColumn); - gamelist->Set("ColumnNotes", m_showNotesColumn); + gamelist->Set("ColumnNotes", m_showMakerColumn); gamelist->Set("ColumnID", m_showIDColumn); gamelist->Set("ColumnRegion", m_showRegionColumn); gamelist->Set("ColumnSize", m_showSizeColumn); @@ -556,7 +556,7 @@ void SConfig::LoadGameListSettings(IniFile& ini) // Gamelist columns toggles gamelist->Get("ColumnPlatform", &m_showSystemColumn, true); gamelist->Get("ColumnBanner", &m_showBannerColumn, true); - gamelist->Get("ColumnNotes", &m_showNotesColumn, true); + gamelist->Get("ColumnNotes", &m_showMakerColumn, true); gamelist->Get("ColumnID", &m_showIDColumn, false); gamelist->Get("ColumnRegion", &m_showRegionColumn, true); gamelist->Get("ColumnSize", &m_showSizeColumn, true); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 23fce73852..2ec97266ff 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -84,7 +84,7 @@ struct SConfig : NonCopyable // Game list column toggles bool m_showSystemColumn; bool m_showBannerColumn; - bool m_showNotesColumn; + bool m_showMakerColumn; bool m_showIDColumn; bool m_showRegionColumn; bool m_showSizeColumn; diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index dde3cd4e4f..68a581fe5c 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -364,8 +364,8 @@ wxMenuBar* CFrame::CreateMenu() columnsMenu->Check(IDM_SHOW_SYSTEM, SConfig::GetInstance().m_showSystemColumn); columnsMenu->AppendCheckItem(IDM_SHOW_BANNER, _("Banner")); columnsMenu->Check(IDM_SHOW_BANNER, SConfig::GetInstance().m_showBannerColumn); - columnsMenu->AppendCheckItem(IDM_SHOW_NOTES, _("Notes")); - columnsMenu->Check(IDM_SHOW_NOTES, SConfig::GetInstance().m_showNotesColumn); + columnsMenu->AppendCheckItem(IDM_SHOW_MAKER, _("Maker")); + columnsMenu->Check(IDM_SHOW_MAKER, SConfig::GetInstance().m_showMakerColumn); columnsMenu->AppendCheckItem(IDM_SHOW_ID, _("Game ID")); columnsMenu->Check(IDM_SHOW_ID, SConfig::GetInstance().m_showIDColumn); columnsMenu->AppendCheckItem(IDM_SHOW_REGION, _("Region")); @@ -2035,8 +2035,8 @@ void CFrame::OnChangeColumnsVisible(wxCommandEvent& event) case IDM_SHOW_BANNER: SConfig::GetInstance().m_showBannerColumn = !SConfig::GetInstance().m_showBannerColumn; break; - case IDM_SHOW_NOTES: - SConfig::GetInstance().m_showNotesColumn = !SConfig::GetInstance().m_showNotesColumn; + case IDM_SHOW_MAKER: + SConfig::GetInstance().m_showMakerColumn = !SConfig::GetInstance().m_showMakerColumn; break; case IDM_SHOW_ID: SConfig::GetInstance().m_showIDColumn = !SConfig::GetInstance().m_showIDColumn; diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp index f0bd9268c6..d4b7d85bcf 100644 --- a/Source/Core/DolphinWX/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/GameListCtrl.cpp @@ -110,24 +110,16 @@ static int CompareGameListItems(const GameListItem* iso1, const GameListItem* is if (iso1->GetUniqueID() != iso2->GetUniqueID()) return t * (iso1->GetUniqueID() > iso2->GetUniqueID() ? 1 : -1); if (iso1->GetRevision() != iso2->GetRevision()) - return t * (iso1->GetRevision() > iso2->GetRevision() ? 1 : -1); + return t * (iso1->GetRevision() > iso2->GetRevision() ? 1 : -1); if (iso1->IsDiscTwo() != iso2->IsDiscTwo()) return t * (iso1->IsDiscTwo() ? 1 : -1); } return strcasecmp(iso1->GetName(languageOne).c_str(), iso2->GetName(languageOther).c_str()) * t; - case CGameListCtrl::COLUMN_NOTES: - { - std::string cmp1 = - (iso1->GetPlatform() == GameListItem::GAMECUBE_DISC) ? - iso1->GetCompany() : iso1->GetDescription(languageOne); - std::string cmp2 = - (iso2->GetPlatform() == GameListItem::GAMECUBE_DISC) ? - iso2->GetCompany() : iso2->GetDescription(languageOther); - return strcasecmp(cmp1.c_str(), cmp2.c_str()) * t; - } + case CGameListCtrl::COLUMN_MAKER: + return strcasecmp(iso1->GetCompany().c_str(), iso2->GetCompany().c_str()) * t; case CGameListCtrl::COLUMN_ID: - return strcasecmp(iso1->GetUniqueID().c_str(), iso2->GetUniqueID().c_str()) * t; + return strcasecmp(iso1->GetUniqueID().c_str(), iso2->GetUniqueID().c_str()) * t; case CGameListCtrl::COLUMN_COUNTRY: if (iso1->GetCountry() > iso2->GetCountry()) return 1 * t; @@ -290,10 +282,7 @@ void CGameListCtrl::Update() InsertColumn(COLUMN_BANNER, _("Banner")); InsertColumn(COLUMN_TITLE, _("Title")); - // Instead of showing the notes + the company, which is unknown with - // Wii titles We show in the same column : company for GC games and - // description for Wii/wad games - InsertColumn(COLUMN_NOTES, _("Notes")); + InsertColumn(COLUMN_MAKER, _("Maker")); InsertColumn(COLUMN_ID, _("ID")); InsertColumn(COLUMN_COUNTRY, ""); InsertColumn(COLUMN_SIZE, _("Size")); @@ -310,7 +299,7 @@ void CGameListCtrl::Update() SetColumnWidth(COLUMN_PLATFORM, SConfig::GetInstance().m_showSystemColumn ? 35 + platform_padding : 0); SetColumnWidth(COLUMN_BANNER, SConfig::GetInstance().m_showBannerColumn ? 96 + platform_padding : 0); SetColumnWidth(COLUMN_TITLE, 175 + platform_padding); - SetColumnWidth(COLUMN_NOTES, SConfig::GetInstance().m_showNotesColumn ? 150 + platform_padding : 0); + SetColumnWidth(COLUMN_MAKER, SConfig::GetInstance().m_showMakerColumn ? 150 + platform_padding : 0); SetColumnWidth(COLUMN_ID, SConfig::GetInstance().m_showIDColumn ? 75 + platform_padding : 0); SetColumnWidth(COLUMN_COUNTRY, SConfig::GetInstance().m_showRegionColumn ? 32 + platform_padding : 0); SetColumnWidth(COLUMN_EMULATION_STATE, SConfig::GetInstance().m_showStateColumn ? 50 + platform_padding : 0); @@ -441,12 +430,7 @@ void CGameListCtrl::InsertItemInReportView(long _Index) name = title; SetItem(_Index, COLUMN_TITLE, StrToWxStr(name), -1); - - // We show the company string on GameCube only - // On Wii we show the description instead as the company string is empty - std::string const notes = (rISOFile.GetPlatform() == GameListItem::GAMECUBE_DISC) ? - rISOFile.GetCompany() : rISOFile.GetDescription(); - SetItem(_Index, COLUMN_NOTES, StrToWxStr(notes), -1); + SetItem(_Index, COLUMN_MAKER, StrToWxStr(rISOFile.GetCompany()), -1); // Emulation state SetItemColumnImage(_Index, COLUMN_EMULATION_STATE, m_EmuStateImageIndex[rISOFile.GetEmuState()]); @@ -670,7 +654,7 @@ void CGameListCtrl::ScanForISOs() void CGameListCtrl::OnColBeginDrag(wxListEvent& event) { - if (event.GetColumn() != COLUMN_TITLE && event.GetColumn() != COLUMN_NOTES) + if (event.GetColumn() != COLUMN_TITLE && event.GetColumn() != COLUMN_MAKER) event.Veto(); } @@ -1319,13 +1303,13 @@ void CGameListCtrl::AutomaticColumnWidth() + GetColumnWidth(COLUMN_SIZE) + GetColumnWidth(COLUMN_EMULATION_STATE)); - // We hide the Notes column if the window is too small + // We hide the Maker column if the window is too small if (resizable > 400) { - if (SConfig::GetInstance().m_showNotesColumn) + if (SConfig::GetInstance().m_showMakerColumn) { SetColumnWidth(COLUMN_TITLE, resizable / 2); - SetColumnWidth(COLUMN_NOTES, resizable / 2); + SetColumnWidth(COLUMN_MAKER, resizable / 2); } else { @@ -1335,7 +1319,7 @@ void CGameListCtrl::AutomaticColumnWidth() else { SetColumnWidth(COLUMN_TITLE, resizable); - SetColumnWidth(COLUMN_NOTES, 0); + SetColumnWidth(COLUMN_MAKER, 0); } } } diff --git a/Source/Core/DolphinWX/GameListCtrl.h b/Source/Core/DolphinWX/GameListCtrl.h index 15f89b2944..b298d1514c 100644 --- a/Source/Core/DolphinWX/GameListCtrl.h +++ b/Source/Core/DolphinWX/GameListCtrl.h @@ -52,7 +52,7 @@ public: COLUMN_PLATFORM, COLUMN_BANNER, COLUMN_TITLE, - COLUMN_NOTES, + COLUMN_MAKER, COLUMN_ID, COLUMN_COUNTRY, COLUMN_SIZE, diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 5f9b2167b7..8c3ff3c691 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -176,7 +176,7 @@ enum // List Column Title Toggles IDM_SHOW_SYSTEM, IDM_SHOW_BANNER, - IDM_SHOW_NOTES, + IDM_SHOW_MAKER, IDM_SHOW_ID, IDM_SHOW_REGION, IDM_SHOW_SIZE,