dservice
Форк от valentingushchin/dservice
1/*
2* Modern Native AddIn
3* Copyright (C) 2018 Infactum
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU Affero General Public License as
7* published by the Free Software Foundation, either version 3 of the
8* License, or (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU Affero General Public License for more details.
14*
15* You should have received a copy of the GNU Affero General Public License
16* along with this program. If not, see <https://www.gnu.org/licenses/>.
17*
18*/
19
20#include <algorithm>
21#include <codecvt>
22#include <cwctype>
23#include <locale>
24
25#include "Component.h"
26
27#ifdef _WINDOWS
28#pragma warning (disable : 4267)
29#endif
30
31bool Component::Init(void *connection_) {
32connection = static_cast<IAddInDefBase *>(connection_);
33return connection != nullptr;
34}
35
36bool Component::setMemManager(void *memory_manager_) {
37memory_manager = static_cast<IMemoryManager *>(memory_manager_);
38return memory_manager != nullptr;
39}
40
41void Component::SetLocale(const WCHAR_T *locale) {
42#ifdef CASE_INSENSITIVE
43try {
44std::locale::global(std::locale{toUTF8String(locale)});
45} catch (std::runtime_error &) {
46std::locale::global(std::locale{""});
47}
48#endif
49}
50
51bool Component::RegisterExtensionAs(WCHAR_T **ext_name) {
52auto name = extensionName();
53
54try {
55storeVariable(name, ext_name);
56} catch (const std::bad_alloc &) {
57return false;
58}
59
60return true;
61}
62
63long Component::GetNProps() {
64return properties_meta.size();
65}
66
67long Component::FindProp(const WCHAR_T *prop_name) {
68
69std::wstring lookup_name = toWstring(prop_name);
70
71#ifdef CASE_INSENSITIVE
72lookup_name = toUpper(lookup_name);
73
74for (auto i = 0u; i < properties_meta.size(); ++i) {
75if (toUpper(properties_meta[i].alias) == lookup_name
76|| toUpper(properties_meta[i].alias_ru) == lookup_name) {
77return static_cast<long>(i);
78}
79}
80#else
81for (auto i = 0u; i < properties_meta.size(); ++i) {
82if (properties_meta[i].alias == lookup_name
83|| properties_meta[i].alias_ru == lookup_name) {
84return static_cast<long>(i);
85}
86}
87#endif
88return -1;
89
90}
91
92const WCHAR_T *Component::GetPropName(long num, long lang_alias) {
93
94std::wstring *name;
95if (lang_alias == 0) {
96name = &(properties_meta[num].alias);
97} else {
98name = &(properties_meta[num].alias_ru);
99}
100
101WCHAR_T *result = nullptr;
102storeVariable(std::u16string(reinterpret_cast<const char16_t *>(name->c_str())), &result);
103
104return result;
105}
106
107bool Component::GetPropVal(const long num, tVariant *value) {
108
109try {
110auto tmp = properties_meta[num].getter();
111storeVariable(*tmp, *value);
112} catch (const std::exception &e) {
113AddError(ADDIN_E_FAIL, extensionName(), e.what(), true);
114return false;
115} catch (...) {
116AddError(ADDIN_E_FAIL, extensionName(), UNKNOWN_EXCP, true);
117return false;
118}
119
120return true;
121}
122
123bool Component::SetPropVal(const long num, tVariant *value) {
124
125try {
126auto tmp = toStlVariant(*value);
127properties_meta[num].setter(std::move(tmp));
128} catch (const std::exception &e) {
129AddError(ADDIN_E_FAIL, extensionName(), e.what(), true);
130return false;
131} catch (...) {
132AddError(ADDIN_E_FAIL, extensionName(), UNKNOWN_EXCP, true);
133return false;
134}
135
136return true;
137}
138
139bool Component::IsPropReadable(const long lPropNum) {
140return static_cast<bool>(properties_meta[lPropNum].getter);
141}
142
143bool Component::IsPropWritable(const long lPropNum) {
144return static_cast<bool>(properties_meta[lPropNum].setter);
145}
146
147long Component::GetNMethods() {
148return methods_meta.size();
149}
150
151long Component::FindMethod(const WCHAR_T *method_name) {
152
153std::wstring lookup_name = toWstring(method_name);
154
155#ifdef CASE_INSENSITIVE
156lookup_name = toUpper(lookup_name);
157
158for (auto i = 0u; i < methods_meta.size(); ++i) {
159if (toUpper(methods_meta[i].alias) == lookup_name
160|| toUpper(methods_meta[i].alias_ru) == lookup_name) {
161return static_cast<long>(i);
162}
163}
164#else
165for (auto i = 0u; i < methods_meta.size(); ++i) {
166if (methods_meta[i].alias == lookup_name
167|| methods_meta[i].alias_ru == lookup_name) {
168return static_cast<long>(i);
169}
170}
171#endif
172
173return -1;
174}
175
176const WCHAR_T *Component::GetMethodName(const long num, const long lang_alias) {
177
178std::wstring *name;
179if (lang_alias == 0) {
180name = &(methods_meta[num].alias);
181} else {
182name = &(methods_meta[num].alias_ru);
183}
184
185WCHAR_T *result = nullptr;
186storeVariable(std::u16string(reinterpret_cast<const char16_t *>(name->c_str())), &result);
187
188return result;
189
190}
191
192long Component::GetNParams(const long method_num) {
193return methods_meta[method_num].params_count;
194}
195
196bool Component::GetParamDefValue(const long method_num, const long param_num, tVariant *def_value) {
197
198auto &def_args = methods_meta[method_num].default_args;
199
200auto it = def_args.find(param_num);
201if (it == def_args.end()) {
202return false;
203}
204
205storeVariable(it->second, *def_value);
206return true;
207}
208
209bool Component::HasRetVal(const long method_num) {
210return methods_meta[method_num].returns_value;
211}
212
213bool Component::CallAsProc(const long method_num, tVariant *params, const long array_size) {
214
215try {
216auto args = parseParams(params, array_size);
217methods_meta[method_num].call(args);
218#ifdef OUT_PARAMS
219storeParams(args, params);
220#endif
221} catch (const std::exception &e) {
222AddError(ADDIN_E_FAIL, extensionName(), e.what(), true);
223return false;
224} catch (...) {
225AddError(ADDIN_E_FAIL, extensionName(), UNKNOWN_EXCP, true);
226return false;
227}
228
229return true;
230}
231
232bool Component::CallAsFunc(const long method_num, tVariant *ret_value, tVariant *params, const long array_size) {
233
234try {
235auto args = parseParams(params, array_size);
236variant_t result = methods_meta[method_num].call(args);
237storeVariable(result, *ret_value);
238#ifdef OUT_PARAMS
239storeParams(args, params);
240#endif
241} catch (const std::exception &e) {
242AddError(ADDIN_E_FAIL, extensionName(), e.what(), true);
243return false;
244} catch (...) {
245AddError(ADDIN_E_FAIL, extensionName(), UNKNOWN_EXCP, true);
246return false;
247}
248
249return true;
250
251}
252
253void Component::AddError(unsigned short code, const std::string &src, const std::string &msg, bool throw_excp) {
254WCHAR_T *source = nullptr;
255WCHAR_T *descr = nullptr;
256
257storeVariable(src, &source);
258storeVariable(msg, &descr);
259
260connection->AddError(code, source, descr, throw_excp);
261
262memory_manager->FreeMemory(reinterpret_cast<void **>(&source));
263memory_manager->FreeMemory(reinterpret_cast<void **>(&descr));
264}
265
266bool Component::ExternalEvent(const std::string &src, const std::string &msg, const std::string &data) {
267WCHAR_T *wszSource = nullptr;
268WCHAR_T *wszMessage = nullptr;
269WCHAR_T *wszData = nullptr;
270
271storeVariable(src, &wszSource);
272storeVariable(msg, &wszMessage);
273storeVariable(data, &wszData);
274
275auto success = connection->ExternalEvent(wszSource, wszMessage, wszData);
276
277memory_manager->FreeMemory(reinterpret_cast<void **>(&wszSource));
278memory_manager->FreeMemory(reinterpret_cast<void **>(&wszMessage));
279memory_manager->FreeMemory(reinterpret_cast<void **>(&wszData));
280
281return success;
282}
283
284bool Component::SetEventBufferDepth(long depth) {
285return connection->SetEventBufferDepth(depth);
286}
287
288long Component::GetEventBufferDepth() {
289return connection->GetEventBufferDepth();
290}
291
292void Component::AddProperty(const std::wstring &alias, const std::wstring &alias_ru,
293std::function<std::shared_ptr<variant_t>(void)> getter,
294std::function<void(variant_t &&)> setter) {
295
296PropertyMeta meta{alias, alias_ru, std::move(getter), std::move(setter)};
297properties_meta.push_back(std::move(meta));
298
299}
300
301void Component::AddProperty(const std::wstring &alias, const std::wstring &alias_ru,
302std::shared_ptr<variant_t> storage) {
303
304if (!storage) {
305return;
306}
307
308AddProperty(alias, alias_ru,
309[storage]() { // getter
310return storage;
311},
312[storage](variant_t &&v) -> void { //setter
313*storage = std::move(v);
314});
315
316}
317
318variant_t Component::toStlVariant(tVariant src) {
319switch (src.vt) {
320case VTYPE_EMPTY:
321return UNDEFINED;
322case VTYPE_I4: //int32_t
323return src.lVal;
324case VTYPE_R8: //double
325return src.dblVal;
326case VTYPE_PWSTR: { //std::string
327return toUTF8String(std::basic_string_view(src.pwstrVal, src.wstrLen));
328}
329case VTYPE_BOOL:
330return src.bVal;
331case VTYPE_BLOB:
332return std::vector<char>(src.pstrVal, src.pstrVal + src.strLen);
333case VTYPE_TM:
334return src.tmVal;
335default:
336throw std::bad_cast();
337}
338}
339
340void Component::storeVariable(const variant_t &src, tVariant &dst) {
341
342if (dst.vt == VTYPE_PWSTR && dst.pwstrVal != nullptr) {
343memory_manager->FreeMemory(reinterpret_cast<void **>(&dst.pwstrVal));
344}
345
346if ((dst.vt == VTYPE_PSTR || dst.vt == VTYPE_BLOB) && dst.pstrVal != nullptr) {
347memory_manager->FreeMemory(reinterpret_cast<void **>(&dst.pstrVal));
348}
349
350std::visit(overloaded{
351[&](std::monostate) { dst.vt = VTYPE_EMPTY; },
352[&](const int32_t &v) {
353dst.vt = VTYPE_I4;
354dst.lVal = v;
355},
356[&](const double &v) {
357dst.vt = VTYPE_R8;
358dst.dblVal = v;
359},
360[&](const bool v) {
361dst.vt = VTYPE_BOOL;
362dst.bVal = v;
363},
364[&](const std::tm &v) {
365dst.vt = VTYPE_TM;
366dst.tmVal = v;
367},
368[&](const std::string &v) { storeVariable(v, dst); },
369[&](const std::vector<char> &v) { storeVariable(v, dst); }
370}, src);
371
372}
373
374void Component::storeVariable(const std::string &src, tVariant &dst) {
375
376std::u16string tmp = toUTF16String(src);
377
378dst.vt = VTYPE_PWSTR;
379storeVariable(tmp, &dst.pwstrVal);
380dst.wstrLen = static_cast<uint32_t>(tmp.length());
381}
382
383void Component::storeVariable(const std::string &src, WCHAR_T **dst) {
384std::u16string tmp = toUTF16String(src);
385storeVariable(tmp, dst);
386}
387
388void Component::storeVariable(const std::u16string &src, WCHAR_T **dst) {
389
390size_t c_size = (src.size() + 1) * sizeof(char16_t);
391
392if (!memory_manager || !memory_manager->AllocMemory(reinterpret_cast<void **>(dst), c_size)) {
393throw std::bad_alloc();
394};
395
396memcpy(*dst, src.c_str(), c_size);
397}
398
399void Component::storeVariable(const std::vector<char> &src, tVariant &dst) {
400
401dst.vt = VTYPE_BLOB;
402dst.strLen = src.size();
403
404if (!memory_manager || !memory_manager->AllocMemory(reinterpret_cast<void **>(&dst.pstrVal), src.size())) {
405throw std::bad_alloc();
406};
407
408memcpy(dst.pstrVal, src.data(), src.size());
409}
410
411std::vector<variant_t> Component::parseParams(tVariant *params, long array_size) {
412std::vector<variant_t> result;
413
414auto size = static_cast<const unsigned long>(array_size);
415result.reserve(size);
416for (size_t i = 0; i < size; i++) {
417result.emplace_back(toStlVariant(params[i]));
418}
419
420return result;
421}
422
423void Component::storeParams(const std::vector<variant_t> &src, tVariant *dest) {
424for (size_t i = 0; i < src.size(); i++) {
425storeVariable(src[i], dest[i]);
426}
427}
428
429std::wstring Component::toUpper(std::wstring str) {
430std::transform(str.begin(), str.end(), str.begin(), std::towupper);
431return str;
432}
433
434std::string Component::toUTF8String(std::basic_string_view<WCHAR_T> src) {
435#ifdef _WINDOWS
436// VS bug
437// https://social.msdn.microsoft.com/Forums/en-US/8f40dcd8-c67f-4eba-9134-a19b9178e481/vs-2015-rc-linker-stdcodecvt-error?forum=vcgeneral
438static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt_utf8_utf16;
439return cvt_utf8_utf16.to_bytes(src.data(), src.data() + src.size());
440#else
441static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> cvt_utf8_utf16;
442return cvt_utf8_utf16.to_bytes(reinterpret_cast<const char16_t *>(src.data()),
443reinterpret_cast<const char16_t *>(src.data() + src.size()));
444#endif
445}
446
447std::wstring Component::toWstring(std::basic_string_view<WCHAR_T> src) {
448#ifdef _WINDOWS
449return std::wstring(src);
450#else
451std::wstring_convert<std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>> conv;
452return conv.from_bytes(reinterpret_cast<const char*>(src.data()),
453reinterpret_cast<const char*>(src.data() + src.size()));
454#endif
455}
456
457std::u16string Component::toUTF16String(std::string_view src) {
458#ifdef _WINDOWS
459static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt_utf8_utf16;
460std::wstring tmp = cvt_utf8_utf16.from_bytes(src.data(), src.data() + src.size());
461return std::u16string(reinterpret_cast<const char16_t *>(tmp.data()), tmp.size());
462#else
463static std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> cvt_utf8_utf16;
464return cvt_utf8_utf16.from_bytes(src.data(), src.data() + src.size());
465#endif
466}
467/*
468// ++ regex
469void Component::returnString(tVariant* Result, const std::wstring& String) const {
470auto count = 1 + String.size();
471auto size = count * sizeof std::wstring::value_type();
472if (!size || !memory_manager->AllocMemory(reinterpret_cast<void**>(&Result->pwstrVal), size)) return;
473#ifdef __linux__
474Chars::ToWCHAR(&Result->pwstrVal, String.data());
475#elif _WIN32
476if (wcscpy_s(Result->pwstrVal, count, String.c_str())) return;
477#endif
478Result->vt = VTYPE_PWSTR;
479Result->wstrLen = count - 1;
480}
481
482void Component::returnBool(tVariant* Result, bool Value) {
483Result->vt = VTYPE_BOOL;
484Result->bVal = Value;
485}
486// -- regex
487*/