liblcf
Loading...
Searching...
No Matches
encoder.cpp
Go to the documentation of this file.
1/*
2 * This file is part of liblcf. Copyright (c) 2020 liblcf authors.
3 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
4 *
5 * liblcf is Free/Libre Open Source Software, released under the MIT License.
6 * For the full copyright and license information, please view the COPYING
7 * file that was distributed with this source code.
8 */
9
10#include "lcf_options.h"
11#include "encoder.h"
12#include "reader_util.h"
13#include "scope_guard.h"
14#include <cstdio>
15#include <cstdlib>
16#include <exception>
17
18#ifdef LCF_SUPPORT_ICU
19# include <unicode/ucsdet.h>
20# include <unicode/ucnv.h>
21#else
22# ifdef _MSC_VER
23# error MSVC builds require ICU
24# endif
25#endif
26
27#ifdef _WIN32
28# include <windows.h>
29#else
30# ifndef LCF_SUPPORT_ICU
31# include <iconv.h>
32# endif
33# include <locale>
34#endif
35
36#if defined(__MORPHOS__) || defined(__amigaos4__)
37#define ICONV_CONST const
38#endif
39
40static std::string filterUtf8Compatible(std::string enc) {
41#ifdef LCF_SUPPORT_ICU
42 if (ucnv_compareNames(enc.c_str(), "UTF-8") == 0) {
43 return "";
44 }
45#endif
46 return enc;
47}
48
49Encoder::Encoder(std::string encoding)
50 : _encoding(filterUtf8Compatible(std::move(encoding)))
51{
52 Init();
53}
54
56 Reset();
57}
58
59bool Encoder::IsOk() const {
60 return _encoding.empty() || (_conv_storage && _conv_runtime);
61}
62
63void Encoder::Encode(std::string& str) {
64 if (_encoding.empty() || str.empty()) {
65 return;
66 }
68}
69
70void Encoder::Decode(std::string& str) {
71 if (_encoding.empty() || str.empty()) {
72 return;
73 }
75}
76
78 if (_encoding.empty()) {
79 return;
80 }
81#ifdef LCF_SUPPORT_ICU
82 auto code_page = atoi(_encoding.c_str());
83 const auto& storage_encoding = code_page > 0
85 : _encoding;
86
87 auto status = U_ZERO_ERROR;
88 constexpr auto runtime_encoding = "UTF-8";
89 auto conv_runtime = ucnv_open(runtime_encoding, &status);
90
91 if (conv_runtime == nullptr) {
92 fprintf(stderr, "liblcf: ucnv_open() error for encoding \"%s\": %s\n", runtime_encoding, u_errorName(status));
93 return;
94 }
95 status = U_ZERO_ERROR;
96 auto sg = makeScopeGuard([&]() { ucnv_close(conv_runtime); });
97
98 auto conv_storage = ucnv_open(storage_encoding.c_str(), &status);
99
100 if (conv_storage == nullptr) {
101 fprintf(stderr, "liblcf: ucnv_open() error for dest encoding \"%s\": %s\n", storage_encoding.c_str(), u_errorName(status));
102 return;
103 }
104
105 sg.Dismiss();
106
107 _conv_runtime = conv_runtime;
108 _conv_storage = conv_storage;
109#else
110 _conv_runtime = const_cast<char*>("UTF-8");
111 _conv_storage = const_cast<char*>(_encoding.c_str());
112#endif
113}
114
116#ifdef LCF_SUPPORT_ICU
117 auto* conv = reinterpret_cast<UConverter*>(_conv_runtime);
118 if (conv) ucnv_close(conv);
119 conv = reinterpret_cast<UConverter*>(_conv_storage);
120 if (conv) ucnv_close(conv);
121#endif
122}
123
124
125void Encoder::Convert(std::string& str, void* conv_dst_void, void* conv_src_void) {
126#ifdef LCF_SUPPORT_ICU
127 const auto& src = str;
128 auto* conv_dst = reinterpret_cast<UConverter*>(conv_dst_void);
129 auto* conv_src = reinterpret_cast<UConverter*>(conv_src_void);
130
131 auto status = U_ZERO_ERROR;
132 _buffer.resize(src.size() * 4);
133
134 const auto* src_p = src.c_str();
135 auto* dst_p = _buffer.data();
136
137 ucnv_convertEx(conv_dst, conv_src,
138 &dst_p, dst_p + _buffer.size(),
139 &src_p, src_p + src.size(),
140 nullptr, nullptr, nullptr, nullptr,
141 true, true,
142 &status);
143
144 if (U_FAILURE(status)) {
145 fprintf(stderr, "liblcf: ucnv_convertEx() error when encoding \"%s\": %s\n", src.c_str(), u_errorName(status));
146 _buffer.clear();
147 }
148
149 str.assign(_buffer.data(), dst_p);
150 return;
151#else
152 auto* conv_dst = reinterpret_cast<const char*>(conv_dst_void);
153 auto* conv_src = reinterpret_cast<const char*>(conv_src_void);
154 iconv_t cd = iconv_open(conv_dst, conv_src);
155 if (cd == (iconv_t)-1)
156 return;
157 char *src = &str.front();
158 size_t src_left = str.size();
159 size_t dst_size = str.size() * 5 + 10;
160 _buffer.resize(dst_size);
161 char *dst = _buffer.data();
162 size_t dst_left = dst_size;
163# ifdef ICONV_CONST
164 char ICONV_CONST *p = src;
165# else
166 char *p = src;
167# endif
168 char *q = dst;
169 size_t status = iconv(cd, &p, &src_left, &q, &dst_left);
170 iconv_close(cd);
171 if (status == (size_t) -1 || src_left > 0) {
172 str.clear();
173 return;
174 }
175 *q++ = '\0';
176 str.assign(dst, dst_size - dst_left);
177 return;
178#endif
179}
180
181
void * _conv_storage
Definition: encoder.h:35
bool IsOk() const
Definition: encoder.cpp:59
void Decode(std::string &str)
Definition: encoder.cpp:70
void Reset()
Definition: encoder.cpp:115
std::vector< char > _buffer
Definition: encoder.h:37
std::string _encoding
Definition: encoder.h:38
void Convert(std::string &str, void *conv_dst, void *conv_src)
Definition: encoder.cpp:125
~Encoder()
Definition: encoder.cpp:55
void * _conv_runtime
Definition: encoder.h:36
Encoder(std::string encoding)
Definition: encoder.cpp:49
void Init()
Definition: encoder.cpp:77
void Encode(std::string &str)
Definition: encoder.cpp:63
static std::string filterUtf8Compatible(std::string enc)
Definition: encoder.cpp:40
std::string CodepageToEncoding(int codepage)
Definition: reader_util.cpp:50
STL namespace.
ScopeGuard< F > makeScopeGuard(F &&f)
Definition: scope_guard.h:39