aboutsummaryrefslogtreecommitdiffhomepage
path: root/win32/HanjaDic.cxx
blob: a218b1f183b3d92f71825347b1ab52bc96e32bfc (plain)
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
// 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>

#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <ole2.h>

#include "UniConversion.h"
#include "HanjaDic.h"

namespace Scintilla::Internal {

namespace HanjaDict {

interface IRadical;
interface IHanja;
interface IStrokes;

typedef enum { HANJA_UNKNOWN = 0, HANJA_K0 = 1, HANJA_K1 = 2, HANJA_OTHER = 3 } HANJA_TYPE;

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 HanjaDic {
private:
	HRESULT hr;
	CLSID CLSID_HanjaDic;

public:
	IHanjaDic *HJinterface;

	HanjaDic() : HJinterface(nullptr) {
		hr = CLSIDFromProgID(OLESTR("mshjdic.hanjadic"), &CLSID_HanjaDic);
		if (SUCCEEDED(hr)) {
			hr = CoCreateInstance(CLSID_HanjaDic, nullptr,
					CLSCTX_INPROC_SERVER, IID_IHanjaDic,
					(LPVOID *)& HJinterface);
			if (SUCCEEDED(hr)) {
				hr = HJinterface->OpenMainDic();
			}
		}
	}

	// Deleted so HanjaDic objects can not be copied.
	HanjaDic(const HanjaDic &) = delete;
	HanjaDic(HanjaDic &&) = delete;
	HanjaDic &operator=(const HanjaDic &) = delete;
	HanjaDic &operator=(HanjaDic &&) = delete;

	~HanjaDic() {
		if (SUCCEEDED(hr)) {
			hr = HJinterface->CloseMainDic();
			try {
				// This can never fail but IUnknown::Release is not marked noexcept.
				HJinterface->Release();
			} catch (...) {
				// Ignore any exception
			}
		}
	}

	bool HJdictAvailable() {
		return SUCCEEDED(hr);
	}

	bool IsHanja(int hanja) {
		HANJA_TYPE hanjaType;
		hr = HJinterface->GetHanjaType(static_cast<unsigned short>(hanja), &hanjaType);
		if (SUCCEEDED(hr)) {
			return (hanjaType > 0);
		}
		return false;
	}
};

int GetHangulOfHanja(wchar_t *inout) {
	// Convert every hanja to hangul.
	// Return the number of characters converted.
	int changed = 0;
	HanjaDic dict;
	if (dict.HJdictAvailable()) {
		const size_t len = wcslen(inout);
		wchar_t conv[UTF8MaxBytes] = {0};
		BSTR bstrHangul = SysAllocString(conv);
		for (size_t i=0; i<len; i++) {
			if (dict.IsHanja(static_cast<int>(inout[i]))) { // Pass hanja only!
				conv[0] = inout[i];
				BSTR bstrHanja = SysAllocString(conv);
				const HRESULT hr = dict.HJinterface->HanjaToHangul(bstrHanja, &bstrHangul);
				if (SUCCEEDED(hr)) {
					inout[i] = static_cast<wchar_t>(bstrHangul[0]);
					changed += 1;
				}
				SysFreeString(bstrHanja);
			}
		}
		SysFreeString(bstrHangul);
	}
	return changed;
}

}
}