1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// Scintilla source code edit control
/** @file HanjaDic.cxx
** Korean Hanja Dictionary
** Convert between Korean Hanja and Hangul by COM interface.
**/
// Copyright 2015 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <string>
#include <string_view>
#include <memory>
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <ole2.h>
#include "WinTypes.h"
#include "HanjaDic.h"
namespace Scintilla::Internal::HanjaDict {
interface IRadical;
interface IHanja;
interface IStrokes;
enum HANJA_TYPE { HANJA_UNKNOWN = 0, HANJA_K0 = 1, HANJA_K1 = 2, HANJA_OTHER = 3 };
interface IHanjaDic : IUnknown {
STDMETHOD(OpenMainDic)();
STDMETHOD(CloseMainDic)();
STDMETHOD(GetHanjaWords)(BSTR bstrHangul, SAFEARRAY* ppsaHanja, VARIANT_BOOL* pfFound);
STDMETHOD(GetHanjaChars)(unsigned short wchHangul, BSTR* pbstrHanjaChars, VARIANT_BOOL* pfFound);
STDMETHOD(HanjaToHangul)(BSTR bstrHanja, BSTR* pbstrHangul);
STDMETHOD(GetHanjaType)(unsigned short wchHanja, HANJA_TYPE* pHanjaType);
STDMETHOD(GetHanjaSense)(unsigned short wchHanja, BSTR* pbstrSense);
STDMETHOD(GetRadicalID)(short SeqNumOfRadical, short* pRadicalID, unsigned short* pwchRadical);
STDMETHOD(GetRadical)(short nRadicalID, IRadical** ppIRadical);
STDMETHOD(RadicalIDToHanja)(short nRadicalID, unsigned short* pwchRadical);
STDMETHOD(GetHanja)(unsigned short wchHanja, IHanja** ppIHanja);
STDMETHOD(GetStrokes)(short nStrokes, IStrokes** ppIStrokes);
STDMETHOD(OpenDefaultCustomDic)();
STDMETHOD(OpenCustomDic)(BSTR bstrPath, long* plUdr);
STDMETHOD(CloseDefaultCustomDic)();
STDMETHOD(CloseCustomDic)(long lUdr);
STDMETHOD(CloseAllCustomDics)();
STDMETHOD(GetDefaultCustomHanjaWords)(BSTR bstrHangul, SAFEARRAY** ppsaHanja, VARIANT_BOOL* pfFound);
STDMETHOD(GetCustomHanjaWords)(long lUdr, BSTR bstrHangul, SAFEARRAY** ppsaHanja, VARIANT_BOOL* pfFound);
STDMETHOD(PutDefaultCustomHanjaWord)(BSTR bstrHangul, BSTR bstrHanja);
STDMETHOD(PutCustomHanjaWord)(long lUdr, BSTR bstrHangul, BSTR bstrHanja);
STDMETHOD(MaxNumOfRadicals)(short* pVal);
STDMETHOD(MaxNumOfStrokes)(short* pVal);
STDMETHOD(DefaultCustomDic)(long* pVal);
STDMETHOD(DefaultCustomDic)(long pVal);
STDMETHOD(MaxHanjaType)(HANJA_TYPE* pHanjaType);
STDMETHOD(MaxHanjaType)(HANJA_TYPE pHanjaType);
};
extern "C" const GUID __declspec(selectany) IID_IHanjaDic =
{ 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } };
class ScopedBSTR {
BSTR bstr = nullptr;
public:
ScopedBSTR() noexcept = default;
explicit ScopedBSTR(const OLECHAR *psz) noexcept :
bstr(SysAllocString(psz)) {
}
explicit ScopedBSTR(OLECHAR character) noexcept :
bstr(SysAllocStringLen(&character, 1)) {
}
// Deleted so ScopedBSTR objects can not be copied. Moves are OK.
ScopedBSTR(const ScopedBSTR &) = delete;
ScopedBSTR &operator=(const ScopedBSTR &) = delete;
// Moves are OK.
ScopedBSTR(ScopedBSTR &&) = default;
ScopedBSTR &operator=(ScopedBSTR &&) = default;
~ScopedBSTR() {
SysFreeString(bstr);
}
BSTR get() const noexcept {
return bstr;
}
void reset(BSTR value=nullptr) noexcept {
// https://en.cppreference.com/w/cpp/memory/unique_ptr/reset
BSTR const old = bstr;
bstr = value;
SysFreeString(old);
}
};
class HanjaDic {
std::unique_ptr<IHanjaDic, UnknownReleaser> HJinterface;
bool OpenHanjaDic(LPCOLESTR lpszProgID) noexcept {
CLSID CLSID_HanjaDic;
HRESULT hr = CLSIDFromProgID(lpszProgID, &CLSID_HanjaDic);
if (SUCCEEDED(hr)) {
IHanjaDic *instance = nullptr;
hr = CoCreateInstance(CLSID_HanjaDic, nullptr,
CLSCTX_INPROC_SERVER, IID_IHanjaDic,
reinterpret_cast<LPVOID *>(&instance));
if (SUCCEEDED(hr) && instance) {
HJinterface.reset(instance);
hr = instance->OpenMainDic();
return SUCCEEDED(hr);
}
}
return false;
}
public:
bool Open() noexcept {
return OpenHanjaDic(OLESTR("imkrhjd.hanjadic"))
|| OpenHanjaDic(OLESTR("mshjdic.hanjadic"));
}
void Close() const noexcept {
HJinterface->CloseMainDic();
}
bool IsHanja(wchar_t hanja) const noexcept {
HANJA_TYPE hanjaType = HANJA_UNKNOWN;
const HRESULT hr = HJinterface->GetHanjaType(hanja, &hanjaType);
return SUCCEEDED(hr) && hanjaType > HANJA_UNKNOWN;
}
bool HanjaToHangul(const ScopedBSTR &bstrHanja, ScopedBSTR &bstrHangul) const noexcept {
BSTR result = nullptr;
const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja.get(), &result);
bstrHangul.reset(result);
return SUCCEEDED(hr);
}
};
bool GetHangulOfHanja(std::wstring &inout) noexcept {
// Convert every hanja to hangul.
// Return whether any character been converted.
// Hanja linked to different notes in Hangul have different codes,
// so current character based conversion is enough.
// great thanks for BLUEnLIVE.
bool changed = false;
HanjaDic dict;
if (dict.Open()) {
for (wchar_t &character : inout) {
if (dict.IsHanja(character)) { // Pass hanja only!
ScopedBSTR bstrHangul;
if (dict.HanjaToHangul(ScopedBSTR(character), bstrHangul)) {
changed = true;
character = *(bstrHangul.get());
}
}
}
dict.Close();
}
return changed;
}
}
|