1 /*
2  * Copyright (C) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <memory>
16 #include <vector>
17 #include "async_call.h"
18 #include "js_native_api.h"
19 #include "js_native_api_types.h"
20 #include "napi_common_want.h"
21 #include "paste_data_record.h"
22 #include "pasteboard_common.h"
23 #include "pasteboard_hilog.h"
24 #include "pasteboard_js_err.h"
25 #include "pasteboard_napi.h"
26 #include "pastedata_napi.h"
27 #include "pastedata_record_napi.h"
28 #include "tlv_object.h"
29 #include "unified_meta.h"
30 
31 using namespace OHOS::MiscServices;
32 using namespace OHOS::Media;
33 
34 namespace OHOS {
35 namespace MiscServicesNapi {
36 static thread_local napi_ref g_pasteDataRecord = nullptr;
37 const int ARGC_TYPE_SET0 = 0;
38 const int ARGC_TYPE_SET1 = 1;
39 const int ARGC_TYPE_SET2 = 2;
40 constexpr int32_t MIMETYPE_MAX_SIZE = 1024;
41 constexpr size_t ENTRY_GETTER_TIMEOUT = 2;
42 
PasteDataRecordNapi()43 PasteDataRecordNapi::PasteDataRecordNapi() : env_(nullptr)
44 {
45 }
46 
~PasteDataRecordNapi()47 PasteDataRecordNapi::~PasteDataRecordNapi()
48 {
49 }
50 
NewInstanceByRecord(napi_env env,napi_value & instance,const std::shared_ptr<MiscServices::PasteDataRecord> & record)51 bool PasteDataRecordNapi::NewInstanceByRecord(
52     napi_env env, napi_value &instance, const std::shared_ptr<MiscServices::PasteDataRecord> &record)
53 {
54     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
55     PasteDataRecordNapi *obj = nullptr;
56     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
57     if ((status != napi_ok) || (obj == nullptr)) {
58         return false;
59     }
60     obj->value_ = record;
61     obj->JSFillInstance(env, instance);
62     return true;
63 }
64 
NewHtmlTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)65 bool PasteDataRecordNapi::NewHtmlTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
66 {
67     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
68     PasteDataRecordNapi *obj = nullptr;
69     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
70     if ((status != napi_ok) || (obj == nullptr)) {
71         return false;
72     }
73     obj->value_ = PasteboardClient::GetInstance()->CreateHtmlTextRecord(text);
74     obj->JSFillInstance(env, instance);
75     return true;
76 }
77 
NewPlainTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)78 bool PasteDataRecordNapi::NewPlainTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
79 {
80     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
81     PasteDataRecordNapi *obj = nullptr;
82     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
83     if ((status != napi_ok) || (obj == nullptr)) {
84         return false;
85     }
86     obj->value_ = PasteboardClient::GetInstance()->CreatePlainTextRecord(text);
87     obj->JSFillInstance(env, instance);
88     return true;
89 }
90 
NewPixelMapRecordInstance(napi_env env,const std::shared_ptr<PixelMap> pixelMap,napi_value & instance)91 bool PasteDataRecordNapi::NewPixelMapRecordInstance(
92     napi_env env, const std::shared_ptr<PixelMap> pixelMap, napi_value &instance)
93 {
94     if (pixelMap == nullptr) {
95         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pixelMap is nullptr.");
96         return false;
97     }
98 
99     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
100     PasteDataRecordNapi *obj = nullptr;
101     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
102     if ((status != napi_ok) || (obj == nullptr)) {
103         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed.");
104         return false;
105     }
106     obj->value_ = PasteboardClient::GetInstance()->CreatePixelMapRecord(pixelMap);
107     obj->JSFillInstance(env, instance);
108     return true;
109 }
110 
NewUriRecordInstance(napi_env env,const std::string & text,napi_value & instance)111 bool PasteDataRecordNapi::NewUriRecordInstance(napi_env env, const std::string &text, napi_value &instance)
112 {
113     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
114     PasteDataRecordNapi *obj = nullptr;
115     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
116     if ((status != napi_ok) || (obj == nullptr)) {
117         return false;
118     }
119     obj->value_ = PasteboardClient::GetInstance()->CreateUriRecord(OHOS::Uri(text));
120     obj->JSFillInstance(env, instance);
121     return true;
122 }
123 
NewWantRecordInstance(napi_env env,const std::shared_ptr<OHOS::AAFwk::Want> want,napi_value & instance)124 bool PasteDataRecordNapi::NewWantRecordInstance(
125     napi_env env, const std::shared_ptr<OHOS::AAFwk::Want> want, napi_value &instance)
126 {
127     if (!want) {
128         return false;
129     }
130 
131     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
132     PasteDataRecordNapi *obj = nullptr;
133     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
134     if ((status != napi_ok) || (obj == nullptr)) {
135         return false;
136     }
137     obj->value_ = PasteboardClient::GetInstance()->CreateWantRecord(want);
138     obj->JSFillInstance(env, instance);
139     return true;
140 }
141 
NewKvRecordInstance(napi_env env,const std::string & mimeType,const std::vector<uint8_t> & arrayBuffer,napi_value & instance)142 bool PasteDataRecordNapi::NewKvRecordInstance(
143     napi_env env, const std::string &mimeType, const std::vector<uint8_t> &arrayBuffer, napi_value &instance)
144 {
145     NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
146     PasteDataRecordNapi *obj = nullptr;
147     napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
148     if ((status != napi_ok) || (obj == nullptr)) {
149         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed");
150         return false;
151     }
152     obj->value_ = PasteboardClient::GetInstance()->CreateKvRecord(mimeType, arrayBuffer);
153     obj->JSFillInstance(env, instance);
154     return true;
155 }
156 
NewEntryGetterRecordInstance(const std::vector<std::string> mimeTypes,std::shared_ptr<PastedataRecordEntryGetterInstance> entryGetter,napi_value & instance)157 bool PasteDataRecordNapi::NewEntryGetterRecordInstance(const std::vector<std::string> mimeTypes,
158     std::shared_ptr<PastedataRecordEntryGetterInstance> entryGetter, napi_value &instance)
159 {
160     if (entryGetter == nullptr) {
161         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "no entry getter");
162         return false;
163     }
164     NAPI_CALL_BASE(entryGetter->GetEnv(), PasteDataRecordNapi::NewInstance(entryGetter->GetEnv(), instance), false);
165     PasteDataRecordNapi *obj = nullptr;
166     napi_status status = napi_unwrap(entryGetter->GetEnv(), instance, reinterpret_cast<void **>(&obj));
167     if ((status != napi_ok) || (obj == nullptr)) {
168         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed");
169         return false;
170     }
171     obj->value_ = PasteboardClient::GetInstance()->CreateMultiDelayRecord(mimeTypes, entryGetter->GetStub());
172     obj->JSFillInstance(entryGetter->GetEnv(), instance);
173     return true;
174 }
175 
SetNamedPropertyByStr(napi_env env,napi_value & instance,const char * propName,const char * propValue)176 void PasteDataRecordNapi::SetNamedPropertyByStr(
177     napi_env env, napi_value &instance, const char *propName, const char *propValue)
178 {
179     if (propName == nullptr || propValue == nullptr) {
180         return;
181     }
182     napi_value prop = nullptr;
183     if (napi_create_string_utf8(env, propValue, NAPI_AUTO_LENGTH, &prop) == napi_ok) {
184         napi_set_named_property(env, instance, propName, prop);
185     }
186 }
187 
SetNapiKvData(napi_env env,std::shared_ptr<MineCustomData> customData)188 napi_value PasteDataRecordNapi::SetNapiKvData(napi_env env, std::shared_ptr<MineCustomData> customData)
189 {
190     if (customData == nullptr) {
191         return nullptr;
192     }
193     napi_value jsCustomData = nullptr;
194     napi_create_object(env, &jsCustomData);
195     auto itemData = customData->GetItemData();
196     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "size = %{public}d.", static_cast<uint32_t>(itemData.size()));
197     for (auto &item : itemData) {
198         void *data = nullptr;
199         napi_value arrayBuffer = nullptr;
200         size_t len = item.second.size();
201         NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &arrayBuffer));
202         errno_t ret = (len == 0) ? EOK : memcpy_s(data, len, reinterpret_cast<const void *>(item.second.data()), len);
203         if (ret != EOK) {
204             PASTEBOARD_HILOGW(PASTEBOARD_MODULE_CLIENT, "copy %{public}s failed, ret=%{public}d",
205                 item.first.c_str(), ret);
206         }
207         NAPI_CALL(env, napi_set_named_property(env, jsCustomData, item.first.c_str(), arrayBuffer));
208         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s.", item.first.c_str());
209     }
210     return jsCustomData;
211 }
212 
GetNativeKvData(napi_env env,napi_value napiValue)213 std::shared_ptr<MineCustomData> PasteDataRecordNapi::GetNativeKvData(napi_env env, napi_value napiValue)
214 {
215     napi_valuetype valueType = napi_undefined;
216     NAPI_CALL(env, napi_typeof(env, napiValue, &valueType));
217     NAPI_ASSERT(env, valueType == napi_object, "Wrong argument type. Object expected.");
218 
219     napi_value mimeTypes = nullptr;
220     NAPI_CALL(env, napi_get_property_names(env, napiValue, &mimeTypes));
221     uint32_t mimeTypesNum = 0;
222     NAPI_CALL(env, napi_get_array_length(env, mimeTypes, &mimeTypesNum));
223 
224     PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "mimeTypesNum = %{public}u", mimeTypesNum);
225     std::shared_ptr<MineCustomData> customData = std::make_shared<MineCustomData>();
226     for (uint32_t i = 0; i < mimeTypesNum; i++) {
227         napi_value mimeTypeNapi = nullptr;
228         NAPI_CALL(env, napi_get_element(env, mimeTypes, i, &mimeTypeNapi));
229 
230         std::string mimeType;
231         bool ret = GetValue(env, mimeTypeNapi, mimeType);
232         if (!ret || (mimeType.size() > MIMETYPE_MAX_SIZE) || mimeType == "") {
233             return nullptr;
234         }
235         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s,", mimeType.c_str());
236 
237         napi_value napiArrayBuffer = nullptr;
238         NAPI_CALL(env, napi_get_property(env, napiValue, mimeTypeNapi, &napiArrayBuffer));
239         void *data = nullptr;
240         size_t dataLen;
241         NAPI_CALL(env, napi_get_arraybuffer_info(env, napiArrayBuffer, &data, &dataLen));
242         customData->AddItemData(mimeType,
243             std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen));
244     }
245     return customData;
246 }
247 
JSFillInstance(napi_env env,napi_value & instance)248 void PasteDataRecordNapi::JSFillInstance(napi_env env, napi_value &instance)
249 {
250     if (value_ == nullptr) {
251         return;
252     }
253     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "mimeType = %{public}s.", value_->GetMimeType().c_str());
254 
255     auto mimeType = value_->GetMimeType();
256     SetNamedPropertyByStr(env, instance, "mimeType", mimeType.c_str());
257 
258     auto plainText = value_->GetPlainText();
259     if (plainText != nullptr) {
260         SetNamedPropertyByStr(env, instance, "plainText", plainText->c_str());
261         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill plainText.");
262     }
263 
264     auto htmlText = value_->GetHtmlText();
265     if (htmlText != nullptr) {
266         SetNamedPropertyByStr(env, instance, "htmlText", htmlText->c_str());
267         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill htmlText.");
268     }
269 
270     auto uri = value_->GetUri();
271     if (uri != nullptr) {
272         SetNamedPropertyByStr(env, instance, "uri", uri->ToString().c_str());
273         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill uri.");
274     }
275 
276     auto want = value_->GetWant();
277     if (want != nullptr) {
278         napi_value jsWant = OHOS::AppExecFwk::WrapWant(env, *want);
279         napi_set_named_property(env, instance, "want", jsWant);
280         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill want.");
281     }
282 
283     auto pixelMap = value_->GetPixelMap();
284     if (pixelMap != nullptr) {
285         napi_value jsPixelMap = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
286         napi_set_named_property(env, instance, "pixelMap", jsPixelMap);
287         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill pixelMap.");
288     }
289 
290     auto customData = value_->GetCustomData();
291     if (customData != nullptr) {
292         napi_value jsCustomData = PasteDataRecordNapi::SetNapiKvData(env, customData);
293         napi_set_named_property(env, instance, "data", jsCustomData);
294         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill data.");
295     }
296 }
297 
ConvertToText(napi_env env,napi_callback_info info)298 napi_value PasteDataRecordNapi::ConvertToText(napi_env env, napi_callback_info info)
299 {
300     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToText is called!");
301 
302     struct ExeContext {
303         std::string text;
304         PasteDataRecordNapi *obj = nullptr;
305     };
306     auto exeContext = std::make_shared<ExeContext>();
307     auto input = [exeContext](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
308         // convertToText(callback: AsyncCallback<string>) has 1 args
309         if (argc > 0 &&
310             !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
311             return napi_invalid_arg;
312         }
313         PasteDataRecordNapi *obj = nullptr;
314         napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&obj));
315         if (status == napi_ok || obj != nullptr) {
316             exeContext->obj = obj;
317         }
318         return napi_ok;
319     };
320 
321     auto exec = [exeContext](AsyncCall::Context *ctx) {
322         if ((exeContext->obj != nullptr) && (exeContext->obj->value_ != nullptr)) {
323             exeContext->text = exeContext->obj->value_->ConvertToText();
324         }
325     };
326     auto output = [exeContext](napi_env env, napi_value *result) -> napi_status {
327         napi_status status =
328             napi_create_string_utf8(env, (exeContext->text).c_str(), (exeContext->text).length(), result);
329         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_create_string_utf8 status = %{public}d", status);
330         return status;
331     };
332 
333     // 0: the AsyncCall at the first position;
334     AsyncCall asyncCall(env, info, std::make_shared<AsyncCall::Context>(std::move(input), std::move(output)), 0);
335     return asyncCall.Call(env, exec);
336 }
337 
ConvertToTextV9(napi_env env,napi_callback_info info)338 napi_value PasteDataRecordNapi::ConvertToTextV9(napi_env env, napi_callback_info info)
339 {
340     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToTextV9 is called!");
341     return ConvertToText(env, info);
342 }
343 
ToPlainText(napi_env env,napi_callback_info info)344 napi_value PasteDataRecordNapi::ToPlainText(napi_env env, napi_callback_info info)
345 {
346     PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ToPlainText is called!");
347     size_t argc = 1;
348     napi_value argv[1] = { 0 };
349     napi_value thisVar = nullptr;
350 
351     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
352     NAPI_ASSERT(env, argc >= ARGC_TYPE_SET0, "Wrong number of arguments");
353 
354     PasteDataRecordNapi *obj = nullptr;
355     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
356     if ((status != napi_ok) || (obj == nullptr)) {
357         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Get ToPlainText object failed");
358         return nullptr;
359     }
360 
361     std::string str = obj->value_->ConvertToText();
362     napi_value result = nullptr;
363     napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &result);
364     return result;
365 }
366 
AddEntry(napi_env env,napi_callback_info info)367 napi_value PasteDataRecordNapi::AddEntry(napi_env env, napi_callback_info info)
368 {
369     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "AddEntry is called!");
370     size_t argc = ARGC_TYPE_SET2;
371     napi_value argv[ARGC_TYPE_SET2] = { 0 };
372     napi_value thisVar = nullptr;
373     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
374     std::string mimeType;
375     if (!CheckArgs(env, argv, argc, mimeType)) {
376         return nullptr;
377     }
378 
379     PasteDataRecordNapi *obj = nullptr;
380     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
381     if ((status != napi_ok) || (obj == nullptr)) {
382         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Get AddEntry object failed");
383         return nullptr;
384     }
385 
386     EntryValue entryValue;
387     if (!GetNativeValue(env, mimeType, argv[1], entryValue)) {
388         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetNativeValue failed");
389         return nullptr;
390     }
391 
392     auto utdType = CommonUtils::Convert2UtdId(UDMF::UD_BUTT, mimeType);
393     std::shared_ptr<PasteDataEntry> pasteDataEntry = std::make_shared<PasteDataEntry>(utdType, entryValue);
394     obj->value_->AddEntry(utdType, pasteDataEntry);
395     return nullptr;
396 }
397 
GetValidTypes(napi_env env,napi_callback_info info)398 napi_value PasteDataRecordNapi::GetValidTypes(napi_env env, napi_callback_info info)
399 {
400     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetValidType is called!");
401     size_t argc = ARGC_TYPE_SET1;
402     napi_value argv[ARGC_TYPE_SET1] = { 0 };
403     napi_value thisVar = nullptr;
404     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
405     std::vector<std::string> mimeTypes;
406 
407     if (!CheckExpression(env, argc >= ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
408         "Parameter error. The number of arguments cannot be less than one.") ||
409         !CheckArgsArray(env, argv[0], mimeTypes)) {
410         return nullptr;
411     }
412 
413     PasteDataRecordNapi *obj = nullptr;
414     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
415     if ((status != napi_ok) || (obj == nullptr)) {
416         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Get GetValidType object failed");
417         return nullptr;
418     }
419     std::vector<std::string> validTypes = obj->value_->GetValidMimeTypes(mimeTypes);
420     napi_value result = nullptr;
421     NAPI_CALL(env, napi_create_array(env, &result));
422     for (uint32_t i = 0; i < validTypes.size(); i++) {
423         napi_value element;
424         NAPI_CALL(env, napi_create_string_utf8(env, validTypes[i].c_str(), NAPI_AUTO_LENGTH, &element));
425         NAPI_CALL(env, napi_set_element(env, result, i, element));
426     }
427     return result;
428 }
429 
GetRecordData(napi_env env,napi_callback_info info)430 napi_value PasteDataRecordNapi::GetRecordData(napi_env env, napi_callback_info info)
431 {
432     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "GetValidType is called!");
433 
434     struct ExeContext {
435         std::string mimeType;
436         std::shared_ptr<PasteDataEntry> entryValue;
437         PasteDataRecordNapi *obj = nullptr;
438     };
439     auto exeContext = std::make_shared<ExeContext>();
440     auto input = [exeContext](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
441         if (!CheckExpression(env, argc >= ARGC_TYPE_SET1, JSErrorCode::INVALID_PARAMETERS,
442             "Parameter error. The number of arguments cannot be less than one.") ||
443             !CheckArgsMimeType(env, argv[0], exeContext->mimeType)) {
444             return napi_invalid_arg;
445         }
446         if (argc > ARGC_TYPE_SET1 &&
447             !CheckArgsType(env, argv[ARGC_TYPE_SET1], napi_function,
448             "Parameter error. The type of callback must be function.")) {
449             return napi_invalid_arg;
450         }
451         napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&(exeContext->obj)));
452         if ((status != napi_ok) || (exeContext->obj == nullptr)) {
453             return napi_object_expected;
454         }
455         return napi_ok;
456     };
457 
458     auto exec = [exeContext](AsyncCall::Context *ctx) {
459         if ((exeContext->obj != nullptr) && (exeContext->obj->value_ != nullptr)) {
460             exeContext->entryValue = exeContext->obj->value_->GetEntryByMimeType(exeContext->mimeType);
461         }
462     };
463     auto output = [exeContext](napi_env env, napi_value *result) -> napi_status {
464         napi_status status = ConvertEntryValue(env, result, exeContext->mimeType, exeContext->entryValue);
465         return status;
466     };
467 
468     // 1: the AsyncCall at the first position;
469     AsyncCall asyncCall(env, info, std::make_shared<AsyncCall::Context>(std::move(input),
470         std::move(output)), ARGC_TYPE_SET1);
471     return asyncCall.Call(env, exec);
472 }
473 
PasteDataRecordInit(napi_env env,napi_value exports)474 napi_value PasteDataRecordNapi::PasteDataRecordInit(napi_env env, napi_value exports)
475 {
476     napi_property_descriptor properties[] = {
477         DECLARE_NAPI_FUNCTION("convertToText", ConvertToText),
478         DECLARE_NAPI_FUNCTION("convertToTextV9", ConvertToTextV9),
479         DECLARE_NAPI_FUNCTION("toPlainText", ToPlainText),
480         DECLARE_NAPI_FUNCTION("addEntry", AddEntry),
481         DECLARE_NAPI_FUNCTION("getValidTypes", GetValidTypes),
482         DECLARE_NAPI_FUNCTION("getData", GetRecordData)
483     };
484 
485     napi_status status = napi_ok;
486 
487     napi_value constructor;
488     status = napi_define_class(env, "PasteDataRecord", NAPI_AUTO_LENGTH, New, nullptr,
489         sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor);
490     if (status != napi_ok) {
491         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at PasteDataRecordInit");
492         return nullptr;
493     }
494 
495     status = napi_create_reference(env, constructor, 1, &g_pasteDataRecord);
496     if (status != napi_ok) {
497         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "PasteDataRecordInit create reference failed");
498         return nullptr;
499     }
500     napi_set_named_property(env, exports, "PasteDataRecord", constructor);
501     return exports;
502 }
503 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)504 void PasteDataRecordNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
505 {
506     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "Destructor");
507     PasteDataRecordNapi *obj = static_cast<PasteDataRecordNapi *>(nativeObject);
508     delete obj;
509 }
510 
New(napi_env env,napi_callback_info info)511 napi_value PasteDataRecordNapi::New(napi_env env, napi_callback_info info)
512 {
513     size_t argc = ARGC_TYPE_SET1;
514     napi_value argv[1] = { 0 };
515     napi_value thisVar = nullptr;
516     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
517 
518     // get native object
519     PasteDataRecordNapi *obj = new PasteDataRecordNapi();
520     obj->env_ = env;
521     ASSERT_CALL(env, napi_wrap(env, thisVar, obj, PasteDataRecordNapi::Destructor, nullptr, nullptr), obj);
522     return thisVar;
523 }
524 
NewInstance(napi_env env,napi_value & instance)525 napi_status PasteDataRecordNapi::NewInstance(napi_env env, napi_value &instance)
526 {
527     napi_status status = napi_invalid_arg;
528 
529     napi_value constructor;
530     status = napi_get_reference_value(env, g_pasteDataRecord, &constructor);
531     if (status != napi_ok) {
532         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
533         return status;
534     }
535 
536     status = napi_new_instance(env, constructor, 0, nullptr, &instance);
537     if (status != napi_ok) {
538         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
539         return status;
540     }
541 
542     return napi_ok;
543 }
544 
PastedataRecordEntryGetterInstance(const napi_env & env,const napi_ref & ref)545 PastedataRecordEntryGetterInstance::PastedataRecordEntryGetterInstance(const napi_env &env, const napi_ref &ref)
546     : env_(env), ref_(ref)
547 {
548     stub_ = std::make_shared<PastedataRecordEntryGetterInstance::PastedataRecordEntryGetterImpl>();
549 }
550 
~PastedataRecordEntryGetterInstance()551 PastedataRecordEntryGetterInstance::~PastedataRecordEntryGetterInstance()
552 {
553     napi_delete_reference(env_, ref_);
554 }
555 
UvWorkGetRecordByEntryGetter(uv_work_t * work,int status)556 void UvWorkGetRecordByEntryGetter(uv_work_t *work, int status)
557 {
558     if (UV_ECANCELED == status || work == nullptr || work->data == nullptr) {
559         return;
560     }
561     PasteboardEntryGetterWorker *entryGetterWork = reinterpret_cast<PasteboardEntryGetterWorker *>(work->data);
562     if (entryGetterWork == nullptr || entryGetterWork->entryGetter == nullptr) {
563         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pasteboardDataWorker or delayGetter is null");
564         delete work;
565         work = nullptr;
566         return;
567     }
568     auto env = entryGetterWork->entryGetter->GetEnv();
569     auto ref = entryGetterWork->entryGetter->GetRef();
570     napi_handle_scope scope = nullptr;
571     napi_open_handle_scope(env, &scope);
572     if (scope == nullptr) {
573         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "scope is null");
574         return;
575     }
576     napi_value undefined = nullptr;
577     napi_get_undefined(env, &undefined);
578     auto mimeType = CommonUtils::Convert2MimeType(entryGetterWork->utdId);
579     napi_value argv[1] = { CreateNapiString(env, mimeType) };
580     napi_value callback = nullptr;
581     napi_value resultOut = nullptr;
582     napi_get_reference_value(env, ref, &callback);
583     {
584         std::unique_lock<std::mutex> lock(entryGetterWork->mutex);
585         auto ret = napi_call_function(env, undefined, callback, 1, argv, &resultOut);
586         if (ret == napi_ok) {
587             EntryValue entryValue;
588             if (GetNativeValue(env, mimeType, resultOut, entryValue)) {
589                 entryGetterWork->entryValue = std::make_shared<UDMF::ValueType>(entryValue);
590             }
591         } else {
592             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "call napi_call_function is not ok, ret: %{public}d", ret);
593         }
594         napi_close_handle_scope(env, scope);
595         entryGetterWork->complete = true;
596         if (!entryGetterWork->clean) {
597             entryGetterWork->cv.notify_all();
598             return;
599         }
600     }
601     delete entryGetterWork;
602     entryGetterWork = nullptr;
603     delete work;
604     work = nullptr;
605 }
606 
GetValueByType(const std::string & utdId)607 UDMF::ValueType PastedataRecordEntryGetterInstance::GetValueByType(const std::string &utdId)
608 {
609     uv_loop_s *loop = nullptr;
610     napi_get_uv_event_loop(env_, &loop);
611     if (loop == nullptr) {
612         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "loop instance is nullptr");
613         return std::monostate{};
614     }
615     uv_work_t *work = new (std::nothrow) uv_work_t;
616     if (work == nullptr) {
617         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "work is null");
618         return std::monostate{};
619     }
620     PasteboardEntryGetterWorker *entryGetterWork = new (std::nothrow) PasteboardEntryGetterWorker();
621     if (entryGetterWork == nullptr) {
622         PASTEBOARD_HILOGW(PASTEBOARD_MODULE_JS_NAPI, "PasteboardEntryGetterWorker is null");
623         delete work;
624         work = nullptr;
625         return std::monostate{};
626     }
627     entryGetterWork->entryGetter = shared_from_this();
628     entryGetterWork->utdId = utdId;
629     work->data = reinterpret_cast<void *>(entryGetterWork);
630     bool noNeedClean = false;
631     {
632         std::unique_lock<std::mutex> lock(entryGetterWork->mutex);
633         int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvWorkGetRecordByEntryGetter);
634         if (ret != 0) {
635             delete entryGetterWork;
636             entryGetterWork = nullptr;
637             delete work;
638             work = nullptr;
639             return std::monostate{};
640         }
641         if (entryGetterWork->cv.wait_for(lock, std::chrono::seconds(ENTRY_GETTER_TIMEOUT),
642             [entryGetterWork] { return entryGetterWork->complete; }) && entryGetterWork->entryValue != nullptr) {
643             return *(entryGetterWork->entryValue);
644         }
645         if (!entryGetterWork->complete && uv_cancel((uv_req_t*)work) != 0) {
646             entryGetterWork->clean = true;
647             noNeedClean = true;
648         }
649     }
650     if (!noNeedClean) {
651         delete entryGetterWork;
652         entryGetterWork = nullptr;
653         delete work;
654         work = nullptr;
655     }
656     return std::monostate{};
657 }
658 
GetValueByType(const std::string & utdId)659 UDMF::ValueType PastedataRecordEntryGetterInstance::PastedataRecordEntryGetterImpl::GetValueByType(
660     const std::string &utdId)
661 {
662     if (wrapper_ == nullptr) {
663         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "PastedataRecordEntryGetterImpl::GetValueByType no entry getter");
664         return std::monostate{};
665     }
666     return wrapper_->GetValueByType(utdId);
667 }
668 
SetEntryGetterWrapper(const std::shared_ptr<PastedataRecordEntryGetterInstance> entryGetterInstance)669 void PastedataRecordEntryGetterInstance::PastedataRecordEntryGetterImpl::SetEntryGetterWrapper(
670     const std::shared_ptr<PastedataRecordEntryGetterInstance> entryGetterInstance)
671 {
672     wrapper_ = entryGetterInstance;
673 }
674 } // namespace MiscServicesNapi
675 } // namespace OHOS
676