Add Encoder class
MODIFY
CMakeLists.txt
CMakeLists.txt
@@ -45,6 +45,7 @@ add_library(lcf
src/reader_flags.cpp
src/reader_lcf.cpp
src/reader_util.cpp
+ src/encoder.cpp
src/reader_xml.cpp
src/rpg_fixup.cpp
src/rpg_setup.cpp

MODIFY
Makefile.am
Makefile.am
@@ -41,6 +41,7 @@ liblcf_la_SOURCES = \
src/lmu_movecommand.cpp \
src/lmu_reader.cpp \
src/lsd_reader.cpp \
+ src/encoder.cpp \
src/reader_flags.cpp \
src/reader_lcf.cpp \
src/reader_util.cpp \
@@ -123,6 +124,7 @@ pkginclude_HEADERS = \
src/lmt_reader.h \
src/lmu_reader.h \
src/lsd_reader.h \
+ src/encoder.h \
src/reader_lcf.h \
src/reader_struct.h \
src/reader_util.h \

MODIFY
builds/vs2015/liblcf.vcxproj
builds/vs2015/liblcf.vcxproj
<ClCompile Include="..\..\src\generated\rpg_enums.cpp" />
<ClCompile Include="..\..\src\reader_struct.cpp" />
<ClCompile Include="..\..\src\data.cpp" />
+ <ClCompile Include="..\..\src\encoder.cpp" />
<ClCompile Include="..\..\src\ini.cpp" />
<ClCompile Include="..\..\src\inireader.cpp" />
<ClCompile Include="..\..\src\ldb_equipment.cpp" />
<ItemGroup>
<ClInclude Include="..\..\src\command_codes.h" />
<ClInclude Include="..\..\src\data.h" />
+ <ClInclude Include="..\..\src\encoder.h" />
<ClInclude Include="..\..\src\ini.h" />
<ClInclude Include="..\..\src\inireader.h" />
<ClInclude Include="..\..\src\scope_guard.h" />

ADD
src/encoder.cpp
+#include "encoder.h"
+#include "reader_util.h"
+#include "scope_guard.h"
+#include <exception>
+
+#ifdef LCF_SUPPORT_ICU
+# include <unicode/ucsdet.h>
+# include <unicode/ucnv.h>
+#else
+# ifdef _MSC_VER
+# error MSVC builds require ICU
+# endif
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+#else
+# ifndef LCF_SUPPORT_ICU
+# include <iconv.h>
+# endif
+# include <locale>
+#endif
+
+#if defined(__MORPHOS__) || defined(__amigaos4__)
+#define ICONV_CONST const
+#endif
+
+Encoder::Encoder(std::string encoding)
+ : _encoding(std::move(encoding))
+{
+ Init();
+}
+
+Encoder::~Encoder() {
+ Reset();
+}
+
+std::string Encoder::Encode(const std::string& src) {
+ return Convert(_conv_runtime, _conv_storage, src);
+}
+
+std::string Encoder::Decode(const std::string& src) {
+ return Convert(_conv_storage, _conv_runtime, src);
+}
+
+void Encoder::Init() {
+ if (_encoding.empty()) {
+ return;
+ }
+ auto code_page = atoi(_encoding.c_str());
+ const auto& storage_encoding = code_page > 0
+ ? ReaderUtil::CodepageToEncoding(code_page)
+ : _encoding;
+
+#ifdef LCF_SUPPORT_ICU
+ auto status = U_ZERO_ERROR;
+ constexpr auto runtime_encoding = "UTF-8";
+ auto conv_runtime = ucnv_open(runtime_encoding, &status);
+
+ if (conv_runtime == nullptr) {
+ fprintf(stderr, "liblcf: ucnv_open() error for encoding \"%s\": %s\n", runtime_encoding, u_errorName(status));
+ throw std::runtime_error("ucnv_open() failed");
+ }
+ status = U_ZERO_ERROR;
+ auto sg = makeScopeGuard([&]() { ucnv_close(conv_runtime); });
+
+ auto conv_storage = ucnv_open(storage_encoding.c_str(), &status);
+
+ if (conv_storage == nullptr) {
+ fprintf(stderr, "liblcf: ucnv_open() error for dest encoding \"%s\": %s\n", storage_encoding.c_str(), u_errorName(status));
+ throw std::runtime_error("ucnv_open() failed");
+ }
+
+ sg.Dismiss();
+
+ _conv_runtime = conv_runtime;
+ _conv_storage = conv_storage;
+#endif
+}
+
+void Encoder::Reset() {
+#ifdef LCF_SUPPORT_ICU
+ auto* conv = reinterpret_cast<UConverter*>(_conv_runtime);
+ if (conv) ucnv_close(conv);
+ conv = reinterpret_cast<UConverter*>(_conv_storage);
+ if (conv) ucnv_close(conv);
+#endif
+}
+
+
+std::string Encoder::Convert(void* conv_dst_void, void* conv_src_void, const std::string& src) {
+ if (_encoding.empty()) {
+ return src;
+ }
+#ifdef LCF_SUPPORT_ICU
+ auto* conv_dst = reinterpret_cast<UConverter*>(conv_dst_void);
+ auto* conv_src = reinterpret_cast<UConverter*>(conv_src_void);
+
+ auto status = U_ZERO_ERROR;
+ _buffer.resize(src.size() * 4);
+
+ const auto* src_p = src.c_str();
+ auto* dst_p = _buffer.data();
+
+ ucnv_convertEx(conv_dst, conv_src,
+ &dst_p, dst_p + _buffer.size(),
+ &src_p, src_p + src.size(),
+ nullptr, nullptr, nullptr, nullptr,
+ true, true,
+ &status);
+
+ if (U_FAILURE(status)) {
+ fprintf(stderr, "liblcf: ucnv_convertEx() error when encoding \"%s\": %s\n", src.c_str(), u_errorName(status));
+ return std::string();
+ }
+
+ return std::string(_buffer.data(), dst_p);
+#endif
+}
+
+

ADD
src/encoder.h
+/*
+ * This file is part of liblcf. Copyright (c) 2018 liblcf authors.
+ * https://github.com/EasyRPG/liblcf - https://easyrpg.org
+ *
+ * liblcf is Free/Libre Open Source Software, released under the MIT License.
+ * For the full copyright and license information, please view the COPYING
+ * file that was distributed with this source code.
+ */
+
+#ifndef LCF_ENCODER_H
+#define LCF_ENCODER_H
+#include <vector>
+#include <string>
+
+class Encoder {
+ public:
+ explicit Encoder(std::string encoding);
+
+ Encoder(const Encoder&) = delete;
+ Encoder& operator=(const Encoder&) = delete;
+
+ ~Encoder();
+
+ std::string Encode(const std::string& src);
+ std::string Decode(const std::string& src);
+
+ const std::string& GetEncoding() const;
+ private:
+ void Init();
+ void Reset();
+ std::string Convert(void* conv_dst, void* conv_src, const std::string& src);
+ private:
+ void* _conv_storage = nullptr;
+ void* _conv_runtime = nullptr;
+ std::vector<char> _buffer;
+ std::string _encoding;
+};
+
+
+inline const std::string& Encoder::GetEncoding() const {
+ return _encoding;
+}
+
+#endif

Add Encoder class