aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaromir Wysoglad2019-08-22 02:49:01 -0700
committerFilippos Karapetis2019-08-24 18:12:45 +0300
commitfcbf59f5ba37c1cbfdfa0ccacfc6b602033b9d86 (patch)
tree3a62e978bb931f456a57455987ac129074847fec
parent0c74a7f27eaad70a31a6dae814954973c5a1da85 (diff)
downloadscummvm-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.cpp61
-rw-r--r--common/encoding.h19
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);
};
}