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