#include <cstring>
#include "Config.hpp"
#include "Converter.hpp"
#include "UTF8Util.hpp"
#include "opencc.h"
#ifdef BAZEL
#include "tools/cpp/runfiles/runfiles.h"
using bazel::tools::cpp::runfiles::Runfiles;
#endif
using namespace opencc;
namespace {
struct InternalData {
const ConverterPtr converter;
InternalData(const ConverterPtr& _converter) : converter(_converter) {}
static InternalData* NewInternalData(const std::string& configFileName,
const std::vector<std::string>& paths,
const char* argv0,
const ConfigLoadOptions& options) {
try {
Config config;
#ifdef BAZEL
std::string err;
std::unique_ptr<Runfiles> bazel_runfiles(
Runfiles::Create(argv0 != nullptr ? argv0 : "", &err));
if (bazel_runfiles != nullptr) {
std::vector<std::string> paths_with_runfiles = paths;
paths_with_runfiles.push_back(
bazel_runfiles->Rlocation("opencc~/data/config"));
paths_with_runfiles.push_back(
bazel_runfiles->Rlocation("opencc~/data/dictionary"));
paths_with_runfiles.push_back(
bazel_runfiles->Rlocation("_main/data/config"));
paths_with_runfiles.push_back(
bazel_runfiles->Rlocation("_main/data/dictionary"));
return new InternalData(
config.NewFromFile(configFileName, paths_with_runfiles, argv0,
options));
}
#endif
return new InternalData(
config.NewFromFile(configFileName, paths, argv0, options));
} catch (Exception& ex) {
throw std::runtime_error(ex.what());
}
}
static InternalData* NewInternalData(
const std::string& configFileName,
const std::shared_ptr<ResourceProvider>& provider,
const ConfigLoadOptions& options) {
try {
Config config;
return new InternalData(
config.NewFromFile(configFileName, provider, options));
} catch (Exception& ex) {
throw std::runtime_error(ex.what());
}
}
};
}
SimpleConverter::SimpleConverter(const std::string& configFileName)
: SimpleConverter(configFileName, ConfigLoadOptions()) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
const ConfigLoadOptions& options)
: SimpleConverter(configFileName, std::vector<std::string>(), options) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
const std::vector<std::string>& paths)
: SimpleConverter(configFileName, paths, ConfigLoadOptions()) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
const std::vector<std::string>& paths,
const ConfigLoadOptions& options)
: SimpleConverter(configFileName, paths, nullptr, options) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
const std::vector<std::string>& paths,
const char* argv0)
: SimpleConverter(configFileName, paths, argv0, ConfigLoadOptions()) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
const std::vector<std::string>& paths,
const char* argv0,
const ConfigLoadOptions& options)
: internalData(
InternalData::NewInternalData(configFileName, paths, argv0,
options)) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
std::shared_ptr<ResourceProvider> provider)
: SimpleConverter(configFileName, provider, ConfigLoadOptions()) {}
SimpleConverter::SimpleConverter(const std::string& configFileName,
std::shared_ptr<ResourceProvider> provider,
const ConfigLoadOptions& options)
: internalData(
InternalData::NewInternalData(configFileName, provider, options)) {}
SimpleConverter::~SimpleConverter() { delete (InternalData*)internalData; }
std::string SimpleConverter::Convert(const std::string& input) const {
return Convert(std::string_view(input));
}
std::string SimpleConverter::Convert(std::string_view input) const {
try {
const InternalData* data = (InternalData*)internalData;
return data->converter->Convert(input);
} catch (Exception& ex) {
throw std::runtime_error(ex.what());
}
}
std::string SimpleConverter::Convert(const char* input) const {
return Convert(std::string_view(input));
}
std::string SimpleConverter::Convert(const char* input, size_t length) const {
if (length == static_cast<size_t>(-1)) {
return Convert(std::string_view(input));
} else {
return Convert(std::string_view(input, length));
}
}
size_t SimpleConverter::Convert(const char* input, char* output) const {
try {
const InternalData* data = (InternalData*)internalData;
const std::string converted = data->converter->Convert(input);
strcpy(output, converted.c_str());
return converted.length();
} catch (Exception& ex) {
throw std::runtime_error(ex.what());
}
}
size_t SimpleConverter::Convert(const char* input, size_t length,
char* output) const {
if (length == static_cast<size_t>(-1)) {
return Convert(input, output);
} else {
std::string trimmed = UTF8Util::FromSubstr(input, length);
return Convert(trimmed.c_str(), output);
}
}
ConversionInspectionResult
SimpleConverter::Inspect(std::string_view input) const {
try {
const InternalData* data = (InternalData*)internalData;
return data->converter->Inspect(input);
} catch (Exception& ex) {
throw std::runtime_error(ex.what());
}
}
static std::string cError;
opencc_t opencc_open_internal(const char* configFileName) {
try {
if (configFileName == nullptr) {
configFileName = OPENCC_DEFAULT_CONFIG_SIMP_TO_TRAD;
}
SimpleConverter* instance = new SimpleConverter(configFileName);
return instance;
} catch (std::runtime_error& ex) {
cError = ex.what();
return reinterpret_cast<opencc_t>(-1);
}
}
#ifdef _MSC_VER
opencc_t opencc_open_w(const wchar_t* configFileName) {
try {
if (configFileName == nullptr) {
return opencc_open_internal(nullptr);
}
std::string utf8fn = UTF8Util::U16ToU8(configFileName);
return opencc_open_internal(utf8fn.c_str());
} catch (std::runtime_error& ex) {
cError = ex.what();
return reinterpret_cast<opencc_t>(-1);
}
}
opencc_t opencc_open(const char* configFileName) {
if (configFileName == nullptr) {
return opencc_open_internal(nullptr);
}
std::wstring wFileName;
int convcnt = MultiByteToWideChar(CP_ACP, 0, configFileName, -1, NULL, 0);
if (convcnt > 0) {
wFileName.resize(convcnt);
MultiByteToWideChar(CP_ACP, 0, configFileName, -1, &wFileName[0], convcnt);
}
return opencc_open_w(wFileName.c_str());
}
#else
opencc_t opencc_open(const char* configFileName) {
return opencc_open_internal(configFileName);
}
#endif
int opencc_close(opencc_t opencc) {
SimpleConverter* instance = reinterpret_cast<SimpleConverter*>(opencc);
delete instance;
return 0;
}
size_t opencc_convert_utf8_to_buffer(opencc_t opencc, const char* input,
size_t length, char* output) {
try {
SimpleConverter* instance = reinterpret_cast<SimpleConverter*>(opencc);
return instance->Convert(input, length, output);
} catch (std::runtime_error& ex) {
cError = ex.what();
return static_cast<size_t>(-1);
}
}
char* opencc_convert_utf8(opencc_t opencc, const char* input, size_t length) {
try {
SimpleConverter* instance = reinterpret_cast<SimpleConverter*>(opencc);
std::string converted = instance->Convert(input, length);
char* output = new char[converted.length() + 1];
memcpy(output, converted.c_str(), converted.length());
output[converted.length()] = '\0';
return output;
} catch (std::runtime_error& ex) {
cError = ex.what();
return nullptr;
}
}
void opencc_convert_utf8_free(char* str) { delete[] str; }
const char* opencc_error(void) { return cError.c_str(); }