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