diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index aab0f3bd58..e499fc40c3 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -17,13 +17,19 @@ #include #include +#include #include "Common.h" #include "CommonPaths.h" #include "StringUtil.h" #ifdef _WIN32 -#include + #include +#elif defined(ANDROID) + +#else + #include + #include #endif // faster than sscanf @@ -418,18 +424,80 @@ std::string SHIFTJISToUTF8(const std::string& input) return UTF16ToUTF8(CPToUTF16(932, input)); } +std::string CP1252ToUTF8(const std::string& input) +{ + return UTF16ToUTF8(CPToUTF16(1252, input)); +} + #else -std::string UTF16ToUTF8(const std::wstring& input) +template +std::string CodeToUTF8(const char* fromcode, const std::basic_string& input) { - // TODO: implement - return std::string(); + std::string result; + +#if defined(ANDROID) + result = "Not implemented on Android!"; + +#else + iconv_t const conv_desc = iconv_open("UTF-8", fromcode); + if ((iconv_t)-1 == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + size_t const in_bytes = sizeof(T) * input.size(); + size_t const out_buffer_size = 4 * in_bytes; + + std::string out_buffer; + out_buffer.resize(out_buffer_size); + + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); + + size_t const iconv_size = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, + &dst_buffer, &dst_bytes); + + if ((size_t)-1 == iconv_size) + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + } + else + { + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + // TODO: why is this needed? + result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); + } + + iconv_close(conv_desc); + } + +#endif + return result; +} + +std::string CP1252ToUTF8(const std::string& input) +{ + return CodeToUTF8("CP1252", input); } std::string SHIFTJISToUTF8(const std::string& input) { - // TODO: implement - return std::string(); + //return CodeToUTF8("CP932", input); + return CodeToUTF8("SJIS", input); +} + +std::string UTF16ToUTF8(const std::wstring& input) +{ + //return CodeToUTF8("UCS-2", input); + //return CodeToUTF8("UCS-2LE", input); + //return CodeToUTF8("UTF-16", input); + return CodeToUTF8("UTF-16LE", input); } #endif diff --git a/Source/Core/Common/Src/StringUtil.h b/Source/Core/Common/Src/StringUtil.h index ce5751f80b..9463db5bb1 100644 --- a/Source/Core/Common/Src/StringUtil.h +++ b/Source/Core/Common/Src/StringUtil.h @@ -97,6 +97,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st std::string UriDecode(const std::string & sSrc); std::string UriEncode(const std::string & sSrc); +std::string CP1252ToUTF8(const std::string& str); std::string SHIFTJISToUTF8(const std::string& str); std::string UTF16ToUTF8(const std::wstring& str); diff --git a/Source/Core/DiscIO/Src/BannerLoader.cpp b/Source/Core/DiscIO/Src/BannerLoader.cpp index 7e641aa85b..d38c7e9ea4 100644 --- a/Source/Core/DiscIO/Src/BannerLoader.cpp +++ b/Source/Core/DiscIO/Src/BannerLoader.cpp @@ -31,9 +31,9 @@ IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVo { return new CBannerLoaderWii(pVolume); } - if (_rFileSystem.IsValid()) + if (_rFileSystem.IsValid()) { - return new CBannerLoaderGC(_rFileSystem); + return new CBannerLoaderGC(_rFileSystem, pVolume); } return NULL; diff --git a/Source/Core/DiscIO/Src/BannerLoader.h b/Source/Core/DiscIO/Src/BannerLoader.h index 92bb874979..b30ee17a46 100644 --- a/Source/Core/DiscIO/Src/BannerLoader.h +++ b/Source/Core/DiscIO/Src/BannerLoader.h @@ -44,12 +44,6 @@ class IBannerLoader virtual std::vector GetNames() = 0; virtual std::string GetCompany() = 0; virtual std::vector GetDescriptions() = 0; - - private: - u16 swap16(u16 data) - { - return ((data & 0xff00) >> 8) | ((data & 0xff) << 8); - } }; IBannerLoader* CreateBannerLoader(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume *pVolume); diff --git a/Source/Core/DiscIO/Src/BannerLoaderGC.cpp b/Source/Core/DiscIO/Src/BannerLoaderGC.cpp index bf087cbfb6..d8ae259b16 100644 --- a/Source/Core/DiscIO/Src/BannerLoaderGC.cpp +++ b/Source/Core/DiscIO/Src/BannerLoaderGC.cpp @@ -23,9 +23,10 @@ namespace DiscIO { -CBannerLoaderGC::CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem) - : m_pBannerFile(NULL), - m_IsValid(false) +CBannerLoaderGC::CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume* volume) + : m_pBannerFile(NULL) + , m_IsValid(false) + , m_country(volume->GetCountry()) { // load the opening.bnr size_t FileSize = (size_t) _rFileSystem.GetFileSize("opening.bnr"); @@ -104,7 +105,7 @@ std::vector CBannerLoaderGC::GetNames() auto const banner = reinterpret_cast(m_pBannerFile); - for (int i = 0; i != name_count; ++i) + for (u32 i = 0; i != name_count; ++i) { auto& comment = banner->comment[i]; @@ -167,7 +168,7 @@ std::vector CBannerLoaderGC::GetDescriptions() auto banner = reinterpret_cast(m_pBannerFile); - for (int 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)); diff --git a/Source/Core/DiscIO/Src/BannerLoaderGC.h b/Source/Core/DiscIO/Src/BannerLoaderGC.h index b4903561e4..8bc8c46483 100644 --- a/Source/Core/DiscIO/Src/BannerLoaderGC.h +++ b/Source/Core/DiscIO/Src/BannerLoaderGC.h @@ -19,6 +19,7 @@ #define _BANNER_LOADER_GC_H_ #include "BannerLoader.h" +#include "StringUtil.h" namespace DiscIO { @@ -26,7 +27,7 @@ class CBannerLoaderGC : public IBannerLoader { public: - CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem); + CBannerLoaderGC(DiscIO::IFileSystem& _rFileSystem, DiscIO::IVolume* volume); virtual ~CBannerLoaderGC(); virtual bool IsValid(); @@ -76,8 +77,12 @@ class CBannerLoaderGC template std::string GetDecodedString(const char (&data)[N]) { - // Can I always assume SHIFT-JIS? - return SHIFTJISToUTF8(std::string(data, strnlen(data, sizeof(data)))); + auto const string_decoder = (DiscIO::IVolume::COUNTRY_JAPAN == m_country || + DiscIO::IVolume::COUNTRY_TAIWAN == m_country) ? + SHIFTJISToUTF8 : CP1252ToUTF8; + + // strnlen to trim NULLs + return string_decoder(std::string(data, strnlen(data, sizeof(data)))); } u8* m_pBannerFile; @@ -86,6 +91,8 @@ class CBannerLoaderGC void decode5A3image(u32* dst, u16* src, int width, int height); BANNER_TYPE getBannerType(); + + DiscIO::IVolume::ECountry const m_country; }; } // namespace diff --git a/Source/Core/DiscIO/Src/BannerLoaderWii.cpp b/Source/Core/DiscIO/Src/BannerLoaderWii.cpp index b94e299f04..f606ed8876 100644 --- a/Source/Core/DiscIO/Src/BannerLoaderWii.cpp +++ b/Source/Core/DiscIO/Src/BannerLoaderWii.cpp @@ -25,25 +25,6 @@ #include "FileUtil.h" #include "FileHandlerARC.h" -// HyperIris: dunno if this suitable, may be need move. -#ifdef _WIN32 -#include -#else -#include -#ifndef ANDROID -#include -#endif -#include -#endif - -#ifndef ICONV_CONST -#if defined __FreeBSD__ || __NetBSD__ -#define ICONV_CONST const -#else -#define ICONV_CONST -#endif -#endif - namespace DiscIO { @@ -164,35 +145,24 @@ bool CBannerLoaderWii::GetBanner(u32* _pBannerImage) return true; } -bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::string& s) -{ - bool ret = false; - - if (IsValid()) - { - // find Banner type - SWiiBanner *pBanner = (SWiiBanner*)m_pBannerFile; - // TODO: trim NULLs - ret = CopyBeUnicodeToString(s, pBanner->m_Comment[index], COMMENT_SIZE); - } - - return ret; -} - -bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::wstring& s) +bool CBannerLoaderWii::GetStringFromComments(const CommentIndex index, std::string& result) { if (IsValid()) { - // find Banner type - SWiiBanner* pBanner = (SWiiBanner*)m_pBannerFile; - - std::wstring description; - for (int i = 0; i < COMMENT_SIZE; ++i) - description.push_back(Common::swap16(pBanner->m_Comment[index][i])); - - s = description; + auto const banner = reinterpret_cast(m_pBannerFile); + auto const src_ptr = banner->m_Comment[index]; + + // Trim at first NULL + 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; } @@ -237,87 +207,4 @@ void CBannerLoaderWii::decode5A3image(u32* dst, u16* src, int width, int height) } } -bool CBannerLoaderWii::CopyBeUnicodeToString( std::string& _rDestination, const u16* _src, int length ) -{ - bool returnCode = false; -#ifdef _WIN32 - if (_src) - { - std::wstring src; - src.resize(length); - std::transform(_src, _src + length, &src[0], (u16(&)(u16))Common::swap16); - - _rDestination = UTF16ToUTF8(src); - returnCode = true; - } -#else -#ifdef ANDROID - return false; -#else - if (_src) - { - iconv_t conv_desc = iconv_open("UTF-8", "CP932"); - if (conv_desc == (iconv_t) -1) - { - // Initialization failure. - if (errno == EINVAL) - { - ERROR_LOG(DISCIO, "Conversion from CP932 to UTF-8 is not supported."); - } - else - { - ERROR_LOG(DISCIO, "Iconv initialization failure: %s\n", strerror (errno)); - } - return false; - } - - char* src_buffer = new char[length]; - for (int i = 0; i < length; i++) - src_buffer[i] = swap16(_src[i]); - - size_t inbytes = sizeof(char) * length; - size_t outbytes = 2 * inbytes; - char* utf8_buffer = new char[outbytes + 1]; - memset(utf8_buffer, 0, (outbytes + 1) * sizeof(char)); - - // Save the buffer locations because iconv increments them - char* utf8_buffer_start = utf8_buffer; - char* src_buffer_start = src_buffer; - - size_t iconv_size = iconv(conv_desc, - (ICONV_CONST char**)&src_buffer, &inbytes, - &utf8_buffer, &outbytes); - - // Handle failures - if (iconv_size == (size_t) -1) - { - ERROR_LOG(DISCIO, "iconv failed."); - switch (errno) { - case EILSEQ: - ERROR_LOG(DISCIO, "Invalid multibyte sequence."); - break; - case EINVAL: - ERROR_LOG(DISCIO, "Incomplete multibyte sequence."); - break; - case E2BIG: - ERROR_LOG(DISCIO, "Insufficient space allocated for output buffer."); - break; - default: - ERROR_LOG(DISCIO, "Error: %s.", strerror(errno)); - } - } - else - { - _rDestination = utf8_buffer_start; - returnCode = true; - } - delete[] utf8_buffer_start; - delete[] src_buffer_start; - iconv_close(conv_desc); - } -#endif -#endif - return returnCode; -} - } // namespace diff --git a/Source/Core/DiscIO/Src/BannerLoaderWii.h b/Source/Core/DiscIO/Src/BannerLoaderWii.h index 60d317155b..036eeeacbd 100644 --- a/Source/Core/DiscIO/Src/BannerLoaderWii.h +++ b/Source/Core/DiscIO/Src/BannerLoaderWii.h @@ -75,9 +75,6 @@ class CBannerLoaderWii void decode5A3image(u32* dst, u16* src, int width, int height); bool GetStringFromComments(const CommentIndex index, std::string& s); - bool GetStringFromComments(const CommentIndex index, std::wstring& s); - - bool CopyBeUnicodeToString(std::string& _rDestination, const u16* _src, int length); }; } // namespace diff --git a/Source/Core/DiscIO/Src/Volume.h b/Source/Core/DiscIO/Src/Volume.h index 4743cfce89..c19aaf93a8 100644 --- a/Source/Core/DiscIO/Src/Volume.h +++ b/Source/Core/DiscIO/Src/Volume.h @@ -22,6 +22,7 @@ #include #include "Common.h" +#include "StringUtil.h" namespace DiscIO { @@ -37,6 +38,7 @@ public: virtual void GetTMD(u8*, u32 *_sz) const { *_sz=0; } virtual std::string GetUniqueID() const = 0; virtual std::string GetMakerID() const = 0; + // TODO: eliminate? virtual std::string GetName() const; virtual std::vector GetNames() const = 0; virtual u32 GetFSTSize() const = 0;