diff options
author | Jaromir Wysoglad | 2019-08-22 02:49:01 -0700 |
---|---|---|
committer | Filippos Karapetis | 2019-08-24 18:12:45 +0300 |
commit | fcbf59f5ba37c1cbfdfa0ccacfc6b602033b9d86 (patch) | |
tree | 3a62e978bb931f456a57455987ac129074847fec | |
parent | 0c74a7f27eaad70a31a6dae814954973c5a1da85 (diff) | |
download | scummvm-rg350-fcbf59f5ba37c1cbfdfa0ccacfc6b602033b9d86.tar.gz scummvm-rg350-fcbf59f5ba37c1cbfdfa0ccacfc6b602033b9d86.tar.bz2 scummvm-rg350-fcbf59f5ba37c1cbfdfa0ccacfc6b602033b9d86.zip |
COMMON: Convert endianity when needed in Encoding.
-rw-r--r-- | common/encoding.cpp | 61 | ||||
-rw-r--r-- | common/encoding.h | 19 |
2 files changed, 77 insertions, 3 deletions
diff --git a/common/encoding.cpp b/common/encoding.cpp index 719887d35e..aeae520dbb 100644 --- a/common/encoding.cpp +++ b/common/encoding.cpp @@ -24,6 +24,7 @@ #include "common/textconsole.h" #include "common/system.h" #include "common/translation.h" +#include "common/endian.h" #include <errno.h> namespace Common { @@ -38,6 +39,29 @@ Encoding::~Encoding() { deinitIconv(_iconvHandle); } +char *Encoding::switchEndian(const char *string, int length, int bitCount) { + assert(bitCount % 8 == 0); + assert(length % (bitCount / 8) == 0); + char *newString = (char *) malloc(length); + if (!newString) { + warning("Could not allocate memory for string conversion"); + return nullptr; + } + if (bitCount == 16) { + int characterCount = length / 2; + for(int i = 0; i < characterCount ; i++) + ((uint16 *) newString)[i] = SWAP_BYTES_16(((const uint16 *) string)[i]); + return newString; + } else if (bitCount == 32) { + int characterCount = length / 4; + for(int i = 0; i < characterCount ; i++) + ((uint32 *) newString)[i] = SWAP_BYTES_32(((const uint32 *) string)[i]); + return newString; + } else { + return nullptr; + } +} + String Encoding::addUtfEndianness(const String &str) { if (str.equalsIgnoreCase("utf-16") || str.equalsIgnoreCase("utf-32")) { #ifdef SCUMM_BIG_ENDIAN @@ -102,6 +126,21 @@ char *Encoding::convertWithTransliteration(iconv_t iconvHandle, const String &to memcpy(result, string, length); return result; } + if ((addUtfEndianness(to).equalsIgnoreCase("utf-16be") && + addUtfEndianness(from).equalsIgnoreCase("utf-16le")) || + (addUtfEndianness(to).equalsIgnoreCase("utf-16le") && + addUtfEndianness(from).equalsIgnoreCase("utf-16be")) || + (addUtfEndianness(to).equalsIgnoreCase("utf-32be") && + addUtfEndianness(from).equalsIgnoreCase("utf-32le")) || + (addUtfEndianness(to).equalsIgnoreCase("utf-32le") && + addUtfEndianness(from).equalsIgnoreCase("utf-32be"))) + { + // The encoding is the same, we just need to switch the endianness + if (to.hasPrefixIgnoreCase("utf-16")) + return switchEndian(string, length, 16); + else + return switchEndian(string, length, 32); + } char *newString = nullptr; String newFrom = from; size_t newLength = length; @@ -265,20 +304,34 @@ char *Encoding::convertTransManMapping(const char *to, const char *from, const c free(partialResult); return finalResult; } else if (currentCharset.equalsIgnoreCase(to) && String(from).hasPrefixIgnoreCase("utf-32")) { - // We accept only the machine endianness + bool swapEndian = false; + char *newString = nullptr; + #ifdef SCUMM_BIG_ENDIAN if (String(from).hasSuffixIgnoreCase("LE")) - return nullptr; + swapEndian = true; #else if (String(from).hasSuffixIgnoreCase("BE")) - return nullptr; + swapEndian = true; #endif + if (swapEndian) { + if (String(from).hasPrefixIgnoreCase("utf-16")) + newString = switchEndian(string, length, 16); + if (String(from).hasPrefixIgnoreCase("utf-32")) + newString = switchEndian(string, length, 32); + if (newString != nullptr) + string = newString; + else + return nullptr; + } // We can do reverse mapping const uint32 *mapping = TransMan.getCharsetMapping(); const uint32 *src = (const uint32 *) string; char *result = (char *) calloc(sizeof(char), (length + 4)); if (!result) { warning("Couldn't allocate memory for encoding conversion"); + if (newString != nullptr) + free(newString); return nullptr; } for (unsigned i = 0; i < length; i++) { @@ -289,6 +342,8 @@ char *Encoding::convertTransManMapping(const char *to, const char *from, const c } } } + if (newString != nullptr) + free(newString); return result; } else return nullptr; diff --git a/common/encoding.h b/common/encoding.h index 6018eaf6e4..c8f864d2ec 100644 --- a/common/encoding.h +++ b/common/encoding.h @@ -35,6 +35,11 @@ typedef void* iconv_t; #include "common/scummsys.h" #include "common/str.h" +#include "common/system.h" + +#ifdef WIN32 +#include "backends/platform/sdl/win32/win32.h" +#endif namespace Common { @@ -44,6 +49,9 @@ namespace Common { * ScummVM is compiled with or without iconv. */ class Encoding { +#ifdef WIN32 + friend char *OSystem_Win32::convertEncoding(const char*, const char *, const char *, size_t); +#endif public: /** * Constructs everything needed for the conversion between 2 encodings @@ -234,6 +242,17 @@ class Encoding { * the same string. */ static String addUtfEndianness(const String &str); + + /** + * Switches the endianity of a string. + * + * @param string Array containing the characters of a string. + * @param length Length of the string in bytes + * @param bitCount Number of bits used for each character. + * + * @return Array of characters with the opposite endianity + */ + static char *switchEndian(const char *string, int length, int bitCount); }; } |