diff --git a/Source/Core/Common/StringUtil.cpp b/Source/Core/Common/StringUtil.cpp index 445224757b..a368e703fe 100644 --- a/Source/Core/Common/StringUtil.cpp +++ b/Source/Core/Common/StringUtil.cpp @@ -22,6 +22,7 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" +#include "Common/Swap.h" #ifdef _WIN32 #include @@ -576,3 +577,11 @@ std::string UTF16ToUTF8(const std::wstring& input) } #endif + +std::string UTF16BEToUTF8(const char16_t* str, size_t max_size) +{ + const char16_t* str_end = std::find(str, str + max_size, '\0'); + std::wstring result(static_cast(str_end - str), '\0'); + std::transform(str, str_end, result.begin(), static_cast(Common::swap16)); + return UTF16ToUTF8(result); +} diff --git a/Source/Core/Common/StringUtil.h b/Source/Core/Common/StringUtil.h index 374f4eeb79..b5632c364b 100644 --- a/Source/Core/Common/StringUtil.h +++ b/Source/Core/Common/StringUtil.h @@ -125,6 +125,7 @@ std::string CP1252ToUTF8(const std::string& str); std::string SHIFTJISToUTF8(const std::string& str); std::string UTF8ToSHIFTJIS(const std::string& str); std::string UTF16ToUTF8(const std::wstring& str); +std::string UTF16BEToUTF8(const char16_t* str, size_t max_size); // Stops at \0 #ifdef _WIN32 diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 9e095f464e..0e6a22fd7a 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -18,6 +18,7 @@ set(SRCS VolumeGC.cpp VolumeWad.cpp VolumeWii.cpp + WiiSaveBanner.cpp WiiWad.cpp ) diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index 4c8b542a6f..b9980f8f29 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -55,6 +55,7 @@ + @@ -77,6 +78,7 @@ + @@ -96,4 +98,4 @@ - + \ No newline at end of file diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index c196ae25aa..4f64f4e33b 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -81,6 +81,9 @@ DiscExtractor + + NAND + @@ -143,8 +146,11 @@ DiscExtractor + + NAND + - + \ No newline at end of file diff --git a/Source/Core/DiscIO/Volume.cpp b/Source/Core/DiscIO/Volume.cpp index 014eda7d31..9ae87466e2 100644 --- a/Source/Core/DiscIO/Volume.cpp +++ b/Source/Core/DiscIO/Volume.cpp @@ -12,13 +12,8 @@ #include #include -#include "Common/ColorUtil.h" #include "Common/CommonTypes.h" -#include "Common/File.h" -#include "Common/FileUtil.h" -#include "Common/NandPaths.h" #include "Common/StringUtil.h" -#include "Common/Swap.h" #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" @@ -28,42 +23,9 @@ 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; - const IOS::ES::TicketReader Volume::INVALID_TICKET{}; const IOS::ES::TMDReader Volume::INVALID_TMD{}; -std::vector Volume::GetWiiBanner(int* width, int* height, u64 title_id) -{ - *width = 0; - *height = 0; - - const std::string file_name = - Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT) + "banner.bin"; - - File::IOFile file(file_name, "rb"); - if (file.GetSize() < WII_BANNER_OFFSET + WII_BANNER_SIZE) - return std::vector(); - - 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; -} - std::map Volume::ReadWiiNames(const std::vector& data) { std::map names; @@ -73,11 +35,8 @@ std::map Volume::ReadWiiNames(const std::vector& data 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); + std::string name = UTF16BEToUTF8(reinterpret_cast(data.data() + name_start), + NAME_STRING_LENGTH); if (!name.empty()) names[static_cast(i)] = name; } diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index 2f075495a6..67609ddabe 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -102,8 +102,6 @@ public: // Size on disc (compressed size) virtual u64 GetRawSize() const = 0; - static std::vector GetWiiBanner(int* width, int* height, u64 title_id); - protected: template std::string DecodeString(const char (&data)[N]) const diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp index 4b45f0b706..d09baf1f6a 100644 --- a/Source/Core/DiscIO/VolumeWad.cpp +++ b/Source/Core/DiscIO/VolumeWad.cpp @@ -22,6 +22,7 @@ #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" #include "DiscIO/VolumeWad.h" +#include "DiscIO/WiiSaveBanner.h" namespace DiscIO { @@ -152,7 +153,7 @@ std::vector VolumeWAD::GetBanner(int* width, int* height) const if (!title_id) return std::vector(); - return GetWiiBanner(width, height, *title_id); + return WiiSaveBanner(*title_id).GetBanner(width, height); } BlobType VolumeWAD::GetBlobType() const diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index 0ed2200f14..2158e71f1a 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -29,6 +29,7 @@ #include "DiscIO/FileSystemGCWii.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" +#include "DiscIO/WiiSaveBanner.h" namespace DiscIO { @@ -316,7 +317,7 @@ std::vector VolumeWii::GetBanner(int* width, int* height) const if (!title_id) return std::vector(); - return GetWiiBanner(width, height, *title_id); + return WiiSaveBanner(*title_id).GetBanner(width, height); } std::string VolumeWii::GetApploaderDate(const Partition& partition) const diff --git a/Source/Core/DiscIO/WiiSaveBanner.cpp b/Source/Core/DiscIO/WiiSaveBanner.cpp new file mode 100644 index 0000000000..798819a42b --- /dev/null +++ b/Source/Core/DiscIO/WiiSaveBanner.cpp @@ -0,0 +1,78 @@ +// Copyright 2009 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DiscIO/WiiSaveBanner.h" + +#include +#include + +#include "Common/ColorUtil.h" +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/File.h" +#include "Common/NandPaths.h" +#include "Common/StringUtil.h" + +namespace DiscIO +{ +constexpr unsigned int BANNER_WIDTH = 192; +constexpr unsigned int BANNER_HEIGHT = 64; +constexpr unsigned int BANNER_SIZE = BANNER_WIDTH * BANNER_HEIGHT * 2; + +constexpr unsigned int ICON_WIDTH = 48; +constexpr unsigned int ICON_HEIGHT = 48; +constexpr unsigned int ICON_SIZE = ICON_WIDTH * ICON_HEIGHT * 2; + +WiiSaveBanner::WiiSaveBanner(u64 title_id) + : WiiSaveBanner(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT) + "banner.bin") +{ +} + +WiiSaveBanner::WiiSaveBanner(const std::string& path) : m_path(path), m_valid(true) +{ + constexpr size_t MINIMUM_SIZE = sizeof(Header) + BANNER_SIZE + ICON_SIZE; + File::IOFile file(path, "rb"); + if (!file.ReadArray(&m_header, 1)) + { + m_header = {}; + m_valid = false; + } + else if (file.GetSize() < MINIMUM_SIZE) + { + m_valid = false; + } +} + +std::string WiiSaveBanner::GetName() const +{ + return UTF16BEToUTF8(m_header.name, ArraySize(m_header.name)); +} + +std::string WiiSaveBanner::GetDescription() const +{ + return UTF16BEToUTF8(m_header.description, ArraySize(m_header.description)); +} + +std::vector WiiSaveBanner::GetBanner(int* width, int* height) const +{ + *width = 0; + *height = 0; + + File::IOFile file(m_path, "rb"); + if (!file.Seek(sizeof(Header), SEEK_SET)) + return std::vector(); + + std::vector banner_data(BANNER_WIDTH * BANNER_HEIGHT); + if (!file.ReadArray(banner_data.data(), banner_data.size())) + return std::vector(); + + std::vector image_buffer(BANNER_WIDTH * BANNER_HEIGHT); + ColorUtil::decode5A3image(image_buffer.data(), banner_data.data(), BANNER_WIDTH, BANNER_HEIGHT); + + *width = BANNER_WIDTH; + *height = BANNER_HEIGHT; + return image_buffer; +} + +} // namespace DiscIO diff --git a/Source/Core/DiscIO/WiiSaveBanner.h b/Source/Core/DiscIO/WiiSaveBanner.h new file mode 100644 index 0000000000..cc3c53a71f --- /dev/null +++ b/Source/Core/DiscIO/WiiSaveBanner.h @@ -0,0 +1,41 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" + +namespace DiscIO +{ +class WiiSaveBanner +{ +public: + explicit WiiSaveBanner(u64 title_id); + explicit WiiSaveBanner(const std::string& path); + + bool IsValid() const { return m_valid; } + const std::string& GetPath() const { return m_path; } + std::string GetName() const; + std::string GetDescription() const; + + std::vector GetBanner(int* width, int* height) const; + +private: + struct Header + { + char magic[4]; // "WIBN" + u32 flags; + u16 animation_speed; + u8 unused[22]; + char16_t name[32]; + char16_t description[32]; + } m_header; + + bool m_valid; + std::string m_path; +}; +} diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 910295b7b2..65e5201dd6 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -34,6 +34,7 @@ #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" +#include "DiscIO/WiiSaveBanner.h" #include "DolphinWX/ISOFile.h" #include "DolphinWX/WxUtils.h" @@ -263,8 +264,9 @@ bool GameListItem::BannerChanged() return false; auto& banner = m_pending.volume_banner; - std::vector buffer = DiscIO::Volume::GetWiiBanner(&banner.width, &banner.height, m_title_id); - if (!buffer.size()) + std::vector buffer = + DiscIO::WiiSaveBanner(m_title_id).GetBanner(&banner.width, &banner.height); + if (buffer.empty()) return false; ReadVolumeBanner(&banner.buffer, buffer, banner.width, banner.height);