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