From dfbbd228e621679ce25caafafd82cea09dabecfb Mon Sep 17 00:00:00 2001 From: Jaromir Wysoglad Date: Fri, 26 Jul 2019 00:39:44 +0200 Subject: COMMON: Add encoding conversion using iconv --- common/encoding.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/encoding.h | 67 +++++++++++++++++++++++ common/module.mk | 1 + 3 files changed, 222 insertions(+) create mode 100644 common/encoding.cpp create mode 100644 common/encoding.h diff --git a/common/encoding.cpp b/common/encoding.cpp new file mode 100644 index 0000000000..43dce0420a --- /dev/null +++ b/common/encoding.cpp @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/encoding.h" +#include "common/debug.h" +#include "common/textconsole.h" +#include + +namespace Common { + +Encoding::Encoding(const String &to, const String &from) + : _to(to) + , _from(from) { +#ifdef USE_ICONV + String toTranslit = to + "//TRANSLIT"; + _iconvHandle = iconv_open(toTranslit.c_str(), from.c_str()); +#endif // USE_ICONV +} + +Encoding::~Encoding() { +#ifdef USE_ICONV + if (_iconvHandle != (iconv_t) -1) + iconv_close(_iconvHandle); +#endif // USE_ICONV +} + +char *Encoding::convert(const char *string, size_t size) { +#ifndef USE_ICONV + _iconvHandle = 0; +#endif + return doConversion(_iconvHandle, _to, _from, string, size); +} + +char *Encoding::convert(const String &to, const String &from, const char *string, size_t size) { +#ifdef USE_ICONV + String toTranslit = to + "//TRANSLIT"; + iconv_t iconvHandle = iconv_open(toTranslit.c_str(), from.c_str()); +#else + iconv_t iconvHandle = 0; +#endif // USE_ICONV + + char *result = doConversion(iconvHandle, to, from, string, size); + +#ifdef USE_ICONV + if (iconvHandle != (iconv_t) -1) + iconv_close(iconvHandle); +#endif // USE_ICONV + return result; +} + +char *Encoding::doConversion(iconv_t iconvHandle, const String &to, const String &from, const char *string, size_t length) { + char *result = nullptr; +#ifdef USE_ICONV + if (iconvHandle != (iconv_t) -1) + result = convertIconv(iconvHandle, string, length); + else + debug("Could not convert from %s to %s using iconv", from.c_str(), to.c_str()); + if (result == nullptr) + debug("Error while converting with iconv"); +#else + debug("Iconv is not available"); +#endif // USE_ICONV + + return result; +} + +char *Encoding::convertIconv(iconv_t iconvHandle, const char *string, size_t length) { +#ifdef USE_ICONV + debug("Trying iconv..."); + + size_t inSize = length; + size_t outSize = inSize; + size_t stringSize = inSize > 4 ? inSize : outSize; + + +#ifdef ICONV_USES_CONST + const char *src = string; +#else + char *src = new char[length]; + char *originalSrc = src; + memcpy(src, string, length); +#endif // ICONV_USES_CONST + + char *buffer = (char *) malloc(sizeof(char) * stringSize); + if (!buffer) { + warning ("Cannot allocate memory for converting string"); + return nullptr; + } + memset(buffer, 0, stringSize); + char *dst = buffer; + bool error = false; + + while (inSize > 0) { + if (iconv(iconvHandle, &src, &inSize, &dst, &outSize) == ((size_t)-1)) { + // from SDLs implementation of SDL_iconv_string (slightly altered) + if (errno == E2BIG) { + char *oldString = buffer; + stringSize *= 2; + buffer = (char *) realloc(buffer, stringSize); + if (!buffer) { + warning ("Cannot allocate memory for converting string"); + error = true; + break; + } + dst = buffer + (dst - oldString); + outSize = stringSize - (dst - buffer); + memset(dst, 0, stringSize / 2); + } else { + error = true; + debug("iconv failed"); + break; + } + } + } + // Add a zero character to the end. Hopefuly UTF32 uses the most bytes from + // all possible encodings, so add 4 zero bytes. + buffer = (char *) realloc(buffer, stringSize + 4); + memset(buffer + stringSize, 0, 4); + +#ifndef ICONV_USES_CONST + delete[] originalSrc; +#endif // ICONV_USES_CONST + + if (error) + return nullptr; + debug("Size: %d", stringSize); + + return buffer; +#else + debug("Iconv isn't available"); + return nullptr; +#endif //USE_ICONV +} + +} diff --git a/common/encoding.h b/common/encoding.h new file mode 100644 index 0000000000..3fbd482eef --- /dev/null +++ b/common/encoding.h @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef COMMON_ENCODING_H +#define COMMON_ENCODING_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#ifdef USE_ICONV +#include +#else +typedef void* iconv_t; +#endif // USE_ICONV + +#include "common/scummsys.h" +#include "common/str.h" + +namespace Common { + +class Encoding { + public: + Encoding(const String &to, const String &from); + ~Encoding(); + + char *convert(const char *string, size_t length); + static char *convert(const String &to, const String &from, const char *string, size_t length); + + String getFrom() {return _from;}; + void setFrom(const String &from) {_from = from;}; + + String getTo() {return _to;}; + void setTo(const String &to) {_to = to;}; + + private: + String _to; + String _from; + + static char *doConversion(iconv_t iconvHandle, const String &to, const String &from, const char *string, size_t length); + + iconv_t _iconvHandle; + static char *convertIconv(iconv_t iconvHandle, const char *string, size_t length); + +}; + +} + +#endif // COMMON_ENCODING_H diff --git a/common/module.mk b/common/module.mk index 5ab2367e5d..46e32d72d9 100644 --- a/common/module.mk +++ b/common/module.mk @@ -50,6 +50,7 @@ MODULE_OBJS += \ dct.o \ fft.o \ rdft.o \ + encoding.o \ sinetables.o ifdef ENABLE_EVENTRECORDER -- cgit v1.2.3