diff options
| author | comex <comexk@gmail.com> | 2015-05-05 16:20:04 -0400 |
|---|---|---|
| committer | comex <comexk@gmail.com> | 2015-05-05 16:20:04 -0400 |
| commit | 6414cdabb2ae7762f2d98427b9ff024af07bb959 (patch) | |
| tree | 5362ae99777fc494d6c2b059b0bd63a6bb296b97 /Source/Core/DiscIO | |
| parent | 430e8b7adeb5b3adb12ef50ce7961562463b0fa0 (diff) | |
| parent | df8e768b77b551832ace0d552ec10c1b062c55f3 (diff) | |
Merge pull request #2286 from JosJuice/wii-opening-bnr
Read opening.bnr to get names from Wii discs
Diffstat (limited to 'Source/Core/DiscIO')
22 files changed, 399 insertions, 659 deletions
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 <cstddef> - -#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 7d6a25b8cf..0000000000 --- a/Source/Core/DiscIO/BannerLoader.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include <vector> - -#include "Common/CommonTypes.h" - -namespace DiscIO -{ - -class IFileSystem; -class IVolume; - -class IBannerLoader -{ -public: - IBannerLoader() - : m_IsValid(false) - , m_pBannerFile(nullptr) - {} - - virtual ~IBannerLoader() - {} - - virtual std::vector<u32> GetBanner(int* pWidth, int* pHeight) = 0; - - virtual std::vector<std::string> GetNames() = 0; - virtual std::string GetCompany() = 0; - virtual std::vector<std::string> 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 ce265a016e..0000000000 --- a/Source/Core/DiscIO/BannerLoaderGC.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include <cstddef> -#include <string> -#include <vector> - -#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<u32> CBannerLoaderGC::GetBanner(int* pWidth, int* pHeight) -{ - std::vector<u32> 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::vector<std::string> CBannerLoaderGC::GetNames() -{ - std::vector<std::string> names; - - if (!IsValid()) - { - return names; - } - - u32 name_count = 0; - - // find Banner type - switch (m_BNRType) - { - case CBannerLoaderGC::BANNER_BNR1: - name_count = 1; - break; - - case CBannerLoaderGC::BANNER_BNR2: - name_count = 6; - break; - - default: - break; - } - - auto const banner = reinterpret_cast<const DVDBanner*>(m_pBannerFile); - - for (u32 i = 0; i != name_count; ++i) - { - auto& comment = banner->comment[i]; - - if (comment.longTitle[0]) - { - auto& data = comment.longTitle; - names.push_back(GetDecodedString(data)); - } - else - { - auto& data = comment.shortTitle; - names.push_back(GetDecodedString(data)); - } - } - - 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::vector<std::string> CBannerLoaderGC::GetDescriptions() -{ - std::vector<std::string> descriptions; - - if (!IsValid()) - { - return descriptions; - } - - u32 desc_count = 0; - - // find Banner type - switch (m_BNRType) - { - case CBannerLoaderGC::BANNER_BNR1: - desc_count = 1; - break; - - // English, German, French, Spanish, Italian, Dutch - case CBannerLoaderGC::BANNER_BNR2: - desc_count = 6; - break; - - default: - break; - } - - auto banner = reinterpret_cast<const DVDBanner*>(m_pBannerFile); - - for (u32 i = 0; i != desc_count; ++i) - { - auto& data = banner->comment[i].comment; - descriptions.push_back(GetDecodedString(data)); - } - - return descriptions; -} - -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; - } - return type; -} - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoaderGC.h b/Source/Core/DiscIO/BannerLoaderGC.h deleted file mode 100644 index 94e261699c..0000000000 --- a/Source/Core/DiscIO/BannerLoaderGC.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include <cstring> -#include <string> -#include <vector> - -#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<u32> GetBanner(int* pWidth, int* pHeight) override; - - virtual std::vector<std::string> GetNames() override; - virtual std::string GetCompany() override; - virtual std::vector<std::string> 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 <u32 N> - 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 eaab54a942..0000000000 --- a/Source/Core/DiscIO/BannerLoaderWii.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include <algorithm> -#include <cstddef> -#include <cstdio> -#include <string> -#include <vector> - -#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<u32> CBannerLoaderWii::GetBanner(int* pWidth, int* pHeight) -{ - SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile; - std::vector<u32> 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<const SWiiBanner*>(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::vector<std::string> CBannerLoaderWii::GetNames() -{ - std::vector<std::string> ret(1); - - if (!GetStringFromComments(NAME_IDX, ret[0])) - ret.clear(); - - return ret; -} - -std::string CBannerLoaderWii::GetCompany() -{ - return ""; -} - -std::vector<std::string> CBannerLoaderWii::GetDescriptions() -{ - std::vector<std::string> result(1); - if (!GetStringFromComments(DESC_IDX, result[0])) - result.clear(); - return result; -} - -} // namespace diff --git a/Source/Core/DiscIO/BannerLoaderWii.h b/Source/Core/DiscIO/BannerLoaderWii.h deleted file mode 100644 index 1bbe077509..0000000000 --- a/Source/Core/DiscIO/BannerLoaderWii.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include <string> -#include <vector> - -#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<u32> GetBanner(int* pWidth, int* pHeight) override; - - virtual std::vector<std::string> GetNames() override; - virtual std::string GetCompany() override; - virtual std::vector<std::string> 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 @@ </ImportGroup> <PropertyGroup Label="UserMacros" /> <ItemGroup> - <ClCompile Include="BannerLoader.cpp" /> - <ClCompile Include="BannerLoaderGC.cpp" /> - <ClCompile Include="BannerLoaderWii.cpp" /> <ClCompile Include="Blob.cpp" /> <ClCompile Include="CISOBlob.cpp" /> <ClCompile Include="CompressedBlob.cpp" /> @@ -58,9 +55,6 @@ <ClCompile Include="WiiWad.cpp" /> </ItemGroup> <ItemGroup> - <ClInclude Include="BannerLoader.h" /> - <ClInclude Include="BannerLoaderGC.h" /> - <ClInclude Include="BannerLoaderWii.h" /> <ClInclude Include="Blob.h" /> <ClInclude Include="CISOBlob.h" /> <ClInclude Include="CompressedBlob.h" /> 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 @@ <ClCompile Include="DiscScrubber.cpp"> <Filter>DiscScrubber</Filter> </ClCompile> - <ClCompile Include="BannerLoader.cpp"> - <Filter>FileHandler</Filter> - </ClCompile> - <ClCompile Include="BannerLoaderGC.cpp"> - <Filter>FileHandler</Filter> - </ClCompile> - <ClCompile Include="BannerLoaderWii.cpp"> - <Filter>FileHandler</Filter> - </ClCompile> <ClCompile Include="Filesystem.cpp"> <Filter>FileSystem</Filter> </ClCompile> @@ -89,15 +80,6 @@ <ClInclude Include="DiscScrubber.h"> <Filter>DiscScrubber</Filter> </ClInclude> - <ClInclude Include="BannerLoaderWii.h"> - <Filter>FileHandler</Filter> - </ClInclude> - <ClInclude Include="BannerLoader.h"> - <Filter>FileHandler</Filter> - </ClInclude> - <ClInclude Include="BannerLoaderGC.h"> - <Filter>FileHandler</Filter> - </ClInclude> <ClInclude Include="Filesystem.h"> <Filter>FileSystem</Filter> </ClInclude> 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<const SFileInfo *> &_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<const SFileInfo *> &_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; diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 6efe04a37f..c0fea6ccc4 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -4,18 +4,57 @@ #pragma once +#include <map> #include <memory> #include <string> #include <vector> #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "Common/StringUtil.h" 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() {} @@ -36,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 std::vector<std::string> GetNames() const = 0; + virtual int GetRevision() const = 0; + virtual std::string GetName() const = 0; + virtual std::map<ELanguage, std::string> GetNames() const = 0; + virtual std::map<ELanguage, std::string> GetDescriptions() const { return std::map<ELanguage, std::string>(); } + virtual std::string GetCompany() const { return std::string(); } + virtual std::vector<u32> GetBanner(int* width, int* height) const; virtual u32 GetFSTSize() const = 0; virtual std::string GetApploaderDate() const = 0; @@ -50,31 +91,35 @@ 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; // Size on disc (compressed size) virtual u64 GetRawSize() const = 0; + +protected: + template <u32 N> + 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); + } + + static std::map<IVolume::ELanguage, std::string> ReadWiiNames(std::vector<u8>& 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 87f0c722a7..d9b5240327 100644 --- a/Source/Core/DiscIO/VolumeCommon.cpp +++ b/Source/Core/DiscIO/VolumeCommon.cpp @@ -2,16 +2,83 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include <algorithm> +#include <map> #include <string> +#include <utility> #include <vector> +#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<u32> 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<u32>(); + + if (File::GetSize(file_name) < WII_BANNER_OFFSET + WII_BANNER_SIZE) + return std::vector<u32>(); + + File::IOFile file(file_name, "rb"); + if (!file.Seek(WII_BANNER_OFFSET, SEEK_SET)) + return std::vector<u32>(); + + std::vector<u8> banner_file(WII_BANNER_SIZE); + if (!file.ReadBytes(banner_file.data(), banner_file.size())) + return std::vector<u32>(); + + std::vector<u32> 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; +} + +std::map<IVolume::ELanguage, std::string> IVolume::ReadWiiNames(std::vector<u8>& data) +{ + std::map<IVolume::ELanguage, std::string> 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) { switch (country_code) @@ -98,13 +165,4 @@ u8 GetSysMenuRegion(u16 _TitleVersion) } } -std::string IVolume::GetName() const -{ - auto names = GetNames(); - if (names.empty()) - return ""; - else - return names[0]; -} - } diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 6f3e4ccb7f..876848b2d3 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -8,7 +8,6 @@ #include <map> #include <memory> #include <string> -#include <utility> #include <vector> #include "Common/CommonPaths.h" @@ -183,9 +182,22 @@ std::string CVolumeDirectory::GetMakerID() const return "VOID"; } -std::vector<std::string> CVolumeDirectory::GetNames() const +std::string CVolumeDirectory::GetName() const { - return std::vector<std::string>(1, (char*)(&m_diskHeader[0x20])); + char name[0x60]; + if (Read(0x20, 0x60, (u8*)name, false)) + return DecodeString(name); + else + return ""; +} + +std::map<IVolume::ELanguage, std::string> CVolumeDirectory::GetNames() const +{ + std::map<IVolume::ELanguage, std::string> names; + std::string name = GetName(); + if (!name.empty()) + names[IVolume::ELanguage::LANGUAGE_UNKNOWN] = name; + 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..7187e8a017 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -39,7 +39,9 @@ public: std::string GetMakerID() const override; - std::vector<std::string> GetNames() const override; + int GetRevision() const override { return 0; } + std::string GetName() const override; + std::map<IVolume::ELanguage, std::string> 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..dd18338f63 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -3,14 +3,18 @@ // Refer to the license.txt file included. #include <cstddef> +#include <map> #include <memory> #include <string> #include <vector> +#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" @@ -92,19 +96,133 @@ int CVolumeGC::GetRevision() const return revision; } -std::vector<std::string> CVolumeGC::GetNames() const +std::string CVolumeGC::GetName() const { - std::vector<std::string> names; + char name[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) + return DecodeString(name); + else + return ""; +} - auto const string_decoder = GetStringDecoder(GetCountry()); +std::map<IVolume::ELanguage, std::string> CVolumeGC::GetNames() const +{ + std::map<IVolume::ELanguage, std::string> names; - char name[0x60 + 1] = {}; - if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)name)) - names.push_back(string_decoder(name)); + if (!LoadBannerFile()) + return names; + + 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<const GCBanner*>(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<IVolume::ELanguage, std::string> CVolumeGC::GetDescriptions() const +{ + std::map<IVolume::ELanguage, std::string> 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<const GCBanner*>(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<u32> CVolumeGC::GetBanner(int* width, int* height) const +{ + if (!LoadBannerFile()) + { + *width = 0; + *height = 0; + return std::vector<u32>(); + } + + std::vector<u32> 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) @@ -154,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<IFileSystem> 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 c2efcd6e9f..3c4abcba31 100644 --- a/Source/Core/DiscIO/VolumeGC.h +++ b/Source/Core/DiscIO/VolumeGC.h @@ -4,6 +4,7 @@ #pragma once +#include <map> #include <memory> #include <string> #include <vector> @@ -27,7 +28,11 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector<std::string> GetNames() const override; + virtual std::string GetName() const override; + std::map<ELanguage, std::string> GetNames() const override; + std::map<ELanguage, std::string> GetDescriptions() const override; + std::string GetCompany() const override; + std::vector<u32> GetBanner(int* width, int* height) const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; @@ -37,11 +42,44 @@ public: u64 GetSize() const override; u64 GetRawSize() const override; - typedef std::string(*StringDecoder)(const std::string&); +private: + bool LoadBannerFile() const; - static StringDecoder GetStringDecoder(ECountry country); + 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<u8> m_banner_file; -private: std::unique_ptr<IBlobReader> m_pReader; }; diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index 1dc746ea4d..7b52e7a82e 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -2,8 +2,8 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include <algorithm> #include <cstddef> +#include <map> #include <string> #include <vector> @@ -117,42 +117,12 @@ bool CVolumeWAD::IsWadFile() const return true; } -std::vector<std::string> CVolumeWAD::GetNames() const +std::map<IVolume::ELanguage, std::string> CVolumeWAD::GetNames() const { - std::vector<std::string> 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, unknown, unknown, 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 - { - 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)); - } - } - - return names; + std::vector<u8> name_data(NAMES_TOTAL_BYTES); + if (!Read(m_opening_bnr_offset + 0x9C, NAMES_TOTAL_BYTES, name_data.data())) + return std::map<IVolume::ELanguage, std::string>(); + return ReadWiiNames(name_data); } u64 CVolumeWAD::GetSize() const diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h index 3205da3a24..229ec6d31b 100644 --- a/Source/Core/DiscIO/VolumeWad.h +++ b/Source/Core/DiscIO/VolumeWad.h @@ -4,6 +4,7 @@ #pragma once +#include <map> #include <memory> #include <string> #include <vector> @@ -30,9 +31,10 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector<std::string> GetNames() const override; - u32 GetFSTSize() const override { return 0; } - std::string GetApploaderDate() const override { return "0"; } + std::string GetName() const override { return ""; } + std::map<IVolume::ELanguage, std::string> GetNames() const override; + 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 4c703fdb3f..7657c0a28d 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp @@ -4,6 +4,7 @@ #include <cstddef> #include <cstring> +#include <map> #include <string> #include <vector> #include <polarssl/aes.h> @@ -15,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" @@ -191,17 +193,21 @@ int CVolumeWiiCrypted::GetRevision() const return revision; } -std::vector<std::string> CVolumeWiiCrypted::GetNames() const +std::string CVolumeWiiCrypted::GetName() const { - std::vector<std::string> names; + char name_buffer[0x60]; + if (m_pReader != nullptr && Read(0x20, 0x60, (u8*)&name_buffer, false)) + return DecodeString(name_buffer); - 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)); + return ""; +} - return names; +std::map<IVolume::ELanguage, std::string> CVolumeWiiCrypted::GetNames() const +{ + std::unique_ptr<IFileSystem> file_system(CreateFileSystem(this)); + std::vector<u8> 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 diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h index 4816bc2ebc..11092c33d1 100644 --- a/Source/Core/DiscIO/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/VolumeWiiCrypted.h @@ -4,6 +4,7 @@ #pragma once +#include <map> #include <memory> #include <string> #include <vector> @@ -30,7 +31,8 @@ public: std::string GetUniqueID() const override; std::string GetMakerID() const override; int GetRevision() const override; - std::vector<std::string> GetNames() const override; + std::string GetName() const override; + std::map<IVolume::ELanguage, std::string> GetNames() const override; u32 GetFSTSize() const override; std::string GetApploaderDate() const override; |
